aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/regulator
diff options
context:
space:
mode:
authorBalaji T K <balajitk@ti.com>2014-02-19 09:56:40 -0500
committerChris Ball <chris@printf.net>2014-03-04 11:44:47 -0500
commit11469e0bb1c5eedd3b489a4b19dbd26c02577674 (patch)
tree62ead13af6af8dba9426277a2cfced9bc5b48d4f /drivers/regulator
parent987fd49b894ec964231dfc5b6bbb2bc12e2b56b5 (diff)
regulator: add pbias regulator support
pbias register controls internal power supply to sd card i/o pads in most OMAPs (OMAP2-5, DRA7). Control bits for selecting voltage level and enabling/disabling are in the same PBIAS register. Signed-off-by: Balaji T K <balajitk@ti.com> Acked-by: Tony Lindgren <tony@atomide.com> Acked-by: Mark Brown <broonie@linaro.org> Tested-by: Florian Vaussard <florian.vaussard@epfl.ch> Tested-by: Stefan Roese <sr@denx.de> Signed-off-by: Chris Ball <chris@printf.net>
Diffstat (limited to 'drivers/regulator')
-rw-r--r--drivers/regulator/Kconfig9
-rw-r--r--drivers/regulator/Makefile1
-rw-r--r--drivers/regulator/pbias-regulator.c255
3 files changed, 265 insertions, 0 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 6a7932822e37..58f08d1d24e8 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -384,6 +384,15 @@ config REGULATOR_PALMAS
384 on the muxing. This is handled automatically in the driver by 384 on the muxing. This is handled automatically in the driver by
385 reading the mux info from OTP. 385 reading the mux info from OTP.
386 386
387config REGULATOR_PBIAS
388 tristate "PBIAS OMAP regulator driver"
389 depends on (ARCH_OMAP || COMPILE_TEST) && MFD_SYSCON
390 help
391 Say y here to support pbias regulator for mmc1:SD card i/o
392 on OMAP SoCs.
393 This driver provides support for OMAP pbias modelled
394 regulators.
395
387config REGULATOR_PCAP 396config REGULATOR_PCAP
388 tristate "Motorola PCAP2 regulator driver" 397 tristate "Motorola PCAP2 regulator driver"
389 depends on EZX_PCAP 398 depends on EZX_PCAP
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 979f9ddcf259..001712ebbf25 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o
54obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o 54obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
55obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o 55obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
56obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o 56obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o
57obj-$(CONFIG_REGULATOR_PBIAS) += pbias-regulator.o
57obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o 58obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
58obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o 59obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
59obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o 60obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o
diff --git a/drivers/regulator/pbias-regulator.c b/drivers/regulator/pbias-regulator.c
new file mode 100644
index 000000000000..ded3b3574209
--- /dev/null
+++ b/drivers/regulator/pbias-regulator.c
@@ -0,0 +1,255 @@
1/*
2 * pbias-regulator.c
3 *
4 * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
5 * Author: Balaji T K <balajitk@ti.com>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation version 2.
10 *
11 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
12 * kind, whether express or implied; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#include <linux/err.h>
18#include <linux/io.h>
19#include <linux/module.h>
20#include <linux/mfd/syscon.h>
21#include <linux/platform_device.h>
22#include <linux/regulator/driver.h>
23#include <linux/regulator/machine.h>
24#include <linux/regulator/of_regulator.h>
25#include <linux/regmap.h>
26#include <linux/slab.h>
27#include <linux/of.h>
28#include <linux/of_device.h>
29
30struct pbias_reg_info {
31 u32 enable;
32 u32 enable_mask;
33 u32 vmode;
34 unsigned int enable_time;
35 char *name;
36};
37
38struct pbias_regulator_data {
39 struct regulator_desc desc;
40 void __iomem *pbias_addr;
41 unsigned int pbias_reg;
42 struct regulator_dev *dev;
43 struct regmap *syscon;
44 const struct pbias_reg_info *info;
45 int voltage;
46};
47
48static int pbias_regulator_set_voltage(struct regulator_dev *dev,
49 int min_uV, int max_uV, unsigned *selector)
50{
51 struct pbias_regulator_data *data = rdev_get_drvdata(dev);
52 const struct pbias_reg_info *info = data->info;
53 int ret, vmode;
54
55 if (min_uV <= 1800000)
56 vmode = 0;
57 else if (min_uV > 1800000)
58 vmode = info->vmode;
59
60 ret = regmap_update_bits(data->syscon, data->pbias_reg,
61 info->vmode, vmode);
62
63 return ret;
64}
65
66static int pbias_regulator_get_voltage(struct regulator_dev *rdev)
67{
68 struct pbias_regulator_data *data = rdev_get_drvdata(rdev);
69 const struct pbias_reg_info *info = data->info;
70 int value, voltage;
71
72 regmap_read(data->syscon, data->pbias_reg, &value);
73 value &= info->vmode;
74
75 voltage = value ? 3000000 : 1800000;
76
77 return voltage;
78}
79
80static int pbias_regulator_enable(struct regulator_dev *rdev)
81{
82 struct pbias_regulator_data *data = rdev_get_drvdata(rdev);
83 const struct pbias_reg_info *info = data->info;
84 int ret;
85
86 ret = regmap_update_bits(data->syscon, data->pbias_reg,
87 info->enable_mask, info->enable);
88
89 return ret;
90}
91
92static int pbias_regulator_disable(struct regulator_dev *rdev)
93{
94 struct pbias_regulator_data *data = rdev_get_drvdata(rdev);
95 const struct pbias_reg_info *info = data->info;
96 int ret;
97
98 ret = regmap_update_bits(data->syscon, data->pbias_reg,
99 info->enable_mask, 0);
100 return ret;
101}
102
103static int pbias_regulator_is_enable(struct regulator_dev *rdev)
104{
105 struct pbias_regulator_data *data = rdev_get_drvdata(rdev);
106 const struct pbias_reg_info *info = data->info;
107 int value;
108
109 regmap_read(data->syscon, data->pbias_reg, &value);
110
111 return (value & info->enable_mask) == info->enable_mask;
112}
113
114static struct regulator_ops pbias_regulator_voltage_ops = {
115 .set_voltage = pbias_regulator_set_voltage,
116 .get_voltage = pbias_regulator_get_voltage,
117 .enable = pbias_regulator_enable,
118 .disable = pbias_regulator_disable,
119 .is_enabled = pbias_regulator_is_enable,
120};
121
122static const struct pbias_reg_info pbias_mmc_omap2430 = {
123 .enable = BIT(1),
124 .enable_mask = BIT(1),
125 .vmode = BIT(0),
126 .enable_time = 100,
127 .name = "pbias_mmc_omap2430"
128};
129
130static const struct pbias_reg_info pbias_sim_omap3 = {
131 .enable = BIT(9),
132 .enable_mask = BIT(9),
133 .vmode = BIT(8),
134 .enable_time = 100,
135 .name = "pbias_sim_omap3"
136};
137
138static const struct pbias_reg_info pbias_mmc_omap4 = {
139 .enable = BIT(26) | BIT(22),
140 .enable_mask = BIT(26) | BIT(25) | BIT(22),
141 .vmode = BIT(21),
142 .enable_time = 100,
143 .name = "pbias_mmc_omap4"
144};
145
146static const struct pbias_reg_info pbias_mmc_omap5 = {
147 .enable = BIT(27) | BIT(26),
148 .enable_mask = BIT(27) | BIT(25) | BIT(26),
149 .vmode = BIT(21),
150 .enable_time = 100,
151 .name = "pbias_mmc_omap5"
152};
153
154static struct of_regulator_match pbias_matches[] = {
155 { .name = "pbias_mmc_omap2430", .driver_data = (void *)&pbias_mmc_omap2430},
156 { .name = "pbias_sim_omap3", .driver_data = (void *)&pbias_sim_omap3},
157 { .name = "pbias_mmc_omap4", .driver_data = (void *)&pbias_mmc_omap4},
158 { .name = "pbias_mmc_omap5", .driver_data = (void *)&pbias_mmc_omap5},
159};
160#define PBIAS_NUM_REGS ARRAY_SIZE(pbias_matches)
161
162static const struct of_device_id pbias_of_match[] = {
163 { .compatible = "ti,pbias-omap", },
164 {},
165};
166MODULE_DEVICE_TABLE(of, pbias_of_match);
167
168static int pbias_regulator_probe(struct platform_device *pdev)
169{
170 struct device_node *np = pdev->dev.of_node;
171 struct pbias_regulator_data *drvdata;
172 struct resource *res;
173 struct regulator_config cfg = { };
174 struct regmap *syscon;
175 const struct pbias_reg_info *info;
176 int ret = 0;
177 int count, idx, data_idx = 0;
178
179 count = of_regulator_match(&pdev->dev, np, pbias_matches,
180 PBIAS_NUM_REGS);
181 if (count < 0)
182 return count;
183
184 drvdata = devm_kzalloc(&pdev->dev, sizeof(struct pbias_regulator_data)
185 * count, GFP_KERNEL);
186 if (drvdata == NULL) {
187 dev_err(&pdev->dev, "Failed to allocate device data\n");
188 return -ENOMEM;
189 }
190
191 syscon = syscon_regmap_lookup_by_phandle(np, "syscon");
192 if (IS_ERR(syscon))
193 return PTR_ERR(syscon);
194
195 cfg.dev = &pdev->dev;
196
197 for (idx = 0; idx < PBIAS_NUM_REGS && data_idx < count; idx++) {
198 if (!pbias_matches[idx].init_data ||
199 !pbias_matches[idx].of_node)
200 continue;
201
202 info = pbias_matches[idx].driver_data;
203 if (!info)
204 return -ENODEV;
205
206 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
207 if (!res)
208 return -EINVAL;
209
210 drvdata[data_idx].pbias_reg = res->start;
211 drvdata[data_idx].syscon = syscon;
212 drvdata[data_idx].info = info;
213 drvdata[data_idx].desc.name = info->name;
214 drvdata[data_idx].desc.owner = THIS_MODULE;
215 drvdata[data_idx].desc.type = REGULATOR_VOLTAGE;
216 drvdata[data_idx].desc.ops = &pbias_regulator_voltage_ops;
217 drvdata[data_idx].desc.n_voltages = 2;
218 drvdata[data_idx].desc.enable_time = info->enable_time;
219
220 cfg.init_data = pbias_matches[idx].init_data;
221 cfg.driver_data = &drvdata[data_idx];
222 cfg.of_node = pbias_matches[idx].of_node;
223
224 drvdata[data_idx].dev = devm_regulator_register(&pdev->dev,
225 &drvdata[data_idx].desc, &cfg);
226 if (IS_ERR(drvdata[data_idx].dev)) {
227 ret = PTR_ERR(drvdata[data_idx].dev);
228 dev_err(&pdev->dev,
229 "Failed to register regulator: %d\n", ret);
230 goto err_regulator;
231 }
232 data_idx++;
233 }
234
235 platform_set_drvdata(pdev, drvdata);
236
237err_regulator:
238 return ret;
239}
240
241static struct platform_driver pbias_regulator_driver = {
242 .probe = pbias_regulator_probe,
243 .driver = {
244 .name = "pbias-regulator",
245 .owner = THIS_MODULE,
246 .of_match_table = of_match_ptr(pbias_of_match),
247 },
248};
249
250module_platform_driver(pbias_regulator_driver);
251
252MODULE_AUTHOR("Balaji T K <balajitk@ti.com>");
253MODULE_DESCRIPTION("pbias voltage regulator");
254MODULE_LICENSE("GPL");
255MODULE_ALIAS("platform:pbias-regulator");