aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlora Fu <flora.fu@mediatek.com>2014-12-04 23:07:54 -0500
committerMark Brown <broonie@kernel.org>2014-12-24 07:41:05 -0500
commit0425e2420c0ab1b5da24f6d9fce39241ad85fc46 (patch)
treed49d269a3cc4b7c10eb245706297ad26a79f758f
parent97bf6af1f928216fd6c5a66e8a57bfa95a659672 (diff)
regulator: mt6397: Add support for MT6397 regulator
Add MT6397 regulator driver. Signed-off-by: Flora Fu <flora.fu@mediatek.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--drivers/regulator/Kconfig9
-rw-r--r--drivers/regulator/Makefile1
-rw-r--r--drivers/regulator/mt6397-regulator.c332
-rw-r--r--include/linux/regulator/mt6397-regulator.h49
4 files changed, 391 insertions, 0 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index c3a60b57a865..f622d0613d27 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -433,6 +433,15 @@ config REGULATOR_MC13892
433 Say y here to support the regulators found on the Freescale MC13892 433 Say y here to support the regulators found on the Freescale MC13892
434 PMIC. 434 PMIC.
435 435
436config REGULATOR_MT6397
437 tristate "MediaTek MT6397 PMIC"
438 depends on MFD_MT6397
439 help
440 Say y here to select this option to enable the power regulator of
441 MediaTek MT6397 PMIC.
442 This driver supports the control of different power rails of device
443 through regulator interface.
444
436config REGULATOR_PALMAS 445config REGULATOR_PALMAS
437 tristate "TI Palmas PMIC Regulators" 446 tristate "TI Palmas PMIC Regulators"
438 depends on MFD_PALMAS 447 depends on MFD_PALMAS
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 1f28ebfc6f3a..1a0fbc397de1 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -58,6 +58,7 @@ obj-$(CONFIG_REGULATOR_MAX77802) += max77802.o
58obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o 58obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
59obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o 59obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
60obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o 60obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o
61obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o
61obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o 62obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
62obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o 63obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
63obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o 64obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
diff --git a/drivers/regulator/mt6397-regulator.c b/drivers/regulator/mt6397-regulator.c
new file mode 100644
index 000000000000..a5b2f4762677
--- /dev/null
+++ b/drivers/regulator/mt6397-regulator.c
@@ -0,0 +1,332 @@
1/*
2 * Copyright (c) 2014 MediaTek Inc.
3 * Author: Flora Fu <flora.fu@mediatek.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#include <linux/module.h>
16#include <linux/of.h>
17#include <linux/platform_device.h>
18#include <linux/regmap.h>
19#include <linux/mfd/mt6397/core.h>
20#include <linux/mfd/mt6397/registers.h>
21#include <linux/regulator/driver.h>
22#include <linux/regulator/machine.h>
23#include <linux/regulator/mt6397-regulator.h>
24#include <linux/regulator/of_regulator.h>
25
26/*
27 * MT6397 regulators' information
28 *
29 * @desc: standard fields of regulator description.
30 * @qi: Mask for query enable signal status of regulators
31 * @vselon_reg: Register sections for hardware control mode of bucks
32 * @vselctrl_reg: Register for controlling the buck control mode.
33 * @vselctrl_mask: Mask for query buck's voltage control mode.
34 */
35struct mt6397_regulator_info {
36 struct regulator_desc desc;
37 u32 qi;
38 u32 vselon_reg;
39 u32 vselctrl_reg;
40 u32 vselctrl_mask;
41};
42
43#define MT6397_BUCK(match, vreg, min, max, step, volt_ranges, enreg, \
44 vosel, vosel_mask, voselon, vosel_ctrl) \
45[MT6397_ID_##vreg] = { \
46 .desc = { \
47 .name = #vreg, \
48 .of_match = of_match_ptr(match), \
49 .ops = &mt6397_volt_range_ops, \
50 .type = REGULATOR_VOLTAGE, \
51 .id = MT6397_ID_##vreg, \
52 .owner = THIS_MODULE, \
53 .n_voltages = (max - min)/step + 1, \
54 .linear_ranges = volt_ranges, \
55 .n_linear_ranges = ARRAY_SIZE(volt_ranges), \
56 .vsel_reg = vosel, \
57 .vsel_mask = vosel_mask, \
58 .enable_reg = enreg, \
59 .enable_mask = BIT(0), \
60 }, \
61 .qi = BIT(13), \
62 .vselon_reg = voselon, \
63 .vselctrl_reg = vosel_ctrl, \
64 .vselctrl_mask = BIT(1), \
65}
66
67#define MT6397_LDO(match, vreg, ldo_volt_table, enreg, enbit, vosel, \
68 vosel_mask) \
69[MT6397_ID_##vreg] = { \
70 .desc = { \
71 .name = #vreg, \
72 .of_match = of_match_ptr(match), \
73 .ops = &mt6397_volt_table_ops, \
74 .type = REGULATOR_VOLTAGE, \
75 .id = MT6397_ID_##vreg, \
76 .owner = THIS_MODULE, \
77 .n_voltages = ARRAY_SIZE(ldo_volt_table), \
78 .volt_table = ldo_volt_table, \
79 .vsel_reg = vosel, \
80 .vsel_mask = vosel_mask, \
81 .enable_reg = enreg, \
82 .enable_mask = BIT(enbit), \
83 }, \
84 .qi = BIT(15), \
85}
86
87#define MT6397_REG_FIXED(match, vreg, enreg, enbit, volt) \
88[MT6397_ID_##vreg] = { \
89 .desc = { \
90 .name = #vreg, \
91 .of_match = of_match_ptr(match), \
92 .ops = &mt6397_volt_fixed_ops, \
93 .type = REGULATOR_VOLTAGE, \
94 .id = MT6397_ID_##vreg, \
95 .owner = THIS_MODULE, \
96 .n_voltages = 1, \
97 .enable_reg = enreg, \
98 .enable_mask = BIT(enbit), \
99 .min_uV = volt, \
100 }, \
101 .qi = BIT(15), \
102}
103
104static const struct regulator_linear_range buck_volt_range1[] = {
105 REGULATOR_LINEAR_RANGE(700000, 0, 0x7f, 6250),
106};
107
108static const struct regulator_linear_range buck_volt_range2[] = {
109 REGULATOR_LINEAR_RANGE(800000, 0, 0x7f, 6250),
110};
111
112static const struct regulator_linear_range buck_volt_range3[] = {
113 REGULATOR_LINEAR_RANGE(1500000, 0, 0x1f, 20000),
114};
115
116static const u32 ldo_volt_table1[] = {
117 1500000, 1800000, 2500000, 2800000,
118};
119
120static const u32 ldo_volt_table2[] = {
121 1800000, 3300000,
122};
123
124static const u32 ldo_volt_table3[] = {
125 3000000, 3300000,
126};
127
128static const u32 ldo_volt_table4[] = {
129 1220000, 1300000, 1500000, 1800000, 2500000, 2800000, 3000000, 3300000,
130};
131
132static const u32 ldo_volt_table5[] = {
133 1200000, 1300000, 1500000, 1800000, 2500000, 2800000, 3000000, 3300000,
134};
135
136static const u32 ldo_volt_table5_v2[] = {
137 1200000, 1000000, 1500000, 1800000, 2500000, 2800000, 3000000, 3300000,
138};
139
140static const u32 ldo_volt_table6[] = {
141 1200000, 1300000, 1500000, 1800000, 2500000, 2800000, 3000000, 2000000,
142};
143
144static const u32 ldo_volt_table7[] = {
145 1300000, 1500000, 1800000, 2000000, 2500000, 2800000, 3000000, 3300000,
146};
147
148static int mt6397_get_status(struct regulator_dev *rdev)
149{
150 int ret;
151 u32 regval;
152 struct mt6397_regulator_info *info = rdev_get_drvdata(rdev);
153
154 ret = regmap_read(rdev->regmap, info->desc.enable_reg, &regval);
155 if (ret != 0) {
156 dev_err(&rdev->dev, "Failed to get enable reg: %d\n", ret);
157 return ret;
158 }
159
160 return (regval & info->qi) ? REGULATOR_STATUS_ON : REGULATOR_STATUS_OFF;
161}
162
163static struct regulator_ops mt6397_volt_range_ops = {
164 .list_voltage = regulator_list_voltage_linear_range,
165 .map_voltage = regulator_map_voltage_linear_range,
166 .set_voltage_sel = regulator_set_voltage_sel_regmap,
167 .get_voltage_sel = regulator_get_voltage_sel_regmap,
168 .set_voltage_time_sel = regulator_set_voltage_time_sel,
169 .enable = regulator_enable_regmap,
170 .disable = regulator_disable_regmap,
171 .is_enabled = regulator_is_enabled_regmap,
172 .get_status = mt6397_get_status,
173};
174
175static struct regulator_ops mt6397_volt_table_ops = {
176 .list_voltage = regulator_list_voltage_table,
177 .map_voltage = regulator_map_voltage_iterate,
178 .set_voltage_sel = regulator_set_voltage_sel_regmap,
179 .get_voltage_sel = regulator_get_voltage_sel_regmap,
180 .set_voltage_time_sel = regulator_set_voltage_time_sel,
181 .enable = regulator_enable_regmap,
182 .disable = regulator_disable_regmap,
183 .is_enabled = regulator_is_enabled_regmap,
184 .get_status = mt6397_get_status,
185};
186
187static struct regulator_ops mt6397_volt_fixed_ops = {
188 .list_voltage = regulator_list_voltage_linear,
189 .enable = regulator_enable_regmap,
190 .disable = regulator_disable_regmap,
191 .is_enabled = regulator_is_enabled_regmap,
192 .get_status = mt6397_get_status,
193};
194
195/* The array is indexed by id(MT6397_ID_XXX) */
196static struct mt6397_regulator_info mt6397_regulators[] = {
197 MT6397_BUCK("buck_vpca15", VPCA15, 700000, 1493750, 6250,
198 buck_volt_range1, MT6397_VCA15_CON7, MT6397_VCA15_CON9, 0x7f,
199 MT6397_VCA15_CON10, MT6397_VCA15_CON5),
200 MT6397_BUCK("buck_vpca7", VPCA7, 700000, 1493750, 6250,
201 buck_volt_range1, MT6397_VPCA7_CON7, MT6397_VPCA7_CON9, 0x7f,
202 MT6397_VPCA7_CON10, MT6397_VPCA7_CON5),
203 MT6397_BUCK("buck_vsramca15", VSRAMCA15, 700000, 1493750, 6250,
204 buck_volt_range1, MT6397_VSRMCA15_CON7, MT6397_VSRMCA15_CON9,
205 0x7f, MT6397_VSRMCA15_CON10, MT6397_VSRMCA15_CON5),
206 MT6397_BUCK("buck_vsramca7", VSRAMCA7, 700000, 1493750, 6250,
207 buck_volt_range1, MT6397_VSRMCA7_CON7, MT6397_VSRMCA7_CON9,
208 0x7f, MT6397_VSRMCA7_CON10, MT6397_VSRMCA7_CON5),
209 MT6397_BUCK("buck_vcore", VCORE, 700000, 1493750, 6250,
210 buck_volt_range1, MT6397_VCORE_CON7, MT6397_VCORE_CON9, 0x7f,
211 MT6397_VCORE_CON10, MT6397_VCORE_CON5),
212 MT6397_BUCK("buck_vgpu", VGPU, 700000, 1493750, 6250, buck_volt_range1,
213 MT6397_VGPU_CON7, MT6397_VGPU_CON9, 0x7f,
214 MT6397_VGPU_CON10, MT6397_VGPU_CON5),
215 MT6397_BUCK("buck_vdrm", VDRM, 800000, 1593750, 6250, buck_volt_range2,
216 MT6397_VDRM_CON7, MT6397_VDRM_CON9, 0x7f,
217 MT6397_VDRM_CON10, MT6397_VDRM_CON5),
218 MT6397_BUCK("buck_vio18", VIO18, 1500000, 2120000, 20000,
219 buck_volt_range3, MT6397_VIO18_CON7, MT6397_VIO18_CON9, 0x1f,
220 MT6397_VIO18_CON10, MT6397_VIO18_CON5),
221 MT6397_REG_FIXED("ldo_vtcxo", VTCXO, MT6397_ANALDO_CON0, 10, 2800000),
222 MT6397_REG_FIXED("ldo_va28", VA28, MT6397_ANALDO_CON1, 14, 2800000),
223 MT6397_LDO("ldo_vcama", VCAMA, ldo_volt_table1,
224 MT6397_ANALDO_CON2, 15, MT6397_ANALDO_CON6, 0xC0),
225 MT6397_REG_FIXED("ldo_vio28", VIO28, MT6397_DIGLDO_CON0, 14, 2800000),
226 MT6397_REG_FIXED("ldo_vusb", VUSB, MT6397_DIGLDO_CON1, 14, 3300000),
227 MT6397_LDO("ldo_vmc", VMC, ldo_volt_table2,
228 MT6397_DIGLDO_CON2, 12, MT6397_DIGLDO_CON29, 0x10),
229 MT6397_LDO("ldo_vmch", VMCH, ldo_volt_table3,
230 MT6397_DIGLDO_CON3, 14, MT6397_DIGLDO_CON17, 0x80),
231 MT6397_LDO("ldo_vemc3v3", VEMC3V3, ldo_volt_table3,
232 MT6397_DIGLDO_CON4, 14, MT6397_DIGLDO_CON18, 0x10),
233 MT6397_LDO("ldo_vgp1", VGP1, ldo_volt_table4,
234 MT6397_DIGLDO_CON5, 15, MT6397_DIGLDO_CON19, 0xE0),
235 MT6397_LDO("ldo_vgp2", VGP2, ldo_volt_table5,
236 MT6397_DIGLDO_CON6, 15, MT6397_DIGLDO_CON20, 0xE0),
237 MT6397_LDO("ldo_vgp3", VGP3, ldo_volt_table5,
238 MT6397_DIGLDO_CON7, 15, MT6397_DIGLDO_CON21, 0xE0),
239 MT6397_LDO("ldo_vgp4", VGP4, ldo_volt_table5,
240 MT6397_DIGLDO_CON8, 15, MT6397_DIGLDO_CON22, 0xE0),
241 MT6397_LDO("ldo_vgp5", VGP5, ldo_volt_table6,
242 MT6397_DIGLDO_CON9, 15, MT6397_DIGLDO_CON23, 0xE0),
243 MT6397_LDO("ldo_vgp6", VGP6, ldo_volt_table5,
244 MT6397_DIGLDO_CON10, 15, MT6397_DIGLDO_CON33, 0xE0),
245 MT6397_LDO("ldo_vibr", VIBR, ldo_volt_table7,
246 MT6397_DIGLDO_CON24, 15, MT6397_DIGLDO_CON25, 0xE00),
247};
248
249static int mt6397_set_buck_vosel_reg(struct platform_device *pdev)
250{
251 struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent);
252 int i;
253 u32 regval;
254
255 for (i = 0; i < MT6397_MAX_REGULATOR; i++) {
256 if (mt6397_regulators[i].vselctrl_reg) {
257 if (regmap_read(mt6397->regmap,
258 mt6397_regulators[i].vselctrl_reg,
259 &regval) < 0) {
260 dev_err(&pdev->dev,
261 "Failed to read buck ctrl\n");
262 return -EIO;
263 }
264
265 if (regval & mt6397_regulators[i].vselctrl_mask) {
266 mt6397_regulators[i].desc.vsel_reg =
267 mt6397_regulators[i].vselon_reg;
268 }
269 }
270 }
271
272 return 0;
273}
274
275static int mt6397_regulator_probe(struct platform_device *pdev)
276{
277 struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent);
278 struct regulator_config config = {};
279 struct regulator_dev *rdev;
280 int i;
281 u32 reg_value, version;
282
283 /* Query buck controller to select activated voltage register part */
284 if (mt6397_set_buck_vosel_reg(pdev))
285 return -EIO;
286
287 /* Read PMIC chip revision to update constraints and voltage table */
288 if (regmap_read(mt6397->regmap, MT6397_CID, &reg_value) < 0) {
289 dev_err(&pdev->dev, "Failed to read Chip ID\n");
290 return -EIO;
291 }
292 dev_info(&pdev->dev, "Chip ID = 0x%x\n", reg_value);
293
294 version = (reg_value & 0xFF);
295 switch (version) {
296 case MT6397_REGULATOR_ID91:
297 mt6397_regulators[MT6397_ID_VGP2].desc.volt_table =
298 ldo_volt_table5_v2;
299 break;
300 default:
301 break;
302 }
303
304 for (i = 0; i < MT6397_MAX_REGULATOR; i++) {
305 config.dev = &pdev->dev;
306 config.driver_data = &mt6397_regulators[i];
307 config.regmap = mt6397->regmap;
308 rdev = devm_regulator_register(&pdev->dev,
309 &mt6397_regulators[i].desc, &config);
310 if (IS_ERR(rdev)) {
311 dev_err(&pdev->dev, "failed to register %s\n",
312 mt6397_regulators[i].desc.name);
313 return PTR_ERR(rdev);
314 }
315 }
316
317 return 0;
318}
319
320static struct platform_driver mt6397_regulator_driver = {
321 .driver = {
322 .name = "mt6397-regulator",
323 },
324 .probe = mt6397_regulator_probe,
325};
326
327module_platform_driver(mt6397_regulator_driver);
328
329MODULE_AUTHOR("Flora Fu <flora.fu@mediatek.com>");
330MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6397 PMIC");
331MODULE_LICENSE("GPL");
332MODULE_ALIAS("platform:mt6397-regulator");
diff --git a/include/linux/regulator/mt6397-regulator.h b/include/linux/regulator/mt6397-regulator.h
new file mode 100644
index 000000000000..30cc5963e265
--- /dev/null
+++ b/include/linux/regulator/mt6397-regulator.h
@@ -0,0 +1,49 @@
1/*
2 * Copyright (c) 2014 MediaTek Inc.
3 * Author: Flora Fu <flora.fu@mediatek.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#ifndef __LINUX_REGULATOR_MT6397_H
16#define __LINUX_REGULATOR_MT6397_H
17
18enum {
19 MT6397_ID_VPCA15 = 0,
20 MT6397_ID_VPCA7,
21 MT6397_ID_VSRAMCA15,
22 MT6397_ID_VSRAMCA7,
23 MT6397_ID_VCORE,
24 MT6397_ID_VGPU,
25 MT6397_ID_VDRM,
26 MT6397_ID_VIO18 = 7,
27 MT6397_ID_VTCXO,
28 MT6397_ID_VA28,
29 MT6397_ID_VCAMA,
30 MT6397_ID_VIO28,
31 MT6397_ID_VUSB,
32 MT6397_ID_VMC,
33 MT6397_ID_VMCH,
34 MT6397_ID_VEMC3V3,
35 MT6397_ID_VGP1,
36 MT6397_ID_VGP2,
37 MT6397_ID_VGP3,
38 MT6397_ID_VGP4,
39 MT6397_ID_VGP5,
40 MT6397_ID_VGP6,
41 MT6397_ID_VIBR,
42 MT6397_ID_RG_MAX,
43};
44
45#define MT6397_MAX_REGULATOR MT6397_ID_RG_MAX
46#define MT6397_REGULATOR_ID97 0x97
47#define MT6397_REGULATOR_ID91 0x91
48
49#endif /* __LINUX_REGULATOR_MT6397_H */