1// SPDX-License-Identifier: GPL-2.0-or-later
2/* ROHM BD71815, BD71828 and BD71878 Charger driver */
3
4#include <linux/interrupt.h>
5#include <linux/kernel.h>
6#include <linux/mfd/rohm-bd71815.h>
7#include <linux/mfd/rohm-bd71828.h>
8#include <linux/module.h>
9#include <linux/mod_devicetable.h>
10#include <linux/platform_device.h>
11#include <linux/property.h>
12#include <linux/power_supply.h>
13#include <linux/slab.h>
14
15/* common defines */
16#define BD7182x_MASK_VBAT_U 0x1f
17#define BD7182x_MASK_VDCIN_U 0x0f
18#define BD7182x_MASK_IBAT_U 0x3f
19#define BD7182x_MASK_CURDIR_DISCHG 0x80
20#define BD7182x_MASK_CHG_STATE 0x7f
21#define BD7182x_MASK_BAT_TEMP 0x07
22#define BD7182x_MASK_DCIN_DET BIT(0)
23#define BD7182x_MASK_CONF_PON BIT(0)
24#define BD71815_MASK_CONF_XSTB BIT(1)
25#define BD7182x_MASK_BAT_STAT 0x3f
26#define BD7182x_MASK_DCIN_STAT 0x07
27
28#define BD7182x_MASK_WDT_AUTO 0x40
29#define BD7182x_MASK_VBAT_ALM_LIMIT_U 0x01
30#define BD7182x_MASK_CHG_EN 0x01
31
32#define BD7182x_DCIN_COLLAPSE_DEFAULT 0x36
33
34#define MAX_CURRENT_DEFAULT 890000 /* uA */
35#define AC_NAME "bd71828_ac"
36#define BAT_NAME "bd71828_bat"
37
38#define BAT_OPEN 0x7
39
40/*
41 * VBAT Low voltage detection Threshold
42 * 0x00D4*16mV = 212*0.016 = 3.392v
43 */
44#define VBAT_LOW_TH 0x00D4
45
46struct pwr_regs {
47 u8 vbat_avg;
48 u8 ibat;
49 u8 ibat_avg;
50 u8 btemp_vth;
51 u8 chg_state;
52 u8 bat_temp;
53 u8 dcin_stat;
54 u8 dcin_collapse_limit;
55 u8 chg_set1;
56 u8 chg_en;
57 u8 vbat_alm_limit_u;
58 u8 conf;
59 u8 vdcin;
60};
61
62static const struct pwr_regs pwr_regs_bd71828 = {
63 .vbat_avg = BD71828_REG_VBAT_U,
64 .ibat = BD71828_REG_IBAT_U,
65 .ibat_avg = BD71828_REG_IBAT_AVG_U,
66 .btemp_vth = BD71828_REG_VM_BTMP_U,
67 .chg_state = BD71828_REG_CHG_STATE,
68 .bat_temp = BD71828_REG_BAT_TEMP,
69 .dcin_stat = BD71828_REG_DCIN_STAT,
70 .dcin_collapse_limit = BD71828_REG_DCIN_CLPS,
71 .chg_set1 = BD71828_REG_CHG_SET1,
72 .chg_en = BD71828_REG_CHG_EN,
73 .vbat_alm_limit_u = BD71828_REG_ALM_VBAT_LIMIT_U,
74 .conf = BD71828_REG_CONF,
75 .vdcin = BD71828_REG_VDCIN_U,
76};
77
78static const struct pwr_regs pwr_regs_bd71815 = {
79 .vbat_avg = BD71815_REG_VM_SA_VBAT_U,
80 /* BD71815 does not have separate current and current avg */
81 .ibat = BD71815_REG_CC_CURCD_U,
82 .ibat_avg = BD71815_REG_CC_CURCD_U,
83
84 .btemp_vth = BD71815_REG_VM_BTMP,
85 .chg_state = BD71815_REG_CHG_STATE,
86 .bat_temp = BD71815_REG_BAT_TEMP,
87 .dcin_stat = BD71815_REG_DCIN_STAT,
88 .dcin_collapse_limit = BD71815_REG_DCIN_CLPS,
89 .chg_set1 = BD71815_REG_CHG_SET1,
90 .chg_en = BD71815_REG_CHG_SET1,
91 .vbat_alm_limit_u = BD71815_REG_ALM_VBAT_TH_U,
92 .conf = BD71815_REG_CONF,
93
94 .vdcin = BD71815_REG_VM_DCIN_U,
95};
96
97struct bd71828_power {
98 struct regmap *regmap;
99 enum rohm_chip_type chip_type;
100 struct device *dev;
101 struct power_supply *ac;
102 struct power_supply *bat;
103
104 const struct pwr_regs *regs;
105 /* Reg val to uA */
106 int curr_factor;
107 int rsens;
108 int (*get_temp)(struct bd71828_power *pwr, int *temp);
109 int (*bat_inserted)(struct bd71828_power *pwr);
110};
111
112static int bd7182x_write16(struct bd71828_power *pwr, int reg, u16 val)
113{
114 __be16 tmp;
115
116 tmp = cpu_to_be16(val);
117
118 return regmap_bulk_write(map: pwr->regmap, reg, val: &tmp, val_count: sizeof(tmp));
119}
120
121static int bd7182x_read16_himask(struct bd71828_power *pwr, int reg, int himask,
122 u16 *val)
123{
124 struct regmap *regmap = pwr->regmap;
125 int ret;
126 __be16 rvals;
127 u8 *tmp = (u8 *)&rvals;
128
129 ret = regmap_bulk_read(map: regmap, reg, val: &rvals, val_count: sizeof(*val));
130 if (!ret) {
131 *tmp &= himask;
132 *val = be16_to_cpu(rvals);
133 }
134
135 return ret;
136}
137
138static int bd71828_get_vbat(struct bd71828_power *pwr, int *vcell)
139{
140 u16 tmp_vcell;
141 int ret;
142
143 ret = bd7182x_read16_himask(pwr, reg: pwr->regs->vbat_avg,
144 BD7182x_MASK_VBAT_U, val: &tmp_vcell);
145 if (ret)
146 dev_err(pwr->dev, "Failed to read battery average voltage\n");
147 else
148 *vcell = ((int)tmp_vcell) * 1000;
149
150 return ret;
151}
152
153static int bd71828_get_current_ds_adc(struct bd71828_power *pwr, int *curr, int *curr_avg)
154{
155 __be16 tmp_curr;
156 char *tmp = (char *)&tmp_curr;
157 int dir = 1;
158 int regs[] = { pwr->regs->ibat, pwr->regs->ibat_avg };
159 int *vals[] = { curr, curr_avg };
160 int ret, i;
161
162 for (dir = 1, i = 0; i < ARRAY_SIZE(regs); i++) {
163 ret = regmap_bulk_read(map: pwr->regmap, reg: regs[i], val: &tmp_curr,
164 val_count: sizeof(tmp_curr));
165 if (ret)
166 break;
167
168 if (*tmp & BD7182x_MASK_CURDIR_DISCHG)
169 dir = -1;
170
171 *tmp &= BD7182x_MASK_IBAT_U;
172
173 *vals[i] = dir * ((int)be16_to_cpu(tmp_curr)) * pwr->curr_factor;
174 }
175
176 return ret;
177}
178
179/* Unit is tenths of degree C */
180static int bd71815_get_temp(struct bd71828_power *pwr, int *temp)
181{
182 struct regmap *regmap = pwr->regmap;
183 int ret;
184 int t;
185
186 ret = regmap_read(map: regmap, reg: pwr->regs->btemp_vth, val: &t);
187 if (ret)
188 return ret;
189
190 t = 200 - t;
191
192 if (t > 200) {
193 dev_err(pwr->dev, "Failed to read battery temperature\n");
194 return -ENODATA;
195 }
196
197 return 0;
198}
199
200/* Unit is tenths of degree C */
201static int bd71828_get_temp(struct bd71828_power *pwr, int *temp)
202{
203 u16 t;
204 int ret;
205 int tmp = 200 * 10000;
206
207 ret = bd7182x_read16_himask(pwr, reg: pwr->regs->btemp_vth,
208 BD71828_MASK_VM_BTMP_U, val: &t);
209 if (ret)
210 return ret;
211
212 if (t > 3200) {
213 dev_err(pwr->dev,
214 "Failed to read battery temperature\n");
215 return -ENODATA;
216 }
217
218 tmp -= 625ULL * (unsigned int)t;
219 *temp = tmp / 1000;
220
221 return ret;
222}
223
224static int bd71828_charge_status(struct bd71828_power *pwr,
225 int *s, int *h)
226{
227 unsigned int state;
228 int status, health;
229 int ret = 1;
230
231 ret = regmap_read(map: pwr->regmap, reg: pwr->regs->chg_state, val: &state);
232 if (ret) {
233 dev_err(pwr->dev, "charger status reading failed (%d)\n", ret);
234 return ret;
235 }
236
237 state &= BD7182x_MASK_CHG_STATE;
238
239 dev_dbg(pwr->dev, "CHG_STATE %d\n", state);
240
241 switch (state) {
242 case 0x00:
243 status = POWER_SUPPLY_STATUS_DISCHARGING;
244 health = POWER_SUPPLY_HEALTH_GOOD;
245 break;
246 case 0x01:
247 case 0x02:
248 case 0x03:
249 case 0x0E:
250 status = POWER_SUPPLY_STATUS_CHARGING;
251 health = POWER_SUPPLY_HEALTH_GOOD;
252 break;
253 case 0x0F:
254 status = POWER_SUPPLY_STATUS_FULL;
255 health = POWER_SUPPLY_HEALTH_GOOD;
256 break;
257 case 0x10:
258 case 0x11:
259 case 0x12:
260 case 0x13:
261 case 0x14:
262 case 0x20:
263 case 0x21:
264 case 0x22:
265 case 0x23:
266 case 0x24:
267 status = POWER_SUPPLY_STATUS_NOT_CHARGING;
268 health = POWER_SUPPLY_HEALTH_OVERHEAT;
269 break;
270 case 0x30:
271 case 0x31:
272 case 0x32:
273 case 0x40:
274 status = POWER_SUPPLY_STATUS_DISCHARGING;
275 health = POWER_SUPPLY_HEALTH_GOOD;
276 break;
277 case 0x7f:
278 default:
279 status = POWER_SUPPLY_STATUS_NOT_CHARGING;
280 health = POWER_SUPPLY_HEALTH_DEAD;
281 break;
282 }
283
284 if (s)
285 *s = status;
286 if (h)
287 *h = health;
288
289 return ret;
290}
291
292static int get_chg_online(struct bd71828_power *pwr, int *chg_online)
293{
294 int r, ret;
295
296 ret = regmap_read(map: pwr->regmap, reg: pwr->regs->dcin_stat, val: &r);
297 if (ret) {
298 dev_err(pwr->dev, "Failed to read DCIN status\n");
299 return ret;
300 }
301 *chg_online = ((r & BD7182x_MASK_DCIN_DET) != 0);
302
303 return 0;
304}
305
306static int get_bat_online(struct bd71828_power *pwr, int *bat_online)
307{
308 int r, ret;
309
310 ret = regmap_read(map: pwr->regmap, reg: pwr->regs->bat_temp, val: &r);
311 if (ret) {
312 dev_err(pwr->dev, "Failed to read battery temperature\n");
313 return ret;
314 }
315 *bat_online = ((r & BD7182x_MASK_BAT_TEMP) != BAT_OPEN);
316
317 return 0;
318}
319
320static int bd71828_bat_inserted(struct bd71828_power *pwr)
321{
322 int ret, val;
323
324 ret = regmap_read(map: pwr->regmap, reg: pwr->regs->conf, val: &val);
325 if (ret) {
326 dev_err(pwr->dev, "Failed to read CONF register\n");
327 return 0;
328 }
329 ret = val & BD7182x_MASK_CONF_PON;
330
331 if (ret)
332 regmap_update_bits(map: pwr->regmap, reg: pwr->regs->conf,
333 BD7182x_MASK_CONF_PON, val: 0);
334
335 return ret;
336}
337
338static int bd71815_bat_inserted(struct bd71828_power *pwr)
339{
340 int ret, val;
341
342 ret = regmap_read(map: pwr->regmap, reg: pwr->regs->conf, val: &val);
343 if (ret) {
344 dev_err(pwr->dev, "Failed to read CONF register\n");
345 return ret;
346 }
347
348 ret = !(val & BD71815_MASK_CONF_XSTB);
349 if (ret)
350 regmap_write(map: pwr->regmap, reg: pwr->regs->conf, val: val |
351 BD71815_MASK_CONF_XSTB);
352
353 return ret;
354}
355
356static int bd71828_init_hardware(struct bd71828_power *pwr)
357{
358 int ret;
359
360 /* TODO: Collapse limit should come from device-tree ? */
361 ret = regmap_write(map: pwr->regmap, reg: pwr->regs->dcin_collapse_limit,
362 BD7182x_DCIN_COLLAPSE_DEFAULT);
363 if (ret) {
364 dev_err(pwr->dev, "Failed to write DCIN collapse limit\n");
365 return ret;
366 }
367
368 ret = pwr->bat_inserted(pwr);
369 if (ret < 0)
370 return ret;
371
372 if (ret) {
373 /* WDT_FST auto set */
374 ret = regmap_update_bits(map: pwr->regmap, reg: pwr->regs->chg_set1,
375 BD7182x_MASK_WDT_AUTO,
376 BD7182x_MASK_WDT_AUTO);
377 if (ret)
378 return ret;
379
380 ret = bd7182x_write16(pwr, reg: pwr->regs->vbat_alm_limit_u,
381 VBAT_LOW_TH);
382 if (ret)
383 return ret;
384
385 /*
386 * On BD71815 "we mask the power-state" from relax detection.
387 * I am unsure what the impact of the power-state would be if
388 * we didn't - but this is what the vendor driver did - and
389 * that driver has been used in few projects so I just assume
390 * this is needed.
391 */
392 if (pwr->chip_type == ROHM_CHIP_TYPE_BD71815) {
393 ret = regmap_set_bits(map: pwr->regmap,
394 reg: BD71815_REG_REX_CTRL_1,
395 REX_PMU_STATE_MASK);
396 if (ret)
397 return ret;
398 }
399 }
400
401 return 0;
402}
403
404static int bd71828_charger_get_property(struct power_supply *psy,
405 enum power_supply_property psp,
406 union power_supply_propval *val)
407{
408 struct bd71828_power *pwr = dev_get_drvdata(dev: psy->dev.parent);
409 u32 vot;
410 u16 tmp;
411 int online;
412 int ret;
413
414 switch (psp) {
415 case POWER_SUPPLY_PROP_ONLINE:
416 ret = get_chg_online(pwr, chg_online: &online);
417 if (!ret)
418 val->intval = online;
419 break;
420 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
421 ret = bd7182x_read16_himask(pwr, reg: pwr->regs->vdcin,
422 BD7182x_MASK_VDCIN_U, val: &tmp);
423 if (ret)
424 return ret;
425
426 vot = tmp;
427 /* 5 milli volt steps */
428 val->intval = 5000 * vot;
429 break;
430 default:
431 return -EINVAL;
432 }
433
434 return 0;
435}
436
437static int bd71828_battery_get_property(struct power_supply *psy,
438 enum power_supply_property psp,
439 union power_supply_propval *val)
440{
441 struct bd71828_power *pwr = dev_get_drvdata(dev: psy->dev.parent);
442 int ret = 0;
443 int status, health, tmp, curr, curr_avg, chg_en;
444
445 if (psp == POWER_SUPPLY_PROP_STATUS ||
446 psp == POWER_SUPPLY_PROP_HEALTH ||
447 psp == POWER_SUPPLY_PROP_CHARGE_TYPE)
448 ret = bd71828_charge_status(pwr, s: &status, h: &health);
449 else if (psp == POWER_SUPPLY_PROP_CURRENT_AVG ||
450 psp == POWER_SUPPLY_PROP_CURRENT_NOW)
451 ret = bd71828_get_current_ds_adc(pwr, curr: &curr, curr_avg: &curr_avg);
452 if (ret)
453 return ret;
454
455 switch (psp) {
456 case POWER_SUPPLY_PROP_STATUS:
457 val->intval = status;
458 break;
459 case POWER_SUPPLY_PROP_HEALTH:
460 val->intval = health;
461 break;
462 case POWER_SUPPLY_PROP_PRESENT:
463 ret = get_bat_online(pwr, bat_online: &tmp);
464 if (!ret)
465 val->intval = tmp;
466 break;
467 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
468 ret = bd71828_get_vbat(pwr, vcell: &tmp);
469 val->intval = tmp;
470 break;
471 case POWER_SUPPLY_PROP_TECHNOLOGY:
472 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
473 break;
474 case POWER_SUPPLY_PROP_CURRENT_AVG:
475 val->intval = curr_avg;
476 break;
477 case POWER_SUPPLY_PROP_CURRENT_NOW:
478 val->intval = curr;
479 break;
480 case POWER_SUPPLY_PROP_CURRENT_MAX:
481 val->intval = MAX_CURRENT_DEFAULT;
482 break;
483 case POWER_SUPPLY_PROP_TEMP:
484 ret = pwr->get_temp(pwr, &val->intval);
485 break;
486 case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
487 ret = regmap_read(map: pwr->regmap, reg: pwr->regs->chg_en, val: &chg_en);
488 if (ret)
489 return ret;
490
491 val->intval = (chg_en & BD7182x_MASK_CHG_EN) ?
492 POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO :
493 POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE;
494 break;
495 default:
496 ret = -EINVAL;
497 break;
498 }
499
500 return ret;
501}
502
503static int bd71828_battery_set_property(struct power_supply *psy,
504 enum power_supply_property psp,
505 const union power_supply_propval *val)
506{
507 struct bd71828_power *pwr = dev_get_drvdata(dev: psy->dev.parent);
508 int ret = 0;
509
510 switch (psp) {
511 case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
512 if (val->intval == POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO)
513 ret = regmap_update_bits(map: pwr->regmap, reg: pwr->regs->chg_en,
514 BD7182x_MASK_CHG_EN,
515 BD7182x_MASK_CHG_EN);
516 else
517 ret = regmap_update_bits(map: pwr->regmap, reg: pwr->regs->chg_en,
518 BD7182x_MASK_CHG_EN,
519 val: 0);
520 break;
521 default:
522 return -EINVAL;
523 }
524
525 return ret;
526}
527
528static int bd71828_battery_property_is_writeable(struct power_supply *psy,
529 enum power_supply_property psp)
530{
531 switch (psp) {
532 case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
533 return true;
534 default:
535 return false;
536 }
537}
538
539/** @brief ac properties */
540static const enum power_supply_property bd71828_charger_props[] = {
541 POWER_SUPPLY_PROP_ONLINE,
542 POWER_SUPPLY_PROP_VOLTAGE_NOW,
543};
544
545static const enum power_supply_property bd71828_battery_props[] = {
546 POWER_SUPPLY_PROP_STATUS,
547 POWER_SUPPLY_PROP_HEALTH,
548 POWER_SUPPLY_PROP_VOLTAGE_NOW,
549 POWER_SUPPLY_PROP_HEALTH,
550 POWER_SUPPLY_PROP_PRESENT,
551 POWER_SUPPLY_PROP_TECHNOLOGY,
552 POWER_SUPPLY_PROP_TEMP,
553 POWER_SUPPLY_PROP_CURRENT_AVG,
554 POWER_SUPPLY_PROP_CURRENT_NOW,
555 POWER_SUPPLY_PROP_CURRENT_MAX,
556 POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR,
557};
558
559/** @brief powers supplied by bd71828_ac */
560static char *bd71828_ac_supplied_to[] = {
561 BAT_NAME,
562};
563
564static const struct power_supply_desc bd71828_ac_desc = {
565 .name = AC_NAME,
566 .type = POWER_SUPPLY_TYPE_MAINS,
567 .properties = bd71828_charger_props,
568 .num_properties = ARRAY_SIZE(bd71828_charger_props),
569 .get_property = bd71828_charger_get_property,
570};
571
572static const struct power_supply_desc bd71828_bat_desc = {
573 .name = BAT_NAME,
574 .type = POWER_SUPPLY_TYPE_BATTERY,
575 .charge_behaviours = BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO) |
576 BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE),
577 .properties = bd71828_battery_props,
578 .num_properties = ARRAY_SIZE(bd71828_battery_props),
579 .get_property = bd71828_battery_get_property,
580 .set_property = bd71828_battery_set_property,
581 .property_is_writeable = bd71828_battery_property_is_writeable,
582};
583
584#define RSENS_CURR 10000000LLU
585
586#define BD_ISR_NAME(name) \
587bd7181x_##name##_isr
588
589#define BD_ISR_BAT(name, print, run_gauge) \
590static irqreturn_t BD_ISR_NAME(name)(int irq, void *data) \
591{ \
592 struct bd71828_power *pwr = (struct bd71828_power *)data; \
593 \
594 dev_dbg(pwr->dev, "%s\n", print); \
595 power_supply_changed(pwr->bat); \
596 \
597 return IRQ_HANDLED; \
598}
599
600#define BD_ISR_AC(name, print, run_gauge) \
601static irqreturn_t BD_ISR_NAME(name)(int irq, void *data) \
602{ \
603 struct bd71828_power *pwr = (struct bd71828_power *)data; \
604 \
605 power_supply_changed(pwr->ac); \
606 dev_dbg(pwr->dev, "%s\n", print); \
607 power_supply_changed(pwr->bat); \
608 \
609 return IRQ_HANDLED; \
610}
611
612#define BD_ISR_DUMMY(name, print) \
613static irqreturn_t BD_ISR_NAME(name)(int irq, void *data) \
614{ \
615 struct bd71828_power *pwr = (struct bd71828_power *)data; \
616 \
617 dev_dbg(pwr->dev, "%s\n", print); \
618 \
619 return IRQ_HANDLED; \
620}
621
622BD_ISR_BAT(chg_state_changed, "CHG state changed", true)
623/* DCIN voltage changes */
624BD_ISR_AC(dcin_removed, "DCIN removed", true)
625BD_ISR_AC(clps_out, "DCIN voltage back to normal", true)
626BD_ISR_AC(clps_in, "DCIN voltage collapsed", false)
627BD_ISR_AC(dcin_ovp_res, "DCIN voltage normal", true)
628BD_ISR_AC(dcin_ovp_det, "DCIN OVER VOLTAGE", true)
629
630BD_ISR_DUMMY(dcin_mon_det, "DCIN voltage below threshold")
631BD_ISR_DUMMY(dcin_mon_res, "DCIN voltage above threshold")
632
633BD_ISR_DUMMY(vsys_uv_res, "VSYS under-voltage cleared")
634BD_ISR_DUMMY(vsys_uv_det, "VSYS under-voltage")
635BD_ISR_DUMMY(vsys_low_res, "'VSYS low' cleared")
636BD_ISR_DUMMY(vsys_low_det, "VSYS low")
637BD_ISR_DUMMY(vsys_mon_res, "VSYS mon - resumed")
638BD_ISR_DUMMY(vsys_mon_det, "VSYS mon - detected")
639BD_ISR_BAT(chg_wdg_temp, "charger temperature watchdog triggered", true)
640BD_ISR_BAT(chg_wdg, "charging watchdog triggered", true)
641BD_ISR_BAT(bat_removed, "Battery removed", true)
642BD_ISR_BAT(bat_det, "Battery detected", true)
643/* TODO: Verify the meaning of these interrupts */
644BD_ISR_BAT(rechg_det, "Recharging", true)
645BD_ISR_BAT(rechg_res, "Recharge ending", true)
646BD_ISR_DUMMY(temp_transit, "Temperature transition")
647BD_ISR_BAT(therm_rmv, "bd71815-therm-rmv", false)
648BD_ISR_BAT(therm_det, "bd71815-therm-det", true)
649BD_ISR_BAT(bat_dead, "bd71815-bat-dead", false)
650BD_ISR_BAT(bat_short_res, "bd71815-bat-short-res", true)
651BD_ISR_BAT(bat_short, "bd71815-bat-short-det", false)
652BD_ISR_BAT(bat_low_res, "bd71815-bat-low-res", true)
653BD_ISR_BAT(bat_low, "bd71815-bat-low-det", true)
654BD_ISR_BAT(bat_ov_res, "bd71815-bat-over-res", true)
655/* What should we do here? */
656BD_ISR_BAT(bat_ov, "bd71815-bat-over-det", false)
657BD_ISR_BAT(bat_mon_res, "bd71815-bat-mon-res", true)
658BD_ISR_BAT(bat_mon, "bd71815-bat-mon-det", true)
659BD_ISR_BAT(bat_cc_mon, "bd71815-bat-cc-mon2", false)
660BD_ISR_BAT(bat_oc1_res, "bd71815-bat-oc1-res", true)
661BD_ISR_BAT(bat_oc1, "bd71815-bat-oc1-det", false)
662BD_ISR_BAT(bat_oc2_res, "bd71815-bat-oc2-res", true)
663BD_ISR_BAT(bat_oc2, "bd71815-bat-oc2-det", false)
664BD_ISR_BAT(bat_oc3_res, "bd71815-bat-oc3-res", true)
665BD_ISR_BAT(bat_oc3, "bd71815-bat-oc3-det", false)
666BD_ISR_BAT(temp_bat_low_res, "bd71815-temp-bat-low-res", true)
667BD_ISR_BAT(temp_bat_low, "bd71815-temp-bat-low-det", true)
668BD_ISR_BAT(temp_bat_hi_res, "bd71815-temp-bat-hi-res", true)
669BD_ISR_BAT(temp_bat_hi, "bd71815-temp-bat-hi-det", true)
670
671static irqreturn_t bd7182x_dcin_removed(int irq, void *data)
672{
673 struct bd71828_power *pwr = (struct bd71828_power *)data;
674
675 power_supply_changed(psy: pwr->ac);
676 dev_dbg(pwr->dev, "DCIN removed\n");
677
678 return IRQ_HANDLED;
679}
680
681static irqreturn_t bd718x7_chg_done(int irq, void *data)
682{
683 struct bd71828_power *pwr = (struct bd71828_power *)data;
684
685 power_supply_changed(psy: pwr->bat);
686
687 return IRQ_HANDLED;
688}
689
690static irqreturn_t bd7182x_dcin_detected(int irq, void *data)
691{
692 struct bd71828_power *pwr = (struct bd71828_power *)data;
693
694 dev_dbg(pwr->dev, "DCIN inserted\n");
695 power_supply_changed(psy: pwr->ac);
696
697 return IRQ_HANDLED;
698}
699
700static irqreturn_t bd71828_vbat_low_res(int irq, void *data)
701{
702 struct bd71828_power *pwr = (struct bd71828_power *)data;
703
704 dev_dbg(pwr->dev, "VBAT LOW Resumed\n");
705
706 return IRQ_HANDLED;
707}
708
709static irqreturn_t bd71828_vbat_low_det(int irq, void *data)
710{
711 struct bd71828_power *pwr = (struct bd71828_power *)data;
712
713 dev_dbg(pwr->dev, "VBAT LOW Detected\n");
714
715 return IRQ_HANDLED;
716}
717
718static irqreturn_t bd71828_temp_bat_hi_det(int irq, void *data)
719{
720 struct bd71828_power *pwr = (struct bd71828_power *)data;
721
722 dev_warn(pwr->dev, "Overtemp Detected\n");
723 power_supply_changed(psy: pwr->bat);
724
725 return IRQ_HANDLED;
726}
727
728static irqreturn_t bd71828_temp_bat_hi_res(int irq, void *data)
729{
730 struct bd71828_power *pwr = (struct bd71828_power *)data;
731
732 dev_dbg(pwr->dev, "Overtemp Resumed\n");
733 power_supply_changed(psy: pwr->bat);
734
735 return IRQ_HANDLED;
736}
737
738static irqreturn_t bd71828_temp_bat_low_det(int irq, void *data)
739{
740 struct bd71828_power *pwr = (struct bd71828_power *)data;
741
742 dev_dbg(pwr->dev, "Lowtemp Detected\n");
743 power_supply_changed(psy: pwr->bat);
744
745 return IRQ_HANDLED;
746}
747
748static irqreturn_t bd71828_temp_bat_low_res(int irq, void *data)
749{
750 struct bd71828_power *pwr = (struct bd71828_power *)data;
751
752 dev_dbg(pwr->dev, "Lowtemp Resumed\n");
753 power_supply_changed(psy: pwr->bat);
754
755 return IRQ_HANDLED;
756}
757
758static irqreturn_t bd71828_temp_vf_det(int irq, void *data)
759{
760 struct bd71828_power *pwr = (struct bd71828_power *)data;
761
762 dev_dbg(pwr->dev, "VF Detected\n");
763 power_supply_changed(psy: pwr->bat);
764
765 return IRQ_HANDLED;
766}
767
768static irqreturn_t bd71828_temp_vf_res(int irq, void *data)
769{
770 struct bd71828_power *pwr = (struct bd71828_power *)data;
771
772 dev_dbg(pwr->dev, "VF Resumed\n");
773 power_supply_changed(psy: pwr->bat);
774
775 return IRQ_HANDLED;
776}
777
778static irqreturn_t bd71828_temp_vf125_det(int irq, void *data)
779{
780 struct bd71828_power *pwr = (struct bd71828_power *)data;
781
782 dev_dbg(pwr->dev, "VF125 Detected\n");
783 power_supply_changed(psy: pwr->bat);
784
785 return IRQ_HANDLED;
786}
787
788static irqreturn_t bd71828_temp_vf125_res(int irq, void *data)
789{
790 struct bd71828_power *pwr = (struct bd71828_power *)data;
791
792 dev_dbg(pwr->dev, "VF125 Resumed\n");
793 power_supply_changed(psy: pwr->bat);
794
795 return IRQ_HANDLED;
796}
797
798struct bd7182x_irq_res {
799 const char *name;
800 irq_handler_t handler;
801};
802
803#define BDIRQ(na, hn) { .name = (na), .handler = (hn) }
804
805static int bd7182x_get_irqs(struct platform_device *pdev,
806 struct bd71828_power *pwr)
807{
808 int i, irq, ret;
809 static const struct bd7182x_irq_res bd71815_irqs[] = {
810 BDIRQ("bd71815-dcin-rmv", BD_ISR_NAME(dcin_removed)),
811 BDIRQ("bd71815-dcin-clps-out", BD_ISR_NAME(clps_out)),
812 BDIRQ("bd71815-dcin-clps-in", BD_ISR_NAME(clps_in)),
813 BDIRQ("bd71815-dcin-ovp-res", BD_ISR_NAME(dcin_ovp_res)),
814 BDIRQ("bd71815-dcin-ovp-det", BD_ISR_NAME(dcin_ovp_det)),
815 BDIRQ("bd71815-dcin-mon-res", BD_ISR_NAME(dcin_mon_res)),
816 BDIRQ("bd71815-dcin-mon-det", BD_ISR_NAME(dcin_mon_det)),
817
818 BDIRQ("bd71815-vsys-uv-res", BD_ISR_NAME(vsys_uv_res)),
819 BDIRQ("bd71815-vsys-uv-det", BD_ISR_NAME(vsys_uv_det)),
820 BDIRQ("bd71815-vsys-low-res", BD_ISR_NAME(vsys_low_res)),
821 BDIRQ("bd71815-vsys-low-det", BD_ISR_NAME(vsys_low_det)),
822 BDIRQ("bd71815-vsys-mon-res", BD_ISR_NAME(vsys_mon_res)),
823 BDIRQ("bd71815-vsys-mon-det", BD_ISR_NAME(vsys_mon_det)),
824 BDIRQ("bd71815-chg-wdg-temp", BD_ISR_NAME(chg_wdg_temp)),
825 BDIRQ("bd71815-chg-wdg", BD_ISR_NAME(chg_wdg)),
826 BDIRQ("bd71815-rechg-det", BD_ISR_NAME(rechg_det)),
827 BDIRQ("bd71815-rechg-res", BD_ISR_NAME(rechg_res)),
828 BDIRQ("bd71815-ranged-temp-transit", BD_ISR_NAME(temp_transit)),
829 BDIRQ("bd71815-chg-state-change", BD_ISR_NAME(chg_state_changed)),
830 BDIRQ("bd71815-bat-temp-normal", bd71828_temp_bat_hi_res),
831 BDIRQ("bd71815-bat-temp-erange", bd71828_temp_bat_hi_det),
832 BDIRQ("bd71815-bat-rmv", BD_ISR_NAME(bat_removed)),
833 BDIRQ("bd71815-bat-det", BD_ISR_NAME(bat_det)),
834
835 /* Add ISRs for these */
836 BDIRQ("bd71815-therm-rmv", BD_ISR_NAME(therm_rmv)),
837 BDIRQ("bd71815-therm-det", BD_ISR_NAME(therm_det)),
838 BDIRQ("bd71815-bat-dead", BD_ISR_NAME(bat_dead)),
839 BDIRQ("bd71815-bat-short-res", BD_ISR_NAME(bat_short_res)),
840 BDIRQ("bd71815-bat-short-det", BD_ISR_NAME(bat_short)),
841 BDIRQ("bd71815-bat-low-res", BD_ISR_NAME(bat_low_res)),
842 BDIRQ("bd71815-bat-low-det", BD_ISR_NAME(bat_low)),
843 BDIRQ("bd71815-bat-over-res", BD_ISR_NAME(bat_ov_res)),
844 BDIRQ("bd71815-bat-over-det", BD_ISR_NAME(bat_ov)),
845 BDIRQ("bd71815-bat-mon-res", BD_ISR_NAME(bat_mon_res)),
846 BDIRQ("bd71815-bat-mon-det", BD_ISR_NAME(bat_mon)),
847 /* cc-mon 1 & 3 ? */
848 BDIRQ("bd71815-bat-cc-mon2", BD_ISR_NAME(bat_cc_mon)),
849 BDIRQ("bd71815-bat-oc1-res", BD_ISR_NAME(bat_oc1_res)),
850 BDIRQ("bd71815-bat-oc1-det", BD_ISR_NAME(bat_oc1)),
851 BDIRQ("bd71815-bat-oc2-res", BD_ISR_NAME(bat_oc2_res)),
852 BDIRQ("bd71815-bat-oc2-det", BD_ISR_NAME(bat_oc2)),
853 BDIRQ("bd71815-bat-oc3-res", BD_ISR_NAME(bat_oc3_res)),
854 BDIRQ("bd71815-bat-oc3-det", BD_ISR_NAME(bat_oc3)),
855 BDIRQ("bd71815-temp-bat-low-res", BD_ISR_NAME(temp_bat_low_res)),
856 BDIRQ("bd71815-temp-bat-low-det", BD_ISR_NAME(temp_bat_low)),
857 BDIRQ("bd71815-temp-bat-hi-res", BD_ISR_NAME(temp_bat_hi_res)),
858 BDIRQ("bd71815-temp-bat-hi-det", BD_ISR_NAME(temp_bat_hi)),
859 /*
860 * TODO: add rest of the IRQs and re-check the handling.
861 * Check the bd71815-bat-cc-mon1, bd71815-bat-cc-mon3,
862 * bd71815-bat-low-res, bd71815-bat-low-det,
863 * bd71815-bat-hi-res, bd71815-bat-hi-det.
864 */
865 };
866 static const struct bd7182x_irq_res bd71828_irqs[] = {
867 BDIRQ("bd71828-chg-done", bd718x7_chg_done),
868 BDIRQ("bd71828-pwr-dcin-in", bd7182x_dcin_detected),
869 BDIRQ("bd71828-pwr-dcin-out", bd7182x_dcin_removed),
870 BDIRQ("bd71828-vbat-normal", bd71828_vbat_low_res),
871 BDIRQ("bd71828-vbat-low", bd71828_vbat_low_det),
872 BDIRQ("bd71828-btemp-hi", bd71828_temp_bat_hi_det),
873 BDIRQ("bd71828-btemp-cool", bd71828_temp_bat_hi_res),
874 BDIRQ("bd71828-btemp-lo", bd71828_temp_bat_low_det),
875 BDIRQ("bd71828-btemp-warm", bd71828_temp_bat_low_res),
876 BDIRQ("bd71828-temp-hi", bd71828_temp_vf_det),
877 BDIRQ("bd71828-temp-norm", bd71828_temp_vf_res),
878 BDIRQ("bd71828-temp-125-over", bd71828_temp_vf125_det),
879 BDIRQ("bd71828-temp-125-under", bd71828_temp_vf125_res),
880 };
881 int num_irqs;
882 const struct bd7182x_irq_res *irqs;
883
884 switch (pwr->chip_type) {
885 case ROHM_CHIP_TYPE_BD71828:
886 irqs = &bd71828_irqs[0];
887 num_irqs = ARRAY_SIZE(bd71828_irqs);
888 break;
889 case ROHM_CHIP_TYPE_BD71815:
890 irqs = &bd71815_irqs[0];
891 num_irqs = ARRAY_SIZE(bd71815_irqs);
892 break;
893 default:
894 return -EINVAL;
895 }
896
897 for (i = 0; i < num_irqs; i++) {
898 irq = platform_get_irq_byname(pdev, irqs[i].name);
899
900 ret = devm_request_threaded_irq(dev: &pdev->dev, irq, NULL,
901 thread_fn: irqs[i].handler, irqflags: 0,
902 devname: irqs[i].name, dev_id: pwr);
903 if (ret)
904 break;
905 }
906
907 return ret;
908}
909
910#define RSENS_DEFAULT_30MOHM 30000 /* 30 mOhm in uOhms*/
911
912static int bd7182x_get_rsens(struct bd71828_power *pwr)
913{
914 u64 tmp = RSENS_CURR;
915 int rsens_ohm = RSENS_DEFAULT_30MOHM;
916 struct fwnode_handle *node = NULL;
917
918 if (pwr->dev->parent)
919 node = dev_fwnode(pwr->dev->parent);
920
921 if (node) {
922 int ret;
923 u32 rs;
924
925 ret = fwnode_property_read_u32(fwnode: node,
926 propname: "rohm,charger-sense-resistor-micro-ohms",
927 val: &rs);
928 if (ret) {
929 if (ret == -EINVAL) {
930 rs = RSENS_DEFAULT_30MOHM;
931 } else {
932 dev_err(pwr->dev, "Bad RSENS dt property\n");
933 return ret;
934 }
935 }
936 if (!rs) {
937 dev_err(pwr->dev, "Bad RSENS value\n");
938 return -EINVAL;
939 }
940
941 rsens_ohm = (int)rs;
942 }
943
944 /* Reg val to uA */
945 do_div(tmp, rsens_ohm);
946
947 pwr->curr_factor = tmp;
948 pwr->rsens = rsens_ohm;
949 dev_dbg(pwr->dev, "Setting rsens to %u micro ohm\n", pwr->rsens);
950 dev_dbg(pwr->dev, "Setting curr-factor to %u\n", pwr->curr_factor);
951
952 return 0;
953}
954
955static int bd71828_power_probe(struct platform_device *pdev)
956{
957 struct bd71828_power *pwr;
958 struct power_supply_config ac_cfg = {};
959 struct power_supply_config bat_cfg = {};
960 int ret;
961 struct regmap *regmap;
962
963 regmap = dev_get_regmap(dev: pdev->dev.parent, NULL);
964 if (!regmap) {
965 dev_err(&pdev->dev, "No parent regmap\n");
966 return -EINVAL;
967 }
968
969 pwr = devm_kzalloc(dev: &pdev->dev, size: sizeof(*pwr), GFP_KERNEL);
970 if (!pwr)
971 return -ENOMEM;
972
973 pwr->regmap = regmap;
974 pwr->dev = &pdev->dev;
975 pwr->chip_type = platform_get_device_id(pdev)->driver_data;
976
977 switch (pwr->chip_type) {
978 case ROHM_CHIP_TYPE_BD71828:
979 pwr->bat_inserted = bd71828_bat_inserted;
980 pwr->get_temp = bd71828_get_temp;
981 pwr->regs = &pwr_regs_bd71828;
982 break;
983 case ROHM_CHIP_TYPE_BD71815:
984 pwr->bat_inserted = bd71815_bat_inserted;
985 pwr->get_temp = bd71815_get_temp;
986 pwr->regs = &pwr_regs_bd71815;
987 break;
988 default:
989 dev_err(pwr->dev, "Unknown PMIC\n");
990 return -EINVAL;
991 }
992
993 ret = bd7182x_get_rsens(pwr);
994 if (ret)
995 return dev_err_probe(dev: &pdev->dev, err: ret, fmt: "sense resistor missing\n");
996
997 dev_set_drvdata(dev: &pdev->dev, data: pwr);
998 bd71828_init_hardware(pwr);
999
1000 bat_cfg.drv_data = pwr;
1001 bat_cfg.fwnode = dev_fwnode(&pdev->dev);
1002
1003 ac_cfg.supplied_to = bd71828_ac_supplied_to;
1004 ac_cfg.num_supplicants = ARRAY_SIZE(bd71828_ac_supplied_to);
1005 ac_cfg.drv_data = pwr;
1006
1007 pwr->ac = devm_power_supply_register(parent: &pdev->dev, desc: &bd71828_ac_desc,
1008 cfg: &ac_cfg);
1009 if (IS_ERR(ptr: pwr->ac))
1010 return dev_err_probe(dev: &pdev->dev, err: PTR_ERR(ptr: pwr->ac),
1011 fmt: "failed to register ac\n");
1012
1013 pwr->bat = devm_power_supply_register(parent: &pdev->dev, desc: &bd71828_bat_desc,
1014 cfg: &bat_cfg);
1015 if (IS_ERR(ptr: pwr->bat))
1016 return dev_err_probe(dev: &pdev->dev, err: PTR_ERR(ptr: pwr->bat),
1017 fmt: "failed to register bat\n");
1018
1019 ret = bd7182x_get_irqs(pdev, pwr);
1020 if (ret)
1021 return dev_err_probe(dev: &pdev->dev, err: ret, fmt: "failed to request IRQs");
1022
1023 /* Configure wakeup capable */
1024 device_set_wakeup_capable(dev: pwr->dev, capable: 1);
1025 device_set_wakeup_enable(dev: pwr->dev, enable: 1);
1026
1027 return 0;
1028}
1029
1030static const struct platform_device_id bd71828_charger_id[] = {
1031 { "bd71815-power", ROHM_CHIP_TYPE_BD71815 },
1032 { "bd71828-power", ROHM_CHIP_TYPE_BD71828 },
1033 { },
1034};
1035MODULE_DEVICE_TABLE(platform, bd71828_charger_id);
1036
1037static struct platform_driver bd71828_power_driver = {
1038 .driver = {
1039 .name = "bd718xx-power",
1040 },
1041 .probe = bd71828_power_probe,
1042 .id_table = bd71828_charger_id,
1043};
1044
1045module_platform_driver(bd71828_power_driver);
1046
1047MODULE_AUTHOR("Cong Pham <cpham2403@gmail.com>");
1048MODULE_DESCRIPTION("ROHM BD718(15/28/78) PMIC Battery Charger driver");
1049MODULE_LICENSE("GPL");
1050

source code of linux/drivers/power/supply/bd71828-power.c