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

ip5xxx_power.c (16777B)


      1// SPDX-License-Identifier: GPL-2.0
      2//
      3// Copyright (C) 2021 Samuel Holland <samuel@sholland.org>
      4
      5#include <linux/i2c.h>
      6#include <linux/module.h>
      7#include <linux/power_supply.h>
      8#include <linux/regmap.h>
      9
     10#define IP5XXX_SYS_CTL0			0x01
     11#define IP5XXX_SYS_CTL0_WLED_DET_EN		BIT(4)
     12#define IP5XXX_SYS_CTL0_WLED_EN			BIT(3)
     13#define IP5XXX_SYS_CTL0_BOOST_EN		BIT(2)
     14#define IP5XXX_SYS_CTL0_CHARGER_EN		BIT(1)
     15#define IP5XXX_SYS_CTL1			0x02
     16#define IP5XXX_SYS_CTL1_LIGHT_SHDN_EN		BIT(1)
     17#define IP5XXX_SYS_CTL1_LOAD_PWRUP_EN		BIT(0)
     18#define IP5XXX_SYS_CTL2			0x0c
     19#define IP5XXX_SYS_CTL2_LIGHT_SHDN_TH		GENMASK(7, 3)
     20#define IP5XXX_SYS_CTL3			0x03
     21#define IP5XXX_SYS_CTL3_LONG_PRESS_TIME_SEL	GENMASK(7, 6)
     22#define IP5XXX_SYS_CTL3_BTN_SHDN_EN		BIT(5)
     23#define IP5XXX_SYS_CTL4			0x04
     24#define IP5XXX_SYS_CTL4_SHDN_TIME_SEL		GENMASK(7, 6)
     25#define IP5XXX_SYS_CTL4_VIN_PULLOUT_BOOST_EN	BIT(5)
     26#define IP5XXX_SYS_CTL5			0x07
     27#define IP5XXX_SYS_CTL5_NTC_DIS			BIT(6)
     28#define IP5XXX_SYS_CTL5_WLED_MODE_SEL		BIT(1)
     29#define IP5XXX_SYS_CTL5_BTN_SHDN_SEL		BIT(0)
     30#define IP5XXX_CHG_CTL1			0x22
     31#define IP5XXX_CHG_CTL1_BOOST_UVP_SEL		GENMASK(3, 2)
     32#define IP5XXX_CHG_CTL2			0x24
     33#define IP5XXX_CHG_CTL2_BAT_TYPE_SEL		GENMASK(6, 5)
     34#define IP5XXX_CHG_CTL2_BAT_TYPE_SEL_4_2V	(0x0 << 5)
     35#define IP5XXX_CHG_CTL2_BAT_TYPE_SEL_4_3V	(0x1 << 5)
     36#define IP5XXX_CHG_CTL2_BAT_TYPE_SEL_4_35V	(0x2 << 5)
     37#define IP5XXX_CHG_CTL2_CONST_VOLT_SEL		GENMASK(2, 1)
     38#define IP5XXX_CHG_CTL4			0x26
     39#define IP5XXX_CHG_CTL4_BAT_TYPE_SEL_EN		BIT(6)
     40#define IP5XXX_CHG_CTL4A		0x25
     41#define IP5XXX_CHG_CTL4A_CONST_CUR_SEL		GENMASK(4, 0)
     42#define IP5XXX_MFP_CTL0			0x51
     43#define IP5XXX_MFP_CTL1			0x52
     44#define IP5XXX_GPIO_CTL2		0x53
     45#define IP5XXX_GPIO_CTL2A		0x54
     46#define IP5XXX_GPIO_CTL3		0x55
     47#define IP5XXX_READ0			0x71
     48#define IP5XXX_READ0_CHG_STAT			GENMASK(7, 5)
     49#define IP5XXX_READ0_CHG_STAT_IDLE		(0x0 << 5)
     50#define IP5XXX_READ0_CHG_STAT_TRICKLE		(0x1 << 5)
     51#define IP5XXX_READ0_CHG_STAT_CONST_VOLT	(0x2 << 5)
     52#define IP5XXX_READ0_CHG_STAT_CONST_CUR		(0x3 << 5)
     53#define IP5XXX_READ0_CHG_STAT_CONST_VOLT_STOP	(0x4 << 5)
     54#define IP5XXX_READ0_CHG_STAT_FULL		(0x5 << 5)
     55#define IP5XXX_READ0_CHG_STAT_TIMEOUT		(0x6 << 5)
     56#define IP5XXX_READ0_CHG_OP			BIT(4)
     57#define IP5XXX_READ0_CHG_END			BIT(3)
     58#define IP5XXX_READ0_CONST_VOLT_TIMEOUT		BIT(2)
     59#define IP5XXX_READ0_CHG_TIMEOUT		BIT(1)
     60#define IP5XXX_READ0_TRICKLE_TIMEOUT		BIT(0)
     61#define IP5XXX_READ0_TIMEOUT			GENMASK(2, 0)
     62#define IP5XXX_READ1			0x72
     63#define IP5XXX_READ1_WLED_PRESENT		BIT(7)
     64#define IP5XXX_READ1_LIGHT_LOAD			BIT(6)
     65#define IP5XXX_READ1_VIN_OVERVOLT		BIT(5)
     66#define IP5XXX_READ2			0x77
     67#define IP5XXX_READ2_BTN_PRESS			BIT(3)
     68#define IP5XXX_READ2_BTN_LONG_PRESS		BIT(1)
     69#define IP5XXX_READ2_BTN_SHORT_PRESS		BIT(0)
     70#define IP5XXX_BATVADC_DAT0		0xa2
     71#define IP5XXX_BATVADC_DAT1		0xa3
     72#define IP5XXX_BATIADC_DAT0		0xa4
     73#define IP5XXX_BATIADC_DAT1		0xa5
     74#define IP5XXX_BATOCV_DAT0		0xa8
     75#define IP5XXX_BATOCV_DAT1		0xa9
     76
     77struct ip5xxx {
     78	struct regmap *regmap;
     79	bool initialized;
     80};
     81
     82/*
     83 * The IP5xxx charger only responds on I2C when it is "awake". The charger is
     84 * generally only awake when VIN is powered or when its boost converter is
     85 * enabled. Going into shutdown resets all register values. To handle this:
     86 *  1) When any bus error occurs, assume the charger has gone into shutdown.
     87 *  2) Attempt the initialization sequence on each subsequent register access
     88 *     until it succeeds.
     89 */
     90static int ip5xxx_read(struct ip5xxx *ip5xxx, unsigned int reg,
     91		       unsigned int *val)
     92{
     93	int ret;
     94
     95	ret = regmap_read(ip5xxx->regmap, reg, val);
     96	if (ret)
     97		ip5xxx->initialized = false;
     98
     99	return ret;
    100}
    101
    102static int ip5xxx_update_bits(struct ip5xxx *ip5xxx, unsigned int reg,
    103			      unsigned int mask, unsigned int val)
    104{
    105	int ret;
    106
    107	ret = regmap_update_bits(ip5xxx->regmap, reg, mask, val);
    108	if (ret)
    109		ip5xxx->initialized = false;
    110
    111	return ret;
    112}
    113
    114static int ip5xxx_initialize(struct power_supply *psy)
    115{
    116	struct ip5xxx *ip5xxx = power_supply_get_drvdata(psy);
    117	int ret;
    118
    119	if (ip5xxx->initialized)
    120		return 0;
    121
    122	/*
    123	 * Disable shutdown under light load.
    124	 * Enable power on when under load.
    125	 */
    126	ret = ip5xxx_update_bits(ip5xxx, IP5XXX_SYS_CTL1,
    127				 IP5XXX_SYS_CTL1_LIGHT_SHDN_EN |
    128				 IP5XXX_SYS_CTL1_LOAD_PWRUP_EN,
    129				 IP5XXX_SYS_CTL1_LOAD_PWRUP_EN);
    130	if (ret)
    131		return ret;
    132
    133	/*
    134	 * Enable shutdown after a long button press (as configured below).
    135	 */
    136	ret = ip5xxx_update_bits(ip5xxx, IP5XXX_SYS_CTL3,
    137				 IP5XXX_SYS_CTL3_BTN_SHDN_EN,
    138				 IP5XXX_SYS_CTL3_BTN_SHDN_EN);
    139	if (ret)
    140		return ret;
    141
    142	/*
    143	 * Power on automatically when VIN is removed.
    144	 */
    145	ret = ip5xxx_update_bits(ip5xxx, IP5XXX_SYS_CTL4,
    146				 IP5XXX_SYS_CTL4_VIN_PULLOUT_BOOST_EN,
    147				 IP5XXX_SYS_CTL4_VIN_PULLOUT_BOOST_EN);
    148	if (ret)
    149		return ret;
    150
    151	/*
    152	 * Enable the NTC.
    153	 * Configure the button for two presses => LED, long press => shutdown.
    154	 */
    155	ret = ip5xxx_update_bits(ip5xxx, IP5XXX_SYS_CTL5,
    156				 IP5XXX_SYS_CTL5_NTC_DIS |
    157				 IP5XXX_SYS_CTL5_WLED_MODE_SEL |
    158				 IP5XXX_SYS_CTL5_BTN_SHDN_SEL,
    159				 IP5XXX_SYS_CTL5_WLED_MODE_SEL |
    160				 IP5XXX_SYS_CTL5_BTN_SHDN_SEL);
    161	if (ret)
    162		return ret;
    163
    164	ip5xxx->initialized = true;
    165	dev_dbg(psy->dev.parent, "Initialized after power on\n");
    166
    167	return 0;
    168}
    169
    170static const enum power_supply_property ip5xxx_battery_properties[] = {
    171	POWER_SUPPLY_PROP_STATUS,
    172	POWER_SUPPLY_PROP_CHARGE_TYPE,
    173	POWER_SUPPLY_PROP_HEALTH,
    174	POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
    175	POWER_SUPPLY_PROP_VOLTAGE_NOW,
    176	POWER_SUPPLY_PROP_VOLTAGE_OCV,
    177	POWER_SUPPLY_PROP_CURRENT_NOW,
    178	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
    179	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
    180	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
    181	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
    182};
    183
    184static int ip5xxx_battery_get_status(struct ip5xxx *ip5xxx, int *val)
    185{
    186	unsigned int rval;
    187	int ret;
    188
    189	ret = ip5xxx_read(ip5xxx, IP5XXX_READ0, &rval);
    190	if (ret)
    191		return ret;
    192
    193	switch (rval & IP5XXX_READ0_CHG_STAT) {
    194	case IP5XXX_READ0_CHG_STAT_IDLE:
    195		*val = POWER_SUPPLY_STATUS_DISCHARGING;
    196		break;
    197	case IP5XXX_READ0_CHG_STAT_TRICKLE:
    198	case IP5XXX_READ0_CHG_STAT_CONST_CUR:
    199	case IP5XXX_READ0_CHG_STAT_CONST_VOLT:
    200		*val = POWER_SUPPLY_STATUS_CHARGING;
    201		break;
    202	case IP5XXX_READ0_CHG_STAT_CONST_VOLT_STOP:
    203	case IP5XXX_READ0_CHG_STAT_FULL:
    204		*val = POWER_SUPPLY_STATUS_FULL;
    205		break;
    206	case IP5XXX_READ0_CHG_STAT_TIMEOUT:
    207		*val = POWER_SUPPLY_STATUS_NOT_CHARGING;
    208		break;
    209	default:
    210		return -EINVAL;
    211	}
    212
    213	return 0;
    214}
    215
    216static int ip5xxx_battery_get_charge_type(struct ip5xxx *ip5xxx, int *val)
    217{
    218	unsigned int rval;
    219	int ret;
    220
    221	ret = ip5xxx_read(ip5xxx, IP5XXX_READ0, &rval);
    222	if (ret)
    223		return ret;
    224
    225	switch (rval & IP5XXX_READ0_CHG_STAT) {
    226	case IP5XXX_READ0_CHG_STAT_IDLE:
    227	case IP5XXX_READ0_CHG_STAT_CONST_VOLT_STOP:
    228	case IP5XXX_READ0_CHG_STAT_FULL:
    229	case IP5XXX_READ0_CHG_STAT_TIMEOUT:
    230		*val = POWER_SUPPLY_CHARGE_TYPE_NONE;
    231		break;
    232	case IP5XXX_READ0_CHG_STAT_TRICKLE:
    233		*val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
    234		break;
    235	case IP5XXX_READ0_CHG_STAT_CONST_CUR:
    236	case IP5XXX_READ0_CHG_STAT_CONST_VOLT:
    237		*val = POWER_SUPPLY_CHARGE_TYPE_STANDARD;
    238		break;
    239	default:
    240		return -EINVAL;
    241	}
    242
    243	return 0;
    244}
    245
    246static int ip5xxx_battery_get_health(struct ip5xxx *ip5xxx, int *val)
    247{
    248	unsigned int rval;
    249	int ret;
    250
    251	ret = ip5xxx_read(ip5xxx, IP5XXX_READ0, &rval);
    252	if (ret)
    253		return ret;
    254
    255	if (rval & IP5XXX_READ0_TIMEOUT)
    256		*val = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
    257	else
    258		*val = POWER_SUPPLY_HEALTH_GOOD;
    259
    260	return 0;
    261}
    262
    263static int ip5xxx_battery_get_voltage_max(struct ip5xxx *ip5xxx, int *val)
    264{
    265	unsigned int rval;
    266	int ret;
    267
    268	ret = ip5xxx_read(ip5xxx, IP5XXX_CHG_CTL2, &rval);
    269	if (ret)
    270		return ret;
    271
    272	/*
    273	 * It is not clear what this will return if
    274	 * IP5XXX_CHG_CTL4_BAT_TYPE_SEL_EN is not set...
    275	 */
    276	switch (rval & IP5XXX_CHG_CTL2_BAT_TYPE_SEL) {
    277	case IP5XXX_CHG_CTL2_BAT_TYPE_SEL_4_2V:
    278		*val = 4200000;
    279		break;
    280	case IP5XXX_CHG_CTL2_BAT_TYPE_SEL_4_3V:
    281		*val = 4300000;
    282		break;
    283	case IP5XXX_CHG_CTL2_BAT_TYPE_SEL_4_35V:
    284		*val = 4350000;
    285		break;
    286	default:
    287		return -EINVAL;
    288	}
    289
    290	return 0;
    291}
    292
    293static int ip5xxx_battery_read_adc(struct ip5xxx *ip5xxx,
    294				   u8 lo_reg, u8 hi_reg, int *val)
    295{
    296	unsigned int hi, lo;
    297	int ret;
    298
    299	ret = ip5xxx_read(ip5xxx, lo_reg, &lo);
    300	if (ret)
    301		return ret;
    302
    303	ret = ip5xxx_read(ip5xxx, hi_reg, &hi);
    304	if (ret)
    305		return ret;
    306
    307	*val = sign_extend32(hi << 8 | lo, 13);
    308
    309	return 0;
    310}
    311
    312static int ip5xxx_battery_get_property(struct power_supply *psy,
    313				       enum power_supply_property psp,
    314				       union power_supply_propval *val)
    315{
    316	struct ip5xxx *ip5xxx = power_supply_get_drvdata(psy);
    317	int raw, ret, vmax;
    318	unsigned int rval;
    319
    320	ret = ip5xxx_initialize(psy);
    321	if (ret)
    322		return ret;
    323
    324	switch (psp) {
    325	case POWER_SUPPLY_PROP_STATUS:
    326		return ip5xxx_battery_get_status(ip5xxx, &val->intval);
    327
    328	case POWER_SUPPLY_PROP_CHARGE_TYPE:
    329		return ip5xxx_battery_get_charge_type(ip5xxx, &val->intval);
    330
    331	case POWER_SUPPLY_PROP_HEALTH:
    332		return ip5xxx_battery_get_health(ip5xxx, &val->intval);
    333
    334	case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
    335		return ip5xxx_battery_get_voltage_max(ip5xxx, &val->intval);
    336
    337	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
    338		ret = ip5xxx_battery_read_adc(ip5xxx, IP5XXX_BATVADC_DAT0,
    339					      IP5XXX_BATVADC_DAT1, &raw);
    340
    341		val->intval = 2600000 + DIV_ROUND_CLOSEST(raw * 26855, 100);
    342		return 0;
    343
    344	case POWER_SUPPLY_PROP_VOLTAGE_OCV:
    345		ret = ip5xxx_battery_read_adc(ip5xxx, IP5XXX_BATOCV_DAT0,
    346					      IP5XXX_BATOCV_DAT1, &raw);
    347
    348		val->intval = 2600000 + DIV_ROUND_CLOSEST(raw * 26855, 100);
    349		return 0;
    350
    351	case POWER_SUPPLY_PROP_CURRENT_NOW:
    352		ret = ip5xxx_battery_read_adc(ip5xxx, IP5XXX_BATIADC_DAT0,
    353					      IP5XXX_BATIADC_DAT1, &raw);
    354
    355		val->intval = DIV_ROUND_CLOSEST(raw * 745985, 1000);
    356		return 0;
    357
    358	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
    359		ret = ip5xxx_read(ip5xxx, IP5XXX_CHG_CTL4A, &rval);
    360		if (ret)
    361			return ret;
    362
    363		rval &= IP5XXX_CHG_CTL4A_CONST_CUR_SEL;
    364		val->intval = 100000 * rval;
    365		return 0;
    366
    367	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
    368		val->intval = 100000 * 0x1f;
    369		return 0;
    370
    371	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
    372		ret = ip5xxx_battery_get_voltage_max(ip5xxx, &vmax);
    373		if (ret)
    374			return ret;
    375
    376		ret = ip5xxx_read(ip5xxx, IP5XXX_CHG_CTL2, &rval);
    377		if (ret)
    378			return ret;
    379
    380		rval &= IP5XXX_CHG_CTL2_CONST_VOLT_SEL;
    381		val->intval = vmax + 14000 * (rval >> 1);
    382		return 0;
    383
    384	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
    385		ret = ip5xxx_battery_get_voltage_max(ip5xxx, &vmax);
    386		if (ret)
    387			return ret;
    388
    389		val->intval = vmax + 14000 * 3;
    390		return 0;
    391
    392	default:
    393		return -EINVAL;
    394	}
    395}
    396
    397static int ip5xxx_battery_set_voltage_max(struct ip5xxx *ip5xxx, int val)
    398{
    399	unsigned int rval;
    400	int ret;
    401
    402	switch (val) {
    403	case 4200000:
    404		rval = IP5XXX_CHG_CTL2_BAT_TYPE_SEL_4_2V;
    405		break;
    406	case 4300000:
    407		rval = IP5XXX_CHG_CTL2_BAT_TYPE_SEL_4_3V;
    408		break;
    409	case 4350000:
    410		rval = IP5XXX_CHG_CTL2_BAT_TYPE_SEL_4_35V;
    411		break;
    412	default:
    413		return -EINVAL;
    414	}
    415
    416	ret = ip5xxx_update_bits(ip5xxx, IP5XXX_CHG_CTL2,
    417				 IP5XXX_CHG_CTL2_BAT_TYPE_SEL, rval);
    418	if (ret)
    419		return ret;
    420
    421	ret = ip5xxx_update_bits(ip5xxx, IP5XXX_CHG_CTL4,
    422				 IP5XXX_CHG_CTL4_BAT_TYPE_SEL_EN,
    423				 IP5XXX_CHG_CTL4_BAT_TYPE_SEL_EN);
    424	if (ret)
    425		return ret;
    426
    427	return 0;
    428}
    429
    430static int ip5xxx_battery_set_property(struct power_supply *psy,
    431				       enum power_supply_property psp,
    432				       const union power_supply_propval *val)
    433{
    434	struct ip5xxx *ip5xxx = power_supply_get_drvdata(psy);
    435	unsigned int rval;
    436	int ret, vmax;
    437
    438	ret = ip5xxx_initialize(psy);
    439	if (ret)
    440		return ret;
    441
    442	switch (psp) {
    443	case POWER_SUPPLY_PROP_STATUS:
    444		switch (val->intval) {
    445		case POWER_SUPPLY_STATUS_CHARGING:
    446			rval = IP5XXX_SYS_CTL0_CHARGER_EN;
    447			break;
    448		case POWER_SUPPLY_STATUS_DISCHARGING:
    449		case POWER_SUPPLY_STATUS_NOT_CHARGING:
    450			rval = 0;
    451			break;
    452		default:
    453			return -EINVAL;
    454		}
    455		return ip5xxx_update_bits(ip5xxx, IP5XXX_SYS_CTL0,
    456					  IP5XXX_SYS_CTL0_CHARGER_EN, rval);
    457
    458	case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
    459		return ip5xxx_battery_set_voltage_max(ip5xxx, val->intval);
    460
    461	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
    462		rval = val->intval / 100000;
    463		return ip5xxx_update_bits(ip5xxx, IP5XXX_CHG_CTL4A,
    464					  IP5XXX_CHG_CTL4A_CONST_CUR_SEL, rval);
    465
    466	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
    467		ret = ip5xxx_battery_get_voltage_max(ip5xxx, &vmax);
    468		if (ret)
    469			return ret;
    470
    471		rval = ((val->intval - vmax) / 14000) << 1;
    472		return ip5xxx_update_bits(ip5xxx, IP5XXX_CHG_CTL2,
    473					  IP5XXX_CHG_CTL2_CONST_VOLT_SEL, rval);
    474
    475	default:
    476		return -EINVAL;
    477	}
    478}
    479
    480static int ip5xxx_battery_property_is_writeable(struct power_supply *psy,
    481						enum power_supply_property psp)
    482{
    483	return psp == POWER_SUPPLY_PROP_STATUS ||
    484	       psp == POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN ||
    485	       psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT ||
    486	       psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE;
    487}
    488
    489static const struct power_supply_desc ip5xxx_battery_desc = {
    490	.name			= "ip5xxx-battery",
    491	.type			= POWER_SUPPLY_TYPE_BATTERY,
    492	.properties		= ip5xxx_battery_properties,
    493	.num_properties		= ARRAY_SIZE(ip5xxx_battery_properties),
    494	.get_property		= ip5xxx_battery_get_property,
    495	.set_property		= ip5xxx_battery_set_property,
    496	.property_is_writeable	= ip5xxx_battery_property_is_writeable,
    497};
    498
    499static const enum power_supply_property ip5xxx_boost_properties[] = {
    500	POWER_SUPPLY_PROP_ONLINE,
    501	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
    502};
    503
    504static int ip5xxx_boost_get_property(struct power_supply *psy,
    505				     enum power_supply_property psp,
    506				     union power_supply_propval *val)
    507{
    508	struct ip5xxx *ip5xxx = power_supply_get_drvdata(psy);
    509	unsigned int rval;
    510	int ret;
    511
    512	ret = ip5xxx_initialize(psy);
    513	if (ret)
    514		return ret;
    515
    516	switch (psp) {
    517	case POWER_SUPPLY_PROP_ONLINE:
    518		ret = ip5xxx_read(ip5xxx, IP5XXX_SYS_CTL0, &rval);
    519		if (ret)
    520			return ret;
    521
    522		val->intval = !!(rval & IP5XXX_SYS_CTL0_BOOST_EN);
    523		return 0;
    524
    525	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
    526		ret = ip5xxx_read(ip5xxx, IP5XXX_CHG_CTL1, &rval);
    527		if (ret)
    528			return ret;
    529
    530		rval &= IP5XXX_CHG_CTL1_BOOST_UVP_SEL;
    531		val->intval = 4530000 + 100000 * (rval >> 2);
    532		return 0;
    533
    534	default:
    535		return -EINVAL;
    536	}
    537}
    538
    539static int ip5xxx_boost_set_property(struct power_supply *psy,
    540				     enum power_supply_property psp,
    541				     const union power_supply_propval *val)
    542{
    543	struct ip5xxx *ip5xxx = power_supply_get_drvdata(psy);
    544	unsigned int rval;
    545	int ret;
    546
    547	ret = ip5xxx_initialize(psy);
    548	if (ret)
    549		return ret;
    550
    551	switch (psp) {
    552	case POWER_SUPPLY_PROP_ONLINE:
    553		rval = val->intval ? IP5XXX_SYS_CTL0_BOOST_EN : 0;
    554		return ip5xxx_update_bits(ip5xxx, IP5XXX_SYS_CTL0,
    555					  IP5XXX_SYS_CTL0_BOOST_EN, rval);
    556
    557	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
    558		rval = ((val->intval - 4530000) / 100000) << 2;
    559		return ip5xxx_update_bits(ip5xxx, IP5XXX_CHG_CTL1,
    560					  IP5XXX_CHG_CTL1_BOOST_UVP_SEL, rval);
    561
    562	default:
    563		return -EINVAL;
    564	}
    565}
    566
    567static int ip5xxx_boost_property_is_writeable(struct power_supply *psy,
    568					      enum power_supply_property psp)
    569{
    570	return true;
    571}
    572
    573static const struct power_supply_desc ip5xxx_boost_desc = {
    574	.name			= "ip5xxx-boost",
    575	.type			= POWER_SUPPLY_TYPE_USB,
    576	.properties		= ip5xxx_boost_properties,
    577	.num_properties		= ARRAY_SIZE(ip5xxx_boost_properties),
    578	.get_property		= ip5xxx_boost_get_property,
    579	.set_property		= ip5xxx_boost_set_property,
    580	.property_is_writeable	= ip5xxx_boost_property_is_writeable,
    581};
    582
    583static const struct regmap_config ip5xxx_regmap_config = {
    584	.reg_bits		= 8,
    585	.val_bits		= 8,
    586	.max_register		= IP5XXX_BATOCV_DAT1,
    587};
    588
    589static int ip5xxx_power_probe(struct i2c_client *client)
    590{
    591	struct power_supply_config psy_cfg = {};
    592	struct device *dev = &client->dev;
    593	struct power_supply *psy;
    594	struct ip5xxx *ip5xxx;
    595
    596	ip5xxx = devm_kzalloc(dev, sizeof(*ip5xxx), GFP_KERNEL);
    597	if (!ip5xxx)
    598		return -ENOMEM;
    599
    600	ip5xxx->regmap = devm_regmap_init_i2c(client, &ip5xxx_regmap_config);
    601	if (IS_ERR(ip5xxx->regmap))
    602		return PTR_ERR(ip5xxx->regmap);
    603
    604	psy_cfg.of_node = dev->of_node;
    605	psy_cfg.drv_data = ip5xxx;
    606
    607	psy = devm_power_supply_register(dev, &ip5xxx_battery_desc, &psy_cfg);
    608	if (IS_ERR(psy))
    609		return PTR_ERR(psy);
    610
    611	psy = devm_power_supply_register(dev, &ip5xxx_boost_desc, &psy_cfg);
    612	if (IS_ERR(psy))
    613		return PTR_ERR(psy);
    614
    615	return 0;
    616}
    617
    618static const struct of_device_id ip5xxx_power_of_match[] = {
    619	{ .compatible = "injoinic,ip5108" },
    620	{ .compatible = "injoinic,ip5109" },
    621	{ .compatible = "injoinic,ip5207" },
    622	{ .compatible = "injoinic,ip5209" },
    623	{ }
    624};
    625MODULE_DEVICE_TABLE(of, ip5xxx_power_of_match);
    626
    627static struct i2c_driver ip5xxx_power_driver = {
    628	.probe_new	= ip5xxx_power_probe,
    629	.driver		= {
    630		.name		= "ip5xxx-power",
    631		.of_match_table	= ip5xxx_power_of_match,
    632	}
    633};
    634module_i2c_driver(ip5xxx_power_driver);
    635
    636MODULE_AUTHOR("Samuel Holland <samuel@sholland.org>");
    637MODULE_DESCRIPTION("Injoinic IP5xxx power bank IC driver");
    638MODULE_LICENSE("GPL");