diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-10-01 10:41:06 -0400 |
---|---|---|
committer | Anton Vorontsov <cbouatmailru@gmail.com> | 2009-11-15 19:27:30 -0500 |
commit | c26964ead57f0aa1dff4926aae2982b174798e7b (patch) | |
tree | 3d9330829b1bda042ced8920acefda7f4f2c2da9 /drivers/power/wm831x_backup.c | |
parent | a9366e61b03f55a6e009e687ad10e706714c9907 (diff) |
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>
Diffstat (limited to 'drivers/power/wm831x_backup.c')
-rw-r--r-- | drivers/power/wm831x_backup.c | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/drivers/power/wm831x_backup.c b/drivers/power/wm831x_backup.c new file mode 100644 index 000000000000..f181076a4085 --- /dev/null +++ b/drivers/power/wm831x_backup.c | |||
@@ -0,0 +1,233 @@ | |||
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"); | ||