1137 lines · c
1/*2 * Battery power supply driver for X-Powers AXP20X and AXP22X PMICs3 *4 * Copyright 2016 Free Electrons NextThing Co.5 * Quentin Schulz <quentin.schulz@free-electrons.com>6 *7 * This driver is based on a previous upstreaming attempt by:8 * Bruno Prémont <bonbons@linux-vserver.org>9 *10 * This file is subject to the terms and conditions of the GNU General11 * Public License. See the file "COPYING" in the main directory of this12 * archive for more details.13 *14 * This program is distributed in the hope that it will be useful,15 * but WITHOUT ANY WARRANTY; without even the implied warranty of16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the17 * GNU General Public License for more details.18 */19 20#include <linux/bitfield.h>21#include <linux/err.h>22#include <linux/interrupt.h>23#include <linux/irq.h>24#include <linux/module.h>25#include <linux/of.h>26#include <linux/platform_device.h>27#include <linux/power_supply.h>28#include <linux/regmap.h>29#include <linux/slab.h>30#include <linux/time.h>31#include <linux/iio/iio.h>32#include <linux/iio/consumer.h>33#include <linux/mfd/axp20x.h>34 35#define AXP20X_PWR_STATUS_BAT_CHARGING BIT(2)36#define AXP717_PWR_STATUS_MASK GENMASK(6, 5)37#define AXP717_PWR_STATUS_BAT_STANDBY 038#define AXP717_PWR_STATUS_BAT_CHRG 139#define AXP717_PWR_STATUS_BAT_DISCHRG 240 41#define AXP20X_PWR_OP_BATT_PRESENT BIT(5)42#define AXP20X_PWR_OP_BATT_ACTIVATED BIT(3)43#define AXP717_PWR_OP_BATT_PRESENT BIT(3)44 45#define AXP717_BATT_PMU_FAULT_MASK GENMASK(2, 0)46#define AXP717_BATT_UVLO_2_5V BIT(2)47#define AXP717_BATT_OVER_TEMP BIT(1)48#define AXP717_BATT_UNDER_TEMP BIT(0)49 50#define AXP209_FG_PERCENT GENMASK(6, 0)51#define AXP22X_FG_VALID BIT(7)52 53#define AXP20X_CHRG_CTRL1_ENABLE BIT(7)54#define AXP20X_CHRG_CTRL1_TGT_VOLT GENMASK(6, 5)55#define AXP20X_CHRG_CTRL1_TGT_4_1V (0 << 5)56#define AXP20X_CHRG_CTRL1_TGT_4_15V (1 << 5)57#define AXP20X_CHRG_CTRL1_TGT_4_2V (2 << 5)58#define AXP20X_CHRG_CTRL1_TGT_4_36V (3 << 5)59 60#define AXP22X_CHRG_CTRL1_TGT_4_22V (1 << 5)61#define AXP22X_CHRG_CTRL1_TGT_4_24V (3 << 5)62 63#define AXP717_CHRG_ENABLE BIT(1)64#define AXP717_CHRG_CV_VOLT_MASK GENMASK(2, 0)65#define AXP717_CHRG_CV_4_0V 066#define AXP717_CHRG_CV_4_1V 167#define AXP717_CHRG_CV_4_2V 268#define AXP717_CHRG_CV_4_35V 369#define AXP717_CHRG_CV_4_4V 470/* Values 5 and 6 reserved. */71#define AXP717_CHRG_CV_5_0V 772 73#define AXP813_CHRG_CTRL1_TGT_4_35V (3 << 5)74 75#define AXP20X_CHRG_CTRL1_TGT_CURR GENMASK(3, 0)76#define AXP717_ICC_CHARGER_LIM_MASK GENMASK(5, 0)77 78#define AXP717_ITERM_CHG_LIM_MASK GENMASK(3, 0)79#define AXP717_ITERM_CC_STEP 6400080 81#define AXP20X_V_OFF_MASK GENMASK(2, 0)82#define AXP717_V_OFF_MASK GENMASK(6, 4)83 84#define AXP717_BAT_VMIN_MIN_UV 260000085#define AXP717_BAT_VMIN_MAX_UV 330000086#define AXP717_BAT_VMIN_STEP 10000087#define AXP717_BAT_CV_MIN_UV 400000088#define AXP717_BAT_CV_MAX_UV 500000089#define AXP717_BAT_CC_MIN_UA 090#define AXP717_BAT_CC_MAX_UA 300800091 92struct axp20x_batt_ps;93 94struct axp_data {95 int ccc_scale;96 int ccc_offset;97 unsigned int ccc_reg;98 unsigned int ccc_mask;99 bool has_fg_valid;100 const struct power_supply_desc *bat_ps_desc;101 int (*get_max_voltage)(struct axp20x_batt_ps *batt, int *val);102 int (*set_max_voltage)(struct axp20x_batt_ps *batt, int val);103 int (*cfg_iio_chan)(struct platform_device *pdev,104 struct axp20x_batt_ps *axp_batt);105 void (*set_bat_info)(struct platform_device *pdev,106 struct axp20x_batt_ps *axp_batt,107 struct power_supply_battery_info *info);108};109 110struct axp20x_batt_ps {111 struct regmap *regmap;112 struct power_supply *batt;113 struct device *dev;114 struct iio_channel *batt_chrg_i;115 struct iio_channel *batt_dischrg_i;116 struct iio_channel *batt_v;117 /* Maximum constant charge current */118 unsigned int max_ccc;119 const struct axp_data *data;120};121 122static int axp20x_battery_get_max_voltage(struct axp20x_batt_ps *axp20x_batt,123 int *val)124{125 int ret, reg;126 127 ret = regmap_read(axp20x_batt->regmap, AXP20X_CHRG_CTRL1, ®);128 if (ret)129 return ret;130 131 switch (reg & AXP20X_CHRG_CTRL1_TGT_VOLT) {132 case AXP20X_CHRG_CTRL1_TGT_4_1V:133 *val = 4100000;134 break;135 case AXP20X_CHRG_CTRL1_TGT_4_15V:136 *val = 4150000;137 break;138 case AXP20X_CHRG_CTRL1_TGT_4_2V:139 *val = 4200000;140 break;141 case AXP20X_CHRG_CTRL1_TGT_4_36V:142 *val = 4360000;143 break;144 default:145 return -EINVAL;146 }147 148 return 0;149}150 151static int axp22x_battery_get_max_voltage(struct axp20x_batt_ps *axp20x_batt,152 int *val)153{154 int ret, reg;155 156 ret = regmap_read(axp20x_batt->regmap, AXP20X_CHRG_CTRL1, ®);157 if (ret)158 return ret;159 160 switch (reg & AXP20X_CHRG_CTRL1_TGT_VOLT) {161 case AXP20X_CHRG_CTRL1_TGT_4_1V:162 *val = 4100000;163 break;164 case AXP20X_CHRG_CTRL1_TGT_4_2V:165 *val = 4200000;166 break;167 case AXP22X_CHRG_CTRL1_TGT_4_22V:168 *val = 4220000;169 break;170 case AXP22X_CHRG_CTRL1_TGT_4_24V:171 *val = 4240000;172 break;173 default:174 return -EINVAL;175 }176 177 return 0;178}179 180static int axp717_battery_get_max_voltage(struct axp20x_batt_ps *axp20x_batt,181 int *val)182{183 int ret, reg;184 185 ret = regmap_read(axp20x_batt->regmap, AXP717_CV_CHG_SET, ®);186 if (ret)187 return ret;188 189 switch (reg & AXP717_CHRG_CV_VOLT_MASK) {190 case AXP717_CHRG_CV_4_0V:191 *val = 4000000;192 return 0;193 case AXP717_CHRG_CV_4_1V:194 *val = 4100000;195 return 0;196 case AXP717_CHRG_CV_4_2V:197 *val = 4200000;198 return 0;199 case AXP717_CHRG_CV_4_35V:200 *val = 4350000;201 return 0;202 case AXP717_CHRG_CV_4_4V:203 *val = 4400000;204 return 0;205 case AXP717_CHRG_CV_5_0V:206 *val = 5000000;207 return 0;208 default:209 return -EINVAL;210 }211}212 213static int axp813_battery_get_max_voltage(struct axp20x_batt_ps *axp20x_batt,214 int *val)215{216 int ret, reg;217 218 ret = regmap_read(axp20x_batt->regmap, AXP20X_CHRG_CTRL1, ®);219 if (ret)220 return ret;221 222 switch (reg & AXP20X_CHRG_CTRL1_TGT_VOLT) {223 case AXP20X_CHRG_CTRL1_TGT_4_1V:224 *val = 4100000;225 break;226 case AXP20X_CHRG_CTRL1_TGT_4_15V:227 *val = 4150000;228 break;229 case AXP20X_CHRG_CTRL1_TGT_4_2V:230 *val = 4200000;231 break;232 case AXP813_CHRG_CTRL1_TGT_4_35V:233 *val = 4350000;234 break;235 default:236 return -EINVAL;237 }238 239 return 0;240}241 242static int axp20x_get_constant_charge_current(struct axp20x_batt_ps *axp,243 int *val)244{245 int ret;246 247 ret = regmap_read(axp->regmap, AXP20X_CHRG_CTRL1, val);248 if (ret)249 return ret;250 251 *val &= AXP20X_CHRG_CTRL1_TGT_CURR;252 253 *val = *val * axp->data->ccc_scale + axp->data->ccc_offset;254 255 return 0;256}257 258static int axp717_get_constant_charge_current(struct axp20x_batt_ps *axp,259 int *val)260{261 int ret;262 263 ret = regmap_read(axp->regmap, AXP717_ICC_CHG_SET, val);264 if (ret)265 return ret;266 267 *val = FIELD_GET(AXP717_ICC_CHARGER_LIM_MASK, *val) *268 axp->data->ccc_scale;269 270 return 0;271}272 273static int axp20x_battery_get_prop(struct power_supply *psy,274 enum power_supply_property psp,275 union power_supply_propval *val)276{277 struct axp20x_batt_ps *axp20x_batt = power_supply_get_drvdata(psy);278 int ret = 0, reg, val1;279 280 switch (psp) {281 case POWER_SUPPLY_PROP_PRESENT:282 case POWER_SUPPLY_PROP_ONLINE:283 ret = regmap_read(axp20x_batt->regmap, AXP20X_PWR_OP_MODE,284 ®);285 if (ret)286 return ret;287 288 val->intval = !!(reg & AXP20X_PWR_OP_BATT_PRESENT);289 break;290 291 case POWER_SUPPLY_PROP_STATUS:292 ret = regmap_read(axp20x_batt->regmap, AXP20X_PWR_INPUT_STATUS,293 ®);294 if (ret)295 return ret;296 297 if (reg & AXP20X_PWR_STATUS_BAT_CHARGING) {298 val->intval = POWER_SUPPLY_STATUS_CHARGING;299 return 0;300 }301 302 ret = iio_read_channel_processed(axp20x_batt->batt_dischrg_i,303 &val1);304 if (ret)305 return ret;306 307 if (val1) {308 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;309 return 0;310 }311 312 ret = regmap_read(axp20x_batt->regmap, AXP20X_FG_RES, &val1);313 if (ret)314 return ret;315 316 /*317 * Fuel Gauge data takes 7 bits but the stored value seems to be318 * directly the raw percentage without any scaling to 7 bits.319 */320 if ((val1 & AXP209_FG_PERCENT) == 100)321 val->intval = POWER_SUPPLY_STATUS_FULL;322 else323 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;324 break;325 326 case POWER_SUPPLY_PROP_HEALTH:327 ret = regmap_read(axp20x_batt->regmap, AXP20X_PWR_OP_MODE,328 &val1);329 if (ret)330 return ret;331 332 if (val1 & AXP20X_PWR_OP_BATT_ACTIVATED) {333 val->intval = POWER_SUPPLY_HEALTH_DEAD;334 return 0;335 }336 337 val->intval = POWER_SUPPLY_HEALTH_GOOD;338 break;339 340 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:341 ret = axp20x_get_constant_charge_current(axp20x_batt,342 &val->intval);343 if (ret)344 return ret;345 break;346 347 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:348 val->intval = axp20x_batt->max_ccc;349 break;350 351 case POWER_SUPPLY_PROP_CURRENT_NOW:352 ret = regmap_read(axp20x_batt->regmap, AXP20X_PWR_INPUT_STATUS,353 ®);354 if (ret)355 return ret;356 357 if (reg & AXP20X_PWR_STATUS_BAT_CHARGING) {358 ret = iio_read_channel_processed(axp20x_batt->batt_chrg_i, &val->intval);359 } else {360 ret = iio_read_channel_processed(axp20x_batt->batt_dischrg_i, &val1);361 val->intval = -val1;362 }363 if (ret)364 return ret;365 366 /* IIO framework gives mA but Power Supply framework gives uA */367 val->intval *= 1000;368 break;369 370 case POWER_SUPPLY_PROP_CAPACITY:371 /* When no battery is present, return capacity is 100% */372 ret = regmap_read(axp20x_batt->regmap, AXP20X_PWR_OP_MODE,373 ®);374 if (ret)375 return ret;376 377 if (!(reg & AXP20X_PWR_OP_BATT_PRESENT)) {378 val->intval = 100;379 return 0;380 }381 382 ret = regmap_read(axp20x_batt->regmap, AXP20X_FG_RES, ®);383 if (ret)384 return ret;385 386 if (axp20x_batt->data->has_fg_valid && !(reg & AXP22X_FG_VALID))387 return -EINVAL;388 389 /*390 * Fuel Gauge data takes 7 bits but the stored value seems to be391 * directly the raw percentage without any scaling to 7 bits.392 */393 val->intval = reg & AXP209_FG_PERCENT;394 break;395 396 case POWER_SUPPLY_PROP_VOLTAGE_MAX:397 return axp20x_batt->data->get_max_voltage(axp20x_batt,398 &val->intval);399 400 case POWER_SUPPLY_PROP_VOLTAGE_MIN:401 ret = regmap_read(axp20x_batt->regmap, AXP20X_V_OFF, ®);402 if (ret)403 return ret;404 405 val->intval = 2600000 + 100000 * (reg & AXP20X_V_OFF_MASK);406 break;407 408 case POWER_SUPPLY_PROP_VOLTAGE_NOW:409 ret = iio_read_channel_processed(axp20x_batt->batt_v,410 &val->intval);411 if (ret)412 return ret;413 414 /* IIO framework gives mV but Power Supply framework gives uV */415 val->intval *= 1000;416 break;417 418 default:419 return -EINVAL;420 }421 422 return 0;423}424 425static int axp717_battery_get_prop(struct power_supply *psy,426 enum power_supply_property psp,427 union power_supply_propval *val)428{429 struct axp20x_batt_ps *axp20x_batt = power_supply_get_drvdata(psy);430 int ret = 0, reg;431 432 switch (psp) {433 case POWER_SUPPLY_PROP_PRESENT:434 case POWER_SUPPLY_PROP_ONLINE:435 ret = regmap_read(axp20x_batt->regmap, AXP717_ON_INDICATE,436 ®);437 if (ret)438 return ret;439 440 val->intval = FIELD_GET(AXP717_PWR_OP_BATT_PRESENT, reg);441 return 0;442 443 case POWER_SUPPLY_PROP_STATUS:444 ret = regmap_read(axp20x_batt->regmap, AXP717_PMU_STATUS_2,445 ®);446 if (ret)447 return ret;448 449 switch (FIELD_GET(AXP717_PWR_STATUS_MASK, reg)) {450 case AXP717_PWR_STATUS_BAT_STANDBY:451 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;452 return 0;453 454 case AXP717_PWR_STATUS_BAT_CHRG:455 val->intval = POWER_SUPPLY_STATUS_CHARGING;456 return 0;457 458 case AXP717_PWR_STATUS_BAT_DISCHRG:459 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;460 return 0;461 462 default:463 val->intval = POWER_SUPPLY_STATUS_UNKNOWN;464 return 0;465 }466 467 /*468 * If a fault is detected it must also be cleared; if the469 * condition persists it should reappear (This is an470 * assumption, it's actually not documented). A restart was471 * not sufficient to clear the bit in testing despite the472 * register listed as POR.473 */474 case POWER_SUPPLY_PROP_HEALTH:475 ret = regmap_read(axp20x_batt->regmap, AXP717_PMU_FAULT,476 ®);477 if (ret)478 return ret;479 480 switch (reg & AXP717_BATT_PMU_FAULT_MASK) {481 case AXP717_BATT_UVLO_2_5V:482 val->intval = POWER_SUPPLY_HEALTH_DEAD;483 regmap_update_bits(axp20x_batt->regmap,484 AXP717_PMU_FAULT,485 AXP717_BATT_UVLO_2_5V,486 AXP717_BATT_UVLO_2_5V);487 return 0;488 489 case AXP717_BATT_OVER_TEMP:490 val->intval = POWER_SUPPLY_HEALTH_HOT;491 regmap_update_bits(axp20x_batt->regmap,492 AXP717_PMU_FAULT,493 AXP717_BATT_OVER_TEMP,494 AXP717_BATT_OVER_TEMP);495 return 0;496 497 case AXP717_BATT_UNDER_TEMP:498 val->intval = POWER_SUPPLY_HEALTH_COLD;499 regmap_update_bits(axp20x_batt->regmap,500 AXP717_PMU_FAULT,501 AXP717_BATT_UNDER_TEMP,502 AXP717_BATT_UNDER_TEMP);503 return 0;504 505 default:506 val->intval = POWER_SUPPLY_HEALTH_GOOD;507 return 0;508 }509 510 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:511 ret = axp717_get_constant_charge_current(axp20x_batt,512 &val->intval);513 if (ret)514 return ret;515 return 0;516 517 case POWER_SUPPLY_PROP_CURRENT_NOW:518 /*519 * The offset of this value is currently unknown and is520 * not documented in the datasheet. Based on521 * observation it's assumed to be somewhere around522 * 450ma. I will leave the value raw for now.523 */524 ret = iio_read_channel_processed(axp20x_batt->batt_chrg_i, &val->intval);525 if (ret)526 return ret;527 /* IIO framework gives mA but Power Supply framework gives uA */528 val->intval *= 1000;529 return 0;530 531 case POWER_SUPPLY_PROP_CAPACITY:532 ret = regmap_read(axp20x_batt->regmap, AXP717_ON_INDICATE,533 ®);534 if (ret)535 return ret;536 537 if (!FIELD_GET(AXP717_PWR_OP_BATT_PRESENT, reg))538 return -ENODEV;539 540 ret = regmap_read(axp20x_batt->regmap,541 AXP717_BATT_PERCENT_DATA, ®);542 if (ret)543 return ret;544 545 /*546 * Fuel Gauge data takes 7 bits but the stored value seems to be547 * directly the raw percentage without any scaling to 7 bits.548 */549 val->intval = reg & AXP209_FG_PERCENT;550 return 0;551 552 case POWER_SUPPLY_PROP_VOLTAGE_MAX:553 return axp20x_batt->data->get_max_voltage(axp20x_batt,554 &val->intval);555 556 case POWER_SUPPLY_PROP_VOLTAGE_MIN:557 ret = regmap_read(axp20x_batt->regmap,558 AXP717_VSYS_V_POWEROFF, ®);559 if (ret)560 return ret;561 562 val->intval = AXP717_BAT_VMIN_MIN_UV + AXP717_BAT_VMIN_STEP *563 (reg & AXP717_V_OFF_MASK);564 return 0;565 566 case POWER_SUPPLY_PROP_VOLTAGE_NOW:567 ret = iio_read_channel_processed(axp20x_batt->batt_v,568 &val->intval);569 if (ret)570 return ret;571 572 /* IIO framework gives mV but Power Supply framework gives uV */573 val->intval *= 1000;574 return 0;575 576 case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:577 ret = regmap_read(axp20x_batt->regmap,578 AXP717_ITERM_CHG_SET, ®);579 if (ret)580 return ret;581 582 val->intval = (reg & AXP717_ITERM_CHG_LIM_MASK) * AXP717_ITERM_CC_STEP;583 return 0;584 585 default:586 return -EINVAL;587 }588}589 590static int axp22x_battery_set_max_voltage(struct axp20x_batt_ps *axp20x_batt,591 int val)592{593 switch (val) {594 case 4100000:595 val = AXP20X_CHRG_CTRL1_TGT_4_1V;596 break;597 598 case 4200000:599 val = AXP20X_CHRG_CTRL1_TGT_4_2V;600 break;601 602 default:603 /*604 * AXP20x max voltage can be set to 4.36V and AXP22X max voltage605 * can be set to 4.22V and 4.24V, but these voltages are too606 * high for Lithium based batteries (AXP PMICs are supposed to607 * be used with these kinds of battery).608 */609 return -EINVAL;610 }611 612 return regmap_update_bits(axp20x_batt->regmap, AXP20X_CHRG_CTRL1,613 AXP20X_CHRG_CTRL1_TGT_VOLT, val);614}615 616static int axp20x_battery_set_max_voltage(struct axp20x_batt_ps *axp20x_batt,617 int val)618{619 switch (val) {620 case 4100000:621 val = AXP20X_CHRG_CTRL1_TGT_4_1V;622 break;623 624 case 4150000:625 val = AXP20X_CHRG_CTRL1_TGT_4_15V;626 break;627 628 case 4200000:629 val = AXP20X_CHRG_CTRL1_TGT_4_2V;630 break;631 632 default:633 /*634 * AXP20x max voltage can be set to 4.36V and AXP22X max voltage635 * can be set to 4.22V and 4.24V, but these voltages are too636 * high for Lithium based batteries (AXP PMICs are supposed to637 * be used with these kinds of battery).638 */639 return -EINVAL;640 }641 642 return regmap_update_bits(axp20x_batt->regmap, AXP20X_CHRG_CTRL1,643 AXP20X_CHRG_CTRL1_TGT_VOLT, val);644}645 646static int axp717_battery_set_max_voltage(struct axp20x_batt_ps *axp20x_batt,647 int val)648{649 switch (val) {650 case 4000000:651 val = AXP717_CHRG_CV_4_0V;652 break;653 654 case 4100000:655 val = AXP717_CHRG_CV_4_1V;656 break;657 658 case 4200000:659 val = AXP717_CHRG_CV_4_2V;660 break;661 662 default:663 /*664 * AXP717 can go up to 4.35, 4.4, and 5.0 volts which665 * seem too high for lithium batteries, so do not allow.666 */667 return -EINVAL;668 }669 670 return regmap_update_bits(axp20x_batt->regmap,671 AXP717_CV_CHG_SET,672 AXP717_CHRG_CV_VOLT_MASK, val);673}674 675static int axp20x_set_constant_charge_current(struct axp20x_batt_ps *axp_batt,676 int charge_current)677{678 if (charge_current > axp_batt->max_ccc)679 return -EINVAL;680 681 charge_current = (charge_current - axp_batt->data->ccc_offset) /682 axp_batt->data->ccc_scale;683 684 if (charge_current > AXP20X_CHRG_CTRL1_TGT_CURR || charge_current < 0)685 return -EINVAL;686 687 return regmap_update_bits(axp_batt->regmap, AXP20X_CHRG_CTRL1,688 AXP20X_CHRG_CTRL1_TGT_CURR, charge_current);689}690 691static int axp717_set_constant_charge_current(struct axp20x_batt_ps *axp,692 int charge_current)693{694 int val;695 696 if (charge_current > axp->max_ccc)697 return -EINVAL;698 699 if (charge_current > AXP717_BAT_CC_MAX_UA || charge_current < 0)700 return -EINVAL;701 702 val = (charge_current - axp->data->ccc_offset) /703 axp->data->ccc_scale;704 705 return regmap_update_bits(axp->regmap, AXP717_ICC_CHG_SET,706 AXP717_ICC_CHARGER_LIM_MASK, val);707}708 709static int axp20x_set_max_constant_charge_current(struct axp20x_batt_ps *axp,710 int charge_current)711{712 bool lower_max = false;713 714 charge_current = (charge_current - axp->data->ccc_offset) /715 axp->data->ccc_scale;716 717 if (charge_current > AXP20X_CHRG_CTRL1_TGT_CURR || charge_current < 0)718 return -EINVAL;719 720 charge_current = charge_current * axp->data->ccc_scale +721 axp->data->ccc_offset;722 723 if (charge_current > axp->max_ccc)724 dev_warn(axp->dev,725 "Setting max constant charge current higher than previously defined. Note that increasing the constant charge current may damage your battery.\n");726 else727 lower_max = true;728 729 axp->max_ccc = charge_current;730 731 if (lower_max) {732 int current_cc;733 734 axp20x_get_constant_charge_current(axp, ¤t_cc);735 if (current_cc > charge_current)736 axp20x_set_constant_charge_current(axp, charge_current);737 }738 739 return 0;740}741static int axp20x_set_voltage_min_design(struct axp20x_batt_ps *axp_batt,742 int min_voltage)743{744 int val1 = (min_voltage - 2600000) / 100000;745 746 if (val1 < 0 || val1 > AXP20X_V_OFF_MASK)747 return -EINVAL;748 749 return regmap_update_bits(axp_batt->regmap, AXP20X_V_OFF,750 AXP20X_V_OFF_MASK, val1);751}752 753static int axp717_set_voltage_min_design(struct axp20x_batt_ps *axp_batt,754 int min_voltage)755{756 int val1 = (min_voltage - AXP717_BAT_VMIN_MIN_UV) / AXP717_BAT_VMIN_STEP;757 758 if (val1 < 0 || val1 > AXP717_V_OFF_MASK)759 return -EINVAL;760 761 return regmap_update_bits(axp_batt->regmap,762 AXP717_VSYS_V_POWEROFF,763 AXP717_V_OFF_MASK, val1);764}765 766static int axp20x_battery_set_prop(struct power_supply *psy,767 enum power_supply_property psp,768 const union power_supply_propval *val)769{770 struct axp20x_batt_ps *axp20x_batt = power_supply_get_drvdata(psy);771 772 switch (psp) {773 case POWER_SUPPLY_PROP_VOLTAGE_MIN:774 return axp20x_set_voltage_min_design(axp20x_batt, val->intval);775 776 case POWER_SUPPLY_PROP_VOLTAGE_MAX:777 return axp20x_batt->data->set_max_voltage(axp20x_batt, val->intval);778 779 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:780 return axp20x_set_constant_charge_current(axp20x_batt,781 val->intval);782 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:783 return axp20x_set_max_constant_charge_current(axp20x_batt,784 val->intval);785 case POWER_SUPPLY_PROP_STATUS:786 switch (val->intval) {787 case POWER_SUPPLY_STATUS_CHARGING:788 return regmap_update_bits(axp20x_batt->regmap, AXP20X_CHRG_CTRL1,789 AXP20X_CHRG_CTRL1_ENABLE, AXP20X_CHRG_CTRL1_ENABLE);790 791 case POWER_SUPPLY_STATUS_DISCHARGING:792 case POWER_SUPPLY_STATUS_NOT_CHARGING:793 return regmap_update_bits(axp20x_batt->regmap, AXP20X_CHRG_CTRL1,794 AXP20X_CHRG_CTRL1_ENABLE, 0);795 }796 fallthrough;797 default:798 return -EINVAL;799 }800}801 802static int axp717_battery_set_prop(struct power_supply *psy,803 enum power_supply_property psp,804 const union power_supply_propval *val)805{806 struct axp20x_batt_ps *axp20x_batt = power_supply_get_drvdata(psy);807 808 switch (psp) {809 case POWER_SUPPLY_PROP_VOLTAGE_MIN:810 return axp717_set_voltage_min_design(axp20x_batt, val->intval);811 812 case POWER_SUPPLY_PROP_VOLTAGE_MAX:813 return axp20x_batt->data->set_max_voltage(axp20x_batt, val->intval);814 815 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:816 return axp717_set_constant_charge_current(axp20x_batt,817 val->intval);818 case POWER_SUPPLY_PROP_STATUS:819 switch (val->intval) {820 case POWER_SUPPLY_STATUS_CHARGING:821 return regmap_update_bits(axp20x_batt->regmap,822 AXP717_MODULE_EN_CONTROL_2,823 AXP717_CHRG_ENABLE,824 AXP717_CHRG_ENABLE);825 826 case POWER_SUPPLY_STATUS_DISCHARGING:827 case POWER_SUPPLY_STATUS_NOT_CHARGING:828 return regmap_update_bits(axp20x_batt->regmap,829 AXP717_MODULE_EN_CONTROL_2,830 AXP717_CHRG_ENABLE, 0);831 }832 return -EINVAL;833 default:834 return -EINVAL;835 }836}837 838static enum power_supply_property axp20x_battery_props[] = {839 POWER_SUPPLY_PROP_PRESENT,840 POWER_SUPPLY_PROP_ONLINE,841 POWER_SUPPLY_PROP_STATUS,842 POWER_SUPPLY_PROP_VOLTAGE_NOW,843 POWER_SUPPLY_PROP_CURRENT_NOW,844 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,845 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,846 POWER_SUPPLY_PROP_HEALTH,847 POWER_SUPPLY_PROP_VOLTAGE_MAX,848 POWER_SUPPLY_PROP_VOLTAGE_MIN,849 POWER_SUPPLY_PROP_CAPACITY,850};851 852static enum power_supply_property axp717_battery_props[] = {853 POWER_SUPPLY_PROP_PRESENT,854 POWER_SUPPLY_PROP_ONLINE,855 POWER_SUPPLY_PROP_STATUS,856 POWER_SUPPLY_PROP_VOLTAGE_NOW,857 POWER_SUPPLY_PROP_CURRENT_NOW,858 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,859 POWER_SUPPLY_PROP_HEALTH,860 POWER_SUPPLY_PROP_VOLTAGE_MAX,861 POWER_SUPPLY_PROP_VOLTAGE_MIN,862 POWER_SUPPLY_PROP_CAPACITY,863 POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,864};865 866static int axp20x_battery_prop_writeable(struct power_supply *psy,867 enum power_supply_property psp)868{869 return psp == POWER_SUPPLY_PROP_STATUS ||870 psp == POWER_SUPPLY_PROP_VOLTAGE_MIN ||871 psp == POWER_SUPPLY_PROP_VOLTAGE_MAX ||872 psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT ||873 psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX;874}875 876static int axp717_battery_prop_writeable(struct power_supply *psy,877 enum power_supply_property psp)878{879 return psp == POWER_SUPPLY_PROP_STATUS ||880 psp == POWER_SUPPLY_PROP_VOLTAGE_MIN ||881 psp == POWER_SUPPLY_PROP_VOLTAGE_MAX ||882 psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX;883}884 885static const struct power_supply_desc axp209_batt_ps_desc = {886 .name = "axp20x-battery",887 .type = POWER_SUPPLY_TYPE_BATTERY,888 .properties = axp20x_battery_props,889 .num_properties = ARRAY_SIZE(axp20x_battery_props),890 .property_is_writeable = axp20x_battery_prop_writeable,891 .get_property = axp20x_battery_get_prop,892 .set_property = axp20x_battery_set_prop,893};894 895static const struct power_supply_desc axp717_batt_ps_desc = {896 .name = "axp20x-battery",897 .type = POWER_SUPPLY_TYPE_BATTERY,898 .properties = axp717_battery_props,899 .num_properties = ARRAY_SIZE(axp717_battery_props),900 .property_is_writeable = axp717_battery_prop_writeable,901 .get_property = axp717_battery_get_prop,902 .set_property = axp717_battery_set_prop,903};904 905static int axp209_bat_cfg_iio_channels(struct platform_device *pdev,906 struct axp20x_batt_ps *axp_batt)907{908 axp_batt->batt_v = devm_iio_channel_get(&pdev->dev, "batt_v");909 if (IS_ERR(axp_batt->batt_v)) {910 if (PTR_ERR(axp_batt->batt_v) == -ENODEV)911 return -EPROBE_DEFER;912 return PTR_ERR(axp_batt->batt_v);913 }914 915 axp_batt->batt_chrg_i = devm_iio_channel_get(&pdev->dev,916 "batt_chrg_i");917 if (IS_ERR(axp_batt->batt_chrg_i)) {918 if (PTR_ERR(axp_batt->batt_chrg_i) == -ENODEV)919 return -EPROBE_DEFER;920 return PTR_ERR(axp_batt->batt_chrg_i);921 }922 923 axp_batt->batt_dischrg_i = devm_iio_channel_get(&pdev->dev,924 "batt_dischrg_i");925 if (IS_ERR(axp_batt->batt_dischrg_i)) {926 if (PTR_ERR(axp_batt->batt_dischrg_i) == -ENODEV)927 return -EPROBE_DEFER;928 return PTR_ERR(axp_batt->batt_dischrg_i);929 }930 931 return 0;932}933 934static int axp717_bat_cfg_iio_channels(struct platform_device *pdev,935 struct axp20x_batt_ps *axp_batt)936{937 axp_batt->batt_v = devm_iio_channel_get(&pdev->dev, "batt_v");938 if (IS_ERR(axp_batt->batt_v)) {939 if (PTR_ERR(axp_batt->batt_v) == -ENODEV)940 return -EPROBE_DEFER;941 return PTR_ERR(axp_batt->batt_v);942 }943 944 axp_batt->batt_chrg_i = devm_iio_channel_get(&pdev->dev,945 "batt_chrg_i");946 if (IS_ERR(axp_batt->batt_chrg_i)) {947 if (PTR_ERR(axp_batt->batt_chrg_i) == -ENODEV)948 return -EPROBE_DEFER;949 return PTR_ERR(axp_batt->batt_chrg_i);950 }951 952 return 0;953}954 955static void axp209_set_battery_info(struct platform_device *pdev,956 struct axp20x_batt_ps *axp_batt,957 struct power_supply_battery_info *info)958{959 int vmin = info->voltage_min_design_uv;960 int ccc = info->constant_charge_current_max_ua;961 962 if (vmin > 0 && axp20x_set_voltage_min_design(axp_batt, vmin))963 dev_err(&pdev->dev,964 "couldn't set voltage_min_design\n");965 966 /* Set max to unverified value to be able to set CCC */967 axp_batt->max_ccc = ccc;968 969 if (ccc <= 0 || axp20x_set_constant_charge_current(axp_batt, ccc)) {970 dev_err(&pdev->dev,971 "couldn't set ccc from DT: fallback to min value\n");972 ccc = 300000;973 axp_batt->max_ccc = ccc;974 axp20x_set_constant_charge_current(axp_batt, ccc);975 }976}977 978static void axp717_set_battery_info(struct platform_device *pdev,979 struct axp20x_batt_ps *axp_batt,980 struct power_supply_battery_info *info)981{982 int vmin = info->voltage_min_design_uv;983 int vmax = info->voltage_max_design_uv;984 int ccc = info->constant_charge_current_max_ua;985 int val;986 987 if (vmin > 0 && axp717_set_voltage_min_design(axp_batt, vmin))988 dev_err(&pdev->dev,989 "couldn't set voltage_min_design\n");990 991 if (vmax > 0 && axp717_battery_set_max_voltage(axp_batt, vmax))992 dev_err(&pdev->dev,993 "couldn't set voltage_max_design\n");994 995 axp717_get_constant_charge_current(axp_batt, &val);996 axp_batt->max_ccc = ccc;997 if (ccc <= 0 || axp717_set_constant_charge_current(axp_batt, ccc)) {998 dev_err(&pdev->dev,999 "couldn't set ccc from DT: current ccc is %d\n",1000 val);1001 }1002}1003 1004static const struct axp_data axp209_data = {1005 .ccc_scale = 100000,1006 .ccc_offset = 300000,1007 .ccc_reg = AXP20X_CHRG_CTRL1,1008 .ccc_mask = AXP20X_CHRG_CTRL1_TGT_CURR,1009 .bat_ps_desc = &axp209_batt_ps_desc,1010 .get_max_voltage = axp20x_battery_get_max_voltage,1011 .set_max_voltage = axp20x_battery_set_max_voltage,1012 .cfg_iio_chan = axp209_bat_cfg_iio_channels,1013 .set_bat_info = axp209_set_battery_info,1014};1015 1016static const struct axp_data axp221_data = {1017 .ccc_scale = 150000,1018 .ccc_offset = 300000,1019 .ccc_reg = AXP20X_CHRG_CTRL1,1020 .ccc_mask = AXP20X_CHRG_CTRL1_TGT_CURR,1021 .has_fg_valid = true,1022 .bat_ps_desc = &axp209_batt_ps_desc,1023 .get_max_voltage = axp22x_battery_get_max_voltage,1024 .set_max_voltage = axp22x_battery_set_max_voltage,1025 .cfg_iio_chan = axp209_bat_cfg_iio_channels,1026 .set_bat_info = axp209_set_battery_info,1027};1028 1029static const struct axp_data axp717_data = {1030 .ccc_scale = 64000,1031 .ccc_offset = 0,1032 .ccc_reg = AXP717_ICC_CHG_SET,1033 .ccc_mask = AXP717_ICC_CHARGER_LIM_MASK,1034 .bat_ps_desc = &axp717_batt_ps_desc,1035 .get_max_voltage = axp717_battery_get_max_voltage,1036 .set_max_voltage = axp717_battery_set_max_voltage,1037 .cfg_iio_chan = axp717_bat_cfg_iio_channels,1038 .set_bat_info = axp717_set_battery_info,1039};1040 1041static const struct axp_data axp813_data = {1042 .ccc_scale = 200000,1043 .ccc_offset = 200000,1044 .ccc_reg = AXP20X_CHRG_CTRL1,1045 .ccc_mask = AXP20X_CHRG_CTRL1_TGT_CURR,1046 .has_fg_valid = true,1047 .bat_ps_desc = &axp209_batt_ps_desc,1048 .get_max_voltage = axp813_battery_get_max_voltage,1049 .set_max_voltage = axp20x_battery_set_max_voltage,1050 .cfg_iio_chan = axp209_bat_cfg_iio_channels,1051 .set_bat_info = axp209_set_battery_info,1052};1053 1054static const struct of_device_id axp20x_battery_ps_id[] = {1055 {1056 .compatible = "x-powers,axp209-battery-power-supply",1057 .data = (void *)&axp209_data,1058 }, {1059 .compatible = "x-powers,axp221-battery-power-supply",1060 .data = (void *)&axp221_data,1061 }, {1062 .compatible = "x-powers,axp717-battery-power-supply",1063 .data = (void *)&axp717_data,1064 }, {1065 .compatible = "x-powers,axp813-battery-power-supply",1066 .data = (void *)&axp813_data,1067 }, { /* sentinel */ },1068};1069MODULE_DEVICE_TABLE(of, axp20x_battery_ps_id);1070 1071static int axp20x_power_probe(struct platform_device *pdev)1072{1073 struct axp20x_batt_ps *axp20x_batt;1074 struct power_supply_config psy_cfg = {};1075 struct power_supply_battery_info *info;1076 struct device *dev = &pdev->dev;1077 int ret;1078 1079 if (!of_device_is_available(pdev->dev.of_node))1080 return -ENODEV;1081 1082 axp20x_batt = devm_kzalloc(&pdev->dev, sizeof(*axp20x_batt),1083 GFP_KERNEL);1084 if (!axp20x_batt)1085 return -ENOMEM;1086 1087 axp20x_batt->dev = &pdev->dev;1088 1089 axp20x_batt->regmap = dev_get_regmap(pdev->dev.parent, NULL);1090 platform_set_drvdata(pdev, axp20x_batt);1091 1092 psy_cfg.drv_data = axp20x_batt;1093 psy_cfg.of_node = pdev->dev.of_node;1094 1095 axp20x_batt->data = (struct axp_data *)of_device_get_match_data(dev);1096 1097 ret = axp20x_batt->data->cfg_iio_chan(pdev, axp20x_batt);1098 if (ret)1099 return ret;1100 1101 axp20x_batt->batt = devm_power_supply_register(&pdev->dev,1102 axp20x_batt->data->bat_ps_desc,1103 &psy_cfg);1104 if (IS_ERR(axp20x_batt->batt)) {1105 dev_err(&pdev->dev, "failed to register power supply: %ld\n",1106 PTR_ERR(axp20x_batt->batt));1107 return PTR_ERR(axp20x_batt->batt);1108 }1109 1110 if (!power_supply_get_battery_info(axp20x_batt->batt, &info)) {1111 axp20x_batt->data->set_bat_info(pdev, axp20x_batt, info);1112 power_supply_put_battery_info(axp20x_batt->batt, info);1113 }1114 1115 /*1116 * Update max CCC to a valid value if battery info is present or set it1117 * to current register value by default.1118 */1119 axp20x_get_constant_charge_current(axp20x_batt, &axp20x_batt->max_ccc);1120 1121 return 0;1122}1123 1124static struct platform_driver axp20x_batt_driver = {1125 .probe = axp20x_power_probe,1126 .driver = {1127 .name = "axp20x-battery-power-supply",1128 .of_match_table = axp20x_battery_ps_id,1129 },1130};1131 1132module_platform_driver(axp20x_batt_driver);1133 1134MODULE_DESCRIPTION("Battery power supply driver for AXP20X and AXP22X PMICs");1135MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>");1136MODULE_LICENSE("GPL");1137