]> git.sur5r.net Git - u-boot/blob - drivers/power/regulator/regulator-uclass.c
power: regulator: Introduce regulator_set_value_force function
[u-boot] / drivers / power / regulator / regulator-uclass.c
1 /*
2  * Copyright (C) 2014-2015 Samsung Electronics
3  * Przemyslaw Marczak <p.marczak@samsung.com>
4  *
5  * SPDX-License-Identifier:     GPL-2.0+
6  */
7 #include <common.h>
8 #include <fdtdec.h>
9 #include <errno.h>
10 #include <dm.h>
11 #include <dm/uclass-internal.h>
12 #include <power/pmic.h>
13 #include <power/regulator.h>
14
15 DECLARE_GLOBAL_DATA_PTR;
16
17 int regulator_mode(struct udevice *dev, struct dm_regulator_mode **modep)
18 {
19         struct dm_regulator_uclass_platdata *uc_pdata;
20
21         *modep = NULL;
22
23         uc_pdata = dev_get_uclass_platdata(dev);
24         if (!uc_pdata)
25                 return -ENXIO;
26
27         *modep = uc_pdata->mode;
28         return uc_pdata->mode_count;
29 }
30
31 int regulator_get_value(struct udevice *dev)
32 {
33         const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
34
35         if (!ops || !ops->get_value)
36                 return -ENOSYS;
37
38         return ops->get_value(dev);
39 }
40
41 int regulator_set_value(struct udevice *dev, int uV)
42 {
43         const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
44
45         if (!ops || !ops->set_value)
46                 return -ENOSYS;
47
48         return ops->set_value(dev, uV);
49 }
50
51 /*
52  * To be called with at most caution as there is no check
53  * before setting the actual voltage value.
54  */
55 int regulator_set_value_force(struct udevice *dev, int uV)
56 {
57         const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
58
59         if (!ops || !ops->set_value)
60                 return -ENOSYS;
61
62         return ops->set_value(dev, uV);
63 }
64
65 int regulator_get_current(struct udevice *dev)
66 {
67         const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
68
69         if (!ops || !ops->get_current)
70                 return -ENOSYS;
71
72         return ops->get_current(dev);
73 }
74
75 int regulator_set_current(struct udevice *dev, int uA)
76 {
77         const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
78
79         if (!ops || !ops->set_current)
80                 return -ENOSYS;
81
82         return ops->set_current(dev, uA);
83 }
84
85 bool regulator_get_enable(struct udevice *dev)
86 {
87         const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
88
89         if (!ops || !ops->get_enable)
90                 return -ENOSYS;
91
92         return ops->get_enable(dev);
93 }
94
95 int regulator_set_enable(struct udevice *dev, bool enable)
96 {
97         const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
98
99         if (!ops || !ops->set_enable)
100                 return -ENOSYS;
101
102         return ops->set_enable(dev, enable);
103 }
104
105 int regulator_get_mode(struct udevice *dev)
106 {
107         const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
108
109         if (!ops || !ops->get_mode)
110                 return -ENOSYS;
111
112         return ops->get_mode(dev);
113 }
114
115 int regulator_set_mode(struct udevice *dev, int mode)
116 {
117         const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
118
119         if (!ops || !ops->set_mode)
120                 return -ENOSYS;
121
122         return ops->set_mode(dev, mode);
123 }
124
125 int regulator_get_by_platname(const char *plat_name, struct udevice **devp)
126 {
127         struct dm_regulator_uclass_platdata *uc_pdata;
128         struct udevice *dev;
129         int ret;
130
131         *devp = NULL;
132
133         for (ret = uclass_find_first_device(UCLASS_REGULATOR, &dev); dev;
134              ret = uclass_find_next_device(&dev)) {
135                 if (ret)
136                         continue;
137
138                 uc_pdata = dev_get_uclass_platdata(dev);
139                 if (!uc_pdata || strcmp(plat_name, uc_pdata->name))
140                         continue;
141
142                 return uclass_get_device_tail(dev, 0, devp);
143         }
144
145         debug("%s: can't find: %s\n", __func__, plat_name);
146
147         return -ENODEV;
148 }
149
150 int regulator_get_by_devname(const char *devname, struct udevice **devp)
151 {
152         return uclass_get_device_by_name(UCLASS_REGULATOR, devname, devp);
153 }
154
155 int device_get_supply_regulator(struct udevice *dev, const char *supply_name,
156                                 struct udevice **devp)
157 {
158         return uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
159                                             supply_name, devp);
160 }
161
162 int regulator_autoset(struct udevice *dev)
163 {
164         struct dm_regulator_uclass_platdata *uc_pdata;
165         int ret = 0;
166
167         uc_pdata = dev_get_uclass_platdata(dev);
168         if (!uc_pdata->always_on && !uc_pdata->boot_on)
169                 return -EMEDIUMTYPE;
170
171         if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UV)
172                 ret = regulator_set_value(dev, uc_pdata->min_uV);
173         if (!ret && (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UA))
174                 ret = regulator_set_current(dev, uc_pdata->min_uA);
175
176         if (!ret)
177                 ret = regulator_set_enable(dev, true);
178
179         return ret;
180 }
181
182 static void regulator_show(struct udevice *dev, int ret)
183 {
184         struct dm_regulator_uclass_platdata *uc_pdata;
185
186         uc_pdata = dev_get_uclass_platdata(dev);
187
188         printf("%s@%s: ", dev->name, uc_pdata->name);
189         if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UV)
190                 printf("set %d uV", uc_pdata->min_uV);
191         if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UA)
192                 printf("; set %d uA", uc_pdata->min_uA);
193         printf("; enabling");
194         if (ret)
195                 printf(" (ret: %d)", ret);
196         printf("\n");
197 }
198
199 int regulator_autoset_by_name(const char *platname, struct udevice **devp)
200 {
201         struct udevice *dev;
202         int ret;
203
204         ret = regulator_get_by_platname(platname, &dev);
205         if (devp)
206                 *devp = dev;
207         if (ret) {
208                 debug("Can get the regulator: %s!", platname);
209                 return ret;
210         }
211
212         return regulator_autoset(dev);
213 }
214
215 int regulator_list_autoset(const char *list_platname[],
216                            struct udevice *list_devp[],
217                            bool verbose)
218 {
219         struct udevice *dev;
220         int error = 0, i = 0, ret;
221
222         while (list_platname[i]) {
223                 ret = regulator_autoset_by_name(list_platname[i], &dev);
224                 if (ret != -EMEDIUMTYPE && verbose)
225                         regulator_show(dev, ret);
226                 if (ret & !error)
227                         error = ret;
228
229                 if (list_devp)
230                         list_devp[i] = dev;
231
232                 i++;
233         }
234
235         return error;
236 }
237
238 static bool regulator_name_is_unique(struct udevice *check_dev,
239                                      const char *check_name)
240 {
241         struct dm_regulator_uclass_platdata *uc_pdata;
242         struct udevice *dev;
243         int check_len = strlen(check_name);
244         int ret;
245         int len;
246
247         for (ret = uclass_find_first_device(UCLASS_REGULATOR, &dev); dev;
248              ret = uclass_find_next_device(&dev)) {
249                 if (ret || dev == check_dev)
250                         continue;
251
252                 uc_pdata = dev_get_uclass_platdata(dev);
253                 len = strlen(uc_pdata->name);
254                 if (len != check_len)
255                         continue;
256
257                 if (!strcmp(uc_pdata->name, check_name))
258                         return false;
259         }
260
261         return true;
262 }
263
264 static int regulator_post_bind(struct udevice *dev)
265 {
266         struct dm_regulator_uclass_platdata *uc_pdata;
267         int offset = dev->of_offset;
268         const void *blob = gd->fdt_blob;
269         const char *property = "regulator-name";
270
271         uc_pdata = dev_get_uclass_platdata(dev);
272         if (!uc_pdata)
273                 return -ENXIO;
274
275         /* Regulator's mandatory constraint */
276         uc_pdata->name = fdt_getprop(blob, offset, property, NULL);
277         if (!uc_pdata->name) {
278                 debug("%s: dev: %s has no property 'regulator-name'\n",
279                       __func__, dev->name);
280                 uc_pdata->name = fdt_get_name(blob, offset, NULL);
281                 if (!uc_pdata->name)
282                         return -EINVAL;
283         }
284
285         if (regulator_name_is_unique(dev, uc_pdata->name))
286                 return 0;
287
288         debug("\"%s\" of dev: \"%s\", has nonunique value: \"%s\"",
289               property, dev->name, uc_pdata->name);
290
291         return -EINVAL;
292 }
293
294 static int regulator_pre_probe(struct udevice *dev)
295 {
296         struct dm_regulator_uclass_platdata *uc_pdata;
297         int offset = dev->of_offset;
298
299         uc_pdata = dev_get_uclass_platdata(dev);
300         if (!uc_pdata)
301                 return -ENXIO;
302
303         /* Regulator's optional constraints */
304         uc_pdata->min_uV = fdtdec_get_int(gd->fdt_blob, offset,
305                                           "regulator-min-microvolt", -ENODATA);
306         uc_pdata->max_uV = fdtdec_get_int(gd->fdt_blob, offset,
307                                           "regulator-max-microvolt", -ENODATA);
308         uc_pdata->min_uA = fdtdec_get_int(gd->fdt_blob, offset,
309                                           "regulator-min-microamp", -ENODATA);
310         uc_pdata->max_uA = fdtdec_get_int(gd->fdt_blob, offset,
311                                           "regulator-max-microamp", -ENODATA);
312         uc_pdata->always_on = fdtdec_get_bool(gd->fdt_blob, offset,
313                                               "regulator-always-on");
314         uc_pdata->boot_on = fdtdec_get_bool(gd->fdt_blob, offset,
315                                             "regulator-boot-on");
316
317         /* Those values are optional (-ENODATA if unset) */
318         if ((uc_pdata->min_uV != -ENODATA) &&
319             (uc_pdata->max_uV != -ENODATA) &&
320             (uc_pdata->min_uV == uc_pdata->max_uV))
321                 uc_pdata->flags |= REGULATOR_FLAG_AUTOSET_UV;
322
323         /* Those values are optional (-ENODATA if unset) */
324         if ((uc_pdata->min_uA != -ENODATA) &&
325             (uc_pdata->max_uA != -ENODATA) &&
326             (uc_pdata->min_uA == uc_pdata->max_uA))
327                 uc_pdata->flags |= REGULATOR_FLAG_AUTOSET_UA;
328
329         return 0;
330 }
331
332 int regulators_enable_boot_on(bool verbose)
333 {
334         struct udevice *dev;
335         struct uclass *uc;
336         int ret;
337
338         ret = uclass_get(UCLASS_REGULATOR, &uc);
339         if (ret)
340                 return ret;
341         for (uclass_first_device(UCLASS_REGULATOR, &dev);
342              dev;
343              uclass_next_device(&dev)) {
344                 ret = regulator_autoset(dev);
345                 if (ret == -EMEDIUMTYPE) {
346                         ret = 0;
347                         continue;
348                 }
349                 if (verbose)
350                         regulator_show(dev, ret);
351                 if (ret == -ENOSYS)
352                         ret = 0;
353         }
354
355         return ret;
356 }
357
358 UCLASS_DRIVER(regulator) = {
359         .id             = UCLASS_REGULATOR,
360         .name           = "regulator",
361         .post_bind      = regulator_post_bind,
362         .pre_probe      = regulator_pre_probe,
363         .per_device_platdata_auto_alloc_size =
364                                 sizeof(struct dm_regulator_uclass_platdata),
365 };