linux/drivers/power/supply/wm831x_power.c
<<
>>
Prefs
   1/*
   2 * PMU driver for Wolfson Microelectronics wm831x PMICs
   3 *
   4 * Copyright 2009 Wolfson Microelectronics PLC.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 */
  10
  11#include <linux/module.h>
  12#include <linux/err.h>
  13#include <linux/platform_device.h>
  14#include <linux/power_supply.h>
  15#include <linux/slab.h>
  16#include <linux/usb/phy.h>
  17
  18#include <linux/mfd/wm831x/core.h>
  19#include <linux/mfd/wm831x/auxadc.h>
  20#include <linux/mfd/wm831x/pmu.h>
  21#include <linux/mfd/wm831x/pdata.h>
  22
  23struct wm831x_power {
  24        struct wm831x *wm831x;
  25        struct power_supply *wall;
  26        struct power_supply *usb;
  27        struct power_supply *battery;
  28        struct power_supply_desc wall_desc;
  29        struct power_supply_desc usb_desc;
  30        struct power_supply_desc battery_desc;
  31        char wall_name[20];
  32        char usb_name[20];
  33        char battery_name[20];
  34        bool have_battery;
  35        struct usb_phy *usb_phy;
  36        struct notifier_block usb_notify;
  37};
  38
  39static int wm831x_power_check_online(struct wm831x *wm831x, int supply,
  40                                     union power_supply_propval *val)
  41{
  42        int ret;
  43
  44        ret = wm831x_reg_read(wm831x, WM831X_SYSTEM_STATUS);
  45        if (ret < 0)
  46                return ret;
  47
  48        if (ret & supply)
  49                val->intval = 1;
  50        else
  51                val->intval = 0;
  52
  53        return 0;
  54}
  55
  56static int wm831x_power_read_voltage(struct wm831x *wm831x,
  57                                     enum wm831x_auxadc src,
  58                                     union power_supply_propval *val)
  59{
  60        int ret;
  61
  62        ret = wm831x_auxadc_read_uv(wm831x, src);
  63        if (ret >= 0)
  64                val->intval = ret;
  65
  66        return ret;
  67}
  68
  69/*********************************************************************
  70 *              WALL Power
  71 *********************************************************************/
  72static int wm831x_wall_get_prop(struct power_supply *psy,
  73                                enum power_supply_property psp,
  74                                union power_supply_propval *val)
  75{
  76        struct wm831x_power *wm831x_power = dev_get_drvdata(psy->dev.parent);
  77        struct wm831x *wm831x = wm831x_power->wm831x;
  78        int ret = 0;
  79
  80        switch (psp) {
  81        case POWER_SUPPLY_PROP_ONLINE:
  82                ret = wm831x_power_check_online(wm831x, WM831X_PWR_WALL, val);
  83                break;
  84        case POWER_SUPPLY_PROP_VOLTAGE_NOW:
  85                ret = wm831x_power_read_voltage(wm831x, WM831X_AUX_WALL, val);
  86                break;
  87        default:
  88                ret = -EINVAL;
  89                break;
  90        }
  91
  92        return ret;
  93}
  94
  95static enum power_supply_property wm831x_wall_props[] = {
  96        POWER_SUPPLY_PROP_ONLINE,
  97        POWER_SUPPLY_PROP_VOLTAGE_NOW,
  98};
  99
 100/*********************************************************************
 101 *              USB Power
 102 *********************************************************************/
 103static int wm831x_usb_get_prop(struct power_supply *psy,
 104                               enum power_supply_property psp,
 105                               union power_supply_propval *val)
 106{
 107        struct wm831x_power *wm831x_power = dev_get_drvdata(psy->dev.parent);
 108        struct wm831x *wm831x = wm831x_power->wm831x;
 109        int ret = 0;
 110
 111        switch (psp) {
 112        case POWER_SUPPLY_PROP_ONLINE:
 113                ret = wm831x_power_check_online(wm831x, WM831X_PWR_USB, val);
 114                break;
 115        case POWER_SUPPLY_PROP_VOLTAGE_NOW:
 116                ret = wm831x_power_read_voltage(wm831x, WM831X_AUX_USB, val);
 117                break;
 118        default:
 119                ret = -EINVAL;
 120                break;
 121        }
 122
 123        return ret;
 124}
 125
 126static enum power_supply_property wm831x_usb_props[] = {
 127        POWER_SUPPLY_PROP_ONLINE,
 128        POWER_SUPPLY_PROP_VOLTAGE_NOW,
 129};
 130
 131/* In milliamps */
 132static const unsigned int wm831x_usb_limits[] = {
 133        0,
 134        2,
 135        100,
 136        500,
 137        900,
 138        1500,
 139        1800,
 140        550,
 141};
 142
 143static int wm831x_usb_limit_change(struct notifier_block *nb,
 144                                   unsigned long limit, void *data)
 145{
 146        struct wm831x_power *wm831x_power = container_of(nb,
 147                                                         struct wm831x_power,
 148                                                         usb_notify);
 149        unsigned int i, best;
 150
 151        /* Find the highest supported limit */
 152        best = 0;
 153        for (i = 0; i < ARRAY_SIZE(wm831x_usb_limits); i++) {
 154                if (limit >= wm831x_usb_limits[i] &&
 155                    wm831x_usb_limits[best] < wm831x_usb_limits[i])
 156                        best = i;
 157        }
 158
 159        dev_dbg(wm831x_power->wm831x->dev,
 160                "Limiting USB current to %umA", wm831x_usb_limits[best]);
 161
 162        wm831x_set_bits(wm831x_power->wm831x, WM831X_POWER_STATE,
 163                        WM831X_USB_ILIM_MASK, best);
 164
 165        return 0;
 166}
 167
 168/*********************************************************************
 169 *              Battery properties
 170 *********************************************************************/
 171
 172struct chg_map {
 173        int val;
 174        int reg_val;
 175};
 176
 177static struct chg_map trickle_ilims[] = {
 178        {  50, 0 << WM831X_CHG_TRKL_ILIM_SHIFT },
 179        { 100, 1 << WM831X_CHG_TRKL_ILIM_SHIFT },
 180        { 150, 2 << WM831X_CHG_TRKL_ILIM_SHIFT },
 181        { 200, 3 << WM831X_CHG_TRKL_ILIM_SHIFT },
 182};
 183
 184static struct chg_map vsels[] = {
 185        { 4050, 0 << WM831X_CHG_VSEL_SHIFT },
 186        { 4100, 1 << WM831X_CHG_VSEL_SHIFT },
 187        { 4150, 2 << WM831X_CHG_VSEL_SHIFT },
 188        { 4200, 3 << WM831X_CHG_VSEL_SHIFT },
 189};
 190
 191static struct chg_map fast_ilims[] = {
 192        {    0,  0 << WM831X_CHG_FAST_ILIM_SHIFT },
 193        {   50,  1 << WM831X_CHG_FAST_ILIM_SHIFT },
 194        {  100,  2 << WM831X_CHG_FAST_ILIM_SHIFT },
 195        {  150,  3 << WM831X_CHG_FAST_ILIM_SHIFT },
 196        {  200,  4 << WM831X_CHG_FAST_ILIM_SHIFT },
 197        {  250,  5 << WM831X_CHG_FAST_ILIM_SHIFT },
 198        {  300,  6 << WM831X_CHG_FAST_ILIM_SHIFT },
 199        {  350,  7 << WM831X_CHG_FAST_ILIM_SHIFT },
 200        {  400,  8 << WM831X_CHG_FAST_ILIM_SHIFT },
 201        {  450,  9 << WM831X_CHG_FAST_ILIM_SHIFT },
 202        {  500, 10 << WM831X_CHG_FAST_ILIM_SHIFT },
 203        {  600, 11 << WM831X_CHG_FAST_ILIM_SHIFT },
 204        {  700, 12 << WM831X_CHG_FAST_ILIM_SHIFT },
 205        {  800, 13 << WM831X_CHG_FAST_ILIM_SHIFT },
 206        {  900, 14 << WM831X_CHG_FAST_ILIM_SHIFT },
 207        { 1000, 15 << WM831X_CHG_FAST_ILIM_SHIFT },
 208};
 209
 210static struct chg_map eoc_iterms[] = {
 211        { 20, 0 << WM831X_CHG_ITERM_SHIFT },
 212        { 30, 1 << WM831X_CHG_ITERM_SHIFT },
 213        { 40, 2 << WM831X_CHG_ITERM_SHIFT },
 214        { 50, 3 << WM831X_CHG_ITERM_SHIFT },
 215        { 60, 4 << WM831X_CHG_ITERM_SHIFT },
 216        { 70, 5 << WM831X_CHG_ITERM_SHIFT },
 217        { 80, 6 << WM831X_CHG_ITERM_SHIFT },
 218        { 90, 7 << WM831X_CHG_ITERM_SHIFT },
 219};
 220
 221static struct chg_map chg_times[] = {
 222        {  60,  0 << WM831X_CHG_TIME_SHIFT },
 223        {  90,  1 << WM831X_CHG_TIME_SHIFT },
 224        { 120,  2 << WM831X_CHG_TIME_SHIFT },
 225        { 150,  3 << WM831X_CHG_TIME_SHIFT },
 226        { 180,  4 << WM831X_CHG_TIME_SHIFT },
 227        { 210,  5 << WM831X_CHG_TIME_SHIFT },
 228        { 240,  6 << WM831X_CHG_TIME_SHIFT },
 229        { 270,  7 << WM831X_CHG_TIME_SHIFT },
 230        { 300,  8 << WM831X_CHG_TIME_SHIFT },
 231        { 330,  9 << WM831X_CHG_TIME_SHIFT },
 232        { 360, 10 << WM831X_CHG_TIME_SHIFT },
 233        { 390, 11 << WM831X_CHG_TIME_SHIFT },
 234        { 420, 12 << WM831X_CHG_TIME_SHIFT },
 235        { 450, 13 << WM831X_CHG_TIME_SHIFT },
 236        { 480, 14 << WM831X_CHG_TIME_SHIFT },
 237        { 510, 15 << WM831X_CHG_TIME_SHIFT },
 238};
 239
 240static void wm831x_battey_apply_config(struct wm831x *wm831x,
 241                                       struct chg_map *map, int count, int val,
 242                                       int *reg, const char *name,
 243                                       const char *units)
 244{
 245        int i;
 246
 247        for (i = 0; i < count; i++)
 248                if (val == map[i].val)
 249                        break;
 250        if (i == count) {
 251                dev_err(wm831x->dev, "Invalid %s %d%s\n",
 252                        name, val, units);
 253        } else {
 254                *reg |= map[i].reg_val;
 255                dev_dbg(wm831x->dev, "Set %s of %d%s\n", name, val, units);
 256        }
 257}
 258
 259static void wm831x_config_battery(struct wm831x *wm831x)
 260{
 261        struct wm831x_pdata *wm831x_pdata = wm831x->dev->platform_data;
 262        struct wm831x_battery_pdata *pdata;
 263        int ret, reg1, reg2;
 264
 265        if (!wm831x_pdata || !wm831x_pdata->battery) {
 266                dev_warn(wm831x->dev,
 267                         "No battery charger configuration\n");
 268                return;
 269        }
 270
 271        pdata = wm831x_pdata->battery;
 272
 273        reg1 = 0;
 274        reg2 = 0;
 275
 276        if (!pdata->enable) {
 277                dev_info(wm831x->dev, "Battery charger disabled\n");
 278                return;
 279        }
 280
 281        reg1 |= WM831X_CHG_ENA;
 282        if (pdata->off_mask)
 283                reg2 |= WM831X_CHG_OFF_MSK;
 284        if (pdata->fast_enable)
 285                reg1 |= WM831X_CHG_FAST;
 286
 287        wm831x_battey_apply_config(wm831x, trickle_ilims,
 288                                   ARRAY_SIZE(trickle_ilims),
 289                                   pdata->trickle_ilim, &reg2,
 290                                   "trickle charge current limit", "mA");
 291
 292        wm831x_battey_apply_config(wm831x, vsels, ARRAY_SIZE(vsels),
 293                                   pdata->vsel, &reg2,
 294                                   "target voltage", "mV");
 295
 296        wm831x_battey_apply_config(wm831x, fast_ilims, ARRAY_SIZE(fast_ilims),
 297                                   pdata->fast_ilim, &reg2,
 298                                   "fast charge current limit", "mA");
 299
 300        wm831x_battey_apply_config(wm831x, eoc_iterms, ARRAY_SIZE(eoc_iterms),
 301                                   pdata->eoc_iterm, &reg1,
 302                                   "end of charge current threshold", "mA");
 303
 304        wm831x_battey_apply_config(wm831x, chg_times, ARRAY_SIZE(chg_times),
 305                                   pdata->timeout, &reg2,
 306                                   "charger timeout", "min");
 307
 308        ret = wm831x_reg_unlock(wm831x);
 309        if (ret != 0) {
 310                dev_err(wm831x->dev, "Failed to unlock registers: %d\n", ret);
 311                return;
 312        }
 313
 314        ret = wm831x_set_bits(wm831x, WM831X_CHARGER_CONTROL_1,
 315                              WM831X_CHG_ENA_MASK |
 316                              WM831X_CHG_FAST_MASK |
 317                              WM831X_CHG_ITERM_MASK,
 318                              reg1);
 319        if (ret != 0)
 320                dev_err(wm831x->dev, "Failed to set charger control 1: %d\n",
 321                        ret);
 322
 323        ret = wm831x_set_bits(wm831x, WM831X_CHARGER_CONTROL_2,
 324                              WM831X_CHG_OFF_MSK |
 325                              WM831X_CHG_TIME_MASK |
 326                              WM831X_CHG_FAST_ILIM_MASK |
 327                              WM831X_CHG_TRKL_ILIM_MASK |
 328                              WM831X_CHG_VSEL_MASK,
 329                              reg2);
 330        if (ret != 0)
 331                dev_err(wm831x->dev, "Failed to set charger control 2: %d\n",
 332                        ret);
 333
 334        wm831x_reg_lock(wm831x);
 335}
 336
 337static int wm831x_bat_check_status(struct wm831x *wm831x, int *status)
 338{
 339        int ret;
 340
 341        ret = wm831x_reg_read(wm831x, WM831X_SYSTEM_STATUS);
 342        if (ret < 0)
 343                return ret;
 344
 345        if (ret & WM831X_PWR_SRC_BATT) {
 346                *status = POWER_SUPPLY_STATUS_DISCHARGING;
 347                return 0;
 348        }
 349
 350        ret = wm831x_reg_read(wm831x, WM831X_CHARGER_STATUS);
 351        if (ret < 0)
 352                return ret;
 353
 354        switch (ret & WM831X_CHG_STATE_MASK) {
 355        case WM831X_CHG_STATE_OFF:
 356                *status = POWER_SUPPLY_STATUS_NOT_CHARGING;
 357                break;
 358        case WM831X_CHG_STATE_TRICKLE:
 359        case WM831X_CHG_STATE_FAST:
 360                *status = POWER_SUPPLY_STATUS_CHARGING;
 361                break;
 362
 363        default:
 364                *status = POWER_SUPPLY_STATUS_UNKNOWN;
 365                break;
 366        }
 367
 368        return 0;
 369}
 370
 371static int wm831x_bat_check_type(struct wm831x *wm831x, int *type)
 372{
 373        int ret;
 374
 375        ret = wm831x_reg_read(wm831x, WM831X_CHARGER_STATUS);
 376        if (ret < 0)
 377                return ret;
 378
 379        switch (ret & WM831X_CHG_STATE_MASK) {
 380        case WM831X_CHG_STATE_TRICKLE:
 381        case WM831X_CHG_STATE_TRICKLE_OT:
 382                *type = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
 383                break;
 384        case WM831X_CHG_STATE_FAST:
 385        case WM831X_CHG_STATE_FAST_OT:
 386                *type = POWER_SUPPLY_CHARGE_TYPE_FAST;
 387                break;
 388        default:
 389                *type = POWER_SUPPLY_CHARGE_TYPE_NONE;
 390                break;
 391        }
 392
 393        return 0;
 394}
 395
 396static int wm831x_bat_check_health(struct wm831x *wm831x, int *health)
 397{
 398        int ret;
 399
 400        ret = wm831x_reg_read(wm831x, WM831X_CHARGER_STATUS);
 401        if (ret < 0)
 402                return ret;
 403
 404        if (ret & WM831X_BATT_HOT_STS) {
 405                *health = POWER_SUPPLY_HEALTH_OVERHEAT;
 406                return 0;
 407        }
 408
 409        if (ret & WM831X_BATT_COLD_STS) {
 410                *health = POWER_SUPPLY_HEALTH_COLD;
 411                return 0;
 412        }
 413
 414        if (ret & WM831X_BATT_OV_STS) {
 415                *health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
 416                return 0;
 417        }
 418
 419        switch (ret & WM831X_CHG_STATE_MASK) {
 420        case WM831X_CHG_STATE_TRICKLE_OT:
 421        case WM831X_CHG_STATE_FAST_OT:
 422                *health = POWER_SUPPLY_HEALTH_OVERHEAT;
 423                break;
 424        case WM831X_CHG_STATE_DEFECTIVE:
 425                *health = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
 426                break;
 427        default:
 428                *health = POWER_SUPPLY_HEALTH_GOOD;
 429                break;
 430        }
 431
 432        return 0;
 433}
 434
 435static int wm831x_bat_get_prop(struct power_supply *psy,
 436                               enum power_supply_property psp,
 437                               union power_supply_propval *val)
 438{
 439        struct wm831x_power *wm831x_power = dev_get_drvdata(psy->dev.parent);
 440        struct wm831x *wm831x = wm831x_power->wm831x;
 441        int ret = 0;
 442
 443        switch (psp) {
 444        case POWER_SUPPLY_PROP_STATUS:
 445                ret = wm831x_bat_check_status(wm831x, &val->intval);
 446                break;
 447        case POWER_SUPPLY_PROP_ONLINE:
 448                ret = wm831x_power_check_online(wm831x, WM831X_PWR_SRC_BATT,
 449                                                val);
 450                break;
 451        case POWER_SUPPLY_PROP_VOLTAGE_NOW:
 452                ret = wm831x_power_read_voltage(wm831x, WM831X_AUX_BATT, val);
 453                break;
 454        case POWER_SUPPLY_PROP_HEALTH:
 455                ret = wm831x_bat_check_health(wm831x, &val->intval);
 456                break;
 457        case POWER_SUPPLY_PROP_CHARGE_TYPE:
 458                ret = wm831x_bat_check_type(wm831x, &val->intval);
 459                break;
 460        default:
 461                ret = -EINVAL;
 462                break;
 463        }
 464
 465        return ret;
 466}
 467
 468static enum power_supply_property wm831x_bat_props[] = {
 469        POWER_SUPPLY_PROP_STATUS,
 470        POWER_SUPPLY_PROP_ONLINE,
 471        POWER_SUPPLY_PROP_VOLTAGE_NOW,
 472        POWER_SUPPLY_PROP_HEALTH,
 473        POWER_SUPPLY_PROP_CHARGE_TYPE,
 474};
 475
 476static const char *wm831x_bat_irqs[] = {
 477        "BATT HOT",
 478        "BATT COLD",
 479        "BATT FAIL",
 480        "OV",
 481        "END",
 482        "TO",
 483        "MODE",
 484        "START",
 485};
 486
 487static irqreturn_t wm831x_bat_irq(int irq, void *data)
 488{
 489        struct wm831x_power *wm831x_power = data;
 490        struct wm831x *wm831x = wm831x_power->wm831x;
 491
 492        dev_dbg(wm831x->dev, "Battery status changed: %d\n", irq);
 493
 494        /* The battery charger is autonomous so we don't need to do
 495         * anything except kick user space */
 496        if (wm831x_power->have_battery)
 497                power_supply_changed(wm831x_power->battery);
 498
 499        return IRQ_HANDLED;
 500}
 501
 502
 503/*********************************************************************
 504 *              Initialisation
 505 *********************************************************************/
 506
 507static irqreturn_t wm831x_syslo_irq(int irq, void *data)
 508{
 509        struct wm831x_power *wm831x_power = data;
 510        struct wm831x *wm831x = wm831x_power->wm831x;
 511
 512        /* Not much we can actually *do* but tell people for
 513         * posterity, we're probably about to run out of power. */
 514        dev_crit(wm831x->dev, "SYSVDD under voltage\n");
 515
 516        return IRQ_HANDLED;
 517}
 518
 519static irqreturn_t wm831x_pwr_src_irq(int irq, void *data)
 520{
 521        struct wm831x_power *wm831x_power = data;
 522        struct wm831x *wm831x = wm831x_power->wm831x;
 523
 524        dev_dbg(wm831x->dev, "Power source changed\n");
 525
 526        /* Just notify for everything - little harm in overnotifying. */
 527        if (wm831x_power->have_battery)
 528                power_supply_changed(wm831x_power->battery);
 529        power_supply_changed(wm831x_power->usb);
 530        power_supply_changed(wm831x_power->wall);
 531
 532        return IRQ_HANDLED;
 533}
 534
 535static int wm831x_power_probe(struct platform_device *pdev)
 536{
 537        struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
 538        struct wm831x_pdata *wm831x_pdata = wm831x->dev->platform_data;
 539        struct wm831x_power *power;
 540        int ret, irq, i;
 541
 542        power = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_power),
 543                             GFP_KERNEL);
 544        if (power == NULL)
 545                return -ENOMEM;
 546
 547        power->wm831x = wm831x;
 548        platform_set_drvdata(pdev, power);
 549
 550        if (wm831x_pdata && wm831x_pdata->wm831x_num) {
 551                snprintf(power->wall_name, sizeof(power->wall_name),
 552                         "wm831x-wall.%d", wm831x_pdata->wm831x_num);
 553                snprintf(power->battery_name, sizeof(power->wall_name),
 554                         "wm831x-battery.%d", wm831x_pdata->wm831x_num);
 555                snprintf(power->usb_name, sizeof(power->wall_name),
 556                         "wm831x-usb.%d", wm831x_pdata->wm831x_num);
 557        } else {
 558                snprintf(power->wall_name, sizeof(power->wall_name),
 559                         "wm831x-wall");
 560                snprintf(power->battery_name, sizeof(power->wall_name),
 561                         "wm831x-battery");
 562                snprintf(power->usb_name, sizeof(power->wall_name),
 563                         "wm831x-usb");
 564        }
 565
 566        /* We ignore configuration failures since we can still read back
 567         * the status without enabling the charger.
 568         */
 569        wm831x_config_battery(wm831x);
 570
 571        power->wall_desc.name = power->wall_name;
 572        power->wall_desc.type = POWER_SUPPLY_TYPE_MAINS;
 573        power->wall_desc.properties = wm831x_wall_props;
 574        power->wall_desc.num_properties = ARRAY_SIZE(wm831x_wall_props);
 575        power->wall_desc.get_property = wm831x_wall_get_prop;
 576        power->wall = power_supply_register(&pdev->dev, &power->wall_desc,
 577                                            NULL);
 578        if (IS_ERR(power->wall)) {
 579                ret = PTR_ERR(power->wall);
 580                goto err;
 581        }
 582
 583        power->usb_desc.name = power->usb_name,
 584        power->usb_desc.type = POWER_SUPPLY_TYPE_USB;
 585        power->usb_desc.properties = wm831x_usb_props;
 586        power->usb_desc.num_properties = ARRAY_SIZE(wm831x_usb_props);
 587        power->usb_desc.get_property = wm831x_usb_get_prop;
 588        power->usb = power_supply_register(&pdev->dev, &power->usb_desc, NULL);
 589        if (IS_ERR(power->usb)) {
 590                ret = PTR_ERR(power->usb);
 591                goto err_wall;
 592        }
 593
 594        ret = wm831x_reg_read(wm831x, WM831X_CHARGER_CONTROL_1);
 595        if (ret < 0)
 596                goto err_wall;
 597        power->have_battery = ret & WM831X_CHG_ENA;
 598
 599        if (power->have_battery) {
 600                power->battery_desc.name = power->battery_name;
 601                power->battery_desc.properties = wm831x_bat_props;
 602                power->battery_desc.num_properties = ARRAY_SIZE(wm831x_bat_props);
 603                power->battery_desc.get_property = wm831x_bat_get_prop;
 604                power->battery_desc.use_for_apm = 1;
 605                power->battery = power_supply_register(&pdev->dev,
 606                                                       &power->battery_desc,
 607                                                       NULL);
 608                if (IS_ERR(power->battery)) {
 609                        ret = PTR_ERR(power->battery);
 610                        goto err_usb;
 611                }
 612        }
 613
 614        irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "SYSLO"));
 615        ret = request_threaded_irq(irq, NULL, wm831x_syslo_irq,
 616                                   IRQF_TRIGGER_RISING | IRQF_ONESHOT, "System power low",
 617                                   power);
 618        if (ret != 0) {
 619                dev_err(&pdev->dev, "Failed to request SYSLO IRQ %d: %d\n",
 620                        irq, ret);
 621                goto err_battery;
 622        }
 623
 624        irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "PWR SRC"));
 625        ret = request_threaded_irq(irq, NULL, wm831x_pwr_src_irq,
 626                                   IRQF_TRIGGER_RISING | IRQF_ONESHOT, "Power source",
 627                                   power);
 628        if (ret != 0) {
 629                dev_err(&pdev->dev, "Failed to request PWR SRC IRQ %d: %d\n",
 630                        irq, ret);
 631                goto err_syslo;
 632        }
 633
 634        for (i = 0; i < ARRAY_SIZE(wm831x_bat_irqs); i++) {
 635                irq = wm831x_irq(wm831x,
 636                                 platform_get_irq_byname(pdev,
 637                                                         wm831x_bat_irqs[i]));
 638                ret = request_threaded_irq(irq, NULL, wm831x_bat_irq,
 639                                           IRQF_TRIGGER_RISING | IRQF_ONESHOT,
 640                                           wm831x_bat_irqs[i],
 641                                           power);
 642                if (ret != 0) {
 643                        dev_err(&pdev->dev,
 644                                "Failed to request %s IRQ %d: %d\n",
 645                                wm831x_bat_irqs[i], irq, ret);
 646                        goto err_bat_irq;
 647                }
 648        }
 649
 650        power->usb_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "phys", 0);
 651        ret = PTR_ERR_OR_ZERO(power->usb_phy);
 652
 653        switch (ret) {
 654        case 0:
 655                power->usb_notify.notifier_call = wm831x_usb_limit_change;
 656                ret = usb_register_notifier(power->usb_phy, &power->usb_notify);
 657                if (ret) {
 658                        dev_err(&pdev->dev, "Failed to register notifier: %d\n",
 659                                ret);
 660                        goto err_bat_irq;
 661                }
 662                break;
 663        case -EINVAL:
 664        case -ENODEV:
 665                /* ignore missing usb-phy, it's optional */
 666                power->usb_phy = NULL;
 667                ret = 0;
 668                break;
 669        default:
 670                dev_err(&pdev->dev, "Failed to find USB phy: %d\n", ret);
 671                /* fall-through */
 672        case -EPROBE_DEFER:
 673                goto err_bat_irq;
 674                break;
 675        }
 676
 677        return ret;
 678
 679err_bat_irq:
 680        --i;
 681        for (; i >= 0; i--) {
 682                irq = platform_get_irq_byname(pdev, wm831x_bat_irqs[i]);
 683                free_irq(irq, power);
 684        }
 685        irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "PWR SRC"));
 686        free_irq(irq, power);
 687err_syslo:
 688        irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "SYSLO"));
 689        free_irq(irq, power);
 690err_battery:
 691        if (power->have_battery)
 692                power_supply_unregister(power->battery);
 693err_usb:
 694        power_supply_unregister(power->usb);
 695err_wall:
 696        power_supply_unregister(power->wall);
 697err:
 698        return ret;
 699}
 700
 701static int wm831x_power_remove(struct platform_device *pdev)
 702{
 703        struct wm831x_power *wm831x_power = platform_get_drvdata(pdev);
 704        struct wm831x *wm831x = wm831x_power->wm831x;
 705        int irq, i;
 706
 707        if (wm831x_power->usb_phy) {
 708                usb_unregister_notifier(wm831x_power->usb_phy,
 709                                        &wm831x_power->usb_notify);
 710        }
 711
 712        for (i = 0; i < ARRAY_SIZE(wm831x_bat_irqs); i++) {
 713                irq = wm831x_irq(wm831x, 
 714                                 platform_get_irq_byname(pdev,
 715                                                         wm831x_bat_irqs[i]));
 716                free_irq(irq, wm831x_power);
 717        }
 718
 719        irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "PWR SRC"));
 720        free_irq(irq, wm831x_power);
 721
 722        irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "SYSLO"));
 723        free_irq(irq, wm831x_power);
 724
 725        if (wm831x_power->have_battery)
 726                power_supply_unregister(wm831x_power->battery);
 727        power_supply_unregister(wm831x_power->wall);
 728        power_supply_unregister(wm831x_power->usb);
 729        return 0;
 730}
 731
 732static struct platform_driver wm831x_power_driver = {
 733        .probe = wm831x_power_probe,
 734        .remove = wm831x_power_remove,
 735        .driver = {
 736                .name = "wm831x-power",
 737        },
 738};
 739
 740module_platform_driver(wm831x_power_driver);
 741
 742MODULE_DESCRIPTION("Power supply driver for WM831x PMICs");
 743MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
 744MODULE_LICENSE("GPL");
 745MODULE_ALIAS("platform:wm831x-power");
 746