blob: a671eb63a4e5515e45ed3e7f7fb059cb0a16c9ac [file] [log] [blame]
Sangbeom Kimcb746852012-07-11 21:08:17 +09001/*
2 * s2mps11.c
3 *
4 * Copyright (c) 2012 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 Kimcb746852012-07-11 21:08:17 +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/samsung/core.h>
23#include <linux/mfd/samsung/s2mps11.h>
24
25struct s2mps11_info {
Axel Linad46ed12012-07-13 10:12:40 +080026 struct regulator_dev *rdev[S2MPS11_REGULATOR_MAX];
Sangbeom Kimcb746852012-07-11 21:08:17 +090027
28 int ramp_delay2;
29 int ramp_delay34;
30 int ramp_delay5;
31 int ramp_delay16;
32 int ramp_delay7810;
33 int ramp_delay9;
34
35 bool buck6_ramp;
36 bool buck2_ramp;
37 bool buck3_ramp;
38 bool buck4_ramp;
39};
40
41static int get_ramp_delay(int ramp_delay)
42{
43 unsigned char cnt = 0;
44
Yadwinder Singh Brar90068342013-06-24 16:50:55 +053045 ramp_delay /= 6250;
Sangbeom Kimcb746852012-07-11 21:08:17 +090046
47 while (true) {
48 ramp_delay = ramp_delay >> 1;
49 if (ramp_delay == 0)
50 break;
51 cnt++;
52 }
53 return cnt;
54}
55
Yadwinder Singh Brar1e1598e2013-06-24 16:50:56 +053056static int s2mps11_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
57 unsigned int old_selector,
58 unsigned int new_selector)
59{
60 struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev);
61 unsigned int ramp_delay = 0;
62 int old_volt, new_volt;
63
64 switch (rdev->desc->id) {
65 case S2MPS11_BUCK2:
66 if (!s2mps11->buck2_ramp)
67 return 0;
68 ramp_delay = s2mps11->ramp_delay2;
69 break;
70 case S2MPS11_BUCK3:
71 if (!s2mps11->buck3_ramp)
72 return 0;
73 ramp_delay = s2mps11->ramp_delay34;
74 break;
75 case S2MPS11_BUCK4:
76 if (!s2mps11->buck4_ramp)
77 return 0;
78 ramp_delay = s2mps11->ramp_delay34;
79 break;
80 case S2MPS11_BUCK5:
81 ramp_delay = s2mps11->ramp_delay5;
82 break;
83 case S2MPS11_BUCK6:
84 if (!s2mps11->buck6_ramp)
85 return 0;
86 case S2MPS11_BUCK1:
87 ramp_delay = s2mps11->ramp_delay16;
88 break;
89 case S2MPS11_BUCK7:
90 case S2MPS11_BUCK8:
91 case S2MPS11_BUCK10:
92 ramp_delay = s2mps11->ramp_delay7810;
93 break;
94 case S2MPS11_BUCK9:
95 ramp_delay = s2mps11->ramp_delay9;
96 }
97
98 if (ramp_delay == 0)
99 ramp_delay = rdev->desc->ramp_delay;
100
101 old_volt = rdev->desc->min_uV + (rdev->desc->uV_step * old_selector);
102 new_volt = rdev->desc->min_uV + (rdev->desc->uV_step * new_selector);
103
104 return DIV_ROUND_UP(abs(new_volt - old_volt), ramp_delay);
105}
106
Sangbeom Kimcb746852012-07-11 21:08:17 +0900107static struct regulator_ops s2mps11_ldo_ops = {
108 .list_voltage = regulator_list_voltage_linear,
109 .map_voltage = regulator_map_voltage_linear,
110 .is_enabled = regulator_is_enabled_regmap,
111 .enable = regulator_enable_regmap,
112 .disable = regulator_disable_regmap,
113 .get_voltage_sel = regulator_get_voltage_sel_regmap,
114 .set_voltage_sel = regulator_set_voltage_sel_regmap,
115 .set_voltage_time_sel = regulator_set_voltage_time_sel,
116};
117
118static struct regulator_ops s2mps11_buck_ops = {
119 .list_voltage = regulator_list_voltage_linear,
120 .map_voltage = regulator_map_voltage_linear,
121 .is_enabled = regulator_is_enabled_regmap,
122 .enable = regulator_enable_regmap,
123 .disable = regulator_disable_regmap,
124 .get_voltage_sel = regulator_get_voltage_sel_regmap,
125 .set_voltage_sel = regulator_set_voltage_sel_regmap,
Yadwinder Singh Brar1e1598e2013-06-24 16:50:56 +0530126 .set_voltage_time_sel = s2mps11_regulator_set_voltage_time_sel,
Sangbeom Kimcb746852012-07-11 21:08:17 +0900127};
128
129#define regulator_desc_ldo1(num) { \
130 .name = "LDO"#num, \
131 .id = S2MPS11_LDO##num, \
132 .ops = &s2mps11_ldo_ops, \
133 .type = REGULATOR_VOLTAGE, \
134 .owner = THIS_MODULE, \
135 .min_uV = S2MPS11_LDO_MIN, \
136 .uV_step = S2MPS11_LDO_STEP1, \
137 .n_voltages = S2MPS11_LDO_N_VOLTAGES, \
138 .vsel_reg = S2MPS11_REG_L1CTRL + num - 1, \
Axel Lin2693fca2012-07-12 09:35:50 +0800139 .vsel_mask = S2MPS11_LDO_VSEL_MASK, \
Sangbeom Kimcb746852012-07-11 21:08:17 +0900140 .enable_reg = S2MPS11_REG_L1CTRL + num - 1, \
141 .enable_mask = S2MPS11_ENABLE_MASK \
142}
143#define regulator_desc_ldo2(num) { \
144 .name = "LDO"#num, \
145 .id = S2MPS11_LDO##num, \
146 .ops = &s2mps11_ldo_ops, \
147 .type = REGULATOR_VOLTAGE, \
148 .owner = THIS_MODULE, \
149 .min_uV = S2MPS11_LDO_MIN, \
150 .uV_step = S2MPS11_LDO_STEP2, \
151 .n_voltages = S2MPS11_LDO_N_VOLTAGES, \
152 .vsel_reg = S2MPS11_REG_L1CTRL + num - 1, \
Axel Lin2693fca2012-07-12 09:35:50 +0800153 .vsel_mask = S2MPS11_LDO_VSEL_MASK, \
Sangbeom Kimcb746852012-07-11 21:08:17 +0900154 .enable_reg = S2MPS11_REG_L1CTRL + num - 1, \
155 .enable_mask = S2MPS11_ENABLE_MASK \
156}
157
158#define regulator_desc_buck1_4(num) { \
159 .name = "BUCK"#num, \
160 .id = S2MPS11_BUCK##num, \
161 .ops = &s2mps11_buck_ops, \
162 .type = REGULATOR_VOLTAGE, \
163 .owner = THIS_MODULE, \
164 .min_uV = S2MPS11_BUCK_MIN1, \
165 .uV_step = S2MPS11_BUCK_STEP1, \
166 .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \
Yadwinder Singh Brar90068342013-06-24 16:50:55 +0530167 .ramp_delay = S2MPS11_RAMP_DELAY, \
Sangbeom Kimcb746852012-07-11 21:08:17 +0900168 .vsel_reg = S2MPS11_REG_B1CTRL2 + (num - 1) * 2, \
Axel Lin2693fca2012-07-12 09:35:50 +0800169 .vsel_mask = S2MPS11_BUCK_VSEL_MASK, \
Sangbeom Kimcb746852012-07-11 21:08:17 +0900170 .enable_reg = S2MPS11_REG_B1CTRL1 + (num - 1) * 2, \
171 .enable_mask = S2MPS11_ENABLE_MASK \
172}
173
174#define regulator_desc_buck5 { \
175 .name = "BUCK5", \
176 .id = S2MPS11_BUCK5, \
177 .ops = &s2mps11_buck_ops, \
178 .type = REGULATOR_VOLTAGE, \
179 .owner = THIS_MODULE, \
180 .min_uV = S2MPS11_BUCK_MIN1, \
181 .uV_step = S2MPS11_BUCK_STEP1, \
182 .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \
Yadwinder Singh Brar90068342013-06-24 16:50:55 +0530183 .ramp_delay = S2MPS11_RAMP_DELAY, \
Sangbeom Kimcb746852012-07-11 21:08:17 +0900184 .vsel_reg = S2MPS11_REG_B5CTRL2, \
Axel Lin2693fca2012-07-12 09:35:50 +0800185 .vsel_mask = S2MPS11_BUCK_VSEL_MASK, \
Sangbeom Kimcb746852012-07-11 21:08:17 +0900186 .enable_reg = S2MPS11_REG_B5CTRL1, \
187 .enable_mask = S2MPS11_ENABLE_MASK \
188}
189
190#define regulator_desc_buck6_8(num) { \
191 .name = "BUCK"#num, \
192 .id = S2MPS11_BUCK##num, \
193 .ops = &s2mps11_buck_ops, \
194 .type = REGULATOR_VOLTAGE, \
195 .owner = THIS_MODULE, \
196 .min_uV = S2MPS11_BUCK_MIN1, \
197 .uV_step = S2MPS11_BUCK_STEP1, \
198 .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \
Yadwinder Singh Brar90068342013-06-24 16:50:55 +0530199 .ramp_delay = S2MPS11_RAMP_DELAY, \
Sangbeom Kimcb746852012-07-11 21:08:17 +0900200 .vsel_reg = S2MPS11_REG_B6CTRL2 + (num - 6) * 2, \
Axel Lin2693fca2012-07-12 09:35:50 +0800201 .vsel_mask = S2MPS11_BUCK_VSEL_MASK, \
Sangbeom Kimcb746852012-07-11 21:08:17 +0900202 .enable_reg = S2MPS11_REG_B6CTRL1 + (num - 6) * 2, \
203 .enable_mask = S2MPS11_ENABLE_MASK \
204}
205
206#define regulator_desc_buck9 { \
207 .name = "BUCK9", \
208 .id = S2MPS11_BUCK9, \
209 .ops = &s2mps11_buck_ops, \
210 .type = REGULATOR_VOLTAGE, \
211 .owner = THIS_MODULE, \
212 .min_uV = S2MPS11_BUCK_MIN3, \
213 .uV_step = S2MPS11_BUCK_STEP3, \
214 .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \
Yadwinder Singh Brar90068342013-06-24 16:50:55 +0530215 .ramp_delay = S2MPS11_RAMP_DELAY, \
Sangbeom Kimcb746852012-07-11 21:08:17 +0900216 .vsel_reg = S2MPS11_REG_B9CTRL2, \
Axel Lin2693fca2012-07-12 09:35:50 +0800217 .vsel_mask = S2MPS11_BUCK_VSEL_MASK, \
Sangbeom Kimcb746852012-07-11 21:08:17 +0900218 .enable_reg = S2MPS11_REG_B9CTRL1, \
219 .enable_mask = S2MPS11_ENABLE_MASK \
220}
221
222#define regulator_desc_buck10 { \
223 .name = "BUCK10", \
224 .id = S2MPS11_BUCK10, \
225 .ops = &s2mps11_buck_ops, \
226 .type = REGULATOR_VOLTAGE, \
227 .owner = THIS_MODULE, \
228 .min_uV = S2MPS11_BUCK_MIN2, \
229 .uV_step = S2MPS11_BUCK_STEP2, \
230 .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \
Yadwinder Singh Brar90068342013-06-24 16:50:55 +0530231 .ramp_delay = S2MPS11_RAMP_DELAY, \
Alim Akhtarc76edd52013-01-30 08:02:27 -0500232 .vsel_reg = S2MPS11_REG_B10CTRL2, \
Axel Lin2693fca2012-07-12 09:35:50 +0800233 .vsel_mask = S2MPS11_BUCK_VSEL_MASK, \
Alim Akhtarc76edd52013-01-30 08:02:27 -0500234 .enable_reg = S2MPS11_REG_B10CTRL1, \
Sangbeom Kimcb746852012-07-11 21:08:17 +0900235 .enable_mask = S2MPS11_ENABLE_MASK \
236}
237
238static struct regulator_desc regulators[] = {
239 regulator_desc_ldo2(1),
240 regulator_desc_ldo1(2),
241 regulator_desc_ldo1(3),
242 regulator_desc_ldo1(4),
243 regulator_desc_ldo1(5),
244 regulator_desc_ldo2(6),
245 regulator_desc_ldo1(7),
246 regulator_desc_ldo1(8),
247 regulator_desc_ldo1(9),
248 regulator_desc_ldo1(10),
249 regulator_desc_ldo2(11),
250 regulator_desc_ldo1(12),
251 regulator_desc_ldo1(13),
252 regulator_desc_ldo1(14),
253 regulator_desc_ldo1(15),
254 regulator_desc_ldo1(16),
255 regulator_desc_ldo1(17),
256 regulator_desc_ldo1(18),
257 regulator_desc_ldo1(19),
258 regulator_desc_ldo1(20),
259 regulator_desc_ldo1(21),
260 regulator_desc_ldo2(22),
261 regulator_desc_ldo2(23),
262 regulator_desc_ldo1(24),
263 regulator_desc_ldo1(25),
264 regulator_desc_ldo1(26),
265 regulator_desc_ldo2(27),
266 regulator_desc_ldo1(28),
267 regulator_desc_ldo1(29),
268 regulator_desc_ldo1(30),
269 regulator_desc_ldo1(31),
270 regulator_desc_ldo1(32),
271 regulator_desc_ldo1(33),
272 regulator_desc_ldo1(34),
273 regulator_desc_ldo1(35),
274 regulator_desc_ldo1(36),
275 regulator_desc_ldo1(37),
276 regulator_desc_ldo1(38),
277 regulator_desc_buck1_4(1),
278 regulator_desc_buck1_4(2),
279 regulator_desc_buck1_4(3),
280 regulator_desc_buck1_4(4),
281 regulator_desc_buck5,
282 regulator_desc_buck6_8(6),
283 regulator_desc_buck6_8(7),
284 regulator_desc_buck6_8(8),
285 regulator_desc_buck9,
286 regulator_desc_buck10,
287};
288
Bill Pembertona5023572012-11-19 13:22:22 -0500289static int s2mps11_pmic_probe(struct platform_device *pdev)
Sangbeom Kimcb746852012-07-11 21:08:17 +0900290{
291 struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
292 struct sec_platform_data *pdata = dev_get_platdata(iodev->dev);
293 struct regulator_config config = { };
Sangbeom Kimcb746852012-07-11 21:08:17 +0900294 struct s2mps11_info *s2mps11;
Axel Linad46ed12012-07-13 10:12:40 +0800295 int i, ret;
Sangbeom Kimcb746852012-07-11 21:08:17 +0900296 unsigned char ramp_enable, ramp_reg = 0;
297
298 if (!pdata) {
299 dev_err(pdev->dev.parent, "Platform data not supplied\n");
300 return -ENODEV;
301 }
302
303 s2mps11 = devm_kzalloc(&pdev->dev, sizeof(struct s2mps11_info),
304 GFP_KERNEL);
305 if (!s2mps11)
306 return -ENOMEM;
307
Sangbeom Kimcb746852012-07-11 21:08:17 +0900308 platform_set_drvdata(pdev, s2mps11);
309
310 s2mps11->ramp_delay2 = pdata->buck2_ramp_delay;
311 s2mps11->ramp_delay34 = pdata->buck34_ramp_delay;
312 s2mps11->ramp_delay5 = pdata->buck5_ramp_delay;
313 s2mps11->ramp_delay16 = pdata->buck16_ramp_delay;
314 s2mps11->ramp_delay7810 = pdata->buck7810_ramp_delay;
315 s2mps11->ramp_delay9 = pdata->buck9_ramp_delay;
316
317 s2mps11->buck6_ramp = pdata->buck6_ramp_enable;
318 s2mps11->buck2_ramp = pdata->buck2_ramp_enable;
319 s2mps11->buck3_ramp = pdata->buck3_ramp_enable;
320 s2mps11->buck4_ramp = pdata->buck4_ramp_enable;
321
322 ramp_enable = (s2mps11->buck2_ramp << 3) | (s2mps11->buck3_ramp << 2) |
323 (s2mps11->buck4_ramp << 1) | s2mps11->buck6_ramp ;
324
325 if (ramp_enable) {
326 if (s2mps11->buck2_ramp)
Sangbeom Kimf7ebaae2012-11-24 11:13:28 +0900327 ramp_reg |= get_ramp_delay(s2mps11->ramp_delay2) << 6;
Sangbeom Kimcb746852012-07-11 21:08:17 +0900328 if (s2mps11->buck3_ramp || s2mps11->buck4_ramp)
Sangbeom Kimf7ebaae2012-11-24 11:13:28 +0900329 ramp_reg |= get_ramp_delay(s2mps11->ramp_delay34) << 4;
Axel Linc06eed32012-07-12 09:39:10 +0800330 sec_reg_write(iodev, S2MPS11_REG_RAMP, ramp_reg | ramp_enable);
Sangbeom Kimcb746852012-07-11 21:08:17 +0900331 }
332
333 ramp_reg &= 0x00;
Sangbeom Kimf7ebaae2012-11-24 11:13:28 +0900334 ramp_reg |= get_ramp_delay(s2mps11->ramp_delay5) << 6;
335 ramp_reg |= get_ramp_delay(s2mps11->ramp_delay16) << 4;
336 ramp_reg |= get_ramp_delay(s2mps11->ramp_delay7810) << 2;
Sangbeom Kimcb746852012-07-11 21:08:17 +0900337 ramp_reg |= get_ramp_delay(s2mps11->ramp_delay9);
Axel Linc06eed32012-07-12 09:39:10 +0800338 sec_reg_write(iodev, S2MPS11_REG_RAMP_BUCK, ramp_reg);
Sangbeom Kimcb746852012-07-11 21:08:17 +0900339
340 for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) {
341
Axel Lin232b2502012-07-12 09:37:37 +0800342 config.dev = &pdev->dev;
Sangbeom Kimcb746852012-07-11 21:08:17 +0900343 config.regmap = iodev->regmap;
344 config.init_data = pdata->regulators[i].initdata;
345 config.driver_data = s2mps11;
346
Axel Linad46ed12012-07-13 10:12:40 +0800347 s2mps11->rdev[i] = regulator_register(&regulators[i], &config);
348 if (IS_ERR(s2mps11->rdev[i])) {
349 ret = PTR_ERR(s2mps11->rdev[i]);
Axel Lin232b2502012-07-12 09:37:37 +0800350 dev_err(&pdev->dev, "regulator init failed for %d\n",
351 i);
Axel Linad46ed12012-07-13 10:12:40 +0800352 s2mps11->rdev[i] = NULL;
Sangbeom Kimcb746852012-07-11 21:08:17 +0900353 goto err;
354 }
355 }
356
357 return 0;
358err:
359 for (i = 0; i < S2MPS11_REGULATOR_MAX; i++)
Axel Linad46ed12012-07-13 10:12:40 +0800360 regulator_unregister(s2mps11->rdev[i]);
Sangbeom Kimcb746852012-07-11 21:08:17 +0900361
362 return ret;
363}
364
Bill Pemberton8dc995f2012-11-19 13:26:10 -0500365static int s2mps11_pmic_remove(struct platform_device *pdev)
Sangbeom Kimcb746852012-07-11 21:08:17 +0900366{
367 struct s2mps11_info *s2mps11 = platform_get_drvdata(pdev);
Sangbeom Kimcb746852012-07-11 21:08:17 +0900368 int i;
369
370 for (i = 0; i < S2MPS11_REGULATOR_MAX; i++)
Axel Linad46ed12012-07-13 10:12:40 +0800371 regulator_unregister(s2mps11->rdev[i]);
Sangbeom Kimcb746852012-07-11 21:08:17 +0900372
373 return 0;
374}
375
376static const struct platform_device_id s2mps11_pmic_id[] = {
377 { "s2mps11-pmic", 0},
378 { },
379};
380MODULE_DEVICE_TABLE(platform, s2mps11_pmic_id);
381
382static struct platform_driver s2mps11_pmic_driver = {
383 .driver = {
384 .name = "s2mps11-pmic",
385 .owner = THIS_MODULE,
386 },
387 .probe = s2mps11_pmic_probe,
Bill Pemberton5eb9f2b2012-11-19 13:20:42 -0500388 .remove = s2mps11_pmic_remove,
Sangbeom Kimcb746852012-07-11 21:08:17 +0900389 .id_table = s2mps11_pmic_id,
390};
391
392static int __init s2mps11_pmic_init(void)
393{
394 return platform_driver_register(&s2mps11_pmic_driver);
395}
396subsys_initcall(s2mps11_pmic_init);
397
398static void __exit s2mps11_pmic_exit(void)
399{
400 platform_driver_unregister(&s2mps11_pmic_driver);
401}
402module_exit(s2mps11_pmic_exit);
403
404/* Module information */
405MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
406MODULE_DESCRIPTION("SAMSUNG S2MPS11 Regulator Driver");
407MODULE_LICENSE("GPL");