xref: /linux/drivers/regulator/88pm8607.c (revision e7a7810ae08bfca5cb2cad8a8d55c16f299cc3fe)
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;
26*e7a7810aSJett.Zhou 	struct i2c_client	*i2c_8606;
27be0e2d3eSHaojian Zhuang 
289f79e9dbSHaojian Zhuang 	unsigned int	*vol_table;
299f79e9dbSHaojian Zhuang 	unsigned int	*vol_suspend;
309f79e9dbSHaojian Zhuang 
31be0e2d3eSHaojian Zhuang 	int	update_reg;
32be0e2d3eSHaojian Zhuang 	int	update_bit;
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 
2234ca1e1d9SAxel Lin static int pm8607_set_voltage_sel(struct regulator_dev *rdev, unsigned selector)
224be0e2d3eSHaojian Zhuang {
225be0e2d3eSHaojian Zhuang 	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
226c006b21fSAxel Lin 	uint8_t val;
227be0e2d3eSHaojian Zhuang 	int ret;
228be0e2d3eSHaojian Zhuang 
229c006b21fSAxel Lin 	val = (uint8_t)(selector << (ffs(rdev->desc->vsel_mask) - 1));
230be0e2d3eSHaojian Zhuang 
231c006b21fSAxel Lin 	ret = pm860x_set_bits(info->i2c, rdev->desc->vsel_reg,
232c006b21fSAxel Lin 			      rdev->desc->vsel_mask, val);
233be0e2d3eSHaojian Zhuang 	if (ret)
234be0e2d3eSHaojian Zhuang 		return ret;
235be0e2d3eSHaojian Zhuang 	switch (info->desc.id) {
236be0e2d3eSHaojian Zhuang 	case PM8607_ID_BUCK1:
237be0e2d3eSHaojian Zhuang 	case PM8607_ID_BUCK3:
23853dbab7aSHaojian Zhuang 		ret = pm860x_set_bits(info->i2c, info->update_reg,
239be0e2d3eSHaojian Zhuang 				      1 << info->update_bit,
240be0e2d3eSHaojian Zhuang 				      1 << info->update_bit);
241be0e2d3eSHaojian Zhuang 		break;
242be0e2d3eSHaojian Zhuang 	}
243be0e2d3eSHaojian Zhuang 	return ret;
244be0e2d3eSHaojian Zhuang }
245be0e2d3eSHaojian Zhuang 
246*e7a7810aSJett.Zhou static int pm8606_preg_enable(struct regulator_dev *rdev)
247*e7a7810aSJett.Zhou {
248*e7a7810aSJett.Zhou 	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
249*e7a7810aSJett.Zhou 
250*e7a7810aSJett.Zhou 	return pm860x_set_bits(info->i2c, rdev->desc->enable_reg,
251*e7a7810aSJett.Zhou 			       1 << rdev->desc->enable_mask, 0);
252*e7a7810aSJett.Zhou }
253*e7a7810aSJett.Zhou 
254*e7a7810aSJett.Zhou static int pm8606_preg_disable(struct regulator_dev *rdev)
255*e7a7810aSJett.Zhou {
256*e7a7810aSJett.Zhou 	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
257*e7a7810aSJett.Zhou 
258*e7a7810aSJett.Zhou 	return pm860x_set_bits(info->i2c, rdev->desc->enable_reg,
259*e7a7810aSJett.Zhou 			       1 << rdev->desc->enable_mask,
260*e7a7810aSJett.Zhou 			       1 << rdev->desc->enable_mask);
261*e7a7810aSJett.Zhou }
262*e7a7810aSJett.Zhou 
263*e7a7810aSJett.Zhou static int pm8606_preg_is_enabled(struct regulator_dev *rdev)
264*e7a7810aSJett.Zhou {
265*e7a7810aSJett.Zhou 	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
266*e7a7810aSJett.Zhou 	int ret;
267*e7a7810aSJett.Zhou 
268*e7a7810aSJett.Zhou 	ret = pm860x_reg_read(info->i2c, rdev->desc->enable_reg);
269*e7a7810aSJett.Zhou 	if (ret < 0)
270*e7a7810aSJett.Zhou 		return ret;
271*e7a7810aSJett.Zhou 
272*e7a7810aSJett.Zhou 	return !((unsigned char)ret & (1 << rdev->desc->enable_mask));
273*e7a7810aSJett.Zhou }
274*e7a7810aSJett.Zhou 
275be0e2d3eSHaojian Zhuang static struct regulator_ops pm8607_regulator_ops = {
276d3d7bcccSAxel Lin 	.list_voltage	= pm8607_list_voltage,
2774ca1e1d9SAxel Lin 	.set_voltage_sel = pm8607_set_voltage_sel,
278c006b21fSAxel Lin 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
279ef26e0dbSAxel Lin 	.enable = regulator_enable_regmap,
280ef26e0dbSAxel Lin 	.disable = regulator_disable_regmap,
281ef26e0dbSAxel Lin 	.is_enabled = regulator_is_enabled_regmap,
282be0e2d3eSHaojian Zhuang };
283be0e2d3eSHaojian Zhuang 
284*e7a7810aSJett.Zhou static struct regulator_ops pm8606_preg_ops = {
285*e7a7810aSJett.Zhou 	.enable		= pm8606_preg_enable,
286*e7a7810aSJett.Zhou 	.disable	= pm8606_preg_disable,
287*e7a7810aSJett.Zhou 	.is_enabled	= pm8606_preg_is_enabled,
288*e7a7810aSJett.Zhou };
289*e7a7810aSJett.Zhou 
290*e7a7810aSJett.Zhou #define PM8606_PREG(ereg, ebit)						\
291*e7a7810aSJett.Zhou {									\
292*e7a7810aSJett.Zhou 	.desc	= {							\
293*e7a7810aSJett.Zhou 		.name	= "PREG",					\
294*e7a7810aSJett.Zhou 		.ops	= &pm8606_preg_ops,				\
295*e7a7810aSJett.Zhou 		.type	= REGULATOR_CURRENT,				\
296*e7a7810aSJett.Zhou 		.id	= PM8606_ID_PREG,				\
297*e7a7810aSJett.Zhou 		.owner	= THIS_MODULE,					\
298*e7a7810aSJett.Zhou 		.enable_reg = PM8606_##ereg,				\
299*e7a7810aSJett.Zhou 		.enable_mask = (ebit),					\
300*e7a7810aSJett.Zhou 	},								\
301*e7a7810aSJett.Zhou }
302*e7a7810aSJett.Zhou 
30353b6949eSAxel Lin #define PM8607_DVC(vreg, ureg, ubit, ereg, ebit)			\
304be0e2d3eSHaojian Zhuang {									\
305be0e2d3eSHaojian Zhuang 	.desc	= {							\
3069f79e9dbSHaojian Zhuang 		.name	= #vreg,					\
307be0e2d3eSHaojian Zhuang 		.ops	= &pm8607_regulator_ops,			\
308be0e2d3eSHaojian Zhuang 		.type	= REGULATOR_VOLTAGE,				\
3099f79e9dbSHaojian Zhuang 		.id	= PM8607_ID_##vreg,				\
310be0e2d3eSHaojian Zhuang 		.owner	= THIS_MODULE,					\
31153b6949eSAxel Lin 		.n_voltages = ARRAY_SIZE(vreg##_table),			\
312c006b21fSAxel Lin 		.vsel_reg = PM8607_##vreg,				\
313c006b21fSAxel Lin 		.vsel_mask = ARRAY_SIZE(vreg##_table) - 1,		\
314ef26e0dbSAxel Lin 		.enable_reg = PM8607_##ereg,				\
315ef26e0dbSAxel Lin 		.enable_mask = 1 << (ebit),				\
316be0e2d3eSHaojian Zhuang 	},								\
317be0e2d3eSHaojian Zhuang 	.update_reg	= PM8607_##ureg,				\
318be0e2d3eSHaojian Zhuang 	.update_bit	= (ubit),					\
319be0e2d3eSHaojian Zhuang 	.slope_double	= (0),						\
3209f79e9dbSHaojian Zhuang 	.vol_table	= (unsigned int *)&vreg##_table,		\
3219f79e9dbSHaojian Zhuang 	.vol_suspend	= (unsigned int *)&vreg##_suspend_table,	\
322be0e2d3eSHaojian Zhuang }
323be0e2d3eSHaojian Zhuang 
32453b6949eSAxel Lin #define PM8607_LDO(_id, vreg, shift, ereg, ebit)			\
325be0e2d3eSHaojian Zhuang {									\
326be0e2d3eSHaojian Zhuang 	.desc	= {							\
327be0e2d3eSHaojian Zhuang 		.name	= "LDO" #_id,					\
328be0e2d3eSHaojian Zhuang 		.ops	= &pm8607_regulator_ops,			\
329be0e2d3eSHaojian Zhuang 		.type	= REGULATOR_VOLTAGE,				\
330be0e2d3eSHaojian Zhuang 		.id	= PM8607_ID_LDO##_id,				\
331be0e2d3eSHaojian Zhuang 		.owner	= THIS_MODULE,					\
33253b6949eSAxel Lin 		.n_voltages = ARRAY_SIZE(LDO##_id##_table),		\
333c006b21fSAxel Lin 		.vsel_reg = PM8607_##vreg,				\
334c006b21fSAxel Lin 		.vsel_mask = (ARRAY_SIZE(LDO##_id##_table) - 1) << (shift), \
335ef26e0dbSAxel Lin 		.enable_reg = PM8607_##ereg,				\
336ef26e0dbSAxel Lin 		.enable_mask = 1 << (ebit),				\
337be0e2d3eSHaojian Zhuang 	},								\
338be0e2d3eSHaojian Zhuang 	.slope_double	= (0),						\
3399f79e9dbSHaojian Zhuang 	.vol_table	= (unsigned int *)&LDO##_id##_table,		\
3409f79e9dbSHaojian Zhuang 	.vol_suspend	= (unsigned int *)&LDO##_id##_suspend_table,	\
341be0e2d3eSHaojian Zhuang }
342be0e2d3eSHaojian Zhuang 
343be0e2d3eSHaojian Zhuang static struct pm8607_regulator_info pm8607_regulator_info[] = {
34453b6949eSAxel Lin 	PM8607_DVC(BUCK1, GO, 0, SUPPLIES_EN11, 0),
34553b6949eSAxel Lin 	PM8607_DVC(BUCK2, GO, 1, SUPPLIES_EN11, 1),
34653b6949eSAxel Lin 	PM8607_DVC(BUCK3, GO, 2, SUPPLIES_EN11, 2),
347be0e2d3eSHaojian Zhuang 
34853b6949eSAxel Lin 	PM8607_LDO(1,         LDO1, 0, SUPPLIES_EN11, 3),
34953b6949eSAxel Lin 	PM8607_LDO(2,         LDO2, 0, SUPPLIES_EN11, 4),
35053b6949eSAxel Lin 	PM8607_LDO(3,         LDO3, 0, SUPPLIES_EN11, 5),
35153b6949eSAxel Lin 	PM8607_LDO(4,         LDO4, 0, SUPPLIES_EN11, 6),
35253b6949eSAxel Lin 	PM8607_LDO(5,         LDO5, 0, SUPPLIES_EN11, 7),
35353b6949eSAxel Lin 	PM8607_LDO(6,         LDO6, 0, SUPPLIES_EN12, 0),
35453b6949eSAxel Lin 	PM8607_LDO(7,         LDO7, 0, SUPPLIES_EN12, 1),
35553b6949eSAxel Lin 	PM8607_LDO(8,         LDO8, 0, SUPPLIES_EN12, 2),
35653b6949eSAxel Lin 	PM8607_LDO(9,         LDO9, 0, SUPPLIES_EN12, 3),
35753b6949eSAxel Lin 	PM8607_LDO(10,        LDO10, 0, SUPPLIES_EN12, 4),
35853b6949eSAxel Lin 	PM8607_LDO(12,        LDO12, 0, SUPPLIES_EN12, 5),
35953b6949eSAxel Lin 	PM8607_LDO(13, VIBRATOR_SET, 1, VIBRATOR_SET, 0),
36053b6949eSAxel Lin 	PM8607_LDO(14,        LDO14, 0, SUPPLIES_EN12, 6),
361*e7a7810aSJett.Zhou 
362*e7a7810aSJett.Zhou 	PM8606_PREG(PREREGULATORB, 5),
363be0e2d3eSHaojian Zhuang };
364be0e2d3eSHaojian Zhuang 
365be0e2d3eSHaojian Zhuang static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
366be0e2d3eSHaojian Zhuang {
36753dbab7aSHaojian Zhuang 	struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
368be0e2d3eSHaojian Zhuang 	struct pm8607_regulator_info *info = NULL;
369586e1a17SHaojian Zhuang 	struct regulator_init_data *pdata = pdev->dev.platform_data;
370c172708dSMark Brown 	struct regulator_config config = { };
371586e1a17SHaojian Zhuang 	struct resource *res;
37222aad001SHaojian Zhuang 	int i;
373be0e2d3eSHaojian Zhuang 
37402367029SMark Brown 	res = platform_get_resource(pdev, IORESOURCE_REG, 0);
375586e1a17SHaojian Zhuang 	if (res == NULL) {
376a70abacbSHaojian Zhuang 		dev_err(&pdev->dev, "No REG resource!\n");
37722aad001SHaojian Zhuang 		return -EINVAL;
378586e1a17SHaojian Zhuang 	}
37922aad001SHaojian Zhuang 	for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) {
38022aad001SHaojian Zhuang 		info = &pm8607_regulator_info[i];
381a70abacbSHaojian Zhuang 		if (info->desc.vsel_reg == res->start)
38222aad001SHaojian Zhuang 			break;
38322aad001SHaojian Zhuang 	}
38499cd25ceSAxel Lin 	if (i == ARRAY_SIZE(pm8607_regulator_info)) {
38509969108SRandy Dunlap 		dev_err(&pdev->dev, "Failed to find regulator %llu\n",
38609969108SRandy Dunlap 			(unsigned long long)res->start);
387be0e2d3eSHaojian Zhuang 		return -EINVAL;
388be0e2d3eSHaojian Zhuang 	}
38953dbab7aSHaojian Zhuang 	info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
390*e7a7810aSJett.Zhou 	info->i2c_8606 = (chip->id == CHIP_PM8607) ? chip->companion :
391*e7a7810aSJett.Zhou 			chip->client;
392be0e2d3eSHaojian Zhuang 	info->chip = chip;
393be0e2d3eSHaojian Zhuang 
39422aad001SHaojian Zhuang 	/* check DVC ramp slope double */
395586e1a17SHaojian Zhuang 	if ((i == PM8607_ID_BUCK3) && info->chip->buck3_double)
39622aad001SHaojian Zhuang 		info->slope_double = 1;
39722aad001SHaojian Zhuang 
398c172708dSMark Brown 	config.dev = &pdev->dev;
399c172708dSMark Brown 	config.init_data = pdata;
400c172708dSMark Brown 	config.driver_data = info;
401c172708dSMark Brown 
402ef26e0dbSAxel Lin 	if (chip->id == CHIP_PM8607)
403ef26e0dbSAxel Lin 		config.regmap = chip->regmap;
404ef26e0dbSAxel Lin 	else
405ef26e0dbSAxel Lin 		config.regmap = chip->regmap_companion;
406ef26e0dbSAxel Lin 
407c172708dSMark Brown 	info->regulator = regulator_register(&info->desc, &config);
408be0e2d3eSHaojian Zhuang 	if (IS_ERR(info->regulator)) {
409be0e2d3eSHaojian Zhuang 		dev_err(&pdev->dev, "failed to register regulator %s\n",
410be0e2d3eSHaojian Zhuang 			info->desc.name);
411be0e2d3eSHaojian Zhuang 		return PTR_ERR(info->regulator);
412be0e2d3eSHaojian Zhuang 	}
413be0e2d3eSHaojian Zhuang 
414be0e2d3eSHaojian Zhuang 	platform_set_drvdata(pdev, info);
415be0e2d3eSHaojian Zhuang 	return 0;
416be0e2d3eSHaojian Zhuang }
417be0e2d3eSHaojian Zhuang 
418be0e2d3eSHaojian Zhuang static int __devexit pm8607_regulator_remove(struct platform_device *pdev)
419be0e2d3eSHaojian Zhuang {
420be0e2d3eSHaojian Zhuang 	struct pm8607_regulator_info *info = platform_get_drvdata(pdev);
421be0e2d3eSHaojian Zhuang 
422192bbb95SHaojian Zhuang 	platform_set_drvdata(pdev, NULL);
423be0e2d3eSHaojian Zhuang 	regulator_unregister(info->regulator);
424be0e2d3eSHaojian Zhuang 	return 0;
425be0e2d3eSHaojian Zhuang }
426be0e2d3eSHaojian Zhuang 
427*e7a7810aSJett.Zhou static struct platform_device_id pm8607_regulator_driver_ids[] = {
428*e7a7810aSJett.Zhou 	{
429*e7a7810aSJett.Zhou 		.name	= "88pm860x-regulator",
430*e7a7810aSJett.Zhou 		.driver_data	= 0,
431*e7a7810aSJett.Zhou 	}, {
432*e7a7810aSJett.Zhou 		.name	= "88pm860x-preg",
433*e7a7810aSJett.Zhou 		.driver_data	= 0,
434*e7a7810aSJett.Zhou 	},
435*e7a7810aSJett.Zhou 	{ },
436*e7a7810aSJett.Zhou };
437*e7a7810aSJett.Zhou MODULE_DEVICE_TABLE(platform, pm8607_regulator_driver_ids);
438*e7a7810aSJett.Zhou 
439192bbb95SHaojian Zhuang static struct platform_driver pm8607_regulator_driver = {
440192bbb95SHaojian Zhuang 	.driver		= {
441192bbb95SHaojian Zhuang 		.name	= "88pm860x-regulator",
442192bbb95SHaojian Zhuang 		.owner	= THIS_MODULE,
443192bbb95SHaojian Zhuang 	},
444192bbb95SHaojian Zhuang 	.probe		= pm8607_regulator_probe,
445192bbb95SHaojian Zhuang 	.remove		= __devexit_p(pm8607_regulator_remove),
446*e7a7810aSJett.Zhou 	.id_table	= pm8607_regulator_driver_ids,
447be0e2d3eSHaojian Zhuang };
448be0e2d3eSHaojian Zhuang 
449be0e2d3eSHaojian Zhuang static int __init pm8607_regulator_init(void)
450be0e2d3eSHaojian Zhuang {
451192bbb95SHaojian Zhuang 	return platform_driver_register(&pm8607_regulator_driver);
452be0e2d3eSHaojian Zhuang }
453be0e2d3eSHaojian Zhuang subsys_initcall(pm8607_regulator_init);
454be0e2d3eSHaojian Zhuang 
455be0e2d3eSHaojian Zhuang static void __exit pm8607_regulator_exit(void)
456be0e2d3eSHaojian Zhuang {
457192bbb95SHaojian Zhuang 	platform_driver_unregister(&pm8607_regulator_driver);
458be0e2d3eSHaojian Zhuang }
459be0e2d3eSHaojian Zhuang module_exit(pm8607_regulator_exit);
460be0e2d3eSHaojian Zhuang 
461be0e2d3eSHaojian Zhuang MODULE_LICENSE("GPL");
462be0e2d3eSHaojian Zhuang MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
463be0e2d3eSHaojian Zhuang MODULE_DESCRIPTION("Regulator Driver for Marvell 88PM8607 PMIC");
464be0e2d3eSHaojian Zhuang MODULE_ALIAS("platform:88pm8607-regulator");
465