blob: af6ea4396466f9ad3dbf70e2add13332a2427d41 [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 Glass0fd3d912020-12-22 19:30:28 -070012#include <dm/device-internal.h>
Simon Glasscd93d622020-05-10 11:40:13 -060013#include <linux/bitops.h>
Simon Glass61b29b82020-02-03 07:36:15 -070014#include <linux/err.h>
Patrick Delaunaye8b85e82018-04-26 16:45:18 +020015#include <power/pmic.h>
16#include <power/regulator.h>
17
18#define STM32MP_PWR_CR3 0xc
19#define STM32MP_PWR_CR3_USB33DEN BIT(24)
20#define STM32MP_PWR_CR3_USB33RDY BIT(26)
21#define STM32MP_PWR_CR3_REG18DEN BIT(28)
22#define STM32MP_PWR_CR3_REG18RDY BIT(29)
23#define STM32MP_PWR_CR3_REG11DEN BIT(30)
24#define STM32MP_PWR_CR3_REG11RDY BIT(31)
25
26struct stm32mp_pwr_reg_info {
27 u32 enable;
28 u32 ready;
29 char *name;
30};
31
32struct stm32mp_pwr_priv {
Patrick Delaunay7915b992020-01-28 10:10:59 +010033 fdt_addr_t base;
Patrick Delaunaye8b85e82018-04-26 16:45:18 +020034};
35
36static int stm32mp_pwr_write(struct udevice *dev, uint reg,
37 const uint8_t *buff, int len)
38{
39 struct stm32mp_pwr_priv *priv = dev_get_priv(dev);
40 u32 val = *(u32 *)buff;
41
42 if (len != 4)
43 return -EINVAL;
44
Patrick Delaunay7915b992020-01-28 10:10:59 +010045 writel(val, priv->base + STM32MP_PWR_CR3);
46
47 return 0;
Patrick Delaunaye8b85e82018-04-26 16:45:18 +020048}
49
50static int stm32mp_pwr_read(struct udevice *dev, uint reg, uint8_t *buff,
51 int len)
52{
53 struct stm32mp_pwr_priv *priv = dev_get_priv(dev);
54
55 if (len != 4)
56 return -EINVAL;
57
Patrick Delaunay7915b992020-01-28 10:10:59 +010058 *(u32 *)buff = readl(priv->base + STM32MP_PWR_CR3);
59
60 return 0;
Patrick Delaunaye8b85e82018-04-26 16:45:18 +020061}
62
Simon Glassd1998a92020-12-03 16:55:21 -070063static int stm32mp_pwr_of_to_plat(struct udevice *dev)
Patrick Delaunaye8b85e82018-04-26 16:45:18 +020064{
65 struct stm32mp_pwr_priv *priv = dev_get_priv(dev);
Patrick Delaunaye8b85e82018-04-26 16:45:18 +020066
Patrick Delaunay7915b992020-01-28 10:10:59 +010067 priv->base = dev_read_addr(dev);
68 if (priv->base == FDT_ADDR_T_NONE)
69 return -EINVAL;
Patrick Delaunaye8b85e82018-04-26 16:45:18 +020070
71 return 0;
72}
73
74static const struct pmic_child_info pwr_children_info[] = {
75 { .prefix = "reg", .driver = "stm32mp_pwr_regulator"},
76 { .prefix = "usb", .driver = "stm32mp_pwr_regulator"},
77 { },
78};
79
80static int stm32mp_pwr_bind(struct udevice *dev)
81{
82 int children;
83
84 children = pmic_bind_children(dev, dev->node, pwr_children_info);
85 if (!children)
86 dev_dbg(dev, "no child found\n");
87
88 return 0;
89}
90
91static struct dm_pmic_ops stm32mp_pwr_ops = {
92 .read = stm32mp_pwr_read,
93 .write = stm32mp_pwr_write,
94};
95
96static const struct udevice_id stm32mp_pwr_ids[] = {
97 { .compatible = "st,stm32mp1,pwr-reg" },
98 { }
99};
100
101U_BOOT_DRIVER(stm32mp_pwr_pmic) = {
102 .name = "stm32mp_pwr_pmic",
103 .id = UCLASS_PMIC,
104 .of_match = stm32mp_pwr_ids,
105 .bind = stm32mp_pwr_bind,
106 .ops = &stm32mp_pwr_ops,
Simon Glassd1998a92020-12-03 16:55:21 -0700107 .of_to_plat = stm32mp_pwr_of_to_plat,
Simon Glass41575d82020-12-03 16:55:17 -0700108 .priv_auto = sizeof(struct stm32mp_pwr_priv),
Patrick Delaunaye8b85e82018-04-26 16:45:18 +0200109};
110
111static const struct stm32mp_pwr_reg_info stm32mp_pwr_reg11 = {
112 .enable = STM32MP_PWR_CR3_REG11DEN,
113 .ready = STM32MP_PWR_CR3_REG11RDY,
114 .name = "reg11"
115};
116
117static const struct stm32mp_pwr_reg_info stm32mp_pwr_reg18 = {
118 .enable = STM32MP_PWR_CR3_REG18DEN,
119 .ready = STM32MP_PWR_CR3_REG18RDY,
120 .name = "reg18"
121};
122
123static const struct stm32mp_pwr_reg_info stm32mp_pwr_usb33 = {
124 .enable = STM32MP_PWR_CR3_USB33DEN,
125 .ready = STM32MP_PWR_CR3_USB33RDY,
126 .name = "usb33"
127};
128
129static const struct stm32mp_pwr_reg_info *stm32mp_pwr_reg_infos[] = {
130 &stm32mp_pwr_reg11,
131 &stm32mp_pwr_reg18,
132 &stm32mp_pwr_usb33,
133 NULL
134};
135
136static int stm32mp_pwr_regulator_probe(struct udevice *dev)
137{
138 const struct stm32mp_pwr_reg_info **p = stm32mp_pwr_reg_infos;
Simon Glasscaa4daa2020-12-03 16:55:18 -0700139 struct dm_regulator_uclass_plat *uc_pdata;
Patrick Delaunaye8b85e82018-04-26 16:45:18 +0200140
Simon Glasscaa4daa2020-12-03 16:55:18 -0700141 uc_pdata = dev_get_uclass_plat(dev);
Patrick Delaunaye8b85e82018-04-26 16:45:18 +0200142
143 while (*p) {
144 int rc;
145
146 rc = dev_read_stringlist_search(dev, "regulator-name",
147 (*p)->name);
148 if (rc >= 0) {
149 dev_dbg(dev, "found regulator %s\n", (*p)->name);
150 break;
151 } else if (rc != -ENODATA) {
152 return rc;
153 }
154 p++;
155 }
156 if (!*p) {
157 int i = 0;
158 const char *s;
159
160 dev_dbg(dev, "regulator ");
161 while (dev_read_string_index(dev, "regulator-name",
162 i++, &s) >= 0)
163 dev_dbg(dev, "%s'%s' ", (i > 1) ? ", " : "", s);
164 dev_dbg(dev, "%s not supported\n", (i > 2) ? "are" : "is");
165 return -EINVAL;
166 }
167
168 uc_pdata->type = REGULATOR_TYPE_FIXED;
Simon Glass0fd3d912020-12-22 19:30:28 -0700169 dev_set_priv(dev, (void *)*p);
Patrick Delaunaye8b85e82018-04-26 16:45:18 +0200170
171 return 0;
172}
173
174static int stm32mp_pwr_regulator_set_value(struct udevice *dev, int uV)
175{
Simon Glasscaa4daa2020-12-03 16:55:18 -0700176 struct dm_regulator_uclass_plat *uc_pdata;
Patrick Delaunaye8b85e82018-04-26 16:45:18 +0200177
Simon Glasscaa4daa2020-12-03 16:55:18 -0700178 uc_pdata = dev_get_uclass_plat(dev);
Patrick Delaunaye8b85e82018-04-26 16:45:18 +0200179 if (!uc_pdata)
180 return -ENXIO;
181
182 if (uc_pdata->min_uV != uV) {
183 dev_dbg(dev, "Invalid uV=%d for: %s\n", uV, uc_pdata->name);
184 return -EINVAL;
185 }
186
187 return 0;
188}
189
190static int stm32mp_pwr_regulator_get_value(struct udevice *dev)
191{
Simon Glasscaa4daa2020-12-03 16:55:18 -0700192 struct dm_regulator_uclass_plat *uc_pdata;
Patrick Delaunaye8b85e82018-04-26 16:45:18 +0200193
Simon Glasscaa4daa2020-12-03 16:55:18 -0700194 uc_pdata = dev_get_uclass_plat(dev);
Patrick Delaunaye8b85e82018-04-26 16:45:18 +0200195 if (!uc_pdata)
196 return -ENXIO;
197
198 if (uc_pdata->min_uV != uc_pdata->max_uV) {
199 dev_dbg(dev, "Invalid constraints for: %s\n", uc_pdata->name);
200 return -EINVAL;
201 }
202
203 return uc_pdata->min_uV;
204}
205
206static int stm32mp_pwr_regulator_get_enable(struct udevice *dev)
207{
208 const struct stm32mp_pwr_reg_info *p = dev_get_priv(dev);
209 int rc;
210 u32 reg;
211
212 rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
213 if (rc)
214 return rc;
215
216 dev_dbg(dev, "%s id %s\n", p->name, (reg & p->enable) ? "on" : "off");
217
218 return (reg & p->enable) != 0;
219}
220
221static int stm32mp_pwr_regulator_set_enable(struct udevice *dev, bool enable)
222{
223 const struct stm32mp_pwr_reg_info *p = dev_get_priv(dev);
224 int rc;
225 u32 reg;
226 u32 time_start;
227
228 dev_dbg(dev, "Turning %s %s\n", enable ? "on" : "off", p->name);
229
230 rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
231 if (rc)
232 return rc;
233
234 /* if regulator is already in the wanted state, nothing to do */
235 if (!!(reg & p->enable) == enable)
236 return 0;
237
238 reg &= ~p->enable;
239 if (enable)
240 reg |= p->enable;
241
242 rc = pmic_write(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
243 if (rc)
244 return rc;
245
246 if (!enable)
247 return 0;
248
249 /* waiting ready for enable */
250 time_start = get_timer(0);
251 while (1) {
252 rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
253 if (rc)
254 return rc;
255 if (reg & p->ready)
256 break;
257 if (get_timer(time_start) > CONFIG_SYS_HZ) {
258 dev_dbg(dev, "%s: timeout\n", p->name);
259 return -ETIMEDOUT;
260 }
261 }
262 return 0;
263}
264
265static const struct dm_regulator_ops stm32mp_pwr_regulator_ops = {
266 .set_value = stm32mp_pwr_regulator_set_value,
267 .get_value = stm32mp_pwr_regulator_get_value,
268 .get_enable = stm32mp_pwr_regulator_get_enable,
269 .set_enable = stm32mp_pwr_regulator_set_enable,
270};
271
272U_BOOT_DRIVER(stm32mp_pwr_regulator) = {
273 .name = "stm32mp_pwr_regulator",
274 .id = UCLASS_REGULATOR,
275 .ops = &stm32mp_pwr_regulator_ops,
276 .probe = stm32mp_pwr_regulator_probe,
277};