577 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Battery driver for Maxim MAX89254 *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 0x5421#define MAX8925_OUT3VEN 0x5822#define MAX8925_CHG_CNTL1 0x7c23 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 0x0633#define MAX8925_ADC_AVG_CNFG1 0x0734#define MAX8925_ADC_ACQ_CNFG1 0x0835#define MAX8925_ADC_ACQ_CNFG2 0x0936/* 2 bytes registers in below. MSB is 1st, LSB is 2nd. */37#define MAX8925_ADC_AUX2 0x6238#define MAX8925_ADC_VCHG 0x6439#define MAX8925_ADC_VBBATT 0x6640#define MAX8925_ADC_VMBATT 0x6841#define MAX8925_ADC_ISNS 0x6a42#define MAX8925_ADC_THM 0x6c43#define MAX8925_ADC_TDIE 0x6e44#define MAX8925_CMD_AUX2 0xc845#define MAX8925_CMD_VCHG 0xd046#define MAX8925_CMD_VBBATT 0xd847#define MAX8925_CMD_VMBATT 0xe048#define MAX8925_CMD_ISNS 0xe849#define MAX8925_CMD_THM 0xf050#define MAX8925_CMD_TDIE 0xf851 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 } else330 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 else410 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 is416 * connected to MBDET pin of MAX8925. It could be used to417 * 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 else423 info->bat_online = 1;424 if (ret & MAX8925_CHG_AC_RANGE_MASK)425 info->ac_online = 1;426 else427 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_OF453static 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#else497static struct max8925_power_pdata *498max8925_power_dt_init(struct platform_device *pdev)499{500 return pdev->dev.platform_data;501}502#endif503 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 511 pdata = max8925_power_dt_init(pdev);512 if (!pdata) {513 dev_err(&pdev->dev, "platform data isn't assigned to "514 "power supply\n");515 return -EINVAL;516 }517 518 info = devm_kzalloc(&pdev->dev, sizeof(struct max8925_power_info),519 GFP_KERNEL);520 if (!info)521 return -ENOMEM;522 info->chip = chip;523 info->gpm = chip->i2c;524 info->adc = chip->adc;525 platform_set_drvdata(pdev, info);526 527 psy_cfg.supplied_to = pdata->supplied_to;528 psy_cfg.num_supplicants = pdata->num_supplicants;529 530 info->ac = devm_power_supply_register(&pdev->dev, &ac_desc, &psy_cfg);531 if (IS_ERR(info->ac))532 return PTR_ERR(info->ac);533 info->ac->dev.parent = &pdev->dev;534 535 info->usb = devm_power_supply_register(&pdev->dev, &usb_desc, &psy_cfg);536 if (IS_ERR(info->usb))537 return PTR_ERR(info->usb);538 info->usb->dev.parent = &pdev->dev;539 540 info->battery = devm_power_supply_register(&pdev->dev, &battery_desc, NULL);541 if (IS_ERR(info->battery))542 return PTR_ERR(info->battery);543 info->battery->dev.parent = &pdev->dev;544 545 info->batt_detect = pdata->batt_detect;546 info->topoff_threshold = pdata->topoff_threshold;547 info->fast_charge = pdata->fast_charge;548 info->set_charger = pdata->set_charger;549 info->no_temp_support = pdata->no_temp_support;550 info->no_insert_detect = pdata->no_insert_detect;551 552 max8925_init_charger(chip, info);553 return 0;554}555 556static void max8925_power_remove(struct platform_device *pdev)557{558 struct max8925_power_info *info = platform_get_drvdata(pdev);559 560 if (info)561 max8925_deinit_charger(info);562}563 564static struct platform_driver max8925_power_driver = {565 .probe = max8925_power_probe,566 .remove_new = max8925_power_remove,567 .driver = {568 .name = "max8925-power",569 },570};571 572module_platform_driver(max8925_power_driver);573 574MODULE_LICENSE("GPL");575MODULE_DESCRIPTION("Power supply driver for MAX8925");576MODULE_ALIAS("platform:max8925-power");577