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