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