xref: /openbmc/linux/drivers/regulator/88pm8607.c (revision 64405360)
1 /*
2  * Regulators driver for Marvell 88PM8607
3  *
4  * Copyright (C) 2009 Marvell International Ltd.
5  * 	Haojian Zhuang <haojian.zhuang@marvell.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11 #include <linux/kernel.h>
12 #include <linux/init.h>
13 #include <linux/err.h>
14 #include <linux/i2c.h>
15 #include <linux/platform_device.h>
16 #include <linux/regulator/driver.h>
17 #include <linux/regulator/machine.h>
18 #include <linux/mfd/88pm860x.h>
19 #include <linux/module.h>
20 
21 struct pm8607_regulator_info {
22 	struct regulator_desc	desc;
23 	struct pm860x_chip	*chip;
24 	struct regulator_dev	*regulator;
25 	struct i2c_client	*i2c;
26 
27 	unsigned int	*vol_table;
28 	unsigned int	*vol_suspend;
29 
30 	int	vol_reg;
31 	int	vol_shift;
32 	int	vol_nbits;
33 	int	update_reg;
34 	int	update_bit;
35 	int	enable_reg;
36 	int	enable_bit;
37 	int	slope_double;
38 };
39 
40 static const unsigned int BUCK1_table[] = {
41 	 725000,  750000,  775000,  800000,  825000,  850000,  875000,  900000,
42 	 925000,  950000,  975000, 1000000, 1025000, 1050000, 1075000, 1100000,
43 	1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000,
44 	1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000,
45 	      0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
46 	 200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
47 	 400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
48 	 600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
49 };
50 
51 static const unsigned int BUCK1_suspend_table[] = {
52 	      0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
53 	 200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
54 	 400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
55 	 600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
56 	 800000,  825000,  850000,  875000,  900000,  925000,  950000,  975000,
57 	1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
58 	1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000,
59 	1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000,
60 };
61 
62 static const unsigned int BUCK2_table[] = {
63 	      0,   50000,  100000,  150000,  200000,  250000,  300000,  350000,
64 	 400000,  450000,  500000,  550000,  600000,  650000,  700000,  750000,
65 	 800000,  850000,  900000,  950000, 1000000, 1050000, 1100000, 1150000,
66 	1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1550000,
67 	1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 1950000,
68 	2000000, 2050000, 2100000, 2150000, 2200000, 2250000, 2300000, 2350000,
69 	2400000, 2450000, 2500000, 2550000, 2600000, 2650000, 2700000, 2750000,
70 	2800000, 2850000, 2900000, 2950000, 3000000, 3000000, 3000000, 3000000,
71 };
72 
73 static const unsigned int BUCK2_suspend_table[] = {
74 	      0,   50000,  100000,  150000,  200000,  250000,  300000,  350000,
75 	 400000,  450000,  500000,  550000,  600000,  650000,  700000,  750000,
76 	 800000,  850000,  900000,  950000, 1000000, 1050000, 1100000, 1150000,
77 	1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1550000,
78 	1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 1950000,
79 	2000000, 2050000, 2100000, 2150000, 2200000, 2250000, 2300000, 2350000,
80 	2400000, 2450000, 2500000, 2550000, 2600000, 2650000, 2700000, 2750000,
81 	2800000, 2850000, 2900000, 2950000, 3000000, 3000000, 3000000, 3000000,
82 };
83 
84 static const unsigned int BUCK3_table[] = {
85               0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
86 	 200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
87 	 400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
88 	 600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
89 	 800000,  825000,  850000,  875000,  900000,  925000,  950000,  975000,
90 	1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
91 	1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000,
92 	1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000,
93 };
94 
95 static const unsigned int BUCK3_suspend_table[] = {
96               0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
97 	 200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
98 	 400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
99 	 600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
100 	 800000,  825000,  850000,  875000,  900000,  925000,  950000,  975000,
101 	1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
102 	1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000,
103 	1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000,
104 };
105 
106 static const unsigned int LDO1_table[] = {
107 	1800000, 1200000, 2800000, 0,
108 };
109 
110 static const unsigned int LDO1_suspend_table[] = {
111 	1800000, 1200000, 0, 0,
112 };
113 
114 static const unsigned int LDO2_table[] = {
115 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
116 };
117 
118 static const unsigned int LDO2_suspend_table[] = {
119 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
120 };
121 
122 static const unsigned int LDO3_table[] = {
123 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
124 };
125 
126 static const unsigned int LDO3_suspend_table[] = {
127 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
128 };
129 
130 static const unsigned int LDO4_table[] = {
131 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2900000, 3300000,
132 };
133 
134 static const unsigned int LDO4_suspend_table[] = {
135 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2900000, 2900000,
136 };
137 
138 static const unsigned int LDO5_table[] = {
139 	2900000, 3000000, 3100000, 3300000,
140 };
141 
142 static const unsigned int LDO5_suspend_table[] = {
143 	2900000, 0, 0, 0,
144 };
145 
146 static const unsigned int LDO6_table[] = {
147 	1800000, 1850000, 2600000, 2650000, 2700000, 2750000, 2800000, 3300000,
148 };
149 
150 static const unsigned int LDO6_suspend_table[] = {
151 	1800000, 1850000, 2600000, 2650000, 2700000, 2750000, 2800000, 2900000,
152 };
153 
154 static const unsigned int LDO7_table[] = {
155 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
156 };
157 
158 static const unsigned int LDO7_suspend_table[] = {
159 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
160 };
161 
162 static const unsigned int LDO8_table[] = {
163 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
164 };
165 
166 static const unsigned int LDO8_suspend_table[] = {
167 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
168 };
169 
170 static const unsigned int LDO9_table[] = {
171 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
172 };
173 
174 static const unsigned int LDO9_suspend_table[] = {
175 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
176 };
177 
178 static const unsigned int LDO10_table[] = {
179 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
180 	1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
181 };
182 
183 static const unsigned int LDO10_suspend_table[] = {
184 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
185 	1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
186 };
187 
188 static const unsigned int LDO12_table[] = {
189 	1800000, 1900000, 2700000, 2800000, 2900000, 3000000, 3100000, 3300000,
190 	1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
191 };
192 
193 static const unsigned int LDO12_suspend_table[] = {
194 	1800000, 1900000, 2700000, 2800000, 2900000, 2900000, 2900000, 2900000,
195 	1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
196 };
197 
198 static const unsigned int LDO13_table[] = {
199 	1200000, 1300000, 1800000, 2000000, 2500000, 2800000, 3000000, 0,
200 };
201 
202 static const unsigned int LDO13_suspend_table[] = {
203 	0,
204 };
205 
206 static const unsigned int LDO14_table[] = {
207 	1800000, 1850000, 2700000, 2750000, 2800000, 2850000, 2900000, 3300000,
208 };
209 
210 static const unsigned int LDO14_suspend_table[] = {
211 	1800000, 1850000, 2700000, 2750000, 2800000, 2850000, 2900000, 2900000,
212 };
213 
214 static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index)
215 {
216 	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
217 	int ret = -EINVAL;
218 
219 	if (info->vol_table && (index < (1 << info->vol_nbits))) {
220 		ret = info->vol_table[index];
221 		if (info->slope_double)
222 			ret <<= 1;
223 	}
224 	return ret;
225 }
226 
227 static int choose_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
228 {
229 	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
230 	int i, ret = -ENOENT;
231 
232 	if (info->slope_double) {
233 		min_uV = min_uV >> 1;
234 		max_uV = max_uV >> 1;
235 	}
236 	if (info->vol_table) {
237 		for (i = 0; i < (1 << info->vol_nbits); i++) {
238 			if (!info->vol_table[i])
239 				break;
240 			if ((min_uV <= info->vol_table[i])
241 				&& (max_uV >= info->vol_table[i])) {
242 				ret = i;
243 				break;
244 			}
245 		}
246 	}
247 	if (ret < 0)
248 		pr_err("invalid voltage range (%d %d) uV\n", min_uV, max_uV);
249 	return ret;
250 }
251 
252 static int pm8607_set_voltage(struct regulator_dev *rdev,
253 			      int min_uV, int max_uV, unsigned *selector)
254 {
255 	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
256 	uint8_t val, mask;
257 	int ret;
258 
259 	if (min_uV > max_uV) {
260 		pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
261 		return -EINVAL;
262 	}
263 
264 	ret = choose_voltage(rdev, min_uV, max_uV);
265 	if (ret < 0)
266 		return -EINVAL;
267 	*selector = ret;
268 	val = (uint8_t)(ret << info->vol_shift);
269 	mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
270 
271 	ret = pm860x_set_bits(info->i2c, info->vol_reg, mask, val);
272 	if (ret)
273 		return ret;
274 	switch (info->desc.id) {
275 	case PM8607_ID_BUCK1:
276 	case PM8607_ID_BUCK3:
277 		ret = pm860x_set_bits(info->i2c, info->update_reg,
278 				      1 << info->update_bit,
279 				      1 << info->update_bit);
280 		break;
281 	}
282 	return ret;
283 }
284 
285 static int pm8607_get_voltage(struct regulator_dev *rdev)
286 {
287 	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
288 	uint8_t val, mask;
289 	int ret;
290 
291 	ret = pm860x_reg_read(info->i2c, info->vol_reg);
292 	if (ret < 0)
293 		return ret;
294 
295 	mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
296 	val = ((unsigned char)ret & mask) >> info->vol_shift;
297 
298 	return pm8607_list_voltage(rdev, val);
299 }
300 
301 static int pm8607_enable(struct regulator_dev *rdev)
302 {
303 	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
304 
305 	return pm860x_set_bits(info->i2c, info->enable_reg,
306 			       1 << info->enable_bit,
307 			       1 << info->enable_bit);
308 }
309 
310 static int pm8607_disable(struct regulator_dev *rdev)
311 {
312 	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
313 
314 	return pm860x_set_bits(info->i2c, info->enable_reg,
315 			       1 << info->enable_bit, 0);
316 }
317 
318 static int pm8607_is_enabled(struct regulator_dev *rdev)
319 {
320 	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
321 	int ret;
322 
323 	ret = pm860x_reg_read(info->i2c, info->enable_reg);
324 	if (ret < 0)
325 		return ret;
326 
327 	return !!((unsigned char)ret & (1 << info->enable_bit));
328 }
329 
330 static struct regulator_ops pm8607_regulator_ops = {
331 	.set_voltage	= pm8607_set_voltage,
332 	.get_voltage	= pm8607_get_voltage,
333 	.enable		= pm8607_enable,
334 	.disable	= pm8607_disable,
335 	.is_enabled	= pm8607_is_enabled,
336 };
337 
338 #define PM8607_DVC(vreg, nbits, ureg, ubit, ereg, ebit)			\
339 {									\
340 	.desc	= {							\
341 		.name	= #vreg,					\
342 		.ops	= &pm8607_regulator_ops,			\
343 		.type	= REGULATOR_VOLTAGE,				\
344 		.id	= PM8607_ID_##vreg,				\
345 		.owner	= THIS_MODULE,					\
346 	},								\
347 	.vol_reg	= PM8607_##vreg,				\
348 	.vol_shift	= (0),						\
349 	.vol_nbits	= (nbits),					\
350 	.update_reg	= PM8607_##ureg,				\
351 	.update_bit	= (ubit),					\
352 	.enable_reg	= PM8607_##ereg,				\
353 	.enable_bit	= (ebit),					\
354 	.slope_double	= (0),						\
355 	.vol_table	= (unsigned int *)&vreg##_table,		\
356 	.vol_suspend	= (unsigned int *)&vreg##_suspend_table,	\
357 }
358 
359 #define PM8607_LDO(_id, vreg, shift, nbits, ereg, ebit)			\
360 {									\
361 	.desc	= {							\
362 		.name	= "LDO" #_id,					\
363 		.ops	= &pm8607_regulator_ops,			\
364 		.type	= REGULATOR_VOLTAGE,				\
365 		.id	= PM8607_ID_LDO##_id,				\
366 		.owner	= THIS_MODULE,					\
367 	},								\
368 	.vol_reg	= PM8607_##vreg,				\
369 	.vol_shift	= (shift),					\
370 	.vol_nbits	= (nbits),					\
371 	.enable_reg	= PM8607_##ereg,				\
372 	.enable_bit	= (ebit),					\
373 	.slope_double	= (0),						\
374 	.vol_table	= (unsigned int *)&LDO##_id##_table,		\
375 	.vol_suspend	= (unsigned int *)&LDO##_id##_suspend_table,	\
376 }
377 
378 static struct pm8607_regulator_info pm8607_regulator_info[] = {
379 	PM8607_DVC(BUCK1, 6, GO, 0, SUPPLIES_EN11, 0),
380 	PM8607_DVC(BUCK2, 6, GO, 1, SUPPLIES_EN11, 1),
381 	PM8607_DVC(BUCK3, 6, GO, 2, SUPPLIES_EN11, 2),
382 
383 	PM8607_LDO( 1,         LDO1, 0, 2, SUPPLIES_EN11, 3),
384 	PM8607_LDO( 2,         LDO2, 0, 3, SUPPLIES_EN11, 4),
385 	PM8607_LDO( 3,         LDO3, 0, 3, SUPPLIES_EN11, 5),
386 	PM8607_LDO( 4,         LDO4, 0, 3, SUPPLIES_EN11, 6),
387 	PM8607_LDO( 5,         LDO5, 0, 2, SUPPLIES_EN11, 7),
388 	PM8607_LDO( 6,         LDO6, 0, 3, SUPPLIES_EN12, 0),
389 	PM8607_LDO( 7,         LDO7, 0, 3, SUPPLIES_EN12, 1),
390 	PM8607_LDO( 8,         LDO8, 0, 3, SUPPLIES_EN12, 2),
391 	PM8607_LDO( 9,         LDO9, 0, 3, SUPPLIES_EN12, 3),
392 	PM8607_LDO(10,        LDO10, 0, 4, SUPPLIES_EN12, 4),
393 	PM8607_LDO(12,        LDO12, 0, 4, SUPPLIES_EN12, 5),
394 	PM8607_LDO(13, VIBRATOR_SET, 1, 3,  VIBRATOR_SET, 0),
395 	PM8607_LDO(14,        LDO14, 0, 3, SUPPLIES_EN12, 6),
396 };
397 
398 static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
399 {
400 	struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
401 	struct pm8607_regulator_info *info = NULL;
402 	struct regulator_init_data *pdata = pdev->dev.platform_data;
403 	struct resource *res;
404 	int i;
405 
406 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
407 	if (res == NULL) {
408 		dev_err(&pdev->dev, "No I/O resource!\n");
409 		return -EINVAL;
410 	}
411 	for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) {
412 		info = &pm8607_regulator_info[i];
413 		if (info->desc.id == res->start)
414 			break;
415 	}
416 	if (i == ARRAY_SIZE(pm8607_regulator_info)) {
417 		dev_err(&pdev->dev, "Failed to find regulator %llu\n",
418 			(unsigned long long)res->start);
419 		return -EINVAL;
420 	}
421 	info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
422 	info->chip = chip;
423 
424 	/* check DVC ramp slope double */
425 	if ((i == PM8607_ID_BUCK3) && info->chip->buck3_double)
426 		info->slope_double = 1;
427 
428 	/* replace driver_data with info */
429 	info->regulator = regulator_register(&info->desc, &pdev->dev,
430 					     pdata, info, NULL);
431 	if (IS_ERR(info->regulator)) {
432 		dev_err(&pdev->dev, "failed to register regulator %s\n",
433 			info->desc.name);
434 		return PTR_ERR(info->regulator);
435 	}
436 
437 	platform_set_drvdata(pdev, info);
438 	return 0;
439 }
440 
441 static int __devexit pm8607_regulator_remove(struct platform_device *pdev)
442 {
443 	struct pm8607_regulator_info *info = platform_get_drvdata(pdev);
444 
445 	platform_set_drvdata(pdev, NULL);
446 	regulator_unregister(info->regulator);
447 	return 0;
448 }
449 
450 static struct platform_driver pm8607_regulator_driver = {
451 	.driver		= {
452 		.name	= "88pm860x-regulator",
453 		.owner	= THIS_MODULE,
454 	},
455 	.probe		= pm8607_regulator_probe,
456 	.remove		= __devexit_p(pm8607_regulator_remove),
457 };
458 
459 static int __init pm8607_regulator_init(void)
460 {
461 	return platform_driver_register(&pm8607_regulator_driver);
462 }
463 subsys_initcall(pm8607_regulator_init);
464 
465 static void __exit pm8607_regulator_exit(void)
466 {
467 	platform_driver_unregister(&pm8607_regulator_driver);
468 }
469 module_exit(pm8607_regulator_exit);
470 
471 MODULE_LICENSE("GPL");
472 MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
473 MODULE_DESCRIPTION("Regulator Driver for Marvell 88PM8607 PMIC");
474 MODULE_ALIAS("platform:88pm8607-regulator");
475