aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/regulator/gpio-switch-regulator.c
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
commitfcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch)
treea57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/regulator/gpio-switch-regulator.c
parent8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff)
Added missing tegra files.HEADmaster
Diffstat (limited to 'drivers/regulator/gpio-switch-regulator.c')
-rw-r--r--drivers/regulator/gpio-switch-regulator.c412
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
35struct 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
54static 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
75static 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
96static 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
107static 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
130static 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
141static 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
164static 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
189static 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
201static 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
210static 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*/
336reg_reg_fail:
337 if (ri->is_enable)
338 _gpio_regulator_disable(&pdev->dev, ri);
339reg_cont_fail:
340 gpio_free(ri->gpio_nr);
341gpio_req_fail:
342 if (ri->is_enable && ri->input_regulator)
343 regulator_disable(ri->input_regulator);
344reg_en_fail:
345 if (ri->input_regulator) {
346 regulator_put(ri->input_regulator);
347 ri->input_regulator = NULL;
348 }
349reg_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
358static 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
392static 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
401static int __init gpio_switch_regulator_init(void)
402{
403 return platform_driver_register(&gpio_switch_regulator_driver);
404}
405
406static void __exit gpio_switch_regulator_exit(void)
407{
408 platform_driver_unregister(&gpio_switch_regulator_driver);
409}
410
411subsys_initcall_sync(gpio_switch_regulator_init);
412module_exit(gpio_switch_regulator_exit);