blob: e84b6e4da14a8a9e522c18dffad341a403301c88 [file] [log] [blame]
Quentin Schulz46c202b2017-04-18 09:34:17 +02001/*
2 * Battery power supply driver for X-Powers AXP20X and AXP22X PMICs
3 *
4 * Copyright 2016 Free Electrons NextThing Co.
5 * Quentin Schulz <quentin.schulz@free-electrons.com>
6 *
7 * This driver is based on a previous upstreaming attempt by:
8 * Bruno Prémont <bonbons@linux-vserver.org>
9 *
10 * This file is subject to the terms and conditions of the GNU General
11 * Public License. See the file "COPYING" in the main directory of this
12 * archive for more details.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 */
19
20#include <linux/err.h>
21#include <linux/interrupt.h>
22#include <linux/irq.h>
23#include <linux/module.h>
24#include <linux/of.h>
25#include <linux/of_device.h>
26#include <linux/platform_device.h>
27#include <linux/power_supply.h>
28#include <linux/regmap.h>
29#include <linux/slab.h>
30#include <linux/time.h>
31#include <linux/iio/iio.h>
32#include <linux/iio/consumer.h>
33#include <linux/mfd/axp20x.h>
34
35#define AXP20X_PWR_STATUS_BAT_CHARGING BIT(2)
36
37#define AXP20X_PWR_OP_BATT_PRESENT BIT(5)
38#define AXP20X_PWR_OP_BATT_ACTIVATED BIT(3)
39
40#define AXP209_FG_PERCENT GENMASK(6, 0)
41#define AXP22X_FG_VALID BIT(7)
42
43#define AXP20X_CHRG_CTRL1_TGT_VOLT GENMASK(6, 5)
44#define AXP20X_CHRG_CTRL1_TGT_4_1V (0 << 5)
45#define AXP20X_CHRG_CTRL1_TGT_4_15V (1 << 5)
46#define AXP20X_CHRG_CTRL1_TGT_4_2V (2 << 5)
47#define AXP20X_CHRG_CTRL1_TGT_4_36V (3 << 5)
48
49#define AXP22X_CHRG_CTRL1_TGT_4_22V (1 << 5)
50#define AXP22X_CHRG_CTRL1_TGT_4_24V (3 << 5)
51
Quentin Schulz6ff653e2018-02-28 11:36:00 +010052#define AXP813_CHRG_CTRL1_TGT_4_35V (3 << 5)
53
Quentin Schulz46c202b2017-04-18 09:34:17 +020054#define AXP20X_CHRG_CTRL1_TGT_CURR GENMASK(3, 0)
55
56#define AXP20X_V_OFF_MASK GENMASK(2, 0)
57
Quentin Schulz648badd2018-02-28 11:35:58 +010058struct axp20x_batt_ps;
59
60struct axp_data {
61 int ccc_scale;
62 int ccc_offset;
63 bool has_fg_valid;
64 int (*get_max_voltage)(struct axp20x_batt_ps *batt, int *val);
65 int (*set_max_voltage)(struct axp20x_batt_ps *batt, int val);
66};
67
Quentin Schulz46c202b2017-04-18 09:34:17 +020068struct axp20x_batt_ps {
69 struct regmap *regmap;
70 struct power_supply *batt;
71 struct device *dev;
72 struct iio_channel *batt_chrg_i;
73 struct iio_channel *batt_dischrg_i;
74 struct iio_channel *batt_v;
Quentin Schulzc8003842017-05-11 15:42:20 +020075 /* Maximum constant charge current */
76 unsigned int max_ccc;
Quentin Schulz648badd2018-02-28 11:35:58 +010077 const struct axp_data *data;
Quentin Schulz46c202b2017-04-18 09:34:17 +020078};
79
80static int axp20x_battery_get_max_voltage(struct axp20x_batt_ps *axp20x_batt,
81 int *val)
82{
83 int ret, reg;
84
85 ret = regmap_read(axp20x_batt->regmap, AXP20X_CHRG_CTRL1, &reg);
86 if (ret)
87 return ret;
88
89 switch (reg & AXP20X_CHRG_CTRL1_TGT_VOLT) {
90 case AXP20X_CHRG_CTRL1_TGT_4_1V:
91 *val = 4100000;
92 break;
93 case AXP20X_CHRG_CTRL1_TGT_4_15V:
94 *val = 4150000;
95 break;
96 case AXP20X_CHRG_CTRL1_TGT_4_2V:
97 *val = 4200000;
98 break;
99 case AXP20X_CHRG_CTRL1_TGT_4_36V:
100 *val = 4360000;
101 break;
102 default:
103 return -EINVAL;
104 }
105
106 return 0;
107}
108
109static int axp22x_battery_get_max_voltage(struct axp20x_batt_ps *axp20x_batt,
110 int *val)
111{
112 int ret, reg;
113
114 ret = regmap_read(axp20x_batt->regmap, AXP20X_CHRG_CTRL1, &reg);
115 if (ret)
116 return ret;
117
118 switch (reg & AXP20X_CHRG_CTRL1_TGT_VOLT) {
119 case AXP20X_CHRG_CTRL1_TGT_4_1V:
120 *val = 4100000;
121 break;
122 case AXP20X_CHRG_CTRL1_TGT_4_2V:
123 *val = 4200000;
124 break;
125 case AXP22X_CHRG_CTRL1_TGT_4_22V:
126 *val = 4220000;
127 break;
128 case AXP22X_CHRG_CTRL1_TGT_4_24V:
129 *val = 4240000;
130 break;
131 default:
132 return -EINVAL;
133 }
134
135 return 0;
136}
137
Quentin Schulz6ff653e2018-02-28 11:36:00 +0100138static int axp813_battery_get_max_voltage(struct axp20x_batt_ps *axp20x_batt,
139 int *val)
140{
141 int ret, reg;
142
143 ret = regmap_read(axp20x_batt->regmap, AXP20X_CHRG_CTRL1, &reg);
144 if (ret)
145 return ret;
146
147 switch (reg & AXP20X_CHRG_CTRL1_TGT_VOLT) {
148 case AXP20X_CHRG_CTRL1_TGT_4_1V:
149 *val = 4100000;
150 break;
151 case AXP20X_CHRG_CTRL1_TGT_4_15V:
152 *val = 4150000;
153 break;
154 case AXP20X_CHRG_CTRL1_TGT_4_2V:
155 *val = 4200000;
156 break;
157 case AXP813_CHRG_CTRL1_TGT_4_35V:
158 *val = 4350000;
159 break;
160 default:
161 return -EINVAL;
162 }
163
164 return 0;
165}
166
Quentin Schulz46c202b2017-04-18 09:34:17 +0200167static int axp20x_get_constant_charge_current(struct axp20x_batt_ps *axp,
168 int *val)
169{
170 int ret;
171
172 ret = regmap_read(axp->regmap, AXP20X_CHRG_CTRL1, val);
173 if (ret)
174 return ret;
175
176 *val &= AXP20X_CHRG_CTRL1_TGT_CURR;
177
Quentin Schulz648badd2018-02-28 11:35:58 +0100178 *val = *val * axp->data->ccc_scale + axp->data->ccc_offset;
Quentin Schulz46c202b2017-04-18 09:34:17 +0200179
180 return 0;
181}
182
183static int axp20x_battery_get_prop(struct power_supply *psy,
184 enum power_supply_property psp,
185 union power_supply_propval *val)
186{
187 struct axp20x_batt_ps *axp20x_batt = power_supply_get_drvdata(psy);
188 struct iio_channel *chan;
189 int ret = 0, reg, val1;
190
191 switch (psp) {
192 case POWER_SUPPLY_PROP_PRESENT:
193 case POWER_SUPPLY_PROP_ONLINE:
194 ret = regmap_read(axp20x_batt->regmap, AXP20X_PWR_OP_MODE,
195 &reg);
196 if (ret)
197 return ret;
198
199 val->intval = !!(reg & AXP20X_PWR_OP_BATT_PRESENT);
200 break;
201
202 case POWER_SUPPLY_PROP_STATUS:
203 ret = regmap_read(axp20x_batt->regmap, AXP20X_PWR_INPUT_STATUS,
204 &reg);
205 if (ret)
206 return ret;
207
208 if (reg & AXP20X_PWR_STATUS_BAT_CHARGING) {
209 val->intval = POWER_SUPPLY_STATUS_CHARGING;
210 return 0;
211 }
212
213 ret = iio_read_channel_processed(axp20x_batt->batt_dischrg_i,
214 &val1);
215 if (ret)
216 return ret;
217
218 if (val1) {
219 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
220 return 0;
221 }
222
223 ret = regmap_read(axp20x_batt->regmap, AXP20X_FG_RES, &val1);
224 if (ret)
225 return ret;
226
227 /*
228 * Fuel Gauge data takes 7 bits but the stored value seems to be
229 * directly the raw percentage without any scaling to 7 bits.
230 */
231 if ((val1 & AXP209_FG_PERCENT) == 100)
232 val->intval = POWER_SUPPLY_STATUS_FULL;
233 else
234 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
235 break;
236
237 case POWER_SUPPLY_PROP_HEALTH:
238 ret = regmap_read(axp20x_batt->regmap, AXP20X_PWR_OP_MODE,
239 &val1);
240 if (ret)
241 return ret;
242
243 if (val1 & AXP20X_PWR_OP_BATT_ACTIVATED) {
244 val->intval = POWER_SUPPLY_HEALTH_DEAD;
245 return 0;
246 }
247
248 val->intval = POWER_SUPPLY_HEALTH_GOOD;
249 break;
250
251 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
252 ret = axp20x_get_constant_charge_current(axp20x_batt,
253 &val->intval);
254 if (ret)
255 return ret;
256 break;
257
258 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
Quentin Schulzc8003842017-05-11 15:42:20 +0200259 val->intval = axp20x_batt->max_ccc;
Quentin Schulz46c202b2017-04-18 09:34:17 +0200260 break;
261
262 case POWER_SUPPLY_PROP_CURRENT_NOW:
263 ret = regmap_read(axp20x_batt->regmap, AXP20X_PWR_INPUT_STATUS,
264 &reg);
265 if (ret)
266 return ret;
267
268 if (reg & AXP20X_PWR_STATUS_BAT_CHARGING)
269 chan = axp20x_batt->batt_chrg_i;
270 else
271 chan = axp20x_batt->batt_dischrg_i;
272
273 ret = iio_read_channel_processed(chan, &val->intval);
274 if (ret)
275 return ret;
276
277 /* IIO framework gives mA but Power Supply framework gives uA */
278 val->intval *= 1000;
279 break;
280
281 case POWER_SUPPLY_PROP_CAPACITY:
282 /* When no battery is present, return capacity is 100% */
283 ret = regmap_read(axp20x_batt->regmap, AXP20X_PWR_OP_MODE,
284 &reg);
285 if (ret)
286 return ret;
287
288 if (!(reg & AXP20X_PWR_OP_BATT_PRESENT)) {
289 val->intval = 100;
290 return 0;
291 }
292
293 ret = regmap_read(axp20x_batt->regmap, AXP20X_FG_RES, &reg);
294 if (ret)
295 return ret;
296
Quentin Schulz648badd2018-02-28 11:35:58 +0100297 if (axp20x_batt->data->has_fg_valid && !(reg & AXP22X_FG_VALID))
Quentin Schulz46c202b2017-04-18 09:34:17 +0200298 return -EINVAL;
299
300 /*
301 * Fuel Gauge data takes 7 bits but the stored value seems to be
302 * directly the raw percentage without any scaling to 7 bits.
303 */
304 val->intval = reg & AXP209_FG_PERCENT;
305 break;
306
307 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
Quentin Schulz648badd2018-02-28 11:35:58 +0100308 return axp20x_batt->data->get_max_voltage(axp20x_batt,
309 &val->intval);
Quentin Schulz46c202b2017-04-18 09:34:17 +0200310
311 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
312 ret = regmap_read(axp20x_batt->regmap, AXP20X_V_OFF, &reg);
313 if (ret)
314 return ret;
315
316 val->intval = 2600000 + 100000 * (reg & AXP20X_V_OFF_MASK);
317 break;
318
319 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
320 ret = iio_read_channel_processed(axp20x_batt->batt_v,
321 &val->intval);
322 if (ret)
323 return ret;
324
325 /* IIO framework gives mV but Power Supply framework gives uV */
326 val->intval *= 1000;
327 break;
328
329 default:
330 return -EINVAL;
331 }
332
333 return 0;
334}
335
Quentin Schulz648badd2018-02-28 11:35:58 +0100336static int axp22x_battery_set_max_voltage(struct axp20x_batt_ps *axp20x_batt,
337 int val)
338{
339 switch (val) {
340 case 4100000:
341 val = AXP20X_CHRG_CTRL1_TGT_4_1V;
342 break;
343
344 case 4200000:
345 val = AXP20X_CHRG_CTRL1_TGT_4_2V;
346 break;
347
348 default:
349 /*
350 * AXP20x max voltage can be set to 4.36V and AXP22X max voltage
351 * can be set to 4.22V and 4.24V, but these voltages are too
352 * high for Lithium based batteries (AXP PMICs are supposed to
353 * be used with these kinds of battery).
354 */
355 return -EINVAL;
356 }
357
358 return regmap_update_bits(axp20x_batt->regmap, AXP20X_CHRG_CTRL1,
359 AXP20X_CHRG_CTRL1_TGT_VOLT, val);
360}
361
Quentin Schulz46c202b2017-04-18 09:34:17 +0200362static int axp20x_battery_set_max_voltage(struct axp20x_batt_ps *axp20x_batt,
363 int val)
364{
365 switch (val) {
366 case 4100000:
367 val = AXP20X_CHRG_CTRL1_TGT_4_1V;
368 break;
369
370 case 4150000:
Quentin Schulz46c202b2017-04-18 09:34:17 +0200371 val = AXP20X_CHRG_CTRL1_TGT_4_15V;
372 break;
373
374 case 4200000:
375 val = AXP20X_CHRG_CTRL1_TGT_4_2V;
376 break;
377
378 default:
379 /*
380 * AXP20x max voltage can be set to 4.36V and AXP22X max voltage
381 * can be set to 4.22V and 4.24V, but these voltages are too
382 * high for Lithium based batteries (AXP PMICs are supposed to
383 * be used with these kinds of battery).
384 */
385 return -EINVAL;
386 }
387
388 return regmap_update_bits(axp20x_batt->regmap, AXP20X_CHRG_CTRL1,
389 AXP20X_CHRG_CTRL1_TGT_VOLT, val);
390}
391
392static int axp20x_set_constant_charge_current(struct axp20x_batt_ps *axp_batt,
393 int charge_current)
394{
Quentin Schulzc8003842017-05-11 15:42:20 +0200395 if (charge_current > axp_batt->max_ccc)
396 return -EINVAL;
397
Quentin Schulz648badd2018-02-28 11:35:58 +0100398 charge_current = (charge_current - axp_batt->data->ccc_offset) /
399 axp_batt->data->ccc_scale;
Quentin Schulz46c202b2017-04-18 09:34:17 +0200400
401 if (charge_current > AXP20X_CHRG_CTRL1_TGT_CURR || charge_current < 0)
402 return -EINVAL;
403
404 return regmap_update_bits(axp_batt->regmap, AXP20X_CHRG_CTRL1,
405 AXP20X_CHRG_CTRL1_TGT_CURR, charge_current);
406}
407
Quentin Schulzc8003842017-05-11 15:42:20 +0200408static int axp20x_set_max_constant_charge_current(struct axp20x_batt_ps *axp,
409 int charge_current)
410{
411 bool lower_max = false;
412
Quentin Schulz648badd2018-02-28 11:35:58 +0100413 charge_current = (charge_current - axp->data->ccc_offset) /
414 axp->data->ccc_scale;
Quentin Schulzc8003842017-05-11 15:42:20 +0200415
416 if (charge_current > AXP20X_CHRG_CTRL1_TGT_CURR || charge_current < 0)
417 return -EINVAL;
418
Quentin Schulz648badd2018-02-28 11:35:58 +0100419 charge_current = charge_current * axp->data->ccc_scale +
420 axp->data->ccc_offset;
Quentin Schulzc8003842017-05-11 15:42:20 +0200421
422 if (charge_current > axp->max_ccc)
423 dev_warn(axp->dev,
424 "Setting max constant charge current higher than previously defined. Note that increasing the constant charge current may damage your battery.\n");
425 else
426 lower_max = true;
427
428 axp->max_ccc = charge_current;
429
430 if (lower_max) {
431 int current_cc;
432
433 axp20x_get_constant_charge_current(axp, &current_cc);
434 if (current_cc > charge_current)
435 axp20x_set_constant_charge_current(axp, charge_current);
436 }
437
438 return 0;
439}
Quentin Schulz46c202b2017-04-18 09:34:17 +0200440static int axp20x_set_voltage_min_design(struct axp20x_batt_ps *axp_batt,
441 int min_voltage)
442{
443 int val1 = (min_voltage - 2600000) / 100000;
444
445 if (val1 < 0 || val1 > AXP20X_V_OFF_MASK)
446 return -EINVAL;
447
448 return regmap_update_bits(axp_batt->regmap, AXP20X_V_OFF,
449 AXP20X_V_OFF_MASK, val1);
450}
451
452static int axp20x_battery_set_prop(struct power_supply *psy,
453 enum power_supply_property psp,
454 const union power_supply_propval *val)
455{
456 struct axp20x_batt_ps *axp20x_batt = power_supply_get_drvdata(psy);
457
458 switch (psp) {
459 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
460 return axp20x_set_voltage_min_design(axp20x_batt, val->intval);
461
462 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
Quentin Schulz648badd2018-02-28 11:35:58 +0100463 return axp20x_batt->data->set_max_voltage(axp20x_batt, val->intval);
Quentin Schulz46c202b2017-04-18 09:34:17 +0200464
465 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
466 return axp20x_set_constant_charge_current(axp20x_batt,
467 val->intval);
Quentin Schulzc8003842017-05-11 15:42:20 +0200468 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
469 return axp20x_set_max_constant_charge_current(axp20x_batt,
470 val->intval);
Quentin Schulz46c202b2017-04-18 09:34:17 +0200471
472 default:
473 return -EINVAL;
474 }
475}
476
477static enum power_supply_property axp20x_battery_props[] = {
478 POWER_SUPPLY_PROP_PRESENT,
479 POWER_SUPPLY_PROP_ONLINE,
480 POWER_SUPPLY_PROP_STATUS,
481 POWER_SUPPLY_PROP_VOLTAGE_NOW,
482 POWER_SUPPLY_PROP_CURRENT_NOW,
483 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
484 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
485 POWER_SUPPLY_PROP_HEALTH,
486 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
487 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
488 POWER_SUPPLY_PROP_CAPACITY,
489};
490
491static int axp20x_battery_prop_writeable(struct power_supply *psy,
492 enum power_supply_property psp)
493{
494 return psp == POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN ||
495 psp == POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN ||
Quentin Schulzc8003842017-05-11 15:42:20 +0200496 psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT ||
497 psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX;
Quentin Schulz46c202b2017-04-18 09:34:17 +0200498}
499
500static const struct power_supply_desc axp20x_batt_ps_desc = {
501 .name = "axp20x-battery",
502 .type = POWER_SUPPLY_TYPE_BATTERY,
503 .properties = axp20x_battery_props,
504 .num_properties = ARRAY_SIZE(axp20x_battery_props),
505 .property_is_writeable = axp20x_battery_prop_writeable,
506 .get_property = axp20x_battery_get_prop,
507 .set_property = axp20x_battery_set_prop,
508};
509
Quentin Schulz648badd2018-02-28 11:35:58 +0100510static const struct axp_data axp209_data = {
511 .ccc_scale = 100000,
512 .ccc_offset = 300000,
513 .get_max_voltage = axp20x_battery_get_max_voltage,
514 .set_max_voltage = axp20x_battery_set_max_voltage,
515};
516
517static const struct axp_data axp221_data = {
518 .ccc_scale = 150000,
519 .ccc_offset = 300000,
520 .has_fg_valid = true,
521 .get_max_voltage = axp22x_battery_get_max_voltage,
522 .set_max_voltage = axp22x_battery_set_max_voltage,
523};
524
Quentin Schulz6ff653e2018-02-28 11:36:00 +0100525static const struct axp_data axp813_data = {
526 .ccc_scale = 200000,
527 .ccc_offset = 200000,
528 .has_fg_valid = true,
529 .get_max_voltage = axp813_battery_get_max_voltage,
530 .set_max_voltage = axp20x_battery_set_max_voltage,
531};
532
Quentin Schulz46c202b2017-04-18 09:34:17 +0200533static const struct of_device_id axp20x_battery_ps_id[] = {
534 {
535 .compatible = "x-powers,axp209-battery-power-supply",
Quentin Schulz648badd2018-02-28 11:35:58 +0100536 .data = (void *)&axp209_data,
Quentin Schulz46c202b2017-04-18 09:34:17 +0200537 }, {
538 .compatible = "x-powers,axp221-battery-power-supply",
Quentin Schulz648badd2018-02-28 11:35:58 +0100539 .data = (void *)&axp221_data,
Quentin Schulz6ff653e2018-02-28 11:36:00 +0100540 }, {
541 .compatible = "x-powers,axp813-battery-power-supply",
542 .data = (void *)&axp813_data,
Quentin Schulz46c202b2017-04-18 09:34:17 +0200543 }, { /* sentinel */ },
544};
545MODULE_DEVICE_TABLE(of, axp20x_battery_ps_id);
546
547static int axp20x_power_probe(struct platform_device *pdev)
548{
549 struct axp20x_batt_ps *axp20x_batt;
550 struct power_supply_config psy_cfg = {};
Quentin Schulzf8c91bae2017-05-11 15:42:17 +0200551 struct power_supply_battery_info info;
Quentin Schulz648badd2018-02-28 11:35:58 +0100552 struct device *dev = &pdev->dev;
Quentin Schulz46c202b2017-04-18 09:34:17 +0200553
554 if (!of_device_is_available(pdev->dev.of_node))
555 return -ENODEV;
556
557 axp20x_batt = devm_kzalloc(&pdev->dev, sizeof(*axp20x_batt),
558 GFP_KERNEL);
559 if (!axp20x_batt)
560 return -ENOMEM;
561
562 axp20x_batt->dev = &pdev->dev;
563
564 axp20x_batt->batt_v = devm_iio_channel_get(&pdev->dev, "batt_v");
565 if (IS_ERR(axp20x_batt->batt_v)) {
566 if (PTR_ERR(axp20x_batt->batt_v) == -ENODEV)
567 return -EPROBE_DEFER;
568 return PTR_ERR(axp20x_batt->batt_v);
569 }
570
571 axp20x_batt->batt_chrg_i = devm_iio_channel_get(&pdev->dev,
572 "batt_chrg_i");
573 if (IS_ERR(axp20x_batt->batt_chrg_i)) {
574 if (PTR_ERR(axp20x_batt->batt_chrg_i) == -ENODEV)
575 return -EPROBE_DEFER;
576 return PTR_ERR(axp20x_batt->batt_chrg_i);
577 }
578
579 axp20x_batt->batt_dischrg_i = devm_iio_channel_get(&pdev->dev,
580 "batt_dischrg_i");
581 if (IS_ERR(axp20x_batt->batt_dischrg_i)) {
582 if (PTR_ERR(axp20x_batt->batt_dischrg_i) == -ENODEV)
583 return -EPROBE_DEFER;
584 return PTR_ERR(axp20x_batt->batt_dischrg_i);
585 }
586
587 axp20x_batt->regmap = dev_get_regmap(pdev->dev.parent, NULL);
588 platform_set_drvdata(pdev, axp20x_batt);
589
590 psy_cfg.drv_data = axp20x_batt;
591 psy_cfg.of_node = pdev->dev.of_node;
592
Quentin Schulz648badd2018-02-28 11:35:58 +0100593 axp20x_batt->data = (struct axp_data *)of_device_get_match_data(dev);
Quentin Schulz46c202b2017-04-18 09:34:17 +0200594
595 axp20x_batt->batt = devm_power_supply_register(&pdev->dev,
596 &axp20x_batt_ps_desc,
597 &psy_cfg);
598 if (IS_ERR(axp20x_batt->batt)) {
599 dev_err(&pdev->dev, "failed to register power supply: %ld\n",
600 PTR_ERR(axp20x_batt->batt));
601 return PTR_ERR(axp20x_batt->batt);
602 }
603
Quentin Schulzf8c91bae2017-05-11 15:42:17 +0200604 if (!power_supply_get_battery_info(axp20x_batt->batt, &info)) {
605 int vmin = info.voltage_min_design_uv;
Quentin Schulzc8003842017-05-11 15:42:20 +0200606 int ccc = info.constant_charge_current_max_ua;
Quentin Schulzf8c91bae2017-05-11 15:42:17 +0200607
608 if (vmin > 0 && axp20x_set_voltage_min_design(axp20x_batt,
609 vmin))
610 dev_err(&pdev->dev,
611 "couldn't set voltage_min_design\n");
Quentin Schulzc8003842017-05-11 15:42:20 +0200612
613 /* Set max to unverified value to be able to set CCC */
614 axp20x_batt->max_ccc = ccc;
615
616 if (ccc <= 0 || axp20x_set_constant_charge_current(axp20x_batt,
617 ccc)) {
618 dev_err(&pdev->dev,
619 "couldn't set constant charge current from DT: fallback to minimum value\n");
620 ccc = 300000;
621 axp20x_batt->max_ccc = ccc;
622 axp20x_set_constant_charge_current(axp20x_batt, ccc);
623 }
Quentin Schulzf8c91bae2017-05-11 15:42:17 +0200624 }
625
Quentin Schulzc8003842017-05-11 15:42:20 +0200626 /*
627 * Update max CCC to a valid value if battery info is present or set it
628 * to current register value by default.
629 */
630 axp20x_get_constant_charge_current(axp20x_batt,
631 &axp20x_batt->max_ccc);
632
Quentin Schulz46c202b2017-04-18 09:34:17 +0200633 return 0;
634}
635
636static struct platform_driver axp20x_batt_driver = {
637 .probe = axp20x_power_probe,
638 .driver = {
639 .name = "axp20x-battery-power-supply",
640 .of_match_table = axp20x_battery_ps_id,
641 },
642};
643
644module_platform_driver(axp20x_batt_driver);
645
646MODULE_DESCRIPTION("Battery power supply driver for AXP20X and AXP22X PMICs");
647MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>");
648MODULE_LICENSE("GPL");