blob: 74a5df5948719674c986e36db458fca52e9ecfcb [file] [log] [blame]
Patrick Delaunaye8b85e82018-04-26 16:45:18 +02001// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
2/*
3 * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
4 */
5
6#include <common.h>
7#include <dm.h>
8#include <errno.h>
Patrick Delaunaye8b85e82018-04-26 16:45:18 +02009#include <syscon.h>
Patrick Delaunay7915b992020-01-28 10:10:59 +010010#include <asm/io.h>
Simon Glass336d4612020-02-03 07:36:16 -070011#include <dm/device_compat.h>
Simon Glasscd93d622020-05-10 11:40:13 -060012#include <linux/bitops.h>
Simon Glass61b29b82020-02-03 07:36:15 -070013#include <linux/err.h>
Patrick Delaunaye8b85e82018-04-26 16:45:18 +020014#include <power/pmic.h>
15#include <power/regulator.h>
16
17#define STM32MP_PWR_CR3 0xc
18#define STM32MP_PWR_CR3_USB33DEN BIT(24)
19#define STM32MP_PWR_CR3_USB33RDY BIT(26)
20#define STM32MP_PWR_CR3_REG18DEN BIT(28)
21#define STM32MP_PWR_CR3_REG18RDY BIT(29)
22#define STM32MP_PWR_CR3_REG11DEN BIT(30)
23#define STM32MP_PWR_CR3_REG11RDY BIT(31)
24
25struct stm32mp_pwr_reg_info {
26 u32 enable;
27 u32 ready;
28 char *name;
29};
30
31struct stm32mp_pwr_priv {
Patrick Delaunay7915b992020-01-28 10:10:59 +010032 fdt_addr_t base;
Patrick Delaunaye8b85e82018-04-26 16:45:18 +020033};
34
35static int stm32mp_pwr_write(struct udevice *dev, uint reg,
36 const uint8_t *buff, int len)
37{
38 struct stm32mp_pwr_priv *priv = dev_get_priv(dev);
39 u32 val = *(u32 *)buff;
40
41 if (len != 4)
42 return -EINVAL;
43
Patrick Delaunay7915b992020-01-28 10:10:59 +010044 writel(val, priv->base + STM32MP_PWR_CR3);
45
46 return 0;
Patrick Delaunaye8b85e82018-04-26 16:45:18 +020047}
48
49static int stm32mp_pwr_read(struct udevice *dev, uint reg, uint8_t *buff,
50 int len)
51{
52 struct stm32mp_pwr_priv *priv = dev_get_priv(dev);
53
54 if (len != 4)
55 return -EINVAL;
56
Patrick Delaunay7915b992020-01-28 10:10:59 +010057 *(u32 *)buff = readl(priv->base + STM32MP_PWR_CR3);
58
59 return 0;
Patrick Delaunaye8b85e82018-04-26 16:45:18 +020060}
61
Simon Glassd1998a92020-12-03 16:55:21 -070062static int stm32mp_pwr_of_to_plat(struct udevice *dev)
Patrick Delaunaye8b85e82018-04-26 16:45:18 +020063{
64 struct stm32mp_pwr_priv *priv = dev_get_priv(dev);
Patrick Delaunaye8b85e82018-04-26 16:45:18 +020065
Patrick Delaunay7915b992020-01-28 10:10:59 +010066 priv->base = dev_read_addr(dev);
67 if (priv->base == FDT_ADDR_T_NONE)
68 return -EINVAL;
Patrick Delaunaye8b85e82018-04-26 16:45:18 +020069
70 return 0;
71}
72
73static const struct pmic_child_info pwr_children_info[] = {
74 { .prefix = "reg", .driver = "stm32mp_pwr_regulator"},
75 { .prefix = "usb", .driver = "stm32mp_pwr_regulator"},
76 { },
77};
78
79static int stm32mp_pwr_bind(struct udevice *dev)
80{
81 int children;
82
83 children = pmic_bind_children(dev, dev->node, pwr_children_info);
84 if (!children)
85 dev_dbg(dev, "no child found\n");
86
87 return 0;
88}
89
90static struct dm_pmic_ops stm32mp_pwr_ops = {
91 .read = stm32mp_pwr_read,
92 .write = stm32mp_pwr_write,
93};
94
95static const struct udevice_id stm32mp_pwr_ids[] = {
96 { .compatible = "st,stm32mp1,pwr-reg" },
97 { }
98};
99
100U_BOOT_DRIVER(stm32mp_pwr_pmic) = {
101 .name = "stm32mp_pwr_pmic",
102 .id = UCLASS_PMIC,
103 .of_match = stm32mp_pwr_ids,
104 .bind = stm32mp_pwr_bind,
105 .ops = &stm32mp_pwr_ops,
Simon Glassd1998a92020-12-03 16:55:21 -0700106 .of_to_plat = stm32mp_pwr_of_to_plat,
Simon Glass41575d82020-12-03 16:55:17 -0700107 .priv_auto = sizeof(struct stm32mp_pwr_priv),
Patrick Delaunaye8b85e82018-04-26 16:45:18 +0200108};
109
110static const struct stm32mp_pwr_reg_info stm32mp_pwr_reg11 = {
111 .enable = STM32MP_PWR_CR3_REG11DEN,
112 .ready = STM32MP_PWR_CR3_REG11RDY,
113 .name = "reg11"
114};
115
116static const struct stm32mp_pwr_reg_info stm32mp_pwr_reg18 = {
117 .enable = STM32MP_PWR_CR3_REG18DEN,
118 .ready = STM32MP_PWR_CR3_REG18RDY,
119 .name = "reg18"
120};
121
122static const struct stm32mp_pwr_reg_info stm32mp_pwr_usb33 = {
123 .enable = STM32MP_PWR_CR3_USB33DEN,
124 .ready = STM32MP_PWR_CR3_USB33RDY,
125 .name = "usb33"
126};
127
128static const struct stm32mp_pwr_reg_info *stm32mp_pwr_reg_infos[] = {
129 &stm32mp_pwr_reg11,
130 &stm32mp_pwr_reg18,
131 &stm32mp_pwr_usb33,
132 NULL
133};
134
135static int stm32mp_pwr_regulator_probe(struct udevice *dev)
136{
137 const struct stm32mp_pwr_reg_info **p = stm32mp_pwr_reg_infos;
Simon Glasscaa4daa2020-12-03 16:55:18 -0700138 struct dm_regulator_uclass_plat *uc_pdata;
Patrick Delaunaye8b85e82018-04-26 16:45:18 +0200139
Simon Glasscaa4daa2020-12-03 16:55:18 -0700140 uc_pdata = dev_get_uclass_plat(dev);
Patrick Delaunaye8b85e82018-04-26 16:45:18 +0200141
142 while (*p) {
143 int rc;
144
145 rc = dev_read_stringlist_search(dev, "regulator-name",
146 (*p)->name);
147 if (rc >= 0) {
148 dev_dbg(dev, "found regulator %s\n", (*p)->name);
149 break;
150 } else if (rc != -ENODATA) {
151 return rc;
152 }
153 p++;
154 }
155 if (!*p) {
156 int i = 0;
157 const char *s;
158
159 dev_dbg(dev, "regulator ");
160 while (dev_read_string_index(dev, "regulator-name",
161 i++, &s) >= 0)
162 dev_dbg(dev, "%s'%s' ", (i > 1) ? ", " : "", s);
163 dev_dbg(dev, "%s not supported\n", (i > 2) ? "are" : "is");
164 return -EINVAL;
165 }
166
167 uc_pdata->type = REGULATOR_TYPE_FIXED;
168 dev->priv = (void *)*p;
169
170 return 0;
171}
172
173static int stm32mp_pwr_regulator_set_value(struct udevice *dev, int uV)
174{
Simon Glasscaa4daa2020-12-03 16:55:18 -0700175 struct dm_regulator_uclass_plat *uc_pdata;
Patrick Delaunaye8b85e82018-04-26 16:45:18 +0200176
Simon Glasscaa4daa2020-12-03 16:55:18 -0700177 uc_pdata = dev_get_uclass_plat(dev);
Patrick Delaunaye8b85e82018-04-26 16:45:18 +0200178 if (!uc_pdata)
179 return -ENXIO;
180
181 if (uc_pdata->min_uV != uV) {
182 dev_dbg(dev, "Invalid uV=%d for: %s\n", uV, uc_pdata->name);
183 return -EINVAL;
184 }
185
186 return 0;
187}
188
189static int stm32mp_pwr_regulator_get_value(struct udevice *dev)
190{
Simon Glasscaa4daa2020-12-03 16:55:18 -0700191 struct dm_regulator_uclass_plat *uc_pdata;
Patrick Delaunaye8b85e82018-04-26 16:45:18 +0200192
Simon Glasscaa4daa2020-12-03 16:55:18 -0700193 uc_pdata = dev_get_uclass_plat(dev);
Patrick Delaunaye8b85e82018-04-26 16:45:18 +0200194 if (!uc_pdata)
195 return -ENXIO;
196
197 if (uc_pdata->min_uV != uc_pdata->max_uV) {
198 dev_dbg(dev, "Invalid constraints for: %s\n", uc_pdata->name);
199 return -EINVAL;
200 }
201
202 return uc_pdata->min_uV;
203}
204
205static int stm32mp_pwr_regulator_get_enable(struct udevice *dev)
206{
207 const struct stm32mp_pwr_reg_info *p = dev_get_priv(dev);
208 int rc;
209 u32 reg;
210
211 rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
212 if (rc)
213 return rc;
214
215 dev_dbg(dev, "%s id %s\n", p->name, (reg & p->enable) ? "on" : "off");
216
217 return (reg & p->enable) != 0;
218}
219
220static int stm32mp_pwr_regulator_set_enable(struct udevice *dev, bool enable)
221{
222 const struct stm32mp_pwr_reg_info *p = dev_get_priv(dev);
223 int rc;
224 u32 reg;
225 u32 time_start;
226
227 dev_dbg(dev, "Turning %s %s\n", enable ? "on" : "off", p->name);
228
229 rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
230 if (rc)
231 return rc;
232
233 /* if regulator is already in the wanted state, nothing to do */
234 if (!!(reg & p->enable) == enable)
235 return 0;
236
237 reg &= ~p->enable;
238 if (enable)
239 reg |= p->enable;
240
241 rc = pmic_write(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
242 if (rc)
243 return rc;
244
245 if (!enable)
246 return 0;
247
248 /* waiting ready for enable */
249 time_start = get_timer(0);
250 while (1) {
251 rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
252 if (rc)
253 return rc;
254 if (reg & p->ready)
255 break;
256 if (get_timer(time_start) > CONFIG_SYS_HZ) {
257 dev_dbg(dev, "%s: timeout\n", p->name);
258 return -ETIMEDOUT;
259 }
260 }
261 return 0;
262}
263
264static const struct dm_regulator_ops stm32mp_pwr_regulator_ops = {
265 .set_value = stm32mp_pwr_regulator_set_value,
266 .get_value = stm32mp_pwr_regulator_get_value,
267 .get_enable = stm32mp_pwr_regulator_get_enable,
268 .set_enable = stm32mp_pwr_regulator_set_enable,
269};
270
271U_BOOT_DRIVER(stm32mp_pwr_regulator) = {
272 .name = "stm32mp_pwr_regulator",
273 .id = UCLASS_REGULATOR,
274 .ops = &stm32mp_pwr_regulator_ops,
275 .probe = stm32mp_pwr_regulator_probe,
276};