Commit c26964ead57f0aa1dff4926aae2982b174798e7b
Committed by
Anton Vorontsov
1 parent
a9366e61b0
Exists in
master
and in
7 other branches
wm831x: Factor out WM831x backup battery charger
The backup battery on WM831x is a separate IP block to the main PMU and is largely unrelated to the main supply functionality. Factor it out into a separate driver in order to reflect this and better support future hardware versions. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Acked-by: Samuel Ortiz <sameo@linux.intel.com> Signed-off-by: Anton Vorontsov <cbouatmailru@gmail.com>
Showing 5 changed files with 253 additions and 141 deletions Side-by-side Diff
drivers/mfd/wm831x-core.c
... | ... | @@ -794,6 +794,9 @@ |
794 | 794 | |
795 | 795 | static struct mfd_cell wm8310_devs[] = { |
796 | 796 | { |
797 | + .name = "wm831x-backup", | |
798 | + }, | |
799 | + { | |
797 | 800 | .name = "wm831x-buckv", |
798 | 801 | .id = 1, |
799 | 802 | .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources), |
... | ... | @@ -947,6 +950,9 @@ |
947 | 950 | |
948 | 951 | static struct mfd_cell wm8311_devs[] = { |
949 | 952 | { |
953 | + .name = "wm831x-backup", | |
954 | + }, | |
955 | + { | |
950 | 956 | .name = "wm831x-buckv", |
951 | 957 | .id = 1, |
952 | 958 | .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources), |
... | ... | @@ -1080,6 +1086,9 @@ |
1080 | 1086 | }; |
1081 | 1087 | |
1082 | 1088 | static struct mfd_cell wm8312_devs[] = { |
1089 | + { | |
1090 | + .name = "wm831x-backup", | |
1091 | + }, | |
1083 | 1092 | { |
1084 | 1093 | .name = "wm831x-buckv", |
1085 | 1094 | .id = 1, |
drivers/power/Kconfig
... | ... | @@ -29,6 +29,13 @@ |
29 | 29 | Say Y here to enable support APM status emulation using |
30 | 30 | battery class devices. |
31 | 31 | |
32 | +config WM831X_BACKUP | |
33 | + tristate "WM831X backup battery charger support" | |
34 | + depends on MFD_WM831X | |
35 | + help | |
36 | + Say Y here to enable support for the backup battery charger | |
37 | + in the Wolfson Microelectronics WM831x PMICs. | |
38 | + | |
32 | 39 | config WM831X_POWER |
33 | 40 | tristate "WM831X PMU support" |
34 | 41 | depends on MFD_WM831X |
drivers/power/Makefile
drivers/power/wm831x_backup.c
1 | +/* | |
2 | + * Backup battery driver for Wolfson Microelectronics wm831x PMICs | |
3 | + * | |
4 | + * Copyright 2009 Wolfson Microelectronics PLC. | |
5 | + * | |
6 | + * This program is free software; you can redistribute it and/or modify | |
7 | + * it under the terms of the GNU General Public License version 2 as | |
8 | + * published by the Free Software Foundation. | |
9 | + */ | |
10 | + | |
11 | +#include <linux/module.h> | |
12 | +#include <linux/err.h> | |
13 | +#include <linux/platform_device.h> | |
14 | +#include <linux/power_supply.h> | |
15 | + | |
16 | +#include <linux/mfd/wm831x/core.h> | |
17 | +#include <linux/mfd/wm831x/auxadc.h> | |
18 | +#include <linux/mfd/wm831x/pmu.h> | |
19 | +#include <linux/mfd/wm831x/pdata.h> | |
20 | + | |
21 | +struct wm831x_backup { | |
22 | + struct wm831x *wm831x; | |
23 | + struct power_supply backup; | |
24 | +}; | |
25 | + | |
26 | +static int wm831x_backup_read_voltage(struct wm831x *wm831x, | |
27 | + enum wm831x_auxadc src, | |
28 | + union power_supply_propval *val) | |
29 | +{ | |
30 | + int ret; | |
31 | + | |
32 | + ret = wm831x_auxadc_read_uv(wm831x, src); | |
33 | + if (ret >= 0) | |
34 | + val->intval = ret; | |
35 | + | |
36 | + return ret; | |
37 | +} | |
38 | + | |
39 | +/********************************************************************* | |
40 | + * Backup supply properties | |
41 | + *********************************************************************/ | |
42 | + | |
43 | +static void wm831x_config_backup(struct wm831x *wm831x) | |
44 | +{ | |
45 | + struct wm831x_pdata *wm831x_pdata = wm831x->dev->platform_data; | |
46 | + struct wm831x_backup_pdata *pdata; | |
47 | + int ret, reg; | |
48 | + | |
49 | + if (!wm831x_pdata || !wm831x_pdata->backup) { | |
50 | + dev_warn(wm831x->dev, | |
51 | + "No backup battery charger configuration\n"); | |
52 | + return; | |
53 | + } | |
54 | + | |
55 | + pdata = wm831x_pdata->backup; | |
56 | + | |
57 | + reg = 0; | |
58 | + | |
59 | + if (pdata->charger_enable) | |
60 | + reg |= WM831X_BKUP_CHG_ENA | WM831X_BKUP_BATT_DET_ENA; | |
61 | + if (pdata->no_constant_voltage) | |
62 | + reg |= WM831X_BKUP_CHG_MODE; | |
63 | + | |
64 | + switch (pdata->vlim) { | |
65 | + case 2500: | |
66 | + break; | |
67 | + case 3100: | |
68 | + reg |= WM831X_BKUP_CHG_VLIM; | |
69 | + break; | |
70 | + default: | |
71 | + dev_err(wm831x->dev, "Invalid backup voltage limit %dmV\n", | |
72 | + pdata->vlim); | |
73 | + } | |
74 | + | |
75 | + switch (pdata->ilim) { | |
76 | + case 100: | |
77 | + break; | |
78 | + case 200: | |
79 | + reg |= 1; | |
80 | + break; | |
81 | + case 300: | |
82 | + reg |= 2; | |
83 | + break; | |
84 | + case 400: | |
85 | + reg |= 3; | |
86 | + break; | |
87 | + default: | |
88 | + dev_err(wm831x->dev, "Invalid backup current limit %duA\n", | |
89 | + pdata->ilim); | |
90 | + } | |
91 | + | |
92 | + ret = wm831x_reg_unlock(wm831x); | |
93 | + if (ret != 0) { | |
94 | + dev_err(wm831x->dev, "Failed to unlock registers: %d\n", ret); | |
95 | + return; | |
96 | + } | |
97 | + | |
98 | + ret = wm831x_set_bits(wm831x, WM831X_BACKUP_CHARGER_CONTROL, | |
99 | + WM831X_BKUP_CHG_ENA_MASK | | |
100 | + WM831X_BKUP_CHG_MODE_MASK | | |
101 | + WM831X_BKUP_BATT_DET_ENA_MASK | | |
102 | + WM831X_BKUP_CHG_VLIM_MASK | | |
103 | + WM831X_BKUP_CHG_ILIM_MASK, | |
104 | + reg); | |
105 | + if (ret != 0) | |
106 | + dev_err(wm831x->dev, | |
107 | + "Failed to set backup charger config: %d\n", ret); | |
108 | + | |
109 | + wm831x_reg_lock(wm831x); | |
110 | +} | |
111 | + | |
112 | +static int wm831x_backup_get_prop(struct power_supply *psy, | |
113 | + enum power_supply_property psp, | |
114 | + union power_supply_propval *val) | |
115 | +{ | |
116 | + struct wm831x_backup *devdata = dev_get_drvdata(psy->dev->parent); | |
117 | + struct wm831x *wm831x = devdata->wm831x; | |
118 | + int ret = 0; | |
119 | + | |
120 | + ret = wm831x_reg_read(wm831x, WM831X_BACKUP_CHARGER_CONTROL); | |
121 | + if (ret < 0) | |
122 | + return ret; | |
123 | + | |
124 | + switch (psp) { | |
125 | + case POWER_SUPPLY_PROP_STATUS: | |
126 | + if (ret & WM831X_BKUP_CHG_STS) | |
127 | + val->intval = POWER_SUPPLY_STATUS_CHARGING; | |
128 | + else | |
129 | + val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; | |
130 | + break; | |
131 | + | |
132 | + case POWER_SUPPLY_PROP_VOLTAGE_NOW: | |
133 | + ret = wm831x_backup_read_voltage(wm831x, WM831X_AUX_BKUP_BATT, | |
134 | + val); | |
135 | + break; | |
136 | + | |
137 | + case POWER_SUPPLY_PROP_PRESENT: | |
138 | + if (ret & WM831X_BKUP_CHG_STS) | |
139 | + val->intval = 1; | |
140 | + else | |
141 | + val->intval = 0; | |
142 | + break; | |
143 | + | |
144 | + default: | |
145 | + ret = -EINVAL; | |
146 | + break; | |
147 | + } | |
148 | + | |
149 | + return ret; | |
150 | +} | |
151 | + | |
152 | +static enum power_supply_property wm831x_backup_props[] = { | |
153 | + POWER_SUPPLY_PROP_STATUS, | |
154 | + POWER_SUPPLY_PROP_VOLTAGE_NOW, | |
155 | + POWER_SUPPLY_PROP_PRESENT, | |
156 | +}; | |
157 | + | |
158 | +/********************************************************************* | |
159 | + * Initialisation | |
160 | + *********************************************************************/ | |
161 | + | |
162 | +static __devinit int wm831x_backup_probe(struct platform_device *pdev) | |
163 | +{ | |
164 | + struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); | |
165 | + struct wm831x_backup *devdata; | |
166 | + struct power_supply *backup; | |
167 | + int ret, irq, i; | |
168 | + | |
169 | + devdata = kzalloc(sizeof(struct wm831x_backup), GFP_KERNEL); | |
170 | + if (devdata == NULL) | |
171 | + return -ENOMEM; | |
172 | + | |
173 | + devdata->wm831x = wm831x; | |
174 | + platform_set_drvdata(pdev, devdata); | |
175 | + | |
176 | + backup = &devdata->backup; | |
177 | + | |
178 | + /* We ignore configuration failures since we can still read | |
179 | + * back the status without enabling the charger (which may | |
180 | + * already be enabled anyway). | |
181 | + */ | |
182 | + wm831x_config_backup(wm831x); | |
183 | + | |
184 | + backup->name = "wm831x-backup"; | |
185 | + backup->type = POWER_SUPPLY_TYPE_BATTERY; | |
186 | + backup->properties = wm831x_backup_props; | |
187 | + backup->num_properties = ARRAY_SIZE(wm831x_backup_props); | |
188 | + backup->get_property = wm831x_backup_get_prop; | |
189 | + ret = power_supply_register(&pdev->dev, backup); | |
190 | + if (ret) | |
191 | + goto err_kmalloc; | |
192 | + | |
193 | + return ret; | |
194 | + | |
195 | +err_kmalloc: | |
196 | + kfree(devdata); | |
197 | + return ret; | |
198 | +} | |
199 | + | |
200 | +static __devexit int wm831x_backup_remove(struct platform_device *pdev) | |
201 | +{ | |
202 | + struct wm831x_backup *devdata = platform_get_drvdata(pdev); | |
203 | + | |
204 | + power_supply_unregister(&devdata->backup); | |
205 | + kfree(devdata); | |
206 | + | |
207 | + return 0; | |
208 | +} | |
209 | + | |
210 | +static struct platform_driver wm831x_backup_driver = { | |
211 | + .probe = wm831x_backup_probe, | |
212 | + .remove = __devexit_p(wm831x_backup_remove), | |
213 | + .driver = { | |
214 | + .name = "wm831x-backup", | |
215 | + }, | |
216 | +}; | |
217 | + | |
218 | +static int __init wm831x_backup_init(void) | |
219 | +{ | |
220 | + return platform_driver_register(&wm831x_backup_driver); | |
221 | +} | |
222 | +module_init(wm831x_backup_init); | |
223 | + | |
224 | +static void __exit wm831x_backup_exit(void) | |
225 | +{ | |
226 | + platform_driver_unregister(&wm831x_backup_driver); | |
227 | +} | |
228 | +module_exit(wm831x_backup_exit); | |
229 | + | |
230 | +MODULE_DESCRIPTION("Backup battery charger driver for WM831x PMICs"); | |
231 | +MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | |
232 | +MODULE_LICENSE("GPL"); | |
233 | +MODULE_ALIAS("platform:wm831x-backup"); |
drivers/power/wm831x_power.c
... | ... | @@ -21,7 +21,6 @@ |
21 | 21 | struct wm831x_power { |
22 | 22 | struct wm831x *wm831x; |
23 | 23 | struct power_supply wall; |
24 | - struct power_supply backup; | |
25 | 24 | struct power_supply usb; |
26 | 25 | struct power_supply battery; |
27 | 26 | }; |
... | ... | @@ -454,125 +453,6 @@ |
454 | 453 | |
455 | 454 | |
456 | 455 | /********************************************************************* |
457 | - * Backup supply properties | |
458 | - *********************************************************************/ | |
459 | - | |
460 | -static void wm831x_config_backup(struct wm831x *wm831x) | |
461 | -{ | |
462 | - struct wm831x_pdata *wm831x_pdata = wm831x->dev->platform_data; | |
463 | - struct wm831x_backup_pdata *pdata; | |
464 | - int ret, reg; | |
465 | - | |
466 | - if (!wm831x_pdata || !wm831x_pdata->backup) { | |
467 | - dev_warn(wm831x->dev, | |
468 | - "No backup battery charger configuration\n"); | |
469 | - return; | |
470 | - } | |
471 | - | |
472 | - pdata = wm831x_pdata->backup; | |
473 | - | |
474 | - reg = 0; | |
475 | - | |
476 | - if (pdata->charger_enable) | |
477 | - reg |= WM831X_BKUP_CHG_ENA | WM831X_BKUP_BATT_DET_ENA; | |
478 | - if (pdata->no_constant_voltage) | |
479 | - reg |= WM831X_BKUP_CHG_MODE; | |
480 | - | |
481 | - switch (pdata->vlim) { | |
482 | - case 2500: | |
483 | - break; | |
484 | - case 3100: | |
485 | - reg |= WM831X_BKUP_CHG_VLIM; | |
486 | - break; | |
487 | - default: | |
488 | - dev_err(wm831x->dev, "Invalid backup voltage limit %dmV\n", | |
489 | - pdata->vlim); | |
490 | - } | |
491 | - | |
492 | - switch (pdata->ilim) { | |
493 | - case 100: | |
494 | - break; | |
495 | - case 200: | |
496 | - reg |= 1; | |
497 | - break; | |
498 | - case 300: | |
499 | - reg |= 2; | |
500 | - break; | |
501 | - case 400: | |
502 | - reg |= 3; | |
503 | - break; | |
504 | - default: | |
505 | - dev_err(wm831x->dev, "Invalid backup current limit %duA\n", | |
506 | - pdata->ilim); | |
507 | - } | |
508 | - | |
509 | - ret = wm831x_reg_unlock(wm831x); | |
510 | - if (ret != 0) { | |
511 | - dev_err(wm831x->dev, "Failed to unlock registers: %d\n", ret); | |
512 | - return; | |
513 | - } | |
514 | - | |
515 | - ret = wm831x_set_bits(wm831x, WM831X_BACKUP_CHARGER_CONTROL, | |
516 | - WM831X_BKUP_CHG_ENA_MASK | | |
517 | - WM831X_BKUP_CHG_MODE_MASK | | |
518 | - WM831X_BKUP_BATT_DET_ENA_MASK | | |
519 | - WM831X_BKUP_CHG_VLIM_MASK | | |
520 | - WM831X_BKUP_CHG_ILIM_MASK, | |
521 | - reg); | |
522 | - if (ret != 0) | |
523 | - dev_err(wm831x->dev, | |
524 | - "Failed to set backup charger config: %d\n", ret); | |
525 | - | |
526 | - wm831x_reg_lock(wm831x); | |
527 | -} | |
528 | - | |
529 | -static int wm831x_backup_get_prop(struct power_supply *psy, | |
530 | - enum power_supply_property psp, | |
531 | - union power_supply_propval *val) | |
532 | -{ | |
533 | - struct wm831x_power *wm831x_power = dev_get_drvdata(psy->dev->parent); | |
534 | - struct wm831x *wm831x = wm831x_power->wm831x; | |
535 | - int ret = 0; | |
536 | - | |
537 | - ret = wm831x_reg_read(wm831x, WM831X_BACKUP_CHARGER_CONTROL); | |
538 | - if (ret < 0) | |
539 | - return ret; | |
540 | - | |
541 | - switch (psp) { | |
542 | - case POWER_SUPPLY_PROP_STATUS: | |
543 | - if (ret & WM831X_BKUP_CHG_STS) | |
544 | - val->intval = POWER_SUPPLY_STATUS_CHARGING; | |
545 | - else | |
546 | - val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; | |
547 | - break; | |
548 | - | |
549 | - case POWER_SUPPLY_PROP_VOLTAGE_NOW: | |
550 | - ret = wm831x_power_read_voltage(wm831x, WM831X_AUX_BKUP_BATT, | |
551 | - val); | |
552 | - break; | |
553 | - | |
554 | - case POWER_SUPPLY_PROP_PRESENT: | |
555 | - if (ret & WM831X_BKUP_CHG_STS) | |
556 | - val->intval = 1; | |
557 | - else | |
558 | - val->intval = 0; | |
559 | - break; | |
560 | - | |
561 | - default: | |
562 | - ret = -EINVAL; | |
563 | - break; | |
564 | - } | |
565 | - | |
566 | - return ret; | |
567 | -} | |
568 | - | |
569 | -static enum power_supply_property wm831x_backup_props[] = { | |
570 | - POWER_SUPPLY_PROP_STATUS, | |
571 | - POWER_SUPPLY_PROP_VOLTAGE_NOW, | |
572 | - POWER_SUPPLY_PROP_PRESENT, | |
573 | -}; | |
574 | - | |
575 | -/********************************************************************* | |
576 | 456 | * Initialisation |
577 | 457 | *********************************************************************/ |
578 | 458 | |
... | ... | @@ -595,10 +475,7 @@ |
595 | 475 | |
596 | 476 | dev_dbg(wm831x->dev, "Power source changed\n"); |
597 | 477 | |
598 | - /* Just notify for everything - little harm in overnotifying. | |
599 | - * The backup battery is not a power source while the system | |
600 | - * is running so skip that. | |
601 | - */ | |
478 | + /* Just notify for everything - little harm in overnotifying. */ | |
602 | 479 | power_supply_changed(&wm831x_power->battery); |
603 | 480 | power_supply_changed(&wm831x_power->usb); |
604 | 481 | power_supply_changed(&wm831x_power->wall); |
... | ... | @@ -613,7 +490,6 @@ |
613 | 490 | struct power_supply *usb; |
614 | 491 | struct power_supply *battery; |
615 | 492 | struct power_supply *wall; |
616 | - struct power_supply *backup; | |
617 | 493 | int ret, irq, i; |
618 | 494 | |
619 | 495 | power = kzalloc(sizeof(struct wm831x_power), GFP_KERNEL); |
620 | 496 | |
621 | 497 | |
... | ... | @@ -626,13 +502,11 @@ |
626 | 502 | usb = &power->usb; |
627 | 503 | battery = &power->battery; |
628 | 504 | wall = &power->wall; |
629 | - backup = &power->backup; | |
630 | 505 | |
631 | 506 | /* We ignore configuration failures since we can still read back |
632 | - * the status without enabling either of the chargers. | |
507 | + * the status without enabling the charger. | |
633 | 508 | */ |
634 | 509 | wm831x_config_battery(wm831x); |
635 | - wm831x_config_backup(wm831x); | |
636 | 510 | |
637 | 511 | wall->name = "wm831x-wall"; |
638 | 512 | wall->type = POWER_SUPPLY_TYPE_MAINS; |
... | ... | @@ -661,15 +535,6 @@ |
661 | 535 | if (ret) |
662 | 536 | goto err_battery; |
663 | 537 | |
664 | - backup->name = "wm831x-backup"; | |
665 | - backup->type = POWER_SUPPLY_TYPE_BATTERY; | |
666 | - backup->properties = wm831x_backup_props; | |
667 | - backup->num_properties = ARRAY_SIZE(wm831x_backup_props); | |
668 | - backup->get_property = wm831x_backup_get_prop; | |
669 | - ret = power_supply_register(&pdev->dev, backup); | |
670 | - if (ret) | |
671 | - goto err_usb; | |
672 | - | |
673 | 538 | irq = platform_get_irq_byname(pdev, "SYSLO"); |
674 | 539 | ret = wm831x_request_irq(wm831x, irq, wm831x_syslo_irq, |
675 | 540 | IRQF_TRIGGER_RISING, "SYSLO", |
... | ... | @@ -677,7 +542,7 @@ |
677 | 542 | if (ret != 0) { |
678 | 543 | dev_err(&pdev->dev, "Failed to request SYSLO IRQ %d: %d\n", |
679 | 544 | irq, ret); |
680 | - goto err_backup; | |
545 | + goto err_usb; | |
681 | 546 | } |
682 | 547 | |
683 | 548 | irq = platform_get_irq_byname(pdev, "PWR SRC"); |
... | ... | @@ -716,8 +581,6 @@ |
716 | 581 | err_syslo: |
717 | 582 | irq = platform_get_irq_byname(pdev, "SYSLO"); |
718 | 583 | wm831x_free_irq(wm831x, irq, power); |
719 | -err_backup: | |
720 | - power_supply_unregister(backup); | |
721 | 584 | err_usb: |
722 | 585 | power_supply_unregister(usb); |
723 | 586 | err_battery: |
... | ... | @@ -746,7 +609,6 @@ |
746 | 609 | irq = platform_get_irq_byname(pdev, "SYSLO"); |
747 | 610 | wm831x_free_irq(wm831x, irq, wm831x_power); |
748 | 611 | |
749 | - power_supply_unregister(&wm831x_power->backup); | |
750 | 612 | power_supply_unregister(&wm831x_power->battery); |
751 | 613 | power_supply_unregister(&wm831x_power->wall); |
752 | 614 | power_supply_unregister(&wm831x_power->usb); |