13bc6d790SSaravanan Sekar // SPDX-License-Identifier: GPL-2.0-or-later
23bc6d790SSaravanan Sekar /*
33bc6d790SSaravanan Sekar * MP2629 battery charger driver
43bc6d790SSaravanan Sekar *
53bc6d790SSaravanan Sekar * Copyright 2020 Monolithic Power Systems, Inc
63bc6d790SSaravanan Sekar *
73bc6d790SSaravanan Sekar * Author: Saravanan Sekar <sravanhome@gmail.com>
83bc6d790SSaravanan Sekar */
93bc6d790SSaravanan Sekar
103bc6d790SSaravanan Sekar #include <linux/bits.h>
113bc6d790SSaravanan Sekar #include <linux/iio/consumer.h>
123bc6d790SSaravanan Sekar #include <linux/iio/types.h>
133bc6d790SSaravanan Sekar #include <linux/interrupt.h>
143bc6d790SSaravanan Sekar #include <linux/mfd/mp2629.h>
153bc6d790SSaravanan Sekar #include <linux/module.h>
163bc6d790SSaravanan Sekar #include <linux/mod_devicetable.h>
173bc6d790SSaravanan Sekar #include <linux/platform_device.h>
183bc6d790SSaravanan Sekar #include <linux/power_supply.h>
193bc6d790SSaravanan Sekar #include <linux/regmap.h>
203bc6d790SSaravanan Sekar
213bc6d790SSaravanan Sekar #define MP2629_REG_INPUT_ILIM 0x00
223bc6d790SSaravanan Sekar #define MP2629_REG_INPUT_VLIM 0x01
233bc6d790SSaravanan Sekar #define MP2629_REG_CHARGE_CTRL 0x04
243bc6d790SSaravanan Sekar #define MP2629_REG_CHARGE_ILIM 0x05
253bc6d790SSaravanan Sekar #define MP2629_REG_PRECHARGE 0x06
263bc6d790SSaravanan Sekar #define MP2629_REG_TERM_CURRENT 0x06
273bc6d790SSaravanan Sekar #define MP2629_REG_CHARGE_VLIM 0x07
283bc6d790SSaravanan Sekar #define MP2629_REG_TIMER_CTRL 0x08
293bc6d790SSaravanan Sekar #define MP2629_REG_IMPEDANCE_COMP 0x09
303bc6d790SSaravanan Sekar #define MP2629_REG_INTERRUPT 0x0b
313bc6d790SSaravanan Sekar #define MP2629_REG_STATUS 0x0c
323bc6d790SSaravanan Sekar #define MP2629_REG_FAULT 0x0d
333bc6d790SSaravanan Sekar
343bc6d790SSaravanan Sekar #define MP2629_MASK_INPUT_TYPE GENMASK(7, 5)
353bc6d790SSaravanan Sekar #define MP2629_MASK_CHARGE_TYPE GENMASK(4, 3)
363bc6d790SSaravanan Sekar #define MP2629_MASK_CHARGE_CTRL GENMASK(5, 4)
373bc6d790SSaravanan Sekar #define MP2629_MASK_WDOG_CTRL GENMASK(5, 4)
383bc6d790SSaravanan Sekar #define MP2629_MASK_IMPEDANCE GENMASK(7, 4)
393bc6d790SSaravanan Sekar
403bc6d790SSaravanan Sekar #define MP2629_INPUTSOURCE_CHANGE GENMASK(7, 5)
413bc6d790SSaravanan Sekar #define MP2629_CHARGING_CHANGE GENMASK(4, 3)
423bc6d790SSaravanan Sekar #define MP2629_FAULT_BATTERY BIT(3)
433bc6d790SSaravanan Sekar #define MP2629_FAULT_THERMAL BIT(4)
443bc6d790SSaravanan Sekar #define MP2629_FAULT_INPUT BIT(5)
453bc6d790SSaravanan Sekar #define MP2629_FAULT_OTG BIT(6)
463bc6d790SSaravanan Sekar
473bc6d790SSaravanan Sekar #define MP2629_MAX_BATT_CAPACITY 100
483bc6d790SSaravanan Sekar
493bc6d790SSaravanan Sekar #define MP2629_PROPS(_idx, _min, _max, _step) \
503bc6d790SSaravanan Sekar [_idx] = { \
513bc6d790SSaravanan Sekar .min = _min, \
523bc6d790SSaravanan Sekar .max = _max, \
533bc6d790SSaravanan Sekar .step = _step, \
543bc6d790SSaravanan Sekar }
553bc6d790SSaravanan Sekar
563bc6d790SSaravanan Sekar enum mp2629_source_type {
573bc6d790SSaravanan Sekar MP2629_SOURCE_TYPE_NO_INPUT,
583bc6d790SSaravanan Sekar MP2629_SOURCE_TYPE_NON_STD,
593bc6d790SSaravanan Sekar MP2629_SOURCE_TYPE_SDP,
603bc6d790SSaravanan Sekar MP2629_SOURCE_TYPE_CDP,
613bc6d790SSaravanan Sekar MP2629_SOURCE_TYPE_DCP,
623bc6d790SSaravanan Sekar MP2629_SOURCE_TYPE_OTG = 7,
633bc6d790SSaravanan Sekar };
643bc6d790SSaravanan Sekar
653bc6d790SSaravanan Sekar enum mp2629_field {
663bc6d790SSaravanan Sekar INPUT_ILIM,
673bc6d790SSaravanan Sekar INPUT_VLIM,
683bc6d790SSaravanan Sekar CHARGE_ILIM,
693bc6d790SSaravanan Sekar CHARGE_VLIM,
703bc6d790SSaravanan Sekar PRECHARGE,
713bc6d790SSaravanan Sekar TERM_CURRENT,
723bc6d790SSaravanan Sekar MP2629_MAX_FIELD
733bc6d790SSaravanan Sekar };
743bc6d790SSaravanan Sekar
753bc6d790SSaravanan Sekar struct mp2629_charger {
763bc6d790SSaravanan Sekar struct device *dev;
773bc6d790SSaravanan Sekar int status;
783bc6d790SSaravanan Sekar int fault;
793bc6d790SSaravanan Sekar
803bc6d790SSaravanan Sekar struct regmap *regmap;
813bc6d790SSaravanan Sekar struct regmap_field *regmap_fields[MP2629_MAX_FIELD];
823bc6d790SSaravanan Sekar struct mutex lock;
833bc6d790SSaravanan Sekar struct power_supply *usb;
843bc6d790SSaravanan Sekar struct power_supply *battery;
853bc6d790SSaravanan Sekar struct iio_channel *iiochan[MP2629_ADC_CHAN_END];
863bc6d790SSaravanan Sekar };
873bc6d790SSaravanan Sekar
883bc6d790SSaravanan Sekar struct mp2629_prop {
893bc6d790SSaravanan Sekar int reg;
903bc6d790SSaravanan Sekar int mask;
913bc6d790SSaravanan Sekar int min;
923bc6d790SSaravanan Sekar int max;
933bc6d790SSaravanan Sekar int step;
943bc6d790SSaravanan Sekar int shift;
953bc6d790SSaravanan Sekar };
963bc6d790SSaravanan Sekar
973bc6d790SSaravanan Sekar static enum power_supply_usb_type mp2629_usb_types[] = {
983bc6d790SSaravanan Sekar POWER_SUPPLY_USB_TYPE_SDP,
993bc6d790SSaravanan Sekar POWER_SUPPLY_USB_TYPE_DCP,
1003bc6d790SSaravanan Sekar POWER_SUPPLY_USB_TYPE_CDP,
1013bc6d790SSaravanan Sekar POWER_SUPPLY_USB_TYPE_PD_DRP,
1023bc6d790SSaravanan Sekar POWER_SUPPLY_USB_TYPE_UNKNOWN
1033bc6d790SSaravanan Sekar };
1043bc6d790SSaravanan Sekar
1053bc6d790SSaravanan Sekar static enum power_supply_property mp2629_charger_usb_props[] = {
1063bc6d790SSaravanan Sekar POWER_SUPPLY_PROP_ONLINE,
1073bc6d790SSaravanan Sekar POWER_SUPPLY_PROP_USB_TYPE,
1083bc6d790SSaravanan Sekar POWER_SUPPLY_PROP_VOLTAGE_NOW,
1093bc6d790SSaravanan Sekar POWER_SUPPLY_PROP_CURRENT_NOW,
1103bc6d790SSaravanan Sekar POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
1113bc6d790SSaravanan Sekar POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT,
1123bc6d790SSaravanan Sekar };
1133bc6d790SSaravanan Sekar
1143bc6d790SSaravanan Sekar static enum power_supply_property mp2629_charger_bat_props[] = {
1153bc6d790SSaravanan Sekar POWER_SUPPLY_PROP_STATUS,
1163bc6d790SSaravanan Sekar POWER_SUPPLY_PROP_HEALTH,
1173bc6d790SSaravanan Sekar POWER_SUPPLY_PROP_CHARGE_TYPE,
1183bc6d790SSaravanan Sekar POWER_SUPPLY_PROP_VOLTAGE_NOW,
1193bc6d790SSaravanan Sekar POWER_SUPPLY_PROP_CURRENT_NOW,
1203bc6d790SSaravanan Sekar POWER_SUPPLY_PROP_CAPACITY,
1213bc6d790SSaravanan Sekar POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
1223bc6d790SSaravanan Sekar POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
1233bc6d790SSaravanan Sekar POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
1243bc6d790SSaravanan Sekar POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
1253bc6d790SSaravanan Sekar POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
1263bc6d790SSaravanan Sekar POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
1273bc6d790SSaravanan Sekar };
1283bc6d790SSaravanan Sekar
1293bc6d790SSaravanan Sekar static struct mp2629_prop props[] = {
1303bc6d790SSaravanan Sekar MP2629_PROPS(INPUT_ILIM, 100000, 3250000, 50000),
1313bc6d790SSaravanan Sekar MP2629_PROPS(INPUT_VLIM, 3800000, 5300000, 100000),
1323bc6d790SSaravanan Sekar MP2629_PROPS(CHARGE_ILIM, 320000, 4520000, 40000),
1333bc6d790SSaravanan Sekar MP2629_PROPS(CHARGE_VLIM, 3400000, 4670000, 10000),
1343bc6d790SSaravanan Sekar MP2629_PROPS(PRECHARGE, 120000, 720000, 40000),
1353bc6d790SSaravanan Sekar MP2629_PROPS(TERM_CURRENT, 80000, 680000, 40000),
1363bc6d790SSaravanan Sekar };
1373bc6d790SSaravanan Sekar
1383bc6d790SSaravanan Sekar static const struct reg_field mp2629_reg_fields[] = {
1393bc6d790SSaravanan Sekar [INPUT_ILIM] = REG_FIELD(MP2629_REG_INPUT_ILIM, 0, 5),
1403bc6d790SSaravanan Sekar [INPUT_VLIM] = REG_FIELD(MP2629_REG_INPUT_VLIM, 0, 3),
1413bc6d790SSaravanan Sekar [CHARGE_ILIM] = REG_FIELD(MP2629_REG_CHARGE_ILIM, 0, 6),
1423bc6d790SSaravanan Sekar [CHARGE_VLIM] = REG_FIELD(MP2629_REG_CHARGE_VLIM, 1, 7),
1433bc6d790SSaravanan Sekar [PRECHARGE] = REG_FIELD(MP2629_REG_PRECHARGE, 4, 7),
1443bc6d790SSaravanan Sekar [TERM_CURRENT] = REG_FIELD(MP2629_REG_TERM_CURRENT, 0, 3),
1453bc6d790SSaravanan Sekar };
1463bc6d790SSaravanan Sekar
1473bc6d790SSaravanan Sekar static char *adc_chan_name[] = {
1483bc6d790SSaravanan Sekar "mp2629-batt-volt",
1493bc6d790SSaravanan Sekar "mp2629-system-volt",
1503bc6d790SSaravanan Sekar "mp2629-input-volt",
1513bc6d790SSaravanan Sekar "mp2629-batt-current",
1523bc6d790SSaravanan Sekar "mp2629-input-current",
1533bc6d790SSaravanan Sekar };
1543bc6d790SSaravanan Sekar
mp2629_read_adc(struct mp2629_charger * charger,enum mp2629_adc_chan ch,union power_supply_propval * val)1553bc6d790SSaravanan Sekar static int mp2629_read_adc(struct mp2629_charger *charger,
1563bc6d790SSaravanan Sekar enum mp2629_adc_chan ch,
1573bc6d790SSaravanan Sekar union power_supply_propval *val)
1583bc6d790SSaravanan Sekar {
1593bc6d790SSaravanan Sekar int ret;
1603bc6d790SSaravanan Sekar int chval;
1613bc6d790SSaravanan Sekar
1623bc6d790SSaravanan Sekar ret = iio_read_channel_processed(charger->iiochan[ch], &chval);
1633bc6d790SSaravanan Sekar if (ret)
1643bc6d790SSaravanan Sekar return ret;
1653bc6d790SSaravanan Sekar
1663bc6d790SSaravanan Sekar val->intval = chval * 1000;
1673bc6d790SSaravanan Sekar
1683bc6d790SSaravanan Sekar return 0;
1693bc6d790SSaravanan Sekar }
1703bc6d790SSaravanan Sekar
mp2629_get_prop(struct mp2629_charger * charger,enum mp2629_field fld,union power_supply_propval * val)1713bc6d790SSaravanan Sekar static int mp2629_get_prop(struct mp2629_charger *charger,
1723bc6d790SSaravanan Sekar enum mp2629_field fld,
1733bc6d790SSaravanan Sekar union power_supply_propval *val)
1743bc6d790SSaravanan Sekar {
1753bc6d790SSaravanan Sekar int ret;
1763bc6d790SSaravanan Sekar unsigned int rval;
1773bc6d790SSaravanan Sekar
1783bc6d790SSaravanan Sekar ret = regmap_field_read(charger->regmap_fields[fld], &rval);
1793bc6d790SSaravanan Sekar if (ret)
1803bc6d790SSaravanan Sekar return ret;
1813bc6d790SSaravanan Sekar
1823bc6d790SSaravanan Sekar val->intval = rval * props[fld].step + props[fld].min;
1833bc6d790SSaravanan Sekar
1843bc6d790SSaravanan Sekar return 0;
1853bc6d790SSaravanan Sekar }
1863bc6d790SSaravanan Sekar
mp2629_set_prop(struct mp2629_charger * charger,enum mp2629_field fld,const union power_supply_propval * val)1873bc6d790SSaravanan Sekar static int mp2629_set_prop(struct mp2629_charger *charger,
1883bc6d790SSaravanan Sekar enum mp2629_field fld,
1893bc6d790SSaravanan Sekar const union power_supply_propval *val)
1903bc6d790SSaravanan Sekar {
1913bc6d790SSaravanan Sekar unsigned int rval;
1923bc6d790SSaravanan Sekar
1933bc6d790SSaravanan Sekar if (val->intval < props[fld].min || val->intval > props[fld].max)
1943bc6d790SSaravanan Sekar return -EINVAL;
1953bc6d790SSaravanan Sekar
1963bc6d790SSaravanan Sekar rval = (val->intval - props[fld].min) / props[fld].step;
1973bc6d790SSaravanan Sekar return regmap_field_write(charger->regmap_fields[fld], rval);
1983bc6d790SSaravanan Sekar }
1993bc6d790SSaravanan Sekar
mp2629_get_battery_capacity(struct mp2629_charger * charger,union power_supply_propval * val)2003bc6d790SSaravanan Sekar static int mp2629_get_battery_capacity(struct mp2629_charger *charger,
2013bc6d790SSaravanan Sekar union power_supply_propval *val)
2023bc6d790SSaravanan Sekar {
2033bc6d790SSaravanan Sekar union power_supply_propval vnow, vlim;
2043bc6d790SSaravanan Sekar int ret;
2053bc6d790SSaravanan Sekar
2063bc6d790SSaravanan Sekar ret = mp2629_read_adc(charger, MP2629_BATT_VOLT, &vnow);
2073bc6d790SSaravanan Sekar if (ret)
2083bc6d790SSaravanan Sekar return ret;
2093bc6d790SSaravanan Sekar
2103bc6d790SSaravanan Sekar ret = mp2629_get_prop(charger, CHARGE_VLIM, &vlim);
2113bc6d790SSaravanan Sekar if (ret)
2123bc6d790SSaravanan Sekar return ret;
2133bc6d790SSaravanan Sekar
2143bc6d790SSaravanan Sekar val->intval = (vnow.intval * 100) / vlim.intval;
2153bc6d790SSaravanan Sekar val->intval = min(val->intval, MP2629_MAX_BATT_CAPACITY);
2163bc6d790SSaravanan Sekar
2173bc6d790SSaravanan Sekar return 0;
2183bc6d790SSaravanan Sekar }
2193bc6d790SSaravanan Sekar
mp2629_charger_battery_get_prop(struct power_supply * psy,enum power_supply_property psp,union power_supply_propval * val)2203bc6d790SSaravanan Sekar static int mp2629_charger_battery_get_prop(struct power_supply *psy,
2213bc6d790SSaravanan Sekar enum power_supply_property psp,
2223bc6d790SSaravanan Sekar union power_supply_propval *val)
2233bc6d790SSaravanan Sekar {
2243bc6d790SSaravanan Sekar struct mp2629_charger *charger = dev_get_drvdata(psy->dev.parent);
2253bc6d790SSaravanan Sekar unsigned int rval;
2263bc6d790SSaravanan Sekar int ret = 0;
2273bc6d790SSaravanan Sekar
2283bc6d790SSaravanan Sekar switch (psp) {
2293bc6d790SSaravanan Sekar case POWER_SUPPLY_PROP_VOLTAGE_NOW:
2303bc6d790SSaravanan Sekar ret = mp2629_read_adc(charger, MP2629_BATT_VOLT, val);
2313bc6d790SSaravanan Sekar break;
2323bc6d790SSaravanan Sekar
2333bc6d790SSaravanan Sekar case POWER_SUPPLY_PROP_CURRENT_NOW:
2343bc6d790SSaravanan Sekar ret = mp2629_read_adc(charger, MP2629_BATT_CURRENT, val);
2353bc6d790SSaravanan Sekar break;
2363bc6d790SSaravanan Sekar
2373bc6d790SSaravanan Sekar case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
2383bc6d790SSaravanan Sekar val->intval = 4520000;
2393bc6d790SSaravanan Sekar break;
2403bc6d790SSaravanan Sekar
2413bc6d790SSaravanan Sekar case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
2423bc6d790SSaravanan Sekar val->intval = 4670000;
2433bc6d790SSaravanan Sekar break;
2443bc6d790SSaravanan Sekar
2453bc6d790SSaravanan Sekar case POWER_SUPPLY_PROP_CAPACITY:
2463bc6d790SSaravanan Sekar ret = mp2629_get_battery_capacity(charger, val);
2473bc6d790SSaravanan Sekar break;
2483bc6d790SSaravanan Sekar
2493bc6d790SSaravanan Sekar case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
2503bc6d790SSaravanan Sekar ret = mp2629_get_prop(charger, TERM_CURRENT, val);
2513bc6d790SSaravanan Sekar break;
2523bc6d790SSaravanan Sekar
2533bc6d790SSaravanan Sekar case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
2543bc6d790SSaravanan Sekar ret = mp2629_get_prop(charger, PRECHARGE, val);
2553bc6d790SSaravanan Sekar break;
2563bc6d790SSaravanan Sekar
2573bc6d790SSaravanan Sekar case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
2583bc6d790SSaravanan Sekar ret = mp2629_get_prop(charger, CHARGE_VLIM, val);
2593bc6d790SSaravanan Sekar break;
2603bc6d790SSaravanan Sekar
2613bc6d790SSaravanan Sekar case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
2623bc6d790SSaravanan Sekar ret = mp2629_get_prop(charger, CHARGE_ILIM, val);
2633bc6d790SSaravanan Sekar break;
2643bc6d790SSaravanan Sekar
2653bc6d790SSaravanan Sekar case POWER_SUPPLY_PROP_HEALTH:
2663bc6d790SSaravanan Sekar if (!charger->fault)
2673bc6d790SSaravanan Sekar val->intval = POWER_SUPPLY_HEALTH_GOOD;
2683bc6d790SSaravanan Sekar if (MP2629_FAULT_BATTERY & charger->fault)
2693bc6d790SSaravanan Sekar val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
2703bc6d790SSaravanan Sekar else if (MP2629_FAULT_THERMAL & charger->fault)
2713bc6d790SSaravanan Sekar val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
2723bc6d790SSaravanan Sekar else if (MP2629_FAULT_INPUT & charger->fault)
2733bc6d790SSaravanan Sekar val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
2743bc6d790SSaravanan Sekar break;
2753bc6d790SSaravanan Sekar
2763bc6d790SSaravanan Sekar case POWER_SUPPLY_PROP_STATUS:
2773bc6d790SSaravanan Sekar ret = regmap_read(charger->regmap, MP2629_REG_STATUS, &rval);
2783bc6d790SSaravanan Sekar if (ret)
2793bc6d790SSaravanan Sekar break;
2803bc6d790SSaravanan Sekar
2813bc6d790SSaravanan Sekar rval = (rval & MP2629_MASK_CHARGE_TYPE) >> 3;
2823bc6d790SSaravanan Sekar switch (rval) {
2833bc6d790SSaravanan Sekar case 0x00:
2843bc6d790SSaravanan Sekar val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
2853bc6d790SSaravanan Sekar break;
2863bc6d790SSaravanan Sekar case 0x01:
2873bc6d790SSaravanan Sekar case 0x10:
2883bc6d790SSaravanan Sekar val->intval = POWER_SUPPLY_STATUS_CHARGING;
2893bc6d790SSaravanan Sekar break;
2903bc6d790SSaravanan Sekar case 0x11:
2913bc6d790SSaravanan Sekar val->intval = POWER_SUPPLY_STATUS_FULL;
2923bc6d790SSaravanan Sekar }
2933bc6d790SSaravanan Sekar break;
2943bc6d790SSaravanan Sekar
2953bc6d790SSaravanan Sekar case POWER_SUPPLY_PROP_CHARGE_TYPE:
2963bc6d790SSaravanan Sekar ret = regmap_read(charger->regmap, MP2629_REG_STATUS, &rval);
2973bc6d790SSaravanan Sekar if (ret)
2983bc6d790SSaravanan Sekar break;
2993bc6d790SSaravanan Sekar
3003bc6d790SSaravanan Sekar rval = (rval & MP2629_MASK_CHARGE_TYPE) >> 3;
3013bc6d790SSaravanan Sekar switch (rval) {
3023bc6d790SSaravanan Sekar case 0x00:
3033bc6d790SSaravanan Sekar val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
3043bc6d790SSaravanan Sekar break;
3053bc6d790SSaravanan Sekar case 0x01:
3063bc6d790SSaravanan Sekar val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
3073bc6d790SSaravanan Sekar break;
3083bc6d790SSaravanan Sekar case 0x10:
3093bc6d790SSaravanan Sekar val->intval = POWER_SUPPLY_CHARGE_TYPE_STANDARD;
3103bc6d790SSaravanan Sekar break;
3113bc6d790SSaravanan Sekar default:
3123bc6d790SSaravanan Sekar val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
3133bc6d790SSaravanan Sekar }
3143bc6d790SSaravanan Sekar break;
3153bc6d790SSaravanan Sekar
3163bc6d790SSaravanan Sekar default:
3173bc6d790SSaravanan Sekar return -EINVAL;
3183bc6d790SSaravanan Sekar }
3193bc6d790SSaravanan Sekar
3203bc6d790SSaravanan Sekar return ret;
3213bc6d790SSaravanan Sekar }
3223bc6d790SSaravanan Sekar
mp2629_charger_battery_set_prop(struct power_supply * psy,enum power_supply_property psp,const union power_supply_propval * val)3233bc6d790SSaravanan Sekar static int mp2629_charger_battery_set_prop(struct power_supply *psy,
3243bc6d790SSaravanan Sekar enum power_supply_property psp,
3253bc6d790SSaravanan Sekar const union power_supply_propval *val)
3263bc6d790SSaravanan Sekar {
3273bc6d790SSaravanan Sekar struct mp2629_charger *charger = dev_get_drvdata(psy->dev.parent);
3283bc6d790SSaravanan Sekar
3293bc6d790SSaravanan Sekar switch (psp) {
3303bc6d790SSaravanan Sekar case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
3313bc6d790SSaravanan Sekar return mp2629_set_prop(charger, TERM_CURRENT, val);
3323bc6d790SSaravanan Sekar
3333bc6d790SSaravanan Sekar case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
3343bc6d790SSaravanan Sekar return mp2629_set_prop(charger, PRECHARGE, val);
3353bc6d790SSaravanan Sekar
3363bc6d790SSaravanan Sekar case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
3373bc6d790SSaravanan Sekar return mp2629_set_prop(charger, CHARGE_VLIM, val);
3383bc6d790SSaravanan Sekar
3393bc6d790SSaravanan Sekar case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
3403bc6d790SSaravanan Sekar return mp2629_set_prop(charger, CHARGE_ILIM, val);
3413bc6d790SSaravanan Sekar
3423bc6d790SSaravanan Sekar default:
3433bc6d790SSaravanan Sekar return -EINVAL;
3443bc6d790SSaravanan Sekar }
3453bc6d790SSaravanan Sekar }
3463bc6d790SSaravanan Sekar
mp2629_charger_usb_get_prop(struct power_supply * psy,enum power_supply_property psp,union power_supply_propval * val)3473bc6d790SSaravanan Sekar static int mp2629_charger_usb_get_prop(struct power_supply *psy,
3483bc6d790SSaravanan Sekar enum power_supply_property psp,
3493bc6d790SSaravanan Sekar union power_supply_propval *val)
3503bc6d790SSaravanan Sekar {
3513bc6d790SSaravanan Sekar struct mp2629_charger *charger = dev_get_drvdata(psy->dev.parent);
3523bc6d790SSaravanan Sekar unsigned int rval;
3533bc6d790SSaravanan Sekar int ret;
3543bc6d790SSaravanan Sekar
3553bc6d790SSaravanan Sekar switch (psp) {
3563bc6d790SSaravanan Sekar case POWER_SUPPLY_PROP_ONLINE:
3573bc6d790SSaravanan Sekar ret = regmap_read(charger->regmap, MP2629_REG_STATUS, &rval);
3583bc6d790SSaravanan Sekar if (ret)
3593bc6d790SSaravanan Sekar break;
3603bc6d790SSaravanan Sekar
3613bc6d790SSaravanan Sekar val->intval = !!(rval & MP2629_MASK_INPUT_TYPE);
3623bc6d790SSaravanan Sekar break;
3633bc6d790SSaravanan Sekar
3643bc6d790SSaravanan Sekar case POWER_SUPPLY_PROP_USB_TYPE:
3653bc6d790SSaravanan Sekar ret = regmap_read(charger->regmap, MP2629_REG_STATUS, &rval);
3663bc6d790SSaravanan Sekar if (ret)
3673bc6d790SSaravanan Sekar break;
3683bc6d790SSaravanan Sekar
3693bc6d790SSaravanan Sekar rval = (rval & MP2629_MASK_INPUT_TYPE) >> 5;
3703bc6d790SSaravanan Sekar switch (rval) {
3713bc6d790SSaravanan Sekar case MP2629_SOURCE_TYPE_SDP:
3723bc6d790SSaravanan Sekar val->intval = POWER_SUPPLY_USB_TYPE_SDP;
3733bc6d790SSaravanan Sekar break;
3743bc6d790SSaravanan Sekar case MP2629_SOURCE_TYPE_CDP:
3753bc6d790SSaravanan Sekar val->intval = POWER_SUPPLY_USB_TYPE_CDP;
3763bc6d790SSaravanan Sekar break;
3773bc6d790SSaravanan Sekar case MP2629_SOURCE_TYPE_DCP:
3783bc6d790SSaravanan Sekar val->intval = POWER_SUPPLY_USB_TYPE_DCP;
3793bc6d790SSaravanan Sekar break;
3803bc6d790SSaravanan Sekar case MP2629_SOURCE_TYPE_OTG:
3813bc6d790SSaravanan Sekar val->intval = POWER_SUPPLY_USB_TYPE_PD_DRP;
3823bc6d790SSaravanan Sekar break;
3833bc6d790SSaravanan Sekar default:
3843bc6d790SSaravanan Sekar val->intval = POWER_SUPPLY_USB_TYPE_UNKNOWN;
3853bc6d790SSaravanan Sekar break;
3863bc6d790SSaravanan Sekar }
3873bc6d790SSaravanan Sekar break;
3883bc6d790SSaravanan Sekar
3893bc6d790SSaravanan Sekar case POWER_SUPPLY_PROP_VOLTAGE_NOW:
3903bc6d790SSaravanan Sekar ret = mp2629_read_adc(charger, MP2629_INPUT_VOLT, val);
3913bc6d790SSaravanan Sekar break;
3923bc6d790SSaravanan Sekar
3933bc6d790SSaravanan Sekar case POWER_SUPPLY_PROP_CURRENT_NOW:
3943bc6d790SSaravanan Sekar ret = mp2629_read_adc(charger, MP2629_INPUT_CURRENT, val);
3953bc6d790SSaravanan Sekar break;
3963bc6d790SSaravanan Sekar
3973bc6d790SSaravanan Sekar case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
3983bc6d790SSaravanan Sekar ret = mp2629_get_prop(charger, INPUT_VLIM, val);
3993bc6d790SSaravanan Sekar break;
4003bc6d790SSaravanan Sekar
4013bc6d790SSaravanan Sekar case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
4023bc6d790SSaravanan Sekar ret = mp2629_get_prop(charger, INPUT_ILIM, val);
4033bc6d790SSaravanan Sekar break;
4043bc6d790SSaravanan Sekar
4053bc6d790SSaravanan Sekar default:
4063bc6d790SSaravanan Sekar return -EINVAL;
4073bc6d790SSaravanan Sekar }
4083bc6d790SSaravanan Sekar
4093bc6d790SSaravanan Sekar return ret;
4103bc6d790SSaravanan Sekar }
4113bc6d790SSaravanan Sekar
mp2629_charger_usb_set_prop(struct power_supply * psy,enum power_supply_property psp,const union power_supply_propval * val)4123bc6d790SSaravanan Sekar static int mp2629_charger_usb_set_prop(struct power_supply *psy,
4133bc6d790SSaravanan Sekar enum power_supply_property psp,
4143bc6d790SSaravanan Sekar const union power_supply_propval *val)
4153bc6d790SSaravanan Sekar {
4163bc6d790SSaravanan Sekar struct mp2629_charger *charger = dev_get_drvdata(psy->dev.parent);
4173bc6d790SSaravanan Sekar
4183bc6d790SSaravanan Sekar switch (psp) {
4193bc6d790SSaravanan Sekar case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
4203bc6d790SSaravanan Sekar return mp2629_set_prop(charger, INPUT_VLIM, val);
4213bc6d790SSaravanan Sekar
4223bc6d790SSaravanan Sekar case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
4233bc6d790SSaravanan Sekar return mp2629_set_prop(charger, INPUT_ILIM, val);
4243bc6d790SSaravanan Sekar
4253bc6d790SSaravanan Sekar default:
4263bc6d790SSaravanan Sekar return -EINVAL;
4273bc6d790SSaravanan Sekar }
4283bc6d790SSaravanan Sekar }
4293bc6d790SSaravanan Sekar
mp2629_charger_battery_prop_writeable(struct power_supply * psy,enum power_supply_property psp)4303bc6d790SSaravanan Sekar static int mp2629_charger_battery_prop_writeable(struct power_supply *psy,
4313bc6d790SSaravanan Sekar enum power_supply_property psp)
4323bc6d790SSaravanan Sekar {
4333bc6d790SSaravanan Sekar return (psp == POWER_SUPPLY_PROP_PRECHARGE_CURRENT) ||
4343bc6d790SSaravanan Sekar (psp == POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT) ||
4353bc6d790SSaravanan Sekar (psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT) ||
4363bc6d790SSaravanan Sekar (psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE);
4373bc6d790SSaravanan Sekar }
4383bc6d790SSaravanan Sekar
mp2629_charger_usb_prop_writeable(struct power_supply * psy,enum power_supply_property psp)4393bc6d790SSaravanan Sekar static int mp2629_charger_usb_prop_writeable(struct power_supply *psy,
4403bc6d790SSaravanan Sekar enum power_supply_property psp)
4413bc6d790SSaravanan Sekar {
4423bc6d790SSaravanan Sekar return (psp == POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT) ||
4433bc6d790SSaravanan Sekar (psp == POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT);
4443bc6d790SSaravanan Sekar }
4453bc6d790SSaravanan Sekar
mp2629_irq_handler(int irq,void * dev_id)4463bc6d790SSaravanan Sekar static irqreturn_t mp2629_irq_handler(int irq, void *dev_id)
4473bc6d790SSaravanan Sekar {
4483bc6d790SSaravanan Sekar struct mp2629_charger *charger = dev_id;
4493bc6d790SSaravanan Sekar unsigned int rval;
4503bc6d790SSaravanan Sekar int ret;
4513bc6d790SSaravanan Sekar
4523bc6d790SSaravanan Sekar mutex_lock(&charger->lock);
4533bc6d790SSaravanan Sekar
4543bc6d790SSaravanan Sekar ret = regmap_read(charger->regmap, MP2629_REG_FAULT, &rval);
4553bc6d790SSaravanan Sekar if (ret)
4563bc6d790SSaravanan Sekar goto unlock;
4573bc6d790SSaravanan Sekar
4583bc6d790SSaravanan Sekar if (rval) {
4593bc6d790SSaravanan Sekar charger->fault = rval;
4603bc6d790SSaravanan Sekar if (MP2629_FAULT_BATTERY & rval)
4613bc6d790SSaravanan Sekar dev_err(charger->dev, "Battery fault OVP\n");
4623bc6d790SSaravanan Sekar else if (MP2629_FAULT_THERMAL & rval)
4633bc6d790SSaravanan Sekar dev_err(charger->dev, "Thermal shutdown fault\n");
4643bc6d790SSaravanan Sekar else if (MP2629_FAULT_INPUT & rval)
4653bc6d790SSaravanan Sekar dev_err(charger->dev, "no input or input OVP\n");
4663bc6d790SSaravanan Sekar else if (MP2629_FAULT_OTG & rval)
4673bc6d790SSaravanan Sekar dev_err(charger->dev, "VIN overloaded\n");
4683bc6d790SSaravanan Sekar
4693bc6d790SSaravanan Sekar goto unlock;
4703bc6d790SSaravanan Sekar }
4713bc6d790SSaravanan Sekar
4723bc6d790SSaravanan Sekar ret = regmap_read(charger->regmap, MP2629_REG_STATUS, &rval);
4733bc6d790SSaravanan Sekar if (ret)
4743bc6d790SSaravanan Sekar goto unlock;
4753bc6d790SSaravanan Sekar
4763bc6d790SSaravanan Sekar if (rval & MP2629_INPUTSOURCE_CHANGE)
4773bc6d790SSaravanan Sekar power_supply_changed(charger->usb);
4783bc6d790SSaravanan Sekar else if (rval & MP2629_CHARGING_CHANGE)
4793bc6d790SSaravanan Sekar power_supply_changed(charger->battery);
4803bc6d790SSaravanan Sekar
4813bc6d790SSaravanan Sekar unlock:
4823bc6d790SSaravanan Sekar mutex_unlock(&charger->lock);
4833bc6d790SSaravanan Sekar
4843bc6d790SSaravanan Sekar return IRQ_HANDLED;
4853bc6d790SSaravanan Sekar }
4863bc6d790SSaravanan Sekar
4873bc6d790SSaravanan Sekar static const struct power_supply_desc mp2629_usb_desc = {
4883bc6d790SSaravanan Sekar .name = "mp2629_usb",
4893bc6d790SSaravanan Sekar .type = POWER_SUPPLY_TYPE_USB,
4903bc6d790SSaravanan Sekar .usb_types = mp2629_usb_types,
4913bc6d790SSaravanan Sekar .num_usb_types = ARRAY_SIZE(mp2629_usb_types),
4923bc6d790SSaravanan Sekar .properties = mp2629_charger_usb_props,
4933bc6d790SSaravanan Sekar .num_properties = ARRAY_SIZE(mp2629_charger_usb_props),
4943bc6d790SSaravanan Sekar .get_property = mp2629_charger_usb_get_prop,
4953bc6d790SSaravanan Sekar .set_property = mp2629_charger_usb_set_prop,
4963bc6d790SSaravanan Sekar .property_is_writeable = mp2629_charger_usb_prop_writeable,
4973bc6d790SSaravanan Sekar };
4983bc6d790SSaravanan Sekar
4993bc6d790SSaravanan Sekar static const struct power_supply_desc mp2629_battery_desc = {
5003bc6d790SSaravanan Sekar .name = "mp2629_battery",
5013bc6d790SSaravanan Sekar .type = POWER_SUPPLY_TYPE_BATTERY,
5023bc6d790SSaravanan Sekar .properties = mp2629_charger_bat_props,
5033bc6d790SSaravanan Sekar .num_properties = ARRAY_SIZE(mp2629_charger_bat_props),
5043bc6d790SSaravanan Sekar .get_property = mp2629_charger_battery_get_prop,
5053bc6d790SSaravanan Sekar .set_property = mp2629_charger_battery_set_prop,
5063bc6d790SSaravanan Sekar .property_is_writeable = mp2629_charger_battery_prop_writeable,
5073bc6d790SSaravanan Sekar };
5083bc6d790SSaravanan Sekar
batt_impedance_compensation_show(struct device * dev,struct device_attribute * attr,char * buf)5093bc6d790SSaravanan Sekar static ssize_t batt_impedance_compensation_show(struct device *dev,
5103bc6d790SSaravanan Sekar struct device_attribute *attr,
5113bc6d790SSaravanan Sekar char *buf)
5123bc6d790SSaravanan Sekar {
5133bc6d790SSaravanan Sekar struct mp2629_charger *charger = dev_get_drvdata(dev->parent);
5143bc6d790SSaravanan Sekar unsigned int rval;
5153bc6d790SSaravanan Sekar int ret;
5163bc6d790SSaravanan Sekar
5173bc6d790SSaravanan Sekar ret = regmap_read(charger->regmap, MP2629_REG_IMPEDANCE_COMP, &rval);
5183bc6d790SSaravanan Sekar if (ret)
5193bc6d790SSaravanan Sekar return ret;
5203bc6d790SSaravanan Sekar
5213bc6d790SSaravanan Sekar rval = (rval >> 4) * 10;
522*a441f3b9Sye xingchen return sysfs_emit(buf, "%d mohm\n", rval);
5233bc6d790SSaravanan Sekar }
5243bc6d790SSaravanan Sekar
batt_impedance_compensation_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)5253bc6d790SSaravanan Sekar static ssize_t batt_impedance_compensation_store(struct device *dev,
5263bc6d790SSaravanan Sekar struct device_attribute *attr,
5273bc6d790SSaravanan Sekar const char *buf,
5283bc6d790SSaravanan Sekar size_t count)
5293bc6d790SSaravanan Sekar {
5303bc6d790SSaravanan Sekar struct mp2629_charger *charger = dev_get_drvdata(dev->parent);
5313bc6d790SSaravanan Sekar unsigned int val;
5323bc6d790SSaravanan Sekar int ret;
5333bc6d790SSaravanan Sekar
5343bc6d790SSaravanan Sekar ret = kstrtouint(buf, 10, &val);
5353bc6d790SSaravanan Sekar if (ret)
5363bc6d790SSaravanan Sekar return ret;
5373bc6d790SSaravanan Sekar
5383bc6d790SSaravanan Sekar if (val > 140)
5393bc6d790SSaravanan Sekar return -ERANGE;
5403bc6d790SSaravanan Sekar
5413bc6d790SSaravanan Sekar /* multiples of 10 mohm so round off */
5423bc6d790SSaravanan Sekar val = val / 10;
5433bc6d790SSaravanan Sekar ret = regmap_update_bits(charger->regmap, MP2629_REG_IMPEDANCE_COMP,
5443bc6d790SSaravanan Sekar MP2629_MASK_IMPEDANCE, val << 4);
5453bc6d790SSaravanan Sekar if (ret)
5463bc6d790SSaravanan Sekar return ret;
5473bc6d790SSaravanan Sekar
5483bc6d790SSaravanan Sekar return count;
5493bc6d790SSaravanan Sekar }
5503bc6d790SSaravanan Sekar
5513bc6d790SSaravanan Sekar static DEVICE_ATTR_RW(batt_impedance_compensation);
5523bc6d790SSaravanan Sekar
5533bc6d790SSaravanan Sekar static struct attribute *mp2629_charger_sysfs_attrs[] = {
5543bc6d790SSaravanan Sekar &dev_attr_batt_impedance_compensation.attr,
5553bc6d790SSaravanan Sekar NULL
5563bc6d790SSaravanan Sekar };
5573bc6d790SSaravanan Sekar ATTRIBUTE_GROUPS(mp2629_charger_sysfs);
5583bc6d790SSaravanan Sekar
mp2629_charger_disable(void * data)5593bc6d790SSaravanan Sekar static void mp2629_charger_disable(void *data)
5603bc6d790SSaravanan Sekar {
5613bc6d790SSaravanan Sekar struct mp2629_charger *charger = data;
5623bc6d790SSaravanan Sekar
5633bc6d790SSaravanan Sekar regmap_update_bits(charger->regmap, MP2629_REG_CHARGE_CTRL,
5643bc6d790SSaravanan Sekar MP2629_MASK_CHARGE_CTRL, 0);
5653bc6d790SSaravanan Sekar }
5663bc6d790SSaravanan Sekar
mp2629_charger_probe(struct platform_device * pdev)5673bc6d790SSaravanan Sekar static int mp2629_charger_probe(struct platform_device *pdev)
5683bc6d790SSaravanan Sekar {
5693bc6d790SSaravanan Sekar struct device *dev = &pdev->dev;
5703bc6d790SSaravanan Sekar struct mp2629_data *ddata = dev_get_drvdata(dev->parent);
5713bc6d790SSaravanan Sekar struct mp2629_charger *charger;
5723bc6d790SSaravanan Sekar struct power_supply_config psy_cfg = {};
5733bc6d790SSaravanan Sekar int ret, i, irq;
5743bc6d790SSaravanan Sekar
5753bc6d790SSaravanan Sekar charger = devm_kzalloc(dev, sizeof(*charger), GFP_KERNEL);
5763bc6d790SSaravanan Sekar if (!charger)
5773bc6d790SSaravanan Sekar return -ENOMEM;
5783bc6d790SSaravanan Sekar
5793bc6d790SSaravanan Sekar charger->regmap = ddata->regmap;
5803bc6d790SSaravanan Sekar charger->dev = dev;
5813bc6d790SSaravanan Sekar platform_set_drvdata(pdev, charger);
5823bc6d790SSaravanan Sekar
5832b7950c7SSergey Shtylyov irq = platform_get_irq(to_platform_device(dev->parent), 0);
5842b7950c7SSergey Shtylyov if (irq < 0)
5853bc6d790SSaravanan Sekar return irq;
5863bc6d790SSaravanan Sekar
5873bc6d790SSaravanan Sekar for (i = 0; i < MP2629_MAX_FIELD; i++) {
5883bc6d790SSaravanan Sekar charger->regmap_fields[i] = devm_regmap_field_alloc(dev,
5893bc6d790SSaravanan Sekar charger->regmap, mp2629_reg_fields[i]);
5903bc6d790SSaravanan Sekar if (IS_ERR(charger->regmap_fields[i])) {
5913bc6d790SSaravanan Sekar dev_err(dev, "regmap field alloc fail %d\n", i);
5923bc6d790SSaravanan Sekar return PTR_ERR(charger->regmap_fields[i]);
5933bc6d790SSaravanan Sekar }
5943bc6d790SSaravanan Sekar }
5953bc6d790SSaravanan Sekar
5963bc6d790SSaravanan Sekar for (i = 0; i < MP2629_ADC_CHAN_END; i++) {
5973bc6d790SSaravanan Sekar charger->iiochan[i] = devm_iio_channel_get(dev,
5983bc6d790SSaravanan Sekar adc_chan_name[i]);
5993bc6d790SSaravanan Sekar if (IS_ERR(charger->iiochan[i])) {
6003bc6d790SSaravanan Sekar dev_err(dev, "iio chan get %s err\n", adc_chan_name[i]);
6013bc6d790SSaravanan Sekar return PTR_ERR(charger->iiochan[i]);
6023bc6d790SSaravanan Sekar }
6033bc6d790SSaravanan Sekar }
6043bc6d790SSaravanan Sekar
6053bc6d790SSaravanan Sekar ret = devm_add_action_or_reset(dev, mp2629_charger_disable, charger);
6063bc6d790SSaravanan Sekar if (ret)
6073bc6d790SSaravanan Sekar return ret;
6083bc6d790SSaravanan Sekar
6093bc6d790SSaravanan Sekar charger->usb = devm_power_supply_register(dev, &mp2629_usb_desc, NULL);
6103bc6d790SSaravanan Sekar if (IS_ERR(charger->usb)) {
6113bc6d790SSaravanan Sekar dev_err(dev, "power supply register usb failed\n");
6123bc6d790SSaravanan Sekar return PTR_ERR(charger->usb);
6133bc6d790SSaravanan Sekar }
6143bc6d790SSaravanan Sekar
6153bc6d790SSaravanan Sekar psy_cfg.drv_data = charger;
6163bc6d790SSaravanan Sekar psy_cfg.attr_grp = mp2629_charger_sysfs_groups;
6173bc6d790SSaravanan Sekar charger->battery = devm_power_supply_register(dev,
6183bc6d790SSaravanan Sekar &mp2629_battery_desc, &psy_cfg);
6193bc6d790SSaravanan Sekar if (IS_ERR(charger->battery)) {
6203bc6d790SSaravanan Sekar dev_err(dev, "power supply register battery failed\n");
6213bc6d790SSaravanan Sekar return PTR_ERR(charger->battery);
6223bc6d790SSaravanan Sekar }
6233bc6d790SSaravanan Sekar
6243bc6d790SSaravanan Sekar ret = regmap_update_bits(charger->regmap, MP2629_REG_CHARGE_CTRL,
6253bc6d790SSaravanan Sekar MP2629_MASK_CHARGE_CTRL, BIT(4));
6263bc6d790SSaravanan Sekar if (ret) {
6273bc6d790SSaravanan Sekar dev_err(dev, "enable charge fail: %d\n", ret);
6283bc6d790SSaravanan Sekar return ret;
6293bc6d790SSaravanan Sekar }
6303bc6d790SSaravanan Sekar
6313bc6d790SSaravanan Sekar regmap_update_bits(charger->regmap, MP2629_REG_TIMER_CTRL,
6323bc6d790SSaravanan Sekar MP2629_MASK_WDOG_CTRL, 0);
6333bc6d790SSaravanan Sekar
6343bc6d790SSaravanan Sekar mutex_init(&charger->lock);
6353bc6d790SSaravanan Sekar
6363bc6d790SSaravanan Sekar ret = devm_request_threaded_irq(dev, irq, NULL, mp2629_irq_handler,
6373bc6d790SSaravanan Sekar IRQF_ONESHOT | IRQF_TRIGGER_RISING,
6383bc6d790SSaravanan Sekar "mp2629-charger", charger);
6393bc6d790SSaravanan Sekar if (ret) {
6403bc6d790SSaravanan Sekar dev_err(dev, "failed to request gpio IRQ\n");
6413bc6d790SSaravanan Sekar return ret;
6423bc6d790SSaravanan Sekar }
6433bc6d790SSaravanan Sekar
6443bc6d790SSaravanan Sekar regmap_update_bits(charger->regmap, MP2629_REG_INTERRUPT,
6453bc6d790SSaravanan Sekar GENMASK(6, 5), BIT(6) | BIT(5));
6463bc6d790SSaravanan Sekar
6473bc6d790SSaravanan Sekar return 0;
6483bc6d790SSaravanan Sekar }
6493bc6d790SSaravanan Sekar
6503bc6d790SSaravanan Sekar static const struct of_device_id mp2629_charger_of_match[] = {
6513bc6d790SSaravanan Sekar { .compatible = "mps,mp2629_charger"},
6523bc6d790SSaravanan Sekar {}
6533bc6d790SSaravanan Sekar };
6543bc6d790SSaravanan Sekar MODULE_DEVICE_TABLE(of, mp2629_charger_of_match);
6553bc6d790SSaravanan Sekar
6563bc6d790SSaravanan Sekar static struct platform_driver mp2629_charger_driver = {
6573bc6d790SSaravanan Sekar .driver = {
6583bc6d790SSaravanan Sekar .name = "mp2629_charger",
6593bc6d790SSaravanan Sekar .of_match_table = mp2629_charger_of_match,
6603bc6d790SSaravanan Sekar },
6613bc6d790SSaravanan Sekar .probe = mp2629_charger_probe,
6623bc6d790SSaravanan Sekar };
6633bc6d790SSaravanan Sekar module_platform_driver(mp2629_charger_driver);
6643bc6d790SSaravanan Sekar
6653bc6d790SSaravanan Sekar MODULE_AUTHOR("Saravanan Sekar <sravanhome@gmail.com>");
6663bc6d790SSaravanan Sekar MODULE_DESCRIPTION("MP2629 Charger driver");
6673bc6d790SSaravanan Sekar MODULE_LICENSE("GPL");
668