Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.17 751 lines 18 kB view raw
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 int lp8788_psy_register(struct platform_device *pdev, 401 struct lp8788_charger *pchg) 402{ 403 pchg->charger.name = LP8788_CHARGER_NAME; 404 pchg->charger.type = POWER_SUPPLY_TYPE_MAINS; 405 pchg->charger.properties = lp8788_charger_prop; 406 pchg->charger.num_properties = ARRAY_SIZE(lp8788_charger_prop); 407 pchg->charger.get_property = lp8788_charger_get_property; 408 pchg->charger.supplied_to = battery_supplied_to; 409 pchg->charger.num_supplicants = ARRAY_SIZE(battery_supplied_to); 410 411 if (power_supply_register(&pdev->dev, &pchg->charger)) 412 return -EPERM; 413 414 pchg->battery.name = LP8788_BATTERY_NAME; 415 pchg->battery.type = POWER_SUPPLY_TYPE_BATTERY; 416 pchg->battery.properties = lp8788_battery_prop; 417 pchg->battery.num_properties = ARRAY_SIZE(lp8788_battery_prop); 418 pchg->battery.get_property = lp8788_battery_get_property; 419 420 if (power_supply_register(&pdev->dev, &pchg->battery)) 421 return -EPERM; 422 423 return 0; 424} 425 426static void lp8788_psy_unregister(struct lp8788_charger *pchg) 427{ 428 power_supply_unregister(&pchg->battery); 429 power_supply_unregister(&pchg->charger); 430} 431 432static void lp8788_charger_event(struct work_struct *work) 433{ 434 struct lp8788_charger *pchg = 435 container_of(work, struct lp8788_charger, charger_work); 436 struct lp8788_charger_platform_data *pdata = pchg->pdata; 437 enum lp8788_charger_event event = lp8788_is_charger_detected(pchg); 438 439 pdata->charger_event(pchg->lp, event); 440} 441 442static bool lp8788_find_irq_id(struct lp8788_charger *pchg, int virq, int *id) 443{ 444 bool found; 445 int i; 446 447 for (i = 0; i < pchg->num_irqs; i++) { 448 if (pchg->irqs[i].virq == virq) { 449 *id = pchg->irqs[i].which; 450 found = true; 451 break; 452 } 453 } 454 455 return found; 456} 457 458static irqreturn_t lp8788_charger_irq_thread(int virq, void *ptr) 459{ 460 struct lp8788_charger *pchg = ptr; 461 struct lp8788_charger_platform_data *pdata = pchg->pdata; 462 int id = -1; 463 464 if (!lp8788_find_irq_id(pchg, virq, &id)) 465 return IRQ_NONE; 466 467 switch (id) { 468 case LP8788_INT_CHG_INPUT_STATE: 469 case LP8788_INT_CHG_STATE: 470 case LP8788_INT_EOC: 471 case LP8788_INT_BATT_LOW: 472 case LP8788_INT_NO_BATT: 473 power_supply_changed(&pchg->charger); 474 power_supply_changed(&pchg->battery); 475 break; 476 default: 477 break; 478 } 479 480 /* report charger dectection event if used */ 481 if (!pdata) 482 goto irq_handled; 483 484 if (pdata->charger_event && id == LP8788_INT_CHG_INPUT_STATE) 485 schedule_work(&pchg->charger_work); 486 487irq_handled: 488 return IRQ_HANDLED; 489} 490 491static int lp8788_set_irqs(struct platform_device *pdev, 492 struct lp8788_charger *pchg, const char *name) 493{ 494 struct resource *r; 495 struct irq_domain *irqdm = pchg->lp->irqdm; 496 int irq_start; 497 int irq_end; 498 int virq; 499 int nr_irq; 500 int i; 501 int ret; 502 503 /* no error even if no irq resource */ 504 r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, name); 505 if (!r) 506 return 0; 507 508 irq_start = r->start; 509 irq_end = r->end; 510 511 for (i = irq_start; i <= irq_end; i++) { 512 nr_irq = pchg->num_irqs; 513 514 virq = irq_create_mapping(irqdm, i); 515 pchg->irqs[nr_irq].virq = virq; 516 pchg->irqs[nr_irq].which = i; 517 pchg->num_irqs++; 518 519 ret = request_threaded_irq(virq, NULL, 520 lp8788_charger_irq_thread, 521 0, name, pchg); 522 if (ret) 523 break; 524 } 525 526 if (i <= irq_end) 527 goto err_free_irq; 528 529 return 0; 530 531err_free_irq: 532 for (i = 0; i < pchg->num_irqs; i++) 533 free_irq(pchg->irqs[i].virq, pchg); 534 return ret; 535} 536 537static int lp8788_irq_register(struct platform_device *pdev, 538 struct lp8788_charger *pchg) 539{ 540 const char *name[] = { 541 LP8788_CHG_IRQ, LP8788_PRSW_IRQ, LP8788_BATT_IRQ 542 }; 543 int i; 544 int ret; 545 546 INIT_WORK(&pchg->charger_work, lp8788_charger_event); 547 pchg->num_irqs = 0; 548 549 for (i = 0; i < ARRAY_SIZE(name); i++) { 550 ret = lp8788_set_irqs(pdev, pchg, name[i]); 551 if (ret) { 552 dev_warn(&pdev->dev, "irq setup failed: %s\n", name[i]); 553 return ret; 554 } 555 } 556 557 if (pchg->num_irqs > LP8788_MAX_CHG_IRQS) { 558 dev_err(&pdev->dev, "invalid total number of irqs: %d\n", 559 pchg->num_irqs); 560 return -EINVAL; 561 } 562 563 564 return 0; 565} 566 567static void lp8788_irq_unregister(struct platform_device *pdev, 568 struct lp8788_charger *pchg) 569{ 570 int i; 571 int irq; 572 573 for (i = 0; i < pchg->num_irqs; i++) { 574 irq = pchg->irqs[i].virq; 575 if (!irq) 576 continue; 577 578 free_irq(irq, pchg); 579 } 580} 581 582static void lp8788_setup_adc_channel(struct device *dev, 583 struct lp8788_charger *pchg) 584{ 585 struct lp8788_charger_platform_data *pdata = pchg->pdata; 586 struct iio_channel *chan; 587 588 if (!pdata) 589 return; 590 591 /* ADC channel for battery voltage */ 592 chan = iio_channel_get(dev, pdata->adc_vbatt); 593 pchg->chan[LP8788_VBATT] = IS_ERR(chan) ? NULL : chan; 594 595 /* ADC channel for battery temperature */ 596 chan = iio_channel_get(dev, pdata->adc_batt_temp); 597 pchg->chan[LP8788_BATT_TEMP] = IS_ERR(chan) ? NULL : chan; 598} 599 600static void lp8788_release_adc_channel(struct lp8788_charger *pchg) 601{ 602 int i; 603 604 for (i = 0; i < LP8788_NUM_CHG_ADC; i++) { 605 if (!pchg->chan[i]) 606 continue; 607 608 iio_channel_release(pchg->chan[i]); 609 pchg->chan[i] = NULL; 610 } 611} 612 613static ssize_t lp8788_show_charger_status(struct device *dev, 614 struct device_attribute *attr, char *buf) 615{ 616 struct lp8788_charger *pchg = dev_get_drvdata(dev); 617 enum lp8788_charging_state state; 618 char *desc[LP8788_MAX_CHG_STATE] = { 619 [LP8788_OFF] = "CHARGER OFF", 620 [LP8788_WARM_UP] = "WARM UP", 621 [LP8788_LOW_INPUT] = "LOW INPUT STATE", 622 [LP8788_PRECHARGE] = "CHARGING - PRECHARGE", 623 [LP8788_CC] = "CHARGING - CC", 624 [LP8788_CV] = "CHARGING - CV", 625 [LP8788_MAINTENANCE] = "NO CHARGING - MAINTENANCE", 626 [LP8788_BATTERY_FAULT] = "BATTERY FAULT", 627 [LP8788_SYSTEM_SUPPORT] = "SYSTEM SUPPORT", 628 [LP8788_HIGH_CURRENT] = "HIGH CURRENT", 629 }; 630 u8 data; 631 632 lp8788_read_byte(pchg->lp, LP8788_CHG_STATUS, &data); 633 state = (data & LP8788_CHG_STATE_M) >> LP8788_CHG_STATE_S; 634 635 return scnprintf(buf, PAGE_SIZE, "%s\n", desc[state]); 636} 637 638static ssize_t lp8788_show_eoc_time(struct device *dev, 639 struct device_attribute *attr, char *buf) 640{ 641 struct lp8788_charger *pchg = dev_get_drvdata(dev); 642 char *stime[] = { "400ms", "5min", "10min", "15min", 643 "20min", "25min", "30min" "No timeout" }; 644 u8 val; 645 646 lp8788_read_byte(pchg->lp, LP8788_CHG_EOC, &val); 647 val = (val & LP8788_CHG_EOC_TIME_M) >> LP8788_CHG_EOC_TIME_S; 648 649 return scnprintf(buf, PAGE_SIZE, "End Of Charge Time: %s\n", 650 stime[val]); 651} 652 653static ssize_t lp8788_show_eoc_level(struct device *dev, 654 struct device_attribute *attr, char *buf) 655{ 656 struct lp8788_charger *pchg = dev_get_drvdata(dev); 657 char *abs_level[] = { "25mA", "49mA", "75mA", "98mA" }; 658 char *relative_level[] = { "5%", "10%", "15%", "20%" }; 659 char *level; 660 u8 val; 661 u8 mode; 662 663 lp8788_read_byte(pchg->lp, LP8788_CHG_EOC, &val); 664 665 mode = val & LP8788_CHG_EOC_MODE_M; 666 val = (val & LP8788_CHG_EOC_LEVEL_M) >> LP8788_CHG_EOC_LEVEL_S; 667 level = mode ? abs_level[val] : relative_level[val]; 668 669 return scnprintf(buf, PAGE_SIZE, "End Of Charge Level: %s\n", level); 670} 671 672static DEVICE_ATTR(charger_status, S_IRUSR, lp8788_show_charger_status, NULL); 673static DEVICE_ATTR(eoc_time, S_IRUSR, lp8788_show_eoc_time, NULL); 674static DEVICE_ATTR(eoc_level, S_IRUSR, lp8788_show_eoc_level, NULL); 675 676static struct attribute *lp8788_charger_attr[] = { 677 &dev_attr_charger_status.attr, 678 &dev_attr_eoc_time.attr, 679 &dev_attr_eoc_level.attr, 680 NULL, 681}; 682 683static const struct attribute_group lp8788_attr_group = { 684 .attrs = lp8788_charger_attr, 685}; 686 687static int lp8788_charger_probe(struct platform_device *pdev) 688{ 689 struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent); 690 struct lp8788_charger *pchg; 691 struct device *dev = &pdev->dev; 692 int ret; 693 694 pchg = devm_kzalloc(dev, sizeof(struct lp8788_charger), GFP_KERNEL); 695 if (!pchg) 696 return -ENOMEM; 697 698 pchg->lp = lp; 699 pchg->pdata = lp->pdata ? lp->pdata->chg_pdata : NULL; 700 platform_set_drvdata(pdev, pchg); 701 702 ret = lp8788_update_charger_params(pdev, pchg); 703 if (ret) 704 return ret; 705 706 lp8788_setup_adc_channel(&pdev->dev, pchg); 707 708 ret = lp8788_psy_register(pdev, pchg); 709 if (ret) 710 return ret; 711 712 ret = sysfs_create_group(&pdev->dev.kobj, &lp8788_attr_group); 713 if (ret) { 714 lp8788_psy_unregister(pchg); 715 return ret; 716 } 717 718 ret = lp8788_irq_register(pdev, pchg); 719 if (ret) 720 dev_warn(dev, "failed to register charger irq: %d\n", ret); 721 722 return 0; 723} 724 725static int lp8788_charger_remove(struct platform_device *pdev) 726{ 727 struct lp8788_charger *pchg = platform_get_drvdata(pdev); 728 729 flush_work(&pchg->charger_work); 730 lp8788_irq_unregister(pdev, pchg); 731 sysfs_remove_group(&pdev->dev.kobj, &lp8788_attr_group); 732 lp8788_psy_unregister(pchg); 733 lp8788_release_adc_channel(pchg); 734 735 return 0; 736} 737 738static struct platform_driver lp8788_charger_driver = { 739 .probe = lp8788_charger_probe, 740 .remove = lp8788_charger_remove, 741 .driver = { 742 .name = LP8788_DEV_CHARGER, 743 .owner = THIS_MODULE, 744 }, 745}; 746module_platform_driver(lp8788_charger_driver); 747 748MODULE_DESCRIPTION("TI LP8788 Charger Driver"); 749MODULE_AUTHOR("Milo Kim"); 750MODULE_LICENSE("GPL"); 751MODULE_ALIAS("platform:lp8788-charger");