blob: 366f97b38b72266dc297b1437615ef1202263f16 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Jean-Jacques Hiblot4612bdd2017-09-21 17:03:10 +02002/*
3 * (C) Copyright 2016 Texas Instruments Incorporated, <www.ti.com>
4 * Jean-Jacques Hiblot <jjhiblot@ti.com>
Jean-Jacques Hiblot4612bdd2017-09-21 17:03:10 +02005 */
6
7#include <common.h>
8#include <errno.h>
9#include <dm.h>
10#include <power/pmic.h>
11#include <power/regulator.h>
12#include <regmap.h>
13#include <syscon.h>
14#include <linux/bitops.h>
15#include <linux/ioport.h>
16#include <dm/read.h>
17
Jean-Jacques Hiblot4612bdd2017-09-21 17:03:10 +020018struct pbias_reg_info {
19 u32 enable;
20 u32 enable_mask;
21 u32 disable_val;
22 u32 vmode;
23 unsigned int enable_time;
24 char *name;
25};
26
27struct pbias_priv {
28 struct regmap *regmap;
29 int offset;
30};
31
32static const struct pmic_child_info pmic_children_info[] = {
33 { .prefix = "pbias", .driver = "pbias_regulator"},
34 { },
35};
36
37static int pbias_write(struct udevice *dev, uint reg, const uint8_t *buff,
38 int len)
39{
40 struct pbias_priv *priv = dev_get_priv(dev);
41 u32 val = *(u32 *)buff;
42
43 if (len != 4)
44 return -EINVAL;
45
46 return regmap_write(priv->regmap, priv->offset, val);
47}
48
49static int pbias_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
50{
51 struct pbias_priv *priv = dev_get_priv(dev);
52
53 if (len != 4)
54 return -EINVAL;
55
56 return regmap_read(priv->regmap, priv->offset, (u32 *)buff);
57}
58
59static int pbias_ofdata_to_platdata(struct udevice *dev)
60{
61 struct pbias_priv *priv = dev_get_priv(dev);
62 struct udevice *syscon;
63 struct regmap *regmap;
64 struct resource res;
65 int err;
66
67 err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
68 "syscon", &syscon);
69 if (err) {
Masahiro Yamada81e10422017-09-16 14:10:41 +090070 pr_err("%s: unable to find syscon device (%d)\n", __func__,
Jean-Jacques Hiblot4612bdd2017-09-21 17:03:10 +020071 err);
72 return err;
73 }
74
75 regmap = syscon_get_regmap(syscon);
76 if (IS_ERR(regmap)) {
Masahiro Yamada81e10422017-09-16 14:10:41 +090077 pr_err("%s: unable to find regmap (%ld)\n", __func__,
Jean-Jacques Hiblot4612bdd2017-09-21 17:03:10 +020078 PTR_ERR(regmap));
79 return PTR_ERR(regmap);
80 }
81 priv->regmap = regmap;
82
83 err = dev_read_resource(dev, 0, &res);
84 if (err) {
Masahiro Yamada81e10422017-09-16 14:10:41 +090085 pr_err("%s: unable to find offset (%d)\n", __func__, err);
Jean-Jacques Hiblot4612bdd2017-09-21 17:03:10 +020086 return err;
87 }
88 priv->offset = res.start;
89
90 return 0;
91}
92
93static int pbias_bind(struct udevice *dev)
94{
95 int children;
96
97 children = pmic_bind_children(dev, dev->node, pmic_children_info);
98 if (!children)
99 debug("%s: %s - no child found\n", __func__, dev->name);
100
101 return 0;
102}
103
104static struct dm_pmic_ops pbias_ops = {
105 .read = pbias_read,
106 .write = pbias_write,
107};
108
109static const struct udevice_id pbias_ids[] = {
110 { .compatible = "ti,pbias-dra7" },
Adam Fordb40404e2018-08-19 20:54:00 -0500111 { .compatible = "ti,pbias-omap2" },
112 { .compatible = "ti,pbias-omap3" },
113 { .compatible = "ti,pbias-omap4" },
114 { .compatible = "ti,pbias-omap5" },
Jean-Jacques Hiblot4612bdd2017-09-21 17:03:10 +0200115 { }
116};
117
118U_BOOT_DRIVER(pbias_pmic) = {
119 .name = "pbias_pmic",
120 .id = UCLASS_PMIC,
121 .of_match = pbias_ids,
122 .bind = pbias_bind,
123 .ops = &pbias_ops,
124 .ofdata_to_platdata = pbias_ofdata_to_platdata,
125 .priv_auto_alloc_size = sizeof(struct pbias_priv),
126};
127
128static const struct pbias_reg_info pbias_mmc_omap2430 = {
129 .enable = BIT(1),
130 .enable_mask = BIT(1),
131 .vmode = BIT(0),
132 .disable_val = 0,
133 .enable_time = 100,
134 .name = "pbias_mmc_omap2430"
135};
136
137static const struct pbias_reg_info pbias_sim_omap3 = {
138 .enable = BIT(9),
139 .enable_mask = BIT(9),
140 .vmode = BIT(8),
141 .enable_time = 100,
142 .name = "pbias_sim_omap3"
143};
144
145static const struct pbias_reg_info pbias_mmc_omap4 = {
146 .enable = BIT(26) | BIT(22),
147 .enable_mask = BIT(26) | BIT(25) | BIT(22),
148 .disable_val = BIT(25),
149 .vmode = BIT(21),
150 .enable_time = 100,
151 .name = "pbias_mmc_omap4"
152};
153
154static const struct pbias_reg_info pbias_mmc_omap5 = {
155 .enable = BIT(27) | BIT(26),
156 .enable_mask = BIT(27) | BIT(25) | BIT(26),
157 .disable_val = BIT(25),
158 .vmode = BIT(21),
159 .enable_time = 100,
160 .name = "pbias_mmc_omap5"
161};
162
163static const struct pbias_reg_info *pbias_reg_infos[] = {
164 &pbias_mmc_omap5,
165 &pbias_mmc_omap4,
166 &pbias_sim_omap3,
167 &pbias_mmc_omap2430,
168 NULL
169};
170
171static int pbias_regulator_probe(struct udevice *dev)
172{
173 const struct pbias_reg_info **p = pbias_reg_infos;
174 struct dm_regulator_uclass_platdata *uc_pdata;
175
176 uc_pdata = dev_get_uclass_platdata(dev);
177
178 while (*p) {
179 int rc;
180
181 rc = dev_read_stringlist_search(dev, "regulator-name",
182 (*p)->name);
183 if (rc >= 0) {
184 debug("found regulator %s\n", (*p)->name);
185 break;
186 } else if (rc != -ENODATA) {
187 return rc;
188 }
189 p++;
190 }
191 if (!*p) {
192 int i = 0;
193 const char *s;
194
195 debug("regulator ");
196 while (dev_read_string_index(dev, "regulator-name", i++, &s) >= 0)
197 debug("%s'%s' ", (i > 1) ? ", " : "", s);
198 debug("%s not supported\n", (i > 2) ? "are" : "is");
199 return -EINVAL;
200 }
201
202 uc_pdata->type = REGULATOR_TYPE_OTHER;
203 dev->priv = (void *)*p;
204
205 return 0;
206}
207
208static int pbias_regulator_get_value(struct udevice *dev)
209{
210 const struct pbias_reg_info *p = dev_get_priv(dev);
211 int rc;
212 u32 reg;
213
214 rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
215 if (rc)
216 return rc;
217
218 debug("%s voltage id %s\n", p->name,
219 (reg & p->vmode) ? "3.0v" : "1.8v");
220 return (reg & p->vmode) ? 3000000 : 1800000;
221}
222
223static int pbias_regulator_set_value(struct udevice *dev, int uV)
224{
225 const struct pbias_reg_info *p = dev_get_priv(dev);
226 int rc;
227 u32 reg;
228
Jean-Jacques Hiblot4612bdd2017-09-21 17:03:10 +0200229 rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
230 if (rc)
231 return rc;
232
233 if (uV == 3000000)
234 reg |= p->vmode;
235 else if (uV == 1800000)
236 reg &= ~p->vmode;
237 else
238 return -EINVAL;
239
Heinrich Schuchardtdfe81982018-03-18 12:01:06 +0100240 debug("Setting %s voltage to %s\n", p->name,
241 (reg & p->vmode) ? "3.0v" : "1.8v");
242
Jean-Jacques Hiblot4612bdd2017-09-21 17:03:10 +0200243 return pmic_write(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
244}
245
246static int pbias_regulator_get_enable(struct udevice *dev)
247{
248 const struct pbias_reg_info *p = dev_get_priv(dev);
249 int rc;
250 u32 reg;
251
252 rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
253 if (rc)
254 return rc;
255
256 debug("%s id %s\n", p->name,
257 (reg & p->enable_mask) == (p->disable_val) ? "on" : "off");
258
259 return (reg & p->enable_mask) == (p->disable_val);
260}
261
262static int pbias_regulator_set_enable(struct udevice *dev, bool enable)
263{
264 const struct pbias_reg_info *p = dev_get_priv(dev);
265 int rc;
266 u32 reg;
267
268 debug("Turning %s %s\n", enable ? "on" : "off", p->name);
269
270 rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
271 if (rc)
272 return rc;
273
274 reg &= ~p->enable_mask;
275 if (enable)
276 reg |= p->enable;
277 else
278 reg |= p->disable_val;
279
280 rc = pmic_write(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
281 if (rc)
282 return rc;
283
284 if (enable)
285 udelay(p->enable_time);
286
287 return 0;
288}
289
290static const struct dm_regulator_ops pbias_regulator_ops = {
291 .get_value = pbias_regulator_get_value,
292 .set_value = pbias_regulator_set_value,
293 .get_enable = pbias_regulator_get_enable,
294 .set_enable = pbias_regulator_set_enable,
295};
296
297U_BOOT_DRIVER(pbias_regulator) = {
298 .name = "pbias_regulator",
299 .id = UCLASS_REGULATOR,
300 .ops = &pbias_regulator_ops,
301 .probe = pbias_regulator_probe,
302};