Merge tag 'v3.4-rc2' into regulator-drivers
[deliverable/linux.git] / drivers / regulator / s5m8767.c
CommitLineData
9767ec7f
SK
1/*
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>
15#include <linux/delay.h>
16#include <linux/err.h>
17#include <linux/gpio.h>
18#include <linux/slab.h>
19#include <linux/module.h>
20#include <linux/platform_device.h>
21#include <linux/regulator/driver.h>
22#include <linux/regulator/machine.h>
23#include <linux/mfd/s5m87xx/s5m-core.h>
24#include <linux/mfd/s5m87xx/s5m-pmic.h>
25
26struct s5m8767_info {
27 struct device *dev;
28 struct s5m87xx_dev *iodev;
29 int num_regulators;
30 struct regulator_dev **rdev;
7e44bb83 31 struct s5m_opmode_data *opmode;
9767ec7f
SK
32
33 int ramp_delay;
34 bool buck2_ramp;
35 bool buck3_ramp;
36 bool buck4_ramp;
37
38 bool buck2_gpiodvs;
39 bool buck3_gpiodvs;
40 bool buck4_gpiodvs;
41 u8 buck2_vol[8];
42 u8 buck3_vol[8];
43 u8 buck4_vol[8];
44 int buck_gpios[3];
45 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
9767ec7f
SK
124static int s5m8767_list_voltage(struct regulator_dev *rdev,
125 unsigned int selector)
126{
127 const struct s5m_voltage_desc *desc;
20a14b84 128 int reg_id = rdev_get_id(rdev);
9767ec7f
SK
129 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
7e44bb83
SK
145unsigned int s5m8767_opmode_reg[][4] = {
146 /* {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)
9767ec7f 191{
20a14b84 192 int reg_id = rdev_get_id(rdev);
7e44bb83
SK
193 unsigned int mode;
194 struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
9767ec7f
SK
195
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
7e44bb83
SK
219 mode = s5m8767->opmode[reg_id].mode;
220 *enable_ctrl = s5m8767_opmode_reg[reg_id][mode] << S5M8767_ENCTRL_SHIFT;
9767ec7f
SK
221 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;
7e44bb83 228 int mask = 0xc0, enable_ctrl;
9767ec7f
SK
229 u8 val;
230
7e44bb83 231 ret = s5m8767_get_register(rdev, &reg, &enable_ctrl);
9767ec7f
SK
232 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
7e44bb83 241 return (val & mask) == enable_ctrl;
9767ec7f
SK
242}
243
244static int s5m8767_reg_enable(struct regulator_dev *rdev)
245{
246 struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
247 int ret, reg;
7e44bb83 248 int mask = 0xc0, enable_ctrl;
9767ec7f 249
7e44bb83 250 ret = s5m8767_get_register(rdev, &reg, &enable_ctrl);
9767ec7f
SK
251 if (ret)
252 return ret;
253
7e44bb83 254 return s5m_reg_update(s5m8767->iodev, reg, enable_ctrl, mask);
9767ec7f
SK
255}
256
257static int s5m8767_reg_disable(struct regulator_dev *rdev)
258{
259 struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
260 int ret, reg;
7e44bb83 261 int mask = 0xc0, enable_ctrl;
9767ec7f 262
7e44bb83 263 ret = s5m8767_get_register(rdev, &reg, &enable_ctrl);
9767ec7f
SK
264 if (ret)
265 return ret;
266
7e44bb83 267 return s5m_reg_update(s5m8767->iodev, reg, ~mask, mask);
9767ec7f
SK
268}
269
270static int s5m8767_get_voltage_register(struct regulator_dev *rdev, int *_reg)
271{
0a41685f 272 struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
20a14b84 273 int reg_id = rdev_get_id(rdev);
9767ec7f
SK
274 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:
287 reg = S5M8767_REG_BUCK2DVS1;
0a41685f
AL
288 if (s5m8767->buck2_gpiodvs)
289 reg += s5m8767->buck_gpioindex;
9767ec7f
SK
290 break;
291 case S5M8767_BUCK3:
292 reg = S5M8767_REG_BUCK3DVS1;
0a41685f
AL
293 if (s5m8767->buck3_gpiodvs)
294 reg += s5m8767->buck_gpioindex;
9767ec7f
SK
295 break;
296 case S5M8767_BUCK4:
297 reg = S5M8767_REG_BUCK4DVS1;
0a41685f
AL
298 if (s5m8767->buck4_gpiodvs)
299 reg += s5m8767->buck_gpioindex;
9767ec7f
SK
300 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);
0a41685f 319 int reg, mask, ret;
20a14b84 320 int reg_id = rdev_get_id(rdev);
9767ec7f
SK
321 u8 val;
322
323 ret = s5m8767_get_voltage_register(rdev, &reg);
324 if (ret)
325 return ret;
326
0a41685f 327 mask = (reg_id < S5M8767_BUCK1) ? 0x3f : 0xff;
9767ec7f
SK
328
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
5b5e977c 338static int s5m8767_convert_voltage_to_sel(
9767ec7f
SK
339 const struct s5m_voltage_desc *desc,
340 int min_vol, int max_vol)
341{
5b5e977c 342 int selector = 0;
9767ec7f
SK
343
344 if (desc == NULL)
345 return -EINVAL;
346
347 if (max_vol < desc->min || min_vol > desc->max)
348 return -EINVAL;
349
5b5e977c 350 selector = (min_vol - desc->min) / desc->step;
9767ec7f 351
5b5e977c 352 if (desc->min + desc->step * selector > max_vol)
9767ec7f
SK
353 return -EINVAL;
354
5b5e977c 355 return selector;
9767ec7f
SK
356}
357
358static int s5m8767_set_voltage(struct regulator_dev *rdev,
359 int min_uV, int max_uV, unsigned *selector)
360{
361 struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
9767ec7f 362 const struct s5m_voltage_desc *desc;
20a14b84 363 int reg_id = rdev_get_id(rdev);
546e7845 364 int sel, reg, mask, ret;
9767ec7f
SK
365 u8 val;
366
367 switch (reg_id) {
368 case S5M8767_LDO1 ... S5M8767_LDO28:
369 mask = 0x3f;
370 break;
371 case S5M8767_BUCK1 ... S5M8767_BUCK6:
372 mask = 0xff;
373 break;
374 case S5M8767_BUCK7 ... S5M8767_BUCK8:
375 return -EINVAL;
376 case S5M8767_BUCK9:
377 mask = 0xff;
378 break;
379 default:
380 return -EINVAL;
381 }
382
383 desc = reg_voltage_map[reg_id];
384
546e7845
AL
385 sel = s5m8767_convert_voltage_to_sel(desc, min_uV, max_uV);
386 if (sel < 0)
387 return sel;
9767ec7f
SK
388
389 ret = s5m8767_get_voltage_register(rdev, &reg);
390 if (ret)
391 return ret;
392
393 s5m_reg_read(s5m8767->iodev, reg, &val);
546e7845
AL
394 val &= ~mask;
395 val |= sel;
9767ec7f
SK
396
397 ret = s5m_reg_write(s5m8767->iodev, reg, val);
546e7845 398 *selector = sel;
9767ec7f
SK
399
400 return ret;
401}
402
403static inline void s5m8767_set_high(struct s5m8767_info *s5m8767)
404{
405 int temp_index = s5m8767->buck_gpioindex;
406
407 gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1);
408 gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1);
409 gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1);
410}
411
412static inline void s5m8767_set_low(struct s5m8767_info *s5m8767)
413{
414 int temp_index = s5m8767->buck_gpioindex;
415
416 gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1);
417 gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1);
418 gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1);
419}
420
421static int s5m8767_set_voltage_buck(struct regulator_dev *rdev,
422 int min_uV, int max_uV, unsigned *selector)
423{
424 struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
20a14b84 425 int reg_id = rdev_get_id(rdev);
9767ec7f
SK
426 const struct s5m_voltage_desc *desc;
427 int new_val, old_val, i = 0;
9767ec7f
SK
428
429 if (reg_id < S5M8767_BUCK1 || reg_id > S5M8767_BUCK6)
430 return -EINVAL;
431
432 switch (reg_id) {
433 case S5M8767_BUCK1:
434 return s5m8767_set_voltage(rdev, min_uV, max_uV, selector);
435 case S5M8767_BUCK2 ... S5M8767_BUCK4:
436 break;
437 case S5M8767_BUCK5 ... S5M8767_BUCK6:
438 return s5m8767_set_voltage(rdev, min_uV, max_uV, selector);
439 case S5M8767_BUCK9:
440 return s5m8767_set_voltage(rdev, min_uV, max_uV, selector);
441 }
442
443 desc = reg_voltage_map[reg_id];
5b5e977c 444 new_val = s5m8767_convert_voltage_to_sel(desc, min_uV, max_uV);
9767ec7f
SK
445 if (new_val < 0)
446 return new_val;
447
448 switch (reg_id) {
449 case S5M8767_BUCK2:
450 if (s5m8767->buck2_gpiodvs) {
451 while (s5m8767->buck2_vol[i] != new_val)
452 i++;
453 } else
454 return s5m8767_set_voltage(rdev, min_uV,
455 max_uV, selector);
456 break;
457 case S5M8767_BUCK3:
458 if (s5m8767->buck3_gpiodvs) {
459 while (s5m8767->buck3_vol[i] != new_val)
460 i++;
461 } else
462 return s5m8767_set_voltage(rdev, min_uV,
463 max_uV, selector);
464 break;
465 case S5M8767_BUCK4:
466 if (s5m8767->buck3_gpiodvs) {
467 while (s5m8767->buck4_vol[i] != new_val)
468 i++;
469 } else
470 return s5m8767_set_voltage(rdev, min_uV,
471 max_uV, selector);
472 break;
473 }
474
475 old_val = s5m8767->buck_gpioindex;
476 s5m8767->buck_gpioindex = i;
477
478 if (i > old_val)
479 s5m8767_set_high(s5m8767);
480 else
481 s5m8767_set_low(s5m8767);
482
483 *selector = new_val;
484 return 0;
485}
486
487static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev,
488 unsigned int old_sel,
489 unsigned int new_sel)
490{
491 struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
492 const struct s5m_voltage_desc *desc;
20a14b84 493 int reg_id = rdev_get_id(rdev);
9767ec7f 494
9767ec7f
SK
495 desc = reg_voltage_map[reg_id];
496
9767ec7f 497 if (old_sel < new_sel)
89e0f0e4 498 return DIV_ROUND_UP(desc->step * (new_sel - old_sel),
0f8b9c77 499 s5m8767->ramp_delay * 1000);
89e0f0e4 500 return 0;
9767ec7f
SK
501}
502
503static struct regulator_ops s5m8767_ldo_ops = {
504 .list_voltage = s5m8767_list_voltage,
505 .is_enabled = s5m8767_reg_is_enabled,
506 .enable = s5m8767_reg_enable,
507 .disable = s5m8767_reg_disable,
508 .get_voltage_sel = s5m8767_get_voltage_sel,
509 .set_voltage = s5m8767_set_voltage,
510 .set_voltage_time_sel = s5m8767_set_voltage_time_sel,
511};
512
513static struct regulator_ops s5m8767_buck_ops = {
514 .list_voltage = s5m8767_list_voltage,
515 .is_enabled = s5m8767_reg_is_enabled,
516 .enable = s5m8767_reg_enable,
517 .disable = s5m8767_reg_disable,
518 .get_voltage_sel = s5m8767_get_voltage_sel,
519 .set_voltage = s5m8767_set_voltage_buck,
520 .set_voltage_time_sel = s5m8767_set_voltage_time_sel,
521};
522
523#define regulator_desc_ldo(num) { \
524 .name = "LDO"#num, \
525 .id = S5M8767_LDO##num, \
526 .ops = &s5m8767_ldo_ops, \
527 .type = REGULATOR_VOLTAGE, \
528 .owner = THIS_MODULE, \
529}
530#define regulator_desc_buck(num) { \
531 .name = "BUCK"#num, \
532 .id = S5M8767_BUCK##num, \
533 .ops = &s5m8767_buck_ops, \
534 .type = REGULATOR_VOLTAGE, \
535 .owner = THIS_MODULE, \
536}
537
538static struct regulator_desc regulators[] = {
539 regulator_desc_ldo(1),
540 regulator_desc_ldo(2),
541 regulator_desc_ldo(3),
542 regulator_desc_ldo(4),
543 regulator_desc_ldo(5),
544 regulator_desc_ldo(6),
545 regulator_desc_ldo(7),
546 regulator_desc_ldo(8),
547 regulator_desc_ldo(9),
548 regulator_desc_ldo(10),
549 regulator_desc_ldo(11),
550 regulator_desc_ldo(12),
551 regulator_desc_ldo(13),
552 regulator_desc_ldo(14),
553 regulator_desc_ldo(15),
554 regulator_desc_ldo(16),
555 regulator_desc_ldo(17),
556 regulator_desc_ldo(18),
557 regulator_desc_ldo(19),
558 regulator_desc_ldo(20),
559 regulator_desc_ldo(21),
560 regulator_desc_ldo(22),
561 regulator_desc_ldo(23),
562 regulator_desc_ldo(24),
563 regulator_desc_ldo(25),
564 regulator_desc_ldo(26),
565 regulator_desc_ldo(27),
566 regulator_desc_ldo(28),
567 regulator_desc_buck(1),
568 regulator_desc_buck(2),
569 regulator_desc_buck(3),
570 regulator_desc_buck(4),
571 regulator_desc_buck(5),
572 regulator_desc_buck(6),
573 regulator_desc_buck(7),
574 regulator_desc_buck(8),
575 regulator_desc_buck(9),
576};
577
578static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
579{
580 struct s5m87xx_dev *iodev = dev_get_drvdata(pdev->dev.parent);
581 struct s5m_platform_data *pdata = dev_get_platdata(iodev->dev);
c172708d 582 struct regulator_config config = { };
9767ec7f
SK
583 struct regulator_dev **rdev;
584 struct s5m8767_info *s5m8767;
22cd2fef 585 int i, ret, size;
9767ec7f
SK
586
587 if (!pdata) {
588 dev_err(pdev->dev.parent, "Platform data not supplied\n");
589 return -ENODEV;
590 }
591
6c4efe24
AL
592 if (pdata->buck2_gpiodvs) {
593 if (pdata->buck3_gpiodvs || pdata->buck4_gpiodvs) {
594 dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n");
595 return -EINVAL;
596 }
597 }
598
599 if (pdata->buck3_gpiodvs) {
600 if (pdata->buck2_gpiodvs || pdata->buck4_gpiodvs) {
601 dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n");
602 return -EINVAL;
603 }
604 }
605
606 if (pdata->buck4_gpiodvs) {
607 if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs) {
608 dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n");
609 return -EINVAL;
610 }
611 }
612
9767ec7f
SK
613 s5m8767 = devm_kzalloc(&pdev->dev, sizeof(struct s5m8767_info),
614 GFP_KERNEL);
615 if (!s5m8767)
616 return -ENOMEM;
617
618 size = sizeof(struct regulator_dev *) * (S5M8767_REG_MAX - 2);
619 s5m8767->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
620 if (!s5m8767->rdev)
621 return -ENOMEM;
622
623 rdev = s5m8767->rdev;
624 s5m8767->dev = &pdev->dev;
625 s5m8767->iodev = iodev;
626 s5m8767->num_regulators = S5M8767_REG_MAX - 2;
627 platform_set_drvdata(pdev, s5m8767);
9767ec7f
SK
628
629 s5m8767->buck_gpioindex = pdata->buck_default_idx;
630 s5m8767->buck2_gpiodvs = pdata->buck2_gpiodvs;
631 s5m8767->buck3_gpiodvs = pdata->buck3_gpiodvs;
632 s5m8767->buck4_gpiodvs = pdata->buck4_gpiodvs;
633 s5m8767->buck_gpios[0] = pdata->buck_gpios[0];
634 s5m8767->buck_gpios[1] = pdata->buck_gpios[1];
635 s5m8767->buck_gpios[2] = pdata->buck_gpios[2];
636 s5m8767->ramp_delay = pdata->buck_ramp_delay;
637 s5m8767->buck2_ramp = pdata->buck2_ramp_enable;
638 s5m8767->buck3_ramp = pdata->buck3_ramp_enable;
639 s5m8767->buck4_ramp = pdata->buck4_ramp_enable;
7e44bb83 640 s5m8767->opmode = pdata->opmode;
9767ec7f
SK
641
642 for (i = 0; i < 8; i++) {
643 if (s5m8767->buck2_gpiodvs) {
644 s5m8767->buck2_vol[i] =
5b5e977c 645 s5m8767_convert_voltage_to_sel(
9767ec7f
SK
646 &buck_voltage_val2,
647 pdata->buck2_voltage[i],
648 pdata->buck2_voltage[i] +
649 buck_voltage_val2.step);
650 }
651
652 if (s5m8767->buck3_gpiodvs) {
653 s5m8767->buck3_vol[i] =
5b5e977c 654 s5m8767_convert_voltage_to_sel(
9767ec7f
SK
655 &buck_voltage_val2,
656 pdata->buck3_voltage[i],
657 pdata->buck3_voltage[i] +
658 buck_voltage_val2.step);
659 }
660
661 if (s5m8767->buck4_gpiodvs) {
662 s5m8767->buck4_vol[i] =
5b5e977c 663 s5m8767_convert_voltage_to_sel(
9767ec7f
SK
664 &buck_voltage_val2,
665 pdata->buck4_voltage[i],
666 pdata->buck4_voltage[i] +
667 buck_voltage_val2.step);
668 }
669 }
670
671 if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs ||
672 pdata->buck4_gpiodvs) {
673 if (gpio_is_valid(pdata->buck_gpios[0]) &&
674 gpio_is_valid(pdata->buck_gpios[1]) &&
675 gpio_is_valid(pdata->buck_gpios[2])) {
676 ret = gpio_request(pdata->buck_gpios[0],
677 "S5M8767 SET1");
678 if (ret == -EBUSY)
679 dev_warn(&pdev->dev, "Duplicated gpio request for SET1\n");
680
681 ret = gpio_request(pdata->buck_gpios[1],
682 "S5M8767 SET2");
683 if (ret == -EBUSY)
684 dev_warn(&pdev->dev, "Duplicated gpio request for SET2\n");
685
686 ret = gpio_request(pdata->buck_gpios[2],
687 "S5M8767 SET3");
688 if (ret == -EBUSY)
689 dev_warn(&pdev->dev, "Duplicated gpio request for SET3\n");
690 /* SET1 GPIO */
691 gpio_direction_output(pdata->buck_gpios[0],
692 (s5m8767->buck_gpioindex >> 2) & 0x1);
693 /* SET2 GPIO */
694 gpio_direction_output(pdata->buck_gpios[1],
695 (s5m8767->buck_gpioindex >> 1) & 0x1);
696 /* SET3 GPIO */
697 gpio_direction_output(pdata->buck_gpios[2],
698 (s5m8767->buck_gpioindex >> 0) & 0x1);
699 ret = 0;
700 } else {
701 dev_err(&pdev->dev, "GPIO NOT VALID\n");
702 ret = -EINVAL;
703 return ret;
704 }
705 }
706
9767ec7f
SK
707 s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL,
708 (pdata->buck2_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1);
709 s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL,
710 (pdata->buck3_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1);
711 s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL,
712 (pdata->buck4_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1);
713
714 /* Initialize GPIO DVS registers */
715 for (i = 0; i < 8; i++) {
716 if (s5m8767->buck2_gpiodvs) {
717 s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS1 + i,
718 s5m8767->buck2_vol[i]);
719 }
720
721 if (s5m8767->buck3_gpiodvs) {
722 s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS1 + i,
723 s5m8767->buck3_vol[i]);
724 }
725
726 if (s5m8767->buck4_gpiodvs) {
727 s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS1 + i,
728 s5m8767->buck4_vol[i]);
729 }
730 }
731 s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL, 0x78, 0xff);
732 s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL, 0x58, 0xff);
733 s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL, 0x78, 0xff);
734
735 if (s5m8767->buck2_ramp)
736 s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x08, 0x08);
737
738 if (s5m8767->buck3_ramp)
739 s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x04, 0x04);
740
741 if (s5m8767->buck4_ramp)
742 s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x02, 0x02);
743
744 if (s5m8767->buck2_ramp || s5m8767->buck3_ramp
745 || s5m8767->buck4_ramp) {
746 switch (s5m8767->ramp_delay) {
747 case 15:
748 s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
749 0xc0, 0xf0);
047ec220 750 break;
9767ec7f
SK
751 case 25:
752 s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
753 0xd0, 0xf0);
047ec220 754 break;
9767ec7f
SK
755 case 50:
756 s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
757 0xe0, 0xf0);
047ec220 758 break;
9767ec7f
SK
759 case 100:
760 s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
761 0xf0, 0xf0);
047ec220 762 break;
9767ec7f
SK
763 default:
764 s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
765 0x90, 0xf0);
766 }
767 }
768
769 for (i = 0; i < pdata->num_regulators; i++) {
770 const struct s5m_voltage_desc *desc;
771 int id = pdata->regulators[i].id;
772
773 desc = reg_voltage_map[id];
774 if (desc)
775 regulators[id].n_voltages =
776 (desc->max - desc->min) / desc->step + 1;
777
c172708d
MB
778 config.dev = s5m8767->dev;
779 config.init_data = pdata->regulators[i].initdata;
780 config.driver_data = s5m8767;
781
782 rdev[i] = regulator_register(&regulators[id], &config);
9767ec7f
SK
783 if (IS_ERR(rdev[i])) {
784 ret = PTR_ERR(rdev[i]);
785 dev_err(s5m8767->dev, "regulator init failed for %d\n",
786 id);
787 rdev[i] = NULL;
788 goto err;
789 }
790 }
791
792 return 0;
793err:
794 for (i = 0; i < s5m8767->num_regulators; i++)
795 if (rdev[i])
796 regulator_unregister(rdev[i]);
797
798 return ret;
799}
800
801static int __devexit s5m8767_pmic_remove(struct platform_device *pdev)
802{
803 struct s5m8767_info *s5m8767 = platform_get_drvdata(pdev);
804 struct regulator_dev **rdev = s5m8767->rdev;
805 int i;
806
807 for (i = 0; i < s5m8767->num_regulators; i++)
808 if (rdev[i])
809 regulator_unregister(rdev[i]);
810
811 return 0;
812}
813
814static const struct platform_device_id s5m8767_pmic_id[] = {
815 { "s5m8767-pmic", 0},
816 { },
817};
818MODULE_DEVICE_TABLE(platform, s5m8767_pmic_id);
819
820static struct platform_driver s5m8767_pmic_driver = {
821 .driver = {
822 .name = "s5m8767-pmic",
823 .owner = THIS_MODULE,
824 },
825 .probe = s5m8767_pmic_probe,
826 .remove = __devexit_p(s5m8767_pmic_remove),
827 .id_table = s5m8767_pmic_id,
828};
829
830static int __init s5m8767_pmic_init(void)
831{
832 return platform_driver_register(&s5m8767_pmic_driver);
833}
834subsys_initcall(s5m8767_pmic_init);
835
836static void __exit s5m8767_pmic_exit(void)
837{
838 platform_driver_unregister(&s5m8767_pmic_driver);
839}
840module_exit(s5m8767_pmic_exit);
841
842/* Module information */
843MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
844MODULE_DESCRIPTION("SAMSUNG S5M8767 Regulator Driver");
845MODULE_LICENSE("GPL");
This page took 0.069883 seconds and 5 git commands to generate.