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 * 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