Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * MP2629 battery charger driver
0004  *
0005  * Copyright 2020 Monolithic Power Systems, Inc
0006  *
0007  * Author: Saravanan Sekar <sravanhome@gmail.com>
0008  */
0009 
0010 #include <linux/bits.h>
0011 #include <linux/iio/consumer.h>
0012 #include <linux/iio/types.h>
0013 #include <linux/interrupt.h>
0014 #include <linux/mfd/mp2629.h>
0015 #include <linux/module.h>
0016 #include <linux/mod_devicetable.h>
0017 #include <linux/platform_device.h>
0018 #include <linux/power_supply.h>
0019 #include <linux/regmap.h>
0020 
0021 #define MP2629_REG_INPUT_ILIM       0x00
0022 #define MP2629_REG_INPUT_VLIM       0x01
0023 #define MP2629_REG_CHARGE_CTRL      0x04
0024 #define MP2629_REG_CHARGE_ILIM      0x05
0025 #define MP2629_REG_PRECHARGE        0x06
0026 #define MP2629_REG_TERM_CURRENT     0x06
0027 #define MP2629_REG_CHARGE_VLIM      0x07
0028 #define MP2629_REG_TIMER_CTRL       0x08
0029 #define MP2629_REG_IMPEDANCE_COMP   0x09
0030 #define MP2629_REG_INTERRUPT        0x0b
0031 #define MP2629_REG_STATUS       0x0c
0032 #define MP2629_REG_FAULT        0x0d
0033 
0034 #define MP2629_MASK_INPUT_TYPE      GENMASK(7, 5)
0035 #define MP2629_MASK_CHARGE_TYPE     GENMASK(4, 3)
0036 #define MP2629_MASK_CHARGE_CTRL     GENMASK(5, 4)
0037 #define MP2629_MASK_WDOG_CTRL       GENMASK(5, 4)
0038 #define MP2629_MASK_IMPEDANCE       GENMASK(7, 4)
0039 
0040 #define MP2629_INPUTSOURCE_CHANGE   GENMASK(7, 5)
0041 #define MP2629_CHARGING_CHANGE      GENMASK(4, 3)
0042 #define MP2629_FAULT_BATTERY        BIT(3)
0043 #define MP2629_FAULT_THERMAL        BIT(4)
0044 #define MP2629_FAULT_INPUT      BIT(5)
0045 #define MP2629_FAULT_OTG        BIT(6)
0046 
0047 #define MP2629_MAX_BATT_CAPACITY    100
0048 
0049 #define MP2629_PROPS(_idx, _min, _max, _step)       \
0050     [_idx] = {                  \
0051         .min    = _min,             \
0052         .max    = _max,             \
0053         .step   = _step,            \
0054 }
0055 
0056 enum mp2629_source_type {
0057     MP2629_SOURCE_TYPE_NO_INPUT,
0058     MP2629_SOURCE_TYPE_NON_STD,
0059     MP2629_SOURCE_TYPE_SDP,
0060     MP2629_SOURCE_TYPE_CDP,
0061     MP2629_SOURCE_TYPE_DCP,
0062     MP2629_SOURCE_TYPE_OTG = 7,
0063 };
0064 
0065 enum mp2629_field {
0066     INPUT_ILIM,
0067     INPUT_VLIM,
0068     CHARGE_ILIM,
0069     CHARGE_VLIM,
0070     PRECHARGE,
0071     TERM_CURRENT,
0072     MP2629_MAX_FIELD
0073 };
0074 
0075 struct mp2629_charger {
0076     struct device *dev;
0077     int status;
0078     int fault;
0079 
0080     struct regmap *regmap;
0081     struct regmap_field *regmap_fields[MP2629_MAX_FIELD];
0082     struct mutex lock;
0083     struct power_supply *usb;
0084     struct power_supply *battery;
0085     struct iio_channel *iiochan[MP2629_ADC_CHAN_END];
0086 };
0087 
0088 struct mp2629_prop {
0089     int reg;
0090     int mask;
0091     int min;
0092     int max;
0093     int step;
0094     int shift;
0095 };
0096 
0097 static enum power_supply_usb_type mp2629_usb_types[] = {
0098     POWER_SUPPLY_USB_TYPE_SDP,
0099     POWER_SUPPLY_USB_TYPE_DCP,
0100     POWER_SUPPLY_USB_TYPE_CDP,
0101     POWER_SUPPLY_USB_TYPE_PD_DRP,
0102     POWER_SUPPLY_USB_TYPE_UNKNOWN
0103 };
0104 
0105 static enum power_supply_property mp2629_charger_usb_props[] = {
0106     POWER_SUPPLY_PROP_ONLINE,
0107     POWER_SUPPLY_PROP_USB_TYPE,
0108     POWER_SUPPLY_PROP_VOLTAGE_NOW,
0109     POWER_SUPPLY_PROP_CURRENT_NOW,
0110     POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
0111     POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT,
0112 };
0113 
0114 static enum power_supply_property mp2629_charger_bat_props[] = {
0115     POWER_SUPPLY_PROP_STATUS,
0116     POWER_SUPPLY_PROP_HEALTH,
0117     POWER_SUPPLY_PROP_CHARGE_TYPE,
0118     POWER_SUPPLY_PROP_VOLTAGE_NOW,
0119     POWER_SUPPLY_PROP_CURRENT_NOW,
0120     POWER_SUPPLY_PROP_CAPACITY,
0121     POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
0122     POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
0123     POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
0124     POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
0125     POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
0126     POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
0127 };
0128 
0129 static struct mp2629_prop props[] = {
0130     MP2629_PROPS(INPUT_ILIM, 100000, 3250000, 50000),
0131     MP2629_PROPS(INPUT_VLIM, 3800000, 5300000, 100000),
0132     MP2629_PROPS(CHARGE_ILIM, 320000, 4520000, 40000),
0133     MP2629_PROPS(CHARGE_VLIM, 3400000, 4670000, 10000),
0134     MP2629_PROPS(PRECHARGE, 120000, 720000, 40000),
0135     MP2629_PROPS(TERM_CURRENT, 80000, 680000, 40000),
0136 };
0137 
0138 static const struct reg_field mp2629_reg_fields[] = {
0139     [INPUT_ILIM]    = REG_FIELD(MP2629_REG_INPUT_ILIM, 0, 5),
0140     [INPUT_VLIM]    = REG_FIELD(MP2629_REG_INPUT_VLIM, 0, 3),
0141     [CHARGE_ILIM]   = REG_FIELD(MP2629_REG_CHARGE_ILIM, 0, 6),
0142     [CHARGE_VLIM]   = REG_FIELD(MP2629_REG_CHARGE_VLIM, 1, 7),
0143     [PRECHARGE] = REG_FIELD(MP2629_REG_PRECHARGE, 4, 7),
0144     [TERM_CURRENT]  = REG_FIELD(MP2629_REG_TERM_CURRENT, 0, 3),
0145 };
0146 
0147 static char *adc_chan_name[] = {
0148     "mp2629-batt-volt",
0149     "mp2629-system-volt",
0150     "mp2629-input-volt",
0151     "mp2629-batt-current",
0152     "mp2629-input-current",
0153 };
0154 
0155 static int mp2629_read_adc(struct mp2629_charger *charger,
0156                enum mp2629_adc_chan ch,
0157                union power_supply_propval *val)
0158 {
0159     int ret;
0160     int chval;
0161 
0162     ret = iio_read_channel_processed(charger->iiochan[ch], &chval);
0163     if (ret)
0164         return ret;
0165 
0166     val->intval = chval * 1000;
0167 
0168     return 0;
0169 }
0170 
0171 static int mp2629_get_prop(struct mp2629_charger *charger,
0172                enum mp2629_field fld,
0173                union power_supply_propval *val)
0174 {
0175     int ret;
0176     unsigned int rval;
0177 
0178     ret = regmap_field_read(charger->regmap_fields[fld], &rval);
0179     if (ret)
0180         return ret;
0181 
0182     val->intval = rval * props[fld].step + props[fld].min;
0183 
0184     return 0;
0185 }
0186 
0187 static int mp2629_set_prop(struct mp2629_charger *charger,
0188                enum mp2629_field fld,
0189                const union power_supply_propval *val)
0190 {
0191     unsigned int rval;
0192 
0193     if (val->intval < props[fld].min || val->intval > props[fld].max)
0194         return -EINVAL;
0195 
0196     rval = (val->intval - props[fld].min) / props[fld].step;
0197     return regmap_field_write(charger->regmap_fields[fld], rval);
0198 }
0199 
0200 static int mp2629_get_battery_capacity(struct mp2629_charger *charger,
0201                        union power_supply_propval *val)
0202 {
0203     union power_supply_propval vnow, vlim;
0204     int ret;
0205 
0206     ret = mp2629_read_adc(charger, MP2629_BATT_VOLT, &vnow);
0207     if (ret)
0208         return ret;
0209 
0210     ret = mp2629_get_prop(charger, CHARGE_VLIM, &vlim);
0211     if (ret)
0212         return ret;
0213 
0214     val->intval = (vnow.intval * 100) / vlim.intval;
0215     val->intval = min(val->intval, MP2629_MAX_BATT_CAPACITY);
0216 
0217     return 0;
0218 }
0219 
0220 static int mp2629_charger_battery_get_prop(struct power_supply *psy,
0221                     enum power_supply_property psp,
0222                     union power_supply_propval *val)
0223 {
0224     struct mp2629_charger *charger = dev_get_drvdata(psy->dev.parent);
0225     unsigned int rval;
0226     int ret = 0;
0227 
0228     switch (psp) {
0229     case POWER_SUPPLY_PROP_VOLTAGE_NOW:
0230         ret = mp2629_read_adc(charger, MP2629_BATT_VOLT, val);
0231         break;
0232 
0233     case POWER_SUPPLY_PROP_CURRENT_NOW:
0234         ret = mp2629_read_adc(charger, MP2629_BATT_CURRENT, val);
0235         break;
0236 
0237     case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
0238         val->intval = 4520000;
0239         break;
0240 
0241     case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
0242         val->intval = 4670000;
0243         break;
0244 
0245     case POWER_SUPPLY_PROP_CAPACITY:
0246         ret = mp2629_get_battery_capacity(charger, val);
0247         break;
0248 
0249     case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
0250         ret = mp2629_get_prop(charger, TERM_CURRENT, val);
0251         break;
0252 
0253     case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
0254         ret = mp2629_get_prop(charger, PRECHARGE, val);
0255         break;
0256 
0257     case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
0258         ret = mp2629_get_prop(charger, CHARGE_VLIM, val);
0259         break;
0260 
0261     case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
0262         ret = mp2629_get_prop(charger, CHARGE_ILIM, val);
0263         break;
0264 
0265     case POWER_SUPPLY_PROP_HEALTH:
0266         if (!charger->fault)
0267             val->intval = POWER_SUPPLY_HEALTH_GOOD;
0268         if (MP2629_FAULT_BATTERY & charger->fault)
0269             val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
0270         else if (MP2629_FAULT_THERMAL & charger->fault)
0271             val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
0272         else if (MP2629_FAULT_INPUT & charger->fault)
0273             val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
0274         break;
0275 
0276     case POWER_SUPPLY_PROP_STATUS:
0277         ret = regmap_read(charger->regmap, MP2629_REG_STATUS, &rval);
0278         if (ret)
0279             break;
0280 
0281         rval = (rval & MP2629_MASK_CHARGE_TYPE) >> 3;
0282         switch (rval) {
0283         case 0x00:
0284             val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
0285             break;
0286         case 0x01:
0287         case 0x10:
0288             val->intval = POWER_SUPPLY_STATUS_CHARGING;
0289             break;
0290         case 0x11:
0291             val->intval = POWER_SUPPLY_STATUS_FULL;
0292         }
0293         break;
0294 
0295     case POWER_SUPPLY_PROP_CHARGE_TYPE:
0296         ret = regmap_read(charger->regmap, MP2629_REG_STATUS, &rval);
0297         if (ret)
0298             break;
0299 
0300         rval = (rval & MP2629_MASK_CHARGE_TYPE) >> 3;
0301         switch (rval) {
0302         case 0x00:
0303             val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
0304             break;
0305         case 0x01:
0306             val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
0307             break;
0308         case 0x10:
0309             val->intval = POWER_SUPPLY_CHARGE_TYPE_STANDARD;
0310             break;
0311         default:
0312             val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
0313         }
0314         break;
0315 
0316     default:
0317         return -EINVAL;
0318     }
0319 
0320     return ret;
0321 }
0322 
0323 static int mp2629_charger_battery_set_prop(struct power_supply *psy,
0324                     enum power_supply_property psp,
0325                     const union power_supply_propval *val)
0326 {
0327     struct mp2629_charger *charger = dev_get_drvdata(psy->dev.parent);
0328 
0329     switch (psp) {
0330     case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
0331         return mp2629_set_prop(charger, TERM_CURRENT, val);
0332 
0333     case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
0334         return mp2629_set_prop(charger, PRECHARGE, val);
0335 
0336     case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
0337         return mp2629_set_prop(charger, CHARGE_VLIM, val);
0338 
0339     case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
0340         return mp2629_set_prop(charger, CHARGE_ILIM, val);
0341 
0342     default:
0343         return -EINVAL;
0344     }
0345 }
0346 
0347 static int mp2629_charger_usb_get_prop(struct power_supply *psy,
0348                 enum power_supply_property psp,
0349                 union power_supply_propval *val)
0350 {
0351     struct mp2629_charger *charger = dev_get_drvdata(psy->dev.parent);
0352     unsigned int rval;
0353     int ret;
0354 
0355     switch (psp) {
0356     case POWER_SUPPLY_PROP_ONLINE:
0357         ret = regmap_read(charger->regmap, MP2629_REG_STATUS, &rval);
0358         if (ret)
0359             break;
0360 
0361         val->intval = !!(rval & MP2629_MASK_INPUT_TYPE);
0362         break;
0363 
0364     case POWER_SUPPLY_PROP_USB_TYPE:
0365         ret = regmap_read(charger->regmap, MP2629_REG_STATUS, &rval);
0366         if (ret)
0367             break;
0368 
0369         rval = (rval & MP2629_MASK_INPUT_TYPE) >> 5;
0370         switch (rval) {
0371         case MP2629_SOURCE_TYPE_SDP:
0372             val->intval = POWER_SUPPLY_USB_TYPE_SDP;
0373             break;
0374         case MP2629_SOURCE_TYPE_CDP:
0375             val->intval = POWER_SUPPLY_USB_TYPE_CDP;
0376             break;
0377         case MP2629_SOURCE_TYPE_DCP:
0378             val->intval = POWER_SUPPLY_USB_TYPE_DCP;
0379             break;
0380         case MP2629_SOURCE_TYPE_OTG:
0381             val->intval = POWER_SUPPLY_USB_TYPE_PD_DRP;
0382             break;
0383         default:
0384             val->intval = POWER_SUPPLY_USB_TYPE_UNKNOWN;
0385             break;
0386         }
0387         break;
0388 
0389     case POWER_SUPPLY_PROP_VOLTAGE_NOW:
0390         ret = mp2629_read_adc(charger, MP2629_INPUT_VOLT, val);
0391         break;
0392 
0393     case POWER_SUPPLY_PROP_CURRENT_NOW:
0394         ret = mp2629_read_adc(charger, MP2629_INPUT_CURRENT, val);
0395         break;
0396 
0397     case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
0398         ret = mp2629_get_prop(charger, INPUT_VLIM, val);
0399         break;
0400 
0401     case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
0402         ret = mp2629_get_prop(charger, INPUT_ILIM, val);
0403         break;
0404 
0405     default:
0406         return -EINVAL;
0407     }
0408 
0409     return ret;
0410 }
0411 
0412 static int mp2629_charger_usb_set_prop(struct power_supply *psy,
0413                 enum power_supply_property psp,
0414                 const union power_supply_propval *val)
0415 {
0416     struct mp2629_charger *charger = dev_get_drvdata(psy->dev.parent);
0417 
0418     switch (psp) {
0419     case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
0420         return mp2629_set_prop(charger, INPUT_VLIM, val);
0421 
0422     case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
0423         return mp2629_set_prop(charger, INPUT_ILIM, val);
0424 
0425     default:
0426         return -EINVAL;
0427     }
0428 }
0429 
0430 static int mp2629_charger_battery_prop_writeable(struct power_supply *psy,
0431                      enum power_supply_property psp)
0432 {
0433     return (psp == POWER_SUPPLY_PROP_PRECHARGE_CURRENT) ||
0434            (psp == POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT) ||
0435            (psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT) ||
0436            (psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE);
0437 }
0438 
0439 static int mp2629_charger_usb_prop_writeable(struct power_supply *psy,
0440                      enum power_supply_property psp)
0441 {
0442     return (psp == POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT) ||
0443            (psp == POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT);
0444 }
0445 
0446 static irqreturn_t mp2629_irq_handler(int irq, void *dev_id)
0447 {
0448     struct mp2629_charger *charger = dev_id;
0449     unsigned int rval;
0450     int ret;
0451 
0452     mutex_lock(&charger->lock);
0453 
0454     ret = regmap_read(charger->regmap, MP2629_REG_FAULT, &rval);
0455     if (ret)
0456         goto unlock;
0457 
0458     if (rval) {
0459         charger->fault = rval;
0460         if (MP2629_FAULT_BATTERY & rval)
0461             dev_err(charger->dev, "Battery fault OVP\n");
0462         else if (MP2629_FAULT_THERMAL & rval)
0463             dev_err(charger->dev, "Thermal shutdown fault\n");
0464         else if (MP2629_FAULT_INPUT & rval)
0465             dev_err(charger->dev, "no input or input OVP\n");
0466         else if (MP2629_FAULT_OTG & rval)
0467             dev_err(charger->dev, "VIN overloaded\n");
0468 
0469         goto unlock;
0470     }
0471 
0472     ret = regmap_read(charger->regmap, MP2629_REG_STATUS, &rval);
0473     if (ret)
0474         goto unlock;
0475 
0476     if (rval & MP2629_INPUTSOURCE_CHANGE)
0477         power_supply_changed(charger->usb);
0478     else if (rval & MP2629_CHARGING_CHANGE)
0479         power_supply_changed(charger->battery);
0480 
0481 unlock:
0482     mutex_unlock(&charger->lock);
0483 
0484     return IRQ_HANDLED;
0485 }
0486 
0487 static const struct power_supply_desc mp2629_usb_desc = {
0488     .name       = "mp2629_usb",
0489     .type       = POWER_SUPPLY_TYPE_USB,
0490     .usb_types      = mp2629_usb_types,
0491     .num_usb_types  = ARRAY_SIZE(mp2629_usb_types),
0492     .properties = mp2629_charger_usb_props,
0493     .num_properties = ARRAY_SIZE(mp2629_charger_usb_props),
0494     .get_property   = mp2629_charger_usb_get_prop,
0495     .set_property   = mp2629_charger_usb_set_prop,
0496     .property_is_writeable = mp2629_charger_usb_prop_writeable,
0497 };
0498 
0499 static const struct power_supply_desc mp2629_battery_desc = {
0500     .name       = "mp2629_battery",
0501     .type       = POWER_SUPPLY_TYPE_BATTERY,
0502     .properties = mp2629_charger_bat_props,
0503     .num_properties = ARRAY_SIZE(mp2629_charger_bat_props),
0504     .get_property   = mp2629_charger_battery_get_prop,
0505     .set_property   = mp2629_charger_battery_set_prop,
0506     .property_is_writeable = mp2629_charger_battery_prop_writeable,
0507 };
0508 
0509 static ssize_t batt_impedance_compensation_show(struct device *dev,
0510                        struct device_attribute *attr,
0511                        char *buf)
0512 {
0513     struct mp2629_charger *charger = dev_get_drvdata(dev->parent);
0514     unsigned int rval;
0515     int ret;
0516 
0517     ret = regmap_read(charger->regmap, MP2629_REG_IMPEDANCE_COMP, &rval);
0518     if (ret)
0519         return ret;
0520 
0521     rval = (rval >> 4) * 10;
0522     return sprintf(buf, "%d mohm\n", rval);
0523 }
0524 
0525 static ssize_t batt_impedance_compensation_store(struct device *dev,
0526                         struct device_attribute *attr,
0527                         const char *buf,
0528                         size_t count)
0529 {
0530     struct mp2629_charger *charger = dev_get_drvdata(dev->parent);
0531     unsigned int val;
0532     int ret;
0533 
0534     ret = kstrtouint(buf, 10, &val);
0535     if (ret)
0536         return ret;
0537 
0538     if (val > 140)
0539         return -ERANGE;
0540 
0541     /* multiples of 10 mohm so round off */
0542     val = val / 10;
0543     ret = regmap_update_bits(charger->regmap, MP2629_REG_IMPEDANCE_COMP,
0544                     MP2629_MASK_IMPEDANCE, val << 4);
0545     if (ret)
0546         return ret;
0547 
0548     return count;
0549 }
0550 
0551 static DEVICE_ATTR_RW(batt_impedance_compensation);
0552 
0553 static struct attribute *mp2629_charger_sysfs_attrs[] = {
0554     &dev_attr_batt_impedance_compensation.attr,
0555     NULL
0556 };
0557 ATTRIBUTE_GROUPS(mp2629_charger_sysfs);
0558 
0559 static void mp2629_charger_disable(void *data)
0560 {
0561     struct mp2629_charger *charger = data;
0562 
0563     regmap_update_bits(charger->regmap, MP2629_REG_CHARGE_CTRL,
0564                     MP2629_MASK_CHARGE_CTRL, 0);
0565 }
0566 
0567 static int mp2629_charger_probe(struct platform_device *pdev)
0568 {
0569     struct device *dev = &pdev->dev;
0570     struct mp2629_data *ddata = dev_get_drvdata(dev->parent);
0571     struct mp2629_charger *charger;
0572     struct power_supply_config psy_cfg = {};
0573     int ret, i, irq;
0574 
0575     charger = devm_kzalloc(dev, sizeof(*charger), GFP_KERNEL);
0576     if (!charger)
0577         return -ENOMEM;
0578 
0579     charger->regmap = ddata->regmap;
0580     charger->dev = dev;
0581     platform_set_drvdata(pdev, charger);
0582 
0583     irq = platform_get_irq(to_platform_device(dev->parent), 0);
0584     if (irq < 0)
0585         return irq;
0586 
0587     for (i = 0; i < MP2629_MAX_FIELD; i++) {
0588         charger->regmap_fields[i] = devm_regmap_field_alloc(dev,
0589                     charger->regmap, mp2629_reg_fields[i]);
0590         if (IS_ERR(charger->regmap_fields[i])) {
0591             dev_err(dev, "regmap field alloc fail %d\n", i);
0592             return PTR_ERR(charger->regmap_fields[i]);
0593         }
0594     }
0595 
0596     for (i = 0; i < MP2629_ADC_CHAN_END; i++) {
0597         charger->iiochan[i] = devm_iio_channel_get(dev,
0598                             adc_chan_name[i]);
0599         if (IS_ERR(charger->iiochan[i])) {
0600             dev_err(dev, "iio chan get %s err\n", adc_chan_name[i]);
0601             return PTR_ERR(charger->iiochan[i]);
0602         }
0603     }
0604 
0605     ret = devm_add_action_or_reset(dev, mp2629_charger_disable, charger);
0606     if (ret)
0607         return ret;
0608 
0609     charger->usb = devm_power_supply_register(dev, &mp2629_usb_desc, NULL);
0610     if (IS_ERR(charger->usb)) {
0611         dev_err(dev, "power supply register usb failed\n");
0612         return PTR_ERR(charger->usb);
0613     }
0614 
0615     psy_cfg.drv_data = charger;
0616     psy_cfg.attr_grp = mp2629_charger_sysfs_groups;
0617     charger->battery = devm_power_supply_register(dev,
0618                      &mp2629_battery_desc, &psy_cfg);
0619     if (IS_ERR(charger->battery)) {
0620         dev_err(dev, "power supply register battery failed\n");
0621         return PTR_ERR(charger->battery);
0622     }
0623 
0624     ret = regmap_update_bits(charger->regmap, MP2629_REG_CHARGE_CTRL,
0625                     MP2629_MASK_CHARGE_CTRL, BIT(4));
0626     if (ret) {
0627         dev_err(dev, "enable charge fail: %d\n", ret);
0628         return ret;
0629     }
0630 
0631     regmap_update_bits(charger->regmap, MP2629_REG_TIMER_CTRL,
0632                     MP2629_MASK_WDOG_CTRL, 0);
0633 
0634     mutex_init(&charger->lock);
0635 
0636     ret = devm_request_threaded_irq(dev, irq, NULL, mp2629_irq_handler,
0637                     IRQF_ONESHOT | IRQF_TRIGGER_RISING,
0638                     "mp2629-charger", charger);
0639     if (ret) {
0640         dev_err(dev, "failed to request gpio IRQ\n");
0641         return ret;
0642     }
0643 
0644     regmap_update_bits(charger->regmap, MP2629_REG_INTERRUPT,
0645                 GENMASK(6, 5), BIT(6) | BIT(5));
0646 
0647     return 0;
0648 }
0649 
0650 static const struct of_device_id mp2629_charger_of_match[] = {
0651     { .compatible = "mps,mp2629_charger"},
0652     {}
0653 };
0654 MODULE_DEVICE_TABLE(of, mp2629_charger_of_match);
0655 
0656 static struct platform_driver mp2629_charger_driver = {
0657     .driver = {
0658         .name = "mp2629_charger",
0659         .of_match_table = mp2629_charger_of_match,
0660     },
0661     .probe      = mp2629_charger_probe,
0662 };
0663 module_platform_driver(mp2629_charger_driver);
0664 
0665 MODULE_AUTHOR("Saravanan Sekar <sravanhome@gmail.com>");
0666 MODULE_DESCRIPTION("MP2629 Charger driver");
0667 MODULE_LICENSE("GPL");