xref: /linux/drivers/power/supply/ip5xxx_power.c (revision f28f4890454cc97c18d31ab4686957857cc862b5)
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_BAT_TYPE_4_2V			0x0
11 #define IP5XXX_BAT_TYPE_4_3V			0x1
12 #define IP5XXX_BAT_TYPE_4_35V			0x2
13 #define IP5XXX_BAT_TYPE_4_4V			0x3
14 #define IP5XXX_CHG_STAT_IDLE			0x0
15 #define IP5XXX_CHG_STAT_TRICKLE		0x1
16 #define IP5XXX_CHG_STAT_CONST_VOLT		0x2
17 #define IP5XXX_CHG_STAT_CONST_CUR		0x3
18 #define IP5XXX_CHG_STAT_CONST_VOLT_STOP	0x4
19 #define IP5XXX_CHG_STAT_FULL			0x5
20 #define IP5XXX_CHG_STAT_TIMEOUT		0x6
21 
22 struct ip5xxx {
23 	struct regmap *regmap;
24 	bool initialized;
25 	struct {
26 		struct {
27 			/* Charger enable */
28 			struct regmap_field *enable;
29 			/* Constant voltage value */
30 			struct regmap_field *const_volt_sel;
31 			/* Constant current value */
32 			struct regmap_field *const_curr_sel;
33 			/* Charger status */
34 			struct regmap_field *status;
35 			/* Charging ended flag */
36 			struct regmap_field *chg_end;
37 			/* Timeout flags (CV, charge, trickle) */
38 			struct regmap_field *timeout;
39 			/* Overvoltage limit */
40 			struct regmap_field *vin_overvolt;
41 		} charger;
42 		struct {
43 			/* Boost converter enable */
44 			struct regmap_field *enable;
45 			struct {
46 				/* Light load shutdown enable */
47 				struct regmap_field *enable;
48 				/* Light load shutdown current limit */
49 				struct regmap_field *i_limit;
50 			} light_load_shutdown;
51 			/* Automatic powerup on increased load */
52 			struct regmap_field *load_powerup_en;
53 			/* Automatic powerup on VIN pull-out */
54 			struct regmap_field *vin_pullout_en;
55 			/* Undervoltage limit */
56 			struct regmap_field *undervolt_limit;
57 			/* Light load status flag */
58 			struct regmap_field *light_load_status;
59 		} boost;
60 		struct {
61 			/* NTC disable */
62 			struct regmap_field *ntc_dis;
63 			/* Battery voltage type */
64 			struct regmap_field *type;
65 			/* Battery voltage autoset from Vset pin */
66 			struct regmap_field *vset_en;
67 			struct {
68 				/* Battery measurement registers */
69 				struct ip5xxx_battery_adc_regs {
70 					struct regmap_field *low;
71 					struct regmap_field *high;
72 				} volt, curr, open_volt;
73 			} adc;
74 		} battery;
75 		struct {
76 			/* Double/long press shutdown enable */
77 			struct regmap_field *shdn_enable;
78 			/* WLED activation: double press or long press */
79 			struct regmap_field *wled_mode;
80 			/* Shutdown activation: double press or long press */
81 			struct regmap_field *shdn_mode;
82 			/* Long press time */
83 			struct regmap_field *long_press_time;
84 			/* Button pressed */
85 			struct regmap_field *pressed;
86 			/* Button long-pressed */
87 			struct regmap_field *long_pressed;
88 			/* Button short-pressed */
89 			struct regmap_field *short_pressed;
90 		} btn;
91 		struct {
92 			/* WLED enable */
93 			struct regmap_field *enable;
94 			/* WLED detect */
95 			struct regmap_field *detect_en;
96 			/* WLED present */
97 			struct regmap_field *present;
98 		} wled;
99 	} regs;
100 
101 	/* Maximum supported battery voltage (via regs.battery.type) */
102 	int vbat_max;
103 	/* Scaling constants for regs.boost.undervolt_limit */
104 	struct {
105 		int setpoint;
106 		int microvolts_per_bit;
107 	} boost_undervolt;
108 	/* Scaling constants for regs.charger.const_curr_sel */
109 	struct {
110 		int setpoint;
111 	} const_curr;
112 	/* Whether regs.charger.chg_end is inverted */
113 	u8 chg_end_inverted;
114 };
115 
116 #define REG_FIELD_UNSUPPORTED { .lsb = 1 }
117 /* Register fields layout. Unsupported registers marked as { .lsb = 1 } */
118 struct ip5xxx_regfield_config {
119 	const struct reg_field charger_enable;
120 	const struct reg_field charger_const_volt_sel;
121 	const struct reg_field charger_const_curr_sel;
122 	const struct reg_field charger_status;
123 	const struct reg_field charger_chg_end;
124 	const struct reg_field charger_timeout;
125 	const struct reg_field charger_vin_overvolt;
126 	const struct reg_field boost_enable;
127 	const struct reg_field boost_llshdn_enable;
128 	const struct reg_field boost_llshdn_i_limit;
129 	const struct reg_field boost_load_powerup_en;
130 	const struct reg_field boost_vin_pullout_en;
131 	const struct reg_field boost_undervolt_limit;
132 	const struct reg_field boost_light_load_status;
133 	const struct reg_field battery_ntc_dis;
134 	const struct reg_field battery_type;
135 	const struct reg_field battery_vset_en;
136 	const struct reg_field battery_adc_volt_low;
137 	const struct reg_field battery_adc_volt_high;
138 	const struct reg_field battery_adc_curr_low;
139 	const struct reg_field battery_adc_curr_high;
140 	const struct reg_field battery_adc_ovolt_low;
141 	const struct reg_field battery_adc_ovolt_high;
142 	const struct reg_field btn_shdn_enable;
143 	const struct reg_field btn_wled_mode;
144 	const struct reg_field btn_shdn_mode;
145 	const struct reg_field btn_long_press_time;
146 	const struct reg_field btn_pressed;
147 	const struct reg_field btn_long_pressed;
148 	const struct reg_field btn_short_pressed;
149 	const struct reg_field wled_enable;
150 	const struct reg_field wled_detect_en;
151 	const struct reg_field wled_present;
152 
153 	int vbat_max;
154 	int boost_undervolt_setpoint;
155 	int boost_undervolt_uv_per_bit;
156 	int const_curr_setpoint;
157 	u8  chg_end_inverted;
158 };
159 
160 /*
161  * The IP5xxx charger only responds on I2C when it is "awake". The charger is
162  * generally only awake when VIN is powered or when its boost converter is
163  * enabled. Going into shutdown resets all register values. To handle this:
164  *  1) When any bus error occurs, assume the charger has gone into shutdown.
165  *  2) Attempt the initialization sequence on each subsequent register access
166  *     until it succeeds.
167  */
168 static int ip5xxx_read(struct ip5xxx *ip5xxx, struct regmap_field *field,
169 		       unsigned int *val)
170 {
171 	int ret;
172 
173 	if (!field)
174 		return -EOPNOTSUPP;
175 
176 	ret = regmap_field_read(field, val);
177 	if (ret)
178 		ip5xxx->initialized = false;
179 
180 	return ret;
181 }
182 
183 static int ip5xxx_write(struct ip5xxx *ip5xxx, struct regmap_field *field,
184 			unsigned int val)
185 {
186 	int ret;
187 
188 	if (!field)
189 		return -EOPNOTSUPP;
190 
191 	ret = regmap_field_write(field, val);
192 	if (ret)
193 		ip5xxx->initialized = false;
194 
195 	return ret;
196 }
197 
198 static int ip5xxx_initialize(struct power_supply *psy)
199 {
200 	struct ip5xxx *ip5xxx = power_supply_get_drvdata(psy);
201 	int ret;
202 
203 	if (ip5xxx->initialized)
204 		return 0;
205 
206 	/*
207 	 * Disable shutdown under light load.
208 	 * Enable power on when under load.
209 	 */
210 	if (ip5xxx->regs.boost.light_load_shutdown.enable) {
211 		ret = ip5xxx_write(ip5xxx, ip5xxx->regs.boost.light_load_shutdown.enable, 0);
212 		if (ret)
213 			return ret;
214 	}
215 	ret = ip5xxx_write(ip5xxx, ip5xxx->regs.boost.load_powerup_en, 1);
216 	if (ret)
217 		return ret;
218 
219 	/*
220 	 * Enable shutdown after a long button press (as configured below).
221 	 */
222 	ret = ip5xxx_write(ip5xxx, ip5xxx->regs.btn.shdn_enable, 1);
223 	if (ret)
224 		return ret;
225 
226 	/*
227 	 * Power on automatically when VIN is removed.
228 	 */
229 	ret = ip5xxx_write(ip5xxx, ip5xxx->regs.boost.vin_pullout_en, 1);
230 	if (ret)
231 		return ret;
232 
233 	/*
234 	 * Enable the NTC.
235 	 * Configure the button for two presses => LED, long press => shutdown.
236 	 */
237 	if (ip5xxx->regs.battery.ntc_dis) {
238 		ret = ip5xxx_write(ip5xxx, ip5xxx->regs.battery.ntc_dis, 0);
239 		if (ret)
240 			return ret;
241 	}
242 	ret = ip5xxx_write(ip5xxx, ip5xxx->regs.btn.wled_mode, 1);
243 	if (ret)
244 		return ret;
245 	ret = ip5xxx_write(ip5xxx, ip5xxx->regs.btn.shdn_mode, 1);
246 	if (ret)
247 		return ret;
248 
249 	ip5xxx->initialized = true;
250 	dev_dbg(psy->dev.parent, "Initialized after power on\n");
251 
252 	return 0;
253 }
254 
255 static const enum power_supply_property ip5xxx_battery_properties[] = {
256 	POWER_SUPPLY_PROP_STATUS,
257 	POWER_SUPPLY_PROP_CHARGE_TYPE,
258 	POWER_SUPPLY_PROP_HEALTH,
259 	POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
260 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
261 	POWER_SUPPLY_PROP_VOLTAGE_OCV,
262 	POWER_SUPPLY_PROP_CURRENT_NOW,
263 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
264 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
265 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
266 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
267 };
268 
269 static int ip5xxx_battery_get_status(struct ip5xxx *ip5xxx, int *val)
270 {
271 	unsigned int rval;
272 	int ret;
273 
274 	if (!ip5xxx->regs.charger.status) {
275 		// Fall-back to Charging Ended bit
276 		ret = ip5xxx_read(ip5xxx, ip5xxx->regs.charger.chg_end, &rval);
277 		if (ret)
278 			return ret;
279 
280 		if (rval == ip5xxx->chg_end_inverted)
281 			*val = POWER_SUPPLY_STATUS_CHARGING;
282 		else
283 			*val = POWER_SUPPLY_STATUS_NOT_CHARGING;
284 		return 0;
285 	}
286 
287 	ret = ip5xxx_read(ip5xxx, ip5xxx->regs.charger.status, &rval);
288 	if (ret)
289 		return ret;
290 
291 	switch (rval) {
292 	case IP5XXX_CHG_STAT_IDLE:
293 		*val = POWER_SUPPLY_STATUS_DISCHARGING;
294 		break;
295 	case IP5XXX_CHG_STAT_TRICKLE:
296 	case IP5XXX_CHG_STAT_CONST_CUR:
297 	case IP5XXX_CHG_STAT_CONST_VOLT:
298 		*val = POWER_SUPPLY_STATUS_CHARGING;
299 		break;
300 	case IP5XXX_CHG_STAT_CONST_VOLT_STOP:
301 	case IP5XXX_CHG_STAT_FULL:
302 		*val = POWER_SUPPLY_STATUS_FULL;
303 		break;
304 	case IP5XXX_CHG_STAT_TIMEOUT:
305 		*val = POWER_SUPPLY_STATUS_NOT_CHARGING;
306 		break;
307 	default:
308 		return -EINVAL;
309 	}
310 
311 	return 0;
312 }
313 
314 static int ip5xxx_battery_get_charge_type(struct ip5xxx *ip5xxx, int *val)
315 {
316 	unsigned int rval;
317 	int ret;
318 
319 	ret = ip5xxx_read(ip5xxx, ip5xxx->regs.charger.status, &rval);
320 	if (ret)
321 		return ret;
322 
323 	switch (rval) {
324 	case IP5XXX_CHG_STAT_IDLE:
325 	case IP5XXX_CHG_STAT_CONST_VOLT_STOP:
326 	case IP5XXX_CHG_STAT_FULL:
327 	case IP5XXX_CHG_STAT_TIMEOUT:
328 		*val = POWER_SUPPLY_CHARGE_TYPE_NONE;
329 		break;
330 	case IP5XXX_CHG_STAT_TRICKLE:
331 		*val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
332 		break;
333 	case IP5XXX_CHG_STAT_CONST_CUR:
334 	case IP5XXX_CHG_STAT_CONST_VOLT:
335 		*val = POWER_SUPPLY_CHARGE_TYPE_STANDARD;
336 		break;
337 	default:
338 		return -EINVAL;
339 	}
340 
341 	return 0;
342 }
343 
344 static int ip5xxx_battery_get_health(struct ip5xxx *ip5xxx, int *val)
345 {
346 	unsigned int rval;
347 	int ret;
348 
349 	ret = ip5xxx_read(ip5xxx, ip5xxx->regs.charger.timeout, &rval);
350 	if (ret)
351 		return ret;
352 
353 	if (rval)
354 		*val = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
355 	else
356 		*val = POWER_SUPPLY_HEALTH_GOOD;
357 
358 	return 0;
359 }
360 
361 static int ip5xxx_battery_get_voltage_max(struct ip5xxx *ip5xxx, int *val)
362 {
363 	unsigned int rval;
364 	int ret;
365 
366 	ret = ip5xxx_read(ip5xxx, ip5xxx->regs.battery.type, &rval);
367 	if (ret)
368 		return ret;
369 
370 	/*
371 	 * It is not clear what this will return if
372 	 * IP5XXX_CHG_CTL4_BAT_TYPE_SEL_EN is not set...
373 	 */
374 	switch (rval) {
375 	case IP5XXX_BAT_TYPE_4_2V:
376 		*val = 4200000;
377 		break;
378 	case IP5XXX_BAT_TYPE_4_3V:
379 		*val = 4300000;
380 		break;
381 	case IP5XXX_BAT_TYPE_4_35V:
382 		*val = 4350000;
383 		break;
384 	case IP5XXX_BAT_TYPE_4_4V:
385 		*val = 4400000;
386 		break;
387 	default:
388 		return -EINVAL;
389 	}
390 
391 	return 0;
392 }
393 
394 static int ip5xxx_battery_read_adc(struct ip5xxx *ip5xxx,
395 				   struct ip5xxx_battery_adc_regs *regs, int *val)
396 {
397 	unsigned int hi, lo;
398 	int ret;
399 
400 	ret = ip5xxx_read(ip5xxx, regs->low, &lo);
401 	if (ret)
402 		return ret;
403 
404 	ret = ip5xxx_read(ip5xxx, regs->high, &hi);
405 	if (ret)
406 		return ret;
407 
408 	*val = sign_extend32(hi << 8 | lo, 13);
409 
410 	return 0;
411 }
412 
413 static int ip5xxx_battery_get_property(struct power_supply *psy,
414 				       enum power_supply_property psp,
415 				       union power_supply_propval *val)
416 {
417 	struct ip5xxx *ip5xxx = power_supply_get_drvdata(psy);
418 	int raw, ret, vmax;
419 	unsigned int rval;
420 
421 	ret = ip5xxx_initialize(psy);
422 	if (ret)
423 		return ret;
424 
425 	switch (psp) {
426 	case POWER_SUPPLY_PROP_STATUS:
427 		return ip5xxx_battery_get_status(ip5xxx, &val->intval);
428 
429 	case POWER_SUPPLY_PROP_CHARGE_TYPE:
430 		return ip5xxx_battery_get_charge_type(ip5xxx, &val->intval);
431 
432 	case POWER_SUPPLY_PROP_HEALTH:
433 		return ip5xxx_battery_get_health(ip5xxx, &val->intval);
434 
435 	case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
436 		return ip5xxx_battery_get_voltage_max(ip5xxx, &val->intval);
437 
438 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
439 		ret = ip5xxx_battery_read_adc(ip5xxx, &ip5xxx->regs.battery.adc.volt, &raw);
440 		if (ret)
441 			return ret;
442 
443 		val->intval = 2600000 + DIV_ROUND_CLOSEST(raw * 26855, 100);
444 		return 0;
445 
446 	case POWER_SUPPLY_PROP_VOLTAGE_OCV:
447 		ret = ip5xxx_battery_read_adc(ip5xxx, &ip5xxx->regs.battery.adc.open_volt, &raw);
448 		if (ret)
449 			return ret;
450 
451 		val->intval = 2600000 + DIV_ROUND_CLOSEST(raw * 26855, 100);
452 		return 0;
453 
454 	case POWER_SUPPLY_PROP_CURRENT_NOW:
455 		ret = ip5xxx_battery_read_adc(ip5xxx, &ip5xxx->regs.battery.adc.curr, &raw);
456 		if (ret)
457 			return ret;
458 
459 		val->intval = DIV_ROUND_CLOSEST(raw * 149197, 200);
460 		return 0;
461 
462 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
463 		ret = ip5xxx_read(ip5xxx, ip5xxx->regs.charger.const_curr_sel, &rval);
464 		if (ret)
465 			return ret;
466 
467 		val->intval = ip5xxx->const_curr.setpoint + 100000 * rval;
468 		return 0;
469 
470 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
471 		val->intval = 100000 * 0x1f;
472 		return 0;
473 
474 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
475 		ret = ip5xxx_battery_get_voltage_max(ip5xxx, &vmax);
476 		if (ret)
477 			return ret;
478 
479 		ret = ip5xxx_read(ip5xxx, ip5xxx->regs.charger.const_volt_sel, &rval);
480 		if (ret)
481 			return ret;
482 
483 		val->intval = vmax + 14000 * rval;
484 		return 0;
485 
486 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
487 		ret = ip5xxx_battery_get_voltage_max(ip5xxx, &vmax);
488 		if (ret)
489 			return ret;
490 
491 		val->intval = vmax + 14000 * 3;
492 		return 0;
493 
494 	default:
495 		return -EINVAL;
496 	}
497 }
498 
499 static int ip5xxx_battery_set_voltage_max(struct ip5xxx *ip5xxx, int val)
500 {
501 	unsigned int rval;
502 	int ret;
503 
504 	if (val > ip5xxx->vbat_max)
505 		return -EINVAL;
506 
507 	switch (val) {
508 	case 4200000:
509 		rval = IP5XXX_BAT_TYPE_4_2V;
510 		break;
511 	case 4300000:
512 		rval = IP5XXX_BAT_TYPE_4_3V;
513 		break;
514 	case 4350000:
515 		rval = IP5XXX_BAT_TYPE_4_35V;
516 		break;
517 	case 4400000:
518 		rval = IP5XXX_BAT_TYPE_4_4V;
519 		break;
520 	default:
521 		return -EINVAL;
522 	}
523 
524 	ret = ip5xxx_write(ip5xxx, ip5xxx->regs.battery.type, rval);
525 	if (ret)
526 		return ret;
527 
528 	/* Don't try to auto-detect battery type, even if the IC could */
529 	if (ip5xxx->regs.battery.vset_en) {
530 		ret = ip5xxx_write(ip5xxx, ip5xxx->regs.battery.vset_en, 1);
531 		if (ret)
532 			return ret;
533 	}
534 
535 	return 0;
536 }
537 
538 static int ip5xxx_battery_set_property(struct power_supply *psy,
539 				       enum power_supply_property psp,
540 				       const union power_supply_propval *val)
541 {
542 	struct ip5xxx *ip5xxx = power_supply_get_drvdata(psy);
543 	unsigned int rval;
544 	int ret, vmax;
545 
546 	ret = ip5xxx_initialize(psy);
547 	if (ret)
548 		return ret;
549 
550 	switch (psp) {
551 	case POWER_SUPPLY_PROP_STATUS:
552 		switch (val->intval) {
553 		case POWER_SUPPLY_STATUS_CHARGING:
554 			rval = 1;
555 			break;
556 		case POWER_SUPPLY_STATUS_DISCHARGING:
557 		case POWER_SUPPLY_STATUS_NOT_CHARGING:
558 			rval = 0;
559 			break;
560 		default:
561 			return -EINVAL;
562 		}
563 		return ip5xxx_write(ip5xxx, ip5xxx->regs.charger.enable, rval);
564 
565 	case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
566 		return ip5xxx_battery_set_voltage_max(ip5xxx, val->intval);
567 
568 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
569 		rval = (val->intval - ip5xxx->const_curr.setpoint) / 100000;
570 		return ip5xxx_write(ip5xxx, ip5xxx->regs.charger.const_curr_sel, rval);
571 
572 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
573 		ret = ip5xxx_battery_get_voltage_max(ip5xxx, &vmax);
574 		if (ret)
575 			return ret;
576 
577 		rval = (val->intval - vmax) / 14000;
578 		return ip5xxx_write(ip5xxx, ip5xxx->regs.charger.const_volt_sel, rval);
579 
580 	default:
581 		return -EINVAL;
582 	}
583 }
584 
585 static int ip5xxx_battery_property_is_writeable(struct power_supply *psy,
586 						enum power_supply_property psp)
587 {
588 	return psp == POWER_SUPPLY_PROP_STATUS ||
589 	       psp == POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN ||
590 	       psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT ||
591 	       psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE;
592 }
593 
594 static const struct power_supply_desc ip5xxx_battery_desc = {
595 	.name			= "ip5xxx-battery",
596 	.type			= POWER_SUPPLY_TYPE_BATTERY,
597 	.properties		= ip5xxx_battery_properties,
598 	.num_properties		= ARRAY_SIZE(ip5xxx_battery_properties),
599 	.get_property		= ip5xxx_battery_get_property,
600 	.set_property		= ip5xxx_battery_set_property,
601 	.property_is_writeable	= ip5xxx_battery_property_is_writeable,
602 };
603 
604 static const enum power_supply_property ip5xxx_boost_properties[] = {
605 	POWER_SUPPLY_PROP_ONLINE,
606 	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
607 };
608 
609 static int ip5xxx_boost_get_property(struct power_supply *psy,
610 				     enum power_supply_property psp,
611 				     union power_supply_propval *val)
612 {
613 	struct ip5xxx *ip5xxx = power_supply_get_drvdata(psy);
614 	unsigned int rval;
615 	int ret;
616 
617 	ret = ip5xxx_initialize(psy);
618 	if (ret)
619 		return ret;
620 
621 	switch (psp) {
622 	case POWER_SUPPLY_PROP_ONLINE:
623 		ret = ip5xxx_read(ip5xxx, ip5xxx->regs.boost.enable, &rval);
624 		if (ret)
625 			return ret;
626 
627 		val->intval = !!rval;
628 		return 0;
629 
630 	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
631 		ret = ip5xxx_read(ip5xxx, ip5xxx->regs.boost.undervolt_limit, &rval);
632 		if (ret)
633 			return ret;
634 
635 		val->intval = ip5xxx->boost_undervolt.setpoint +
636 			      ip5xxx->boost_undervolt.microvolts_per_bit * rval;
637 		return 0;
638 
639 	default:
640 		return -EINVAL;
641 	}
642 }
643 
644 static int ip5xxx_boost_set_property(struct power_supply *psy,
645 				     enum power_supply_property psp,
646 				     const union power_supply_propval *val)
647 {
648 	struct ip5xxx *ip5xxx = power_supply_get_drvdata(psy);
649 	unsigned int rval;
650 	int ret;
651 
652 	ret = ip5xxx_initialize(psy);
653 	if (ret)
654 		return ret;
655 
656 	switch (psp) {
657 	case POWER_SUPPLY_PROP_ONLINE:
658 		return ip5xxx_write(ip5xxx, ip5xxx->regs.boost.enable, !!val->intval);
659 
660 	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
661 		rval = (val->intval - ip5xxx->boost_undervolt.setpoint) /
662 			ip5xxx->boost_undervolt.microvolts_per_bit;
663 		return ip5xxx_write(ip5xxx, ip5xxx->regs.boost.undervolt_limit, rval);
664 
665 	default:
666 		return -EINVAL;
667 	}
668 }
669 
670 static int ip5xxx_boost_property_is_writeable(struct power_supply *psy,
671 					      enum power_supply_property psp)
672 {
673 	return true;
674 }
675 
676 static const struct power_supply_desc ip5xxx_boost_desc = {
677 	.name			= "ip5xxx-boost",
678 	.type			= POWER_SUPPLY_TYPE_USB,
679 	.properties		= ip5xxx_boost_properties,
680 	.num_properties		= ARRAY_SIZE(ip5xxx_boost_properties),
681 	.get_property		= ip5xxx_boost_get_property,
682 	.set_property		= ip5xxx_boost_set_property,
683 	.property_is_writeable	= ip5xxx_boost_property_is_writeable,
684 };
685 
686 static const struct regmap_config ip5xxx_regmap_config = {
687 	.reg_bits		= 8,
688 	.val_bits		= 8,
689 	.max_register		= 0xa9,
690 };
691 
692 static struct ip5xxx_regfield_config ip51xx_fields = {
693 	.charger_enable = REG_FIELD(0x01, 1, 1),
694 	.charger_const_volt_sel = REG_FIELD(0x24, 1, 2),
695 	.charger_const_curr_sel = REG_FIELD(0x25, 0, 4),
696 	.charger_status = REG_FIELD(0x71, 5, 7),
697 	.charger_chg_end = REG_FIELD(0x71, 3, 3),
698 	.charger_timeout = REG_FIELD(0x71, 0, 2),
699 	.charger_vin_overvolt = REG_FIELD(0x72, 5, 5),
700 	.boost_enable = REG_FIELD(0x01, 2, 2),
701 	.boost_llshdn_enable = REG_FIELD(0x02, 1, 1),
702 	.boost_llshdn_i_limit = REG_FIELD(0x0c, 3, 7),
703 	.boost_load_powerup_en = REG_FIELD(0x02, 0, 0),
704 	.boost_vin_pullout_en = REG_FIELD(0x04, 5, 5),
705 	.boost_undervolt_limit = REG_FIELD(0x22, 2, 3),
706 	.boost_light_load_status = REG_FIELD(0x72, 6, 6),
707 	.battery_ntc_dis = REG_FIELD(0x07, 6, 6),
708 	.battery_type = REG_FIELD(0x24, 5, 6),
709 	.battery_vset_en = REG_FIELD(0x26, 6, 6),
710 	.battery_adc_volt_low = REG_FIELD(0xa2, 0, 7),
711 	.battery_adc_volt_high = REG_FIELD(0xa3, 0, 5),
712 	.battery_adc_curr_low = REG_FIELD(0xa4, 0, 7),
713 	.battery_adc_curr_high = REG_FIELD(0xa5, 0, 5),
714 	.battery_adc_ovolt_low = REG_FIELD(0xa8, 0, 7),
715 	.battery_adc_ovolt_high = REG_FIELD(0xa9, 0, 5),
716 	.btn_shdn_enable = REG_FIELD(0x03, 5, 5),
717 	.btn_wled_mode = REG_FIELD(0x07, 1, 1),
718 	.btn_shdn_mode = REG_FIELD(0x07, 0, 0),
719 	.btn_long_press_time = REG_FIELD(0x03, 6, 7),
720 	.btn_pressed = REG_FIELD(0x77, 3, 3),
721 	.btn_long_pressed = REG_FIELD(0x77, 1, 1),
722 	.btn_short_pressed = REG_FIELD(0x77, 0, 0),
723 	.wled_enable = REG_FIELD(0x01, 3, 3),
724 	.wled_detect_en = REG_FIELD(0x01, 4, 4),
725 	.wled_present = REG_FIELD(0x72, 7, 7),
726 
727 	.vbat_max = 4350000,
728 	.boost_undervolt_setpoint = 4530000,
729 	.boost_undervolt_uv_per_bit = 100000,
730 };
731 
732 static struct ip5xxx_regfield_config ip5306_fields = {
733 	.charger_enable = REG_FIELD(0x00, 4, 4),
734 	.charger_const_volt_sel = REG_FIELD(0x22, 0, 1),
735 	.charger_const_curr_sel = REG_FIELD(0x24, 0, 4),
736 	.charger_status = REG_FIELD_UNSUPPORTED, // other bits...
737 	.charger_chg_end = REG_FIELD(0x71, 3, 3),
738 	.charger_timeout = REG_FIELD_UNSUPPORTED,
739 	.charger_vin_overvolt = REG_FIELD_UNSUPPORTED,
740 	.boost_enable = REG_FIELD(0x00, 5, 5),
741 	.boost_llshdn_enable = REG_FIELD_UNSUPPORTED,
742 	.boost_llshdn_i_limit = REG_FIELD_UNSUPPORTED,
743 	.boost_load_powerup_en = REG_FIELD(0x00, 2, 2),
744 	.boost_vin_pullout_en = REG_FIELD(0x01, 2, 2),
745 	.boost_undervolt_limit = REG_FIELD(0x21, 2, 4),
746 	.boost_light_load_status = REG_FIELD(0x72, 2, 2),
747 	.battery_ntc_dis = REG_FIELD_UNSUPPORTED,
748 	.battery_type = REG_FIELD(0x22, 2, 3),
749 	.battery_vset_en = REG_FIELD_UNSUPPORTED,
750 	.battery_adc_volt_low = REG_FIELD_UNSUPPORTED,
751 	.battery_adc_volt_high = REG_FIELD_UNSUPPORTED,
752 	.battery_adc_curr_low = REG_FIELD_UNSUPPORTED,
753 	.battery_adc_curr_high = REG_FIELD_UNSUPPORTED,
754 	.battery_adc_ovolt_low = REG_FIELD_UNSUPPORTED,
755 	.battery_adc_ovolt_high = REG_FIELD_UNSUPPORTED,
756 	.btn_shdn_enable = REG_FIELD(0x00, 0, 0),
757 	.btn_wled_mode = REG_FIELD(0x01, 6, 6),
758 	.btn_shdn_mode = REG_FIELD(0x01, 7, 7),
759 	.btn_long_press_time = REG_FIELD(0x02, 4, 4), // +1s
760 	.btn_pressed = REG_FIELD_UNSUPPORTED,
761 	/* TODO: double press */
762 	.btn_long_pressed = REG_FIELD(0x77, 1, 1),
763 	.btn_short_pressed = REG_FIELD(0x77, 0, 0),
764 	.wled_enable = REG_FIELD_UNSUPPORTED,
765 	.wled_detect_en = REG_FIELD_UNSUPPORTED,
766 	.wled_present = REG_FIELD_UNSUPPORTED,
767 
768 	.vbat_max = 4400000,
769 	.boost_undervolt_setpoint = 4450000,
770 	.boost_undervolt_uv_per_bit = 50000,
771 	.const_curr_setpoint = 50000,
772 	.chg_end_inverted = 1,
773 };
774 
775 #define ip5xxx_setup_reg(_field, _reg) \
776 			do { \
777 				if (likely(cfg->_field.lsb <= cfg->_field.msb)) { \
778 					struct regmap_field *_tmp = devm_regmap_field_alloc(dev, \
779 							ip5xxx->regmap, cfg->_field); \
780 					if (!IS_ERR(_tmp)) \
781 						ip5xxx->regs._reg = _tmp; \
782 				} \
783 			} while (0)
784 
785 static void ip5xxx_setup_regs(struct device *dev, struct ip5xxx *ip5xxx,
786 			      const struct ip5xxx_regfield_config *cfg)
787 {
788 	ip5xxx_setup_reg(charger_enable, charger.enable);
789 	ip5xxx_setup_reg(charger_const_volt_sel, charger.const_volt_sel);
790 	ip5xxx_setup_reg(charger_const_curr_sel, charger.const_curr_sel);
791 	ip5xxx_setup_reg(charger_status, charger.status);
792 	ip5xxx_setup_reg(charger_chg_end, charger.chg_end);
793 	ip5xxx_setup_reg(charger_timeout, charger.timeout);
794 	ip5xxx_setup_reg(charger_vin_overvolt, charger.vin_overvolt);
795 	ip5xxx_setup_reg(boost_enable, boost.enable);
796 	ip5xxx_setup_reg(boost_llshdn_enable, boost.light_load_shutdown.enable);
797 	ip5xxx_setup_reg(boost_llshdn_i_limit, boost.light_load_shutdown.i_limit);
798 	ip5xxx_setup_reg(boost_load_powerup_en, boost.load_powerup_en);
799 	ip5xxx_setup_reg(boost_vin_pullout_en, boost.vin_pullout_en);
800 	ip5xxx_setup_reg(boost_undervolt_limit, boost.undervolt_limit);
801 	ip5xxx_setup_reg(boost_light_load_status, boost.light_load_status);
802 	ip5xxx_setup_reg(battery_ntc_dis, battery.ntc_dis);
803 	ip5xxx_setup_reg(battery_type, battery.type);
804 	ip5xxx_setup_reg(battery_vset_en, battery.vset_en);
805 	ip5xxx_setup_reg(battery_adc_volt_low, battery.adc.volt.low);
806 	ip5xxx_setup_reg(battery_adc_volt_high, battery.adc.volt.high);
807 	ip5xxx_setup_reg(battery_adc_curr_low, battery.adc.curr.low);
808 	ip5xxx_setup_reg(battery_adc_curr_high, battery.adc.curr.high);
809 	ip5xxx_setup_reg(battery_adc_ovolt_low, battery.adc.open_volt.low);
810 	ip5xxx_setup_reg(battery_adc_ovolt_high, battery.adc.open_volt.high);
811 	ip5xxx_setup_reg(btn_shdn_enable, btn.shdn_enable);
812 	ip5xxx_setup_reg(btn_wled_mode, btn.wled_mode);
813 	ip5xxx_setup_reg(btn_shdn_mode, btn.shdn_mode);
814 	ip5xxx_setup_reg(btn_long_press_time, btn.long_press_time);
815 	ip5xxx_setup_reg(btn_pressed, btn.pressed);
816 	ip5xxx_setup_reg(btn_long_pressed, btn.long_pressed);
817 	ip5xxx_setup_reg(btn_short_pressed, btn.short_pressed);
818 	ip5xxx_setup_reg(wled_enable, wled.enable);
819 	ip5xxx_setup_reg(wled_detect_en, wled.detect_en);
820 	ip5xxx_setup_reg(wled_present, wled.present);
821 
822 	ip5xxx->vbat_max = cfg->vbat_max;
823 	ip5xxx->boost_undervolt.setpoint = cfg->boost_undervolt_setpoint;
824 	ip5xxx->boost_undervolt.microvolts_per_bit = cfg->boost_undervolt_uv_per_bit;
825 	ip5xxx->const_curr.setpoint = cfg->const_curr_setpoint;
826 	ip5xxx->chg_end_inverted = cfg->chg_end_inverted;
827 }
828 
829 static int ip5xxx_power_probe(struct i2c_client *client)
830 {
831 	const struct ip5xxx_regfield_config *fields = &ip51xx_fields;
832 	struct power_supply_config psy_cfg = {};
833 	struct device *dev = &client->dev;
834 	const struct of_device_id *of_id;
835 	struct power_supply *psy;
836 	struct ip5xxx *ip5xxx;
837 
838 	ip5xxx = devm_kzalloc(dev, sizeof(*ip5xxx), GFP_KERNEL);
839 	if (!ip5xxx)
840 		return -ENOMEM;
841 
842 	ip5xxx->regmap = devm_regmap_init_i2c(client, &ip5xxx_regmap_config);
843 	if (IS_ERR(ip5xxx->regmap))
844 		return PTR_ERR(ip5xxx->regmap);
845 
846 	of_id = i2c_of_match_device(dev->driver->of_match_table, client);
847 	if (of_id)
848 		fields = (const struct ip5xxx_regfield_config *)of_id->data;
849 	ip5xxx_setup_regs(dev, ip5xxx, fields);
850 
851 	psy_cfg.of_node = dev->of_node;
852 	psy_cfg.drv_data = ip5xxx;
853 
854 	psy = devm_power_supply_register(dev, &ip5xxx_battery_desc, &psy_cfg);
855 	if (IS_ERR(psy))
856 		return PTR_ERR(psy);
857 
858 	psy = devm_power_supply_register(dev, &ip5xxx_boost_desc, &psy_cfg);
859 	if (IS_ERR(psy))
860 		return PTR_ERR(psy);
861 
862 	return 0;
863 }
864 
865 static const struct of_device_id ip5xxx_power_of_match[] = {
866 	{ .compatible = "injoinic,ip5108", .data = &ip51xx_fields },
867 	{ .compatible = "injoinic,ip5109", .data = &ip51xx_fields },
868 	{ .compatible = "injoinic,ip5207", .data = &ip51xx_fields },
869 	{ .compatible = "injoinic,ip5209", .data = &ip51xx_fields },
870 	{ .compatible = "injoinic,ip5306", .data = &ip5306_fields },
871 	{ }
872 };
873 MODULE_DEVICE_TABLE(of, ip5xxx_power_of_match);
874 
875 static struct i2c_driver ip5xxx_power_driver = {
876 	.probe		= ip5xxx_power_probe,
877 	.driver		= {
878 		.name		= "ip5xxx-power",
879 		.of_match_table	= ip5xxx_power_of_match,
880 	}
881 };
882 module_i2c_driver(ip5xxx_power_driver);
883 
884 MODULE_AUTHOR("Samuel Holland <samuel@sholland.org>");
885 MODULE_DESCRIPTION("Injoinic IP5xxx power bank IC driver");
886 MODULE_LICENSE("GPL");
887