xref: /openbmc/linux/drivers/power/supply/adp5061.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
1fda8d26eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2fe8e81b7SStefan Popa /*
3fe8e81b7SStefan Popa  * ADP5061 I2C Programmable Linear Battery Charger
4fe8e81b7SStefan Popa  *
5fe8e81b7SStefan Popa  * Copyright 2018 Analog Devices Inc.
6fe8e81b7SStefan Popa  */
7fe8e81b7SStefan Popa 
8fe8e81b7SStefan Popa #include <linux/init.h>
9fe8e81b7SStefan Popa #include <linux/module.h>
10fe8e81b7SStefan Popa #include <linux/slab.h>
11fe8e81b7SStefan Popa #include <linux/i2c.h>
12fe8e81b7SStefan Popa #include <linux/delay.h>
13fe8e81b7SStefan Popa #include <linux/pm.h>
14fe8e81b7SStefan Popa #include <linux/mod_devicetable.h>
15fe8e81b7SStefan Popa #include <linux/power_supply.h>
16fe8e81b7SStefan Popa #include <linux/platform_device.h>
17fe8e81b7SStefan Popa #include <linux/of.h>
18fe8e81b7SStefan Popa #include <linux/regmap.h>
19fe8e81b7SStefan Popa 
20fe8e81b7SStefan Popa /* ADP5061 registers definition */
21fe8e81b7SStefan Popa #define ADP5061_ID			0x00
22fe8e81b7SStefan Popa #define ADP5061_REV			0x01
23fe8e81b7SStefan Popa #define ADP5061_VINX_SET		0x02
24fe8e81b7SStefan Popa #define ADP5061_TERM_SET		0x03
25fe8e81b7SStefan Popa #define ADP5061_CHG_CURR		0x04
26fe8e81b7SStefan Popa #define ADP5061_VOLTAGE_TH		0x05
27fe8e81b7SStefan Popa #define ADP5061_TIMER_SET		0x06
28fe8e81b7SStefan Popa #define ADP5061_FUNC_SET_1		0x07
29fe8e81b7SStefan Popa #define ADP5061_FUNC_SET_2		0x08
30fe8e81b7SStefan Popa #define ADP5061_INT_EN			0x09
31fe8e81b7SStefan Popa #define ADP5061_INT_ACT			0x0A
32fe8e81b7SStefan Popa #define ADP5061_CHG_STATUS_1		0x0B
33fe8e81b7SStefan Popa #define ADP5061_CHG_STATUS_2		0x0C
34fe8e81b7SStefan Popa #define ADP5061_FAULT			0x0D
35fe8e81b7SStefan Popa #define ADP5061_BATTERY_SHORT		0x10
36fe8e81b7SStefan Popa #define ADP5061_IEND			0x11
37fe8e81b7SStefan Popa 
38fe8e81b7SStefan Popa /* ADP5061_VINX_SET */
39fe8e81b7SStefan Popa #define ADP5061_VINX_SET_ILIM_MSK		GENMASK(3, 0)
40fe8e81b7SStefan Popa #define ADP5061_VINX_SET_ILIM_MODE(x)		(((x) & 0x0F) << 0)
41fe8e81b7SStefan Popa 
42fe8e81b7SStefan Popa /* ADP5061_TERM_SET */
43fe8e81b7SStefan Popa #define ADP5061_TERM_SET_VTRM_MSK		GENMASK(7, 2)
44fe8e81b7SStefan Popa #define ADP5061_TERM_SET_VTRM_MODE(x)		(((x) & 0x3F) << 2)
45fe8e81b7SStefan Popa #define ADP5061_TERM_SET_CHG_VLIM_MSK		GENMASK(1, 0)
46fe8e81b7SStefan Popa #define ADP5061_TERM_SET_CHG_VLIM_MODE(x)	(((x) & 0x03) << 0)
47fe8e81b7SStefan Popa 
48fe8e81b7SStefan Popa /* ADP5061_CHG_CURR */
49fe8e81b7SStefan Popa #define ADP5061_CHG_CURR_ICHG_MSK		GENMASK(6, 2)
50fe8e81b7SStefan Popa #define ADP5061_CHG_CURR_ICHG_MODE(x)		(((x) & 0x1F) << 2)
51fe8e81b7SStefan Popa #define ADP5061_CHG_CURR_ITRK_DEAD_MSK		GENMASK(1, 0)
52fe8e81b7SStefan Popa #define ADP5061_CHG_CURR_ITRK_DEAD_MODE(x)	(((x) & 0x03) << 0)
53fe8e81b7SStefan Popa 
54fe8e81b7SStefan Popa /* ADP5061_VOLTAGE_TH */
55fe8e81b7SStefan Popa #define ADP5061_VOLTAGE_TH_DIS_RCH_MSK		BIT(7)
56fe8e81b7SStefan Popa #define ADP5061_VOLTAGE_TH_DIS_RCH_MODE(x)	(((x) & 0x01) << 7)
57fe8e81b7SStefan Popa #define ADP5061_VOLTAGE_TH_VRCH_MSK		GENMASK(6, 5)
58fe8e81b7SStefan Popa #define ADP5061_VOLTAGE_TH_VRCH_MODE(x)		(((x) & 0x03) << 5)
59fe8e81b7SStefan Popa #define ADP5061_VOLTAGE_TH_VTRK_DEAD_MSK	GENMASK(4, 3)
60fe8e81b7SStefan Popa #define ADP5061_VOLTAGE_TH_VTRK_DEAD_MODE(x)	(((x) & 0x03) << 3)
61fe8e81b7SStefan Popa #define ADP5061_VOLTAGE_TH_VWEAK_MSK		GENMASK(2, 0)
62fe8e81b7SStefan Popa #define ADP5061_VOLTAGE_TH_VWEAK_MODE(x)	(((x) & 0x07) << 0)
63fe8e81b7SStefan Popa 
64fe8e81b7SStefan Popa /* ADP5061_CHG_STATUS_1 */
65fe8e81b7SStefan Popa #define ADP5061_CHG_STATUS_1_VIN_OV(x)		(((x) >> 7) & 0x1)
66fe8e81b7SStefan Popa #define ADP5061_CHG_STATUS_1_VIN_OK(x)		(((x) >> 6) & 0x1)
67fe8e81b7SStefan Popa #define ADP5061_CHG_STATUS_1_VIN_ILIM(x)	(((x) >> 5) & 0x1)
68fe8e81b7SStefan Popa #define ADP5061_CHG_STATUS_1_THERM_LIM(x)	(((x) >> 4) & 0x1)
69fe8e81b7SStefan Popa #define ADP5061_CHG_STATUS_1_CHDONE(x)		(((x) >> 3) & 0x1)
70fe8e81b7SStefan Popa #define ADP5061_CHG_STATUS_1_CHG_STATUS(x)	(((x) >> 0) & 0x7)
71fe8e81b7SStefan Popa 
72fe8e81b7SStefan Popa /* ADP5061_CHG_STATUS_2 */
73fe8e81b7SStefan Popa #define ADP5061_CHG_STATUS_2_THR_STATUS(x)	(((x) >> 5) & 0x7)
74fe8e81b7SStefan Popa #define ADP5061_CHG_STATUS_2_RCH_LIM_INFO(x)	(((x) >> 3) & 0x1)
75fe8e81b7SStefan Popa #define ADP5061_CHG_STATUS_2_BAT_STATUS(x)	(((x) >> 0) & 0x7)
76fe8e81b7SStefan Popa 
77fe8e81b7SStefan Popa /* ADP5061_IEND */
78fe8e81b7SStefan Popa #define ADP5061_IEND_IEND_MSK			GENMASK(7, 5)
79fe8e81b7SStefan Popa #define ADP5061_IEND_IEND_MODE(x)		(((x) & 0x07) << 5)
80fe8e81b7SStefan Popa 
81fe8e81b7SStefan Popa #define ADP5061_NO_BATTERY	0x01
82fe8e81b7SStefan Popa #define ADP5061_ICHG_MAX	1300 // mA
83fe8e81b7SStefan Popa 
84fe8e81b7SStefan Popa enum adp5061_chg_status {
85fe8e81b7SStefan Popa 	ADP5061_CHG_OFF,
86fe8e81b7SStefan Popa 	ADP5061_CHG_TRICKLE,
87fe8e81b7SStefan Popa 	ADP5061_CHG_FAST_CC,
88fe8e81b7SStefan Popa 	ADP5061_CHG_FAST_CV,
89fe8e81b7SStefan Popa 	ADP5061_CHG_COMPLETE,
90fe8e81b7SStefan Popa 	ADP5061_CHG_LDO_MODE,
91fe8e81b7SStefan Popa 	ADP5061_CHG_TIMER_EXP,
92fe8e81b7SStefan Popa 	ADP5061_CHG_BAT_DET,
93fe8e81b7SStefan Popa };
94fe8e81b7SStefan Popa 
95fe8e81b7SStefan Popa static const int adp5061_chg_type[4] = {
96fe8e81b7SStefan Popa 	[ADP5061_CHG_OFF] = POWER_SUPPLY_CHARGE_TYPE_NONE,
97fe8e81b7SStefan Popa 	[ADP5061_CHG_TRICKLE] = POWER_SUPPLY_CHARGE_TYPE_TRICKLE,
98fe8e81b7SStefan Popa 	[ADP5061_CHG_FAST_CC] = POWER_SUPPLY_CHARGE_TYPE_FAST,
99fe8e81b7SStefan Popa 	[ADP5061_CHG_FAST_CV] = POWER_SUPPLY_CHARGE_TYPE_FAST,
100fe8e81b7SStefan Popa };
101fe8e81b7SStefan Popa 
102fe8e81b7SStefan Popa static const int adp5061_vweak_th[8] = {
103fe8e81b7SStefan Popa 	2700, 2800, 2900, 3000, 3100, 3200, 3300, 3400,
104fe8e81b7SStefan Popa };
105fe8e81b7SStefan Popa 
106fe8e81b7SStefan Popa static const int adp5061_prechg_current[4] = {
107fe8e81b7SStefan Popa 	5, 10, 20, 80,
108fe8e81b7SStefan Popa };
109fe8e81b7SStefan Popa 
110fe8e81b7SStefan Popa static const int adp5061_vmin[4] = {
111fe8e81b7SStefan Popa 	2000, 2500, 2600, 2900,
112fe8e81b7SStefan Popa };
113fe8e81b7SStefan Popa 
114fe8e81b7SStefan Popa static const int adp5061_const_chg_vmax[4] = {
115fe8e81b7SStefan Popa 	3200, 3400, 3700, 3800,
116fe8e81b7SStefan Popa };
117fe8e81b7SStefan Popa 
118fe8e81b7SStefan Popa static const int adp5061_const_ichg[24] = {
119fe8e81b7SStefan Popa 	50, 100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 650,
120fe8e81b7SStefan Popa 	700, 750, 800, 850, 900, 950, 1000, 1050, 1100, 1200, 1300,
121fe8e81b7SStefan Popa };
122fe8e81b7SStefan Popa 
123fe8e81b7SStefan Popa static const int adp5061_vmax[36] = {
124fe8e81b7SStefan Popa 	3800, 3820, 3840, 3860, 3880, 3900, 3920, 3940, 3960, 3980,
125fe8e81b7SStefan Popa 	4000, 4020, 4040, 4060, 4080, 4100, 4120, 4140, 4160, 4180,
126fe8e81b7SStefan Popa 	4200, 4220, 4240, 4260, 4280, 4300, 4320, 4340, 4360, 4380,
127fe8e81b7SStefan Popa 	4400, 4420, 4440, 4460, 4480, 4500,
128fe8e81b7SStefan Popa };
129fe8e81b7SStefan Popa 
130fe8e81b7SStefan Popa static const int adp5061_in_current_lim[16] = {
131fe8e81b7SStefan Popa 	100, 150, 200, 250, 300, 400, 500, 600, 700,
132fe8e81b7SStefan Popa 	800, 900, 1000, 1200, 1500, 1800, 2100,
133fe8e81b7SStefan Popa };
134fe8e81b7SStefan Popa 
135fe8e81b7SStefan Popa static const int adp5061_iend[8] = {
136fe8e81b7SStefan Popa 	12500, 32500, 52500, 72500, 92500, 117500, 142500, 170000,
137fe8e81b7SStefan Popa };
138fe8e81b7SStefan Popa 
139fe8e81b7SStefan Popa struct adp5061_state {
140fe8e81b7SStefan Popa 	struct i2c_client		*client;
141fe8e81b7SStefan Popa 	struct regmap			*regmap;
142fe8e81b7SStefan Popa 	struct power_supply		*psy;
143fe8e81b7SStefan Popa };
144fe8e81b7SStefan Popa 
adp5061_get_array_index(const int * array,u8 size,int val)145fe8e81b7SStefan Popa static int adp5061_get_array_index(const int *array, u8 size, int val)
146fe8e81b7SStefan Popa {
147fe8e81b7SStefan Popa 	int i;
148fe8e81b7SStefan Popa 
149fe8e81b7SStefan Popa 	for (i = 1; i < size; i++) {
150fe8e81b7SStefan Popa 		if (val < array[i])
151fe8e81b7SStefan Popa 			break;
152fe8e81b7SStefan Popa 	}
153fe8e81b7SStefan Popa 
154fe8e81b7SStefan Popa 	return i-1;
155fe8e81b7SStefan Popa }
156fe8e81b7SStefan Popa 
adp5061_get_status(struct adp5061_state * st,u8 * status1,u8 * status2)157fe8e81b7SStefan Popa static int adp5061_get_status(struct adp5061_state *st,
158fe8e81b7SStefan Popa 			      u8 *status1, u8 *status2)
159fe8e81b7SStefan Popa {
160fe8e81b7SStefan Popa 	u8 buf[2];
161fe8e81b7SStefan Popa 	int ret;
162fe8e81b7SStefan Popa 
163fe8e81b7SStefan Popa 	/* CHG_STATUS1 and CHG_STATUS2 are adjacent regs */
164fe8e81b7SStefan Popa 	ret = regmap_bulk_read(st->regmap, ADP5061_CHG_STATUS_1,
165fe8e81b7SStefan Popa 			       &buf[0], 2);
166fe8e81b7SStefan Popa 	if (ret < 0)
167fe8e81b7SStefan Popa 		return ret;
168fe8e81b7SStefan Popa 
169fe8e81b7SStefan Popa 	*status1 = buf[0];
170fe8e81b7SStefan Popa 	*status2 = buf[1];
171fe8e81b7SStefan Popa 
172fe8e81b7SStefan Popa 	return ret;
173fe8e81b7SStefan Popa }
174fe8e81b7SStefan Popa 
adp5061_get_input_current_limit(struct adp5061_state * st,union power_supply_propval * val)175fe8e81b7SStefan Popa static int adp5061_get_input_current_limit(struct adp5061_state *st,
176fe8e81b7SStefan Popa 		union power_supply_propval *val)
177fe8e81b7SStefan Popa {
178fe8e81b7SStefan Popa 	unsigned int regval;
179fe8e81b7SStefan Popa 	int mode, ret;
180fe8e81b7SStefan Popa 
181fe8e81b7SStefan Popa 	ret = regmap_read(st->regmap, ADP5061_VINX_SET, &regval);
182fe8e81b7SStefan Popa 	if (ret < 0)
183fe8e81b7SStefan Popa 		return ret;
184fe8e81b7SStefan Popa 
185fe8e81b7SStefan Popa 	mode = ADP5061_VINX_SET_ILIM_MODE(regval);
186fe8e81b7SStefan Popa 	val->intval = adp5061_in_current_lim[mode] * 1000;
187fe8e81b7SStefan Popa 
188fe8e81b7SStefan Popa 	return ret;
189fe8e81b7SStefan Popa }
190fe8e81b7SStefan Popa 
adp5061_set_input_current_limit(struct adp5061_state * st,int val)191fe8e81b7SStefan Popa static int adp5061_set_input_current_limit(struct adp5061_state *st, int val)
192fe8e81b7SStefan Popa {
193fe8e81b7SStefan Popa 	int index;
194fe8e81b7SStefan Popa 
195fe8e81b7SStefan Popa 	/* Convert from uA to mA */
196fe8e81b7SStefan Popa 	val /= 1000;
197fe8e81b7SStefan Popa 	index = adp5061_get_array_index(adp5061_in_current_lim,
198fe8e81b7SStefan Popa 					ARRAY_SIZE(adp5061_in_current_lim),
199fe8e81b7SStefan Popa 					val);
200fe8e81b7SStefan Popa 	if (index < 0)
201fe8e81b7SStefan Popa 		return index;
202fe8e81b7SStefan Popa 
203fe8e81b7SStefan Popa 	return regmap_update_bits(st->regmap, ADP5061_VINX_SET,
204fe8e81b7SStefan Popa 				  ADP5061_VINX_SET_ILIM_MSK,
205fe8e81b7SStefan Popa 				  ADP5061_VINX_SET_ILIM_MODE(index));
206fe8e81b7SStefan Popa }
207fe8e81b7SStefan Popa 
adp5061_set_min_voltage(struct adp5061_state * st,int val)208fe8e81b7SStefan Popa static int adp5061_set_min_voltage(struct adp5061_state *st, int val)
209fe8e81b7SStefan Popa {
210fe8e81b7SStefan Popa 	int index;
211fe8e81b7SStefan Popa 
212fe8e81b7SStefan Popa 	/* Convert from uV to mV */
213fe8e81b7SStefan Popa 	val /= 1000;
214fe8e81b7SStefan Popa 	index = adp5061_get_array_index(adp5061_vmin,
215fe8e81b7SStefan Popa 					ARRAY_SIZE(adp5061_vmin),
216fe8e81b7SStefan Popa 					val);
217fe8e81b7SStefan Popa 	if (index < 0)
218fe8e81b7SStefan Popa 		return index;
219fe8e81b7SStefan Popa 
220fe8e81b7SStefan Popa 	return regmap_update_bits(st->regmap, ADP5061_VOLTAGE_TH,
221fe8e81b7SStefan Popa 				  ADP5061_VOLTAGE_TH_VTRK_DEAD_MSK,
222fe8e81b7SStefan Popa 				  ADP5061_VOLTAGE_TH_VTRK_DEAD_MODE(index));
223fe8e81b7SStefan Popa }
224fe8e81b7SStefan Popa 
adp5061_get_min_voltage(struct adp5061_state * st,union power_supply_propval * val)225fe8e81b7SStefan Popa static int adp5061_get_min_voltage(struct adp5061_state *st,
226fe8e81b7SStefan Popa 				   union power_supply_propval *val)
227fe8e81b7SStefan Popa {
228fe8e81b7SStefan Popa 	unsigned int regval;
229fe8e81b7SStefan Popa 	int ret;
230fe8e81b7SStefan Popa 
231fe8e81b7SStefan Popa 	ret = regmap_read(st->regmap, ADP5061_VOLTAGE_TH, &regval);
232fe8e81b7SStefan Popa 	if (ret < 0)
233fe8e81b7SStefan Popa 		return ret;
234fe8e81b7SStefan Popa 
235fe8e81b7SStefan Popa 	regval = ((regval & ADP5061_VOLTAGE_TH_VTRK_DEAD_MSK) >> 3);
236fe8e81b7SStefan Popa 	val->intval = adp5061_vmin[regval] * 1000;
237fe8e81b7SStefan Popa 
238fe8e81b7SStefan Popa 	return ret;
239fe8e81b7SStefan Popa }
240fe8e81b7SStefan Popa 
adp5061_get_chg_volt_lim(struct adp5061_state * st,union power_supply_propval * val)241fe8e81b7SStefan Popa static int adp5061_get_chg_volt_lim(struct adp5061_state *st,
242fe8e81b7SStefan Popa 				    union power_supply_propval *val)
243fe8e81b7SStefan Popa {
244fe8e81b7SStefan Popa 	unsigned int regval;
245fe8e81b7SStefan Popa 	int mode, ret;
246fe8e81b7SStefan Popa 
247fe8e81b7SStefan Popa 	ret = regmap_read(st->regmap, ADP5061_TERM_SET, &regval);
248fe8e81b7SStefan Popa 	if (ret < 0)
249fe8e81b7SStefan Popa 		return ret;
250fe8e81b7SStefan Popa 
251fe8e81b7SStefan Popa 	mode = ADP5061_TERM_SET_CHG_VLIM_MODE(regval);
252fe8e81b7SStefan Popa 	val->intval = adp5061_const_chg_vmax[mode] * 1000;
253fe8e81b7SStefan Popa 
254fe8e81b7SStefan Popa 	return ret;
255fe8e81b7SStefan Popa }
256fe8e81b7SStefan Popa 
adp5061_get_max_voltage(struct adp5061_state * st,union power_supply_propval * val)257fe8e81b7SStefan Popa static int adp5061_get_max_voltage(struct adp5061_state *st,
258fe8e81b7SStefan Popa 				   union power_supply_propval *val)
259fe8e81b7SStefan Popa {
260fe8e81b7SStefan Popa 	unsigned int regval;
261fe8e81b7SStefan Popa 	int ret;
262fe8e81b7SStefan Popa 
263fe8e81b7SStefan Popa 	ret = regmap_read(st->regmap, ADP5061_TERM_SET, &regval);
264fe8e81b7SStefan Popa 	if (ret < 0)
265fe8e81b7SStefan Popa 		return ret;
266fe8e81b7SStefan Popa 
267fe8e81b7SStefan Popa 	regval = ((regval & ADP5061_TERM_SET_VTRM_MSK) >> 2) - 0x0F;
26889b135baSDan Carpenter 	if (regval >= ARRAY_SIZE(adp5061_vmax))
26989b135baSDan Carpenter 		regval = ARRAY_SIZE(adp5061_vmax) - 1;
270fe8e81b7SStefan Popa 
271fe8e81b7SStefan Popa 	val->intval = adp5061_vmax[regval] * 1000;
272fe8e81b7SStefan Popa 
273fe8e81b7SStefan Popa 	return ret;
274fe8e81b7SStefan Popa }
275fe8e81b7SStefan Popa 
adp5061_set_max_voltage(struct adp5061_state * st,int val)276fe8e81b7SStefan Popa static int adp5061_set_max_voltage(struct adp5061_state *st, int val)
277fe8e81b7SStefan Popa {
278fe8e81b7SStefan Popa 	int vmax_index;
279fe8e81b7SStefan Popa 
280fe8e81b7SStefan Popa 	/* Convert from uV to mV */
281fe8e81b7SStefan Popa 	val /= 1000;
282fe8e81b7SStefan Popa 	if (val > 4500)
283fe8e81b7SStefan Popa 		val = 4500;
284fe8e81b7SStefan Popa 
285fe8e81b7SStefan Popa 	vmax_index = adp5061_get_array_index(adp5061_vmax,
286fe8e81b7SStefan Popa 					     ARRAY_SIZE(adp5061_vmax), val);
287fe8e81b7SStefan Popa 	if (vmax_index < 0)
288fe8e81b7SStefan Popa 		return vmax_index;
289fe8e81b7SStefan Popa 
290fe8e81b7SStefan Popa 	vmax_index += 0x0F;
291fe8e81b7SStefan Popa 
292fe8e81b7SStefan Popa 	return regmap_update_bits(st->regmap, ADP5061_TERM_SET,
293fe8e81b7SStefan Popa 				  ADP5061_TERM_SET_VTRM_MSK,
294fe8e81b7SStefan Popa 				  ADP5061_TERM_SET_VTRM_MODE(vmax_index));
295fe8e81b7SStefan Popa }
296fe8e81b7SStefan Popa 
adp5061_set_const_chg_vmax(struct adp5061_state * st,int val)297fe8e81b7SStefan Popa static int adp5061_set_const_chg_vmax(struct adp5061_state *st, int val)
298fe8e81b7SStefan Popa {
299fe8e81b7SStefan Popa 	int index;
300fe8e81b7SStefan Popa 
301fe8e81b7SStefan Popa 	/* Convert from uV to mV */
302fe8e81b7SStefan Popa 	val /= 1000;
303fe8e81b7SStefan Popa 	index = adp5061_get_array_index(adp5061_const_chg_vmax,
304fe8e81b7SStefan Popa 					ARRAY_SIZE(adp5061_const_chg_vmax),
305fe8e81b7SStefan Popa 					val);
306fe8e81b7SStefan Popa 	if (index < 0)
307fe8e81b7SStefan Popa 		return index;
308fe8e81b7SStefan Popa 
309fe8e81b7SStefan Popa 	return regmap_update_bits(st->regmap, ADP5061_TERM_SET,
310fe8e81b7SStefan Popa 				  ADP5061_TERM_SET_CHG_VLIM_MSK,
311fe8e81b7SStefan Popa 				  ADP5061_TERM_SET_CHG_VLIM_MODE(index));
312fe8e81b7SStefan Popa }
313fe8e81b7SStefan Popa 
adp5061_set_const_chg_current(struct adp5061_state * st,int val)314fe8e81b7SStefan Popa static int adp5061_set_const_chg_current(struct adp5061_state *st, int val)
315fe8e81b7SStefan Popa {
316fe8e81b7SStefan Popa 
317fe8e81b7SStefan Popa 	int index;
318fe8e81b7SStefan Popa 
319fe8e81b7SStefan Popa 	/* Convert from uA to mA */
320fe8e81b7SStefan Popa 	val /= 1000;
321fe8e81b7SStefan Popa 	if (val > ADP5061_ICHG_MAX)
322fe8e81b7SStefan Popa 		val = ADP5061_ICHG_MAX;
323fe8e81b7SStefan Popa 
324fe8e81b7SStefan Popa 	index = adp5061_get_array_index(adp5061_const_ichg,
325fe8e81b7SStefan Popa 					ARRAY_SIZE(adp5061_const_ichg),
326fe8e81b7SStefan Popa 					val);
327fe8e81b7SStefan Popa 	if (index < 0)
328fe8e81b7SStefan Popa 		return index;
329fe8e81b7SStefan Popa 
330fe8e81b7SStefan Popa 	return regmap_update_bits(st->regmap, ADP5061_CHG_CURR,
331fe8e81b7SStefan Popa 				  ADP5061_CHG_CURR_ICHG_MSK,
332fe8e81b7SStefan Popa 				  ADP5061_CHG_CURR_ICHG_MODE(index));
333fe8e81b7SStefan Popa }
334fe8e81b7SStefan Popa 
adp5061_get_const_chg_current(struct adp5061_state * st,union power_supply_propval * val)335fe8e81b7SStefan Popa static int adp5061_get_const_chg_current(struct adp5061_state *st,
336fe8e81b7SStefan Popa 		union power_supply_propval *val)
337fe8e81b7SStefan Popa {
338fe8e81b7SStefan Popa 	unsigned int regval;
339fe8e81b7SStefan Popa 	int ret;
340fe8e81b7SStefan Popa 
341fe8e81b7SStefan Popa 	ret = regmap_read(st->regmap, ADP5061_CHG_CURR, &regval);
342fe8e81b7SStefan Popa 	if (ret < 0)
343fe8e81b7SStefan Popa 		return ret;
344fe8e81b7SStefan Popa 
345fe8e81b7SStefan Popa 	regval = ((regval & ADP5061_CHG_CURR_ICHG_MSK) >> 2);
34689b135baSDan Carpenter 	if (regval >= ARRAY_SIZE(adp5061_const_ichg))
34789b135baSDan Carpenter 		regval = ARRAY_SIZE(adp5061_const_ichg) - 1;
348fe8e81b7SStefan Popa 
349fe8e81b7SStefan Popa 	val->intval = adp5061_const_ichg[regval] * 1000;
350fe8e81b7SStefan Popa 
351fe8e81b7SStefan Popa 	return ret;
352fe8e81b7SStefan Popa }
353fe8e81b7SStefan Popa 
adp5061_get_prechg_current(struct adp5061_state * st,union power_supply_propval * val)354fe8e81b7SStefan Popa static int adp5061_get_prechg_current(struct adp5061_state *st,
355fe8e81b7SStefan Popa 				      union power_supply_propval *val)
356fe8e81b7SStefan Popa {
357fe8e81b7SStefan Popa 	unsigned int regval;
358fe8e81b7SStefan Popa 	int ret;
359fe8e81b7SStefan Popa 
360fe8e81b7SStefan Popa 	ret = regmap_read(st->regmap, ADP5061_CHG_CURR, &regval);
361fe8e81b7SStefan Popa 	if (ret < 0)
362fe8e81b7SStefan Popa 		return ret;
363fe8e81b7SStefan Popa 
364fe8e81b7SStefan Popa 	regval &= ADP5061_CHG_CURR_ITRK_DEAD_MSK;
365fe8e81b7SStefan Popa 	val->intval = adp5061_prechg_current[regval] * 1000;
366fe8e81b7SStefan Popa 
367fe8e81b7SStefan Popa 	return ret;
368fe8e81b7SStefan Popa }
369fe8e81b7SStefan Popa 
adp5061_set_prechg_current(struct adp5061_state * st,int val)370fe8e81b7SStefan Popa static int adp5061_set_prechg_current(struct adp5061_state *st, int val)
371fe8e81b7SStefan Popa {
372fe8e81b7SStefan Popa 	int index;
373fe8e81b7SStefan Popa 
374fe8e81b7SStefan Popa 	/* Convert from uA to mA */
375fe8e81b7SStefan Popa 	val /= 1000;
376fe8e81b7SStefan Popa 	index = adp5061_get_array_index(adp5061_prechg_current,
377fe8e81b7SStefan Popa 					ARRAY_SIZE(adp5061_prechg_current),
378fe8e81b7SStefan Popa 					val);
379fe8e81b7SStefan Popa 	if (index < 0)
380fe8e81b7SStefan Popa 		return index;
381fe8e81b7SStefan Popa 
382fe8e81b7SStefan Popa 	return regmap_update_bits(st->regmap, ADP5061_CHG_CURR,
383fe8e81b7SStefan Popa 				  ADP5061_CHG_CURR_ITRK_DEAD_MSK,
384fe8e81b7SStefan Popa 				  ADP5061_CHG_CURR_ITRK_DEAD_MODE(index));
385fe8e81b7SStefan Popa }
386fe8e81b7SStefan Popa 
adp5061_get_vweak_th(struct adp5061_state * st,union power_supply_propval * val)387fe8e81b7SStefan Popa static int adp5061_get_vweak_th(struct adp5061_state *st,
388fe8e81b7SStefan Popa 				union power_supply_propval *val)
389fe8e81b7SStefan Popa {
390fe8e81b7SStefan Popa 	unsigned int regval;
391fe8e81b7SStefan Popa 	int ret;
392fe8e81b7SStefan Popa 
393fe8e81b7SStefan Popa 	ret = regmap_read(st->regmap, ADP5061_VOLTAGE_TH, &regval);
394fe8e81b7SStefan Popa 	if (ret < 0)
395fe8e81b7SStefan Popa 		return ret;
396fe8e81b7SStefan Popa 
397fe8e81b7SStefan Popa 	regval &= ADP5061_VOLTAGE_TH_VWEAK_MSK;
398fe8e81b7SStefan Popa 	val->intval = adp5061_vweak_th[regval] * 1000;
399fe8e81b7SStefan Popa 
400fe8e81b7SStefan Popa 	return ret;
401fe8e81b7SStefan Popa }
402fe8e81b7SStefan Popa 
adp5061_set_vweak_th(struct adp5061_state * st,int val)403fe8e81b7SStefan Popa static int adp5061_set_vweak_th(struct adp5061_state *st, int val)
404fe8e81b7SStefan Popa {
405fe8e81b7SStefan Popa 	int index;
406fe8e81b7SStefan Popa 
407fe8e81b7SStefan Popa 	/* Convert from uV to mV */
408fe8e81b7SStefan Popa 	val /= 1000;
409fe8e81b7SStefan Popa 	index = adp5061_get_array_index(adp5061_vweak_th,
410fe8e81b7SStefan Popa 					ARRAY_SIZE(adp5061_vweak_th),
411fe8e81b7SStefan Popa 					val);
412fe8e81b7SStefan Popa 	if (index < 0)
413fe8e81b7SStefan Popa 		return index;
414fe8e81b7SStefan Popa 
415fe8e81b7SStefan Popa 	return regmap_update_bits(st->regmap, ADP5061_VOLTAGE_TH,
416fe8e81b7SStefan Popa 				  ADP5061_VOLTAGE_TH_VWEAK_MSK,
417fe8e81b7SStefan Popa 				  ADP5061_VOLTAGE_TH_VWEAK_MODE(index));
418fe8e81b7SStefan Popa }
419fe8e81b7SStefan Popa 
adp5061_get_chg_type(struct adp5061_state * st,union power_supply_propval * val)420fe8e81b7SStefan Popa static int adp5061_get_chg_type(struct adp5061_state *st,
421fe8e81b7SStefan Popa 				union power_supply_propval *val)
422fe8e81b7SStefan Popa {
423fe8e81b7SStefan Popa 	u8 status1, status2;
424fe8e81b7SStefan Popa 	int chg_type, ret;
425fe8e81b7SStefan Popa 
426fe8e81b7SStefan Popa 	ret = adp5061_get_status(st, &status1, &status2);
427fe8e81b7SStefan Popa 	if (ret < 0)
428fe8e81b7SStefan Popa 		return ret;
429fe8e81b7SStefan Popa 
4309d47e01bSWei Yongjun 	chg_type = ADP5061_CHG_STATUS_1_CHG_STATUS(status1);
4319d47e01bSWei Yongjun 	if (chg_type >= ARRAY_SIZE(adp5061_chg_type))
432fe8e81b7SStefan Popa 		val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
433fe8e81b7SStefan Popa 	else
4349d47e01bSWei Yongjun 		val->intval = adp5061_chg_type[chg_type];
435fe8e81b7SStefan Popa 
436fe8e81b7SStefan Popa 	return ret;
437fe8e81b7SStefan Popa }
438fe8e81b7SStefan Popa 
adp5061_get_charger_status(struct adp5061_state * st,union power_supply_propval * val)439fe8e81b7SStefan Popa static int adp5061_get_charger_status(struct adp5061_state *st,
440fe8e81b7SStefan Popa 				      union power_supply_propval *val)
441fe8e81b7SStefan Popa {
442fe8e81b7SStefan Popa 	u8 status1, status2;
443fe8e81b7SStefan Popa 	int ret;
444fe8e81b7SStefan Popa 
445fe8e81b7SStefan Popa 	ret = adp5061_get_status(st, &status1, &status2);
446fe8e81b7SStefan Popa 	if (ret < 0)
447fe8e81b7SStefan Popa 		return ret;
448fe8e81b7SStefan Popa 
449fe8e81b7SStefan Popa 	switch (ADP5061_CHG_STATUS_1_CHG_STATUS(status1)) {
450fe8e81b7SStefan Popa 	case ADP5061_CHG_OFF:
451fe8e81b7SStefan Popa 		val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
452fe8e81b7SStefan Popa 		break;
453fe8e81b7SStefan Popa 	case ADP5061_CHG_TRICKLE:
454fe8e81b7SStefan Popa 	case ADP5061_CHG_FAST_CC:
455fe8e81b7SStefan Popa 	case ADP5061_CHG_FAST_CV:
456fe8e81b7SStefan Popa 		val->intval = POWER_SUPPLY_STATUS_CHARGING;
457fe8e81b7SStefan Popa 		break;
458fe8e81b7SStefan Popa 	case ADP5061_CHG_COMPLETE:
459fe8e81b7SStefan Popa 		val->intval = POWER_SUPPLY_STATUS_FULL;
460fe8e81b7SStefan Popa 		break;
461fe8e81b7SStefan Popa 	case ADP5061_CHG_TIMER_EXP:
462fe8e81b7SStefan Popa 		/* The battery must be discharging if there is a charge fault */
463fe8e81b7SStefan Popa 		val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
464fe8e81b7SStefan Popa 		break;
465fe8e81b7SStefan Popa 	default:
466fe8e81b7SStefan Popa 		val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
467fe8e81b7SStefan Popa 	}
468fe8e81b7SStefan Popa 
469fe8e81b7SStefan Popa 	return ret;
470fe8e81b7SStefan Popa }
471fe8e81b7SStefan Popa 
adp5061_get_battery_status(struct adp5061_state * st,union power_supply_propval * val)472fe8e81b7SStefan Popa static int adp5061_get_battery_status(struct adp5061_state *st,
473fe8e81b7SStefan Popa 				      union power_supply_propval *val)
474fe8e81b7SStefan Popa {
475fe8e81b7SStefan Popa 	u8 status1, status2;
476fe8e81b7SStefan Popa 	int ret;
477fe8e81b7SStefan Popa 
478fe8e81b7SStefan Popa 	ret = adp5061_get_status(st, &status1, &status2);
479fe8e81b7SStefan Popa 	if (ret < 0)
480fe8e81b7SStefan Popa 		return ret;
481fe8e81b7SStefan Popa 
482fe8e81b7SStefan Popa 	switch (ADP5061_CHG_STATUS_2_BAT_STATUS(status2)) {
483fe8e81b7SStefan Popa 	case 0x0: /* Battery monitor off */
484fe8e81b7SStefan Popa 	case 0x1: /* No battery */
485fe8e81b7SStefan Popa 		val->intval = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
486fe8e81b7SStefan Popa 		break;
487fe8e81b7SStefan Popa 	case 0x2: /* VBAT < VTRK */
488fe8e81b7SStefan Popa 		val->intval = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
489fe8e81b7SStefan Popa 		break;
490fe8e81b7SStefan Popa 	case 0x3: /* VTRK < VBAT_SNS < VWEAK */
491fe8e81b7SStefan Popa 		val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
492fe8e81b7SStefan Popa 		break;
493fe8e81b7SStefan Popa 	case 0x4: /* VBAT_SNS > VWEAK */
494fe8e81b7SStefan Popa 		val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
495fe8e81b7SStefan Popa 		break;
496e568252dSWei Yongjun 	default:
497e568252dSWei Yongjun 		val->intval = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
498e568252dSWei Yongjun 		break;
499fe8e81b7SStefan Popa 	}
500fe8e81b7SStefan Popa 
501fe8e81b7SStefan Popa 	return ret;
502fe8e81b7SStefan Popa }
503fe8e81b7SStefan Popa 
adp5061_get_termination_current(struct adp5061_state * st,union power_supply_propval * val)504fe8e81b7SStefan Popa static int adp5061_get_termination_current(struct adp5061_state *st,
505fe8e81b7SStefan Popa 					   union power_supply_propval *val)
506fe8e81b7SStefan Popa {
507fe8e81b7SStefan Popa 	unsigned int regval;
508fe8e81b7SStefan Popa 	int ret;
509fe8e81b7SStefan Popa 
510fe8e81b7SStefan Popa 	ret = regmap_read(st->regmap, ADP5061_IEND, &regval);
511fe8e81b7SStefan Popa 	if (ret < 0)
512fe8e81b7SStefan Popa 		return ret;
513fe8e81b7SStefan Popa 
514fe8e81b7SStefan Popa 	regval = (regval & ADP5061_IEND_IEND_MSK) >> 5;
515fe8e81b7SStefan Popa 	val->intval = adp5061_iend[regval];
516fe8e81b7SStefan Popa 
517fe8e81b7SStefan Popa 	return ret;
518fe8e81b7SStefan Popa }
519fe8e81b7SStefan Popa 
adp5061_set_termination_current(struct adp5061_state * st,int val)520fe8e81b7SStefan Popa static int adp5061_set_termination_current(struct adp5061_state *st, int val)
521fe8e81b7SStefan Popa {
522fe8e81b7SStefan Popa 	int index;
523fe8e81b7SStefan Popa 
524fe8e81b7SStefan Popa 	index = adp5061_get_array_index(adp5061_iend,
525fe8e81b7SStefan Popa 					ARRAY_SIZE(adp5061_iend),
526fe8e81b7SStefan Popa 					val);
527fe8e81b7SStefan Popa 	if (index < 0)
528fe8e81b7SStefan Popa 		return index;
529fe8e81b7SStefan Popa 
530fe8e81b7SStefan Popa 	return regmap_update_bits(st->regmap, ADP5061_IEND,
531fe8e81b7SStefan Popa 				  ADP5061_IEND_IEND_MSK,
532fe8e81b7SStefan Popa 				  ADP5061_IEND_IEND_MODE(index));
533fe8e81b7SStefan Popa }
534fe8e81b7SStefan Popa 
adp5061_get_property(struct power_supply * psy,enum power_supply_property psp,union power_supply_propval * val)535fe8e81b7SStefan Popa static int adp5061_get_property(struct power_supply *psy,
536fe8e81b7SStefan Popa 				enum power_supply_property psp,
537fe8e81b7SStefan Popa 				union power_supply_propval *val)
538fe8e81b7SStefan Popa {
539fe8e81b7SStefan Popa 	struct adp5061_state *st = power_supply_get_drvdata(psy);
540fe8e81b7SStefan Popa 	u8 status1, status2;
541fe8e81b7SStefan Popa 	int mode, ret;
542fe8e81b7SStefan Popa 
543fe8e81b7SStefan Popa 	switch (psp) {
544fe8e81b7SStefan Popa 	case POWER_SUPPLY_PROP_PRESENT:
545fe8e81b7SStefan Popa 		ret = adp5061_get_status(st, &status1, &status2);
546fe8e81b7SStefan Popa 		if (ret < 0)
547fe8e81b7SStefan Popa 			return ret;
548fe8e81b7SStefan Popa 
549fe8e81b7SStefan Popa 		mode = ADP5061_CHG_STATUS_2_BAT_STATUS(status2);
550fe8e81b7SStefan Popa 		if (mode == ADP5061_NO_BATTERY)
551fe8e81b7SStefan Popa 			val->intval = 0;
552fe8e81b7SStefan Popa 		else
553fe8e81b7SStefan Popa 			val->intval = 1;
554fe8e81b7SStefan Popa 		break;
555fe8e81b7SStefan Popa 	case POWER_SUPPLY_PROP_CHARGE_TYPE:
556fe8e81b7SStefan Popa 		return adp5061_get_chg_type(st, val);
557fe8e81b7SStefan Popa 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
558fe8e81b7SStefan Popa 		/* This property is used to indicate the input current
559fe8e81b7SStefan Popa 		 * limit into VINx (ILIM)
560fe8e81b7SStefan Popa 		 */
561fe8e81b7SStefan Popa 		return adp5061_get_input_current_limit(st, val);
562fe8e81b7SStefan Popa 	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
563fe8e81b7SStefan Popa 		/* This property is used to indicate the termination
564fe8e81b7SStefan Popa 		 * voltage (VTRM)
565fe8e81b7SStefan Popa 		 */
566fe8e81b7SStefan Popa 		return adp5061_get_max_voltage(st, val);
567fe8e81b7SStefan Popa 	case POWER_SUPPLY_PROP_VOLTAGE_MIN:
568fe8e81b7SStefan Popa 		/*
569fe8e81b7SStefan Popa 		 * This property is used to indicate the trickle to fast
570fe8e81b7SStefan Popa 		 * charge threshold (VTRK_DEAD)
571fe8e81b7SStefan Popa 		 */
572fe8e81b7SStefan Popa 		return adp5061_get_min_voltage(st, val);
573fe8e81b7SStefan Popa 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
574fe8e81b7SStefan Popa 		/* This property is used to indicate the charging
575fe8e81b7SStefan Popa 		 * voltage limit (CHG_VLIM)
576fe8e81b7SStefan Popa 		 */
577fe8e81b7SStefan Popa 		return adp5061_get_chg_volt_lim(st, val);
578fe8e81b7SStefan Popa 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
579fe8e81b7SStefan Popa 		/*
580fe8e81b7SStefan Popa 		 * This property is used to indicate the value of the constant
581fe8e81b7SStefan Popa 		 * current charge (ICHG)
582fe8e81b7SStefan Popa 		 */
583fe8e81b7SStefan Popa 		return adp5061_get_const_chg_current(st, val);
584fe8e81b7SStefan Popa 	case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
585fe8e81b7SStefan Popa 		/*
586fe8e81b7SStefan Popa 		 * This property is used to indicate the value of the trickle
587fe8e81b7SStefan Popa 		 * and weak charge currents (ITRK_DEAD)
588fe8e81b7SStefan Popa 		 */
589fe8e81b7SStefan Popa 		return adp5061_get_prechg_current(st, val);
590fe8e81b7SStefan Popa 	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
591fe8e81b7SStefan Popa 		/*
592fe8e81b7SStefan Popa 		 * This property is used to set the VWEAK threshold
593fe8e81b7SStefan Popa 		 * bellow this value, weak charge mode is entered
594fe8e81b7SStefan Popa 		 * above this value, fast chargerge mode is entered
595fe8e81b7SStefan Popa 		 */
596fe8e81b7SStefan Popa 		return adp5061_get_vweak_th(st, val);
597fe8e81b7SStefan Popa 	case POWER_SUPPLY_PROP_STATUS:
598fe8e81b7SStefan Popa 		/*
599fe8e81b7SStefan Popa 		 * Indicate the charger status in relation to power
600fe8e81b7SStefan Popa 		 * supply status property
601fe8e81b7SStefan Popa 		 */
602fe8e81b7SStefan Popa 		return adp5061_get_charger_status(st, val);
603fe8e81b7SStefan Popa 	case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
604fe8e81b7SStefan Popa 		/*
605fe8e81b7SStefan Popa 		 * Indicate the battery status in relation to power
606fe8e81b7SStefan Popa 		 * supply capacity level property
607fe8e81b7SStefan Popa 		 */
608fe8e81b7SStefan Popa 		return adp5061_get_battery_status(st, val);
609fe8e81b7SStefan Popa 	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
610fe8e81b7SStefan Popa 		/* Indicate the values of the termination current */
611fe8e81b7SStefan Popa 		return adp5061_get_termination_current(st, val);
612fe8e81b7SStefan Popa 	default:
613fe8e81b7SStefan Popa 		return -EINVAL;
614fe8e81b7SStefan Popa 	}
615fe8e81b7SStefan Popa 
616fe8e81b7SStefan Popa 	return 0;
617fe8e81b7SStefan Popa }
618fe8e81b7SStefan Popa 
adp5061_set_property(struct power_supply * psy,enum power_supply_property psp,const union power_supply_propval * val)619fe8e81b7SStefan Popa static int adp5061_set_property(struct power_supply *psy,
620fe8e81b7SStefan Popa 				enum power_supply_property psp,
621fe8e81b7SStefan Popa 				const union power_supply_propval *val)
622fe8e81b7SStefan Popa {
623fe8e81b7SStefan Popa 	struct adp5061_state *st = power_supply_get_drvdata(psy);
624fe8e81b7SStefan Popa 
625fe8e81b7SStefan Popa 	switch (psp) {
626fe8e81b7SStefan Popa 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
627fe8e81b7SStefan Popa 		return adp5061_set_input_current_limit(st, val->intval);
628fe8e81b7SStefan Popa 	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
629fe8e81b7SStefan Popa 		return adp5061_set_max_voltage(st, val->intval);
630fe8e81b7SStefan Popa 	case POWER_SUPPLY_PROP_VOLTAGE_MIN:
631fe8e81b7SStefan Popa 		return adp5061_set_min_voltage(st, val->intval);
632fe8e81b7SStefan Popa 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
633fe8e81b7SStefan Popa 		return adp5061_set_const_chg_vmax(st, val->intval);
634fe8e81b7SStefan Popa 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
635fe8e81b7SStefan Popa 		return adp5061_set_const_chg_current(st, val->intval);
636fe8e81b7SStefan Popa 	case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
637fe8e81b7SStefan Popa 		return adp5061_set_prechg_current(st, val->intval);
638fe8e81b7SStefan Popa 	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
639fe8e81b7SStefan Popa 		return adp5061_set_vweak_th(st, val->intval);
640fe8e81b7SStefan Popa 	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
641fe8e81b7SStefan Popa 		return adp5061_set_termination_current(st, val->intval);
642fe8e81b7SStefan Popa 	default:
643fe8e81b7SStefan Popa 		return -EINVAL;
644fe8e81b7SStefan Popa 	}
645fe8e81b7SStefan Popa 
646fe8e81b7SStefan Popa 	return 0;
647fe8e81b7SStefan Popa }
648fe8e81b7SStefan Popa 
adp5061_prop_writeable(struct power_supply * psy,enum power_supply_property psp)649fe8e81b7SStefan Popa static int adp5061_prop_writeable(struct power_supply *psy,
650fe8e81b7SStefan Popa 				  enum power_supply_property psp)
651fe8e81b7SStefan Popa {
652fe8e81b7SStefan Popa 	switch (psp) {
653fe8e81b7SStefan Popa 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
654fe8e81b7SStefan Popa 	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
655fe8e81b7SStefan Popa 	case POWER_SUPPLY_PROP_VOLTAGE_MIN:
656fe8e81b7SStefan Popa 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
657fe8e81b7SStefan Popa 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
658fe8e81b7SStefan Popa 	case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
659fe8e81b7SStefan Popa 	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
660fe8e81b7SStefan Popa 	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
661fe8e81b7SStefan Popa 		return 1;
662fe8e81b7SStefan Popa 	default:
663fe8e81b7SStefan Popa 		return 0;
664fe8e81b7SStefan Popa 	}
665fe8e81b7SStefan Popa }
666fe8e81b7SStefan Popa 
667fe8e81b7SStefan Popa static enum power_supply_property adp5061_props[] = {
668fe8e81b7SStefan Popa 	POWER_SUPPLY_PROP_PRESENT,
669fe8e81b7SStefan Popa 	POWER_SUPPLY_PROP_CHARGE_TYPE,
670fe8e81b7SStefan Popa 	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
671fe8e81b7SStefan Popa 	POWER_SUPPLY_PROP_VOLTAGE_MAX,
672fe8e81b7SStefan Popa 	POWER_SUPPLY_PROP_VOLTAGE_MIN,
673fe8e81b7SStefan Popa 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
674fe8e81b7SStefan Popa 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
675fe8e81b7SStefan Popa 	POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
676fe8e81b7SStefan Popa 	POWER_SUPPLY_PROP_VOLTAGE_AVG,
677fe8e81b7SStefan Popa 	POWER_SUPPLY_PROP_STATUS,
678fe8e81b7SStefan Popa 	POWER_SUPPLY_PROP_CAPACITY_LEVEL,
679fe8e81b7SStefan Popa 	POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
680fe8e81b7SStefan Popa };
681fe8e81b7SStefan Popa 
682fe8e81b7SStefan Popa static const struct regmap_config adp5061_regmap_config = {
683fe8e81b7SStefan Popa 	.reg_bits = 8,
684fe8e81b7SStefan Popa 	.val_bits = 8,
685fe8e81b7SStefan Popa };
686fe8e81b7SStefan Popa 
687fe8e81b7SStefan Popa static const struct power_supply_desc adp5061_desc = {
688fe8e81b7SStefan Popa 	.name			= "adp5061",
689fe8e81b7SStefan Popa 	.type			= POWER_SUPPLY_TYPE_USB,
690fe8e81b7SStefan Popa 	.get_property		= adp5061_get_property,
691fe8e81b7SStefan Popa 	.set_property		= adp5061_set_property,
692fe8e81b7SStefan Popa 	.property_is_writeable	= adp5061_prop_writeable,
693fe8e81b7SStefan Popa 	.properties		= adp5061_props,
694fe8e81b7SStefan Popa 	.num_properties		= ARRAY_SIZE(adp5061_props),
695fe8e81b7SStefan Popa };
696fe8e81b7SStefan Popa 
adp5061_probe(struct i2c_client * client)69702c70e91SUwe Kleine-König static int adp5061_probe(struct i2c_client *client)
698fe8e81b7SStefan Popa {
699fe8e81b7SStefan Popa 	struct power_supply_config psy_cfg = {};
700fe8e81b7SStefan Popa 	struct adp5061_state *st;
701fe8e81b7SStefan Popa 
702fe8e81b7SStefan Popa 	st = devm_kzalloc(&client->dev, sizeof(*st), GFP_KERNEL);
703fe8e81b7SStefan Popa 	if (!st)
704fe8e81b7SStefan Popa 		return -ENOMEM;
705fe8e81b7SStefan Popa 
706fe8e81b7SStefan Popa 	st->client = client;
707fe8e81b7SStefan Popa 	st->regmap = devm_regmap_init_i2c(client,
708fe8e81b7SStefan Popa 					  &adp5061_regmap_config);
709fe8e81b7SStefan Popa 	if (IS_ERR(st->regmap)) {
710fe8e81b7SStefan Popa 		dev_err(&client->dev, "Failed to initialize register map\n");
711fe8e81b7SStefan Popa 		return -EINVAL;
712fe8e81b7SStefan Popa 	}
713fe8e81b7SStefan Popa 
714fe8e81b7SStefan Popa 	i2c_set_clientdata(client, st);
715fe8e81b7SStefan Popa 	psy_cfg.drv_data = st;
716fe8e81b7SStefan Popa 
717fe8e81b7SStefan Popa 	st->psy = devm_power_supply_register(&client->dev,
718fe8e81b7SStefan Popa 					     &adp5061_desc,
719fe8e81b7SStefan Popa 					     &psy_cfg);
720fe8e81b7SStefan Popa 
721fe8e81b7SStefan Popa 	if (IS_ERR(st->psy)) {
722fe8e81b7SStefan Popa 		dev_err(&client->dev, "Failed to register power supply\n");
723fe8e81b7SStefan Popa 		return PTR_ERR(st->psy);
724fe8e81b7SStefan Popa 	}
725fe8e81b7SStefan Popa 
726fe8e81b7SStefan Popa 	return 0;
727fe8e81b7SStefan Popa }
728fe8e81b7SStefan Popa 
729fe8e81b7SStefan Popa static const struct i2c_device_id adp5061_id[] = {
730fe8e81b7SStefan Popa 	{ "adp5061", 0},
731fe8e81b7SStefan Popa 	{ }
732fe8e81b7SStefan Popa };
733fe8e81b7SStefan Popa MODULE_DEVICE_TABLE(i2c, adp5061_id);
734fe8e81b7SStefan Popa 
735fe8e81b7SStefan Popa static struct i2c_driver adp5061_driver = {
736fe8e81b7SStefan Popa 	.driver = {
737fe8e81b7SStefan Popa 		.name = KBUILD_MODNAME,
738fe8e81b7SStefan Popa 	},
739*fe20b1dcSUwe Kleine-König 	.probe = adp5061_probe,
740fe8e81b7SStefan Popa 	.id_table = adp5061_id,
741fe8e81b7SStefan Popa };
742fe8e81b7SStefan Popa module_i2c_driver(adp5061_driver);
743fe8e81b7SStefan Popa 
744fe8e81b7SStefan Popa MODULE_DESCRIPTION("Analog Devices adp5061 battery charger driver");
745fe8e81b7SStefan Popa MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
746fe8e81b7SStefan Popa MODULE_LICENSE("GPL v2");
747