xref: /openbmc/linux/drivers/regulator/lp8788-buck.c (revision c42ea5cdfb14418a9d81e7192d65196b2785c3c2)
1ade7515fSKim, Milo /*
2ade7515fSKim, Milo  * TI LP8788 MFD - buck regulator driver
3ade7515fSKim, Milo  *
4ade7515fSKim, Milo  * Copyright 2012 Texas Instruments
5ade7515fSKim, Milo  *
6ade7515fSKim, Milo  * Author: Milo(Woogyom) Kim <milo.kim@ti.com>
7ade7515fSKim, Milo  *
8ade7515fSKim, Milo  * This program is free software; you can redistribute it and/or modify
9ade7515fSKim, Milo  * it under the terms of the GNU General Public License version 2 as
10ade7515fSKim, Milo  * published by the Free Software Foundation.
11ade7515fSKim, Milo  *
12ade7515fSKim, Milo  */
13ade7515fSKim, Milo 
14ade7515fSKim, Milo #include <linux/module.h>
15ade7515fSKim, Milo #include <linux/slab.h>
16ade7515fSKim, Milo #include <linux/err.h>
17ade7515fSKim, Milo #include <linux/platform_device.h>
18ade7515fSKim, Milo #include <linux/regulator/driver.h>
19ade7515fSKim, Milo #include <linux/mfd/lp8788.h>
20ade7515fSKim, Milo #include <linux/gpio.h>
21ade7515fSKim, Milo 
22ade7515fSKim, Milo /* register address */
23ade7515fSKim, Milo #define LP8788_EN_BUCK			0x0C
24ade7515fSKim, Milo #define LP8788_BUCK_DVS_SEL		0x1D
25ade7515fSKim, Milo #define LP8788_BUCK1_VOUT0		0x1E
26ade7515fSKim, Milo #define LP8788_BUCK1_VOUT1		0x1F
27ade7515fSKim, Milo #define LP8788_BUCK1_VOUT2		0x20
28ade7515fSKim, Milo #define LP8788_BUCK1_VOUT3		0x21
29ade7515fSKim, Milo #define LP8788_BUCK2_VOUT0		0x22
30ade7515fSKim, Milo #define LP8788_BUCK2_VOUT1		0x23
31ade7515fSKim, Milo #define LP8788_BUCK2_VOUT2		0x24
32ade7515fSKim, Milo #define LP8788_BUCK2_VOUT3		0x25
33ade7515fSKim, Milo #define LP8788_BUCK3_VOUT		0x26
34ade7515fSKim, Milo #define LP8788_BUCK4_VOUT		0x27
35ade7515fSKim, Milo #define LP8788_BUCK1_TIMESTEP		0x28
36ade7515fSKim, Milo #define LP8788_BUCK_PWM			0x2D
37ade7515fSKim, Milo 
38ade7515fSKim, Milo /* mask/shift bits */
39ade7515fSKim, Milo #define LP8788_EN_BUCK1_M		BIT(0)	/* Addr 0Ch */
40ade7515fSKim, Milo #define LP8788_EN_BUCK2_M		BIT(1)
41ade7515fSKim, Milo #define LP8788_EN_BUCK3_M		BIT(2)
42ade7515fSKim, Milo #define LP8788_EN_BUCK4_M		BIT(3)
43ade7515fSKim, Milo #define LP8788_BUCK1_DVS_SEL_M		0x04	/* Addr 1Dh */
44ade7515fSKim, Milo #define LP8788_BUCK1_DVS_M		0x03
45ade7515fSKim, Milo #define LP8788_BUCK1_DVS_S		0
46ade7515fSKim, Milo #define LP8788_BUCK2_DVS_SEL_M		0x40
47ade7515fSKim, Milo #define LP8788_BUCK2_DVS_M		0x30
48ade7515fSKim, Milo #define LP8788_BUCK2_DVS_S		4
49ade7515fSKim, Milo #define LP8788_BUCK1_DVS_I2C		BIT(2)
50ade7515fSKim, Milo #define LP8788_BUCK2_DVS_I2C		BIT(6)
51ade7515fSKim, Milo #define LP8788_BUCK1_DVS_PIN		(0 << 2)
52ade7515fSKim, Milo #define LP8788_BUCK2_DVS_PIN		(0 << 6)
53ade7515fSKim, Milo #define LP8788_VOUT_M			0x1F	/* Addr 1Eh ~ 27h */
54ade7515fSKim, Milo #define LP8788_STARTUP_TIME_M		0xF8	/* Addr 28h ~ 2Bh */
55ade7515fSKim, Milo #define LP8788_STARTUP_TIME_S		3
56ade7515fSKim, Milo #define LP8788_FPWM_BUCK1_M		BIT(0)	/* Addr 2Dh */
57ade7515fSKim, Milo #define LP8788_FPWM_BUCK1_S		0
58ade7515fSKim, Milo #define LP8788_FPWM_BUCK2_M		BIT(1)
59ade7515fSKim, Milo #define LP8788_FPWM_BUCK2_S		1
60ade7515fSKim, Milo #define LP8788_FPWM_BUCK3_M		BIT(2)
61ade7515fSKim, Milo #define LP8788_FPWM_BUCK3_S		2
62ade7515fSKim, Milo #define LP8788_FPWM_BUCK4_M		BIT(3)
63ade7515fSKim, Milo #define LP8788_FPWM_BUCK4_S		3
64ade7515fSKim, Milo 
65ade7515fSKim, Milo #define INVALID_ADDR			0xFF
66ade7515fSKim, Milo #define LP8788_FORCE_PWM		1
67ade7515fSKim, Milo #define LP8788_AUTO_PWM			0
68ade7515fSKim, Milo #define PIN_LOW				0
69ade7515fSKim, Milo #define PIN_HIGH			1
70ade7515fSKim, Milo #define ENABLE_TIME_USEC		32
71ade7515fSKim, Milo 
72ade7515fSKim, Milo enum lp8788_dvs_state {
73ade7515fSKim, Milo 	DVS_LOW  = GPIOF_OUT_INIT_LOW,
74ade7515fSKim, Milo 	DVS_HIGH = GPIOF_OUT_INIT_HIGH,
75ade7515fSKim, Milo };
76ade7515fSKim, Milo 
77ade7515fSKim, Milo enum lp8788_dvs_mode {
78ade7515fSKim, Milo 	REGISTER,
79ade7515fSKim, Milo 	EXTPIN,
80ade7515fSKim, Milo };
81ade7515fSKim, Milo 
82ade7515fSKim, Milo enum lp8788_buck_id {
83ade7515fSKim, Milo 	BUCK1,
84ade7515fSKim, Milo 	BUCK2,
85ade7515fSKim, Milo 	BUCK3,
86ade7515fSKim, Milo 	BUCK4,
87ade7515fSKim, Milo };
88ade7515fSKim, Milo 
89ade7515fSKim, Milo struct lp8788_pwm_map {
90ade7515fSKim, Milo 	u8 mask;
91ade7515fSKim, Milo 	u8 shift;
92ade7515fSKim, Milo };
93ade7515fSKim, Milo 
94ade7515fSKim, Milo struct lp8788_buck {
95ade7515fSKim, Milo 	struct lp8788 *lp;
96ade7515fSKim, Milo 	struct regulator_dev *regulator;
97ade7515fSKim, Milo 	struct lp8788_pwm_map *pmap;
98ade7515fSKim, Milo 	void *dvs;
99ade7515fSKim, Milo };
100ade7515fSKim, Milo 
101ade7515fSKim, Milo /* BUCK 1 ~ 4 voltage table */
102ade7515fSKim, Milo static const int lp8788_buck_vtbl[] = {
103ade7515fSKim, Milo 	 500000,  800000,  850000,  900000,  950000, 1000000, 1050000, 1100000,
104ade7515fSKim, Milo 	1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000,
105ade7515fSKim, Milo 	1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000,
106ade7515fSKim, Milo 	1950000, 2000000,
107ade7515fSKim, Milo };
108ade7515fSKim, Milo 
109ade7515fSKim, Milo /* buck pwm mode selection : used for set/get_mode in regulator ops
110ade7515fSKim, Milo  * @forced pwm : fast mode
111ade7515fSKim, Milo  * @auto pwm   : normal mode
112ade7515fSKim, Milo  */
113ade7515fSKim, Milo static struct lp8788_pwm_map buck_pmap[] = {
114ade7515fSKim, Milo 	[BUCK1] = {
115ade7515fSKim, Milo 		.mask = LP8788_FPWM_BUCK1_M,
116ade7515fSKim, Milo 		.shift = LP8788_FPWM_BUCK1_S,
117ade7515fSKim, Milo 	},
118ade7515fSKim, Milo 	[BUCK2] = {
119ade7515fSKim, Milo 		.mask = LP8788_FPWM_BUCK2_M,
120ade7515fSKim, Milo 		.shift = LP8788_FPWM_BUCK2_S,
121ade7515fSKim, Milo 	},
122ade7515fSKim, Milo 	[BUCK3] = {
123ade7515fSKim, Milo 		.mask = LP8788_FPWM_BUCK3_M,
124ade7515fSKim, Milo 		.shift = LP8788_FPWM_BUCK3_S,
125ade7515fSKim, Milo 	},
126ade7515fSKim, Milo 	[BUCK4] = {
127ade7515fSKim, Milo 		.mask = LP8788_FPWM_BUCK4_M,
128ade7515fSKim, Milo 		.shift = LP8788_FPWM_BUCK4_S,
129ade7515fSKim, Milo 	},
130ade7515fSKim, Milo };
131ade7515fSKim, Milo 
132ade7515fSKim, Milo static const u8 buck1_vout_addr[] = {
133ade7515fSKim, Milo 	LP8788_BUCK1_VOUT0, LP8788_BUCK1_VOUT1,
134ade7515fSKim, Milo 	LP8788_BUCK1_VOUT2, LP8788_BUCK1_VOUT3,
135ade7515fSKim, Milo };
136ade7515fSKim, Milo 
137ade7515fSKim, Milo static const u8 buck2_vout_addr[] = {
138ade7515fSKim, Milo 	LP8788_BUCK2_VOUT0, LP8788_BUCK2_VOUT1,
139ade7515fSKim, Milo 	LP8788_BUCK2_VOUT2, LP8788_BUCK2_VOUT3,
140ade7515fSKim, Milo };
141ade7515fSKim, Milo 
142ade7515fSKim, Milo static void lp8788_buck1_set_dvs(struct lp8788_buck *buck)
143ade7515fSKim, Milo {
144ade7515fSKim, Milo 	struct lp8788_buck1_dvs *dvs = (struct lp8788_buck1_dvs *)buck->dvs;
145ade7515fSKim, Milo 	enum lp8788_dvs_state pinstate;
146ade7515fSKim, Milo 
147ade7515fSKim, Milo 	if (!dvs)
148ade7515fSKim, Milo 		return;
149ade7515fSKim, Milo 
150ade7515fSKim, Milo 	pinstate = dvs->vsel == DVS_SEL_V0 ? DVS_LOW : DVS_HIGH;
151ade7515fSKim, Milo 	if (gpio_is_valid(dvs->gpio))
152ade7515fSKim, Milo 		gpio_set_value(dvs->gpio, pinstate);
153ade7515fSKim, Milo }
154ade7515fSKim, Milo 
155ade7515fSKim, Milo static void lp8788_buck2_set_dvs(struct lp8788_buck *buck)
156ade7515fSKim, Milo {
157ade7515fSKim, Milo 	struct lp8788_buck2_dvs *dvs = (struct lp8788_buck2_dvs *)buck->dvs;
158ade7515fSKim, Milo 	enum lp8788_dvs_state pin1, pin2;
159ade7515fSKim, Milo 
160ade7515fSKim, Milo 	if (!dvs)
161ade7515fSKim, Milo 		return;
162ade7515fSKim, Milo 
163ade7515fSKim, Milo 	switch (dvs->vsel) {
164ade7515fSKim, Milo 	case DVS_SEL_V0:
165ade7515fSKim, Milo 		pin1 = DVS_LOW;
166ade7515fSKim, Milo 		pin2 = DVS_LOW;
167ade7515fSKim, Milo 		break;
168ade7515fSKim, Milo 	case DVS_SEL_V1:
169ade7515fSKim, Milo 		pin1 = DVS_HIGH;
170ade7515fSKim, Milo 		pin2 = DVS_LOW;
171ade7515fSKim, Milo 		break;
172ade7515fSKim, Milo 	case DVS_SEL_V2:
173ade7515fSKim, Milo 		pin1 = DVS_LOW;
174ade7515fSKim, Milo 		pin2 = DVS_HIGH;
175ade7515fSKim, Milo 		break;
176ade7515fSKim, Milo 	case DVS_SEL_V3:
177ade7515fSKim, Milo 		pin1 = DVS_HIGH;
178ade7515fSKim, Milo 		pin2 = DVS_HIGH;
179ade7515fSKim, Milo 		break;
180ade7515fSKim, Milo 	default:
181ade7515fSKim, Milo 		return;
182ade7515fSKim, Milo 	}
183ade7515fSKim, Milo 
184ade7515fSKim, Milo 	if (gpio_is_valid(dvs->gpio[0]))
185ade7515fSKim, Milo 		gpio_set_value(dvs->gpio[0], pin1);
186ade7515fSKim, Milo 
187ade7515fSKim, Milo 	if (gpio_is_valid(dvs->gpio[1]))
188ade7515fSKim, Milo 		gpio_set_value(dvs->gpio[1], pin2);
189ade7515fSKim, Milo }
190ade7515fSKim, Milo 
191ade7515fSKim, Milo static void lp8788_set_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id)
192ade7515fSKim, Milo {
193ade7515fSKim, Milo 	switch (id) {
194ade7515fSKim, Milo 	case BUCK1:
195ade7515fSKim, Milo 		lp8788_buck1_set_dvs(buck);
196ade7515fSKim, Milo 		break;
197ade7515fSKim, Milo 	case BUCK2:
198ade7515fSKim, Milo 		lp8788_buck2_set_dvs(buck);
199ade7515fSKim, Milo 		break;
200ade7515fSKim, Milo 	default:
201ade7515fSKim, Milo 		break;
202ade7515fSKim, Milo 	}
203ade7515fSKim, Milo }
204ade7515fSKim, Milo 
205ade7515fSKim, Milo static enum lp8788_dvs_mode
206ade7515fSKim, Milo lp8788_get_buck_dvs_ctrl_mode(struct lp8788_buck *buck, enum lp8788_buck_id id)
207ade7515fSKim, Milo {
208ade7515fSKim, Milo 	u8 val, mask;
209ade7515fSKim, Milo 
210ade7515fSKim, Milo 	switch (id) {
211ade7515fSKim, Milo 	case BUCK1:
212ade7515fSKim, Milo 		mask = LP8788_BUCK1_DVS_SEL_M;
213ade7515fSKim, Milo 		break;
214ade7515fSKim, Milo 	case BUCK2:
215ade7515fSKim, Milo 		mask = LP8788_BUCK2_DVS_SEL_M;
216ade7515fSKim, Milo 		break;
217ade7515fSKim, Milo 	default:
218ade7515fSKim, Milo 		return REGISTER;
219ade7515fSKim, Milo 	}
220ade7515fSKim, Milo 
221ade7515fSKim, Milo 	lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val);
222ade7515fSKim, Milo 
223ade7515fSKim, Milo 	return val & mask ? REGISTER : EXTPIN;
224ade7515fSKim, Milo }
225ade7515fSKim, Milo 
226ade7515fSKim, Milo static bool lp8788_is_valid_buck_addr(u8 addr)
227ade7515fSKim, Milo {
228ade7515fSKim, Milo 	switch (addr) {
229ade7515fSKim, Milo 	case LP8788_BUCK1_VOUT0:
230ade7515fSKim, Milo 	case LP8788_BUCK1_VOUT1:
231ade7515fSKim, Milo 	case LP8788_BUCK1_VOUT2:
232ade7515fSKim, Milo 	case LP8788_BUCK1_VOUT3:
233ade7515fSKim, Milo 	case LP8788_BUCK2_VOUT0:
234ade7515fSKim, Milo 	case LP8788_BUCK2_VOUT1:
235ade7515fSKim, Milo 	case LP8788_BUCK2_VOUT2:
236ade7515fSKim, Milo 	case LP8788_BUCK2_VOUT3:
237ade7515fSKim, Milo 		return true;
238ade7515fSKim, Milo 	default:
239ade7515fSKim, Milo 		return false;
240ade7515fSKim, Milo 	}
241ade7515fSKim, Milo }
242ade7515fSKim, Milo 
243ade7515fSKim, Milo static u8 lp8788_select_buck_vout_addr(struct lp8788_buck *buck,
244ade7515fSKim, Milo 					enum lp8788_buck_id id)
245ade7515fSKim, Milo {
246ade7515fSKim, Milo 	enum lp8788_dvs_mode mode = lp8788_get_buck_dvs_ctrl_mode(buck, id);
247ade7515fSKim, Milo 	struct lp8788_buck1_dvs *b1_dvs;
248ade7515fSKim, Milo 	struct lp8788_buck2_dvs *b2_dvs;
249ade7515fSKim, Milo 	u8 val, idx, addr;
250ade7515fSKim, Milo 	int pin1, pin2;
251ade7515fSKim, Milo 
252ade7515fSKim, Milo 	switch (id) {
253ade7515fSKim, Milo 	case BUCK1:
254ade7515fSKim, Milo 		if (mode == EXTPIN) {
255ade7515fSKim, Milo 			b1_dvs = (struct lp8788_buck1_dvs *)buck->dvs;
256ade7515fSKim, Milo 			if (!b1_dvs)
257ade7515fSKim, Milo 				goto err;
258ade7515fSKim, Milo 
259ade7515fSKim, Milo 			idx = gpio_get_value(b1_dvs->gpio) ? 1 : 0;
260ade7515fSKim, Milo 		} else {
261ade7515fSKim, Milo 			lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val);
262ade7515fSKim, Milo 			idx = (val & LP8788_BUCK1_DVS_M) >> LP8788_BUCK1_DVS_S;
263ade7515fSKim, Milo 		}
264ade7515fSKim, Milo 		addr = buck1_vout_addr[idx];
265ade7515fSKim, Milo 		break;
266ade7515fSKim, Milo 	case BUCK2:
267ade7515fSKim, Milo 		if (mode == EXTPIN) {
268ade7515fSKim, Milo 			b2_dvs = (struct lp8788_buck2_dvs *)buck->dvs;
269ade7515fSKim, Milo 			if (!b2_dvs)
270ade7515fSKim, Milo 				goto err;
271ade7515fSKim, Milo 
272ade7515fSKim, Milo 			pin1 = gpio_get_value(b2_dvs->gpio[0]);
273ade7515fSKim, Milo 			pin2 = gpio_get_value(b2_dvs->gpio[1]);
274ade7515fSKim, Milo 
275ade7515fSKim, Milo 			if (pin1 == PIN_LOW && pin2 == PIN_LOW)
276ade7515fSKim, Milo 				idx = 0;
277ade7515fSKim, Milo 			else if (pin1 == PIN_LOW && pin2 == PIN_HIGH)
278ade7515fSKim, Milo 				idx = 2;
279ade7515fSKim, Milo 			else if (pin1 == PIN_HIGH && pin2 == PIN_LOW)
280ade7515fSKim, Milo 				idx = 1;
281ade7515fSKim, Milo 			else
282ade7515fSKim, Milo 				idx = 3;
283ade7515fSKim, Milo 		} else {
284ade7515fSKim, Milo 			lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val);
285ade7515fSKim, Milo 			idx = (val & LP8788_BUCK2_DVS_M) >> LP8788_BUCK2_DVS_S;
286ade7515fSKim, Milo 		}
287ade7515fSKim, Milo 		addr = buck2_vout_addr[idx];
288ade7515fSKim, Milo 		break;
289ade7515fSKim, Milo 	default:
290ade7515fSKim, Milo 		goto err;
291ade7515fSKim, Milo 	}
292ade7515fSKim, Milo 
293ade7515fSKim, Milo 	return addr;
294ade7515fSKim, Milo err:
295ade7515fSKim, Milo 	return INVALID_ADDR;
296ade7515fSKim, Milo }
297ade7515fSKim, Milo 
298ade7515fSKim, Milo static int lp8788_buck12_set_voltage_sel(struct regulator_dev *rdev,
299ade7515fSKim, Milo 					unsigned selector)
300ade7515fSKim, Milo {
301ade7515fSKim, Milo 	struct lp8788_buck *buck = rdev_get_drvdata(rdev);
302ade7515fSKim, Milo 	enum lp8788_buck_id id = rdev_get_id(rdev);
303ade7515fSKim, Milo 	u8 addr;
304ade7515fSKim, Milo 
305ade7515fSKim, Milo 	if (buck->dvs)
306ade7515fSKim, Milo 		lp8788_set_dvs(buck, id);
307ade7515fSKim, Milo 
308ade7515fSKim, Milo 	addr = lp8788_select_buck_vout_addr(buck, id);
309ade7515fSKim, Milo 	if (!lp8788_is_valid_buck_addr(addr))
310ade7515fSKim, Milo 		return -EINVAL;
311ade7515fSKim, Milo 
312ade7515fSKim, Milo 	return lp8788_update_bits(buck->lp, addr, LP8788_VOUT_M, selector);
313ade7515fSKim, Milo }
314ade7515fSKim, Milo 
315ade7515fSKim, Milo static int lp8788_buck12_get_voltage_sel(struct regulator_dev *rdev)
316ade7515fSKim, Milo {
317ade7515fSKim, Milo 	struct lp8788_buck *buck = rdev_get_drvdata(rdev);
318ade7515fSKim, Milo 	enum lp8788_buck_id id = rdev_get_id(rdev);
319ade7515fSKim, Milo 	int ret;
320ade7515fSKim, Milo 	u8 val, addr;
321ade7515fSKim, Milo 
322ade7515fSKim, Milo 	addr = lp8788_select_buck_vout_addr(buck, id);
323ade7515fSKim, Milo 	if (!lp8788_is_valid_buck_addr(addr))
324ade7515fSKim, Milo 		return -EINVAL;
325ade7515fSKim, Milo 
326ade7515fSKim, Milo 	ret = lp8788_read_byte(buck->lp, addr, &val);
327ade7515fSKim, Milo 	if (ret)
328ade7515fSKim, Milo 		return ret;
329ade7515fSKim, Milo 
330ade7515fSKim, Milo 	return val & LP8788_VOUT_M;
331ade7515fSKim, Milo }
332ade7515fSKim, Milo 
333ade7515fSKim, Milo static int lp8788_buck_enable_time(struct regulator_dev *rdev)
334ade7515fSKim, Milo {
335ade7515fSKim, Milo 	struct lp8788_buck *buck = rdev_get_drvdata(rdev);
336ade7515fSKim, Milo 	enum lp8788_buck_id id = rdev_get_id(rdev);
337ade7515fSKim, Milo 	u8 val, addr = LP8788_BUCK1_TIMESTEP + id;
338ade7515fSKim, Milo 
339ade7515fSKim, Milo 	if (lp8788_read_byte(buck->lp, addr, &val))
340ade7515fSKim, Milo 		return -EINVAL;
341ade7515fSKim, Milo 
342ade7515fSKim, Milo 	val = (val & LP8788_STARTUP_TIME_M) >> LP8788_STARTUP_TIME_S;
343ade7515fSKim, Milo 
344ade7515fSKim, Milo 	return ENABLE_TIME_USEC * val;
345ade7515fSKim, Milo }
346ade7515fSKim, Milo 
347ade7515fSKim, Milo static int lp8788_buck_set_mode(struct regulator_dev *rdev, unsigned int mode)
348ade7515fSKim, Milo {
349ade7515fSKim, Milo 	struct lp8788_buck *buck = rdev_get_drvdata(rdev);
350ade7515fSKim, Milo 	struct lp8788_pwm_map *pmap = buck->pmap;
351ade7515fSKim, Milo 	u8 val;
352ade7515fSKim, Milo 
353ade7515fSKim, Milo 	if (!pmap)
354ade7515fSKim, Milo 		return -EINVAL;
355ade7515fSKim, Milo 
356ade7515fSKim, Milo 	switch (mode) {
357ade7515fSKim, Milo 	case REGULATOR_MODE_FAST:
358ade7515fSKim, Milo 		val = LP8788_FORCE_PWM << pmap->shift;
359ade7515fSKim, Milo 		break;
360ade7515fSKim, Milo 	case REGULATOR_MODE_NORMAL:
361ade7515fSKim, Milo 		val = LP8788_AUTO_PWM << pmap->shift;
362ade7515fSKim, Milo 		break;
363ade7515fSKim, Milo 	default:
364ade7515fSKim, Milo 		return -EINVAL;
365ade7515fSKim, Milo 	}
366ade7515fSKim, Milo 
367ade7515fSKim, Milo 	return lp8788_update_bits(buck->lp, LP8788_BUCK_PWM, pmap->mask, val);
368ade7515fSKim, Milo }
369ade7515fSKim, Milo 
370ade7515fSKim, Milo static unsigned int lp8788_buck_get_mode(struct regulator_dev *rdev)
371ade7515fSKim, Milo {
372ade7515fSKim, Milo 	struct lp8788_buck *buck = rdev_get_drvdata(rdev);
373ade7515fSKim, Milo 	struct lp8788_pwm_map *pmap = buck->pmap;
374ade7515fSKim, Milo 	u8 val;
375ade7515fSKim, Milo 	int ret;
376ade7515fSKim, Milo 
377ade7515fSKim, Milo 	if (!pmap)
378ade7515fSKim, Milo 		return -EINVAL;
379ade7515fSKim, Milo 
380ade7515fSKim, Milo 	ret = lp8788_read_byte(buck->lp, LP8788_BUCK_PWM, &val);
381ade7515fSKim, Milo 	if (ret)
382ade7515fSKim, Milo 		return ret;
383ade7515fSKim, Milo 
384ade7515fSKim, Milo 	return val & pmap->mask ? REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL;
385ade7515fSKim, Milo }
386ade7515fSKim, Milo 
387ade7515fSKim, Milo static struct regulator_ops lp8788_buck12_ops = {
388ade7515fSKim, Milo 	.list_voltage = regulator_list_voltage_table,
389ade7515fSKim, Milo 	.set_voltage_sel = lp8788_buck12_set_voltage_sel,
390ade7515fSKim, Milo 	.get_voltage_sel = lp8788_buck12_get_voltage_sel,
391ade7515fSKim, Milo 	.enable = regulator_enable_regmap,
392ade7515fSKim, Milo 	.disable = regulator_disable_regmap,
393ade7515fSKim, Milo 	.is_enabled = regulator_is_enabled_regmap,
394ade7515fSKim, Milo 	.enable_time = lp8788_buck_enable_time,
395ade7515fSKim, Milo 	.set_mode = lp8788_buck_set_mode,
396ade7515fSKim, Milo 	.get_mode = lp8788_buck_get_mode,
397ade7515fSKim, Milo };
398ade7515fSKim, Milo 
399ade7515fSKim, Milo static struct regulator_ops lp8788_buck34_ops = {
400ade7515fSKim, Milo 	.list_voltage = regulator_list_voltage_table,
401ade7515fSKim, Milo 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
402ade7515fSKim, Milo 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
403ade7515fSKim, Milo 	.enable = regulator_enable_regmap,
404ade7515fSKim, Milo 	.disable = regulator_disable_regmap,
405ade7515fSKim, Milo 	.is_enabled = regulator_is_enabled_regmap,
406ade7515fSKim, Milo 	.enable_time = lp8788_buck_enable_time,
407ade7515fSKim, Milo 	.set_mode = lp8788_buck_set_mode,
408ade7515fSKim, Milo 	.get_mode = lp8788_buck_get_mode,
409ade7515fSKim, Milo };
410ade7515fSKim, Milo 
411ade7515fSKim, Milo static struct regulator_desc lp8788_buck_desc[] = {
412ade7515fSKim, Milo 	{
413ade7515fSKim, Milo 		.name = "buck1",
414ade7515fSKim, Milo 		.id = BUCK1,
415ade7515fSKim, Milo 		.ops = &lp8788_buck12_ops,
416ade7515fSKim, Milo 		.n_voltages = ARRAY_SIZE(lp8788_buck_vtbl),
417ade7515fSKim, Milo 		.volt_table = lp8788_buck_vtbl,
418ade7515fSKim, Milo 		.type = REGULATOR_VOLTAGE,
419ade7515fSKim, Milo 		.owner = THIS_MODULE,
420ade7515fSKim, Milo 		.enable_reg = LP8788_EN_BUCK,
421ade7515fSKim, Milo 		.enable_mask = LP8788_EN_BUCK1_M,
422ade7515fSKim, Milo 	},
423ade7515fSKim, Milo 	{
424ade7515fSKim, Milo 		.name = "buck2",
425ade7515fSKim, Milo 		.id = BUCK2,
426ade7515fSKim, Milo 		.ops = &lp8788_buck12_ops,
427ade7515fSKim, Milo 		.n_voltages = ARRAY_SIZE(lp8788_buck_vtbl),
428ade7515fSKim, Milo 		.volt_table = lp8788_buck_vtbl,
429ade7515fSKim, Milo 		.type = REGULATOR_VOLTAGE,
430ade7515fSKim, Milo 		.owner = THIS_MODULE,
431ade7515fSKim, Milo 		.enable_reg = LP8788_EN_BUCK,
432ade7515fSKim, Milo 		.enable_mask = LP8788_EN_BUCK2_M,
433ade7515fSKim, Milo 	},
434ade7515fSKim, Milo 	{
435ade7515fSKim, Milo 		.name = "buck3",
436ade7515fSKim, Milo 		.id = BUCK3,
437ade7515fSKim, Milo 		.ops = &lp8788_buck34_ops,
438ade7515fSKim, Milo 		.n_voltages = ARRAY_SIZE(lp8788_buck_vtbl),
439ade7515fSKim, Milo 		.volt_table = lp8788_buck_vtbl,
440ade7515fSKim, Milo 		.type = REGULATOR_VOLTAGE,
441ade7515fSKim, Milo 		.owner = THIS_MODULE,
442ade7515fSKim, Milo 		.vsel_reg = LP8788_BUCK3_VOUT,
443ade7515fSKim, Milo 		.vsel_mask = LP8788_VOUT_M,
444ade7515fSKim, Milo 		.enable_reg = LP8788_EN_BUCK,
445ade7515fSKim, Milo 		.enable_mask = LP8788_EN_BUCK3_M,
446ade7515fSKim, Milo 	},
447ade7515fSKim, Milo 	{
448ade7515fSKim, Milo 		.name = "buck4",
449ade7515fSKim, Milo 		.id = BUCK4,
450ade7515fSKim, Milo 		.ops = &lp8788_buck34_ops,
451ade7515fSKim, Milo 		.n_voltages = ARRAY_SIZE(lp8788_buck_vtbl),
452ade7515fSKim, Milo 		.volt_table = lp8788_buck_vtbl,
453ade7515fSKim, Milo 		.type = REGULATOR_VOLTAGE,
454ade7515fSKim, Milo 		.owner = THIS_MODULE,
455ade7515fSKim, Milo 		.vsel_reg = LP8788_BUCK4_VOUT,
456ade7515fSKim, Milo 		.vsel_mask = LP8788_VOUT_M,
457ade7515fSKim, Milo 		.enable_reg = LP8788_EN_BUCK,
458ade7515fSKim, Milo 		.enable_mask = LP8788_EN_BUCK4_M,
459ade7515fSKim, Milo 	},
460ade7515fSKim, Milo };
461ade7515fSKim, Milo 
462ade7515fSKim, Milo static int _gpio_request(struct lp8788_buck *buck, int gpio, char *name)
463ade7515fSKim, Milo {
464ade7515fSKim, Milo 	struct device *dev = buck->lp->dev;
465ade7515fSKim, Milo 
466ade7515fSKim, Milo 	if (!gpio_is_valid(gpio)) {
467ade7515fSKim, Milo 		dev_err(dev, "invalid gpio: %d\n", gpio);
468ade7515fSKim, Milo 		return -EINVAL;
469ade7515fSKim, Milo 	}
470ade7515fSKim, Milo 
471ade7515fSKim, Milo 	return devm_gpio_request_one(dev, gpio, DVS_LOW, name);
472ade7515fSKim, Milo }
473ade7515fSKim, Milo 
474ade7515fSKim, Milo static int lp8788_dvs_gpio_request(struct lp8788_buck *buck,
475ade7515fSKim, Milo 				enum lp8788_buck_id id)
476ade7515fSKim, Milo {
477ade7515fSKim, Milo 	struct lp8788_platform_data *pdata = buck->lp->pdata;
478ade7515fSKim, Milo 	char *b1_name = "LP8788_B1_DVS";
479ade7515fSKim, Milo 	char *b2_name[] = { "LP8788_B2_DVS1", "LP8788_B2_DVS2" };
480ade7515fSKim, Milo 	int i, gpio, ret;
481ade7515fSKim, Milo 
482ade7515fSKim, Milo 	switch (id) {
483ade7515fSKim, Milo 	case BUCK1:
484ade7515fSKim, Milo 		gpio = pdata->buck1_dvs->gpio;
485ade7515fSKim, Milo 		ret = _gpio_request(buck, gpio, b1_name);
486ade7515fSKim, Milo 		if (ret)
487ade7515fSKim, Milo 			return ret;
488ade7515fSKim, Milo 
489ade7515fSKim, Milo 		buck->dvs = pdata->buck1_dvs;
490ade7515fSKim, Milo 		break;
491ade7515fSKim, Milo 	case BUCK2:
492ade7515fSKim, Milo 		for (i = 0 ; i < LP8788_NUM_BUCK2_DVS ; i++) {
493ade7515fSKim, Milo 			gpio = pdata->buck2_dvs->gpio[i];
494ade7515fSKim, Milo 			ret = _gpio_request(buck, gpio, b2_name[i]);
495ade7515fSKim, Milo 			if (ret)
496ade7515fSKim, Milo 				return ret;
497ade7515fSKim, Milo 		}
498ade7515fSKim, Milo 		buck->dvs = pdata->buck2_dvs;
499ade7515fSKim, Milo 		break;
500ade7515fSKim, Milo 	default:
501ade7515fSKim, Milo 		break;
502ade7515fSKim, Milo 	}
503ade7515fSKim, Milo 
504ade7515fSKim, Milo 	return 0;
505ade7515fSKim, Milo }
506ade7515fSKim, Milo 
507ade7515fSKim, Milo static int lp8788_init_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id)
508ade7515fSKim, Milo {
509ade7515fSKim, Milo 	struct lp8788_platform_data *pdata = buck->lp->pdata;
510ade7515fSKim, Milo 	u8 mask[] = { LP8788_BUCK1_DVS_SEL_M, LP8788_BUCK2_DVS_SEL_M };
511ade7515fSKim, Milo 	u8 val[]  = { LP8788_BUCK1_DVS_PIN, LP8788_BUCK2_DVS_PIN };
512*c42ea5cdSAxel Lin 	u8 default_dvs_mode[] = { LP8788_BUCK1_DVS_I2C, LP8788_BUCK2_DVS_I2C };
513ade7515fSKim, Milo 
514ade7515fSKim, Milo 	/* no dvs for buck3, 4 */
515ade7515fSKim, Milo 	if (id == BUCK3 || id == BUCK4)
516ade7515fSKim, Milo 		return 0;
517ade7515fSKim, Milo 
518ade7515fSKim, Milo 	/* no dvs platform data, then dvs will be selected by I2C registers */
519ade7515fSKim, Milo 	if (!pdata)
520ade7515fSKim, Milo 		goto set_default_dvs_mode;
521ade7515fSKim, Milo 
522ade7515fSKim, Milo 	if ((id == BUCK1 && !pdata->buck1_dvs) ||
523ade7515fSKim, Milo 		(id == BUCK2 && !pdata->buck2_dvs))
524ade7515fSKim, Milo 		goto set_default_dvs_mode;
525ade7515fSKim, Milo 
526ade7515fSKim, Milo 	if (lp8788_dvs_gpio_request(buck, id))
527ade7515fSKim, Milo 		goto set_default_dvs_mode;
528ade7515fSKim, Milo 
529ade7515fSKim, Milo 	return lp8788_update_bits(buck->lp, LP8788_BUCK_DVS_SEL, mask[id],
530ade7515fSKim, Milo 				val[id]);
531ade7515fSKim, Milo 
532ade7515fSKim, Milo set_default_dvs_mode:
533*c42ea5cdSAxel Lin 	return lp8788_update_bits(buck->lp, LP8788_BUCK_DVS_SEL, mask[id],
534*c42ea5cdSAxel Lin 				  default_dvs_mode[id]);
535ade7515fSKim, Milo }
536ade7515fSKim, Milo 
537ade7515fSKim, Milo static __devinit int lp8788_buck_probe(struct platform_device *pdev)
538ade7515fSKim, Milo {
539ade7515fSKim, Milo 	struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);
540ade7515fSKim, Milo 	int id = pdev->id;
541ade7515fSKim, Milo 	struct lp8788_buck *buck;
542ade7515fSKim, Milo 	struct regulator_config cfg = { };
543ade7515fSKim, Milo 	struct regulator_dev *rdev;
544ade7515fSKim, Milo 	int ret;
545ade7515fSKim, Milo 
546ade7515fSKim, Milo 	buck = devm_kzalloc(lp->dev, sizeof(struct lp8788_buck), GFP_KERNEL);
547ade7515fSKim, Milo 	if (!buck)
548ade7515fSKim, Milo 		return -ENOMEM;
549ade7515fSKim, Milo 
550ade7515fSKim, Milo 	buck->lp = lp;
551ade7515fSKim, Milo 	buck->pmap = &buck_pmap[id];
552ade7515fSKim, Milo 
553ade7515fSKim, Milo 	ret = lp8788_init_dvs(buck, id);
554ade7515fSKim, Milo 	if (ret)
555ade7515fSKim, Milo 		return ret;
556ade7515fSKim, Milo 
557ade7515fSKim, Milo 	cfg.dev = lp->dev;
558ade7515fSKim, Milo 	cfg.init_data = lp->pdata ? lp->pdata->buck_data[id] : NULL;
559ade7515fSKim, Milo 	cfg.driver_data = buck;
560ade7515fSKim, Milo 	cfg.regmap = lp->regmap;
561ade7515fSKim, Milo 
562ade7515fSKim, Milo 	rdev = regulator_register(&lp8788_buck_desc[id], &cfg);
563ade7515fSKim, Milo 	if (IS_ERR(rdev)) {
564ade7515fSKim, Milo 		ret = PTR_ERR(rdev);
565ade7515fSKim, Milo 		dev_err(lp->dev, "BUCK%d regulator register err = %d\n",
566ade7515fSKim, Milo 				id + 1, ret);
567ade7515fSKim, Milo 		return ret;
568ade7515fSKim, Milo 	}
569ade7515fSKim, Milo 
570ade7515fSKim, Milo 	buck->regulator = rdev;
571ade7515fSKim, Milo 	platform_set_drvdata(pdev, buck);
572ade7515fSKim, Milo 
573ade7515fSKim, Milo 	return 0;
574ade7515fSKim, Milo }
575ade7515fSKim, Milo 
576ade7515fSKim, Milo static int __devexit lp8788_buck_remove(struct platform_device *pdev)
577ade7515fSKim, Milo {
578ade7515fSKim, Milo 	struct lp8788_buck *buck = platform_get_drvdata(pdev);
579ade7515fSKim, Milo 
580ade7515fSKim, Milo 	platform_set_drvdata(pdev, NULL);
581ade7515fSKim, Milo 	regulator_unregister(buck->regulator);
582ade7515fSKim, Milo 
583ade7515fSKim, Milo 	return 0;
584ade7515fSKim, Milo }
585ade7515fSKim, Milo 
586ade7515fSKim, Milo static struct platform_driver lp8788_buck_driver = {
587ade7515fSKim, Milo 	.probe = lp8788_buck_probe,
588ade7515fSKim, Milo 	.remove = __devexit_p(lp8788_buck_remove),
589ade7515fSKim, Milo 	.driver = {
590ade7515fSKim, Milo 		.name = LP8788_DEV_BUCK,
591ade7515fSKim, Milo 		.owner = THIS_MODULE,
592ade7515fSKim, Milo 	},
593ade7515fSKim, Milo };
594ade7515fSKim, Milo 
595ade7515fSKim, Milo static int __init lp8788_buck_init(void)
596ade7515fSKim, Milo {
597ade7515fSKim, Milo 	return platform_driver_register(&lp8788_buck_driver);
598ade7515fSKim, Milo }
599ade7515fSKim, Milo subsys_initcall(lp8788_buck_init);
600ade7515fSKim, Milo 
601ade7515fSKim, Milo static void __exit lp8788_buck_exit(void)
602ade7515fSKim, Milo {
603ade7515fSKim, Milo 	platform_driver_unregister(&lp8788_buck_driver);
604ade7515fSKim, Milo }
605ade7515fSKim, Milo module_exit(lp8788_buck_exit);
606ade7515fSKim, Milo 
607ade7515fSKim, Milo MODULE_DESCRIPTION("TI LP8788 BUCK Driver");
608ade7515fSKim, Milo MODULE_AUTHOR("Milo Kim");
609ade7515fSKim, Milo MODULE_LICENSE("GPL");
610ade7515fSKim, Milo MODULE_ALIAS("platform:lp8788-buck");
611