Merge tag 'for-v6.1-rc' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux...
[sfrench/cifs-2.6.git] / drivers / power / supply / ip5xxx_power.c
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  */
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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_new      = 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");