brintos

brintos / linux-shallow public Read only

0
0
Text · 29.5 KiB · f71cc90 Raw
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, &reg);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, &reg);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, &reg);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, &reg);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				  &reg);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				  &reg);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				  &reg);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				  &reg);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, &reg);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, &reg);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				  &reg);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				  &reg);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				  &reg);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				  &reg);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, &reg);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, &reg);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, &reg);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, &current_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