1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun //
3*4882a593Smuzhiyun // Copyright (c) 2011 Samsung Electronics Co., Ltd
4*4882a593Smuzhiyun // http://www.samsung.com
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun #include <linux/err.h>
7*4882a593Smuzhiyun #include <linux/of_gpio.h>
8*4882a593Smuzhiyun #include <linux/gpio/consumer.h>
9*4882a593Smuzhiyun #include <linux/module.h>
10*4882a593Smuzhiyun #include <linux/platform_device.h>
11*4882a593Smuzhiyun #include <linux/regulator/driver.h>
12*4882a593Smuzhiyun #include <linux/regulator/machine.h>
13*4882a593Smuzhiyun #include <linux/mfd/samsung/core.h>
14*4882a593Smuzhiyun #include <linux/mfd/samsung/s5m8767.h>
15*4882a593Smuzhiyun #include <linux/regulator/of_regulator.h>
16*4882a593Smuzhiyun #include <linux/regmap.h>
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #define S5M8767_OPMODE_NORMAL_MODE 0x1
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun struct s5m8767_info {
21*4882a593Smuzhiyun struct device *dev;
22*4882a593Smuzhiyun struct sec_pmic_dev *iodev;
23*4882a593Smuzhiyun int num_regulators;
24*4882a593Smuzhiyun struct sec_opmode_data *opmode;
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun int ramp_delay;
27*4882a593Smuzhiyun bool buck2_ramp;
28*4882a593Smuzhiyun bool buck3_ramp;
29*4882a593Smuzhiyun bool buck4_ramp;
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun bool buck2_gpiodvs;
32*4882a593Smuzhiyun bool buck3_gpiodvs;
33*4882a593Smuzhiyun bool buck4_gpiodvs;
34*4882a593Smuzhiyun u8 buck2_vol[8];
35*4882a593Smuzhiyun u8 buck3_vol[8];
36*4882a593Smuzhiyun u8 buck4_vol[8];
37*4882a593Smuzhiyun int buck_gpios[3];
38*4882a593Smuzhiyun int buck_ds[3];
39*4882a593Smuzhiyun int buck_gpioindex;
40*4882a593Smuzhiyun };
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun struct sec_voltage_desc {
43*4882a593Smuzhiyun int max;
44*4882a593Smuzhiyun int min;
45*4882a593Smuzhiyun int step;
46*4882a593Smuzhiyun };
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun static const struct sec_voltage_desc buck_voltage_val1 = {
49*4882a593Smuzhiyun .max = 2225000,
50*4882a593Smuzhiyun .min = 650000,
51*4882a593Smuzhiyun .step = 6250,
52*4882a593Smuzhiyun };
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun static const struct sec_voltage_desc buck_voltage_val2 = {
55*4882a593Smuzhiyun .max = 1600000,
56*4882a593Smuzhiyun .min = 600000,
57*4882a593Smuzhiyun .step = 6250,
58*4882a593Smuzhiyun };
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun static const struct sec_voltage_desc buck_voltage_val3 = {
61*4882a593Smuzhiyun .max = 3000000,
62*4882a593Smuzhiyun .min = 750000,
63*4882a593Smuzhiyun .step = 12500,
64*4882a593Smuzhiyun };
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun static const struct sec_voltage_desc ldo_voltage_val1 = {
67*4882a593Smuzhiyun .max = 3950000,
68*4882a593Smuzhiyun .min = 800000,
69*4882a593Smuzhiyun .step = 50000,
70*4882a593Smuzhiyun };
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun static const struct sec_voltage_desc ldo_voltage_val2 = {
73*4882a593Smuzhiyun .max = 2375000,
74*4882a593Smuzhiyun .min = 800000,
75*4882a593Smuzhiyun .step = 25000,
76*4882a593Smuzhiyun };
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun static const struct sec_voltage_desc *reg_voltage_map[] = {
79*4882a593Smuzhiyun [S5M8767_LDO1] = &ldo_voltage_val2,
80*4882a593Smuzhiyun [S5M8767_LDO2] = &ldo_voltage_val2,
81*4882a593Smuzhiyun [S5M8767_LDO3] = &ldo_voltage_val1,
82*4882a593Smuzhiyun [S5M8767_LDO4] = &ldo_voltage_val1,
83*4882a593Smuzhiyun [S5M8767_LDO5] = &ldo_voltage_val1,
84*4882a593Smuzhiyun [S5M8767_LDO6] = &ldo_voltage_val2,
85*4882a593Smuzhiyun [S5M8767_LDO7] = &ldo_voltage_val2,
86*4882a593Smuzhiyun [S5M8767_LDO8] = &ldo_voltage_val2,
87*4882a593Smuzhiyun [S5M8767_LDO9] = &ldo_voltage_val1,
88*4882a593Smuzhiyun [S5M8767_LDO10] = &ldo_voltage_val1,
89*4882a593Smuzhiyun [S5M8767_LDO11] = &ldo_voltage_val1,
90*4882a593Smuzhiyun [S5M8767_LDO12] = &ldo_voltage_val1,
91*4882a593Smuzhiyun [S5M8767_LDO13] = &ldo_voltage_val1,
92*4882a593Smuzhiyun [S5M8767_LDO14] = &ldo_voltage_val1,
93*4882a593Smuzhiyun [S5M8767_LDO15] = &ldo_voltage_val2,
94*4882a593Smuzhiyun [S5M8767_LDO16] = &ldo_voltage_val1,
95*4882a593Smuzhiyun [S5M8767_LDO17] = &ldo_voltage_val1,
96*4882a593Smuzhiyun [S5M8767_LDO18] = &ldo_voltage_val1,
97*4882a593Smuzhiyun [S5M8767_LDO19] = &ldo_voltage_val1,
98*4882a593Smuzhiyun [S5M8767_LDO20] = &ldo_voltage_val1,
99*4882a593Smuzhiyun [S5M8767_LDO21] = &ldo_voltage_val1,
100*4882a593Smuzhiyun [S5M8767_LDO22] = &ldo_voltage_val1,
101*4882a593Smuzhiyun [S5M8767_LDO23] = &ldo_voltage_val1,
102*4882a593Smuzhiyun [S5M8767_LDO24] = &ldo_voltage_val1,
103*4882a593Smuzhiyun [S5M8767_LDO25] = &ldo_voltage_val1,
104*4882a593Smuzhiyun [S5M8767_LDO26] = &ldo_voltage_val1,
105*4882a593Smuzhiyun [S5M8767_LDO27] = &ldo_voltage_val1,
106*4882a593Smuzhiyun [S5M8767_LDO28] = &ldo_voltage_val1,
107*4882a593Smuzhiyun [S5M8767_BUCK1] = &buck_voltage_val1,
108*4882a593Smuzhiyun [S5M8767_BUCK2] = &buck_voltage_val2,
109*4882a593Smuzhiyun [S5M8767_BUCK3] = &buck_voltage_val2,
110*4882a593Smuzhiyun [S5M8767_BUCK4] = &buck_voltage_val2,
111*4882a593Smuzhiyun [S5M8767_BUCK5] = &buck_voltage_val1,
112*4882a593Smuzhiyun [S5M8767_BUCK6] = &buck_voltage_val1,
113*4882a593Smuzhiyun [S5M8767_BUCK7] = &buck_voltage_val3,
114*4882a593Smuzhiyun [S5M8767_BUCK8] = &buck_voltage_val3,
115*4882a593Smuzhiyun [S5M8767_BUCK9] = &buck_voltage_val3,
116*4882a593Smuzhiyun };
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun static const unsigned int s5m8767_opmode_reg[][4] = {
119*4882a593Smuzhiyun /* {OFF, ON, LOWPOWER, SUSPEND} */
120*4882a593Smuzhiyun /* LDO1 ... LDO28 */
121*4882a593Smuzhiyun {0x0, 0x3, 0x2, 0x1}, /* LDO1 */
122*4882a593Smuzhiyun {0x0, 0x3, 0x2, 0x1},
123*4882a593Smuzhiyun {0x0, 0x3, 0x2, 0x1},
124*4882a593Smuzhiyun {0x0, 0x0, 0x0, 0x0},
125*4882a593Smuzhiyun {0x0, 0x3, 0x2, 0x1}, /* LDO5 */
126*4882a593Smuzhiyun {0x0, 0x3, 0x2, 0x1},
127*4882a593Smuzhiyun {0x0, 0x3, 0x2, 0x1},
128*4882a593Smuzhiyun {0x0, 0x3, 0x2, 0x1},
129*4882a593Smuzhiyun {0x0, 0x3, 0x2, 0x1},
130*4882a593Smuzhiyun {0x0, 0x3, 0x2, 0x1}, /* LDO10 */
131*4882a593Smuzhiyun {0x0, 0x3, 0x2, 0x1},
132*4882a593Smuzhiyun {0x0, 0x3, 0x2, 0x1},
133*4882a593Smuzhiyun {0x0, 0x3, 0x2, 0x1},
134*4882a593Smuzhiyun {0x0, 0x3, 0x2, 0x1},
135*4882a593Smuzhiyun {0x0, 0x3, 0x2, 0x1}, /* LDO15 */
136*4882a593Smuzhiyun {0x0, 0x3, 0x2, 0x1},
137*4882a593Smuzhiyun {0x0, 0x3, 0x2, 0x1},
138*4882a593Smuzhiyun {0x0, 0x0, 0x0, 0x0},
139*4882a593Smuzhiyun {0x0, 0x3, 0x2, 0x1},
140*4882a593Smuzhiyun {0x0, 0x3, 0x2, 0x1}, /* LDO20 */
141*4882a593Smuzhiyun {0x0, 0x3, 0x2, 0x1},
142*4882a593Smuzhiyun {0x0, 0x3, 0x2, 0x1},
143*4882a593Smuzhiyun {0x0, 0x0, 0x0, 0x0},
144*4882a593Smuzhiyun {0x0, 0x3, 0x2, 0x1},
145*4882a593Smuzhiyun {0x0, 0x3, 0x2, 0x1}, /* LDO25 */
146*4882a593Smuzhiyun {0x0, 0x3, 0x2, 0x1},
147*4882a593Smuzhiyun {0x0, 0x3, 0x2, 0x1},
148*4882a593Smuzhiyun {0x0, 0x3, 0x2, 0x1}, /* LDO28 */
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun /* BUCK1 ... BUCK9 */
151*4882a593Smuzhiyun {0x0, 0x3, 0x1, 0x1}, /* BUCK1 */
152*4882a593Smuzhiyun {0x0, 0x3, 0x1, 0x1},
153*4882a593Smuzhiyun {0x0, 0x3, 0x1, 0x1},
154*4882a593Smuzhiyun {0x0, 0x3, 0x1, 0x1},
155*4882a593Smuzhiyun {0x0, 0x3, 0x2, 0x1}, /* BUCK5 */
156*4882a593Smuzhiyun {0x0, 0x3, 0x1, 0x1},
157*4882a593Smuzhiyun {0x0, 0x3, 0x1, 0x1},
158*4882a593Smuzhiyun {0x0, 0x3, 0x1, 0x1},
159*4882a593Smuzhiyun {0x0, 0x3, 0x1, 0x1}, /* BUCK9 */
160*4882a593Smuzhiyun };
161*4882a593Smuzhiyun
s5m8767_get_register(struct s5m8767_info * s5m8767,int reg_id,int * reg,int * enable_ctrl)162*4882a593Smuzhiyun static int s5m8767_get_register(struct s5m8767_info *s5m8767, int reg_id,
163*4882a593Smuzhiyun int *reg, int *enable_ctrl)
164*4882a593Smuzhiyun {
165*4882a593Smuzhiyun int i;
166*4882a593Smuzhiyun unsigned int mode;
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun switch (reg_id) {
169*4882a593Smuzhiyun case S5M8767_LDO1 ... S5M8767_LDO2:
170*4882a593Smuzhiyun *reg = S5M8767_REG_LDO1CTRL + (reg_id - S5M8767_LDO1);
171*4882a593Smuzhiyun break;
172*4882a593Smuzhiyun case S5M8767_LDO3 ... S5M8767_LDO28:
173*4882a593Smuzhiyun *reg = S5M8767_REG_LDO3CTRL + (reg_id - S5M8767_LDO3);
174*4882a593Smuzhiyun break;
175*4882a593Smuzhiyun case S5M8767_BUCK1:
176*4882a593Smuzhiyun *reg = S5M8767_REG_BUCK1CTRL1;
177*4882a593Smuzhiyun break;
178*4882a593Smuzhiyun case S5M8767_BUCK2 ... S5M8767_BUCK4:
179*4882a593Smuzhiyun *reg = S5M8767_REG_BUCK2CTRL + (reg_id - S5M8767_BUCK2) * 9;
180*4882a593Smuzhiyun break;
181*4882a593Smuzhiyun case S5M8767_BUCK5:
182*4882a593Smuzhiyun *reg = S5M8767_REG_BUCK5CTRL1;
183*4882a593Smuzhiyun break;
184*4882a593Smuzhiyun case S5M8767_BUCK6 ... S5M8767_BUCK9:
185*4882a593Smuzhiyun *reg = S5M8767_REG_BUCK6CTRL1 + (reg_id - S5M8767_BUCK6) * 2;
186*4882a593Smuzhiyun break;
187*4882a593Smuzhiyun default:
188*4882a593Smuzhiyun return -EINVAL;
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun for (i = 0; i < s5m8767->num_regulators; i++) {
192*4882a593Smuzhiyun if (s5m8767->opmode[i].id == reg_id) {
193*4882a593Smuzhiyun mode = s5m8767->opmode[i].mode;
194*4882a593Smuzhiyun break;
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun if (i >= s5m8767->num_regulators)
199*4882a593Smuzhiyun return -EINVAL;
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun *enable_ctrl = s5m8767_opmode_reg[reg_id][mode] << S5M8767_ENCTRL_SHIFT;
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun return 0;
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun
s5m8767_get_vsel_reg(int reg_id,struct s5m8767_info * s5m8767)206*4882a593Smuzhiyun static int s5m8767_get_vsel_reg(int reg_id, struct s5m8767_info *s5m8767)
207*4882a593Smuzhiyun {
208*4882a593Smuzhiyun int reg;
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun switch (reg_id) {
211*4882a593Smuzhiyun case S5M8767_LDO1 ... S5M8767_LDO2:
212*4882a593Smuzhiyun reg = S5M8767_REG_LDO1CTRL + (reg_id - S5M8767_LDO1);
213*4882a593Smuzhiyun break;
214*4882a593Smuzhiyun case S5M8767_LDO3 ... S5M8767_LDO28:
215*4882a593Smuzhiyun reg = S5M8767_REG_LDO3CTRL + (reg_id - S5M8767_LDO3);
216*4882a593Smuzhiyun break;
217*4882a593Smuzhiyun case S5M8767_BUCK1:
218*4882a593Smuzhiyun reg = S5M8767_REG_BUCK1CTRL2;
219*4882a593Smuzhiyun break;
220*4882a593Smuzhiyun case S5M8767_BUCK2:
221*4882a593Smuzhiyun reg = S5M8767_REG_BUCK2DVS1;
222*4882a593Smuzhiyun if (s5m8767->buck2_gpiodvs)
223*4882a593Smuzhiyun reg += s5m8767->buck_gpioindex;
224*4882a593Smuzhiyun break;
225*4882a593Smuzhiyun case S5M8767_BUCK3:
226*4882a593Smuzhiyun reg = S5M8767_REG_BUCK3DVS1;
227*4882a593Smuzhiyun if (s5m8767->buck3_gpiodvs)
228*4882a593Smuzhiyun reg += s5m8767->buck_gpioindex;
229*4882a593Smuzhiyun break;
230*4882a593Smuzhiyun case S5M8767_BUCK4:
231*4882a593Smuzhiyun reg = S5M8767_REG_BUCK4DVS1;
232*4882a593Smuzhiyun if (s5m8767->buck4_gpiodvs)
233*4882a593Smuzhiyun reg += s5m8767->buck_gpioindex;
234*4882a593Smuzhiyun break;
235*4882a593Smuzhiyun case S5M8767_BUCK5:
236*4882a593Smuzhiyun reg = S5M8767_REG_BUCK5CTRL2;
237*4882a593Smuzhiyun break;
238*4882a593Smuzhiyun case S5M8767_BUCK6 ... S5M8767_BUCK9:
239*4882a593Smuzhiyun reg = S5M8767_REG_BUCK6CTRL2 + (reg_id - S5M8767_BUCK6) * 2;
240*4882a593Smuzhiyun break;
241*4882a593Smuzhiyun default:
242*4882a593Smuzhiyun return -EINVAL;
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun return reg;
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun
s5m8767_convert_voltage_to_sel(const struct sec_voltage_desc * desc,int min_vol)248*4882a593Smuzhiyun static int s5m8767_convert_voltage_to_sel(const struct sec_voltage_desc *desc,
249*4882a593Smuzhiyun int min_vol)
250*4882a593Smuzhiyun {
251*4882a593Smuzhiyun int selector = 0;
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun if (desc == NULL)
254*4882a593Smuzhiyun return -EINVAL;
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun if (min_vol > desc->max)
257*4882a593Smuzhiyun return -EINVAL;
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun if (min_vol < desc->min)
260*4882a593Smuzhiyun min_vol = desc->min;
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun selector = DIV_ROUND_UP(min_vol - desc->min, desc->step);
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun if (desc->min + desc->step * selector > desc->max)
265*4882a593Smuzhiyun return -EINVAL;
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun return selector;
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun
s5m8767_set_high(struct s5m8767_info * s5m8767)270*4882a593Smuzhiyun static inline int s5m8767_set_high(struct s5m8767_info *s5m8767)
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun int temp_index = s5m8767->buck_gpioindex;
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1);
275*4882a593Smuzhiyun gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1);
276*4882a593Smuzhiyun gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1);
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun return 0;
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun
s5m8767_set_low(struct s5m8767_info * s5m8767)281*4882a593Smuzhiyun static inline int s5m8767_set_low(struct s5m8767_info *s5m8767)
282*4882a593Smuzhiyun {
283*4882a593Smuzhiyun int temp_index = s5m8767->buck_gpioindex;
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1);
286*4882a593Smuzhiyun gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1);
287*4882a593Smuzhiyun gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1);
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun return 0;
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun
s5m8767_set_voltage_sel(struct regulator_dev * rdev,unsigned selector)292*4882a593Smuzhiyun static int s5m8767_set_voltage_sel(struct regulator_dev *rdev,
293*4882a593Smuzhiyun unsigned selector)
294*4882a593Smuzhiyun {
295*4882a593Smuzhiyun struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
296*4882a593Smuzhiyun int reg_id = rdev_get_id(rdev);
297*4882a593Smuzhiyun int old_index, index = 0;
298*4882a593Smuzhiyun u8 *buck234_vol = NULL;
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun switch (reg_id) {
301*4882a593Smuzhiyun case S5M8767_LDO1 ... S5M8767_LDO28:
302*4882a593Smuzhiyun break;
303*4882a593Smuzhiyun case S5M8767_BUCK1 ... S5M8767_BUCK6:
304*4882a593Smuzhiyun if (reg_id == S5M8767_BUCK2 && s5m8767->buck2_gpiodvs)
305*4882a593Smuzhiyun buck234_vol = &s5m8767->buck2_vol[0];
306*4882a593Smuzhiyun else if (reg_id == S5M8767_BUCK3 && s5m8767->buck3_gpiodvs)
307*4882a593Smuzhiyun buck234_vol = &s5m8767->buck3_vol[0];
308*4882a593Smuzhiyun else if (reg_id == S5M8767_BUCK4 && s5m8767->buck4_gpiodvs)
309*4882a593Smuzhiyun buck234_vol = &s5m8767->buck4_vol[0];
310*4882a593Smuzhiyun break;
311*4882a593Smuzhiyun case S5M8767_BUCK7 ... S5M8767_BUCK8:
312*4882a593Smuzhiyun return -EINVAL;
313*4882a593Smuzhiyun case S5M8767_BUCK9:
314*4882a593Smuzhiyun break;
315*4882a593Smuzhiyun default:
316*4882a593Smuzhiyun return -EINVAL;
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun /* buck234_vol != NULL means to control buck234 voltage via DVS GPIO */
320*4882a593Smuzhiyun if (buck234_vol) {
321*4882a593Smuzhiyun while (*buck234_vol != selector) {
322*4882a593Smuzhiyun buck234_vol++;
323*4882a593Smuzhiyun index++;
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun old_index = s5m8767->buck_gpioindex;
326*4882a593Smuzhiyun s5m8767->buck_gpioindex = index;
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun if (index > old_index)
329*4882a593Smuzhiyun return s5m8767_set_high(s5m8767);
330*4882a593Smuzhiyun else
331*4882a593Smuzhiyun return s5m8767_set_low(s5m8767);
332*4882a593Smuzhiyun } else {
333*4882a593Smuzhiyun return regulator_set_voltage_sel_regmap(rdev, selector);
334*4882a593Smuzhiyun }
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun
s5m8767_set_voltage_time_sel(struct regulator_dev * rdev,unsigned int old_sel,unsigned int new_sel)337*4882a593Smuzhiyun static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev,
338*4882a593Smuzhiyun unsigned int old_sel,
339*4882a593Smuzhiyun unsigned int new_sel)
340*4882a593Smuzhiyun {
341*4882a593Smuzhiyun struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun if ((old_sel < new_sel) && s5m8767->ramp_delay)
344*4882a593Smuzhiyun return DIV_ROUND_UP(rdev->desc->uV_step * (new_sel - old_sel),
345*4882a593Smuzhiyun s5m8767->ramp_delay * 1000);
346*4882a593Smuzhiyun return 0;
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun static const struct regulator_ops s5m8767_ops = {
350*4882a593Smuzhiyun .list_voltage = regulator_list_voltage_linear,
351*4882a593Smuzhiyun .is_enabled = regulator_is_enabled_regmap,
352*4882a593Smuzhiyun .enable = regulator_enable_regmap,
353*4882a593Smuzhiyun .disable = regulator_disable_regmap,
354*4882a593Smuzhiyun .get_voltage_sel = regulator_get_voltage_sel_regmap,
355*4882a593Smuzhiyun .set_voltage_sel = s5m8767_set_voltage_sel,
356*4882a593Smuzhiyun .set_voltage_time_sel = s5m8767_set_voltage_time_sel,
357*4882a593Smuzhiyun };
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun static const struct regulator_ops s5m8767_buck78_ops = {
360*4882a593Smuzhiyun .list_voltage = regulator_list_voltage_linear,
361*4882a593Smuzhiyun .is_enabled = regulator_is_enabled_regmap,
362*4882a593Smuzhiyun .enable = regulator_enable_regmap,
363*4882a593Smuzhiyun .disable = regulator_disable_regmap,
364*4882a593Smuzhiyun .get_voltage_sel = regulator_get_voltage_sel_regmap,
365*4882a593Smuzhiyun .set_voltage_sel = regulator_set_voltage_sel_regmap,
366*4882a593Smuzhiyun };
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun #define s5m8767_regulator_desc(_name) { \
369*4882a593Smuzhiyun .name = #_name, \
370*4882a593Smuzhiyun .id = S5M8767_##_name, \
371*4882a593Smuzhiyun .ops = &s5m8767_ops, \
372*4882a593Smuzhiyun .type = REGULATOR_VOLTAGE, \
373*4882a593Smuzhiyun .owner = THIS_MODULE, \
374*4882a593Smuzhiyun }
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun #define s5m8767_regulator_buck78_desc(_name) { \
377*4882a593Smuzhiyun .name = #_name, \
378*4882a593Smuzhiyun .id = S5M8767_##_name, \
379*4882a593Smuzhiyun .ops = &s5m8767_buck78_ops, \
380*4882a593Smuzhiyun .type = REGULATOR_VOLTAGE, \
381*4882a593Smuzhiyun .owner = THIS_MODULE, \
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun static struct regulator_desc regulators[] = {
385*4882a593Smuzhiyun s5m8767_regulator_desc(LDO1),
386*4882a593Smuzhiyun s5m8767_regulator_desc(LDO2),
387*4882a593Smuzhiyun s5m8767_regulator_desc(LDO3),
388*4882a593Smuzhiyun s5m8767_regulator_desc(LDO4),
389*4882a593Smuzhiyun s5m8767_regulator_desc(LDO5),
390*4882a593Smuzhiyun s5m8767_regulator_desc(LDO6),
391*4882a593Smuzhiyun s5m8767_regulator_desc(LDO7),
392*4882a593Smuzhiyun s5m8767_regulator_desc(LDO8),
393*4882a593Smuzhiyun s5m8767_regulator_desc(LDO9),
394*4882a593Smuzhiyun s5m8767_regulator_desc(LDO10),
395*4882a593Smuzhiyun s5m8767_regulator_desc(LDO11),
396*4882a593Smuzhiyun s5m8767_regulator_desc(LDO12),
397*4882a593Smuzhiyun s5m8767_regulator_desc(LDO13),
398*4882a593Smuzhiyun s5m8767_regulator_desc(LDO14),
399*4882a593Smuzhiyun s5m8767_regulator_desc(LDO15),
400*4882a593Smuzhiyun s5m8767_regulator_desc(LDO16),
401*4882a593Smuzhiyun s5m8767_regulator_desc(LDO17),
402*4882a593Smuzhiyun s5m8767_regulator_desc(LDO18),
403*4882a593Smuzhiyun s5m8767_regulator_desc(LDO19),
404*4882a593Smuzhiyun s5m8767_regulator_desc(LDO20),
405*4882a593Smuzhiyun s5m8767_regulator_desc(LDO21),
406*4882a593Smuzhiyun s5m8767_regulator_desc(LDO22),
407*4882a593Smuzhiyun s5m8767_regulator_desc(LDO23),
408*4882a593Smuzhiyun s5m8767_regulator_desc(LDO24),
409*4882a593Smuzhiyun s5m8767_regulator_desc(LDO25),
410*4882a593Smuzhiyun s5m8767_regulator_desc(LDO26),
411*4882a593Smuzhiyun s5m8767_regulator_desc(LDO27),
412*4882a593Smuzhiyun s5m8767_regulator_desc(LDO28),
413*4882a593Smuzhiyun s5m8767_regulator_desc(BUCK1),
414*4882a593Smuzhiyun s5m8767_regulator_desc(BUCK2),
415*4882a593Smuzhiyun s5m8767_regulator_desc(BUCK3),
416*4882a593Smuzhiyun s5m8767_regulator_desc(BUCK4),
417*4882a593Smuzhiyun s5m8767_regulator_desc(BUCK5),
418*4882a593Smuzhiyun s5m8767_regulator_desc(BUCK6),
419*4882a593Smuzhiyun s5m8767_regulator_buck78_desc(BUCK7),
420*4882a593Smuzhiyun s5m8767_regulator_buck78_desc(BUCK8),
421*4882a593Smuzhiyun s5m8767_regulator_desc(BUCK9),
422*4882a593Smuzhiyun };
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun /*
425*4882a593Smuzhiyun * Enable GPIO control over BUCK9 in regulator_config for that regulator.
426*4882a593Smuzhiyun */
s5m8767_regulator_config_ext_control(struct s5m8767_info * s5m8767,struct sec_regulator_data * rdata,struct regulator_config * config)427*4882a593Smuzhiyun static void s5m8767_regulator_config_ext_control(struct s5m8767_info *s5m8767,
428*4882a593Smuzhiyun struct sec_regulator_data *rdata,
429*4882a593Smuzhiyun struct regulator_config *config)
430*4882a593Smuzhiyun {
431*4882a593Smuzhiyun int i, mode = 0;
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun if (rdata->id != S5M8767_BUCK9)
434*4882a593Smuzhiyun return;
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun /* Check if opmode for regulator matches S5M8767_ENCTRL_USE_GPIO */
437*4882a593Smuzhiyun for (i = 0; i < s5m8767->num_regulators; i++) {
438*4882a593Smuzhiyun const struct sec_opmode_data *opmode = &s5m8767->opmode[i];
439*4882a593Smuzhiyun if (opmode->id == rdata->id) {
440*4882a593Smuzhiyun mode = s5m8767_opmode_reg[rdata->id][opmode->mode];
441*4882a593Smuzhiyun break;
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun }
444*4882a593Smuzhiyun if (mode != S5M8767_ENCTRL_USE_GPIO) {
445*4882a593Smuzhiyun dev_warn(s5m8767->dev,
446*4882a593Smuzhiyun "ext-control for %pOFn: mismatched op_mode (%x), ignoring\n",
447*4882a593Smuzhiyun rdata->reg_node, mode);
448*4882a593Smuzhiyun return;
449*4882a593Smuzhiyun }
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun if (!rdata->ext_control_gpiod) {
452*4882a593Smuzhiyun dev_warn(s5m8767->dev,
453*4882a593Smuzhiyun "ext-control for %pOFn: GPIO not valid, ignoring\n",
454*4882a593Smuzhiyun rdata->reg_node);
455*4882a593Smuzhiyun return;
456*4882a593Smuzhiyun }
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun config->ena_gpiod = rdata->ext_control_gpiod;
459*4882a593Smuzhiyun }
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun /*
462*4882a593Smuzhiyun * Turn on GPIO control over BUCK9.
463*4882a593Smuzhiyun */
s5m8767_enable_ext_control(struct s5m8767_info * s5m8767,struct regulator_dev * rdev)464*4882a593Smuzhiyun static int s5m8767_enable_ext_control(struct s5m8767_info *s5m8767,
465*4882a593Smuzhiyun struct regulator_dev *rdev)
466*4882a593Smuzhiyun {
467*4882a593Smuzhiyun int id = rdev_get_id(rdev);
468*4882a593Smuzhiyun int ret, reg, enable_ctrl;
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun if (id != S5M8767_BUCK9)
471*4882a593Smuzhiyun return -EINVAL;
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun ret = s5m8767_get_register(s5m8767, id, ®, &enable_ctrl);
474*4882a593Smuzhiyun if (ret)
475*4882a593Smuzhiyun return ret;
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun return regmap_update_bits(s5m8767->iodev->regmap_pmic,
478*4882a593Smuzhiyun reg, S5M8767_ENCTRL_MASK,
479*4882a593Smuzhiyun S5M8767_ENCTRL_USE_GPIO << S5M8767_ENCTRL_SHIFT);
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun #ifdef CONFIG_OF
s5m8767_pmic_dt_parse_dvs_gpio(struct sec_pmic_dev * iodev,struct sec_platform_data * pdata,struct device_node * pmic_np)484*4882a593Smuzhiyun static int s5m8767_pmic_dt_parse_dvs_gpio(struct sec_pmic_dev *iodev,
485*4882a593Smuzhiyun struct sec_platform_data *pdata,
486*4882a593Smuzhiyun struct device_node *pmic_np)
487*4882a593Smuzhiyun {
488*4882a593Smuzhiyun int i, gpio;
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun for (i = 0; i < 3; i++) {
491*4882a593Smuzhiyun gpio = of_get_named_gpio(pmic_np,
492*4882a593Smuzhiyun "s5m8767,pmic-buck-dvs-gpios", i);
493*4882a593Smuzhiyun if (!gpio_is_valid(gpio)) {
494*4882a593Smuzhiyun dev_err(iodev->dev, "invalid gpio[%d]: %d\n", i, gpio);
495*4882a593Smuzhiyun return -EINVAL;
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun pdata->buck_gpios[i] = gpio;
498*4882a593Smuzhiyun }
499*4882a593Smuzhiyun return 0;
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun
s5m8767_pmic_dt_parse_ds_gpio(struct sec_pmic_dev * iodev,struct sec_platform_data * pdata,struct device_node * pmic_np)502*4882a593Smuzhiyun static int s5m8767_pmic_dt_parse_ds_gpio(struct sec_pmic_dev *iodev,
503*4882a593Smuzhiyun struct sec_platform_data *pdata,
504*4882a593Smuzhiyun struct device_node *pmic_np)
505*4882a593Smuzhiyun {
506*4882a593Smuzhiyun int i, gpio;
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun for (i = 0; i < 3; i++) {
509*4882a593Smuzhiyun gpio = of_get_named_gpio(pmic_np,
510*4882a593Smuzhiyun "s5m8767,pmic-buck-ds-gpios", i);
511*4882a593Smuzhiyun if (!gpio_is_valid(gpio)) {
512*4882a593Smuzhiyun dev_err(iodev->dev, "invalid gpio[%d]: %d\n", i, gpio);
513*4882a593Smuzhiyun return -EINVAL;
514*4882a593Smuzhiyun }
515*4882a593Smuzhiyun pdata->buck_ds[i] = gpio;
516*4882a593Smuzhiyun }
517*4882a593Smuzhiyun return 0;
518*4882a593Smuzhiyun }
519*4882a593Smuzhiyun
s5m8767_pmic_dt_parse_pdata(struct platform_device * pdev,struct sec_platform_data * pdata)520*4882a593Smuzhiyun static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
521*4882a593Smuzhiyun struct sec_platform_data *pdata)
522*4882a593Smuzhiyun {
523*4882a593Smuzhiyun struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
524*4882a593Smuzhiyun struct device_node *pmic_np, *regulators_np, *reg_np;
525*4882a593Smuzhiyun struct sec_regulator_data *rdata;
526*4882a593Smuzhiyun struct sec_opmode_data *rmode;
527*4882a593Smuzhiyun unsigned int i, dvs_voltage_nr = 8, ret;
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun pmic_np = iodev->dev->of_node;
530*4882a593Smuzhiyun if (!pmic_np) {
531*4882a593Smuzhiyun dev_err(iodev->dev, "could not find pmic sub-node\n");
532*4882a593Smuzhiyun return -ENODEV;
533*4882a593Smuzhiyun }
534*4882a593Smuzhiyun
535*4882a593Smuzhiyun regulators_np = of_get_child_by_name(pmic_np, "regulators");
536*4882a593Smuzhiyun if (!regulators_np) {
537*4882a593Smuzhiyun dev_err(iodev->dev, "could not find regulators sub-node\n");
538*4882a593Smuzhiyun return -EINVAL;
539*4882a593Smuzhiyun }
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun /* count the number of regulators to be supported in pmic */
542*4882a593Smuzhiyun pdata->num_regulators = of_get_child_count(regulators_np);
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun rdata = devm_kcalloc(&pdev->dev,
545*4882a593Smuzhiyun pdata->num_regulators, sizeof(*rdata),
546*4882a593Smuzhiyun GFP_KERNEL);
547*4882a593Smuzhiyun if (!rdata) {
548*4882a593Smuzhiyun of_node_put(regulators_np);
549*4882a593Smuzhiyun return -ENOMEM;
550*4882a593Smuzhiyun }
551*4882a593Smuzhiyun
552*4882a593Smuzhiyun rmode = devm_kcalloc(&pdev->dev,
553*4882a593Smuzhiyun pdata->num_regulators, sizeof(*rmode),
554*4882a593Smuzhiyun GFP_KERNEL);
555*4882a593Smuzhiyun if (!rmode) {
556*4882a593Smuzhiyun of_node_put(regulators_np);
557*4882a593Smuzhiyun return -ENOMEM;
558*4882a593Smuzhiyun }
559*4882a593Smuzhiyun
560*4882a593Smuzhiyun pdata->regulators = rdata;
561*4882a593Smuzhiyun pdata->opmode = rmode;
562*4882a593Smuzhiyun for_each_child_of_node(regulators_np, reg_np) {
563*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(regulators); i++)
564*4882a593Smuzhiyun if (of_node_name_eq(reg_np, regulators[i].name))
565*4882a593Smuzhiyun break;
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun if (i == ARRAY_SIZE(regulators)) {
568*4882a593Smuzhiyun dev_warn(iodev->dev,
569*4882a593Smuzhiyun "don't know how to configure regulator %pOFn\n",
570*4882a593Smuzhiyun reg_np);
571*4882a593Smuzhiyun continue;
572*4882a593Smuzhiyun }
573*4882a593Smuzhiyun
574*4882a593Smuzhiyun rdata->ext_control_gpiod = devm_fwnode_gpiod_get(
575*4882a593Smuzhiyun &pdev->dev,
576*4882a593Smuzhiyun of_fwnode_handle(reg_np),
577*4882a593Smuzhiyun "s5m8767,pmic-ext-control",
578*4882a593Smuzhiyun GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE,
579*4882a593Smuzhiyun "s5m8767");
580*4882a593Smuzhiyun if (PTR_ERR(rdata->ext_control_gpiod) == -ENOENT) {
581*4882a593Smuzhiyun rdata->ext_control_gpiod = NULL;
582*4882a593Smuzhiyun } else if (IS_ERR(rdata->ext_control_gpiod)) {
583*4882a593Smuzhiyun of_node_put(reg_np);
584*4882a593Smuzhiyun of_node_put(regulators_np);
585*4882a593Smuzhiyun return PTR_ERR(rdata->ext_control_gpiod);
586*4882a593Smuzhiyun }
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun rdata->id = i;
589*4882a593Smuzhiyun rdata->initdata = of_get_regulator_init_data(
590*4882a593Smuzhiyun &pdev->dev, reg_np,
591*4882a593Smuzhiyun ®ulators[i]);
592*4882a593Smuzhiyun rdata->reg_node = reg_np;
593*4882a593Smuzhiyun rdata++;
594*4882a593Smuzhiyun rmode->id = i;
595*4882a593Smuzhiyun if (of_property_read_u32(reg_np, "op_mode",
596*4882a593Smuzhiyun &rmode->mode)) {
597*4882a593Smuzhiyun dev_warn(iodev->dev,
598*4882a593Smuzhiyun "no op_mode property at %pOF\n",
599*4882a593Smuzhiyun reg_np);
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun rmode->mode = S5M8767_OPMODE_NORMAL_MODE;
602*4882a593Smuzhiyun }
603*4882a593Smuzhiyun rmode++;
604*4882a593Smuzhiyun }
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun of_node_put(regulators_np);
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun if (of_get_property(pmic_np, "s5m8767,pmic-buck2-uses-gpio-dvs", NULL)) {
609*4882a593Smuzhiyun pdata->buck2_gpiodvs = true;
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun if (of_property_read_u32_array(pmic_np,
612*4882a593Smuzhiyun "s5m8767,pmic-buck2-dvs-voltage",
613*4882a593Smuzhiyun pdata->buck2_voltage, dvs_voltage_nr)) {
614*4882a593Smuzhiyun dev_err(iodev->dev, "buck2 voltages not specified\n");
615*4882a593Smuzhiyun return -EINVAL;
616*4882a593Smuzhiyun }
617*4882a593Smuzhiyun }
618*4882a593Smuzhiyun
619*4882a593Smuzhiyun if (of_get_property(pmic_np, "s5m8767,pmic-buck3-uses-gpio-dvs", NULL)) {
620*4882a593Smuzhiyun pdata->buck3_gpiodvs = true;
621*4882a593Smuzhiyun
622*4882a593Smuzhiyun if (of_property_read_u32_array(pmic_np,
623*4882a593Smuzhiyun "s5m8767,pmic-buck3-dvs-voltage",
624*4882a593Smuzhiyun pdata->buck3_voltage, dvs_voltage_nr)) {
625*4882a593Smuzhiyun dev_err(iodev->dev, "buck3 voltages not specified\n");
626*4882a593Smuzhiyun return -EINVAL;
627*4882a593Smuzhiyun }
628*4882a593Smuzhiyun }
629*4882a593Smuzhiyun
630*4882a593Smuzhiyun if (of_get_property(pmic_np, "s5m8767,pmic-buck4-uses-gpio-dvs", NULL)) {
631*4882a593Smuzhiyun pdata->buck4_gpiodvs = true;
632*4882a593Smuzhiyun
633*4882a593Smuzhiyun if (of_property_read_u32_array(pmic_np,
634*4882a593Smuzhiyun "s5m8767,pmic-buck4-dvs-voltage",
635*4882a593Smuzhiyun pdata->buck4_voltage, dvs_voltage_nr)) {
636*4882a593Smuzhiyun dev_err(iodev->dev, "buck4 voltages not specified\n");
637*4882a593Smuzhiyun return -EINVAL;
638*4882a593Smuzhiyun }
639*4882a593Smuzhiyun }
640*4882a593Smuzhiyun
641*4882a593Smuzhiyun if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs ||
642*4882a593Smuzhiyun pdata->buck4_gpiodvs) {
643*4882a593Smuzhiyun ret = s5m8767_pmic_dt_parse_dvs_gpio(iodev, pdata, pmic_np);
644*4882a593Smuzhiyun if (ret)
645*4882a593Smuzhiyun return -EINVAL;
646*4882a593Smuzhiyun
647*4882a593Smuzhiyun if (of_property_read_u32(pmic_np,
648*4882a593Smuzhiyun "s5m8767,pmic-buck-default-dvs-idx",
649*4882a593Smuzhiyun &pdata->buck_default_idx)) {
650*4882a593Smuzhiyun pdata->buck_default_idx = 0;
651*4882a593Smuzhiyun } else {
652*4882a593Smuzhiyun if (pdata->buck_default_idx >= 8) {
653*4882a593Smuzhiyun pdata->buck_default_idx = 0;
654*4882a593Smuzhiyun dev_info(iodev->dev,
655*4882a593Smuzhiyun "invalid value for default dvs index, use 0\n");
656*4882a593Smuzhiyun }
657*4882a593Smuzhiyun }
658*4882a593Smuzhiyun }
659*4882a593Smuzhiyun
660*4882a593Smuzhiyun ret = s5m8767_pmic_dt_parse_ds_gpio(iodev, pdata, pmic_np);
661*4882a593Smuzhiyun if (ret)
662*4882a593Smuzhiyun return -EINVAL;
663*4882a593Smuzhiyun
664*4882a593Smuzhiyun if (of_get_property(pmic_np, "s5m8767,pmic-buck2-ramp-enable", NULL))
665*4882a593Smuzhiyun pdata->buck2_ramp_enable = true;
666*4882a593Smuzhiyun
667*4882a593Smuzhiyun if (of_get_property(pmic_np, "s5m8767,pmic-buck3-ramp-enable", NULL))
668*4882a593Smuzhiyun pdata->buck3_ramp_enable = true;
669*4882a593Smuzhiyun
670*4882a593Smuzhiyun if (of_get_property(pmic_np, "s5m8767,pmic-buck4-ramp-enable", NULL))
671*4882a593Smuzhiyun pdata->buck4_ramp_enable = true;
672*4882a593Smuzhiyun
673*4882a593Smuzhiyun if (pdata->buck2_ramp_enable || pdata->buck3_ramp_enable
674*4882a593Smuzhiyun || pdata->buck4_ramp_enable) {
675*4882a593Smuzhiyun if (of_property_read_u32(pmic_np, "s5m8767,pmic-buck-ramp-delay",
676*4882a593Smuzhiyun &pdata->buck_ramp_delay))
677*4882a593Smuzhiyun pdata->buck_ramp_delay = 0;
678*4882a593Smuzhiyun }
679*4882a593Smuzhiyun
680*4882a593Smuzhiyun return 0;
681*4882a593Smuzhiyun }
682*4882a593Smuzhiyun #else
s5m8767_pmic_dt_parse_pdata(struct platform_device * pdev,struct sec_platform_data * pdata)683*4882a593Smuzhiyun static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
684*4882a593Smuzhiyun struct sec_platform_data *pdata)
685*4882a593Smuzhiyun {
686*4882a593Smuzhiyun return 0;
687*4882a593Smuzhiyun }
688*4882a593Smuzhiyun #endif /* CONFIG_OF */
689*4882a593Smuzhiyun
s5m8767_pmic_probe(struct platform_device * pdev)690*4882a593Smuzhiyun static int s5m8767_pmic_probe(struct platform_device *pdev)
691*4882a593Smuzhiyun {
692*4882a593Smuzhiyun struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
693*4882a593Smuzhiyun struct sec_platform_data *pdata = iodev->pdata;
694*4882a593Smuzhiyun struct regulator_config config = { };
695*4882a593Smuzhiyun struct s5m8767_info *s5m8767;
696*4882a593Smuzhiyun int i, ret, buck_init;
697*4882a593Smuzhiyun
698*4882a593Smuzhiyun if (!pdata) {
699*4882a593Smuzhiyun dev_err(pdev->dev.parent, "Platform data not supplied\n");
700*4882a593Smuzhiyun return -ENODEV;
701*4882a593Smuzhiyun }
702*4882a593Smuzhiyun
703*4882a593Smuzhiyun if (iodev->dev->of_node) {
704*4882a593Smuzhiyun ret = s5m8767_pmic_dt_parse_pdata(pdev, pdata);
705*4882a593Smuzhiyun if (ret)
706*4882a593Smuzhiyun return ret;
707*4882a593Smuzhiyun }
708*4882a593Smuzhiyun
709*4882a593Smuzhiyun if (pdata->buck2_gpiodvs) {
710*4882a593Smuzhiyun if (pdata->buck3_gpiodvs || pdata->buck4_gpiodvs) {
711*4882a593Smuzhiyun dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n");
712*4882a593Smuzhiyun return -EINVAL;
713*4882a593Smuzhiyun }
714*4882a593Smuzhiyun }
715*4882a593Smuzhiyun
716*4882a593Smuzhiyun if (pdata->buck3_gpiodvs) {
717*4882a593Smuzhiyun if (pdata->buck2_gpiodvs || pdata->buck4_gpiodvs) {
718*4882a593Smuzhiyun dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n");
719*4882a593Smuzhiyun return -EINVAL;
720*4882a593Smuzhiyun }
721*4882a593Smuzhiyun }
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun if (pdata->buck4_gpiodvs) {
724*4882a593Smuzhiyun if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs) {
725*4882a593Smuzhiyun dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n");
726*4882a593Smuzhiyun return -EINVAL;
727*4882a593Smuzhiyun }
728*4882a593Smuzhiyun }
729*4882a593Smuzhiyun
730*4882a593Smuzhiyun s5m8767 = devm_kzalloc(&pdev->dev, sizeof(struct s5m8767_info),
731*4882a593Smuzhiyun GFP_KERNEL);
732*4882a593Smuzhiyun if (!s5m8767)
733*4882a593Smuzhiyun return -ENOMEM;
734*4882a593Smuzhiyun
735*4882a593Smuzhiyun s5m8767->dev = &pdev->dev;
736*4882a593Smuzhiyun s5m8767->iodev = iodev;
737*4882a593Smuzhiyun s5m8767->num_regulators = pdata->num_regulators;
738*4882a593Smuzhiyun platform_set_drvdata(pdev, s5m8767);
739*4882a593Smuzhiyun
740*4882a593Smuzhiyun s5m8767->buck_gpioindex = pdata->buck_default_idx;
741*4882a593Smuzhiyun s5m8767->buck2_gpiodvs = pdata->buck2_gpiodvs;
742*4882a593Smuzhiyun s5m8767->buck3_gpiodvs = pdata->buck3_gpiodvs;
743*4882a593Smuzhiyun s5m8767->buck4_gpiodvs = pdata->buck4_gpiodvs;
744*4882a593Smuzhiyun s5m8767->buck_gpios[0] = pdata->buck_gpios[0];
745*4882a593Smuzhiyun s5m8767->buck_gpios[1] = pdata->buck_gpios[1];
746*4882a593Smuzhiyun s5m8767->buck_gpios[2] = pdata->buck_gpios[2];
747*4882a593Smuzhiyun s5m8767->buck_ds[0] = pdata->buck_ds[0];
748*4882a593Smuzhiyun s5m8767->buck_ds[1] = pdata->buck_ds[1];
749*4882a593Smuzhiyun s5m8767->buck_ds[2] = pdata->buck_ds[2];
750*4882a593Smuzhiyun
751*4882a593Smuzhiyun s5m8767->ramp_delay = pdata->buck_ramp_delay;
752*4882a593Smuzhiyun s5m8767->buck2_ramp = pdata->buck2_ramp_enable;
753*4882a593Smuzhiyun s5m8767->buck3_ramp = pdata->buck3_ramp_enable;
754*4882a593Smuzhiyun s5m8767->buck4_ramp = pdata->buck4_ramp_enable;
755*4882a593Smuzhiyun s5m8767->opmode = pdata->opmode;
756*4882a593Smuzhiyun
757*4882a593Smuzhiyun buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
758*4882a593Smuzhiyun pdata->buck2_init);
759*4882a593Smuzhiyun
760*4882a593Smuzhiyun regmap_write(s5m8767->iodev->regmap_pmic, S5M8767_REG_BUCK2DVS2,
761*4882a593Smuzhiyun buck_init);
762*4882a593Smuzhiyun
763*4882a593Smuzhiyun buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
764*4882a593Smuzhiyun pdata->buck3_init);
765*4882a593Smuzhiyun
766*4882a593Smuzhiyun regmap_write(s5m8767->iodev->regmap_pmic, S5M8767_REG_BUCK3DVS2,
767*4882a593Smuzhiyun buck_init);
768*4882a593Smuzhiyun
769*4882a593Smuzhiyun buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
770*4882a593Smuzhiyun pdata->buck4_init);
771*4882a593Smuzhiyun
772*4882a593Smuzhiyun regmap_write(s5m8767->iodev->regmap_pmic, S5M8767_REG_BUCK4DVS2,
773*4882a593Smuzhiyun buck_init);
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun for (i = 0; i < 8; i++) {
776*4882a593Smuzhiyun if (s5m8767->buck2_gpiodvs) {
777*4882a593Smuzhiyun s5m8767->buck2_vol[i] =
778*4882a593Smuzhiyun s5m8767_convert_voltage_to_sel(
779*4882a593Smuzhiyun &buck_voltage_val2,
780*4882a593Smuzhiyun pdata->buck2_voltage[i]);
781*4882a593Smuzhiyun }
782*4882a593Smuzhiyun
783*4882a593Smuzhiyun if (s5m8767->buck3_gpiodvs) {
784*4882a593Smuzhiyun s5m8767->buck3_vol[i] =
785*4882a593Smuzhiyun s5m8767_convert_voltage_to_sel(
786*4882a593Smuzhiyun &buck_voltage_val2,
787*4882a593Smuzhiyun pdata->buck3_voltage[i]);
788*4882a593Smuzhiyun }
789*4882a593Smuzhiyun
790*4882a593Smuzhiyun if (s5m8767->buck4_gpiodvs) {
791*4882a593Smuzhiyun s5m8767->buck4_vol[i] =
792*4882a593Smuzhiyun s5m8767_convert_voltage_to_sel(
793*4882a593Smuzhiyun &buck_voltage_val2,
794*4882a593Smuzhiyun pdata->buck4_voltage[i]);
795*4882a593Smuzhiyun }
796*4882a593Smuzhiyun }
797*4882a593Smuzhiyun
798*4882a593Smuzhiyun if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs ||
799*4882a593Smuzhiyun pdata->buck4_gpiodvs) {
800*4882a593Smuzhiyun
801*4882a593Smuzhiyun if (!gpio_is_valid(pdata->buck_gpios[0]) ||
802*4882a593Smuzhiyun !gpio_is_valid(pdata->buck_gpios[1]) ||
803*4882a593Smuzhiyun !gpio_is_valid(pdata->buck_gpios[2])) {
804*4882a593Smuzhiyun dev_err(&pdev->dev, "GPIO NOT VALID\n");
805*4882a593Smuzhiyun return -EINVAL;
806*4882a593Smuzhiyun }
807*4882a593Smuzhiyun
808*4882a593Smuzhiyun ret = devm_gpio_request(&pdev->dev, pdata->buck_gpios[0],
809*4882a593Smuzhiyun "S5M8767 SET1");
810*4882a593Smuzhiyun if (ret)
811*4882a593Smuzhiyun return ret;
812*4882a593Smuzhiyun
813*4882a593Smuzhiyun ret = devm_gpio_request(&pdev->dev, pdata->buck_gpios[1],
814*4882a593Smuzhiyun "S5M8767 SET2");
815*4882a593Smuzhiyun if (ret)
816*4882a593Smuzhiyun return ret;
817*4882a593Smuzhiyun
818*4882a593Smuzhiyun ret = devm_gpio_request(&pdev->dev, pdata->buck_gpios[2],
819*4882a593Smuzhiyun "S5M8767 SET3");
820*4882a593Smuzhiyun if (ret)
821*4882a593Smuzhiyun return ret;
822*4882a593Smuzhiyun
823*4882a593Smuzhiyun /* SET1 GPIO */
824*4882a593Smuzhiyun gpio_direction_output(pdata->buck_gpios[0],
825*4882a593Smuzhiyun (s5m8767->buck_gpioindex >> 2) & 0x1);
826*4882a593Smuzhiyun /* SET2 GPIO */
827*4882a593Smuzhiyun gpio_direction_output(pdata->buck_gpios[1],
828*4882a593Smuzhiyun (s5m8767->buck_gpioindex >> 1) & 0x1);
829*4882a593Smuzhiyun /* SET3 GPIO */
830*4882a593Smuzhiyun gpio_direction_output(pdata->buck_gpios[2],
831*4882a593Smuzhiyun (s5m8767->buck_gpioindex >> 0) & 0x1);
832*4882a593Smuzhiyun }
833*4882a593Smuzhiyun
834*4882a593Smuzhiyun ret = devm_gpio_request(&pdev->dev, pdata->buck_ds[0], "S5M8767 DS2");
835*4882a593Smuzhiyun if (ret)
836*4882a593Smuzhiyun return ret;
837*4882a593Smuzhiyun
838*4882a593Smuzhiyun ret = devm_gpio_request(&pdev->dev, pdata->buck_ds[1], "S5M8767 DS3");
839*4882a593Smuzhiyun if (ret)
840*4882a593Smuzhiyun return ret;
841*4882a593Smuzhiyun
842*4882a593Smuzhiyun ret = devm_gpio_request(&pdev->dev, pdata->buck_ds[2], "S5M8767 DS4");
843*4882a593Smuzhiyun if (ret)
844*4882a593Smuzhiyun return ret;
845*4882a593Smuzhiyun
846*4882a593Smuzhiyun /* DS2 GPIO */
847*4882a593Smuzhiyun gpio_direction_output(pdata->buck_ds[0], 0x0);
848*4882a593Smuzhiyun /* DS3 GPIO */
849*4882a593Smuzhiyun gpio_direction_output(pdata->buck_ds[1], 0x0);
850*4882a593Smuzhiyun /* DS4 GPIO */
851*4882a593Smuzhiyun gpio_direction_output(pdata->buck_ds[2], 0x0);
852*4882a593Smuzhiyun
853*4882a593Smuzhiyun regmap_update_bits(s5m8767->iodev->regmap_pmic,
854*4882a593Smuzhiyun S5M8767_REG_BUCK2CTRL, 1 << 1,
855*4882a593Smuzhiyun (pdata->buck2_gpiodvs) ? (1 << 1) : (0 << 1));
856*4882a593Smuzhiyun regmap_update_bits(s5m8767->iodev->regmap_pmic,
857*4882a593Smuzhiyun S5M8767_REG_BUCK3CTRL, 1 << 1,
858*4882a593Smuzhiyun (pdata->buck3_gpiodvs) ? (1 << 1) : (0 << 1));
859*4882a593Smuzhiyun regmap_update_bits(s5m8767->iodev->regmap_pmic,
860*4882a593Smuzhiyun S5M8767_REG_BUCK4CTRL, 1 << 1,
861*4882a593Smuzhiyun (pdata->buck4_gpiodvs) ? (1 << 1) : (0 << 1));
862*4882a593Smuzhiyun
863*4882a593Smuzhiyun /* Initialize GPIO DVS registers */
864*4882a593Smuzhiyun for (i = 0; i < 8; i++) {
865*4882a593Smuzhiyun if (s5m8767->buck2_gpiodvs) {
866*4882a593Smuzhiyun regmap_write(s5m8767->iodev->regmap_pmic,
867*4882a593Smuzhiyun S5M8767_REG_BUCK2DVS1 + i,
868*4882a593Smuzhiyun s5m8767->buck2_vol[i]);
869*4882a593Smuzhiyun }
870*4882a593Smuzhiyun
871*4882a593Smuzhiyun if (s5m8767->buck3_gpiodvs) {
872*4882a593Smuzhiyun regmap_write(s5m8767->iodev->regmap_pmic,
873*4882a593Smuzhiyun S5M8767_REG_BUCK3DVS1 + i,
874*4882a593Smuzhiyun s5m8767->buck3_vol[i]);
875*4882a593Smuzhiyun }
876*4882a593Smuzhiyun
877*4882a593Smuzhiyun if (s5m8767->buck4_gpiodvs) {
878*4882a593Smuzhiyun regmap_write(s5m8767->iodev->regmap_pmic,
879*4882a593Smuzhiyun S5M8767_REG_BUCK4DVS1 + i,
880*4882a593Smuzhiyun s5m8767->buck4_vol[i]);
881*4882a593Smuzhiyun }
882*4882a593Smuzhiyun }
883*4882a593Smuzhiyun
884*4882a593Smuzhiyun if (s5m8767->buck2_ramp)
885*4882a593Smuzhiyun regmap_update_bits(s5m8767->iodev->regmap_pmic,
886*4882a593Smuzhiyun S5M8767_REG_DVSRAMP, 0x08, 0x08);
887*4882a593Smuzhiyun
888*4882a593Smuzhiyun if (s5m8767->buck3_ramp)
889*4882a593Smuzhiyun regmap_update_bits(s5m8767->iodev->regmap_pmic,
890*4882a593Smuzhiyun S5M8767_REG_DVSRAMP, 0x04, 0x04);
891*4882a593Smuzhiyun
892*4882a593Smuzhiyun if (s5m8767->buck4_ramp)
893*4882a593Smuzhiyun regmap_update_bits(s5m8767->iodev->regmap_pmic,
894*4882a593Smuzhiyun S5M8767_REG_DVSRAMP, 0x02, 0x02);
895*4882a593Smuzhiyun
896*4882a593Smuzhiyun if (s5m8767->buck2_ramp || s5m8767->buck3_ramp
897*4882a593Smuzhiyun || s5m8767->buck4_ramp) {
898*4882a593Smuzhiyun unsigned int val;
899*4882a593Smuzhiyun switch (s5m8767->ramp_delay) {
900*4882a593Smuzhiyun case 5:
901*4882a593Smuzhiyun val = S5M8767_DVS_BUCK_RAMP_5;
902*4882a593Smuzhiyun break;
903*4882a593Smuzhiyun case 10:
904*4882a593Smuzhiyun val = S5M8767_DVS_BUCK_RAMP_10;
905*4882a593Smuzhiyun break;
906*4882a593Smuzhiyun case 25:
907*4882a593Smuzhiyun val = S5M8767_DVS_BUCK_RAMP_25;
908*4882a593Smuzhiyun break;
909*4882a593Smuzhiyun case 50:
910*4882a593Smuzhiyun val = S5M8767_DVS_BUCK_RAMP_50;
911*4882a593Smuzhiyun break;
912*4882a593Smuzhiyun case 100:
913*4882a593Smuzhiyun val = S5M8767_DVS_BUCK_RAMP_100;
914*4882a593Smuzhiyun break;
915*4882a593Smuzhiyun default:
916*4882a593Smuzhiyun val = S5M8767_DVS_BUCK_RAMP_10;
917*4882a593Smuzhiyun }
918*4882a593Smuzhiyun regmap_update_bits(s5m8767->iodev->regmap_pmic,
919*4882a593Smuzhiyun S5M8767_REG_DVSRAMP,
920*4882a593Smuzhiyun S5M8767_DVS_BUCK_RAMP_MASK,
921*4882a593Smuzhiyun val << S5M8767_DVS_BUCK_RAMP_SHIFT);
922*4882a593Smuzhiyun }
923*4882a593Smuzhiyun
924*4882a593Smuzhiyun for (i = 0; i < pdata->num_regulators; i++) {
925*4882a593Smuzhiyun const struct sec_voltage_desc *desc;
926*4882a593Smuzhiyun int id = pdata->regulators[i].id;
927*4882a593Smuzhiyun int enable_reg, enable_val;
928*4882a593Smuzhiyun struct regulator_dev *rdev;
929*4882a593Smuzhiyun
930*4882a593Smuzhiyun desc = reg_voltage_map[id];
931*4882a593Smuzhiyun if (desc) {
932*4882a593Smuzhiyun regulators[id].n_voltages =
933*4882a593Smuzhiyun (desc->max - desc->min) / desc->step + 1;
934*4882a593Smuzhiyun regulators[id].min_uV = desc->min;
935*4882a593Smuzhiyun regulators[id].uV_step = desc->step;
936*4882a593Smuzhiyun regulators[id].vsel_reg =
937*4882a593Smuzhiyun s5m8767_get_vsel_reg(id, s5m8767);
938*4882a593Smuzhiyun if (id < S5M8767_BUCK1)
939*4882a593Smuzhiyun regulators[id].vsel_mask = 0x3f;
940*4882a593Smuzhiyun else
941*4882a593Smuzhiyun regulators[id].vsel_mask = 0xff;
942*4882a593Smuzhiyun
943*4882a593Smuzhiyun ret = s5m8767_get_register(s5m8767, id, &enable_reg,
944*4882a593Smuzhiyun &enable_val);
945*4882a593Smuzhiyun if (ret) {
946*4882a593Smuzhiyun dev_err(s5m8767->dev, "error reading registers\n");
947*4882a593Smuzhiyun return ret;
948*4882a593Smuzhiyun }
949*4882a593Smuzhiyun regulators[id].enable_reg = enable_reg;
950*4882a593Smuzhiyun regulators[id].enable_mask = S5M8767_ENCTRL_MASK;
951*4882a593Smuzhiyun regulators[id].enable_val = enable_val;
952*4882a593Smuzhiyun }
953*4882a593Smuzhiyun
954*4882a593Smuzhiyun config.dev = s5m8767->dev;
955*4882a593Smuzhiyun config.init_data = pdata->regulators[i].initdata;
956*4882a593Smuzhiyun config.driver_data = s5m8767;
957*4882a593Smuzhiyun config.regmap = iodev->regmap_pmic;
958*4882a593Smuzhiyun config.of_node = pdata->regulators[i].reg_node;
959*4882a593Smuzhiyun config.ena_gpiod = NULL;
960*4882a593Smuzhiyun if (pdata->regulators[i].ext_control_gpiod) {
961*4882a593Smuzhiyun /* Assigns config.ena_gpiod */
962*4882a593Smuzhiyun s5m8767_regulator_config_ext_control(s5m8767,
963*4882a593Smuzhiyun &pdata->regulators[i], &config);
964*4882a593Smuzhiyun
965*4882a593Smuzhiyun /*
966*4882a593Smuzhiyun * Hand the GPIO descriptor management over to the
967*4882a593Smuzhiyun * regulator core, remove it from devres management.
968*4882a593Smuzhiyun */
969*4882a593Smuzhiyun devm_gpiod_unhinge(s5m8767->dev, config.ena_gpiod);
970*4882a593Smuzhiyun }
971*4882a593Smuzhiyun rdev = devm_regulator_register(&pdev->dev, ®ulators[id],
972*4882a593Smuzhiyun &config);
973*4882a593Smuzhiyun if (IS_ERR(rdev)) {
974*4882a593Smuzhiyun ret = PTR_ERR(rdev);
975*4882a593Smuzhiyun dev_err(s5m8767->dev, "regulator init failed for %d\n",
976*4882a593Smuzhiyun id);
977*4882a593Smuzhiyun return ret;
978*4882a593Smuzhiyun }
979*4882a593Smuzhiyun
980*4882a593Smuzhiyun if (pdata->regulators[i].ext_control_gpiod) {
981*4882a593Smuzhiyun ret = s5m8767_enable_ext_control(s5m8767, rdev);
982*4882a593Smuzhiyun if (ret < 0) {
983*4882a593Smuzhiyun dev_err(s5m8767->dev,
984*4882a593Smuzhiyun "failed to enable gpio control over %s: %d\n",
985*4882a593Smuzhiyun rdev->desc->name, ret);
986*4882a593Smuzhiyun return ret;
987*4882a593Smuzhiyun }
988*4882a593Smuzhiyun }
989*4882a593Smuzhiyun }
990*4882a593Smuzhiyun
991*4882a593Smuzhiyun return 0;
992*4882a593Smuzhiyun }
993*4882a593Smuzhiyun
994*4882a593Smuzhiyun static const struct platform_device_id s5m8767_pmic_id[] = {
995*4882a593Smuzhiyun { "s5m8767-pmic", 0},
996*4882a593Smuzhiyun { },
997*4882a593Smuzhiyun };
998*4882a593Smuzhiyun MODULE_DEVICE_TABLE(platform, s5m8767_pmic_id);
999*4882a593Smuzhiyun
1000*4882a593Smuzhiyun static struct platform_driver s5m8767_pmic_driver = {
1001*4882a593Smuzhiyun .driver = {
1002*4882a593Smuzhiyun .name = "s5m8767-pmic",
1003*4882a593Smuzhiyun },
1004*4882a593Smuzhiyun .probe = s5m8767_pmic_probe,
1005*4882a593Smuzhiyun .id_table = s5m8767_pmic_id,
1006*4882a593Smuzhiyun };
1007*4882a593Smuzhiyun module_platform_driver(s5m8767_pmic_driver);
1008*4882a593Smuzhiyun
1009*4882a593Smuzhiyun /* Module information */
1010*4882a593Smuzhiyun MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
1011*4882a593Smuzhiyun MODULE_DESCRIPTION("Samsung S5M8767 Regulator Driver");
1012*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1013