qcom_smbb.c (25751B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* Copyright (c) 2014, Sony Mobile Communications Inc. 3 * 4 * This driver is for the multi-block Switch-Mode Battery Charger and Boost 5 * (SMBB) hardware, found in Qualcomm PM8941 PMICs. The charger is an 6 * integrated, single-cell lithium-ion battery charger. 7 * 8 * Sub-components: 9 * - Charger core 10 * - Buck 11 * - DC charge-path 12 * - USB charge-path 13 * - Battery interface 14 * - Boost (not implemented) 15 * - Misc 16 * - HF-Buck 17 */ 18 19#include <linux/errno.h> 20#include <linux/interrupt.h> 21#include <linux/kernel.h> 22#include <linux/module.h> 23#include <linux/mutex.h> 24#include <linux/of.h> 25#include <linux/platform_device.h> 26#include <linux/power_supply.h> 27#include <linux/regmap.h> 28#include <linux/slab.h> 29#include <linux/extcon-provider.h> 30#include <linux/regulator/driver.h> 31 32#define SMBB_CHG_VMAX 0x040 33#define SMBB_CHG_VSAFE 0x041 34#define SMBB_CHG_CFG 0x043 35#define SMBB_CHG_IMAX 0x044 36#define SMBB_CHG_ISAFE 0x045 37#define SMBB_CHG_VIN_MIN 0x047 38#define SMBB_CHG_CTRL 0x049 39#define CTRL_EN BIT(7) 40#define SMBB_CHG_VBAT_WEAK 0x052 41#define SMBB_CHG_IBAT_TERM_CHG 0x05b 42#define IBAT_TERM_CHG_IEOC BIT(7) 43#define IBAT_TERM_CHG_IEOC_BMS BIT(7) 44#define IBAT_TERM_CHG_IEOC_CHG 0 45#define SMBB_CHG_VBAT_DET 0x05d 46#define SMBB_CHG_TCHG_MAX_EN 0x060 47#define TCHG_MAX_EN BIT(7) 48#define SMBB_CHG_WDOG_TIME 0x062 49#define SMBB_CHG_WDOG_EN 0x065 50#define WDOG_EN BIT(7) 51 52#define SMBB_BUCK_REG_MODE 0x174 53#define BUCK_REG_MODE BIT(0) 54#define BUCK_REG_MODE_VBAT BIT(0) 55#define BUCK_REG_MODE_VSYS 0 56 57#define SMBB_BAT_PRES_STATUS 0x208 58#define PRES_STATUS_BAT_PRES BIT(7) 59#define SMBB_BAT_TEMP_STATUS 0x209 60#define TEMP_STATUS_OK BIT(7) 61#define TEMP_STATUS_HOT BIT(6) 62#define SMBB_BAT_BTC_CTRL 0x249 63#define BTC_CTRL_COMP_EN BIT(7) 64#define BTC_CTRL_COLD_EXT BIT(1) 65#define BTC_CTRL_HOT_EXT_N BIT(0) 66 67#define SMBB_USB_IMAX 0x344 68#define SMBB_USB_OTG_CTL 0x348 69#define OTG_CTL_EN BIT(0) 70#define SMBB_USB_ENUM_TIMER_STOP 0x34e 71#define ENUM_TIMER_STOP BIT(0) 72#define SMBB_USB_SEC_ACCESS 0x3d0 73#define SEC_ACCESS_MAGIC 0xa5 74#define SMBB_USB_REV_BST 0x3ed 75#define REV_BST_CHG_GONE BIT(7) 76 77#define SMBB_DC_IMAX 0x444 78 79#define SMBB_MISC_REV2 0x601 80#define SMBB_MISC_BOOT_DONE 0x642 81#define BOOT_DONE BIT(7) 82 83#define STATUS_USBIN_VALID BIT(0) /* USB connection is valid */ 84#define STATUS_DCIN_VALID BIT(1) /* DC connection is valid */ 85#define STATUS_BAT_HOT BIT(2) /* Battery temp 1=Hot, 0=Cold */ 86#define STATUS_BAT_OK BIT(3) /* Battery temp OK */ 87#define STATUS_BAT_PRESENT BIT(4) /* Battery is present */ 88#define STATUS_CHG_DONE BIT(5) /* Charge cycle is complete */ 89#define STATUS_CHG_TRKL BIT(6) /* Trickle charging */ 90#define STATUS_CHG_FAST BIT(7) /* Fast charging */ 91#define STATUS_CHG_GONE BIT(8) /* No charger is connected */ 92 93enum smbb_attr { 94 ATTR_BAT_ISAFE, 95 ATTR_BAT_IMAX, 96 ATTR_USBIN_IMAX, 97 ATTR_DCIN_IMAX, 98 ATTR_BAT_VSAFE, 99 ATTR_BAT_VMAX, 100 ATTR_BAT_VMIN, 101 ATTR_CHG_VDET, 102 ATTR_VIN_MIN, 103 _ATTR_CNT, 104}; 105 106struct smbb_charger { 107 unsigned int revision; 108 unsigned int addr; 109 struct device *dev; 110 struct extcon_dev *edev; 111 112 bool dc_disabled; 113 bool jeita_ext_temp; 114 unsigned long status; 115 struct mutex statlock; 116 117 unsigned int attr[_ATTR_CNT]; 118 119 struct power_supply *usb_psy; 120 struct power_supply *dc_psy; 121 struct power_supply *bat_psy; 122 struct regmap *regmap; 123 124 struct regulator_desc otg_rdesc; 125 struct regulator_dev *otg_reg; 126}; 127 128static const unsigned int smbb_usb_extcon_cable[] = { 129 EXTCON_USB, 130 EXTCON_NONE, 131}; 132 133static int smbb_vbat_weak_fn(unsigned int index) 134{ 135 return 2100000 + index * 100000; 136} 137 138static int smbb_vin_fn(unsigned int index) 139{ 140 if (index > 42) 141 return 5600000 + (index - 43) * 200000; 142 return 3400000 + index * 50000; 143} 144 145static int smbb_vmax_fn(unsigned int index) 146{ 147 return 3240000 + index * 10000; 148} 149 150static int smbb_vbat_det_fn(unsigned int index) 151{ 152 return 3240000 + index * 20000; 153} 154 155static int smbb_imax_fn(unsigned int index) 156{ 157 if (index < 2) 158 return 100000 + index * 50000; 159 return index * 100000; 160} 161 162static int smbb_bat_imax_fn(unsigned int index) 163{ 164 return index * 50000; 165} 166 167static unsigned int smbb_hw_lookup(unsigned int val, int (*fn)(unsigned int)) 168{ 169 unsigned int widx; 170 unsigned int sel; 171 172 for (widx = sel = 0; (*fn)(widx) <= val; ++widx) 173 sel = widx; 174 175 return sel; 176} 177 178static const struct smbb_charger_attr { 179 const char *name; 180 unsigned int reg; 181 unsigned int safe_reg; 182 unsigned int max; 183 unsigned int min; 184 unsigned int fail_ok; 185 int (*hw_fn)(unsigned int); 186} smbb_charger_attrs[] = { 187 [ATTR_BAT_ISAFE] = { 188 .name = "qcom,fast-charge-safe-current", 189 .reg = SMBB_CHG_ISAFE, 190 .max = 3000000, 191 .min = 200000, 192 .hw_fn = smbb_bat_imax_fn, 193 .fail_ok = 1, 194 }, 195 [ATTR_BAT_IMAX] = { 196 .name = "qcom,fast-charge-current-limit", 197 .reg = SMBB_CHG_IMAX, 198 .safe_reg = SMBB_CHG_ISAFE, 199 .max = 3000000, 200 .min = 200000, 201 .hw_fn = smbb_bat_imax_fn, 202 }, 203 [ATTR_DCIN_IMAX] = { 204 .name = "qcom,dc-current-limit", 205 .reg = SMBB_DC_IMAX, 206 .max = 2500000, 207 .min = 100000, 208 .hw_fn = smbb_imax_fn, 209 }, 210 [ATTR_BAT_VSAFE] = { 211 .name = "qcom,fast-charge-safe-voltage", 212 .reg = SMBB_CHG_VSAFE, 213 .max = 5000000, 214 .min = 3240000, 215 .hw_fn = smbb_vmax_fn, 216 .fail_ok = 1, 217 }, 218 [ATTR_BAT_VMAX] = { 219 .name = "qcom,fast-charge-high-threshold-voltage", 220 .reg = SMBB_CHG_VMAX, 221 .safe_reg = SMBB_CHG_VSAFE, 222 .max = 5000000, 223 .min = 3240000, 224 .hw_fn = smbb_vmax_fn, 225 }, 226 [ATTR_BAT_VMIN] = { 227 .name = "qcom,fast-charge-low-threshold-voltage", 228 .reg = SMBB_CHG_VBAT_WEAK, 229 .max = 3600000, 230 .min = 2100000, 231 .hw_fn = smbb_vbat_weak_fn, 232 }, 233 [ATTR_CHG_VDET] = { 234 .name = "qcom,auto-recharge-threshold-voltage", 235 .reg = SMBB_CHG_VBAT_DET, 236 .max = 5000000, 237 .min = 3240000, 238 .hw_fn = smbb_vbat_det_fn, 239 }, 240 [ATTR_VIN_MIN] = { 241 .name = "qcom,minimum-input-voltage", 242 .reg = SMBB_CHG_VIN_MIN, 243 .max = 9600000, 244 .min = 4200000, 245 .hw_fn = smbb_vin_fn, 246 }, 247 [ATTR_USBIN_IMAX] = { 248 .name = "usb-charge-current-limit", 249 .reg = SMBB_USB_IMAX, 250 .max = 2500000, 251 .min = 100000, 252 .hw_fn = smbb_imax_fn, 253 }, 254}; 255 256static int smbb_charger_attr_write(struct smbb_charger *chg, 257 enum smbb_attr which, unsigned int val) 258{ 259 const struct smbb_charger_attr *prop; 260 unsigned int wval; 261 unsigned int out; 262 int rc; 263 264 prop = &smbb_charger_attrs[which]; 265 266 if (val > prop->max || val < prop->min) { 267 dev_err(chg->dev, "value out of range for %s [%u:%u]\n", 268 prop->name, prop->min, prop->max); 269 return -EINVAL; 270 } 271 272 if (prop->safe_reg) { 273 rc = regmap_read(chg->regmap, 274 chg->addr + prop->safe_reg, &wval); 275 if (rc) { 276 dev_err(chg->dev, 277 "unable to read safe value for '%s'\n", 278 prop->name); 279 return rc; 280 } 281 282 wval = prop->hw_fn(wval); 283 284 if (val > wval) { 285 dev_warn(chg->dev, 286 "%s above safe value, clamping at %u\n", 287 prop->name, wval); 288 val = wval; 289 } 290 } 291 292 wval = smbb_hw_lookup(val, prop->hw_fn); 293 294 rc = regmap_write(chg->regmap, chg->addr + prop->reg, wval); 295 if (rc) { 296 dev_err(chg->dev, "unable to update %s", prop->name); 297 return rc; 298 } 299 out = prop->hw_fn(wval); 300 if (out != val) { 301 dev_warn(chg->dev, 302 "%s inaccurate, rounded to %u\n", 303 prop->name, out); 304 } 305 306 dev_dbg(chg->dev, "%s <= %d\n", prop->name, out); 307 308 chg->attr[which] = out; 309 310 return 0; 311} 312 313static int smbb_charger_attr_read(struct smbb_charger *chg, 314 enum smbb_attr which) 315{ 316 const struct smbb_charger_attr *prop; 317 unsigned int val; 318 int rc; 319 320 prop = &smbb_charger_attrs[which]; 321 322 rc = regmap_read(chg->regmap, chg->addr + prop->reg, &val); 323 if (rc) { 324 dev_err(chg->dev, "failed to read %s\n", prop->name); 325 return rc; 326 } 327 val = prop->hw_fn(val); 328 dev_dbg(chg->dev, "%s => %d\n", prop->name, val); 329 330 chg->attr[which] = val; 331 332 return 0; 333} 334 335static int smbb_charger_attr_parse(struct smbb_charger *chg, 336 enum smbb_attr which) 337{ 338 const struct smbb_charger_attr *prop; 339 unsigned int val; 340 int rc; 341 342 prop = &smbb_charger_attrs[which]; 343 344 rc = of_property_read_u32(chg->dev->of_node, prop->name, &val); 345 if (rc == 0) { 346 rc = smbb_charger_attr_write(chg, which, val); 347 if (!rc || !prop->fail_ok) 348 return rc; 349 } 350 return smbb_charger_attr_read(chg, which); 351} 352 353static void smbb_set_line_flag(struct smbb_charger *chg, int irq, int flag) 354{ 355 bool state; 356 int ret; 357 358 ret = irq_get_irqchip_state(irq, IRQCHIP_STATE_LINE_LEVEL, &state); 359 if (ret < 0) { 360 dev_err(chg->dev, "failed to read irq line\n"); 361 return; 362 } 363 364 mutex_lock(&chg->statlock); 365 if (state) 366 chg->status |= flag; 367 else 368 chg->status &= ~flag; 369 mutex_unlock(&chg->statlock); 370 371 dev_dbg(chg->dev, "status = %03lx\n", chg->status); 372} 373 374static irqreturn_t smbb_usb_valid_handler(int irq, void *_data) 375{ 376 struct smbb_charger *chg = _data; 377 378 smbb_set_line_flag(chg, irq, STATUS_USBIN_VALID); 379 extcon_set_state_sync(chg->edev, EXTCON_USB, 380 chg->status & STATUS_USBIN_VALID); 381 power_supply_changed(chg->usb_psy); 382 383 return IRQ_HANDLED; 384} 385 386static irqreturn_t smbb_dc_valid_handler(int irq, void *_data) 387{ 388 struct smbb_charger *chg = _data; 389 390 smbb_set_line_flag(chg, irq, STATUS_DCIN_VALID); 391 if (!chg->dc_disabled) 392 power_supply_changed(chg->dc_psy); 393 394 return IRQ_HANDLED; 395} 396 397static irqreturn_t smbb_bat_temp_handler(int irq, void *_data) 398{ 399 struct smbb_charger *chg = _data; 400 unsigned int val; 401 int rc; 402 403 rc = regmap_read(chg->regmap, chg->addr + SMBB_BAT_TEMP_STATUS, &val); 404 if (rc) 405 return IRQ_HANDLED; 406 407 mutex_lock(&chg->statlock); 408 if (val & TEMP_STATUS_OK) { 409 chg->status |= STATUS_BAT_OK; 410 } else { 411 chg->status &= ~STATUS_BAT_OK; 412 if (val & TEMP_STATUS_HOT) 413 chg->status |= STATUS_BAT_HOT; 414 } 415 mutex_unlock(&chg->statlock); 416 417 power_supply_changed(chg->bat_psy); 418 return IRQ_HANDLED; 419} 420 421static irqreturn_t smbb_bat_present_handler(int irq, void *_data) 422{ 423 struct smbb_charger *chg = _data; 424 425 smbb_set_line_flag(chg, irq, STATUS_BAT_PRESENT); 426 power_supply_changed(chg->bat_psy); 427 428 return IRQ_HANDLED; 429} 430 431static irqreturn_t smbb_chg_done_handler(int irq, void *_data) 432{ 433 struct smbb_charger *chg = _data; 434 435 smbb_set_line_flag(chg, irq, STATUS_CHG_DONE); 436 power_supply_changed(chg->bat_psy); 437 438 return IRQ_HANDLED; 439} 440 441static irqreturn_t smbb_chg_gone_handler(int irq, void *_data) 442{ 443 struct smbb_charger *chg = _data; 444 445 smbb_set_line_flag(chg, irq, STATUS_CHG_GONE); 446 power_supply_changed(chg->bat_psy); 447 power_supply_changed(chg->usb_psy); 448 if (!chg->dc_disabled) 449 power_supply_changed(chg->dc_psy); 450 451 return IRQ_HANDLED; 452} 453 454static irqreturn_t smbb_chg_fast_handler(int irq, void *_data) 455{ 456 struct smbb_charger *chg = _data; 457 458 smbb_set_line_flag(chg, irq, STATUS_CHG_FAST); 459 power_supply_changed(chg->bat_psy); 460 461 return IRQ_HANDLED; 462} 463 464static irqreturn_t smbb_chg_trkl_handler(int irq, void *_data) 465{ 466 struct smbb_charger *chg = _data; 467 468 smbb_set_line_flag(chg, irq, STATUS_CHG_TRKL); 469 power_supply_changed(chg->bat_psy); 470 471 return IRQ_HANDLED; 472} 473 474static const struct smbb_irq { 475 const char *name; 476 irqreturn_t (*handler)(int, void *); 477} smbb_charger_irqs[] = { 478 { "chg-done", smbb_chg_done_handler }, 479 { "chg-fast", smbb_chg_fast_handler }, 480 { "chg-trkl", smbb_chg_trkl_handler }, 481 { "bat-temp-ok", smbb_bat_temp_handler }, 482 { "bat-present", smbb_bat_present_handler }, 483 { "chg-gone", smbb_chg_gone_handler }, 484 { "usb-valid", smbb_usb_valid_handler }, 485 { "dc-valid", smbb_dc_valid_handler }, 486}; 487 488static int smbb_usbin_get_property(struct power_supply *psy, 489 enum power_supply_property psp, 490 union power_supply_propval *val) 491{ 492 struct smbb_charger *chg = power_supply_get_drvdata(psy); 493 int rc = 0; 494 495 switch (psp) { 496 case POWER_SUPPLY_PROP_ONLINE: 497 mutex_lock(&chg->statlock); 498 val->intval = !(chg->status & STATUS_CHG_GONE) && 499 (chg->status & STATUS_USBIN_VALID); 500 mutex_unlock(&chg->statlock); 501 break; 502 case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: 503 val->intval = chg->attr[ATTR_USBIN_IMAX]; 504 break; 505 case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX: 506 val->intval = 2500000; 507 break; 508 default: 509 rc = -EINVAL; 510 break; 511 } 512 513 return rc; 514} 515 516static int smbb_usbin_set_property(struct power_supply *psy, 517 enum power_supply_property psp, 518 const union power_supply_propval *val) 519{ 520 struct smbb_charger *chg = power_supply_get_drvdata(psy); 521 int rc; 522 523 switch (psp) { 524 case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: 525 rc = smbb_charger_attr_write(chg, ATTR_USBIN_IMAX, 526 val->intval); 527 break; 528 default: 529 rc = -EINVAL; 530 break; 531 } 532 533 return rc; 534} 535 536static int smbb_dcin_get_property(struct power_supply *psy, 537 enum power_supply_property psp, 538 union power_supply_propval *val) 539{ 540 struct smbb_charger *chg = power_supply_get_drvdata(psy); 541 int rc = 0; 542 543 switch (psp) { 544 case POWER_SUPPLY_PROP_ONLINE: 545 mutex_lock(&chg->statlock); 546 val->intval = !(chg->status & STATUS_CHG_GONE) && 547 (chg->status & STATUS_DCIN_VALID); 548 mutex_unlock(&chg->statlock); 549 break; 550 case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: 551 val->intval = chg->attr[ATTR_DCIN_IMAX]; 552 break; 553 case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX: 554 val->intval = 2500000; 555 break; 556 default: 557 rc = -EINVAL; 558 break; 559 } 560 561 return rc; 562} 563 564static int smbb_dcin_set_property(struct power_supply *psy, 565 enum power_supply_property psp, 566 const union power_supply_propval *val) 567{ 568 struct smbb_charger *chg = power_supply_get_drvdata(psy); 569 int rc; 570 571 switch (psp) { 572 case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: 573 rc = smbb_charger_attr_write(chg, ATTR_DCIN_IMAX, 574 val->intval); 575 break; 576 default: 577 rc = -EINVAL; 578 break; 579 } 580 581 return rc; 582} 583 584static int smbb_charger_writable_property(struct power_supply *psy, 585 enum power_supply_property psp) 586{ 587 return psp == POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT; 588} 589 590static int smbb_battery_get_property(struct power_supply *psy, 591 enum power_supply_property psp, 592 union power_supply_propval *val) 593{ 594 struct smbb_charger *chg = power_supply_get_drvdata(psy); 595 unsigned long status; 596 int rc = 0; 597 598 mutex_lock(&chg->statlock); 599 status = chg->status; 600 mutex_unlock(&chg->statlock); 601 602 switch (psp) { 603 case POWER_SUPPLY_PROP_STATUS: 604 if (status & STATUS_CHG_GONE) 605 val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 606 else if (!(status & (STATUS_DCIN_VALID | STATUS_USBIN_VALID))) 607 val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 608 else if (status & STATUS_CHG_DONE) 609 val->intval = POWER_SUPPLY_STATUS_FULL; 610 else if (!(status & STATUS_BAT_OK)) 611 val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 612 else if (status & (STATUS_CHG_FAST | STATUS_CHG_TRKL)) 613 val->intval = POWER_SUPPLY_STATUS_CHARGING; 614 else /* everything is ok for charging, but we are not... */ 615 val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 616 break; 617 case POWER_SUPPLY_PROP_HEALTH: 618 if (status & STATUS_BAT_OK) 619 val->intval = POWER_SUPPLY_HEALTH_GOOD; 620 else if (status & STATUS_BAT_HOT) 621 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; 622 else 623 val->intval = POWER_SUPPLY_HEALTH_COLD; 624 break; 625 case POWER_SUPPLY_PROP_CHARGE_TYPE: 626 if (status & STATUS_CHG_FAST) 627 val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST; 628 else if (status & STATUS_CHG_TRKL) 629 val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; 630 else 631 val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE; 632 break; 633 case POWER_SUPPLY_PROP_PRESENT: 634 val->intval = !!(status & STATUS_BAT_PRESENT); 635 break; 636 case POWER_SUPPLY_PROP_CURRENT_MAX: 637 val->intval = chg->attr[ATTR_BAT_IMAX]; 638 break; 639 case POWER_SUPPLY_PROP_VOLTAGE_MAX: 640 val->intval = chg->attr[ATTR_BAT_VMAX]; 641 break; 642 case POWER_SUPPLY_PROP_TECHNOLOGY: 643 /* this charger is a single-cell lithium-ion battery charger 644 * only. If you hook up some other technology, there will be 645 * fireworks. 646 */ 647 val->intval = POWER_SUPPLY_TECHNOLOGY_LION; 648 break; 649 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: 650 val->intval = 3000000; /* single-cell li-ion low end */ 651 break; 652 default: 653 rc = -EINVAL; 654 break; 655 } 656 657 return rc; 658} 659 660static int smbb_battery_set_property(struct power_supply *psy, 661 enum power_supply_property psp, 662 const union power_supply_propval *val) 663{ 664 struct smbb_charger *chg = power_supply_get_drvdata(psy); 665 int rc; 666 667 switch (psp) { 668 case POWER_SUPPLY_PROP_CURRENT_MAX: 669 rc = smbb_charger_attr_write(chg, ATTR_BAT_IMAX, val->intval); 670 break; 671 case POWER_SUPPLY_PROP_VOLTAGE_MAX: 672 rc = smbb_charger_attr_write(chg, ATTR_BAT_VMAX, val->intval); 673 break; 674 default: 675 rc = -EINVAL; 676 break; 677 } 678 679 return rc; 680} 681 682static int smbb_battery_writable_property(struct power_supply *psy, 683 enum power_supply_property psp) 684{ 685 switch (psp) { 686 case POWER_SUPPLY_PROP_CURRENT_MAX: 687 case POWER_SUPPLY_PROP_VOLTAGE_MAX: 688 return 1; 689 default: 690 return 0; 691 } 692} 693 694static enum power_supply_property smbb_charger_properties[] = { 695 POWER_SUPPLY_PROP_ONLINE, 696 POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, 697 POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX, 698}; 699 700static enum power_supply_property smbb_battery_properties[] = { 701 POWER_SUPPLY_PROP_STATUS, 702 POWER_SUPPLY_PROP_HEALTH, 703 POWER_SUPPLY_PROP_PRESENT, 704 POWER_SUPPLY_PROP_CHARGE_TYPE, 705 POWER_SUPPLY_PROP_CURRENT_MAX, 706 POWER_SUPPLY_PROP_VOLTAGE_MAX, 707 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, 708 POWER_SUPPLY_PROP_TECHNOLOGY, 709}; 710 711static const struct reg_off_mask_default { 712 unsigned int offset; 713 unsigned int mask; 714 unsigned int value; 715 unsigned int rev_mask; 716} smbb_charger_setup[] = { 717 /* The bootloader is supposed to set this... make sure anyway. */ 718 { SMBB_MISC_BOOT_DONE, BOOT_DONE, BOOT_DONE }, 719 720 /* Disable software timer */ 721 { SMBB_CHG_TCHG_MAX_EN, TCHG_MAX_EN, 0 }, 722 723 /* Clear and disable watchdog */ 724 { SMBB_CHG_WDOG_TIME, 0xff, 160 }, 725 { SMBB_CHG_WDOG_EN, WDOG_EN, 0 }, 726 727 /* Use charger based EoC detection */ 728 { SMBB_CHG_IBAT_TERM_CHG, IBAT_TERM_CHG_IEOC, IBAT_TERM_CHG_IEOC_CHG }, 729 730 /* Disable GSM PA load adjustment. 731 * The PA signal is incorrectly connected on v2. 732 */ 733 { SMBB_CHG_CFG, 0xff, 0x00, BIT(3) }, 734 735 /* Use VBAT (not VSYS) to compensate for IR drop during fast charging */ 736 { SMBB_BUCK_REG_MODE, BUCK_REG_MODE, BUCK_REG_MODE_VBAT }, 737 738 /* Enable battery temperature comparators */ 739 { SMBB_BAT_BTC_CTRL, BTC_CTRL_COMP_EN, BTC_CTRL_COMP_EN }, 740 741 /* Stop USB enumeration timer */ 742 { SMBB_USB_ENUM_TIMER_STOP, ENUM_TIMER_STOP, ENUM_TIMER_STOP }, 743 744#if 0 /* FIXME supposedly only to disable hardware ARB termination */ 745 { SMBB_USB_SEC_ACCESS, SEC_ACCESS_MAGIC }, 746 { SMBB_USB_REV_BST, 0xff, REV_BST_CHG_GONE }, 747#endif 748 749 /* Stop USB enumeration timer, again */ 750 { SMBB_USB_ENUM_TIMER_STOP, ENUM_TIMER_STOP, ENUM_TIMER_STOP }, 751 752 /* Enable charging */ 753 { SMBB_CHG_CTRL, CTRL_EN, CTRL_EN }, 754}; 755 756static char *smbb_bif[] = { "smbb-bif" }; 757 758static const struct power_supply_desc bat_psy_desc = { 759 .name = "smbb-bif", 760 .type = POWER_SUPPLY_TYPE_BATTERY, 761 .properties = smbb_battery_properties, 762 .num_properties = ARRAY_SIZE(smbb_battery_properties), 763 .get_property = smbb_battery_get_property, 764 .set_property = smbb_battery_set_property, 765 .property_is_writeable = smbb_battery_writable_property, 766}; 767 768static const struct power_supply_desc usb_psy_desc = { 769 .name = "smbb-usbin", 770 .type = POWER_SUPPLY_TYPE_USB, 771 .properties = smbb_charger_properties, 772 .num_properties = ARRAY_SIZE(smbb_charger_properties), 773 .get_property = smbb_usbin_get_property, 774 .set_property = smbb_usbin_set_property, 775 .property_is_writeable = smbb_charger_writable_property, 776}; 777 778static const struct power_supply_desc dc_psy_desc = { 779 .name = "smbb-dcin", 780 .type = POWER_SUPPLY_TYPE_MAINS, 781 .properties = smbb_charger_properties, 782 .num_properties = ARRAY_SIZE(smbb_charger_properties), 783 .get_property = smbb_dcin_get_property, 784 .set_property = smbb_dcin_set_property, 785 .property_is_writeable = smbb_charger_writable_property, 786}; 787 788static int smbb_chg_otg_enable(struct regulator_dev *rdev) 789{ 790 struct smbb_charger *chg = rdev_get_drvdata(rdev); 791 int rc; 792 793 rc = regmap_update_bits(chg->regmap, chg->addr + SMBB_USB_OTG_CTL, 794 OTG_CTL_EN, OTG_CTL_EN); 795 if (rc) 796 dev_err(chg->dev, "failed to update OTG_CTL\n"); 797 return rc; 798} 799 800static int smbb_chg_otg_disable(struct regulator_dev *rdev) 801{ 802 struct smbb_charger *chg = rdev_get_drvdata(rdev); 803 int rc; 804 805 rc = regmap_update_bits(chg->regmap, chg->addr + SMBB_USB_OTG_CTL, 806 OTG_CTL_EN, 0); 807 if (rc) 808 dev_err(chg->dev, "failed to update OTG_CTL\n"); 809 return rc; 810} 811 812static int smbb_chg_otg_is_enabled(struct regulator_dev *rdev) 813{ 814 struct smbb_charger *chg = rdev_get_drvdata(rdev); 815 unsigned int value = 0; 816 int rc; 817 818 rc = regmap_read(chg->regmap, chg->addr + SMBB_USB_OTG_CTL, &value); 819 if (rc) 820 dev_err(chg->dev, "failed to read OTG_CTL\n"); 821 822 return !!(value & OTG_CTL_EN); 823} 824 825static const struct regulator_ops smbb_chg_otg_ops = { 826 .enable = smbb_chg_otg_enable, 827 .disable = smbb_chg_otg_disable, 828 .is_enabled = smbb_chg_otg_is_enabled, 829}; 830 831static int smbb_charger_probe(struct platform_device *pdev) 832{ 833 struct power_supply_config bat_cfg = {}; 834 struct power_supply_config usb_cfg = {}; 835 struct power_supply_config dc_cfg = {}; 836 struct smbb_charger *chg; 837 struct regulator_config config = { }; 838 int rc, i; 839 840 chg = devm_kzalloc(&pdev->dev, sizeof(*chg), GFP_KERNEL); 841 if (!chg) 842 return -ENOMEM; 843 844 chg->dev = &pdev->dev; 845 mutex_init(&chg->statlock); 846 847 chg->regmap = dev_get_regmap(pdev->dev.parent, NULL); 848 if (!chg->regmap) { 849 dev_err(&pdev->dev, "failed to locate regmap\n"); 850 return -ENODEV; 851 } 852 853 rc = of_property_read_u32(pdev->dev.of_node, "reg", &chg->addr); 854 if (rc) { 855 dev_err(&pdev->dev, "missing or invalid 'reg' property\n"); 856 return rc; 857 } 858 859 rc = regmap_read(chg->regmap, chg->addr + SMBB_MISC_REV2, &chg->revision); 860 if (rc) { 861 dev_err(&pdev->dev, "unable to read revision\n"); 862 return rc; 863 } 864 865 chg->revision += 1; 866 if (chg->revision != 1 && chg->revision != 2 && chg->revision != 3) { 867 dev_err(&pdev->dev, "v%d hardware not supported\n", chg->revision); 868 return -ENODEV; 869 } 870 dev_info(&pdev->dev, "Initializing SMBB rev %u", chg->revision); 871 872 chg->dc_disabled = of_property_read_bool(pdev->dev.of_node, "qcom,disable-dc"); 873 874 for (i = 0; i < _ATTR_CNT; ++i) { 875 rc = smbb_charger_attr_parse(chg, i); 876 if (rc) { 877 dev_err(&pdev->dev, "failed to parse/apply settings\n"); 878 return rc; 879 } 880 } 881 882 bat_cfg.drv_data = chg; 883 bat_cfg.of_node = pdev->dev.of_node; 884 chg->bat_psy = devm_power_supply_register(&pdev->dev, 885 &bat_psy_desc, 886 &bat_cfg); 887 if (IS_ERR(chg->bat_psy)) { 888 dev_err(&pdev->dev, "failed to register battery\n"); 889 return PTR_ERR(chg->bat_psy); 890 } 891 892 usb_cfg.drv_data = chg; 893 usb_cfg.supplied_to = smbb_bif; 894 usb_cfg.num_supplicants = ARRAY_SIZE(smbb_bif); 895 chg->usb_psy = devm_power_supply_register(&pdev->dev, 896 &usb_psy_desc, 897 &usb_cfg); 898 if (IS_ERR(chg->usb_psy)) { 899 dev_err(&pdev->dev, "failed to register USB power supply\n"); 900 return PTR_ERR(chg->usb_psy); 901 } 902 903 chg->edev = devm_extcon_dev_allocate(&pdev->dev, smbb_usb_extcon_cable); 904 if (IS_ERR(chg->edev)) { 905 dev_err(&pdev->dev, "failed to allocate extcon device\n"); 906 return -ENOMEM; 907 } 908 909 rc = devm_extcon_dev_register(&pdev->dev, chg->edev); 910 if (rc < 0) { 911 dev_err(&pdev->dev, "failed to register extcon device\n"); 912 return rc; 913 } 914 915 if (!chg->dc_disabled) { 916 dc_cfg.drv_data = chg; 917 dc_cfg.supplied_to = smbb_bif; 918 dc_cfg.num_supplicants = ARRAY_SIZE(smbb_bif); 919 chg->dc_psy = devm_power_supply_register(&pdev->dev, 920 &dc_psy_desc, 921 &dc_cfg); 922 if (IS_ERR(chg->dc_psy)) { 923 dev_err(&pdev->dev, "failed to register DC power supply\n"); 924 return PTR_ERR(chg->dc_psy); 925 } 926 } 927 928 for (i = 0; i < ARRAY_SIZE(smbb_charger_irqs); ++i) { 929 int irq; 930 931 irq = platform_get_irq_byname(pdev, smbb_charger_irqs[i].name); 932 if (irq < 0) 933 return irq; 934 935 smbb_charger_irqs[i].handler(irq, chg); 936 937 rc = devm_request_threaded_irq(&pdev->dev, irq, NULL, 938 smbb_charger_irqs[i].handler, IRQF_ONESHOT, 939 smbb_charger_irqs[i].name, chg); 940 if (rc) { 941 dev_err(&pdev->dev, "failed to request irq '%s'\n", 942 smbb_charger_irqs[i].name); 943 return rc; 944 } 945 } 946 947 /* 948 * otg regulator is used to control VBUS voltage direction 949 * when USB switches between host and gadget mode 950 */ 951 chg->otg_rdesc.id = -1; 952 chg->otg_rdesc.name = "otg-vbus"; 953 chg->otg_rdesc.ops = &smbb_chg_otg_ops; 954 chg->otg_rdesc.owner = THIS_MODULE; 955 chg->otg_rdesc.type = REGULATOR_VOLTAGE; 956 chg->otg_rdesc.supply_name = "usb-otg-in"; 957 chg->otg_rdesc.of_match = "otg-vbus"; 958 959 config.dev = &pdev->dev; 960 config.driver_data = chg; 961 962 chg->otg_reg = devm_regulator_register(&pdev->dev, &chg->otg_rdesc, 963 &config); 964 if (IS_ERR(chg->otg_reg)) 965 return PTR_ERR(chg->otg_reg); 966 967 chg->jeita_ext_temp = of_property_read_bool(pdev->dev.of_node, 968 "qcom,jeita-extended-temp-range"); 969 970 /* Set temperature range to [35%:70%] or [25%:80%] accordingly */ 971 rc = regmap_update_bits(chg->regmap, chg->addr + SMBB_BAT_BTC_CTRL, 972 BTC_CTRL_COLD_EXT | BTC_CTRL_HOT_EXT_N, 973 chg->jeita_ext_temp ? 974 BTC_CTRL_COLD_EXT : 975 BTC_CTRL_HOT_EXT_N); 976 if (rc) { 977 dev_err(&pdev->dev, 978 "unable to set %s temperature range\n", 979 chg->jeita_ext_temp ? "JEITA extended" : "normal"); 980 return rc; 981 } 982 983 for (i = 0; i < ARRAY_SIZE(smbb_charger_setup); ++i) { 984 const struct reg_off_mask_default *r = &smbb_charger_setup[i]; 985 986 if (r->rev_mask & BIT(chg->revision)) 987 continue; 988 989 rc = regmap_update_bits(chg->regmap, chg->addr + r->offset, 990 r->mask, r->value); 991 if (rc) { 992 dev_err(&pdev->dev, 993 "unable to initializing charging, bailing\n"); 994 return rc; 995 } 996 } 997 998 platform_set_drvdata(pdev, chg); 999 1000 return 0; 1001} 1002 1003static int smbb_charger_remove(struct platform_device *pdev) 1004{ 1005 struct smbb_charger *chg; 1006 1007 chg = platform_get_drvdata(pdev); 1008 1009 regmap_update_bits(chg->regmap, chg->addr + SMBB_CHG_CTRL, CTRL_EN, 0); 1010 1011 return 0; 1012} 1013 1014static const struct of_device_id smbb_charger_id_table[] = { 1015 { .compatible = "qcom,pm8226-charger" }, 1016 { .compatible = "qcom,pm8941-charger" }, 1017 { } 1018}; 1019MODULE_DEVICE_TABLE(of, smbb_charger_id_table); 1020 1021static struct platform_driver smbb_charger_driver = { 1022 .probe = smbb_charger_probe, 1023 .remove = smbb_charger_remove, 1024 .driver = { 1025 .name = "qcom-smbb", 1026 .of_match_table = smbb_charger_id_table, 1027 }, 1028}; 1029module_platform_driver(smbb_charger_driver); 1030 1031MODULE_DESCRIPTION("Qualcomm Switch-Mode Battery Charger and Boost driver"); 1032MODULE_LICENSE("GPL v2");