Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * charger driver for the PF1550
4 *
5 * Copyright (C) 2016 Freescale Semiconductor, Inc.
6 * Robin Gong <yibin.gong@freescale.com>
7 *
8 * Portions Copyright (c) 2025 Savoir-faire Linux Inc.
9 * Samuel Kayode <samuel.kayode@savoirfairelinux.com>
10 */
11
12#include <linux/devm-helpers.h>
13#include <linux/interrupt.h>
14#include <linux/mfd/pf1550.h>
15#include <linux/module.h>
16#include <linux/platform_device.h>
17#include <linux/power_supply.h>
18
19#define PF1550_DEFAULT_CONSTANT_VOLT 4200000
20#define PF1550_DEFAULT_MIN_SYSTEM_VOLT 3500000
21#define PF1550_DEFAULT_THERMAL_TEMP 95
22#define PF1550_CHARGER_IRQ_NR 5
23
24struct pf1550_charger {
25 struct device *dev;
26 const struct pf1550_ddata *pf1550;
27 struct power_supply *charger;
28 struct power_supply *battery;
29 struct delayed_work vbus_sense_work;
30 struct delayed_work chg_sense_work;
31 struct delayed_work bat_sense_work;
32 int virqs[PF1550_CHARGER_IRQ_NR];
33
34 u32 constant_volt;
35 u32 min_system_volt;
36 u32 thermal_regulation_temp;
37};
38
39static int pf1550_get_charger_state(struct regmap *regmap, int *val)
40{
41 unsigned int data;
42 int ret;
43
44 ret = regmap_read(regmap, PF1550_CHARG_REG_CHG_SNS, &data);
45 if (ret < 0)
46 return ret;
47
48 data &= PF1550_CHG_SNS_MASK;
49
50 switch (data) {
51 case PF1550_CHG_PRECHARGE:
52 case PF1550_CHG_CONSTANT_CURRENT:
53 case PF1550_CHG_CONSTANT_VOL:
54 case PF1550_CHG_EOC:
55 *val = POWER_SUPPLY_STATUS_CHARGING;
56 break;
57 case PF1550_CHG_DONE:
58 *val = POWER_SUPPLY_STATUS_FULL;
59 break;
60 case PF1550_CHG_TIMER_FAULT:
61 case PF1550_CHG_SUSPEND:
62 *val = POWER_SUPPLY_STATUS_NOT_CHARGING;
63 break;
64 case PF1550_CHG_OFF_INV:
65 case PF1550_CHG_OFF_TEMP:
66 case PF1550_CHG_LINEAR_ONLY:
67 *val = POWER_SUPPLY_STATUS_DISCHARGING;
68 break;
69 default:
70 *val = POWER_SUPPLY_STATUS_UNKNOWN;
71 }
72
73 return 0;
74}
75
76static int pf1550_get_charge_type(struct regmap *regmap, int *val)
77{
78 unsigned int data;
79 int ret;
80
81 ret = regmap_read(regmap, PF1550_CHARG_REG_CHG_SNS, &data);
82 if (ret < 0)
83 return ret;
84
85 data &= PF1550_CHG_SNS_MASK;
86
87 switch (data) {
88 case PF1550_CHG_SNS_MASK:
89 *val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
90 break;
91 case PF1550_CHG_CONSTANT_CURRENT:
92 case PF1550_CHG_CONSTANT_VOL:
93 case PF1550_CHG_EOC:
94 *val = POWER_SUPPLY_CHARGE_TYPE_FAST;
95 break;
96 case PF1550_CHG_DONE:
97 case PF1550_CHG_TIMER_FAULT:
98 case PF1550_CHG_SUSPEND:
99 case PF1550_CHG_OFF_INV:
100 case PF1550_CHG_BAT_OVER:
101 case PF1550_CHG_OFF_TEMP:
102 case PF1550_CHG_LINEAR_ONLY:
103 *val = POWER_SUPPLY_CHARGE_TYPE_NONE;
104 break;
105 default:
106 *val = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
107 }
108
109 return 0;
110}
111
112/*
113 * Supported health statuses:
114 * - POWER_SUPPLY_HEALTH_DEAD
115 * - POWER_SUPPLY_HEALTH_GOOD
116 * - POWER_SUPPLY_HEALTH_OVERVOLTAGE
117 * - POWER_SUPPLY_HEALTH_UNKNOWN
118 */
119static int pf1550_get_battery_health(struct regmap *regmap, int *val)
120{
121 unsigned int data;
122 int ret;
123
124 ret = regmap_read(regmap, PF1550_CHARG_REG_BATT_SNS, &data);
125 if (ret < 0)
126 return ret;
127
128 data &= PF1550_BAT_SNS_MASK;
129
130 switch (data) {
131 case PF1550_BAT_NO_DETECT:
132 *val = POWER_SUPPLY_HEALTH_NO_BATTERY;
133 break;
134 case PF1550_BAT_NO_VBUS:
135 case PF1550_BAT_LOW_THAN_PRECHARG:
136 case PF1550_BAT_CHARG_FAIL:
137 case PF1550_BAT_HIGH_THAN_PRECHARG:
138 *val = POWER_SUPPLY_HEALTH_GOOD;
139 break;
140 case PF1550_BAT_OVER_VOL:
141 *val = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
142 break;
143 default:
144 *val = POWER_SUPPLY_HEALTH_UNKNOWN;
145 break;
146 }
147
148 return 0;
149}
150
151static int pf1550_get_present(struct regmap *regmap, int *val)
152{
153 unsigned int data;
154 int ret;
155
156 ret = regmap_read(regmap, PF1550_CHARG_REG_BATT_SNS, &data);
157 if (ret < 0)
158 return ret;
159
160 data &= PF1550_BAT_SNS_MASK;
161 *val = (data == PF1550_BAT_NO_DETECT) ? 0 : 1;
162
163 return 0;
164}
165
166static int pf1550_get_online(struct regmap *regmap, int *val)
167{
168 unsigned int data;
169 int ret;
170
171 ret = regmap_read(regmap, PF1550_CHARG_REG_VBUS_SNS, &data);
172 if (ret < 0)
173 return ret;
174
175 *val = (data & PF1550_VBUS_VALID) ? 1 : 0;
176
177 return 0;
178}
179
180static void pf1550_chg_bat_work(struct work_struct *work)
181{
182 struct pf1550_charger *chg = container_of(to_delayed_work(work),
183 struct pf1550_charger,
184 bat_sense_work);
185 unsigned int data;
186
187 if (regmap_read(chg->pf1550->regmap, PF1550_CHARG_REG_BATT_SNS, &data)) {
188 dev_err(chg->dev, "Read BATT_SNS error.\n");
189 return;
190 }
191
192 switch (data & PF1550_BAT_SNS_MASK) {
193 case PF1550_BAT_NO_VBUS:
194 dev_dbg(chg->dev, "No valid VBUS input.\n");
195 break;
196 case PF1550_BAT_LOW_THAN_PRECHARG:
197 dev_dbg(chg->dev, "VBAT < VPRECHG.LB.\n");
198 break;
199 case PF1550_BAT_CHARG_FAIL:
200 dev_dbg(chg->dev, "Battery charging failed.\n");
201 break;
202 case PF1550_BAT_HIGH_THAN_PRECHARG:
203 dev_dbg(chg->dev, "VBAT > VPRECHG.LB.\n");
204 break;
205 case PF1550_BAT_OVER_VOL:
206 dev_dbg(chg->dev, "VBAT > VBATOV.\n");
207 break;
208 case PF1550_BAT_NO_DETECT:
209 dev_dbg(chg->dev, "Battery not detected.\n");
210 break;
211 default:
212 dev_err(chg->dev, "Unknown value read:%x\n",
213 data & PF1550_CHG_SNS_MASK);
214 }
215}
216
217static void pf1550_chg_chg_work(struct work_struct *work)
218{
219 struct pf1550_charger *chg = container_of(to_delayed_work(work),
220 struct pf1550_charger,
221 chg_sense_work);
222 unsigned int data;
223
224 if (regmap_read(chg->pf1550->regmap, PF1550_CHARG_REG_CHG_SNS, &data)) {
225 dev_err(chg->dev, "Read CHG_SNS error.\n");
226 return;
227 }
228
229 switch (data & PF1550_CHG_SNS_MASK) {
230 case PF1550_CHG_PRECHARGE:
231 dev_dbg(chg->dev, "In pre-charger mode.\n");
232 break;
233 case PF1550_CHG_CONSTANT_CURRENT:
234 dev_dbg(chg->dev, "In fast-charge constant current mode.\n");
235 break;
236 case PF1550_CHG_CONSTANT_VOL:
237 dev_dbg(chg->dev, "In fast-charge constant voltage mode.\n");
238 break;
239 case PF1550_CHG_EOC:
240 dev_dbg(chg->dev, "In EOC mode.\n");
241 break;
242 case PF1550_CHG_DONE:
243 dev_dbg(chg->dev, "In DONE mode.\n");
244 break;
245 case PF1550_CHG_TIMER_FAULT:
246 dev_info(chg->dev, "In timer fault mode.\n");
247 break;
248 case PF1550_CHG_SUSPEND:
249 dev_info(chg->dev, "In thermistor suspend mode.\n");
250 break;
251 case PF1550_CHG_OFF_INV:
252 dev_info(chg->dev, "Input invalid, charger off.\n");
253 break;
254 case PF1550_CHG_BAT_OVER:
255 dev_warn(chg->dev, "Battery over-voltage.\n");
256 break;
257 case PF1550_CHG_OFF_TEMP:
258 dev_info(chg->dev, "Temp high, charger off.\n");
259 break;
260 case PF1550_CHG_LINEAR_ONLY:
261 dev_dbg(chg->dev, "In Linear mode, not charging.\n");
262 break;
263 default:
264 dev_err(chg->dev, "Unknown value read:%x\n",
265 data & PF1550_CHG_SNS_MASK);
266 }
267}
268
269static void pf1550_chg_vbus_work(struct work_struct *work)
270{
271 struct pf1550_charger *chg = container_of(to_delayed_work(work),
272 struct pf1550_charger,
273 vbus_sense_work);
274 unsigned int data;
275
276 if (regmap_read(chg->pf1550->regmap, PF1550_CHARG_REG_VBUS_SNS, &data)) {
277 dev_err(chg->dev, "Read VBUS_SNS error.\n");
278 return;
279 }
280
281 if (data & PF1550_VBUS_UVLO) {
282 dev_dbg(chg->dev, "VBUS detached.\n");
283 power_supply_changed(chg->battery);
284 }
285 if (data & PF1550_VBUS_IN2SYS)
286 dev_dbg(chg->dev, "VBUS_IN2SYS_SNS.\n");
287 if (data & PF1550_VBUS_OVLO)
288 dev_dbg(chg->dev, "VBUS_OVLO_SNS.\n");
289 if (data & PF1550_VBUS_VALID) {
290 dev_dbg(chg->dev, "VBUS attached.\n");
291 power_supply_changed(chg->charger);
292 }
293}
294
295static irqreturn_t pf1550_charger_irq_handler(int irq, void *data)
296{
297 struct pf1550_charger *chg = data;
298 struct device *dev = chg->dev;
299 int i, irq_type = -1;
300
301 for (i = 0; i < PF1550_CHARGER_IRQ_NR; i++)
302 if (irq == chg->virqs[i])
303 irq_type = i;
304
305 switch (irq_type) {
306 case PF1550_CHARG_IRQ_BAT2SOCI:
307 dev_info(dev, "BAT to SYS Overcurrent interrupt.\n");
308 break;
309 case PF1550_CHARG_IRQ_BATI:
310 schedule_delayed_work(&chg->bat_sense_work,
311 msecs_to_jiffies(10));
312 break;
313 case PF1550_CHARG_IRQ_CHGI:
314 schedule_delayed_work(&chg->chg_sense_work,
315 msecs_to_jiffies(10));
316 break;
317 case PF1550_CHARG_IRQ_VBUSI:
318 schedule_delayed_work(&chg->vbus_sense_work,
319 msecs_to_jiffies(10));
320 break;
321 case PF1550_CHARG_IRQ_THMI:
322 dev_info(dev, "Thermal interrupt.\n");
323 break;
324 default:
325 dev_err(dev, "unknown interrupt occurred.\n");
326 }
327
328 return IRQ_HANDLED;
329}
330
331static enum power_supply_property pf1550_charger_props[] = {
332 POWER_SUPPLY_PROP_ONLINE,
333 POWER_SUPPLY_PROP_MODEL_NAME,
334 POWER_SUPPLY_PROP_MANUFACTURER,
335};
336
337static enum power_supply_property pf1550_battery_props[] = {
338 POWER_SUPPLY_PROP_STATUS,
339 POWER_SUPPLY_PROP_CHARGE_TYPE,
340 POWER_SUPPLY_PROP_HEALTH,
341 POWER_SUPPLY_PROP_PRESENT,
342 POWER_SUPPLY_PROP_MODEL_NAME,
343 POWER_SUPPLY_PROP_MANUFACTURER,
344};
345
346static int pf1550_charger_get_property(struct power_supply *psy,
347 enum power_supply_property psp,
348 union power_supply_propval *val)
349{
350 struct pf1550_charger *chg = power_supply_get_drvdata(psy);
351 struct regmap *regmap = chg->pf1550->regmap;
352 int ret = 0;
353
354 switch (psp) {
355 case POWER_SUPPLY_PROP_STATUS:
356 ret = pf1550_get_charger_state(regmap, &val->intval);
357 break;
358 case POWER_SUPPLY_PROP_CHARGE_TYPE:
359 ret = pf1550_get_charge_type(regmap, &val->intval);
360 break;
361 case POWER_SUPPLY_PROP_HEALTH:
362 ret = pf1550_get_battery_health(regmap, &val->intval);
363 break;
364 case POWER_SUPPLY_PROP_PRESENT:
365 ret = pf1550_get_present(regmap, &val->intval);
366 break;
367 case POWER_SUPPLY_PROP_ONLINE:
368 ret = pf1550_get_online(regmap, &val->intval);
369 break;
370 case POWER_SUPPLY_PROP_MODEL_NAME:
371 val->strval = "PF1550";
372 break;
373 case POWER_SUPPLY_PROP_MANUFACTURER:
374 val->strval = "NXP";
375 break;
376 default:
377 return -EINVAL;
378 }
379
380 return ret;
381}
382
383static const struct power_supply_desc pf1550_charger_desc = {
384 .name = "pf1550-charger",
385 .type = POWER_SUPPLY_TYPE_MAINS,
386 .properties = pf1550_charger_props,
387 .num_properties = ARRAY_SIZE(pf1550_charger_props),
388 .get_property = pf1550_charger_get_property,
389};
390
391static const struct power_supply_desc pf1550_battery_desc = {
392 .name = "pf1550-battery",
393 .type = POWER_SUPPLY_TYPE_BATTERY,
394 .properties = pf1550_battery_props,
395 .num_properties = ARRAY_SIZE(pf1550_battery_props),
396 .get_property = pf1550_charger_get_property,
397};
398
399static int pf1550_set_constant_volt(struct pf1550_charger *chg,
400 unsigned int uvolt)
401{
402 unsigned int data;
403
404 if (uvolt >= 3500000 && uvolt <= 4440000)
405 data = 8 + (uvolt - 3500000) / 20000;
406 else
407 return dev_err_probe(chg->dev, -EINVAL,
408 "Wrong value for constant voltage\n");
409
410 dev_dbg(chg->dev, "Charging constant voltage: %u (0x%x)\n", uvolt,
411 data);
412
413 return regmap_update_bits(chg->pf1550->regmap,
414 PF1550_CHARG_REG_BATT_REG,
415 PF1550_CHARG_REG_BATT_REG_CHGCV_MASK, data);
416}
417
418static int pf1550_set_min_system_volt(struct pf1550_charger *chg,
419 unsigned int uvolt)
420{
421 unsigned int data;
422
423 switch (uvolt) {
424 case 3500000:
425 data = 0x0;
426 break;
427 case 3700000:
428 data = 0x1;
429 break;
430 case 4300000:
431 data = 0x2;
432 break;
433 default:
434 return dev_err_probe(chg->dev, -EINVAL,
435 "Wrong value for minimum system voltage\n");
436 }
437
438 data <<= PF1550_CHARG_REG_BATT_REG_VMINSYS_SHIFT;
439
440 dev_dbg(chg->dev, "Minimum system regulation voltage: %u (0x%x)\n",
441 uvolt, data);
442
443 return regmap_update_bits(chg->pf1550->regmap,
444 PF1550_CHARG_REG_BATT_REG,
445 PF1550_CHARG_REG_BATT_REG_VMINSYS_MASK, data);
446}
447
448static int pf1550_set_thermal_regulation_temp(struct pf1550_charger *chg,
449 unsigned int cells)
450{
451 unsigned int data;
452
453 switch (cells) {
454 case 80:
455 data = 0x0;
456 break;
457 case 95:
458 data = 0x1;
459 break;
460 case 110:
461 data = 0x2;
462 break;
463 case 125:
464 data = 0x3;
465 break;
466 default:
467 return dev_err_probe(chg->dev, -EINVAL,
468 "Wrong value for thermal temperature\n");
469 }
470
471 data <<= PF1550_CHARG_REG_THM_REG_CNFG_REGTEMP_SHIFT;
472
473 dev_dbg(chg->dev, "Thermal regulation loop temperature: %u (0x%x)\n",
474 cells, data);
475
476 return regmap_update_bits(chg->pf1550->regmap,
477 PF1550_CHARG_REG_THM_REG_CNFG,
478 PF1550_CHARG_REG_THM_REG_CNFG_REGTEMP_MASK,
479 data);
480}
481
482/*
483 * Sets charger registers to proper and safe default values.
484 */
485static int pf1550_reg_init(struct pf1550_charger *chg)
486{
487 struct power_supply_battery_info *info;
488 struct device *dev = chg->dev;
489 int ret;
490
491 /* Unmask charger interrupt, mask DPMI and reserved bit */
492 ret = regmap_write(chg->pf1550->regmap, PF1550_CHARG_REG_CHG_INT_MASK,
493 PF1550_CHG_INT_MASK);
494 if (ret)
495 return dev_err_probe(dev, ret,
496 "Error unmask charger interrupt\n");
497
498 ret = pf1550_set_constant_volt(chg, chg->constant_volt);
499 if (ret)
500 return ret;
501
502 ret = pf1550_set_min_system_volt(chg, chg->min_system_volt);
503 if (ret)
504 return ret;
505
506 ret = pf1550_set_thermal_regulation_temp(chg,
507 chg->thermal_regulation_temp);
508 if (ret)
509 return ret;
510
511 /*
512 * The PF1550 charger has 3 modes of operation. By default, the charger
513 * is in mode 1; it remains off. Appropriate for applications not using
514 * a battery. The other supported mode is mode 2, the charger is turned
515 * on to charge a battery when present.
516 */
517 if (power_supply_get_battery_info(chg->charger, &info)) {
518 ret = regmap_write(chg->pf1550->regmap,
519 PF1550_CHARG_REG_CHG_OPER,
520 PF1550_CHG_BAT_ON);
521 if (ret)
522 return dev_err_probe(dev, ret,
523 "Error turn on charger\n");
524 }
525
526 return 0;
527}
528
529static void pf1550_dt_parse_dev_info(struct pf1550_charger *chg)
530{
531 struct power_supply_battery_info *info;
532 struct device *dev = chg->dev;
533
534 if (device_property_read_u32(dev->parent, "nxp,min-system-microvolt",
535 &chg->min_system_volt))
536 chg->min_system_volt = PF1550_DEFAULT_MIN_SYSTEM_VOLT;
537
538 if (device_property_read_u32(dev->parent,
539 "nxp,thermal-regulation-celsius",
540 &chg->thermal_regulation_temp))
541 chg->thermal_regulation_temp = PF1550_DEFAULT_THERMAL_TEMP;
542
543 if (power_supply_get_battery_info(chg->charger, &info))
544 chg->constant_volt = PF1550_DEFAULT_CONSTANT_VOLT;
545 else
546 chg->constant_volt = info->constant_charge_voltage_max_uv;
547}
548
549static int pf1550_charger_probe(struct platform_device *pdev)
550{
551 const struct pf1550_ddata *pf1550 = dev_get_drvdata(pdev->dev.parent);
552 struct power_supply_config psy_cfg = {};
553 struct pf1550_charger *chg;
554 int i, irq, ret;
555
556 chg = devm_kzalloc(&pdev->dev, sizeof(*chg), GFP_KERNEL);
557 if (!chg)
558 return -ENOMEM;
559
560 chg->dev = &pdev->dev;
561 chg->pf1550 = pf1550;
562
563 if (!chg->pf1550->regmap)
564 return dev_err_probe(&pdev->dev, -ENODEV,
565 "failed to get regmap\n");
566
567 platform_set_drvdata(pdev, chg);
568
569 ret = devm_delayed_work_autocancel(chg->dev, &chg->vbus_sense_work,
570 pf1550_chg_vbus_work);
571 if (ret)
572 return dev_err_probe(chg->dev, ret,
573 "failed to add vbus sense work\n");
574
575 ret = devm_delayed_work_autocancel(chg->dev, &chg->chg_sense_work,
576 pf1550_chg_chg_work);
577 if (ret)
578 return dev_err_probe(chg->dev, ret,
579 "failed to add charger sense work\n");
580
581 ret = devm_delayed_work_autocancel(chg->dev, &chg->bat_sense_work,
582 pf1550_chg_bat_work);
583 if (ret)
584 return dev_err_probe(chg->dev, ret,
585 "failed to add battery sense work\n");
586
587 for (i = 0; i < PF1550_CHARGER_IRQ_NR; i++) {
588 irq = platform_get_irq(pdev, i);
589 if (irq < 0)
590 return irq;
591
592 chg->virqs[i] = irq;
593
594 ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
595 pf1550_charger_irq_handler,
596 IRQF_NO_SUSPEND,
597 "pf1550-charger", chg);
598 if (ret)
599 return dev_err_probe(&pdev->dev, ret,
600 "failed irq request\n");
601 }
602
603 psy_cfg.drv_data = chg;
604
605 chg->charger = devm_power_supply_register(&pdev->dev,
606 &pf1550_charger_desc,
607 &psy_cfg);
608 if (IS_ERR(chg->charger))
609 return dev_err_probe(&pdev->dev, PTR_ERR(chg->charger),
610 "failed: power supply register\n");
611
612 chg->battery = devm_power_supply_register(&pdev->dev,
613 &pf1550_battery_desc,
614 &psy_cfg);
615 if (IS_ERR(chg->battery))
616 return dev_err_probe(&pdev->dev, PTR_ERR(chg->battery),
617 "failed: power supply register\n");
618
619 pf1550_dt_parse_dev_info(chg);
620
621 return pf1550_reg_init(chg);
622}
623
624static const struct platform_device_id pf1550_charger_id[] = {
625 { "pf1550-charger", },
626 { /* sentinel */ }
627};
628MODULE_DEVICE_TABLE(platform, pf1550_charger_id);
629
630static struct platform_driver pf1550_charger_driver = {
631 .driver = {
632 .name = "pf1550-charger",
633 },
634 .probe = pf1550_charger_probe,
635 .id_table = pf1550_charger_id,
636};
637module_platform_driver(pf1550_charger_driver);
638
639MODULE_AUTHOR("Robin Gong <yibin.gong@freescale.com>");
640MODULE_DESCRIPTION("PF1550 charger driver");
641MODULE_LICENSE("GPL");