sunxi: Allow booting from 128KB SD/eMMC offset
[oweals/u-boot.git] / drivers / power / regulator / pbias_regulator.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2016 Texas Instruments Incorporated, <www.ti.com>
4  * Jean-Jacques Hiblot <jjhiblot@ti.com>
5  */
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 #ifdef CONFIG_MMC_OMAP36XX_PINS
18 #include <asm/arch/sys_proto.h>
19 #include <asm/io.h>
20 #include <asm/arch/mux.h>
21 #endif
22
23 struct pbias_reg_info {
24         u32 enable;
25         u32 enable_mask;
26         u32 disable_val;
27         u32 vmode;
28         unsigned int enable_time;
29         char *name;
30 };
31
32 struct pbias_priv {
33         struct regmap *regmap;
34         int offset;
35 };
36
37 static const struct pmic_child_info pmic_children_info[] = {
38         { .prefix = "pbias", .driver = "pbias_regulator"},
39         { },
40 };
41
42 static int pbias_write(struct udevice *dev, uint reg, const uint8_t *buff,
43                        int len)
44 {
45         struct pbias_priv *priv = dev_get_priv(dev);
46         u32 val = *(u32 *)buff;
47
48         if (len != 4)
49                 return -EINVAL;
50
51         return regmap_write(priv->regmap, priv->offset, val);
52 }
53
54 static int pbias_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
55 {
56         struct pbias_priv *priv = dev_get_priv(dev);
57
58         if (len != 4)
59                 return -EINVAL;
60
61         return regmap_read(priv->regmap, priv->offset, (u32 *)buff);
62 }
63
64 static int pbias_ofdata_to_platdata(struct udevice *dev)
65 {
66         struct pbias_priv *priv = dev_get_priv(dev);
67         struct udevice *syscon;
68         struct regmap *regmap;
69         struct resource res;
70         int err;
71
72         err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
73                                            "syscon", &syscon);
74         if (err) {
75                 pr_err("%s: unable to find syscon device (%d)\n", __func__,
76                       err);
77                 return err;
78         }
79
80         regmap = syscon_get_regmap(syscon);
81         if (IS_ERR(regmap)) {
82                 pr_err("%s: unable to find regmap (%ld)\n", __func__,
83                       PTR_ERR(regmap));
84                 return PTR_ERR(regmap);
85         }
86         priv->regmap = regmap;
87
88         err = dev_read_resource(dev, 0, &res);
89         if (err) {
90                 pr_err("%s: unable to find offset (%d)\n", __func__, err);
91                 return err;
92         }
93         priv->offset = res.start;
94
95         return 0;
96 }
97
98 static int pbias_bind(struct udevice *dev)
99 {
100         int children;
101
102         children = pmic_bind_children(dev, dev->node, pmic_children_info);
103         if (!children)
104                 debug("%s: %s - no child found\n", __func__, dev->name);
105
106         return 0;
107 }
108
109 static struct dm_pmic_ops pbias_ops = {
110         .read = pbias_read,
111         .write = pbias_write,
112 };
113
114 static const struct udevice_id pbias_ids[] = {
115         { .compatible = "ti,pbias-dra7" },
116         { .compatible = "ti,pbias-omap2" },
117         { .compatible = "ti,pbias-omap3" },
118         { .compatible = "ti,pbias-omap4" },
119         { .compatible = "ti,pbias-omap5" },
120         { }
121 };
122
123 U_BOOT_DRIVER(pbias_pmic) = {
124         .name = "pbias_pmic",
125         .id = UCLASS_PMIC,
126         .of_match = pbias_ids,
127         .bind = pbias_bind,
128         .ops = &pbias_ops,
129         .ofdata_to_platdata = pbias_ofdata_to_platdata,
130         .priv_auto_alloc_size = sizeof(struct pbias_priv),
131 };
132
133 static const struct pbias_reg_info pbias_mmc_omap2430 = {
134         .enable = BIT(1),
135         .enable_mask = BIT(1),
136         .vmode = BIT(0),
137         .disable_val = 0,
138         .enable_time = 100,
139         .name = "pbias_mmc_omap2430"
140 };
141
142 static const struct pbias_reg_info pbias_sim_omap3 = {
143         .enable = BIT(9),
144         .enable_mask = BIT(9),
145         .vmode = BIT(8),
146         .enable_time = 100,
147         .name = "pbias_sim_omap3"
148 };
149
150 static const struct pbias_reg_info pbias_mmc_omap4 = {
151         .enable = BIT(26) | BIT(22),
152         .enable_mask = BIT(26) | BIT(25) | BIT(22),
153         .disable_val = BIT(25),
154         .vmode = BIT(21),
155         .enable_time = 100,
156         .name = "pbias_mmc_omap4"
157 };
158
159 static const struct pbias_reg_info pbias_mmc_omap5 = {
160         .enable = BIT(27) | BIT(26),
161         .enable_mask = BIT(27) | BIT(25) | BIT(26),
162         .disable_val = BIT(25),
163         .vmode = BIT(21),
164         .enable_time = 100,
165         .name = "pbias_mmc_omap5"
166 };
167
168 static const struct pbias_reg_info *pbias_reg_infos[] = {
169         &pbias_mmc_omap5,
170         &pbias_mmc_omap4,
171         &pbias_sim_omap3,
172         &pbias_mmc_omap2430,
173         NULL
174 };
175
176 static int pbias_regulator_probe(struct udevice *dev)
177 {
178         const struct pbias_reg_info **p = pbias_reg_infos;
179         struct dm_regulator_uclass_platdata *uc_pdata;
180
181         uc_pdata = dev_get_uclass_platdata(dev);
182
183         while (*p) {
184                 int rc;
185
186                 rc = dev_read_stringlist_search(dev, "regulator-name",
187                                                 (*p)->name);
188                 if (rc >= 0) {
189                         debug("found regulator %s\n", (*p)->name);
190                         break;
191                 } else if (rc != -ENODATA) {
192                         return rc;
193                 }
194                 p++;
195         }
196         if (!*p) {
197                 int i = 0;
198                 const char *s;
199
200                 debug("regulator ");
201                 while (dev_read_string_index(dev, "regulator-name", i++, &s) >= 0)
202                         debug("%s'%s' ", (i > 1) ? ", " : "", s);
203                 debug("%s not supported\n", (i > 2) ? "are" : "is");
204                 return -EINVAL;
205         }
206
207         uc_pdata->type = REGULATOR_TYPE_OTHER;
208         dev->priv = (void *)*p;
209
210         return 0;
211 }
212
213 static int pbias_regulator_get_value(struct udevice *dev)
214 {
215         const struct pbias_reg_info *p = dev_get_priv(dev);
216         int rc;
217         u32 reg;
218
219         rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
220         if (rc)
221                 return rc;
222
223         debug("%s voltage id %s\n", p->name,
224               (reg & p->vmode) ? "3.0v" : "1.8v");
225         return (reg & p->vmode) ? 3000000 : 1800000;
226 }
227
228 static int pbias_regulator_set_value(struct udevice *dev, int uV)
229 {
230         const struct pbias_reg_info *p = dev_get_priv(dev);
231         int rc, ret;
232         u32 reg;
233 #ifdef CONFIG_MMC_OMAP36XX_PINS
234         u32 wkup_ctrl = readl(OMAP34XX_CTRL_WKUP_CTRL);
235 #endif
236
237         rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
238         if (rc)
239                 return rc;
240
241         if (uV == 3000000)
242                 reg |= p->vmode;
243         else if (uV == 1800000)
244                 reg &= ~p->vmode;
245         else
246                 return -EINVAL;
247
248         debug("Setting %s voltage to %s\n", p->name,
249               (reg & p->vmode) ? "3.0v" : "1.8v");
250
251 #ifdef CONFIG_MMC_OMAP36XX_PINS
252         if (get_cpu_family() == CPU_OMAP36XX) {
253                 /* Disable extended drain IO before changing PBIAS */
254                 wkup_ctrl &= ~OMAP34XX_CTRL_WKUP_CTRL_GPIO_IO_PWRDNZ;
255                 writel(wkup_ctrl, OMAP34XX_CTRL_WKUP_CTRL);
256         }
257 #endif
258         ret = pmic_write(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
259 #ifdef CONFIG_MMC_OMAP36XX_PINS
260         if (get_cpu_family() == CPU_OMAP36XX) {
261                 /* Enable extended drain IO after changing PBIAS */
262                 writel(wkup_ctrl |
263                                 OMAP34XX_CTRL_WKUP_CTRL_GPIO_IO_PWRDNZ,
264                                 OMAP34XX_CTRL_WKUP_CTRL);
265         }
266 #endif
267         return ret;
268 }
269
270 static int pbias_regulator_get_enable(struct udevice *dev)
271 {
272         const struct pbias_reg_info *p = dev_get_priv(dev);
273         int rc;
274         u32 reg;
275
276         rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
277         if (rc)
278                 return rc;
279
280         debug("%s id %s\n", p->name,
281               (reg & p->enable_mask) == (p->disable_val) ? "on" : "off");
282
283         return (reg & p->enable_mask) == (p->disable_val);
284 }
285
286 static int pbias_regulator_set_enable(struct udevice *dev, bool enable)
287 {
288         const struct pbias_reg_info *p = dev_get_priv(dev);
289         int rc;
290         u32 reg;
291 #ifdef CONFIG_MMC_OMAP36XX_PINS
292         u32 wkup_ctrl = readl(OMAP34XX_CTRL_WKUP_CTRL);
293 #endif
294
295         debug("Turning %s %s\n", enable ? "on" : "off", p->name);
296
297 #ifdef CONFIG_MMC_OMAP36XX_PINS
298         if (get_cpu_family() == CPU_OMAP36XX) {
299                 /* Disable extended drain IO before changing PBIAS */
300                 wkup_ctrl &= ~OMAP34XX_CTRL_WKUP_CTRL_GPIO_IO_PWRDNZ;
301                 writel(wkup_ctrl, OMAP34XX_CTRL_WKUP_CTRL);
302         }
303 #endif
304
305         rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
306         if (rc)
307                 return rc;
308
309         reg &= ~p->enable_mask;
310         if (enable)
311                 reg |= p->enable;
312         else
313                 reg |= p->disable_val;
314
315         rc = pmic_write(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
316
317 #ifdef CONFIG_MMC_OMAP36XX_PINS
318         if (get_cpu_family() == CPU_OMAP36XX) {
319                 /* Enable extended drain IO after changing PBIAS */
320                 writel(wkup_ctrl |
321                                 OMAP34XX_CTRL_WKUP_CTRL_GPIO_IO_PWRDNZ,
322                                 OMAP34XX_CTRL_WKUP_CTRL);
323         }
324 #endif
325
326         if (rc)
327                 return rc;
328
329         if (enable)
330                 udelay(p->enable_time);
331
332         return 0;
333 }
334
335 static const struct dm_regulator_ops pbias_regulator_ops = {
336         .get_value  = pbias_regulator_get_value,
337         .set_value  = pbias_regulator_set_value,
338         .get_enable = pbias_regulator_get_enable,
339         .set_enable = pbias_regulator_set_enable,
340 };
341
342 U_BOOT_DRIVER(pbias_regulator) = {
343         .name = "pbias_regulator",
344         .id = UCLASS_REGULATOR,
345         .ops = &pbias_regulator_ops,
346         .probe = pbias_regulator_probe,
347 };