cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mp2629_charger.c (17320B)


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