max8925_power.c (15232B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Battery driver for Maxim MAX8925 4 * 5 * Copyright (c) 2009-2010 Marvell International Ltd. 6 * Haojian Zhuang <haojian.zhuang@marvell.com> 7 */ 8 9#include <linux/module.h> 10#include <linux/err.h> 11#include <linux/slab.h> 12#include <linux/of.h> 13#include <linux/i2c.h> 14#include <linux/interrupt.h> 15#include <linux/platform_device.h> 16#include <linux/power_supply.h> 17#include <linux/mfd/max8925.h> 18 19/* registers in GPM */ 20#define MAX8925_OUT5VEN 0x54 21#define MAX8925_OUT3VEN 0x58 22#define MAX8925_CHG_CNTL1 0x7c 23 24/* bits definition */ 25#define MAX8925_CHG_STAT_VSYSLOW (1 << 0) 26#define MAX8925_CHG_STAT_MODE_MASK (3 << 2) 27#define MAX8925_CHG_STAT_EN_MASK (1 << 4) 28#define MAX8925_CHG_MBDET (1 << 1) 29#define MAX8925_CHG_AC_RANGE_MASK (3 << 6) 30 31/* registers in ADC */ 32#define MAX8925_ADC_RES_CNFG1 0x06 33#define MAX8925_ADC_AVG_CNFG1 0x07 34#define MAX8925_ADC_ACQ_CNFG1 0x08 35#define MAX8925_ADC_ACQ_CNFG2 0x09 36/* 2 bytes registers in below. MSB is 1st, LSB is 2nd. */ 37#define MAX8925_ADC_AUX2 0x62 38#define MAX8925_ADC_VCHG 0x64 39#define MAX8925_ADC_VBBATT 0x66 40#define MAX8925_ADC_VMBATT 0x68 41#define MAX8925_ADC_ISNS 0x6a 42#define MAX8925_ADC_THM 0x6c 43#define MAX8925_ADC_TDIE 0x6e 44#define MAX8925_CMD_AUX2 0xc8 45#define MAX8925_CMD_VCHG 0xd0 46#define MAX8925_CMD_VBBATT 0xd8 47#define MAX8925_CMD_VMBATT 0xe0 48#define MAX8925_CMD_ISNS 0xe8 49#define MAX8925_CMD_THM 0xf0 50#define MAX8925_CMD_TDIE 0xf8 51 52enum { 53 MEASURE_AUX2, 54 MEASURE_VCHG, 55 MEASURE_VBBATT, 56 MEASURE_VMBATT, 57 MEASURE_ISNS, 58 MEASURE_THM, 59 MEASURE_TDIE, 60 MEASURE_MAX, 61}; 62 63struct max8925_power_info { 64 struct max8925_chip *chip; 65 struct i2c_client *gpm; 66 struct i2c_client *adc; 67 68 struct power_supply *ac; 69 struct power_supply *usb; 70 struct power_supply *battery; 71 int irq_base; 72 unsigned ac_online:1; 73 unsigned usb_online:1; 74 unsigned bat_online:1; 75 unsigned chg_mode:2; 76 unsigned batt_detect:1; /* detecing MB by ID pin */ 77 unsigned topoff_threshold:2; 78 unsigned fast_charge:3; 79 unsigned no_temp_support:1; 80 unsigned no_insert_detect:1; 81 82 int (*set_charger) (int); 83}; 84 85static int __set_charger(struct max8925_power_info *info, int enable) 86{ 87 struct max8925_chip *chip = info->chip; 88 if (enable) { 89 /* enable charger in platform */ 90 if (info->set_charger) 91 info->set_charger(1); 92 /* enable charger */ 93 max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 1 << 7, 0); 94 } else { 95 /* disable charge */ 96 max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 1 << 7, 1 << 7); 97 if (info->set_charger) 98 info->set_charger(0); 99 } 100 dev_dbg(chip->dev, "%s\n", (enable) ? "Enable charger" 101 : "Disable charger"); 102 return 0; 103} 104 105static irqreturn_t max8925_charger_handler(int irq, void *data) 106{ 107 struct max8925_power_info *info = (struct max8925_power_info *)data; 108 struct max8925_chip *chip = info->chip; 109 110 switch (irq - chip->irq_base) { 111 case MAX8925_IRQ_VCHG_DC_R: 112 info->ac_online = 1; 113 __set_charger(info, 1); 114 dev_dbg(chip->dev, "Adapter inserted\n"); 115 break; 116 case MAX8925_IRQ_VCHG_DC_F: 117 info->ac_online = 0; 118 __set_charger(info, 0); 119 dev_dbg(chip->dev, "Adapter removed\n"); 120 break; 121 case MAX8925_IRQ_VCHG_THM_OK_F: 122 /* Battery is not ready yet */ 123 dev_dbg(chip->dev, "Battery temperature is out of range\n"); 124 fallthrough; 125 case MAX8925_IRQ_VCHG_DC_OVP: 126 dev_dbg(chip->dev, "Error detection\n"); 127 __set_charger(info, 0); 128 break; 129 case MAX8925_IRQ_VCHG_THM_OK_R: 130 /* Battery is ready now */ 131 dev_dbg(chip->dev, "Battery temperature is in range\n"); 132 break; 133 case MAX8925_IRQ_VCHG_SYSLOW_R: 134 /* VSYS is low */ 135 dev_info(chip->dev, "Sys power is too low\n"); 136 break; 137 case MAX8925_IRQ_VCHG_SYSLOW_F: 138 dev_dbg(chip->dev, "Sys power is above low threshold\n"); 139 break; 140 case MAX8925_IRQ_VCHG_DONE: 141 __set_charger(info, 0); 142 dev_dbg(chip->dev, "Charging is done\n"); 143 break; 144 case MAX8925_IRQ_VCHG_TOPOFF: 145 dev_dbg(chip->dev, "Charging in top-off mode\n"); 146 break; 147 case MAX8925_IRQ_VCHG_TMR_FAULT: 148 __set_charger(info, 0); 149 dev_dbg(chip->dev, "Safe timer is expired\n"); 150 break; 151 case MAX8925_IRQ_VCHG_RST: 152 __set_charger(info, 0); 153 dev_dbg(chip->dev, "Charger is reset\n"); 154 break; 155 } 156 return IRQ_HANDLED; 157} 158 159static int start_measure(struct max8925_power_info *info, int type) 160{ 161 unsigned char buf[2] = {0, 0}; 162 int meas_cmd; 163 int meas_reg = 0, ret; 164 165 switch (type) { 166 case MEASURE_VCHG: 167 meas_cmd = MAX8925_CMD_VCHG; 168 meas_reg = MAX8925_ADC_VCHG; 169 break; 170 case MEASURE_VBBATT: 171 meas_cmd = MAX8925_CMD_VBBATT; 172 meas_reg = MAX8925_ADC_VBBATT; 173 break; 174 case MEASURE_VMBATT: 175 meas_cmd = MAX8925_CMD_VMBATT; 176 meas_reg = MAX8925_ADC_VMBATT; 177 break; 178 case MEASURE_ISNS: 179 meas_cmd = MAX8925_CMD_ISNS; 180 meas_reg = MAX8925_ADC_ISNS; 181 break; 182 default: 183 return -EINVAL; 184 } 185 186 max8925_reg_write(info->adc, meas_cmd, 0); 187 max8925_bulk_read(info->adc, meas_reg, 2, buf); 188 ret = ((buf[0]<<8) | buf[1]) >> 4; 189 190 return ret; 191} 192 193static int max8925_ac_get_prop(struct power_supply *psy, 194 enum power_supply_property psp, 195 union power_supply_propval *val) 196{ 197 struct max8925_power_info *info = dev_get_drvdata(psy->dev.parent); 198 int ret = 0; 199 200 switch (psp) { 201 case POWER_SUPPLY_PROP_ONLINE: 202 val->intval = info->ac_online; 203 break; 204 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 205 if (info->ac_online) { 206 ret = start_measure(info, MEASURE_VCHG); 207 if (ret >= 0) { 208 val->intval = ret * 2000; /* unit is uV */ 209 goto out; 210 } 211 } 212 ret = -ENODATA; 213 break; 214 default: 215 ret = -ENODEV; 216 break; 217 } 218out: 219 return ret; 220} 221 222static enum power_supply_property max8925_ac_props[] = { 223 POWER_SUPPLY_PROP_ONLINE, 224 POWER_SUPPLY_PROP_VOLTAGE_NOW, 225}; 226 227static int max8925_usb_get_prop(struct power_supply *psy, 228 enum power_supply_property psp, 229 union power_supply_propval *val) 230{ 231 struct max8925_power_info *info = dev_get_drvdata(psy->dev.parent); 232 int ret = 0; 233 234 switch (psp) { 235 case POWER_SUPPLY_PROP_ONLINE: 236 val->intval = info->usb_online; 237 break; 238 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 239 if (info->usb_online) { 240 ret = start_measure(info, MEASURE_VCHG); 241 if (ret >= 0) { 242 val->intval = ret * 2000; /* unit is uV */ 243 goto out; 244 } 245 } 246 ret = -ENODATA; 247 break; 248 default: 249 ret = -ENODEV; 250 break; 251 } 252out: 253 return ret; 254} 255 256static enum power_supply_property max8925_usb_props[] = { 257 POWER_SUPPLY_PROP_ONLINE, 258 POWER_SUPPLY_PROP_VOLTAGE_NOW, 259}; 260 261static int max8925_bat_get_prop(struct power_supply *psy, 262 enum power_supply_property psp, 263 union power_supply_propval *val) 264{ 265 struct max8925_power_info *info = dev_get_drvdata(psy->dev.parent); 266 int ret = 0; 267 268 switch (psp) { 269 case POWER_SUPPLY_PROP_ONLINE: 270 val->intval = info->bat_online; 271 break; 272 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 273 if (info->bat_online) { 274 ret = start_measure(info, MEASURE_VMBATT); 275 if (ret >= 0) { 276 val->intval = ret * 2000; /* unit is uV */ 277 ret = 0; 278 break; 279 } 280 } 281 ret = -ENODATA; 282 break; 283 case POWER_SUPPLY_PROP_CURRENT_NOW: 284 if (info->bat_online) { 285 ret = start_measure(info, MEASURE_ISNS); 286 if (ret >= 0) { 287 /* assume r_sns is 0.02 */ 288 ret = ((ret * 6250) - 3125) /* uA */; 289 val->intval = 0; 290 if (ret > 0) 291 val->intval = ret; /* unit is mA */ 292 ret = 0; 293 break; 294 } 295 } 296 ret = -ENODATA; 297 break; 298 case POWER_SUPPLY_PROP_CHARGE_TYPE: 299 if (!info->bat_online) { 300 ret = -ENODATA; 301 break; 302 } 303 ret = max8925_reg_read(info->gpm, MAX8925_CHG_STATUS); 304 ret = (ret & MAX8925_CHG_STAT_MODE_MASK) >> 2; 305 switch (ret) { 306 case 1: 307 val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST; 308 break; 309 case 0: 310 case 2: 311 val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; 312 break; 313 case 3: 314 val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE; 315 break; 316 } 317 ret = 0; 318 break; 319 case POWER_SUPPLY_PROP_STATUS: 320 if (!info->bat_online) { 321 ret = -ENODATA; 322 break; 323 } 324 ret = max8925_reg_read(info->gpm, MAX8925_CHG_STATUS); 325 if (info->usb_online || info->ac_online) { 326 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; 327 if (ret & MAX8925_CHG_STAT_EN_MASK) 328 val->intval = POWER_SUPPLY_STATUS_CHARGING; 329 } else 330 val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 331 ret = 0; 332 break; 333 default: 334 ret = -ENODEV; 335 break; 336 } 337 return ret; 338} 339 340static enum power_supply_property max8925_battery_props[] = { 341 POWER_SUPPLY_PROP_ONLINE, 342 POWER_SUPPLY_PROP_VOLTAGE_NOW, 343 POWER_SUPPLY_PROP_CURRENT_NOW, 344 POWER_SUPPLY_PROP_CHARGE_TYPE, 345 POWER_SUPPLY_PROP_STATUS, 346}; 347 348static const struct power_supply_desc ac_desc = { 349 .name = "max8925-ac", 350 .type = POWER_SUPPLY_TYPE_MAINS, 351 .properties = max8925_ac_props, 352 .num_properties = ARRAY_SIZE(max8925_ac_props), 353 .get_property = max8925_ac_get_prop, 354}; 355 356static const struct power_supply_desc usb_desc = { 357 .name = "max8925-usb", 358 .type = POWER_SUPPLY_TYPE_USB, 359 .properties = max8925_usb_props, 360 .num_properties = ARRAY_SIZE(max8925_usb_props), 361 .get_property = max8925_usb_get_prop, 362}; 363 364static const struct power_supply_desc battery_desc = { 365 .name = "max8925-battery", 366 .type = POWER_SUPPLY_TYPE_BATTERY, 367 .properties = max8925_battery_props, 368 .num_properties = ARRAY_SIZE(max8925_battery_props), 369 .get_property = max8925_bat_get_prop, 370}; 371 372#define REQUEST_IRQ(_irq, _name) \ 373do { \ 374 ret = request_threaded_irq(chip->irq_base + _irq, NULL, \ 375 max8925_charger_handler, \ 376 IRQF_ONESHOT, _name, info); \ 377 if (ret) \ 378 dev_err(chip->dev, "Failed to request IRQ #%d: %d\n", \ 379 _irq, ret); \ 380} while (0) 381 382static int max8925_init_charger(struct max8925_chip *chip, 383 struct max8925_power_info *info) 384{ 385 int ret; 386 387 REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_OVP, "ac-ovp"); 388 if (!info->no_insert_detect) { 389 REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_F, "ac-remove"); 390 REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_R, "ac-insert"); 391 } 392 if (!info->no_temp_support) { 393 REQUEST_IRQ(MAX8925_IRQ_VCHG_THM_OK_R, "batt-temp-in-range"); 394 REQUEST_IRQ(MAX8925_IRQ_VCHG_THM_OK_F, "batt-temp-out-range"); 395 } 396 REQUEST_IRQ(MAX8925_IRQ_VCHG_SYSLOW_F, "vsys-high"); 397 REQUEST_IRQ(MAX8925_IRQ_VCHG_SYSLOW_R, "vsys-low"); 398 REQUEST_IRQ(MAX8925_IRQ_VCHG_RST, "charger-reset"); 399 REQUEST_IRQ(MAX8925_IRQ_VCHG_DONE, "charger-done"); 400 REQUEST_IRQ(MAX8925_IRQ_VCHG_TOPOFF, "charger-topoff"); 401 REQUEST_IRQ(MAX8925_IRQ_VCHG_TMR_FAULT, "charger-timer-expire"); 402 403 info->usb_online = 0; 404 info->bat_online = 0; 405 406 /* check for power - can miss interrupt at boot time */ 407 if (start_measure(info, MEASURE_VCHG) * 2000 > 500000) 408 info->ac_online = 1; 409 else 410 info->ac_online = 0; 411 412 ret = max8925_reg_read(info->gpm, MAX8925_CHG_STATUS); 413 if (ret >= 0) { 414 /* 415 * If battery detection is enabled, ID pin of battery is 416 * connected to MBDET pin of MAX8925. It could be used to 417 * detect battery presence. 418 * Otherwise, we have to assume that battery is always on. 419 */ 420 if (info->batt_detect) 421 info->bat_online = (ret & MAX8925_CHG_MBDET) ? 0 : 1; 422 else 423 info->bat_online = 1; 424 if (ret & MAX8925_CHG_AC_RANGE_MASK) 425 info->ac_online = 1; 426 else 427 info->ac_online = 0; 428 } 429 /* disable charge */ 430 max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 1 << 7, 1 << 7); 431 /* set charging current in charge topoff mode */ 432 max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 3 << 5, 433 info->topoff_threshold << 5); 434 /* set charing current in fast charge mode */ 435 max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 7, info->fast_charge); 436 437 return 0; 438} 439 440static int max8925_deinit_charger(struct max8925_power_info *info) 441{ 442 struct max8925_chip *chip = info->chip; 443 int irq; 444 445 irq = chip->irq_base + MAX8925_IRQ_VCHG_DC_OVP; 446 for (; irq <= chip->irq_base + MAX8925_IRQ_VCHG_TMR_FAULT; irq++) 447 free_irq(irq, info); 448 449 return 0; 450} 451 452#ifdef CONFIG_OF 453static struct max8925_power_pdata * 454max8925_power_dt_init(struct platform_device *pdev) 455{ 456 struct device_node *nproot = pdev->dev.parent->of_node; 457 struct device_node *np; 458 int batt_detect; 459 int topoff_threshold; 460 int fast_charge; 461 int no_temp_support; 462 int no_insert_detect; 463 struct max8925_power_pdata *pdata; 464 465 if (!nproot) 466 return pdev->dev.platform_data; 467 468 np = of_get_child_by_name(nproot, "charger"); 469 if (!np) { 470 dev_err(&pdev->dev, "failed to find charger node\n"); 471 return NULL; 472 } 473 474 pdata = devm_kzalloc(&pdev->dev, 475 sizeof(struct max8925_power_pdata), 476 GFP_KERNEL); 477 if (!pdata) 478 goto ret; 479 480 of_property_read_u32(np, "topoff-threshold", &topoff_threshold); 481 of_property_read_u32(np, "batt-detect", &batt_detect); 482 of_property_read_u32(np, "fast-charge", &fast_charge); 483 of_property_read_u32(np, "no-insert-detect", &no_insert_detect); 484 of_property_read_u32(np, "no-temp-support", &no_temp_support); 485 486 pdata->batt_detect = batt_detect; 487 pdata->fast_charge = fast_charge; 488 pdata->topoff_threshold = topoff_threshold; 489 pdata->no_insert_detect = no_insert_detect; 490 pdata->no_temp_support = no_temp_support; 491 492ret: 493 of_node_put(np); 494 return pdata; 495} 496#else 497static struct max8925_power_pdata * 498max8925_power_dt_init(struct platform_device *pdev) 499{ 500 return pdev->dev.platform_data; 501} 502#endif 503 504static int max8925_power_probe(struct platform_device *pdev) 505{ 506 struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); 507 struct power_supply_config psy_cfg = {}; /* Only for ac and usb */ 508 struct max8925_power_pdata *pdata = NULL; 509 struct max8925_power_info *info; 510 int ret; 511 512 pdata = max8925_power_dt_init(pdev); 513 if (!pdata) { 514 dev_err(&pdev->dev, "platform data isn't assigned to " 515 "power supply\n"); 516 return -EINVAL; 517 } 518 519 info = devm_kzalloc(&pdev->dev, sizeof(struct max8925_power_info), 520 GFP_KERNEL); 521 if (!info) 522 return -ENOMEM; 523 info->chip = chip; 524 info->gpm = chip->i2c; 525 info->adc = chip->adc; 526 platform_set_drvdata(pdev, info); 527 528 psy_cfg.supplied_to = pdata->supplied_to; 529 psy_cfg.num_supplicants = pdata->num_supplicants; 530 531 info->ac = power_supply_register(&pdev->dev, &ac_desc, &psy_cfg); 532 if (IS_ERR(info->ac)) { 533 ret = PTR_ERR(info->ac); 534 goto out; 535 } 536 info->ac->dev.parent = &pdev->dev; 537 538 info->usb = power_supply_register(&pdev->dev, &usb_desc, &psy_cfg); 539 if (IS_ERR(info->usb)) { 540 ret = PTR_ERR(info->usb); 541 goto out_unregister_ac; 542 } 543 info->usb->dev.parent = &pdev->dev; 544 545 info->battery = power_supply_register(&pdev->dev, &battery_desc, NULL); 546 if (IS_ERR(info->battery)) { 547 ret = PTR_ERR(info->battery); 548 goto out_unregister_usb; 549 } 550 info->battery->dev.parent = &pdev->dev; 551 552 info->batt_detect = pdata->batt_detect; 553 info->topoff_threshold = pdata->topoff_threshold; 554 info->fast_charge = pdata->fast_charge; 555 info->set_charger = pdata->set_charger; 556 info->no_temp_support = pdata->no_temp_support; 557 info->no_insert_detect = pdata->no_insert_detect; 558 559 max8925_init_charger(chip, info); 560 return 0; 561out_unregister_usb: 562 power_supply_unregister(info->usb); 563out_unregister_ac: 564 power_supply_unregister(info->ac); 565out: 566 return ret; 567} 568 569static int max8925_power_remove(struct platform_device *pdev) 570{ 571 struct max8925_power_info *info = platform_get_drvdata(pdev); 572 573 if (info) { 574 power_supply_unregister(info->ac); 575 power_supply_unregister(info->usb); 576 power_supply_unregister(info->battery); 577 max8925_deinit_charger(info); 578 } 579 return 0; 580} 581 582static struct platform_driver max8925_power_driver = { 583 .probe = max8925_power_probe, 584 .remove = max8925_power_remove, 585 .driver = { 586 .name = "max8925-power", 587 }, 588}; 589 590module_platform_driver(max8925_power_driver); 591 592MODULE_LICENSE("GPL"); 593MODULE_DESCRIPTION("Power supply driver for MAX8925"); 594MODULE_ALIAS("platform:max8925-power");