Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * TI LP8788 MFD - battery charger driver
0004  *
0005  * Copyright 2012 Texas Instruments
0006  *
0007  * Author: Milo(Woogyom) Kim <milo.kim@ti.com>
0008  */
0009 
0010 #include <linux/err.h>
0011 #include <linux/iio/consumer.h>
0012 #include <linux/interrupt.h>
0013 #include <linux/irqdomain.h>
0014 #include <linux/mfd/lp8788.h>
0015 #include <linux/module.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/power_supply.h>
0018 #include <linux/slab.h>
0019 #include <linux/workqueue.h>
0020 
0021 /* register address */
0022 #define LP8788_CHG_STATUS       0x07
0023 #define LP8788_CHG_IDCIN        0x13
0024 #define LP8788_CHG_IBATT        0x14
0025 #define LP8788_CHG_VTERM        0x15
0026 #define LP8788_CHG_EOC          0x16
0027 
0028 /* mask/shift bits */
0029 #define LP8788_CHG_INPUT_STATE_M    0x03    /* Addr 07h */
0030 #define LP8788_CHG_STATE_M      0x3C
0031 #define LP8788_CHG_STATE_S      2
0032 #define LP8788_NO_BATT_M        BIT(6)
0033 #define LP8788_BAD_BATT_M       BIT(7)
0034 #define LP8788_CHG_IBATT_M      0x1F    /* Addr 14h */
0035 #define LP8788_CHG_VTERM_M      0x0F    /* Addr 15h */
0036 #define LP8788_CHG_EOC_LEVEL_M      0x30    /* Addr 16h */
0037 #define LP8788_CHG_EOC_LEVEL_S      4
0038 #define LP8788_CHG_EOC_TIME_M       0x0E
0039 #define LP8788_CHG_EOC_TIME_S       1
0040 #define LP8788_CHG_EOC_MODE_M       BIT(0)
0041 
0042 #define LP8788_CHARGER_NAME     "charger"
0043 #define LP8788_BATTERY_NAME     "main_batt"
0044 
0045 #define LP8788_CHG_START        0x11
0046 #define LP8788_CHG_END          0x1C
0047 
0048 #define LP8788_ISEL_MAX         23
0049 #define LP8788_ISEL_STEP        50
0050 #define LP8788_VTERM_MIN        4100
0051 #define LP8788_VTERM_STEP       25
0052 #define LP8788_MAX_BATT_CAPACITY    100
0053 #define LP8788_MAX_CHG_IRQS     11
0054 
0055 enum lp8788_charging_state {
0056     LP8788_OFF,
0057     LP8788_WARM_UP,
0058     LP8788_LOW_INPUT = 0x3,
0059     LP8788_PRECHARGE,
0060     LP8788_CC,
0061     LP8788_CV,
0062     LP8788_MAINTENANCE,
0063     LP8788_BATTERY_FAULT,
0064     LP8788_SYSTEM_SUPPORT = 0xC,
0065     LP8788_HIGH_CURRENT = 0xF,
0066     LP8788_MAX_CHG_STATE,
0067 };
0068 
0069 enum lp8788_charger_adc_sel {
0070     LP8788_VBATT,
0071     LP8788_BATT_TEMP,
0072     LP8788_NUM_CHG_ADC,
0073 };
0074 
0075 enum lp8788_charger_input_state {
0076     LP8788_SYSTEM_SUPPLY = 1,
0077     LP8788_FULL_FUNCTION,
0078 };
0079 
0080 /*
0081  * struct lp8788_chg_irq
0082  * @which        : lp8788 interrupt id
0083  * @virq         : Linux IRQ number from irq_domain
0084  */
0085 struct lp8788_chg_irq {
0086     enum lp8788_int_id which;
0087     int virq;
0088 };
0089 
0090 /*
0091  * struct lp8788_charger
0092  * @lp           : used for accessing the registers of mfd lp8788 device
0093  * @charger      : power supply driver for the battery charger
0094  * @battery      : power supply driver for the battery
0095  * @charger_work : work queue for charger input interrupts
0096  * @chan         : iio channels for getting adc values
0097  *                 eg) battery voltage, capacity and temperature
0098  * @irqs         : charger dedicated interrupts
0099  * @num_irqs     : total numbers of charger interrupts
0100  * @pdata        : charger platform specific data
0101  */
0102 struct lp8788_charger {
0103     struct lp8788 *lp;
0104     struct power_supply *charger;
0105     struct power_supply *battery;
0106     struct work_struct charger_work;
0107     struct iio_channel *chan[LP8788_NUM_CHG_ADC];
0108     struct lp8788_chg_irq irqs[LP8788_MAX_CHG_IRQS];
0109     int num_irqs;
0110     struct lp8788_charger_platform_data *pdata;
0111 };
0112 
0113 static char *battery_supplied_to[] = {
0114     LP8788_BATTERY_NAME,
0115 };
0116 
0117 static enum power_supply_property lp8788_charger_prop[] = {
0118     POWER_SUPPLY_PROP_ONLINE,
0119     POWER_SUPPLY_PROP_CURRENT_MAX,
0120 };
0121 
0122 static enum power_supply_property lp8788_battery_prop[] = {
0123     POWER_SUPPLY_PROP_STATUS,
0124     POWER_SUPPLY_PROP_HEALTH,
0125     POWER_SUPPLY_PROP_PRESENT,
0126     POWER_SUPPLY_PROP_VOLTAGE_NOW,
0127     POWER_SUPPLY_PROP_CAPACITY,
0128     POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
0129     POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
0130     POWER_SUPPLY_PROP_TEMP,
0131 };
0132 
0133 static bool lp8788_is_charger_detected(struct lp8788_charger *pchg)
0134 {
0135     u8 data;
0136 
0137     lp8788_read_byte(pchg->lp, LP8788_CHG_STATUS, &data);
0138     data &= LP8788_CHG_INPUT_STATE_M;
0139 
0140     return data == LP8788_SYSTEM_SUPPLY || data == LP8788_FULL_FUNCTION;
0141 }
0142 
0143 static int lp8788_charger_get_property(struct power_supply *psy,
0144                     enum power_supply_property psp,
0145                     union power_supply_propval *val)
0146 {
0147     struct lp8788_charger *pchg = dev_get_drvdata(psy->dev.parent);
0148     u8 read;
0149 
0150     switch (psp) {
0151     case POWER_SUPPLY_PROP_ONLINE:
0152         val->intval = lp8788_is_charger_detected(pchg);
0153         break;
0154     case POWER_SUPPLY_PROP_CURRENT_MAX:
0155         lp8788_read_byte(pchg->lp, LP8788_CHG_IDCIN, &read);
0156         val->intval = LP8788_ISEL_STEP *
0157                 (min_t(int, read, LP8788_ISEL_MAX) + 1);
0158         break;
0159     default:
0160         return -EINVAL;
0161     }
0162 
0163     return 0;
0164 }
0165 
0166 static int lp8788_get_battery_status(struct lp8788_charger *pchg,
0167                 union power_supply_propval *val)
0168 {
0169     enum lp8788_charging_state state;
0170     u8 data;
0171     int ret;
0172 
0173     ret = lp8788_read_byte(pchg->lp, LP8788_CHG_STATUS, &data);
0174     if (ret)
0175         return ret;
0176 
0177     state = (data & LP8788_CHG_STATE_M) >> LP8788_CHG_STATE_S;
0178     switch (state) {
0179     case LP8788_OFF:
0180         val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
0181         break;
0182     case LP8788_PRECHARGE:
0183     case LP8788_CC:
0184     case LP8788_CV:
0185     case LP8788_HIGH_CURRENT:
0186         val->intval = POWER_SUPPLY_STATUS_CHARGING;
0187         break;
0188     case LP8788_MAINTENANCE:
0189         val->intval = POWER_SUPPLY_STATUS_FULL;
0190         break;
0191     default:
0192         val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
0193         break;
0194     }
0195 
0196     return 0;
0197 }
0198 
0199 static int lp8788_get_battery_health(struct lp8788_charger *pchg,
0200                 union power_supply_propval *val)
0201 {
0202     u8 data;
0203     int ret;
0204 
0205     ret = lp8788_read_byte(pchg->lp, LP8788_CHG_STATUS, &data);
0206     if (ret)
0207         return ret;
0208 
0209     if (data & LP8788_NO_BATT_M)
0210         val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
0211     else if (data & LP8788_BAD_BATT_M)
0212         val->intval = POWER_SUPPLY_HEALTH_DEAD;
0213     else
0214         val->intval = POWER_SUPPLY_HEALTH_GOOD;
0215 
0216     return 0;
0217 }
0218 
0219 static int lp8788_get_battery_present(struct lp8788_charger *pchg,
0220                 union power_supply_propval *val)
0221 {
0222     u8 data;
0223     int ret;
0224 
0225     ret = lp8788_read_byte(pchg->lp, LP8788_CHG_STATUS, &data);
0226     if (ret)
0227         return ret;
0228 
0229     val->intval = !(data & LP8788_NO_BATT_M);
0230     return 0;
0231 }
0232 
0233 static int lp8788_get_vbatt_adc(struct lp8788_charger *pchg, int *result)
0234 {
0235     struct iio_channel *channel = pchg->chan[LP8788_VBATT];
0236 
0237     if (!channel)
0238         return -EINVAL;
0239 
0240     return iio_read_channel_processed(channel, result);
0241 }
0242 
0243 static int lp8788_get_battery_voltage(struct lp8788_charger *pchg,
0244                 union power_supply_propval *val)
0245 {
0246     return lp8788_get_vbatt_adc(pchg, &val->intval);
0247 }
0248 
0249 static int lp8788_get_battery_capacity(struct lp8788_charger *pchg,
0250                 union power_supply_propval *val)
0251 {
0252     struct lp8788 *lp = pchg->lp;
0253     struct lp8788_charger_platform_data *pdata = pchg->pdata;
0254     unsigned int max_vbatt;
0255     int vbatt;
0256     enum lp8788_charging_state state;
0257     u8 data;
0258     int ret;
0259 
0260     if (!pdata)
0261         return -EINVAL;
0262 
0263     max_vbatt = pdata->max_vbatt_mv;
0264     if (max_vbatt == 0)
0265         return -EINVAL;
0266 
0267     ret = lp8788_read_byte(lp, LP8788_CHG_STATUS, &data);
0268     if (ret)
0269         return ret;
0270 
0271     state = (data & LP8788_CHG_STATE_M) >> LP8788_CHG_STATE_S;
0272 
0273     if (state == LP8788_MAINTENANCE) {
0274         val->intval = LP8788_MAX_BATT_CAPACITY;
0275     } else {
0276         ret = lp8788_get_vbatt_adc(pchg, &vbatt);
0277         if (ret)
0278             return ret;
0279 
0280         val->intval = (vbatt * LP8788_MAX_BATT_CAPACITY) / max_vbatt;
0281         val->intval = min(val->intval, LP8788_MAX_BATT_CAPACITY);
0282     }
0283 
0284     return 0;
0285 }
0286 
0287 static int lp8788_get_battery_temperature(struct lp8788_charger *pchg,
0288                 union power_supply_propval *val)
0289 {
0290     struct iio_channel *channel = pchg->chan[LP8788_BATT_TEMP];
0291     int result;
0292     int ret;
0293 
0294     if (!channel)
0295         return -EINVAL;
0296 
0297     ret = iio_read_channel_processed(channel, &result);
0298     if (ret < 0)
0299         return -EINVAL;
0300 
0301     /* unit: 0.1 'C */
0302     val->intval = result * 10;
0303 
0304     return 0;
0305 }
0306 
0307 static int lp8788_get_battery_charging_current(struct lp8788_charger *pchg,
0308                 union power_supply_propval *val)
0309 {
0310     u8 read;
0311 
0312     lp8788_read_byte(pchg->lp, LP8788_CHG_IBATT, &read);
0313     read &= LP8788_CHG_IBATT_M;
0314     val->intval = LP8788_ISEL_STEP *
0315             (min_t(int, read, LP8788_ISEL_MAX) + 1);
0316 
0317     return 0;
0318 }
0319 
0320 static int lp8788_get_charging_termination_voltage(struct lp8788_charger *pchg,
0321                 union power_supply_propval *val)
0322 {
0323     u8 read;
0324 
0325     lp8788_read_byte(pchg->lp, LP8788_CHG_VTERM, &read);
0326     read &= LP8788_CHG_VTERM_M;
0327     val->intval = LP8788_VTERM_MIN + LP8788_VTERM_STEP * read;
0328 
0329     return 0;
0330 }
0331 
0332 static int lp8788_battery_get_property(struct power_supply *psy,
0333                     enum power_supply_property psp,
0334                     union power_supply_propval *val)
0335 {
0336     struct lp8788_charger *pchg = dev_get_drvdata(psy->dev.parent);
0337 
0338     switch (psp) {
0339     case POWER_SUPPLY_PROP_STATUS:
0340         return lp8788_get_battery_status(pchg, val);
0341     case POWER_SUPPLY_PROP_HEALTH:
0342         return lp8788_get_battery_health(pchg, val);
0343     case POWER_SUPPLY_PROP_PRESENT:
0344         return lp8788_get_battery_present(pchg, val);
0345     case POWER_SUPPLY_PROP_VOLTAGE_NOW:
0346         return lp8788_get_battery_voltage(pchg, val);
0347     case POWER_SUPPLY_PROP_CAPACITY:
0348         return lp8788_get_battery_capacity(pchg, val);
0349     case POWER_SUPPLY_PROP_TEMP:
0350         return lp8788_get_battery_temperature(pchg, val);
0351     case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
0352         return lp8788_get_battery_charging_current(pchg, val);
0353     case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
0354         return lp8788_get_charging_termination_voltage(pchg, val);
0355     default:
0356         return -EINVAL;
0357     }
0358 }
0359 
0360 static inline bool lp8788_is_valid_charger_register(u8 addr)
0361 {
0362     return addr >= LP8788_CHG_START && addr <= LP8788_CHG_END;
0363 }
0364 
0365 static int lp8788_update_charger_params(struct platform_device *pdev,
0366                     struct lp8788_charger *pchg)
0367 {
0368     struct lp8788 *lp = pchg->lp;
0369     struct lp8788_charger_platform_data *pdata = pchg->pdata;
0370     struct lp8788_chg_param *param;
0371     int i;
0372     int ret;
0373 
0374     if (!pdata || !pdata->chg_params) {
0375         dev_info(&pdev->dev, "skip updating charger parameters\n");
0376         return 0;
0377     }
0378 
0379     /* setting charging parameters */
0380     for (i = 0; i < pdata->num_chg_params; i++) {
0381         param = pdata->chg_params + i;
0382 
0383         if (lp8788_is_valid_charger_register(param->addr)) {
0384             ret = lp8788_write_byte(lp, param->addr, param->val);
0385             if (ret)
0386                 return ret;
0387         }
0388     }
0389 
0390     return 0;
0391 }
0392 
0393 static const struct power_supply_desc lp8788_psy_charger_desc = {
0394     .name       = LP8788_CHARGER_NAME,
0395     .type       = POWER_SUPPLY_TYPE_MAINS,
0396     .properties = lp8788_charger_prop,
0397     .num_properties = ARRAY_SIZE(lp8788_charger_prop),
0398     .get_property   = lp8788_charger_get_property,
0399 };
0400 
0401 static const struct power_supply_desc lp8788_psy_battery_desc = {
0402     .name       = LP8788_BATTERY_NAME,
0403     .type       = POWER_SUPPLY_TYPE_BATTERY,
0404     .properties = lp8788_battery_prop,
0405     .num_properties = ARRAY_SIZE(lp8788_battery_prop),
0406     .get_property   = lp8788_battery_get_property,
0407 };
0408 
0409 static void lp8788_psy_unregister(struct lp8788_charger *pchg)
0410 {
0411     power_supply_unregister(pchg->battery);
0412     power_supply_unregister(pchg->charger);
0413 }
0414 
0415 static void lp8788_charger_event(struct work_struct *work)
0416 {
0417     struct lp8788_charger *pchg =
0418         container_of(work, struct lp8788_charger, charger_work);
0419     struct lp8788_charger_platform_data *pdata = pchg->pdata;
0420     enum lp8788_charger_event event = lp8788_is_charger_detected(pchg);
0421 
0422     pdata->charger_event(pchg->lp, event);
0423 }
0424 
0425 static bool lp8788_find_irq_id(struct lp8788_charger *pchg, int virq, int *id)
0426 {
0427     bool found = false;
0428     int i;
0429 
0430     for (i = 0; i < pchg->num_irqs; i++) {
0431         if (pchg->irqs[i].virq == virq) {
0432             *id = pchg->irqs[i].which;
0433             found = true;
0434             break;
0435         }
0436     }
0437 
0438     return found;
0439 }
0440 
0441 static irqreturn_t lp8788_charger_irq_thread(int virq, void *ptr)
0442 {
0443     struct lp8788_charger *pchg = ptr;
0444     struct lp8788_charger_platform_data *pdata = pchg->pdata;
0445     int id = -1;
0446 
0447     if (!lp8788_find_irq_id(pchg, virq, &id))
0448         return IRQ_NONE;
0449 
0450     switch (id) {
0451     case LP8788_INT_CHG_INPUT_STATE:
0452     case LP8788_INT_CHG_STATE:
0453     case LP8788_INT_EOC:
0454     case LP8788_INT_BATT_LOW:
0455     case LP8788_INT_NO_BATT:
0456         power_supply_changed(pchg->charger);
0457         power_supply_changed(pchg->battery);
0458         break;
0459     default:
0460         break;
0461     }
0462 
0463     /* report charger dectection event if used */
0464     if (!pdata)
0465         goto irq_handled;
0466 
0467     if (pdata->charger_event && id == LP8788_INT_CHG_INPUT_STATE)
0468         schedule_work(&pchg->charger_work);
0469 
0470 irq_handled:
0471     return IRQ_HANDLED;
0472 }
0473 
0474 static int lp8788_set_irqs(struct platform_device *pdev,
0475             struct lp8788_charger *pchg, const char *name)
0476 {
0477     struct resource *r;
0478     struct irq_domain *irqdm = pchg->lp->irqdm;
0479     int irq_start;
0480     int irq_end;
0481     int virq;
0482     int nr_irq;
0483     int i;
0484     int ret;
0485 
0486     /* no error even if no irq resource */
0487     r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, name);
0488     if (!r)
0489         return 0;
0490 
0491     irq_start = r->start;
0492     irq_end = r->end;
0493 
0494     for (i = irq_start; i <= irq_end; i++) {
0495         nr_irq = pchg->num_irqs;
0496 
0497         virq = irq_create_mapping(irqdm, i);
0498         pchg->irqs[nr_irq].virq = virq;
0499         pchg->irqs[nr_irq].which = i;
0500         pchg->num_irqs++;
0501 
0502         ret = request_threaded_irq(virq, NULL,
0503                     lp8788_charger_irq_thread,
0504                     IRQF_ONESHOT, name, pchg);
0505         if (ret)
0506             break;
0507     }
0508 
0509     if (i <= irq_end)
0510         goto err_free_irq;
0511 
0512     return 0;
0513 
0514 err_free_irq:
0515     for (i = 0; i < pchg->num_irqs; i++)
0516         free_irq(pchg->irqs[i].virq, pchg);
0517     return ret;
0518 }
0519 
0520 static int lp8788_irq_register(struct platform_device *pdev,
0521                 struct lp8788_charger *pchg)
0522 {
0523     const char *name[] = {
0524         LP8788_CHG_IRQ, LP8788_PRSW_IRQ, LP8788_BATT_IRQ
0525     };
0526     int i;
0527     int ret;
0528 
0529     INIT_WORK(&pchg->charger_work, lp8788_charger_event);
0530     pchg->num_irqs = 0;
0531 
0532     for (i = 0; i < ARRAY_SIZE(name); i++) {
0533         ret = lp8788_set_irqs(pdev, pchg, name[i]);
0534         if (ret) {
0535             dev_warn(&pdev->dev, "irq setup failed: %s\n", name[i]);
0536             return ret;
0537         }
0538     }
0539 
0540     if (pchg->num_irqs > LP8788_MAX_CHG_IRQS) {
0541         dev_err(&pdev->dev, "invalid total number of irqs: %d\n",
0542             pchg->num_irqs);
0543         return -EINVAL;
0544     }
0545 
0546 
0547     return 0;
0548 }
0549 
0550 static void lp8788_irq_unregister(struct platform_device *pdev,
0551                   struct lp8788_charger *pchg)
0552 {
0553     int i;
0554     int irq;
0555 
0556     for (i = 0; i < pchg->num_irqs; i++) {
0557         irq = pchg->irqs[i].virq;
0558         if (!irq)
0559             continue;
0560 
0561         free_irq(irq, pchg);
0562     }
0563 }
0564 
0565 static void lp8788_setup_adc_channel(struct device *dev,
0566                 struct lp8788_charger *pchg)
0567 {
0568     struct lp8788_charger_platform_data *pdata = pchg->pdata;
0569     struct iio_channel *chan;
0570 
0571     if (!pdata)
0572         return;
0573 
0574     /* ADC channel for battery voltage */
0575     chan = devm_iio_channel_get(dev, pdata->adc_vbatt);
0576     pchg->chan[LP8788_VBATT] = IS_ERR(chan) ? NULL : chan;
0577 
0578     /* ADC channel for battery temperature */
0579     chan = devm_iio_channel_get(dev, pdata->adc_batt_temp);
0580     pchg->chan[LP8788_BATT_TEMP] = IS_ERR(chan) ? NULL : chan;
0581 }
0582 
0583 static ssize_t lp8788_show_charger_status(struct device *dev,
0584                 struct device_attribute *attr, char *buf)
0585 {
0586     struct lp8788_charger *pchg = dev_get_drvdata(dev);
0587     enum lp8788_charging_state state;
0588     static const char * const desc[LP8788_MAX_CHG_STATE] = {
0589         [LP8788_OFF] = "CHARGER OFF",
0590         [LP8788_WARM_UP] = "WARM UP",
0591         [LP8788_LOW_INPUT] = "LOW INPUT STATE",
0592         [LP8788_PRECHARGE] = "CHARGING - PRECHARGE",
0593         [LP8788_CC] = "CHARGING - CC",
0594         [LP8788_CV] = "CHARGING - CV",
0595         [LP8788_MAINTENANCE] = "NO CHARGING - MAINTENANCE",
0596         [LP8788_BATTERY_FAULT] = "BATTERY FAULT",
0597         [LP8788_SYSTEM_SUPPORT] = "SYSTEM SUPPORT",
0598         [LP8788_HIGH_CURRENT] = "HIGH CURRENT",
0599     };
0600     u8 data;
0601 
0602     lp8788_read_byte(pchg->lp, LP8788_CHG_STATUS, &data);
0603     state = (data & LP8788_CHG_STATE_M) >> LP8788_CHG_STATE_S;
0604 
0605     return scnprintf(buf, PAGE_SIZE, "%s\n", desc[state]);
0606 }
0607 
0608 static ssize_t lp8788_show_eoc_time(struct device *dev,
0609                 struct device_attribute *attr, char *buf)
0610 {
0611     struct lp8788_charger *pchg = dev_get_drvdata(dev);
0612     static const char * const stime[] = {
0613         "400ms", "5min", "10min", "15min",
0614         "20min", "25min", "30min", "No timeout"
0615     };
0616     u8 val;
0617 
0618     lp8788_read_byte(pchg->lp, LP8788_CHG_EOC, &val);
0619     val = (val & LP8788_CHG_EOC_TIME_M) >> LP8788_CHG_EOC_TIME_S;
0620 
0621     return scnprintf(buf, PAGE_SIZE, "End Of Charge Time: %s\n",
0622             stime[val]);
0623 }
0624 
0625 static ssize_t lp8788_show_eoc_level(struct device *dev,
0626                 struct device_attribute *attr, char *buf)
0627 {
0628     struct lp8788_charger *pchg = dev_get_drvdata(dev);
0629     static const char * const abs_level[] = {
0630             "25mA", "49mA", "75mA", "98mA"
0631     };
0632     static const char * const relative_level[] = {
0633             "5%", "10%", "15%", "20%"
0634     };
0635     const char *level;
0636     u8 val;
0637     u8 mode;
0638 
0639     lp8788_read_byte(pchg->lp, LP8788_CHG_EOC, &val);
0640 
0641     mode = val & LP8788_CHG_EOC_MODE_M;
0642     val = (val & LP8788_CHG_EOC_LEVEL_M) >> LP8788_CHG_EOC_LEVEL_S;
0643     level = mode ? abs_level[val] : relative_level[val];
0644 
0645     return scnprintf(buf, PAGE_SIZE, "End Of Charge Level: %s\n", level);
0646 }
0647 
0648 static DEVICE_ATTR(charger_status, S_IRUSR, lp8788_show_charger_status, NULL);
0649 static DEVICE_ATTR(eoc_time, S_IRUSR, lp8788_show_eoc_time, NULL);
0650 static DEVICE_ATTR(eoc_level, S_IRUSR, lp8788_show_eoc_level, NULL);
0651 
0652 static struct attribute *lp8788_charger_sysfs_attrs[] = {
0653     &dev_attr_charger_status.attr,
0654     &dev_attr_eoc_time.attr,
0655     &dev_attr_eoc_level.attr,
0656     NULL,
0657 };
0658 
0659 ATTRIBUTE_GROUPS(lp8788_charger_sysfs);
0660 
0661 static int lp8788_psy_register(struct platform_device *pdev,
0662                 struct lp8788_charger *pchg)
0663 {
0664     struct power_supply_config charger_cfg = {};
0665 
0666     charger_cfg.attr_grp = lp8788_charger_sysfs_groups;
0667     charger_cfg.supplied_to = battery_supplied_to;
0668     charger_cfg.num_supplicants = ARRAY_SIZE(battery_supplied_to);
0669 
0670     pchg->charger = power_supply_register(&pdev->dev,
0671                           &lp8788_psy_charger_desc,
0672                           &charger_cfg);
0673     if (IS_ERR(pchg->charger))
0674         return -EPERM;
0675 
0676     pchg->battery = power_supply_register(&pdev->dev,
0677                           &lp8788_psy_battery_desc, NULL);
0678     if (IS_ERR(pchg->battery)) {
0679         power_supply_unregister(pchg->charger);
0680         return -EPERM;
0681     }
0682 
0683     return 0;
0684 }
0685 
0686 static int lp8788_charger_probe(struct platform_device *pdev)
0687 {
0688     struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);
0689     struct lp8788_charger *pchg;
0690     struct device *dev = &pdev->dev;
0691     int ret;
0692 
0693     pchg = devm_kzalloc(dev, sizeof(struct lp8788_charger), GFP_KERNEL);
0694     if (!pchg)
0695         return -ENOMEM;
0696 
0697     pchg->lp = lp;
0698     pchg->pdata = lp->pdata ? lp->pdata->chg_pdata : NULL;
0699     platform_set_drvdata(pdev, pchg);
0700 
0701     ret = lp8788_update_charger_params(pdev, pchg);
0702     if (ret)
0703         return ret;
0704 
0705     lp8788_setup_adc_channel(&pdev->dev, pchg);
0706 
0707     ret = lp8788_psy_register(pdev, pchg);
0708     if (ret)
0709         return ret;
0710 
0711     ret = lp8788_irq_register(pdev, pchg);
0712     if (ret)
0713         dev_warn(dev, "failed to register charger irq: %d\n", ret);
0714 
0715     return 0;
0716 }
0717 
0718 static int lp8788_charger_remove(struct platform_device *pdev)
0719 {
0720     struct lp8788_charger *pchg = platform_get_drvdata(pdev);
0721 
0722     flush_work(&pchg->charger_work);
0723     lp8788_irq_unregister(pdev, pchg);
0724     lp8788_psy_unregister(pchg);
0725 
0726     return 0;
0727 }
0728 
0729 static struct platform_driver lp8788_charger_driver = {
0730     .probe = lp8788_charger_probe,
0731     .remove = lp8788_charger_remove,
0732     .driver = {
0733         .name = LP8788_DEV_CHARGER,
0734     },
0735 };
0736 module_platform_driver(lp8788_charger_driver);
0737 
0738 MODULE_DESCRIPTION("TI LP8788 Charger Driver");
0739 MODULE_AUTHOR("Milo Kim");
0740 MODULE_LICENSE("GPL");
0741 MODULE_ALIAS("platform:lp8788-charger");