xref: /linux/drivers/power/supply/ip5xxx_power.c (revision cdd5b5a9761fd66d17586e4f4ba6588c70e640ea)
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 
77 struct 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  */
ip5xxx_read(struct ip5xxx * ip5xxx,unsigned int reg,unsigned int * val)90 static 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 
ip5xxx_update_bits(struct ip5xxx * ip5xxx,unsigned int reg,unsigned int mask,unsigned int val)102 static 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 
ip5xxx_initialize(struct power_supply * psy)114 static 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 
170 static 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 
ip5xxx_battery_get_status(struct ip5xxx * ip5xxx,int * val)184 static 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 
ip5xxx_battery_get_charge_type(struct ip5xxx * ip5xxx,int * val)216 static 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 
ip5xxx_battery_get_health(struct ip5xxx * ip5xxx,int * val)246 static 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 
ip5xxx_battery_get_voltage_max(struct ip5xxx * ip5xxx,int * val)263 static 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 
ip5xxx_battery_read_adc(struct ip5xxx * ip5xxx,u8 lo_reg,u8 hi_reg,int * val)293 static 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 
ip5xxx_battery_get_property(struct power_supply * psy,enum power_supply_property psp,union power_supply_propval * val)312 static 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 
ip5xxx_battery_set_voltage_max(struct ip5xxx * ip5xxx,int val)397 static 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 
ip5xxx_battery_set_property(struct power_supply * psy,enum power_supply_property psp,const union power_supply_propval * val)430 static 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 
ip5xxx_battery_property_is_writeable(struct power_supply * psy,enum power_supply_property psp)480 static 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 
489 static 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 
499 static const enum power_supply_property ip5xxx_boost_properties[] = {
500 	POWER_SUPPLY_PROP_ONLINE,
501 	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
502 };
503 
ip5xxx_boost_get_property(struct power_supply * psy,enum power_supply_property psp,union power_supply_propval * val)504 static 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 
ip5xxx_boost_set_property(struct power_supply * psy,enum power_supply_property psp,const union power_supply_propval * val)539 static 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 
ip5xxx_boost_property_is_writeable(struct power_supply * psy,enum power_supply_property psp)567 static int ip5xxx_boost_property_is_writeable(struct power_supply *psy,
568 					      enum power_supply_property psp)
569 {
570 	return true;
571 }
572 
573 static 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 
583 static const struct regmap_config ip5xxx_regmap_config = {
584 	.reg_bits		= 8,
585 	.val_bits		= 8,
586 	.max_register		= IP5XXX_BATOCV_DAT1,
587 };
588 
ip5xxx_power_probe(struct i2c_client * client)589 static 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 
618 static 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 };
625 MODULE_DEVICE_TABLE(of, ip5xxx_power_of_match);
626 
627 static 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 };
634 module_i2c_driver(ip5xxx_power_driver);
635 
636 MODULE_AUTHOR("Samuel Holland <samuel@sholland.org>");
637 MODULE_DESCRIPTION("Injoinic IP5xxx power bank IC driver");
638 MODULE_LICENSE("GPL");
639