blob: cf4e2858443da2771e287ce5088fc488c13fec1b [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>
Simon Glass0f2af882020-05-10 11:40:05 -060010#include <log.h>
Simon Glassdbd79542020-05-10 11:40:11 -060011#include <linux/delay.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070012#include <linux/err.h>
Simon Glassbdd5f812023-09-14 18:21:46 -060013#include <linux/printk.h>
Jean-Jacques Hiblot4612bdd2017-09-21 17:03:10 +020014#include <power/pmic.h>
15#include <power/regulator.h>
16#include <regmap.h>
17#include <syscon.h>
18#include <linux/bitops.h>
19#include <linux/ioport.h>
Simon Glass95588622020-12-22 19:30:28 -070020#include <dm/device-internal.h>
Jean-Jacques Hiblot4612bdd2017-09-21 17:03:10 +020021#include <dm/read.h>
Adam Ford73d55e52019-01-24 14:33:36 -060022#ifdef CONFIG_MMC_OMAP36XX_PINS
23#include <asm/arch/sys_proto.h>
24#include <asm/io.h>
25#include <asm/arch/mux.h>
26#endif
Jean-Jacques Hiblot4612bdd2017-09-21 17:03:10 +020027
Jean-Jacques Hiblot4612bdd2017-09-21 17:03:10 +020028struct pbias_reg_info {
29 u32 enable;
30 u32 enable_mask;
31 u32 disable_val;
32 u32 vmode;
33 unsigned int enable_time;
34 char *name;
35};
36
37struct pbias_priv {
38 struct regmap *regmap;
39 int offset;
40};
41
42static const struct pmic_child_info pmic_children_info[] = {
43 { .prefix = "pbias", .driver = "pbias_regulator"},
44 { },
45};
46
47static int pbias_write(struct udevice *dev, uint reg, const uint8_t *buff,
48 int len)
49{
50 struct pbias_priv *priv = dev_get_priv(dev);
51 u32 val = *(u32 *)buff;
52
53 if (len != 4)
54 return -EINVAL;
55
56 return regmap_write(priv->regmap, priv->offset, val);
57}
58
59static int pbias_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
60{
61 struct pbias_priv *priv = dev_get_priv(dev);
62
63 if (len != 4)
64 return -EINVAL;
65
66 return regmap_read(priv->regmap, priv->offset, (u32 *)buff);
67}
68
Simon Glassaad29ae2020-12-03 16:55:21 -070069static int pbias_of_to_plat(struct udevice *dev)
Jean-Jacques Hiblot4612bdd2017-09-21 17:03:10 +020070{
71 struct pbias_priv *priv = dev_get_priv(dev);
72 struct udevice *syscon;
73 struct regmap *regmap;
74 struct resource res;
75 int err;
76
77 err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
78 "syscon", &syscon);
79 if (err) {
Masahiro Yamada81e10422017-09-16 14:10:41 +090080 pr_err("%s: unable to find syscon device (%d)\n", __func__,
Jean-Jacques Hiblot4612bdd2017-09-21 17:03:10 +020081 err);
82 return err;
83 }
84
85 regmap = syscon_get_regmap(syscon);
86 if (IS_ERR(regmap)) {
Masahiro Yamada81e10422017-09-16 14:10:41 +090087 pr_err("%s: unable to find regmap (%ld)\n", __func__,
Jean-Jacques Hiblot4612bdd2017-09-21 17:03:10 +020088 PTR_ERR(regmap));
89 return PTR_ERR(regmap);
90 }
91 priv->regmap = regmap;
92
93 err = dev_read_resource(dev, 0, &res);
94 if (err) {
Masahiro Yamada81e10422017-09-16 14:10:41 +090095 pr_err("%s: unable to find offset (%d)\n", __func__, err);
Jean-Jacques Hiblot4612bdd2017-09-21 17:03:10 +020096 return err;
97 }
98 priv->offset = res.start;
99
100 return 0;
101}
102
103static int pbias_bind(struct udevice *dev)
104{
105 int children;
106
Simon Glassa7ece582020-12-19 10:40:14 -0700107 children = pmic_bind_children(dev, dev_ofnode(dev),
108 pmic_children_info);
Jean-Jacques Hiblot4612bdd2017-09-21 17:03:10 +0200109 if (!children)
110 debug("%s: %s - no child found\n", __func__, dev->name);
111
112 return 0;
113}
114
115static struct dm_pmic_ops pbias_ops = {
116 .read = pbias_read,
117 .write = pbias_write,
118};
119
120static const struct udevice_id pbias_ids[] = {
121 { .compatible = "ti,pbias-dra7" },
Adam Fordb40404e2018-08-19 20:54:00 -0500122 { .compatible = "ti,pbias-omap2" },
123 { .compatible = "ti,pbias-omap3" },
124 { .compatible = "ti,pbias-omap4" },
125 { .compatible = "ti,pbias-omap5" },
Jean-Jacques Hiblot4612bdd2017-09-21 17:03:10 +0200126 { }
127};
128
129U_BOOT_DRIVER(pbias_pmic) = {
130 .name = "pbias_pmic",
131 .id = UCLASS_PMIC,
132 .of_match = pbias_ids,
133 .bind = pbias_bind,
134 .ops = &pbias_ops,
Simon Glassaad29ae2020-12-03 16:55:21 -0700135 .of_to_plat = pbias_of_to_plat,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700136 .priv_auto = sizeof(struct pbias_priv),
Jean-Jacques Hiblot4612bdd2017-09-21 17:03:10 +0200137};
138
139static const struct pbias_reg_info pbias_mmc_omap2430 = {
140 .enable = BIT(1),
141 .enable_mask = BIT(1),
142 .vmode = BIT(0),
143 .disable_val = 0,
144 .enable_time = 100,
145 .name = "pbias_mmc_omap2430"
146};
147
148static const struct pbias_reg_info pbias_sim_omap3 = {
149 .enable = BIT(9),
150 .enable_mask = BIT(9),
151 .vmode = BIT(8),
152 .enable_time = 100,
153 .name = "pbias_sim_omap3"
154};
155
156static const struct pbias_reg_info pbias_mmc_omap4 = {
157 .enable = BIT(26) | BIT(22),
158 .enable_mask = BIT(26) | BIT(25) | BIT(22),
159 .disable_val = BIT(25),
160 .vmode = BIT(21),
161 .enable_time = 100,
162 .name = "pbias_mmc_omap4"
163};
164
165static const struct pbias_reg_info pbias_mmc_omap5 = {
166 .enable = BIT(27) | BIT(26),
167 .enable_mask = BIT(27) | BIT(25) | BIT(26),
168 .disable_val = BIT(25),
169 .vmode = BIT(21),
170 .enable_time = 100,
171 .name = "pbias_mmc_omap5"
172};
173
174static const struct pbias_reg_info *pbias_reg_infos[] = {
175 &pbias_mmc_omap5,
176 &pbias_mmc_omap4,
177 &pbias_sim_omap3,
178 &pbias_mmc_omap2430,
179 NULL
180};
181
182static int pbias_regulator_probe(struct udevice *dev)
183{
184 const struct pbias_reg_info **p = pbias_reg_infos;
Simon Glass71fa5b42020-12-03 16:55:18 -0700185 struct dm_regulator_uclass_plat *uc_pdata;
Jean-Jacques Hiblot4612bdd2017-09-21 17:03:10 +0200186
Simon Glass71fa5b42020-12-03 16:55:18 -0700187 uc_pdata = dev_get_uclass_plat(dev);
Jean-Jacques Hiblot4612bdd2017-09-21 17:03:10 +0200188
189 while (*p) {
190 int rc;
191
192 rc = dev_read_stringlist_search(dev, "regulator-name",
193 (*p)->name);
194 if (rc >= 0) {
195 debug("found regulator %s\n", (*p)->name);
196 break;
197 } else if (rc != -ENODATA) {
198 return rc;
199 }
200 p++;
201 }
202 if (!*p) {
203 int i = 0;
204 const char *s;
205
206 debug("regulator ");
207 while (dev_read_string_index(dev, "regulator-name", i++, &s) >= 0)
208 debug("%s'%s' ", (i > 1) ? ", " : "", s);
209 debug("%s not supported\n", (i > 2) ? "are" : "is");
210 return -EINVAL;
211 }
212
213 uc_pdata->type = REGULATOR_TYPE_OTHER;
Simon Glass95588622020-12-22 19:30:28 -0700214 dev_set_priv(dev, (void *)*p);
Jean-Jacques Hiblot4612bdd2017-09-21 17:03:10 +0200215
216 return 0;
217}
218
219static int pbias_regulator_get_value(struct udevice *dev)
220{
221 const struct pbias_reg_info *p = dev_get_priv(dev);
222 int rc;
223 u32 reg;
224
225 rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
226 if (rc)
227 return rc;
228
229 debug("%s voltage id %s\n", p->name,
230 (reg & p->vmode) ? "3.0v" : "1.8v");
231 return (reg & p->vmode) ? 3000000 : 1800000;
232}
233
234static int pbias_regulator_set_value(struct udevice *dev, int uV)
235{
236 const struct pbias_reg_info *p = dev_get_priv(dev);
Adam Ford73d55e52019-01-24 14:33:36 -0600237 int rc, ret;
Jean-Jacques Hiblot4612bdd2017-09-21 17:03:10 +0200238 u32 reg;
Adam Ford73d55e52019-01-24 14:33:36 -0600239#ifdef CONFIG_MMC_OMAP36XX_PINS
240 u32 wkup_ctrl = readl(OMAP34XX_CTRL_WKUP_CTRL);
241#endif
Jean-Jacques Hiblot4612bdd2017-09-21 17:03:10 +0200242
Jean-Jacques Hiblot4612bdd2017-09-21 17:03:10 +0200243 rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
244 if (rc)
245 return rc;
246
Faiz Abbas0b9f5d82019-04-05 14:18:44 +0530247 if (uV == 3300000)
Jean-Jacques Hiblot4612bdd2017-09-21 17:03:10 +0200248 reg |= p->vmode;
249 else if (uV == 1800000)
250 reg &= ~p->vmode;
251 else
252 return -EINVAL;
253
Heinrich Schuchardtdfe81982018-03-18 12:01:06 +0100254 debug("Setting %s voltage to %s\n", p->name,
255 (reg & p->vmode) ? "3.0v" : "1.8v");
256
Adam Ford73d55e52019-01-24 14:33:36 -0600257#ifdef CONFIG_MMC_OMAP36XX_PINS
258 if (get_cpu_family() == CPU_OMAP36XX) {
259 /* Disable extended drain IO before changing PBIAS */
260 wkup_ctrl &= ~OMAP34XX_CTRL_WKUP_CTRL_GPIO_IO_PWRDNZ;
261 writel(wkup_ctrl, OMAP34XX_CTRL_WKUP_CTRL);
262 }
263#endif
264 ret = pmic_write(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
265#ifdef CONFIG_MMC_OMAP36XX_PINS
266 if (get_cpu_family() == CPU_OMAP36XX) {
267 /* Enable extended drain IO after changing PBIAS */
268 writel(wkup_ctrl |
269 OMAP34XX_CTRL_WKUP_CTRL_GPIO_IO_PWRDNZ,
270 OMAP34XX_CTRL_WKUP_CTRL);
271 }
272#endif
273 return ret;
Jean-Jacques Hiblot4612bdd2017-09-21 17:03:10 +0200274}
275
276static int pbias_regulator_get_enable(struct udevice *dev)
277{
278 const struct pbias_reg_info *p = dev_get_priv(dev);
279 int rc;
280 u32 reg;
281
282 rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
283 if (rc)
284 return rc;
285
286 debug("%s id %s\n", p->name,
287 (reg & p->enable_mask) == (p->disable_val) ? "on" : "off");
288
289 return (reg & p->enable_mask) == (p->disable_val);
290}
291
292static int pbias_regulator_set_enable(struct udevice *dev, bool enable)
293{
294 const struct pbias_reg_info *p = dev_get_priv(dev);
295 int rc;
296 u32 reg;
Adam Ford73d55e52019-01-24 14:33:36 -0600297#ifdef CONFIG_MMC_OMAP36XX_PINS
298 u32 wkup_ctrl = readl(OMAP34XX_CTRL_WKUP_CTRL);
299#endif
Jean-Jacques Hiblot4612bdd2017-09-21 17:03:10 +0200300
301 debug("Turning %s %s\n", enable ? "on" : "off", p->name);
302
Adam Ford73d55e52019-01-24 14:33:36 -0600303#ifdef CONFIG_MMC_OMAP36XX_PINS
304 if (get_cpu_family() == CPU_OMAP36XX) {
305 /* Disable extended drain IO before changing PBIAS */
306 wkup_ctrl &= ~OMAP34XX_CTRL_WKUP_CTRL_GPIO_IO_PWRDNZ;
307 writel(wkup_ctrl, OMAP34XX_CTRL_WKUP_CTRL);
308 }
309#endif
310
Jean-Jacques Hiblot4612bdd2017-09-21 17:03:10 +0200311 rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
312 if (rc)
313 return rc;
314
315 reg &= ~p->enable_mask;
316 if (enable)
317 reg |= p->enable;
318 else
319 reg |= p->disable_val;
320
321 rc = pmic_write(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
Adam Ford73d55e52019-01-24 14:33:36 -0600322
323#ifdef CONFIG_MMC_OMAP36XX_PINS
324 if (get_cpu_family() == CPU_OMAP36XX) {
325 /* Enable extended drain IO after changing PBIAS */
326 writel(wkup_ctrl |
327 OMAP34XX_CTRL_WKUP_CTRL_GPIO_IO_PWRDNZ,
328 OMAP34XX_CTRL_WKUP_CTRL);
329 }
330#endif
331
Jean-Jacques Hiblot4612bdd2017-09-21 17:03:10 +0200332 if (rc)
333 return rc;
334
335 if (enable)
336 udelay(p->enable_time);
337
338 return 0;
339}
340
341static const struct dm_regulator_ops pbias_regulator_ops = {
342 .get_value = pbias_regulator_get_value,
343 .set_value = pbias_regulator_set_value,
344 .get_enable = pbias_regulator_get_enable,
345 .set_enable = pbias_regulator_set_enable,
346};
347
348U_BOOT_DRIVER(pbias_regulator) = {
349 .name = "pbias_regulator",
350 .id = UCLASS_REGULATOR,
351 .ops = &pbias_regulator_ops,
352 .probe = pbias_regulator_probe,
353};