Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Battery driver for wm8350 PMIC
0004  *
0005  * Copyright 2007, 2008 Wolfson Microelectronics PLC.
0006  *
0007  * Based on OLPC Battery Driver
0008  *
0009  * Copyright 2006  David Woodhouse <dwmw2@infradead.org>
0010  */
0011 
0012 #include <linux/module.h>
0013 #include <linux/err.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/power_supply.h>
0016 #include <linux/mfd/wm8350/supply.h>
0017 #include <linux/mfd/wm8350/core.h>
0018 #include <linux/mfd/wm8350/comparator.h>
0019 
0020 static int wm8350_read_battery_uvolts(struct wm8350 *wm8350)
0021 {
0022     return wm8350_read_auxadc(wm8350, WM8350_AUXADC_BATT, 0, 0)
0023         * WM8350_AUX_COEFF;
0024 }
0025 
0026 static int wm8350_read_line_uvolts(struct wm8350 *wm8350)
0027 {
0028     return wm8350_read_auxadc(wm8350, WM8350_AUXADC_LINE, 0, 0)
0029         * WM8350_AUX_COEFF;
0030 }
0031 
0032 static int wm8350_read_usb_uvolts(struct wm8350 *wm8350)
0033 {
0034     return wm8350_read_auxadc(wm8350, WM8350_AUXADC_USB, 0, 0)
0035         * WM8350_AUX_COEFF;
0036 }
0037 
0038 #define WM8350_BATT_SUPPLY  1
0039 #define WM8350_USB_SUPPLY   2
0040 #define WM8350_LINE_SUPPLY  4
0041 
0042 static inline int wm8350_charge_time_min(struct wm8350 *wm8350, int min)
0043 {
0044     if (!wm8350->power.rev_g_coeff)
0045         return (((min - 30) / 15) & 0xf) << 8;
0046     else
0047         return (((min - 30) / 30) & 0xf) << 8;
0048 }
0049 
0050 static int wm8350_get_supplies(struct wm8350 *wm8350)
0051 {
0052     u16 sm, ov, co, chrg;
0053     int supplies = 0;
0054 
0055     sm = wm8350_reg_read(wm8350, WM8350_STATE_MACHINE_STATUS);
0056     ov = wm8350_reg_read(wm8350, WM8350_MISC_OVERRIDES);
0057     co = wm8350_reg_read(wm8350, WM8350_COMPARATOR_OVERRIDES);
0058     chrg = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2);
0059 
0060     /* USB_SM */
0061     sm = (sm & WM8350_USB_SM_MASK) >> WM8350_USB_SM_SHIFT;
0062 
0063     /* CHG_ISEL */
0064     chrg &= WM8350_CHG_ISEL_MASK;
0065 
0066     /* If the USB state machine is active then we're using that with or
0067      * without battery, otherwise check for wall supply */
0068     if (((sm == WM8350_USB_SM_100_SLV) ||
0069          (sm == WM8350_USB_SM_500_SLV) ||
0070          (sm == WM8350_USB_SM_STDBY_SLV))
0071         && !(ov & WM8350_USB_LIMIT_OVRDE))
0072         supplies = WM8350_USB_SUPPLY;
0073     else if (((sm == WM8350_USB_SM_100_SLV) ||
0074           (sm == WM8350_USB_SM_500_SLV) ||
0075           (sm == WM8350_USB_SM_STDBY_SLV))
0076          && (ov & WM8350_USB_LIMIT_OVRDE) && (chrg == 0))
0077         supplies = WM8350_USB_SUPPLY | WM8350_BATT_SUPPLY;
0078     else if (co & WM8350_WALL_FB_OVRDE)
0079         supplies = WM8350_LINE_SUPPLY;
0080     else
0081         supplies = WM8350_BATT_SUPPLY;
0082 
0083     return supplies;
0084 }
0085 
0086 static int wm8350_charger_config(struct wm8350 *wm8350,
0087                  struct wm8350_charger_policy *policy)
0088 {
0089     u16 reg, eoc_mA, fast_limit_mA;
0090 
0091     if (!policy) {
0092         dev_warn(wm8350->dev,
0093              "No charger policy, charger not configured.\n");
0094         return -EINVAL;
0095     }
0096 
0097     /* make sure USB fast charge current is not > 500mA */
0098     if (policy->fast_limit_USB_mA > 500) {
0099         dev_err(wm8350->dev, "USB fast charge > 500mA\n");
0100         return -EINVAL;
0101     }
0102 
0103     eoc_mA = WM8350_CHG_EOC_mA(policy->eoc_mA);
0104 
0105     wm8350_reg_unlock(wm8350);
0106 
0107     reg = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_1)
0108         & WM8350_CHG_ENA_R168;
0109     wm8350_reg_write(wm8350, WM8350_BATTERY_CHARGER_CONTROL_1,
0110              reg | eoc_mA | policy->trickle_start_mV |
0111              WM8350_CHG_TRICKLE_TEMP_CHOKE |
0112              WM8350_CHG_TRICKLE_USB_CHOKE |
0113              WM8350_CHG_FAST_USB_THROTTLE);
0114 
0115     if (wm8350_get_supplies(wm8350) & WM8350_USB_SUPPLY) {
0116         fast_limit_mA =
0117             WM8350_CHG_FAST_LIMIT_mA(policy->fast_limit_USB_mA);
0118         wm8350_reg_write(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2,
0119                 policy->charge_mV | policy->trickle_charge_USB_mA |
0120                 fast_limit_mA | wm8350_charge_time_min(wm8350,
0121                         policy->charge_timeout));
0122 
0123     } else {
0124         fast_limit_mA =
0125             WM8350_CHG_FAST_LIMIT_mA(policy->fast_limit_mA);
0126         wm8350_reg_write(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2,
0127                 policy->charge_mV | policy->trickle_charge_mA |
0128                 fast_limit_mA | wm8350_charge_time_min(wm8350,
0129                         policy->charge_timeout));
0130     }
0131 
0132     wm8350_reg_lock(wm8350);
0133     return 0;
0134 }
0135 
0136 static int wm8350_batt_status(struct wm8350 *wm8350)
0137 {
0138     u16 state;
0139 
0140     state = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2);
0141     state &= WM8350_CHG_STS_MASK;
0142 
0143     switch (state) {
0144     case WM8350_CHG_STS_OFF:
0145         return POWER_SUPPLY_STATUS_DISCHARGING;
0146 
0147     case WM8350_CHG_STS_TRICKLE:
0148     case WM8350_CHG_STS_FAST:
0149         return POWER_SUPPLY_STATUS_CHARGING;
0150 
0151     default:
0152         return POWER_SUPPLY_STATUS_UNKNOWN;
0153     }
0154 }
0155 
0156 static ssize_t charger_state_show(struct device *dev,
0157                  struct device_attribute *attr, char *buf)
0158 {
0159     struct wm8350 *wm8350 = dev_get_drvdata(dev);
0160     char *charge;
0161     int state;
0162 
0163     state = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2) &
0164         WM8350_CHG_STS_MASK;
0165     switch (state) {
0166     case WM8350_CHG_STS_OFF:
0167         charge = "Charger Off";
0168         break;
0169     case WM8350_CHG_STS_TRICKLE:
0170         charge = "Trickle Charging";
0171         break;
0172     case WM8350_CHG_STS_FAST:
0173         charge = "Fast Charging";
0174         break;
0175     default:
0176         return 0;
0177     }
0178 
0179     return sprintf(buf, "%s\n", charge);
0180 }
0181 
0182 static DEVICE_ATTR_RO(charger_state);
0183 
0184 static irqreturn_t wm8350_charger_handler(int irq, void *data)
0185 {
0186     struct wm8350 *wm8350 = data;
0187     struct wm8350_power *power = &wm8350->power;
0188     struct wm8350_charger_policy *policy = power->policy;
0189 
0190     switch (irq - wm8350->irq_base) {
0191     case WM8350_IRQ_CHG_BAT_FAIL:
0192         dev_err(wm8350->dev, "battery failed\n");
0193         break;
0194     case WM8350_IRQ_CHG_TO:
0195         dev_err(wm8350->dev, "charger timeout\n");
0196         power_supply_changed(power->battery);
0197         break;
0198 
0199     case WM8350_IRQ_CHG_BAT_HOT:
0200     case WM8350_IRQ_CHG_BAT_COLD:
0201     case WM8350_IRQ_CHG_START:
0202     case WM8350_IRQ_CHG_END:
0203         power_supply_changed(power->battery);
0204         break;
0205 
0206     case WM8350_IRQ_CHG_FAST_RDY:
0207         dev_dbg(wm8350->dev, "fast charger ready\n");
0208         wm8350_charger_config(wm8350, policy);
0209         wm8350_reg_unlock(wm8350);
0210         wm8350_set_bits(wm8350, WM8350_BATTERY_CHARGER_CONTROL_1,
0211                 WM8350_CHG_FAST);
0212         wm8350_reg_lock(wm8350);
0213         break;
0214 
0215     case WM8350_IRQ_CHG_VBATT_LT_3P9:
0216         dev_warn(wm8350->dev, "battery < 3.9V\n");
0217         break;
0218     case WM8350_IRQ_CHG_VBATT_LT_3P1:
0219         dev_warn(wm8350->dev, "battery < 3.1V\n");
0220         break;
0221     case WM8350_IRQ_CHG_VBATT_LT_2P85:
0222         dev_warn(wm8350->dev, "battery < 2.85V\n");
0223         break;
0224 
0225         /* Supply change.  We will overnotify but it should do
0226          * no harm. */
0227     case WM8350_IRQ_EXT_USB_FB:
0228     case WM8350_IRQ_EXT_WALL_FB:
0229         wm8350_charger_config(wm8350, policy);
0230         fallthrough;
0231     case WM8350_IRQ_EXT_BAT_FB:
0232         power_supply_changed(power->battery);
0233         power_supply_changed(power->usb);
0234         power_supply_changed(power->ac);
0235         break;
0236 
0237     default:
0238         dev_err(wm8350->dev, "Unknown interrupt %d\n", irq);
0239     }
0240 
0241     return IRQ_HANDLED;
0242 }
0243 
0244 /*********************************************************************
0245  *      AC Power
0246  *********************************************************************/
0247 static int wm8350_ac_get_prop(struct power_supply *psy,
0248                   enum power_supply_property psp,
0249                   union power_supply_propval *val)
0250 {
0251     struct wm8350 *wm8350 = dev_get_drvdata(psy->dev.parent);
0252     int ret = 0;
0253 
0254     switch (psp) {
0255     case POWER_SUPPLY_PROP_ONLINE:
0256         val->intval = !!(wm8350_get_supplies(wm8350) &
0257                  WM8350_LINE_SUPPLY);
0258         break;
0259     case POWER_SUPPLY_PROP_VOLTAGE_NOW:
0260         val->intval = wm8350_read_line_uvolts(wm8350);
0261         break;
0262     default:
0263         ret = -EINVAL;
0264         break;
0265     }
0266     return ret;
0267 }
0268 
0269 static enum power_supply_property wm8350_ac_props[] = {
0270     POWER_SUPPLY_PROP_ONLINE,
0271     POWER_SUPPLY_PROP_VOLTAGE_NOW,
0272 };
0273 
0274 /*********************************************************************
0275  *      USB Power
0276  *********************************************************************/
0277 static int wm8350_usb_get_prop(struct power_supply *psy,
0278                    enum power_supply_property psp,
0279                    union power_supply_propval *val)
0280 {
0281     struct wm8350 *wm8350 = dev_get_drvdata(psy->dev.parent);
0282     int ret = 0;
0283 
0284     switch (psp) {
0285     case POWER_SUPPLY_PROP_ONLINE:
0286         val->intval = !!(wm8350_get_supplies(wm8350) &
0287                  WM8350_USB_SUPPLY);
0288         break;
0289     case POWER_SUPPLY_PROP_VOLTAGE_NOW:
0290         val->intval = wm8350_read_usb_uvolts(wm8350);
0291         break;
0292     default:
0293         ret = -EINVAL;
0294         break;
0295     }
0296     return ret;
0297 }
0298 
0299 static enum power_supply_property wm8350_usb_props[] = {
0300     POWER_SUPPLY_PROP_ONLINE,
0301     POWER_SUPPLY_PROP_VOLTAGE_NOW,
0302 };
0303 
0304 /*********************************************************************
0305  *      Battery properties
0306  *********************************************************************/
0307 
0308 static int wm8350_bat_check_health(struct wm8350 *wm8350)
0309 {
0310     u16 reg;
0311 
0312     if (wm8350_read_battery_uvolts(wm8350) < 2850000)
0313         return POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
0314 
0315     reg = wm8350_reg_read(wm8350, WM8350_CHARGER_OVERRIDES);
0316     if (reg & WM8350_CHG_BATT_HOT_OVRDE)
0317         return POWER_SUPPLY_HEALTH_OVERHEAT;
0318 
0319     if (reg & WM8350_CHG_BATT_COLD_OVRDE)
0320         return POWER_SUPPLY_HEALTH_COLD;
0321 
0322     return POWER_SUPPLY_HEALTH_GOOD;
0323 }
0324 
0325 static int wm8350_bat_get_charge_type(struct wm8350 *wm8350)
0326 {
0327     int state;
0328 
0329     state = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2) &
0330         WM8350_CHG_STS_MASK;
0331     switch (state) {
0332     case WM8350_CHG_STS_OFF:
0333         return POWER_SUPPLY_CHARGE_TYPE_NONE;
0334     case WM8350_CHG_STS_TRICKLE:
0335         return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
0336     case WM8350_CHG_STS_FAST:
0337         return POWER_SUPPLY_CHARGE_TYPE_FAST;
0338     default:
0339         return POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
0340     }
0341 }
0342 
0343 static int wm8350_bat_get_property(struct power_supply *psy,
0344                    enum power_supply_property psp,
0345                    union power_supply_propval *val)
0346 {
0347     struct wm8350 *wm8350 = dev_get_drvdata(psy->dev.parent);
0348     int ret = 0;
0349 
0350     switch (psp) {
0351     case POWER_SUPPLY_PROP_STATUS:
0352         val->intval = wm8350_batt_status(wm8350);
0353         break;
0354     case POWER_SUPPLY_PROP_ONLINE:
0355         val->intval = !!(wm8350_get_supplies(wm8350) &
0356                  WM8350_BATT_SUPPLY);
0357         break;
0358     case POWER_SUPPLY_PROP_VOLTAGE_NOW:
0359         val->intval = wm8350_read_battery_uvolts(wm8350);
0360         break;
0361     case POWER_SUPPLY_PROP_HEALTH:
0362         val->intval = wm8350_bat_check_health(wm8350);
0363         break;
0364     case POWER_SUPPLY_PROP_CHARGE_TYPE:
0365         val->intval = wm8350_bat_get_charge_type(wm8350);
0366         break;
0367     default:
0368         ret = -EINVAL;
0369         break;
0370     }
0371 
0372     return ret;
0373 }
0374 
0375 static enum power_supply_property wm8350_bat_props[] = {
0376     POWER_SUPPLY_PROP_STATUS,
0377     POWER_SUPPLY_PROP_ONLINE,
0378     POWER_SUPPLY_PROP_VOLTAGE_NOW,
0379     POWER_SUPPLY_PROP_HEALTH,
0380     POWER_SUPPLY_PROP_CHARGE_TYPE,
0381 };
0382 
0383 static const struct power_supply_desc wm8350_ac_desc = {
0384     .name       = "wm8350-ac",
0385     .type       = POWER_SUPPLY_TYPE_MAINS,
0386     .properties = wm8350_ac_props,
0387     .num_properties = ARRAY_SIZE(wm8350_ac_props),
0388     .get_property   = wm8350_ac_get_prop,
0389 };
0390 
0391 static const struct power_supply_desc wm8350_battery_desc = {
0392     .name       = "wm8350-battery",
0393     .properties = wm8350_bat_props,
0394     .num_properties = ARRAY_SIZE(wm8350_bat_props),
0395     .get_property   = wm8350_bat_get_property,
0396     .use_for_apm    = 1,
0397 };
0398 
0399 static const struct power_supply_desc wm8350_usb_desc = {
0400     .name       = "wm8350-usb",
0401     .type       = POWER_SUPPLY_TYPE_USB,
0402     .properties = wm8350_usb_props,
0403     .num_properties = ARRAY_SIZE(wm8350_usb_props),
0404     .get_property   = wm8350_usb_get_prop,
0405 };
0406 
0407 /*********************************************************************
0408  *      Initialisation
0409  *********************************************************************/
0410 
0411 static int wm8350_init_charger(struct wm8350 *wm8350)
0412 {
0413     int ret;
0414 
0415     /* register our interest in charger events */
0416     ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT,
0417                 wm8350_charger_handler, 0, "Battery hot", wm8350);
0418     if (ret)
0419         goto err;
0420 
0421     ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD,
0422                 wm8350_charger_handler, 0, "Battery cold", wm8350);
0423     if (ret)
0424         goto free_chg_bat_hot;
0425 
0426     ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL,
0427                 wm8350_charger_handler, 0, "Battery fail", wm8350);
0428     if (ret)
0429         goto free_chg_bat_cold;
0430 
0431     ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_TO,
0432                 wm8350_charger_handler, 0,
0433                 "Charger timeout", wm8350);
0434     if (ret)
0435         goto free_chg_bat_fail;
0436 
0437     ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_END,
0438                 wm8350_charger_handler, 0,
0439                 "Charge end", wm8350);
0440     if (ret)
0441         goto free_chg_to;
0442 
0443     ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_START,
0444                 wm8350_charger_handler, 0,
0445                 "Charge start", wm8350);
0446     if (ret)
0447         goto free_chg_end;
0448 
0449     ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY,
0450                 wm8350_charger_handler, 0,
0451                 "Fast charge ready", wm8350);
0452     if (ret)
0453         goto free_chg_start;
0454 
0455     ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9,
0456                 wm8350_charger_handler, 0,
0457                 "Battery <3.9V", wm8350);
0458     if (ret)
0459         goto free_chg_fast_rdy;
0460 
0461     ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1,
0462                 wm8350_charger_handler, 0,
0463                 "Battery <3.1V", wm8350);
0464     if (ret)
0465         goto free_chg_vbatt_lt_3p9;
0466 
0467     ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85,
0468                 wm8350_charger_handler, 0,
0469                 "Battery <2.85V", wm8350);
0470     if (ret)
0471         goto free_chg_vbatt_lt_3p1;
0472 
0473     /* and supply change events */
0474     ret = wm8350_register_irq(wm8350, WM8350_IRQ_EXT_USB_FB,
0475                 wm8350_charger_handler, 0, "USB", wm8350);
0476     if (ret)
0477         goto free_chg_vbatt_lt_2p85;
0478 
0479     ret = wm8350_register_irq(wm8350, WM8350_IRQ_EXT_WALL_FB,
0480                 wm8350_charger_handler, 0, "Wall", wm8350);
0481     if (ret)
0482         goto free_ext_usb_fb;
0483 
0484     ret = wm8350_register_irq(wm8350, WM8350_IRQ_EXT_BAT_FB,
0485                 wm8350_charger_handler, 0, "Battery", wm8350);
0486     if (ret)
0487         goto free_ext_wall_fb;
0488 
0489     return 0;
0490 
0491 free_ext_wall_fb:
0492     wm8350_free_irq(wm8350, WM8350_IRQ_EXT_WALL_FB, wm8350);
0493 free_ext_usb_fb:
0494     wm8350_free_irq(wm8350, WM8350_IRQ_EXT_USB_FB, wm8350);
0495 free_chg_vbatt_lt_2p85:
0496     wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85, wm8350);
0497 free_chg_vbatt_lt_3p1:
0498     wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1, wm8350);
0499 free_chg_vbatt_lt_3p9:
0500     wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9, wm8350);
0501 free_chg_fast_rdy:
0502     wm8350_free_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY, wm8350);
0503 free_chg_start:
0504     wm8350_free_irq(wm8350, WM8350_IRQ_CHG_START, wm8350);
0505 free_chg_end:
0506     wm8350_free_irq(wm8350, WM8350_IRQ_CHG_END, wm8350);
0507 free_chg_to:
0508     wm8350_free_irq(wm8350, WM8350_IRQ_CHG_TO, wm8350);
0509 free_chg_bat_fail:
0510     wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL, wm8350);
0511 free_chg_bat_cold:
0512     wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD, wm8350);
0513 free_chg_bat_hot:
0514     wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT, wm8350);
0515 err:
0516     return ret;
0517 }
0518 
0519 static void free_charger_irq(struct wm8350 *wm8350)
0520 {
0521     wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT, wm8350);
0522     wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD, wm8350);
0523     wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL, wm8350);
0524     wm8350_free_irq(wm8350, WM8350_IRQ_CHG_TO, wm8350);
0525     wm8350_free_irq(wm8350, WM8350_IRQ_CHG_END, wm8350);
0526     wm8350_free_irq(wm8350, WM8350_IRQ_CHG_START, wm8350);
0527     wm8350_free_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY, wm8350);
0528     wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9, wm8350);
0529     wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1, wm8350);
0530     wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85, wm8350);
0531     wm8350_free_irq(wm8350, WM8350_IRQ_EXT_USB_FB, wm8350);
0532     wm8350_free_irq(wm8350, WM8350_IRQ_EXT_WALL_FB, wm8350);
0533     wm8350_free_irq(wm8350, WM8350_IRQ_EXT_BAT_FB, wm8350);
0534 }
0535 
0536 static int wm8350_power_probe(struct platform_device *pdev)
0537 {
0538     struct wm8350 *wm8350 = platform_get_drvdata(pdev);
0539     struct wm8350_power *power = &wm8350->power;
0540     struct wm8350_charger_policy *policy = power->policy;
0541     int ret;
0542 
0543     power->ac = power_supply_register(&pdev->dev, &wm8350_ac_desc, NULL);
0544     if (IS_ERR(power->ac))
0545         return PTR_ERR(power->ac);
0546 
0547     power->battery = power_supply_register(&pdev->dev, &wm8350_battery_desc,
0548                            NULL);
0549     if (IS_ERR(power->battery)) {
0550         ret = PTR_ERR(power->battery);
0551         goto battery_failed;
0552     }
0553 
0554     power->usb = power_supply_register(&pdev->dev, &wm8350_usb_desc, NULL);
0555     if (IS_ERR(power->usb)) {
0556         ret = PTR_ERR(power->usb);
0557         goto usb_failed;
0558     }
0559 
0560     ret = device_create_file(&pdev->dev, &dev_attr_charger_state);
0561     if (ret < 0)
0562         dev_warn(wm8350->dev, "failed to add charge sysfs: %d\n", ret);
0563     ret = 0;
0564 
0565     wm8350_init_charger(wm8350);
0566     if (wm8350_charger_config(wm8350, policy) == 0) {
0567         wm8350_reg_unlock(wm8350);
0568         wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CHG_ENA);
0569         wm8350_reg_lock(wm8350);
0570     }
0571 
0572     return ret;
0573 
0574 usb_failed:
0575     power_supply_unregister(power->battery);
0576 battery_failed:
0577     power_supply_unregister(power->ac);
0578 
0579     return ret;
0580 }
0581 
0582 static int wm8350_power_remove(struct platform_device *pdev)
0583 {
0584     struct wm8350 *wm8350 = platform_get_drvdata(pdev);
0585     struct wm8350_power *power = &wm8350->power;
0586 
0587     free_charger_irq(wm8350);
0588     device_remove_file(&pdev->dev, &dev_attr_charger_state);
0589     power_supply_unregister(power->battery);
0590     power_supply_unregister(power->ac);
0591     power_supply_unregister(power->usb);
0592     return 0;
0593 }
0594 
0595 static struct platform_driver wm8350_power_driver = {
0596     .probe = wm8350_power_probe,
0597     .remove = wm8350_power_remove,
0598     .driver = {
0599         .name = "wm8350-power",
0600     },
0601 };
0602 
0603 module_platform_driver(wm8350_power_driver);
0604 
0605 MODULE_LICENSE("GPL");
0606 MODULE_DESCRIPTION("Power supply driver for WM8350");
0607 MODULE_ALIAS("platform:wm8350-power");