imx8: power: Add PD device lookup interface to power domain uclass
[oweals/u-boot.git] / arch / arm / mach-stm32mp / pwr_regulator.c
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>
9 #include <syscon.h>
10 #include <asm/io.h>
11 #include <dm/device_compat.h>
12 #include <linux/err.h>
13 #include <power/pmic.h>
14 #include <power/regulator.h>
15
16 #define STM32MP_PWR_CR3 0xc
17 #define STM32MP_PWR_CR3_USB33DEN BIT(24)
18 #define STM32MP_PWR_CR3_USB33RDY BIT(26)
19 #define STM32MP_PWR_CR3_REG18DEN BIT(28)
20 #define STM32MP_PWR_CR3_REG18RDY BIT(29)
21 #define STM32MP_PWR_CR3_REG11DEN BIT(30)
22 #define STM32MP_PWR_CR3_REG11RDY BIT(31)
23
24 struct stm32mp_pwr_reg_info {
25         u32 enable;
26         u32 ready;
27         char *name;
28 };
29
30 struct stm32mp_pwr_priv {
31         fdt_addr_t base;
32 };
33
34 static int stm32mp_pwr_write(struct udevice *dev, uint reg,
35                              const uint8_t *buff, int len)
36 {
37         struct stm32mp_pwr_priv *priv = dev_get_priv(dev);
38         u32 val = *(u32 *)buff;
39
40         if (len != 4)
41                 return -EINVAL;
42
43         writel(val, priv->base + STM32MP_PWR_CR3);
44
45         return 0;
46 }
47
48 static int stm32mp_pwr_read(struct udevice *dev, uint reg, uint8_t *buff,
49                             int len)
50 {
51         struct stm32mp_pwr_priv *priv = dev_get_priv(dev);
52
53         if (len != 4)
54                 return -EINVAL;
55
56         *(u32 *)buff = readl(priv->base + STM32MP_PWR_CR3);
57
58         return 0;
59 }
60
61 static int stm32mp_pwr_ofdata_to_platdata(struct udevice *dev)
62 {
63         struct stm32mp_pwr_priv *priv = dev_get_priv(dev);
64
65         priv->base = dev_read_addr(dev);
66         if (priv->base == FDT_ADDR_T_NONE)
67                 return -EINVAL;
68
69         return 0;
70 }
71
72 static const struct pmic_child_info pwr_children_info[] = {
73         { .prefix = "reg", .driver = "stm32mp_pwr_regulator"},
74         { .prefix = "usb", .driver = "stm32mp_pwr_regulator"},
75         { },
76 };
77
78 static int stm32mp_pwr_bind(struct udevice *dev)
79 {
80         int children;
81
82         children = pmic_bind_children(dev, dev->node, pwr_children_info);
83         if (!children)
84                 dev_dbg(dev, "no child found\n");
85
86         return 0;
87 }
88
89 static struct dm_pmic_ops stm32mp_pwr_ops = {
90         .read = stm32mp_pwr_read,
91         .write = stm32mp_pwr_write,
92 };
93
94 static const struct udevice_id stm32mp_pwr_ids[] = {
95         { .compatible = "st,stm32mp1,pwr-reg" },
96         { }
97 };
98
99 U_BOOT_DRIVER(stm32mp_pwr_pmic) = {
100         .name = "stm32mp_pwr_pmic",
101         .id = UCLASS_PMIC,
102         .of_match = stm32mp_pwr_ids,
103         .bind = stm32mp_pwr_bind,
104         .ops = &stm32mp_pwr_ops,
105         .ofdata_to_platdata = stm32mp_pwr_ofdata_to_platdata,
106         .priv_auto_alloc_size = sizeof(struct stm32mp_pwr_priv),
107 };
108
109 static const struct stm32mp_pwr_reg_info stm32mp_pwr_reg11 = {
110         .enable = STM32MP_PWR_CR3_REG11DEN,
111         .ready = STM32MP_PWR_CR3_REG11RDY,
112         .name = "reg11"
113 };
114
115 static const struct stm32mp_pwr_reg_info stm32mp_pwr_reg18 = {
116         .enable = STM32MP_PWR_CR3_REG18DEN,
117         .ready = STM32MP_PWR_CR3_REG18RDY,
118         .name = "reg18"
119 };
120
121 static const struct stm32mp_pwr_reg_info stm32mp_pwr_usb33 = {
122         .enable = STM32MP_PWR_CR3_USB33DEN,
123         .ready = STM32MP_PWR_CR3_USB33RDY,
124         .name = "usb33"
125 };
126
127 static const struct stm32mp_pwr_reg_info *stm32mp_pwr_reg_infos[] = {
128         &stm32mp_pwr_reg11,
129         &stm32mp_pwr_reg18,
130         &stm32mp_pwr_usb33,
131         NULL
132 };
133
134 static int stm32mp_pwr_regulator_probe(struct udevice *dev)
135 {
136         const struct stm32mp_pwr_reg_info **p = stm32mp_pwr_reg_infos;
137         struct dm_regulator_uclass_platdata *uc_pdata;
138
139         uc_pdata = dev_get_uclass_platdata(dev);
140
141         while (*p) {
142                 int rc;
143
144                 rc = dev_read_stringlist_search(dev, "regulator-name",
145                                                 (*p)->name);
146                 if (rc >= 0) {
147                         dev_dbg(dev, "found regulator %s\n", (*p)->name);
148                         break;
149                 } else if (rc != -ENODATA) {
150                         return rc;
151                 }
152                 p++;
153         }
154         if (!*p) {
155                 int i = 0;
156                 const char *s;
157
158                 dev_dbg(dev, "regulator ");
159                 while (dev_read_string_index(dev, "regulator-name",
160                                              i++, &s) >= 0)
161                         dev_dbg(dev, "%s'%s' ", (i > 1) ? ", " : "", s);
162                 dev_dbg(dev, "%s not supported\n", (i > 2) ? "are" : "is");
163                 return -EINVAL;
164         }
165
166         uc_pdata->type = REGULATOR_TYPE_FIXED;
167         dev->priv = (void *)*p;
168
169         return 0;
170 }
171
172 static int stm32mp_pwr_regulator_set_value(struct udevice *dev, int uV)
173 {
174         struct dm_regulator_uclass_platdata *uc_pdata;
175
176         uc_pdata = dev_get_uclass_platdata(dev);
177         if (!uc_pdata)
178                 return -ENXIO;
179
180         if (uc_pdata->min_uV != uV) {
181                 dev_dbg(dev, "Invalid uV=%d for: %s\n", uV, uc_pdata->name);
182                 return -EINVAL;
183         }
184
185         return 0;
186 }
187
188 static int stm32mp_pwr_regulator_get_value(struct udevice *dev)
189 {
190         struct dm_regulator_uclass_platdata *uc_pdata;
191
192         uc_pdata = dev_get_uclass_platdata(dev);
193         if (!uc_pdata)
194                 return -ENXIO;
195
196         if (uc_pdata->min_uV != uc_pdata->max_uV) {
197                 dev_dbg(dev, "Invalid constraints for: %s\n", uc_pdata->name);
198                 return -EINVAL;
199         }
200
201         return uc_pdata->min_uV;
202 }
203
204 static int stm32mp_pwr_regulator_get_enable(struct udevice *dev)
205 {
206         const struct stm32mp_pwr_reg_info *p = dev_get_priv(dev);
207         int rc;
208         u32 reg;
209
210         rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
211         if (rc)
212                 return rc;
213
214         dev_dbg(dev, "%s id %s\n", p->name, (reg & p->enable) ? "on" : "off");
215
216         return (reg & p->enable) != 0;
217 }
218
219 static int stm32mp_pwr_regulator_set_enable(struct udevice *dev, bool enable)
220 {
221         const struct stm32mp_pwr_reg_info *p = dev_get_priv(dev);
222         int rc;
223         u32 reg;
224         u32 time_start;
225
226         dev_dbg(dev, "Turning %s %s\n", enable ? "on" : "off", p->name);
227
228         rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
229         if (rc)
230                 return rc;
231
232         /* if regulator is already in the wanted state, nothing to do */
233         if (!!(reg & p->enable) == enable)
234                 return 0;
235
236         reg &= ~p->enable;
237         if (enable)
238                 reg |= p->enable;
239
240         rc = pmic_write(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
241         if (rc)
242                 return rc;
243
244         if (!enable)
245                 return 0;
246
247         /* waiting ready for enable */
248         time_start = get_timer(0);
249         while (1) {
250                 rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
251                 if (rc)
252                         return rc;
253                 if (reg & p->ready)
254                         break;
255                 if (get_timer(time_start) > CONFIG_SYS_HZ) {
256                         dev_dbg(dev, "%s: timeout\n", p->name);
257                         return -ETIMEDOUT;
258                 }
259         }
260         return 0;
261 }
262
263 static const struct dm_regulator_ops stm32mp_pwr_regulator_ops = {
264         .set_value  = stm32mp_pwr_regulator_set_value,
265         .get_value  = stm32mp_pwr_regulator_get_value,
266         .get_enable = stm32mp_pwr_regulator_get_enable,
267         .set_enable = stm32mp_pwr_regulator_set_enable,
268 };
269
270 U_BOOT_DRIVER(stm32mp_pwr_regulator) = {
271         .name = "stm32mp_pwr_regulator",
272         .id = UCLASS_REGULATOR,
273         .ops = &stm32mp_pwr_regulator_ops,
274         .probe = stm32mp_pwr_regulator_probe,
275 };