diff options
Diffstat (limited to 'drivers/regulator/gpio-regulator.c')
-rw-r--r-- | drivers/regulator/gpio-regulator.c | 104 |
1 files changed, 102 insertions, 2 deletions
diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c index 8b5944f2d7d1..5ffee5ec3660 100644 --- a/drivers/regulator/gpio-regulator.c +++ b/drivers/regulator/gpio-regulator.c | |||
@@ -28,9 +28,12 @@ | |||
28 | #include <linux/platform_device.h> | 28 | #include <linux/platform_device.h> |
29 | #include <linux/regulator/driver.h> | 29 | #include <linux/regulator/driver.h> |
30 | #include <linux/regulator/machine.h> | 30 | #include <linux/regulator/machine.h> |
31 | #include <linux/regulator/of_regulator.h> | ||
31 | #include <linux/regulator/gpio-regulator.h> | 32 | #include <linux/regulator/gpio-regulator.h> |
32 | #include <linux/gpio.h> | 33 | #include <linux/gpio.h> |
33 | #include <linux/slab.h> | 34 | #include <linux/slab.h> |
35 | #include <linux/of.h> | ||
36 | #include <linux/of_gpio.h> | ||
34 | 37 | ||
35 | struct gpio_regulator_data { | 38 | struct gpio_regulator_data { |
36 | struct regulator_desc desc; | 39 | struct regulator_desc desc; |
@@ -129,18 +132,108 @@ static struct regulator_ops gpio_regulator_voltage_ops = { | |||
129 | .list_voltage = gpio_regulator_list_voltage, | 132 | .list_voltage = gpio_regulator_list_voltage, |
130 | }; | 133 | }; |
131 | 134 | ||
135 | struct gpio_regulator_config * | ||
136 | of_get_gpio_regulator_config(struct device *dev, struct device_node *np) | ||
137 | { | ||
138 | struct gpio_regulator_config *config; | ||
139 | struct property *prop; | ||
140 | const char *regtype; | ||
141 | int proplen, gpio, i; | ||
142 | |||
143 | config = devm_kzalloc(dev, | ||
144 | sizeof(struct gpio_regulator_config), | ||
145 | GFP_KERNEL); | ||
146 | if (!config) | ||
147 | return ERR_PTR(-ENOMEM); | ||
148 | |||
149 | config->init_data = of_get_regulator_init_data(dev, np); | ||
150 | if (!config->init_data) | ||
151 | return ERR_PTR(-EINVAL); | ||
152 | |||
153 | config->supply_name = config->init_data->constraints.name; | ||
154 | |||
155 | if (of_property_read_bool(np, "enable-active-high")) | ||
156 | config->enable_high = true; | ||
157 | |||
158 | if (of_property_read_bool(np, "enable-at-boot")) | ||
159 | config->enabled_at_boot = true; | ||
160 | |||
161 | of_property_read_u32(np, "startup-delay-us", &config->startup_delay); | ||
162 | |||
163 | config->enable_gpio = of_get_named_gpio(np, "enable-gpio", 0); | ||
164 | |||
165 | /* Fetch GPIOs. */ | ||
166 | for (i = 0; ; i++) | ||
167 | if (of_get_named_gpio(np, "gpios", i) < 0) | ||
168 | break; | ||
169 | config->nr_gpios = i; | ||
170 | |||
171 | config->gpios = devm_kzalloc(dev, | ||
172 | sizeof(struct gpio) * config->nr_gpios, | ||
173 | GFP_KERNEL); | ||
174 | if (!config->gpios) | ||
175 | return ERR_PTR(-ENOMEM); | ||
176 | |||
177 | for (i = 0; config->nr_gpios; i++) { | ||
178 | gpio = of_get_named_gpio(np, "gpios", i); | ||
179 | if (gpio < 0) | ||
180 | break; | ||
181 | config->gpios[i].gpio = gpio; | ||
182 | } | ||
183 | |||
184 | /* Fetch states. */ | ||
185 | prop = of_find_property(np, "states", NULL); | ||
186 | if (!prop) { | ||
187 | dev_err(dev, "No 'states' property found\n"); | ||
188 | return ERR_PTR(-EINVAL); | ||
189 | } | ||
190 | |||
191 | proplen = prop->length / sizeof(int); | ||
192 | |||
193 | config->states = devm_kzalloc(dev, | ||
194 | sizeof(struct gpio_regulator_state) | ||
195 | * (proplen / 2), | ||
196 | GFP_KERNEL); | ||
197 | if (!config->states) | ||
198 | return ERR_PTR(-ENOMEM); | ||
199 | |||
200 | for (i = 0; i < proplen / 2; i++) { | ||
201 | config->states[i].value = | ||
202 | be32_to_cpup((int *)prop->value + (i * 2)); | ||
203 | config->states[i].gpios = | ||
204 | be32_to_cpup((int *)prop->value + (i * 2 + 1)); | ||
205 | } | ||
206 | config->nr_states = i; | ||
207 | |||
208 | of_property_read_string(np, "regulator-type", ®type); | ||
209 | |||
210 | if (!strncmp("voltage", regtype, 7)) | ||
211 | config->type = REGULATOR_VOLTAGE; | ||
212 | else if (!strncmp("current", regtype, 7)) | ||
213 | config->type = REGULATOR_CURRENT; | ||
214 | |||
215 | return config; | ||
216 | } | ||
217 | |||
132 | static struct regulator_ops gpio_regulator_current_ops = { | 218 | static struct regulator_ops gpio_regulator_current_ops = { |
133 | .get_current_limit = gpio_regulator_get_value, | 219 | .get_current_limit = gpio_regulator_get_value, |
134 | .set_current_limit = gpio_regulator_set_current_limit, | 220 | .set_current_limit = gpio_regulator_set_current_limit, |
135 | }; | 221 | }; |
136 | 222 | ||
137 | static int __devinit gpio_regulator_probe(struct platform_device *pdev) | 223 | static int gpio_regulator_probe(struct platform_device *pdev) |
138 | { | 224 | { |
139 | struct gpio_regulator_config *config = pdev->dev.platform_data; | 225 | struct gpio_regulator_config *config = pdev->dev.platform_data; |
226 | struct device_node *np = pdev->dev.of_node; | ||
140 | struct gpio_regulator_data *drvdata; | 227 | struct gpio_regulator_data *drvdata; |
141 | struct regulator_config cfg = { }; | 228 | struct regulator_config cfg = { }; |
142 | int ptr, ret, state; | 229 | int ptr, ret, state; |
143 | 230 | ||
231 | if (np) { | ||
232 | config = of_get_gpio_regulator_config(&pdev->dev, np); | ||
233 | if (IS_ERR(config)) | ||
234 | return PTR_ERR(config); | ||
235 | } | ||
236 | |||
144 | drvdata = devm_kzalloc(&pdev->dev, sizeof(struct gpio_regulator_data), | 237 | drvdata = devm_kzalloc(&pdev->dev, sizeof(struct gpio_regulator_data), |
145 | GFP_KERNEL); | 238 | GFP_KERNEL); |
146 | if (drvdata == NULL) { | 239 | if (drvdata == NULL) { |
@@ -215,6 +308,7 @@ static int __devinit gpio_regulator_probe(struct platform_device *pdev) | |||
215 | cfg.dev = &pdev->dev; | 308 | cfg.dev = &pdev->dev; |
216 | cfg.init_data = config->init_data; | 309 | cfg.init_data = config->init_data; |
217 | cfg.driver_data = drvdata; | 310 | cfg.driver_data = drvdata; |
311 | cfg.of_node = np; | ||
218 | 312 | ||
219 | if (config->enable_gpio >= 0) | 313 | if (config->enable_gpio >= 0) |
220 | cfg.ena_gpio = config->enable_gpio; | 314 | cfg.ena_gpio = config->enable_gpio; |
@@ -270,12 +364,18 @@ static int __devexit gpio_regulator_remove(struct platform_device *pdev) | |||
270 | return 0; | 364 | return 0; |
271 | } | 365 | } |
272 | 366 | ||
367 | static const struct of_device_id regulator_gpio_of_match[] __devinitconst = { | ||
368 | { .compatible = "regulator-gpio", }, | ||
369 | {}, | ||
370 | }; | ||
371 | |||
273 | static struct platform_driver gpio_regulator_driver = { | 372 | static struct platform_driver gpio_regulator_driver = { |
274 | .probe = gpio_regulator_probe, | 373 | .probe = gpio_regulator_probe, |
275 | .remove = __devexit_p(gpio_regulator_remove), | 374 | .remove = gpio_regulator_remove, |
276 | .driver = { | 375 | .driver = { |
277 | .name = "gpio-regulator", | 376 | .name = "gpio-regulator", |
278 | .owner = THIS_MODULE, | 377 | .owner = THIS_MODULE, |
378 | .of_match_table = regulator_gpio_of_match, | ||
279 | }, | 379 | }, |
280 | }; | 380 | }; |
281 | 381 | ||