xref: /linux/drivers/regulator/88pm8607.c (revision 32cb5d30cf4948e74be3dda5fd85781bc8eb9d49)
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>
152e57d567SHaojian Zhuang #include <linux/of.h>
162e57d567SHaojian Zhuang #include <linux/regulator/of_regulator.h>
17be0e2d3eSHaojian Zhuang #include <linux/platform_device.h>
18be0e2d3eSHaojian Zhuang #include <linux/regulator/driver.h>
19be0e2d3eSHaojian Zhuang #include <linux/regulator/machine.h>
2053dbab7aSHaojian Zhuang #include <linux/mfd/88pm860x.h>
2165602c32SPaul Gortmaker #include <linux/module.h>
22be0e2d3eSHaojian Zhuang 
23be0e2d3eSHaojian Zhuang struct pm8607_regulator_info {
24be0e2d3eSHaojian Zhuang 	struct regulator_desc	desc;
2553dbab7aSHaojian Zhuang 	struct pm860x_chip	*chip;
26be0e2d3eSHaojian Zhuang 	struct regulator_dev	*regulator;
2753dbab7aSHaojian Zhuang 	struct i2c_client	*i2c;
28e7a7810aSJett.Zhou 	struct i2c_client	*i2c_8606;
29be0e2d3eSHaojian Zhuang 
309f79e9dbSHaojian Zhuang 	unsigned int	*vol_table;
319f79e9dbSHaojian Zhuang 	unsigned int	*vol_suspend;
329f79e9dbSHaojian Zhuang 
33be0e2d3eSHaojian Zhuang 	int	slope_double;
34be0e2d3eSHaojian Zhuang };
35be0e2d3eSHaojian Zhuang 
369f79e9dbSHaojian Zhuang static const unsigned int BUCK1_table[] = {
379f79e9dbSHaojian Zhuang 	 725000,  750000,  775000,  800000,  825000,  850000,  875000,  900000,
389f79e9dbSHaojian Zhuang 	 925000,  950000,  975000, 1000000, 1025000, 1050000, 1075000, 1100000,
399f79e9dbSHaojian Zhuang 	1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000,
409f79e9dbSHaojian Zhuang 	1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000,
419f79e9dbSHaojian Zhuang 	      0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
429f79e9dbSHaojian Zhuang 	 200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
439f79e9dbSHaojian Zhuang 	 400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
449f79e9dbSHaojian Zhuang 	 600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
459f79e9dbSHaojian Zhuang };
46be0e2d3eSHaojian Zhuang 
479f79e9dbSHaojian Zhuang static const unsigned int BUCK1_suspend_table[] = {
489f79e9dbSHaojian Zhuang 	      0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
499f79e9dbSHaojian Zhuang 	 200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
509f79e9dbSHaojian Zhuang 	 400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
519f79e9dbSHaojian Zhuang 	 600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
529f79e9dbSHaojian Zhuang 	 800000,  825000,  850000,  875000,  900000,  925000,  950000,  975000,
539f79e9dbSHaojian Zhuang 	1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
549f79e9dbSHaojian Zhuang 	1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000,
559f79e9dbSHaojian Zhuang 	1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000,
569f79e9dbSHaojian Zhuang };
579f79e9dbSHaojian Zhuang 
589f79e9dbSHaojian Zhuang static const unsigned int BUCK2_table[] = {
599f79e9dbSHaojian Zhuang 	      0,   50000,  100000,  150000,  200000,  250000,  300000,  350000,
609f79e9dbSHaojian Zhuang 	 400000,  450000,  500000,  550000,  600000,  650000,  700000,  750000,
619f79e9dbSHaojian Zhuang 	 800000,  850000,  900000,  950000, 1000000, 1050000, 1100000, 1150000,
629f79e9dbSHaojian Zhuang 	1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1550000,
639f79e9dbSHaojian Zhuang 	1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 1950000,
649f79e9dbSHaojian Zhuang 	2000000, 2050000, 2100000, 2150000, 2200000, 2250000, 2300000, 2350000,
659f79e9dbSHaojian Zhuang 	2400000, 2450000, 2500000, 2550000, 2600000, 2650000, 2700000, 2750000,
669f79e9dbSHaojian Zhuang 	2800000, 2850000, 2900000, 2950000, 3000000, 3000000, 3000000, 3000000,
679f79e9dbSHaojian Zhuang };
689f79e9dbSHaojian Zhuang 
699f79e9dbSHaojian Zhuang static const unsigned int BUCK2_suspend_table[] = {
709f79e9dbSHaojian Zhuang 	      0,   50000,  100000,  150000,  200000,  250000,  300000,  350000,
719f79e9dbSHaojian Zhuang 	 400000,  450000,  500000,  550000,  600000,  650000,  700000,  750000,
729f79e9dbSHaojian Zhuang 	 800000,  850000,  900000,  950000, 1000000, 1050000, 1100000, 1150000,
739f79e9dbSHaojian Zhuang 	1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1550000,
749f79e9dbSHaojian Zhuang 	1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 1950000,
759f79e9dbSHaojian Zhuang 	2000000, 2050000, 2100000, 2150000, 2200000, 2250000, 2300000, 2350000,
769f79e9dbSHaojian Zhuang 	2400000, 2450000, 2500000, 2550000, 2600000, 2650000, 2700000, 2750000,
779f79e9dbSHaojian Zhuang 	2800000, 2850000, 2900000, 2950000, 3000000, 3000000, 3000000, 3000000,
789f79e9dbSHaojian Zhuang };
799f79e9dbSHaojian Zhuang 
809f79e9dbSHaojian Zhuang static const unsigned int BUCK3_table[] = {
819f79e9dbSHaojian Zhuang 	      0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
829f79e9dbSHaojian Zhuang 	 200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
839f79e9dbSHaojian Zhuang 	 400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
849f79e9dbSHaojian Zhuang 	 600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
859f79e9dbSHaojian Zhuang 	 800000,  825000,  850000,  875000,  900000,  925000,  950000,  975000,
869f79e9dbSHaojian Zhuang 	1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
879f79e9dbSHaojian Zhuang 	1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000,
889f79e9dbSHaojian Zhuang 	1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000,
899f79e9dbSHaojian Zhuang };
909f79e9dbSHaojian Zhuang 
919f79e9dbSHaojian Zhuang static const unsigned int BUCK3_suspend_table[] = {
929f79e9dbSHaojian Zhuang 	      0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
939f79e9dbSHaojian Zhuang 	 200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
949f79e9dbSHaojian Zhuang 	 400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
959f79e9dbSHaojian Zhuang 	 600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
969f79e9dbSHaojian Zhuang 	 800000,  825000,  850000,  875000,  900000,  925000,  950000,  975000,
979f79e9dbSHaojian Zhuang 	1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
989f79e9dbSHaojian Zhuang 	1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000,
999f79e9dbSHaojian Zhuang 	1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000,
1009f79e9dbSHaojian Zhuang };
1019f79e9dbSHaojian Zhuang 
1029f79e9dbSHaojian Zhuang static const unsigned int LDO1_table[] = {
1039f79e9dbSHaojian Zhuang 	1800000, 1200000, 2800000, 0,
1049f79e9dbSHaojian Zhuang };
1059f79e9dbSHaojian Zhuang 
1069f79e9dbSHaojian Zhuang static const unsigned int LDO1_suspend_table[] = {
1079f79e9dbSHaojian Zhuang 	1800000, 1200000, 0, 0,
1089f79e9dbSHaojian Zhuang };
1099f79e9dbSHaojian Zhuang 
1109f79e9dbSHaojian Zhuang static const unsigned int LDO2_table[] = {
1119f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
1129f79e9dbSHaojian Zhuang };
1139f79e9dbSHaojian Zhuang 
1149f79e9dbSHaojian Zhuang static const unsigned int LDO2_suspend_table[] = {
1159f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
1169f79e9dbSHaojian Zhuang };
1179f79e9dbSHaojian Zhuang 
1189f79e9dbSHaojian Zhuang static const unsigned int LDO3_table[] = {
1199f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
1209f79e9dbSHaojian Zhuang };
1219f79e9dbSHaojian Zhuang 
1229f79e9dbSHaojian Zhuang static const unsigned int LDO3_suspend_table[] = {
1239f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
1249f79e9dbSHaojian Zhuang };
1259f79e9dbSHaojian Zhuang 
1269f79e9dbSHaojian Zhuang static const unsigned int LDO4_table[] = {
1279f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2900000, 3300000,
1289f79e9dbSHaojian Zhuang };
1299f79e9dbSHaojian Zhuang 
1309f79e9dbSHaojian Zhuang static const unsigned int LDO4_suspend_table[] = {
1319f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2900000, 2900000,
1329f79e9dbSHaojian Zhuang };
1339f79e9dbSHaojian Zhuang 
1349f79e9dbSHaojian Zhuang static const unsigned int LDO5_table[] = {
1359f79e9dbSHaojian Zhuang 	2900000, 3000000, 3100000, 3300000,
1369f79e9dbSHaojian Zhuang };
1379f79e9dbSHaojian Zhuang 
1389f79e9dbSHaojian Zhuang static const unsigned int LDO5_suspend_table[] = {
1399f79e9dbSHaojian Zhuang 	2900000, 0, 0, 0,
1409f79e9dbSHaojian Zhuang };
1419f79e9dbSHaojian Zhuang 
1429f79e9dbSHaojian Zhuang static const unsigned int LDO6_table[] = {
1439f79e9dbSHaojian Zhuang 	1800000, 1850000, 2600000, 2650000, 2700000, 2750000, 2800000, 3300000,
1449f79e9dbSHaojian Zhuang };
1459f79e9dbSHaojian Zhuang 
1469f79e9dbSHaojian Zhuang static const unsigned int LDO6_suspend_table[] = {
1479f79e9dbSHaojian Zhuang 	1800000, 1850000, 2600000, 2650000, 2700000, 2750000, 2800000, 2900000,
1489f79e9dbSHaojian Zhuang };
1499f79e9dbSHaojian Zhuang 
1509f79e9dbSHaojian Zhuang static const unsigned int LDO7_table[] = {
1519f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
1529f79e9dbSHaojian Zhuang };
1539f79e9dbSHaojian Zhuang 
1549f79e9dbSHaojian Zhuang static const unsigned int LDO7_suspend_table[] = {
1559f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
1569f79e9dbSHaojian Zhuang };
1579f79e9dbSHaojian Zhuang 
1589f79e9dbSHaojian Zhuang static const unsigned int LDO8_table[] = {
1599f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
1609f79e9dbSHaojian Zhuang };
1619f79e9dbSHaojian Zhuang 
1629f79e9dbSHaojian Zhuang static const unsigned int LDO8_suspend_table[] = {
1639f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
1649f79e9dbSHaojian Zhuang };
1659f79e9dbSHaojian Zhuang 
1669f79e9dbSHaojian Zhuang static const unsigned int LDO9_table[] = {
1679f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
1689f79e9dbSHaojian Zhuang };
1699f79e9dbSHaojian Zhuang 
1709f79e9dbSHaojian Zhuang static const unsigned int LDO9_suspend_table[] = {
1719f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
1729f79e9dbSHaojian Zhuang };
1739f79e9dbSHaojian Zhuang 
1749f79e9dbSHaojian Zhuang static const unsigned int LDO10_table[] = {
1759f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
1769f79e9dbSHaojian Zhuang 	1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
1779f79e9dbSHaojian Zhuang };
1789f79e9dbSHaojian Zhuang 
1799f79e9dbSHaojian Zhuang static const unsigned int LDO10_suspend_table[] = {
1809f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
1819f79e9dbSHaojian Zhuang 	1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
1829f79e9dbSHaojian Zhuang };
1839f79e9dbSHaojian Zhuang 
1849f79e9dbSHaojian Zhuang static const unsigned int LDO12_table[] = {
1859f79e9dbSHaojian Zhuang 	1800000, 1900000, 2700000, 2800000, 2900000, 3000000, 3100000, 3300000,
1869f79e9dbSHaojian Zhuang 	1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
1879f79e9dbSHaojian Zhuang };
1889f79e9dbSHaojian Zhuang 
1899f79e9dbSHaojian Zhuang static const unsigned int LDO12_suspend_table[] = {
1909f79e9dbSHaojian Zhuang 	1800000, 1900000, 2700000, 2800000, 2900000, 2900000, 2900000, 2900000,
1919f79e9dbSHaojian Zhuang 	1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
1929f79e9dbSHaojian Zhuang };
1939f79e9dbSHaojian Zhuang 
1949f79e9dbSHaojian Zhuang static const unsigned int LDO13_table[] = {
1953380643bSJett.Zhou 	1200000, 1300000, 1800000, 2000000, 2500000, 2800000, 3000000, 0,
1969f79e9dbSHaojian Zhuang };
1979f79e9dbSHaojian Zhuang 
1989f79e9dbSHaojian Zhuang static const unsigned int LDO13_suspend_table[] = {
1999f79e9dbSHaojian Zhuang 	0,
2009f79e9dbSHaojian Zhuang };
2019f79e9dbSHaojian Zhuang 
2029f79e9dbSHaojian Zhuang static const unsigned int LDO14_table[] = {
2039f79e9dbSHaojian Zhuang 	1800000, 1850000, 2700000, 2750000, 2800000, 2850000, 2900000, 3300000,
2049f79e9dbSHaojian Zhuang };
2059f79e9dbSHaojian Zhuang 
2069f79e9dbSHaojian Zhuang static const unsigned int LDO14_suspend_table[] = {
2079f79e9dbSHaojian Zhuang 	1800000, 1850000, 2700000, 2750000, 2800000, 2850000, 2900000, 2900000,
2089f79e9dbSHaojian Zhuang };
209be0e2d3eSHaojian Zhuang 
210be0e2d3eSHaojian Zhuang static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index)
211be0e2d3eSHaojian Zhuang {
212be0e2d3eSHaojian Zhuang 	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
213be0e2d3eSHaojian Zhuang 	int ret = -EINVAL;
214be0e2d3eSHaojian Zhuang 
21553b6949eSAxel Lin 	if (info->vol_table && (index < rdev->desc->n_voltages)) {
2169f79e9dbSHaojian Zhuang 		ret = info->vol_table[index];
217be0e2d3eSHaojian Zhuang 		if (info->slope_double)
218be0e2d3eSHaojian Zhuang 			ret <<= 1;
219be0e2d3eSHaojian Zhuang 	}
220be0e2d3eSHaojian Zhuang 	return ret;
221be0e2d3eSHaojian Zhuang }
222be0e2d3eSHaojian Zhuang 
223*32cb5d30SBhumika Goyal static const struct regulator_ops pm8607_regulator_ops = {
224d3d7bcccSAxel Lin 	.list_voltage	= pm8607_list_voltage,
225c6f0a0efSAxel Lin 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
226c006b21fSAxel Lin 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
227ef26e0dbSAxel Lin 	.enable = regulator_enable_regmap,
228ef26e0dbSAxel Lin 	.disable = regulator_disable_regmap,
229ef26e0dbSAxel Lin 	.is_enabled = regulator_is_enabled_regmap,
230be0e2d3eSHaojian Zhuang };
231be0e2d3eSHaojian Zhuang 
232*32cb5d30SBhumika Goyal static const struct regulator_ops pm8606_preg_ops = {
233318c658bSAxel Lin 	.enable		= regulator_enable_regmap,
234318c658bSAxel Lin 	.disable	= regulator_disable_regmap,
235318c658bSAxel Lin 	.is_enabled	= regulator_is_enabled_regmap,
236e7a7810aSJett.Zhou };
237e7a7810aSJett.Zhou 
238e7a7810aSJett.Zhou #define PM8606_PREG(ereg, ebit)						\
239e7a7810aSJett.Zhou {									\
240e7a7810aSJett.Zhou 	.desc	= {							\
241e7a7810aSJett.Zhou 		.name	= "PREG",					\
242e7a7810aSJett.Zhou 		.ops	= &pm8606_preg_ops,				\
243e7a7810aSJett.Zhou 		.type	= REGULATOR_CURRENT,				\
244e7a7810aSJett.Zhou 		.id	= PM8606_ID_PREG,				\
245e7a7810aSJett.Zhou 		.owner	= THIS_MODULE,					\
246e7a7810aSJett.Zhou 		.enable_reg = PM8606_##ereg,				\
247e7a7810aSJett.Zhou 		.enable_mask = (ebit),					\
248318c658bSAxel Lin 		.enable_is_inverted = true,				\
249e7a7810aSJett.Zhou 	},								\
250e7a7810aSJett.Zhou }
251e7a7810aSJett.Zhou 
25253b6949eSAxel Lin #define PM8607_DVC(vreg, ureg, ubit, ereg, ebit)			\
253be0e2d3eSHaojian Zhuang {									\
254be0e2d3eSHaojian Zhuang 	.desc	= {							\
2559f79e9dbSHaojian Zhuang 		.name	= #vreg,					\
256be0e2d3eSHaojian Zhuang 		.ops	= &pm8607_regulator_ops,			\
257be0e2d3eSHaojian Zhuang 		.type	= REGULATOR_VOLTAGE,				\
2589f79e9dbSHaojian Zhuang 		.id	= PM8607_ID_##vreg,				\
259be0e2d3eSHaojian Zhuang 		.owner	= THIS_MODULE,					\
26053b6949eSAxel Lin 		.n_voltages = ARRAY_SIZE(vreg##_table),			\
261c006b21fSAxel Lin 		.vsel_reg = PM8607_##vreg,				\
262c006b21fSAxel Lin 		.vsel_mask = ARRAY_SIZE(vreg##_table) - 1,		\
263c6f0a0efSAxel Lin 		.apply_reg = PM8607_##ureg,				\
264c6f0a0efSAxel Lin 		.apply_bit = (ubit),					\
265ef26e0dbSAxel Lin 		.enable_reg = PM8607_##ereg,				\
266ef26e0dbSAxel Lin 		.enable_mask = 1 << (ebit),				\
267be0e2d3eSHaojian Zhuang 	},								\
268be0e2d3eSHaojian Zhuang 	.slope_double	= (0),						\
2699f79e9dbSHaojian Zhuang 	.vol_table	= (unsigned int *)&vreg##_table,		\
2709f79e9dbSHaojian Zhuang 	.vol_suspend	= (unsigned int *)&vreg##_suspend_table,	\
271be0e2d3eSHaojian Zhuang }
272be0e2d3eSHaojian Zhuang 
27353b6949eSAxel Lin #define PM8607_LDO(_id, vreg, shift, ereg, ebit)			\
274be0e2d3eSHaojian Zhuang {									\
275be0e2d3eSHaojian Zhuang 	.desc	= {							\
276be0e2d3eSHaojian Zhuang 		.name	= "LDO" #_id,					\
277be0e2d3eSHaojian Zhuang 		.ops	= &pm8607_regulator_ops,			\
278be0e2d3eSHaojian Zhuang 		.type	= REGULATOR_VOLTAGE,				\
279be0e2d3eSHaojian Zhuang 		.id	= PM8607_ID_LDO##_id,				\
280be0e2d3eSHaojian Zhuang 		.owner	= THIS_MODULE,					\
28153b6949eSAxel Lin 		.n_voltages = ARRAY_SIZE(LDO##_id##_table),		\
282c006b21fSAxel Lin 		.vsel_reg = PM8607_##vreg,				\
283c006b21fSAxel Lin 		.vsel_mask = (ARRAY_SIZE(LDO##_id##_table) - 1) << (shift), \
284ef26e0dbSAxel Lin 		.enable_reg = PM8607_##ereg,				\
285ef26e0dbSAxel Lin 		.enable_mask = 1 << (ebit),				\
286be0e2d3eSHaojian Zhuang 	},								\
287be0e2d3eSHaojian Zhuang 	.slope_double	= (0),						\
2889f79e9dbSHaojian Zhuang 	.vol_table	= (unsigned int *)&LDO##_id##_table,		\
2899f79e9dbSHaojian Zhuang 	.vol_suspend	= (unsigned int *)&LDO##_id##_suspend_table,	\
290be0e2d3eSHaojian Zhuang }
291be0e2d3eSHaojian Zhuang 
292be0e2d3eSHaojian Zhuang static struct pm8607_regulator_info pm8607_regulator_info[] = {
293c6f0a0efSAxel Lin 	PM8607_DVC(BUCK1, GO, BIT(0), SUPPLIES_EN11, 0),
294c6f0a0efSAxel Lin 	PM8607_DVC(BUCK2, GO, BIT(1), SUPPLIES_EN11, 1),
295c6f0a0efSAxel Lin 	PM8607_DVC(BUCK3, GO, BIT(2), SUPPLIES_EN11, 2),
296be0e2d3eSHaojian Zhuang 
29753b6949eSAxel Lin 	PM8607_LDO(1,         LDO1, 0, SUPPLIES_EN11, 3),
29853b6949eSAxel Lin 	PM8607_LDO(2,         LDO2, 0, SUPPLIES_EN11, 4),
29953b6949eSAxel Lin 	PM8607_LDO(3,         LDO3, 0, SUPPLIES_EN11, 5),
30053b6949eSAxel Lin 	PM8607_LDO(4,         LDO4, 0, SUPPLIES_EN11, 6),
30153b6949eSAxel Lin 	PM8607_LDO(5,         LDO5, 0, SUPPLIES_EN11, 7),
30253b6949eSAxel Lin 	PM8607_LDO(6,         LDO6, 0, SUPPLIES_EN12, 0),
30353b6949eSAxel Lin 	PM8607_LDO(7,         LDO7, 0, SUPPLIES_EN12, 1),
30453b6949eSAxel Lin 	PM8607_LDO(8,         LDO8, 0, SUPPLIES_EN12, 2),
30553b6949eSAxel Lin 	PM8607_LDO(9,         LDO9, 0, SUPPLIES_EN12, 3),
30653b6949eSAxel Lin 	PM8607_LDO(10,        LDO10, 0, SUPPLIES_EN12, 4),
30753b6949eSAxel Lin 	PM8607_LDO(12,        LDO12, 0, SUPPLIES_EN12, 5),
30853b6949eSAxel Lin 	PM8607_LDO(13, VIBRATOR_SET, 1, VIBRATOR_SET, 0),
30953b6949eSAxel Lin 	PM8607_LDO(14,        LDO14, 0, SUPPLIES_EN12, 6),
310ff13e9e2SHaojian Zhuang };
311e7a7810aSJett.Zhou 
312ff13e9e2SHaojian Zhuang static struct pm8607_regulator_info pm8606_regulator_info[] = {
313e7a7810aSJett.Zhou 	PM8606_PREG(PREREGULATORB, 5),
314be0e2d3eSHaojian Zhuang };
315be0e2d3eSHaojian Zhuang 
3162e57d567SHaojian Zhuang #ifdef CONFIG_OF
3172e57d567SHaojian Zhuang static int pm8607_regulator_dt_init(struct platform_device *pdev,
3182e57d567SHaojian Zhuang 				    struct pm8607_regulator_info *info,
3192e57d567SHaojian Zhuang 				    struct regulator_config *config)
3202e57d567SHaojian Zhuang {
3212e57d567SHaojian Zhuang 	struct device_node *nproot, *np;
322b8b27a44SGuodong Xu 	nproot = pdev->dev.parent->of_node;
3232e57d567SHaojian Zhuang 	if (!nproot)
3242e57d567SHaojian Zhuang 		return -ENODEV;
325ca1e3f33SSachin Kamat 	nproot = of_get_child_by_name(nproot, "regulators");
3262e57d567SHaojian Zhuang 	if (!nproot) {
3272e57d567SHaojian Zhuang 		dev_err(&pdev->dev, "failed to find regulators node\n");
3282e57d567SHaojian Zhuang 		return -ENODEV;
3292e57d567SHaojian Zhuang 	}
3302e57d567SHaojian Zhuang 	for_each_child_of_node(nproot, np) {
3312e57d567SHaojian Zhuang 		if (!of_node_cmp(np->name, info->desc.name)) {
3322e57d567SHaojian Zhuang 			config->init_data =
333072e78b1SJavier Martinez Canillas 				of_get_regulator_init_data(&pdev->dev, np,
334072e78b1SJavier Martinez Canillas 							   &info->desc);
3352e57d567SHaojian Zhuang 			config->of_node = np;
3362e57d567SHaojian Zhuang 			break;
3372e57d567SHaojian Zhuang 		}
3382e57d567SHaojian Zhuang 	}
339c92f5dd2SAxel Lin 	of_node_put(nproot);
3402e57d567SHaojian Zhuang 	return 0;
3412e57d567SHaojian Zhuang }
3422e57d567SHaojian Zhuang #else
3432e57d567SHaojian Zhuang #define pm8607_regulator_dt_init(x, y, z)	(-1)
3442e57d567SHaojian Zhuang #endif
3452e57d567SHaojian Zhuang 
346a5023574SBill Pemberton static int pm8607_regulator_probe(struct platform_device *pdev)
347be0e2d3eSHaojian Zhuang {
34853dbab7aSHaojian Zhuang 	struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
349be0e2d3eSHaojian Zhuang 	struct pm8607_regulator_info *info = NULL;
350dff91d0bSJingoo Han 	struct regulator_init_data *pdata = dev_get_platdata(&pdev->dev);
351c172708dSMark Brown 	struct regulator_config config = { };
352586e1a17SHaojian Zhuang 	struct resource *res;
35322aad001SHaojian Zhuang 	int i;
354be0e2d3eSHaojian Zhuang 
35502367029SMark Brown 	res = platform_get_resource(pdev, IORESOURCE_REG, 0);
356ff13e9e2SHaojian Zhuang 	if (res) {
357ff13e9e2SHaojian Zhuang 		/* There're resources in 88PM8607 regulator driver */
35822aad001SHaojian Zhuang 		for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) {
35922aad001SHaojian Zhuang 			info = &pm8607_regulator_info[i];
360a70abacbSHaojian Zhuang 			if (info->desc.vsel_reg == res->start)
36122aad001SHaojian Zhuang 				break;
36222aad001SHaojian Zhuang 		}
36399cd25ceSAxel Lin 		if (i == ARRAY_SIZE(pm8607_regulator_info)) {
36409969108SRandy Dunlap 			dev_err(&pdev->dev, "Failed to find regulator %llu\n",
36509969108SRandy Dunlap 				(unsigned long long)res->start);
366be0e2d3eSHaojian Zhuang 			return -EINVAL;
367be0e2d3eSHaojian Zhuang 		}
368ff13e9e2SHaojian Zhuang 	} else {
369ff13e9e2SHaojian Zhuang 		/* There's no resource in 88PM8606 PREG regulator driver */
370ff13e9e2SHaojian Zhuang 		info = &pm8606_regulator_info[0];
371ff13e9e2SHaojian Zhuang 		/* i is used to check regulator ID */
372ff13e9e2SHaojian Zhuang 		i = -1;
373ff13e9e2SHaojian Zhuang 	}
37453dbab7aSHaojian Zhuang 	info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
375e7a7810aSJett.Zhou 	info->i2c_8606 = (chip->id == CHIP_PM8607) ? chip->companion :
376e7a7810aSJett.Zhou 			chip->client;
377be0e2d3eSHaojian Zhuang 	info->chip = chip;
378be0e2d3eSHaojian Zhuang 
37922aad001SHaojian Zhuang 	/* check DVC ramp slope double */
380586e1a17SHaojian Zhuang 	if ((i == PM8607_ID_BUCK3) && info->chip->buck3_double)
38122aad001SHaojian Zhuang 		info->slope_double = 1;
38222aad001SHaojian Zhuang 
383c172708dSMark Brown 	config.dev = &pdev->dev;
384c172708dSMark Brown 	config.driver_data = info;
385c172708dSMark Brown 
3862e57d567SHaojian Zhuang 	if (pm8607_regulator_dt_init(pdev, info, &config))
3872e57d567SHaojian Zhuang 		if (pdata)
3882e57d567SHaojian Zhuang 			config.init_data = pdata;
3892e57d567SHaojian Zhuang 
390ef26e0dbSAxel Lin 	if (chip->id == CHIP_PM8607)
391ef26e0dbSAxel Lin 		config.regmap = chip->regmap;
392ef26e0dbSAxel Lin 	else
393ef26e0dbSAxel Lin 		config.regmap = chip->regmap_companion;
394ef26e0dbSAxel Lin 
395bcb5fe44SAxel Lin 	info->regulator = devm_regulator_register(&pdev->dev, &info->desc,
396bcb5fe44SAxel Lin 						  &config);
397be0e2d3eSHaojian Zhuang 	if (IS_ERR(info->regulator)) {
398be0e2d3eSHaojian Zhuang 		dev_err(&pdev->dev, "failed to register regulator %s\n",
399be0e2d3eSHaojian Zhuang 			info->desc.name);
400be0e2d3eSHaojian Zhuang 		return PTR_ERR(info->regulator);
401be0e2d3eSHaojian Zhuang 	}
402be0e2d3eSHaojian Zhuang 
403be0e2d3eSHaojian Zhuang 	platform_set_drvdata(pdev, info);
404be0e2d3eSHaojian Zhuang 	return 0;
405be0e2d3eSHaojian Zhuang }
406be0e2d3eSHaojian Zhuang 
4070cfeddbdSKrzysztof Kozlowski static const struct platform_device_id pm8607_regulator_driver_ids[] = {
408e7a7810aSJett.Zhou 	{
409e7a7810aSJett.Zhou 		.name	= "88pm860x-regulator",
410e7a7810aSJett.Zhou 		.driver_data	= 0,
411e7a7810aSJett.Zhou 	}, {
412e7a7810aSJett.Zhou 		.name	= "88pm860x-preg",
413e7a7810aSJett.Zhou 		.driver_data	= 0,
414e7a7810aSJett.Zhou 	},
415e7a7810aSJett.Zhou 	{ },
416e7a7810aSJett.Zhou };
417e7a7810aSJett.Zhou MODULE_DEVICE_TABLE(platform, pm8607_regulator_driver_ids);
418e7a7810aSJett.Zhou 
419192bbb95SHaojian Zhuang static struct platform_driver pm8607_regulator_driver = {
420192bbb95SHaojian Zhuang 	.driver		= {
421192bbb95SHaojian Zhuang 		.name	= "88pm860x-regulator",
422192bbb95SHaojian Zhuang 	},
423192bbb95SHaojian Zhuang 	.probe		= pm8607_regulator_probe,
424e7a7810aSJett.Zhou 	.id_table	= pm8607_regulator_driver_ids,
425be0e2d3eSHaojian Zhuang };
426be0e2d3eSHaojian Zhuang 
427be0e2d3eSHaojian Zhuang static int __init pm8607_regulator_init(void)
428be0e2d3eSHaojian Zhuang {
429192bbb95SHaojian Zhuang 	return platform_driver_register(&pm8607_regulator_driver);
430be0e2d3eSHaojian Zhuang }
431be0e2d3eSHaojian Zhuang subsys_initcall(pm8607_regulator_init);
432be0e2d3eSHaojian Zhuang 
433be0e2d3eSHaojian Zhuang static void __exit pm8607_regulator_exit(void)
434be0e2d3eSHaojian Zhuang {
435192bbb95SHaojian Zhuang 	platform_driver_unregister(&pm8607_regulator_driver);
436be0e2d3eSHaojian Zhuang }
437be0e2d3eSHaojian Zhuang module_exit(pm8607_regulator_exit);
438be0e2d3eSHaojian Zhuang 
439be0e2d3eSHaojian Zhuang MODULE_LICENSE("GPL");
440be0e2d3eSHaojian Zhuang MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
441be0e2d3eSHaojian Zhuang MODULE_DESCRIPTION("Regulator Driver for Marvell 88PM8607 PMIC");
442be0e2d3eSHaojian Zhuang MODULE_ALIAS("platform:88pm8607-regulator");
443