act8945a_charger.c (15963B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Power supply driver for the Active-semi ACT8945A PMIC 4 * 5 * Copyright (C) 2015 Atmel Corporation 6 * 7 * Author: Wenyou Yang <wenyou.yang@atmel.com> 8 */ 9#include <linux/interrupt.h> 10#include <linux/module.h> 11#include <linux/of.h> 12#include <linux/of_irq.h> 13#include <linux/platform_device.h> 14#include <linux/power_supply.h> 15#include <linux/regmap.h> 16#include <linux/gpio/consumer.h> 17 18static const char *act8945a_charger_model = "ACT8945A"; 19static const char *act8945a_charger_manufacturer = "Active-semi"; 20 21/* 22 * ACT8945A Charger Register Map 23 */ 24 25/* 0x70: Reserved */ 26#define ACT8945A_APCH_CFG 0x71 27#define ACT8945A_APCH_STATUS 0x78 28#define ACT8945A_APCH_CTRL 0x79 29#define ACT8945A_APCH_STATE 0x7A 30 31/* ACT8945A_APCH_CFG */ 32#define APCH_CFG_OVPSET (0x3 << 0) 33#define APCH_CFG_OVPSET_6V6 (0x0 << 0) 34#define APCH_CFG_OVPSET_7V (0x1 << 0) 35#define APCH_CFG_OVPSET_7V5 (0x2 << 0) 36#define APCH_CFG_OVPSET_8V (0x3 << 0) 37#define APCH_CFG_PRETIMO (0x3 << 2) 38#define APCH_CFG_PRETIMO_40_MIN (0x0 << 2) 39#define APCH_CFG_PRETIMO_60_MIN (0x1 << 2) 40#define APCH_CFG_PRETIMO_80_MIN (0x2 << 2) 41#define APCH_CFG_PRETIMO_DISABLED (0x3 << 2) 42#define APCH_CFG_TOTTIMO (0x3 << 4) 43#define APCH_CFG_TOTTIMO_3_HOUR (0x0 << 4) 44#define APCH_CFG_TOTTIMO_4_HOUR (0x1 << 4) 45#define APCH_CFG_TOTTIMO_5_HOUR (0x2 << 4) 46#define APCH_CFG_TOTTIMO_DISABLED (0x3 << 4) 47#define APCH_CFG_SUSCHG (0x1 << 7) 48 49#define APCH_STATUS_CHGDAT BIT(0) 50#define APCH_STATUS_INDAT BIT(1) 51#define APCH_STATUS_TEMPDAT BIT(2) 52#define APCH_STATUS_TIMRDAT BIT(3) 53#define APCH_STATUS_CHGSTAT BIT(4) 54#define APCH_STATUS_INSTAT BIT(5) 55#define APCH_STATUS_TEMPSTAT BIT(6) 56#define APCH_STATUS_TIMRSTAT BIT(7) 57 58#define APCH_CTRL_CHGEOCOUT BIT(0) 59#define APCH_CTRL_INDIS BIT(1) 60#define APCH_CTRL_TEMPOUT BIT(2) 61#define APCH_CTRL_TIMRPRE BIT(3) 62#define APCH_CTRL_CHGEOCIN BIT(4) 63#define APCH_CTRL_INCON BIT(5) 64#define APCH_CTRL_TEMPIN BIT(6) 65#define APCH_CTRL_TIMRTOT BIT(7) 66 67#define APCH_STATE_ACINSTAT (0x1 << 1) 68#define APCH_STATE_CSTATE (0x3 << 4) 69#define APCH_STATE_CSTATE_SHIFT 4 70#define APCH_STATE_CSTATE_DISABLED 0x00 71#define APCH_STATE_CSTATE_EOC 0x01 72#define APCH_STATE_CSTATE_FAST 0x02 73#define APCH_STATE_CSTATE_PRE 0x03 74 75struct act8945a_charger { 76 struct power_supply *psy; 77 struct power_supply_desc desc; 78 struct regmap *regmap; 79 struct work_struct work; 80 81 bool init_done; 82 struct gpio_desc *lbo_gpio; 83 struct gpio_desc *chglev_gpio; 84}; 85 86static int act8945a_get_charger_state(struct regmap *regmap, int *val) 87{ 88 int ret; 89 unsigned int status, state; 90 91 ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status); 92 if (ret < 0) 93 return ret; 94 95 ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state); 96 if (ret < 0) 97 return ret; 98 99 state &= APCH_STATE_CSTATE; 100 state >>= APCH_STATE_CSTATE_SHIFT; 101 102 switch (state) { 103 case APCH_STATE_CSTATE_PRE: 104 case APCH_STATE_CSTATE_FAST: 105 *val = POWER_SUPPLY_STATUS_CHARGING; 106 break; 107 case APCH_STATE_CSTATE_EOC: 108 if (status & APCH_STATUS_CHGDAT) 109 *val = POWER_SUPPLY_STATUS_FULL; 110 else 111 *val = POWER_SUPPLY_STATUS_CHARGING; 112 break; 113 case APCH_STATE_CSTATE_DISABLED: 114 default: 115 if (!(status & APCH_STATUS_INDAT)) 116 *val = POWER_SUPPLY_STATUS_DISCHARGING; 117 else 118 *val = POWER_SUPPLY_STATUS_NOT_CHARGING; 119 break; 120 } 121 122 return 0; 123} 124 125static int act8945a_get_charge_type(struct regmap *regmap, int *val) 126{ 127 int ret; 128 unsigned int status, state; 129 130 ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status); 131 if (ret < 0) 132 return ret; 133 134 ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state); 135 if (ret < 0) 136 return ret; 137 138 state &= APCH_STATE_CSTATE; 139 state >>= APCH_STATE_CSTATE_SHIFT; 140 141 switch (state) { 142 case APCH_STATE_CSTATE_PRE: 143 *val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; 144 break; 145 case APCH_STATE_CSTATE_FAST: 146 *val = POWER_SUPPLY_CHARGE_TYPE_FAST; 147 break; 148 case APCH_STATE_CSTATE_EOC: 149 *val = POWER_SUPPLY_CHARGE_TYPE_NONE; 150 break; 151 case APCH_STATE_CSTATE_DISABLED: 152 default: 153 if (!(status & APCH_STATUS_INDAT)) 154 *val = POWER_SUPPLY_CHARGE_TYPE_NONE; 155 else 156 *val = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; 157 break; 158 } 159 160 return 0; 161} 162 163static int act8945a_get_battery_health(struct regmap *regmap, int *val) 164{ 165 int ret; 166 unsigned int status, state, config; 167 168 ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status); 169 if (ret < 0) 170 return ret; 171 172 ret = regmap_read(regmap, ACT8945A_APCH_CFG, &config); 173 if (ret < 0) 174 return ret; 175 176 ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state); 177 if (ret < 0) 178 return ret; 179 180 state &= APCH_STATE_CSTATE; 181 state >>= APCH_STATE_CSTATE_SHIFT; 182 183 switch (state) { 184 case APCH_STATE_CSTATE_DISABLED: 185 if (config & APCH_CFG_SUSCHG) { 186 *val = POWER_SUPPLY_HEALTH_UNKNOWN; 187 } else if (status & APCH_STATUS_INDAT) { 188 if (!(status & APCH_STATUS_TEMPDAT)) 189 *val = POWER_SUPPLY_HEALTH_OVERHEAT; 190 else if (status & APCH_STATUS_TIMRDAT) 191 *val = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE; 192 else 193 *val = POWER_SUPPLY_HEALTH_OVERVOLTAGE; 194 } else { 195 *val = POWER_SUPPLY_HEALTH_GOOD; 196 } 197 break; 198 case APCH_STATE_CSTATE_PRE: 199 case APCH_STATE_CSTATE_FAST: 200 case APCH_STATE_CSTATE_EOC: 201 default: 202 *val = POWER_SUPPLY_HEALTH_GOOD; 203 break; 204 } 205 206 return 0; 207} 208 209static int act8945a_get_capacity_level(struct act8945a_charger *charger, 210 struct regmap *regmap, int *val) 211{ 212 int ret; 213 unsigned int status, state, config; 214 int lbo_level = gpiod_get_value(charger->lbo_gpio); 215 216 ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status); 217 if (ret < 0) 218 return ret; 219 220 ret = regmap_read(regmap, ACT8945A_APCH_CFG, &config); 221 if (ret < 0) 222 return ret; 223 224 ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state); 225 if (ret < 0) 226 return ret; 227 228 state &= APCH_STATE_CSTATE; 229 state >>= APCH_STATE_CSTATE_SHIFT; 230 231 switch (state) { 232 case APCH_STATE_CSTATE_PRE: 233 *val = POWER_SUPPLY_CAPACITY_LEVEL_LOW; 234 break; 235 case APCH_STATE_CSTATE_FAST: 236 if (lbo_level) 237 *val = POWER_SUPPLY_CAPACITY_LEVEL_HIGH; 238 else 239 *val = POWER_SUPPLY_CAPACITY_LEVEL_LOW; 240 break; 241 case APCH_STATE_CSTATE_EOC: 242 if (status & APCH_STATUS_CHGDAT) 243 *val = POWER_SUPPLY_CAPACITY_LEVEL_FULL; 244 else 245 *val = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; 246 break; 247 case APCH_STATE_CSTATE_DISABLED: 248 default: 249 if (config & APCH_CFG_SUSCHG) { 250 *val = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; 251 } else { 252 *val = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; 253 if (!(status & APCH_STATUS_INDAT)) { 254 if (!lbo_level) 255 *val = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; 256 } 257 } 258 break; 259 } 260 261 return 0; 262} 263 264#define MAX_CURRENT_USB_HIGH 450000 265#define MAX_CURRENT_USB_LOW 90000 266#define MAX_CURRENT_USB_PRE 45000 267/* 268 * Riset(K) = 2336 * (1V/Ichg(mA)) - 0.205 269 * Riset = 2.43K 270 */ 271#define MAX_CURRENT_AC_HIGH 886527 272#define MAX_CURRENT_AC_LOW 117305 273#define MAX_CURRENT_AC_HIGH_PRE 88653 274#define MAX_CURRENT_AC_LOW_PRE 11731 275 276static int act8945a_get_current_max(struct act8945a_charger *charger, 277 struct regmap *regmap, int *val) 278{ 279 int ret; 280 unsigned int status, state; 281 unsigned int acin_state; 282 int chgin_level = gpiod_get_value(charger->chglev_gpio); 283 284 ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status); 285 if (ret < 0) 286 return ret; 287 288 ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state); 289 if (ret < 0) 290 return ret; 291 292 acin_state = (state & APCH_STATE_ACINSTAT) >> 1; 293 294 state &= APCH_STATE_CSTATE; 295 state >>= APCH_STATE_CSTATE_SHIFT; 296 297 switch (state) { 298 case APCH_STATE_CSTATE_PRE: 299 if (acin_state) { 300 if (chgin_level) 301 *val = MAX_CURRENT_AC_HIGH_PRE; 302 else 303 *val = MAX_CURRENT_AC_LOW_PRE; 304 } else { 305 *val = MAX_CURRENT_USB_PRE; 306 } 307 break; 308 case APCH_STATE_CSTATE_FAST: 309 if (acin_state) { 310 if (chgin_level) 311 *val = MAX_CURRENT_AC_HIGH; 312 else 313 *val = MAX_CURRENT_AC_LOW; 314 } else { 315 if (chgin_level) 316 *val = MAX_CURRENT_USB_HIGH; 317 else 318 *val = MAX_CURRENT_USB_LOW; 319 } 320 break; 321 case APCH_STATE_CSTATE_EOC: 322 case APCH_STATE_CSTATE_DISABLED: 323 default: 324 *val = 0; 325 break; 326 } 327 328 return 0; 329} 330 331static enum power_supply_property act8945a_charger_props[] = { 332 POWER_SUPPLY_PROP_STATUS, 333 POWER_SUPPLY_PROP_CHARGE_TYPE, 334 POWER_SUPPLY_PROP_TECHNOLOGY, 335 POWER_SUPPLY_PROP_HEALTH, 336 POWER_SUPPLY_PROP_CAPACITY_LEVEL, 337 POWER_SUPPLY_PROP_CURRENT_MAX, 338 POWER_SUPPLY_PROP_MODEL_NAME, 339 POWER_SUPPLY_PROP_MANUFACTURER 340}; 341 342static int act8945a_charger_get_property(struct power_supply *psy, 343 enum power_supply_property prop, 344 union power_supply_propval *val) 345{ 346 struct act8945a_charger *charger = power_supply_get_drvdata(psy); 347 struct regmap *regmap = charger->regmap; 348 int ret = 0; 349 350 switch (prop) { 351 case POWER_SUPPLY_PROP_STATUS: 352 ret = act8945a_get_charger_state(regmap, &val->intval); 353 break; 354 case POWER_SUPPLY_PROP_CHARGE_TYPE: 355 ret = act8945a_get_charge_type(regmap, &val->intval); 356 break; 357 case POWER_SUPPLY_PROP_TECHNOLOGY: 358 val->intval = POWER_SUPPLY_TECHNOLOGY_LION; 359 break; 360 case POWER_SUPPLY_PROP_HEALTH: 361 ret = act8945a_get_battery_health(regmap, &val->intval); 362 break; 363 case POWER_SUPPLY_PROP_CAPACITY_LEVEL: 364 ret = act8945a_get_capacity_level(charger, 365 regmap, &val->intval); 366 break; 367 case POWER_SUPPLY_PROP_CURRENT_MAX: 368 ret = act8945a_get_current_max(charger, 369 regmap, &val->intval); 370 break; 371 case POWER_SUPPLY_PROP_MODEL_NAME: 372 val->strval = act8945a_charger_model; 373 break; 374 case POWER_SUPPLY_PROP_MANUFACTURER: 375 val->strval = act8945a_charger_manufacturer; 376 break; 377 default: 378 return -EINVAL; 379 } 380 381 return ret; 382} 383 384static int act8945a_enable_interrupt(struct act8945a_charger *charger) 385{ 386 struct regmap *regmap = charger->regmap; 387 unsigned char ctrl; 388 int ret; 389 390 ctrl = APCH_CTRL_CHGEOCOUT | APCH_CTRL_CHGEOCIN | 391 APCH_CTRL_INDIS | APCH_CTRL_INCON | 392 APCH_CTRL_TEMPOUT | APCH_CTRL_TEMPIN | 393 APCH_CTRL_TIMRPRE | APCH_CTRL_TIMRTOT; 394 ret = regmap_write(regmap, ACT8945A_APCH_CTRL, ctrl); 395 if (ret) 396 return ret; 397 398 ctrl = APCH_STATUS_CHGSTAT | APCH_STATUS_INSTAT | 399 APCH_STATUS_TEMPSTAT | APCH_STATUS_TIMRSTAT; 400 ret = regmap_write(regmap, ACT8945A_APCH_STATUS, ctrl); 401 if (ret) 402 return ret; 403 404 return 0; 405} 406 407static unsigned int act8945a_set_supply_type(struct act8945a_charger *charger, 408 unsigned int *type) 409{ 410 unsigned int status, state; 411 int ret; 412 413 ret = regmap_read(charger->regmap, ACT8945A_APCH_STATUS, &status); 414 if (ret < 0) 415 return ret; 416 417 ret = regmap_read(charger->regmap, ACT8945A_APCH_STATE, &state); 418 if (ret < 0) 419 return ret; 420 421 if (status & APCH_STATUS_INDAT) { 422 if (state & APCH_STATE_ACINSTAT) 423 *type = POWER_SUPPLY_TYPE_MAINS; 424 else 425 *type = POWER_SUPPLY_TYPE_USB; 426 } else { 427 *type = POWER_SUPPLY_TYPE_BATTERY; 428 } 429 430 return 0; 431} 432 433static void act8945a_work(struct work_struct *work) 434{ 435 struct act8945a_charger *charger = 436 container_of(work, struct act8945a_charger, work); 437 438 act8945a_set_supply_type(charger, &charger->desc.type); 439 440 power_supply_changed(charger->psy); 441} 442 443static irqreturn_t act8945a_status_changed(int irq, void *dev_id) 444{ 445 struct act8945a_charger *charger = dev_id; 446 447 if (charger->init_done) 448 schedule_work(&charger->work); 449 450 return IRQ_HANDLED; 451} 452 453#define DEFAULT_TOTAL_TIME_OUT 3 454#define DEFAULT_PRE_TIME_OUT 40 455#define DEFAULT_INPUT_OVP_THRESHOLD 6600 456 457static int act8945a_charger_config(struct device *dev, 458 struct act8945a_charger *charger) 459{ 460 struct device_node *np = dev->of_node; 461 struct regmap *regmap = charger->regmap; 462 463 u32 total_time_out; 464 u32 pre_time_out; 465 u32 input_voltage_threshold; 466 int err, ret; 467 468 unsigned int tmp; 469 unsigned int value = 0; 470 471 if (!np) { 472 dev_err(dev, "no charger of node\n"); 473 return -EINVAL; 474 } 475 476 ret = regmap_read(regmap, ACT8945A_APCH_CFG, &tmp); 477 if (ret) 478 return ret; 479 480 if (tmp & APCH_CFG_SUSCHG) { 481 value |= APCH_CFG_SUSCHG; 482 dev_info(dev, "have been suspended\n"); 483 } 484 485 charger->lbo_gpio = devm_gpiod_get_optional(dev, "active-semi,lbo", 486 GPIOD_IN); 487 if (IS_ERR(charger->lbo_gpio)) { 488 err = PTR_ERR(charger->lbo_gpio); 489 dev_err(dev, "unable to claim gpio \"lbo\": %d\n", err); 490 return err; 491 } 492 493 ret = devm_request_irq(dev, gpiod_to_irq(charger->lbo_gpio), 494 act8945a_status_changed, 495 (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING), 496 "act8945a_lbo_detect", charger); 497 if (ret) 498 dev_info(dev, "failed to request gpio \"lbo\" IRQ\n"); 499 500 charger->chglev_gpio = devm_gpiod_get_optional(dev, 501 "active-semi,chglev", 502 GPIOD_IN); 503 if (IS_ERR(charger->chglev_gpio)) { 504 err = PTR_ERR(charger->chglev_gpio); 505 dev_err(dev, "unable to claim gpio \"chglev\": %d\n", err); 506 return err; 507 } 508 509 if (of_property_read_u32(np, 510 "active-semi,input-voltage-threshold-microvolt", 511 &input_voltage_threshold)) 512 input_voltage_threshold = DEFAULT_INPUT_OVP_THRESHOLD; 513 514 if (of_property_read_u32(np, 515 "active-semi,precondition-timeout", 516 &pre_time_out)) 517 pre_time_out = DEFAULT_PRE_TIME_OUT; 518 519 if (of_property_read_u32(np, "active-semi,total-timeout", 520 &total_time_out)) 521 total_time_out = DEFAULT_TOTAL_TIME_OUT; 522 523 switch (input_voltage_threshold) { 524 case 8000: 525 value |= APCH_CFG_OVPSET_8V; 526 break; 527 case 7500: 528 value |= APCH_CFG_OVPSET_7V5; 529 break; 530 case 7000: 531 value |= APCH_CFG_OVPSET_7V; 532 break; 533 case 6600: 534 default: 535 value |= APCH_CFG_OVPSET_6V6; 536 break; 537 } 538 539 switch (pre_time_out) { 540 case 60: 541 value |= APCH_CFG_PRETIMO_60_MIN; 542 break; 543 case 80: 544 value |= APCH_CFG_PRETIMO_80_MIN; 545 break; 546 case 0: 547 value |= APCH_CFG_PRETIMO_DISABLED; 548 break; 549 case 40: 550 default: 551 value |= APCH_CFG_PRETIMO_40_MIN; 552 break; 553 } 554 555 switch (total_time_out) { 556 case 4: 557 value |= APCH_CFG_TOTTIMO_4_HOUR; 558 break; 559 case 5: 560 value |= APCH_CFG_TOTTIMO_5_HOUR; 561 break; 562 case 0: 563 value |= APCH_CFG_TOTTIMO_DISABLED; 564 break; 565 case 3: 566 default: 567 value |= APCH_CFG_TOTTIMO_3_HOUR; 568 break; 569 } 570 571 return regmap_write(regmap, ACT8945A_APCH_CFG, value); 572} 573 574static int act8945a_charger_probe(struct platform_device *pdev) 575{ 576 struct act8945a_charger *charger; 577 struct power_supply_config psy_cfg = {}; 578 int irq, ret; 579 580 charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL); 581 if (!charger) 582 return -ENOMEM; 583 584 charger->regmap = dev_get_regmap(pdev->dev.parent, NULL); 585 if (!charger->regmap) { 586 dev_err(&pdev->dev, "Parent did not provide regmap\n"); 587 return -EINVAL; 588 } 589 590 ret = act8945a_charger_config(&pdev->dev, charger); 591 if (ret) 592 return ret; 593 594 irq = of_irq_get(pdev->dev.of_node, 0); 595 if (irq <= 0) { 596 dev_err(&pdev->dev, "failed to find IRQ number\n"); 597 return irq ?: -ENXIO; 598 } 599 600 ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed, 601 IRQF_TRIGGER_FALLING, "act8945a_interrupt", 602 charger); 603 if (ret) { 604 dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n"); 605 return ret; 606 } 607 608 charger->desc.name = "act8945a-charger"; 609 charger->desc.get_property = act8945a_charger_get_property; 610 charger->desc.properties = act8945a_charger_props; 611 charger->desc.num_properties = ARRAY_SIZE(act8945a_charger_props); 612 613 ret = act8945a_set_supply_type(charger, &charger->desc.type); 614 if (ret) 615 return -EINVAL; 616 617 psy_cfg.of_node = pdev->dev.of_node; 618 psy_cfg.drv_data = charger; 619 620 charger->psy = devm_power_supply_register(&pdev->dev, 621 &charger->desc, 622 &psy_cfg); 623 if (IS_ERR(charger->psy)) { 624 dev_err(&pdev->dev, "failed to register power supply\n"); 625 return PTR_ERR(charger->psy); 626 } 627 628 platform_set_drvdata(pdev, charger); 629 630 INIT_WORK(&charger->work, act8945a_work); 631 632 ret = act8945a_enable_interrupt(charger); 633 if (ret) 634 return -EIO; 635 636 charger->init_done = true; 637 638 return 0; 639} 640 641static int act8945a_charger_remove(struct platform_device *pdev) 642{ 643 struct act8945a_charger *charger = platform_get_drvdata(pdev); 644 645 charger->init_done = false; 646 cancel_work_sync(&charger->work); 647 648 return 0; 649} 650 651static struct platform_driver act8945a_charger_driver = { 652 .driver = { 653 .name = "act8945a-charger", 654 }, 655 .probe = act8945a_charger_probe, 656 .remove = act8945a_charger_remove, 657}; 658module_platform_driver(act8945a_charger_driver); 659 660MODULE_DESCRIPTION("Active-semi ACT8945A ActivePath charger driver"); 661MODULE_AUTHOR("Wenyou Yang <wenyou.yang@atmel.com>"); 662MODULE_LICENSE("GPL");