1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // Copyright (C) 2021 Samuel Holland <[email protected]>
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 */
ip5xxx_read(struct ip5xxx * ip5xxx,struct regmap_field * field,unsigned int * val)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
ip5xxx_write(struct ip5xxx * ip5xxx,struct regmap_field * field,unsigned int val)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
ip5xxx_initialize(struct power_supply * psy)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
ip5xxx_battery_get_status(struct ip5xxx * ip5xxx,int * val)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
ip5xxx_battery_get_charge_type(struct ip5xxx * ip5xxx,int * val)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
ip5xxx_battery_get_health(struct ip5xxx * ip5xxx,int * val)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
ip5xxx_battery_get_voltage_max(struct ip5xxx * ip5xxx,int * val)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
ip5xxx_battery_read_adc(struct ip5xxx * ip5xxx,struct ip5xxx_battery_adc_regs * regs,int * val)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
ip5xxx_battery_get_property(struct power_supply * psy,enum power_supply_property psp,union power_supply_propval * val)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
ip5xxx_battery_set_voltage_max(struct ip5xxx * ip5xxx,int val)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
ip5xxx_battery_set_property(struct power_supply * psy,enum power_supply_property psp,const union power_supply_propval * val)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
ip5xxx_battery_property_is_writeable(struct power_supply * psy,enum power_supply_property psp)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
ip5xxx_boost_get_property(struct power_supply * psy,enum power_supply_property psp,union power_supply_propval * val)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
ip5xxx_boost_set_property(struct power_supply * psy,enum power_supply_property psp,const union power_supply_propval * val)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
ip5xxx_boost_property_is_writeable(struct power_supply * psy,enum power_supply_property psp)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
ip5xxx_setup_regs(struct device * dev,struct ip5xxx * ip5xxx,const struct ip5xxx_regfield_config * cfg)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
ip5xxx_power_probe(struct i2c_client * client)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 <[email protected]>");
885 MODULE_DESCRIPTION("Injoinic IP5xxx power bank IC driver");
886 MODULE_LICENSE("GPL");
887