blob: 1c4b935d90dec5d655b49ddfb9a50ab78238b963 [file] [log] [blame]
Michael Bohan9b7ac512012-02-24 14:42:44 -08001/*
2 * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#define pr_fmt(fmt) "%s: " fmt, __func__
15
16#include <linux/module.h>
17#include <linux/err.h>
18#include <linux/kernel.h>
19#include <linux/regulator/driver.h>
20#include <linux/regulator/stub-regulator.h>
21#include <linux/platform_device.h>
22#include <linux/slab.h>
23#include <linux/types.h>
24
25#define STUB_REGULATOR_MAX_NAME 40
26
27struct regulator_stub {
28 struct regulator_desc rdesc;
29 struct regulator_dev *rdev;
30 int voltage;
31 bool enabled;
32 int mode;
33 int hpm_min_load;
34 int system_uA;
35 char name[STUB_REGULATOR_MAX_NAME];
36};
37
38static int regulator_stub_set_voltage(struct regulator_dev *rdev, int min_uV,
39 int max_uV, unsigned *selector)
40{
41 struct regulator_stub *vreg_priv = rdev_get_drvdata(rdev);
42 vreg_priv->voltage = min_uV;
43 return 0;
44}
45
46static int regulator_stub_get_voltage(struct regulator_dev *rdev)
47{
48 struct regulator_stub *vreg_priv = rdev_get_drvdata(rdev);
49 return vreg_priv->voltage;
50}
51
52static int regulator_stub_list_voltage(struct regulator_dev *rdev,
53 unsigned selector)
54{
55 struct regulation_constraints *constraints = rdev->constraints;
56
57 if (selector >= 2)
58 return -EINVAL;
59 else if (selector == 0)
60 return constraints->min_uV;
61 else
62 return constraints->max_uV;
63}
64
65static unsigned int regulator_stub_get_mode(struct regulator_dev *rdev)
66{
67 struct regulator_stub *vreg_priv = rdev_get_drvdata(rdev);
68 return vreg_priv->mode;
69}
70
71static int regulator_stub_set_mode(struct regulator_dev *rdev,
72 unsigned int mode)
73{
74 struct regulator_stub *vreg_priv = rdev_get_drvdata(rdev);
75
76 if (mode != REGULATOR_MODE_NORMAL && mode != REGULATOR_MODE_IDLE) {
77 dev_err(&rdev->dev, "%s: invalid mode requested %u\n",
78 __func__, mode);
79 return -EINVAL;
80 }
81 vreg_priv->mode = mode;
82 return 0;
83}
84
85static unsigned int regulator_stub_get_optimum_mode(struct regulator_dev *rdev,
86 int input_uV, int output_uV, int load_uA)
87{
88 struct regulator_stub *vreg_priv = rdev_get_drvdata(rdev);
89 unsigned int mode;
90
91 if (load_uA + vreg_priv->system_uA >= vreg_priv->hpm_min_load)
92 mode = REGULATOR_MODE_NORMAL;
93 else
94 mode = REGULATOR_MODE_IDLE;
95
96 return mode;
97}
98
99static int regulator_stub_enable(struct regulator_dev *rdev)
100{
101 struct regulator_stub *vreg_priv = rdev_get_drvdata(rdev);
102 vreg_priv->enabled = true;
103 return 0;
104}
105
106static int regulator_stub_disable(struct regulator_dev *rdev)
107{
108 struct regulator_stub *vreg_priv = rdev_get_drvdata(rdev);
109 vreg_priv->enabled = false;
110 return 0;
111}
112
113static int regulator_stub_is_enabled(struct regulator_dev *rdev)
114{
115 struct regulator_stub *vreg_priv = rdev_get_drvdata(rdev);
116 return vreg_priv->enabled;
117}
118
119/* Real regulator operations. */
120static struct regulator_ops regulator_stub_ops = {
121 .enable = regulator_stub_enable,
122 .disable = regulator_stub_disable,
123 .is_enabled = regulator_stub_is_enabled,
124 .set_voltage = regulator_stub_set_voltage,
125 .get_voltage = regulator_stub_get_voltage,
126 .list_voltage = regulator_stub_list_voltage,
127 .set_mode = regulator_stub_set_mode,
128 .get_mode = regulator_stub_get_mode,
129 .get_optimum_mode = regulator_stub_get_optimum_mode,
130};
131
132static void regulator_stub_cleanup(struct regulator_stub *vreg_priv)
133{
134 if (vreg_priv && vreg_priv->rdev)
135 regulator_unregister(vreg_priv->rdev);
136 kfree(vreg_priv);
137}
138
139static int __devinit regulator_stub_probe(struct platform_device *pdev)
140{
141 struct stub_regulator_pdata *vreg_pdata;
142 struct regulator_desc *rdesc;
143 struct regulator_stub *vreg_priv;
144 int rc;
145
146 vreg_pdata = pdev->dev.platform_data;
147 if (!vreg_pdata) {
148 dev_err(&pdev->dev, "%s: no platform data\n", __func__);
149 return -EINVAL;
150 }
151
152 vreg_priv = kzalloc(sizeof(*vreg_priv), GFP_KERNEL);
153 if (!vreg_priv) {
154 dev_err(&pdev->dev, "%s: Unable to allocate memory\n",
155 __func__);
156 return -ENOMEM;
157 }
158 dev_set_drvdata(&pdev->dev, vreg_priv);
159
160 rdesc = &vreg_priv->rdesc;
161 strncpy(vreg_priv->name, vreg_pdata->init_data.constraints.name,
162 STUB_REGULATOR_MAX_NAME);
163 rdesc->name = vreg_priv->name;
164 rdesc->ops = &regulator_stub_ops;
165
166 /*
167 * Ensure that voltage set points are handled correctly for regulators
168 * which have a specified voltage constraint range, as well as those
169 * that do not.
170 */
171 if (vreg_pdata->init_data.constraints.min_uV == 0 &&
172 vreg_pdata->init_data.constraints.max_uV == 0)
173 rdesc->n_voltages = 0;
174 else
175 rdesc->n_voltages = 2;
176
177 rdesc->id = pdev->id;
178 rdesc->owner = THIS_MODULE;
179 rdesc->type = REGULATOR_VOLTAGE;
180 vreg_priv->system_uA = vreg_pdata->system_uA;
181 vreg_priv->hpm_min_load = vreg_pdata->hpm_min_load;
Michael Bohan19f18652012-03-20 10:30:35 -0700182 vreg_priv->voltage = vreg_pdata->init_data.constraints.min_uV;
Michael Bohan9b7ac512012-02-24 14:42:44 -0800183
184 vreg_priv->rdev = regulator_register(rdesc, &pdev->dev,
Rajendra Nayak11eafc62011-11-18 16:47:19 +0530185 &(vreg_pdata->init_data), vreg_priv, NULL);
Michael Bohan9b7ac512012-02-24 14:42:44 -0800186 if (IS_ERR(vreg_priv->rdev)) {
187 rc = PTR_ERR(vreg_priv->rdev);
188 vreg_priv->rdev = NULL;
189 dev_err(&pdev->dev, "%s: regulator_register failed\n",
190 __func__);
191 goto err_probe;
192 }
193
194 return 0;
195
196err_probe:
197 regulator_stub_cleanup(vreg_priv);
198 return rc;
199}
200
201static int __devexit regulator_stub_remove(struct platform_device *pdev)
202{
203 struct regulator_stub *vreg_priv = dev_get_drvdata(&pdev->dev);
204
205 regulator_stub_cleanup(vreg_priv);
206 return 0;
207}
208
209static struct platform_driver regulator_stub_driver = {
210 .probe = regulator_stub_probe,
211 .remove = __devexit_p(regulator_stub_remove),
212 .driver = {
213 .name = STUB_REGULATOR_DRIVER_NAME,
214 .owner = THIS_MODULE,
215 },
216};
217
Michael Bohan83b00652012-03-30 14:19:38 -0700218int __init regulator_stub_init(void)
Michael Bohan9b7ac512012-02-24 14:42:44 -0800219{
Michael Bohan83b00652012-03-30 14:19:38 -0700220 static int registered;
221
222 if (registered)
223 return 0;
224 else
225 registered = 1;
Michael Bohan9b7ac512012-02-24 14:42:44 -0800226 return platform_driver_register(&regulator_stub_driver);
227}
228postcore_initcall(regulator_stub_init);
Michael Bohan83b00652012-03-30 14:19:38 -0700229EXPORT_SYMBOL(regulator_stub_init);
Michael Bohan9b7ac512012-02-24 14:42:44 -0800230
231static void __exit regulator_stub_exit(void)
232{
233 platform_driver_unregister(&regulator_stub_driver);
234}
235module_exit(regulator_stub_exit);
236
237MODULE_LICENSE("GPL v2");
238MODULE_DESCRIPTION("stub regulator driver");
239MODULE_VERSION("1.0");
240MODULE_ALIAS("platform: " STUB_REGULATOR_DRIVER_NAME);