Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * DA9150 Charger Driver
0004  *
0005  * Copyright (c) 2014 Dialog Semiconductor
0006  *
0007  * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
0008  */
0009 
0010 #include <linux/kernel.h>
0011 #include <linux/slab.h>
0012 #include <linux/module.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/of.h>
0015 #include <linux/of_platform.h>
0016 #include <linux/interrupt.h>
0017 #include <linux/power_supply.h>
0018 #include <linux/notifier.h>
0019 #include <linux/usb/phy.h>
0020 #include <linux/iio/consumer.h>
0021 #include <linux/mfd/da9150/core.h>
0022 #include <linux/mfd/da9150/registers.h>
0023 
0024 /* Private data */
0025 struct da9150_charger {
0026     struct da9150 *da9150;
0027     struct device *dev;
0028 
0029     struct power_supply *usb;
0030     struct power_supply *battery;
0031     struct power_supply *supply_online;
0032 
0033     struct usb_phy *usb_phy;
0034     struct notifier_block otg_nb;
0035     struct work_struct otg_work;
0036     unsigned long usb_event;
0037 
0038     struct iio_channel *ibus_chan;
0039     struct iio_channel *vbus_chan;
0040     struct iio_channel *tjunc_chan;
0041     struct iio_channel *vbat_chan;
0042 };
0043 
0044 static inline int da9150_charger_supply_online(struct da9150_charger *charger,
0045                            struct power_supply *psy,
0046                            union power_supply_propval *val)
0047 {
0048     val->intval = (psy == charger->supply_online) ? 1 : 0;
0049 
0050     return 0;
0051 }
0052 
0053 /* Charger Properties */
0054 static int da9150_charger_vbus_voltage_now(struct da9150_charger *charger,
0055                        union power_supply_propval *val)
0056 {
0057     int v_val, ret;
0058 
0059     /* Read processed value - mV units */
0060     ret = iio_read_channel_processed(charger->vbus_chan, &v_val);
0061     if (ret < 0)
0062         return ret;
0063 
0064     /* Convert voltage to expected uV units */
0065     val->intval = v_val * 1000;
0066 
0067     return 0;
0068 }
0069 
0070 static int da9150_charger_ibus_current_avg(struct da9150_charger *charger,
0071                        union power_supply_propval *val)
0072 {
0073     int i_val, ret;
0074 
0075     /* Read processed value - mA units */
0076     ret = iio_read_channel_processed(charger->ibus_chan, &i_val);
0077     if (ret < 0)
0078         return ret;
0079 
0080     /* Convert current to expected uA units */
0081     val->intval = i_val * 1000;
0082 
0083     return 0;
0084 }
0085 
0086 static int da9150_charger_tjunc_temp(struct da9150_charger *charger,
0087                      union power_supply_propval *val)
0088 {
0089     int t_val, ret;
0090 
0091     /* Read processed value - 0.001 degrees C units */
0092     ret = iio_read_channel_processed(charger->tjunc_chan, &t_val);
0093     if (ret < 0)
0094         return ret;
0095 
0096     /* Convert temp to expect 0.1 degrees C units */
0097     val->intval = t_val / 100;
0098 
0099     return 0;
0100 }
0101 
0102 static enum power_supply_property da9150_charger_props[] = {
0103     POWER_SUPPLY_PROP_ONLINE,
0104     POWER_SUPPLY_PROP_VOLTAGE_NOW,
0105     POWER_SUPPLY_PROP_CURRENT_AVG,
0106     POWER_SUPPLY_PROP_TEMP,
0107 };
0108 
0109 static int da9150_charger_get_prop(struct power_supply *psy,
0110                    enum power_supply_property psp,
0111                    union power_supply_propval *val)
0112 {
0113     struct da9150_charger *charger = dev_get_drvdata(psy->dev.parent);
0114     int ret;
0115 
0116     switch (psp) {
0117     case POWER_SUPPLY_PROP_ONLINE:
0118         ret = da9150_charger_supply_online(charger, psy, val);
0119         break;
0120     case POWER_SUPPLY_PROP_VOLTAGE_NOW:
0121         ret = da9150_charger_vbus_voltage_now(charger, val);
0122         break;
0123     case POWER_SUPPLY_PROP_CURRENT_AVG:
0124         ret = da9150_charger_ibus_current_avg(charger, val);
0125         break;
0126     case POWER_SUPPLY_PROP_TEMP:
0127         ret = da9150_charger_tjunc_temp(charger, val);
0128         break;
0129     default:
0130         ret = -EINVAL;
0131         break;
0132     }
0133 
0134     return ret;
0135 }
0136 
0137 /* Battery Properties */
0138 static int da9150_charger_battery_status(struct da9150_charger *charger,
0139                      union power_supply_propval *val)
0140 {
0141     u8 reg;
0142 
0143     /* Check to see if battery is discharging */
0144     reg = da9150_reg_read(charger->da9150, DA9150_STATUS_H);
0145 
0146     if (((reg & DA9150_VBUS_STAT_MASK) == DA9150_VBUS_STAT_OFF) ||
0147         ((reg & DA9150_VBUS_STAT_MASK) == DA9150_VBUS_STAT_WAIT)) {
0148         val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
0149 
0150         return 0;
0151     }
0152 
0153     reg = da9150_reg_read(charger->da9150, DA9150_STATUS_J);
0154 
0155     /* Now check for other states */
0156     switch (reg & DA9150_CHG_STAT_MASK) {
0157     case DA9150_CHG_STAT_ACT:
0158     case DA9150_CHG_STAT_PRE:
0159     case DA9150_CHG_STAT_CC:
0160     case DA9150_CHG_STAT_CV:
0161         val->intval = POWER_SUPPLY_STATUS_CHARGING;
0162         break;
0163     case DA9150_CHG_STAT_OFF:
0164     case DA9150_CHG_STAT_SUSP:
0165     case DA9150_CHG_STAT_TEMP:
0166     case DA9150_CHG_STAT_TIME:
0167     case DA9150_CHG_STAT_BAT:
0168         val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
0169         break;
0170     case DA9150_CHG_STAT_FULL:
0171         val->intval = POWER_SUPPLY_STATUS_FULL;
0172         break;
0173     default:
0174         val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
0175         break;
0176     }
0177 
0178     return 0;
0179 }
0180 
0181 static int da9150_charger_battery_health(struct da9150_charger *charger,
0182                      union power_supply_propval *val)
0183 {
0184     u8 reg;
0185 
0186     reg = da9150_reg_read(charger->da9150, DA9150_STATUS_J);
0187 
0188     /* Check if temperature limit reached */
0189     switch (reg & DA9150_CHG_TEMP_MASK) {
0190     case DA9150_CHG_TEMP_UNDER:
0191         val->intval = POWER_SUPPLY_HEALTH_COLD;
0192         return 0;
0193     case DA9150_CHG_TEMP_OVER:
0194         val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
0195         return 0;
0196     default:
0197         break;
0198     }
0199 
0200     /* Check for other health states */
0201     switch (reg & DA9150_CHG_STAT_MASK) {
0202     case DA9150_CHG_STAT_ACT:
0203     case DA9150_CHG_STAT_PRE:
0204         val->intval = POWER_SUPPLY_HEALTH_DEAD;
0205         break;
0206     case DA9150_CHG_STAT_TIME:
0207         val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
0208         break;
0209     default:
0210         val->intval = POWER_SUPPLY_HEALTH_GOOD;
0211         break;
0212     }
0213 
0214     return 0;
0215 }
0216 
0217 static int da9150_charger_battery_present(struct da9150_charger *charger,
0218                       union power_supply_propval *val)
0219 {
0220     u8 reg;
0221 
0222     /* Check if battery present or removed */
0223     reg = da9150_reg_read(charger->da9150, DA9150_STATUS_J);
0224     if ((reg & DA9150_CHG_STAT_MASK) == DA9150_CHG_STAT_BAT)
0225         val->intval = 0;
0226     else
0227         val->intval = 1;
0228 
0229     return 0;
0230 }
0231 
0232 static int da9150_charger_battery_charge_type(struct da9150_charger *charger,
0233                           union power_supply_propval *val)
0234 {
0235     u8 reg;
0236 
0237     reg = da9150_reg_read(charger->da9150, DA9150_STATUS_J);
0238 
0239     switch (reg & DA9150_CHG_STAT_MASK) {
0240     case DA9150_CHG_STAT_CC:
0241         val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
0242         break;
0243     case DA9150_CHG_STAT_ACT:
0244     case DA9150_CHG_STAT_PRE:
0245     case DA9150_CHG_STAT_CV:
0246         val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
0247         break;
0248     default:
0249         val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
0250         break;
0251     }
0252 
0253     return 0;
0254 }
0255 
0256 static int da9150_charger_battery_voltage_min(struct da9150_charger *charger,
0257                           union power_supply_propval *val)
0258 {
0259     u8 reg;
0260 
0261     reg = da9150_reg_read(charger->da9150, DA9150_PPR_CHGCTRL_C);
0262 
0263     /* Value starts at 2500 mV, 50 mV increments, presented in uV */
0264     val->intval = ((reg & DA9150_CHG_VFAULT_MASK) * 50000) + 2500000;
0265 
0266     return 0;
0267 }
0268 
0269 static int da9150_charger_battery_voltage_now(struct da9150_charger *charger,
0270                           union power_supply_propval *val)
0271 {
0272     int v_val, ret;
0273 
0274     /* Read processed value - mV units */
0275     ret = iio_read_channel_processed(charger->vbat_chan, &v_val);
0276     if (ret < 0)
0277         return ret;
0278 
0279     val->intval = v_val * 1000;
0280 
0281     return 0;
0282 }
0283 
0284 static int da9150_charger_battery_current_max(struct da9150_charger *charger,
0285                           union power_supply_propval *val)
0286 {
0287     int reg;
0288 
0289     reg = da9150_reg_read(charger->da9150, DA9150_PPR_CHGCTRL_D);
0290 
0291     /* 25mA increments */
0292     val->intval = reg * 25000;
0293 
0294     return 0;
0295 }
0296 
0297 static int da9150_charger_battery_voltage_max(struct da9150_charger *charger,
0298                           union power_supply_propval *val)
0299 {
0300     u8 reg;
0301 
0302     reg = da9150_reg_read(charger->da9150, DA9150_PPR_CHGCTRL_B);
0303 
0304     /* Value starts at 3650 mV, 25 mV increments, presented in uV */
0305     val->intval = ((reg & DA9150_CHG_VBAT_MASK) * 25000) + 3650000;
0306     return 0;
0307 }
0308 
0309 static enum power_supply_property da9150_charger_bat_props[] = {
0310     POWER_SUPPLY_PROP_STATUS,
0311     POWER_SUPPLY_PROP_ONLINE,
0312     POWER_SUPPLY_PROP_HEALTH,
0313     POWER_SUPPLY_PROP_PRESENT,
0314     POWER_SUPPLY_PROP_CHARGE_TYPE,
0315     POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
0316     POWER_SUPPLY_PROP_VOLTAGE_NOW,
0317     POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
0318     POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
0319 };
0320 
0321 static int da9150_charger_battery_get_prop(struct power_supply *psy,
0322                        enum power_supply_property psp,
0323                        union power_supply_propval *val)
0324 {
0325     struct da9150_charger *charger = dev_get_drvdata(psy->dev.parent);
0326     int ret;
0327 
0328     switch (psp) {
0329     case POWER_SUPPLY_PROP_STATUS:
0330         ret = da9150_charger_battery_status(charger, val);
0331         break;
0332     case POWER_SUPPLY_PROP_ONLINE:
0333         ret = da9150_charger_supply_online(charger, psy, val);
0334         break;
0335     case POWER_SUPPLY_PROP_HEALTH:
0336         ret = da9150_charger_battery_health(charger, val);
0337         break;
0338     case POWER_SUPPLY_PROP_PRESENT:
0339         ret = da9150_charger_battery_present(charger, val);
0340         break;
0341     case POWER_SUPPLY_PROP_CHARGE_TYPE:
0342         ret = da9150_charger_battery_charge_type(charger, val);
0343         break;
0344     case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
0345         ret = da9150_charger_battery_voltage_min(charger, val);
0346         break;
0347     case POWER_SUPPLY_PROP_VOLTAGE_NOW:
0348         ret = da9150_charger_battery_voltage_now(charger, val);
0349         break;
0350     case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
0351         ret = da9150_charger_battery_current_max(charger, val);
0352         break;
0353     case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
0354         ret = da9150_charger_battery_voltage_max(charger, val);
0355         break;
0356     default:
0357         ret = -EINVAL;
0358         break;
0359     }
0360 
0361     return ret;
0362 }
0363 
0364 static irqreturn_t da9150_charger_chg_irq(int irq, void *data)
0365 {
0366     struct da9150_charger *charger = data;
0367 
0368     power_supply_changed(charger->battery);
0369 
0370     return IRQ_HANDLED;
0371 }
0372 
0373 static irqreturn_t da9150_charger_tjunc_irq(int irq, void *data)
0374 {
0375     struct da9150_charger *charger = data;
0376 
0377     /* Nothing we can really do except report this. */
0378     dev_crit(charger->dev, "TJunc over temperature!!!\n");
0379     power_supply_changed(charger->usb);
0380 
0381     return IRQ_HANDLED;
0382 }
0383 
0384 static irqreturn_t da9150_charger_vfault_irq(int irq, void *data)
0385 {
0386     struct da9150_charger *charger = data;
0387 
0388     /* Nothing we can really do except report this. */
0389     dev_crit(charger->dev, "VSYS under voltage!!!\n");
0390     power_supply_changed(charger->usb);
0391     power_supply_changed(charger->battery);
0392 
0393     return IRQ_HANDLED;
0394 }
0395 
0396 static irqreturn_t da9150_charger_vbus_irq(int irq, void *data)
0397 {
0398     struct da9150_charger *charger = data;
0399     u8 reg;
0400 
0401     reg = da9150_reg_read(charger->da9150, DA9150_STATUS_H);
0402 
0403     /* Charger plugged in or battery only */
0404     switch (reg & DA9150_VBUS_STAT_MASK) {
0405     case DA9150_VBUS_STAT_OFF:
0406     case DA9150_VBUS_STAT_WAIT:
0407         charger->supply_online = charger->battery;
0408         break;
0409     case DA9150_VBUS_STAT_CHG:
0410         charger->supply_online = charger->usb;
0411         break;
0412     default:
0413         dev_warn(charger->dev, "Unknown VBUS state - reg = 0x%x\n",
0414              reg);
0415         charger->supply_online = NULL;
0416         break;
0417     }
0418 
0419     power_supply_changed(charger->usb);
0420     power_supply_changed(charger->battery);
0421 
0422     return IRQ_HANDLED;
0423 }
0424 
0425 static void da9150_charger_otg_work(struct work_struct *data)
0426 {
0427     struct da9150_charger *charger =
0428         container_of(data, struct da9150_charger, otg_work);
0429 
0430     switch (charger->usb_event) {
0431     case USB_EVENT_ID:
0432         /* Enable OTG Boost */
0433         da9150_set_bits(charger->da9150, DA9150_PPR_BKCTRL_A,
0434                 DA9150_VBUS_MODE_MASK, DA9150_VBUS_MODE_OTG);
0435         break;
0436     case USB_EVENT_NONE:
0437         /* Revert to charge mode */
0438         power_supply_changed(charger->usb);
0439         power_supply_changed(charger->battery);
0440         da9150_set_bits(charger->da9150, DA9150_PPR_BKCTRL_A,
0441                 DA9150_VBUS_MODE_MASK, DA9150_VBUS_MODE_CHG);
0442         break;
0443     }
0444 }
0445 
0446 static int da9150_charger_otg_ncb(struct notifier_block *nb, unsigned long val,
0447                   void *priv)
0448 {
0449     struct da9150_charger *charger =
0450         container_of(nb, struct da9150_charger, otg_nb);
0451 
0452     dev_dbg(charger->dev, "DA9150 OTG notify %lu\n", val);
0453 
0454     charger->usb_event = val;
0455     schedule_work(&charger->otg_work);
0456 
0457     return NOTIFY_OK;
0458 }
0459 
0460 static int da9150_charger_register_irq(struct platform_device *pdev,
0461                        irq_handler_t handler,
0462                        const char *irq_name)
0463 {
0464     struct device *dev = &pdev->dev;
0465     struct da9150_charger *charger = platform_get_drvdata(pdev);
0466     int irq, ret;
0467 
0468     irq = platform_get_irq_byname(pdev, irq_name);
0469     if (irq < 0) {
0470         dev_err(dev, "Failed to get IRQ CHG_STATUS: %d\n", irq);
0471         return irq;
0472     }
0473 
0474     ret = request_threaded_irq(irq, NULL, handler, IRQF_ONESHOT, irq_name,
0475                    charger);
0476     if (ret)
0477         dev_err(dev, "Failed to request IRQ %d: %d\n", irq, ret);
0478 
0479     return ret;
0480 }
0481 
0482 static void da9150_charger_unregister_irq(struct platform_device *pdev,
0483                       const char *irq_name)
0484 {
0485     struct device *dev = &pdev->dev;
0486     struct da9150_charger *charger = platform_get_drvdata(pdev);
0487     int irq;
0488 
0489     irq = platform_get_irq_byname(pdev, irq_name);
0490     if (irq < 0) {
0491         dev_err(dev, "Failed to get IRQ CHG_STATUS: %d\n", irq);
0492         return;
0493     }
0494 
0495     free_irq(irq, charger);
0496 }
0497 
0498 static const struct power_supply_desc usb_desc = {
0499     .name       = "da9150-usb",
0500     .type       = POWER_SUPPLY_TYPE_USB,
0501     .properties = da9150_charger_props,
0502     .num_properties = ARRAY_SIZE(da9150_charger_props),
0503     .get_property   = da9150_charger_get_prop,
0504 };
0505 
0506 static const struct power_supply_desc battery_desc = {
0507     .name       = "da9150-battery",
0508     .type       = POWER_SUPPLY_TYPE_BATTERY,
0509     .properties = da9150_charger_bat_props,
0510     .num_properties = ARRAY_SIZE(da9150_charger_bat_props),
0511     .get_property   = da9150_charger_battery_get_prop,
0512 };
0513 
0514 static int da9150_charger_probe(struct platform_device *pdev)
0515 {
0516     struct device *dev = &pdev->dev;
0517     struct da9150 *da9150 = dev_get_drvdata(dev->parent);
0518     struct da9150_charger *charger;
0519     u8 reg;
0520     int ret;
0521 
0522     charger = devm_kzalloc(dev, sizeof(struct da9150_charger), GFP_KERNEL);
0523     if (!charger)
0524         return -ENOMEM;
0525 
0526     platform_set_drvdata(pdev, charger);
0527     charger->da9150 = da9150;
0528     charger->dev = dev;
0529 
0530     /* Acquire ADC channels */
0531     charger->ibus_chan = iio_channel_get(dev, "CHAN_IBUS");
0532     if (IS_ERR(charger->ibus_chan)) {
0533         ret = PTR_ERR(charger->ibus_chan);
0534         goto ibus_chan_fail;
0535     }
0536 
0537     charger->vbus_chan = iio_channel_get(dev, "CHAN_VBUS");
0538     if (IS_ERR(charger->vbus_chan)) {
0539         ret = PTR_ERR(charger->vbus_chan);
0540         goto vbus_chan_fail;
0541     }
0542 
0543     charger->tjunc_chan = iio_channel_get(dev, "CHAN_TJUNC");
0544     if (IS_ERR(charger->tjunc_chan)) {
0545         ret = PTR_ERR(charger->tjunc_chan);
0546         goto tjunc_chan_fail;
0547     }
0548 
0549     charger->vbat_chan = iio_channel_get(dev, "CHAN_VBAT");
0550     if (IS_ERR(charger->vbat_chan)) {
0551         ret = PTR_ERR(charger->vbat_chan);
0552         goto vbat_chan_fail;
0553     }
0554 
0555     /* Register power supplies */
0556     charger->usb = power_supply_register(dev, &usb_desc, NULL);
0557     if (IS_ERR(charger->usb)) {
0558         ret = PTR_ERR(charger->usb);
0559         goto usb_fail;
0560     }
0561 
0562     charger->battery = power_supply_register(dev, &battery_desc, NULL);
0563     if (IS_ERR(charger->battery)) {
0564         ret = PTR_ERR(charger->battery);
0565         goto battery_fail;
0566     }
0567 
0568     /* Get initial online supply */
0569     reg = da9150_reg_read(da9150, DA9150_STATUS_H);
0570 
0571     switch (reg & DA9150_VBUS_STAT_MASK) {
0572     case DA9150_VBUS_STAT_OFF:
0573     case DA9150_VBUS_STAT_WAIT:
0574         charger->supply_online = charger->battery;
0575         break;
0576     case DA9150_VBUS_STAT_CHG:
0577         charger->supply_online = charger->usb;
0578         break;
0579     default:
0580         dev_warn(dev, "Unknown VBUS state - reg = 0x%x\n", reg);
0581         charger->supply_online = NULL;
0582         break;
0583     }
0584 
0585     /* Setup OTG reporting & configuration */
0586     charger->usb_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
0587     if (!IS_ERR_OR_NULL(charger->usb_phy)) {
0588         INIT_WORK(&charger->otg_work, da9150_charger_otg_work);
0589         charger->otg_nb.notifier_call = da9150_charger_otg_ncb;
0590         usb_register_notifier(charger->usb_phy, &charger->otg_nb);
0591     }
0592 
0593     /* Register IRQs */
0594     ret = da9150_charger_register_irq(pdev, da9150_charger_chg_irq,
0595                       "CHG_STATUS");
0596     if (ret < 0)
0597         goto chg_irq_fail;
0598 
0599     ret = da9150_charger_register_irq(pdev, da9150_charger_tjunc_irq,
0600                       "CHG_TJUNC");
0601     if (ret < 0)
0602         goto tjunc_irq_fail;
0603 
0604     ret = da9150_charger_register_irq(pdev, da9150_charger_vfault_irq,
0605                       "CHG_VFAULT");
0606     if (ret < 0)
0607         goto vfault_irq_fail;
0608 
0609     ret = da9150_charger_register_irq(pdev, da9150_charger_vbus_irq,
0610                       "CHG_VBUS");
0611     if (ret < 0)
0612         goto vbus_irq_fail;
0613 
0614     return 0;
0615 
0616 
0617 vbus_irq_fail:
0618     da9150_charger_unregister_irq(pdev, "CHG_VFAULT");
0619 vfault_irq_fail:
0620     da9150_charger_unregister_irq(pdev, "CHG_TJUNC");
0621 tjunc_irq_fail:
0622     da9150_charger_unregister_irq(pdev, "CHG_STATUS");
0623 chg_irq_fail:
0624     if (!IS_ERR_OR_NULL(charger->usb_phy))
0625         usb_unregister_notifier(charger->usb_phy, &charger->otg_nb);
0626 battery_fail:
0627     power_supply_unregister(charger->usb);
0628 
0629 usb_fail:
0630     iio_channel_release(charger->vbat_chan);
0631 
0632 vbat_chan_fail:
0633     iio_channel_release(charger->tjunc_chan);
0634 
0635 tjunc_chan_fail:
0636     iio_channel_release(charger->vbus_chan);
0637 
0638 vbus_chan_fail:
0639     iio_channel_release(charger->ibus_chan);
0640 
0641 ibus_chan_fail:
0642     return ret;
0643 }
0644 
0645 static int da9150_charger_remove(struct platform_device *pdev)
0646 {
0647     struct da9150_charger *charger = platform_get_drvdata(pdev);
0648     int irq;
0649 
0650     /* Make sure IRQs are released before unregistering power supplies */
0651     irq = platform_get_irq_byname(pdev, "CHG_VBUS");
0652     free_irq(irq, charger);
0653 
0654     irq = platform_get_irq_byname(pdev, "CHG_VFAULT");
0655     free_irq(irq, charger);
0656 
0657     irq = platform_get_irq_byname(pdev, "CHG_TJUNC");
0658     free_irq(irq, charger);
0659 
0660     irq = platform_get_irq_byname(pdev, "CHG_STATUS");
0661     free_irq(irq, charger);
0662 
0663     if (!IS_ERR_OR_NULL(charger->usb_phy))
0664         usb_unregister_notifier(charger->usb_phy, &charger->otg_nb);
0665 
0666     power_supply_unregister(charger->battery);
0667     power_supply_unregister(charger->usb);
0668 
0669     /* Release ADC channels */
0670     iio_channel_release(charger->ibus_chan);
0671     iio_channel_release(charger->vbus_chan);
0672     iio_channel_release(charger->tjunc_chan);
0673     iio_channel_release(charger->vbat_chan);
0674 
0675     return 0;
0676 }
0677 
0678 static struct platform_driver da9150_charger_driver = {
0679     .driver = {
0680         .name = "da9150-charger",
0681     },
0682     .probe = da9150_charger_probe,
0683     .remove = da9150_charger_remove,
0684 };
0685 
0686 module_platform_driver(da9150_charger_driver);
0687 
0688 MODULE_DESCRIPTION("Charger Driver for DA9150");
0689 MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>");
0690 MODULE_LICENSE("GPL");