]>
Commit | Line | Data |
---|---|---|
e8b85e81 PD |
1 | // 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> | |
e8b85e81 | 9 | #include <syscon.h> |
7915b991 | 10 | #include <asm/io.h> |
336d4615 | 11 | #include <dm/device_compat.h> |
cd93d625 | 12 | #include <linux/bitops.h> |
61b29b82 | 13 | #include <linux/err.h> |
e8b85e81 PD |
14 | #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 | ||
25 | struct stm32mp_pwr_reg_info { | |
26 | u32 enable; | |
27 | u32 ready; | |
28 | char *name; | |
29 | }; | |
30 | ||
31 | struct stm32mp_pwr_priv { | |
7915b991 | 32 | fdt_addr_t base; |
e8b85e81 PD |
33 | }; |
34 | ||
35 | static 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 | ||
7915b991 PD |
44 | writel(val, priv->base + STM32MP_PWR_CR3); |
45 | ||
46 | return 0; | |
e8b85e81 PD |
47 | } |
48 | ||
49 | static 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 | ||
7915b991 PD |
57 | *(u32 *)buff = readl(priv->base + STM32MP_PWR_CR3); |
58 | ||
59 | return 0; | |
e8b85e81 PD |
60 | } |
61 | ||
62 | static int stm32mp_pwr_ofdata_to_platdata(struct udevice *dev) | |
63 | { | |
64 | struct stm32mp_pwr_priv *priv = dev_get_priv(dev); | |
7915b991 PD |
65 | |
66 | priv->base = dev_read_addr(dev); | |
67 | if (priv->base == FDT_ADDR_T_NONE) | |
68 | return -EINVAL; | |
e8b85e81 PD |
69 | |
70 | return 0; | |
71 | } | |
72 | ||
73 | static 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 | ||
79 | static 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 | ||
90 | static struct dm_pmic_ops stm32mp_pwr_ops = { | |
91 | .read = stm32mp_pwr_read, | |
92 | .write = stm32mp_pwr_write, | |
93 | }; | |
94 | ||
95 | static const struct udevice_id stm32mp_pwr_ids[] = { | |
96 | { .compatible = "st,stm32mp1,pwr-reg" }, | |
97 | { } | |
98 | }; | |
99 | ||
100 | U_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, | |
106 | .ofdata_to_platdata = stm32mp_pwr_ofdata_to_platdata, | |
41575d8e | 107 | .priv_auto = sizeof(struct stm32mp_pwr_priv), |
e8b85e81 PD |
108 | }; |
109 | ||
110 | static 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 | ||
116 | static 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 | ||
122 | static 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 | ||
128 | static 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 | ||
135 | static int stm32mp_pwr_regulator_probe(struct udevice *dev) | |
136 | { | |
137 | const struct stm32mp_pwr_reg_info **p = stm32mp_pwr_reg_infos; | |
caa4daa2 | 138 | struct dm_regulator_uclass_plat *uc_pdata; |
e8b85e81 | 139 | |
caa4daa2 | 140 | uc_pdata = dev_get_uclass_plat(dev); |
e8b85e81 PD |
141 | |
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 | ||
173 | static int stm32mp_pwr_regulator_set_value(struct udevice *dev, int uV) | |
174 | { | |
caa4daa2 | 175 | struct dm_regulator_uclass_plat *uc_pdata; |
e8b85e81 | 176 | |
caa4daa2 | 177 | uc_pdata = dev_get_uclass_plat(dev); |
e8b85e81 PD |
178 | 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 | ||
189 | static int stm32mp_pwr_regulator_get_value(struct udevice *dev) | |
190 | { | |
caa4daa2 | 191 | struct dm_regulator_uclass_plat *uc_pdata; |
e8b85e81 | 192 | |
caa4daa2 | 193 | uc_pdata = dev_get_uclass_plat(dev); |
e8b85e81 PD |
194 | 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 | ||
205 | static 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 *)®, 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 | ||
220 | static 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 *)®, 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 *)®, 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 *)®, 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 | ||
264 | static 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 | ||
271 | U_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 | }; |