730 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * TI LP8788 MFD - battery charger driver4 *5 * Copyright 2012 Texas Instruments6 *7 * Author: Milo(Woogyom) Kim <milo.kim@ti.com>8 */9 10#include <linux/err.h>11#include <linux/iio/consumer.h>12#include <linux/interrupt.h>13#include <linux/irqdomain.h>14#include <linux/mfd/lp8788.h>15#include <linux/module.h>16#include <linux/platform_device.h>17#include <linux/power_supply.h>18#include <linux/slab.h>19#include <linux/workqueue.h>20 21/* register address */22#define LP8788_CHG_STATUS 0x0723#define LP8788_CHG_IDCIN 0x1324#define LP8788_CHG_IBATT 0x1425#define LP8788_CHG_VTERM 0x1526#define LP8788_CHG_EOC 0x1627 28/* mask/shift bits */29#define LP8788_CHG_INPUT_STATE_M 0x03 /* Addr 07h */30#define LP8788_CHG_STATE_M 0x3C31#define LP8788_CHG_STATE_S 232#define LP8788_NO_BATT_M BIT(6)33#define LP8788_BAD_BATT_M BIT(7)34#define LP8788_CHG_IBATT_M 0x1F /* Addr 14h */35#define LP8788_CHG_VTERM_M 0x0F /* Addr 15h */36#define LP8788_CHG_EOC_LEVEL_M 0x30 /* Addr 16h */37#define LP8788_CHG_EOC_LEVEL_S 438#define LP8788_CHG_EOC_TIME_M 0x0E39#define LP8788_CHG_EOC_TIME_S 140#define LP8788_CHG_EOC_MODE_M BIT(0)41 42#define LP8788_CHARGER_NAME "charger"43#define LP8788_BATTERY_NAME "main_batt"44 45#define LP8788_CHG_START 0x1146#define LP8788_CHG_END 0x1C47 48#define LP8788_ISEL_MAX 2349#define LP8788_ISEL_STEP 5050#define LP8788_VTERM_MIN 410051#define LP8788_VTERM_STEP 2552#define LP8788_MAX_BATT_CAPACITY 10053#define LP8788_MAX_CHG_IRQS 1154 55enum lp8788_charging_state {56 LP8788_OFF,57 LP8788_WARM_UP,58 LP8788_LOW_INPUT = 0x3,59 LP8788_PRECHARGE,60 LP8788_CC,61 LP8788_CV,62 LP8788_MAINTENANCE,63 LP8788_BATTERY_FAULT,64 LP8788_SYSTEM_SUPPORT = 0xC,65 LP8788_HIGH_CURRENT = 0xF,66 LP8788_MAX_CHG_STATE,67};68 69enum lp8788_charger_adc_sel {70 LP8788_VBATT,71 LP8788_BATT_TEMP,72 LP8788_NUM_CHG_ADC,73};74 75enum lp8788_charger_input_state {76 LP8788_SYSTEM_SUPPLY = 1,77 LP8788_FULL_FUNCTION,78};79 80/*81 * struct lp8788_chg_irq82 * @which : lp8788 interrupt id83 * @virq : Linux IRQ number from irq_domain84 */85struct lp8788_chg_irq {86 enum lp8788_int_id which;87 int virq;88};89 90/*91 * struct lp8788_charger92 * @lp : used for accessing the registers of mfd lp8788 device93 * @charger : power supply driver for the battery charger94 * @battery : power supply driver for the battery95 * @charger_work : work queue for charger input interrupts96 * @chan : iio channels for getting adc values97 * eg) battery voltage, capacity and temperature98 * @irqs : charger dedicated interrupts99 * @num_irqs : total numbers of charger interrupts100 * @pdata : charger platform specific data101 */102struct lp8788_charger {103 struct lp8788 *lp;104 struct power_supply *charger;105 struct power_supply *battery;106 struct work_struct charger_work;107 struct iio_channel *chan[LP8788_NUM_CHG_ADC];108 struct lp8788_chg_irq irqs[LP8788_MAX_CHG_IRQS];109 int num_irqs;110 struct lp8788_charger_platform_data *pdata;111};112 113static char *battery_supplied_to[] = {114 LP8788_BATTERY_NAME,115};116 117static enum power_supply_property lp8788_charger_prop[] = {118 POWER_SUPPLY_PROP_ONLINE,119 POWER_SUPPLY_PROP_CURRENT_MAX,120};121 122static enum power_supply_property lp8788_battery_prop[] = {123 POWER_SUPPLY_PROP_STATUS,124 POWER_SUPPLY_PROP_HEALTH,125 POWER_SUPPLY_PROP_PRESENT,126 POWER_SUPPLY_PROP_VOLTAGE_NOW,127 POWER_SUPPLY_PROP_CAPACITY,128 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,129 POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,130 POWER_SUPPLY_PROP_TEMP,131};132 133static bool lp8788_is_charger_detected(struct lp8788_charger *pchg)134{135 u8 data;136 137 lp8788_read_byte(pchg->lp, LP8788_CHG_STATUS, &data);138 data &= LP8788_CHG_INPUT_STATE_M;139 140 return data == LP8788_SYSTEM_SUPPLY || data == LP8788_FULL_FUNCTION;141}142 143static int lp8788_charger_get_property(struct power_supply *psy,144 enum power_supply_property psp,145 union power_supply_propval *val)146{147 struct lp8788_charger *pchg = dev_get_drvdata(psy->dev.parent);148 u8 read;149 150 switch (psp) {151 case POWER_SUPPLY_PROP_ONLINE:152 val->intval = lp8788_is_charger_detected(pchg);153 break;154 case POWER_SUPPLY_PROP_CURRENT_MAX:155 lp8788_read_byte(pchg->lp, LP8788_CHG_IDCIN, &read);156 val->intval = LP8788_ISEL_STEP *157 (min_t(int, read, LP8788_ISEL_MAX) + 1);158 break;159 default:160 return -EINVAL;161 }162 163 return 0;164}165 166static int lp8788_get_battery_status(struct lp8788_charger *pchg,167 union power_supply_propval *val)168{169 enum lp8788_charging_state state;170 u8 data;171 int ret;172 173 ret = lp8788_read_byte(pchg->lp, LP8788_CHG_STATUS, &data);174 if (ret)175 return ret;176 177 state = (data & LP8788_CHG_STATE_M) >> LP8788_CHG_STATE_S;178 switch (state) {179 case LP8788_OFF:180 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;181 break;182 case LP8788_PRECHARGE:183 case LP8788_CC:184 case LP8788_CV:185 case LP8788_HIGH_CURRENT:186 val->intval = POWER_SUPPLY_STATUS_CHARGING;187 break;188 case LP8788_MAINTENANCE:189 val->intval = POWER_SUPPLY_STATUS_FULL;190 break;191 default:192 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;193 break;194 }195 196 return 0;197}198 199static int lp8788_get_battery_health(struct lp8788_charger *pchg,200 union power_supply_propval *val)201{202 u8 data;203 int ret;204 205 ret = lp8788_read_byte(pchg->lp, LP8788_CHG_STATUS, &data);206 if (ret)207 return ret;208 209 if (data & LP8788_NO_BATT_M)210 val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;211 else if (data & LP8788_BAD_BATT_M)212 val->intval = POWER_SUPPLY_HEALTH_DEAD;213 else214 val->intval = POWER_SUPPLY_HEALTH_GOOD;215 216 return 0;217}218 219static int lp8788_get_battery_present(struct lp8788_charger *pchg,220 union power_supply_propval *val)221{222 u8 data;223 int ret;224 225 ret = lp8788_read_byte(pchg->lp, LP8788_CHG_STATUS, &data);226 if (ret)227 return ret;228 229 val->intval = !(data & LP8788_NO_BATT_M);230 return 0;231}232 233static int lp8788_get_vbatt_adc(struct lp8788_charger *pchg, int *result)234{235 struct iio_channel *channel = pchg->chan[LP8788_VBATT];236 237 if (!channel)238 return -EINVAL;239 240 return iio_read_channel_processed(channel, result);241}242 243static int lp8788_get_battery_voltage(struct lp8788_charger *pchg,244 union power_supply_propval *val)245{246 return lp8788_get_vbatt_adc(pchg, &val->intval);247}248 249static int lp8788_get_battery_capacity(struct lp8788_charger *pchg,250 union power_supply_propval *val)251{252 struct lp8788 *lp = pchg->lp;253 struct lp8788_charger_platform_data *pdata = pchg->pdata;254 unsigned int max_vbatt;255 int vbatt;256 enum lp8788_charging_state state;257 u8 data;258 int ret;259 260 if (!pdata)261 return -EINVAL;262 263 max_vbatt = pdata->max_vbatt_mv;264 if (max_vbatt == 0)265 return -EINVAL;266 267 ret = lp8788_read_byte(lp, LP8788_CHG_STATUS, &data);268 if (ret)269 return ret;270 271 state = (data & LP8788_CHG_STATE_M) >> LP8788_CHG_STATE_S;272 273 if (state == LP8788_MAINTENANCE) {274 val->intval = LP8788_MAX_BATT_CAPACITY;275 } else {276 ret = lp8788_get_vbatt_adc(pchg, &vbatt);277 if (ret)278 return ret;279 280 val->intval = (vbatt * LP8788_MAX_BATT_CAPACITY) / max_vbatt;281 val->intval = min(val->intval, LP8788_MAX_BATT_CAPACITY);282 }283 284 return 0;285}286 287static int lp8788_get_battery_temperature(struct lp8788_charger *pchg,288 union power_supply_propval *val)289{290 struct iio_channel *channel = pchg->chan[LP8788_BATT_TEMP];291 int result;292 int ret;293 294 if (!channel)295 return -EINVAL;296 297 ret = iio_read_channel_processed(channel, &result);298 if (ret < 0)299 return -EINVAL;300 301 /* unit: 0.1 'C */302 val->intval = result * 10;303 304 return 0;305}306 307static int lp8788_get_battery_charging_current(struct lp8788_charger *pchg,308 union power_supply_propval *val)309{310 u8 read;311 312 lp8788_read_byte(pchg->lp, LP8788_CHG_IBATT, &read);313 read &= LP8788_CHG_IBATT_M;314 val->intval = LP8788_ISEL_STEP *315 (min_t(int, read, LP8788_ISEL_MAX) + 1);316 317 return 0;318}319 320static int lp8788_get_charging_termination_voltage(struct lp8788_charger *pchg,321 union power_supply_propval *val)322{323 u8 read;324 325 lp8788_read_byte(pchg->lp, LP8788_CHG_VTERM, &read);326 read &= LP8788_CHG_VTERM_M;327 val->intval = LP8788_VTERM_MIN + LP8788_VTERM_STEP * read;328 329 return 0;330}331 332static int lp8788_battery_get_property(struct power_supply *psy,333 enum power_supply_property psp,334 union power_supply_propval *val)335{336 struct lp8788_charger *pchg = dev_get_drvdata(psy->dev.parent);337 338 switch (psp) {339 case POWER_SUPPLY_PROP_STATUS:340 return lp8788_get_battery_status(pchg, val);341 case POWER_SUPPLY_PROP_HEALTH:342 return lp8788_get_battery_health(pchg, val);343 case POWER_SUPPLY_PROP_PRESENT:344 return lp8788_get_battery_present(pchg, val);345 case POWER_SUPPLY_PROP_VOLTAGE_NOW:346 return lp8788_get_battery_voltage(pchg, val);347 case POWER_SUPPLY_PROP_CAPACITY:348 return lp8788_get_battery_capacity(pchg, val);349 case POWER_SUPPLY_PROP_TEMP:350 return lp8788_get_battery_temperature(pchg, val);351 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:352 return lp8788_get_battery_charging_current(pchg, val);353 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:354 return lp8788_get_charging_termination_voltage(pchg, val);355 default:356 return -EINVAL;357 }358}359 360static inline bool lp8788_is_valid_charger_register(u8 addr)361{362 return addr >= LP8788_CHG_START && addr <= LP8788_CHG_END;363}364 365static int lp8788_update_charger_params(struct platform_device *pdev,366 struct lp8788_charger *pchg)367{368 struct lp8788 *lp = pchg->lp;369 struct lp8788_charger_platform_data *pdata = pchg->pdata;370 struct lp8788_chg_param *param;371 int i;372 int ret;373 374 if (!pdata || !pdata->chg_params) {375 dev_info(&pdev->dev, "skip updating charger parameters\n");376 return 0;377 }378 379 /* setting charging parameters */380 for (i = 0; i < pdata->num_chg_params; i++) {381 param = pdata->chg_params + i;382 383 if (lp8788_is_valid_charger_register(param->addr)) {384 ret = lp8788_write_byte(lp, param->addr, param->val);385 if (ret)386 return ret;387 }388 }389 390 return 0;391}392 393static const struct power_supply_desc lp8788_psy_charger_desc = {394 .name = LP8788_CHARGER_NAME,395 .type = POWER_SUPPLY_TYPE_MAINS,396 .properties = lp8788_charger_prop,397 .num_properties = ARRAY_SIZE(lp8788_charger_prop),398 .get_property = lp8788_charger_get_property,399};400 401static const struct power_supply_desc lp8788_psy_battery_desc = {402 .name = LP8788_BATTERY_NAME,403 .type = POWER_SUPPLY_TYPE_BATTERY,404 .properties = lp8788_battery_prop,405 .num_properties = ARRAY_SIZE(lp8788_battery_prop),406 .get_property = lp8788_battery_get_property,407};408 409static void lp8788_charger_event(struct work_struct *work)410{411 struct lp8788_charger *pchg =412 container_of(work, struct lp8788_charger, charger_work);413 struct lp8788_charger_platform_data *pdata = pchg->pdata;414 enum lp8788_charger_event event = lp8788_is_charger_detected(pchg);415 416 pdata->charger_event(pchg->lp, event);417}418 419static bool lp8788_find_irq_id(struct lp8788_charger *pchg, int virq, int *id)420{421 bool found = false;422 int i;423 424 for (i = 0; i < pchg->num_irqs; i++) {425 if (pchg->irqs[i].virq == virq) {426 *id = pchg->irqs[i].which;427 found = true;428 break;429 }430 }431 432 return found;433}434 435static irqreturn_t lp8788_charger_irq_thread(int virq, void *ptr)436{437 struct lp8788_charger *pchg = ptr;438 struct lp8788_charger_platform_data *pdata = pchg->pdata;439 int id = -1;440 441 if (!lp8788_find_irq_id(pchg, virq, &id))442 return IRQ_NONE;443 444 switch (id) {445 case LP8788_INT_CHG_INPUT_STATE:446 case LP8788_INT_CHG_STATE:447 case LP8788_INT_EOC:448 case LP8788_INT_BATT_LOW:449 case LP8788_INT_NO_BATT:450 power_supply_changed(pchg->charger);451 power_supply_changed(pchg->battery);452 break;453 default:454 break;455 }456 457 /* report charger dectection event if used */458 if (!pdata)459 goto irq_handled;460 461 if (pdata->charger_event && id == LP8788_INT_CHG_INPUT_STATE)462 schedule_work(&pchg->charger_work);463 464irq_handled:465 return IRQ_HANDLED;466}467 468static int lp8788_set_irqs(struct platform_device *pdev,469 struct lp8788_charger *pchg, const char *name)470{471 struct resource *r;472 struct irq_domain *irqdm = pchg->lp->irqdm;473 int irq_start;474 int irq_end;475 int virq;476 int nr_irq;477 int i;478 int ret;479 480 /* no error even if no irq resource */481 r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, name);482 if (!r)483 return 0;484 485 irq_start = r->start;486 irq_end = r->end;487 488 for (i = irq_start; i <= irq_end; i++) {489 nr_irq = pchg->num_irqs;490 491 virq = irq_create_mapping(irqdm, i);492 pchg->irqs[nr_irq].virq = virq;493 pchg->irqs[nr_irq].which = i;494 pchg->num_irqs++;495 496 ret = request_threaded_irq(virq, NULL,497 lp8788_charger_irq_thread,498 IRQF_ONESHOT, name, pchg);499 if (ret)500 break;501 }502 503 if (i <= irq_end)504 goto err_free_irq;505 506 return 0;507 508err_free_irq:509 for (i = 0; i < pchg->num_irqs; i++)510 free_irq(pchg->irqs[i].virq, pchg);511 return ret;512}513 514static int lp8788_irq_register(struct platform_device *pdev,515 struct lp8788_charger *pchg)516{517 static const char * const name[] = {518 LP8788_CHG_IRQ, LP8788_PRSW_IRQ, LP8788_BATT_IRQ519 };520 int i;521 int ret;522 523 INIT_WORK(&pchg->charger_work, lp8788_charger_event);524 pchg->num_irqs = 0;525 526 for (i = 0; i < ARRAY_SIZE(name); i++) {527 ret = lp8788_set_irqs(pdev, pchg, name[i]);528 if (ret) {529 dev_warn(&pdev->dev, "irq setup failed: %s\n", name[i]);530 return ret;531 }532 }533 534 if (pchg->num_irqs > LP8788_MAX_CHG_IRQS) {535 dev_err(&pdev->dev, "invalid total number of irqs: %d\n",536 pchg->num_irqs);537 return -EINVAL;538 }539 540 541 return 0;542}543 544static void lp8788_irq_unregister(struct platform_device *pdev,545 struct lp8788_charger *pchg)546{547 int i;548 int irq;549 550 for (i = 0; i < pchg->num_irqs; i++) {551 irq = pchg->irqs[i].virq;552 if (!irq)553 continue;554 555 free_irq(irq, pchg);556 }557}558 559static void lp8788_setup_adc_channel(struct device *dev,560 struct lp8788_charger *pchg)561{562 struct lp8788_charger_platform_data *pdata = pchg->pdata;563 struct iio_channel *chan;564 565 if (!pdata)566 return;567 568 /* ADC channel for battery voltage */569 chan = devm_iio_channel_get(dev, pdata->adc_vbatt);570 pchg->chan[LP8788_VBATT] = IS_ERR(chan) ? NULL : chan;571 572 /* ADC channel for battery temperature */573 chan = devm_iio_channel_get(dev, pdata->adc_batt_temp);574 pchg->chan[LP8788_BATT_TEMP] = IS_ERR(chan) ? NULL : chan;575}576 577static ssize_t lp8788_show_charger_status(struct device *dev,578 struct device_attribute *attr, char *buf)579{580 struct lp8788_charger *pchg = dev_get_drvdata(dev);581 enum lp8788_charging_state state;582 static const char * const desc[LP8788_MAX_CHG_STATE] = {583 [LP8788_OFF] = "CHARGER OFF",584 [LP8788_WARM_UP] = "WARM UP",585 [LP8788_LOW_INPUT] = "LOW INPUT STATE",586 [LP8788_PRECHARGE] = "CHARGING - PRECHARGE",587 [LP8788_CC] = "CHARGING - CC",588 [LP8788_CV] = "CHARGING - CV",589 [LP8788_MAINTENANCE] = "NO CHARGING - MAINTENANCE",590 [LP8788_BATTERY_FAULT] = "BATTERY FAULT",591 [LP8788_SYSTEM_SUPPORT] = "SYSTEM SUPPORT",592 [LP8788_HIGH_CURRENT] = "HIGH CURRENT",593 };594 u8 data;595 596 lp8788_read_byte(pchg->lp, LP8788_CHG_STATUS, &data);597 state = (data & LP8788_CHG_STATE_M) >> LP8788_CHG_STATE_S;598 599 return sysfs_emit(buf, "%s\n", desc[state]);600}601 602static ssize_t lp8788_show_eoc_time(struct device *dev,603 struct device_attribute *attr, char *buf)604{605 struct lp8788_charger *pchg = dev_get_drvdata(dev);606 static const char * const stime[] = {607 "400ms", "5min", "10min", "15min",608 "20min", "25min", "30min", "No timeout"609 };610 u8 val;611 612 lp8788_read_byte(pchg->lp, LP8788_CHG_EOC, &val);613 val = (val & LP8788_CHG_EOC_TIME_M) >> LP8788_CHG_EOC_TIME_S;614 615 return sysfs_emit(buf, "End Of Charge Time: %s\n", stime[val]);616}617 618static ssize_t lp8788_show_eoc_level(struct device *dev,619 struct device_attribute *attr, char *buf)620{621 struct lp8788_charger *pchg = dev_get_drvdata(dev);622 static const char * const abs_level[] = {623 "25mA", "49mA", "75mA", "98mA"624 };625 static const char * const relative_level[] = {626 "5%", "10%", "15%", "20%"627 };628 const char *level;629 u8 val;630 u8 mode;631 632 lp8788_read_byte(pchg->lp, LP8788_CHG_EOC, &val);633 634 mode = val & LP8788_CHG_EOC_MODE_M;635 val = (val & LP8788_CHG_EOC_LEVEL_M) >> LP8788_CHG_EOC_LEVEL_S;636 level = mode ? abs_level[val] : relative_level[val];637 638 return sysfs_emit(buf, "End Of Charge Level: %s\n", level);639}640 641static DEVICE_ATTR(charger_status, S_IRUSR, lp8788_show_charger_status, NULL);642static DEVICE_ATTR(eoc_time, S_IRUSR, lp8788_show_eoc_time, NULL);643static DEVICE_ATTR(eoc_level, S_IRUSR, lp8788_show_eoc_level, NULL);644 645static struct attribute *lp8788_charger_sysfs_attrs[] = {646 &dev_attr_charger_status.attr,647 &dev_attr_eoc_time.attr,648 &dev_attr_eoc_level.attr,649 NULL,650};651 652ATTRIBUTE_GROUPS(lp8788_charger_sysfs);653 654static int lp8788_psy_register(struct platform_device *pdev,655 struct lp8788_charger *pchg)656{657 struct power_supply_config charger_cfg = {};658 659 charger_cfg.attr_grp = lp8788_charger_sysfs_groups;660 charger_cfg.supplied_to = battery_supplied_to;661 charger_cfg.num_supplicants = ARRAY_SIZE(battery_supplied_to);662 663 pchg->charger = devm_power_supply_register(&pdev->dev,664 &lp8788_psy_charger_desc,665 &charger_cfg);666 if (IS_ERR(pchg->charger))667 return -EPERM;668 669 pchg->battery = devm_power_supply_register(&pdev->dev,670 &lp8788_psy_battery_desc, NULL);671 if (IS_ERR(pchg->battery))672 return -EPERM;673 674 return 0;675}676 677static int lp8788_charger_probe(struct platform_device *pdev)678{679 struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);680 struct lp8788_charger *pchg;681 struct device *dev = &pdev->dev;682 int ret;683 684 pchg = devm_kzalloc(dev, sizeof(struct lp8788_charger), GFP_KERNEL);685 if (!pchg)686 return -ENOMEM;687 688 pchg->lp = lp;689 pchg->pdata = lp->pdata ? lp->pdata->chg_pdata : NULL;690 platform_set_drvdata(pdev, pchg);691 692 ret = lp8788_update_charger_params(pdev, pchg);693 if (ret)694 return ret;695 696 lp8788_setup_adc_channel(&pdev->dev, pchg);697 698 ret = lp8788_psy_register(pdev, pchg);699 if (ret)700 return ret;701 702 ret = lp8788_irq_register(pdev, pchg);703 if (ret)704 dev_warn(dev, "failed to register charger irq: %d\n", ret);705 706 return 0;707}708 709static void lp8788_charger_remove(struct platform_device *pdev)710{711 struct lp8788_charger *pchg = platform_get_drvdata(pdev);712 713 flush_work(&pchg->charger_work);714 lp8788_irq_unregister(pdev, pchg);715}716 717static struct platform_driver lp8788_charger_driver = {718 .probe = lp8788_charger_probe,719 .remove_new = lp8788_charger_remove,720 .driver = {721 .name = LP8788_DEV_CHARGER,722 },723};724module_platform_driver(lp8788_charger_driver);725 726MODULE_DESCRIPTION("TI LP8788 Charger Driver");727MODULE_AUTHOR("Milo Kim");728MODULE_LICENSE("GPL");729MODULE_ALIAS("platform:lp8788-charger");730