xref: /linux/drivers/regulator/88pm8607.c (revision a70abacb06b884131ec181551a71ef325490f374)
1be0e2d3eSHaojian Zhuang /*
2be0e2d3eSHaojian Zhuang  * Regulators driver for Marvell 88PM8607
3be0e2d3eSHaojian Zhuang  *
4be0e2d3eSHaojian Zhuang  * Copyright (C) 2009 Marvell International Ltd.
5be0e2d3eSHaojian Zhuang  * 	Haojian Zhuang <haojian.zhuang@marvell.com>
6be0e2d3eSHaojian Zhuang  *
7be0e2d3eSHaojian Zhuang  * This program is free software; you can redistribute it and/or modify
8be0e2d3eSHaojian Zhuang  * it under the terms of the GNU General Public License version 2 as
9be0e2d3eSHaojian Zhuang  * published by the Free Software Foundation.
10be0e2d3eSHaojian Zhuang  */
11be0e2d3eSHaojian Zhuang #include <linux/kernel.h>
12be0e2d3eSHaojian Zhuang #include <linux/init.h>
13be0e2d3eSHaojian Zhuang #include <linux/err.h>
1453dbab7aSHaojian Zhuang #include <linux/i2c.h>
15be0e2d3eSHaojian Zhuang #include <linux/platform_device.h>
16be0e2d3eSHaojian Zhuang #include <linux/regulator/driver.h>
17be0e2d3eSHaojian Zhuang #include <linux/regulator/machine.h>
1853dbab7aSHaojian Zhuang #include <linux/mfd/88pm860x.h>
1965602c32SPaul Gortmaker #include <linux/module.h>
20be0e2d3eSHaojian Zhuang 
21be0e2d3eSHaojian Zhuang struct pm8607_regulator_info {
22be0e2d3eSHaojian Zhuang 	struct regulator_desc	desc;
2353dbab7aSHaojian Zhuang 	struct pm860x_chip	*chip;
24be0e2d3eSHaojian Zhuang 	struct regulator_dev	*regulator;
2553dbab7aSHaojian Zhuang 	struct i2c_client	*i2c;
26be0e2d3eSHaojian Zhuang 
279f79e9dbSHaojian Zhuang 	unsigned int	*vol_table;
289f79e9dbSHaojian Zhuang 	unsigned int	*vol_suspend;
299f79e9dbSHaojian Zhuang 
30be0e2d3eSHaojian Zhuang 	int	update_reg;
31be0e2d3eSHaojian Zhuang 	int	update_bit;
32be0e2d3eSHaojian Zhuang 	int	slope_double;
33be0e2d3eSHaojian Zhuang };
34be0e2d3eSHaojian Zhuang 
359f79e9dbSHaojian Zhuang static const unsigned int BUCK1_table[] = {
369f79e9dbSHaojian Zhuang 	 725000,  750000,  775000,  800000,  825000,  850000,  875000,  900000,
379f79e9dbSHaojian Zhuang 	 925000,  950000,  975000, 1000000, 1025000, 1050000, 1075000, 1100000,
389f79e9dbSHaojian Zhuang 	1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000,
399f79e9dbSHaojian Zhuang 	1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000,
409f79e9dbSHaojian Zhuang 	      0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
419f79e9dbSHaojian Zhuang 	 200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
429f79e9dbSHaojian Zhuang 	 400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
439f79e9dbSHaojian Zhuang 	 600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
449f79e9dbSHaojian Zhuang };
45be0e2d3eSHaojian Zhuang 
469f79e9dbSHaojian Zhuang static const unsigned int BUCK1_suspend_table[] = {
479f79e9dbSHaojian Zhuang 	      0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
489f79e9dbSHaojian Zhuang 	 200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
499f79e9dbSHaojian Zhuang 	 400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
509f79e9dbSHaojian Zhuang 	 600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
519f79e9dbSHaojian Zhuang 	 800000,  825000,  850000,  875000,  900000,  925000,  950000,  975000,
529f79e9dbSHaojian Zhuang 	1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
539f79e9dbSHaojian Zhuang 	1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000,
549f79e9dbSHaojian Zhuang 	1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000,
559f79e9dbSHaojian Zhuang };
569f79e9dbSHaojian Zhuang 
579f79e9dbSHaojian Zhuang static const unsigned int BUCK2_table[] = {
589f79e9dbSHaojian Zhuang 	      0,   50000,  100000,  150000,  200000,  250000,  300000,  350000,
599f79e9dbSHaojian Zhuang 	 400000,  450000,  500000,  550000,  600000,  650000,  700000,  750000,
609f79e9dbSHaojian Zhuang 	 800000,  850000,  900000,  950000, 1000000, 1050000, 1100000, 1150000,
619f79e9dbSHaojian Zhuang 	1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1550000,
629f79e9dbSHaojian Zhuang 	1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 1950000,
639f79e9dbSHaojian Zhuang 	2000000, 2050000, 2100000, 2150000, 2200000, 2250000, 2300000, 2350000,
649f79e9dbSHaojian Zhuang 	2400000, 2450000, 2500000, 2550000, 2600000, 2650000, 2700000, 2750000,
659f79e9dbSHaojian Zhuang 	2800000, 2850000, 2900000, 2950000, 3000000, 3000000, 3000000, 3000000,
669f79e9dbSHaojian Zhuang };
679f79e9dbSHaojian Zhuang 
689f79e9dbSHaojian Zhuang static const unsigned int BUCK2_suspend_table[] = {
699f79e9dbSHaojian Zhuang 	      0,   50000,  100000,  150000,  200000,  250000,  300000,  350000,
709f79e9dbSHaojian Zhuang 	 400000,  450000,  500000,  550000,  600000,  650000,  700000,  750000,
719f79e9dbSHaojian Zhuang 	 800000,  850000,  900000,  950000, 1000000, 1050000, 1100000, 1150000,
729f79e9dbSHaojian Zhuang 	1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1550000,
739f79e9dbSHaojian Zhuang 	1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 1950000,
749f79e9dbSHaojian Zhuang 	2000000, 2050000, 2100000, 2150000, 2200000, 2250000, 2300000, 2350000,
759f79e9dbSHaojian Zhuang 	2400000, 2450000, 2500000, 2550000, 2600000, 2650000, 2700000, 2750000,
769f79e9dbSHaojian Zhuang 	2800000, 2850000, 2900000, 2950000, 3000000, 3000000, 3000000, 3000000,
779f79e9dbSHaojian Zhuang };
789f79e9dbSHaojian Zhuang 
799f79e9dbSHaojian Zhuang static const unsigned int BUCK3_table[] = {
809f79e9dbSHaojian Zhuang               0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
819f79e9dbSHaojian Zhuang 	 200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
829f79e9dbSHaojian Zhuang 	 400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
839f79e9dbSHaojian Zhuang 	 600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
849f79e9dbSHaojian Zhuang 	 800000,  825000,  850000,  875000,  900000,  925000,  950000,  975000,
859f79e9dbSHaojian Zhuang 	1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
869f79e9dbSHaojian Zhuang 	1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000,
879f79e9dbSHaojian Zhuang 	1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000,
889f79e9dbSHaojian Zhuang };
899f79e9dbSHaojian Zhuang 
909f79e9dbSHaojian Zhuang static const unsigned int BUCK3_suspend_table[] = {
919f79e9dbSHaojian Zhuang               0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
929f79e9dbSHaojian Zhuang 	 200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
939f79e9dbSHaojian Zhuang 	 400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
949f79e9dbSHaojian Zhuang 	 600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
959f79e9dbSHaojian Zhuang 	 800000,  825000,  850000,  875000,  900000,  925000,  950000,  975000,
969f79e9dbSHaojian Zhuang 	1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
979f79e9dbSHaojian Zhuang 	1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000,
989f79e9dbSHaojian Zhuang 	1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000,
999f79e9dbSHaojian Zhuang };
1009f79e9dbSHaojian Zhuang 
1019f79e9dbSHaojian Zhuang static const unsigned int LDO1_table[] = {
1029f79e9dbSHaojian Zhuang 	1800000, 1200000, 2800000, 0,
1039f79e9dbSHaojian Zhuang };
1049f79e9dbSHaojian Zhuang 
1059f79e9dbSHaojian Zhuang static const unsigned int LDO1_suspend_table[] = {
1069f79e9dbSHaojian Zhuang 	1800000, 1200000, 0, 0,
1079f79e9dbSHaojian Zhuang };
1089f79e9dbSHaojian Zhuang 
1099f79e9dbSHaojian Zhuang static const unsigned int LDO2_table[] = {
1109f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
1119f79e9dbSHaojian Zhuang };
1129f79e9dbSHaojian Zhuang 
1139f79e9dbSHaojian Zhuang static const unsigned int LDO2_suspend_table[] = {
1149f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
1159f79e9dbSHaojian Zhuang };
1169f79e9dbSHaojian Zhuang 
1179f79e9dbSHaojian Zhuang static const unsigned int LDO3_table[] = {
1189f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
1199f79e9dbSHaojian Zhuang };
1209f79e9dbSHaojian Zhuang 
1219f79e9dbSHaojian Zhuang static const unsigned int LDO3_suspend_table[] = {
1229f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
1239f79e9dbSHaojian Zhuang };
1249f79e9dbSHaojian Zhuang 
1259f79e9dbSHaojian Zhuang static const unsigned int LDO4_table[] = {
1269f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2900000, 3300000,
1279f79e9dbSHaojian Zhuang };
1289f79e9dbSHaojian Zhuang 
1299f79e9dbSHaojian Zhuang static const unsigned int LDO4_suspend_table[] = {
1309f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2900000, 2900000,
1319f79e9dbSHaojian Zhuang };
1329f79e9dbSHaojian Zhuang 
1339f79e9dbSHaojian Zhuang static const unsigned int LDO5_table[] = {
1349f79e9dbSHaojian Zhuang 	2900000, 3000000, 3100000, 3300000,
1359f79e9dbSHaojian Zhuang };
1369f79e9dbSHaojian Zhuang 
1379f79e9dbSHaojian Zhuang static const unsigned int LDO5_suspend_table[] = {
1389f79e9dbSHaojian Zhuang 	2900000, 0, 0, 0,
1399f79e9dbSHaojian Zhuang };
1409f79e9dbSHaojian Zhuang 
1419f79e9dbSHaojian Zhuang static const unsigned int LDO6_table[] = {
1429f79e9dbSHaojian Zhuang 	1800000, 1850000, 2600000, 2650000, 2700000, 2750000, 2800000, 3300000,
1439f79e9dbSHaojian Zhuang };
1449f79e9dbSHaojian Zhuang 
1459f79e9dbSHaojian Zhuang static const unsigned int LDO6_suspend_table[] = {
1469f79e9dbSHaojian Zhuang 	1800000, 1850000, 2600000, 2650000, 2700000, 2750000, 2800000, 2900000,
1479f79e9dbSHaojian Zhuang };
1489f79e9dbSHaojian Zhuang 
1499f79e9dbSHaojian Zhuang static const unsigned int LDO7_table[] = {
1509f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
1519f79e9dbSHaojian Zhuang };
1529f79e9dbSHaojian Zhuang 
1539f79e9dbSHaojian Zhuang static const unsigned int LDO7_suspend_table[] = {
1549f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
1559f79e9dbSHaojian Zhuang };
1569f79e9dbSHaojian Zhuang 
1579f79e9dbSHaojian Zhuang static const unsigned int LDO8_table[] = {
1589f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
1599f79e9dbSHaojian Zhuang };
1609f79e9dbSHaojian Zhuang 
1619f79e9dbSHaojian Zhuang static const unsigned int LDO8_suspend_table[] = {
1629f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
1639f79e9dbSHaojian Zhuang };
1649f79e9dbSHaojian Zhuang 
1659f79e9dbSHaojian Zhuang static const unsigned int LDO9_table[] = {
1669f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
1679f79e9dbSHaojian Zhuang };
1689f79e9dbSHaojian Zhuang 
1699f79e9dbSHaojian Zhuang static const unsigned int LDO9_suspend_table[] = {
1709f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
1719f79e9dbSHaojian Zhuang };
1729f79e9dbSHaojian Zhuang 
1739f79e9dbSHaojian Zhuang static const unsigned int LDO10_table[] = {
1749f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
1759f79e9dbSHaojian Zhuang 	1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
1769f79e9dbSHaojian Zhuang };
1779f79e9dbSHaojian Zhuang 
1789f79e9dbSHaojian Zhuang static const unsigned int LDO10_suspend_table[] = {
1799f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
1809f79e9dbSHaojian Zhuang 	1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
1819f79e9dbSHaojian Zhuang };
1829f79e9dbSHaojian Zhuang 
1839f79e9dbSHaojian Zhuang static const unsigned int LDO12_table[] = {
1849f79e9dbSHaojian Zhuang 	1800000, 1900000, 2700000, 2800000, 2900000, 3000000, 3100000, 3300000,
1859f79e9dbSHaojian Zhuang 	1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
1869f79e9dbSHaojian Zhuang };
1879f79e9dbSHaojian Zhuang 
1889f79e9dbSHaojian Zhuang static const unsigned int LDO12_suspend_table[] = {
1899f79e9dbSHaojian Zhuang 	1800000, 1900000, 2700000, 2800000, 2900000, 2900000, 2900000, 2900000,
1909f79e9dbSHaojian Zhuang 	1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
1919f79e9dbSHaojian Zhuang };
1929f79e9dbSHaojian Zhuang 
1939f79e9dbSHaojian Zhuang static const unsigned int LDO13_table[] = {
1943380643bSJett.Zhou 	1200000, 1300000, 1800000, 2000000, 2500000, 2800000, 3000000, 0,
1959f79e9dbSHaojian Zhuang };
1969f79e9dbSHaojian Zhuang 
1979f79e9dbSHaojian Zhuang static const unsigned int LDO13_suspend_table[] = {
1989f79e9dbSHaojian Zhuang 	0,
1999f79e9dbSHaojian Zhuang };
2009f79e9dbSHaojian Zhuang 
2019f79e9dbSHaojian Zhuang static const unsigned int LDO14_table[] = {
2029f79e9dbSHaojian Zhuang 	1800000, 1850000, 2700000, 2750000, 2800000, 2850000, 2900000, 3300000,
2039f79e9dbSHaojian Zhuang };
2049f79e9dbSHaojian Zhuang 
2059f79e9dbSHaojian Zhuang static const unsigned int LDO14_suspend_table[] = {
2069f79e9dbSHaojian Zhuang 	1800000, 1850000, 2700000, 2750000, 2800000, 2850000, 2900000, 2900000,
2079f79e9dbSHaojian Zhuang };
208be0e2d3eSHaojian Zhuang 
209be0e2d3eSHaojian Zhuang static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index)
210be0e2d3eSHaojian Zhuang {
211be0e2d3eSHaojian Zhuang 	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
212be0e2d3eSHaojian Zhuang 	int ret = -EINVAL;
213be0e2d3eSHaojian Zhuang 
21453b6949eSAxel Lin 	if (info->vol_table && (index < rdev->desc->n_voltages)) {
2159f79e9dbSHaojian Zhuang 		ret = info->vol_table[index];
216be0e2d3eSHaojian Zhuang 		if (info->slope_double)
217be0e2d3eSHaojian Zhuang 			ret <<= 1;
218be0e2d3eSHaojian Zhuang 	}
219be0e2d3eSHaojian Zhuang 	return ret;
220be0e2d3eSHaojian Zhuang }
221be0e2d3eSHaojian Zhuang 
2224ca1e1d9SAxel Lin static int pm8607_set_voltage_sel(struct regulator_dev *rdev, unsigned selector)
223be0e2d3eSHaojian Zhuang {
224be0e2d3eSHaojian Zhuang 	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
225c006b21fSAxel Lin 	uint8_t val;
226be0e2d3eSHaojian Zhuang 	int ret;
227be0e2d3eSHaojian Zhuang 
228c006b21fSAxel Lin 	val = (uint8_t)(selector << (ffs(rdev->desc->vsel_mask) - 1));
229be0e2d3eSHaojian Zhuang 
230c006b21fSAxel Lin 	ret = pm860x_set_bits(info->i2c, rdev->desc->vsel_reg,
231c006b21fSAxel Lin 			      rdev->desc->vsel_mask, val);
232be0e2d3eSHaojian Zhuang 	if (ret)
233be0e2d3eSHaojian Zhuang 		return ret;
234be0e2d3eSHaojian Zhuang 	switch (info->desc.id) {
235be0e2d3eSHaojian Zhuang 	case PM8607_ID_BUCK1:
236be0e2d3eSHaojian Zhuang 	case PM8607_ID_BUCK3:
23753dbab7aSHaojian Zhuang 		ret = pm860x_set_bits(info->i2c, info->update_reg,
238be0e2d3eSHaojian Zhuang 				      1 << info->update_bit,
239be0e2d3eSHaojian Zhuang 				      1 << info->update_bit);
240be0e2d3eSHaojian Zhuang 		break;
241be0e2d3eSHaojian Zhuang 	}
242be0e2d3eSHaojian Zhuang 	return ret;
243be0e2d3eSHaojian Zhuang }
244be0e2d3eSHaojian Zhuang 
245be0e2d3eSHaojian Zhuang static struct regulator_ops pm8607_regulator_ops = {
246d3d7bcccSAxel Lin 	.list_voltage	= pm8607_list_voltage,
2474ca1e1d9SAxel Lin 	.set_voltage_sel = pm8607_set_voltage_sel,
248c006b21fSAxel Lin 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
249ef26e0dbSAxel Lin 	.enable = regulator_enable_regmap,
250ef26e0dbSAxel Lin 	.disable = regulator_disable_regmap,
251ef26e0dbSAxel Lin 	.is_enabled = regulator_is_enabled_regmap,
252be0e2d3eSHaojian Zhuang };
253be0e2d3eSHaojian Zhuang 
25453b6949eSAxel Lin #define PM8607_DVC(vreg, ureg, ubit, ereg, ebit)			\
255be0e2d3eSHaojian Zhuang {									\
256be0e2d3eSHaojian Zhuang 	.desc	= {							\
2579f79e9dbSHaojian Zhuang 		.name	= #vreg,					\
258be0e2d3eSHaojian Zhuang 		.ops	= &pm8607_regulator_ops,			\
259be0e2d3eSHaojian Zhuang 		.type	= REGULATOR_VOLTAGE,				\
2609f79e9dbSHaojian Zhuang 		.id	= PM8607_ID_##vreg,				\
261be0e2d3eSHaojian Zhuang 		.owner	= THIS_MODULE,					\
26253b6949eSAxel Lin 		.n_voltages = ARRAY_SIZE(vreg##_table),			\
263c006b21fSAxel Lin 		.vsel_reg = PM8607_##vreg,				\
264c006b21fSAxel Lin 		.vsel_mask = ARRAY_SIZE(vreg##_table) - 1,		\
265ef26e0dbSAxel Lin 		.enable_reg = PM8607_##ereg,				\
266ef26e0dbSAxel Lin 		.enable_mask = 1 << (ebit),				\
267be0e2d3eSHaojian Zhuang 	},								\
268be0e2d3eSHaojian Zhuang 	.update_reg	= PM8607_##ureg,				\
269be0e2d3eSHaojian Zhuang 	.update_bit	= (ubit),					\
270be0e2d3eSHaojian Zhuang 	.slope_double	= (0),						\
2719f79e9dbSHaojian Zhuang 	.vol_table	= (unsigned int *)&vreg##_table,		\
2729f79e9dbSHaojian Zhuang 	.vol_suspend	= (unsigned int *)&vreg##_suspend_table,	\
273be0e2d3eSHaojian Zhuang }
274be0e2d3eSHaojian Zhuang 
27553b6949eSAxel Lin #define PM8607_LDO(_id, vreg, shift, ereg, ebit)			\
276be0e2d3eSHaojian Zhuang {									\
277be0e2d3eSHaojian Zhuang 	.desc	= {							\
278be0e2d3eSHaojian Zhuang 		.name	= "LDO" #_id,					\
279be0e2d3eSHaojian Zhuang 		.ops	= &pm8607_regulator_ops,			\
280be0e2d3eSHaojian Zhuang 		.type	= REGULATOR_VOLTAGE,				\
281be0e2d3eSHaojian Zhuang 		.id	= PM8607_ID_LDO##_id,				\
282be0e2d3eSHaojian Zhuang 		.owner	= THIS_MODULE,					\
28353b6949eSAxel Lin 		.n_voltages = ARRAY_SIZE(LDO##_id##_table),		\
284c006b21fSAxel Lin 		.vsel_reg = PM8607_##vreg,				\
285c006b21fSAxel Lin 		.vsel_mask = (ARRAY_SIZE(LDO##_id##_table) - 1) << (shift), \
286ef26e0dbSAxel Lin 		.enable_reg = PM8607_##ereg,				\
287ef26e0dbSAxel Lin 		.enable_mask = 1 << (ebit),				\
288be0e2d3eSHaojian Zhuang 	},								\
289be0e2d3eSHaojian Zhuang 	.slope_double	= (0),						\
2909f79e9dbSHaojian Zhuang 	.vol_table	= (unsigned int *)&LDO##_id##_table,		\
2919f79e9dbSHaojian Zhuang 	.vol_suspend	= (unsigned int *)&LDO##_id##_suspend_table,	\
292be0e2d3eSHaojian Zhuang }
293be0e2d3eSHaojian Zhuang 
294be0e2d3eSHaojian Zhuang static struct pm8607_regulator_info pm8607_regulator_info[] = {
29553b6949eSAxel Lin 	PM8607_DVC(BUCK1, GO, 0, SUPPLIES_EN11, 0),
29653b6949eSAxel Lin 	PM8607_DVC(BUCK2, GO, 1, SUPPLIES_EN11, 1),
29753b6949eSAxel Lin 	PM8607_DVC(BUCK3, GO, 2, SUPPLIES_EN11, 2),
298be0e2d3eSHaojian Zhuang 
29953b6949eSAxel Lin 	PM8607_LDO(1,         LDO1, 0, SUPPLIES_EN11, 3),
30053b6949eSAxel Lin 	PM8607_LDO(2,         LDO2, 0, SUPPLIES_EN11, 4),
30153b6949eSAxel Lin 	PM8607_LDO(3,         LDO3, 0, SUPPLIES_EN11, 5),
30253b6949eSAxel Lin 	PM8607_LDO(4,         LDO4, 0, SUPPLIES_EN11, 6),
30353b6949eSAxel Lin 	PM8607_LDO(5,         LDO5, 0, SUPPLIES_EN11, 7),
30453b6949eSAxel Lin 	PM8607_LDO(6,         LDO6, 0, SUPPLIES_EN12, 0),
30553b6949eSAxel Lin 	PM8607_LDO(7,         LDO7, 0, SUPPLIES_EN12, 1),
30653b6949eSAxel Lin 	PM8607_LDO(8,         LDO8, 0, SUPPLIES_EN12, 2),
30753b6949eSAxel Lin 	PM8607_LDO(9,         LDO9, 0, SUPPLIES_EN12, 3),
30853b6949eSAxel Lin 	PM8607_LDO(10,        LDO10, 0, SUPPLIES_EN12, 4),
30953b6949eSAxel Lin 	PM8607_LDO(12,        LDO12, 0, SUPPLIES_EN12, 5),
31053b6949eSAxel Lin 	PM8607_LDO(13, VIBRATOR_SET, 1, VIBRATOR_SET, 0),
31153b6949eSAxel Lin 	PM8607_LDO(14,        LDO14, 0, SUPPLIES_EN12, 6),
312be0e2d3eSHaojian Zhuang };
313be0e2d3eSHaojian Zhuang 
314be0e2d3eSHaojian Zhuang static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
315be0e2d3eSHaojian Zhuang {
31653dbab7aSHaojian Zhuang 	struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
317be0e2d3eSHaojian Zhuang 	struct pm8607_regulator_info *info = NULL;
318586e1a17SHaojian Zhuang 	struct regulator_init_data *pdata = pdev->dev.platform_data;
319c172708dSMark Brown 	struct regulator_config config = { };
320586e1a17SHaojian Zhuang 	struct resource *res;
32122aad001SHaojian Zhuang 	int i;
322be0e2d3eSHaojian Zhuang 
32302367029SMark Brown 	res = platform_get_resource(pdev, IORESOURCE_REG, 0);
324586e1a17SHaojian Zhuang 	if (res == NULL) {
325*a70abacbSHaojian Zhuang 		dev_err(&pdev->dev, "No REG resource!\n");
32622aad001SHaojian Zhuang 		return -EINVAL;
327586e1a17SHaojian Zhuang 	}
32822aad001SHaojian Zhuang 	for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) {
32922aad001SHaojian Zhuang 		info = &pm8607_regulator_info[i];
330*a70abacbSHaojian Zhuang 		if (info->desc.vsel_reg == res->start)
33122aad001SHaojian Zhuang 			break;
33222aad001SHaojian Zhuang 	}
33399cd25ceSAxel Lin 	if (i == ARRAY_SIZE(pm8607_regulator_info)) {
33409969108SRandy Dunlap 		dev_err(&pdev->dev, "Failed to find regulator %llu\n",
33509969108SRandy Dunlap 			(unsigned long long)res->start);
336be0e2d3eSHaojian Zhuang 		return -EINVAL;
337be0e2d3eSHaojian Zhuang 	}
33853dbab7aSHaojian Zhuang 	info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
339be0e2d3eSHaojian Zhuang 	info->chip = chip;
340be0e2d3eSHaojian Zhuang 
34122aad001SHaojian Zhuang 	/* check DVC ramp slope double */
342586e1a17SHaojian Zhuang 	if ((i == PM8607_ID_BUCK3) && info->chip->buck3_double)
34322aad001SHaojian Zhuang 		info->slope_double = 1;
34422aad001SHaojian Zhuang 
345c172708dSMark Brown 	config.dev = &pdev->dev;
346c172708dSMark Brown 	config.init_data = pdata;
347c172708dSMark Brown 	config.driver_data = info;
348c172708dSMark Brown 
349ef26e0dbSAxel Lin 	if (chip->id == CHIP_PM8607)
350ef26e0dbSAxel Lin 		config.regmap = chip->regmap;
351ef26e0dbSAxel Lin 	else
352ef26e0dbSAxel Lin 		config.regmap = chip->regmap_companion;
353ef26e0dbSAxel Lin 
354c172708dSMark Brown 	info->regulator = regulator_register(&info->desc, &config);
355be0e2d3eSHaojian Zhuang 	if (IS_ERR(info->regulator)) {
356be0e2d3eSHaojian Zhuang 		dev_err(&pdev->dev, "failed to register regulator %s\n",
357be0e2d3eSHaojian Zhuang 			info->desc.name);
358be0e2d3eSHaojian Zhuang 		return PTR_ERR(info->regulator);
359be0e2d3eSHaojian Zhuang 	}
360be0e2d3eSHaojian Zhuang 
361be0e2d3eSHaojian Zhuang 	platform_set_drvdata(pdev, info);
362be0e2d3eSHaojian Zhuang 	return 0;
363be0e2d3eSHaojian Zhuang }
364be0e2d3eSHaojian Zhuang 
365be0e2d3eSHaojian Zhuang static int __devexit pm8607_regulator_remove(struct platform_device *pdev)
366be0e2d3eSHaojian Zhuang {
367be0e2d3eSHaojian Zhuang 	struct pm8607_regulator_info *info = platform_get_drvdata(pdev);
368be0e2d3eSHaojian Zhuang 
369192bbb95SHaojian Zhuang 	platform_set_drvdata(pdev, NULL);
370be0e2d3eSHaojian Zhuang 	regulator_unregister(info->regulator);
371be0e2d3eSHaojian Zhuang 	return 0;
372be0e2d3eSHaojian Zhuang }
373be0e2d3eSHaojian Zhuang 
374192bbb95SHaojian Zhuang static struct platform_driver pm8607_regulator_driver = {
375192bbb95SHaojian Zhuang 	.driver		= {
376192bbb95SHaojian Zhuang 		.name	= "88pm860x-regulator",
377192bbb95SHaojian Zhuang 		.owner	= THIS_MODULE,
378192bbb95SHaojian Zhuang 	},
379192bbb95SHaojian Zhuang 	.probe		= pm8607_regulator_probe,
380192bbb95SHaojian Zhuang 	.remove		= __devexit_p(pm8607_regulator_remove),
381be0e2d3eSHaojian Zhuang };
382be0e2d3eSHaojian Zhuang 
383be0e2d3eSHaojian Zhuang static int __init pm8607_regulator_init(void)
384be0e2d3eSHaojian Zhuang {
385192bbb95SHaojian Zhuang 	return platform_driver_register(&pm8607_regulator_driver);
386be0e2d3eSHaojian Zhuang }
387be0e2d3eSHaojian Zhuang subsys_initcall(pm8607_regulator_init);
388be0e2d3eSHaojian Zhuang 
389be0e2d3eSHaojian Zhuang static void __exit pm8607_regulator_exit(void)
390be0e2d3eSHaojian Zhuang {
391192bbb95SHaojian Zhuang 	platform_driver_unregister(&pm8607_regulator_driver);
392be0e2d3eSHaojian Zhuang }
393be0e2d3eSHaojian Zhuang module_exit(pm8607_regulator_exit);
394be0e2d3eSHaojian Zhuang 
395be0e2d3eSHaojian Zhuang MODULE_LICENSE("GPL");
396be0e2d3eSHaojian Zhuang MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
397be0e2d3eSHaojian Zhuang MODULE_DESCRIPTION("Regulator Driver for Marvell 88PM8607 PMIC");
398be0e2d3eSHaojian Zhuang MODULE_ALIAS("platform:88pm8607-regulator");
399