xref: /OK3568_Linux_fs/kernel/drivers/regulator/wm8350-regulator.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun //
3*4882a593Smuzhiyun // wm8350.c  --  Voltage and current regulation for the Wolfson WM8350 PMIC
4*4882a593Smuzhiyun //
5*4882a593Smuzhiyun // Copyright 2007, 2008 Wolfson Microelectronics PLC.
6*4882a593Smuzhiyun //
7*4882a593Smuzhiyun // Author: Liam Girdwood
8*4882a593Smuzhiyun //         linux@wolfsonmicro.com
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/module.h>
11*4882a593Smuzhiyun #include <linux/moduleparam.h>
12*4882a593Smuzhiyun #include <linux/init.h>
13*4882a593Smuzhiyun #include <linux/bitops.h>
14*4882a593Smuzhiyun #include <linux/err.h>
15*4882a593Smuzhiyun #include <linux/i2c.h>
16*4882a593Smuzhiyun #include <linux/mfd/wm8350/core.h>
17*4882a593Smuzhiyun #include <linux/mfd/wm8350/pmic.h>
18*4882a593Smuzhiyun #include <linux/platform_device.h>
19*4882a593Smuzhiyun #include <linux/regulator/driver.h>
20*4882a593Smuzhiyun #include <linux/regulator/machine.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun /* Maximum value possible for VSEL */
23*4882a593Smuzhiyun #define WM8350_DCDC_MAX_VSEL 0x66
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun /* Microamps */
26*4882a593Smuzhiyun static const unsigned int isink_cur[] = {
27*4882a593Smuzhiyun 	4,
28*4882a593Smuzhiyun 	5,
29*4882a593Smuzhiyun 	6,
30*4882a593Smuzhiyun 	7,
31*4882a593Smuzhiyun 	8,
32*4882a593Smuzhiyun 	10,
33*4882a593Smuzhiyun 	11,
34*4882a593Smuzhiyun 	14,
35*4882a593Smuzhiyun 	16,
36*4882a593Smuzhiyun 	19,
37*4882a593Smuzhiyun 	23,
38*4882a593Smuzhiyun 	27,
39*4882a593Smuzhiyun 	32,
40*4882a593Smuzhiyun 	39,
41*4882a593Smuzhiyun 	46,
42*4882a593Smuzhiyun 	54,
43*4882a593Smuzhiyun 	65,
44*4882a593Smuzhiyun 	77,
45*4882a593Smuzhiyun 	92,
46*4882a593Smuzhiyun 	109,
47*4882a593Smuzhiyun 	130,
48*4882a593Smuzhiyun 	154,
49*4882a593Smuzhiyun 	183,
50*4882a593Smuzhiyun 	218,
51*4882a593Smuzhiyun 	259,
52*4882a593Smuzhiyun 	308,
53*4882a593Smuzhiyun 	367,
54*4882a593Smuzhiyun 	436,
55*4882a593Smuzhiyun 	518,
56*4882a593Smuzhiyun 	616,
57*4882a593Smuzhiyun 	733,
58*4882a593Smuzhiyun 	872,
59*4882a593Smuzhiyun 	1037,
60*4882a593Smuzhiyun 	1233,
61*4882a593Smuzhiyun 	1466,
62*4882a593Smuzhiyun 	1744,
63*4882a593Smuzhiyun 	2073,
64*4882a593Smuzhiyun 	2466,
65*4882a593Smuzhiyun 	2933,
66*4882a593Smuzhiyun 	3487,
67*4882a593Smuzhiyun 	4147,
68*4882a593Smuzhiyun 	4932,
69*4882a593Smuzhiyun 	5865,
70*4882a593Smuzhiyun 	6975,
71*4882a593Smuzhiyun 	8294,
72*4882a593Smuzhiyun 	9864,
73*4882a593Smuzhiyun 	11730,
74*4882a593Smuzhiyun 	13949,
75*4882a593Smuzhiyun 	16589,
76*4882a593Smuzhiyun 	19728,
77*4882a593Smuzhiyun 	23460,
78*4882a593Smuzhiyun 	27899,
79*4882a593Smuzhiyun 	33178,
80*4882a593Smuzhiyun 	39455,
81*4882a593Smuzhiyun 	46920,
82*4882a593Smuzhiyun 	55798,
83*4882a593Smuzhiyun 	66355,
84*4882a593Smuzhiyun 	78910,
85*4882a593Smuzhiyun 	93840,
86*4882a593Smuzhiyun 	111596,
87*4882a593Smuzhiyun 	132710,
88*4882a593Smuzhiyun 	157820,
89*4882a593Smuzhiyun 	187681,
90*4882a593Smuzhiyun 	223191
91*4882a593Smuzhiyun };
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun /* turn on ISINK followed by DCDC */
wm8350_isink_enable(struct regulator_dev * rdev)94*4882a593Smuzhiyun static int wm8350_isink_enable(struct regulator_dev *rdev)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun 	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
97*4882a593Smuzhiyun 	int isink = rdev_get_id(rdev);
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	switch (isink) {
100*4882a593Smuzhiyun 	case WM8350_ISINK_A:
101*4882a593Smuzhiyun 		switch (wm8350->pmic.isink_A_dcdc) {
102*4882a593Smuzhiyun 		case WM8350_DCDC_2:
103*4882a593Smuzhiyun 		case WM8350_DCDC_5:
104*4882a593Smuzhiyun 			wm8350_set_bits(wm8350, WM8350_POWER_MGMT_7,
105*4882a593Smuzhiyun 					WM8350_CS1_ENA);
106*4882a593Smuzhiyun 			wm8350_set_bits(wm8350, WM8350_CSA_FLASH_CONTROL,
107*4882a593Smuzhiyun 					WM8350_CS1_DRIVE);
108*4882a593Smuzhiyun 			wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED,
109*4882a593Smuzhiyun 					1 << (wm8350->pmic.isink_A_dcdc -
110*4882a593Smuzhiyun 					      WM8350_DCDC_1));
111*4882a593Smuzhiyun 			break;
112*4882a593Smuzhiyun 		default:
113*4882a593Smuzhiyun 			return -EINVAL;
114*4882a593Smuzhiyun 		}
115*4882a593Smuzhiyun 		break;
116*4882a593Smuzhiyun 	case WM8350_ISINK_B:
117*4882a593Smuzhiyun 		switch (wm8350->pmic.isink_B_dcdc) {
118*4882a593Smuzhiyun 		case WM8350_DCDC_2:
119*4882a593Smuzhiyun 		case WM8350_DCDC_5:
120*4882a593Smuzhiyun 			wm8350_set_bits(wm8350, WM8350_POWER_MGMT_7,
121*4882a593Smuzhiyun 					WM8350_CS2_ENA);
122*4882a593Smuzhiyun 			wm8350_set_bits(wm8350, WM8350_CSB_FLASH_CONTROL,
123*4882a593Smuzhiyun 					WM8350_CS2_DRIVE);
124*4882a593Smuzhiyun 			wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED,
125*4882a593Smuzhiyun 					1 << (wm8350->pmic.isink_B_dcdc -
126*4882a593Smuzhiyun 					      WM8350_DCDC_1));
127*4882a593Smuzhiyun 			break;
128*4882a593Smuzhiyun 		default:
129*4882a593Smuzhiyun 			return -EINVAL;
130*4882a593Smuzhiyun 		}
131*4882a593Smuzhiyun 		break;
132*4882a593Smuzhiyun 	default:
133*4882a593Smuzhiyun 		return -EINVAL;
134*4882a593Smuzhiyun 	}
135*4882a593Smuzhiyun 	return 0;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun 
wm8350_isink_disable(struct regulator_dev * rdev)138*4882a593Smuzhiyun static int wm8350_isink_disable(struct regulator_dev *rdev)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun 	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
141*4882a593Smuzhiyun 	int isink = rdev_get_id(rdev);
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	switch (isink) {
144*4882a593Smuzhiyun 	case WM8350_ISINK_A:
145*4882a593Smuzhiyun 		switch (wm8350->pmic.isink_A_dcdc) {
146*4882a593Smuzhiyun 		case WM8350_DCDC_2:
147*4882a593Smuzhiyun 		case WM8350_DCDC_5:
148*4882a593Smuzhiyun 			wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED,
149*4882a593Smuzhiyun 					  1 << (wm8350->pmic.isink_A_dcdc -
150*4882a593Smuzhiyun 						WM8350_DCDC_1));
151*4882a593Smuzhiyun 			wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_7,
152*4882a593Smuzhiyun 					  WM8350_CS1_ENA);
153*4882a593Smuzhiyun 			break;
154*4882a593Smuzhiyun 		default:
155*4882a593Smuzhiyun 			return -EINVAL;
156*4882a593Smuzhiyun 		}
157*4882a593Smuzhiyun 		break;
158*4882a593Smuzhiyun 	case WM8350_ISINK_B:
159*4882a593Smuzhiyun 		switch (wm8350->pmic.isink_B_dcdc) {
160*4882a593Smuzhiyun 		case WM8350_DCDC_2:
161*4882a593Smuzhiyun 		case WM8350_DCDC_5:
162*4882a593Smuzhiyun 			wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED,
163*4882a593Smuzhiyun 					  1 << (wm8350->pmic.isink_B_dcdc -
164*4882a593Smuzhiyun 						WM8350_DCDC_1));
165*4882a593Smuzhiyun 			wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_7,
166*4882a593Smuzhiyun 					  WM8350_CS2_ENA);
167*4882a593Smuzhiyun 			break;
168*4882a593Smuzhiyun 		default:
169*4882a593Smuzhiyun 			return -EINVAL;
170*4882a593Smuzhiyun 		}
171*4882a593Smuzhiyun 		break;
172*4882a593Smuzhiyun 	default:
173*4882a593Smuzhiyun 		return -EINVAL;
174*4882a593Smuzhiyun 	}
175*4882a593Smuzhiyun 	return 0;
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun 
wm8350_isink_is_enabled(struct regulator_dev * rdev)178*4882a593Smuzhiyun static int wm8350_isink_is_enabled(struct regulator_dev *rdev)
179*4882a593Smuzhiyun {
180*4882a593Smuzhiyun 	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
181*4882a593Smuzhiyun 	int isink = rdev_get_id(rdev);
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	switch (isink) {
184*4882a593Smuzhiyun 	case WM8350_ISINK_A:
185*4882a593Smuzhiyun 		return wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_A) &
186*4882a593Smuzhiyun 		    0x8000;
187*4882a593Smuzhiyun 	case WM8350_ISINK_B:
188*4882a593Smuzhiyun 		return wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_B) &
189*4882a593Smuzhiyun 		    0x8000;
190*4882a593Smuzhiyun 	}
191*4882a593Smuzhiyun 	return -EINVAL;
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun 
wm8350_isink_enable_time(struct regulator_dev * rdev)194*4882a593Smuzhiyun static int wm8350_isink_enable_time(struct regulator_dev *rdev)
195*4882a593Smuzhiyun {
196*4882a593Smuzhiyun 	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
197*4882a593Smuzhiyun 	int isink = rdev_get_id(rdev);
198*4882a593Smuzhiyun 	int reg;
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	switch (isink) {
201*4882a593Smuzhiyun 	case WM8350_ISINK_A:
202*4882a593Smuzhiyun 		reg = wm8350_reg_read(wm8350, WM8350_CSA_FLASH_CONTROL);
203*4882a593Smuzhiyun 		break;
204*4882a593Smuzhiyun 	case WM8350_ISINK_B:
205*4882a593Smuzhiyun 		reg = wm8350_reg_read(wm8350, WM8350_CSB_FLASH_CONTROL);
206*4882a593Smuzhiyun 		break;
207*4882a593Smuzhiyun 	default:
208*4882a593Smuzhiyun 		return -EINVAL;
209*4882a593Smuzhiyun 	}
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	if (reg & WM8350_CS1_FLASH_MODE) {
212*4882a593Smuzhiyun 		switch (reg & WM8350_CS1_ON_RAMP_MASK) {
213*4882a593Smuzhiyun 		case 0:
214*4882a593Smuzhiyun 			return 0;
215*4882a593Smuzhiyun 		case 1:
216*4882a593Smuzhiyun 			return 1950;
217*4882a593Smuzhiyun 		case 2:
218*4882a593Smuzhiyun 			return 3910;
219*4882a593Smuzhiyun 		case 3:
220*4882a593Smuzhiyun 			return 7800;
221*4882a593Smuzhiyun 		}
222*4882a593Smuzhiyun 	} else {
223*4882a593Smuzhiyun 		switch (reg & WM8350_CS1_ON_RAMP_MASK) {
224*4882a593Smuzhiyun 		case 0:
225*4882a593Smuzhiyun 			return 0;
226*4882a593Smuzhiyun 		case 1:
227*4882a593Smuzhiyun 			return 250000;
228*4882a593Smuzhiyun 		case 2:
229*4882a593Smuzhiyun 			return 500000;
230*4882a593Smuzhiyun 		case 3:
231*4882a593Smuzhiyun 			return 1000000;
232*4882a593Smuzhiyun 		}
233*4882a593Smuzhiyun 	}
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	return -EINVAL;
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 
wm8350_isink_set_flash(struct wm8350 * wm8350,int isink,u16 mode,u16 trigger,u16 duration,u16 on_ramp,u16 off_ramp,u16 drive)239*4882a593Smuzhiyun int wm8350_isink_set_flash(struct wm8350 *wm8350, int isink, u16 mode,
240*4882a593Smuzhiyun 			   u16 trigger, u16 duration, u16 on_ramp, u16 off_ramp,
241*4882a593Smuzhiyun 			   u16 drive)
242*4882a593Smuzhiyun {
243*4882a593Smuzhiyun 	switch (isink) {
244*4882a593Smuzhiyun 	case WM8350_ISINK_A:
245*4882a593Smuzhiyun 		wm8350_reg_write(wm8350, WM8350_CSA_FLASH_CONTROL,
246*4882a593Smuzhiyun 				 (mode ? WM8350_CS1_FLASH_MODE : 0) |
247*4882a593Smuzhiyun 				 (trigger ? WM8350_CS1_TRIGSRC : 0) |
248*4882a593Smuzhiyun 				 duration | on_ramp | off_ramp | drive);
249*4882a593Smuzhiyun 		break;
250*4882a593Smuzhiyun 	case WM8350_ISINK_B:
251*4882a593Smuzhiyun 		wm8350_reg_write(wm8350, WM8350_CSB_FLASH_CONTROL,
252*4882a593Smuzhiyun 				 (mode ? WM8350_CS2_FLASH_MODE : 0) |
253*4882a593Smuzhiyun 				 (trigger ? WM8350_CS2_TRIGSRC : 0) |
254*4882a593Smuzhiyun 				 duration | on_ramp | off_ramp | drive);
255*4882a593Smuzhiyun 		break;
256*4882a593Smuzhiyun 	default:
257*4882a593Smuzhiyun 		return -EINVAL;
258*4882a593Smuzhiyun 	}
259*4882a593Smuzhiyun 	return 0;
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(wm8350_isink_set_flash);
262*4882a593Smuzhiyun 
wm8350_dcdc_set_suspend_voltage(struct regulator_dev * rdev,int uV)263*4882a593Smuzhiyun static int wm8350_dcdc_set_suspend_voltage(struct regulator_dev *rdev, int uV)
264*4882a593Smuzhiyun {
265*4882a593Smuzhiyun 	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
266*4882a593Smuzhiyun 	int sel, volt_reg, dcdc = rdev_get_id(rdev);
267*4882a593Smuzhiyun 	u16 val;
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 	dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, dcdc, uV / 1000);
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	switch (dcdc) {
272*4882a593Smuzhiyun 	case WM8350_DCDC_1:
273*4882a593Smuzhiyun 		volt_reg = WM8350_DCDC1_LOW_POWER;
274*4882a593Smuzhiyun 		break;
275*4882a593Smuzhiyun 	case WM8350_DCDC_3:
276*4882a593Smuzhiyun 		volt_reg = WM8350_DCDC3_LOW_POWER;
277*4882a593Smuzhiyun 		break;
278*4882a593Smuzhiyun 	case WM8350_DCDC_4:
279*4882a593Smuzhiyun 		volt_reg = WM8350_DCDC4_LOW_POWER;
280*4882a593Smuzhiyun 		break;
281*4882a593Smuzhiyun 	case WM8350_DCDC_6:
282*4882a593Smuzhiyun 		volt_reg = WM8350_DCDC6_LOW_POWER;
283*4882a593Smuzhiyun 		break;
284*4882a593Smuzhiyun 	case WM8350_DCDC_2:
285*4882a593Smuzhiyun 	case WM8350_DCDC_5:
286*4882a593Smuzhiyun 	default:
287*4882a593Smuzhiyun 		return -EINVAL;
288*4882a593Smuzhiyun 	}
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	sel = regulator_map_voltage_linear(rdev, uV, uV);
291*4882a593Smuzhiyun 	if (sel < 0)
292*4882a593Smuzhiyun 		return sel;
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	/* all DCDCs have same mV bits */
295*4882a593Smuzhiyun 	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK;
296*4882a593Smuzhiyun 	wm8350_reg_write(wm8350, volt_reg, val | sel);
297*4882a593Smuzhiyun 	return 0;
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun 
wm8350_dcdc_set_suspend_enable(struct regulator_dev * rdev)300*4882a593Smuzhiyun static int wm8350_dcdc_set_suspend_enable(struct regulator_dev *rdev)
301*4882a593Smuzhiyun {
302*4882a593Smuzhiyun 	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
303*4882a593Smuzhiyun 	int dcdc = rdev_get_id(rdev);
304*4882a593Smuzhiyun 	u16 val;
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	switch (dcdc) {
307*4882a593Smuzhiyun 	case WM8350_DCDC_1:
308*4882a593Smuzhiyun 		val = wm8350_reg_read(wm8350, WM8350_DCDC1_LOW_POWER)
309*4882a593Smuzhiyun 			& ~WM8350_DCDC_HIB_MODE_MASK;
310*4882a593Smuzhiyun 		wm8350_reg_write(wm8350, WM8350_DCDC1_LOW_POWER,
311*4882a593Smuzhiyun 			val | wm8350->pmic.dcdc1_hib_mode);
312*4882a593Smuzhiyun 		break;
313*4882a593Smuzhiyun 	case WM8350_DCDC_3:
314*4882a593Smuzhiyun 		val = wm8350_reg_read(wm8350, WM8350_DCDC3_LOW_POWER)
315*4882a593Smuzhiyun 			& ~WM8350_DCDC_HIB_MODE_MASK;
316*4882a593Smuzhiyun 		wm8350_reg_write(wm8350, WM8350_DCDC3_LOW_POWER,
317*4882a593Smuzhiyun 			val | wm8350->pmic.dcdc3_hib_mode);
318*4882a593Smuzhiyun 		break;
319*4882a593Smuzhiyun 	case WM8350_DCDC_4:
320*4882a593Smuzhiyun 		val = wm8350_reg_read(wm8350, WM8350_DCDC4_LOW_POWER)
321*4882a593Smuzhiyun 			& ~WM8350_DCDC_HIB_MODE_MASK;
322*4882a593Smuzhiyun 		wm8350_reg_write(wm8350, WM8350_DCDC4_LOW_POWER,
323*4882a593Smuzhiyun 			val | wm8350->pmic.dcdc4_hib_mode);
324*4882a593Smuzhiyun 		break;
325*4882a593Smuzhiyun 	case WM8350_DCDC_6:
326*4882a593Smuzhiyun 		val = wm8350_reg_read(wm8350, WM8350_DCDC6_LOW_POWER)
327*4882a593Smuzhiyun 			& ~WM8350_DCDC_HIB_MODE_MASK;
328*4882a593Smuzhiyun 		wm8350_reg_write(wm8350, WM8350_DCDC6_LOW_POWER,
329*4882a593Smuzhiyun 			val | wm8350->pmic.dcdc6_hib_mode);
330*4882a593Smuzhiyun 		break;
331*4882a593Smuzhiyun 	case WM8350_DCDC_2:
332*4882a593Smuzhiyun 	case WM8350_DCDC_5:
333*4882a593Smuzhiyun 	default:
334*4882a593Smuzhiyun 		return -EINVAL;
335*4882a593Smuzhiyun 	}
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	return 0;
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun 
wm8350_dcdc_set_suspend_disable(struct regulator_dev * rdev)340*4882a593Smuzhiyun static int wm8350_dcdc_set_suspend_disable(struct regulator_dev *rdev)
341*4882a593Smuzhiyun {
342*4882a593Smuzhiyun 	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
343*4882a593Smuzhiyun 	int dcdc = rdev_get_id(rdev);
344*4882a593Smuzhiyun 	u16 val;
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	switch (dcdc) {
347*4882a593Smuzhiyun 	case WM8350_DCDC_1:
348*4882a593Smuzhiyun 		val = wm8350_reg_read(wm8350, WM8350_DCDC1_LOW_POWER);
349*4882a593Smuzhiyun 		wm8350->pmic.dcdc1_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
350*4882a593Smuzhiyun 		wm8350_reg_write(wm8350, WM8350_DCDC1_LOW_POWER,
351*4882a593Smuzhiyun 				 val | WM8350_DCDC_HIB_MODE_DIS);
352*4882a593Smuzhiyun 		break;
353*4882a593Smuzhiyun 	case WM8350_DCDC_3:
354*4882a593Smuzhiyun 		val = wm8350_reg_read(wm8350, WM8350_DCDC3_LOW_POWER);
355*4882a593Smuzhiyun 		wm8350->pmic.dcdc3_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
356*4882a593Smuzhiyun 		wm8350_reg_write(wm8350, WM8350_DCDC3_LOW_POWER,
357*4882a593Smuzhiyun 				 val | WM8350_DCDC_HIB_MODE_DIS);
358*4882a593Smuzhiyun 		break;
359*4882a593Smuzhiyun 	case WM8350_DCDC_4:
360*4882a593Smuzhiyun 		val = wm8350_reg_read(wm8350, WM8350_DCDC4_LOW_POWER);
361*4882a593Smuzhiyun 		wm8350->pmic.dcdc4_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
362*4882a593Smuzhiyun 		wm8350_reg_write(wm8350, WM8350_DCDC4_LOW_POWER,
363*4882a593Smuzhiyun 				 val | WM8350_DCDC_HIB_MODE_DIS);
364*4882a593Smuzhiyun 		break;
365*4882a593Smuzhiyun 	case WM8350_DCDC_6:
366*4882a593Smuzhiyun 		val = wm8350_reg_read(wm8350, WM8350_DCDC6_LOW_POWER);
367*4882a593Smuzhiyun 		wm8350->pmic.dcdc6_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
368*4882a593Smuzhiyun 		wm8350_reg_write(wm8350, WM8350_DCDC6_LOW_POWER,
369*4882a593Smuzhiyun 				 val | WM8350_DCDC_HIB_MODE_DIS);
370*4882a593Smuzhiyun 		break;
371*4882a593Smuzhiyun 	case WM8350_DCDC_2:
372*4882a593Smuzhiyun 	case WM8350_DCDC_5:
373*4882a593Smuzhiyun 	default:
374*4882a593Smuzhiyun 		return -EINVAL;
375*4882a593Smuzhiyun 	}
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 	return 0;
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun 
wm8350_dcdc25_set_suspend_enable(struct regulator_dev * rdev)380*4882a593Smuzhiyun static int wm8350_dcdc25_set_suspend_enable(struct regulator_dev *rdev)
381*4882a593Smuzhiyun {
382*4882a593Smuzhiyun 	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
383*4882a593Smuzhiyun 	int dcdc = rdev_get_id(rdev);
384*4882a593Smuzhiyun 	u16 val;
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	switch (dcdc) {
387*4882a593Smuzhiyun 	case WM8350_DCDC_2:
388*4882a593Smuzhiyun 		val = wm8350_reg_read(wm8350, WM8350_DCDC2_CONTROL)
389*4882a593Smuzhiyun 		    & ~WM8350_DC2_HIB_MODE_MASK;
390*4882a593Smuzhiyun 		wm8350_reg_write(wm8350, WM8350_DCDC2_CONTROL, val |
391*4882a593Smuzhiyun 		    (WM8350_DC2_HIB_MODE_ACTIVE << WM8350_DC2_HIB_MODE_SHIFT));
392*4882a593Smuzhiyun 		break;
393*4882a593Smuzhiyun 	case WM8350_DCDC_5:
394*4882a593Smuzhiyun 		val = wm8350_reg_read(wm8350, WM8350_DCDC5_CONTROL)
395*4882a593Smuzhiyun 		    & ~WM8350_DC5_HIB_MODE_MASK;
396*4882a593Smuzhiyun 		wm8350_reg_write(wm8350, WM8350_DCDC5_CONTROL, val |
397*4882a593Smuzhiyun 		    (WM8350_DC5_HIB_MODE_ACTIVE << WM8350_DC5_HIB_MODE_SHIFT));
398*4882a593Smuzhiyun 		break;
399*4882a593Smuzhiyun 	default:
400*4882a593Smuzhiyun 		return -EINVAL;
401*4882a593Smuzhiyun 	}
402*4882a593Smuzhiyun 	return 0;
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun 
wm8350_dcdc25_set_suspend_disable(struct regulator_dev * rdev)405*4882a593Smuzhiyun static int wm8350_dcdc25_set_suspend_disable(struct regulator_dev *rdev)
406*4882a593Smuzhiyun {
407*4882a593Smuzhiyun 	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
408*4882a593Smuzhiyun 	int dcdc = rdev_get_id(rdev);
409*4882a593Smuzhiyun 	u16 val;
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	switch (dcdc) {
412*4882a593Smuzhiyun 	case WM8350_DCDC_2:
413*4882a593Smuzhiyun 		val = wm8350_reg_read(wm8350, WM8350_DCDC2_CONTROL)
414*4882a593Smuzhiyun 		    & ~WM8350_DC2_HIB_MODE_MASK;
415*4882a593Smuzhiyun 		wm8350_reg_write(wm8350, WM8350_DCDC2_CONTROL, val |
416*4882a593Smuzhiyun 		    (WM8350_DC2_HIB_MODE_DISABLE << WM8350_DC2_HIB_MODE_SHIFT));
417*4882a593Smuzhiyun 		break;
418*4882a593Smuzhiyun 	case WM8350_DCDC_5:
419*4882a593Smuzhiyun 		val = wm8350_reg_read(wm8350, WM8350_DCDC5_CONTROL)
420*4882a593Smuzhiyun 		    & ~WM8350_DC5_HIB_MODE_MASK;
421*4882a593Smuzhiyun 		wm8350_reg_write(wm8350, WM8350_DCDC5_CONTROL, val |
422*4882a593Smuzhiyun 		    (WM8350_DC5_HIB_MODE_DISABLE << WM8350_DC5_HIB_MODE_SHIFT));
423*4882a593Smuzhiyun 		break;
424*4882a593Smuzhiyun 	default:
425*4882a593Smuzhiyun 		return -EINVAL;
426*4882a593Smuzhiyun 	}
427*4882a593Smuzhiyun 	return 0;
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun 
wm8350_dcdc_set_suspend_mode(struct regulator_dev * rdev,unsigned int mode)430*4882a593Smuzhiyun static int wm8350_dcdc_set_suspend_mode(struct regulator_dev *rdev,
431*4882a593Smuzhiyun 	unsigned int mode)
432*4882a593Smuzhiyun {
433*4882a593Smuzhiyun 	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
434*4882a593Smuzhiyun 	int dcdc = rdev_get_id(rdev);
435*4882a593Smuzhiyun 	u16 *hib_mode;
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 	switch (dcdc) {
438*4882a593Smuzhiyun 	case WM8350_DCDC_1:
439*4882a593Smuzhiyun 		hib_mode = &wm8350->pmic.dcdc1_hib_mode;
440*4882a593Smuzhiyun 		break;
441*4882a593Smuzhiyun 	case WM8350_DCDC_3:
442*4882a593Smuzhiyun 		hib_mode = &wm8350->pmic.dcdc3_hib_mode;
443*4882a593Smuzhiyun 		break;
444*4882a593Smuzhiyun 	case WM8350_DCDC_4:
445*4882a593Smuzhiyun 		hib_mode = &wm8350->pmic.dcdc4_hib_mode;
446*4882a593Smuzhiyun 		break;
447*4882a593Smuzhiyun 	case WM8350_DCDC_6:
448*4882a593Smuzhiyun 		hib_mode = &wm8350->pmic.dcdc6_hib_mode;
449*4882a593Smuzhiyun 		break;
450*4882a593Smuzhiyun 	case WM8350_DCDC_2:
451*4882a593Smuzhiyun 	case WM8350_DCDC_5:
452*4882a593Smuzhiyun 	default:
453*4882a593Smuzhiyun 		return -EINVAL;
454*4882a593Smuzhiyun 	}
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	switch (mode) {
457*4882a593Smuzhiyun 	case REGULATOR_MODE_NORMAL:
458*4882a593Smuzhiyun 		*hib_mode = WM8350_DCDC_HIB_MODE_IMAGE;
459*4882a593Smuzhiyun 		break;
460*4882a593Smuzhiyun 	case REGULATOR_MODE_IDLE:
461*4882a593Smuzhiyun 		*hib_mode = WM8350_DCDC_HIB_MODE_STANDBY;
462*4882a593Smuzhiyun 		break;
463*4882a593Smuzhiyun 	case REGULATOR_MODE_STANDBY:
464*4882a593Smuzhiyun 		*hib_mode = WM8350_DCDC_HIB_MODE_LDO_IM;
465*4882a593Smuzhiyun 		break;
466*4882a593Smuzhiyun 	default:
467*4882a593Smuzhiyun 		return -EINVAL;
468*4882a593Smuzhiyun 	}
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun 	return 0;
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun static const struct linear_range wm8350_ldo_ranges[] = {
474*4882a593Smuzhiyun 	REGULATOR_LINEAR_RANGE(900000, 0, 15, 50000),
475*4882a593Smuzhiyun 	REGULATOR_LINEAR_RANGE(1800000, 16, 31, 100000),
476*4882a593Smuzhiyun };
477*4882a593Smuzhiyun 
wm8350_ldo_set_suspend_voltage(struct regulator_dev * rdev,int uV)478*4882a593Smuzhiyun static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV)
479*4882a593Smuzhiyun {
480*4882a593Smuzhiyun 	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
481*4882a593Smuzhiyun 	int sel, volt_reg, ldo = rdev_get_id(rdev);
482*4882a593Smuzhiyun 	u16 val;
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 	dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, ldo, uV / 1000);
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	switch (ldo) {
487*4882a593Smuzhiyun 	case WM8350_LDO_1:
488*4882a593Smuzhiyun 		volt_reg = WM8350_LDO1_LOW_POWER;
489*4882a593Smuzhiyun 		break;
490*4882a593Smuzhiyun 	case WM8350_LDO_2:
491*4882a593Smuzhiyun 		volt_reg = WM8350_LDO2_LOW_POWER;
492*4882a593Smuzhiyun 		break;
493*4882a593Smuzhiyun 	case WM8350_LDO_3:
494*4882a593Smuzhiyun 		volt_reg = WM8350_LDO3_LOW_POWER;
495*4882a593Smuzhiyun 		break;
496*4882a593Smuzhiyun 	case WM8350_LDO_4:
497*4882a593Smuzhiyun 		volt_reg = WM8350_LDO4_LOW_POWER;
498*4882a593Smuzhiyun 		break;
499*4882a593Smuzhiyun 	default:
500*4882a593Smuzhiyun 		return -EINVAL;
501*4882a593Smuzhiyun 	}
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 	sel = regulator_map_voltage_linear_range(rdev, uV, uV);
504*4882a593Smuzhiyun 	if (sel < 0)
505*4882a593Smuzhiyun 		return sel;
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 	/* all LDOs have same mV bits */
508*4882a593Smuzhiyun 	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_VSEL_MASK;
509*4882a593Smuzhiyun 	wm8350_reg_write(wm8350, volt_reg, val | sel);
510*4882a593Smuzhiyun 	return 0;
511*4882a593Smuzhiyun }
512*4882a593Smuzhiyun 
wm8350_ldo_set_suspend_enable(struct regulator_dev * rdev)513*4882a593Smuzhiyun static int wm8350_ldo_set_suspend_enable(struct regulator_dev *rdev)
514*4882a593Smuzhiyun {
515*4882a593Smuzhiyun 	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
516*4882a593Smuzhiyun 	int volt_reg, ldo = rdev_get_id(rdev);
517*4882a593Smuzhiyun 	u16 val;
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun 	switch (ldo) {
520*4882a593Smuzhiyun 	case WM8350_LDO_1:
521*4882a593Smuzhiyun 		volt_reg = WM8350_LDO1_LOW_POWER;
522*4882a593Smuzhiyun 		break;
523*4882a593Smuzhiyun 	case WM8350_LDO_2:
524*4882a593Smuzhiyun 		volt_reg = WM8350_LDO2_LOW_POWER;
525*4882a593Smuzhiyun 		break;
526*4882a593Smuzhiyun 	case WM8350_LDO_3:
527*4882a593Smuzhiyun 		volt_reg = WM8350_LDO3_LOW_POWER;
528*4882a593Smuzhiyun 		break;
529*4882a593Smuzhiyun 	case WM8350_LDO_4:
530*4882a593Smuzhiyun 		volt_reg = WM8350_LDO4_LOW_POWER;
531*4882a593Smuzhiyun 		break;
532*4882a593Smuzhiyun 	default:
533*4882a593Smuzhiyun 		return -EINVAL;
534*4882a593Smuzhiyun 	}
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun 	/* all LDOs have same mV bits */
537*4882a593Smuzhiyun 	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_HIB_MODE_MASK;
538*4882a593Smuzhiyun 	wm8350_reg_write(wm8350, volt_reg, val);
539*4882a593Smuzhiyun 	return 0;
540*4882a593Smuzhiyun }
541*4882a593Smuzhiyun 
wm8350_ldo_set_suspend_disable(struct regulator_dev * rdev)542*4882a593Smuzhiyun static int wm8350_ldo_set_suspend_disable(struct regulator_dev *rdev)
543*4882a593Smuzhiyun {
544*4882a593Smuzhiyun 	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
545*4882a593Smuzhiyun 	int volt_reg, ldo = rdev_get_id(rdev);
546*4882a593Smuzhiyun 	u16 val;
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun 	switch (ldo) {
549*4882a593Smuzhiyun 	case WM8350_LDO_1:
550*4882a593Smuzhiyun 		volt_reg = WM8350_LDO1_LOW_POWER;
551*4882a593Smuzhiyun 		break;
552*4882a593Smuzhiyun 	case WM8350_LDO_2:
553*4882a593Smuzhiyun 		volt_reg = WM8350_LDO2_LOW_POWER;
554*4882a593Smuzhiyun 		break;
555*4882a593Smuzhiyun 	case WM8350_LDO_3:
556*4882a593Smuzhiyun 		volt_reg = WM8350_LDO3_LOW_POWER;
557*4882a593Smuzhiyun 		break;
558*4882a593Smuzhiyun 	case WM8350_LDO_4:
559*4882a593Smuzhiyun 		volt_reg = WM8350_LDO4_LOW_POWER;
560*4882a593Smuzhiyun 		break;
561*4882a593Smuzhiyun 	default:
562*4882a593Smuzhiyun 		return -EINVAL;
563*4882a593Smuzhiyun 	}
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun 	/* all LDOs have same mV bits */
566*4882a593Smuzhiyun 	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_HIB_MODE_MASK;
567*4882a593Smuzhiyun 	wm8350_reg_write(wm8350, volt_reg, val | WM8350_LDO1_HIB_MODE_DIS);
568*4882a593Smuzhiyun 	return 0;
569*4882a593Smuzhiyun }
570*4882a593Smuzhiyun 
wm8350_dcdc_set_slot(struct wm8350 * wm8350,int dcdc,u16 start,u16 stop,u16 fault)571*4882a593Smuzhiyun int wm8350_dcdc_set_slot(struct wm8350 *wm8350, int dcdc, u16 start,
572*4882a593Smuzhiyun 			 u16 stop, u16 fault)
573*4882a593Smuzhiyun {
574*4882a593Smuzhiyun 	int slot_reg;
575*4882a593Smuzhiyun 	u16 val;
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun 	dev_dbg(wm8350->dev, "%s %d start %d stop %d\n",
578*4882a593Smuzhiyun 		__func__, dcdc, start, stop);
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun 	/* slot valid ? */
581*4882a593Smuzhiyun 	if (start > 15 || stop > 15)
582*4882a593Smuzhiyun 		return -EINVAL;
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun 	switch (dcdc) {
585*4882a593Smuzhiyun 	case WM8350_DCDC_1:
586*4882a593Smuzhiyun 		slot_reg = WM8350_DCDC1_TIMEOUTS;
587*4882a593Smuzhiyun 		break;
588*4882a593Smuzhiyun 	case WM8350_DCDC_2:
589*4882a593Smuzhiyun 		slot_reg = WM8350_DCDC2_TIMEOUTS;
590*4882a593Smuzhiyun 		break;
591*4882a593Smuzhiyun 	case WM8350_DCDC_3:
592*4882a593Smuzhiyun 		slot_reg = WM8350_DCDC3_TIMEOUTS;
593*4882a593Smuzhiyun 		break;
594*4882a593Smuzhiyun 	case WM8350_DCDC_4:
595*4882a593Smuzhiyun 		slot_reg = WM8350_DCDC4_TIMEOUTS;
596*4882a593Smuzhiyun 		break;
597*4882a593Smuzhiyun 	case WM8350_DCDC_5:
598*4882a593Smuzhiyun 		slot_reg = WM8350_DCDC5_TIMEOUTS;
599*4882a593Smuzhiyun 		break;
600*4882a593Smuzhiyun 	case WM8350_DCDC_6:
601*4882a593Smuzhiyun 		slot_reg = WM8350_DCDC6_TIMEOUTS;
602*4882a593Smuzhiyun 		break;
603*4882a593Smuzhiyun 	default:
604*4882a593Smuzhiyun 		return -EINVAL;
605*4882a593Smuzhiyun 	}
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun 	val = wm8350_reg_read(wm8350, slot_reg) &
608*4882a593Smuzhiyun 	    ~(WM8350_DC1_ENSLOT_MASK | WM8350_DC1_SDSLOT_MASK |
609*4882a593Smuzhiyun 	      WM8350_DC1_ERRACT_MASK);
610*4882a593Smuzhiyun 	wm8350_reg_write(wm8350, slot_reg,
611*4882a593Smuzhiyun 			 val | (start << WM8350_DC1_ENSLOT_SHIFT) |
612*4882a593Smuzhiyun 			 (stop << WM8350_DC1_SDSLOT_SHIFT) |
613*4882a593Smuzhiyun 			 (fault << WM8350_DC1_ERRACT_SHIFT));
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun 	return 0;
616*4882a593Smuzhiyun }
617*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(wm8350_dcdc_set_slot);
618*4882a593Smuzhiyun 
wm8350_ldo_set_slot(struct wm8350 * wm8350,int ldo,u16 start,u16 stop)619*4882a593Smuzhiyun int wm8350_ldo_set_slot(struct wm8350 *wm8350, int ldo, u16 start, u16 stop)
620*4882a593Smuzhiyun {
621*4882a593Smuzhiyun 	int slot_reg;
622*4882a593Smuzhiyun 	u16 val;
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun 	dev_dbg(wm8350->dev, "%s %d start %d stop %d\n",
625*4882a593Smuzhiyun 		__func__, ldo, start, stop);
626*4882a593Smuzhiyun 
627*4882a593Smuzhiyun 	/* slot valid ? */
628*4882a593Smuzhiyun 	if (start > 15 || stop > 15)
629*4882a593Smuzhiyun 		return -EINVAL;
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun 	switch (ldo) {
632*4882a593Smuzhiyun 	case WM8350_LDO_1:
633*4882a593Smuzhiyun 		slot_reg = WM8350_LDO1_TIMEOUTS;
634*4882a593Smuzhiyun 		break;
635*4882a593Smuzhiyun 	case WM8350_LDO_2:
636*4882a593Smuzhiyun 		slot_reg = WM8350_LDO2_TIMEOUTS;
637*4882a593Smuzhiyun 		break;
638*4882a593Smuzhiyun 	case WM8350_LDO_3:
639*4882a593Smuzhiyun 		slot_reg = WM8350_LDO3_TIMEOUTS;
640*4882a593Smuzhiyun 		break;
641*4882a593Smuzhiyun 	case WM8350_LDO_4:
642*4882a593Smuzhiyun 		slot_reg = WM8350_LDO4_TIMEOUTS;
643*4882a593Smuzhiyun 		break;
644*4882a593Smuzhiyun 	default:
645*4882a593Smuzhiyun 		return -EINVAL;
646*4882a593Smuzhiyun 	}
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun 	val = wm8350_reg_read(wm8350, slot_reg) & ~WM8350_LDO1_SDSLOT_MASK;
649*4882a593Smuzhiyun 	wm8350_reg_write(wm8350, slot_reg, val | ((start << 10) | (stop << 6)));
650*4882a593Smuzhiyun 	return 0;
651*4882a593Smuzhiyun }
652*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(wm8350_ldo_set_slot);
653*4882a593Smuzhiyun 
wm8350_dcdc25_set_mode(struct wm8350 * wm8350,int dcdc,u16 mode,u16 ilim,u16 ramp,u16 feedback)654*4882a593Smuzhiyun int wm8350_dcdc25_set_mode(struct wm8350 *wm8350, int dcdc, u16 mode,
655*4882a593Smuzhiyun 			   u16 ilim, u16 ramp, u16 feedback)
656*4882a593Smuzhiyun {
657*4882a593Smuzhiyun 	u16 val;
658*4882a593Smuzhiyun 
659*4882a593Smuzhiyun 	dev_dbg(wm8350->dev, "%s %d mode: %s %s\n", __func__, dcdc,
660*4882a593Smuzhiyun 		mode ? "normal" : "boost", ilim ? "low" : "normal");
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	switch (dcdc) {
663*4882a593Smuzhiyun 	case WM8350_DCDC_2:
664*4882a593Smuzhiyun 		val = wm8350_reg_read(wm8350, WM8350_DCDC2_CONTROL)
665*4882a593Smuzhiyun 		    & ~(WM8350_DC2_MODE_MASK | WM8350_DC2_ILIM_MASK |
666*4882a593Smuzhiyun 			WM8350_DC2_RMP_MASK | WM8350_DC2_FBSRC_MASK);
667*4882a593Smuzhiyun 		wm8350_reg_write(wm8350, WM8350_DCDC2_CONTROL, val |
668*4882a593Smuzhiyun 				 (mode << WM8350_DC2_MODE_SHIFT) |
669*4882a593Smuzhiyun 				 (ilim << WM8350_DC2_ILIM_SHIFT) |
670*4882a593Smuzhiyun 				 (ramp << WM8350_DC2_RMP_SHIFT) |
671*4882a593Smuzhiyun 				 (feedback << WM8350_DC2_FBSRC_SHIFT));
672*4882a593Smuzhiyun 		break;
673*4882a593Smuzhiyun 	case WM8350_DCDC_5:
674*4882a593Smuzhiyun 		val = wm8350_reg_read(wm8350, WM8350_DCDC5_CONTROL)
675*4882a593Smuzhiyun 		    & ~(WM8350_DC5_MODE_MASK | WM8350_DC5_ILIM_MASK |
676*4882a593Smuzhiyun 			WM8350_DC5_RMP_MASK | WM8350_DC5_FBSRC_MASK);
677*4882a593Smuzhiyun 		wm8350_reg_write(wm8350, WM8350_DCDC5_CONTROL, val |
678*4882a593Smuzhiyun 				 (mode << WM8350_DC5_MODE_SHIFT) |
679*4882a593Smuzhiyun 				 (ilim << WM8350_DC5_ILIM_SHIFT) |
680*4882a593Smuzhiyun 				 (ramp << WM8350_DC5_RMP_SHIFT) |
681*4882a593Smuzhiyun 				 (feedback << WM8350_DC5_FBSRC_SHIFT));
682*4882a593Smuzhiyun 		break;
683*4882a593Smuzhiyun 	default:
684*4882a593Smuzhiyun 		return -EINVAL;
685*4882a593Smuzhiyun 	}
686*4882a593Smuzhiyun 
687*4882a593Smuzhiyun 	return 0;
688*4882a593Smuzhiyun }
689*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(wm8350_dcdc25_set_mode);
690*4882a593Smuzhiyun 
force_continuous_enable(struct wm8350 * wm8350,int dcdc,int enable)691*4882a593Smuzhiyun static int force_continuous_enable(struct wm8350 *wm8350, int dcdc, int enable)
692*4882a593Smuzhiyun {
693*4882a593Smuzhiyun 	int reg = 0, ret;
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 	switch (dcdc) {
696*4882a593Smuzhiyun 	case WM8350_DCDC_1:
697*4882a593Smuzhiyun 		reg = WM8350_DCDC1_FORCE_PWM;
698*4882a593Smuzhiyun 		break;
699*4882a593Smuzhiyun 	case WM8350_DCDC_3:
700*4882a593Smuzhiyun 		reg = WM8350_DCDC3_FORCE_PWM;
701*4882a593Smuzhiyun 		break;
702*4882a593Smuzhiyun 	case WM8350_DCDC_4:
703*4882a593Smuzhiyun 		reg = WM8350_DCDC4_FORCE_PWM;
704*4882a593Smuzhiyun 		break;
705*4882a593Smuzhiyun 	case WM8350_DCDC_6:
706*4882a593Smuzhiyun 		reg = WM8350_DCDC6_FORCE_PWM;
707*4882a593Smuzhiyun 		break;
708*4882a593Smuzhiyun 	default:
709*4882a593Smuzhiyun 		return -EINVAL;
710*4882a593Smuzhiyun 	}
711*4882a593Smuzhiyun 
712*4882a593Smuzhiyun 	if (enable)
713*4882a593Smuzhiyun 		ret = wm8350_set_bits(wm8350, reg,
714*4882a593Smuzhiyun 			WM8350_DCDC1_FORCE_PWM_ENA);
715*4882a593Smuzhiyun 	else
716*4882a593Smuzhiyun 		ret = wm8350_clear_bits(wm8350, reg,
717*4882a593Smuzhiyun 			WM8350_DCDC1_FORCE_PWM_ENA);
718*4882a593Smuzhiyun 	return ret;
719*4882a593Smuzhiyun }
720*4882a593Smuzhiyun 
wm8350_dcdc_set_mode(struct regulator_dev * rdev,unsigned int mode)721*4882a593Smuzhiyun static int wm8350_dcdc_set_mode(struct regulator_dev *rdev, unsigned int mode)
722*4882a593Smuzhiyun {
723*4882a593Smuzhiyun 	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
724*4882a593Smuzhiyun 	int dcdc = rdev_get_id(rdev);
725*4882a593Smuzhiyun 	u16 val;
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun 	if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
728*4882a593Smuzhiyun 		return -EINVAL;
729*4882a593Smuzhiyun 
730*4882a593Smuzhiyun 	if (dcdc == WM8350_DCDC_2 || dcdc == WM8350_DCDC_5)
731*4882a593Smuzhiyun 		return -EINVAL;
732*4882a593Smuzhiyun 
733*4882a593Smuzhiyun 	val = 1 << (dcdc - WM8350_DCDC_1);
734*4882a593Smuzhiyun 
735*4882a593Smuzhiyun 	switch (mode) {
736*4882a593Smuzhiyun 	case REGULATOR_MODE_FAST:
737*4882a593Smuzhiyun 		/* force continuous mode */
738*4882a593Smuzhiyun 		wm8350_set_bits(wm8350, WM8350_DCDC_ACTIVE_OPTIONS, val);
739*4882a593Smuzhiyun 		wm8350_clear_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val);
740*4882a593Smuzhiyun 		force_continuous_enable(wm8350, dcdc, 1);
741*4882a593Smuzhiyun 		break;
742*4882a593Smuzhiyun 	case REGULATOR_MODE_NORMAL:
743*4882a593Smuzhiyun 		/* active / pulse skipping */
744*4882a593Smuzhiyun 		wm8350_set_bits(wm8350, WM8350_DCDC_ACTIVE_OPTIONS, val);
745*4882a593Smuzhiyun 		wm8350_clear_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val);
746*4882a593Smuzhiyun 		force_continuous_enable(wm8350, dcdc, 0);
747*4882a593Smuzhiyun 		break;
748*4882a593Smuzhiyun 	case REGULATOR_MODE_IDLE:
749*4882a593Smuzhiyun 		/* standby mode */
750*4882a593Smuzhiyun 		force_continuous_enable(wm8350, dcdc, 0);
751*4882a593Smuzhiyun 		wm8350_clear_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val);
752*4882a593Smuzhiyun 		wm8350_clear_bits(wm8350, WM8350_DCDC_ACTIVE_OPTIONS, val);
753*4882a593Smuzhiyun 		break;
754*4882a593Smuzhiyun 	case REGULATOR_MODE_STANDBY:
755*4882a593Smuzhiyun 		/* LDO mode */
756*4882a593Smuzhiyun 		force_continuous_enable(wm8350, dcdc, 0);
757*4882a593Smuzhiyun 		wm8350_set_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val);
758*4882a593Smuzhiyun 		break;
759*4882a593Smuzhiyun 	}
760*4882a593Smuzhiyun 
761*4882a593Smuzhiyun 	return 0;
762*4882a593Smuzhiyun }
763*4882a593Smuzhiyun 
wm8350_dcdc_get_mode(struct regulator_dev * rdev)764*4882a593Smuzhiyun static unsigned int wm8350_dcdc_get_mode(struct regulator_dev *rdev)
765*4882a593Smuzhiyun {
766*4882a593Smuzhiyun 	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
767*4882a593Smuzhiyun 	int dcdc = rdev_get_id(rdev);
768*4882a593Smuzhiyun 	u16 mask, sleep, active, force;
769*4882a593Smuzhiyun 	int mode = REGULATOR_MODE_NORMAL;
770*4882a593Smuzhiyun 	int reg;
771*4882a593Smuzhiyun 
772*4882a593Smuzhiyun 	switch (dcdc) {
773*4882a593Smuzhiyun 	case WM8350_DCDC_1:
774*4882a593Smuzhiyun 		reg = WM8350_DCDC1_FORCE_PWM;
775*4882a593Smuzhiyun 		break;
776*4882a593Smuzhiyun 	case WM8350_DCDC_3:
777*4882a593Smuzhiyun 		reg = WM8350_DCDC3_FORCE_PWM;
778*4882a593Smuzhiyun 		break;
779*4882a593Smuzhiyun 	case WM8350_DCDC_4:
780*4882a593Smuzhiyun 		reg = WM8350_DCDC4_FORCE_PWM;
781*4882a593Smuzhiyun 		break;
782*4882a593Smuzhiyun 	case WM8350_DCDC_6:
783*4882a593Smuzhiyun 		reg = WM8350_DCDC6_FORCE_PWM;
784*4882a593Smuzhiyun 		break;
785*4882a593Smuzhiyun 	default:
786*4882a593Smuzhiyun 		return -EINVAL;
787*4882a593Smuzhiyun 	}
788*4882a593Smuzhiyun 
789*4882a593Smuzhiyun 	mask = 1 << (dcdc - WM8350_DCDC_1);
790*4882a593Smuzhiyun 	active = wm8350_reg_read(wm8350, WM8350_DCDC_ACTIVE_OPTIONS) & mask;
791*4882a593Smuzhiyun 	force = wm8350_reg_read(wm8350, reg) & WM8350_DCDC1_FORCE_PWM_ENA;
792*4882a593Smuzhiyun 	sleep = wm8350_reg_read(wm8350, WM8350_DCDC_SLEEP_OPTIONS) & mask;
793*4882a593Smuzhiyun 
794*4882a593Smuzhiyun 	dev_dbg(wm8350->dev, "mask %x active %x sleep %x force %x",
795*4882a593Smuzhiyun 		mask, active, sleep, force);
796*4882a593Smuzhiyun 
797*4882a593Smuzhiyun 	if (active && !sleep) {
798*4882a593Smuzhiyun 		if (force)
799*4882a593Smuzhiyun 			mode = REGULATOR_MODE_FAST;
800*4882a593Smuzhiyun 		else
801*4882a593Smuzhiyun 			mode = REGULATOR_MODE_NORMAL;
802*4882a593Smuzhiyun 	} else if (!active && !sleep)
803*4882a593Smuzhiyun 		mode = REGULATOR_MODE_IDLE;
804*4882a593Smuzhiyun 	else if (sleep)
805*4882a593Smuzhiyun 		mode = REGULATOR_MODE_STANDBY;
806*4882a593Smuzhiyun 
807*4882a593Smuzhiyun 	return mode;
808*4882a593Smuzhiyun }
809*4882a593Smuzhiyun 
wm8350_ldo_get_mode(struct regulator_dev * rdev)810*4882a593Smuzhiyun static unsigned int wm8350_ldo_get_mode(struct regulator_dev *rdev)
811*4882a593Smuzhiyun {
812*4882a593Smuzhiyun 	return REGULATOR_MODE_NORMAL;
813*4882a593Smuzhiyun }
814*4882a593Smuzhiyun 
815*4882a593Smuzhiyun struct wm8350_dcdc_efficiency {
816*4882a593Smuzhiyun 	int uA_load_min;
817*4882a593Smuzhiyun 	int uA_load_max;
818*4882a593Smuzhiyun 	unsigned int mode;
819*4882a593Smuzhiyun };
820*4882a593Smuzhiyun 
821*4882a593Smuzhiyun static const struct wm8350_dcdc_efficiency dcdc1_6_efficiency[] = {
822*4882a593Smuzhiyun 	{0, 10000, REGULATOR_MODE_STANDBY},       /* 0 - 10mA - LDO */
823*4882a593Smuzhiyun 	{10000, 100000, REGULATOR_MODE_IDLE},     /* 10mA - 100mA - Standby */
824*4882a593Smuzhiyun 	{100000, 1000000, REGULATOR_MODE_NORMAL}, /* > 100mA - Active */
825*4882a593Smuzhiyun 	{-1, -1, REGULATOR_MODE_NORMAL},
826*4882a593Smuzhiyun };
827*4882a593Smuzhiyun 
828*4882a593Smuzhiyun static const struct wm8350_dcdc_efficiency dcdc3_4_efficiency[] = {
829*4882a593Smuzhiyun 	{0, 10000, REGULATOR_MODE_STANDBY},      /* 0 - 10mA - LDO */
830*4882a593Smuzhiyun 	{10000, 100000, REGULATOR_MODE_IDLE},    /* 10mA - 100mA - Standby */
831*4882a593Smuzhiyun 	{100000, 800000, REGULATOR_MODE_NORMAL}, /* > 100mA - Active */
832*4882a593Smuzhiyun 	{-1, -1, REGULATOR_MODE_NORMAL},
833*4882a593Smuzhiyun };
834*4882a593Smuzhiyun 
get_mode(int uA,const struct wm8350_dcdc_efficiency * eff)835*4882a593Smuzhiyun static unsigned int get_mode(int uA, const struct wm8350_dcdc_efficiency *eff)
836*4882a593Smuzhiyun {
837*4882a593Smuzhiyun 	int i = 0;
838*4882a593Smuzhiyun 
839*4882a593Smuzhiyun 	while (eff[i].uA_load_min != -1) {
840*4882a593Smuzhiyun 		if (uA >= eff[i].uA_load_min && uA <= eff[i].uA_load_max)
841*4882a593Smuzhiyun 			return eff[i].mode;
842*4882a593Smuzhiyun 		i++;
843*4882a593Smuzhiyun 	}
844*4882a593Smuzhiyun 	return REGULATOR_MODE_NORMAL;
845*4882a593Smuzhiyun }
846*4882a593Smuzhiyun 
847*4882a593Smuzhiyun /* Query the regulator for it's most efficient mode @ uV,uA
848*4882a593Smuzhiyun  * WM8350 regulator efficiency is pretty similar over
849*4882a593Smuzhiyun  * different input and output uV.
850*4882a593Smuzhiyun  */
wm8350_dcdc_get_optimum_mode(struct regulator_dev * rdev,int input_uV,int output_uV,int output_uA)851*4882a593Smuzhiyun static unsigned int wm8350_dcdc_get_optimum_mode(struct regulator_dev *rdev,
852*4882a593Smuzhiyun 						 int input_uV, int output_uV,
853*4882a593Smuzhiyun 						 int output_uA)
854*4882a593Smuzhiyun {
855*4882a593Smuzhiyun 	int dcdc = rdev_get_id(rdev), mode;
856*4882a593Smuzhiyun 
857*4882a593Smuzhiyun 	switch (dcdc) {
858*4882a593Smuzhiyun 	case WM8350_DCDC_1:
859*4882a593Smuzhiyun 	case WM8350_DCDC_6:
860*4882a593Smuzhiyun 		mode = get_mode(output_uA, dcdc1_6_efficiency);
861*4882a593Smuzhiyun 		break;
862*4882a593Smuzhiyun 	case WM8350_DCDC_3:
863*4882a593Smuzhiyun 	case WM8350_DCDC_4:
864*4882a593Smuzhiyun 		mode = get_mode(output_uA, dcdc3_4_efficiency);
865*4882a593Smuzhiyun 		break;
866*4882a593Smuzhiyun 	default:
867*4882a593Smuzhiyun 		mode = REGULATOR_MODE_NORMAL;
868*4882a593Smuzhiyun 		break;
869*4882a593Smuzhiyun 	}
870*4882a593Smuzhiyun 	return mode;
871*4882a593Smuzhiyun }
872*4882a593Smuzhiyun 
873*4882a593Smuzhiyun static const struct regulator_ops wm8350_dcdc_ops = {
874*4882a593Smuzhiyun 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
875*4882a593Smuzhiyun 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
876*4882a593Smuzhiyun 	.list_voltage = regulator_list_voltage_linear,
877*4882a593Smuzhiyun 	.map_voltage = regulator_map_voltage_linear,
878*4882a593Smuzhiyun 	.enable = regulator_enable_regmap,
879*4882a593Smuzhiyun 	.disable = regulator_disable_regmap,
880*4882a593Smuzhiyun 	.is_enabled = regulator_is_enabled_regmap,
881*4882a593Smuzhiyun 	.get_mode = wm8350_dcdc_get_mode,
882*4882a593Smuzhiyun 	.set_mode = wm8350_dcdc_set_mode,
883*4882a593Smuzhiyun 	.get_optimum_mode = wm8350_dcdc_get_optimum_mode,
884*4882a593Smuzhiyun 	.set_suspend_voltage = wm8350_dcdc_set_suspend_voltage,
885*4882a593Smuzhiyun 	.set_suspend_enable = wm8350_dcdc_set_suspend_enable,
886*4882a593Smuzhiyun 	.set_suspend_disable = wm8350_dcdc_set_suspend_disable,
887*4882a593Smuzhiyun 	.set_suspend_mode = wm8350_dcdc_set_suspend_mode,
888*4882a593Smuzhiyun };
889*4882a593Smuzhiyun 
890*4882a593Smuzhiyun static const struct regulator_ops wm8350_dcdc2_5_ops = {
891*4882a593Smuzhiyun 	.enable = regulator_enable_regmap,
892*4882a593Smuzhiyun 	.disable = regulator_disable_regmap,
893*4882a593Smuzhiyun 	.is_enabled = regulator_is_enabled_regmap,
894*4882a593Smuzhiyun 	.set_suspend_enable = wm8350_dcdc25_set_suspend_enable,
895*4882a593Smuzhiyun 	.set_suspend_disable = wm8350_dcdc25_set_suspend_disable,
896*4882a593Smuzhiyun };
897*4882a593Smuzhiyun 
898*4882a593Smuzhiyun static const struct regulator_ops wm8350_ldo_ops = {
899*4882a593Smuzhiyun 	.map_voltage = regulator_map_voltage_linear_range,
900*4882a593Smuzhiyun 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
901*4882a593Smuzhiyun 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
902*4882a593Smuzhiyun 	.list_voltage = regulator_list_voltage_linear_range,
903*4882a593Smuzhiyun 	.enable = regulator_enable_regmap,
904*4882a593Smuzhiyun 	.disable = regulator_disable_regmap,
905*4882a593Smuzhiyun 	.is_enabled = regulator_is_enabled_regmap,
906*4882a593Smuzhiyun 	.get_mode = wm8350_ldo_get_mode,
907*4882a593Smuzhiyun 	.set_suspend_voltage = wm8350_ldo_set_suspend_voltage,
908*4882a593Smuzhiyun 	.set_suspend_enable = wm8350_ldo_set_suspend_enable,
909*4882a593Smuzhiyun 	.set_suspend_disable = wm8350_ldo_set_suspend_disable,
910*4882a593Smuzhiyun };
911*4882a593Smuzhiyun 
912*4882a593Smuzhiyun static const struct regulator_ops wm8350_isink_ops = {
913*4882a593Smuzhiyun 	.set_current_limit = regulator_set_current_limit_regmap,
914*4882a593Smuzhiyun 	.get_current_limit = regulator_get_current_limit_regmap,
915*4882a593Smuzhiyun 	.enable = wm8350_isink_enable,
916*4882a593Smuzhiyun 	.disable = wm8350_isink_disable,
917*4882a593Smuzhiyun 	.is_enabled = wm8350_isink_is_enabled,
918*4882a593Smuzhiyun 	.enable_time = wm8350_isink_enable_time,
919*4882a593Smuzhiyun };
920*4882a593Smuzhiyun 
921*4882a593Smuzhiyun static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
922*4882a593Smuzhiyun 	{
923*4882a593Smuzhiyun 		.name = "DCDC1",
924*4882a593Smuzhiyun 		.id = WM8350_DCDC_1,
925*4882a593Smuzhiyun 		.ops = &wm8350_dcdc_ops,
926*4882a593Smuzhiyun 		.irq = WM8350_IRQ_UV_DC1,
927*4882a593Smuzhiyun 		.type = REGULATOR_VOLTAGE,
928*4882a593Smuzhiyun 		.n_voltages = WM8350_DCDC_MAX_VSEL + 1,
929*4882a593Smuzhiyun 		.min_uV = 850000,
930*4882a593Smuzhiyun 		.uV_step = 25000,
931*4882a593Smuzhiyun 		.vsel_reg = WM8350_DCDC1_CONTROL,
932*4882a593Smuzhiyun 		.vsel_mask = WM8350_DC1_VSEL_MASK,
933*4882a593Smuzhiyun 		.enable_reg = WM8350_DCDC_LDO_REQUESTED,
934*4882a593Smuzhiyun 		.enable_mask = WM8350_DC1_ENA,
935*4882a593Smuzhiyun 		.owner = THIS_MODULE,
936*4882a593Smuzhiyun 	},
937*4882a593Smuzhiyun 	{
938*4882a593Smuzhiyun 		.name = "DCDC2",
939*4882a593Smuzhiyun 		.id = WM8350_DCDC_2,
940*4882a593Smuzhiyun 		.ops = &wm8350_dcdc2_5_ops,
941*4882a593Smuzhiyun 		.irq = WM8350_IRQ_UV_DC2,
942*4882a593Smuzhiyun 		.type = REGULATOR_VOLTAGE,
943*4882a593Smuzhiyun 		.enable_reg = WM8350_DCDC_LDO_REQUESTED,
944*4882a593Smuzhiyun 		.enable_mask = WM8350_DC2_ENA,
945*4882a593Smuzhiyun 		.owner = THIS_MODULE,
946*4882a593Smuzhiyun 	},
947*4882a593Smuzhiyun 	{
948*4882a593Smuzhiyun 		.name = "DCDC3",
949*4882a593Smuzhiyun 		.id = WM8350_DCDC_3,
950*4882a593Smuzhiyun 		.ops = &wm8350_dcdc_ops,
951*4882a593Smuzhiyun 		.irq = WM8350_IRQ_UV_DC3,
952*4882a593Smuzhiyun 		.type = REGULATOR_VOLTAGE,
953*4882a593Smuzhiyun 		.n_voltages = WM8350_DCDC_MAX_VSEL + 1,
954*4882a593Smuzhiyun 		.min_uV = 850000,
955*4882a593Smuzhiyun 		.uV_step = 25000,
956*4882a593Smuzhiyun 		.vsel_reg = WM8350_DCDC3_CONTROL,
957*4882a593Smuzhiyun 		.vsel_mask = WM8350_DC3_VSEL_MASK,
958*4882a593Smuzhiyun 		.enable_reg = WM8350_DCDC_LDO_REQUESTED,
959*4882a593Smuzhiyun 		.enable_mask = WM8350_DC3_ENA,
960*4882a593Smuzhiyun 		.owner = THIS_MODULE,
961*4882a593Smuzhiyun 	},
962*4882a593Smuzhiyun 	{
963*4882a593Smuzhiyun 		.name = "DCDC4",
964*4882a593Smuzhiyun 		.id = WM8350_DCDC_4,
965*4882a593Smuzhiyun 		.ops = &wm8350_dcdc_ops,
966*4882a593Smuzhiyun 		.irq = WM8350_IRQ_UV_DC4,
967*4882a593Smuzhiyun 		.type = REGULATOR_VOLTAGE,
968*4882a593Smuzhiyun 		.n_voltages = WM8350_DCDC_MAX_VSEL + 1,
969*4882a593Smuzhiyun 		.min_uV = 850000,
970*4882a593Smuzhiyun 		.uV_step = 25000,
971*4882a593Smuzhiyun 		.vsel_reg = WM8350_DCDC4_CONTROL,
972*4882a593Smuzhiyun 		.vsel_mask = WM8350_DC4_VSEL_MASK,
973*4882a593Smuzhiyun 		.enable_reg = WM8350_DCDC_LDO_REQUESTED,
974*4882a593Smuzhiyun 		.enable_mask = WM8350_DC4_ENA,
975*4882a593Smuzhiyun 		.owner = THIS_MODULE,
976*4882a593Smuzhiyun 	},
977*4882a593Smuzhiyun 	{
978*4882a593Smuzhiyun 		.name = "DCDC5",
979*4882a593Smuzhiyun 		.id = WM8350_DCDC_5,
980*4882a593Smuzhiyun 		.ops = &wm8350_dcdc2_5_ops,
981*4882a593Smuzhiyun 		.irq = WM8350_IRQ_UV_DC5,
982*4882a593Smuzhiyun 		.type = REGULATOR_VOLTAGE,
983*4882a593Smuzhiyun 		.enable_reg = WM8350_DCDC_LDO_REQUESTED,
984*4882a593Smuzhiyun 		.enable_mask = WM8350_DC5_ENA,
985*4882a593Smuzhiyun 		.owner = THIS_MODULE,
986*4882a593Smuzhiyun 	 },
987*4882a593Smuzhiyun 	{
988*4882a593Smuzhiyun 		.name = "DCDC6",
989*4882a593Smuzhiyun 		.id = WM8350_DCDC_6,
990*4882a593Smuzhiyun 		.ops = &wm8350_dcdc_ops,
991*4882a593Smuzhiyun 		.irq = WM8350_IRQ_UV_DC6,
992*4882a593Smuzhiyun 		.type = REGULATOR_VOLTAGE,
993*4882a593Smuzhiyun 		.n_voltages = WM8350_DCDC_MAX_VSEL + 1,
994*4882a593Smuzhiyun 		.min_uV = 850000,
995*4882a593Smuzhiyun 		.uV_step = 25000,
996*4882a593Smuzhiyun 		.vsel_reg = WM8350_DCDC6_CONTROL,
997*4882a593Smuzhiyun 		.vsel_mask = WM8350_DC6_VSEL_MASK,
998*4882a593Smuzhiyun 		.enable_reg = WM8350_DCDC_LDO_REQUESTED,
999*4882a593Smuzhiyun 		.enable_mask = WM8350_DC6_ENA,
1000*4882a593Smuzhiyun 		.owner = THIS_MODULE,
1001*4882a593Smuzhiyun 	},
1002*4882a593Smuzhiyun 	{
1003*4882a593Smuzhiyun 		.name = "LDO1",
1004*4882a593Smuzhiyun 		.id = WM8350_LDO_1,
1005*4882a593Smuzhiyun 		.ops = &wm8350_ldo_ops,
1006*4882a593Smuzhiyun 		.irq = WM8350_IRQ_UV_LDO1,
1007*4882a593Smuzhiyun 		.type = REGULATOR_VOLTAGE,
1008*4882a593Smuzhiyun 		.n_voltages = WM8350_LDO1_VSEL_MASK + 1,
1009*4882a593Smuzhiyun 		.linear_ranges = wm8350_ldo_ranges,
1010*4882a593Smuzhiyun 		.n_linear_ranges = ARRAY_SIZE(wm8350_ldo_ranges),
1011*4882a593Smuzhiyun 		.vsel_reg = WM8350_LDO1_CONTROL,
1012*4882a593Smuzhiyun 		.vsel_mask = WM8350_LDO1_VSEL_MASK,
1013*4882a593Smuzhiyun 		.enable_reg = WM8350_DCDC_LDO_REQUESTED,
1014*4882a593Smuzhiyun 		.enable_mask = WM8350_LDO1_ENA,
1015*4882a593Smuzhiyun 		.owner = THIS_MODULE,
1016*4882a593Smuzhiyun 	},
1017*4882a593Smuzhiyun 	{
1018*4882a593Smuzhiyun 		.name = "LDO2",
1019*4882a593Smuzhiyun 		.id = WM8350_LDO_2,
1020*4882a593Smuzhiyun 		.ops = &wm8350_ldo_ops,
1021*4882a593Smuzhiyun 		.irq = WM8350_IRQ_UV_LDO2,
1022*4882a593Smuzhiyun 		.type = REGULATOR_VOLTAGE,
1023*4882a593Smuzhiyun 		.n_voltages = WM8350_LDO2_VSEL_MASK + 1,
1024*4882a593Smuzhiyun 		.linear_ranges = wm8350_ldo_ranges,
1025*4882a593Smuzhiyun 		.n_linear_ranges = ARRAY_SIZE(wm8350_ldo_ranges),
1026*4882a593Smuzhiyun 		.vsel_reg = WM8350_LDO2_CONTROL,
1027*4882a593Smuzhiyun 		.vsel_mask = WM8350_LDO2_VSEL_MASK,
1028*4882a593Smuzhiyun 		.enable_reg = WM8350_DCDC_LDO_REQUESTED,
1029*4882a593Smuzhiyun 		.enable_mask = WM8350_LDO2_ENA,
1030*4882a593Smuzhiyun 		.owner = THIS_MODULE,
1031*4882a593Smuzhiyun 	},
1032*4882a593Smuzhiyun 	{
1033*4882a593Smuzhiyun 		.name = "LDO3",
1034*4882a593Smuzhiyun 		.id = WM8350_LDO_3,
1035*4882a593Smuzhiyun 		.ops = &wm8350_ldo_ops,
1036*4882a593Smuzhiyun 		.irq = WM8350_IRQ_UV_LDO3,
1037*4882a593Smuzhiyun 		.type = REGULATOR_VOLTAGE,
1038*4882a593Smuzhiyun 		.n_voltages = WM8350_LDO3_VSEL_MASK + 1,
1039*4882a593Smuzhiyun 		.linear_ranges = wm8350_ldo_ranges,
1040*4882a593Smuzhiyun 		.n_linear_ranges = ARRAY_SIZE(wm8350_ldo_ranges),
1041*4882a593Smuzhiyun 		.vsel_reg = WM8350_LDO3_CONTROL,
1042*4882a593Smuzhiyun 		.vsel_mask = WM8350_LDO3_VSEL_MASK,
1043*4882a593Smuzhiyun 		.enable_reg = WM8350_DCDC_LDO_REQUESTED,
1044*4882a593Smuzhiyun 		.enable_mask = WM8350_LDO3_ENA,
1045*4882a593Smuzhiyun 		.owner = THIS_MODULE,
1046*4882a593Smuzhiyun 	},
1047*4882a593Smuzhiyun 	{
1048*4882a593Smuzhiyun 		.name = "LDO4",
1049*4882a593Smuzhiyun 		.id = WM8350_LDO_4,
1050*4882a593Smuzhiyun 		.ops = &wm8350_ldo_ops,
1051*4882a593Smuzhiyun 		.irq = WM8350_IRQ_UV_LDO4,
1052*4882a593Smuzhiyun 		.type = REGULATOR_VOLTAGE,
1053*4882a593Smuzhiyun 		.n_voltages = WM8350_LDO4_VSEL_MASK + 1,
1054*4882a593Smuzhiyun 		.linear_ranges = wm8350_ldo_ranges,
1055*4882a593Smuzhiyun 		.n_linear_ranges = ARRAY_SIZE(wm8350_ldo_ranges),
1056*4882a593Smuzhiyun 		.vsel_reg = WM8350_LDO4_CONTROL,
1057*4882a593Smuzhiyun 		.vsel_mask = WM8350_LDO4_VSEL_MASK,
1058*4882a593Smuzhiyun 		.enable_reg = WM8350_DCDC_LDO_REQUESTED,
1059*4882a593Smuzhiyun 		.enable_mask = WM8350_LDO4_ENA,
1060*4882a593Smuzhiyun 		.owner = THIS_MODULE,
1061*4882a593Smuzhiyun 	},
1062*4882a593Smuzhiyun 	{
1063*4882a593Smuzhiyun 		.name = "ISINKA",
1064*4882a593Smuzhiyun 		.id = WM8350_ISINK_A,
1065*4882a593Smuzhiyun 		.ops = &wm8350_isink_ops,
1066*4882a593Smuzhiyun 		.irq = WM8350_IRQ_CS1,
1067*4882a593Smuzhiyun 		.type = REGULATOR_CURRENT,
1068*4882a593Smuzhiyun 		.owner = THIS_MODULE,
1069*4882a593Smuzhiyun 		.curr_table = isink_cur,
1070*4882a593Smuzhiyun 		.n_current_limits = ARRAY_SIZE(isink_cur),
1071*4882a593Smuzhiyun 		.csel_reg = WM8350_CURRENT_SINK_DRIVER_A,
1072*4882a593Smuzhiyun 		.csel_mask = WM8350_CS1_ISEL_MASK,
1073*4882a593Smuzhiyun 	 },
1074*4882a593Smuzhiyun 	{
1075*4882a593Smuzhiyun 		.name = "ISINKB",
1076*4882a593Smuzhiyun 		.id = WM8350_ISINK_B,
1077*4882a593Smuzhiyun 		.ops = &wm8350_isink_ops,
1078*4882a593Smuzhiyun 		.irq = WM8350_IRQ_CS2,
1079*4882a593Smuzhiyun 		.type = REGULATOR_CURRENT,
1080*4882a593Smuzhiyun 		.owner = THIS_MODULE,
1081*4882a593Smuzhiyun 		.curr_table = isink_cur,
1082*4882a593Smuzhiyun 		.n_current_limits = ARRAY_SIZE(isink_cur),
1083*4882a593Smuzhiyun 		.csel_reg = WM8350_CURRENT_SINK_DRIVER_B,
1084*4882a593Smuzhiyun 		.csel_mask = WM8350_CS2_ISEL_MASK,
1085*4882a593Smuzhiyun 	 },
1086*4882a593Smuzhiyun };
1087*4882a593Smuzhiyun 
pmic_uv_handler(int irq,void * data)1088*4882a593Smuzhiyun static irqreturn_t pmic_uv_handler(int irq, void *data)
1089*4882a593Smuzhiyun {
1090*4882a593Smuzhiyun 	struct regulator_dev *rdev = (struct regulator_dev *)data;
1091*4882a593Smuzhiyun 
1092*4882a593Smuzhiyun 	if (irq == WM8350_IRQ_CS1 || irq == WM8350_IRQ_CS2)
1093*4882a593Smuzhiyun 		regulator_notifier_call_chain(rdev,
1094*4882a593Smuzhiyun 					      REGULATOR_EVENT_REGULATION_OUT,
1095*4882a593Smuzhiyun 					      NULL);
1096*4882a593Smuzhiyun 	else
1097*4882a593Smuzhiyun 		regulator_notifier_call_chain(rdev,
1098*4882a593Smuzhiyun 					      REGULATOR_EVENT_UNDER_VOLTAGE,
1099*4882a593Smuzhiyun 					      NULL);
1100*4882a593Smuzhiyun 
1101*4882a593Smuzhiyun 	return IRQ_HANDLED;
1102*4882a593Smuzhiyun }
1103*4882a593Smuzhiyun 
wm8350_regulator_probe(struct platform_device * pdev)1104*4882a593Smuzhiyun static int wm8350_regulator_probe(struct platform_device *pdev)
1105*4882a593Smuzhiyun {
1106*4882a593Smuzhiyun 	struct wm8350 *wm8350 = dev_get_drvdata(&pdev->dev);
1107*4882a593Smuzhiyun 	struct regulator_config config = { };
1108*4882a593Smuzhiyun 	struct regulator_dev *rdev;
1109*4882a593Smuzhiyun 	int ret;
1110*4882a593Smuzhiyun 	u16 val;
1111*4882a593Smuzhiyun 
1112*4882a593Smuzhiyun 	if (pdev->id < WM8350_DCDC_1 || pdev->id > WM8350_ISINK_B)
1113*4882a593Smuzhiyun 		return -ENODEV;
1114*4882a593Smuzhiyun 
1115*4882a593Smuzhiyun 	/* do any regulatior specific init */
1116*4882a593Smuzhiyun 	switch (pdev->id) {
1117*4882a593Smuzhiyun 	case WM8350_DCDC_1:
1118*4882a593Smuzhiyun 		val = wm8350_reg_read(wm8350, WM8350_DCDC1_LOW_POWER);
1119*4882a593Smuzhiyun 		wm8350->pmic.dcdc1_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
1120*4882a593Smuzhiyun 		break;
1121*4882a593Smuzhiyun 	case WM8350_DCDC_3:
1122*4882a593Smuzhiyun 		val = wm8350_reg_read(wm8350, WM8350_DCDC3_LOW_POWER);
1123*4882a593Smuzhiyun 		wm8350->pmic.dcdc3_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
1124*4882a593Smuzhiyun 		break;
1125*4882a593Smuzhiyun 	case WM8350_DCDC_4:
1126*4882a593Smuzhiyun 		val = wm8350_reg_read(wm8350, WM8350_DCDC4_LOW_POWER);
1127*4882a593Smuzhiyun 		wm8350->pmic.dcdc4_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
1128*4882a593Smuzhiyun 		break;
1129*4882a593Smuzhiyun 	case WM8350_DCDC_6:
1130*4882a593Smuzhiyun 		val = wm8350_reg_read(wm8350, WM8350_DCDC6_LOW_POWER);
1131*4882a593Smuzhiyun 		wm8350->pmic.dcdc6_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
1132*4882a593Smuzhiyun 		break;
1133*4882a593Smuzhiyun 	}
1134*4882a593Smuzhiyun 
1135*4882a593Smuzhiyun 	config.dev = &pdev->dev;
1136*4882a593Smuzhiyun 	config.init_data = dev_get_platdata(&pdev->dev);
1137*4882a593Smuzhiyun 	config.driver_data = dev_get_drvdata(&pdev->dev);
1138*4882a593Smuzhiyun 	config.regmap = wm8350->regmap;
1139*4882a593Smuzhiyun 
1140*4882a593Smuzhiyun 	/* register regulator */
1141*4882a593Smuzhiyun 	rdev = devm_regulator_register(&pdev->dev, &wm8350_reg[pdev->id],
1142*4882a593Smuzhiyun 				       &config);
1143*4882a593Smuzhiyun 	if (IS_ERR(rdev)) {
1144*4882a593Smuzhiyun 		dev_err(&pdev->dev, "failed to register %s\n",
1145*4882a593Smuzhiyun 			wm8350_reg[pdev->id].name);
1146*4882a593Smuzhiyun 		return PTR_ERR(rdev);
1147*4882a593Smuzhiyun 	}
1148*4882a593Smuzhiyun 
1149*4882a593Smuzhiyun 	/* register regulator IRQ */
1150*4882a593Smuzhiyun 	ret = wm8350_register_irq(wm8350, wm8350_reg[pdev->id].irq,
1151*4882a593Smuzhiyun 				  pmic_uv_handler, 0, "UV", rdev);
1152*4882a593Smuzhiyun 	if (ret < 0) {
1153*4882a593Smuzhiyun 		dev_err(&pdev->dev, "failed to register regulator %s IRQ\n",
1154*4882a593Smuzhiyun 			wm8350_reg[pdev->id].name);
1155*4882a593Smuzhiyun 		return ret;
1156*4882a593Smuzhiyun 	}
1157*4882a593Smuzhiyun 
1158*4882a593Smuzhiyun 	return 0;
1159*4882a593Smuzhiyun }
1160*4882a593Smuzhiyun 
wm8350_regulator_remove(struct platform_device * pdev)1161*4882a593Smuzhiyun static int wm8350_regulator_remove(struct platform_device *pdev)
1162*4882a593Smuzhiyun {
1163*4882a593Smuzhiyun 	struct regulator_dev *rdev = platform_get_drvdata(pdev);
1164*4882a593Smuzhiyun 	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
1165*4882a593Smuzhiyun 
1166*4882a593Smuzhiyun 	wm8350_free_irq(wm8350, wm8350_reg[pdev->id].irq, rdev);
1167*4882a593Smuzhiyun 
1168*4882a593Smuzhiyun 	return 0;
1169*4882a593Smuzhiyun }
1170*4882a593Smuzhiyun 
wm8350_register_regulator(struct wm8350 * wm8350,int reg,struct regulator_init_data * initdata)1171*4882a593Smuzhiyun int wm8350_register_regulator(struct wm8350 *wm8350, int reg,
1172*4882a593Smuzhiyun 			      struct regulator_init_data *initdata)
1173*4882a593Smuzhiyun {
1174*4882a593Smuzhiyun 	struct platform_device *pdev;
1175*4882a593Smuzhiyun 	int ret;
1176*4882a593Smuzhiyun 	if (reg < 0 || reg >= NUM_WM8350_REGULATORS)
1177*4882a593Smuzhiyun 		return -EINVAL;
1178*4882a593Smuzhiyun 
1179*4882a593Smuzhiyun 	if (wm8350->pmic.pdev[reg])
1180*4882a593Smuzhiyun 		return -EBUSY;
1181*4882a593Smuzhiyun 
1182*4882a593Smuzhiyun 	if (reg >= WM8350_DCDC_1 && reg <= WM8350_DCDC_6 &&
1183*4882a593Smuzhiyun 	    reg > wm8350->pmic.max_dcdc)
1184*4882a593Smuzhiyun 		return -ENODEV;
1185*4882a593Smuzhiyun 	if (reg >= WM8350_ISINK_A && reg <= WM8350_ISINK_B &&
1186*4882a593Smuzhiyun 	    reg > wm8350->pmic.max_isink)
1187*4882a593Smuzhiyun 		return -ENODEV;
1188*4882a593Smuzhiyun 
1189*4882a593Smuzhiyun 	pdev = platform_device_alloc("wm8350-regulator", reg);
1190*4882a593Smuzhiyun 	if (!pdev)
1191*4882a593Smuzhiyun 		return -ENOMEM;
1192*4882a593Smuzhiyun 
1193*4882a593Smuzhiyun 	wm8350->pmic.pdev[reg] = pdev;
1194*4882a593Smuzhiyun 
1195*4882a593Smuzhiyun 	initdata->driver_data = wm8350;
1196*4882a593Smuzhiyun 
1197*4882a593Smuzhiyun 	pdev->dev.platform_data = initdata;
1198*4882a593Smuzhiyun 	pdev->dev.parent = wm8350->dev;
1199*4882a593Smuzhiyun 	platform_set_drvdata(pdev, wm8350);
1200*4882a593Smuzhiyun 
1201*4882a593Smuzhiyun 	ret = platform_device_add(pdev);
1202*4882a593Smuzhiyun 
1203*4882a593Smuzhiyun 	if (ret != 0) {
1204*4882a593Smuzhiyun 		dev_err(wm8350->dev, "Failed to register regulator %d: %d\n",
1205*4882a593Smuzhiyun 			reg, ret);
1206*4882a593Smuzhiyun 		platform_device_put(pdev);
1207*4882a593Smuzhiyun 		wm8350->pmic.pdev[reg] = NULL;
1208*4882a593Smuzhiyun 	}
1209*4882a593Smuzhiyun 
1210*4882a593Smuzhiyun 	return ret;
1211*4882a593Smuzhiyun }
1212*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(wm8350_register_regulator);
1213*4882a593Smuzhiyun 
1214*4882a593Smuzhiyun /**
1215*4882a593Smuzhiyun  * wm8350_register_led - Register a WM8350 LED output
1216*4882a593Smuzhiyun  *
1217*4882a593Smuzhiyun  * @wm8350: The WM8350 device to configure.
1218*4882a593Smuzhiyun  * @lednum: LED device index to create.
1219*4882a593Smuzhiyun  * @dcdc: The DCDC to use for the LED.
1220*4882a593Smuzhiyun  * @isink: The ISINK to use for the LED.
1221*4882a593Smuzhiyun  * @pdata: Configuration for the LED.
1222*4882a593Smuzhiyun  *
1223*4882a593Smuzhiyun  * The WM8350 supports the use of an ISINK together with a DCDC to
1224*4882a593Smuzhiyun  * provide a power-efficient LED driver.  This function registers the
1225*4882a593Smuzhiyun  * regulators and instantiates the platform device for a LED.  The
1226*4882a593Smuzhiyun  * operating modes for the LED regulators must be configured using
1227*4882a593Smuzhiyun  * wm8350_isink_set_flash(), wm8350_dcdc25_set_mode() and
1228*4882a593Smuzhiyun  * wm8350_dcdc_set_slot() prior to calling this function.
1229*4882a593Smuzhiyun  */
wm8350_register_led(struct wm8350 * wm8350,int lednum,int dcdc,int isink,struct wm8350_led_platform_data * pdata)1230*4882a593Smuzhiyun int wm8350_register_led(struct wm8350 *wm8350, int lednum, int dcdc, int isink,
1231*4882a593Smuzhiyun 			struct wm8350_led_platform_data *pdata)
1232*4882a593Smuzhiyun {
1233*4882a593Smuzhiyun 	struct wm8350_led *led;
1234*4882a593Smuzhiyun 	struct platform_device *pdev;
1235*4882a593Smuzhiyun 	int ret;
1236*4882a593Smuzhiyun 
1237*4882a593Smuzhiyun 	if (lednum >= ARRAY_SIZE(wm8350->pmic.led) || lednum < 0) {
1238*4882a593Smuzhiyun 		dev_err(wm8350->dev, "Invalid LED index %d\n", lednum);
1239*4882a593Smuzhiyun 		return -ENODEV;
1240*4882a593Smuzhiyun 	}
1241*4882a593Smuzhiyun 
1242*4882a593Smuzhiyun 	led = &wm8350->pmic.led[lednum];
1243*4882a593Smuzhiyun 
1244*4882a593Smuzhiyun 	if (led->pdev) {
1245*4882a593Smuzhiyun 		dev_err(wm8350->dev, "LED %d already allocated\n", lednum);
1246*4882a593Smuzhiyun 		return -EINVAL;
1247*4882a593Smuzhiyun 	}
1248*4882a593Smuzhiyun 
1249*4882a593Smuzhiyun 	pdev = platform_device_alloc("wm8350-led", lednum);
1250*4882a593Smuzhiyun 	if (pdev == NULL) {
1251*4882a593Smuzhiyun 		dev_err(wm8350->dev, "Failed to allocate LED %d\n", lednum);
1252*4882a593Smuzhiyun 		return -ENOMEM;
1253*4882a593Smuzhiyun 	}
1254*4882a593Smuzhiyun 
1255*4882a593Smuzhiyun 	led->isink_consumer.dev_name = dev_name(&pdev->dev);
1256*4882a593Smuzhiyun 	led->isink_consumer.supply = "led_isink";
1257*4882a593Smuzhiyun 	led->isink_init.num_consumer_supplies = 1;
1258*4882a593Smuzhiyun 	led->isink_init.consumer_supplies = &led->isink_consumer;
1259*4882a593Smuzhiyun 	led->isink_init.constraints.min_uA = 0;
1260*4882a593Smuzhiyun 	led->isink_init.constraints.max_uA = pdata->max_uA;
1261*4882a593Smuzhiyun 	led->isink_init.constraints.valid_ops_mask
1262*4882a593Smuzhiyun 		= REGULATOR_CHANGE_CURRENT | REGULATOR_CHANGE_STATUS;
1263*4882a593Smuzhiyun 	led->isink_init.constraints.valid_modes_mask = REGULATOR_MODE_NORMAL;
1264*4882a593Smuzhiyun 	ret = wm8350_register_regulator(wm8350, isink, &led->isink_init);
1265*4882a593Smuzhiyun 	if (ret != 0) {
1266*4882a593Smuzhiyun 		platform_device_put(pdev);
1267*4882a593Smuzhiyun 		return ret;
1268*4882a593Smuzhiyun 	}
1269*4882a593Smuzhiyun 
1270*4882a593Smuzhiyun 	led->dcdc_consumer.dev_name = dev_name(&pdev->dev);
1271*4882a593Smuzhiyun 	led->dcdc_consumer.supply = "led_vcc";
1272*4882a593Smuzhiyun 	led->dcdc_init.num_consumer_supplies = 1;
1273*4882a593Smuzhiyun 	led->dcdc_init.consumer_supplies = &led->dcdc_consumer;
1274*4882a593Smuzhiyun 	led->dcdc_init.constraints.valid_modes_mask = REGULATOR_MODE_NORMAL;
1275*4882a593Smuzhiyun 	led->dcdc_init.constraints.valid_ops_mask =  REGULATOR_CHANGE_STATUS;
1276*4882a593Smuzhiyun 	ret = wm8350_register_regulator(wm8350, dcdc, &led->dcdc_init);
1277*4882a593Smuzhiyun 	if (ret != 0) {
1278*4882a593Smuzhiyun 		platform_device_put(pdev);
1279*4882a593Smuzhiyun 		return ret;
1280*4882a593Smuzhiyun 	}
1281*4882a593Smuzhiyun 
1282*4882a593Smuzhiyun 	switch (isink) {
1283*4882a593Smuzhiyun 	case WM8350_ISINK_A:
1284*4882a593Smuzhiyun 		wm8350->pmic.isink_A_dcdc = dcdc;
1285*4882a593Smuzhiyun 		break;
1286*4882a593Smuzhiyun 	case WM8350_ISINK_B:
1287*4882a593Smuzhiyun 		wm8350->pmic.isink_B_dcdc = dcdc;
1288*4882a593Smuzhiyun 		break;
1289*4882a593Smuzhiyun 	}
1290*4882a593Smuzhiyun 
1291*4882a593Smuzhiyun 	pdev->dev.platform_data = pdata;
1292*4882a593Smuzhiyun 	pdev->dev.parent = wm8350->dev;
1293*4882a593Smuzhiyun 	ret = platform_device_add(pdev);
1294*4882a593Smuzhiyun 	if (ret != 0) {
1295*4882a593Smuzhiyun 		dev_err(wm8350->dev, "Failed to register LED %d: %d\n",
1296*4882a593Smuzhiyun 			lednum, ret);
1297*4882a593Smuzhiyun 		platform_device_put(pdev);
1298*4882a593Smuzhiyun 		return ret;
1299*4882a593Smuzhiyun 	}
1300*4882a593Smuzhiyun 
1301*4882a593Smuzhiyun 	led->pdev = pdev;
1302*4882a593Smuzhiyun 
1303*4882a593Smuzhiyun 	return 0;
1304*4882a593Smuzhiyun }
1305*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(wm8350_register_led);
1306*4882a593Smuzhiyun 
1307*4882a593Smuzhiyun static struct platform_driver wm8350_regulator_driver = {
1308*4882a593Smuzhiyun 	.probe = wm8350_regulator_probe,
1309*4882a593Smuzhiyun 	.remove = wm8350_regulator_remove,
1310*4882a593Smuzhiyun 	.driver		= {
1311*4882a593Smuzhiyun 		.name	= "wm8350-regulator",
1312*4882a593Smuzhiyun 	},
1313*4882a593Smuzhiyun };
1314*4882a593Smuzhiyun 
wm8350_regulator_init(void)1315*4882a593Smuzhiyun static int __init wm8350_regulator_init(void)
1316*4882a593Smuzhiyun {
1317*4882a593Smuzhiyun 	return platform_driver_register(&wm8350_regulator_driver);
1318*4882a593Smuzhiyun }
1319*4882a593Smuzhiyun subsys_initcall(wm8350_regulator_init);
1320*4882a593Smuzhiyun 
wm8350_regulator_exit(void)1321*4882a593Smuzhiyun static void __exit wm8350_regulator_exit(void)
1322*4882a593Smuzhiyun {
1323*4882a593Smuzhiyun 	platform_driver_unregister(&wm8350_regulator_driver);
1324*4882a593Smuzhiyun }
1325*4882a593Smuzhiyun module_exit(wm8350_regulator_exit);
1326*4882a593Smuzhiyun 
1327*4882a593Smuzhiyun /* Module information */
1328*4882a593Smuzhiyun MODULE_AUTHOR("Liam Girdwood");
1329*4882a593Smuzhiyun MODULE_DESCRIPTION("WM8350 voltage and current regulator driver");
1330*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1331*4882a593Smuzhiyun MODULE_ALIAS("platform:wm8350-regulator");
1332