Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Power supply driver for the Active-semi ACT8945A PMIC
0004  *
0005  * Copyright (C) 2015 Atmel Corporation
0006  *
0007  * Author: Wenyou Yang <wenyou.yang@atmel.com>
0008  */
0009 #include <linux/interrupt.h>
0010 #include <linux/module.h>
0011 #include <linux/of.h>
0012 #include <linux/of_irq.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/power_supply.h>
0015 #include <linux/regmap.h>
0016 #include <linux/gpio/consumer.h>
0017 
0018 static const char *act8945a_charger_model = "ACT8945A";
0019 static const char *act8945a_charger_manufacturer = "Active-semi";
0020 
0021 /*
0022  * ACT8945A Charger Register Map
0023  */
0024 
0025 /* 0x70: Reserved */
0026 #define ACT8945A_APCH_CFG       0x71
0027 #define ACT8945A_APCH_STATUS        0x78
0028 #define ACT8945A_APCH_CTRL      0x79
0029 #define ACT8945A_APCH_STATE     0x7A
0030 
0031 /* ACT8945A_APCH_CFG */
0032 #define APCH_CFG_OVPSET         (0x3 << 0)
0033 #define APCH_CFG_OVPSET_6V6     (0x0 << 0)
0034 #define APCH_CFG_OVPSET_7V      (0x1 << 0)
0035 #define APCH_CFG_OVPSET_7V5     (0x2 << 0)
0036 #define APCH_CFG_OVPSET_8V      (0x3 << 0)
0037 #define APCH_CFG_PRETIMO        (0x3 << 2)
0038 #define APCH_CFG_PRETIMO_40_MIN     (0x0 << 2)
0039 #define APCH_CFG_PRETIMO_60_MIN     (0x1 << 2)
0040 #define APCH_CFG_PRETIMO_80_MIN     (0x2 << 2)
0041 #define APCH_CFG_PRETIMO_DISABLED   (0x3 << 2)
0042 #define APCH_CFG_TOTTIMO        (0x3 << 4)
0043 #define APCH_CFG_TOTTIMO_3_HOUR     (0x0 << 4)
0044 #define APCH_CFG_TOTTIMO_4_HOUR     (0x1 << 4)
0045 #define APCH_CFG_TOTTIMO_5_HOUR     (0x2 << 4)
0046 #define APCH_CFG_TOTTIMO_DISABLED   (0x3 << 4)
0047 #define APCH_CFG_SUSCHG         (0x1 << 7)
0048 
0049 #define APCH_STATUS_CHGDAT      BIT(0)
0050 #define APCH_STATUS_INDAT       BIT(1)
0051 #define APCH_STATUS_TEMPDAT     BIT(2)
0052 #define APCH_STATUS_TIMRDAT     BIT(3)
0053 #define APCH_STATUS_CHGSTAT     BIT(4)
0054 #define APCH_STATUS_INSTAT      BIT(5)
0055 #define APCH_STATUS_TEMPSTAT        BIT(6)
0056 #define APCH_STATUS_TIMRSTAT        BIT(7)
0057 
0058 #define APCH_CTRL_CHGEOCOUT     BIT(0)
0059 #define APCH_CTRL_INDIS         BIT(1)
0060 #define APCH_CTRL_TEMPOUT       BIT(2)
0061 #define APCH_CTRL_TIMRPRE       BIT(3)
0062 #define APCH_CTRL_CHGEOCIN      BIT(4)
0063 #define APCH_CTRL_INCON         BIT(5)
0064 #define APCH_CTRL_TEMPIN        BIT(6)
0065 #define APCH_CTRL_TIMRTOT       BIT(7)
0066 
0067 #define APCH_STATE_ACINSTAT     (0x1 << 1)
0068 #define APCH_STATE_CSTATE       (0x3 << 4)
0069 #define APCH_STATE_CSTATE_SHIFT     4
0070 #define APCH_STATE_CSTATE_DISABLED  0x00
0071 #define APCH_STATE_CSTATE_EOC       0x01
0072 #define APCH_STATE_CSTATE_FAST      0x02
0073 #define APCH_STATE_CSTATE_PRE       0x03
0074 
0075 struct act8945a_charger {
0076     struct power_supply *psy;
0077     struct power_supply_desc desc;
0078     struct regmap *regmap;
0079     struct work_struct work;
0080 
0081     bool init_done;
0082     struct gpio_desc *lbo_gpio;
0083     struct gpio_desc *chglev_gpio;
0084 };
0085 
0086 static int act8945a_get_charger_state(struct regmap *regmap, int *val)
0087 {
0088     int ret;
0089     unsigned int status, state;
0090 
0091     ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status);
0092     if (ret < 0)
0093         return ret;
0094 
0095     ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state);
0096     if (ret < 0)
0097         return ret;
0098 
0099     state &= APCH_STATE_CSTATE;
0100     state >>= APCH_STATE_CSTATE_SHIFT;
0101 
0102     switch (state) {
0103     case APCH_STATE_CSTATE_PRE:
0104     case APCH_STATE_CSTATE_FAST:
0105         *val = POWER_SUPPLY_STATUS_CHARGING;
0106         break;
0107     case APCH_STATE_CSTATE_EOC:
0108         if (status & APCH_STATUS_CHGDAT)
0109             *val = POWER_SUPPLY_STATUS_FULL;
0110         else
0111             *val = POWER_SUPPLY_STATUS_CHARGING;
0112         break;
0113     case APCH_STATE_CSTATE_DISABLED:
0114     default:
0115         if (!(status & APCH_STATUS_INDAT))
0116             *val = POWER_SUPPLY_STATUS_DISCHARGING;
0117         else
0118             *val = POWER_SUPPLY_STATUS_NOT_CHARGING;
0119         break;
0120     }
0121 
0122     return 0;
0123 }
0124 
0125 static int act8945a_get_charge_type(struct regmap *regmap, int *val)
0126 {
0127     int ret;
0128     unsigned int status, state;
0129 
0130     ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status);
0131     if (ret < 0)
0132         return ret;
0133 
0134     ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state);
0135     if (ret < 0)
0136         return ret;
0137 
0138     state &= APCH_STATE_CSTATE;
0139     state >>= APCH_STATE_CSTATE_SHIFT;
0140 
0141     switch (state) {
0142     case APCH_STATE_CSTATE_PRE:
0143         *val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
0144         break;
0145     case APCH_STATE_CSTATE_FAST:
0146         *val = POWER_SUPPLY_CHARGE_TYPE_FAST;
0147         break;
0148     case APCH_STATE_CSTATE_EOC:
0149         *val = POWER_SUPPLY_CHARGE_TYPE_NONE;
0150         break;
0151     case APCH_STATE_CSTATE_DISABLED:
0152     default:
0153         if (!(status & APCH_STATUS_INDAT))
0154             *val = POWER_SUPPLY_CHARGE_TYPE_NONE;
0155         else
0156             *val = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
0157         break;
0158     }
0159 
0160     return 0;
0161 }
0162 
0163 static int act8945a_get_battery_health(struct regmap *regmap, int *val)
0164 {
0165     int ret;
0166     unsigned int status, state, config;
0167 
0168     ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status);
0169     if (ret < 0)
0170         return ret;
0171 
0172     ret = regmap_read(regmap, ACT8945A_APCH_CFG, &config);
0173     if (ret < 0)
0174         return ret;
0175 
0176     ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state);
0177     if (ret < 0)
0178         return ret;
0179 
0180     state &= APCH_STATE_CSTATE;
0181     state >>= APCH_STATE_CSTATE_SHIFT;
0182 
0183     switch (state) {
0184     case APCH_STATE_CSTATE_DISABLED:
0185         if (config & APCH_CFG_SUSCHG) {
0186             *val = POWER_SUPPLY_HEALTH_UNKNOWN;
0187         } else if (status & APCH_STATUS_INDAT) {
0188             if (!(status & APCH_STATUS_TEMPDAT))
0189                 *val = POWER_SUPPLY_HEALTH_OVERHEAT;
0190             else if (status & APCH_STATUS_TIMRDAT)
0191                 *val = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
0192             else
0193                 *val = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
0194         } else {
0195             *val = POWER_SUPPLY_HEALTH_GOOD;
0196         }
0197         break;
0198     case APCH_STATE_CSTATE_PRE:
0199     case APCH_STATE_CSTATE_FAST:
0200     case APCH_STATE_CSTATE_EOC:
0201     default:
0202         *val = POWER_SUPPLY_HEALTH_GOOD;
0203         break;
0204     }
0205 
0206     return 0;
0207 }
0208 
0209 static int act8945a_get_capacity_level(struct act8945a_charger *charger,
0210                        struct regmap *regmap, int *val)
0211 {
0212     int ret;
0213     unsigned int status, state, config;
0214     int lbo_level = gpiod_get_value(charger->lbo_gpio);
0215 
0216     ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status);
0217     if (ret < 0)
0218         return ret;
0219 
0220     ret = regmap_read(regmap, ACT8945A_APCH_CFG, &config);
0221     if (ret < 0)
0222         return ret;
0223 
0224     ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state);
0225     if (ret < 0)
0226         return ret;
0227 
0228     state &= APCH_STATE_CSTATE;
0229     state >>= APCH_STATE_CSTATE_SHIFT;
0230 
0231     switch (state) {
0232     case APCH_STATE_CSTATE_PRE:
0233         *val = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
0234         break;
0235     case APCH_STATE_CSTATE_FAST:
0236         if (lbo_level)
0237             *val = POWER_SUPPLY_CAPACITY_LEVEL_HIGH;
0238         else
0239             *val = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
0240         break;
0241     case APCH_STATE_CSTATE_EOC:
0242         if (status & APCH_STATUS_CHGDAT)
0243             *val = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
0244         else
0245             *val = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
0246         break;
0247     case APCH_STATE_CSTATE_DISABLED:
0248     default:
0249         if (config & APCH_CFG_SUSCHG) {
0250             *val = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
0251         } else {
0252             *val = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
0253             if (!(status & APCH_STATUS_INDAT)) {
0254                 if (!lbo_level)
0255                     *val = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
0256             }
0257         }
0258         break;
0259     }
0260 
0261     return 0;
0262 }
0263 
0264 #define MAX_CURRENT_USB_HIGH    450000
0265 #define MAX_CURRENT_USB_LOW 90000
0266 #define MAX_CURRENT_USB_PRE 45000
0267 /*
0268  * Riset(K) = 2336 * (1V/Ichg(mA)) - 0.205
0269  * Riset = 2.43K
0270  */
0271 #define MAX_CURRENT_AC_HIGH     886527
0272 #define MAX_CURRENT_AC_LOW      117305
0273 #define MAX_CURRENT_AC_HIGH_PRE     88653
0274 #define MAX_CURRENT_AC_LOW_PRE      11731
0275 
0276 static int act8945a_get_current_max(struct act8945a_charger *charger,
0277                     struct regmap *regmap, int *val)
0278 {
0279     int ret;
0280     unsigned int status, state;
0281     unsigned int acin_state;
0282     int chgin_level = gpiod_get_value(charger->chglev_gpio);
0283 
0284     ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status);
0285     if (ret < 0)
0286         return ret;
0287 
0288     ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state);
0289     if (ret < 0)
0290         return ret;
0291 
0292     acin_state = (state & APCH_STATE_ACINSTAT) >> 1;
0293 
0294     state &= APCH_STATE_CSTATE;
0295     state >>= APCH_STATE_CSTATE_SHIFT;
0296 
0297     switch (state) {
0298     case APCH_STATE_CSTATE_PRE:
0299         if (acin_state) {
0300             if (chgin_level)
0301                 *val = MAX_CURRENT_AC_HIGH_PRE;
0302             else
0303                 *val = MAX_CURRENT_AC_LOW_PRE;
0304         } else {
0305             *val = MAX_CURRENT_USB_PRE;
0306         }
0307         break;
0308     case APCH_STATE_CSTATE_FAST:
0309         if (acin_state) {
0310             if (chgin_level)
0311                 *val = MAX_CURRENT_AC_HIGH;
0312             else
0313                 *val = MAX_CURRENT_AC_LOW;
0314         } else {
0315             if (chgin_level)
0316                 *val = MAX_CURRENT_USB_HIGH;
0317             else
0318                 *val = MAX_CURRENT_USB_LOW;
0319         }
0320         break;
0321     case APCH_STATE_CSTATE_EOC:
0322     case APCH_STATE_CSTATE_DISABLED:
0323     default:
0324         *val = 0;
0325         break;
0326     }
0327 
0328     return 0;
0329 }
0330 
0331 static enum power_supply_property act8945a_charger_props[] = {
0332     POWER_SUPPLY_PROP_STATUS,
0333     POWER_SUPPLY_PROP_CHARGE_TYPE,
0334     POWER_SUPPLY_PROP_TECHNOLOGY,
0335     POWER_SUPPLY_PROP_HEALTH,
0336     POWER_SUPPLY_PROP_CAPACITY_LEVEL,
0337     POWER_SUPPLY_PROP_CURRENT_MAX,
0338     POWER_SUPPLY_PROP_MODEL_NAME,
0339     POWER_SUPPLY_PROP_MANUFACTURER
0340 };
0341 
0342 static int act8945a_charger_get_property(struct power_supply *psy,
0343                      enum power_supply_property prop,
0344                      union power_supply_propval *val)
0345 {
0346     struct act8945a_charger *charger = power_supply_get_drvdata(psy);
0347     struct regmap *regmap = charger->regmap;
0348     int ret = 0;
0349 
0350     switch (prop) {
0351     case POWER_SUPPLY_PROP_STATUS:
0352         ret = act8945a_get_charger_state(regmap, &val->intval);
0353         break;
0354     case POWER_SUPPLY_PROP_CHARGE_TYPE:
0355         ret = act8945a_get_charge_type(regmap, &val->intval);
0356         break;
0357     case POWER_SUPPLY_PROP_TECHNOLOGY:
0358         val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
0359         break;
0360     case POWER_SUPPLY_PROP_HEALTH:
0361         ret = act8945a_get_battery_health(regmap, &val->intval);
0362         break;
0363     case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
0364         ret = act8945a_get_capacity_level(charger,
0365                           regmap, &val->intval);
0366         break;
0367     case POWER_SUPPLY_PROP_CURRENT_MAX:
0368         ret = act8945a_get_current_max(charger,
0369                            regmap, &val->intval);
0370         break;
0371     case POWER_SUPPLY_PROP_MODEL_NAME:
0372         val->strval = act8945a_charger_model;
0373         break;
0374     case POWER_SUPPLY_PROP_MANUFACTURER:
0375         val->strval = act8945a_charger_manufacturer;
0376         break;
0377     default:
0378         return -EINVAL;
0379     }
0380 
0381     return ret;
0382 }
0383 
0384 static int act8945a_enable_interrupt(struct act8945a_charger *charger)
0385 {
0386     struct regmap *regmap = charger->regmap;
0387     unsigned char ctrl;
0388     int ret;
0389 
0390     ctrl = APCH_CTRL_CHGEOCOUT | APCH_CTRL_CHGEOCIN |
0391            APCH_CTRL_INDIS | APCH_CTRL_INCON |
0392            APCH_CTRL_TEMPOUT | APCH_CTRL_TEMPIN |
0393            APCH_CTRL_TIMRPRE | APCH_CTRL_TIMRTOT;
0394     ret = regmap_write(regmap, ACT8945A_APCH_CTRL, ctrl);
0395     if (ret)
0396         return ret;
0397 
0398     ctrl = APCH_STATUS_CHGSTAT | APCH_STATUS_INSTAT |
0399            APCH_STATUS_TEMPSTAT | APCH_STATUS_TIMRSTAT;
0400     ret = regmap_write(regmap, ACT8945A_APCH_STATUS, ctrl);
0401     if (ret)
0402         return ret;
0403 
0404     return 0;
0405 }
0406 
0407 static unsigned int act8945a_set_supply_type(struct act8945a_charger *charger,
0408                          unsigned int *type)
0409 {
0410     unsigned int status, state;
0411     int ret;
0412 
0413     ret = regmap_read(charger->regmap, ACT8945A_APCH_STATUS, &status);
0414     if (ret < 0)
0415         return ret;
0416 
0417     ret = regmap_read(charger->regmap, ACT8945A_APCH_STATE, &state);
0418     if (ret < 0)
0419         return ret;
0420 
0421     if (status & APCH_STATUS_INDAT) {
0422         if (state & APCH_STATE_ACINSTAT)
0423             *type = POWER_SUPPLY_TYPE_MAINS;
0424         else
0425             *type = POWER_SUPPLY_TYPE_USB;
0426     } else {
0427         *type = POWER_SUPPLY_TYPE_BATTERY;
0428     }
0429 
0430     return 0;
0431 }
0432 
0433 static void act8945a_work(struct work_struct *work)
0434 {
0435     struct act8945a_charger *charger =
0436             container_of(work, struct act8945a_charger, work);
0437 
0438     act8945a_set_supply_type(charger, &charger->desc.type);
0439 
0440     power_supply_changed(charger->psy);
0441 }
0442 
0443 static irqreturn_t act8945a_status_changed(int irq, void *dev_id)
0444 {
0445     struct act8945a_charger *charger = dev_id;
0446 
0447     if (charger->init_done)
0448         schedule_work(&charger->work);
0449 
0450     return IRQ_HANDLED;
0451 }
0452 
0453 #define DEFAULT_TOTAL_TIME_OUT      3
0454 #define DEFAULT_PRE_TIME_OUT        40
0455 #define DEFAULT_INPUT_OVP_THRESHOLD 6600
0456 
0457 static int act8945a_charger_config(struct device *dev,
0458                    struct act8945a_charger *charger)
0459 {
0460     struct device_node *np = dev->of_node;
0461     struct regmap *regmap = charger->regmap;
0462 
0463     u32 total_time_out;
0464     u32 pre_time_out;
0465     u32 input_voltage_threshold;
0466     int err, ret;
0467 
0468     unsigned int tmp;
0469     unsigned int value = 0;
0470 
0471     if (!np) {
0472         dev_err(dev, "no charger of node\n");
0473         return -EINVAL;
0474     }
0475 
0476     ret = regmap_read(regmap, ACT8945A_APCH_CFG, &tmp);
0477     if (ret)
0478         return ret;
0479 
0480     if (tmp & APCH_CFG_SUSCHG) {
0481         value |= APCH_CFG_SUSCHG;
0482         dev_info(dev, "have been suspended\n");
0483     }
0484 
0485     charger->lbo_gpio = devm_gpiod_get_optional(dev, "active-semi,lbo",
0486                             GPIOD_IN);
0487     if (IS_ERR(charger->lbo_gpio)) {
0488         err = PTR_ERR(charger->lbo_gpio);
0489         dev_err(dev, "unable to claim gpio \"lbo\": %d\n", err);
0490         return err;
0491     }
0492 
0493     ret = devm_request_irq(dev, gpiod_to_irq(charger->lbo_gpio),
0494                    act8945a_status_changed,
0495                    (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING),
0496                    "act8945a_lbo_detect", charger);
0497     if (ret)
0498         dev_info(dev, "failed to request gpio \"lbo\" IRQ\n");
0499 
0500     charger->chglev_gpio = devm_gpiod_get_optional(dev,
0501                                "active-semi,chglev",
0502                                GPIOD_IN);
0503     if (IS_ERR(charger->chglev_gpio)) {
0504         err = PTR_ERR(charger->chglev_gpio);
0505         dev_err(dev, "unable to claim gpio \"chglev\": %d\n", err);
0506         return err;
0507     }
0508 
0509     if (of_property_read_u32(np,
0510                  "active-semi,input-voltage-threshold-microvolt",
0511                  &input_voltage_threshold))
0512         input_voltage_threshold = DEFAULT_INPUT_OVP_THRESHOLD;
0513 
0514     if (of_property_read_u32(np,
0515                  "active-semi,precondition-timeout",
0516                  &pre_time_out))
0517         pre_time_out = DEFAULT_PRE_TIME_OUT;
0518 
0519     if (of_property_read_u32(np, "active-semi,total-timeout",
0520                  &total_time_out))
0521         total_time_out = DEFAULT_TOTAL_TIME_OUT;
0522 
0523     switch (input_voltage_threshold) {
0524     case 8000:
0525         value |= APCH_CFG_OVPSET_8V;
0526         break;
0527     case 7500:
0528         value |= APCH_CFG_OVPSET_7V5;
0529         break;
0530     case 7000:
0531         value |= APCH_CFG_OVPSET_7V;
0532         break;
0533     case 6600:
0534     default:
0535         value |= APCH_CFG_OVPSET_6V6;
0536         break;
0537     }
0538 
0539     switch (pre_time_out) {
0540     case 60:
0541         value |= APCH_CFG_PRETIMO_60_MIN;
0542         break;
0543     case 80:
0544         value |= APCH_CFG_PRETIMO_80_MIN;
0545         break;
0546     case 0:
0547         value |= APCH_CFG_PRETIMO_DISABLED;
0548         break;
0549     case 40:
0550     default:
0551         value |= APCH_CFG_PRETIMO_40_MIN;
0552         break;
0553     }
0554 
0555     switch (total_time_out) {
0556     case 4:
0557         value |= APCH_CFG_TOTTIMO_4_HOUR;
0558         break;
0559     case 5:
0560         value |= APCH_CFG_TOTTIMO_5_HOUR;
0561         break;
0562     case 0:
0563         value |= APCH_CFG_TOTTIMO_DISABLED;
0564         break;
0565     case 3:
0566     default:
0567         value |= APCH_CFG_TOTTIMO_3_HOUR;
0568         break;
0569     }
0570 
0571     return regmap_write(regmap, ACT8945A_APCH_CFG, value);
0572 }
0573 
0574 static int act8945a_charger_probe(struct platform_device *pdev)
0575 {
0576     struct act8945a_charger *charger;
0577     struct power_supply_config psy_cfg = {};
0578     int irq, ret;
0579 
0580     charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL);
0581     if (!charger)
0582         return -ENOMEM;
0583 
0584     charger->regmap = dev_get_regmap(pdev->dev.parent, NULL);
0585     if (!charger->regmap) {
0586         dev_err(&pdev->dev, "Parent did not provide regmap\n");
0587         return -EINVAL;
0588     }
0589 
0590     ret = act8945a_charger_config(&pdev->dev, charger);
0591     if (ret)
0592         return ret;
0593 
0594     irq = of_irq_get(pdev->dev.of_node, 0);
0595     if (irq <= 0) {
0596         dev_err(&pdev->dev, "failed to find IRQ number\n");
0597         return irq ?: -ENXIO;
0598     }
0599 
0600     ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed,
0601                    IRQF_TRIGGER_FALLING, "act8945a_interrupt",
0602                    charger);
0603     if (ret) {
0604         dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n");
0605         return ret;
0606     }
0607 
0608     charger->desc.name = "act8945a-charger";
0609     charger->desc.get_property = act8945a_charger_get_property;
0610     charger->desc.properties = act8945a_charger_props;
0611     charger->desc.num_properties = ARRAY_SIZE(act8945a_charger_props);
0612 
0613     ret = act8945a_set_supply_type(charger, &charger->desc.type);
0614     if (ret)
0615         return -EINVAL;
0616 
0617     psy_cfg.of_node = pdev->dev.of_node;
0618     psy_cfg.drv_data = charger;
0619 
0620     charger->psy = devm_power_supply_register(&pdev->dev,
0621                           &charger->desc,
0622                           &psy_cfg);
0623     if (IS_ERR(charger->psy)) {
0624         dev_err(&pdev->dev, "failed to register power supply\n");
0625         return PTR_ERR(charger->psy);
0626     }
0627 
0628     platform_set_drvdata(pdev, charger);
0629 
0630     INIT_WORK(&charger->work, act8945a_work);
0631 
0632     ret = act8945a_enable_interrupt(charger);
0633     if (ret)
0634         return -EIO;
0635 
0636     charger->init_done = true;
0637 
0638     return 0;
0639 }
0640 
0641 static int act8945a_charger_remove(struct platform_device *pdev)
0642 {
0643     struct act8945a_charger *charger = platform_get_drvdata(pdev);
0644 
0645     charger->init_done = false;
0646     cancel_work_sync(&charger->work);
0647 
0648     return 0;
0649 }
0650 
0651 static struct platform_driver act8945a_charger_driver = {
0652     .driver = {
0653         .name = "act8945a-charger",
0654     },
0655     .probe  = act8945a_charger_probe,
0656     .remove = act8945a_charger_remove,
0657 };
0658 module_platform_driver(act8945a_charger_driver);
0659 
0660 MODULE_DESCRIPTION("Active-semi ACT8945A ActivePath charger driver");
0661 MODULE_AUTHOR("Wenyou Yang <wenyou.yang@atmel.com>");
0662 MODULE_LICENSE("GPL");