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