• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/regulator/
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/platform_device.h>
24#include <linux/regulator/driver.h>
25#include <linux/regulator/fixed.h>
26#include <linux/gpio.h>
27#include <linux/delay.h>
28#include <linux/slab.h>
29
30struct fixed_voltage_data {
31	struct regulator_desc desc;
32	struct regulator_dev *dev;
33	int microvolts;
34	int gpio;
35	unsigned startup_delay;
36	bool enable_high;
37	bool is_enabled;
38};
39
40static int fixed_voltage_is_enabled(struct regulator_dev *dev)
41{
42	struct fixed_voltage_data *data = rdev_get_drvdata(dev);
43
44	return data->is_enabled;
45}
46
47static int fixed_voltage_enable(struct regulator_dev *dev)
48{
49	struct fixed_voltage_data *data = rdev_get_drvdata(dev);
50
51	if (gpio_is_valid(data->gpio)) {
52		gpio_set_value_cansleep(data->gpio, data->enable_high);
53		data->is_enabled = true;
54	}
55
56	return 0;
57}
58
59static int fixed_voltage_disable(struct regulator_dev *dev)
60{
61	struct fixed_voltage_data *data = rdev_get_drvdata(dev);
62
63	if (gpio_is_valid(data->gpio)) {
64		gpio_set_value_cansleep(data->gpio, !data->enable_high);
65		data->is_enabled = false;
66	}
67
68	return 0;
69}
70
71static int fixed_voltage_enable_time(struct regulator_dev *dev)
72{
73	struct fixed_voltage_data *data = rdev_get_drvdata(dev);
74
75	return data->startup_delay;
76}
77
78static int fixed_voltage_get_voltage(struct regulator_dev *dev)
79{
80	struct fixed_voltage_data *data = rdev_get_drvdata(dev);
81
82	return data->microvolts;
83}
84
85static int fixed_voltage_list_voltage(struct regulator_dev *dev,
86				      unsigned selector)
87{
88	struct fixed_voltage_data *data = rdev_get_drvdata(dev);
89
90	if (selector != 0)
91		return -EINVAL;
92
93	return data->microvolts;
94}
95
96static struct regulator_ops fixed_voltage_ops = {
97	.is_enabled = fixed_voltage_is_enabled,
98	.enable = fixed_voltage_enable,
99	.disable = fixed_voltage_disable,
100	.enable_time = fixed_voltage_enable_time,
101	.get_voltage = fixed_voltage_get_voltage,
102	.list_voltage = fixed_voltage_list_voltage,
103};
104
105static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev)
106{
107	struct fixed_voltage_config *config = pdev->dev.platform_data;
108	struct fixed_voltage_data *drvdata;
109	int ret;
110
111	drvdata = kzalloc(sizeof(struct fixed_voltage_data), GFP_KERNEL);
112	if (drvdata == NULL) {
113		dev_err(&pdev->dev, "Failed to allocate device data\n");
114		ret = -ENOMEM;
115		goto err;
116	}
117
118	drvdata->desc.name = kstrdup(config->supply_name, GFP_KERNEL);
119	if (drvdata->desc.name == NULL) {
120		dev_err(&pdev->dev, "Failed to allocate supply name\n");
121		ret = -ENOMEM;
122		goto err;
123	}
124	drvdata->desc.type = REGULATOR_VOLTAGE;
125	drvdata->desc.owner = THIS_MODULE;
126	drvdata->desc.ops = &fixed_voltage_ops;
127	drvdata->desc.n_voltages = 1;
128
129	drvdata->microvolts = config->microvolts;
130	drvdata->gpio = config->gpio;
131	drvdata->startup_delay = config->startup_delay;
132
133	if (gpio_is_valid(config->gpio)) {
134		drvdata->enable_high = config->enable_high;
135
136		if (!config->gpio)
137			dev_warn(&pdev->dev,
138				"using GPIO 0 for regulator enable control\n");
139
140		ret = gpio_request(config->gpio, config->supply_name);
141		if (ret) {
142			dev_err(&pdev->dev,
143			   "Could not obtain regulator enable GPIO %d: %d\n",
144							config->gpio, ret);
145			goto err_name;
146		}
147
148		/* set output direction without changing state
149		 * to prevent glitch
150		 */
151		drvdata->is_enabled = config->enabled_at_boot;
152		ret = drvdata->is_enabled ?
153				config->enable_high : !config->enable_high;
154
155		ret = gpio_direction_output(config->gpio, ret);
156		if (ret) {
157			dev_err(&pdev->dev,
158			   "Could not configure regulator enable GPIO %d direction: %d\n",
159							config->gpio, ret);
160			goto err_gpio;
161		}
162
163	} else {
164		/* Regulator without GPIO control is considered
165		 * always enabled
166		 */
167		drvdata->is_enabled = true;
168	}
169
170	drvdata->dev = regulator_register(&drvdata->desc, &pdev->dev,
171					  config->init_data, drvdata);
172	if (IS_ERR(drvdata->dev)) {
173		ret = PTR_ERR(drvdata->dev);
174		dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret);
175		goto err_gpio;
176	}
177
178	platform_set_drvdata(pdev, drvdata);
179
180	dev_dbg(&pdev->dev, "%s supplying %duV\n", drvdata->desc.name,
181		drvdata->microvolts);
182
183	return 0;
184
185err_gpio:
186	if (gpio_is_valid(config->gpio))
187		gpio_free(config->gpio);
188err_name:
189	kfree(drvdata->desc.name);
190err:
191	kfree(drvdata);
192	return ret;
193}
194
195static int __devexit reg_fixed_voltage_remove(struct platform_device *pdev)
196{
197	struct fixed_voltage_data *drvdata = platform_get_drvdata(pdev);
198
199	regulator_unregister(drvdata->dev);
200	if (gpio_is_valid(drvdata->gpio))
201		gpio_free(drvdata->gpio);
202	kfree(drvdata->desc.name);
203	kfree(drvdata);
204
205	return 0;
206}
207
208static struct platform_driver regulator_fixed_voltage_driver = {
209	.probe		= reg_fixed_voltage_probe,
210	.remove		= __devexit_p(reg_fixed_voltage_remove),
211	.driver		= {
212		.name		= "reg-fixed-voltage",
213		.owner		= THIS_MODULE,
214	},
215};
216
217static int __init regulator_fixed_voltage_init(void)
218{
219	return platform_driver_register(&regulator_fixed_voltage_driver);
220}
221subsys_initcall(regulator_fixed_voltage_init);
222
223static void __exit regulator_fixed_voltage_exit(void)
224{
225	platform_driver_unregister(&regulator_fixed_voltage_driver);
226}
227module_exit(regulator_fixed_voltage_exit);
228
229MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
230MODULE_DESCRIPTION("Fixed voltage regulator");
231MODULE_LICENSE("GPL");
232MODULE_ALIAS("platform:reg-fixed-voltage");
233