blob: 533bde68e4b70616d17155838afd18371c143fb1 [file] [log] [blame]
Sangbeom Kim9767ec72012-01-09 19:10:25 +09001/*
2 * s5m8767.c
3 *
4 * Copyright (c) 2011 Samsung Electronics Co., Ltd
5 * http://www.samsung.com
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 *
12 */
13
14#include <linux/bug.h>
Sangbeom Kim9767ec72012-01-09 19:10:25 +090015#include <linux/err.h>
16#include <linux/gpio.h>
17#include <linux/slab.h>
18#include <linux/module.h>
19#include <linux/platform_device.h>
20#include <linux/regulator/driver.h>
21#include <linux/regulator/machine.h>
22#include <linux/mfd/s5m87xx/s5m-core.h>
23#include <linux/mfd/s5m87xx/s5m-pmic.h>
24
25struct s5m8767_info {
26 struct device *dev;
27 struct s5m87xx_dev *iodev;
28 int num_regulators;
29 struct regulator_dev **rdev;
Sangbeom Kim7e44bb82012-03-09 17:55:34 +090030 struct s5m_opmode_data *opmode;
Sangbeom Kim9767ec72012-01-09 19:10:25 +090031
32 int ramp_delay;
33 bool buck2_ramp;
34 bool buck3_ramp;
35 bool buck4_ramp;
36
37 bool buck2_gpiodvs;
38 bool buck3_gpiodvs;
39 bool buck4_gpiodvs;
40 u8 buck2_vol[8];
41 u8 buck3_vol[8];
42 u8 buck4_vol[8];
43 int buck_gpios[3];
Sangbeom Kimc848bc82012-06-18 09:49:20 +090044 int buck_ds[3];
Sangbeom Kim9767ec72012-01-09 19:10:25 +090045 int buck_gpioindex;
46};
47
48struct s5m_voltage_desc {
49 int max;
50 int min;
51 int step;
52};
53
54static const struct s5m_voltage_desc buck_voltage_val1 = {
55 .max = 2225000,
56 .min = 650000,
57 .step = 6250,
58};
59
60static const struct s5m_voltage_desc buck_voltage_val2 = {
61 .max = 1600000,
62 .min = 600000,
63 .step = 6250,
64};
65
66static const struct s5m_voltage_desc buck_voltage_val3 = {
67 .max = 3000000,
68 .min = 750000,
69 .step = 12500,
70};
71
72static const struct s5m_voltage_desc ldo_voltage_val1 = {
73 .max = 3950000,
74 .min = 800000,
75 .step = 50000,
76};
77
78static const struct s5m_voltage_desc ldo_voltage_val2 = {
79 .max = 2375000,
80 .min = 800000,
81 .step = 25000,
82};
83
84static const struct s5m_voltage_desc *reg_voltage_map[] = {
85 [S5M8767_LDO1] = &ldo_voltage_val2,
86 [S5M8767_LDO2] = &ldo_voltage_val2,
87 [S5M8767_LDO3] = &ldo_voltage_val1,
88 [S5M8767_LDO4] = &ldo_voltage_val1,
89 [S5M8767_LDO5] = &ldo_voltage_val1,
90 [S5M8767_LDO6] = &ldo_voltage_val2,
91 [S5M8767_LDO7] = &ldo_voltage_val2,
92 [S5M8767_LDO8] = &ldo_voltage_val2,
93 [S5M8767_LDO9] = &ldo_voltage_val1,
94 [S5M8767_LDO10] = &ldo_voltage_val1,
95 [S5M8767_LDO11] = &ldo_voltage_val1,
96 [S5M8767_LDO12] = &ldo_voltage_val1,
97 [S5M8767_LDO13] = &ldo_voltage_val1,
98 [S5M8767_LDO14] = &ldo_voltage_val1,
99 [S5M8767_LDO15] = &ldo_voltage_val2,
100 [S5M8767_LDO16] = &ldo_voltage_val1,
101 [S5M8767_LDO17] = &ldo_voltage_val1,
102 [S5M8767_LDO18] = &ldo_voltage_val1,
103 [S5M8767_LDO19] = &ldo_voltage_val1,
104 [S5M8767_LDO20] = &ldo_voltage_val1,
105 [S5M8767_LDO21] = &ldo_voltage_val1,
106 [S5M8767_LDO22] = &ldo_voltage_val1,
107 [S5M8767_LDO23] = &ldo_voltage_val1,
108 [S5M8767_LDO24] = &ldo_voltage_val1,
109 [S5M8767_LDO25] = &ldo_voltage_val1,
110 [S5M8767_LDO26] = &ldo_voltage_val1,
111 [S5M8767_LDO27] = &ldo_voltage_val1,
112 [S5M8767_LDO28] = &ldo_voltage_val1,
113 [S5M8767_BUCK1] = &buck_voltage_val1,
114 [S5M8767_BUCK2] = &buck_voltage_val2,
115 [S5M8767_BUCK3] = &buck_voltage_val2,
116 [S5M8767_BUCK4] = &buck_voltage_val2,
117 [S5M8767_BUCK5] = &buck_voltage_val1,
118 [S5M8767_BUCK6] = &buck_voltage_val1,
119 [S5M8767_BUCK7] = NULL,
120 [S5M8767_BUCK8] = NULL,
121 [S5M8767_BUCK9] = &buck_voltage_val3,
122};
123
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900124static int s5m8767_list_voltage(struct regulator_dev *rdev,
125 unsigned int selector)
126{
127 const struct s5m_voltage_desc *desc;
Axel Lin20a14b82012-01-31 15:13:31 +0800128 int reg_id = rdev_get_id(rdev);
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900129 int val;
130
131 if (reg_id >= ARRAY_SIZE(reg_voltage_map) || reg_id < 0)
132 return -EINVAL;
133
134 desc = reg_voltage_map[reg_id];
135 if (desc == NULL)
136 return -EINVAL;
137
138 val = desc->min + desc->step * selector;
139 if (val > desc->max)
140 return -EINVAL;
141
142 return val;
143}
144
Mark Brown5ceba7b2012-05-09 20:37:51 +0100145static unsigned int s5m8767_opmode_reg[][4] = {
Sangbeom Kim7e44bb82012-03-09 17:55:34 +0900146 /* {OFF, ON, LOWPOWER, SUSPEND} */
147 /* LDO1 ... LDO28 */
148 {0x0, 0x3, 0x2, 0x1}, /* LDO1 */
149 {0x0, 0x3, 0x2, 0x1},
150 {0x0, 0x3, 0x2, 0x1},
151 {0x0, 0x0, 0x0, 0x0},
152 {0x0, 0x3, 0x2, 0x1}, /* LDO5 */
153 {0x0, 0x3, 0x2, 0x1},
154 {0x0, 0x3, 0x2, 0x1},
155 {0x0, 0x3, 0x2, 0x1},
156 {0x0, 0x3, 0x2, 0x1},
157 {0x0, 0x3, 0x2, 0x1}, /* LDO10 */
158 {0x0, 0x3, 0x2, 0x1},
159 {0x0, 0x3, 0x2, 0x1},
160 {0x0, 0x3, 0x2, 0x1},
161 {0x0, 0x3, 0x2, 0x1},
162 {0x0, 0x3, 0x2, 0x1}, /* LDO15 */
163 {0x0, 0x3, 0x2, 0x1},
164 {0x0, 0x3, 0x2, 0x1},
165 {0x0, 0x0, 0x0, 0x0},
166 {0x0, 0x3, 0x2, 0x1},
167 {0x0, 0x3, 0x2, 0x1}, /* LDO20 */
168 {0x0, 0x3, 0x2, 0x1},
169 {0x0, 0x3, 0x2, 0x1},
170 {0x0, 0x0, 0x0, 0x0},
171 {0x0, 0x3, 0x2, 0x1},
172 {0x0, 0x3, 0x2, 0x1}, /* LDO25 */
173 {0x0, 0x3, 0x2, 0x1},
174 {0x0, 0x3, 0x2, 0x1},
175 {0x0, 0x3, 0x2, 0x1}, /* LDO28 */
176
177 /* BUCK1 ... BUCK9 */
178 {0x0, 0x3, 0x1, 0x1}, /* BUCK1 */
179 {0x0, 0x3, 0x1, 0x1},
180 {0x0, 0x3, 0x1, 0x1},
181 {0x0, 0x3, 0x1, 0x1},
182 {0x0, 0x3, 0x2, 0x1}, /* BUCK5 */
183 {0x0, 0x3, 0x1, 0x1},
184 {0x0, 0x3, 0x1, 0x1},
185 {0x0, 0x3, 0x1, 0x1},
186 {0x0, 0x3, 0x1, 0x1}, /* BUCK9 */
187};
188
189static int s5m8767_get_register(struct regulator_dev *rdev, int *reg,
190 int *enable_ctrl)
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900191{
Axel Lin20a14b82012-01-31 15:13:31 +0800192 int reg_id = rdev_get_id(rdev);
Sangbeom Kim7e44bb82012-03-09 17:55:34 +0900193 unsigned int mode;
194 struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900195
196 switch (reg_id) {
197 case S5M8767_LDO1 ... S5M8767_LDO2:
198 *reg = S5M8767_REG_LDO1CTRL + (reg_id - S5M8767_LDO1);
199 break;
200 case S5M8767_LDO3 ... S5M8767_LDO28:
201 *reg = S5M8767_REG_LDO3CTRL + (reg_id - S5M8767_LDO3);
202 break;
203 case S5M8767_BUCK1:
204 *reg = S5M8767_REG_BUCK1CTRL1;
205 break;
206 case S5M8767_BUCK2 ... S5M8767_BUCK4:
207 *reg = S5M8767_REG_BUCK2CTRL + (reg_id - S5M8767_BUCK2) * 9;
208 break;
209 case S5M8767_BUCK5:
210 *reg = S5M8767_REG_BUCK5CTRL1;
211 break;
212 case S5M8767_BUCK6 ... S5M8767_BUCK9:
213 *reg = S5M8767_REG_BUCK6CTRL1 + (reg_id - S5M8767_BUCK6) * 2;
214 break;
215 default:
216 return -EINVAL;
217 }
218
Sangbeom Kim7e44bb82012-03-09 17:55:34 +0900219 mode = s5m8767->opmode[reg_id].mode;
220 *enable_ctrl = s5m8767_opmode_reg[reg_id][mode] << S5M8767_ENCTRL_SHIFT;
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900221 return 0;
222}
223
224static int s5m8767_reg_is_enabled(struct regulator_dev *rdev)
225{
226 struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
227 int ret, reg;
Sangbeom Kim7e44bb82012-03-09 17:55:34 +0900228 int mask = 0xc0, enable_ctrl;
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900229 u8 val;
230
Sangbeom Kim7e44bb82012-03-09 17:55:34 +0900231 ret = s5m8767_get_register(rdev, &reg, &enable_ctrl);
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900232 if (ret == -EINVAL)
233 return 1;
234 else if (ret)
235 return ret;
236
237 ret = s5m_reg_read(s5m8767->iodev, reg, &val);
238 if (ret)
239 return ret;
240
Sangbeom Kim7e44bb82012-03-09 17:55:34 +0900241 return (val & mask) == enable_ctrl;
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900242}
243
244static int s5m8767_reg_enable(struct regulator_dev *rdev)
245{
246 struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
247 int ret, reg;
Sangbeom Kim7e44bb82012-03-09 17:55:34 +0900248 int mask = 0xc0, enable_ctrl;
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900249
Sangbeom Kim7e44bb82012-03-09 17:55:34 +0900250 ret = s5m8767_get_register(rdev, &reg, &enable_ctrl);
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900251 if (ret)
252 return ret;
253
Sangbeom Kim7e44bb82012-03-09 17:55:34 +0900254 return s5m_reg_update(s5m8767->iodev, reg, enable_ctrl, mask);
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900255}
256
257static int s5m8767_reg_disable(struct regulator_dev *rdev)
258{
259 struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
260 int ret, reg;
Sangbeom Kim7e44bb82012-03-09 17:55:34 +0900261 int mask = 0xc0, enable_ctrl;
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900262
Sangbeom Kim7e44bb82012-03-09 17:55:34 +0900263 ret = s5m8767_get_register(rdev, &reg, &enable_ctrl);
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900264 if (ret)
265 return ret;
266
Sangbeom Kim7e44bb82012-03-09 17:55:34 +0900267 return s5m_reg_update(s5m8767->iodev, reg, ~mask, mask);
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900268}
269
270static int s5m8767_get_voltage_register(struct regulator_dev *rdev, int *_reg)
271{
Axel Lin0a416852012-03-10 10:59:43 +0800272 struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
Axel Lin20a14b82012-01-31 15:13:31 +0800273 int reg_id = rdev_get_id(rdev);
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900274 int reg;
275
276 switch (reg_id) {
277 case S5M8767_LDO1 ... S5M8767_LDO2:
278 reg = S5M8767_REG_LDO1CTRL + (reg_id - S5M8767_LDO1);
279 break;
280 case S5M8767_LDO3 ... S5M8767_LDO28:
281 reg = S5M8767_REG_LDO3CTRL + (reg_id - S5M8767_LDO3);
282 break;
283 case S5M8767_BUCK1:
284 reg = S5M8767_REG_BUCK1CTRL2;
285 break;
286 case S5M8767_BUCK2:
Sangbeom Kimc848bc82012-06-18 09:49:20 +0900287 reg = S5M8767_REG_BUCK2DVS2;
Axel Lin0a416852012-03-10 10:59:43 +0800288 if (s5m8767->buck2_gpiodvs)
289 reg += s5m8767->buck_gpioindex;
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900290 break;
291 case S5M8767_BUCK3:
Sangbeom Kimc848bc82012-06-18 09:49:20 +0900292 reg = S5M8767_REG_BUCK3DVS2;
Axel Lin0a416852012-03-10 10:59:43 +0800293 if (s5m8767->buck3_gpiodvs)
294 reg += s5m8767->buck_gpioindex;
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900295 break;
296 case S5M8767_BUCK4:
Sangbeom Kimc848bc82012-06-18 09:49:20 +0900297 reg = S5M8767_REG_BUCK4DVS2;
Axel Lin0a416852012-03-10 10:59:43 +0800298 if (s5m8767->buck4_gpiodvs)
299 reg += s5m8767->buck_gpioindex;
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900300 break;
301 case S5M8767_BUCK5:
302 reg = S5M8767_REG_BUCK5CTRL2;
303 break;
304 case S5M8767_BUCK6 ... S5M8767_BUCK9:
305 reg = S5M8767_REG_BUCK6CTRL2 + (reg_id - S5M8767_BUCK6) * 2;
306 break;
307 default:
308 return -EINVAL;
309 }
310
311 *_reg = reg;
312
313 return 0;
314}
315
316static int s5m8767_get_voltage_sel(struct regulator_dev *rdev)
317{
318 struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
Axel Lin0a416852012-03-10 10:59:43 +0800319 int reg, mask, ret;
Axel Lin20a14b82012-01-31 15:13:31 +0800320 int reg_id = rdev_get_id(rdev);
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900321 u8 val;
322
323 ret = s5m8767_get_voltage_register(rdev, &reg);
324 if (ret)
325 return ret;
326
Axel Lin0a416852012-03-10 10:59:43 +0800327 mask = (reg_id < S5M8767_BUCK1) ? 0x3f : 0xff;
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900328
329 ret = s5m_reg_read(s5m8767->iodev, reg, &val);
330 if (ret)
331 return ret;
332
333 val &= mask;
334
335 return val;
336}
337
Axel Lin5b5e9772012-03-09 11:31:08 +0800338static int s5m8767_convert_voltage_to_sel(
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900339 const struct s5m_voltage_desc *desc,
340 int min_vol, int max_vol)
341{
Axel Lin5b5e9772012-03-09 11:31:08 +0800342 int selector = 0;
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900343
344 if (desc == NULL)
345 return -EINVAL;
346
347 if (max_vol < desc->min || min_vol > desc->max)
348 return -EINVAL;
349
Axel Lin94e85a32012-04-13 09:30:05 +0800350 if (min_vol < desc->min)
351 min_vol = desc->min;
352
353 selector = DIV_ROUND_UP(min_vol - desc->min, desc->step);
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900354
Axel Lin5b5e9772012-03-09 11:31:08 +0800355 if (desc->min + desc->step * selector > max_vol)
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900356 return -EINVAL;
357
Axel Lin5b5e9772012-03-09 11:31:08 +0800358 return selector;
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900359}
360
Sangbeom Kimdf2643c2012-06-13 17:28:18 +0900361static inline int s5m8767_set_high(struct s5m8767_info *s5m8767)
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900362{
363 int temp_index = s5m8767->buck_gpioindex;
364
365 gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1);
366 gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1);
367 gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1);
Sangbeom Kimdf2643c2012-06-13 17:28:18 +0900368
369 return 0;
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900370}
371
Sangbeom Kimdf2643c2012-06-13 17:28:18 +0900372static inline int s5m8767_set_low(struct s5m8767_info *s5m8767)
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900373{
374 int temp_index = s5m8767->buck_gpioindex;
375
376 gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1);
377 gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1);
378 gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1);
Sangbeom Kimdf2643c2012-06-13 17:28:18 +0900379
380 return 0;
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900381}
382
Sangbeom Kimdf2643c2012-06-13 17:28:18 +0900383static int s5m8767_set_voltage_sel(struct regulator_dev *rdev,
384 unsigned selector)
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900385{
386 struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
Axel Lin321d2ab2012-04-10 14:05:44 +0800387 int reg_id = rdev_get_id(rdev);
Sangbeom Kimdf2643c2012-06-13 17:28:18 +0900388 int reg, mask, ret = 0, old_index, index = 0;
Axel Lin321d2ab2012-04-10 14:05:44 +0800389 u8 *buck234_vol = NULL;
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900390
391 switch (reg_id) {
Axel Lin321d2ab2012-04-10 14:05:44 +0800392 case S5M8767_LDO1 ... S5M8767_LDO28:
393 mask = 0x3f;
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900394 break;
Axel Lin321d2ab2012-04-10 14:05:44 +0800395 case S5M8767_BUCK1 ... S5M8767_BUCK6:
396 mask = 0xff;
397 if (reg_id == S5M8767_BUCK2 && s5m8767->buck2_gpiodvs)
398 buck234_vol = &s5m8767->buck2_vol[0];
399 else if (reg_id == S5M8767_BUCK3 && s5m8767->buck3_gpiodvs)
400 buck234_vol = &s5m8767->buck3_vol[0];
401 else if (reg_id == S5M8767_BUCK4 && s5m8767->buck4_gpiodvs)
402 buck234_vol = &s5m8767->buck4_vol[0];
403 break;
404 case S5M8767_BUCK7 ... S5M8767_BUCK8:
405 return -EINVAL;
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900406 case S5M8767_BUCK9:
Axel Lin321d2ab2012-04-10 14:05:44 +0800407 mask = 0xff;
408 break;
409 default:
410 return -EINVAL;
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900411 }
412
Axel Lin321d2ab2012-04-10 14:05:44 +0800413 /* buck234_vol != NULL means to control buck234 voltage via DVS GPIO */
414 if (buck234_vol) {
Sangbeom Kimdf2643c2012-06-13 17:28:18 +0900415 while (*buck234_vol != selector) {
Axel Lin321d2ab2012-04-10 14:05:44 +0800416 buck234_vol++;
417 index++;
418 }
419 old_index = s5m8767->buck_gpioindex;
420 s5m8767->buck_gpioindex = index;
421
422 if (index > old_index)
Sangbeom Kimdf2643c2012-06-13 17:28:18 +0900423 return s5m8767_set_high(s5m8767);
Axel Lin321d2ab2012-04-10 14:05:44 +0800424 else
Sangbeom Kimdf2643c2012-06-13 17:28:18 +0900425 return s5m8767_set_low(s5m8767);
Axel Lin321d2ab2012-04-10 14:05:44 +0800426 } else {
427 ret = s5m8767_get_voltage_register(rdev, &reg);
428 if (ret)
429 return ret;
430
Sangbeom Kimdf2643c2012-06-13 17:28:18 +0900431 return s5m_reg_update(s5m8767->iodev, reg, selector, mask);
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900432 }
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900433}
434
435static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev,
436 unsigned int old_sel,
437 unsigned int new_sel)
438{
439 struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
440 const struct s5m_voltage_desc *desc;
Axel Lin20a14b82012-01-31 15:13:31 +0800441 int reg_id = rdev_get_id(rdev);
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900442
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900443 desc = reg_voltage_map[reg_id];
444
Sangbeom Kim9d88fc02012-06-13 17:27:16 +0900445 if ((old_sel < new_sel) && s5m8767->ramp_delay)
Axel Lin89e0f0e2012-02-24 14:52:45 +0800446 return DIV_ROUND_UP(desc->step * (new_sel - old_sel),
Sangbeom Kim0f8b9c72012-03-09 16:28:10 +0900447 s5m8767->ramp_delay * 1000);
Axel Lin89e0f0e2012-02-24 14:52:45 +0800448 return 0;
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900449}
450
Axel Lind35aad02012-04-10 14:07:15 +0800451static struct regulator_ops s5m8767_ops = {
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900452 .list_voltage = s5m8767_list_voltage,
453 .is_enabled = s5m8767_reg_is_enabled,
454 .enable = s5m8767_reg_enable,
455 .disable = s5m8767_reg_disable,
456 .get_voltage_sel = s5m8767_get_voltage_sel,
Sangbeom Kimdf2643c2012-06-13 17:28:18 +0900457 .set_voltage_sel = s5m8767_set_voltage_sel,
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900458 .set_voltage_time_sel = s5m8767_set_voltage_time_sel,
459};
460
Axel Lin65896e72012-04-10 14:08:19 +0800461#define s5m8767_regulator_desc(_name) { \
462 .name = #_name, \
463 .id = S5M8767_##_name, \
464 .ops = &s5m8767_ops, \
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900465 .type = REGULATOR_VOLTAGE, \
466 .owner = THIS_MODULE, \
467}
468
469static struct regulator_desc regulators[] = {
Axel Lin65896e72012-04-10 14:08:19 +0800470 s5m8767_regulator_desc(LDO1),
471 s5m8767_regulator_desc(LDO2),
472 s5m8767_regulator_desc(LDO3),
473 s5m8767_regulator_desc(LDO4),
474 s5m8767_regulator_desc(LDO5),
475 s5m8767_regulator_desc(LDO6),
476 s5m8767_regulator_desc(LDO7),
477 s5m8767_regulator_desc(LDO8),
478 s5m8767_regulator_desc(LDO9),
479 s5m8767_regulator_desc(LDO10),
480 s5m8767_regulator_desc(LDO11),
481 s5m8767_regulator_desc(LDO12),
482 s5m8767_regulator_desc(LDO13),
483 s5m8767_regulator_desc(LDO14),
484 s5m8767_regulator_desc(LDO15),
485 s5m8767_regulator_desc(LDO16),
486 s5m8767_regulator_desc(LDO17),
487 s5m8767_regulator_desc(LDO18),
488 s5m8767_regulator_desc(LDO19),
489 s5m8767_regulator_desc(LDO20),
490 s5m8767_regulator_desc(LDO21),
491 s5m8767_regulator_desc(LDO22),
492 s5m8767_regulator_desc(LDO23),
493 s5m8767_regulator_desc(LDO24),
494 s5m8767_regulator_desc(LDO25),
495 s5m8767_regulator_desc(LDO26),
496 s5m8767_regulator_desc(LDO27),
497 s5m8767_regulator_desc(LDO28),
498 s5m8767_regulator_desc(BUCK1),
499 s5m8767_regulator_desc(BUCK2),
500 s5m8767_regulator_desc(BUCK3),
501 s5m8767_regulator_desc(BUCK4),
502 s5m8767_regulator_desc(BUCK5),
503 s5m8767_regulator_desc(BUCK6),
504 s5m8767_regulator_desc(BUCK7),
505 s5m8767_regulator_desc(BUCK8),
506 s5m8767_regulator_desc(BUCK9),
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900507};
508
509static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
510{
511 struct s5m87xx_dev *iodev = dev_get_drvdata(pdev->dev.parent);
512 struct s5m_platform_data *pdata = dev_get_platdata(iodev->dev);
Mark Brownc1727082012-04-04 00:50:22 +0100513 struct regulator_config config = { };
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900514 struct regulator_dev **rdev;
515 struct s5m8767_info *s5m8767;
Sangbeom Kimc848bc82012-06-18 09:49:20 +0900516 int i, ret, size, buck_init;
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900517
518 if (!pdata) {
519 dev_err(pdev->dev.parent, "Platform data not supplied\n");
520 return -ENODEV;
521 }
522
Axel Lin6c4efe22012-03-10 08:43:02 +0800523 if (pdata->buck2_gpiodvs) {
524 if (pdata->buck3_gpiodvs || pdata->buck4_gpiodvs) {
525 dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n");
526 return -EINVAL;
527 }
528 }
529
530 if (pdata->buck3_gpiodvs) {
531 if (pdata->buck2_gpiodvs || pdata->buck4_gpiodvs) {
532 dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n");
533 return -EINVAL;
534 }
535 }
536
537 if (pdata->buck4_gpiodvs) {
538 if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs) {
539 dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n");
540 return -EINVAL;
541 }
542 }
543
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900544 s5m8767 = devm_kzalloc(&pdev->dev, sizeof(struct s5m8767_info),
545 GFP_KERNEL);
546 if (!s5m8767)
547 return -ENOMEM;
548
549 size = sizeof(struct regulator_dev *) * (S5M8767_REG_MAX - 2);
550 s5m8767->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
551 if (!s5m8767->rdev)
552 return -ENOMEM;
553
554 rdev = s5m8767->rdev;
555 s5m8767->dev = &pdev->dev;
556 s5m8767->iodev = iodev;
557 s5m8767->num_regulators = S5M8767_REG_MAX - 2;
558 platform_set_drvdata(pdev, s5m8767);
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900559
560 s5m8767->buck_gpioindex = pdata->buck_default_idx;
561 s5m8767->buck2_gpiodvs = pdata->buck2_gpiodvs;
562 s5m8767->buck3_gpiodvs = pdata->buck3_gpiodvs;
563 s5m8767->buck4_gpiodvs = pdata->buck4_gpiodvs;
564 s5m8767->buck_gpios[0] = pdata->buck_gpios[0];
565 s5m8767->buck_gpios[1] = pdata->buck_gpios[1];
566 s5m8767->buck_gpios[2] = pdata->buck_gpios[2];
Sangbeom Kimc848bc82012-06-18 09:49:20 +0900567 s5m8767->buck_ds[0] = pdata->buck_ds[0];
568 s5m8767->buck_ds[1] = pdata->buck_ds[1];
569 s5m8767->buck_ds[2] = pdata->buck_ds[2];
570
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900571 s5m8767->ramp_delay = pdata->buck_ramp_delay;
572 s5m8767->buck2_ramp = pdata->buck2_ramp_enable;
573 s5m8767->buck3_ramp = pdata->buck3_ramp_enable;
574 s5m8767->buck4_ramp = pdata->buck4_ramp_enable;
Sangbeom Kim7e44bb82012-03-09 17:55:34 +0900575 s5m8767->opmode = pdata->opmode;
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900576
Sangbeom Kimc848bc82012-06-18 09:49:20 +0900577 buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
578 pdata->buck2_init,
579 pdata->buck2_init +
580 buck_voltage_val2.step);
581
582 s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS2, buck_init);
583
584 buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
585 pdata->buck3_init,
586 pdata->buck3_init +
587 buck_voltage_val2.step);
588
589 s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS2, buck_init);
590
591 buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
592 pdata->buck4_init,
593 pdata->buck4_init +
594 buck_voltage_val2.step);
595
596 s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS2, buck_init);
597
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900598 for (i = 0; i < 8; i++) {
599 if (s5m8767->buck2_gpiodvs) {
600 s5m8767->buck2_vol[i] =
Axel Lin5b5e9772012-03-09 11:31:08 +0800601 s5m8767_convert_voltage_to_sel(
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900602 &buck_voltage_val2,
603 pdata->buck2_voltage[i],
604 pdata->buck2_voltage[i] +
605 buck_voltage_val2.step);
606 }
607
608 if (s5m8767->buck3_gpiodvs) {
609 s5m8767->buck3_vol[i] =
Axel Lin5b5e9772012-03-09 11:31:08 +0800610 s5m8767_convert_voltage_to_sel(
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900611 &buck_voltage_val2,
612 pdata->buck3_voltage[i],
613 pdata->buck3_voltage[i] +
614 buck_voltage_val2.step);
615 }
616
617 if (s5m8767->buck4_gpiodvs) {
618 s5m8767->buck4_vol[i] =
Axel Lin5b5e9772012-03-09 11:31:08 +0800619 s5m8767_convert_voltage_to_sel(
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900620 &buck_voltage_val2,
621 pdata->buck4_voltage[i],
622 pdata->buck4_voltage[i] +
623 buck_voltage_val2.step);
624 }
625 }
626
Sangbeom Kimc848bc82012-06-18 09:49:20 +0900627 if (gpio_is_valid(pdata->buck_gpios[0]) &&
628 gpio_is_valid(pdata->buck_gpios[1]) &&
629 gpio_is_valid(pdata->buck_gpios[2])) {
630 ret = gpio_request(pdata->buck_gpios[0], "S5M8767 SET1");
631 if (ret == -EBUSY)
632 dev_warn(&pdev->dev, "Duplicated gpio request"
633 " for SET1\n");
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900634
Sangbeom Kimc848bc82012-06-18 09:49:20 +0900635 ret = gpio_request(pdata->buck_gpios[1], "S5M8767 SET2");
636 if (ret == -EBUSY)
637 dev_warn(&pdev->dev, "Duplicated gpio request"
638 " for SET2\n");
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900639
Sangbeom Kimc848bc82012-06-18 09:49:20 +0900640 ret = gpio_request(pdata->buck_gpios[2], "S5M8767 SET3");
641 if (ret == -EBUSY)
642 dev_warn(&pdev->dev, "Duplicated gpio request"
643 " for SET3\n");
644 /* SET1 GPIO */
645 gpio_direction_output(pdata->buck_gpios[0],
646 (s5m8767->buck_gpioindex >> 2) & 0x1);
647 /* SET2 GPIO */
648 gpio_direction_output(pdata->buck_gpios[1],
649 (s5m8767->buck_gpioindex >> 1) & 0x1);
650 /* SET3 GPIO */
651 gpio_direction_output(pdata->buck_gpios[2],
652 (s5m8767->buck_gpioindex >> 0) & 0x1);
653 ret = 0;
654
655 } else {
656 dev_err(&pdev->dev, "GPIO NOT VALID\n");
657 ret = -EINVAL;
658 return ret;
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900659 }
660
Sangbeom Kimc848bc82012-06-18 09:49:20 +0900661 ret = gpio_request(pdata->buck_ds[0], "S5M8767 DS2");
662 if (ret == -EBUSY)
663 dev_warn(&pdev->dev, "Duplicated gpio request for DS2\n");
664
665 ret = gpio_request(pdata->buck_ds[1], "S5M8767 DS3");
666 if (ret == -EBUSY)
667 dev_warn(&pdev->dev, "Duplicated gpio request for DS3\n");
668
669 ret = gpio_request(pdata->buck_ds[2], "S5M8767 DS4");
670 if (ret == -EBUSY)
671 dev_warn(&pdev->dev, "Duplicated gpio request for DS4\n");
672
673 /* DS2 GPIO */
674 gpio_direction_output(pdata->buck_ds[0], 0x0);
675 /* DS3 GPIO */
676 gpio_direction_output(pdata->buck_ds[1], 0x0);
677 /* DS4 GPIO */
678 gpio_direction_output(pdata->buck_ds[2], 0x0);
679
680 if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs ||
681 pdata->buck4_gpiodvs) {
682 s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL,
683 (pdata->buck2_gpiodvs) ? (1 << 1) : (0 << 1),
684 1 << 1);
685 s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL,
686 (pdata->buck3_gpiodvs) ? (1 << 1) : (0 << 1),
687 1 << 1);
688 s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL,
689 (pdata->buck4_gpiodvs) ? (1 << 1) : (0 << 1),
690 1 << 1);
691 }
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900692
693 /* Initialize GPIO DVS registers */
694 for (i = 0; i < 8; i++) {
695 if (s5m8767->buck2_gpiodvs) {
696 s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS1 + i,
697 s5m8767->buck2_vol[i]);
698 }
699
700 if (s5m8767->buck3_gpiodvs) {
701 s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS1 + i,
702 s5m8767->buck3_vol[i]);
703 }
704
705 if (s5m8767->buck4_gpiodvs) {
706 s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS1 + i,
707 s5m8767->buck4_vol[i]);
708 }
709 }
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900710
711 if (s5m8767->buck2_ramp)
712 s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x08, 0x08);
713
714 if (s5m8767->buck3_ramp)
715 s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x04, 0x04);
716
717 if (s5m8767->buck4_ramp)
718 s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x02, 0x02);
719
720 if (s5m8767->buck2_ramp || s5m8767->buck3_ramp
721 || s5m8767->buck4_ramp) {
722 switch (s5m8767->ramp_delay) {
Sangbeom Kim1af142c2012-06-13 17:27:54 +0900723 case 5:
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900724 s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
Sangbeom Kim1af142c2012-06-13 17:27:54 +0900725 0x40, 0xf0);
726 break;
727 case 10:
728 s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
729 0x90, 0xf0);
Axel Lin047ec222012-01-12 14:57:09 +0800730 break;
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900731 case 25:
732 s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
733 0xd0, 0xf0);
Axel Lin047ec222012-01-12 14:57:09 +0800734 break;
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900735 case 50:
736 s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
737 0xe0, 0xf0);
Axel Lin047ec222012-01-12 14:57:09 +0800738 break;
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900739 case 100:
740 s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
741 0xf0, 0xf0);
Axel Lin047ec222012-01-12 14:57:09 +0800742 break;
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900743 default:
744 s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
745 0x90, 0xf0);
746 }
747 }
748
749 for (i = 0; i < pdata->num_regulators; i++) {
750 const struct s5m_voltage_desc *desc;
751 int id = pdata->regulators[i].id;
752
753 desc = reg_voltage_map[id];
754 if (desc)
755 regulators[id].n_voltages =
756 (desc->max - desc->min) / desc->step + 1;
757
Mark Brownc1727082012-04-04 00:50:22 +0100758 config.dev = s5m8767->dev;
759 config.init_data = pdata->regulators[i].initdata;
760 config.driver_data = s5m8767;
761
762 rdev[i] = regulator_register(&regulators[id], &config);
Sangbeom Kim9767ec72012-01-09 19:10:25 +0900763 if (IS_ERR(rdev[i])) {
764 ret = PTR_ERR(rdev[i]);
765 dev_err(s5m8767->dev, "regulator init failed for %d\n",
766 id);
767 rdev[i] = NULL;
768 goto err;
769 }
770 }
771
772 return 0;
773err:
774 for (i = 0; i < s5m8767->num_regulators; i++)
775 if (rdev[i])
776 regulator_unregister(rdev[i]);
777
778 return ret;
779}
780
781static int __devexit s5m8767_pmic_remove(struct platform_device *pdev)
782{
783 struct s5m8767_info *s5m8767 = platform_get_drvdata(pdev);
784 struct regulator_dev **rdev = s5m8767->rdev;
785 int i;
786
787 for (i = 0; i < s5m8767->num_regulators; i++)
788 if (rdev[i])
789 regulator_unregister(rdev[i]);
790
791 return 0;
792}
793
794static const struct platform_device_id s5m8767_pmic_id[] = {
795 { "s5m8767-pmic", 0},
796 { },
797};
798MODULE_DEVICE_TABLE(platform, s5m8767_pmic_id);
799
800static struct platform_driver s5m8767_pmic_driver = {
801 .driver = {
802 .name = "s5m8767-pmic",
803 .owner = THIS_MODULE,
804 },
805 .probe = s5m8767_pmic_probe,
806 .remove = __devexit_p(s5m8767_pmic_remove),
807 .id_table = s5m8767_pmic_id,
808};
809
810static int __init s5m8767_pmic_init(void)
811{
812 return platform_driver_register(&s5m8767_pmic_driver);
813}
814subsys_initcall(s5m8767_pmic_init);
815
816static void __exit s5m8767_pmic_exit(void)
817{
818 platform_driver_unregister(&s5m8767_pmic_driver);
819}
820module_exit(s5m8767_pmic_exit);
821
822/* Module information */
823MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
824MODULE_DESCRIPTION("SAMSUNG S5M8767 Regulator Driver");
825MODULE_LICENSE("GPL");