brintos

brintos / linux-shallow public Read only

0
0
Text · 16.4 KiB · 8226364 Raw
639 lines · c
1// SPDX-License-Identifier: GPL-2.02//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			0x0111#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			0x0216#define IP5XXX_SYS_CTL1_LIGHT_SHDN_EN		BIT(1)17#define IP5XXX_SYS_CTL1_LOAD_PWRUP_EN		BIT(0)18#define IP5XXX_SYS_CTL2			0x0c19#define IP5XXX_SYS_CTL2_LIGHT_SHDN_TH		GENMASK(7, 3)20#define IP5XXX_SYS_CTL3			0x0321#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			0x0424#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			0x0727#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			0x2231#define IP5XXX_CHG_CTL1_BOOST_UVP_SEL		GENMASK(3, 2)32#define IP5XXX_CHG_CTL2			0x2433#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			0x2639#define IP5XXX_CHG_CTL4_BAT_TYPE_SEL_EN		BIT(6)40#define IP5XXX_CHG_CTL4A		0x2541#define IP5XXX_CHG_CTL4A_CONST_CUR_SEL		GENMASK(4, 0)42#define IP5XXX_MFP_CTL0			0x5143#define IP5XXX_MFP_CTL1			0x5244#define IP5XXX_GPIO_CTL2		0x5345#define IP5XXX_GPIO_CTL2A		0x5446#define IP5XXX_GPIO_CTL3		0x5547#define IP5XXX_READ0			0x7148#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			0x7263#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			0x7767#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		0xa271#define IP5XXX_BATVADC_DAT1		0xa372#define IP5XXX_BATIADC_DAT0		0xa473#define IP5XXX_BATIADC_DAT1		0xa574#define IP5XXX_BATOCV_DAT0		0xa875#define IP5XXX_BATOCV_DAT1		0xa976 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 is84 * generally only awake when VIN is powered or when its boost converter is85 * 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 access88 *     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	else258		*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 if274	 * 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 * 149197, 200);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		= 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");639