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