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 
720f4c46d2SAxel Lin #define BUCK_FPWM_MASK(x)		(1 << (x))
730f4c46d2SAxel Lin #define BUCK_FPWM_SHIFT(x)		(x)
740f4c46d2SAxel Lin 
75ade7515fSKim, Milo enum lp8788_dvs_state {
76ade7515fSKim, Milo 	DVS_LOW  = GPIOF_OUT_INIT_LOW,
77ade7515fSKim, Milo 	DVS_HIGH = GPIOF_OUT_INIT_HIGH,
78ade7515fSKim, Milo };
79ade7515fSKim, Milo 
80ade7515fSKim, Milo enum lp8788_dvs_mode {
81ade7515fSKim, Milo 	REGISTER,
82ade7515fSKim, Milo 	EXTPIN,
83ade7515fSKim, Milo };
84ade7515fSKim, Milo 
85ade7515fSKim, Milo enum lp8788_buck_id {
86ade7515fSKim, Milo 	BUCK1,
87ade7515fSKim, Milo 	BUCK2,
88ade7515fSKim, Milo 	BUCK3,
89ade7515fSKim, Milo 	BUCK4,
90ade7515fSKim, Milo };
91ade7515fSKim, Milo 
92ade7515fSKim, Milo struct lp8788_buck {
93ade7515fSKim, Milo 	struct lp8788 *lp;
94ade7515fSKim, Milo 	struct regulator_dev *regulator;
95ade7515fSKim, Milo 	void *dvs;
96ade7515fSKim, Milo };
97ade7515fSKim, Milo 
98ade7515fSKim, Milo /* BUCK 1 ~ 4 voltage table */
99ade7515fSKim, Milo static const int lp8788_buck_vtbl[] = {
100ade7515fSKim, Milo 	 500000,  800000,  850000,  900000,  950000, 1000000, 1050000, 1100000,
101ade7515fSKim, Milo 	1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000,
102ade7515fSKim, Milo 	1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000,
103ade7515fSKim, Milo 	1950000, 2000000,
104ade7515fSKim, Milo };
105ade7515fSKim, Milo 
106ade7515fSKim, Milo static const u8 buck1_vout_addr[] = {
107ade7515fSKim, Milo 	LP8788_BUCK1_VOUT0, LP8788_BUCK1_VOUT1,
108ade7515fSKim, Milo 	LP8788_BUCK1_VOUT2, LP8788_BUCK1_VOUT3,
109ade7515fSKim, Milo };
110ade7515fSKim, Milo 
111ade7515fSKim, Milo static const u8 buck2_vout_addr[] = {
112ade7515fSKim, Milo 	LP8788_BUCK2_VOUT0, LP8788_BUCK2_VOUT1,
113ade7515fSKim, Milo 	LP8788_BUCK2_VOUT2, LP8788_BUCK2_VOUT3,
114ade7515fSKim, Milo };
115ade7515fSKim, Milo 
116ade7515fSKim, Milo static void lp8788_buck1_set_dvs(struct lp8788_buck *buck)
117ade7515fSKim, Milo {
118ade7515fSKim, Milo 	struct lp8788_buck1_dvs *dvs = (struct lp8788_buck1_dvs *)buck->dvs;
119ade7515fSKim, Milo 	enum lp8788_dvs_state pinstate;
120ade7515fSKim, Milo 
121ade7515fSKim, Milo 	if (!dvs)
122ade7515fSKim, Milo 		return;
123ade7515fSKim, Milo 
124ade7515fSKim, Milo 	pinstate = dvs->vsel == DVS_SEL_V0 ? DVS_LOW : DVS_HIGH;
125ade7515fSKim, Milo 	if (gpio_is_valid(dvs->gpio))
126ade7515fSKim, Milo 		gpio_set_value(dvs->gpio, pinstate);
127ade7515fSKim, Milo }
128ade7515fSKim, Milo 
129ade7515fSKim, Milo static void lp8788_buck2_set_dvs(struct lp8788_buck *buck)
130ade7515fSKim, Milo {
131ade7515fSKim, Milo 	struct lp8788_buck2_dvs *dvs = (struct lp8788_buck2_dvs *)buck->dvs;
132ade7515fSKim, Milo 	enum lp8788_dvs_state pin1, pin2;
133ade7515fSKim, Milo 
134ade7515fSKim, Milo 	if (!dvs)
135ade7515fSKim, Milo 		return;
136ade7515fSKim, Milo 
137ade7515fSKim, Milo 	switch (dvs->vsel) {
138ade7515fSKim, Milo 	case DVS_SEL_V0:
139ade7515fSKim, Milo 		pin1 = DVS_LOW;
140ade7515fSKim, Milo 		pin2 = DVS_LOW;
141ade7515fSKim, Milo 		break;
142ade7515fSKim, Milo 	case DVS_SEL_V1:
143ade7515fSKim, Milo 		pin1 = DVS_HIGH;
144ade7515fSKim, Milo 		pin2 = DVS_LOW;
145ade7515fSKim, Milo 		break;
146ade7515fSKim, Milo 	case DVS_SEL_V2:
147ade7515fSKim, Milo 		pin1 = DVS_LOW;
148ade7515fSKim, Milo 		pin2 = DVS_HIGH;
149ade7515fSKim, Milo 		break;
150ade7515fSKim, Milo 	case DVS_SEL_V3:
151ade7515fSKim, Milo 		pin1 = DVS_HIGH;
152ade7515fSKim, Milo 		pin2 = DVS_HIGH;
153ade7515fSKim, Milo 		break;
154ade7515fSKim, Milo 	default:
155ade7515fSKim, Milo 		return;
156ade7515fSKim, Milo 	}
157ade7515fSKim, Milo 
158ade7515fSKim, Milo 	if (gpio_is_valid(dvs->gpio[0]))
159ade7515fSKim, Milo 		gpio_set_value(dvs->gpio[0], pin1);
160ade7515fSKim, Milo 
161ade7515fSKim, Milo 	if (gpio_is_valid(dvs->gpio[1]))
162ade7515fSKim, Milo 		gpio_set_value(dvs->gpio[1], pin2);
163ade7515fSKim, Milo }
164ade7515fSKim, Milo 
165ade7515fSKim, Milo static void lp8788_set_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id)
166ade7515fSKim, Milo {
167ade7515fSKim, Milo 	switch (id) {
168ade7515fSKim, Milo 	case BUCK1:
169ade7515fSKim, Milo 		lp8788_buck1_set_dvs(buck);
170ade7515fSKim, Milo 		break;
171ade7515fSKim, Milo 	case BUCK2:
172ade7515fSKim, Milo 		lp8788_buck2_set_dvs(buck);
173ade7515fSKim, Milo 		break;
174ade7515fSKim, Milo 	default:
175ade7515fSKim, Milo 		break;
176ade7515fSKim, Milo 	}
177ade7515fSKim, Milo }
178ade7515fSKim, Milo 
179ade7515fSKim, Milo static enum lp8788_dvs_mode
180ade7515fSKim, Milo lp8788_get_buck_dvs_ctrl_mode(struct lp8788_buck *buck, enum lp8788_buck_id id)
181ade7515fSKim, Milo {
182ade7515fSKim, Milo 	u8 val, mask;
183ade7515fSKim, Milo 
184ade7515fSKim, Milo 	switch (id) {
185ade7515fSKim, Milo 	case BUCK1:
186ade7515fSKim, Milo 		mask = LP8788_BUCK1_DVS_SEL_M;
187ade7515fSKim, Milo 		break;
188ade7515fSKim, Milo 	case BUCK2:
189ade7515fSKim, Milo 		mask = LP8788_BUCK2_DVS_SEL_M;
190ade7515fSKim, Milo 		break;
191ade7515fSKim, Milo 	default:
192ade7515fSKim, Milo 		return REGISTER;
193ade7515fSKim, Milo 	}
194ade7515fSKim, Milo 
195ade7515fSKim, Milo 	lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val);
196ade7515fSKim, Milo 
197ade7515fSKim, Milo 	return val & mask ? REGISTER : EXTPIN;
198ade7515fSKim, Milo }
199ade7515fSKim, Milo 
200ade7515fSKim, Milo static bool lp8788_is_valid_buck_addr(u8 addr)
201ade7515fSKim, Milo {
202ade7515fSKim, Milo 	switch (addr) {
203ade7515fSKim, Milo 	case LP8788_BUCK1_VOUT0:
204ade7515fSKim, Milo 	case LP8788_BUCK1_VOUT1:
205ade7515fSKim, Milo 	case LP8788_BUCK1_VOUT2:
206ade7515fSKim, Milo 	case LP8788_BUCK1_VOUT3:
207ade7515fSKim, Milo 	case LP8788_BUCK2_VOUT0:
208ade7515fSKim, Milo 	case LP8788_BUCK2_VOUT1:
209ade7515fSKim, Milo 	case LP8788_BUCK2_VOUT2:
210ade7515fSKim, Milo 	case LP8788_BUCK2_VOUT3:
211ade7515fSKim, Milo 		return true;
212ade7515fSKim, Milo 	default:
213ade7515fSKim, Milo 		return false;
214ade7515fSKim, Milo 	}
215ade7515fSKim, Milo }
216ade7515fSKim, Milo 
217ade7515fSKim, Milo static u8 lp8788_select_buck_vout_addr(struct lp8788_buck *buck,
218ade7515fSKim, Milo 					enum lp8788_buck_id id)
219ade7515fSKim, Milo {
220ade7515fSKim, Milo 	enum lp8788_dvs_mode mode = lp8788_get_buck_dvs_ctrl_mode(buck, id);
221ade7515fSKim, Milo 	struct lp8788_buck1_dvs *b1_dvs;
222ade7515fSKim, Milo 	struct lp8788_buck2_dvs *b2_dvs;
223ade7515fSKim, Milo 	u8 val, idx, addr;
224ade7515fSKim, Milo 	int pin1, pin2;
225ade7515fSKim, Milo 
226ade7515fSKim, Milo 	switch (id) {
227ade7515fSKim, Milo 	case BUCK1:
228ade7515fSKim, Milo 		if (mode == EXTPIN) {
229ade7515fSKim, Milo 			b1_dvs = (struct lp8788_buck1_dvs *)buck->dvs;
230ade7515fSKim, Milo 			if (!b1_dvs)
231ade7515fSKim, Milo 				goto err;
232ade7515fSKim, Milo 
233ade7515fSKim, Milo 			idx = gpio_get_value(b1_dvs->gpio) ? 1 : 0;
234ade7515fSKim, Milo 		} else {
235ade7515fSKim, Milo 			lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val);
236ade7515fSKim, Milo 			idx = (val & LP8788_BUCK1_DVS_M) >> LP8788_BUCK1_DVS_S;
237ade7515fSKim, Milo 		}
238ade7515fSKim, Milo 		addr = buck1_vout_addr[idx];
239ade7515fSKim, Milo 		break;
240ade7515fSKim, Milo 	case BUCK2:
241ade7515fSKim, Milo 		if (mode == EXTPIN) {
242ade7515fSKim, Milo 			b2_dvs = (struct lp8788_buck2_dvs *)buck->dvs;
243ade7515fSKim, Milo 			if (!b2_dvs)
244ade7515fSKim, Milo 				goto err;
245ade7515fSKim, Milo 
246ade7515fSKim, Milo 			pin1 = gpio_get_value(b2_dvs->gpio[0]);
247ade7515fSKim, Milo 			pin2 = gpio_get_value(b2_dvs->gpio[1]);
248ade7515fSKim, Milo 
249ade7515fSKim, Milo 			if (pin1 == PIN_LOW && pin2 == PIN_LOW)
250ade7515fSKim, Milo 				idx = 0;
251ade7515fSKim, Milo 			else if (pin1 == PIN_LOW && pin2 == PIN_HIGH)
252ade7515fSKim, Milo 				idx = 2;
253ade7515fSKim, Milo 			else if (pin1 == PIN_HIGH && pin2 == PIN_LOW)
254ade7515fSKim, Milo 				idx = 1;
255ade7515fSKim, Milo 			else
256ade7515fSKim, Milo 				idx = 3;
257ade7515fSKim, Milo 		} else {
258ade7515fSKim, Milo 			lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val);
259ade7515fSKim, Milo 			idx = (val & LP8788_BUCK2_DVS_M) >> LP8788_BUCK2_DVS_S;
260ade7515fSKim, Milo 		}
261ade7515fSKim, Milo 		addr = buck2_vout_addr[idx];
262ade7515fSKim, Milo 		break;
263ade7515fSKim, Milo 	default:
264ade7515fSKim, Milo 		goto err;
265ade7515fSKim, Milo 	}
266ade7515fSKim, Milo 
267ade7515fSKim, Milo 	return addr;
268ade7515fSKim, Milo err:
269ade7515fSKim, Milo 	return INVALID_ADDR;
270ade7515fSKim, Milo }
271ade7515fSKim, Milo 
272ade7515fSKim, Milo static int lp8788_buck12_set_voltage_sel(struct regulator_dev *rdev,
273ade7515fSKim, Milo 					unsigned selector)
274ade7515fSKim, Milo {
275ade7515fSKim, Milo 	struct lp8788_buck *buck = rdev_get_drvdata(rdev);
276ade7515fSKim, Milo 	enum lp8788_buck_id id = rdev_get_id(rdev);
277ade7515fSKim, Milo 	u8 addr;
278ade7515fSKim, Milo 
279ade7515fSKim, Milo 	if (buck->dvs)
280ade7515fSKim, Milo 		lp8788_set_dvs(buck, id);
281ade7515fSKim, Milo 
282ade7515fSKim, Milo 	addr = lp8788_select_buck_vout_addr(buck, id);
283ade7515fSKim, Milo 	if (!lp8788_is_valid_buck_addr(addr))
284ade7515fSKim, Milo 		return -EINVAL;
285ade7515fSKim, Milo 
286ade7515fSKim, Milo 	return lp8788_update_bits(buck->lp, addr, LP8788_VOUT_M, selector);
287ade7515fSKim, Milo }
288ade7515fSKim, Milo 
289ade7515fSKim, Milo static int lp8788_buck12_get_voltage_sel(struct regulator_dev *rdev)
290ade7515fSKim, Milo {
291ade7515fSKim, Milo 	struct lp8788_buck *buck = rdev_get_drvdata(rdev);
292ade7515fSKim, Milo 	enum lp8788_buck_id id = rdev_get_id(rdev);
293ade7515fSKim, Milo 	int ret;
294ade7515fSKim, Milo 	u8 val, addr;
295ade7515fSKim, Milo 
296ade7515fSKim, Milo 	addr = lp8788_select_buck_vout_addr(buck, id);
297ade7515fSKim, Milo 	if (!lp8788_is_valid_buck_addr(addr))
298ade7515fSKim, Milo 		return -EINVAL;
299ade7515fSKim, Milo 
300ade7515fSKim, Milo 	ret = lp8788_read_byte(buck->lp, addr, &val);
301ade7515fSKim, Milo 	if (ret)
302ade7515fSKim, Milo 		return ret;
303ade7515fSKim, Milo 
304ade7515fSKim, Milo 	return val & LP8788_VOUT_M;
305ade7515fSKim, Milo }
306ade7515fSKim, Milo 
307ade7515fSKim, Milo static int lp8788_buck_enable_time(struct regulator_dev *rdev)
308ade7515fSKim, Milo {
309ade7515fSKim, Milo 	struct lp8788_buck *buck = rdev_get_drvdata(rdev);
310ade7515fSKim, Milo 	enum lp8788_buck_id id = rdev_get_id(rdev);
311ade7515fSKim, Milo 	u8 val, addr = LP8788_BUCK1_TIMESTEP + id;
312ade7515fSKim, Milo 
313ade7515fSKim, Milo 	if (lp8788_read_byte(buck->lp, addr, &val))
314ade7515fSKim, Milo 		return -EINVAL;
315ade7515fSKim, Milo 
316ade7515fSKim, Milo 	val = (val & LP8788_STARTUP_TIME_M) >> LP8788_STARTUP_TIME_S;
317ade7515fSKim, Milo 
318ade7515fSKim, Milo 	return ENABLE_TIME_USEC * val;
319ade7515fSKim, Milo }
320ade7515fSKim, Milo 
321ade7515fSKim, Milo static int lp8788_buck_set_mode(struct regulator_dev *rdev, unsigned int mode)
322ade7515fSKim, Milo {
323ade7515fSKim, Milo 	struct lp8788_buck *buck = rdev_get_drvdata(rdev);
3240f4c46d2SAxel Lin 	enum lp8788_buck_id id = rdev_get_id(rdev);
3250f4c46d2SAxel Lin 	u8 mask, val;
326ade7515fSKim, Milo 
3270f4c46d2SAxel Lin 	mask = BUCK_FPWM_MASK(id);
328ade7515fSKim, Milo 	switch (mode) {
329ade7515fSKim, Milo 	case REGULATOR_MODE_FAST:
3300f4c46d2SAxel Lin 		val = LP8788_FORCE_PWM << BUCK_FPWM_SHIFT(id);
331ade7515fSKim, Milo 		break;
332ade7515fSKim, Milo 	case REGULATOR_MODE_NORMAL:
3330f4c46d2SAxel Lin 		val = LP8788_AUTO_PWM << BUCK_FPWM_SHIFT(id);
334ade7515fSKim, Milo 		break;
335ade7515fSKim, Milo 	default:
336ade7515fSKim, Milo 		return -EINVAL;
337ade7515fSKim, Milo 	}
338ade7515fSKim, Milo 
3390f4c46d2SAxel Lin 	return lp8788_update_bits(buck->lp, LP8788_BUCK_PWM, mask, val);
340ade7515fSKim, Milo }
341ade7515fSKim, Milo 
342ade7515fSKim, Milo static unsigned int lp8788_buck_get_mode(struct regulator_dev *rdev)
343ade7515fSKim, Milo {
344ade7515fSKim, Milo 	struct lp8788_buck *buck = rdev_get_drvdata(rdev);
3450f4c46d2SAxel Lin 	enum lp8788_buck_id id = rdev_get_id(rdev);
346ade7515fSKim, Milo 	u8 val;
347ade7515fSKim, Milo 	int ret;
348ade7515fSKim, Milo 
349ade7515fSKim, Milo 	ret = lp8788_read_byte(buck->lp, LP8788_BUCK_PWM, &val);
350ade7515fSKim, Milo 	if (ret)
351ade7515fSKim, Milo 		return ret;
352ade7515fSKim, Milo 
3530f4c46d2SAxel Lin 	return val & BUCK_FPWM_MASK(id) ?
3540f4c46d2SAxel Lin 				REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL;
355ade7515fSKim, Milo }
356ade7515fSKim, Milo 
357ade7515fSKim, Milo static struct regulator_ops lp8788_buck12_ops = {
358ade7515fSKim, Milo 	.list_voltage = regulator_list_voltage_table,
359ade7515fSKim, Milo 	.set_voltage_sel = lp8788_buck12_set_voltage_sel,
360ade7515fSKim, Milo 	.get_voltage_sel = lp8788_buck12_get_voltage_sel,
361ade7515fSKim, Milo 	.enable = regulator_enable_regmap,
362ade7515fSKim, Milo 	.disable = regulator_disable_regmap,
363ade7515fSKim, Milo 	.is_enabled = regulator_is_enabled_regmap,
364ade7515fSKim, Milo 	.enable_time = lp8788_buck_enable_time,
365ade7515fSKim, Milo 	.set_mode = lp8788_buck_set_mode,
366ade7515fSKim, Milo 	.get_mode = lp8788_buck_get_mode,
367ade7515fSKim, Milo };
368ade7515fSKim, Milo 
369ade7515fSKim, Milo static struct regulator_ops lp8788_buck34_ops = {
370ade7515fSKim, Milo 	.list_voltage = regulator_list_voltage_table,
371ade7515fSKim, Milo 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
372ade7515fSKim, Milo 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
373ade7515fSKim, Milo 	.enable = regulator_enable_regmap,
374ade7515fSKim, Milo 	.disable = regulator_disable_regmap,
375ade7515fSKim, Milo 	.is_enabled = regulator_is_enabled_regmap,
376ade7515fSKim, Milo 	.enable_time = lp8788_buck_enable_time,
377ade7515fSKim, Milo 	.set_mode = lp8788_buck_set_mode,
378ade7515fSKim, Milo 	.get_mode = lp8788_buck_get_mode,
379ade7515fSKim, Milo };
380ade7515fSKim, Milo 
381ade7515fSKim, Milo static struct regulator_desc lp8788_buck_desc[] = {
382ade7515fSKim, Milo 	{
383ade7515fSKim, Milo 		.name = "buck1",
384ade7515fSKim, Milo 		.id = BUCK1,
385ade7515fSKim, Milo 		.ops = &lp8788_buck12_ops,
386ade7515fSKim, Milo 		.n_voltages = ARRAY_SIZE(lp8788_buck_vtbl),
387ade7515fSKim, Milo 		.volt_table = lp8788_buck_vtbl,
388ade7515fSKim, Milo 		.type = REGULATOR_VOLTAGE,
389ade7515fSKim, Milo 		.owner = THIS_MODULE,
390ade7515fSKim, Milo 		.enable_reg = LP8788_EN_BUCK,
391ade7515fSKim, Milo 		.enable_mask = LP8788_EN_BUCK1_M,
392ade7515fSKim, Milo 	},
393ade7515fSKim, Milo 	{
394ade7515fSKim, Milo 		.name = "buck2",
395ade7515fSKim, Milo 		.id = BUCK2,
396ade7515fSKim, Milo 		.ops = &lp8788_buck12_ops,
397ade7515fSKim, Milo 		.n_voltages = ARRAY_SIZE(lp8788_buck_vtbl),
398ade7515fSKim, Milo 		.volt_table = lp8788_buck_vtbl,
399ade7515fSKim, Milo 		.type = REGULATOR_VOLTAGE,
400ade7515fSKim, Milo 		.owner = THIS_MODULE,
401ade7515fSKim, Milo 		.enable_reg = LP8788_EN_BUCK,
402ade7515fSKim, Milo 		.enable_mask = LP8788_EN_BUCK2_M,
403ade7515fSKim, Milo 	},
404ade7515fSKim, Milo 	{
405ade7515fSKim, Milo 		.name = "buck3",
406ade7515fSKim, Milo 		.id = BUCK3,
407ade7515fSKim, Milo 		.ops = &lp8788_buck34_ops,
408ade7515fSKim, Milo 		.n_voltages = ARRAY_SIZE(lp8788_buck_vtbl),
409ade7515fSKim, Milo 		.volt_table = lp8788_buck_vtbl,
410ade7515fSKim, Milo 		.type = REGULATOR_VOLTAGE,
411ade7515fSKim, Milo 		.owner = THIS_MODULE,
412ade7515fSKim, Milo 		.vsel_reg = LP8788_BUCK3_VOUT,
413ade7515fSKim, Milo 		.vsel_mask = LP8788_VOUT_M,
414ade7515fSKim, Milo 		.enable_reg = LP8788_EN_BUCK,
415ade7515fSKim, Milo 		.enable_mask = LP8788_EN_BUCK3_M,
416ade7515fSKim, Milo 	},
417ade7515fSKim, Milo 	{
418ade7515fSKim, Milo 		.name = "buck4",
419ade7515fSKim, Milo 		.id = BUCK4,
420ade7515fSKim, Milo 		.ops = &lp8788_buck34_ops,
421ade7515fSKim, Milo 		.n_voltages = ARRAY_SIZE(lp8788_buck_vtbl),
422ade7515fSKim, Milo 		.volt_table = lp8788_buck_vtbl,
423ade7515fSKim, Milo 		.type = REGULATOR_VOLTAGE,
424ade7515fSKim, Milo 		.owner = THIS_MODULE,
425ade7515fSKim, Milo 		.vsel_reg = LP8788_BUCK4_VOUT,
426ade7515fSKim, Milo 		.vsel_mask = LP8788_VOUT_M,
427ade7515fSKim, Milo 		.enable_reg = LP8788_EN_BUCK,
428ade7515fSKim, Milo 		.enable_mask = LP8788_EN_BUCK4_M,
429ade7515fSKim, Milo 	},
430ade7515fSKim, Milo };
431ade7515fSKim, Milo 
43238d8f67cSKim, Milo static int lp8788_dvs_gpio_request(struct platform_device *pdev,
43338d8f67cSKim, Milo 				struct lp8788_buck *buck,
434ade7515fSKim, Milo 				enum lp8788_buck_id id)
435ade7515fSKim, Milo {
436ade7515fSKim, Milo 	struct lp8788_platform_data *pdata = buck->lp->pdata;
437ade7515fSKim, Milo 	char *b1_name = "LP8788_B1_DVS";
438ade7515fSKim, Milo 	char *b2_name[] = { "LP8788_B2_DVS1", "LP8788_B2_DVS2" };
439ade7515fSKim, Milo 	int i, gpio, ret;
440ade7515fSKim, Milo 
441ade7515fSKim, Milo 	switch (id) {
442ade7515fSKim, Milo 	case BUCK1:
443ade7515fSKim, Milo 		gpio = pdata->buck1_dvs->gpio;
44438d8f67cSKim, Milo 		ret = devm_gpio_request_one(&pdev->dev, gpio, DVS_LOW,
445131a5b9dSAxel Lin 					    b1_name);
446ade7515fSKim, Milo 		if (ret)
447ade7515fSKim, Milo 			return ret;
448ade7515fSKim, Milo 
449ade7515fSKim, Milo 		buck->dvs = pdata->buck1_dvs;
450ade7515fSKim, Milo 		break;
451ade7515fSKim, Milo 	case BUCK2:
452ade7515fSKim, Milo 		for (i = 0 ; i < LP8788_NUM_BUCK2_DVS ; i++) {
453ade7515fSKim, Milo 			gpio = pdata->buck2_dvs->gpio[i];
45438d8f67cSKim, Milo 			ret = devm_gpio_request_one(&pdev->dev, gpio,
455131a5b9dSAxel Lin 						    DVS_LOW, b2_name[i]);
456ade7515fSKim, Milo 			if (ret)
457ade7515fSKim, Milo 				return ret;
458ade7515fSKim, Milo 		}
459ade7515fSKim, Milo 		buck->dvs = pdata->buck2_dvs;
460ade7515fSKim, Milo 		break;
461ade7515fSKim, Milo 	default:
462ade7515fSKim, Milo 		break;
463ade7515fSKim, Milo 	}
464ade7515fSKim, Milo 
465ade7515fSKim, Milo 	return 0;
466ade7515fSKim, Milo }
467ade7515fSKim, Milo 
46838d8f67cSKim, Milo static int lp8788_init_dvs(struct platform_device *pdev,
46938d8f67cSKim, Milo 			struct lp8788_buck *buck, enum lp8788_buck_id id)
470ade7515fSKim, Milo {
471ade7515fSKim, Milo 	struct lp8788_platform_data *pdata = buck->lp->pdata;
472ade7515fSKim, Milo 	u8 mask[] = { LP8788_BUCK1_DVS_SEL_M, LP8788_BUCK2_DVS_SEL_M };
473ade7515fSKim, Milo 	u8 val[]  = { LP8788_BUCK1_DVS_PIN, LP8788_BUCK2_DVS_PIN };
474c42ea5cdSAxel Lin 	u8 default_dvs_mode[] = { LP8788_BUCK1_DVS_I2C, LP8788_BUCK2_DVS_I2C };
475ade7515fSKim, Milo 
476ade7515fSKim, Milo 	/* no dvs for buck3, 4 */
477ade7515fSKim, Milo 	if (id == BUCK3 || id == BUCK4)
478ade7515fSKim, Milo 		return 0;
479ade7515fSKim, Milo 
480ade7515fSKim, Milo 	/* no dvs platform data, then dvs will be selected by I2C registers */
481ade7515fSKim, Milo 	if (!pdata)
482ade7515fSKim, Milo 		goto set_default_dvs_mode;
483ade7515fSKim, Milo 
484ade7515fSKim, Milo 	if ((id == BUCK1 && !pdata->buck1_dvs) ||
485ade7515fSKim, Milo 		(id == BUCK2 && !pdata->buck2_dvs))
486ade7515fSKim, Milo 		goto set_default_dvs_mode;
487ade7515fSKim, Milo 
48838d8f67cSKim, Milo 	if (lp8788_dvs_gpio_request(pdev, buck, id))
489ade7515fSKim, Milo 		goto set_default_dvs_mode;
490ade7515fSKim, Milo 
491ade7515fSKim, Milo 	return lp8788_update_bits(buck->lp, LP8788_BUCK_DVS_SEL, mask[id],
492ade7515fSKim, Milo 				val[id]);
493ade7515fSKim, Milo 
494ade7515fSKim, Milo set_default_dvs_mode:
495c42ea5cdSAxel Lin 	return lp8788_update_bits(buck->lp, LP8788_BUCK_DVS_SEL, mask[id],
496c42ea5cdSAxel Lin 				  default_dvs_mode[id]);
497ade7515fSKim, Milo }
498ade7515fSKim, Milo 
499a5023574SBill Pemberton static int lp8788_buck_probe(struct platform_device *pdev)
500ade7515fSKim, Milo {
501ade7515fSKim, Milo 	struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);
502ade7515fSKim, Milo 	int id = pdev->id;
503ade7515fSKim, Milo 	struct lp8788_buck *buck;
504ade7515fSKim, Milo 	struct regulator_config cfg = { };
505ade7515fSKim, Milo 	struct regulator_dev *rdev;
506ade7515fSKim, Milo 	int ret;
507ade7515fSKim, Milo 
5083b0e8f12SKim, Milo 	buck = devm_kzalloc(&pdev->dev, sizeof(struct lp8788_buck), GFP_KERNEL);
509ade7515fSKim, Milo 	if (!buck)
510ade7515fSKim, Milo 		return -ENOMEM;
511ade7515fSKim, Milo 
512ade7515fSKim, Milo 	buck->lp = lp;
513ade7515fSKim, Milo 
51438d8f67cSKim, Milo 	ret = lp8788_init_dvs(pdev, buck, id);
515ade7515fSKim, Milo 	if (ret)
516ade7515fSKim, Milo 		return ret;
517ade7515fSKim, Milo 
5183b0e8f12SKim, Milo 	cfg.dev = pdev->dev.parent;
519ade7515fSKim, Milo 	cfg.init_data = lp->pdata ? lp->pdata->buck_data[id] : NULL;
520ade7515fSKim, Milo 	cfg.driver_data = buck;
521ade7515fSKim, Milo 	cfg.regmap = lp->regmap;
522ade7515fSKim, Milo 
523ade7515fSKim, Milo 	rdev = regulator_register(&lp8788_buck_desc[id], &cfg);
524ade7515fSKim, Milo 	if (IS_ERR(rdev)) {
525ade7515fSKim, Milo 		ret = PTR_ERR(rdev);
5263b0e8f12SKim, Milo 		dev_err(&pdev->dev, "BUCK%d regulator register err = %d\n",
527ade7515fSKim, Milo 				id + 1, ret);
528ade7515fSKim, Milo 		return ret;
529ade7515fSKim, Milo 	}
530ade7515fSKim, Milo 
531ade7515fSKim, Milo 	buck->regulator = rdev;
532ade7515fSKim, Milo 	platform_set_drvdata(pdev, buck);
533ade7515fSKim, Milo 
534ade7515fSKim, Milo 	return 0;
535ade7515fSKim, Milo }
536ade7515fSKim, Milo 
5378dc995f5SBill Pemberton static int lp8788_buck_remove(struct platform_device *pdev)
538ade7515fSKim, Milo {
539ade7515fSKim, Milo 	struct lp8788_buck *buck = platform_get_drvdata(pdev);
540ade7515fSKim, Milo 
541ade7515fSKim, Milo 	platform_set_drvdata(pdev, NULL);
542ade7515fSKim, Milo 	regulator_unregister(buck->regulator);
543ade7515fSKim, Milo 
544ade7515fSKim, Milo 	return 0;
545ade7515fSKim, Milo }
546ade7515fSKim, Milo 
547ade7515fSKim, Milo static struct platform_driver lp8788_buck_driver = {
548ade7515fSKim, Milo 	.probe = lp8788_buck_probe,
5495eb9f2b9SBill Pemberton 	.remove = lp8788_buck_remove,
550ade7515fSKim, Milo 	.driver = {
551ade7515fSKim, Milo 		.name = LP8788_DEV_BUCK,
552ade7515fSKim, Milo 		.owner = THIS_MODULE,
553ade7515fSKim, Milo 	},
554ade7515fSKim, Milo };
555ade7515fSKim, Milo 
556ade7515fSKim, Milo static int __init lp8788_buck_init(void)
557ade7515fSKim, Milo {
558ade7515fSKim, Milo 	return platform_driver_register(&lp8788_buck_driver);
559ade7515fSKim, Milo }
560ade7515fSKim, Milo subsys_initcall(lp8788_buck_init);
561ade7515fSKim, Milo 
562ade7515fSKim, Milo static void __exit lp8788_buck_exit(void)
563ade7515fSKim, Milo {
564ade7515fSKim, Milo 	platform_driver_unregister(&lp8788_buck_driver);
565ade7515fSKim, Milo }
566ade7515fSKim, Milo module_exit(lp8788_buck_exit);
567ade7515fSKim, Milo 
568ade7515fSKim, Milo MODULE_DESCRIPTION("TI LP8788 BUCK Driver");
569ade7515fSKim, Milo MODULE_AUTHOR("Milo Kim");
570ade7515fSKim, Milo MODULE_LICENSE("GPL");
571ade7515fSKim, Milo MODULE_ALIAS("platform:lp8788-buck");
572