linux/drivers/power/supply/act8945a_charger.c
<<
>>
Prefs
   1/*
   2 * Power supply driver for the Active-semi ACT8945A PMIC
   3 *
   4 * Copyright (C) 2015 Atmel Corporation
   5 *
   6 * Author: Wenyou Yang <wenyou.yang@atmel.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2 as
  10 * published by the Free Software Foundation.
  11 *
  12 */
  13#include <linux/interrupt.h>
  14#include <linux/module.h>
  15#include <linux/of.h>
  16#include <linux/of_irq.h>
  17#include <linux/platform_device.h>
  18#include <linux/power_supply.h>
  19#include <linux/regmap.h>
  20#include <linux/gpio/consumer.h>
  21
  22static const char *act8945a_charger_model = "ACT8945A";
  23static const char *act8945a_charger_manufacturer = "Active-semi";
  24
  25/**
  26 * ACT8945A Charger Register Map
  27 */
  28
  29/* 0x70: Reserved */
  30#define ACT8945A_APCH_CFG               0x71
  31#define ACT8945A_APCH_STATUS            0x78
  32#define ACT8945A_APCH_CTRL              0x79
  33#define ACT8945A_APCH_STATE             0x7A
  34
  35/* ACT8945A_APCH_CFG */
  36#define APCH_CFG_OVPSET                 (0x3 << 0)
  37#define APCH_CFG_OVPSET_6V6             (0x0 << 0)
  38#define APCH_CFG_OVPSET_7V              (0x1 << 0)
  39#define APCH_CFG_OVPSET_7V5             (0x2 << 0)
  40#define APCH_CFG_OVPSET_8V              (0x3 << 0)
  41#define APCH_CFG_PRETIMO                (0x3 << 2)
  42#define APCH_CFG_PRETIMO_40_MIN         (0x0 << 2)
  43#define APCH_CFG_PRETIMO_60_MIN         (0x1 << 2)
  44#define APCH_CFG_PRETIMO_80_MIN         (0x2 << 2)
  45#define APCH_CFG_PRETIMO_DISABLED       (0x3 << 2)
  46#define APCH_CFG_TOTTIMO                (0x3 << 4)
  47#define APCH_CFG_TOTTIMO_3_HOUR         (0x0 << 4)
  48#define APCH_CFG_TOTTIMO_4_HOUR         (0x1 << 4)
  49#define APCH_CFG_TOTTIMO_5_HOUR         (0x2 << 4)
  50#define APCH_CFG_TOTTIMO_DISABLED       (0x3 << 4)
  51#define APCH_CFG_SUSCHG                 (0x1 << 7)
  52
  53#define APCH_STATUS_CHGDAT              BIT(0)
  54#define APCH_STATUS_INDAT               BIT(1)
  55#define APCH_STATUS_TEMPDAT             BIT(2)
  56#define APCH_STATUS_TIMRDAT             BIT(3)
  57#define APCH_STATUS_CHGSTAT             BIT(4)
  58#define APCH_STATUS_INSTAT              BIT(5)
  59#define APCH_STATUS_TEMPSTAT            BIT(6)
  60#define APCH_STATUS_TIMRSTAT            BIT(7)
  61
  62#define APCH_CTRL_CHGEOCOUT             BIT(0)
  63#define APCH_CTRL_INDIS                 BIT(1)
  64#define APCH_CTRL_TEMPOUT               BIT(2)
  65#define APCH_CTRL_TIMRPRE               BIT(3)
  66#define APCH_CTRL_CHGEOCIN              BIT(4)
  67#define APCH_CTRL_INCON                 BIT(5)
  68#define APCH_CTRL_TEMPIN                BIT(6)
  69#define APCH_CTRL_TIMRTOT               BIT(7)
  70
  71#define APCH_STATE_ACINSTAT             (0x1 << 1)
  72#define APCH_STATE_CSTATE               (0x3 << 4)
  73#define APCH_STATE_CSTATE_SHIFT         4
  74#define APCH_STATE_CSTATE_DISABLED      0x00
  75#define APCH_STATE_CSTATE_EOC           0x01
  76#define APCH_STATE_CSTATE_FAST          0x02
  77#define APCH_STATE_CSTATE_PRE           0x03
  78
  79struct act8945a_charger {
  80        struct power_supply *psy;
  81        struct power_supply_desc desc;
  82        struct regmap *regmap;
  83        struct work_struct work;
  84
  85        bool init_done;
  86        struct gpio_desc *lbo_gpio;
  87        struct gpio_desc *chglev_gpio;
  88};
  89
  90static int act8945a_get_charger_state(struct regmap *regmap, int *val)
  91{
  92        int ret;
  93        unsigned int status, state;
  94
  95        ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status);
  96        if (ret < 0)
  97                return ret;
  98
  99        ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state);
 100        if (ret < 0)
 101                return ret;
 102
 103        state &= APCH_STATE_CSTATE;
 104        state >>= APCH_STATE_CSTATE_SHIFT;
 105
 106        switch (state) {
 107        case APCH_STATE_CSTATE_PRE:
 108        case APCH_STATE_CSTATE_FAST:
 109                *val = POWER_SUPPLY_STATUS_CHARGING;
 110                break;
 111        case APCH_STATE_CSTATE_EOC:
 112                if (status & APCH_STATUS_CHGDAT)
 113                        *val = POWER_SUPPLY_STATUS_FULL;
 114                else
 115                        *val = POWER_SUPPLY_STATUS_CHARGING;
 116                break;
 117        case APCH_STATE_CSTATE_DISABLED:
 118        default:
 119                if (!(status & APCH_STATUS_INDAT))
 120                        *val = POWER_SUPPLY_STATUS_DISCHARGING;
 121                else
 122                        *val = POWER_SUPPLY_STATUS_NOT_CHARGING;
 123                break;
 124        }
 125
 126        return 0;
 127}
 128
 129static int act8945a_get_charge_type(struct regmap *regmap, int *val)
 130{
 131        int ret;
 132        unsigned int status, state;
 133
 134        ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status);
 135        if (ret < 0)
 136                return ret;
 137
 138        ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state);
 139        if (ret < 0)
 140                return ret;
 141
 142        state &= APCH_STATE_CSTATE;
 143        state >>= APCH_STATE_CSTATE_SHIFT;
 144
 145        switch (state) {
 146        case APCH_STATE_CSTATE_PRE:
 147                *val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
 148                break;
 149        case APCH_STATE_CSTATE_FAST:
 150                *val = POWER_SUPPLY_CHARGE_TYPE_FAST;
 151                break;
 152        case APCH_STATE_CSTATE_EOC:
 153                *val = POWER_SUPPLY_CHARGE_TYPE_NONE;
 154                break;
 155        case APCH_STATE_CSTATE_DISABLED:
 156        default:
 157                if (!(status & APCH_STATUS_INDAT))
 158                        *val = POWER_SUPPLY_CHARGE_TYPE_NONE;
 159                else
 160                        *val = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
 161                break;
 162        }
 163
 164        return 0;
 165}
 166
 167static int act8945a_get_battery_health(struct regmap *regmap, int *val)
 168{
 169        int ret;
 170        unsigned int status, state, config;
 171
 172        ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status);
 173        if (ret < 0)
 174                return ret;
 175
 176        ret = regmap_read(regmap, ACT8945A_APCH_CFG, &config);
 177        if (ret < 0)
 178                return ret;
 179
 180        ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state);
 181        if (ret < 0)
 182                return ret;
 183
 184        state &= APCH_STATE_CSTATE;
 185        state >>= APCH_STATE_CSTATE_SHIFT;
 186
 187        switch (state) {
 188        case APCH_STATE_CSTATE_DISABLED:
 189                if (config & APCH_CFG_SUSCHG) {
 190                        *val = POWER_SUPPLY_HEALTH_UNKNOWN;
 191                } else if (status & APCH_STATUS_INDAT) {
 192                        if (!(status & APCH_STATUS_TEMPDAT))
 193                                *val = POWER_SUPPLY_HEALTH_OVERHEAT;
 194                        else if (status & APCH_STATUS_TIMRDAT)
 195                                *val = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
 196                        else
 197                                *val = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
 198                } else {
 199                        *val = POWER_SUPPLY_HEALTH_GOOD;
 200                }
 201                break;
 202        case APCH_STATE_CSTATE_PRE:
 203        case APCH_STATE_CSTATE_FAST:
 204        case APCH_STATE_CSTATE_EOC:
 205        default:
 206                *val = POWER_SUPPLY_HEALTH_GOOD;
 207                break;
 208        }
 209
 210        return 0;
 211}
 212
 213static int act8945a_get_capacity_level(struct act8945a_charger *charger,
 214                                       struct regmap *regmap, int *val)
 215{
 216        int ret;
 217        unsigned int status, state, config;
 218        int lbo_level = gpiod_get_value(charger->lbo_gpio);
 219
 220        ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status);
 221        if (ret < 0)
 222                return ret;
 223
 224        ret = regmap_read(regmap, ACT8945A_APCH_CFG, &config);
 225        if (ret < 0)
 226                return ret;
 227
 228        ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state);
 229        if (ret < 0)
 230                return ret;
 231
 232        state &= APCH_STATE_CSTATE;
 233        state >>= APCH_STATE_CSTATE_SHIFT;
 234
 235        switch (state) {
 236        case APCH_STATE_CSTATE_PRE:
 237                *val = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
 238                break;
 239        case APCH_STATE_CSTATE_FAST:
 240                if (lbo_level)
 241                        *val = POWER_SUPPLY_CAPACITY_LEVEL_HIGH;
 242                else
 243                        *val = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
 244                break;
 245        case APCH_STATE_CSTATE_EOC:
 246                if (status & APCH_STATUS_CHGDAT)
 247                        *val = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
 248                else
 249                        *val = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
 250                break;
 251        case APCH_STATE_CSTATE_DISABLED:
 252        default:
 253                if (config & APCH_CFG_SUSCHG) {
 254                        *val = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
 255                } else {
 256                        *val = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
 257                        if (!(status & APCH_STATUS_INDAT)) {
 258                                if (!lbo_level)
 259                                        *val = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
 260                        }
 261                }
 262                break;
 263        }
 264
 265        return 0;
 266}
 267
 268#define MAX_CURRENT_USB_HIGH    450000
 269#define MAX_CURRENT_USB_LOW     90000
 270#define MAX_CURRENT_USB_PRE     45000
 271/*
 272 * Riset(K) = 2336 * (1V/Ichg(mA)) - 0.205
 273 * Riset = 2.43K
 274 */
 275#define MAX_CURRENT_AC_HIGH             886527
 276#define MAX_CURRENT_AC_LOW              117305
 277#define MAX_CURRENT_AC_HIGH_PRE         88653
 278#define MAX_CURRENT_AC_LOW_PRE          11731
 279
 280static int act8945a_get_current_max(struct act8945a_charger *charger,
 281                                    struct regmap *regmap, int *val)
 282{
 283        int ret;
 284        unsigned int status, state;
 285        unsigned int acin_state;
 286        int chgin_level = gpiod_get_value(charger->chglev_gpio);
 287
 288        ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status);
 289        if (ret < 0)
 290                return ret;
 291
 292        ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state);
 293        if (ret < 0)
 294                return ret;
 295
 296        acin_state = (state & APCH_STATE_ACINSTAT) >> 1;
 297
 298        state &= APCH_STATE_CSTATE;
 299        state >>= APCH_STATE_CSTATE_SHIFT;
 300
 301        switch (state) {
 302        case APCH_STATE_CSTATE_PRE:
 303                if (acin_state) {
 304                        if (chgin_level)
 305                                *val = MAX_CURRENT_AC_HIGH_PRE;
 306                        else
 307                                *val = MAX_CURRENT_AC_LOW_PRE;
 308                } else {
 309                        *val = MAX_CURRENT_USB_PRE;
 310                }
 311                break;
 312        case APCH_STATE_CSTATE_FAST:
 313                if (acin_state) {
 314                        if (chgin_level)
 315                                *val = MAX_CURRENT_AC_HIGH;
 316                        else
 317                                *val = MAX_CURRENT_AC_LOW;
 318                } else {
 319                        if (chgin_level)
 320                                *val = MAX_CURRENT_USB_HIGH;
 321                        else
 322                                *val = MAX_CURRENT_USB_LOW;
 323                }
 324                break;
 325        case APCH_STATE_CSTATE_EOC:
 326        case APCH_STATE_CSTATE_DISABLED:
 327        default:
 328                *val = 0;
 329                break;
 330        }
 331
 332        return 0;
 333}
 334
 335static enum power_supply_property act8945a_charger_props[] = {
 336        POWER_SUPPLY_PROP_STATUS,
 337        POWER_SUPPLY_PROP_CHARGE_TYPE,
 338        POWER_SUPPLY_PROP_TECHNOLOGY,
 339        POWER_SUPPLY_PROP_HEALTH,
 340        POWER_SUPPLY_PROP_CAPACITY_LEVEL,
 341        POWER_SUPPLY_PROP_CURRENT_MAX,
 342        POWER_SUPPLY_PROP_MODEL_NAME,
 343        POWER_SUPPLY_PROP_MANUFACTURER
 344};
 345
 346static int act8945a_charger_get_property(struct power_supply *psy,
 347                                         enum power_supply_property prop,
 348                                         union power_supply_propval *val)
 349{
 350        struct act8945a_charger *charger = power_supply_get_drvdata(psy);
 351        struct regmap *regmap = charger->regmap;
 352        int ret = 0;
 353
 354        switch (prop) {
 355        case POWER_SUPPLY_PROP_STATUS:
 356                ret = act8945a_get_charger_state(regmap, &val->intval);
 357                break;
 358        case POWER_SUPPLY_PROP_CHARGE_TYPE:
 359                ret = act8945a_get_charge_type(regmap, &val->intval);
 360                break;
 361        case POWER_SUPPLY_PROP_TECHNOLOGY:
 362                val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
 363                break;
 364        case POWER_SUPPLY_PROP_HEALTH:
 365                ret = act8945a_get_battery_health(regmap, &val->intval);
 366                break;
 367        case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
 368                ret = act8945a_get_capacity_level(charger,
 369                                                  regmap, &val->intval);
 370                break;
 371        case POWER_SUPPLY_PROP_CURRENT_MAX:
 372                ret = act8945a_get_current_max(charger,
 373                                               regmap, &val->intval);
 374                break;
 375        case POWER_SUPPLY_PROP_MODEL_NAME:
 376                val->strval = act8945a_charger_model;
 377                break;
 378        case POWER_SUPPLY_PROP_MANUFACTURER:
 379                val->strval = act8945a_charger_manufacturer;
 380                break;
 381        default:
 382                return -EINVAL;
 383        }
 384
 385        return ret;
 386}
 387
 388static int act8945a_enable_interrupt(struct act8945a_charger *charger)
 389{
 390        struct regmap *regmap = charger->regmap;
 391        unsigned char ctrl;
 392        int ret;
 393
 394        ctrl = APCH_CTRL_CHGEOCOUT | APCH_CTRL_CHGEOCIN |
 395               APCH_CTRL_INDIS | APCH_CTRL_INCON |
 396               APCH_CTRL_TEMPOUT | APCH_CTRL_TEMPIN |
 397               APCH_CTRL_TIMRPRE | APCH_CTRL_TIMRTOT;
 398        ret = regmap_write(regmap, ACT8945A_APCH_CTRL, ctrl);
 399        if (ret)
 400                return ret;
 401
 402        ctrl = APCH_STATUS_CHGSTAT | APCH_STATUS_INSTAT |
 403               APCH_STATUS_TEMPSTAT | APCH_STATUS_TIMRSTAT;
 404        ret = regmap_write(regmap, ACT8945A_APCH_STATUS, ctrl);
 405        if (ret)
 406                return ret;
 407
 408        return 0;
 409}
 410
 411static unsigned int act8945a_set_supply_type(struct act8945a_charger *charger,
 412                                             unsigned int *type)
 413{
 414        unsigned int status, state;
 415        int ret;
 416
 417        ret = regmap_read(charger->regmap, ACT8945A_APCH_STATUS, &status);
 418        if (ret < 0)
 419                return ret;
 420
 421        ret = regmap_read(charger->regmap, ACT8945A_APCH_STATE, &state);
 422        if (ret < 0)
 423                return ret;
 424
 425        if (status & APCH_STATUS_INDAT) {
 426                if (state & APCH_STATE_ACINSTAT)
 427                        *type = POWER_SUPPLY_TYPE_MAINS;
 428                else
 429                        *type = POWER_SUPPLY_TYPE_USB;
 430        } else {
 431                *type = POWER_SUPPLY_TYPE_BATTERY;
 432        }
 433
 434        return 0;
 435}
 436
 437static void act8945a_work(struct work_struct *work)
 438{
 439        struct act8945a_charger *charger =
 440                        container_of(work, struct act8945a_charger, work);
 441
 442        act8945a_set_supply_type(charger, &charger->desc.type);
 443
 444        power_supply_changed(charger->psy);
 445}
 446
 447static irqreturn_t act8945a_status_changed(int irq, void *dev_id)
 448{
 449        struct act8945a_charger *charger = dev_id;
 450
 451        if (charger->init_done)
 452                schedule_work(&charger->work);
 453
 454        return IRQ_HANDLED;
 455}
 456
 457#define DEFAULT_TOTAL_TIME_OUT          3
 458#define DEFAULT_PRE_TIME_OUT            40
 459#define DEFAULT_INPUT_OVP_THRESHOLD     6600
 460
 461static int act8945a_charger_config(struct device *dev,
 462                                   struct act8945a_charger *charger)
 463{
 464        struct device_node *np = dev->of_node;
 465        struct regmap *regmap = charger->regmap;
 466
 467        u32 total_time_out;
 468        u32 pre_time_out;
 469        u32 input_voltage_threshold;
 470        int err, ret;
 471
 472        unsigned int tmp;
 473        unsigned int value = 0;
 474
 475        if (!np) {
 476                dev_err(dev, "no charger of node\n");
 477                return -EINVAL;
 478        }
 479
 480        ret = regmap_read(regmap, ACT8945A_APCH_CFG, &tmp);
 481        if (ret)
 482                return ret;
 483
 484        if (tmp & APCH_CFG_SUSCHG) {
 485                value |= APCH_CFG_SUSCHG;
 486                dev_info(dev, "have been suspended\n");
 487        }
 488
 489        charger->lbo_gpio = devm_gpiod_get_optional(dev, "active-semi,lbo",
 490                                                    GPIOD_IN);
 491        if (IS_ERR(charger->lbo_gpio)) {
 492                err = PTR_ERR(charger->lbo_gpio);
 493                dev_err(dev, "unable to claim gpio \"lbo\": %d\n", err);
 494                return err;
 495        }
 496
 497        ret = devm_request_irq(dev, gpiod_to_irq(charger->lbo_gpio),
 498                               act8945a_status_changed,
 499                               (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING),
 500                               "act8945a_lbo_detect", charger);
 501        if (ret)
 502                dev_info(dev, "failed to request gpio \"lbo\" IRQ\n");
 503
 504        charger->chglev_gpio = devm_gpiod_get_optional(dev,
 505                                                       "active-semi,chglev",
 506                                                       GPIOD_IN);
 507        if (IS_ERR(charger->chglev_gpio)) {
 508                err = PTR_ERR(charger->chglev_gpio);
 509                dev_err(dev, "unable to claim gpio \"chglev\": %d\n", err);
 510                return err;
 511        }
 512
 513        if (of_property_read_u32(np,
 514                                 "active-semi,input-voltage-threshold-microvolt",
 515                                 &input_voltage_threshold))
 516                input_voltage_threshold = DEFAULT_INPUT_OVP_THRESHOLD;
 517
 518        if (of_property_read_u32(np,
 519                                 "active-semi,precondition-timeout",
 520                                 &pre_time_out))
 521                pre_time_out = DEFAULT_PRE_TIME_OUT;
 522
 523        if (of_property_read_u32(np, "active-semi,total-timeout",
 524                                 &total_time_out))
 525                total_time_out = DEFAULT_TOTAL_TIME_OUT;
 526
 527        switch (input_voltage_threshold) {
 528        case 8000:
 529                value |= APCH_CFG_OVPSET_8V;
 530                break;
 531        case 7500:
 532                value |= APCH_CFG_OVPSET_7V5;
 533                break;
 534        case 7000:
 535                value |= APCH_CFG_OVPSET_7V;
 536                break;
 537        case 6600:
 538        default:
 539                value |= APCH_CFG_OVPSET_6V6;
 540                break;
 541        }
 542
 543        switch (pre_time_out) {
 544        case 60:
 545                value |= APCH_CFG_PRETIMO_60_MIN;
 546                break;
 547        case 80:
 548                value |= APCH_CFG_PRETIMO_80_MIN;
 549                break;
 550        case 0:
 551                value |= APCH_CFG_PRETIMO_DISABLED;
 552                break;
 553        case 40:
 554        default:
 555                value |= APCH_CFG_PRETIMO_40_MIN;
 556                break;
 557        }
 558
 559        switch (total_time_out) {
 560        case 4:
 561                value |= APCH_CFG_TOTTIMO_4_HOUR;
 562                break;
 563        case 5:
 564                value |= APCH_CFG_TOTTIMO_5_HOUR;
 565                break;
 566        case 0:
 567                value |= APCH_CFG_TOTTIMO_DISABLED;
 568                break;
 569        case 3:
 570        default:
 571                value |= APCH_CFG_TOTTIMO_3_HOUR;
 572                break;
 573        }
 574
 575        return regmap_write(regmap, ACT8945A_APCH_CFG, value);
 576}
 577
 578static int act8945a_charger_probe(struct platform_device *pdev)
 579{
 580        struct act8945a_charger *charger;
 581        struct power_supply_config psy_cfg = {};
 582        int irq, ret;
 583
 584        charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL);
 585        if (!charger)
 586                return -ENOMEM;
 587
 588        charger->regmap = dev_get_regmap(pdev->dev.parent, NULL);
 589        if (!charger->regmap) {
 590                dev_err(&pdev->dev, "Parent did not provide regmap\n");
 591                return -EINVAL;
 592        }
 593
 594        ret = act8945a_charger_config(&pdev->dev, charger);
 595        if (ret)
 596                return ret;
 597
 598        irq = of_irq_get(pdev->dev.of_node, 0);
 599        if (irq <= 0) {
 600                dev_err(&pdev->dev, "failed to find IRQ number\n");
 601                return irq ?: -ENXIO;
 602        }
 603
 604        ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed,
 605                               IRQF_TRIGGER_FALLING, "act8945a_interrupt",
 606                               charger);
 607        if (ret) {
 608                dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n");
 609                return ret;
 610        }
 611
 612        charger->desc.name = "act8945a-charger";
 613        charger->desc.get_property = act8945a_charger_get_property;
 614        charger->desc.properties = act8945a_charger_props;
 615        charger->desc.num_properties = ARRAY_SIZE(act8945a_charger_props);
 616
 617        ret = act8945a_set_supply_type(charger, &charger->desc.type);
 618        if (ret)
 619                return -EINVAL;
 620
 621        psy_cfg.of_node = pdev->dev.of_node;
 622        psy_cfg.drv_data = charger;
 623
 624        charger->psy = devm_power_supply_register(&pdev->dev,
 625                                                  &charger->desc,
 626                                                  &psy_cfg);
 627        if (IS_ERR(charger->psy)) {
 628                dev_err(&pdev->dev, "failed to register power supply\n");
 629                return PTR_ERR(charger->psy);
 630        }
 631
 632        platform_set_drvdata(pdev, charger);
 633
 634        INIT_WORK(&charger->work, act8945a_work);
 635
 636        ret = act8945a_enable_interrupt(charger);
 637        if (ret)
 638                return -EIO;
 639
 640        charger->init_done = true;
 641
 642        return 0;
 643}
 644
 645static int act8945a_charger_remove(struct platform_device *pdev)
 646{
 647        struct act8945a_charger *charger = platform_get_drvdata(pdev);
 648
 649        charger->init_done = false;
 650        cancel_work_sync(&charger->work);
 651
 652        return 0;
 653}
 654
 655static struct platform_driver act8945a_charger_driver = {
 656        .driver = {
 657                .name = "act8945a-charger",
 658        },
 659        .probe  = act8945a_charger_probe,
 660        .remove = act8945a_charger_remove,
 661};
 662module_platform_driver(act8945a_charger_driver);
 663
 664MODULE_DESCRIPTION("Active-semi ACT8945A ActivePath charger driver");
 665MODULE_AUTHOR("Wenyou Yang <wenyou.yang@atmel.com>");
 666MODULE_LICENSE("GPL");
 667