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