xref: /linux/drivers/regulator/88pm8607.c (revision ef26e0dbe8bebd8dc559d39ed804720002225fc3)
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	vol_reg;
31be0e2d3eSHaojian Zhuang 	int	vol_shift;
32be0e2d3eSHaojian Zhuang 	int	update_reg;
33be0e2d3eSHaojian Zhuang 	int	update_bit;
34be0e2d3eSHaojian Zhuang 	int	slope_double;
35be0e2d3eSHaojian Zhuang };
36be0e2d3eSHaojian Zhuang 
379f79e9dbSHaojian Zhuang static const unsigned int BUCK1_table[] = {
389f79e9dbSHaojian Zhuang 	 725000,  750000,  775000,  800000,  825000,  850000,  875000,  900000,
399f79e9dbSHaojian Zhuang 	 925000,  950000,  975000, 1000000, 1025000, 1050000, 1075000, 1100000,
409f79e9dbSHaojian Zhuang 	1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000,
419f79e9dbSHaojian Zhuang 	1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000,
429f79e9dbSHaojian Zhuang 	      0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
439f79e9dbSHaojian Zhuang 	 200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
449f79e9dbSHaojian Zhuang 	 400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
459f79e9dbSHaojian Zhuang 	 600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
469f79e9dbSHaojian Zhuang };
47be0e2d3eSHaojian Zhuang 
489f79e9dbSHaojian Zhuang static const unsigned int BUCK1_suspend_table[] = {
499f79e9dbSHaojian Zhuang 	      0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
509f79e9dbSHaojian Zhuang 	 200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
519f79e9dbSHaojian Zhuang 	 400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
529f79e9dbSHaojian Zhuang 	 600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
539f79e9dbSHaojian Zhuang 	 800000,  825000,  850000,  875000,  900000,  925000,  950000,  975000,
549f79e9dbSHaojian Zhuang 	1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
559f79e9dbSHaojian Zhuang 	1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000,
569f79e9dbSHaojian Zhuang 	1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000,
579f79e9dbSHaojian Zhuang };
589f79e9dbSHaojian Zhuang 
599f79e9dbSHaojian Zhuang static const unsigned int BUCK2_table[] = {
609f79e9dbSHaojian Zhuang 	      0,   50000,  100000,  150000,  200000,  250000,  300000,  350000,
619f79e9dbSHaojian Zhuang 	 400000,  450000,  500000,  550000,  600000,  650000,  700000,  750000,
629f79e9dbSHaojian Zhuang 	 800000,  850000,  900000,  950000, 1000000, 1050000, 1100000, 1150000,
639f79e9dbSHaojian Zhuang 	1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1550000,
649f79e9dbSHaojian Zhuang 	1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 1950000,
659f79e9dbSHaojian Zhuang 	2000000, 2050000, 2100000, 2150000, 2200000, 2250000, 2300000, 2350000,
669f79e9dbSHaojian Zhuang 	2400000, 2450000, 2500000, 2550000, 2600000, 2650000, 2700000, 2750000,
679f79e9dbSHaojian Zhuang 	2800000, 2850000, 2900000, 2950000, 3000000, 3000000, 3000000, 3000000,
689f79e9dbSHaojian Zhuang };
699f79e9dbSHaojian Zhuang 
709f79e9dbSHaojian Zhuang static const unsigned int BUCK2_suspend_table[] = {
719f79e9dbSHaojian Zhuang 	      0,   50000,  100000,  150000,  200000,  250000,  300000,  350000,
729f79e9dbSHaojian Zhuang 	 400000,  450000,  500000,  550000,  600000,  650000,  700000,  750000,
739f79e9dbSHaojian Zhuang 	 800000,  850000,  900000,  950000, 1000000, 1050000, 1100000, 1150000,
749f79e9dbSHaojian Zhuang 	1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1550000,
759f79e9dbSHaojian Zhuang 	1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 1950000,
769f79e9dbSHaojian Zhuang 	2000000, 2050000, 2100000, 2150000, 2200000, 2250000, 2300000, 2350000,
779f79e9dbSHaojian Zhuang 	2400000, 2450000, 2500000, 2550000, 2600000, 2650000, 2700000, 2750000,
789f79e9dbSHaojian Zhuang 	2800000, 2850000, 2900000, 2950000, 3000000, 3000000, 3000000, 3000000,
799f79e9dbSHaojian Zhuang };
809f79e9dbSHaojian Zhuang 
819f79e9dbSHaojian Zhuang static const unsigned int BUCK3_table[] = {
829f79e9dbSHaojian Zhuang               0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
839f79e9dbSHaojian Zhuang 	 200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
849f79e9dbSHaojian Zhuang 	 400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
859f79e9dbSHaojian Zhuang 	 600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
869f79e9dbSHaojian Zhuang 	 800000,  825000,  850000,  875000,  900000,  925000,  950000,  975000,
879f79e9dbSHaojian Zhuang 	1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
889f79e9dbSHaojian Zhuang 	1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000,
899f79e9dbSHaojian Zhuang 	1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000,
909f79e9dbSHaojian Zhuang };
919f79e9dbSHaojian Zhuang 
929f79e9dbSHaojian Zhuang static const unsigned int BUCK3_suspend_table[] = {
939f79e9dbSHaojian Zhuang               0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
949f79e9dbSHaojian Zhuang 	 200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
959f79e9dbSHaojian Zhuang 	 400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
969f79e9dbSHaojian Zhuang 	 600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
979f79e9dbSHaojian Zhuang 	 800000,  825000,  850000,  875000,  900000,  925000,  950000,  975000,
989f79e9dbSHaojian Zhuang 	1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
999f79e9dbSHaojian Zhuang 	1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000,
1009f79e9dbSHaojian Zhuang 	1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000,
1019f79e9dbSHaojian Zhuang };
1029f79e9dbSHaojian Zhuang 
1039f79e9dbSHaojian Zhuang static const unsigned int LDO1_table[] = {
1049f79e9dbSHaojian Zhuang 	1800000, 1200000, 2800000, 0,
1059f79e9dbSHaojian Zhuang };
1069f79e9dbSHaojian Zhuang 
1079f79e9dbSHaojian Zhuang static const unsigned int LDO1_suspend_table[] = {
1089f79e9dbSHaojian Zhuang 	1800000, 1200000, 0, 0,
1099f79e9dbSHaojian Zhuang };
1109f79e9dbSHaojian Zhuang 
1119f79e9dbSHaojian Zhuang static const unsigned int LDO2_table[] = {
1129f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
1139f79e9dbSHaojian Zhuang };
1149f79e9dbSHaojian Zhuang 
1159f79e9dbSHaojian Zhuang static const unsigned int LDO2_suspend_table[] = {
1169f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
1179f79e9dbSHaojian Zhuang };
1189f79e9dbSHaojian Zhuang 
1199f79e9dbSHaojian Zhuang static const unsigned int LDO3_table[] = {
1209f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
1219f79e9dbSHaojian Zhuang };
1229f79e9dbSHaojian Zhuang 
1239f79e9dbSHaojian Zhuang static const unsigned int LDO3_suspend_table[] = {
1249f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
1259f79e9dbSHaojian Zhuang };
1269f79e9dbSHaojian Zhuang 
1279f79e9dbSHaojian Zhuang static const unsigned int LDO4_table[] = {
1289f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2900000, 3300000,
1299f79e9dbSHaojian Zhuang };
1309f79e9dbSHaojian Zhuang 
1319f79e9dbSHaojian Zhuang static const unsigned int LDO4_suspend_table[] = {
1329f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2900000, 2900000,
1339f79e9dbSHaojian Zhuang };
1349f79e9dbSHaojian Zhuang 
1359f79e9dbSHaojian Zhuang static const unsigned int LDO5_table[] = {
1369f79e9dbSHaojian Zhuang 	2900000, 3000000, 3100000, 3300000,
1379f79e9dbSHaojian Zhuang };
1389f79e9dbSHaojian Zhuang 
1399f79e9dbSHaojian Zhuang static const unsigned int LDO5_suspend_table[] = {
1409f79e9dbSHaojian Zhuang 	2900000, 0, 0, 0,
1419f79e9dbSHaojian Zhuang };
1429f79e9dbSHaojian Zhuang 
1439f79e9dbSHaojian Zhuang static const unsigned int LDO6_table[] = {
1449f79e9dbSHaojian Zhuang 	1800000, 1850000, 2600000, 2650000, 2700000, 2750000, 2800000, 3300000,
1459f79e9dbSHaojian Zhuang };
1469f79e9dbSHaojian Zhuang 
1479f79e9dbSHaojian Zhuang static const unsigned int LDO6_suspend_table[] = {
1489f79e9dbSHaojian Zhuang 	1800000, 1850000, 2600000, 2650000, 2700000, 2750000, 2800000, 2900000,
1499f79e9dbSHaojian Zhuang };
1509f79e9dbSHaojian Zhuang 
1519f79e9dbSHaojian Zhuang static const unsigned int LDO7_table[] = {
1529f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
1539f79e9dbSHaojian Zhuang };
1549f79e9dbSHaojian Zhuang 
1559f79e9dbSHaojian Zhuang static const unsigned int LDO7_suspend_table[] = {
1569f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
1579f79e9dbSHaojian Zhuang };
1589f79e9dbSHaojian Zhuang 
1599f79e9dbSHaojian Zhuang static const unsigned int LDO8_table[] = {
1609f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
1619f79e9dbSHaojian Zhuang };
1629f79e9dbSHaojian Zhuang 
1639f79e9dbSHaojian Zhuang static const unsigned int LDO8_suspend_table[] = {
1649f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
1659f79e9dbSHaojian Zhuang };
1669f79e9dbSHaojian Zhuang 
1679f79e9dbSHaojian Zhuang static const unsigned int LDO9_table[] = {
1689f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
1699f79e9dbSHaojian Zhuang };
1709f79e9dbSHaojian Zhuang 
1719f79e9dbSHaojian Zhuang static const unsigned int LDO9_suspend_table[] = {
1729f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
1739f79e9dbSHaojian Zhuang };
1749f79e9dbSHaojian Zhuang 
1759f79e9dbSHaojian Zhuang static const unsigned int LDO10_table[] = {
1769f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
1779f79e9dbSHaojian Zhuang 	1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
1789f79e9dbSHaojian Zhuang };
1799f79e9dbSHaojian Zhuang 
1809f79e9dbSHaojian Zhuang static const unsigned int LDO10_suspend_table[] = {
1819f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
1829f79e9dbSHaojian Zhuang 	1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
1839f79e9dbSHaojian Zhuang };
1849f79e9dbSHaojian Zhuang 
1859f79e9dbSHaojian Zhuang static const unsigned int LDO12_table[] = {
1869f79e9dbSHaojian Zhuang 	1800000, 1900000, 2700000, 2800000, 2900000, 3000000, 3100000, 3300000,
1879f79e9dbSHaojian Zhuang 	1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
1889f79e9dbSHaojian Zhuang };
1899f79e9dbSHaojian Zhuang 
1909f79e9dbSHaojian Zhuang static const unsigned int LDO12_suspend_table[] = {
1919f79e9dbSHaojian Zhuang 	1800000, 1900000, 2700000, 2800000, 2900000, 2900000, 2900000, 2900000,
1929f79e9dbSHaojian Zhuang 	1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
1939f79e9dbSHaojian Zhuang };
1949f79e9dbSHaojian Zhuang 
1959f79e9dbSHaojian Zhuang static const unsigned int LDO13_table[] = {
1963380643bSJett.Zhou 	1200000, 1300000, 1800000, 2000000, 2500000, 2800000, 3000000, 0,
1979f79e9dbSHaojian Zhuang };
1989f79e9dbSHaojian Zhuang 
1999f79e9dbSHaojian Zhuang static const unsigned int LDO13_suspend_table[] = {
2009f79e9dbSHaojian Zhuang 	0,
2019f79e9dbSHaojian Zhuang };
2029f79e9dbSHaojian Zhuang 
2039f79e9dbSHaojian Zhuang static const unsigned int LDO14_table[] = {
2049f79e9dbSHaojian Zhuang 	1800000, 1850000, 2700000, 2750000, 2800000, 2850000, 2900000, 3300000,
2059f79e9dbSHaojian Zhuang };
2069f79e9dbSHaojian Zhuang 
2079f79e9dbSHaojian Zhuang static const unsigned int LDO14_suspend_table[] = {
2089f79e9dbSHaojian Zhuang 	1800000, 1850000, 2700000, 2750000, 2800000, 2850000, 2900000, 2900000,
2099f79e9dbSHaojian Zhuang };
210be0e2d3eSHaojian Zhuang 
211be0e2d3eSHaojian Zhuang static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index)
212be0e2d3eSHaojian Zhuang {
213be0e2d3eSHaojian Zhuang 	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
214be0e2d3eSHaojian Zhuang 	int ret = -EINVAL;
215be0e2d3eSHaojian Zhuang 
21653b6949eSAxel Lin 	if (info->vol_table && (index < rdev->desc->n_voltages)) {
2179f79e9dbSHaojian Zhuang 		ret = info->vol_table[index];
218be0e2d3eSHaojian Zhuang 		if (info->slope_double)
219be0e2d3eSHaojian Zhuang 			ret <<= 1;
220be0e2d3eSHaojian Zhuang 	}
221be0e2d3eSHaojian Zhuang 	return ret;
222be0e2d3eSHaojian Zhuang }
223be0e2d3eSHaojian Zhuang 
2244ca1e1d9SAxel Lin static int pm8607_set_voltage_sel(struct regulator_dev *rdev, unsigned selector)
225be0e2d3eSHaojian Zhuang {
226be0e2d3eSHaojian Zhuang 	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
227be0e2d3eSHaojian Zhuang 	uint8_t val, mask;
228be0e2d3eSHaojian Zhuang 	int ret;
229be0e2d3eSHaojian Zhuang 
2304ca1e1d9SAxel Lin 	val = (uint8_t)(selector << info->vol_shift);
23153b6949eSAxel Lin 	mask = (rdev->desc->n_voltages - 1)  << info->vol_shift;
232be0e2d3eSHaojian Zhuang 
2334ca1e1d9SAxel Lin 	ret = pm860x_set_bits(info->i2c, info->vol_reg, mask, selector);
234be0e2d3eSHaojian Zhuang 	if (ret)
235be0e2d3eSHaojian Zhuang 		return ret;
236be0e2d3eSHaojian Zhuang 	switch (info->desc.id) {
237be0e2d3eSHaojian Zhuang 	case PM8607_ID_BUCK1:
238be0e2d3eSHaojian Zhuang 	case PM8607_ID_BUCK3:
23953dbab7aSHaojian Zhuang 		ret = pm860x_set_bits(info->i2c, info->update_reg,
240be0e2d3eSHaojian Zhuang 				      1 << info->update_bit,
241be0e2d3eSHaojian Zhuang 				      1 << info->update_bit);
242be0e2d3eSHaojian Zhuang 		break;
243be0e2d3eSHaojian Zhuang 	}
244be0e2d3eSHaojian Zhuang 	return ret;
245be0e2d3eSHaojian Zhuang }
246be0e2d3eSHaojian Zhuang 
247509cbf84SAxel Lin static int pm8607_get_voltage_sel(struct regulator_dev *rdev)
248be0e2d3eSHaojian Zhuang {
249be0e2d3eSHaojian Zhuang 	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
250be0e2d3eSHaojian Zhuang 	uint8_t val, mask;
251be0e2d3eSHaojian Zhuang 	int ret;
252be0e2d3eSHaojian Zhuang 
25353dbab7aSHaojian Zhuang 	ret = pm860x_reg_read(info->i2c, info->vol_reg);
254be0e2d3eSHaojian Zhuang 	if (ret < 0)
255be0e2d3eSHaojian Zhuang 		return ret;
256be0e2d3eSHaojian Zhuang 
25753b6949eSAxel Lin 	mask = (rdev->desc->n_voltages - 1)  << info->vol_shift;
258be0e2d3eSHaojian Zhuang 	val = ((unsigned char)ret & mask) >> info->vol_shift;
259be0e2d3eSHaojian Zhuang 
260509cbf84SAxel Lin 	return val;
261be0e2d3eSHaojian Zhuang }
262be0e2d3eSHaojian Zhuang 
263be0e2d3eSHaojian Zhuang static struct regulator_ops pm8607_regulator_ops = {
264d3d7bcccSAxel Lin 	.list_voltage	= pm8607_list_voltage,
2654ca1e1d9SAxel Lin 	.set_voltage_sel = pm8607_set_voltage_sel,
266509cbf84SAxel Lin 	.get_voltage_sel = pm8607_get_voltage_sel,
267*ef26e0dbSAxel Lin 	.enable = regulator_enable_regmap,
268*ef26e0dbSAxel Lin 	.disable = regulator_disable_regmap,
269*ef26e0dbSAxel Lin 	.is_enabled = regulator_is_enabled_regmap,
270be0e2d3eSHaojian Zhuang };
271be0e2d3eSHaojian Zhuang 
27253b6949eSAxel Lin #define PM8607_DVC(vreg, ureg, ubit, ereg, ebit)			\
273be0e2d3eSHaojian Zhuang {									\
274be0e2d3eSHaojian Zhuang 	.desc	= {							\
2759f79e9dbSHaojian Zhuang 		.name	= #vreg,					\
276be0e2d3eSHaojian Zhuang 		.ops	= &pm8607_regulator_ops,			\
277be0e2d3eSHaojian Zhuang 		.type	= REGULATOR_VOLTAGE,				\
2789f79e9dbSHaojian Zhuang 		.id	= PM8607_ID_##vreg,				\
279be0e2d3eSHaojian Zhuang 		.owner	= THIS_MODULE,					\
28053b6949eSAxel Lin 		.n_voltages = ARRAY_SIZE(vreg##_table),			\
281*ef26e0dbSAxel Lin 		.enable_reg = PM8607_##ereg,				\
282*ef26e0dbSAxel Lin 		.enable_mask = 1 << (ebit),				\
283be0e2d3eSHaojian Zhuang 	},								\
284be0e2d3eSHaojian Zhuang 	.vol_reg	= PM8607_##vreg,				\
285be0e2d3eSHaojian Zhuang 	.vol_shift	= (0),						\
286be0e2d3eSHaojian Zhuang 	.update_reg	= PM8607_##ureg,				\
287be0e2d3eSHaojian Zhuang 	.update_bit	= (ubit),					\
288be0e2d3eSHaojian Zhuang 	.slope_double	= (0),						\
2899f79e9dbSHaojian Zhuang 	.vol_table	= (unsigned int *)&vreg##_table,		\
2909f79e9dbSHaojian Zhuang 	.vol_suspend	= (unsigned int *)&vreg##_suspend_table,	\
291be0e2d3eSHaojian Zhuang }
292be0e2d3eSHaojian Zhuang 
29353b6949eSAxel Lin #define PM8607_LDO(_id, vreg, shift, ereg, ebit)			\
294be0e2d3eSHaojian Zhuang {									\
295be0e2d3eSHaojian Zhuang 	.desc	= {							\
296be0e2d3eSHaojian Zhuang 		.name	= "LDO" #_id,					\
297be0e2d3eSHaojian Zhuang 		.ops	= &pm8607_regulator_ops,			\
298be0e2d3eSHaojian Zhuang 		.type	= REGULATOR_VOLTAGE,				\
299be0e2d3eSHaojian Zhuang 		.id	= PM8607_ID_LDO##_id,				\
300be0e2d3eSHaojian Zhuang 		.owner	= THIS_MODULE,					\
30153b6949eSAxel Lin 		.n_voltages = ARRAY_SIZE(LDO##_id##_table),		\
302*ef26e0dbSAxel Lin 		.enable_reg = PM8607_##ereg,				\
303*ef26e0dbSAxel Lin 		.enable_mask = 1 << (ebit),				\
304be0e2d3eSHaojian Zhuang 	},								\
305be0e2d3eSHaojian Zhuang 	.vol_reg	= PM8607_##vreg,				\
306be0e2d3eSHaojian Zhuang 	.vol_shift	= (shift),					\
307be0e2d3eSHaojian Zhuang 	.slope_double	= (0),						\
3089f79e9dbSHaojian Zhuang 	.vol_table	= (unsigned int *)&LDO##_id##_table,		\
3099f79e9dbSHaojian Zhuang 	.vol_suspend	= (unsigned int *)&LDO##_id##_suspend_table,	\
310be0e2d3eSHaojian Zhuang }
311be0e2d3eSHaojian Zhuang 
312be0e2d3eSHaojian Zhuang static struct pm8607_regulator_info pm8607_regulator_info[] = {
31353b6949eSAxel Lin 	PM8607_DVC(BUCK1, GO, 0, SUPPLIES_EN11, 0),
31453b6949eSAxel Lin 	PM8607_DVC(BUCK2, GO, 1, SUPPLIES_EN11, 1),
31553b6949eSAxel Lin 	PM8607_DVC(BUCK3, GO, 2, SUPPLIES_EN11, 2),
316be0e2d3eSHaojian Zhuang 
31753b6949eSAxel Lin 	PM8607_LDO(1,         LDO1, 0, SUPPLIES_EN11, 3),
31853b6949eSAxel Lin 	PM8607_LDO(2,         LDO2, 0, SUPPLIES_EN11, 4),
31953b6949eSAxel Lin 	PM8607_LDO(3,         LDO3, 0, SUPPLIES_EN11, 5),
32053b6949eSAxel Lin 	PM8607_LDO(4,         LDO4, 0, SUPPLIES_EN11, 6),
32153b6949eSAxel Lin 	PM8607_LDO(5,         LDO5, 0, SUPPLIES_EN11, 7),
32253b6949eSAxel Lin 	PM8607_LDO(6,         LDO6, 0, SUPPLIES_EN12, 0),
32353b6949eSAxel Lin 	PM8607_LDO(7,         LDO7, 0, SUPPLIES_EN12, 1),
32453b6949eSAxel Lin 	PM8607_LDO(8,         LDO8, 0, SUPPLIES_EN12, 2),
32553b6949eSAxel Lin 	PM8607_LDO(9,         LDO9, 0, SUPPLIES_EN12, 3),
32653b6949eSAxel Lin 	PM8607_LDO(10,        LDO10, 0, SUPPLIES_EN12, 4),
32753b6949eSAxel Lin 	PM8607_LDO(12,        LDO12, 0, SUPPLIES_EN12, 5),
32853b6949eSAxel Lin 	PM8607_LDO(13, VIBRATOR_SET, 1, VIBRATOR_SET, 0),
32953b6949eSAxel Lin 	PM8607_LDO(14,        LDO14, 0, SUPPLIES_EN12, 6),
330be0e2d3eSHaojian Zhuang };
331be0e2d3eSHaojian Zhuang 
332be0e2d3eSHaojian Zhuang static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
333be0e2d3eSHaojian Zhuang {
33453dbab7aSHaojian Zhuang 	struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
335be0e2d3eSHaojian Zhuang 	struct pm8607_regulator_info *info = NULL;
336586e1a17SHaojian Zhuang 	struct regulator_init_data *pdata = pdev->dev.platform_data;
337c172708dSMark Brown 	struct regulator_config config = { };
338586e1a17SHaojian Zhuang 	struct resource *res;
33922aad001SHaojian Zhuang 	int i;
340be0e2d3eSHaojian Zhuang 
341586e1a17SHaojian Zhuang 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
342586e1a17SHaojian Zhuang 	if (res == NULL) {
343586e1a17SHaojian Zhuang 		dev_err(&pdev->dev, "No I/O resource!\n");
34422aad001SHaojian Zhuang 		return -EINVAL;
345586e1a17SHaojian Zhuang 	}
34622aad001SHaojian Zhuang 	for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) {
34722aad001SHaojian Zhuang 		info = &pm8607_regulator_info[i];
348586e1a17SHaojian Zhuang 		if (info->desc.id == res->start)
34922aad001SHaojian Zhuang 			break;
35022aad001SHaojian Zhuang 	}
35199cd25ceSAxel Lin 	if (i == ARRAY_SIZE(pm8607_regulator_info)) {
35209969108SRandy Dunlap 		dev_err(&pdev->dev, "Failed to find regulator %llu\n",
35309969108SRandy Dunlap 			(unsigned long long)res->start);
354be0e2d3eSHaojian Zhuang 		return -EINVAL;
355be0e2d3eSHaojian Zhuang 	}
35653dbab7aSHaojian Zhuang 	info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
357be0e2d3eSHaojian Zhuang 	info->chip = chip;
358be0e2d3eSHaojian Zhuang 
35922aad001SHaojian Zhuang 	/* check DVC ramp slope double */
360586e1a17SHaojian Zhuang 	if ((i == PM8607_ID_BUCK3) && info->chip->buck3_double)
36122aad001SHaojian Zhuang 		info->slope_double = 1;
36222aad001SHaojian Zhuang 
363c172708dSMark Brown 	config.dev = &pdev->dev;
364c172708dSMark Brown 	config.init_data = pdata;
365c172708dSMark Brown 	config.driver_data = info;
366c172708dSMark Brown 
367*ef26e0dbSAxel Lin 	if (chip->id == CHIP_PM8607)
368*ef26e0dbSAxel Lin 		config.regmap = chip->regmap;
369*ef26e0dbSAxel Lin 	else
370*ef26e0dbSAxel Lin 		config.regmap = chip->regmap_companion;
371*ef26e0dbSAxel Lin 
372586e1a17SHaojian Zhuang 	/* replace driver_data with info */
373c172708dSMark Brown 	info->regulator = regulator_register(&info->desc, &config);
374be0e2d3eSHaojian Zhuang 	if (IS_ERR(info->regulator)) {
375be0e2d3eSHaojian Zhuang 		dev_err(&pdev->dev, "failed to register regulator %s\n",
376be0e2d3eSHaojian Zhuang 			info->desc.name);
377be0e2d3eSHaojian Zhuang 		return PTR_ERR(info->regulator);
378be0e2d3eSHaojian Zhuang 	}
379be0e2d3eSHaojian Zhuang 
380be0e2d3eSHaojian Zhuang 	platform_set_drvdata(pdev, info);
381be0e2d3eSHaojian Zhuang 	return 0;
382be0e2d3eSHaojian Zhuang }
383be0e2d3eSHaojian Zhuang 
384be0e2d3eSHaojian Zhuang static int __devexit pm8607_regulator_remove(struct platform_device *pdev)
385be0e2d3eSHaojian Zhuang {
386be0e2d3eSHaojian Zhuang 	struct pm8607_regulator_info *info = platform_get_drvdata(pdev);
387be0e2d3eSHaojian Zhuang 
388192bbb95SHaojian Zhuang 	platform_set_drvdata(pdev, NULL);
389be0e2d3eSHaojian Zhuang 	regulator_unregister(info->regulator);
390be0e2d3eSHaojian Zhuang 	return 0;
391be0e2d3eSHaojian Zhuang }
392be0e2d3eSHaojian Zhuang 
393192bbb95SHaojian Zhuang static struct platform_driver pm8607_regulator_driver = {
394192bbb95SHaojian Zhuang 	.driver		= {
395192bbb95SHaojian Zhuang 		.name	= "88pm860x-regulator",
396192bbb95SHaojian Zhuang 		.owner	= THIS_MODULE,
397192bbb95SHaojian Zhuang 	},
398192bbb95SHaojian Zhuang 	.probe		= pm8607_regulator_probe,
399192bbb95SHaojian Zhuang 	.remove		= __devexit_p(pm8607_regulator_remove),
400be0e2d3eSHaojian Zhuang };
401be0e2d3eSHaojian Zhuang 
402be0e2d3eSHaojian Zhuang static int __init pm8607_regulator_init(void)
403be0e2d3eSHaojian Zhuang {
404192bbb95SHaojian Zhuang 	return platform_driver_register(&pm8607_regulator_driver);
405be0e2d3eSHaojian Zhuang }
406be0e2d3eSHaojian Zhuang subsys_initcall(pm8607_regulator_init);
407be0e2d3eSHaojian Zhuang 
408be0e2d3eSHaojian Zhuang static void __exit pm8607_regulator_exit(void)
409be0e2d3eSHaojian Zhuang {
410192bbb95SHaojian Zhuang 	platform_driver_unregister(&pm8607_regulator_driver);
411be0e2d3eSHaojian Zhuang }
412be0e2d3eSHaojian Zhuang module_exit(pm8607_regulator_exit);
413be0e2d3eSHaojian Zhuang 
414be0e2d3eSHaojian Zhuang MODULE_LICENSE("GPL");
415be0e2d3eSHaojian Zhuang MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
416be0e2d3eSHaojian Zhuang MODULE_DESCRIPTION("Regulator Driver for Marvell 88PM8607 PMIC");
417be0e2d3eSHaojian Zhuang MODULE_ALIAS("platform:88pm8607-regulator");
418