Skip to content

Commit cb74685

Browse files
cornusbroonie
authored andcommitted
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>
1 parent 7be5318 commit cb74685

File tree

3 files changed

+377
-0
lines changed

3 files changed

+377
-0
lines changed

drivers/regulator/Kconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,14 @@ config REGULATOR_RC5T583
256256
through regulator interface. The device supports multiple DCDC/LDO
257257
outputs which can be controlled by i2c communication.
258258

259+
config 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+
259267
config REGULATOR_S5M8767
260268
tristate "Samsung S5M8767A voltage regulator"
261269
depends on MFD_S5M_CORE

drivers/regulator/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
4040
obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
4141
obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
4242
obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o
43+
obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
4344
obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
4445
obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
4546
obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o

drivers/regulator/s2mps11.c

Lines changed: 368 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
26+
struct 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+
44+
static 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+
59+
static 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+
70+
static 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+
185+
static 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+
236+
static __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;
316+
err:
317+
for (i = 0; i < S2MPS11_REGULATOR_MAX; i++)
318+
if (rdev[i])
319+
regulator_unregister(rdev[i]);
320+
321+
return ret;
322+
}
323+
324+
static 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+
337+
static const struct platform_device_id s2mps11_pmic_id[] = {
338+
{ "s2mps11-pmic", 0},
339+
{ },
340+
};
341+
MODULE_DEVICE_TABLE(platform, s2mps11_pmic_id);
342+
343+
static 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+
353+
static int __init s2mps11_pmic_init(void)
354+
{
355+
return platform_driver_register(&s2mps11_pmic_driver);
356+
}
357+
subsys_initcall(s2mps11_pmic_init);
358+
359+
static void __exit s2mps11_pmic_exit(void)
360+
{
361+
platform_driver_unregister(&s2mps11_pmic_driver);
362+
}
363+
module_exit(s2mps11_pmic_exit);
364+
365+
/* Module information */
366+
MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
367+
MODULE_DESCRIPTION("SAMSUNG S2MPS11 Regulator Driver");
368+
MODULE_LICENSE("GPL");

0 commit comments

Comments
 (0)