Branch data Line data Source code
1 : : /*
2 : : * fixed.c
3 : : *
4 : : * Copyright 2008 Wolfson Microelectronics PLC.
5 : : *
6 : : * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7 : : *
8 : : * Copyright (c) 2009 Nokia Corporation
9 : : * Roger Quadros <ext-roger.quadros@nokia.com>
10 : : *
11 : : * This program is free software; you can redistribute it and/or
12 : : * modify it under the terms of the GNU General Public License as
13 : : * published by the Free Software Foundation; either version 2 of the
14 : : * License, or (at your option) any later version.
15 : : *
16 : : * This is useful for systems with mixed controllable and
17 : : * non-controllable regulators, as well as for allowing testing on
18 : : * systems with no controllable regulators.
19 : : */
20 : :
21 : : #include <linux/err.h>
22 : : #include <linux/mutex.h>
23 : : #include <linux/module.h>
24 : : #include <linux/platform_device.h>
25 : : #include <linux/regulator/driver.h>
26 : : #include <linux/regulator/fixed.h>
27 : : #include <linux/gpio.h>
28 : : #include <linux/slab.h>
29 : : #include <linux/of.h>
30 : : #include <linux/of_gpio.h>
31 : : #include <linux/regulator/of_regulator.h>
32 : : #include <linux/regulator/machine.h>
33 : :
34 : : struct fixed_voltage_data {
35 : : struct regulator_desc desc;
36 : : struct regulator_dev *dev;
37 : : };
38 : :
39 : :
40 : : /**
41 : : * of_get_fixed_voltage_config - extract fixed_voltage_config structure info
42 : : * @dev: device requesting for fixed_voltage_config
43 : : *
44 : : * Populates fixed_voltage_config structure by extracting data from device
45 : : * tree node, returns a pointer to the populated structure of NULL if memory
46 : : * alloc fails.
47 : : */
48 : : static struct fixed_voltage_config *
49 : 0 : of_get_fixed_voltage_config(struct device *dev)
50 : : {
51 : : struct fixed_voltage_config *config;
52 : 0 : struct device_node *np = dev->of_node;
53 : : const __be32 *delay;
54 : : struct regulator_init_data *init_data;
55 : :
56 : : config = devm_kzalloc(dev, sizeof(struct fixed_voltage_config),
57 : : GFP_KERNEL);
58 [ # # ]: 0 : if (!config)
59 : : return ERR_PTR(-ENOMEM);
60 : :
61 : 0 : config->init_data = of_get_regulator_init_data(dev, dev->of_node);
62 [ # # ]: 0 : if (!config->init_data)
63 : : return ERR_PTR(-EINVAL);
64 : :
65 : : init_data = config->init_data;
66 : 0 : init_data->constraints.apply_uV = 0;
67 : :
68 : 0 : config->supply_name = init_data->constraints.name;
69 [ # # ]: 0 : if (init_data->constraints.min_uV == init_data->constraints.max_uV) {
70 : 0 : config->microvolts = init_data->constraints.min_uV;
71 : : } else {
72 : 0 : dev_err(dev,
73 : : "Fixed regulator specified with variable voltages\n");
74 : 0 : return ERR_PTR(-EINVAL);
75 : : }
76 : :
77 [ # # ]: 0 : if (init_data->constraints.boot_on)
78 : 0 : config->enabled_at_boot = true;
79 : :
80 : 0 : config->gpio = of_get_named_gpio(np, "gpio", 0);
81 : : /*
82 : : * of_get_named_gpio() currently returns ENODEV rather than
83 : : * EPROBE_DEFER. This code attempts to be compatible with both
84 : : * for now; the ENODEV check can be removed once the API is fixed.
85 : : * of_get_named_gpio() doesn't differentiate between a missing
86 : : * property (which would be fine here, since the GPIO is optional)
87 : : * and some other error. Patches have been posted for both issues.
88 : : * Once they are check in, we should replace this with:
89 : : * if (config->gpio < 0 && config->gpio != -ENOENT)
90 : : */
91 [ # # ]: 0 : if ((config->gpio == -ENODEV) || (config->gpio == -EPROBE_DEFER))
92 : : return ERR_PTR(-EPROBE_DEFER);
93 : :
94 : 0 : delay = of_get_property(np, "startup-delay-us", NULL);
95 [ # # ]: 0 : if (delay)
96 [ # # ]: 0 : config->startup_delay = be32_to_cpu(*delay);
97 : :
98 [ # # ]: 0 : if (of_find_property(np, "enable-active-high", NULL))
99 : 0 : config->enable_high = true;
100 : :
101 [ # # ]: 0 : if (of_find_property(np, "gpio-open-drain", NULL))
102 : 0 : config->gpio_is_open_drain = true;
103 : :
104 [ # # ]: 0 : if (of_find_property(np, "vin-supply", NULL))
105 : 0 : config->input_supply = "vin";
106 : :
107 : 0 : return config;
108 : : }
109 : :
110 : : static struct regulator_ops fixed_voltage_ops = {
111 : : };
112 : :
113 : 0 : static int reg_fixed_voltage_probe(struct platform_device *pdev)
114 : : {
115 : : struct fixed_voltage_config *config;
116 : : struct fixed_voltage_data *drvdata;
117 : 0 : struct regulator_config cfg = { };
118 : : int ret;
119 : :
120 [ # # ]: 0 : if (pdev->dev.of_node) {
121 : 0 : config = of_get_fixed_voltage_config(&pdev->dev);
122 [ # # ]: 0 : if (IS_ERR(config))
123 : 0 : return PTR_ERR(config);
124 : : } else {
125 : : config = dev_get_platdata(&pdev->dev);
126 : : }
127 : :
128 [ # # ]: 0 : if (!config)
129 : : return -ENOMEM;
130 : :
131 : 0 : drvdata = devm_kzalloc(&pdev->dev, sizeof(struct fixed_voltage_data),
132 : : GFP_KERNEL);
133 [ # # ]: 0 : if (drvdata == NULL) {
134 : 0 : dev_err(&pdev->dev, "Failed to allocate device data\n");
135 : : ret = -ENOMEM;
136 : 0 : goto err;
137 : : }
138 : :
139 : 0 : drvdata->desc.name = kstrdup(config->supply_name, GFP_KERNEL);
140 [ # # ]: 0 : if (drvdata->desc.name == NULL) {
141 : 0 : dev_err(&pdev->dev, "Failed to allocate supply name\n");
142 : : ret = -ENOMEM;
143 : 0 : goto err;
144 : : }
145 : 0 : drvdata->desc.type = REGULATOR_VOLTAGE;
146 : 0 : drvdata->desc.owner = THIS_MODULE;
147 : 0 : drvdata->desc.ops = &fixed_voltage_ops;
148 : :
149 : 0 : drvdata->desc.enable_time = config->startup_delay;
150 : :
151 [ # # ]: 0 : if (config->input_supply) {
152 : 0 : drvdata->desc.supply_name = kstrdup(config->input_supply,
153 : : GFP_KERNEL);
154 [ # # ]: 0 : if (!drvdata->desc.supply_name) {
155 : 0 : dev_err(&pdev->dev,
156 : : "Failed to allocate input supply\n");
157 : : ret = -ENOMEM;
158 : 0 : goto err_name;
159 : : }
160 : : }
161 : :
162 [ # # ]: 0 : if (config->microvolts)
163 : 0 : drvdata->desc.n_voltages = 1;
164 : :
165 : 0 : drvdata->desc.fixed_uV = config->microvolts;
166 : :
167 [ # # ]: 0 : if (config->gpio >= 0)
168 : 0 : cfg.ena_gpio = config->gpio;
169 : 0 : cfg.ena_gpio_invert = !config->enable_high;
170 [ # # ]: 0 : if (config->enabled_at_boot) {
171 [ # # ]: 0 : if (config->enable_high)
172 : 0 : cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH;
173 : : else
174 : : cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW;
175 : : } else {
176 [ # # ]: 0 : if (config->enable_high)
177 : : cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW;
178 : : else
179 : 0 : cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH;
180 : : }
181 [ # # ]: 0 : if (config->gpio_is_open_drain)
182 : 0 : cfg.ena_gpio_flags |= GPIOF_OPEN_DRAIN;
183 : :
184 : 0 : cfg.dev = &pdev->dev;
185 : 0 : cfg.init_data = config->init_data;
186 : 0 : cfg.driver_data = drvdata;
187 : 0 : cfg.of_node = pdev->dev.of_node;
188 : :
189 : 0 : drvdata->dev = regulator_register(&drvdata->desc, &cfg);
190 [ # # ]: 0 : if (IS_ERR(drvdata->dev)) {
191 : : ret = PTR_ERR(drvdata->dev);
192 : 0 : dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret);
193 : : goto err_input;
194 : : }
195 : :
196 : : platform_set_drvdata(pdev, drvdata);
197 : :
198 : : dev_dbg(&pdev->dev, "%s supplying %duV\n", drvdata->desc.name,
199 : : drvdata->desc.fixed_uV);
200 : :
201 : 0 : return 0;
202 : :
203 : : err_input:
204 : 0 : kfree(drvdata->desc.supply_name);
205 : : err_name:
206 : 0 : kfree(drvdata->desc.name);
207 : : err:
208 : 0 : return ret;
209 : : }
210 : :
211 : 0 : static int reg_fixed_voltage_remove(struct platform_device *pdev)
212 : : {
213 : : struct fixed_voltage_data *drvdata = platform_get_drvdata(pdev);
214 : :
215 : 0 : regulator_unregister(drvdata->dev);
216 : 0 : kfree(drvdata->desc.supply_name);
217 : 0 : kfree(drvdata->desc.name);
218 : :
219 : 0 : return 0;
220 : : }
221 : :
222 : : #if defined(CONFIG_OF)
223 : : static const struct of_device_id fixed_of_match[] = {
224 : : { .compatible = "regulator-fixed", },
225 : : {},
226 : : };
227 : : MODULE_DEVICE_TABLE(of, fixed_of_match);
228 : : #endif
229 : :
230 : : static struct platform_driver regulator_fixed_voltage_driver = {
231 : : .probe = reg_fixed_voltage_probe,
232 : : .remove = reg_fixed_voltage_remove,
233 : : .driver = {
234 : : .name = "reg-fixed-voltage",
235 : : .owner = THIS_MODULE,
236 : : .of_match_table = of_match_ptr(fixed_of_match),
237 : : },
238 : : };
239 : :
240 : 0 : static int __init regulator_fixed_voltage_init(void)
241 : : {
242 : 0 : return platform_driver_register(®ulator_fixed_voltage_driver);
243 : : }
244 : : subsys_initcall(regulator_fixed_voltage_init);
245 : :
246 : 0 : static void __exit regulator_fixed_voltage_exit(void)
247 : : {
248 : 0 : platform_driver_unregister(®ulator_fixed_voltage_driver);
249 : 0 : }
250 : : module_exit(regulator_fixed_voltage_exit);
251 : :
252 : : MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
253 : : MODULE_DESCRIPTION("Fixed voltage regulator");
254 : : MODULE_LICENSE("GPL");
255 : : MODULE_ALIAS("platform:reg-fixed-voltage");
|