diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
commit | fcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch) | |
tree | a57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/regulator/ricoh583-regulator.c | |
parent | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff) |
Diffstat (limited to 'drivers/regulator/ricoh583-regulator.c')
-rw-r--r-- | drivers/regulator/ricoh583-regulator.c | 412 |
1 files changed, 412 insertions, 0 deletions
diff --git a/drivers/regulator/ricoh583-regulator.c b/drivers/regulator/ricoh583-regulator.c new file mode 100644 index 00000000000..867ffe629ed --- /dev/null +++ b/drivers/regulator/ricoh583-regulator.c | |||
@@ -0,0 +1,412 @@ | |||
1 | /* | ||
2 | * drivers/regulator/ricoh583-regulator.c | ||
3 | * | ||
4 | * Regulator driver for RICOH583 power management chip. | ||
5 | * | ||
6 | * Copyright (C) 2011 NVIDIA Corporation | ||
7 | * | ||
8 | * Copyright (C) 2011 RICOH COMPANY,LTD | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
16 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
18 | * more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License along | ||
21 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
22 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | /*#define DEBUG 1*/ | ||
27 | /*#define VERBOSE_DEBUG 1*/ | ||
28 | #include <linux/module.h> | ||
29 | #include <linux/delay.h> | ||
30 | #include <linux/init.h> | ||
31 | #include <linux/slab.h> | ||
32 | #include <linux/err.h> | ||
33 | #include <linux/platform_device.h> | ||
34 | #include <linux/regulator/driver.h> | ||
35 | #include <linux/regulator/machine.h> | ||
36 | #include <linux/mfd/ricoh583.h> | ||
37 | #include <linux/regulator/ricoh583-regulator.h> | ||
38 | |||
39 | struct ricoh583_regulator { | ||
40 | int id; | ||
41 | int deepsleep_id; | ||
42 | /* Regulator register address.*/ | ||
43 | u8 reg_en_reg; | ||
44 | u8 en_bit; | ||
45 | u8 reg_disc_reg; | ||
46 | u8 disc_bit; | ||
47 | u8 vout_reg; | ||
48 | u8 vout_mask; | ||
49 | u8 vout_reg_cache; | ||
50 | u8 deepsleep_reg; | ||
51 | |||
52 | /* chip constraints on regulator behavior */ | ||
53 | int min_uV; | ||
54 | int max_uV; | ||
55 | int step_uV; | ||
56 | int nsteps; | ||
57 | |||
58 | /* regulator specific turn-on delay */ | ||
59 | u16 delay; | ||
60 | |||
61 | /* used by regulator core */ | ||
62 | struct regulator_desc desc; | ||
63 | |||
64 | /* Device */ | ||
65 | struct device *dev; | ||
66 | }; | ||
67 | |||
68 | |||
69 | static inline struct device *to_ricoh583_dev(struct regulator_dev *rdev) | ||
70 | { | ||
71 | return rdev_get_dev(rdev)->parent->parent; | ||
72 | } | ||
73 | |||
74 | static int ricoh583_regulator_enable_time(struct regulator_dev *rdev) | ||
75 | { | ||
76 | struct ricoh583_regulator *ri = rdev_get_drvdata(rdev); | ||
77 | |||
78 | return ri->delay; | ||
79 | } | ||
80 | |||
81 | static int ricoh583_reg_is_enabled(struct regulator_dev *rdev) | ||
82 | { | ||
83 | struct ricoh583_regulator *ri = rdev_get_drvdata(rdev); | ||
84 | struct device *parent = to_ricoh583_dev(rdev); | ||
85 | uint8_t control; | ||
86 | int ret; | ||
87 | |||
88 | ret = ricoh583_read(parent, ri->reg_en_reg, &control); | ||
89 | if (ret < 0) { | ||
90 | dev_err(&rdev->dev, "Error in reading the control register\n"); | ||
91 | return ret; | ||
92 | } | ||
93 | return (((control >> ri->en_bit) & 1) == 1); | ||
94 | } | ||
95 | |||
96 | static int ricoh583_reg_enable(struct regulator_dev *rdev) | ||
97 | { | ||
98 | struct ricoh583_regulator *ri = rdev_get_drvdata(rdev); | ||
99 | struct device *parent = to_ricoh583_dev(rdev); | ||
100 | int ret; | ||
101 | |||
102 | ret = ricoh583_set_bits(parent, ri->reg_en_reg, (1 << ri->en_bit)); | ||
103 | if (ret < 0) { | ||
104 | dev_err(&rdev->dev, "Error in updating the STATE register\n"); | ||
105 | return ret; | ||
106 | } | ||
107 | udelay(ri->delay); | ||
108 | return ret; | ||
109 | } | ||
110 | |||
111 | static int ricoh583_reg_disable(struct regulator_dev *rdev) | ||
112 | { | ||
113 | struct ricoh583_regulator *ri = rdev_get_drvdata(rdev); | ||
114 | struct device *parent = to_ricoh583_dev(rdev); | ||
115 | int ret; | ||
116 | |||
117 | ret = ricoh583_clr_bits(parent, ri->reg_en_reg, (1 << ri->en_bit)); | ||
118 | if (ret < 0) | ||
119 | dev_err(&rdev->dev, "Error in updating the STATE register\n"); | ||
120 | |||
121 | return ret; | ||
122 | } | ||
123 | |||
124 | static int ricoh583_list_voltage(struct regulator_dev *rdev, unsigned index) | ||
125 | { | ||
126 | struct ricoh583_regulator *ri = rdev_get_drvdata(rdev); | ||
127 | |||
128 | return ri->min_uV + (ri->step_uV * index); | ||
129 | } | ||
130 | |||
131 | static int __ricoh583_set_ds_voltage(struct device *parent, | ||
132 | struct ricoh583_regulator *ri, int min_uV, int max_uV) | ||
133 | { | ||
134 | int vsel; | ||
135 | int ret; | ||
136 | |||
137 | if ((min_uV < ri->min_uV) || (max_uV > ri->max_uV)) | ||
138 | return -EDOM; | ||
139 | |||
140 | vsel = (min_uV - ri->min_uV + ri->step_uV - 1)/ri->step_uV; | ||
141 | if (vsel > ri->nsteps) | ||
142 | return -EDOM; | ||
143 | |||
144 | ret = ricoh583_update(parent, ri->deepsleep_reg, vsel, ri->vout_mask); | ||
145 | if (ret < 0) | ||
146 | dev_err(ri->dev, "Error in writing the deepsleep register\n"); | ||
147 | return ret; | ||
148 | } | ||
149 | |||
150 | static int __ricoh583_set_voltage(struct device *parent, | ||
151 | struct ricoh583_regulator *ri, int min_uV, int max_uV, | ||
152 | unsigned *selector) | ||
153 | { | ||
154 | int vsel; | ||
155 | int ret; | ||
156 | uint8_t vout_val; | ||
157 | |||
158 | if ((min_uV < ri->min_uV) || (max_uV > ri->max_uV)) | ||
159 | return -EDOM; | ||
160 | |||
161 | vsel = (min_uV - ri->min_uV + ri->step_uV - 1)/ri->step_uV; | ||
162 | if (vsel > ri->nsteps) | ||
163 | return -EDOM; | ||
164 | |||
165 | if (selector) | ||
166 | *selector = vsel; | ||
167 | |||
168 | vout_val = (ri->vout_reg_cache & ~ri->vout_mask) | | ||
169 | (vsel & ri->vout_mask); | ||
170 | ret = ricoh583_write(parent, ri->vout_reg, vout_val); | ||
171 | if (ret < 0) | ||
172 | dev_err(ri->dev, "Error in writing the Voltage register\n"); | ||
173 | else | ||
174 | ri->vout_reg_cache = vout_val; | ||
175 | |||
176 | return ret; | ||
177 | } | ||
178 | |||
179 | static int ricoh583_set_voltage(struct regulator_dev *rdev, | ||
180 | int min_uV, int max_uV, unsigned *selector) | ||
181 | { | ||
182 | struct ricoh583_regulator *ri = rdev_get_drvdata(rdev); | ||
183 | struct device *parent = to_ricoh583_dev(rdev); | ||
184 | |||
185 | return __ricoh583_set_voltage(parent, ri, min_uV, max_uV, selector); | ||
186 | } | ||
187 | |||
188 | static int ricoh583_get_voltage(struct regulator_dev *rdev) | ||
189 | { | ||
190 | struct ricoh583_regulator *ri = rdev_get_drvdata(rdev); | ||
191 | uint8_t vsel; | ||
192 | |||
193 | vsel = ri->vout_reg_cache & ri->vout_mask; | ||
194 | return ri->min_uV + vsel * ri->step_uV; | ||
195 | } | ||
196 | |||
197 | static struct regulator_ops ricoh583_ops = { | ||
198 | .list_voltage = ricoh583_list_voltage, | ||
199 | .set_voltage = ricoh583_set_voltage, | ||
200 | .get_voltage = ricoh583_get_voltage, | ||
201 | .enable = ricoh583_reg_enable, | ||
202 | .disable = ricoh583_reg_disable, | ||
203 | .is_enabled = ricoh583_reg_is_enabled, | ||
204 | .enable_time = ricoh583_regulator_enable_time, | ||
205 | }; | ||
206 | |||
207 | #define RICOH583_REG(_id, _en_reg, _en_bit, _disc_reg, _disc_bit, _vout_reg, \ | ||
208 | _vout_mask, _ds_reg, _min_mv, _max_mv, _step_uV, _nsteps, \ | ||
209 | _ops, _delay) \ | ||
210 | { \ | ||
211 | .reg_en_reg = _en_reg, \ | ||
212 | .en_bit = _en_bit, \ | ||
213 | .reg_disc_reg = _disc_reg, \ | ||
214 | .disc_bit = _disc_bit, \ | ||
215 | .vout_reg = _vout_reg, \ | ||
216 | .vout_mask = _vout_mask, \ | ||
217 | .deepsleep_reg = _ds_reg, \ | ||
218 | .min_uV = _min_mv * 1000, \ | ||
219 | .max_uV = _max_mv * 1000, \ | ||
220 | .step_uV = _step_uV, \ | ||
221 | .nsteps = _nsteps, \ | ||
222 | .delay = _delay, \ | ||
223 | .id = RICOH583_ID_##_id, \ | ||
224 | .deepsleep_id = RICOH583_DS_##_id, \ | ||
225 | .desc = { \ | ||
226 | .name = ricoh583_rails(_id), \ | ||
227 | .id = RICOH583_ID_##_id, \ | ||
228 | .n_voltages = _nsteps, \ | ||
229 | .ops = &_ops, \ | ||
230 | .type = REGULATOR_VOLTAGE, \ | ||
231 | .owner = THIS_MODULE, \ | ||
232 | }, \ | ||
233 | } | ||
234 | |||
235 | static struct ricoh583_regulator ricoh583_regulator[] = { | ||
236 | RICOH583_REG(DC0, 0x30, 0, 0x30, 1, 0x31, 0x7F, 0x60, | ||
237 | 700, 1500, 12500, 0x41, ricoh583_ops, 500), | ||
238 | RICOH583_REG(DC1, 0x34, 0, 0x34, 1, 0x35, 0x7F, 0x61, | ||
239 | 700, 1500, 12500, 0x41, ricoh583_ops, 500), | ||
240 | RICOH583_REG(DC2, 0x38, 0, 0x38, 1, 0x39, 0x7F, 0x62, | ||
241 | 900, 2400, 12500, 0x79, ricoh583_ops, 500), | ||
242 | RICOH583_REG(DC3, 0x3C, 0, 0x3C, 1, 0x3D, 0x7F, 0x63, | ||
243 | 900, 2400, 12500, 0x79, ricoh583_ops, 500), | ||
244 | RICOH583_REG(LDO0, 0x51, 0, 0x53, 0, 0x54, 0x7F, 0x64, | ||
245 | 900, 3400, 25000, 0x65, ricoh583_ops, 500), | ||
246 | RICOH583_REG(LDO1, 0x51, 1, 0x53, 1, 0x55, 0x7F, 0x65, | ||
247 | 900, 3400, 25000, 0x65, ricoh583_ops, 500), | ||
248 | RICOH583_REG(LDO2, 0x51, 2, 0x53, 2, 0x56, 0x7F, 0x66, | ||
249 | 900, 3400, 25000, 0x65, ricoh583_ops, 500), | ||
250 | RICOH583_REG(LDO3, 0x51, 3, 0x53, 3, 0x57, 0x7F, 0x67, | ||
251 | 900, 3400, 25000, 0x65, ricoh583_ops, 500), | ||
252 | RICOH583_REG(LDO4, 0x51, 4, 0x53, 4, 0x58, 0x3F, 0x68, | ||
253 | 750, 1500, 12500, 0x3D, ricoh583_ops, 500), | ||
254 | RICOH583_REG(LDO5, 0x51, 5, 0x53, 5, 0x59, 0x7F, 0x69, | ||
255 | 900, 3400, 25000, 0x65, ricoh583_ops, 500), | ||
256 | RICOH583_REG(LDO6, 0x51, 6, 0x53, 6, 0x5A, 0x7F, 0x6A, | ||
257 | 900, 3400, 25000, 0x65, ricoh583_ops, 500), | ||
258 | RICOH583_REG(LDO7, 0x51, 7, 0x53, 7, 0x5B, 0x7F, 0x6B, | ||
259 | 900, 3400, 25000, 0x65, ricoh583_ops, 500), | ||
260 | RICOH583_REG(LDO8, 0x50, 0, 0x52, 0, 0x5C, 0x7F, 0x6C, | ||
261 | 900, 3400, 25000, 0x65, ricoh583_ops, 500), | ||
262 | RICOH583_REG(LDO9, 0x50, 1, 0x52, 1, 0x5D, 0x7F, 0x6D, | ||
263 | 900, 3400, 25000, 0x65, ricoh583_ops, 500), | ||
264 | }; | ||
265 | static inline struct ricoh583_regulator *find_regulator_info(int id) | ||
266 | { | ||
267 | struct ricoh583_regulator *ri; | ||
268 | int i; | ||
269 | |||
270 | for (i = 0; i < ARRAY_SIZE(ricoh583_regulator); i++) { | ||
271 | ri = &ricoh583_regulator[i]; | ||
272 | if (ri->desc.id == id) | ||
273 | return ri; | ||
274 | } | ||
275 | return NULL; | ||
276 | } | ||
277 | |||
278 | static int ricoh583_regulator_preinit(struct device *parent, | ||
279 | struct ricoh583_regulator *ri, | ||
280 | struct ricoh583_regulator_platform_data *ricoh583_pdata) | ||
281 | { | ||
282 | int ret = 0; | ||
283 | |||
284 | if (ri->deepsleep_id != RICOH583_DS_NONE) { | ||
285 | ret = ricoh583_ext_power_req_config(parent, ri->deepsleep_id, | ||
286 | ricoh583_pdata->ext_pwr_req, | ||
287 | ricoh583_pdata->deepsleep_slots); | ||
288 | if (ret < 0) | ||
289 | return ret; | ||
290 | } | ||
291 | |||
292 | if (!ricoh583_pdata->init_apply) | ||
293 | return 0; | ||
294 | |||
295 | if (ricoh583_pdata->deepsleep_uV) { | ||
296 | ret = __ricoh583_set_ds_voltage(parent, ri, | ||
297 | ricoh583_pdata->deepsleep_uV, | ||
298 | ricoh583_pdata->deepsleep_uV); | ||
299 | if (ret < 0) { | ||
300 | dev_err(ri->dev, "Not able to initialize ds voltage %d" | ||
301 | " for rail %d err %d\n", | ||
302 | ricoh583_pdata->deepsleep_uV, ri->desc.id, ret); | ||
303 | return ret; | ||
304 | } | ||
305 | } | ||
306 | |||
307 | if (ricoh583_pdata->init_uV >= 0) { | ||
308 | ret = __ricoh583_set_voltage(parent, ri, | ||
309 | ricoh583_pdata->init_uV, | ||
310 | ricoh583_pdata->init_uV, 0); | ||
311 | if (ret < 0) { | ||
312 | dev_err(ri->dev, "Not able to initialize voltage %d " | ||
313 | "for rail %d err %d\n", ricoh583_pdata->init_uV, | ||
314 | ri->desc.id, ret); | ||
315 | return ret; | ||
316 | } | ||
317 | } | ||
318 | |||
319 | if (ricoh583_pdata->init_enable) | ||
320 | ret = ricoh583_set_bits(parent, ri->reg_en_reg, | ||
321 | (1 << ri->en_bit)); | ||
322 | else | ||
323 | ret = ricoh583_clr_bits(parent, ri->reg_en_reg, | ||
324 | (1 << ri->en_bit)); | ||
325 | if (ret < 0) | ||
326 | dev_err(ri->dev, "Not able to %s rail %d err %d\n", | ||
327 | (ricoh583_pdata->init_enable) ? "enable" : "disable", | ||
328 | ri->desc.id, ret); | ||
329 | |||
330 | return ret; | ||
331 | } | ||
332 | |||
333 | static inline int ricoh583_cache_regulator_register(struct device *parent, | ||
334 | struct ricoh583_regulator *ri) | ||
335 | { | ||
336 | ri->vout_reg_cache = 0; | ||
337 | return ricoh583_read(parent, ri->vout_reg, &ri->vout_reg_cache); | ||
338 | } | ||
339 | |||
340 | static int __devinit ricoh583_regulator_probe(struct platform_device *pdev) | ||
341 | { | ||
342 | struct ricoh583_regulator *ri = NULL; | ||
343 | struct regulator_dev *rdev; | ||
344 | struct ricoh583_regulator_platform_data *tps_pdata; | ||
345 | int id = pdev->id; | ||
346 | int err; | ||
347 | |||
348 | dev_dbg(&pdev->dev, "Probing reulator %d\n", id); | ||
349 | |||
350 | ri = find_regulator_info(id); | ||
351 | if (ri == NULL) { | ||
352 | dev_err(&pdev->dev, "invalid regulator ID specified\n"); | ||
353 | return -EINVAL; | ||
354 | } | ||
355 | tps_pdata = pdev->dev.platform_data; | ||
356 | ri->dev = &pdev->dev; | ||
357 | |||
358 | err = ricoh583_cache_regulator_register(pdev->dev.parent, ri); | ||
359 | if (err) { | ||
360 | dev_err(&pdev->dev, "Fail in caching register\n"); | ||
361 | return err; | ||
362 | } | ||
363 | |||
364 | err = ricoh583_regulator_preinit(pdev->dev.parent, ri, tps_pdata); | ||
365 | if (err) { | ||
366 | dev_err(&pdev->dev, "Fail in pre-initialisation\n"); | ||
367 | return err; | ||
368 | } | ||
369 | rdev = regulator_register(&ri->desc, &pdev->dev, | ||
370 | &tps_pdata->regulator, ri); | ||
371 | if (IS_ERR_OR_NULL(rdev)) { | ||
372 | dev_err(&pdev->dev, "failed to register regulator %s\n", | ||
373 | ri->desc.name); | ||
374 | return PTR_ERR(rdev); | ||
375 | } | ||
376 | |||
377 | platform_set_drvdata(pdev, rdev); | ||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | static int __devexit ricoh583_regulator_remove(struct platform_device *pdev) | ||
382 | { | ||
383 | struct regulator_dev *rdev = platform_get_drvdata(pdev); | ||
384 | |||
385 | regulator_unregister(rdev); | ||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | static struct platform_driver ricoh583_regulator_driver = { | ||
390 | .driver = { | ||
391 | .name = "ricoh583-regulator", | ||
392 | .owner = THIS_MODULE, | ||
393 | }, | ||
394 | .probe = ricoh583_regulator_probe, | ||
395 | .remove = __devexit_p(ricoh583_regulator_remove), | ||
396 | }; | ||
397 | |||
398 | static int __init ricoh583_regulator_init(void) | ||
399 | { | ||
400 | return platform_driver_register(&ricoh583_regulator_driver); | ||
401 | } | ||
402 | subsys_initcall(ricoh583_regulator_init); | ||
403 | |||
404 | static void __exit ricoh583_regulator_exit(void) | ||
405 | { | ||
406 | platform_driver_unregister(&ricoh583_regulator_driver); | ||
407 | } | ||
408 | module_exit(ricoh583_regulator_exit); | ||
409 | |||
410 | MODULE_DESCRIPTION("RICOH583 regulator driver"); | ||
411 | MODULE_ALIAS("platform:ricoh583-regulator"); | ||
412 | MODULE_LICENSE("GPL"); | ||