1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * MP2629 battery charger driver
4 *
5 * Copyright 2020 Monolithic Power Systems, Inc
6 *
7 * Author: Saravanan Sekar <sravanhome@gmail.com>
8 */
9
10 #include <linux/bits.h>
11 #include <linux/iio/consumer.h>
12 #include <linux/iio/types.h>
13 #include <linux/interrupt.h>
14 #include <linux/mfd/mp2629.h>
15 #include <linux/module.h>
16 #include <linux/platform_device.h>
17 #include <linux/power_supply.h>
18 #include <linux/regmap.h>
19
20 #define MP2629_REG_INPUT_ILIM 0x00
21 #define MP2629_REG_INPUT_VLIM 0x01
22 #define MP2629_REG_CHARGE_CTRL 0x04
23 #define MP2629_REG_CHARGE_ILIM 0x05
24 #define MP2629_REG_PRECHARGE 0x06
25 #define MP2629_REG_TERM_CURRENT 0x06
26 #define MP2629_REG_CHARGE_VLIM 0x07
27 #define MP2629_REG_TIMER_CTRL 0x08
28 #define MP2629_REG_IMPEDANCE_COMP 0x09
29 #define MP2629_REG_INTERRUPT 0x0b
30 #define MP2629_REG_STATUS 0x0c
31 #define MP2629_REG_FAULT 0x0d
32
33 #define MP2629_MASK_INPUT_TYPE GENMASK(7, 5)
34 #define MP2629_MASK_CHARGE_TYPE GENMASK(4, 3)
35 #define MP2629_MASK_CHARGE_CTRL GENMASK(5, 4)
36 #define MP2629_MASK_WDOG_CTRL GENMASK(5, 4)
37 #define MP2629_MASK_IMPEDANCE GENMASK(7, 4)
38
39 #define MP2629_INPUTSOURCE_CHANGE GENMASK(7, 5)
40 #define MP2629_CHARGING_CHANGE GENMASK(4, 3)
41 #define MP2629_FAULT_BATTERY BIT(3)
42 #define MP2629_FAULT_THERMAL BIT(4)
43 #define MP2629_FAULT_INPUT BIT(5)
44 #define MP2629_FAULT_OTG BIT(6)
45
46 #define MP2629_MAX_BATT_CAPACITY 100
47
48 #define MP2629_PROPS(_idx, _min, _max, _step) \
49 [_idx] = { \
50 .min = _min, \
51 .max = _max, \
52 .step = _step, \
53 }
54
55 enum mp2629_source_type {
56 MP2629_SOURCE_TYPE_NO_INPUT,
57 MP2629_SOURCE_TYPE_NON_STD,
58 MP2629_SOURCE_TYPE_SDP,
59 MP2629_SOURCE_TYPE_CDP,
60 MP2629_SOURCE_TYPE_DCP,
61 MP2629_SOURCE_TYPE_OTG = 7,
62 };
63
64 enum mp2629_field {
65 INPUT_ILIM,
66 INPUT_VLIM,
67 CHARGE_ILIM,
68 CHARGE_VLIM,
69 PRECHARGE,
70 TERM_CURRENT,
71 MP2629_MAX_FIELD
72 };
73
74 struct mp2629_charger {
75 struct device *dev;
76 int status;
77 int fault;
78
79 struct regmap *regmap;
80 struct regmap_field *regmap_fields[MP2629_MAX_FIELD];
81 struct mutex lock;
82 struct power_supply *usb;
83 struct power_supply *battery;
84 struct iio_channel *iiochan[MP2629_ADC_CHAN_END];
85 };
86
87 struct mp2629_prop {
88 int reg;
89 int mask;
90 int min;
91 int max;
92 int step;
93 int shift;
94 };
95
96 static enum power_supply_property mp2629_charger_usb_props[] = {
97 POWER_SUPPLY_PROP_ONLINE,
98 POWER_SUPPLY_PROP_USB_TYPE,
99 POWER_SUPPLY_PROP_VOLTAGE_NOW,
100 POWER_SUPPLY_PROP_CURRENT_NOW,
101 POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
102 POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT,
103 };
104
105 static enum power_supply_property mp2629_charger_bat_props[] = {
106 POWER_SUPPLY_PROP_STATUS,
107 POWER_SUPPLY_PROP_HEALTH,
108 POWER_SUPPLY_PROP_CHARGE_TYPE,
109 POWER_SUPPLY_PROP_VOLTAGE_NOW,
110 POWER_SUPPLY_PROP_CURRENT_NOW,
111 POWER_SUPPLY_PROP_CAPACITY,
112 POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
113 POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
114 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
115 POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
116 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
117 POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
118 };
119
120 static struct mp2629_prop props[] = {
121 MP2629_PROPS(INPUT_ILIM, 100000, 3250000, 50000),
122 MP2629_PROPS(INPUT_VLIM, 3800000, 5300000, 100000),
123 MP2629_PROPS(CHARGE_ILIM, 320000, 4520000, 40000),
124 MP2629_PROPS(CHARGE_VLIM, 3400000, 4670000, 10000),
125 MP2629_PROPS(PRECHARGE, 120000, 720000, 40000),
126 MP2629_PROPS(TERM_CURRENT, 80000, 680000, 40000),
127 };
128
129 static const struct reg_field mp2629_reg_fields[] = {
130 [INPUT_ILIM] = REG_FIELD(MP2629_REG_INPUT_ILIM, 0, 5),
131 [INPUT_VLIM] = REG_FIELD(MP2629_REG_INPUT_VLIM, 0, 3),
132 [CHARGE_ILIM] = REG_FIELD(MP2629_REG_CHARGE_ILIM, 0, 6),
133 [CHARGE_VLIM] = REG_FIELD(MP2629_REG_CHARGE_VLIM, 1, 7),
134 [PRECHARGE] = REG_FIELD(MP2629_REG_PRECHARGE, 4, 7),
135 [TERM_CURRENT] = REG_FIELD(MP2629_REG_TERM_CURRENT, 0, 3),
136 };
137
138 static char *adc_chan_name[] = {
139 "mp2629-batt-volt",
140 "mp2629-system-volt",
141 "mp2629-input-volt",
142 "mp2629-batt-current",
143 "mp2629-input-current",
144 };
145
mp2629_read_adc(struct mp2629_charger * charger,enum mp2629_adc_chan ch,union power_supply_propval * val)146 static int mp2629_read_adc(struct mp2629_charger *charger,
147 enum mp2629_adc_chan ch,
148 union power_supply_propval *val)
149 {
150 int ret;
151 int chval;
152
153 ret = iio_read_channel_processed(charger->iiochan[ch], &chval);
154 if (ret)
155 return ret;
156
157 val->intval = chval * 1000;
158
159 return 0;
160 }
161
mp2629_get_prop(struct mp2629_charger * charger,enum mp2629_field fld,union power_supply_propval * val)162 static int mp2629_get_prop(struct mp2629_charger *charger,
163 enum mp2629_field fld,
164 union power_supply_propval *val)
165 {
166 int ret;
167 unsigned int rval;
168
169 ret = regmap_field_read(charger->regmap_fields[fld], &rval);
170 if (ret)
171 return ret;
172
173 val->intval = rval * props[fld].step + props[fld].min;
174
175 return 0;
176 }
177
mp2629_set_prop(struct mp2629_charger * charger,enum mp2629_field fld,const union power_supply_propval * val)178 static int mp2629_set_prop(struct mp2629_charger *charger,
179 enum mp2629_field fld,
180 const union power_supply_propval *val)
181 {
182 unsigned int rval;
183
184 if (val->intval < props[fld].min || val->intval > props[fld].max)
185 return -EINVAL;
186
187 rval = (val->intval - props[fld].min) / props[fld].step;
188 return regmap_field_write(charger->regmap_fields[fld], rval);
189 }
190
mp2629_get_battery_capacity(struct mp2629_charger * charger,union power_supply_propval * val)191 static int mp2629_get_battery_capacity(struct mp2629_charger *charger,
192 union power_supply_propval *val)
193 {
194 union power_supply_propval vnow, vlim;
195 int ret;
196
197 ret = mp2629_read_adc(charger, MP2629_BATT_VOLT, &vnow);
198 if (ret)
199 return ret;
200
201 ret = mp2629_get_prop(charger, CHARGE_VLIM, &vlim);
202 if (ret)
203 return ret;
204
205 val->intval = (vnow.intval * 100) / vlim.intval;
206 val->intval = min(val->intval, MP2629_MAX_BATT_CAPACITY);
207
208 return 0;
209 }
210
mp2629_charger_battery_get_prop(struct power_supply * psy,enum power_supply_property psp,union power_supply_propval * val)211 static int mp2629_charger_battery_get_prop(struct power_supply *psy,
212 enum power_supply_property psp,
213 union power_supply_propval *val)
214 {
215 struct mp2629_charger *charger = dev_get_drvdata(psy->dev.parent);
216 unsigned int rval;
217 int ret = 0;
218
219 switch (psp) {
220 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
221 ret = mp2629_read_adc(charger, MP2629_BATT_VOLT, val);
222 break;
223
224 case POWER_SUPPLY_PROP_CURRENT_NOW:
225 ret = mp2629_read_adc(charger, MP2629_BATT_CURRENT, val);
226 break;
227
228 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
229 val->intval = 4520000;
230 break;
231
232 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
233 val->intval = 4670000;
234 break;
235
236 case POWER_SUPPLY_PROP_CAPACITY:
237 ret = mp2629_get_battery_capacity(charger, val);
238 break;
239
240 case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
241 ret = mp2629_get_prop(charger, TERM_CURRENT, val);
242 break;
243
244 case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
245 ret = mp2629_get_prop(charger, PRECHARGE, val);
246 break;
247
248 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
249 ret = mp2629_get_prop(charger, CHARGE_VLIM, val);
250 break;
251
252 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
253 ret = mp2629_get_prop(charger, CHARGE_ILIM, val);
254 break;
255
256 case POWER_SUPPLY_PROP_HEALTH:
257 if (!charger->fault)
258 val->intval = POWER_SUPPLY_HEALTH_GOOD;
259 if (MP2629_FAULT_BATTERY & charger->fault)
260 val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
261 else if (MP2629_FAULT_THERMAL & charger->fault)
262 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
263 else if (MP2629_FAULT_INPUT & charger->fault)
264 val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
265 break;
266
267 case POWER_SUPPLY_PROP_STATUS:
268 ret = regmap_read(charger->regmap, MP2629_REG_STATUS, &rval);
269 if (ret)
270 break;
271
272 rval = (rval & MP2629_MASK_CHARGE_TYPE) >> 3;
273 switch (rval) {
274 case 0x00:
275 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
276 break;
277 case 0x01:
278 case 0x10:
279 val->intval = POWER_SUPPLY_STATUS_CHARGING;
280 break;
281 case 0x11:
282 val->intval = POWER_SUPPLY_STATUS_FULL;
283 }
284 break;
285
286 case POWER_SUPPLY_PROP_CHARGE_TYPE:
287 ret = regmap_read(charger->regmap, MP2629_REG_STATUS, &rval);
288 if (ret)
289 break;
290
291 rval = (rval & MP2629_MASK_CHARGE_TYPE) >> 3;
292 switch (rval) {
293 case 0x00:
294 val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
295 break;
296 case 0x01:
297 val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
298 break;
299 case 0x10:
300 val->intval = POWER_SUPPLY_CHARGE_TYPE_STANDARD;
301 break;
302 default:
303 val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
304 }
305 break;
306
307 default:
308 return -EINVAL;
309 }
310
311 return ret;
312 }
313
mp2629_charger_battery_set_prop(struct power_supply * psy,enum power_supply_property psp,const union power_supply_propval * val)314 static int mp2629_charger_battery_set_prop(struct power_supply *psy,
315 enum power_supply_property psp,
316 const union power_supply_propval *val)
317 {
318 struct mp2629_charger *charger = dev_get_drvdata(psy->dev.parent);
319
320 switch (psp) {
321 case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
322 return mp2629_set_prop(charger, TERM_CURRENT, val);
323
324 case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
325 return mp2629_set_prop(charger, PRECHARGE, val);
326
327 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
328 return mp2629_set_prop(charger, CHARGE_VLIM, val);
329
330 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
331 return mp2629_set_prop(charger, CHARGE_ILIM, val);
332
333 default:
334 return -EINVAL;
335 }
336 }
337
mp2629_charger_usb_get_prop(struct power_supply * psy,enum power_supply_property psp,union power_supply_propval * val)338 static int mp2629_charger_usb_get_prop(struct power_supply *psy,
339 enum power_supply_property psp,
340 union power_supply_propval *val)
341 {
342 struct mp2629_charger *charger = dev_get_drvdata(psy->dev.parent);
343 unsigned int rval;
344 int ret;
345
346 switch (psp) {
347 case POWER_SUPPLY_PROP_ONLINE:
348 ret = regmap_read(charger->regmap, MP2629_REG_STATUS, &rval);
349 if (ret)
350 break;
351
352 val->intval = !!(rval & MP2629_MASK_INPUT_TYPE);
353 break;
354
355 case POWER_SUPPLY_PROP_USB_TYPE:
356 ret = regmap_read(charger->regmap, MP2629_REG_STATUS, &rval);
357 if (ret)
358 break;
359
360 rval = (rval & MP2629_MASK_INPUT_TYPE) >> 5;
361 switch (rval) {
362 case MP2629_SOURCE_TYPE_SDP:
363 val->intval = POWER_SUPPLY_USB_TYPE_SDP;
364 break;
365 case MP2629_SOURCE_TYPE_CDP:
366 val->intval = POWER_SUPPLY_USB_TYPE_CDP;
367 break;
368 case MP2629_SOURCE_TYPE_DCP:
369 val->intval = POWER_SUPPLY_USB_TYPE_DCP;
370 break;
371 case MP2629_SOURCE_TYPE_OTG:
372 val->intval = POWER_SUPPLY_USB_TYPE_PD_DRP;
373 break;
374 default:
375 val->intval = POWER_SUPPLY_USB_TYPE_UNKNOWN;
376 break;
377 }
378 break;
379
380 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
381 ret = mp2629_read_adc(charger, MP2629_INPUT_VOLT, val);
382 break;
383
384 case POWER_SUPPLY_PROP_CURRENT_NOW:
385 ret = mp2629_read_adc(charger, MP2629_INPUT_CURRENT, val);
386 break;
387
388 case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
389 ret = mp2629_get_prop(charger, INPUT_VLIM, val);
390 break;
391
392 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
393 ret = mp2629_get_prop(charger, INPUT_ILIM, val);
394 break;
395
396 default:
397 return -EINVAL;
398 }
399
400 return ret;
401 }
402
mp2629_charger_usb_set_prop(struct power_supply * psy,enum power_supply_property psp,const union power_supply_propval * val)403 static int mp2629_charger_usb_set_prop(struct power_supply *psy,
404 enum power_supply_property psp,
405 const union power_supply_propval *val)
406 {
407 struct mp2629_charger *charger = dev_get_drvdata(psy->dev.parent);
408
409 switch (psp) {
410 case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
411 return mp2629_set_prop(charger, INPUT_VLIM, val);
412
413 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
414 return mp2629_set_prop(charger, INPUT_ILIM, val);
415
416 default:
417 return -EINVAL;
418 }
419 }
420
mp2629_charger_battery_prop_writeable(struct power_supply * psy,enum power_supply_property psp)421 static int mp2629_charger_battery_prop_writeable(struct power_supply *psy,
422 enum power_supply_property psp)
423 {
424 return (psp == POWER_SUPPLY_PROP_PRECHARGE_CURRENT) ||
425 (psp == POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT) ||
426 (psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT) ||
427 (psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE);
428 }
429
mp2629_charger_usb_prop_writeable(struct power_supply * psy,enum power_supply_property psp)430 static int mp2629_charger_usb_prop_writeable(struct power_supply *psy,
431 enum power_supply_property psp)
432 {
433 return (psp == POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT) ||
434 (psp == POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT);
435 }
436
mp2629_irq_handler(int irq,void * dev_id)437 static irqreturn_t mp2629_irq_handler(int irq, void *dev_id)
438 {
439 struct mp2629_charger *charger = dev_id;
440 unsigned int rval;
441 int ret;
442
443 mutex_lock(&charger->lock);
444
445 ret = regmap_read(charger->regmap, MP2629_REG_FAULT, &rval);
446 if (ret)
447 goto unlock;
448
449 if (rval) {
450 charger->fault = rval;
451 if (MP2629_FAULT_BATTERY & rval)
452 dev_err(charger->dev, "Battery fault OVP\n");
453 else if (MP2629_FAULT_THERMAL & rval)
454 dev_err(charger->dev, "Thermal shutdown fault\n");
455 else if (MP2629_FAULT_INPUT & rval)
456 dev_err(charger->dev, "no input or input OVP\n");
457 else if (MP2629_FAULT_OTG & rval)
458 dev_err(charger->dev, "VIN overloaded\n");
459
460 goto unlock;
461 }
462
463 ret = regmap_read(charger->regmap, MP2629_REG_STATUS, &rval);
464 if (ret)
465 goto unlock;
466
467 if (rval & MP2629_INPUTSOURCE_CHANGE)
468 power_supply_changed(charger->usb);
469 else if (rval & MP2629_CHARGING_CHANGE)
470 power_supply_changed(charger->battery);
471
472 unlock:
473 mutex_unlock(&charger->lock);
474
475 return IRQ_HANDLED;
476 }
477
478 static const struct power_supply_desc mp2629_usb_desc = {
479 .name = "mp2629_usb",
480 .type = POWER_SUPPLY_TYPE_USB,
481 .usb_types = BIT(POWER_SUPPLY_USB_TYPE_SDP) |
482 BIT(POWER_SUPPLY_USB_TYPE_CDP) |
483 BIT(POWER_SUPPLY_USB_TYPE_DCP) |
484 BIT(POWER_SUPPLY_USB_TYPE_PD_DRP) |
485 BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN),
486 .properties = mp2629_charger_usb_props,
487 .num_properties = ARRAY_SIZE(mp2629_charger_usb_props),
488 .get_property = mp2629_charger_usb_get_prop,
489 .set_property = mp2629_charger_usb_set_prop,
490 .property_is_writeable = mp2629_charger_usb_prop_writeable,
491 };
492
493 static const struct power_supply_desc mp2629_battery_desc = {
494 .name = "mp2629_battery",
495 .type = POWER_SUPPLY_TYPE_BATTERY,
496 .properties = mp2629_charger_bat_props,
497 .num_properties = ARRAY_SIZE(mp2629_charger_bat_props),
498 .get_property = mp2629_charger_battery_get_prop,
499 .set_property = mp2629_charger_battery_set_prop,
500 .property_is_writeable = mp2629_charger_battery_prop_writeable,
501 };
502
batt_impedance_compensation_show(struct device * dev,struct device_attribute * attr,char * buf)503 static ssize_t batt_impedance_compensation_show(struct device *dev,
504 struct device_attribute *attr,
505 char *buf)
506 {
507 struct mp2629_charger *charger = dev_get_drvdata(dev->parent);
508 unsigned int rval;
509 int ret;
510
511 ret = regmap_read(charger->regmap, MP2629_REG_IMPEDANCE_COMP, &rval);
512 if (ret)
513 return ret;
514
515 rval = (rval >> 4) * 10;
516 return sysfs_emit(buf, "%d mohm\n", rval);
517 }
518
batt_impedance_compensation_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)519 static ssize_t batt_impedance_compensation_store(struct device *dev,
520 struct device_attribute *attr,
521 const char *buf,
522 size_t count)
523 {
524 struct mp2629_charger *charger = dev_get_drvdata(dev->parent);
525 unsigned int val;
526 int ret;
527
528 ret = kstrtouint(buf, 10, &val);
529 if (ret)
530 return ret;
531
532 if (val > 140)
533 return -ERANGE;
534
535 /* multiples of 10 mohm so round off */
536 val = val / 10;
537 ret = regmap_update_bits(charger->regmap, MP2629_REG_IMPEDANCE_COMP,
538 MP2629_MASK_IMPEDANCE, val << 4);
539 if (ret)
540 return ret;
541
542 return count;
543 }
544
545 static DEVICE_ATTR_RW(batt_impedance_compensation);
546
547 static struct attribute *mp2629_charger_sysfs_attrs[] = {
548 &dev_attr_batt_impedance_compensation.attr,
549 NULL
550 };
551 ATTRIBUTE_GROUPS(mp2629_charger_sysfs);
552
mp2629_charger_disable(void * data)553 static void mp2629_charger_disable(void *data)
554 {
555 struct mp2629_charger *charger = data;
556
557 regmap_update_bits(charger->regmap, MP2629_REG_CHARGE_CTRL,
558 MP2629_MASK_CHARGE_CTRL, 0);
559 }
560
mp2629_charger_probe(struct platform_device * pdev)561 static int mp2629_charger_probe(struct platform_device *pdev)
562 {
563 struct device *dev = &pdev->dev;
564 struct mp2629_data *ddata = dev_get_drvdata(dev->parent);
565 struct mp2629_charger *charger;
566 struct power_supply_config psy_cfg = {};
567 int ret, i, irq;
568
569 charger = devm_kzalloc(dev, sizeof(*charger), GFP_KERNEL);
570 if (!charger)
571 return -ENOMEM;
572
573 charger->regmap = ddata->regmap;
574 charger->dev = dev;
575 platform_set_drvdata(pdev, charger);
576
577 irq = platform_get_irq(to_platform_device(dev->parent), 0);
578 if (irq < 0)
579 return irq;
580
581 for (i = 0; i < MP2629_MAX_FIELD; i++) {
582 charger->regmap_fields[i] = devm_regmap_field_alloc(dev,
583 charger->regmap, mp2629_reg_fields[i]);
584 if (IS_ERR(charger->regmap_fields[i])) {
585 dev_err(dev, "regmap field alloc fail %d\n", i);
586 return PTR_ERR(charger->regmap_fields[i]);
587 }
588 }
589
590 for (i = 0; i < MP2629_ADC_CHAN_END; i++) {
591 charger->iiochan[i] = devm_iio_channel_get(dev,
592 adc_chan_name[i]);
593 if (IS_ERR(charger->iiochan[i])) {
594 dev_err(dev, "iio chan get %s err\n", adc_chan_name[i]);
595 return PTR_ERR(charger->iiochan[i]);
596 }
597 }
598
599 ret = devm_add_action_or_reset(dev, mp2629_charger_disable, charger);
600 if (ret)
601 return ret;
602
603 charger->usb = devm_power_supply_register(dev, &mp2629_usb_desc, NULL);
604 if (IS_ERR(charger->usb)) {
605 dev_err(dev, "power supply register usb failed\n");
606 return PTR_ERR(charger->usb);
607 }
608
609 psy_cfg.drv_data = charger;
610 psy_cfg.attr_grp = mp2629_charger_sysfs_groups;
611 charger->battery = devm_power_supply_register(dev,
612 &mp2629_battery_desc, &psy_cfg);
613 if (IS_ERR(charger->battery)) {
614 dev_err(dev, "power supply register battery failed\n");
615 return PTR_ERR(charger->battery);
616 }
617
618 ret = regmap_update_bits(charger->regmap, MP2629_REG_CHARGE_CTRL,
619 MP2629_MASK_CHARGE_CTRL, BIT(4));
620 if (ret) {
621 dev_err(dev, "enable charge fail: %d\n", ret);
622 return ret;
623 }
624
625 regmap_update_bits(charger->regmap, MP2629_REG_TIMER_CTRL,
626 MP2629_MASK_WDOG_CTRL, 0);
627
628 mutex_init(&charger->lock);
629
630 ret = devm_request_threaded_irq(dev, irq, NULL, mp2629_irq_handler,
631 IRQF_ONESHOT | IRQF_TRIGGER_RISING,
632 "mp2629-charger", charger);
633 if (ret)
634 return ret;
635
636 regmap_update_bits(charger->regmap, MP2629_REG_INTERRUPT,
637 GENMASK(6, 5), BIT(6) | BIT(5));
638
639 return 0;
640 }
641
642 static const struct of_device_id mp2629_charger_of_match[] = {
643 { .compatible = "mps,mp2629_charger"},
644 {}
645 };
646 MODULE_DEVICE_TABLE(of, mp2629_charger_of_match);
647
648 static struct platform_driver mp2629_charger_driver = {
649 .driver = {
650 .name = "mp2629_charger",
651 .of_match_table = mp2629_charger_of_match,
652 },
653 .probe = mp2629_charger_probe,
654 };
655 module_platform_driver(mp2629_charger_driver);
656
657 MODULE_AUTHOR("Saravanan Sekar <sravanhome@gmail.com>");
658 MODULE_DESCRIPTION("MP2629 Charger driver");
659 MODULE_LICENSE("GPL");
660 MODULE_IMPORT_NS("IIO_CONSUMER");
661