xref: /linux/drivers/regulator/88pm8607.c (revision 53dbab7af9ca13fa95605e9a5c31bb803dcba363)
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>
14*53dbab7aSHaojian 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>
18*53dbab7aSHaojian Zhuang #include <linux/mfd/88pm860x.h>
19be0e2d3eSHaojian Zhuang 
20be0e2d3eSHaojian Zhuang struct pm8607_regulator_info {
21be0e2d3eSHaojian Zhuang 	struct regulator_desc	desc;
22*53dbab7aSHaojian Zhuang 	struct pm860x_chip	*chip;
23be0e2d3eSHaojian Zhuang 	struct regulator_dev	*regulator;
24*53dbab7aSHaojian Zhuang 	struct i2c_client	*i2c;
25be0e2d3eSHaojian Zhuang 
26be0e2d3eSHaojian Zhuang 	int	min_uV;
27be0e2d3eSHaojian Zhuang 	int	max_uV;
28be0e2d3eSHaojian Zhuang 	int	step_uV;
29be0e2d3eSHaojian Zhuang 	int	vol_reg;
30be0e2d3eSHaojian Zhuang 	int	vol_shift;
31be0e2d3eSHaojian Zhuang 	int	vol_nbits;
32be0e2d3eSHaojian Zhuang 	int	update_reg;
33be0e2d3eSHaojian Zhuang 	int	update_bit;
34be0e2d3eSHaojian Zhuang 	int	enable_reg;
35be0e2d3eSHaojian Zhuang 	int	enable_bit;
36be0e2d3eSHaojian Zhuang 	int	slope_double;
37be0e2d3eSHaojian Zhuang };
38be0e2d3eSHaojian Zhuang 
39be0e2d3eSHaojian Zhuang static inline int check_range(struct pm8607_regulator_info *info,
40be0e2d3eSHaojian Zhuang 				int min_uV, int max_uV)
41be0e2d3eSHaojian Zhuang {
42be0e2d3eSHaojian Zhuang 	if (max_uV < info->min_uV || min_uV > info->max_uV || min_uV > max_uV)
43be0e2d3eSHaojian Zhuang 		return -EINVAL;
44be0e2d3eSHaojian Zhuang 
45be0e2d3eSHaojian Zhuang 	return 0;
46be0e2d3eSHaojian Zhuang }
47be0e2d3eSHaojian Zhuang 
48be0e2d3eSHaojian Zhuang static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index)
49be0e2d3eSHaojian Zhuang {
50be0e2d3eSHaojian Zhuang 	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
51*53dbab7aSHaojian Zhuang 	uint8_t chip_id = info->chip->chip_version;
52be0e2d3eSHaojian Zhuang 	int ret = -EINVAL;
53be0e2d3eSHaojian Zhuang 
54be0e2d3eSHaojian Zhuang 	switch (info->desc.id) {
55be0e2d3eSHaojian Zhuang 	case PM8607_ID_BUCK1:
56be0e2d3eSHaojian Zhuang 		ret = (index < 0x1d) ? (index * 25000 + 800000) :
57be0e2d3eSHaojian Zhuang 			((index < 0x20) ? 1500000 :
58be0e2d3eSHaojian Zhuang 			((index < 0x40) ? ((index - 0x20) * 25000) :
59be0e2d3eSHaojian Zhuang 			-EINVAL));
60be0e2d3eSHaojian Zhuang 		break;
61be0e2d3eSHaojian Zhuang 	case PM8607_ID_BUCK3:
62be0e2d3eSHaojian Zhuang 		ret = (index < 0x3d) ? (index * 25000) :
63be0e2d3eSHaojian Zhuang 			((index < 0x40) ? 1500000 : -EINVAL);
64be0e2d3eSHaojian Zhuang 		if (ret < 0)
65be0e2d3eSHaojian Zhuang 			break;
66be0e2d3eSHaojian Zhuang 		if (info->slope_double)
67be0e2d3eSHaojian Zhuang 			ret <<= 1;
68be0e2d3eSHaojian Zhuang 		break;
69be0e2d3eSHaojian Zhuang 	case PM8607_ID_LDO1:
70be0e2d3eSHaojian Zhuang 		ret = (index == 0) ? 1800000 :
71be0e2d3eSHaojian Zhuang 			((index == 1) ? 1200000 :
72be0e2d3eSHaojian Zhuang 			((index == 2) ? 2800000 : -EINVAL));
73be0e2d3eSHaojian Zhuang 		break;
74be0e2d3eSHaojian Zhuang 	case PM8607_ID_LDO5:
75be0e2d3eSHaojian Zhuang 		ret = (index == 0) ? 2900000 :
76be0e2d3eSHaojian Zhuang 			((index == 1) ? 3000000 :
77be0e2d3eSHaojian Zhuang 			((index == 2) ? 3100000 : 3300000));
78be0e2d3eSHaojian Zhuang 		break;
79be0e2d3eSHaojian Zhuang 	case PM8607_ID_LDO7:
80be0e2d3eSHaojian Zhuang 	case PM8607_ID_LDO8:
81be0e2d3eSHaojian Zhuang 		ret = (index < 3) ? (index * 50000 + 1800000) :
82be0e2d3eSHaojian Zhuang 			((index < 8) ? (index * 50000 + 2550000) :
83be0e2d3eSHaojian Zhuang 			 -EINVAL);
84be0e2d3eSHaojian Zhuang 		break;
85be0e2d3eSHaojian Zhuang 	case PM8607_ID_LDO12:
86be0e2d3eSHaojian Zhuang 		ret = (index < 2) ? (index * 100000 + 1800000) :
87be0e2d3eSHaojian Zhuang 			((index < 7) ? (index * 100000 + 2500000) :
88be0e2d3eSHaojian Zhuang 			((index == 7) ? 3300000 : 1200000));
89be0e2d3eSHaojian Zhuang 		break;
90be0e2d3eSHaojian Zhuang 	case PM8607_ID_LDO2:
91be0e2d3eSHaojian Zhuang 	case PM8607_ID_LDO3:
92be0e2d3eSHaojian Zhuang 	case PM8607_ID_LDO9:
93be0e2d3eSHaojian Zhuang 		switch (chip_id) {
94be0e2d3eSHaojian Zhuang 		case PM8607_CHIP_A0:
95be0e2d3eSHaojian Zhuang 		case PM8607_CHIP_A1:
96be0e2d3eSHaojian Zhuang 			ret = (index < 3) ? (index * 50000 + 1800000) :
97be0e2d3eSHaojian Zhuang 				((index < 8) ? (index * 50000 + 2550000) :
98be0e2d3eSHaojian Zhuang 				 -EINVAL);
99be0e2d3eSHaojian Zhuang 			break;
100be0e2d3eSHaojian Zhuang 		case PM8607_CHIP_B0:
101be0e2d3eSHaojian Zhuang 			ret = (index < 3) ? (index * 50000 + 1800000) :
102be0e2d3eSHaojian Zhuang 				((index < 7) ? (index * 50000 + 2550000) :
103be0e2d3eSHaojian Zhuang 				3300000);
104be0e2d3eSHaojian Zhuang 			break;
105be0e2d3eSHaojian Zhuang 		}
106be0e2d3eSHaojian Zhuang 		break;
107be0e2d3eSHaojian Zhuang 	case PM8607_ID_LDO4:
108be0e2d3eSHaojian Zhuang 		switch (chip_id) {
109be0e2d3eSHaojian Zhuang 		case PM8607_CHIP_A0:
110be0e2d3eSHaojian Zhuang 		case PM8607_CHIP_A1:
111be0e2d3eSHaojian Zhuang 			ret = (index < 3) ? (index * 50000 + 1800000) :
112be0e2d3eSHaojian Zhuang 				((index < 8) ? (index * 50000 + 2550000) :
113be0e2d3eSHaojian Zhuang 				 -EINVAL);
114be0e2d3eSHaojian Zhuang 			break;
115be0e2d3eSHaojian Zhuang 		case PM8607_CHIP_B0:
116be0e2d3eSHaojian Zhuang 			ret = (index < 3) ? (index * 50000 + 1800000) :
117be0e2d3eSHaojian Zhuang 				((index < 6) ? (index * 50000 + 2550000) :
118be0e2d3eSHaojian Zhuang 				((index == 6) ? 2900000 : 3300000));
119be0e2d3eSHaojian Zhuang 			break;
120be0e2d3eSHaojian Zhuang 		}
121be0e2d3eSHaojian Zhuang 		break;
122be0e2d3eSHaojian Zhuang 	case PM8607_ID_LDO6:
123be0e2d3eSHaojian Zhuang 		switch (chip_id) {
124be0e2d3eSHaojian Zhuang 		case PM8607_CHIP_A0:
125be0e2d3eSHaojian Zhuang 		case PM8607_CHIP_A1:
126be0e2d3eSHaojian Zhuang 			ret = (index < 3) ? (index * 50000 + 1800000) :
127be0e2d3eSHaojian Zhuang 				((index < 8) ? (index * 50000 + 2450000) :
128be0e2d3eSHaojian Zhuang 				-EINVAL);
129be0e2d3eSHaojian Zhuang 			break;
130be0e2d3eSHaojian Zhuang 		case PM8607_CHIP_B0:
131be0e2d3eSHaojian Zhuang 			ret = (index < 2) ? (index * 50000 + 1800000) :
132be0e2d3eSHaojian Zhuang 				((index < 7) ? (index * 50000 + 2500000) :
133be0e2d3eSHaojian Zhuang 				3300000);
134be0e2d3eSHaojian Zhuang 			break;
135be0e2d3eSHaojian Zhuang 		}
136be0e2d3eSHaojian Zhuang 		break;
137be0e2d3eSHaojian Zhuang 	case PM8607_ID_LDO10:
138be0e2d3eSHaojian Zhuang 		switch (chip_id) {
139be0e2d3eSHaojian Zhuang 		case PM8607_CHIP_A0:
140be0e2d3eSHaojian Zhuang 		case PM8607_CHIP_A1:
141be0e2d3eSHaojian Zhuang 			ret = (index < 3) ? (index * 50000 + 1800000) :
142be0e2d3eSHaojian Zhuang 				((index < 8) ? (index * 50000 + 2550000) :
143be0e2d3eSHaojian Zhuang 				1200000);
144be0e2d3eSHaojian Zhuang 			break;
145be0e2d3eSHaojian Zhuang 		case PM8607_CHIP_B0:
146be0e2d3eSHaojian Zhuang 			ret = (index < 3) ? (index * 50000 + 1800000) :
147be0e2d3eSHaojian Zhuang 				((index < 7) ? (index * 50000 + 2550000) :
148be0e2d3eSHaojian Zhuang 				((index == 7) ? 3300000 : 1200000));
149be0e2d3eSHaojian Zhuang 			break;
150be0e2d3eSHaojian Zhuang 		}
151be0e2d3eSHaojian Zhuang 		break;
152be0e2d3eSHaojian Zhuang 	case PM8607_ID_LDO14:
153be0e2d3eSHaojian Zhuang 		switch (chip_id) {
154be0e2d3eSHaojian Zhuang 		case PM8607_CHIP_A0:
155be0e2d3eSHaojian Zhuang 		case PM8607_CHIP_A1:
156be0e2d3eSHaojian Zhuang 			ret = (index < 3) ? (index * 50000 + 1800000) :
157be0e2d3eSHaojian Zhuang 				((index < 8) ? (index * 50000 + 2550000) :
158be0e2d3eSHaojian Zhuang 				 -EINVAL);
159be0e2d3eSHaojian Zhuang 			break;
160be0e2d3eSHaojian Zhuang 		case PM8607_CHIP_B0:
161be0e2d3eSHaojian Zhuang 			ret = (index < 2) ? (index * 50000 + 1800000) :
162be0e2d3eSHaojian Zhuang 				((index < 7) ? (index * 50000 + 2600000) :
163be0e2d3eSHaojian Zhuang 				3300000);
164be0e2d3eSHaojian Zhuang 			break;
165be0e2d3eSHaojian Zhuang 		}
166be0e2d3eSHaojian Zhuang 		break;
167be0e2d3eSHaojian Zhuang 	}
168be0e2d3eSHaojian Zhuang 	return ret;
169be0e2d3eSHaojian Zhuang }
170be0e2d3eSHaojian Zhuang 
171be0e2d3eSHaojian Zhuang static int choose_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
172be0e2d3eSHaojian Zhuang {
173be0e2d3eSHaojian Zhuang 	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
174*53dbab7aSHaojian Zhuang 	uint8_t chip_id = info->chip->chip_version;
175ddec6810SMark Brown 	int val = -ENOENT;
176ddec6810SMark Brown 	int ret;
177be0e2d3eSHaojian Zhuang 
178be0e2d3eSHaojian Zhuang 	switch (info->desc.id) {
179be0e2d3eSHaojian Zhuang 	case PM8607_ID_BUCK1:
180be0e2d3eSHaojian Zhuang 		if (min_uV >= 800000) 		/* 800mV ~ 1500mV / 25mV */
181be0e2d3eSHaojian Zhuang 			val = (min_uV - 775001) / 25000;
182be0e2d3eSHaojian Zhuang 		else {				/* 25mV ~ 775mV / 25mV */
183be0e2d3eSHaojian Zhuang 			val = (min_uV + 249999) / 25000;
184be0e2d3eSHaojian Zhuang 			val += 32;
185be0e2d3eSHaojian Zhuang 		}
186be0e2d3eSHaojian Zhuang 		break;
187be0e2d3eSHaojian Zhuang 	case PM8607_ID_BUCK3:
188be0e2d3eSHaojian Zhuang 		if (info->slope_double)
189be0e2d3eSHaojian Zhuang 			min_uV = min_uV >> 1;
190be0e2d3eSHaojian Zhuang 		val = (min_uV + 249999) / 25000; /* 0mV ~ 1500mV / 25mV */
191be0e2d3eSHaojian Zhuang 
192be0e2d3eSHaojian Zhuang 		break;
193be0e2d3eSHaojian Zhuang 	case PM8607_ID_LDO1:
194be0e2d3eSHaojian Zhuang 		if (min_uV > 1800000)
195be0e2d3eSHaojian Zhuang 			val = 2;
196be0e2d3eSHaojian Zhuang 		else if (min_uV > 1200000)
197be0e2d3eSHaojian Zhuang 			val = 0;
198be0e2d3eSHaojian Zhuang 		else
199be0e2d3eSHaojian Zhuang 			val = 1;
200be0e2d3eSHaojian Zhuang 		break;
201be0e2d3eSHaojian Zhuang 	case PM8607_ID_LDO5:
202be0e2d3eSHaojian Zhuang 		if (min_uV > 3100000)
203be0e2d3eSHaojian Zhuang 			val = 3;
204be0e2d3eSHaojian Zhuang 		else				/* 2900mV ~ 3100mV / 100mV */
205be0e2d3eSHaojian Zhuang 			val = (min_uV - 2800001) / 100000;
206be0e2d3eSHaojian Zhuang 		break;
207be0e2d3eSHaojian Zhuang 	case PM8607_ID_LDO7:
208be0e2d3eSHaojian Zhuang 	case PM8607_ID_LDO8:
209be0e2d3eSHaojian Zhuang 		if (min_uV < 2700000) {	/* 1800mV ~ 1900mV / 50mV */
210be0e2d3eSHaojian Zhuang 			if (min_uV <= 1800000)
211be0e2d3eSHaojian Zhuang 				val = 0;	/* 1800mv */
212be0e2d3eSHaojian Zhuang 			else if (min_uV <= 1900000)
213be0e2d3eSHaojian Zhuang 				val = (min_uV - 1750001) / 50000;
214be0e2d3eSHaojian Zhuang 			else
215be0e2d3eSHaojian Zhuang 				val = 3;	/* 2700mV */
216be0e2d3eSHaojian Zhuang 		} else {		 /* 2700mV ~ 2900mV / 50mV */
217be0e2d3eSHaojian Zhuang 			if (min_uV <= 2900000) {
218be0e2d3eSHaojian Zhuang 				val = (min_uV - 2650001) / 50000;
219be0e2d3eSHaojian Zhuang 				val += 3;
220be0e2d3eSHaojian Zhuang 			} else
221be0e2d3eSHaojian Zhuang 				val = -EINVAL;
222be0e2d3eSHaojian Zhuang 		}
223be0e2d3eSHaojian Zhuang 		break;
224be0e2d3eSHaojian Zhuang 	case PM8607_ID_LDO10:
225be0e2d3eSHaojian Zhuang 		if (min_uV > 2850000)
226be0e2d3eSHaojian Zhuang 			val = 7;
227be0e2d3eSHaojian Zhuang 		else if (min_uV <= 1200000)
228be0e2d3eSHaojian Zhuang 			val = 8;
229be0e2d3eSHaojian Zhuang 		else if (min_uV < 2700000)	/* 1800mV ~ 1900mV / 50mV */
230be0e2d3eSHaojian Zhuang 			val = (min_uV - 1750001) / 50000;
231be0e2d3eSHaojian Zhuang 		else {				/* 2700mV ~ 2850mV / 50mV */
232be0e2d3eSHaojian Zhuang 			val = (min_uV - 2650001) / 50000;
233be0e2d3eSHaojian Zhuang 			val += 3;
234be0e2d3eSHaojian Zhuang 		}
235be0e2d3eSHaojian Zhuang 		break;
236be0e2d3eSHaojian Zhuang 	case PM8607_ID_LDO12:
237be0e2d3eSHaojian Zhuang 		if (min_uV < 2700000) {		/* 1800mV ~ 1900mV / 100mV */
238be0e2d3eSHaojian Zhuang 			if (min_uV <= 1200000)
239be0e2d3eSHaojian Zhuang 				val = 8;	/* 1200mV */
240be0e2d3eSHaojian Zhuang 			else if (min_uV <= 1800000)
241be0e2d3eSHaojian Zhuang 				val = 0;	/* 1800mV */
242be0e2d3eSHaojian Zhuang 			else if (min_uV <= 1900000)
243be0e2d3eSHaojian Zhuang 				val = (min_uV - 1700001) / 100000;
244be0e2d3eSHaojian Zhuang 			else
245be0e2d3eSHaojian Zhuang 				val = 2;	/* 2700mV */
246be0e2d3eSHaojian Zhuang 		} else {			/* 2700mV ~ 3100mV / 100mV */
247be0e2d3eSHaojian Zhuang 			if (min_uV <= 3100000) {
248be0e2d3eSHaojian Zhuang 				val = (min_uV - 2600001) / 100000;
249be0e2d3eSHaojian Zhuang 				val += 2;
250be0e2d3eSHaojian Zhuang 			} else if (min_uV <= 3300000)
251be0e2d3eSHaojian Zhuang 				val = 7;
252be0e2d3eSHaojian Zhuang 			else
253be0e2d3eSHaojian Zhuang 				val = -EINVAL;
254be0e2d3eSHaojian Zhuang 		}
255be0e2d3eSHaojian Zhuang 		break;
256be0e2d3eSHaojian Zhuang 	case PM8607_ID_LDO2:
257be0e2d3eSHaojian Zhuang 	case PM8607_ID_LDO3:
258be0e2d3eSHaojian Zhuang 	case PM8607_ID_LDO9:
259be0e2d3eSHaojian Zhuang 		switch (chip_id) {
260be0e2d3eSHaojian Zhuang 		case PM8607_CHIP_A0:
261be0e2d3eSHaojian Zhuang 		case PM8607_CHIP_A1:
262be0e2d3eSHaojian Zhuang 			if (min_uV < 2700000)	/* 1800mV ~ 1900mV / 50mV */
263be0e2d3eSHaojian Zhuang 				if (min_uV <= 1800000)
264be0e2d3eSHaojian Zhuang 					val = 0;
265be0e2d3eSHaojian Zhuang 				else if (min_uV <= 1900000)
266be0e2d3eSHaojian Zhuang 					val = (min_uV - 1750001) / 50000;
267be0e2d3eSHaojian Zhuang 				else
268be0e2d3eSHaojian Zhuang 					val = 3;	/* 2700mV */
269be0e2d3eSHaojian Zhuang 			else {			/* 2700mV ~ 2900mV / 50mV */
270be0e2d3eSHaojian Zhuang 				if (min_uV <= 2900000) {
271be0e2d3eSHaojian Zhuang 					val = (min_uV - 2650001) / 50000;
272be0e2d3eSHaojian Zhuang 					val += 3;
273be0e2d3eSHaojian Zhuang 				} else
274be0e2d3eSHaojian Zhuang 					val = -EINVAL;
275be0e2d3eSHaojian Zhuang 			}
276be0e2d3eSHaojian Zhuang 			break;
277be0e2d3eSHaojian Zhuang 		case PM8607_CHIP_B0:
278be0e2d3eSHaojian Zhuang 			if (min_uV < 2700000) {	/* 1800mV ~ 1900mV / 50mV */
279be0e2d3eSHaojian Zhuang 				if (min_uV <= 1800000)
280be0e2d3eSHaojian Zhuang 					val = 0;
281be0e2d3eSHaojian Zhuang 				else if (min_uV <= 1900000)
282be0e2d3eSHaojian Zhuang 					val = (min_uV - 1750001) / 50000;
283be0e2d3eSHaojian Zhuang 				else
284be0e2d3eSHaojian Zhuang 					val = 3;	/* 2700mV */
285be0e2d3eSHaojian Zhuang 			} else {		 /* 2700mV ~ 2850mV / 50mV */
286be0e2d3eSHaojian Zhuang 				if (min_uV <= 2850000) {
287be0e2d3eSHaojian Zhuang 					val = (min_uV - 2650001) / 50000;
288be0e2d3eSHaojian Zhuang 					val += 3;
289be0e2d3eSHaojian Zhuang 				} else if (min_uV <= 3300000)
290be0e2d3eSHaojian Zhuang 					val = 7;
291be0e2d3eSHaojian Zhuang 				else
292be0e2d3eSHaojian Zhuang 					val = -EINVAL;
293be0e2d3eSHaojian Zhuang 			}
294be0e2d3eSHaojian Zhuang 			break;
295be0e2d3eSHaojian Zhuang 		}
296be0e2d3eSHaojian Zhuang 		break;
297be0e2d3eSHaojian Zhuang 	case PM8607_ID_LDO4:
298be0e2d3eSHaojian Zhuang 		switch (chip_id) {
299be0e2d3eSHaojian Zhuang 		case PM8607_CHIP_A0:
300be0e2d3eSHaojian Zhuang 		case PM8607_CHIP_A1:
301be0e2d3eSHaojian Zhuang 			if (min_uV < 2700000)	/* 1800mV ~ 1900mV / 50mV */
302be0e2d3eSHaojian Zhuang 				if (min_uV <= 1800000)
303be0e2d3eSHaojian Zhuang 					val = 0;
304be0e2d3eSHaojian Zhuang 				else if (min_uV <= 1900000)
305be0e2d3eSHaojian Zhuang 					val = (min_uV - 1750001) / 50000;
306be0e2d3eSHaojian Zhuang 				else
307be0e2d3eSHaojian Zhuang 					val = 3;	/* 2700mV */
308be0e2d3eSHaojian Zhuang 			else {			/* 2700mV ~ 2900mV / 50mV */
309be0e2d3eSHaojian Zhuang 				if (min_uV <= 2900000) {
310be0e2d3eSHaojian Zhuang 					val = (min_uV - 2650001) / 50000;
311be0e2d3eSHaojian Zhuang 					val += 3;
312be0e2d3eSHaojian Zhuang 				} else
313be0e2d3eSHaojian Zhuang 					val = -EINVAL;
314be0e2d3eSHaojian Zhuang 			}
315be0e2d3eSHaojian Zhuang 			break;
316be0e2d3eSHaojian Zhuang 		case PM8607_CHIP_B0:
317be0e2d3eSHaojian Zhuang 			if (min_uV < 2700000) {	/* 1800mV ~ 1900mV / 50mV */
318be0e2d3eSHaojian Zhuang 				if (min_uV <= 1800000)
319be0e2d3eSHaojian Zhuang 					val = 0;
320be0e2d3eSHaojian Zhuang 				else if (min_uV <= 1900000)
321be0e2d3eSHaojian Zhuang 					val = (min_uV - 1750001) / 50000;
322be0e2d3eSHaojian Zhuang 				else
323be0e2d3eSHaojian Zhuang 					val = 3;	/* 2700mV */
324be0e2d3eSHaojian Zhuang 			} else {		 /* 2700mV ~ 2800mV / 50mV */
325be0e2d3eSHaojian Zhuang 				if (min_uV <= 2850000) {
326be0e2d3eSHaojian Zhuang 					val = (min_uV - 2650001) / 50000;
327be0e2d3eSHaojian Zhuang 					val += 3;
328be0e2d3eSHaojian Zhuang 				} else if (min_uV <= 2900000)
329be0e2d3eSHaojian Zhuang 					val = 6;
330be0e2d3eSHaojian Zhuang 				else if (min_uV <= 3300000)
331be0e2d3eSHaojian Zhuang 					val = 7;
332be0e2d3eSHaojian Zhuang 				else
333be0e2d3eSHaojian Zhuang 					val = -EINVAL;
334be0e2d3eSHaojian Zhuang 			}
335be0e2d3eSHaojian Zhuang 			break;
336be0e2d3eSHaojian Zhuang 		}
337be0e2d3eSHaojian Zhuang 		break;
338be0e2d3eSHaojian Zhuang 	case PM8607_ID_LDO6:
339be0e2d3eSHaojian Zhuang 		switch (chip_id) {
340be0e2d3eSHaojian Zhuang 		case PM8607_CHIP_A0:
341be0e2d3eSHaojian Zhuang 		case PM8607_CHIP_A1:
342be0e2d3eSHaojian Zhuang 			if (min_uV < 2600000) {	/* 1800mV ~ 1900mV / 50mV */
343be0e2d3eSHaojian Zhuang 				if (min_uV <= 1800000)
344be0e2d3eSHaojian Zhuang 					val = 0;
345be0e2d3eSHaojian Zhuang 				else if (min_uV <= 1900000)
346be0e2d3eSHaojian Zhuang 					val = (min_uV - 1750001) / 50000;
347be0e2d3eSHaojian Zhuang 				else
348be0e2d3eSHaojian Zhuang 					val = 3;	/* 2600mV */
349be0e2d3eSHaojian Zhuang 			} else {		/* 2600mV ~ 2800mV / 50mV */
350be0e2d3eSHaojian Zhuang 				if (min_uV <= 2800000) {
351be0e2d3eSHaojian Zhuang 					val = (min_uV - 2550001) / 50000;
352be0e2d3eSHaojian Zhuang 					val += 3;
353be0e2d3eSHaojian Zhuang 				} else
354be0e2d3eSHaojian Zhuang 					val = -EINVAL;
355be0e2d3eSHaojian Zhuang 			}
356be0e2d3eSHaojian Zhuang 			break;
357be0e2d3eSHaojian Zhuang 		case PM8607_CHIP_B0:
358be0e2d3eSHaojian Zhuang 			if (min_uV < 2600000) {	/* 1800mV ~ 1850mV / 50mV */
359be0e2d3eSHaojian Zhuang 				if (min_uV <= 1800000)
360be0e2d3eSHaojian Zhuang 					val = 0;
361be0e2d3eSHaojian Zhuang 				else if (min_uV <= 1850000)
362be0e2d3eSHaojian Zhuang 					val = (min_uV - 1750001) / 50000;
363be0e2d3eSHaojian Zhuang 				else
364be0e2d3eSHaojian Zhuang 					val = 2;	/* 2600mV */
365be0e2d3eSHaojian Zhuang 			} else {		/* 2600mV ~ 2800mV / 50mV */
366be0e2d3eSHaojian Zhuang 				if (min_uV <= 2800000) {
367be0e2d3eSHaojian Zhuang 					val = (min_uV - 2550001) / 50000;
368be0e2d3eSHaojian Zhuang 					val += 2;
369be0e2d3eSHaojian Zhuang 				} else if (min_uV <= 3300000)
370be0e2d3eSHaojian Zhuang 					val = 7;
371be0e2d3eSHaojian Zhuang 				else
372be0e2d3eSHaojian Zhuang 					val = -EINVAL;
373be0e2d3eSHaojian Zhuang 			}
374be0e2d3eSHaojian Zhuang 			break;
375be0e2d3eSHaojian Zhuang 		}
376be0e2d3eSHaojian Zhuang 		break;
377be0e2d3eSHaojian Zhuang 	case PM8607_ID_LDO14:
378be0e2d3eSHaojian Zhuang 		switch (chip_id) {
379be0e2d3eSHaojian Zhuang 		case PM8607_CHIP_A0:
380be0e2d3eSHaojian Zhuang 		case PM8607_CHIP_A1:
381be0e2d3eSHaojian Zhuang 			if (min_uV < 2700000) {	/* 1800mV ~ 1900mV / 50mV */
382be0e2d3eSHaojian Zhuang 				if (min_uV <= 1800000)
383be0e2d3eSHaojian Zhuang 					val = 0;
384be0e2d3eSHaojian Zhuang 				else if (min_uV <= 1900000)
385be0e2d3eSHaojian Zhuang 					val = (min_uV - 1750001) / 50000;
386be0e2d3eSHaojian Zhuang 				else
387be0e2d3eSHaojian Zhuang 					val = 3;	/* 2700mV */
388be0e2d3eSHaojian Zhuang 			} else {		 /* 2700mV ~ 2900mV / 50mV */
389be0e2d3eSHaojian Zhuang 				if (min_uV <= 2900000) {
390be0e2d3eSHaojian Zhuang 					val = (min_uV - 2650001) / 50000;
391be0e2d3eSHaojian Zhuang 					val += 3;
392be0e2d3eSHaojian Zhuang 				} else
393be0e2d3eSHaojian Zhuang 					val = -EINVAL;
394be0e2d3eSHaojian Zhuang 			}
395be0e2d3eSHaojian Zhuang 			break;
396be0e2d3eSHaojian Zhuang 		case PM8607_CHIP_B0:
397be0e2d3eSHaojian Zhuang 			if (min_uV < 2700000) {	/* 1800mV ~ 1850mV / 50mV */
398be0e2d3eSHaojian Zhuang 				if (min_uV <= 1800000)
399be0e2d3eSHaojian Zhuang 					val = 0;
400be0e2d3eSHaojian Zhuang 				else if (min_uV <= 1850000)
401be0e2d3eSHaojian Zhuang 					val = (min_uV - 1750001) / 50000;
402be0e2d3eSHaojian Zhuang 				else
403be0e2d3eSHaojian Zhuang 					val = 2;	/* 2700mV */
404be0e2d3eSHaojian Zhuang 			} else {		 /* 2700mV ~ 2900mV / 50mV */
405be0e2d3eSHaojian Zhuang 				if (min_uV <= 2900000) {
406be0e2d3eSHaojian Zhuang 					val = (min_uV - 2650001) / 50000;
407be0e2d3eSHaojian Zhuang 					val += 2;
408be0e2d3eSHaojian Zhuang 				} else if (min_uV <= 3300000)
409be0e2d3eSHaojian Zhuang 					val = 7;
410be0e2d3eSHaojian Zhuang 				else
411be0e2d3eSHaojian Zhuang 					val = -EINVAL;
412be0e2d3eSHaojian Zhuang 			}
413be0e2d3eSHaojian Zhuang 			break;
414be0e2d3eSHaojian Zhuang 		}
415be0e2d3eSHaojian Zhuang 		break;
416be0e2d3eSHaojian Zhuang 	}
417be0e2d3eSHaojian Zhuang 	if (val >= 0) {
418be0e2d3eSHaojian Zhuang 		ret = pm8607_list_voltage(rdev, val);
419be0e2d3eSHaojian Zhuang 		if (ret > max_uV) {
420be0e2d3eSHaojian Zhuang 			pr_err("exceed voltage range (%d %d) uV",
421be0e2d3eSHaojian Zhuang 				min_uV, max_uV);
422be0e2d3eSHaojian Zhuang 			return -EINVAL;
423be0e2d3eSHaojian Zhuang 		}
424be0e2d3eSHaojian Zhuang 	} else
425be0e2d3eSHaojian Zhuang 		pr_err("invalid voltage range (%d %d) uV", min_uV, max_uV);
426be0e2d3eSHaojian Zhuang 	return val;
427be0e2d3eSHaojian Zhuang }
428be0e2d3eSHaojian Zhuang 
429be0e2d3eSHaojian Zhuang static int pm8607_set_voltage(struct regulator_dev *rdev,
430be0e2d3eSHaojian Zhuang 			      int min_uV, int max_uV)
431be0e2d3eSHaojian Zhuang {
432be0e2d3eSHaojian Zhuang 	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
433be0e2d3eSHaojian Zhuang 	uint8_t val, mask;
434be0e2d3eSHaojian Zhuang 	int ret;
435be0e2d3eSHaojian Zhuang 
436be0e2d3eSHaojian Zhuang 	if (check_range(info, min_uV, max_uV)) {
437be0e2d3eSHaojian Zhuang 		pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
438be0e2d3eSHaojian Zhuang 		return -EINVAL;
439be0e2d3eSHaojian Zhuang 	}
440be0e2d3eSHaojian Zhuang 
441be0e2d3eSHaojian Zhuang 	ret = choose_voltage(rdev, min_uV, max_uV);
442be0e2d3eSHaojian Zhuang 	if (ret < 0)
443be0e2d3eSHaojian Zhuang 		return -EINVAL;
444be0e2d3eSHaojian Zhuang 	val = (uint8_t)(ret << info->vol_shift);
445be0e2d3eSHaojian Zhuang 	mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
446be0e2d3eSHaojian Zhuang 
447*53dbab7aSHaojian Zhuang 	ret = pm860x_set_bits(info->i2c, info->vol_reg, mask, val);
448be0e2d3eSHaojian Zhuang 	if (ret)
449be0e2d3eSHaojian Zhuang 		return ret;
450be0e2d3eSHaojian Zhuang 	switch (info->desc.id) {
451be0e2d3eSHaojian Zhuang 	case PM8607_ID_BUCK1:
452be0e2d3eSHaojian Zhuang 	case PM8607_ID_BUCK3:
453*53dbab7aSHaojian Zhuang 		ret = pm860x_set_bits(info->i2c, info->update_reg,
454be0e2d3eSHaojian Zhuang 				      1 << info->update_bit,
455be0e2d3eSHaojian Zhuang 				      1 << info->update_bit);
456be0e2d3eSHaojian Zhuang 		break;
457be0e2d3eSHaojian Zhuang 	}
458be0e2d3eSHaojian Zhuang 	return ret;
459be0e2d3eSHaojian Zhuang }
460be0e2d3eSHaojian Zhuang 
461be0e2d3eSHaojian Zhuang static int pm8607_get_voltage(struct regulator_dev *rdev)
462be0e2d3eSHaojian Zhuang {
463be0e2d3eSHaojian Zhuang 	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
464be0e2d3eSHaojian Zhuang 	uint8_t val, mask;
465be0e2d3eSHaojian Zhuang 	int ret;
466be0e2d3eSHaojian Zhuang 
467*53dbab7aSHaojian Zhuang 	ret = pm860x_reg_read(info->i2c, info->vol_reg);
468be0e2d3eSHaojian Zhuang 	if (ret < 0)
469be0e2d3eSHaojian Zhuang 		return ret;
470be0e2d3eSHaojian Zhuang 
471be0e2d3eSHaojian Zhuang 	mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
472be0e2d3eSHaojian Zhuang 	val = ((unsigned char)ret & mask) >> info->vol_shift;
473be0e2d3eSHaojian Zhuang 
474be0e2d3eSHaojian Zhuang 	return pm8607_list_voltage(rdev, val);
475be0e2d3eSHaojian Zhuang }
476be0e2d3eSHaojian Zhuang 
477be0e2d3eSHaojian Zhuang static int pm8607_enable(struct regulator_dev *rdev)
478be0e2d3eSHaojian Zhuang {
479be0e2d3eSHaojian Zhuang 	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
480be0e2d3eSHaojian Zhuang 
481*53dbab7aSHaojian Zhuang 	return pm860x_set_bits(info->i2c, info->enable_reg,
482be0e2d3eSHaojian Zhuang 			       1 << info->enable_bit,
483be0e2d3eSHaojian Zhuang 			       1 << info->enable_bit);
484be0e2d3eSHaojian Zhuang }
485be0e2d3eSHaojian Zhuang 
486be0e2d3eSHaojian Zhuang static int pm8607_disable(struct regulator_dev *rdev)
487be0e2d3eSHaojian Zhuang {
488be0e2d3eSHaojian Zhuang 	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
489be0e2d3eSHaojian Zhuang 
490*53dbab7aSHaojian Zhuang 	return pm860x_set_bits(info->i2c, info->enable_reg,
491be0e2d3eSHaojian Zhuang 			       1 << info->enable_bit, 0);
492be0e2d3eSHaojian Zhuang }
493be0e2d3eSHaojian Zhuang 
494be0e2d3eSHaojian Zhuang static int pm8607_is_enabled(struct regulator_dev *rdev)
495be0e2d3eSHaojian Zhuang {
496be0e2d3eSHaojian Zhuang 	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
497be0e2d3eSHaojian Zhuang 	int ret;
498be0e2d3eSHaojian Zhuang 
499*53dbab7aSHaojian Zhuang 	ret = pm860x_reg_read(info->i2c, info->enable_reg);
500be0e2d3eSHaojian Zhuang 	if (ret < 0)
501be0e2d3eSHaojian Zhuang 		return ret;
502be0e2d3eSHaojian Zhuang 
503be0e2d3eSHaojian Zhuang 	return !!((unsigned char)ret & (1 << info->enable_bit));
504be0e2d3eSHaojian Zhuang }
505be0e2d3eSHaojian Zhuang 
506be0e2d3eSHaojian Zhuang static struct regulator_ops pm8607_regulator_ops = {
507be0e2d3eSHaojian Zhuang 	.set_voltage	= pm8607_set_voltage,
508be0e2d3eSHaojian Zhuang 	.get_voltage	= pm8607_get_voltage,
509be0e2d3eSHaojian Zhuang 	.enable		= pm8607_enable,
510be0e2d3eSHaojian Zhuang 	.disable	= pm8607_disable,
511be0e2d3eSHaojian Zhuang 	.is_enabled	= pm8607_is_enabled,
512be0e2d3eSHaojian Zhuang };
513be0e2d3eSHaojian Zhuang 
514be0e2d3eSHaojian Zhuang #define PM8607_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \
515be0e2d3eSHaojian Zhuang {									\
516be0e2d3eSHaojian Zhuang 	.desc	= {							\
517be0e2d3eSHaojian Zhuang 		.name	= "BUCK" #_id,					\
518be0e2d3eSHaojian Zhuang 		.ops	= &pm8607_regulator_ops,			\
519be0e2d3eSHaojian Zhuang 		.type	= REGULATOR_VOLTAGE,				\
520be0e2d3eSHaojian Zhuang 		.id	= PM8607_ID_BUCK##_id,				\
521be0e2d3eSHaojian Zhuang 		.owner	= THIS_MODULE,					\
522be0e2d3eSHaojian Zhuang 	},								\
523be0e2d3eSHaojian Zhuang 	.min_uV		= (min) * 1000,					\
524be0e2d3eSHaojian Zhuang 	.max_uV		= (max) * 1000,					\
525be0e2d3eSHaojian Zhuang 	.step_uV	= (step) * 1000,				\
526be0e2d3eSHaojian Zhuang 	.vol_reg	= PM8607_##vreg,				\
527be0e2d3eSHaojian Zhuang 	.vol_shift	= (0),						\
528be0e2d3eSHaojian Zhuang 	.vol_nbits	= (nbits),					\
529be0e2d3eSHaojian Zhuang 	.update_reg	= PM8607_##ureg,				\
530be0e2d3eSHaojian Zhuang 	.update_bit	= (ubit),					\
531be0e2d3eSHaojian Zhuang 	.enable_reg	= PM8607_##ereg,				\
532be0e2d3eSHaojian Zhuang 	.enable_bit	= (ebit),					\
533be0e2d3eSHaojian Zhuang 	.slope_double	= (0),						\
534be0e2d3eSHaojian Zhuang }
535be0e2d3eSHaojian Zhuang 
536be0e2d3eSHaojian Zhuang #define PM8607_LDO(_id, min, max, step, vreg, shift, nbits, ereg, ebit)	\
537be0e2d3eSHaojian Zhuang {									\
538be0e2d3eSHaojian Zhuang 	.desc	= {							\
539be0e2d3eSHaojian Zhuang 		.name	= "LDO" #_id,					\
540be0e2d3eSHaojian Zhuang 		.ops	= &pm8607_regulator_ops,			\
541be0e2d3eSHaojian Zhuang 		.type	= REGULATOR_VOLTAGE,				\
542be0e2d3eSHaojian Zhuang 		.id	= PM8607_ID_LDO##_id,				\
543be0e2d3eSHaojian Zhuang 		.owner	= THIS_MODULE,					\
544be0e2d3eSHaojian Zhuang 	},								\
545be0e2d3eSHaojian Zhuang 	.min_uV		= (min) * 1000,					\
546be0e2d3eSHaojian Zhuang 	.max_uV		= (max) * 1000,					\
547be0e2d3eSHaojian Zhuang 	.step_uV	= (step) * 1000,				\
548be0e2d3eSHaojian Zhuang 	.vol_reg	= PM8607_##vreg,				\
549be0e2d3eSHaojian Zhuang 	.vol_shift	= (shift),					\
550be0e2d3eSHaojian Zhuang 	.vol_nbits	= (nbits),					\
551be0e2d3eSHaojian Zhuang 	.enable_reg	= PM8607_##ereg,				\
552be0e2d3eSHaojian Zhuang 	.enable_bit	= (ebit),					\
553be0e2d3eSHaojian Zhuang 	.slope_double	= (0),						\
554be0e2d3eSHaojian Zhuang }
555be0e2d3eSHaojian Zhuang 
556be0e2d3eSHaojian Zhuang static struct pm8607_regulator_info pm8607_regulator_info[] = {
557be0e2d3eSHaojian Zhuang 	PM8607_DVC(1, 0, 1500, 25, BUCK1, 6, GO, 0, SUPPLIES_EN11, 0),
558be0e2d3eSHaojian Zhuang 	PM8607_DVC(3, 0, 1500, 25, BUCK3, 6, GO, 2, SUPPLIES_EN11, 2),
559be0e2d3eSHaojian Zhuang 
560be0e2d3eSHaojian Zhuang 	PM8607_LDO(1 , 1200, 2800, 0, LDO1 , 0, 2, SUPPLIES_EN11, 3),
561be0e2d3eSHaojian Zhuang 	PM8607_LDO(2 , 1800, 3300, 0, LDO2 , 0, 3, SUPPLIES_EN11, 4),
562be0e2d3eSHaojian Zhuang 	PM8607_LDO(3 , 1800, 3300, 0, LDO3 , 0, 3, SUPPLIES_EN11, 5),
563be0e2d3eSHaojian Zhuang 	PM8607_LDO(4 , 1800, 3300, 0, LDO4 , 0, 3, SUPPLIES_EN11, 6),
564be0e2d3eSHaojian Zhuang 	PM8607_LDO(5 , 2900, 3300, 0, LDO5 , 0, 2, SUPPLIES_EN11, 7),
565be0e2d3eSHaojian Zhuang 	PM8607_LDO(6 , 1800, 3300, 0, LDO6 , 0, 3, SUPPLIES_EN12, 0),
566be0e2d3eSHaojian Zhuang 	PM8607_LDO(7 , 1800, 2900, 0, LDO7 , 0, 3, SUPPLIES_EN12, 1),
567be0e2d3eSHaojian Zhuang 	PM8607_LDO(8 , 1800, 2900, 0, LDO8 , 0, 3, SUPPLIES_EN12, 2),
568be0e2d3eSHaojian Zhuang 	PM8607_LDO(9 , 1800, 3300, 0, LDO9 , 0, 3, SUPPLIES_EN12, 3),
569be0e2d3eSHaojian Zhuang 	PM8607_LDO(10, 1200, 3300, 0, LDO10, 0, 4, SUPPLIES_EN11, 4),
570be0e2d3eSHaojian Zhuang 	PM8607_LDO(12, 1200, 3300, 0, LDO12, 0, 4, SUPPLIES_EN11, 5),
571be0e2d3eSHaojian Zhuang 	PM8607_LDO(14, 1800, 3300, 0, LDO14, 0, 3, SUPPLIES_EN11, 6),
572be0e2d3eSHaojian Zhuang };
573be0e2d3eSHaojian Zhuang 
574be0e2d3eSHaojian Zhuang static inline struct pm8607_regulator_info *find_regulator_info(int id)
575be0e2d3eSHaojian Zhuang {
576be0e2d3eSHaojian Zhuang 	struct pm8607_regulator_info *info;
577be0e2d3eSHaojian Zhuang 	int i;
578be0e2d3eSHaojian Zhuang 
579be0e2d3eSHaojian Zhuang 	for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) {
580be0e2d3eSHaojian Zhuang 		info = &pm8607_regulator_info[i];
581be0e2d3eSHaojian Zhuang 		if (info->desc.id == id)
582be0e2d3eSHaojian Zhuang 			return info;
583be0e2d3eSHaojian Zhuang 	}
584be0e2d3eSHaojian Zhuang 	return NULL;
585be0e2d3eSHaojian Zhuang }
586be0e2d3eSHaojian Zhuang 
587be0e2d3eSHaojian Zhuang static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
588be0e2d3eSHaojian Zhuang {
589*53dbab7aSHaojian Zhuang 	struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
590*53dbab7aSHaojian Zhuang 	struct pm860x_platform_data *pdata = chip->dev->platform_data;
591be0e2d3eSHaojian Zhuang 	struct pm8607_regulator_info *info = NULL;
592be0e2d3eSHaojian Zhuang 
593be0e2d3eSHaojian Zhuang 	info = find_regulator_info(pdev->id);
594be0e2d3eSHaojian Zhuang 	if (info == NULL) {
595be0e2d3eSHaojian Zhuang 		dev_err(&pdev->dev, "invalid regulator ID specified\n");
596be0e2d3eSHaojian Zhuang 		return -EINVAL;
597be0e2d3eSHaojian Zhuang 	}
598be0e2d3eSHaojian Zhuang 
599*53dbab7aSHaojian Zhuang 	info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
600be0e2d3eSHaojian Zhuang 	info->chip = chip;
601be0e2d3eSHaojian Zhuang 
602be0e2d3eSHaojian Zhuang 	info->regulator = regulator_register(&info->desc, &pdev->dev,
603be0e2d3eSHaojian Zhuang 					     pdata->regulator[pdev->id], info);
604be0e2d3eSHaojian Zhuang 	if (IS_ERR(info->regulator)) {
605be0e2d3eSHaojian Zhuang 		dev_err(&pdev->dev, "failed to register regulator %s\n",
606be0e2d3eSHaojian Zhuang 			info->desc.name);
607be0e2d3eSHaojian Zhuang 		return PTR_ERR(info->regulator);
608be0e2d3eSHaojian Zhuang 	}
609be0e2d3eSHaojian Zhuang 
610be0e2d3eSHaojian Zhuang 	/* check DVC ramp slope double */
611be0e2d3eSHaojian Zhuang 	if (info->desc.id == PM8607_ID_BUCK3)
612be0e2d3eSHaojian Zhuang 		if (info->chip->buck3_double)
613be0e2d3eSHaojian Zhuang 			info->slope_double = 1;
614be0e2d3eSHaojian Zhuang 
615be0e2d3eSHaojian Zhuang 	platform_set_drvdata(pdev, info);
616be0e2d3eSHaojian Zhuang 	return 0;
617be0e2d3eSHaojian Zhuang }
618be0e2d3eSHaojian Zhuang 
619be0e2d3eSHaojian Zhuang static int __devexit pm8607_regulator_remove(struct platform_device *pdev)
620be0e2d3eSHaojian Zhuang {
621be0e2d3eSHaojian Zhuang 	struct pm8607_regulator_info *info = platform_get_drvdata(pdev);
622be0e2d3eSHaojian Zhuang 
623be0e2d3eSHaojian Zhuang 	regulator_unregister(info->regulator);
624be0e2d3eSHaojian Zhuang 	return 0;
625be0e2d3eSHaojian Zhuang }
626be0e2d3eSHaojian Zhuang 
627be0e2d3eSHaojian Zhuang #define PM8607_REGULATOR_DRIVER(_name)				\
628be0e2d3eSHaojian Zhuang {								\
629be0e2d3eSHaojian Zhuang 	.driver		= {					\
630be0e2d3eSHaojian Zhuang 		.name	= "88pm8607-" #_name,			\
631be0e2d3eSHaojian Zhuang 		.owner	= THIS_MODULE,				\
632be0e2d3eSHaojian Zhuang 	},							\
633be0e2d3eSHaojian Zhuang 	.probe		= pm8607_regulator_probe,		\
634be0e2d3eSHaojian Zhuang 	.remove		= __devexit_p(pm8607_regulator_remove),	\
635be0e2d3eSHaojian Zhuang }
636be0e2d3eSHaojian Zhuang 
637be0e2d3eSHaojian Zhuang static struct platform_driver pm8607_regulator_driver[] = {
638be0e2d3eSHaojian Zhuang 	PM8607_REGULATOR_DRIVER(buck1),
639be0e2d3eSHaojian Zhuang 	PM8607_REGULATOR_DRIVER(buck2),
640be0e2d3eSHaojian Zhuang 	PM8607_REGULATOR_DRIVER(buck3),
641be0e2d3eSHaojian Zhuang 	PM8607_REGULATOR_DRIVER(ldo1),
642be0e2d3eSHaojian Zhuang 	PM8607_REGULATOR_DRIVER(ldo2),
643be0e2d3eSHaojian Zhuang 	PM8607_REGULATOR_DRIVER(ldo3),
644be0e2d3eSHaojian Zhuang 	PM8607_REGULATOR_DRIVER(ldo4),
645be0e2d3eSHaojian Zhuang 	PM8607_REGULATOR_DRIVER(ldo5),
646be0e2d3eSHaojian Zhuang 	PM8607_REGULATOR_DRIVER(ldo6),
647be0e2d3eSHaojian Zhuang 	PM8607_REGULATOR_DRIVER(ldo7),
648be0e2d3eSHaojian Zhuang 	PM8607_REGULATOR_DRIVER(ldo8),
649be0e2d3eSHaojian Zhuang 	PM8607_REGULATOR_DRIVER(ldo9),
650be0e2d3eSHaojian Zhuang 	PM8607_REGULATOR_DRIVER(ldo10),
651be0e2d3eSHaojian Zhuang 	PM8607_REGULATOR_DRIVER(ldo12),
652be0e2d3eSHaojian Zhuang 	PM8607_REGULATOR_DRIVER(ldo14),
653be0e2d3eSHaojian Zhuang };
654be0e2d3eSHaojian Zhuang 
655be0e2d3eSHaojian Zhuang static int __init pm8607_regulator_init(void)
656be0e2d3eSHaojian Zhuang {
657be0e2d3eSHaojian Zhuang 	int i, count, ret;
658be0e2d3eSHaojian Zhuang 
659be0e2d3eSHaojian Zhuang 	count = ARRAY_SIZE(pm8607_regulator_driver);
660be0e2d3eSHaojian Zhuang 	for (i = 0; i < count; i++) {
661be0e2d3eSHaojian Zhuang 		ret = platform_driver_register(&pm8607_regulator_driver[i]);
662be0e2d3eSHaojian Zhuang 		if (ret != 0)
663be0e2d3eSHaojian Zhuang 			pr_err("Failed to register regulator driver: %d\n",
664be0e2d3eSHaojian Zhuang 				ret);
665be0e2d3eSHaojian Zhuang 	}
666be0e2d3eSHaojian Zhuang 	return 0;
667be0e2d3eSHaojian Zhuang }
668be0e2d3eSHaojian Zhuang subsys_initcall(pm8607_regulator_init);
669be0e2d3eSHaojian Zhuang 
670be0e2d3eSHaojian Zhuang static void __exit pm8607_regulator_exit(void)
671be0e2d3eSHaojian Zhuang {
672be0e2d3eSHaojian Zhuang 	int i, count;
673be0e2d3eSHaojian Zhuang 
674be0e2d3eSHaojian Zhuang 	count = ARRAY_SIZE(pm8607_regulator_driver);
675be0e2d3eSHaojian Zhuang 	for (i = 0; i < count; i++)
676be0e2d3eSHaojian Zhuang 		platform_driver_unregister(&pm8607_regulator_driver[i]);
677be0e2d3eSHaojian Zhuang }
678be0e2d3eSHaojian Zhuang module_exit(pm8607_regulator_exit);
679be0e2d3eSHaojian Zhuang 
680be0e2d3eSHaojian Zhuang MODULE_LICENSE("GPL");
681be0e2d3eSHaojian Zhuang MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
682be0e2d3eSHaojian Zhuang MODULE_DESCRIPTION("Regulator Driver for Marvell 88PM8607 PMIC");
683be0e2d3eSHaojian Zhuang MODULE_ALIAS("platform:88pm8607-regulator");
684