Root/
1 | /* |
2 | * gpio-regulator.c |
3 | * |
4 | * Copyright 2011 Heiko Stuebner <heiko@sntech.de> |
5 | * |
6 | * based on fixed.c |
7 | * |
8 | * Copyright 2008 Wolfson Microelectronics PLC. |
9 | * |
10 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> |
11 | * |
12 | * Copyright (c) 2009 Nokia Corporation |
13 | * Roger Quadros <ext-roger.quadros@nokia.com> |
14 | * |
15 | * This program is free software; you can redistribute it and/or |
16 | * modify it under the terms of the GNU General Public License as |
17 | * published by the Free Software Foundation; either version 2 of the |
18 | * License, or (at your option) any later version. |
19 | * |
20 | * This is useful for systems with mixed controllable and |
21 | * non-controllable regulators, as well as for allowing testing on |
22 | * systems with no controllable regulators. |
23 | */ |
24 | |
25 | #include <linux/err.h> |
26 | #include <linux/mutex.h> |
27 | #include <linux/module.h> |
28 | #include <linux/platform_device.h> |
29 | #include <linux/regulator/driver.h> |
30 | #include <linux/regulator/machine.h> |
31 | #include <linux/regulator/gpio-regulator.h> |
32 | #include <linux/gpio.h> |
33 | #include <linux/slab.h> |
34 | |
35 | struct gpio_regulator_data { |
36 | struct regulator_desc desc; |
37 | struct regulator_dev *dev; |
38 | |
39 | struct gpio *gpios; |
40 | int nr_gpios; |
41 | |
42 | struct gpio_regulator_state *states; |
43 | int nr_states; |
44 | |
45 | int state; |
46 | }; |
47 | |
48 | static int gpio_regulator_get_value(struct regulator_dev *dev) |
49 | { |
50 | struct gpio_regulator_data *data = rdev_get_drvdata(dev); |
51 | int ptr; |
52 | |
53 | for (ptr = 0; ptr < data->nr_states; ptr++) |
54 | if (data->states[ptr].gpios == data->state) |
55 | return data->states[ptr].value; |
56 | |
57 | return -EINVAL; |
58 | } |
59 | |
60 | static int gpio_regulator_set_voltage(struct regulator_dev *dev, |
61 | int min_uV, int max_uV, |
62 | unsigned *selector) |
63 | { |
64 | struct gpio_regulator_data *data = rdev_get_drvdata(dev); |
65 | int ptr, target = 0, state, best_val = INT_MAX; |
66 | |
67 | for (ptr = 0; ptr < data->nr_states; ptr++) |
68 | if (data->states[ptr].value < best_val && |
69 | data->states[ptr].value >= min_uV && |
70 | data->states[ptr].value <= max_uV) { |
71 | target = data->states[ptr].gpios; |
72 | best_val = data->states[ptr].value; |
73 | if (selector) |
74 | *selector = ptr; |
75 | } |
76 | |
77 | if (best_val == INT_MAX) |
78 | return -EINVAL; |
79 | |
80 | for (ptr = 0; ptr < data->nr_gpios; ptr++) { |
81 | state = (target & (1 << ptr)) >> ptr; |
82 | gpio_set_value(data->gpios[ptr].gpio, state); |
83 | } |
84 | data->state = target; |
85 | |
86 | return 0; |
87 | } |
88 | |
89 | static int gpio_regulator_list_voltage(struct regulator_dev *dev, |
90 | unsigned selector) |
91 | { |
92 | struct gpio_regulator_data *data = rdev_get_drvdata(dev); |
93 | |
94 | if (selector >= data->nr_states) |
95 | return -EINVAL; |
96 | |
97 | return data->states[selector].value; |
98 | } |
99 | |
100 | static int gpio_regulator_set_current_limit(struct regulator_dev *dev, |
101 | int min_uA, int max_uA) |
102 | { |
103 | struct gpio_regulator_data *data = rdev_get_drvdata(dev); |
104 | int ptr, target = 0, state, best_val = 0; |
105 | |
106 | for (ptr = 0; ptr < data->nr_states; ptr++) |
107 | if (data->states[ptr].value > best_val && |
108 | data->states[ptr].value >= min_uA && |
109 | data->states[ptr].value <= max_uA) { |
110 | target = data->states[ptr].gpios; |
111 | best_val = data->states[ptr].value; |
112 | } |
113 | |
114 | if (best_val == 0) |
115 | return -EINVAL; |
116 | |
117 | for (ptr = 0; ptr < data->nr_gpios; ptr++) { |
118 | state = (target & (1 << ptr)) >> ptr; |
119 | gpio_set_value(data->gpios[ptr].gpio, state); |
120 | } |
121 | data->state = target; |
122 | |
123 | return 0; |
124 | } |
125 | |
126 | static struct regulator_ops gpio_regulator_voltage_ops = { |
127 | .get_voltage = gpio_regulator_get_value, |
128 | .set_voltage = gpio_regulator_set_voltage, |
129 | .list_voltage = gpio_regulator_list_voltage, |
130 | }; |
131 | |
132 | static struct regulator_ops gpio_regulator_current_ops = { |
133 | .get_current_limit = gpio_regulator_get_value, |
134 | .set_current_limit = gpio_regulator_set_current_limit, |
135 | }; |
136 | |
137 | static int __devinit gpio_regulator_probe(struct platform_device *pdev) |
138 | { |
139 | struct gpio_regulator_config *config = pdev->dev.platform_data; |
140 | struct gpio_regulator_data *drvdata; |
141 | struct regulator_config cfg = { }; |
142 | int ptr, ret, state; |
143 | |
144 | drvdata = devm_kzalloc(&pdev->dev, sizeof(struct gpio_regulator_data), |
145 | GFP_KERNEL); |
146 | if (drvdata == NULL) { |
147 | dev_err(&pdev->dev, "Failed to allocate device data\n"); |
148 | return -ENOMEM; |
149 | } |
150 | |
151 | drvdata->desc.name = kstrdup(config->supply_name, GFP_KERNEL); |
152 | if (drvdata->desc.name == NULL) { |
153 | dev_err(&pdev->dev, "Failed to allocate supply name\n"); |
154 | ret = -ENOMEM; |
155 | goto err; |
156 | } |
157 | |
158 | drvdata->gpios = kmemdup(config->gpios, |
159 | config->nr_gpios * sizeof(struct gpio), |
160 | GFP_KERNEL); |
161 | if (drvdata->gpios == NULL) { |
162 | dev_err(&pdev->dev, "Failed to allocate gpio data\n"); |
163 | ret = -ENOMEM; |
164 | goto err_name; |
165 | } |
166 | |
167 | drvdata->states = kmemdup(config->states, |
168 | config->nr_states * |
169 | sizeof(struct gpio_regulator_state), |
170 | GFP_KERNEL); |
171 | if (drvdata->states == NULL) { |
172 | dev_err(&pdev->dev, "Failed to allocate state data\n"); |
173 | ret = -ENOMEM; |
174 | goto err_memgpio; |
175 | } |
176 | drvdata->nr_states = config->nr_states; |
177 | |
178 | drvdata->desc.owner = THIS_MODULE; |
179 | drvdata->desc.enable_time = config->startup_delay; |
180 | |
181 | /* handle regulator type*/ |
182 | switch (config->type) { |
183 | case REGULATOR_VOLTAGE: |
184 | drvdata->desc.type = REGULATOR_VOLTAGE; |
185 | drvdata->desc.ops = &gpio_regulator_voltage_ops; |
186 | drvdata->desc.n_voltages = config->nr_states; |
187 | break; |
188 | case REGULATOR_CURRENT: |
189 | drvdata->desc.type = REGULATOR_CURRENT; |
190 | drvdata->desc.ops = &gpio_regulator_current_ops; |
191 | break; |
192 | default: |
193 | dev_err(&pdev->dev, "No regulator type set\n"); |
194 | ret = -EINVAL; |
195 | goto err_memgpio; |
196 | break; |
197 | } |
198 | |
199 | drvdata->nr_gpios = config->nr_gpios; |
200 | ret = gpio_request_array(drvdata->gpios, drvdata->nr_gpios); |
201 | if (ret) { |
202 | dev_err(&pdev->dev, |
203 | "Could not obtain regulator setting GPIOs: %d\n", ret); |
204 | goto err_memstate; |
205 | } |
206 | |
207 | /* build initial state from gpio init data. */ |
208 | state = 0; |
209 | for (ptr = 0; ptr < drvdata->nr_gpios; ptr++) { |
210 | if (config->gpios[ptr].flags & GPIOF_OUT_INIT_HIGH) |
211 | state |= (1 << ptr); |
212 | } |
213 | drvdata->state = state; |
214 | |
215 | cfg.dev = &pdev->dev; |
216 | cfg.init_data = config->init_data; |
217 | cfg.driver_data = drvdata; |
218 | |
219 | if (config->enable_gpio >= 0) |
220 | cfg.ena_gpio = config->enable_gpio; |
221 | cfg.ena_gpio_invert = !config->enable_high; |
222 | if (config->enabled_at_boot) { |
223 | if (config->enable_high) |
224 | cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; |
225 | else |
226 | cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW; |
227 | } else { |
228 | if (config->enable_high) |
229 | cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW; |
230 | else |
231 | cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; |
232 | } |
233 | |
234 | drvdata->dev = regulator_register(&drvdata->desc, &cfg); |
235 | if (IS_ERR(drvdata->dev)) { |
236 | ret = PTR_ERR(drvdata->dev); |
237 | dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret); |
238 | goto err_stategpio; |
239 | } |
240 | |
241 | platform_set_drvdata(pdev, drvdata); |
242 | |
243 | return 0; |
244 | |
245 | err_stategpio: |
246 | gpio_free_array(drvdata->gpios, drvdata->nr_gpios); |
247 | err_memstate: |
248 | kfree(drvdata->states); |
249 | err_memgpio: |
250 | kfree(drvdata->gpios); |
251 | err_name: |
252 | kfree(drvdata->desc.name); |
253 | err: |
254 | return ret; |
255 | } |
256 | |
257 | static int __devexit gpio_regulator_remove(struct platform_device *pdev) |
258 | { |
259 | struct gpio_regulator_data *drvdata = platform_get_drvdata(pdev); |
260 | |
261 | regulator_unregister(drvdata->dev); |
262 | |
263 | gpio_free_array(drvdata->gpios, drvdata->nr_gpios); |
264 | |
265 | kfree(drvdata->states); |
266 | kfree(drvdata->gpios); |
267 | |
268 | kfree(drvdata->desc.name); |
269 | |
270 | return 0; |
271 | } |
272 | |
273 | static struct platform_driver gpio_regulator_driver = { |
274 | .probe = gpio_regulator_probe, |
275 | .remove = __devexit_p(gpio_regulator_remove), |
276 | .driver = { |
277 | .name = "gpio-regulator", |
278 | .owner = THIS_MODULE, |
279 | }, |
280 | }; |
281 | |
282 | static int __init gpio_regulator_init(void) |
283 | { |
284 | return platform_driver_register(&gpio_regulator_driver); |
285 | } |
286 | subsys_initcall(gpio_regulator_init); |
287 | |
288 | static void __exit gpio_regulator_exit(void) |
289 | { |
290 | platform_driver_unregister(&gpio_regulator_driver); |
291 | } |
292 | module_exit(gpio_regulator_exit); |
293 | |
294 | MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>"); |
295 | MODULE_DESCRIPTION("gpio voltage regulator"); |
296 | MODULE_LICENSE("GPL"); |
297 | MODULE_ALIAS("platform:gpio-regulator"); |
298 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9