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, ®val);
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, ®val);
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, ®val);
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, ®val);
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, ®val);
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, ®val);
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, ®val);
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, ®val);
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