]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/blame - drivers/regulator/gpio-regulator.c
regulator: gpio-regulator: Set enable enable_time in regulator_desc
[mirror_ubuntu-focal-kernel.git] / drivers / regulator / gpio-regulator.c
CommitLineData
3f0292ae
HS
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>
ecc37edf 27#include <linux/module.h>
3f0292ae
HS
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>
3f0292ae
HS
33#include <linux/slab.h>
34
35struct gpio_regulator_data {
36 struct regulator_desc desc;
37 struct regulator_dev *dev;
38
39 int enable_gpio;
40 bool enable_high;
41 bool is_enabled;
3f0292ae
HS
42
43 struct gpio *gpios;
44 int nr_gpios;
45
46 struct gpio_regulator_state *states;
47 int nr_states;
48
49 int state;
50};
51
52static int gpio_regulator_is_enabled(struct regulator_dev *dev)
53{
54 struct gpio_regulator_data *data = rdev_get_drvdata(dev);
55
56 return data->is_enabled;
57}
58
59static int gpio_regulator_enable(struct regulator_dev *dev)
60{
61 struct gpio_regulator_data *data = rdev_get_drvdata(dev);
62
63 if (gpio_is_valid(data->enable_gpio)) {
64 gpio_set_value_cansleep(data->enable_gpio, data->enable_high);
65 data->is_enabled = true;
66 }
67
68 return 0;
69}
70
71static int gpio_regulator_disable(struct regulator_dev *dev)
72{
73 struct gpio_regulator_data *data = rdev_get_drvdata(dev);
74
75 if (gpio_is_valid(data->enable_gpio)) {
76 gpio_set_value_cansleep(data->enable_gpio, !data->enable_high);
77 data->is_enabled = false;
78 }
79
80 return 0;
81}
82
3f0292ae
HS
83static int gpio_regulator_get_value(struct regulator_dev *dev)
84{
85 struct gpio_regulator_data *data = rdev_get_drvdata(dev);
86 int ptr;
87
88 for (ptr = 0; ptr < data->nr_states; ptr++)
89 if (data->states[ptr].gpios == data->state)
90 return data->states[ptr].value;
91
92 return -EINVAL;
93}
94
95static int gpio_regulator_set_value(struct regulator_dev *dev,
b0e4d7bf 96 int min, int max, unsigned *selector)
3f0292ae
HS
97{
98 struct gpio_regulator_data *data = rdev_get_drvdata(dev);
00926369 99 int ptr, target = 0, state, best_val = INT_MAX;
3f0292ae 100
3f0292ae 101 for (ptr = 0; ptr < data->nr_states; ptr++)
4dbd8f63
AL
102 if (data->states[ptr].value < best_val &&
103 data->states[ptr].value >= min &&
00926369 104 data->states[ptr].value <= max) {
3f0292ae 105 target = data->states[ptr].gpios;
00926369 106 best_val = data->states[ptr].value;
b0e4d7bf
HS
107 if (selector)
108 *selector = ptr;
00926369 109 }
3f0292ae 110
4dbd8f63 111 if (best_val == INT_MAX)
3f0292ae
HS
112 return -EINVAL;
113
114 for (ptr = 0; ptr < data->nr_gpios; ptr++) {
115 state = (target & (1 << ptr)) >> ptr;
116 gpio_set_value(data->gpios[ptr].gpio, state);
117 }
118 data->state = target;
119
120 return 0;
121}
122
123static int gpio_regulator_set_voltage(struct regulator_dev *dev,
124 int min_uV, int max_uV,
125 unsigned *selector)
126{
b0e4d7bf 127 return gpio_regulator_set_value(dev, min_uV, max_uV, selector);
3f0292ae
HS
128}
129
130static int gpio_regulator_list_voltage(struct regulator_dev *dev,
131 unsigned selector)
132{
133 struct gpio_regulator_data *data = rdev_get_drvdata(dev);
134
135 if (selector >= data->nr_states)
136 return -EINVAL;
137
138 return data->states[selector].value;
139}
140
141static int gpio_regulator_set_current_limit(struct regulator_dev *dev,
142 int min_uA, int max_uA)
143{
b0e4d7bf 144 return gpio_regulator_set_value(dev, min_uA, max_uA, NULL);
3f0292ae
HS
145}
146
147static struct regulator_ops gpio_regulator_voltage_ops = {
148 .is_enabled = gpio_regulator_is_enabled,
149 .enable = gpio_regulator_enable,
150 .disable = gpio_regulator_disable,
3f0292ae
HS
151 .get_voltage = gpio_regulator_get_value,
152 .set_voltage = gpio_regulator_set_voltage,
153 .list_voltage = gpio_regulator_list_voltage,
154};
155
156static struct regulator_ops gpio_regulator_current_ops = {
157 .is_enabled = gpio_regulator_is_enabled,
158 .enable = gpio_regulator_enable,
159 .disable = gpio_regulator_disable,
3f0292ae
HS
160 .get_current_limit = gpio_regulator_get_value,
161 .set_current_limit = gpio_regulator_set_current_limit,
162};
163
164static int __devinit gpio_regulator_probe(struct platform_device *pdev)
165{
166 struct gpio_regulator_config *config = pdev->dev.platform_data;
167 struct gpio_regulator_data *drvdata;
c172708d 168 struct regulator_config cfg = { };
3f0292ae
HS
169 int ptr, ret, state;
170
02b55216
MB
171 drvdata = devm_kzalloc(&pdev->dev, sizeof(struct gpio_regulator_data),
172 GFP_KERNEL);
3f0292ae
HS
173 if (drvdata == NULL) {
174 dev_err(&pdev->dev, "Failed to allocate device data\n");
175 return -ENOMEM;
176 }
177
178 drvdata->desc.name = kstrdup(config->supply_name, GFP_KERNEL);
179 if (drvdata->desc.name == NULL) {
180 dev_err(&pdev->dev, "Failed to allocate supply name\n");
181 ret = -ENOMEM;
182 goto err;
183 }
184
185 drvdata->gpios = kmemdup(config->gpios,
186 config->nr_gpios * sizeof(struct gpio),
187 GFP_KERNEL);
188 if (drvdata->gpios == NULL) {
189 dev_err(&pdev->dev, "Failed to allocate gpio data\n");
190 ret = -ENOMEM;
191 goto err_name;
192 }
193
194 drvdata->states = kmemdup(config->states,
195 config->nr_states *
196 sizeof(struct gpio_regulator_state),
197 GFP_KERNEL);
198 if (drvdata->states == NULL) {
199 dev_err(&pdev->dev, "Failed to allocate state data\n");
200 ret = -ENOMEM;
201 goto err_memgpio;
202 }
203 drvdata->nr_states = config->nr_states;
204
205 drvdata->desc.owner = THIS_MODULE;
a2a8222b 206 drvdata->desc.enable_time = config->startup_delay;
3f0292ae
HS
207
208 /* handle regulator type*/
209 switch (config->type) {
210 case REGULATOR_VOLTAGE:
211 drvdata->desc.type = REGULATOR_VOLTAGE;
212 drvdata->desc.ops = &gpio_regulator_voltage_ops;
213 drvdata->desc.n_voltages = config->nr_states;
214 break;
215 case REGULATOR_CURRENT:
216 drvdata->desc.type = REGULATOR_CURRENT;
217 drvdata->desc.ops = &gpio_regulator_current_ops;
218 break;
219 default:
220 dev_err(&pdev->dev, "No regulator type set\n");
221 ret = -EINVAL;
222 goto err_memgpio;
223 break;
224 }
225
226 drvdata->enable_gpio = config->enable_gpio;
3f0292ae
HS
227
228 if (gpio_is_valid(config->enable_gpio)) {
229 drvdata->enable_high = config->enable_high;
230
231 ret = gpio_request(config->enable_gpio, config->supply_name);
232 if (ret) {
233 dev_err(&pdev->dev,
234 "Could not obtain regulator enable GPIO %d: %d\n",
235 config->enable_gpio, ret);
236 goto err_memstate;
237 }
238
239 /* set output direction without changing state
240 * to prevent glitch
241 */
242 if (config->enabled_at_boot) {
243 drvdata->is_enabled = true;
244 ret = gpio_direction_output(config->enable_gpio,
245 config->enable_high);
246 } else {
247 drvdata->is_enabled = false;
248 ret = gpio_direction_output(config->enable_gpio,
249 !config->enable_high);
250 }
251
252 if (ret) {
253 dev_err(&pdev->dev,
254 "Could not configure regulator enable GPIO %d direction: %d\n",
255 config->enable_gpio, ret);
256 goto err_enablegpio;
257 }
258 } else {
259 /* Regulator without GPIO control is considered
260 * always enabled
261 */
262 drvdata->is_enabled = true;
263 }
264
265 drvdata->nr_gpios = config->nr_gpios;
266 ret = gpio_request_array(drvdata->gpios, drvdata->nr_gpios);
267 if (ret) {
268 dev_err(&pdev->dev,
269 "Could not obtain regulator setting GPIOs: %d\n", ret);
270 goto err_enablegpio;
271 }
272
273 /* build initial state from gpio init data. */
274 state = 0;
275 for (ptr = 0; ptr < drvdata->nr_gpios; ptr++) {
276 if (config->gpios[ptr].flags & GPIOF_OUT_INIT_HIGH)
277 state |= (1 << ptr);
278 }
279 drvdata->state = state;
280
c172708d
MB
281 cfg.dev = &pdev->dev;
282 cfg.init_data = config->init_data;
7d4be2f5 283 cfg.driver_data = drvdata;
c172708d
MB
284
285 drvdata->dev = regulator_register(&drvdata->desc, &cfg);
3f0292ae
HS
286 if (IS_ERR(drvdata->dev)) {
287 ret = PTR_ERR(drvdata->dev);
288 dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret);
289 goto err_stategpio;
290 }
291
292 platform_set_drvdata(pdev, drvdata);
293
294 return 0;
295
296err_stategpio:
297 gpio_free_array(drvdata->gpios, drvdata->nr_gpios);
298err_enablegpio:
299 if (gpio_is_valid(config->enable_gpio))
300 gpio_free(config->enable_gpio);
301err_memstate:
302 kfree(drvdata->states);
303err_memgpio:
304 kfree(drvdata->gpios);
305err_name:
306 kfree(drvdata->desc.name);
307err:
3f0292ae
HS
308 return ret;
309}
310
311static int __devexit gpio_regulator_remove(struct platform_device *pdev)
312{
313 struct gpio_regulator_data *drvdata = platform_get_drvdata(pdev);
314
315 regulator_unregister(drvdata->dev);
316
317 gpio_free_array(drvdata->gpios, drvdata->nr_gpios);
318
319 kfree(drvdata->states);
320 kfree(drvdata->gpios);
321
322 if (gpio_is_valid(drvdata->enable_gpio))
323 gpio_free(drvdata->enable_gpio);
324
325 kfree(drvdata->desc.name);
3f0292ae
HS
326
327 return 0;
328}
329
330static struct platform_driver gpio_regulator_driver = {
331 .probe = gpio_regulator_probe,
332 .remove = __devexit_p(gpio_regulator_remove),
333 .driver = {
334 .name = "gpio-regulator",
335 .owner = THIS_MODULE,
336 },
337};
338
339static int __init gpio_regulator_init(void)
340{
341 return platform_driver_register(&gpio_regulator_driver);
342}
343subsys_initcall(gpio_regulator_init);
344
345static void __exit gpio_regulator_exit(void)
346{
347 platform_driver_unregister(&gpio_regulator_driver);
348}
349module_exit(gpio_regulator_exit);
350
351MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
352MODULE_DESCRIPTION("gpio voltage regulator");
353MODULE_LICENSE("GPL");
354MODULE_ALIAS("platform:gpio-regulator");