diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
commit | fcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch) | |
tree | a57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/regulator/gpio-switch-regulator.c | |
parent | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff) |
Diffstat (limited to 'drivers/regulator/gpio-switch-regulator.c')
-rw-r--r-- | drivers/regulator/gpio-switch-regulator.c | 412 |
1 files changed, 412 insertions, 0 deletions
diff --git a/drivers/regulator/gpio-switch-regulator.c b/drivers/regulator/gpio-switch-regulator.c new file mode 100644 index 00000000000..55dd63675a0 --- /dev/null +++ b/drivers/regulator/gpio-switch-regulator.c | |||
@@ -0,0 +1,412 @@ | |||
1 | /* | ||
2 | * driver/regulator/gpio-switch-regulator.c | ||
3 | * GPIO based switch regulator to enable/disable power rails. | ||
4 | * | ||
5 | * Copyright (c) 2011, NVIDIA Corporation. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along | ||
18 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
20 | */ | ||
21 | |||
22 | /*#define DEBUG 1*/ | ||
23 | /*#define VERBOSE_DEBUG 1*/ | ||
24 | |||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/err.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/platform_device.h> | ||
30 | #include <linux/regulator/driver.h> | ||
31 | #include <linux/regulator/machine.h> | ||
32 | #include <linux/gpio.h> | ||
33 | #include <linux/regulator/gpio-switch-regulator.h> | ||
34 | |||
35 | struct gpio_switch_regulator { | ||
36 | struct regulator_desc reg_desc; | ||
37 | struct regulator_init_data reg_init_data; | ||
38 | struct regulator *input_regulator; | ||
39 | struct regulator_dev *rdev; | ||
40 | struct device *dev; | ||
41 | int gpio_nr; | ||
42 | int pin_group; | ||
43 | bool is_gpio_init; | ||
44 | bool is_enable; | ||
45 | bool active_low; | ||
46 | bool is_init_success; | ||
47 | int *voltages; | ||
48 | unsigned curr_vol_sel; | ||
49 | struct gpio_switch_regulator_subdev_data *psubdev_data; | ||
50 | int (*enable_rail)(struct gpio_switch_regulator_subdev_data *sdata); | ||
51 | int (*disable_rail)(struct gpio_switch_regulator_subdev_data *sdata); | ||
52 | }; | ||
53 | |||
54 | static int _gpio_regulator_enable(struct device *dev, | ||
55 | struct gpio_switch_regulator *ri) | ||
56 | { | ||
57 | int init_val; | ||
58 | int ret; | ||
59 | |||
60 | if (ri->enable_rail) { | ||
61 | ret = ri->enable_rail(ri->psubdev_data); | ||
62 | if (ret < 0) | ||
63 | dev_err(dev, "Unable to enable rail through board api" | ||
64 | " error %d\n", ret); | ||
65 | } else { | ||
66 | init_val = (ri->active_low) ? 0 : 1; | ||
67 | ret = gpio_direction_output(ri->gpio_nr, init_val); | ||
68 | if (ret < 0) | ||
69 | dev_err(dev, "Unable to set direction %d\n", | ||
70 | ri->gpio_nr); | ||
71 | } | ||
72 | return ret; | ||
73 | } | ||
74 | |||
75 | static int _gpio_regulator_disable(struct device *dev, | ||
76 | struct gpio_switch_regulator *ri) | ||
77 | { | ||
78 | int init_val; | ||
79 | int ret; | ||
80 | |||
81 | if (ri->disable_rail) { | ||
82 | ret = ri->disable_rail(ri->psubdev_data); | ||
83 | if (ret < 0) | ||
84 | dev_err(dev, "Unable to disable rail through " | ||
85 | "board api %d\n", ret); | ||
86 | } else { | ||
87 | init_val = (ri->active_low) ? 1 : 0; | ||
88 | ret = gpio_direction_output(ri->gpio_nr, init_val); | ||
89 | if (ret < 0) | ||
90 | dev_err(dev, "Unable to set direction %d\n", | ||
91 | ri->gpio_nr); | ||
92 | } | ||
93 | return ret; | ||
94 | } | ||
95 | |||
96 | static int gpio_switch_list_voltage(struct regulator_dev *rdev, | ||
97 | unsigned selector) | ||
98 | { | ||
99 | struct gpio_switch_regulator *ri = rdev_get_drvdata(rdev); | ||
100 | |||
101 | if (selector < ri->reg_desc.n_voltages) | ||
102 | return ri->voltages[selector] * 1000; | ||
103 | else | ||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static int gpio_switch_set_voltage(struct regulator_dev *rdev, | ||
108 | int min_uV, int max_uV, unsigned *selector) | ||
109 | { | ||
110 | struct gpio_switch_regulator *ri = rdev_get_drvdata(rdev); | ||
111 | int uV; | ||
112 | bool found = false; | ||
113 | unsigned val; | ||
114 | |||
115 | for (val = 0; val < ri->reg_desc.n_voltages; val++) { | ||
116 | uV = ri->voltages[val] * 1000; | ||
117 | if (min_uV <= uV && uV <= max_uV) { | ||
118 | found = true; | ||
119 | *selector = ri->curr_vol_sel = val; | ||
120 | break; | ||
121 | } | ||
122 | } | ||
123 | if (found && ri->input_regulator) | ||
124 | return regulator_set_voltage(ri->input_regulator, min_uV, | ||
125 | max_uV); | ||
126 | ri->curr_vol_sel = 0; | ||
127 | return -EINVAL; | ||
128 | } | ||
129 | |||
130 | static int gpio_switch_get_voltage(struct regulator_dev *rdev) | ||
131 | { | ||
132 | struct gpio_switch_regulator *ri = rdev_get_drvdata(rdev); | ||
133 | if (ri->input_regulator) | ||
134 | return regulator_get_voltage(ri->input_regulator); | ||
135 | |||
136 | if (ri->curr_vol_sel < ri->reg_desc.n_voltages) | ||
137 | return ri->voltages[ri->curr_vol_sel] * 1000; | ||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | static int gpio_switch_regulator_enable(struct regulator_dev *rdev) | ||
142 | { | ||
143 | struct gpio_switch_regulator *ri = rdev_get_drvdata(rdev); | ||
144 | int ret = 0; | ||
145 | if (ri->is_enable) | ||
146 | return 0; | ||
147 | |||
148 | if (ri->input_regulator) { | ||
149 | ret = regulator_enable(ri->input_regulator); | ||
150 | if (ret < 0) { | ||
151 | dev_err(&rdev->dev, "%s:Failed to enable regulator" | ||
152 | " Error %d\n", __func__, ret); | ||
153 | return ret; | ||
154 | } | ||
155 | } | ||
156 | |||
157 | ret = _gpio_regulator_enable(&rdev->dev, ri); | ||
158 | if (ret < 0) | ||
159 | return ret; | ||
160 | ri->is_enable = true; | ||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | static int gpio_switch_regulator_disable(struct regulator_dev *rdev) | ||
165 | { | ||
166 | struct gpio_switch_regulator *ri = rdev_get_drvdata(rdev); | ||
167 | int ret = 0; | ||
168 | |||
169 | if (!ri->is_enable) | ||
170 | return 0; | ||
171 | |||
172 | ret = _gpio_regulator_disable(&rdev->dev, ri); | ||
173 | if (ret < 0) | ||
174 | return ret; | ||
175 | |||
176 | if (ri->input_regulator) { | ||
177 | ret = regulator_disable(ri->input_regulator); | ||
178 | if (ret < 0) { | ||
179 | dev_err(&rdev->dev, "%s:Failed to disable regulator" | ||
180 | " Error %d\n", __func__, ret); | ||
181 | return ret; | ||
182 | } | ||
183 | } | ||
184 | |||
185 | ri->is_enable = false; | ||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | static int gpio_switch_regulator_is_enabled(struct regulator_dev *rdev) | ||
190 | { | ||
191 | struct gpio_switch_regulator *ri = rdev_get_drvdata(rdev); | ||
192 | int ret = 0; | ||
193 | if (ri->input_regulator) { | ||
194 | ret = regulator_is_enabled(ri->input_regulator); | ||
195 | if (!ret) | ||
196 | return ret; | ||
197 | } | ||
198 | return (ri->is_enable) ? 1 : 0; | ||
199 | } | ||
200 | |||
201 | static struct regulator_ops gpio_switch_regulator_ops = { | ||
202 | .list_voltage = gpio_switch_list_voltage, | ||
203 | .get_voltage = gpio_switch_get_voltage, | ||
204 | .set_voltage = gpio_switch_set_voltage, | ||
205 | .is_enabled = gpio_switch_regulator_is_enabled, | ||
206 | .enable = gpio_switch_regulator_enable, | ||
207 | .disable = gpio_switch_regulator_disable, | ||
208 | }; | ||
209 | |||
210 | static int __devinit gpio_switch_regulator_probe(struct platform_device *pdev) | ||
211 | { | ||
212 | struct gpio_switch_regulator *ri = NULL; | ||
213 | struct gpio_switch_regulator *gswitch_reg = NULL; | ||
214 | struct gpio_switch_regulator_platform_data *pdata; | ||
215 | struct gpio_switch_regulator_subdev_data *sdata = NULL; | ||
216 | int id = pdev->id; | ||
217 | int ret = 0; | ||
218 | int rcount; | ||
219 | |||
220 | dev_dbg(&pdev->dev, "Probing regulator %d\n", id); | ||
221 | |||
222 | pdata = pdev->dev.platform_data; | ||
223 | if (!pdata) { | ||
224 | dev_err(&pdev->dev, "%s:No platform data Exiting\n", __func__); | ||
225 | return -ENODEV; | ||
226 | } | ||
227 | |||
228 | BUG_ON(!pdata->num_subdevs); | ||
229 | |||
230 | gswitch_reg = kzalloc(sizeof(struct gpio_switch_regulator) * | ||
231 | pdata->num_subdevs, GFP_KERNEL); | ||
232 | if (!gswitch_reg) { | ||
233 | dev_err(&pdev->dev, "%s:Failed to allocate memory\n", __func__); | ||
234 | return -ENOMEM; | ||
235 | } | ||
236 | |||
237 | for (rcount = 0; rcount < pdata->num_subdevs; ++rcount) { | ||
238 | ri = &gswitch_reg[rcount]; | ||
239 | sdata = pdata->subdevs[rcount]; | ||
240 | |||
241 | /* Initialize the regulator parameter */ | ||
242 | ri->reg_desc.name = sdata->regulator_name; | ||
243 | ri->reg_desc.ops = &gpio_switch_regulator_ops; | ||
244 | ri->reg_desc.type = REGULATOR_VOLTAGE; | ||
245 | ri->reg_desc.id = sdata->id; | ||
246 | ri->reg_desc.n_voltages = sdata->n_voltages; | ||
247 | ri->reg_desc.owner = THIS_MODULE; | ||
248 | ri->is_init_success = false; | ||
249 | |||
250 | memcpy(&ri->reg_init_data.constraints, &sdata->constraints, | ||
251 | sizeof(struct regulation_constraints)); | ||
252 | |||
253 | /* Initialize min and maximum contraint voltage if it is not | ||
254 | * define in platform device */ | ||
255 | if (!sdata->constraints.min_uV) | ||
256 | ri->reg_init_data.constraints.min_uV = 1000 * | ||
257 | sdata->voltages[0]; | ||
258 | |||
259 | if (!sdata->constraints.max_uV) | ||
260 | ri->reg_init_data.constraints.max_uV = 1000 * | ||
261 | sdata->voltages[sdata->n_voltages - 1]; | ||
262 | |||
263 | ri->reg_init_data.num_consumer_supplies = | ||
264 | sdata->num_consumer_supplies; | ||
265 | ri->reg_init_data.consumer_supplies = sdata->consumer_supplies; | ||
266 | |||
267 | ri->input_regulator = NULL; | ||
268 | ri->is_gpio_init = false; | ||
269 | ri->is_enable = (sdata->init_state) ? true : false; | ||
270 | ri->voltages = sdata->voltages; | ||
271 | ri->psubdev_data = sdata; | ||
272 | ri->gpio_nr = sdata->gpio_nr; | ||
273 | ri->active_low = sdata->active_low; | ||
274 | ri->dev = &pdev->dev; | ||
275 | ri->enable_rail = sdata->enable_rail; | ||
276 | ri->disable_rail = sdata->disable_rail; | ||
277 | ri->pin_group = sdata->pin_group; | ||
278 | |||
279 | /* Checking for board APIs enable/disable rail */ | ||
280 | if (ri->enable_rail || ri->disable_rail) | ||
281 | BUG_ON(!(ri->enable_rail && ri->disable_rail)); | ||
282 | |||
283 | /* Get the regulator structure if input supply is available */ | ||
284 | if (sdata->input_supply) { | ||
285 | ri->input_regulator = regulator_get(NULL, | ||
286 | sdata->input_supply); | ||
287 | if (IS_ERR_OR_NULL(ri->input_regulator)) { | ||
288 | dev_err(&pdev->dev, "Unable to get regu" | ||
289 | "lator %s\n", sdata->input_supply); | ||
290 | ret = -ENODEV; | ||
291 | goto reg_get_fail; | ||
292 | } | ||
293 | if (ri->is_enable) { | ||
294 | ret = regulator_enable(ri->input_regulator); | ||
295 | if (ret < 0) { | ||
296 | dev_err(&pdev->dev, "Unable to enable " | ||
297 | "regulator %s\n", | ||
298 | sdata->input_supply); | ||
299 | goto reg_en_fail; | ||
300 | } | ||
301 | } | ||
302 | } | ||
303 | |||
304 | /* Initialize gpios */ | ||
305 | ret = gpio_request(ri->gpio_nr, sdata->regulator_name); | ||
306 | if (ret < 0) { | ||
307 | dev_err(&pdev->dev, "Unable to request gpio %d\n", | ||
308 | ri->gpio_nr); | ||
309 | goto gpio_req_fail; | ||
310 | } | ||
311 | |||
312 | if (ri->is_enable) | ||
313 | ret = _gpio_regulator_enable(&pdev->dev, ri); | ||
314 | else | ||
315 | ret = _gpio_regulator_disable(&pdev->dev, ri); | ||
316 | if (ret < 0) | ||
317 | goto reg_cont_fail; | ||
318 | |||
319 | ri->is_gpio_init = true; | ||
320 | |||
321 | ri->rdev = regulator_register(&ri->reg_desc, &pdev->dev, | ||
322 | &ri->reg_init_data, ri); | ||
323 | if (IS_ERR_OR_NULL(ri->rdev)) { | ||
324 | dev_err(&pdev->dev, "Failed to register regulator %s\n", | ||
325 | ri->reg_desc.name); | ||
326 | ret = PTR_ERR(ri->rdev); | ||
327 | goto reg_reg_fail; | ||
328 | } | ||
329 | |||
330 | /* If everything success then continue for next registration */ | ||
331 | ri->is_init_success = true; | ||
332 | continue; | ||
333 | |||
334 | /* Cleanup the current registration and continue for next | ||
335 | * registration*/ | ||
336 | reg_reg_fail: | ||
337 | if (ri->is_enable) | ||
338 | _gpio_regulator_disable(&pdev->dev, ri); | ||
339 | reg_cont_fail: | ||
340 | gpio_free(ri->gpio_nr); | ||
341 | gpio_req_fail: | ||
342 | if (ri->is_enable && ri->input_regulator) | ||
343 | regulator_disable(ri->input_regulator); | ||
344 | reg_en_fail: | ||
345 | if (ri->input_regulator) { | ||
346 | regulator_put(ri->input_regulator); | ||
347 | ri->input_regulator = NULL; | ||
348 | } | ||
349 | reg_get_fail: | ||
350 | dev_err(&pdev->dev, "Unable to register regulator %s\n", | ||
351 | sdata->regulator_name); | ||
352 | } | ||
353 | |||
354 | platform_set_drvdata(pdev, gswitch_reg); | ||
355 | return 0; | ||
356 | } | ||
357 | |||
358 | static int __devexit gpio_switch_regulator_remove(struct platform_device *pdev) | ||
359 | { | ||
360 | struct gpio_switch_regulator *ri = NULL; | ||
361 | struct gpio_switch_regulator *gswitch_reg = platform_get_drvdata(pdev); | ||
362 | int i; | ||
363 | struct gpio_switch_regulator_platform_data *pdata; | ||
364 | |||
365 | pdata = pdev->dev.platform_data; | ||
366 | |||
367 | /* Unregister devices in reverse order */ | ||
368 | for (i = pdata->num_subdevs; i; --i) { | ||
369 | ri = &gswitch_reg[i - 1]; | ||
370 | /* If registration was not success, then do not release */ | ||
371 | if (!ri->is_init_success) | ||
372 | continue; | ||
373 | |||
374 | if (ri->is_enable) | ||
375 | _gpio_regulator_disable(&pdev->dev, ri); | ||
376 | |||
377 | if (ri->input_regulator) { | ||
378 | if (ri->is_enable) | ||
379 | regulator_disable(ri->input_regulator); | ||
380 | regulator_put(ri->input_regulator); | ||
381 | } | ||
382 | |||
383 | regulator_unregister(ri->rdev); | ||
384 | gpio_free(ri->gpio_nr); | ||
385 | } | ||
386 | |||
387 | kfree(gswitch_reg); | ||
388 | platform_set_drvdata(pdev, NULL); | ||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | static struct platform_driver gpio_switch_regulator_driver = { | ||
393 | .driver = { | ||
394 | .name = "gpio-switch-regulator", | ||
395 | .owner = THIS_MODULE, | ||
396 | }, | ||
397 | .probe = gpio_switch_regulator_probe, | ||
398 | .remove = __devexit_p(gpio_switch_regulator_remove), | ||
399 | }; | ||
400 | |||
401 | static int __init gpio_switch_regulator_init(void) | ||
402 | { | ||
403 | return platform_driver_register(&gpio_switch_regulator_driver); | ||
404 | } | ||
405 | |||
406 | static void __exit gpio_switch_regulator_exit(void) | ||
407 | { | ||
408 | platform_driver_unregister(&gpio_switch_regulator_driver); | ||
409 | } | ||
410 | |||
411 | subsys_initcall_sync(gpio_switch_regulator_init); | ||
412 | module_exit(gpio_switch_regulator_exit); | ||