1 /* 2 * Battery driver for Marvell 88PM860x PMIC 3 * 4 * Copyright (c) 2012 Marvell International Ltd. 5 * Author: Jett Zhou <jtzhou@marvell.com> 6 * Haojian Zhuang <haojian.zhuang@marvell.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 #include <linux/kernel.h> 14 #include <linux/module.h> 15 #include <linux/platform_device.h> 16 #include <linux/slab.h> 17 #include <linux/power_supply.h> 18 #include <linux/mfd/88pm860x.h> 19 #include <linux/delay.h> 20 #include <linux/uaccess.h> 21 #include <asm/div64.h> 22 23 /* bit definitions of Status Query Interface 2 */ 24 #define STATUS2_CHG (1 << 2) 25 26 /* bit definitions of Reset Out Register */ 27 #define RESET_SW_PD (1 << 7) 28 29 /* bit definitions of PreReg 1 */ 30 #define PREREG1_90MA (0x0) 31 #define PREREG1_180MA (0x1) 32 #define PREREG1_450MA (0x4) 33 #define PREREG1_540MA (0x5) 34 #define PREREG1_1350MA (0xE) 35 #define PREREG1_VSYS_4_5V (3 << 4) 36 37 /* bit definitions of Charger Control 1 Register */ 38 #define CC1_MODE_OFF (0) 39 #define CC1_MODE_PRECHARGE (1) 40 #define CC1_MODE_FASTCHARGE (2) 41 #define CC1_MODE_PULSECHARGE (3) 42 #define CC1_ITERM_20MA (0 << 2) 43 #define CC1_ITERM_60MA (2 << 2) 44 #define CC1_VFCHG_4_2V (9 << 4) 45 46 /* bit definitions of Charger Control 2 Register */ 47 #define CC2_ICHG_100MA (0x1) 48 #define CC2_ICHG_500MA (0x9) 49 #define CC2_ICHG_1000MA (0x13) 50 51 /* bit definitions of Charger Control 3 Register */ 52 #define CC3_180MIN_TIMEOUT (0x6 << 4) 53 #define CC3_270MIN_TIMEOUT (0x7 << 4) 54 #define CC3_360MIN_TIMEOUT (0xA << 4) 55 #define CC3_DISABLE_TIMEOUT (0xF << 4) 56 57 /* bit definitions of Charger Control 4 Register */ 58 #define CC4_IPRE_40MA (7) 59 #define CC4_VPCHG_3_2V (3 << 4) 60 #define CC4_IFCHG_MON_EN (1 << 6) 61 #define CC4_BTEMP_MON_EN (1 << 7) 62 63 /* bit definitions of Charger Control 6 Register */ 64 #define CC6_BAT_OV_EN (1 << 2) 65 #define CC6_BAT_UV_EN (1 << 3) 66 #define CC6_UV_VBAT_SET (0x3 << 6) /* 2.8v */ 67 68 /* bit definitions of Charger Control 7 Register */ 69 #define CC7_BAT_REM_EN (1 << 3) 70 #define CC7_IFSM_EN (1 << 7) 71 72 /* bit definitions of Measurement Enable 1 Register */ 73 #define MEAS1_VBAT (1 << 0) 74 75 /* bit definitions of Measurement Enable 3 Register */ 76 #define MEAS3_IBAT_EN (1 << 0) 77 #define MEAS3_CC_EN (1 << 2) 78 79 #define FSM_INIT 0 80 #define FSM_DISCHARGE 1 81 #define FSM_PRECHARGE 2 82 #define FSM_FASTCHARGE 3 83 84 #define PRECHARGE_THRESHOLD 3100 85 #define POWEROFF_THRESHOLD 3400 86 #define CHARGE_THRESHOLD 4000 87 #define DISCHARGE_THRESHOLD 4180 88 89 /* over-temperature on PM8606 setting */ 90 #define OVER_TEMP_FLAG (1 << 6) 91 #define OVTEMP_AUTORECOVER (1 << 3) 92 93 /* over-voltage protect on vchg setting mv */ 94 #define VCHG_NORMAL_LOW 4200 95 #define VCHG_NORMAL_CHECK 5800 96 #define VCHG_NORMAL_HIGH 6000 97 #define VCHG_OVP_LOW 5500 98 99 struct pm860x_charger_info { 100 struct pm860x_chip *chip; 101 struct i2c_client *i2c; 102 struct i2c_client *i2c_8606; 103 struct device *dev; 104 105 struct power_supply *usb; 106 struct mutex lock; 107 int irq_nums; 108 int irq[7]; 109 unsigned state:3; /* fsm state */ 110 unsigned online:1; /* usb charger */ 111 unsigned present:1; /* battery present */ 112 unsigned allowed:1; 113 }; 114 115 static char *pm860x_supplied_to[] = { 116 "battery-monitor", 117 }; 118 119 static int measure_vchg(struct pm860x_charger_info *info, int *data) 120 { 121 unsigned char buf[2]; 122 int ret = 0; 123 124 ret = pm860x_bulk_read(info->i2c, PM8607_VCHG_MEAS1, 2, buf); 125 if (ret < 0) 126 return ret; 127 128 *data = ((buf[0] & 0xff) << 4) | (buf[1] & 0x0f); 129 /* V_BATT_MEAS(mV) = value * 5 * 1.8 * 1000 / (2^12) */ 130 *data = ((*data & 0xfff) * 9 * 125) >> 9; 131 132 dev_dbg(info->dev, "%s, vchg: %d mv\n", __func__, *data); 133 134 return ret; 135 } 136 137 static void set_vchg_threshold(struct pm860x_charger_info *info, 138 int min, int max) 139 { 140 int data; 141 142 /* (tmp << 8) * / 5 / 1800 */ 143 if (min <= 0) 144 data = 0; 145 else 146 data = (min << 5) / 1125; 147 pm860x_reg_write(info->i2c, PM8607_VCHG_LOWTH, data); 148 dev_dbg(info->dev, "VCHG_LOWTH:%dmv, 0x%x\n", min, data); 149 150 if (max <= 0) 151 data = 0xff; 152 else 153 data = (max << 5) / 1125; 154 pm860x_reg_write(info->i2c, PM8607_VCHG_HIGHTH, data); 155 dev_dbg(info->dev, "VCHG_HIGHTH:%dmv, 0x%x\n", max, data); 156 157 } 158 159 static void set_vbatt_threshold(struct pm860x_charger_info *info, 160 int min, int max) 161 { 162 int data; 163 164 /* (tmp << 8) * 3 / 1800 */ 165 if (min <= 0) 166 data = 0; 167 else 168 data = (min << 5) / 675; 169 pm860x_reg_write(info->i2c, PM8607_VBAT_LOWTH, data); 170 dev_dbg(info->dev, "VBAT Min:%dmv, LOWTH:0x%x\n", min, data); 171 172 if (max <= 0) 173 data = 0xff; 174 else 175 data = (max << 5) / 675; 176 pm860x_reg_write(info->i2c, PM8607_VBAT_HIGHTH, data); 177 dev_dbg(info->dev, "VBAT Max:%dmv, HIGHTH:0x%x\n", max, data); 178 179 return; 180 } 181 182 static int start_precharge(struct pm860x_charger_info *info) 183 { 184 int ret; 185 186 dev_dbg(info->dev, "Start Pre-charging!\n"); 187 set_vbatt_threshold(info, 0, 0); 188 189 ret = pm860x_reg_write(info->i2c_8606, PM8606_PREREGULATORA, 190 PREREG1_1350MA | PREREG1_VSYS_4_5V); 191 if (ret < 0) 192 goto out; 193 /* stop charging */ 194 ret = pm860x_set_bits(info->i2c, PM8607_CHG_CTRL1, 3, 195 CC1_MODE_OFF); 196 if (ret < 0) 197 goto out; 198 /* set 270 minutes timeout */ 199 ret = pm860x_set_bits(info->i2c, PM8607_CHG_CTRL3, (0xf << 4), 200 CC3_270MIN_TIMEOUT); 201 if (ret < 0) 202 goto out; 203 /* set precharge current, termination voltage, IBAT & TBAT monitor */ 204 ret = pm860x_reg_write(info->i2c, PM8607_CHG_CTRL4, 205 CC4_IPRE_40MA | CC4_VPCHG_3_2V | 206 CC4_IFCHG_MON_EN | CC4_BTEMP_MON_EN); 207 if (ret < 0) 208 goto out; 209 ret = pm860x_set_bits(info->i2c, PM8607_CHG_CTRL7, 210 CC7_BAT_REM_EN | CC7_IFSM_EN, 211 CC7_BAT_REM_EN | CC7_IFSM_EN); 212 if (ret < 0) 213 goto out; 214 /* trigger precharge */ 215 ret = pm860x_set_bits(info->i2c, PM8607_CHG_CTRL1, 3, 216 CC1_MODE_PRECHARGE); 217 out: 218 return ret; 219 } 220 221 static int start_fastcharge(struct pm860x_charger_info *info) 222 { 223 int ret; 224 225 dev_dbg(info->dev, "Start Fast-charging!\n"); 226 227 /* set fastcharge termination current & voltage, disable charging */ 228 ret = pm860x_reg_write(info->i2c, PM8607_CHG_CTRL1, 229 CC1_MODE_OFF | CC1_ITERM_60MA | 230 CC1_VFCHG_4_2V); 231 if (ret < 0) 232 goto out; 233 ret = pm860x_reg_write(info->i2c_8606, PM8606_PREREGULATORA, 234 PREREG1_540MA | PREREG1_VSYS_4_5V); 235 if (ret < 0) 236 goto out; 237 ret = pm860x_set_bits(info->i2c, PM8607_CHG_CTRL2, 0x1f, 238 CC2_ICHG_500MA); 239 if (ret < 0) 240 goto out; 241 /* set 270 minutes timeout */ 242 ret = pm860x_set_bits(info->i2c, PM8607_CHG_CTRL3, (0xf << 4), 243 CC3_270MIN_TIMEOUT); 244 if (ret < 0) 245 goto out; 246 /* set IBAT & TBAT monitor */ 247 ret = pm860x_set_bits(info->i2c, PM8607_CHG_CTRL4, 248 CC4_IFCHG_MON_EN | CC4_BTEMP_MON_EN, 249 CC4_IFCHG_MON_EN | CC4_BTEMP_MON_EN); 250 if (ret < 0) 251 goto out; 252 ret = pm860x_set_bits(info->i2c, PM8607_CHG_CTRL6, 253 CC6_BAT_OV_EN | CC6_BAT_UV_EN | 254 CC6_UV_VBAT_SET, 255 CC6_BAT_OV_EN | CC6_BAT_UV_EN | 256 CC6_UV_VBAT_SET); 257 if (ret < 0) 258 goto out; 259 ret = pm860x_set_bits(info->i2c, PM8607_CHG_CTRL7, 260 CC7_BAT_REM_EN | CC7_IFSM_EN, 261 CC7_BAT_REM_EN | CC7_IFSM_EN); 262 if (ret < 0) 263 goto out; 264 /* launch fast-charge */ 265 ret = pm860x_set_bits(info->i2c, PM8607_CHG_CTRL1, 3, 266 CC1_MODE_FASTCHARGE); 267 /* vchg threshold setting */ 268 set_vchg_threshold(info, VCHG_NORMAL_LOW, VCHG_NORMAL_HIGH); 269 out: 270 return ret; 271 } 272 273 static void stop_charge(struct pm860x_charger_info *info, int vbatt) 274 { 275 dev_dbg(info->dev, "Stop charging!\n"); 276 pm860x_set_bits(info->i2c, PM8607_CHG_CTRL1, 3, CC1_MODE_OFF); 277 if (vbatt > CHARGE_THRESHOLD && info->online) 278 set_vbatt_threshold(info, CHARGE_THRESHOLD, 0); 279 } 280 281 static void power_off_notification(struct pm860x_charger_info *info) 282 { 283 dev_dbg(info->dev, "Power-off notification!\n"); 284 } 285 286 static int set_charging_fsm(struct pm860x_charger_info *info) 287 { 288 struct power_supply *psy; 289 union power_supply_propval data; 290 unsigned char fsm_state[][16] = { "init", "discharge", "precharge", 291 "fastcharge", 292 }; 293 int ret; 294 int vbatt; 295 296 psy = power_supply_get_by_name(pm860x_supplied_to[0]); 297 if (!psy) 298 return -EINVAL; 299 ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, 300 &data); 301 if (ret) { 302 power_supply_put(psy); 303 return ret; 304 } 305 vbatt = data.intval / 1000; 306 307 ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_PRESENT, &data); 308 if (ret) { 309 power_supply_put(psy); 310 return ret; 311 } 312 power_supply_put(psy); 313 314 mutex_lock(&info->lock); 315 info->present = data.intval; 316 317 dev_dbg(info->dev, "Entering FSM:%s, Charger:%s, Battery:%s, " 318 "Allowed:%d\n", 319 &fsm_state[info->state][0], 320 (info->online) ? "online" : "N/A", 321 (info->present) ? "present" : "N/A", info->allowed); 322 dev_dbg(info->dev, "set_charging_fsm:vbatt:%d(mV)\n", vbatt); 323 324 switch (info->state) { 325 case FSM_INIT: 326 if (info->online && info->present && info->allowed) { 327 if (vbatt < PRECHARGE_THRESHOLD) { 328 info->state = FSM_PRECHARGE; 329 start_precharge(info); 330 } else if (vbatt > DISCHARGE_THRESHOLD) { 331 info->state = FSM_DISCHARGE; 332 stop_charge(info, vbatt); 333 } else if (vbatt < DISCHARGE_THRESHOLD) { 334 info->state = FSM_FASTCHARGE; 335 start_fastcharge(info); 336 } 337 } else { 338 if (vbatt < POWEROFF_THRESHOLD) { 339 power_off_notification(info); 340 } else { 341 info->state = FSM_DISCHARGE; 342 stop_charge(info, vbatt); 343 } 344 } 345 break; 346 case FSM_PRECHARGE: 347 if (info->online && info->present && info->allowed) { 348 if (vbatt > PRECHARGE_THRESHOLD) { 349 info->state = FSM_FASTCHARGE; 350 start_fastcharge(info); 351 } 352 } else { 353 info->state = FSM_DISCHARGE; 354 stop_charge(info, vbatt); 355 } 356 break; 357 case FSM_FASTCHARGE: 358 if (info->online && info->present && info->allowed) { 359 if (vbatt < PRECHARGE_THRESHOLD) { 360 info->state = FSM_PRECHARGE; 361 start_precharge(info); 362 } 363 } else { 364 info->state = FSM_DISCHARGE; 365 stop_charge(info, vbatt); 366 } 367 break; 368 case FSM_DISCHARGE: 369 if (info->online && info->present && info->allowed) { 370 if (vbatt < PRECHARGE_THRESHOLD) { 371 info->state = FSM_PRECHARGE; 372 start_precharge(info); 373 } else if (vbatt < DISCHARGE_THRESHOLD) { 374 info->state = FSM_FASTCHARGE; 375 start_fastcharge(info); 376 } 377 } else { 378 if (vbatt < POWEROFF_THRESHOLD) 379 power_off_notification(info); 380 else if (vbatt > CHARGE_THRESHOLD && info->online) 381 set_vbatt_threshold(info, CHARGE_THRESHOLD, 0); 382 } 383 break; 384 default: 385 dev_warn(info->dev, "FSM meets wrong state:%d\n", 386 info->state); 387 break; 388 } 389 dev_dbg(info->dev, 390 "Out FSM:%s, Charger:%s, Battery:%s, Allowed:%d\n", 391 &fsm_state[info->state][0], 392 (info->online) ? "online" : "N/A", 393 (info->present) ? "present" : "N/A", info->allowed); 394 mutex_unlock(&info->lock); 395 396 return 0; 397 } 398 399 static irqreturn_t pm860x_charger_handler(int irq, void *data) 400 { 401 struct pm860x_charger_info *info = data; 402 int ret; 403 404 mutex_lock(&info->lock); 405 ret = pm860x_reg_read(info->i2c, PM8607_STATUS_2); 406 if (ret < 0) { 407 mutex_unlock(&info->lock); 408 goto out; 409 } 410 if (ret & STATUS2_CHG) { 411 info->online = 1; 412 info->allowed = 1; 413 } else { 414 info->online = 0; 415 info->allowed = 0; 416 } 417 mutex_unlock(&info->lock); 418 dev_dbg(info->dev, "%s, Charger:%s, Allowed:%d\n", __func__, 419 (info->online) ? "online" : "N/A", info->allowed); 420 421 set_charging_fsm(info); 422 423 power_supply_changed(info->usb); 424 out: 425 return IRQ_HANDLED; 426 } 427 428 static irqreturn_t pm860x_temp_handler(int irq, void *data) 429 { 430 struct power_supply *psy; 431 struct pm860x_charger_info *info = data; 432 union power_supply_propval temp; 433 int value; 434 int ret; 435 436 psy = power_supply_get_by_name(pm860x_supplied_to[0]); 437 if (!psy) 438 return IRQ_HANDLED; 439 ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_TEMP, &temp); 440 if (ret) 441 goto out; 442 value = temp.intval / 10; 443 444 mutex_lock(&info->lock); 445 /* Temperature < -10 C or >40 C, Will not allow charge */ 446 if (value < -10 || value > 40) 447 info->allowed = 0; 448 else 449 info->allowed = 1; 450 dev_dbg(info->dev, "%s, Allowed: %d\n", __func__, info->allowed); 451 mutex_unlock(&info->lock); 452 453 set_charging_fsm(info); 454 out: 455 power_supply_put(psy); 456 return IRQ_HANDLED; 457 } 458 459 static irqreturn_t pm860x_exception_handler(int irq, void *data) 460 { 461 struct pm860x_charger_info *info = data; 462 463 mutex_lock(&info->lock); 464 info->allowed = 0; 465 mutex_unlock(&info->lock); 466 dev_dbg(info->dev, "%s, irq: %d\n", __func__, irq); 467 468 set_charging_fsm(info); 469 return IRQ_HANDLED; 470 } 471 472 static irqreturn_t pm860x_done_handler(int irq, void *data) 473 { 474 struct pm860x_charger_info *info = data; 475 struct power_supply *psy; 476 union power_supply_propval val; 477 int ret; 478 int vbatt; 479 480 mutex_lock(&info->lock); 481 /* pre-charge done, will transimit to fast-charge stage */ 482 if (info->state == FSM_PRECHARGE) { 483 info->allowed = 1; 484 goto out; 485 } 486 /* 487 * Fast charge done, delay to read 488 * the correct status of CHG_DET. 489 */ 490 mdelay(5); 491 info->allowed = 0; 492 psy = power_supply_get_by_name(pm860x_supplied_to[0]); 493 if (!psy) 494 goto out; 495 ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, 496 &val); 497 if (ret) 498 goto out_psy_put; 499 vbatt = val.intval / 1000; 500 /* 501 * CHG_DONE interrupt is faster than CHG_DET interrupt when 502 * plug in/out usb, So we can not rely on info->online, we 503 * need check pm8607 status register to check usb is online 504 * or not, then we can decide it is real charge done 505 * automatically or it is triggered by usb plug out; 506 */ 507 ret = pm860x_reg_read(info->i2c, PM8607_STATUS_2); 508 if (ret < 0) 509 goto out_psy_put; 510 if (vbatt > CHARGE_THRESHOLD && ret & STATUS2_CHG) 511 power_supply_set_property(psy, POWER_SUPPLY_PROP_CHARGE_FULL, 512 &val); 513 514 out_psy_put: 515 power_supply_put(psy); 516 out: 517 mutex_unlock(&info->lock); 518 dev_dbg(info->dev, "%s, Allowed: %d\n", __func__, info->allowed); 519 set_charging_fsm(info); 520 521 return IRQ_HANDLED; 522 } 523 524 static irqreturn_t pm860x_vbattery_handler(int irq, void *data) 525 { 526 struct pm860x_charger_info *info = data; 527 528 mutex_lock(&info->lock); 529 530 set_vbatt_threshold(info, 0, 0); 531 532 if (info->present && info->online) 533 info->allowed = 1; 534 else 535 info->allowed = 0; 536 mutex_unlock(&info->lock); 537 dev_dbg(info->dev, "%s, Allowed: %d\n", __func__, info->allowed); 538 539 set_charging_fsm(info); 540 541 return IRQ_HANDLED; 542 } 543 544 static irqreturn_t pm860x_vchg_handler(int irq, void *data) 545 { 546 struct pm860x_charger_info *info = data; 547 int vchg = 0; 548 549 if (info->present) 550 goto out; 551 552 measure_vchg(info, &vchg); 553 554 mutex_lock(&info->lock); 555 if (!info->online) { 556 int status; 557 /* check if over-temp on pm8606 or not */ 558 status = pm860x_reg_read(info->i2c_8606, PM8606_FLAGS); 559 if (status & OVER_TEMP_FLAG) { 560 /* clear over temp flag and set auto recover */ 561 pm860x_set_bits(info->i2c_8606, PM8606_FLAGS, 562 OVER_TEMP_FLAG, OVER_TEMP_FLAG); 563 pm860x_set_bits(info->i2c_8606, 564 PM8606_VSYS, 565 OVTEMP_AUTORECOVER, 566 OVTEMP_AUTORECOVER); 567 dev_dbg(info->dev, 568 "%s, pm8606 over-temp occurred\n", __func__); 569 } 570 } 571 572 if (vchg > VCHG_NORMAL_CHECK) { 573 set_vchg_threshold(info, VCHG_OVP_LOW, 0); 574 info->allowed = 0; 575 dev_dbg(info->dev, 576 "%s,pm8607 over-vchg occurred,vchg = %dmv\n", 577 __func__, vchg); 578 } else if (vchg < VCHG_OVP_LOW) { 579 set_vchg_threshold(info, VCHG_NORMAL_LOW, 580 VCHG_NORMAL_HIGH); 581 info->allowed = 1; 582 dev_dbg(info->dev, 583 "%s,pm8607 over-vchg recover,vchg = %dmv\n", 584 __func__, vchg); 585 } 586 mutex_unlock(&info->lock); 587 588 dev_dbg(info->dev, "%s, Allowed: %d\n", __func__, info->allowed); 589 set_charging_fsm(info); 590 out: 591 return IRQ_HANDLED; 592 } 593 594 static int pm860x_usb_get_prop(struct power_supply *psy, 595 enum power_supply_property psp, 596 union power_supply_propval *val) 597 { 598 struct pm860x_charger_info *info = power_supply_get_drvdata(psy); 599 600 switch (psp) { 601 case POWER_SUPPLY_PROP_STATUS: 602 if (info->state == FSM_FASTCHARGE || 603 info->state == FSM_PRECHARGE) 604 val->intval = POWER_SUPPLY_STATUS_CHARGING; 605 else 606 val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 607 break; 608 case POWER_SUPPLY_PROP_ONLINE: 609 val->intval = info->online; 610 break; 611 default: 612 return -ENODEV; 613 } 614 return 0; 615 } 616 617 static enum power_supply_property pm860x_usb_props[] = { 618 POWER_SUPPLY_PROP_STATUS, 619 POWER_SUPPLY_PROP_ONLINE, 620 }; 621 622 static int pm860x_init_charger(struct pm860x_charger_info *info) 623 { 624 int ret; 625 626 ret = pm860x_reg_read(info->i2c, PM8607_STATUS_2); 627 if (ret < 0) 628 return ret; 629 630 mutex_lock(&info->lock); 631 info->state = FSM_INIT; 632 if (ret & STATUS2_CHG) { 633 info->online = 1; 634 info->allowed = 1; 635 } else { 636 info->online = 0; 637 info->allowed = 0; 638 } 639 mutex_unlock(&info->lock); 640 641 set_charging_fsm(info); 642 return 0; 643 } 644 645 static struct pm860x_irq_desc { 646 const char *name; 647 irqreturn_t (*handler)(int irq, void *data); 648 } pm860x_irq_descs[] = { 649 { "usb supply detect", pm860x_charger_handler }, 650 { "charge done", pm860x_done_handler }, 651 { "charge timeout", pm860x_exception_handler }, 652 { "charge fault", pm860x_exception_handler }, 653 { "temperature", pm860x_temp_handler }, 654 { "vbatt", pm860x_vbattery_handler }, 655 { "vchg", pm860x_vchg_handler }, 656 }; 657 658 static const struct power_supply_desc pm860x_charger_desc = { 659 .name = "usb", 660 .type = POWER_SUPPLY_TYPE_USB, 661 .properties = pm860x_usb_props, 662 .num_properties = ARRAY_SIZE(pm860x_usb_props), 663 .get_property = pm860x_usb_get_prop, 664 }; 665 666 static int pm860x_charger_probe(struct platform_device *pdev) 667 { 668 struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); 669 struct power_supply_config psy_cfg = {}; 670 struct pm860x_charger_info *info; 671 int ret; 672 int count; 673 int i; 674 int j; 675 676 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); 677 if (!info) 678 return -ENOMEM; 679 680 count = pdev->num_resources; 681 for (i = 0, j = 0; i < count; i++) { 682 info->irq[j] = platform_get_irq(pdev, i); 683 if (info->irq[j] < 0) 684 continue; 685 j++; 686 } 687 info->irq_nums = j; 688 689 info->chip = chip; 690 info->i2c = 691 (chip->id == CHIP_PM8607) ? chip->client : chip->companion; 692 info->i2c_8606 = 693 (chip->id == CHIP_PM8607) ? chip->companion : chip->client; 694 if (!info->i2c_8606) { 695 dev_err(&pdev->dev, "Missed I2C address of 88PM8606!\n"); 696 ret = -EINVAL; 697 goto out; 698 } 699 info->dev = &pdev->dev; 700 701 /* set init value for the case we are not using battery */ 702 set_vchg_threshold(info, VCHG_NORMAL_LOW, VCHG_OVP_LOW); 703 704 mutex_init(&info->lock); 705 platform_set_drvdata(pdev, info); 706 707 psy_cfg.drv_data = info; 708 psy_cfg.supplied_to = pm860x_supplied_to; 709 psy_cfg.num_supplicants = ARRAY_SIZE(pm860x_supplied_to); 710 info->usb = power_supply_register(&pdev->dev, &pm860x_charger_desc, 711 &psy_cfg); 712 if (IS_ERR(info->usb)) { 713 ret = PTR_ERR(info->usb); 714 goto out; 715 } 716 717 pm860x_init_charger(info); 718 719 for (i = 0; i < ARRAY_SIZE(info->irq); i++) { 720 ret = request_threaded_irq(info->irq[i], NULL, 721 pm860x_irq_descs[i].handler, 722 IRQF_ONESHOT, pm860x_irq_descs[i].name, info); 723 if (ret < 0) { 724 dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n", 725 info->irq[i], ret); 726 goto out_irq; 727 } 728 } 729 return 0; 730 731 out_irq: 732 power_supply_unregister(info->usb); 733 while (--i >= 0) 734 free_irq(info->irq[i], info); 735 out: 736 return ret; 737 } 738 739 static int pm860x_charger_remove(struct platform_device *pdev) 740 { 741 struct pm860x_charger_info *info = platform_get_drvdata(pdev); 742 int i; 743 744 power_supply_unregister(info->usb); 745 for (i = 0; i < info->irq_nums; i++) 746 free_irq(info->irq[i], info); 747 return 0; 748 } 749 750 static struct platform_driver pm860x_charger_driver = { 751 .driver = { 752 .name = "88pm860x-charger", 753 }, 754 .probe = pm860x_charger_probe, 755 .remove = pm860x_charger_remove, 756 }; 757 module_platform_driver(pm860x_charger_driver); 758 759 MODULE_DESCRIPTION("Marvell 88PM860x Charger driver"); 760 MODULE_LICENSE("GPL"); 761