1342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport/*
2342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport * Battery charger driver for Dialog Semiconductor DA9030
3342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport *
4342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport * Copyright (C) 2008 Compulab, Ltd.
5342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport * 	Mike Rapoport <mike@compulab.co.il>
6342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport *
7342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport * This program is free software; you can redistribute it and/or modify
8342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport * it under the terms of the GNU General Public License version 2 as
9342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport * published by the Free Software Foundation.
10342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport */
11342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
12342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#include <linux/kernel.h>
135a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
14342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#include <linux/init.h>
15342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#include <linux/types.h>
16342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#include <linux/device.h>
17342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#include <linux/workqueue.h>
18342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#include <linux/module.h>
19342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#include <linux/platform_device.h>
20342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#include <linux/power_supply.h>
21342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#include <linux/mfd/da903x.h>
22342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
23342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#include <linux/debugfs.h>
24342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#include <linux/seq_file.h>
257e6c647ed9994428643e7e740b2d8241ee13da5cMichal Hocko#include <linux/notifier.h>
26342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
27342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#define DA9030_FAULT_LOG		0x0a
28342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#define DA9030_FAULT_LOG_OVER_TEMP	(1 << 7)
29342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#define DA9030_FAULT_LOG_VBAT_OVER	(1 << 4)
30342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
31342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#define DA9030_CHARGE_CONTROL		0x28
32342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#define DA9030_CHRG_CHARGER_ENABLE	(1 << 7)
33342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
34342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#define DA9030_ADC_MAN_CONTROL		0x30
35342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#define DA9030_ADC_TBATREF_ENABLE	(1 << 5)
36342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#define DA9030_ADC_LDO_INT_ENABLE	(1 << 4)
37342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
38342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#define DA9030_ADC_AUTO_CONTROL		0x31
39342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#define DA9030_ADC_TBAT_ENABLE		(1 << 5)
40342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#define DA9030_ADC_VBAT_IN_TXON		(1 << 4)
41342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#define DA9030_ADC_VCH_ENABLE		(1 << 3)
42342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#define DA9030_ADC_ICH_ENABLE		(1 << 2)
43342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#define DA9030_ADC_VBAT_ENABLE		(1 << 1)
44342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#define DA9030_ADC_AUTO_SLEEP_ENABLE	(1 << 0)
45342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
46342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#define DA9030_VBATMON		0x32
47342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#define DA9030_VBATMONTXON	0x33
48342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#define DA9030_TBATHIGHP	0x34
49342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#define DA9030_TBATHIGHN	0x35
50342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#define DA9030_TBATLOW		0x36
51342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
52342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#define DA9030_VBAT_RES		0x41
53342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#define DA9030_VBATMIN_RES	0x42
54342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#define DA9030_VBATMINTXON_RES	0x43
55342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#define DA9030_ICHMAX_RES	0x44
56342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#define DA9030_ICHMIN_RES	0x45
57342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#define DA9030_ICHAVERAGE_RES	0x46
58342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#define DA9030_VCHMAX_RES	0x47
59342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#define DA9030_VCHMIN_RES	0x48
60342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#define DA9030_TBAT_RES		0x49
61342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
62342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoportstruct da9030_adc_res {
63342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	uint8_t vbat_res;
64342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	uint8_t vbatmin_res;
65342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	uint8_t vbatmintxon;
66342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	uint8_t ichmax_res;
67342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	uint8_t ichmin_res;
68342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	uint8_t ichaverage_res;
69342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	uint8_t vchmax_res;
70342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	uint8_t vchmin_res;
71342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	uint8_t tbat_res;
72342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	uint8_t adc_in4_res;
73342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	uint8_t adc_in5_res;
74342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport};
75342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
76342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoportstruct da9030_battery_thresholds {
77342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	int tbat_low;
78342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	int tbat_high;
79342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	int tbat_restart;
80342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
81342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	int vbat_low;
82342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	int vbat_crit;
83342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	int vbat_charge_start;
84342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	int vbat_charge_stop;
85342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	int vbat_charge_restart;
86342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
87342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	int vcharge_min;
88342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	int vcharge_max;
89342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport};
90342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
91342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoportstruct da9030_charger {
92342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	struct power_supply psy;
93342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
94342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	struct device *master;
95342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
96342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	struct da9030_adc_res adc;
97342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	struct delayed_work work;
98342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	unsigned int interval;
99342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
100342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	struct power_supply_info *battery_info;
101342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
102342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	struct da9030_battery_thresholds thresholds;
103342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
104342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	unsigned int charge_milliamp;
105342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	unsigned int charge_millivolt;
106342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
107342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	/* charger status */
108342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	bool chdet;
109342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	uint8_t fault;
110342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	int mA;
111342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	int mV;
112342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	bool is_on;
113342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
114342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	struct notifier_block nb;
115342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
116342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	/* platform callbacks for battery low and critical events */
117342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	void (*battery_low)(void);
118342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	void (*battery_critical)(void);
119342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
120342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	struct dentry *debug_file;
121342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport};
122342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
123342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoportstatic inline int da9030_reg_to_mV(int reg)
124342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport{
125342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	return ((reg * 2650) >> 8) + 2650;
126342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport}
127342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
128342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoportstatic inline int da9030_millivolt_to_reg(int mV)
129342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport{
130342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	return ((mV - 2650) << 8) / 2650;
131342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport}
132342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
133342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoportstatic inline int da9030_reg_to_mA(int reg)
134342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport{
135342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	return ((reg * 24000) >> 8) / 15;
136342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport}
137342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
138342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#ifdef CONFIG_DEBUG_FS
139342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoportstatic int bat_debug_show(struct seq_file *s, void *data)
140342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport{
141342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	struct da9030_charger *charger = s->private;
142342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
143342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	seq_printf(s, "charger is %s\n", charger->is_on ? "on" : "off");
144342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	if (charger->chdet) {
145342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		seq_printf(s, "iset = %dmA, vset = %dmV\n",
146342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport			   charger->mA, charger->mV);
147342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	}
148342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
149342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	seq_printf(s, "vbat_res = %d (%dmV)\n",
150342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		   charger->adc.vbat_res,
151342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		   da9030_reg_to_mV(charger->adc.vbat_res));
152342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	seq_printf(s, "vbatmin_res = %d (%dmV)\n",
153342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		   charger->adc.vbatmin_res,
154342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		   da9030_reg_to_mV(charger->adc.vbatmin_res));
155342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	seq_printf(s, "vbatmintxon = %d (%dmV)\n",
156342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		   charger->adc.vbatmintxon,
157342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		   da9030_reg_to_mV(charger->adc.vbatmintxon));
158342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	seq_printf(s, "ichmax_res = %d (%dmA)\n",
159342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		   charger->adc.ichmax_res,
160342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		   da9030_reg_to_mV(charger->adc.ichmax_res));
161342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	seq_printf(s, "ichmin_res = %d (%dmA)\n",
162342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		   charger->adc.ichmin_res,
163342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		   da9030_reg_to_mA(charger->adc.ichmin_res));
164342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	seq_printf(s, "ichaverage_res = %d (%dmA)\n",
165342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		   charger->adc.ichaverage_res,
166342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		   da9030_reg_to_mA(charger->adc.ichaverage_res));
167342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	seq_printf(s, "vchmax_res = %d (%dmV)\n",
168342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		   charger->adc.vchmax_res,
169342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		   da9030_reg_to_mA(charger->adc.vchmax_res));
170342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	seq_printf(s, "vchmin_res = %d (%dmV)\n",
171342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		   charger->adc.vchmin_res,
172342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		   da9030_reg_to_mV(charger->adc.vchmin_res));
173342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
174342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	return 0;
175342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport}
176342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
177342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoportstatic int debug_open(struct inode *inode, struct file *file)
178342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport{
179342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	return single_open(file, bat_debug_show, inode->i_private);
180342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport}
181342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
182342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoportstatic const struct file_operations bat_debug_fops = {
183342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	.open		= debug_open,
184342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	.read		= seq_read,
185342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	.llseek		= seq_lseek,
186342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	.release	= single_release,
187342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport};
188342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
189342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoportstatic struct dentry *da9030_bat_create_debugfs(struct da9030_charger *charger)
190342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport{
191c084e092e47ca2435673702c6cf6e87a731ecc6fAnton Vorontsov	charger->debug_file = debugfs_create_file("charger", 0666, NULL,
192c084e092e47ca2435673702c6cf6e87a731ecc6fAnton Vorontsov						  charger, &bat_debug_fops);
193342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	return charger->debug_file;
194342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport}
195342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
196342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoportstatic void da9030_bat_remove_debugfs(struct da9030_charger *charger)
197342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport{
198342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	debugfs_remove(charger->debug_file);
199342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport}
200342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#else
201342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoportstatic inline struct dentry *da9030_bat_create_debugfs(struct da9030_charger *charger)
202342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport{
203342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	return NULL;
204342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport}
205342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoportstatic inline void da9030_bat_remove_debugfs(struct da9030_charger *charger)
206342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport{
207342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport}
208342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport#endif
209342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
210342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoportstatic inline void da9030_read_adc(struct da9030_charger *charger,
211342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport				   struct da9030_adc_res *adc)
212342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport{
213342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	da903x_reads(charger->master, DA9030_VBAT_RES,
214342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		     sizeof(*adc), (uint8_t *)adc);
215342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport}
216342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
217342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoportstatic void da9030_charger_update_state(struct da9030_charger *charger)
218342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport{
219342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	uint8_t val;
220342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
221342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	da903x_read(charger->master, DA9030_CHARGE_CONTROL, &val);
222342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	charger->is_on = (val & DA9030_CHRG_CHARGER_ENABLE) ? 1 : 0;
223342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	charger->mA = ((val >> 3) & 0xf) * 100;
224342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	charger->mV = (val & 0x7) * 50 + 4000;
225342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
226342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	da9030_read_adc(charger, &charger->adc);
227342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	da903x_read(charger->master, DA9030_FAULT_LOG, &charger->fault);
228342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	charger->chdet = da903x_query_status(charger->master,
229342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport						     DA9030_STATUS_CHDET);
230342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport}
231342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
232342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoportstatic void da9030_set_charge(struct da9030_charger *charger, int on)
233342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport{
234342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	uint8_t val;
235342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
236342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	if (on) {
237342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		val = DA9030_CHRG_CHARGER_ENABLE;
238342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		val |= (charger->charge_milliamp / 100) << 3;
239342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		val |= (charger->charge_millivolt - 4000) / 50;
240342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		charger->is_on = 1;
241342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	} else {
242342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		val = 0;
243342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		charger->is_on = 0;
244342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	}
245342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
246342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	da903x_write(charger->master, DA9030_CHARGE_CONTROL, val);
247a35d01a5d2ac533edab94a8e3b6749ab213c91c5Mike Rapoport
248a35d01a5d2ac533edab94a8e3b6749ab213c91c5Mike Rapoport	power_supply_changed(&charger->psy);
249342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport}
250342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
251342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoportstatic void da9030_charger_check_state(struct da9030_charger *charger)
252342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport{
253342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	da9030_charger_update_state(charger);
254342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
255342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	/* we wake or boot with external power on */
256342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	if (!charger->is_on) {
257342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		if ((charger->chdet) &&
258342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		    (charger->adc.vbat_res <
259342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		     charger->thresholds.vbat_charge_start)) {
260342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport			da9030_set_charge(charger, 1);
261342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		}
262342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	} else {
263a35d01a5d2ac533edab94a8e3b6749ab213c91c5Mike Rapoport		/* Charger has been pulled out */
264a35d01a5d2ac533edab94a8e3b6749ab213c91c5Mike Rapoport		if (!charger->chdet) {
265a35d01a5d2ac533edab94a8e3b6749ab213c91c5Mike Rapoport			da9030_set_charge(charger, 0);
266a35d01a5d2ac533edab94a8e3b6749ab213c91c5Mike Rapoport			return;
267a35d01a5d2ac533edab94a8e3b6749ab213c91c5Mike Rapoport		}
268a35d01a5d2ac533edab94a8e3b6749ab213c91c5Mike Rapoport
269342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		if (charger->adc.vbat_res >=
270342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		    charger->thresholds.vbat_charge_stop) {
271342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport			da9030_set_charge(charger, 0);
272342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport			da903x_write(charger->master, DA9030_VBATMON,
273342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport				       charger->thresholds.vbat_charge_restart);
274342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		} else if (charger->adc.vbat_res >
275342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport			   charger->thresholds.vbat_low) {
276342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport			/* we are charging and passed LOW_THRESH,
277342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport			   so upate DA9030 VBAT threshold
278342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport			 */
279342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport			da903x_write(charger->master, DA9030_VBATMON,
280342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport				     charger->thresholds.vbat_low);
281342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		}
282342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		if (charger->adc.vchmax_res > charger->thresholds.vcharge_max ||
283342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		    charger->adc.vchmin_res < charger->thresholds.vcharge_min ||
284342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		    /* Tempreture readings are negative */
285342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		    charger->adc.tbat_res < charger->thresholds.tbat_high ||
286342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		    charger->adc.tbat_res > charger->thresholds.tbat_low) {
287342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport			/* disable charger */
288342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport			da9030_set_charge(charger, 0);
289342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		}
290342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	}
291342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport}
292342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
293342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoportstatic void da9030_charging_monitor(struct work_struct *work)
294342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport{
295342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	struct da9030_charger *charger;
296342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
297342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	charger = container_of(work, struct da9030_charger, work.work);
298342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
299342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	da9030_charger_check_state(charger);
300342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
301342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	/* reschedule for the next time */
302342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	schedule_delayed_work(&charger->work, charger->interval);
303342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport}
304342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
305342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoportstatic enum power_supply_property da9030_battery_props[] = {
306342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	POWER_SUPPLY_PROP_MODEL_NAME,
307342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	POWER_SUPPLY_PROP_STATUS,
308342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	POWER_SUPPLY_PROP_HEALTH,
309342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	POWER_SUPPLY_PROP_TECHNOLOGY,
310342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
311342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
312342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	POWER_SUPPLY_PROP_VOLTAGE_NOW,
313342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	POWER_SUPPLY_PROP_CURRENT_AVG,
314342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport};
315342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
316342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoportstatic void da9030_battery_check_status(struct da9030_charger *charger,
317342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport				    union power_supply_propval *val)
318342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport{
319342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	if (charger->chdet) {
320342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		if (charger->is_on)
321342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport			val->intval = POWER_SUPPLY_STATUS_CHARGING;
322342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		else
323342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
324342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	} else {
325342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
326342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	}
327342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport}
328342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
329342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoportstatic void da9030_battery_check_health(struct da9030_charger *charger,
330342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport				    union power_supply_propval *val)
331342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport{
332342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	if (charger->fault & DA9030_FAULT_LOG_OVER_TEMP)
333342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
334342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	else if (charger->fault & DA9030_FAULT_LOG_VBAT_OVER)
335342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
336342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	else
337342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		val->intval = POWER_SUPPLY_HEALTH_GOOD;
338342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport}
339342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
340342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoportstatic int da9030_battery_get_property(struct power_supply *psy,
341342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport				   enum power_supply_property psp,
342342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport				   union power_supply_propval *val)
343342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport{
344342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	struct da9030_charger *charger;
345342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	charger = container_of(psy, struct da9030_charger, psy);
346342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
347342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	switch (psp) {
348342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	case POWER_SUPPLY_PROP_STATUS:
349342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		da9030_battery_check_status(charger, val);
350342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		break;
351342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	case POWER_SUPPLY_PROP_HEALTH:
352342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		da9030_battery_check_health(charger, val);
353342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		break;
354342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	case POWER_SUPPLY_PROP_TECHNOLOGY:
355342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		val->intval = charger->battery_info->technology;
356342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		break;
357342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
358342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		val->intval = charger->battery_info->voltage_max_design;
359342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		break;
360342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
361342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		val->intval = charger->battery_info->voltage_min_design;
362342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		break;
363342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
364342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		val->intval = da9030_reg_to_mV(charger->adc.vbat_res) * 1000;
365342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		break;
366342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	case POWER_SUPPLY_PROP_CURRENT_AVG:
367342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		val->intval =
368342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport			da9030_reg_to_mA(charger->adc.ichaverage_res) * 1000;
369342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		break;
370342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	case POWER_SUPPLY_PROP_MODEL_NAME:
371342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		val->strval = charger->battery_info->name;
372342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		break;
373342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	default:
374342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		break;
375342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	}
376342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
377342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	return 0;
378342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport}
379342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
380342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoportstatic void da9030_battery_vbat_event(struct da9030_charger *charger)
381342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport{
382342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	da9030_read_adc(charger, &charger->adc);
383342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
384342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	if (charger->is_on)
385342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		return;
386342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
387342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	if (charger->adc.vbat_res < charger->thresholds.vbat_low) {
388342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		/* set VBAT threshold for critical */
389342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		da903x_write(charger->master, DA9030_VBATMON,
390342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport			     charger->thresholds.vbat_crit);
391342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		if (charger->battery_low)
392342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport			charger->battery_low();
393342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	} else if (charger->adc.vbat_res <
394342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		   charger->thresholds.vbat_crit) {
395342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		/* notify the system of battery critical */
396342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		if (charger->battery_critical)
397342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport			charger->battery_critical();
398342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	}
399342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport}
400342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
401342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoportstatic int da9030_battery_event(struct notifier_block *nb, unsigned long event,
402342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport				void *data)
403342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport{
404342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	struct da9030_charger *charger =
405342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		container_of(nb, struct da9030_charger, nb);
406342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
407342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	switch (event) {
408342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	case DA9030_EVENT_CHDET:
409a35d01a5d2ac533edab94a8e3b6749ab213c91c5Mike Rapoport		cancel_delayed_work_sync(&charger->work);
410a35d01a5d2ac533edab94a8e3b6749ab213c91c5Mike Rapoport		schedule_work(&charger->work.work);
411342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		break;
412342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	case DA9030_EVENT_VBATMON:
413342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		da9030_battery_vbat_event(charger);
414342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		break;
415342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	case DA9030_EVENT_CHIOVER:
416342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	case DA9030_EVENT_TBAT:
417342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		da9030_set_charge(charger, 0);
418342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		break;
419342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	}
420342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
421342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	return 0;
422342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport}
423342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
424342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoportstatic void da9030_battery_convert_thresholds(struct da9030_charger *charger,
425342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport					      struct da9030_battery_info *pdata)
426342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport{
427342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	charger->thresholds.tbat_low = pdata->tbat_low;
428342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	charger->thresholds.tbat_high = pdata->tbat_high;
429342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	charger->thresholds.tbat_restart  = pdata->tbat_restart;
430342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
431342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	charger->thresholds.vbat_low =
432342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		da9030_millivolt_to_reg(pdata->vbat_low);
433342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	charger->thresholds.vbat_crit =
434342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		da9030_millivolt_to_reg(pdata->vbat_crit);
435342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	charger->thresholds.vbat_charge_start =
436342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		da9030_millivolt_to_reg(pdata->vbat_charge_start);
437342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	charger->thresholds.vbat_charge_stop =
438342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		da9030_millivolt_to_reg(pdata->vbat_charge_stop);
439342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	charger->thresholds.vbat_charge_restart =
440342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		da9030_millivolt_to_reg(pdata->vbat_charge_restart);
441342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
442342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	charger->thresholds.vcharge_min =
443342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		da9030_millivolt_to_reg(pdata->vcharge_min);
444342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	charger->thresholds.vcharge_max =
445342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		da9030_millivolt_to_reg(pdata->vcharge_max);
446342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport}
447342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
448342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoportstatic void da9030_battery_setup_psy(struct da9030_charger *charger)
449342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport{
450342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	struct power_supply *psy = &charger->psy;
451342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	struct power_supply_info *info = charger->battery_info;
452342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
453342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	psy->name = info->name;
454342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	psy->use_for_apm = info->use_for_apm;
455342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	psy->type = POWER_SUPPLY_TYPE_BATTERY;
456342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	psy->get_property = da9030_battery_get_property;
457342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
458342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	psy->properties = da9030_battery_props;
459342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	psy->num_properties = ARRAY_SIZE(da9030_battery_props);
460342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport};
461342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
462342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoportstatic int da9030_battery_charger_init(struct da9030_charger *charger)
463342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport{
464342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	char v[5];
465342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	int ret;
466342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
467342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	v[0] = v[1] = charger->thresholds.vbat_low;
468342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	v[2] = charger->thresholds.tbat_high;
469342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	v[3] = charger->thresholds.tbat_restart;
470342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	v[4] = charger->thresholds.tbat_low;
471342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
472342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	ret = da903x_writes(charger->master, DA9030_VBATMON, 5, v);
473342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	if (ret)
474342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		return ret;
475342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
476342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	/*
477342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	 * Enable reference voltage supply for ADC from the LDO_INTERNAL
478342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	 * regulator. Must be set before ADC measurements can be made.
479342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	 */
480342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	ret = da903x_write(charger->master, DA9030_ADC_MAN_CONTROL,
481342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport			   DA9030_ADC_LDO_INT_ENABLE |
482342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport			   DA9030_ADC_TBATREF_ENABLE);
483342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	if (ret)
484342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		return ret;
485342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
486342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	/* enable auto ADC measuremnts */
487342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	return da903x_write(charger->master, DA9030_ADC_AUTO_CONTROL,
488342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport			    DA9030_ADC_TBAT_ENABLE | DA9030_ADC_VBAT_IN_TXON |
489342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport			    DA9030_ADC_VCH_ENABLE | DA9030_ADC_ICH_ENABLE |
490342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport			    DA9030_ADC_VBAT_ENABLE |
491342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport			    DA9030_ADC_AUTO_SLEEP_ENABLE);
492342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport}
493342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
494342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoportstatic int da9030_battery_probe(struct platform_device *pdev)
495342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport{
496342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	struct da9030_charger *charger;
497342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	struct da9030_battery_info *pdata = pdev->dev.platform_data;
498342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	int ret;
499342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
500342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	if (pdata == NULL)
501342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		return -EINVAL;
502342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
503342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	if (pdata->charge_milliamp >= 1500 ||
504342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	    pdata->charge_millivolt < 4000 ||
505342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	    pdata->charge_millivolt > 4350)
506342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		return -EINVAL;
507342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
508bc67ea8e92d45d1237e289fd1c1ec004a8383cccJingoo Han	charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL);
509342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	if (charger == NULL)
510342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		return -ENOMEM;
511342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
512342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	charger->master = pdev->dev.parent;
513342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
5145324dc0e3872324ed0bf372bce7bc437436910b6Stefan Weil	/* 10 seconds between monitor runs unless platform defines other
515342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	   interval */
516342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	charger->interval = msecs_to_jiffies(
517342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		(pdata->batmon_interval ? : 10) * 1000);
518342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
519342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	charger->charge_milliamp = pdata->charge_milliamp;
520342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	charger->charge_millivolt = pdata->charge_millivolt;
521342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	charger->battery_info = pdata->battery_info;
522342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	charger->battery_low = pdata->battery_low;
523342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	charger->battery_critical = pdata->battery_critical;
524342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
525342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	da9030_battery_convert_thresholds(charger, pdata);
526342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
527342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	ret = da9030_battery_charger_init(charger);
528342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	if (ret)
529342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		goto err_charger_init;
530342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
531342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	INIT_DELAYED_WORK(&charger->work, da9030_charging_monitor);
532342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	schedule_delayed_work(&charger->work, charger->interval);
533342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
534342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	charger->nb.notifier_call = da9030_battery_event;
535342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	ret = da903x_register_notifier(charger->master, &charger->nb,
536342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport				       DA9030_EVENT_CHDET |
537342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport				       DA9030_EVENT_VBATMON |
538342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport				       DA9030_EVENT_CHIOVER |
539342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport				       DA9030_EVENT_TBAT);
540342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	if (ret)
541342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		goto err_notifier;
542342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
543342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	da9030_battery_setup_psy(charger);
544342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	ret = power_supply_register(&pdev->dev, &charger->psy);
545342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	if (ret)
546342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		goto err_ps_register;
547342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
548342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	charger->debug_file = da9030_bat_create_debugfs(charger);
549342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	platform_set_drvdata(pdev, charger);
550342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	return 0;
551342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
552342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoporterr_ps_register:
553342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	da903x_unregister_notifier(charger->master, &charger->nb,
554342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport				   DA9030_EVENT_CHDET | DA9030_EVENT_VBATMON |
555342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport				   DA9030_EVENT_CHIOVER | DA9030_EVENT_TBAT);
556342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoporterr_notifier:
557342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	cancel_delayed_work(&charger->work);
558342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
559342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoporterr_charger_init:
560342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	return ret;
561342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport}
562342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
563342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoportstatic int da9030_battery_remove(struct platform_device *dev)
564342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport{
565342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	struct da9030_charger *charger = platform_get_drvdata(dev);
566342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
567342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	da9030_bat_remove_debugfs(charger);
568342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
569342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	da903x_unregister_notifier(charger->master, &charger->nb,
570342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport				   DA9030_EVENT_CHDET | DA9030_EVENT_VBATMON |
571342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport				   DA9030_EVENT_CHIOVER | DA9030_EVENT_TBAT);
572a35d01a5d2ac533edab94a8e3b6749ab213c91c5Mike Rapoport	cancel_delayed_work_sync(&charger->work);
573a35d01a5d2ac533edab94a8e3b6749ab213c91c5Mike Rapoport	da9030_set_charge(charger, 0);
574342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	power_supply_unregister(&charger->psy);
575342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
576342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	return 0;
577342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport}
578342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
579342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoportstatic struct platform_driver da903x_battery_driver = {
580342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	.driver	= {
581342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		.name	= "da903x-battery",
582342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport		.owner	= THIS_MODULE,
583342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	},
584342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	.probe = da9030_battery_probe,
585342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport	.remove = da9030_battery_remove,
586342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport};
587342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
588300bac7fb85a20b2704dc3645419057992f78565Axel Linmodule_platform_driver(da903x_battery_driver);
589342d765e011f9cbe4292119a9164f76ccf0b922aMike Rapoport
590342d765e011f9cbe4292119a9164f76ccf0b922aMike RapoportMODULE_DESCRIPTION("DA9030 battery charger driver");
591342d765e011f9cbe4292119a9164f76ccf0b922aMike RapoportMODULE_AUTHOR("Mike Rapoport, CompuLab");
592342d765e011f9cbe4292119a9164f76ccf0b922aMike RapoportMODULE_LICENSE("GPL");
593