Skip to content

Commit 433c9bb

Browse files
Erick Chenbroonie
authored andcommitted
regulator: sc2731: Add regulator driver to support Spreadtrum SC2731 PMIC
Add regulator driver for Spreadtrum SC2731 device. It has 17 general purpose LDOs, BUCKs generator and digital output to control regulators. Signed-off-by: Erick Chen <erick.chen@spreadtrum.com> Reviewed-by: Baolin Wang <baolin.wang@spreadtrum.com> Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent 5149b68 commit 433c9bb

File tree

3 files changed

+264
-0
lines changed

3 files changed

+264
-0
lines changed

drivers/regulator/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,13 @@ config REGULATOR_S5M8767
744744
via I2C bus. S5M8767A have 9 Bucks and 28 LDOs output and
745745
supports DVS mode with 8bits of output voltage control.
746746

747+
config REGULATOR_SC2731
748+
tristate "Spreadtrum SC2731 power regulator driver"
749+
depends on MFD_SC27XX_PMIC || COMPILE_TEST
750+
help
751+
This driver provides support for the voltage regulators on the
752+
SC2731 PMIC.
753+
747754
config REGULATOR_SKY81452
748755
tristate "Skyworks Solutions SKY81452 voltage regulator"
749756
depends on MFD_SKY81452

drivers/regulator/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ obj-$(CONFIG_REGULATOR_RT5033) += rt5033-regulator.o
9595
obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o
9696
obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
9797
obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
98+
obj-$(CONFIG_REGULATOR_SC2731) += sc2731-regulator.o
9899
obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o
99100
obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o
100101
obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o

drivers/regulator/sc2731-regulator.c

Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
//SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Copyright (C) 2017 Spreadtrum Communications Inc.
4+
*/
5+
6+
#include <linux/module.h>
7+
#include <linux/of.h>
8+
#include <linux/platform_device.h>
9+
#include <linux/regmap.h>
10+
#include <linux/regulator/driver.h>
11+
#include <linux/regulator/of_regulator.h>
12+
13+
/*
14+
* SC2731 regulator lock register
15+
*/
16+
#define SC2731_PWR_WR_PROT_VALUE 0xf0c
17+
#define SC2731_WR_UNLOCK 0x6e7f
18+
19+
/*
20+
* SC2731 enable register
21+
*/
22+
#define SC2731_POWER_PD_SW 0xc28
23+
#define SC2731_LDO_CAMA0_PD 0xcfc
24+
#define SC2731_LDO_CAMA1_PD 0xd04
25+
#define SC2731_LDO_CAMMOT_PD 0xd0c
26+
#define SC2731_LDO_VLDO_PD 0xd6c
27+
#define SC2731_LDO_EMMCCORE_PD 0xd2c
28+
#define SC2731_LDO_SDCORE_PD 0xd74
29+
#define SC2731_LDO_SDIO_PD 0xd70
30+
#define SC2731_LDO_WIFIPA_PD 0xd4c
31+
#define SC2731_LDO_USB33_PD 0xd5c
32+
#define SC2731_LDO_CAMD0_PD 0xd7c
33+
#define SC2731_LDO_CAMD1_PD 0xd84
34+
#define SC2731_LDO_CON_PD 0xd8c
35+
#define SC2731_LDO_CAMIO_PD 0xd94
36+
#define SC2731_LDO_SRAM_PD 0xd78
37+
38+
/*
39+
* SC2731 enable mask
40+
*/
41+
#define SC2731_DCDC_CPU0_PD_MASK BIT(4)
42+
#define SC2731_DCDC_CPU1_PD_MASK BIT(3)
43+
#define SC2731_DCDC_RF_PD_MASK BIT(11)
44+
#define SC2731_LDO_CAMA0_PD_MASK BIT(0)
45+
#define SC2731_LDO_CAMA1_PD_MASK BIT(0)
46+
#define SC2731_LDO_CAMMOT_PD_MASK BIT(0)
47+
#define SC2731_LDO_VLDO_PD_MASK BIT(0)
48+
#define SC2731_LDO_EMMCCORE_PD_MASK BIT(0)
49+
#define SC2731_LDO_SDCORE_PD_MASK BIT(0)
50+
#define SC2731_LDO_SDIO_PD_MASK BIT(0)
51+
#define SC2731_LDO_WIFIPA_PD_MASK BIT(0)
52+
#define SC2731_LDO_USB33_PD_MASK BIT(0)
53+
#define SC2731_LDO_CAMD0_PD_MASK BIT(0)
54+
#define SC2731_LDO_CAMD1_PD_MASK BIT(0)
55+
#define SC2731_LDO_CON_PD_MASK BIT(0)
56+
#define SC2731_LDO_CAMIO_PD_MASK BIT(0)
57+
#define SC2731_LDO_SRAM_PD_MASK BIT(0)
58+
59+
/*
60+
* SC2731 vsel register
61+
*/
62+
#define SC2731_DCDC_CPU0_VOL 0xc54
63+
#define SC2731_DCDC_CPU1_VOL 0xc64
64+
#define SC2731_DCDC_RF_VOL 0xcb8
65+
#define SC2731_LDO_CAMA0_VOL 0xd00
66+
#define SC2731_LDO_CAMA1_VOL 0xd08
67+
#define SC2731_LDO_CAMMOT_VOL 0xd10
68+
#define SC2731_LDO_VLDO_VOL 0xd28
69+
#define SC2731_LDO_EMMCCORE_VOL 0xd30
70+
#define SC2731_LDO_SDCORE_VOL 0xd38
71+
#define SC2731_LDO_SDIO_VOL 0xd40
72+
#define SC2731_LDO_WIFIPA_VOL 0xd50
73+
#define SC2731_LDO_USB33_VOL 0xd60
74+
#define SC2731_LDO_CAMD0_VOL 0xd80
75+
#define SC2731_LDO_CAMD1_VOL 0xd88
76+
#define SC2731_LDO_CON_VOL 0xd90
77+
#define SC2731_LDO_CAMIO_VOL 0xd98
78+
#define SC2731_LDO_SRAM_VOL 0xdB0
79+
80+
/*
81+
* SC2731 vsel register mask
82+
*/
83+
#define SC2731_DCDC_CPU0_VOL_MASK GENMASK(8, 0)
84+
#define SC2731_DCDC_CPU1_VOL_MASK GENMASK(8, 0)
85+
#define SC2731_DCDC_RF_VOL_MASK GENMASK(8, 0)
86+
#define SC2731_LDO_CAMA0_VOL_MASK GENMASK(7, 0)
87+
#define SC2731_LDO_CAMA1_VOL_MASK GENMASK(7, 0)
88+
#define SC2731_LDO_CAMMOT_VOL_MASK GENMASK(7, 0)
89+
#define SC2731_LDO_VLDO_VOL_MASK GENMASK(7, 0)
90+
#define SC2731_LDO_EMMCCORE_VOL_MASK GENMASK(7, 0)
91+
#define SC2731_LDO_SDCORE_VOL_MASK GENMASK(7, 0)
92+
#define SC2731_LDO_SDIO_VOL_MASK GENMASK(7, 0)
93+
#define SC2731_LDO_WIFIPA_VOL_MASK GENMASK(7, 0)
94+
#define SC2731_LDO_USB33_VOL_MASK GENMASK(7, 0)
95+
#define SC2731_LDO_CAMD0_VOL_MASK GENMASK(6, 0)
96+
#define SC2731_LDO_CAMD1_VOL_MASK GENMASK(6, 0)
97+
#define SC2731_LDO_CON_VOL_MASK GENMASK(6, 0)
98+
#define SC2731_LDO_CAMIO_VOL_MASK GENMASK(6, 0)
99+
#define SC2731_LDO_SRAM_VOL_MASK GENMASK(6, 0)
100+
101+
enum sc2731_regulator_id {
102+
SC2731_BUCK_CPU0,
103+
SC2731_BUCK_CPU1,
104+
SC2731_BUCK_RF,
105+
SC2731_LDO_CAMA0,
106+
SC2731_LDO_CAMA1,
107+
SC2731_LDO_CAMMOT,
108+
SC2731_LDO_VLDO,
109+
SC2731_LDO_EMMCCORE,
110+
SC2731_LDO_SDCORE,
111+
SC2731_LDO_SDIO,
112+
SC2731_LDO_WIFIPA,
113+
SC2731_LDO_USB33,
114+
SC2731_LDO_CAMD0,
115+
SC2731_LDO_CAMD1,
116+
SC2731_LDO_CON,
117+
SC2731_LDO_CAMIO,
118+
SC2731_LDO_SRAM,
119+
};
120+
121+
static const struct regulator_ops sc2731_regu_linear_ops = {
122+
.enable = regulator_enable_regmap,
123+
.disable = regulator_disable_regmap,
124+
.is_enabled = regulator_is_enabled_regmap,
125+
.list_voltage = regulator_list_voltage_linear,
126+
.get_voltage_sel = regulator_get_voltage_sel_regmap,
127+
.set_voltage_sel = regulator_set_voltage_sel_regmap,
128+
};
129+
130+
#define SC2731_REGU_LINEAR(_id, en_reg, en_mask, vreg, vmask, \
131+
vstep, vmin, vmax) { \
132+
.name = #_id, \
133+
.of_match = of_match_ptr(#_id), \
134+
.ops = &sc2731_regu_linear_ops, \
135+
.type = REGULATOR_VOLTAGE, \
136+
.id = SC2731_##_id, \
137+
.owner = THIS_MODULE, \
138+
.min_uV = vmin, \
139+
.n_voltages = ((vmax) - (vmin)) / (vstep) + 1, \
140+
.uV_step = vstep, \
141+
.enable_is_inverted = true, \
142+
.enable_val = 0, \
143+
.enable_reg = en_reg, \
144+
.enable_mask = en_mask, \
145+
.vsel_reg = vreg, \
146+
.vsel_mask = vmask, \
147+
}
148+
149+
static struct regulator_desc regulators[] = {
150+
SC2731_REGU_LINEAR(BUCK_CPU0, SC2731_POWER_PD_SW,
151+
SC2731_DCDC_CPU0_PD_MASK, SC2731_DCDC_CPU0_VOL,
152+
SC2731_DCDC_CPU0_VOL_MASK, 3125, 400000, 1996875),
153+
SC2731_REGU_LINEAR(BUCK_CPU1, SC2731_POWER_PD_SW,
154+
SC2731_DCDC_CPU1_PD_MASK, SC2731_DCDC_CPU1_VOL,
155+
SC2731_DCDC_CPU1_VOL_MASK, 3125, 400000, 1996875),
156+
SC2731_REGU_LINEAR(BUCK_RF, SC2731_POWER_PD_SW, SC2731_DCDC_RF_PD_MASK,
157+
SC2731_DCDC_RF_VOL, SC2731_DCDC_RF_VOL_MASK,
158+
3125, 600000, 2196875),
159+
SC2731_REGU_LINEAR(LDO_CAMA0, SC2731_LDO_CAMA0_PD,
160+
SC2731_LDO_CAMA0_PD_MASK, SC2731_LDO_CAMA0_VOL,
161+
SC2731_LDO_CAMA0_VOL_MASK, 10000, 1200000, 3750000),
162+
SC2731_REGU_LINEAR(LDO_CAMA1, SC2731_LDO_CAMA1_PD,
163+
SC2731_LDO_CAMA1_PD_MASK, SC2731_LDO_CAMA1_VOL,
164+
SC2731_LDO_CAMA1_VOL_MASK, 10000, 1200000, 3750000),
165+
SC2731_REGU_LINEAR(LDO_CAMMOT, SC2731_LDO_CAMMOT_PD,
166+
SC2731_LDO_CAMMOT_PD_MASK, SC2731_LDO_CAMMOT_VOL,
167+
SC2731_LDO_CAMMOT_VOL_MASK, 10000, 1200000, 3750000),
168+
SC2731_REGU_LINEAR(LDO_VLDO, SC2731_LDO_VLDO_PD,
169+
SC2731_LDO_VLDO_PD_MASK, SC2731_LDO_VLDO_VOL,
170+
SC2731_LDO_VLDO_VOL_MASK, 10000, 1200000, 3750000),
171+
SC2731_REGU_LINEAR(LDO_EMMCCORE, SC2731_LDO_EMMCCORE_PD,
172+
SC2731_LDO_EMMCCORE_PD_MASK, SC2731_LDO_EMMCCORE_VOL,
173+
SC2731_LDO_EMMCCORE_VOL_MASK, 10000, 1200000,
174+
3750000),
175+
SC2731_REGU_LINEAR(LDO_SDCORE, SC2731_LDO_SDCORE_PD,
176+
SC2731_LDO_SDCORE_PD_MASK, SC2731_LDO_SDCORE_VOL,
177+
SC2731_LDO_SDCORE_VOL_MASK, 10000, 1200000, 3750000),
178+
SC2731_REGU_LINEAR(LDO_SDIO, SC2731_LDO_SDIO_PD,
179+
SC2731_LDO_SDIO_PD_MASK, SC2731_LDO_SDIO_VOL,
180+
SC2731_LDO_SDIO_VOL_MASK, 10000, 1200000, 3750000),
181+
SC2731_REGU_LINEAR(LDO_WIFIPA, SC2731_LDO_WIFIPA_PD,
182+
SC2731_LDO_WIFIPA_PD_MASK, SC2731_LDO_WIFIPA_VOL,
183+
SC2731_LDO_WIFIPA_VOL_MASK, 10000, 1200000, 3750000),
184+
SC2731_REGU_LINEAR(LDO_USB33, SC2731_LDO_USB33_PD,
185+
SC2731_LDO_USB33_PD_MASK, SC2731_LDO_USB33_VOL,
186+
SC2731_LDO_USB33_VOL_MASK, 10000, 1200000, 3750000),
187+
SC2731_REGU_LINEAR(LDO_CAMD0, SC2731_LDO_CAMD0_PD,
188+
SC2731_LDO_CAMD0_PD_MASK, SC2731_LDO_CAMD0_VOL,
189+
SC2731_LDO_CAMD0_VOL_MASK, 6250, 1000000, 1793750),
190+
SC2731_REGU_LINEAR(LDO_CAMD1, SC2731_LDO_CAMD1_PD,
191+
SC2731_LDO_CAMD1_PD_MASK, SC2731_LDO_CAMD1_VOL,
192+
SC2731_LDO_CAMD1_VOL_MASK, 6250, 1000000, 1793750),
193+
SC2731_REGU_LINEAR(LDO_CON, SC2731_LDO_CON_PD,
194+
SC2731_LDO_CON_PD_MASK, SC2731_LDO_CON_VOL,
195+
SC2731_LDO_CON_VOL_MASK, 6250, 1000000, 1793750),
196+
SC2731_REGU_LINEAR(LDO_CAMIO, SC2731_LDO_CAMIO_PD,
197+
SC2731_LDO_CAMIO_PD_MASK, SC2731_LDO_CAMIO_VOL,
198+
SC2731_LDO_CAMIO_VOL_MASK, 6250, 1000000, 1793750),
199+
SC2731_REGU_LINEAR(LDO_SRAM, SC2731_LDO_SRAM_PD,
200+
SC2731_LDO_SRAM_PD_MASK, SC2731_LDO_SRAM_VOL,
201+
SC2731_LDO_SRAM_VOL_MASK, 6250, 1000000, 1793750),
202+
};
203+
204+
static int sc2731_regulator_unlock(struct regmap *regmap)
205+
{
206+
return regmap_write(regmap, SC2731_PWR_WR_PROT_VALUE,
207+
SC2731_WR_UNLOCK);
208+
}
209+
210+
static int sc2731_regulator_probe(struct platform_device *pdev)
211+
{
212+
int i, ret;
213+
struct regmap *regmap;
214+
struct regulator_config config = { };
215+
struct regulator_dev *rdev;
216+
217+
regmap = dev_get_regmap(pdev->dev.parent, NULL);
218+
if (!regmap) {
219+
dev_err(&pdev->dev, "failed to get regmap.\n");
220+
return -ENODEV;
221+
}
222+
223+
ret = sc2731_regulator_unlock(regmap);
224+
if (ret) {
225+
dev_err(&pdev->dev, "failed to release regulator lock\n");
226+
return ret;
227+
}
228+
229+
config.dev = &pdev->dev;
230+
config.regmap = regmap;
231+
232+
for (i = 0; i < ARRAY_SIZE(regulators); i++) {
233+
rdev = devm_regulator_register(&pdev->dev, &regulators[i],
234+
&config);
235+
if (IS_ERR(rdev)) {
236+
dev_err(&pdev->dev, "failed to register regulator %s\n",
237+
regulators[i].name);
238+
return PTR_ERR(rdev);
239+
}
240+
}
241+
242+
return 0;
243+
}
244+
245+
static struct platform_driver sc2731_regulator_driver = {
246+
.driver = {
247+
.name = "sc27xx-regulator",
248+
},
249+
.probe = sc2731_regulator_probe,
250+
};
251+
252+
module_platform_driver(sc2731_regulator_driver);
253+
254+
MODULE_AUTHOR("Chen Junhui <erick.chen@spreadtrum.com>");
255+
MODULE_DESCRIPTION("Spreadtrum SC2731 regulator driver");
256+
MODULE_LICENSE("GPL v2");

0 commit comments

Comments
 (0)