xref: /linux/drivers/regulator/88pm8607.c (revision a5023574d120ca3b9337cedd4e27de90cae9aff7)
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	update_reg;
34be0e2d3eSHaojian Zhuang 	int	update_bit;
35be0e2d3eSHaojian Zhuang 	int	slope_double;
36be0e2d3eSHaojian Zhuang };
37be0e2d3eSHaojian Zhuang 
389f79e9dbSHaojian Zhuang static const unsigned int BUCK1_table[] = {
399f79e9dbSHaojian Zhuang 	 725000,  750000,  775000,  800000,  825000,  850000,  875000,  900000,
409f79e9dbSHaojian Zhuang 	 925000,  950000,  975000, 1000000, 1025000, 1050000, 1075000, 1100000,
419f79e9dbSHaojian Zhuang 	1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000,
429f79e9dbSHaojian Zhuang 	1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000,
439f79e9dbSHaojian Zhuang 	      0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
449f79e9dbSHaojian Zhuang 	 200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
459f79e9dbSHaojian Zhuang 	 400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
469f79e9dbSHaojian Zhuang 	 600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
479f79e9dbSHaojian Zhuang };
48be0e2d3eSHaojian Zhuang 
499f79e9dbSHaojian Zhuang static const unsigned int BUCK1_suspend_table[] = {
509f79e9dbSHaojian Zhuang 	      0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
519f79e9dbSHaojian Zhuang 	 200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
529f79e9dbSHaojian Zhuang 	 400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
539f79e9dbSHaojian Zhuang 	 600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
549f79e9dbSHaojian Zhuang 	 800000,  825000,  850000,  875000,  900000,  925000,  950000,  975000,
559f79e9dbSHaojian Zhuang 	1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
569f79e9dbSHaojian Zhuang 	1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000,
579f79e9dbSHaojian Zhuang 	1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000,
589f79e9dbSHaojian Zhuang };
599f79e9dbSHaojian Zhuang 
609f79e9dbSHaojian Zhuang static const unsigned int BUCK2_table[] = {
619f79e9dbSHaojian Zhuang 	      0,   50000,  100000,  150000,  200000,  250000,  300000,  350000,
629f79e9dbSHaojian Zhuang 	 400000,  450000,  500000,  550000,  600000,  650000,  700000,  750000,
639f79e9dbSHaojian Zhuang 	 800000,  850000,  900000,  950000, 1000000, 1050000, 1100000, 1150000,
649f79e9dbSHaojian Zhuang 	1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1550000,
659f79e9dbSHaojian Zhuang 	1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 1950000,
669f79e9dbSHaojian Zhuang 	2000000, 2050000, 2100000, 2150000, 2200000, 2250000, 2300000, 2350000,
679f79e9dbSHaojian Zhuang 	2400000, 2450000, 2500000, 2550000, 2600000, 2650000, 2700000, 2750000,
689f79e9dbSHaojian Zhuang 	2800000, 2850000, 2900000, 2950000, 3000000, 3000000, 3000000, 3000000,
699f79e9dbSHaojian Zhuang };
709f79e9dbSHaojian Zhuang 
719f79e9dbSHaojian Zhuang static const unsigned int BUCK2_suspend_table[] = {
729f79e9dbSHaojian Zhuang 	      0,   50000,  100000,  150000,  200000,  250000,  300000,  350000,
739f79e9dbSHaojian Zhuang 	 400000,  450000,  500000,  550000,  600000,  650000,  700000,  750000,
749f79e9dbSHaojian Zhuang 	 800000,  850000,  900000,  950000, 1000000, 1050000, 1100000, 1150000,
759f79e9dbSHaojian Zhuang 	1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1550000,
769f79e9dbSHaojian Zhuang 	1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 1950000,
779f79e9dbSHaojian Zhuang 	2000000, 2050000, 2100000, 2150000, 2200000, 2250000, 2300000, 2350000,
789f79e9dbSHaojian Zhuang 	2400000, 2450000, 2500000, 2550000, 2600000, 2650000, 2700000, 2750000,
799f79e9dbSHaojian Zhuang 	2800000, 2850000, 2900000, 2950000, 3000000, 3000000, 3000000, 3000000,
809f79e9dbSHaojian Zhuang };
819f79e9dbSHaojian Zhuang 
829f79e9dbSHaojian Zhuang static const unsigned int BUCK3_table[] = {
839f79e9dbSHaojian Zhuang               0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
849f79e9dbSHaojian Zhuang 	 200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
859f79e9dbSHaojian Zhuang 	 400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
869f79e9dbSHaojian Zhuang 	 600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
879f79e9dbSHaojian Zhuang 	 800000,  825000,  850000,  875000,  900000,  925000,  950000,  975000,
889f79e9dbSHaojian Zhuang 	1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
899f79e9dbSHaojian Zhuang 	1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000,
909f79e9dbSHaojian Zhuang 	1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000,
919f79e9dbSHaojian Zhuang };
929f79e9dbSHaojian Zhuang 
939f79e9dbSHaojian Zhuang static const unsigned int BUCK3_suspend_table[] = {
949f79e9dbSHaojian Zhuang               0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
959f79e9dbSHaojian Zhuang 	 200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
969f79e9dbSHaojian Zhuang 	 400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
979f79e9dbSHaojian Zhuang 	 600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
989f79e9dbSHaojian Zhuang 	 800000,  825000,  850000,  875000,  900000,  925000,  950000,  975000,
999f79e9dbSHaojian Zhuang 	1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
1009f79e9dbSHaojian Zhuang 	1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000,
1019f79e9dbSHaojian Zhuang 	1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000,
1029f79e9dbSHaojian Zhuang };
1039f79e9dbSHaojian Zhuang 
1049f79e9dbSHaojian Zhuang static const unsigned int LDO1_table[] = {
1059f79e9dbSHaojian Zhuang 	1800000, 1200000, 2800000, 0,
1069f79e9dbSHaojian Zhuang };
1079f79e9dbSHaojian Zhuang 
1089f79e9dbSHaojian Zhuang static const unsigned int LDO1_suspend_table[] = {
1099f79e9dbSHaojian Zhuang 	1800000, 1200000, 0, 0,
1109f79e9dbSHaojian Zhuang };
1119f79e9dbSHaojian Zhuang 
1129f79e9dbSHaojian Zhuang static const unsigned int LDO2_table[] = {
1139f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
1149f79e9dbSHaojian Zhuang };
1159f79e9dbSHaojian Zhuang 
1169f79e9dbSHaojian Zhuang static const unsigned int LDO2_suspend_table[] = {
1179f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
1189f79e9dbSHaojian Zhuang };
1199f79e9dbSHaojian Zhuang 
1209f79e9dbSHaojian Zhuang static const unsigned int LDO3_table[] = {
1219f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
1229f79e9dbSHaojian Zhuang };
1239f79e9dbSHaojian Zhuang 
1249f79e9dbSHaojian Zhuang static const unsigned int LDO3_suspend_table[] = {
1259f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
1269f79e9dbSHaojian Zhuang };
1279f79e9dbSHaojian Zhuang 
1289f79e9dbSHaojian Zhuang static const unsigned int LDO4_table[] = {
1299f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2900000, 3300000,
1309f79e9dbSHaojian Zhuang };
1319f79e9dbSHaojian Zhuang 
1329f79e9dbSHaojian Zhuang static const unsigned int LDO4_suspend_table[] = {
1339f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2900000, 2900000,
1349f79e9dbSHaojian Zhuang };
1359f79e9dbSHaojian Zhuang 
1369f79e9dbSHaojian Zhuang static const unsigned int LDO5_table[] = {
1379f79e9dbSHaojian Zhuang 	2900000, 3000000, 3100000, 3300000,
1389f79e9dbSHaojian Zhuang };
1399f79e9dbSHaojian Zhuang 
1409f79e9dbSHaojian Zhuang static const unsigned int LDO5_suspend_table[] = {
1419f79e9dbSHaojian Zhuang 	2900000, 0, 0, 0,
1429f79e9dbSHaojian Zhuang };
1439f79e9dbSHaojian Zhuang 
1449f79e9dbSHaojian Zhuang static const unsigned int LDO6_table[] = {
1459f79e9dbSHaojian Zhuang 	1800000, 1850000, 2600000, 2650000, 2700000, 2750000, 2800000, 3300000,
1469f79e9dbSHaojian Zhuang };
1479f79e9dbSHaojian Zhuang 
1489f79e9dbSHaojian Zhuang static const unsigned int LDO6_suspend_table[] = {
1499f79e9dbSHaojian Zhuang 	1800000, 1850000, 2600000, 2650000, 2700000, 2750000, 2800000, 2900000,
1509f79e9dbSHaojian Zhuang };
1519f79e9dbSHaojian Zhuang 
1529f79e9dbSHaojian Zhuang static const unsigned int LDO7_table[] = {
1539f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
1549f79e9dbSHaojian Zhuang };
1559f79e9dbSHaojian Zhuang 
1569f79e9dbSHaojian Zhuang static const unsigned int LDO7_suspend_table[] = {
1579f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
1589f79e9dbSHaojian Zhuang };
1599f79e9dbSHaojian Zhuang 
1609f79e9dbSHaojian Zhuang static const unsigned int LDO8_table[] = {
1619f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
1629f79e9dbSHaojian Zhuang };
1639f79e9dbSHaojian Zhuang 
1649f79e9dbSHaojian Zhuang static const unsigned int LDO8_suspend_table[] = {
1659f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
1669f79e9dbSHaojian Zhuang };
1679f79e9dbSHaojian Zhuang 
1689f79e9dbSHaojian Zhuang static const unsigned int LDO9_table[] = {
1699f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
1709f79e9dbSHaojian Zhuang };
1719f79e9dbSHaojian Zhuang 
1729f79e9dbSHaojian Zhuang static const unsigned int LDO9_suspend_table[] = {
1739f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
1749f79e9dbSHaojian Zhuang };
1759f79e9dbSHaojian Zhuang 
1769f79e9dbSHaojian Zhuang static const unsigned int LDO10_table[] = {
1779f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
1789f79e9dbSHaojian Zhuang 	1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
1799f79e9dbSHaojian Zhuang };
1809f79e9dbSHaojian Zhuang 
1819f79e9dbSHaojian Zhuang static const unsigned int LDO10_suspend_table[] = {
1829f79e9dbSHaojian Zhuang 	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
1839f79e9dbSHaojian Zhuang 	1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
1849f79e9dbSHaojian Zhuang };
1859f79e9dbSHaojian Zhuang 
1869f79e9dbSHaojian Zhuang static const unsigned int LDO12_table[] = {
1879f79e9dbSHaojian Zhuang 	1800000, 1900000, 2700000, 2800000, 2900000, 3000000, 3100000, 3300000,
1889f79e9dbSHaojian Zhuang 	1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
1899f79e9dbSHaojian Zhuang };
1909f79e9dbSHaojian Zhuang 
1919f79e9dbSHaojian Zhuang static const unsigned int LDO12_suspend_table[] = {
1929f79e9dbSHaojian Zhuang 	1800000, 1900000, 2700000, 2800000, 2900000, 2900000, 2900000, 2900000,
1939f79e9dbSHaojian Zhuang 	1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
1949f79e9dbSHaojian Zhuang };
1959f79e9dbSHaojian Zhuang 
1969f79e9dbSHaojian Zhuang static const unsigned int LDO13_table[] = {
1973380643bSJett.Zhou 	1200000, 1300000, 1800000, 2000000, 2500000, 2800000, 3000000, 0,
1989f79e9dbSHaojian Zhuang };
1999f79e9dbSHaojian Zhuang 
2009f79e9dbSHaojian Zhuang static const unsigned int LDO13_suspend_table[] = {
2019f79e9dbSHaojian Zhuang 	0,
2029f79e9dbSHaojian Zhuang };
2039f79e9dbSHaojian Zhuang 
2049f79e9dbSHaojian Zhuang static const unsigned int LDO14_table[] = {
2059f79e9dbSHaojian Zhuang 	1800000, 1850000, 2700000, 2750000, 2800000, 2850000, 2900000, 3300000,
2069f79e9dbSHaojian Zhuang };
2079f79e9dbSHaojian Zhuang 
2089f79e9dbSHaojian Zhuang static const unsigned int LDO14_suspend_table[] = {
2099f79e9dbSHaojian Zhuang 	1800000, 1850000, 2700000, 2750000, 2800000, 2850000, 2900000, 2900000,
2109f79e9dbSHaojian Zhuang };
211be0e2d3eSHaojian Zhuang 
212be0e2d3eSHaojian Zhuang static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index)
213be0e2d3eSHaojian Zhuang {
214be0e2d3eSHaojian Zhuang 	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
215be0e2d3eSHaojian Zhuang 	int ret = -EINVAL;
216be0e2d3eSHaojian Zhuang 
21753b6949eSAxel Lin 	if (info->vol_table && (index < rdev->desc->n_voltages)) {
2189f79e9dbSHaojian Zhuang 		ret = info->vol_table[index];
219be0e2d3eSHaojian Zhuang 		if (info->slope_double)
220be0e2d3eSHaojian Zhuang 			ret <<= 1;
221be0e2d3eSHaojian Zhuang 	}
222be0e2d3eSHaojian Zhuang 	return ret;
223be0e2d3eSHaojian Zhuang }
224be0e2d3eSHaojian Zhuang 
2254ca1e1d9SAxel Lin static int pm8607_set_voltage_sel(struct regulator_dev *rdev, unsigned selector)
226be0e2d3eSHaojian Zhuang {
227be0e2d3eSHaojian Zhuang 	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
228c006b21fSAxel Lin 	uint8_t val;
229be0e2d3eSHaojian Zhuang 	int ret;
230be0e2d3eSHaojian Zhuang 
231c006b21fSAxel Lin 	val = (uint8_t)(selector << (ffs(rdev->desc->vsel_mask) - 1));
232be0e2d3eSHaojian Zhuang 
233c006b21fSAxel Lin 	ret = pm860x_set_bits(info->i2c, rdev->desc->vsel_reg,
234c006b21fSAxel Lin 			      rdev->desc->vsel_mask, val);
235be0e2d3eSHaojian Zhuang 	if (ret)
236be0e2d3eSHaojian Zhuang 		return ret;
237be0e2d3eSHaojian Zhuang 	switch (info->desc.id) {
238be0e2d3eSHaojian Zhuang 	case PM8607_ID_BUCK1:
239be0e2d3eSHaojian Zhuang 	case PM8607_ID_BUCK3:
24053dbab7aSHaojian Zhuang 		ret = pm860x_set_bits(info->i2c, info->update_reg,
241be0e2d3eSHaojian Zhuang 				      1 << info->update_bit,
242be0e2d3eSHaojian Zhuang 				      1 << info->update_bit);
243be0e2d3eSHaojian Zhuang 		break;
244be0e2d3eSHaojian Zhuang 	}
245be0e2d3eSHaojian Zhuang 	return ret;
246be0e2d3eSHaojian Zhuang }
247be0e2d3eSHaojian Zhuang 
248e7a7810aSJett.Zhou static int pm8606_preg_enable(struct regulator_dev *rdev)
249e7a7810aSJett.Zhou {
250e7a7810aSJett.Zhou 	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
251e7a7810aSJett.Zhou 
252e7a7810aSJett.Zhou 	return pm860x_set_bits(info->i2c, rdev->desc->enable_reg,
253e7a7810aSJett.Zhou 			       1 << rdev->desc->enable_mask, 0);
254e7a7810aSJett.Zhou }
255e7a7810aSJett.Zhou 
256e7a7810aSJett.Zhou static int pm8606_preg_disable(struct regulator_dev *rdev)
257e7a7810aSJett.Zhou {
258e7a7810aSJett.Zhou 	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
259e7a7810aSJett.Zhou 
260e7a7810aSJett.Zhou 	return pm860x_set_bits(info->i2c, rdev->desc->enable_reg,
261e7a7810aSJett.Zhou 			       1 << rdev->desc->enable_mask,
262e7a7810aSJett.Zhou 			       1 << rdev->desc->enable_mask);
263e7a7810aSJett.Zhou }
264e7a7810aSJett.Zhou 
265e7a7810aSJett.Zhou static int pm8606_preg_is_enabled(struct regulator_dev *rdev)
266e7a7810aSJett.Zhou {
267e7a7810aSJett.Zhou 	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
268e7a7810aSJett.Zhou 	int ret;
269e7a7810aSJett.Zhou 
270e7a7810aSJett.Zhou 	ret = pm860x_reg_read(info->i2c, rdev->desc->enable_reg);
271e7a7810aSJett.Zhou 	if (ret < 0)
272e7a7810aSJett.Zhou 		return ret;
273e7a7810aSJett.Zhou 
274e7a7810aSJett.Zhou 	return !((unsigned char)ret & (1 << rdev->desc->enable_mask));
275e7a7810aSJett.Zhou }
276e7a7810aSJett.Zhou 
277be0e2d3eSHaojian Zhuang static struct regulator_ops pm8607_regulator_ops = {
278d3d7bcccSAxel Lin 	.list_voltage	= pm8607_list_voltage,
2794ca1e1d9SAxel Lin 	.set_voltage_sel = pm8607_set_voltage_sel,
280c006b21fSAxel Lin 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
281ef26e0dbSAxel Lin 	.enable = regulator_enable_regmap,
282ef26e0dbSAxel Lin 	.disable = regulator_disable_regmap,
283ef26e0dbSAxel Lin 	.is_enabled = regulator_is_enabled_regmap,
284be0e2d3eSHaojian Zhuang };
285be0e2d3eSHaojian Zhuang 
286e7a7810aSJett.Zhou static struct regulator_ops pm8606_preg_ops = {
287e7a7810aSJett.Zhou 	.enable		= pm8606_preg_enable,
288e7a7810aSJett.Zhou 	.disable	= pm8606_preg_disable,
289e7a7810aSJett.Zhou 	.is_enabled	= pm8606_preg_is_enabled,
290e7a7810aSJett.Zhou };
291e7a7810aSJett.Zhou 
292e7a7810aSJett.Zhou #define PM8606_PREG(ereg, ebit)						\
293e7a7810aSJett.Zhou {									\
294e7a7810aSJett.Zhou 	.desc	= {							\
295e7a7810aSJett.Zhou 		.name	= "PREG",					\
296e7a7810aSJett.Zhou 		.ops	= &pm8606_preg_ops,				\
297e7a7810aSJett.Zhou 		.type	= REGULATOR_CURRENT,				\
298e7a7810aSJett.Zhou 		.id	= PM8606_ID_PREG,				\
299e7a7810aSJett.Zhou 		.owner	= THIS_MODULE,					\
300e7a7810aSJett.Zhou 		.enable_reg = PM8606_##ereg,				\
301e7a7810aSJett.Zhou 		.enable_mask = (ebit),					\
302e7a7810aSJett.Zhou 	},								\
303e7a7810aSJett.Zhou }
304e7a7810aSJett.Zhou 
30553b6949eSAxel Lin #define PM8607_DVC(vreg, ureg, ubit, ereg, ebit)			\
306be0e2d3eSHaojian Zhuang {									\
307be0e2d3eSHaojian Zhuang 	.desc	= {							\
3089f79e9dbSHaojian Zhuang 		.name	= #vreg,					\
309be0e2d3eSHaojian Zhuang 		.ops	= &pm8607_regulator_ops,			\
310be0e2d3eSHaojian Zhuang 		.type	= REGULATOR_VOLTAGE,				\
3119f79e9dbSHaojian Zhuang 		.id	= PM8607_ID_##vreg,				\
312be0e2d3eSHaojian Zhuang 		.owner	= THIS_MODULE,					\
31353b6949eSAxel Lin 		.n_voltages = ARRAY_SIZE(vreg##_table),			\
314c006b21fSAxel Lin 		.vsel_reg = PM8607_##vreg,				\
315c006b21fSAxel Lin 		.vsel_mask = ARRAY_SIZE(vreg##_table) - 1,		\
316ef26e0dbSAxel Lin 		.enable_reg = PM8607_##ereg,				\
317ef26e0dbSAxel Lin 		.enable_mask = 1 << (ebit),				\
318be0e2d3eSHaojian Zhuang 	},								\
319be0e2d3eSHaojian Zhuang 	.update_reg	= PM8607_##ureg,				\
320be0e2d3eSHaojian Zhuang 	.update_bit	= (ubit),					\
321be0e2d3eSHaojian Zhuang 	.slope_double	= (0),						\
3229f79e9dbSHaojian Zhuang 	.vol_table	= (unsigned int *)&vreg##_table,		\
3239f79e9dbSHaojian Zhuang 	.vol_suspend	= (unsigned int *)&vreg##_suspend_table,	\
324be0e2d3eSHaojian Zhuang }
325be0e2d3eSHaojian Zhuang 
32653b6949eSAxel Lin #define PM8607_LDO(_id, vreg, shift, ereg, ebit)			\
327be0e2d3eSHaojian Zhuang {									\
328be0e2d3eSHaojian Zhuang 	.desc	= {							\
329be0e2d3eSHaojian Zhuang 		.name	= "LDO" #_id,					\
330be0e2d3eSHaojian Zhuang 		.ops	= &pm8607_regulator_ops,			\
331be0e2d3eSHaojian Zhuang 		.type	= REGULATOR_VOLTAGE,				\
332be0e2d3eSHaojian Zhuang 		.id	= PM8607_ID_LDO##_id,				\
333be0e2d3eSHaojian Zhuang 		.owner	= THIS_MODULE,					\
33453b6949eSAxel Lin 		.n_voltages = ARRAY_SIZE(LDO##_id##_table),		\
335c006b21fSAxel Lin 		.vsel_reg = PM8607_##vreg,				\
336c006b21fSAxel Lin 		.vsel_mask = (ARRAY_SIZE(LDO##_id##_table) - 1) << (shift), \
337ef26e0dbSAxel Lin 		.enable_reg = PM8607_##ereg,				\
338ef26e0dbSAxel Lin 		.enable_mask = 1 << (ebit),				\
339be0e2d3eSHaojian Zhuang 	},								\
340be0e2d3eSHaojian Zhuang 	.slope_double	= (0),						\
3419f79e9dbSHaojian Zhuang 	.vol_table	= (unsigned int *)&LDO##_id##_table,		\
3429f79e9dbSHaojian Zhuang 	.vol_suspend	= (unsigned int *)&LDO##_id##_suspend_table,	\
343be0e2d3eSHaojian Zhuang }
344be0e2d3eSHaojian Zhuang 
345be0e2d3eSHaojian Zhuang static struct pm8607_regulator_info pm8607_regulator_info[] = {
34653b6949eSAxel Lin 	PM8607_DVC(BUCK1, GO, 0, SUPPLIES_EN11, 0),
34753b6949eSAxel Lin 	PM8607_DVC(BUCK2, GO, 1, SUPPLIES_EN11, 1),
34853b6949eSAxel Lin 	PM8607_DVC(BUCK3, GO, 2, SUPPLIES_EN11, 2),
349be0e2d3eSHaojian Zhuang 
35053b6949eSAxel Lin 	PM8607_LDO(1,         LDO1, 0, SUPPLIES_EN11, 3),
35153b6949eSAxel Lin 	PM8607_LDO(2,         LDO2, 0, SUPPLIES_EN11, 4),
35253b6949eSAxel Lin 	PM8607_LDO(3,         LDO3, 0, SUPPLIES_EN11, 5),
35353b6949eSAxel Lin 	PM8607_LDO(4,         LDO4, 0, SUPPLIES_EN11, 6),
35453b6949eSAxel Lin 	PM8607_LDO(5,         LDO5, 0, SUPPLIES_EN11, 7),
35553b6949eSAxel Lin 	PM8607_LDO(6,         LDO6, 0, SUPPLIES_EN12, 0),
35653b6949eSAxel Lin 	PM8607_LDO(7,         LDO7, 0, SUPPLIES_EN12, 1),
35753b6949eSAxel Lin 	PM8607_LDO(8,         LDO8, 0, SUPPLIES_EN12, 2),
35853b6949eSAxel Lin 	PM8607_LDO(9,         LDO9, 0, SUPPLIES_EN12, 3),
35953b6949eSAxel Lin 	PM8607_LDO(10,        LDO10, 0, SUPPLIES_EN12, 4),
36053b6949eSAxel Lin 	PM8607_LDO(12,        LDO12, 0, SUPPLIES_EN12, 5),
36153b6949eSAxel Lin 	PM8607_LDO(13, VIBRATOR_SET, 1, VIBRATOR_SET, 0),
36253b6949eSAxel Lin 	PM8607_LDO(14,        LDO14, 0, SUPPLIES_EN12, 6),
363ff13e9e2SHaojian Zhuang };
364e7a7810aSJett.Zhou 
365ff13e9e2SHaojian Zhuang static struct pm8607_regulator_info pm8606_regulator_info[] = {
366e7a7810aSJett.Zhou 	PM8606_PREG(PREREGULATORB, 5),
367be0e2d3eSHaojian Zhuang };
368be0e2d3eSHaojian Zhuang 
3692e57d567SHaojian Zhuang #ifdef CONFIG_OF
3702e57d567SHaojian Zhuang static int pm8607_regulator_dt_init(struct platform_device *pdev,
3712e57d567SHaojian Zhuang 				    struct pm8607_regulator_info *info,
3722e57d567SHaojian Zhuang 				    struct regulator_config *config)
3732e57d567SHaojian Zhuang {
3742e57d567SHaojian Zhuang 	struct device_node *nproot, *np;
3752e57d567SHaojian Zhuang 	nproot = pdev->dev.parent->of_node;
3762e57d567SHaojian Zhuang 	if (!nproot)
3772e57d567SHaojian Zhuang 		return -ENODEV;
3782e57d567SHaojian Zhuang 	nproot = of_find_node_by_name(nproot, "regulators");
3792e57d567SHaojian Zhuang 	if (!nproot) {
3802e57d567SHaojian Zhuang 		dev_err(&pdev->dev, "failed to find regulators node\n");
3812e57d567SHaojian Zhuang 		return -ENODEV;
3822e57d567SHaojian Zhuang 	}
3832e57d567SHaojian Zhuang 	for_each_child_of_node(nproot, np) {
3842e57d567SHaojian Zhuang 		if (!of_node_cmp(np->name, info->desc.name)) {
3852e57d567SHaojian Zhuang 			config->init_data =
3862e57d567SHaojian Zhuang 				of_get_regulator_init_data(&pdev->dev, np);
3872e57d567SHaojian Zhuang 			config->of_node = np;
3882e57d567SHaojian Zhuang 			break;
3892e57d567SHaojian Zhuang 		}
3902e57d567SHaojian Zhuang 	}
3912e57d567SHaojian Zhuang 	return 0;
3922e57d567SHaojian Zhuang }
3932e57d567SHaojian Zhuang #else
3942e57d567SHaojian Zhuang #define pm8607_regulator_dt_init(x, y, z)	(-1)
3952e57d567SHaojian Zhuang #endif
3962e57d567SHaojian Zhuang 
397*a5023574SBill Pemberton static int pm8607_regulator_probe(struct platform_device *pdev)
398be0e2d3eSHaojian Zhuang {
39953dbab7aSHaojian Zhuang 	struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
400be0e2d3eSHaojian Zhuang 	struct pm8607_regulator_info *info = NULL;
401586e1a17SHaojian Zhuang 	struct regulator_init_data *pdata = pdev->dev.platform_data;
402c172708dSMark Brown 	struct regulator_config config = { };
403586e1a17SHaojian Zhuang 	struct resource *res;
40422aad001SHaojian Zhuang 	int i;
405be0e2d3eSHaojian Zhuang 
40602367029SMark Brown 	res = platform_get_resource(pdev, IORESOURCE_REG, 0);
407ff13e9e2SHaojian Zhuang 	if (res) {
408ff13e9e2SHaojian Zhuang 		/* There're resources in 88PM8607 regulator driver */
40922aad001SHaojian Zhuang 		for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) {
41022aad001SHaojian Zhuang 			info = &pm8607_regulator_info[i];
411a70abacbSHaojian Zhuang 			if (info->desc.vsel_reg == res->start)
41222aad001SHaojian Zhuang 				break;
41322aad001SHaojian Zhuang 		}
41499cd25ceSAxel Lin 		if (i == ARRAY_SIZE(pm8607_regulator_info)) {
41509969108SRandy Dunlap 			dev_err(&pdev->dev, "Failed to find regulator %llu\n",
41609969108SRandy Dunlap 				(unsigned long long)res->start);
417be0e2d3eSHaojian Zhuang 			return -EINVAL;
418be0e2d3eSHaojian Zhuang 		}
419ff13e9e2SHaojian Zhuang 	} else {
420ff13e9e2SHaojian Zhuang 		/* There's no resource in 88PM8606 PREG regulator driver */
421ff13e9e2SHaojian Zhuang 		info = &pm8606_regulator_info[0];
422ff13e9e2SHaojian Zhuang 		/* i is used to check regulator ID */
423ff13e9e2SHaojian Zhuang 		i = -1;
424ff13e9e2SHaojian Zhuang 	}
42553dbab7aSHaojian Zhuang 	info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
426e7a7810aSJett.Zhou 	info->i2c_8606 = (chip->id == CHIP_PM8607) ? chip->companion :
427e7a7810aSJett.Zhou 			chip->client;
428be0e2d3eSHaojian Zhuang 	info->chip = chip;
429be0e2d3eSHaojian Zhuang 
43022aad001SHaojian Zhuang 	/* check DVC ramp slope double */
431586e1a17SHaojian Zhuang 	if ((i == PM8607_ID_BUCK3) && info->chip->buck3_double)
43222aad001SHaojian Zhuang 		info->slope_double = 1;
43322aad001SHaojian Zhuang 
434c172708dSMark Brown 	config.dev = &pdev->dev;
435c172708dSMark Brown 	config.driver_data = info;
436c172708dSMark Brown 
4372e57d567SHaojian Zhuang 	if (pm8607_regulator_dt_init(pdev, info, &config))
4382e57d567SHaojian Zhuang 		if (pdata)
4392e57d567SHaojian Zhuang 			config.init_data = pdata;
4402e57d567SHaojian Zhuang 
441ef26e0dbSAxel Lin 	if (chip->id == CHIP_PM8607)
442ef26e0dbSAxel Lin 		config.regmap = chip->regmap;
443ef26e0dbSAxel Lin 	else
444ef26e0dbSAxel Lin 		config.regmap = chip->regmap_companion;
445ef26e0dbSAxel Lin 
446c172708dSMark Brown 	info->regulator = regulator_register(&info->desc, &config);
447be0e2d3eSHaojian Zhuang 	if (IS_ERR(info->regulator)) {
448be0e2d3eSHaojian Zhuang 		dev_err(&pdev->dev, "failed to register regulator %s\n",
449be0e2d3eSHaojian Zhuang 			info->desc.name);
450be0e2d3eSHaojian Zhuang 		return PTR_ERR(info->regulator);
451be0e2d3eSHaojian Zhuang 	}
452be0e2d3eSHaojian Zhuang 
453be0e2d3eSHaojian Zhuang 	platform_set_drvdata(pdev, info);
454be0e2d3eSHaojian Zhuang 	return 0;
455be0e2d3eSHaojian Zhuang }
456be0e2d3eSHaojian Zhuang 
457be0e2d3eSHaojian Zhuang static int __devexit pm8607_regulator_remove(struct platform_device *pdev)
458be0e2d3eSHaojian Zhuang {
459be0e2d3eSHaojian Zhuang 	struct pm8607_regulator_info *info = platform_get_drvdata(pdev);
460be0e2d3eSHaojian Zhuang 
461192bbb95SHaojian Zhuang 	platform_set_drvdata(pdev, NULL);
462be0e2d3eSHaojian Zhuang 	regulator_unregister(info->regulator);
463be0e2d3eSHaojian Zhuang 	return 0;
464be0e2d3eSHaojian Zhuang }
465be0e2d3eSHaojian Zhuang 
466e7a7810aSJett.Zhou static struct platform_device_id pm8607_regulator_driver_ids[] = {
467e7a7810aSJett.Zhou 	{
468e7a7810aSJett.Zhou 		.name	= "88pm860x-regulator",
469e7a7810aSJett.Zhou 		.driver_data	= 0,
470e7a7810aSJett.Zhou 	}, {
471e7a7810aSJett.Zhou 		.name	= "88pm860x-preg",
472e7a7810aSJett.Zhou 		.driver_data	= 0,
473e7a7810aSJett.Zhou 	},
474e7a7810aSJett.Zhou 	{ },
475e7a7810aSJett.Zhou };
476e7a7810aSJett.Zhou MODULE_DEVICE_TABLE(platform, pm8607_regulator_driver_ids);
477e7a7810aSJett.Zhou 
478192bbb95SHaojian Zhuang static struct platform_driver pm8607_regulator_driver = {
479192bbb95SHaojian Zhuang 	.driver		= {
480192bbb95SHaojian Zhuang 		.name	= "88pm860x-regulator",
481192bbb95SHaojian Zhuang 		.owner	= THIS_MODULE,
482192bbb95SHaojian Zhuang 	},
483192bbb95SHaojian Zhuang 	.probe		= pm8607_regulator_probe,
4845eb9f2b9SBill Pemberton 	.remove		= pm8607_regulator_remove,
485e7a7810aSJett.Zhou 	.id_table	= pm8607_regulator_driver_ids,
486be0e2d3eSHaojian Zhuang };
487be0e2d3eSHaojian Zhuang 
488be0e2d3eSHaojian Zhuang static int __init pm8607_regulator_init(void)
489be0e2d3eSHaojian Zhuang {
490192bbb95SHaojian Zhuang 	return platform_driver_register(&pm8607_regulator_driver);
491be0e2d3eSHaojian Zhuang }
492be0e2d3eSHaojian Zhuang subsys_initcall(pm8607_regulator_init);
493be0e2d3eSHaojian Zhuang 
494be0e2d3eSHaojian Zhuang static void __exit pm8607_regulator_exit(void)
495be0e2d3eSHaojian Zhuang {
496192bbb95SHaojian Zhuang 	platform_driver_unregister(&pm8607_regulator_driver);
497be0e2d3eSHaojian Zhuang }
498be0e2d3eSHaojian Zhuang module_exit(pm8607_regulator_exit);
499be0e2d3eSHaojian Zhuang 
500be0e2d3eSHaojian Zhuang MODULE_LICENSE("GPL");
501be0e2d3eSHaojian Zhuang MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
502be0e2d3eSHaojian Zhuang MODULE_DESCRIPTION("Regulator Driver for Marvell 88PM8607 PMIC");
503be0e2d3eSHaojian Zhuang MODULE_ALIAS("platform:88pm8607-regulator");
504