xref: /linux/drivers/regulator/wm8400-regulator.c (revision 4e73e0eb633f8a1b5cbf20e7f42c6dbfec1d1ca7)
1 /*
2  * Regulator support for WM8400
3  *
4  * Copyright 2008 Wolfson Microelectronics PLC.
5  *
6  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of the
11  * License, or (at your option) any later version.
12  *
13  */
14 
15 #include <linux/bug.h>
16 #include <linux/err.h>
17 #include <linux/kernel.h>
18 #include <linux/regulator/driver.h>
19 #include <linux/mfd/wm8400-private.h>
20 
21 static int wm8400_ldo_is_enabled(struct regulator_dev *dev)
22 {
23 	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
24 	u16 val;
25 
26 	val = wm8400_reg_read(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev));
27 	return (val & WM8400_LDO1_ENA) != 0;
28 }
29 
30 static int wm8400_ldo_enable(struct regulator_dev *dev)
31 {
32 	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
33 
34 	return wm8400_set_bits(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev),
35 			       WM8400_LDO1_ENA, WM8400_LDO1_ENA);
36 }
37 
38 static int wm8400_ldo_disable(struct regulator_dev *dev)
39 {
40 	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
41 
42 	return wm8400_set_bits(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev),
43 			       WM8400_LDO1_ENA, 0);
44 }
45 
46 static int wm8400_ldo_list_voltage(struct regulator_dev *dev,
47 				   unsigned selector)
48 {
49 	if (selector > WM8400_LDO1_VSEL_MASK)
50 		return -EINVAL;
51 
52 	if (selector < 15)
53 		return 900000 + (selector * 50000);
54 	else
55 		return 1600000 + ((selector - 14) * 100000);
56 }
57 
58 static int wm8400_ldo_get_voltage(struct regulator_dev *dev)
59 {
60 	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
61 	u16 val;
62 
63 	val = wm8400_reg_read(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev));
64 	val &= WM8400_LDO1_VSEL_MASK;
65 
66 	return wm8400_ldo_list_voltage(dev, val);
67 }
68 
69 static int wm8400_ldo_set_voltage(struct regulator_dev *dev,
70 				  int min_uV, int max_uV)
71 {
72 	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
73 	u16 val;
74 
75 	if (min_uV < 900000 || min_uV > 3300000)
76 		return -EINVAL;
77 
78 	if (min_uV < 1700000) {
79 		/* Steps of 50mV from 900mV;  */
80 		val = (min_uV - 850001) / 50000;
81 
82 		if ((val * 50000) + 900000 > max_uV)
83 			return -EINVAL;
84 		BUG_ON((val * 50000) + 900000 < min_uV);
85 	} else {
86 		/* Steps of 100mV from 1700mV */
87 		val = ((min_uV - 1600001) / 100000);
88 
89 		if ((val * 100000) + 1700000 > max_uV)
90 			return -EINVAL;
91 		BUG_ON((val * 100000) + 1700000 < min_uV);
92 
93 		val += 0xf;
94 	}
95 
96 	return wm8400_set_bits(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev),
97 			       WM8400_LDO1_VSEL_MASK, val);
98 }
99 
100 static struct regulator_ops wm8400_ldo_ops = {
101 	.is_enabled = wm8400_ldo_is_enabled,
102 	.enable = wm8400_ldo_enable,
103 	.disable = wm8400_ldo_disable,
104 	.list_voltage = wm8400_ldo_list_voltage,
105 	.get_voltage = wm8400_ldo_get_voltage,
106 	.set_voltage = wm8400_ldo_set_voltage,
107 };
108 
109 static int wm8400_dcdc_is_enabled(struct regulator_dev *dev)
110 {
111 	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
112 	int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
113 	u16 val;
114 
115 	val = wm8400_reg_read(wm8400, WM8400_DCDC1_CONTROL_1 + offset);
116 	return (val & WM8400_DC1_ENA) != 0;
117 }
118 
119 static int wm8400_dcdc_enable(struct regulator_dev *dev)
120 {
121 	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
122 	int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
123 
124 	return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
125 			       WM8400_DC1_ENA, WM8400_DC1_ENA);
126 }
127 
128 static int wm8400_dcdc_disable(struct regulator_dev *dev)
129 {
130 	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
131 	int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
132 
133 	return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
134 			       WM8400_DC1_ENA, 0);
135 }
136 
137 static int wm8400_dcdc_list_voltage(struct regulator_dev *dev,
138 				    unsigned selector)
139 {
140 	if (selector > WM8400_DC1_VSEL_MASK)
141 		return -EINVAL;
142 
143 	return 850000 + (selector * 25000);
144 }
145 
146 static int wm8400_dcdc_get_voltage(struct regulator_dev *dev)
147 {
148 	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
149 	u16 val;
150 	int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
151 
152 	val = wm8400_reg_read(wm8400, WM8400_DCDC1_CONTROL_1 + offset);
153 	val &= WM8400_DC1_VSEL_MASK;
154 
155 	return 850000 + (25000 * val);
156 }
157 
158 static int wm8400_dcdc_set_voltage(struct regulator_dev *dev,
159 				  int min_uV, int max_uV)
160 {
161 	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
162 	u16 val;
163 	int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
164 
165 	if (min_uV < 850000)
166 		return -EINVAL;
167 
168 	val = (min_uV - 825001) / 25000;
169 
170 	if (850000 + (25000 * val) > max_uV)
171 		return -EINVAL;
172 	BUG_ON(850000 + (25000 * val) < min_uV);
173 
174 	return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
175 			       WM8400_DC1_VSEL_MASK, val);
176 }
177 
178 static unsigned int wm8400_dcdc_get_mode(struct regulator_dev *dev)
179 {
180 	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
181 	int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
182 	u16 data[2];
183 	int ret;
184 
185 	ret = wm8400_block_read(wm8400, WM8400_DCDC1_CONTROL_1 + offset, 2,
186 				data);
187 	if (ret != 0)
188 		return 0;
189 
190 	/* Datasheet: hibernate */
191 	if (data[0] & WM8400_DC1_SLEEP)
192 		return REGULATOR_MODE_STANDBY;
193 
194 	/* Datasheet: standby */
195 	if (!(data[0] & WM8400_DC1_ACTIVE))
196 		return REGULATOR_MODE_IDLE;
197 
198 	/* Datasheet: active with or without force PWM */
199 	if (data[1] & WM8400_DC1_FRC_PWM)
200 		return REGULATOR_MODE_FAST;
201 	else
202 		return REGULATOR_MODE_NORMAL;
203 }
204 
205 static int wm8400_dcdc_set_mode(struct regulator_dev *dev, unsigned int mode)
206 {
207 	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
208 	int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
209 	int ret;
210 
211 	switch (mode) {
212 	case REGULATOR_MODE_FAST:
213 		/* Datasheet: active with force PWM */
214 		ret = wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_2 + offset,
215 				      WM8400_DC1_FRC_PWM, WM8400_DC1_FRC_PWM);
216 		if (ret != 0)
217 			return ret;
218 
219 		return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
220 				       WM8400_DC1_ACTIVE | WM8400_DC1_SLEEP,
221 				       WM8400_DC1_ACTIVE);
222 
223 	case REGULATOR_MODE_NORMAL:
224 		/* Datasheet: active */
225 		ret = wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_2 + offset,
226 				      WM8400_DC1_FRC_PWM, 0);
227 		if (ret != 0)
228 			return ret;
229 
230 		return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
231 				       WM8400_DC1_ACTIVE | WM8400_DC1_SLEEP,
232 				       WM8400_DC1_ACTIVE);
233 
234 	case REGULATOR_MODE_IDLE:
235 		/* Datasheet: standby */
236 		ret = wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
237 				      WM8400_DC1_ACTIVE, 0);
238 		if (ret != 0)
239 			return ret;
240 		return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
241 				       WM8400_DC1_SLEEP, 0);
242 
243 	default:
244 		return -EINVAL;
245 	}
246 }
247 
248 static unsigned int wm8400_dcdc_get_optimum_mode(struct regulator_dev *dev,
249 						 int input_uV, int output_uV,
250 						 int load_uA)
251 {
252 	return REGULATOR_MODE_NORMAL;
253 }
254 
255 static struct regulator_ops wm8400_dcdc_ops = {
256 	.is_enabled = wm8400_dcdc_is_enabled,
257 	.enable = wm8400_dcdc_enable,
258 	.disable = wm8400_dcdc_disable,
259 	.list_voltage = wm8400_dcdc_list_voltage,
260 	.get_voltage = wm8400_dcdc_get_voltage,
261 	.set_voltage = wm8400_dcdc_set_voltage,
262 	.get_mode = wm8400_dcdc_get_mode,
263 	.set_mode = wm8400_dcdc_set_mode,
264 	.get_optimum_mode = wm8400_dcdc_get_optimum_mode,
265 };
266 
267 static struct regulator_desc regulators[] = {
268 	{
269 		.name = "LDO1",
270 		.id = WM8400_LDO1,
271 		.ops = &wm8400_ldo_ops,
272 		.n_voltages = WM8400_LDO1_VSEL_MASK + 1,
273 		.type = REGULATOR_VOLTAGE,
274 		.owner = THIS_MODULE,
275 	},
276 	{
277 		.name = "LDO2",
278 		.id = WM8400_LDO2,
279 		.ops = &wm8400_ldo_ops,
280 		.n_voltages = WM8400_LDO2_VSEL_MASK + 1,
281 		.type = REGULATOR_VOLTAGE,
282 		.owner = THIS_MODULE,
283 	},
284 	{
285 		.name = "LDO3",
286 		.id = WM8400_LDO3,
287 		.ops = &wm8400_ldo_ops,
288 		.n_voltages = WM8400_LDO3_VSEL_MASK + 1,
289 		.type = REGULATOR_VOLTAGE,
290 		.owner = THIS_MODULE,
291 	},
292 	{
293 		.name = "LDO4",
294 		.id = WM8400_LDO4,
295 		.ops = &wm8400_ldo_ops,
296 		.n_voltages = WM8400_LDO4_VSEL_MASK + 1,
297 		.type = REGULATOR_VOLTAGE,
298 		.owner = THIS_MODULE,
299 	},
300 	{
301 		.name = "DCDC1",
302 		.id = WM8400_DCDC1,
303 		.ops = &wm8400_dcdc_ops,
304 		.n_voltages = WM8400_DC1_VSEL_MASK + 1,
305 		.type = REGULATOR_VOLTAGE,
306 		.owner = THIS_MODULE,
307 	},
308 	{
309 		.name = "DCDC2",
310 		.id = WM8400_DCDC2,
311 		.ops = &wm8400_dcdc_ops,
312 		.n_voltages = WM8400_DC2_VSEL_MASK + 1,
313 		.type = REGULATOR_VOLTAGE,
314 		.owner = THIS_MODULE,
315 	},
316 };
317 
318 static int __devinit wm8400_regulator_probe(struct platform_device *pdev)
319 {
320 	struct regulator_dev *rdev;
321 
322 	rdev = regulator_register(&regulators[pdev->id], &pdev->dev,
323 		pdev->dev.platform_data, pdev->dev.driver_data);
324 
325 	if (IS_ERR(rdev))
326 		return PTR_ERR(rdev);
327 
328 	return 0;
329 }
330 
331 static int __devexit wm8400_regulator_remove(struct platform_device *pdev)
332 {
333 	struct regulator_dev *rdev = platform_get_drvdata(pdev);
334 
335 	regulator_unregister(rdev);
336 
337 	return 0;
338 }
339 
340 static struct platform_driver wm8400_regulator_driver = {
341 	.driver = {
342 		.name = "wm8400-regulator",
343 	},
344 	.probe = wm8400_regulator_probe,
345 	.remove = __devexit_p(wm8400_regulator_remove),
346 };
347 
348 /**
349  * wm8400_register_regulator - enable software control of a WM8400 regulator
350  *
351  * This function enables software control of a WM8400 regulator via
352  * the regulator API.  It is intended to be called from the
353  * platform_init() callback of the WM8400 MFD driver.
354  *
355  * @param dev      The WM8400 device to operate on.
356  * @param reg      The regulator to control.
357  * @param initdata Regulator initdata for the regulator.
358  */
359 int wm8400_register_regulator(struct device *dev, int reg,
360 			      struct regulator_init_data *initdata)
361 {
362 	struct wm8400 *wm8400 = dev->driver_data;
363 
364 	if (wm8400->regulators[reg].name)
365 		return -EBUSY;
366 
367 	initdata->driver_data = wm8400;
368 
369 	wm8400->regulators[reg].name = "wm8400-regulator";
370 	wm8400->regulators[reg].id = reg;
371 	wm8400->regulators[reg].dev.parent = dev;
372 	wm8400->regulators[reg].dev.driver_data = wm8400;
373 	wm8400->regulators[reg].dev.platform_data = initdata;
374 
375 	return platform_device_register(&wm8400->regulators[reg]);
376 }
377 EXPORT_SYMBOL_GPL(wm8400_register_regulator);
378 
379 static int __init wm8400_regulator_init(void)
380 {
381 	return platform_driver_register(&wm8400_regulator_driver);
382 }
383 module_init(wm8400_regulator_init);
384 
385 static void __exit wm8400_regulator_exit(void)
386 {
387 	platform_driver_unregister(&wm8400_regulator_driver);
388 }
389 module_exit(wm8400_regulator_exit);
390 
391 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
392 MODULE_DESCRIPTION("WM8400 regulator driver");
393 MODULE_LICENSE("GPL");
394 MODULE_ALIAS("platform:wm8400-regulator");
395