cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

axp20x_battery.c (17310B)


      1/*
      2 * Battery power supply driver for X-Powers AXP20X and AXP22X PMICs
      3 *
      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 General
     11 * Public License. See the file "COPYING" in the main directory of this
     12 * 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 of
     16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     17 * GNU General Public License for more details.
     18 */
     19
     20#include <linux/err.h>
     21#include <linux/interrupt.h>
     22#include <linux/irq.h>
     23#include <linux/module.h>
     24#include <linux/of.h>
     25#include <linux/of_device.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
     37#define AXP20X_PWR_OP_BATT_PRESENT	BIT(5)
     38#define AXP20X_PWR_OP_BATT_ACTIVATED	BIT(3)
     39
     40#define AXP209_FG_PERCENT		GENMASK(6, 0)
     41#define AXP22X_FG_VALID			BIT(7)
     42
     43#define AXP20X_CHRG_CTRL1_ENABLE	BIT(7)
     44#define AXP20X_CHRG_CTRL1_TGT_VOLT	GENMASK(6, 5)
     45#define AXP20X_CHRG_CTRL1_TGT_4_1V	(0 << 5)
     46#define AXP20X_CHRG_CTRL1_TGT_4_15V	(1 << 5)
     47#define AXP20X_CHRG_CTRL1_TGT_4_2V	(2 << 5)
     48#define AXP20X_CHRG_CTRL1_TGT_4_36V	(3 << 5)
     49
     50#define AXP22X_CHRG_CTRL1_TGT_4_22V	(1 << 5)
     51#define AXP22X_CHRG_CTRL1_TGT_4_24V	(3 << 5)
     52
     53#define AXP813_CHRG_CTRL1_TGT_4_35V	(3 << 5)
     54
     55#define AXP20X_CHRG_CTRL1_TGT_CURR	GENMASK(3, 0)
     56
     57#define AXP20X_V_OFF_MASK		GENMASK(2, 0)
     58
     59struct axp20x_batt_ps;
     60
     61struct axp_data {
     62	int	ccc_scale;
     63	int	ccc_offset;
     64	bool	has_fg_valid;
     65	int	(*get_max_voltage)(struct axp20x_batt_ps *batt, int *val);
     66	int	(*set_max_voltage)(struct axp20x_batt_ps *batt, int val);
     67};
     68
     69struct axp20x_batt_ps {
     70	struct regmap *regmap;
     71	struct power_supply *batt;
     72	struct device *dev;
     73	struct iio_channel *batt_chrg_i;
     74	struct iio_channel *batt_dischrg_i;
     75	struct iio_channel *batt_v;
     76	/* Maximum constant charge current */
     77	unsigned int max_ccc;
     78	const struct axp_data	*data;
     79};
     80
     81static int axp20x_battery_get_max_voltage(struct axp20x_batt_ps *axp20x_batt,
     82					  int *val)
     83{
     84	int ret, reg;
     85
     86	ret = regmap_read(axp20x_batt->regmap, AXP20X_CHRG_CTRL1, &reg);
     87	if (ret)
     88		return ret;
     89
     90	switch (reg & AXP20X_CHRG_CTRL1_TGT_VOLT) {
     91	case AXP20X_CHRG_CTRL1_TGT_4_1V:
     92		*val = 4100000;
     93		break;
     94	case AXP20X_CHRG_CTRL1_TGT_4_15V:
     95		*val = 4150000;
     96		break;
     97	case AXP20X_CHRG_CTRL1_TGT_4_2V:
     98		*val = 4200000;
     99		break;
    100	case AXP20X_CHRG_CTRL1_TGT_4_36V:
    101		*val = 4360000;
    102		break;
    103	default:
    104		return -EINVAL;
    105	}
    106
    107	return 0;
    108}
    109
    110static int axp22x_battery_get_max_voltage(struct axp20x_batt_ps *axp20x_batt,
    111					  int *val)
    112{
    113	int ret, reg;
    114
    115	ret = regmap_read(axp20x_batt->regmap, AXP20X_CHRG_CTRL1, &reg);
    116	if (ret)
    117		return ret;
    118
    119	switch (reg & AXP20X_CHRG_CTRL1_TGT_VOLT) {
    120	case AXP20X_CHRG_CTRL1_TGT_4_1V:
    121		*val = 4100000;
    122		break;
    123	case AXP20X_CHRG_CTRL1_TGT_4_2V:
    124		*val = 4200000;
    125		break;
    126	case AXP22X_CHRG_CTRL1_TGT_4_22V:
    127		*val = 4220000;
    128		break;
    129	case AXP22X_CHRG_CTRL1_TGT_4_24V:
    130		*val = 4240000;
    131		break;
    132	default:
    133		return -EINVAL;
    134	}
    135
    136	return 0;
    137}
    138
    139static int axp813_battery_get_max_voltage(struct axp20x_batt_ps *axp20x_batt,
    140					  int *val)
    141{
    142	int ret, reg;
    143
    144	ret = regmap_read(axp20x_batt->regmap, AXP20X_CHRG_CTRL1, &reg);
    145	if (ret)
    146		return ret;
    147
    148	switch (reg & AXP20X_CHRG_CTRL1_TGT_VOLT) {
    149	case AXP20X_CHRG_CTRL1_TGT_4_1V:
    150		*val = 4100000;
    151		break;
    152	case AXP20X_CHRG_CTRL1_TGT_4_15V:
    153		*val = 4150000;
    154		break;
    155	case AXP20X_CHRG_CTRL1_TGT_4_2V:
    156		*val = 4200000;
    157		break;
    158	case AXP813_CHRG_CTRL1_TGT_4_35V:
    159		*val = 4350000;
    160		break;
    161	default:
    162		return -EINVAL;
    163	}
    164
    165	return 0;
    166}
    167
    168static int axp20x_get_constant_charge_current(struct axp20x_batt_ps *axp,
    169					      int *val)
    170{
    171	int ret;
    172
    173	ret = regmap_read(axp->regmap, AXP20X_CHRG_CTRL1, val);
    174	if (ret)
    175		return ret;
    176
    177	*val &= AXP20X_CHRG_CTRL1_TGT_CURR;
    178
    179	*val = *val * axp->data->ccc_scale + axp->data->ccc_offset;
    180
    181	return 0;
    182}
    183
    184static int axp20x_battery_get_prop(struct power_supply *psy,
    185				   enum power_supply_property psp,
    186				   union power_supply_propval *val)
    187{
    188	struct axp20x_batt_ps *axp20x_batt = power_supply_get_drvdata(psy);
    189	int ret = 0, reg, val1;
    190
    191	switch (psp) {
    192	case POWER_SUPPLY_PROP_PRESENT:
    193	case POWER_SUPPLY_PROP_ONLINE:
    194		ret = regmap_read(axp20x_batt->regmap, AXP20X_PWR_OP_MODE,
    195				  &reg);
    196		if (ret)
    197			return ret;
    198
    199		val->intval = !!(reg & AXP20X_PWR_OP_BATT_PRESENT);
    200		break;
    201
    202	case POWER_SUPPLY_PROP_STATUS:
    203		ret = regmap_read(axp20x_batt->regmap, AXP20X_PWR_INPUT_STATUS,
    204				  &reg);
    205		if (ret)
    206			return ret;
    207
    208		if (reg & AXP20X_PWR_STATUS_BAT_CHARGING) {
    209			val->intval = POWER_SUPPLY_STATUS_CHARGING;
    210			return 0;
    211		}
    212
    213		ret = iio_read_channel_processed(axp20x_batt->batt_dischrg_i,
    214						 &val1);
    215		if (ret)
    216			return ret;
    217
    218		if (val1) {
    219			val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
    220			return 0;
    221		}
    222
    223		ret = regmap_read(axp20x_batt->regmap, AXP20X_FG_RES, &val1);
    224		if (ret)
    225			return ret;
    226
    227		/*
    228		 * Fuel Gauge data takes 7 bits but the stored value seems to be
    229		 * directly the raw percentage without any scaling to 7 bits.
    230		 */
    231		if ((val1 & AXP209_FG_PERCENT) == 100)
    232			val->intval = POWER_SUPPLY_STATUS_FULL;
    233		else
    234			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
    235		break;
    236
    237	case POWER_SUPPLY_PROP_HEALTH:
    238		ret = regmap_read(axp20x_batt->regmap, AXP20X_PWR_OP_MODE,
    239				  &val1);
    240		if (ret)
    241			return ret;
    242
    243		if (val1 & AXP20X_PWR_OP_BATT_ACTIVATED) {
    244			val->intval = POWER_SUPPLY_HEALTH_DEAD;
    245			return 0;
    246		}
    247
    248		val->intval = POWER_SUPPLY_HEALTH_GOOD;
    249		break;
    250
    251	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
    252		ret = axp20x_get_constant_charge_current(axp20x_batt,
    253							 &val->intval);
    254		if (ret)
    255			return ret;
    256		break;
    257
    258	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
    259		val->intval = axp20x_batt->max_ccc;
    260		break;
    261
    262	case POWER_SUPPLY_PROP_CURRENT_NOW:
    263		ret = regmap_read(axp20x_batt->regmap, AXP20X_PWR_INPUT_STATUS,
    264				  &reg);
    265		if (ret)
    266			return ret;
    267
    268		if (reg & AXP20X_PWR_STATUS_BAT_CHARGING) {
    269			ret = iio_read_channel_processed(axp20x_batt->batt_chrg_i, &val->intval);
    270		} else {
    271			ret = iio_read_channel_processed(axp20x_batt->batt_dischrg_i, &val1);
    272			val->intval = -val1;
    273		}
    274		if (ret)
    275			return ret;
    276
    277		/* IIO framework gives mA but Power Supply framework gives uA */
    278		val->intval *= 1000;
    279		break;
    280
    281	case POWER_SUPPLY_PROP_CAPACITY:
    282		/* When no battery is present, return capacity is 100% */
    283		ret = regmap_read(axp20x_batt->regmap, AXP20X_PWR_OP_MODE,
    284				  &reg);
    285		if (ret)
    286			return ret;
    287
    288		if (!(reg & AXP20X_PWR_OP_BATT_PRESENT)) {
    289			val->intval = 100;
    290			return 0;
    291		}
    292
    293		ret = regmap_read(axp20x_batt->regmap, AXP20X_FG_RES, &reg);
    294		if (ret)
    295			return ret;
    296
    297		if (axp20x_batt->data->has_fg_valid && !(reg & AXP22X_FG_VALID))
    298			return -EINVAL;
    299
    300		/*
    301		 * Fuel Gauge data takes 7 bits but the stored value seems to be
    302		 * directly the raw percentage without any scaling to 7 bits.
    303		 */
    304		val->intval = reg & AXP209_FG_PERCENT;
    305		break;
    306
    307	case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
    308		return axp20x_batt->data->get_max_voltage(axp20x_batt,
    309							  &val->intval);
    310
    311	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
    312		ret = regmap_read(axp20x_batt->regmap, AXP20X_V_OFF, &reg);
    313		if (ret)
    314			return ret;
    315
    316		val->intval = 2600000 + 100000 * (reg & AXP20X_V_OFF_MASK);
    317		break;
    318
    319	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
    320		ret = iio_read_channel_processed(axp20x_batt->batt_v,
    321						 &val->intval);
    322		if (ret)
    323			return ret;
    324
    325		/* IIO framework gives mV but Power Supply framework gives uV */
    326		val->intval *= 1000;
    327		break;
    328
    329	default:
    330		return -EINVAL;
    331	}
    332
    333	return 0;
    334}
    335
    336static int axp22x_battery_set_max_voltage(struct axp20x_batt_ps *axp20x_batt,
    337					  int val)
    338{
    339	switch (val) {
    340	case 4100000:
    341		val = AXP20X_CHRG_CTRL1_TGT_4_1V;
    342		break;
    343
    344	case 4200000:
    345		val = AXP20X_CHRG_CTRL1_TGT_4_2V;
    346		break;
    347
    348	default:
    349		/*
    350		 * AXP20x max voltage can be set to 4.36V and AXP22X max voltage
    351		 * can be set to 4.22V and 4.24V, but these voltages are too
    352		 * high for Lithium based batteries (AXP PMICs are supposed to
    353		 * be used with these kinds of battery).
    354		 */
    355		return -EINVAL;
    356	}
    357
    358	return regmap_update_bits(axp20x_batt->regmap, AXP20X_CHRG_CTRL1,
    359				  AXP20X_CHRG_CTRL1_TGT_VOLT, val);
    360}
    361
    362static int axp20x_battery_set_max_voltage(struct axp20x_batt_ps *axp20x_batt,
    363					  int val)
    364{
    365	switch (val) {
    366	case 4100000:
    367		val = AXP20X_CHRG_CTRL1_TGT_4_1V;
    368		break;
    369
    370	case 4150000:
    371		val = AXP20X_CHRG_CTRL1_TGT_4_15V;
    372		break;
    373
    374	case 4200000:
    375		val = AXP20X_CHRG_CTRL1_TGT_4_2V;
    376		break;
    377
    378	default:
    379		/*
    380		 * AXP20x max voltage can be set to 4.36V and AXP22X max voltage
    381		 * can be set to 4.22V and 4.24V, but these voltages are too
    382		 * high for Lithium based batteries (AXP PMICs are supposed to
    383		 * be used with these kinds of battery).
    384		 */
    385		return -EINVAL;
    386	}
    387
    388	return regmap_update_bits(axp20x_batt->regmap, AXP20X_CHRG_CTRL1,
    389				  AXP20X_CHRG_CTRL1_TGT_VOLT, val);
    390}
    391
    392static int axp20x_set_constant_charge_current(struct axp20x_batt_ps *axp_batt,
    393					      int charge_current)
    394{
    395	if (charge_current > axp_batt->max_ccc)
    396		return -EINVAL;
    397
    398	charge_current = (charge_current - axp_batt->data->ccc_offset) /
    399		axp_batt->data->ccc_scale;
    400
    401	if (charge_current > AXP20X_CHRG_CTRL1_TGT_CURR || charge_current < 0)
    402		return -EINVAL;
    403
    404	return regmap_update_bits(axp_batt->regmap, AXP20X_CHRG_CTRL1,
    405				  AXP20X_CHRG_CTRL1_TGT_CURR, charge_current);
    406}
    407
    408static int axp20x_set_max_constant_charge_current(struct axp20x_batt_ps *axp,
    409						  int charge_current)
    410{
    411	bool lower_max = false;
    412
    413	charge_current = (charge_current - axp->data->ccc_offset) /
    414		axp->data->ccc_scale;
    415
    416	if (charge_current > AXP20X_CHRG_CTRL1_TGT_CURR || charge_current < 0)
    417		return -EINVAL;
    418
    419	charge_current = charge_current * axp->data->ccc_scale +
    420		axp->data->ccc_offset;
    421
    422	if (charge_current > axp->max_ccc)
    423		dev_warn(axp->dev,
    424			 "Setting max constant charge current higher than previously defined. Note that increasing the constant charge current may damage your battery.\n");
    425	else
    426		lower_max = true;
    427
    428	axp->max_ccc = charge_current;
    429
    430	if (lower_max) {
    431		int current_cc;
    432
    433		axp20x_get_constant_charge_current(axp, &current_cc);
    434		if (current_cc > charge_current)
    435			axp20x_set_constant_charge_current(axp, charge_current);
    436	}
    437
    438	return 0;
    439}
    440static int axp20x_set_voltage_min_design(struct axp20x_batt_ps *axp_batt,
    441					 int min_voltage)
    442{
    443	int val1 = (min_voltage - 2600000) / 100000;
    444
    445	if (val1 < 0 || val1 > AXP20X_V_OFF_MASK)
    446		return -EINVAL;
    447
    448	return regmap_update_bits(axp_batt->regmap, AXP20X_V_OFF,
    449				  AXP20X_V_OFF_MASK, val1);
    450}
    451
    452static int axp20x_battery_set_prop(struct power_supply *psy,
    453				   enum power_supply_property psp,
    454				   const union power_supply_propval *val)
    455{
    456	struct axp20x_batt_ps *axp20x_batt = power_supply_get_drvdata(psy);
    457
    458	switch (psp) {
    459	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
    460		return axp20x_set_voltage_min_design(axp20x_batt, val->intval);
    461
    462	case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
    463		return axp20x_batt->data->set_max_voltage(axp20x_batt, val->intval);
    464
    465	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
    466		return axp20x_set_constant_charge_current(axp20x_batt,
    467							  val->intval);
    468	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
    469		return axp20x_set_max_constant_charge_current(axp20x_batt,
    470							      val->intval);
    471	case POWER_SUPPLY_PROP_STATUS:
    472		switch (val->intval) {
    473		case POWER_SUPPLY_STATUS_CHARGING:
    474			return regmap_update_bits(axp20x_batt->regmap, AXP20X_CHRG_CTRL1,
    475				AXP20X_CHRG_CTRL1_ENABLE, AXP20X_CHRG_CTRL1_ENABLE);
    476
    477		case POWER_SUPPLY_STATUS_DISCHARGING:
    478		case POWER_SUPPLY_STATUS_NOT_CHARGING:
    479			return regmap_update_bits(axp20x_batt->regmap, AXP20X_CHRG_CTRL1,
    480				AXP20X_CHRG_CTRL1_ENABLE, 0);
    481		}
    482		fallthrough;
    483	default:
    484		return -EINVAL;
    485	}
    486}
    487
    488static enum power_supply_property axp20x_battery_props[] = {
    489	POWER_SUPPLY_PROP_PRESENT,
    490	POWER_SUPPLY_PROP_ONLINE,
    491	POWER_SUPPLY_PROP_STATUS,
    492	POWER_SUPPLY_PROP_VOLTAGE_NOW,
    493	POWER_SUPPLY_PROP_CURRENT_NOW,
    494	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
    495	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
    496	POWER_SUPPLY_PROP_HEALTH,
    497	POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
    498	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
    499	POWER_SUPPLY_PROP_CAPACITY,
    500};
    501
    502static int axp20x_battery_prop_writeable(struct power_supply *psy,
    503					 enum power_supply_property psp)
    504{
    505	return psp == POWER_SUPPLY_PROP_STATUS ||
    506	       psp == POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN ||
    507	       psp == POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN ||
    508	       psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT ||
    509	       psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX;
    510}
    511
    512static const struct power_supply_desc axp20x_batt_ps_desc = {
    513	.name = "axp20x-battery",
    514	.type = POWER_SUPPLY_TYPE_BATTERY,
    515	.properties = axp20x_battery_props,
    516	.num_properties = ARRAY_SIZE(axp20x_battery_props),
    517	.property_is_writeable = axp20x_battery_prop_writeable,
    518	.get_property = axp20x_battery_get_prop,
    519	.set_property = axp20x_battery_set_prop,
    520};
    521
    522static const struct axp_data axp209_data = {
    523	.ccc_scale = 100000,
    524	.ccc_offset = 300000,
    525	.get_max_voltage = axp20x_battery_get_max_voltage,
    526	.set_max_voltage = axp20x_battery_set_max_voltage,
    527};
    528
    529static const struct axp_data axp221_data = {
    530	.ccc_scale = 150000,
    531	.ccc_offset = 300000,
    532	.has_fg_valid = true,
    533	.get_max_voltage = axp22x_battery_get_max_voltage,
    534	.set_max_voltage = axp22x_battery_set_max_voltage,
    535};
    536
    537static const struct axp_data axp813_data = {
    538	.ccc_scale = 200000,
    539	.ccc_offset = 200000,
    540	.has_fg_valid = true,
    541	.get_max_voltage = axp813_battery_get_max_voltage,
    542	.set_max_voltage = axp20x_battery_set_max_voltage,
    543};
    544
    545static const struct of_device_id axp20x_battery_ps_id[] = {
    546	{
    547		.compatible = "x-powers,axp209-battery-power-supply",
    548		.data = (void *)&axp209_data,
    549	}, {
    550		.compatible = "x-powers,axp221-battery-power-supply",
    551		.data = (void *)&axp221_data,
    552	}, {
    553		.compatible = "x-powers,axp813-battery-power-supply",
    554		.data = (void *)&axp813_data,
    555	}, { /* sentinel */ },
    556};
    557MODULE_DEVICE_TABLE(of, axp20x_battery_ps_id);
    558
    559static int axp20x_power_probe(struct platform_device *pdev)
    560{
    561	struct axp20x_batt_ps *axp20x_batt;
    562	struct power_supply_config psy_cfg = {};
    563	struct power_supply_battery_info *info;
    564	struct device *dev = &pdev->dev;
    565
    566	if (!of_device_is_available(pdev->dev.of_node))
    567		return -ENODEV;
    568
    569	axp20x_batt = devm_kzalloc(&pdev->dev, sizeof(*axp20x_batt),
    570				   GFP_KERNEL);
    571	if (!axp20x_batt)
    572		return -ENOMEM;
    573
    574	axp20x_batt->dev = &pdev->dev;
    575
    576	axp20x_batt->batt_v = devm_iio_channel_get(&pdev->dev, "batt_v");
    577	if (IS_ERR(axp20x_batt->batt_v)) {
    578		if (PTR_ERR(axp20x_batt->batt_v) == -ENODEV)
    579			return -EPROBE_DEFER;
    580		return PTR_ERR(axp20x_batt->batt_v);
    581	}
    582
    583	axp20x_batt->batt_chrg_i = devm_iio_channel_get(&pdev->dev,
    584							"batt_chrg_i");
    585	if (IS_ERR(axp20x_batt->batt_chrg_i)) {
    586		if (PTR_ERR(axp20x_batt->batt_chrg_i) == -ENODEV)
    587			return -EPROBE_DEFER;
    588		return PTR_ERR(axp20x_batt->batt_chrg_i);
    589	}
    590
    591	axp20x_batt->batt_dischrg_i = devm_iio_channel_get(&pdev->dev,
    592							   "batt_dischrg_i");
    593	if (IS_ERR(axp20x_batt->batt_dischrg_i)) {
    594		if (PTR_ERR(axp20x_batt->batt_dischrg_i) == -ENODEV)
    595			return -EPROBE_DEFER;
    596		return PTR_ERR(axp20x_batt->batt_dischrg_i);
    597	}
    598
    599	axp20x_batt->regmap = dev_get_regmap(pdev->dev.parent, NULL);
    600	platform_set_drvdata(pdev, axp20x_batt);
    601
    602	psy_cfg.drv_data = axp20x_batt;
    603	psy_cfg.of_node = pdev->dev.of_node;
    604
    605	axp20x_batt->data = (struct axp_data *)of_device_get_match_data(dev);
    606
    607	axp20x_batt->batt = devm_power_supply_register(&pdev->dev,
    608						       &axp20x_batt_ps_desc,
    609						       &psy_cfg);
    610	if (IS_ERR(axp20x_batt->batt)) {
    611		dev_err(&pdev->dev, "failed to register power supply: %ld\n",
    612			PTR_ERR(axp20x_batt->batt));
    613		return PTR_ERR(axp20x_batt->batt);
    614	}
    615
    616	if (!power_supply_get_battery_info(axp20x_batt->batt, &info)) {
    617		int vmin = info->voltage_min_design_uv;
    618		int ccc = info->constant_charge_current_max_ua;
    619
    620		if (vmin > 0 && axp20x_set_voltage_min_design(axp20x_batt,
    621							      vmin))
    622			dev_err(&pdev->dev,
    623				"couldn't set voltage_min_design\n");
    624
    625		/* Set max to unverified value to be able to set CCC */
    626		axp20x_batt->max_ccc = ccc;
    627
    628		if (ccc <= 0 || axp20x_set_constant_charge_current(axp20x_batt,
    629								   ccc)) {
    630			dev_err(&pdev->dev,
    631				"couldn't set constant charge current from DT: fallback to minimum value\n");
    632			ccc = 300000;
    633			axp20x_batt->max_ccc = ccc;
    634			axp20x_set_constant_charge_current(axp20x_batt, ccc);
    635		}
    636	}
    637
    638	/*
    639	 * Update max CCC to a valid value if battery info is present or set it
    640	 * to current register value by default.
    641	 */
    642	axp20x_get_constant_charge_current(axp20x_batt,
    643					   &axp20x_batt->max_ccc);
    644
    645	return 0;
    646}
    647
    648static struct platform_driver axp20x_batt_driver = {
    649	.probe    = axp20x_power_probe,
    650	.driver   = {
    651		.name  = "axp20x-battery-power-supply",
    652		.of_match_table = axp20x_battery_ps_id,
    653	},
    654};
    655
    656module_platform_driver(axp20x_batt_driver);
    657
    658MODULE_DESCRIPTION("Battery power supply driver for AXP20X and AXP22X PMICs");
    659MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>");
    660MODULE_LICENSE("GPL");