aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSangbeom Kim <sbkim73@samsung.com>2012-07-11 08:08:17 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-07-11 10:32:40 -0400
commitcb74685ecb394f8af48a9c49c0a5db2ab5383c33 (patch)
treec7d8cf57398f3de89cac65bce674778c88701aa9
parent7be531883a81d2dc23a79c1a34b4fdb0918f2ca8 (diff)
regulator: s2mps11: Add samsung s2mps11 regulator driver
This patch add Samsung S2MPS11 regulator driver. The S2MPS11 can support 10 Bucks and 38 LDOs and RTC. Especially, S2MPS11 is designed for high performance Samsung application processor. Signed-off-by: Sangbeom Kim <sbkim73@samsung.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
-rw-r--r--drivers/regulator/Kconfig8
-rw-r--r--drivers/regulator/Makefile1
-rw-r--r--drivers/regulator/s2mps11.c368
3 files changed, 377 insertions, 0 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 27fe52f592d..3923a3b2e47 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -256,6 +256,14 @@ config REGULATOR_RC5T583
256 through regulator interface. The device supports multiple DCDC/LDO 256 through regulator interface. The device supports multiple DCDC/LDO
257 outputs which can be controlled by i2c communication. 257 outputs which can be controlled by i2c communication.
258 258
259config REGULATOR_S2MPS11
260 tristate "Samsung S2MPS11 voltage regulator"
261 depends on MFD_SEC_CORE
262 help
263 This driver supports a Samsung S2MPS11 voltage output regulator
264 via I2C bus. S2MPS11 is comprised of high efficient Buck converters
265 including Dual-Phase Buck converter, Buck-Boost converter, various LDOs.
266
259config REGULATOR_S5M8767 267config REGULATOR_S5M8767
260 tristate "Samsung S5M8767A voltage regulator" 268 tristate "Samsung S5M8767A voltage regulator"
261 depends on MFD_S5M_CORE 269 depends on MFD_S5M_CORE
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index c7460888edc..a70c4f4525a 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
40obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o 40obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
41obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o 41obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
42obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o 42obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o
43obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
43obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o 44obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
44obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o 45obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
45obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o 46obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o
diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c
new file mode 100644
index 00000000000..514cf5416a3
--- /dev/null
+++ b/drivers/regulator/s2mps11.c
@@ -0,0 +1,368 @@
1/*
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>
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/samsung/core.h>
24#include <linux/mfd/samsung/s2mps11.h>
25
26struct s2mps11_info {
27 struct device *dev;
28 struct sec_pmic_dev *iodev;
29 struct regulator_dev **rdev;
30
31 int ramp_delay2;
32 int ramp_delay34;
33 int ramp_delay5;
34 int ramp_delay16;
35 int ramp_delay7810;
36 int ramp_delay9;
37
38 bool buck6_ramp;
39 bool buck2_ramp;
40 bool buck3_ramp;
41 bool buck4_ramp;
42};
43
44static int get_ramp_delay(int ramp_delay)
45{
46 unsigned char cnt = 0;
47
48 ramp_delay /= 6;
49
50 while (true) {
51 ramp_delay = ramp_delay >> 1;
52 if (ramp_delay == 0)
53 break;
54 cnt++;
55 }
56 return cnt;
57}
58
59static struct regulator_ops s2mps11_ldo_ops = {
60 .list_voltage = regulator_list_voltage_linear,
61 .map_voltage = regulator_map_voltage_linear,
62 .is_enabled = regulator_is_enabled_regmap,
63 .enable = regulator_enable_regmap,
64 .disable = regulator_disable_regmap,
65 .get_voltage_sel = regulator_get_voltage_sel_regmap,
66 .set_voltage_sel = regulator_set_voltage_sel_regmap,
67 .set_voltage_time_sel = regulator_set_voltage_time_sel,
68};
69
70static struct regulator_ops s2mps11_buck_ops = {
71 .list_voltage = regulator_list_voltage_linear,
72 .map_voltage = regulator_map_voltage_linear,
73 .is_enabled = regulator_is_enabled_regmap,
74 .enable = regulator_enable_regmap,
75 .disable = regulator_disable_regmap,
76 .get_voltage_sel = regulator_get_voltage_sel_regmap,
77 .set_voltage_sel = regulator_set_voltage_sel_regmap,
78 .set_voltage_time_sel = regulator_set_voltage_time_sel,
79};
80
81#define regulator_desc_ldo1(num) { \
82 .name = "LDO"#num, \
83 .id = S2MPS11_LDO##num, \
84 .ops = &s2mps11_ldo_ops, \
85 .type = REGULATOR_VOLTAGE, \
86 .owner = THIS_MODULE, \
87 .min_uV = S2MPS11_LDO_MIN, \
88 .uV_step = S2MPS11_LDO_STEP1, \
89 .n_voltages = S2MPS11_LDO_N_VOLTAGES, \
90 .vsel_reg = S2MPS11_REG_L1CTRL + num - 1, \
91 .vsel_mask = S2MPS11_LDO_VSEL_MASK \
92 .enable_reg = S2MPS11_REG_L1CTRL + num - 1, \
93 .enable_mask = S2MPS11_ENABLE_MASK \
94}
95#define regulator_desc_ldo2(num) { \
96 .name = "LDO"#num, \
97 .id = S2MPS11_LDO##num, \
98 .ops = &s2mps11_ldo_ops, \
99 .type = REGULATOR_VOLTAGE, \
100 .owner = THIS_MODULE, \
101 .min_uV = S2MPS11_LDO_MIN, \
102 .uV_step = S2MPS11_LDO_STEP2, \
103 .n_voltages = S2MPS11_LDO_N_VOLTAGES, \
104 .vsel_reg = S2MPS11_REG_L1CTRL + num - 1, \
105 .vsel_mask = S2MPS11_LDO_VSEL_MASK \
106 .enable_reg = S2MPS11_REG_L1CTRL + num - 1, \
107 .enable_mask = S2MPS11_ENABLE_MASK \
108}
109
110#define regulator_desc_buck1_4(num) { \
111 .name = "BUCK"#num, \
112 .id = S2MPS11_BUCK##num, \
113 .ops = &s2mps11_buck_ops, \
114 .type = REGULATOR_VOLTAGE, \
115 .owner = THIS_MODULE, \
116 .min_uV = S2MPS11_BUCK_MIN1, \
117 .uV_step = S2MPS11_BUCK_STEP1, \
118 .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \
119 .vsel_reg = S2MPS11_REG_B1CTRL2 + (num - 1) * 2, \
120 .vsel_mask = S2MPS11_BUCK_VSEL_MASK \
121 .enable_reg = S2MPS11_REG_B1CTRL1 + (num - 1) * 2, \
122 .enable_mask = S2MPS11_ENABLE_MASK \
123}
124
125#define regulator_desc_buck5 { \
126 .name = "BUCK5", \
127 .id = S2MPS11_BUCK5, \
128 .ops = &s2mps11_buck_ops, \
129 .type = REGULATOR_VOLTAGE, \
130 .owner = THIS_MODULE, \
131 .min_uV = S2MPS11_BUCK_MIN1, \
132 .uV_step = S2MPS11_BUCK_STEP1, \
133 .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \
134 .vsel_reg = S2MPS11_REG_B5CTRL2, \
135 .vsel_mask = S2MPS11_BUCK_VSEL_MASK \
136 .enable_reg = S2MPS11_REG_B5CTRL1, \
137 .enable_mask = S2MPS11_ENABLE_MASK \
138}
139
140#define regulator_desc_buck6_8(num) { \
141 .name = "BUCK"#num, \
142 .id = S2MPS11_BUCK##num, \
143 .ops = &s2mps11_buck_ops, \
144 .type = REGULATOR_VOLTAGE, \
145 .owner = THIS_MODULE, \
146 .min_uV = S2MPS11_BUCK_MIN1, \
147 .uV_step = S2MPS11_BUCK_STEP1, \
148 .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \
149 .vsel_reg = S2MPS11_REG_B6CTRL2 + (num - 6) * 2, \
150 .vsel_mask = S2MPS11_BUCK_VSEL_MASK \
151 .enable_reg = S2MPS11_REG_B6CTRL1 + (num - 6) * 2, \
152 .enable_mask = S2MPS11_ENABLE_MASK \
153}
154
155#define regulator_desc_buck9 { \
156 .name = "BUCK9", \
157 .id = S2MPS11_BUCK9, \
158 .ops = &s2mps11_buck_ops, \
159 .type = REGULATOR_VOLTAGE, \
160 .owner = THIS_MODULE, \
161 .min_uV = S2MPS11_BUCK_MIN3, \
162 .uV_step = S2MPS11_BUCK_STEP3, \
163 .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \
164 .vsel_reg = S2MPS11_REG_B9CTRL2, \
165 .vsel_mask = S2MPS11_BUCK_VSEL_MASK \
166 .enable_reg = S2MPS11_REG_B9CTRL1, \
167 .enable_mask = S2MPS11_ENABLE_MASK \
168}
169
170#define regulator_desc_buck10 { \
171 .name = "BUCK10", \
172 .id = S2MPS11_BUCK10, \
173 .ops = &s2mps11_buck_ops, \
174 .type = REGULATOR_VOLTAGE, \
175 .owner = THIS_MODULE, \
176 .min_uV = S2MPS11_BUCK_MIN2, \
177 .uV_step = S2MPS11_BUCK_STEP2, \
178 .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \
179 .vsel_reg = S2MPS11_REG_B9CTRL2, \
180 .vsel_mask = S2MPS11_BUCK_VSEL_MASK \
181 .enable_reg = S2MPS11_REG_B9CTRL1, \
182 .enable_mask = S2MPS11_ENABLE_MASK \
183}
184
185static struct regulator_desc regulators[] = {
186 regulator_desc_ldo2(1),
187 regulator_desc_ldo1(2),
188 regulator_desc_ldo1(3),
189 regulator_desc_ldo1(4),
190 regulator_desc_ldo1(5),
191 regulator_desc_ldo2(6),
192 regulator_desc_ldo1(7),
193 regulator_desc_ldo1(8),
194 regulator_desc_ldo1(9),
195 regulator_desc_ldo1(10),
196 regulator_desc_ldo2(11),
197 regulator_desc_ldo1(12),
198 regulator_desc_ldo1(13),
199 regulator_desc_ldo1(14),
200 regulator_desc_ldo1(15),
201 regulator_desc_ldo1(16),
202 regulator_desc_ldo1(17),
203 regulator_desc_ldo1(18),
204 regulator_desc_ldo1(19),
205 regulator_desc_ldo1(20),
206 regulator_desc_ldo1(21),
207 regulator_desc_ldo2(22),
208 regulator_desc_ldo2(23),
209 regulator_desc_ldo1(24),
210 regulator_desc_ldo1(25),
211 regulator_desc_ldo1(26),
212 regulator_desc_ldo2(27),
213 regulator_desc_ldo1(28),
214 regulator_desc_ldo1(29),
215 regulator_desc_ldo1(30),
216 regulator_desc_ldo1(31),
217 regulator_desc_ldo1(32),
218 regulator_desc_ldo1(33),
219 regulator_desc_ldo1(34),
220 regulator_desc_ldo1(35),
221 regulator_desc_ldo1(36),
222 regulator_desc_ldo1(37),
223 regulator_desc_ldo1(38),
224 regulator_desc_buck1_4(1),
225 regulator_desc_buck1_4(2),
226 regulator_desc_buck1_4(3),
227 regulator_desc_buck1_4(4),
228 regulator_desc_buck5,
229 regulator_desc_buck6_8(6),
230 regulator_desc_buck6_8(7),
231 regulator_desc_buck6_8(8),
232 regulator_desc_buck9,
233 regulator_desc_buck10,
234};
235
236static __devinit int s2mps11_pmic_probe(struct platform_device *pdev)
237{
238 struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
239 struct sec_platform_data *pdata = dev_get_platdata(iodev->dev);
240 struct regulator_config config = { };
241 struct regulator_dev **rdev;
242 struct s2mps11_info *s2mps11;
243 int i, ret, size;
244 unsigned char ramp_enable, ramp_reg = 0;
245
246 if (!pdata) {
247 dev_err(pdev->dev.parent, "Platform data not supplied\n");
248 return -ENODEV;
249 }
250
251 s2mps11 = devm_kzalloc(&pdev->dev, sizeof(struct s2mps11_info),
252 GFP_KERNEL);
253 if (!s2mps11)
254 return -ENOMEM;
255
256 size = sizeof(struct regulator_dev *) * S2MPS11_REGULATOR_MAX;
257 s2mps11->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
258 if (!s2mps11->rdev) {
259 return -ENOMEM;
260 }
261
262 rdev = s2mps11->rdev;
263 config.dev = &pdev->dev;
264 config.regmap = iodev->regmap;
265 platform_set_drvdata(pdev, s2mps11);
266
267 s2mps11->ramp_delay2 = pdata->buck2_ramp_delay;
268 s2mps11->ramp_delay34 = pdata->buck34_ramp_delay;
269 s2mps11->ramp_delay5 = pdata->buck5_ramp_delay;
270 s2mps11->ramp_delay16 = pdata->buck16_ramp_delay;
271 s2mps11->ramp_delay7810 = pdata->buck7810_ramp_delay;
272 s2mps11->ramp_delay9 = pdata->buck9_ramp_delay;
273
274 s2mps11->buck6_ramp = pdata->buck6_ramp_enable;
275 s2mps11->buck2_ramp = pdata->buck2_ramp_enable;
276 s2mps11->buck3_ramp = pdata->buck3_ramp_enable;
277 s2mps11->buck4_ramp = pdata->buck4_ramp_enable;
278
279 ramp_enable = (s2mps11->buck2_ramp << 3) | (s2mps11->buck3_ramp << 2) |
280 (s2mps11->buck4_ramp << 1) | s2mps11->buck6_ramp ;
281
282 if (ramp_enable) {
283 if (s2mps11->buck2_ramp)
284 ramp_reg |= get_ramp_delay(s2mps11->ramp_delay2) >> 6;
285 if (s2mps11->buck3_ramp || s2mps11->buck4_ramp)
286 ramp_reg |= get_ramp_delay(s2mps11->ramp_delay34) >> 4;
287 sec_reg_update(s2mps11->iodev, S2MPS11_REG_RAMP,
288 ramp_reg | ramp_enable, 0xff);
289 }
290
291 ramp_reg &= 0x00;
292 ramp_reg |= get_ramp_delay(s2mps11->ramp_delay5) >> 6;
293 ramp_reg |= get_ramp_delay(s2mps11->ramp_delay16) >> 4;
294 ramp_reg |= get_ramp_delay(s2mps11->ramp_delay7810) >> 2;
295 ramp_reg |= get_ramp_delay(s2mps11->ramp_delay9);
296 sec_reg_update(s2mps11->iodev, S2MPS11_REG_RAMP_BUCK, ramp_reg, 0xff);
297
298 for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) {
299
300 config.dev = s2mps11->dev;
301 config.regmap = iodev->regmap;
302 config.init_data = pdata->regulators[i].initdata;
303 config.driver_data = s2mps11;
304
305 rdev[i] = regulator_register(&regulators[i], &config);
306 if (IS_ERR(rdev[i])) {
307 ret = PTR_ERR(rdev[i]);
308 dev_err(s2mps11->dev, "regulator init failed for %d\n",
309 i);
310 rdev[i] = NULL;
311 goto err;
312 }
313 }
314
315 return 0;
316err:
317 for (i = 0; i < S2MPS11_REGULATOR_MAX; i++)
318 if (rdev[i])
319 regulator_unregister(rdev[i]);
320
321 return ret;
322}
323
324static int __devexit s2mps11_pmic_remove(struct platform_device *pdev)
325{
326 struct s2mps11_info *s2mps11 = platform_get_drvdata(pdev);
327 struct regulator_dev **rdev = s2mps11->rdev;
328 int i;
329
330 for (i = 0; i < S2MPS11_REGULATOR_MAX; i++)
331 if (rdev[i])
332 regulator_unregister(rdev[i]);
333
334 return 0;
335}
336
337static const struct platform_device_id s2mps11_pmic_id[] = {
338 { "s2mps11-pmic", 0},
339 { },
340};
341MODULE_DEVICE_TABLE(platform, s2mps11_pmic_id);
342
343static struct platform_driver s2mps11_pmic_driver = {
344 .driver = {
345 .name = "s2mps11-pmic",
346 .owner = THIS_MODULE,
347 },
348 .probe = s2mps11_pmic_probe,
349 .remove = __devexit_p(s2mps11_pmic_remove),
350 .id_table = s2mps11_pmic_id,
351};
352
353static int __init s2mps11_pmic_init(void)
354{
355 return platform_driver_register(&s2mps11_pmic_driver);
356}
357subsys_initcall(s2mps11_pmic_init);
358
359static void __exit s2mps11_pmic_exit(void)
360{
361 platform_driver_unregister(&s2mps11_pmic_driver);
362}
363module_exit(s2mps11_pmic_exit);
364
365/* Module information */
366MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
367MODULE_DESCRIPTION("SAMSUNG S2MPS11 Regulator Driver");
368MODULE_LICENSE("GPL");