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