dm: regulator: add implementation of driver model regulator uclass
[oweals/u-boot.git] / 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 int regulator_get_current(struct udevice *dev)
52 {
53         const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
54
55         if (!ops || !ops->get_current)
56                 return -ENOSYS;
57
58         return ops->get_current(dev);
59 }
60
61 int regulator_set_current(struct udevice *dev, int uA)
62 {
63         const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
64
65         if (!ops || !ops->set_current)
66                 return -ENOSYS;
67
68         return ops->set_current(dev, uA);
69 }
70
71 bool regulator_get_enable(struct udevice *dev)
72 {
73         const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
74
75         if (!ops || !ops->get_enable)
76                 return -ENOSYS;
77
78         return ops->get_enable(dev);
79 }
80
81 int regulator_set_enable(struct udevice *dev, bool enable)
82 {
83         const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
84
85         if (!ops || !ops->set_enable)
86                 return -ENOSYS;
87
88         return ops->set_enable(dev, enable);
89 }
90
91 int regulator_get_mode(struct udevice *dev)
92 {
93         const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
94
95         if (!ops || !ops->get_mode)
96                 return -ENOSYS;
97
98         return ops->get_mode(dev);
99 }
100
101 int regulator_set_mode(struct udevice *dev, int mode)
102 {
103         const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
104
105         if (!ops || !ops->set_mode)
106                 return -ENOSYS;
107
108         return ops->set_mode(dev, mode);
109 }
110
111 int regulator_by_platname(const char *plat_name, struct udevice **devp)
112 {
113         struct dm_regulator_uclass_platdata *uc_pdata;
114         struct udevice *dev;
115
116         *devp = NULL;
117
118         for (uclass_find_first_device(UCLASS_REGULATOR, &dev);
119              dev;
120              uclass_find_next_device(&dev)) {
121                 uc_pdata = dev_get_uclass_platdata(dev);
122                 if (!uc_pdata || strcmp(plat_name, uc_pdata->name))
123                         continue;
124
125                 return uclass_get_device_tail(dev, 0, devp);
126         }
127
128         debug("%s: can't find: %s\n", __func__, plat_name);
129
130         return -ENODEV;
131 }
132
133 int regulator_by_devname(const char *devname, struct udevice **devp)
134 {
135         return uclass_get_device_by_name(UCLASS_REGULATOR, devname, devp);
136 }
137
138 static int setting_failed(int ret, bool verbose, const char *fmt, ...)
139 {
140         va_list args;
141         char buf[64];
142
143         if (verbose == false)
144                 return ret;
145
146         va_start(args, fmt);
147         vscnprintf(buf, sizeof(buf), fmt, args);
148         va_end(args);
149
150         printf(buf);
151
152         if (!ret)
153                 return 0;
154
155         printf(" (ret: %d)", ret);
156
157         return ret;
158 }
159
160 int regulator_by_platname_autoset_and_enable(const char *platname,
161                                              struct udevice **devp,
162                                              bool verbose)
163 {
164         struct dm_regulator_uclass_platdata *uc_pdata;
165         struct udevice *dev;
166         bool v = verbose;
167         int ret;
168
169         if (devp)
170                 *devp = NULL;
171
172         ret = regulator_by_platname(platname, &dev);
173         if (ret) {
174                 error("Can get the regulator: %s!", platname);
175                 return ret;
176         }
177
178         uc_pdata = dev_get_uclass_platdata(dev);
179         if (!uc_pdata) {
180                 error("Can get the regulator %s uclass platdata!", platname);
181                 return -ENXIO;
182         }
183
184         if (v)
185                 printf("%s@%s: ", dev->name, uc_pdata->name);
186
187         /* Those values are optional (-ENODATA if unset) */
188         if ((uc_pdata->min_uV != -ENODATA) &&
189             (uc_pdata->max_uV != -ENODATA) &&
190             (uc_pdata->min_uV == uc_pdata->max_uV)) {
191                 ret = regulator_set_value(dev, uc_pdata->min_uV);
192                 if (setting_failed(ret, v, "set %d uV", uc_pdata->min_uV))
193                         goto exit;
194         }
195
196         /* Those values are optional (-ENODATA if unset) */
197         if ((uc_pdata->min_uA != -ENODATA) &&
198             (uc_pdata->max_uA != -ENODATA) &&
199             (uc_pdata->min_uA == uc_pdata->max_uA)) {
200                 ret = regulator_set_current(dev, uc_pdata->min_uA);
201                 if (setting_failed(ret, v, "; set %d uA", uc_pdata->min_uA))
202                         goto exit;
203         }
204
205         if (!uc_pdata->always_on && !uc_pdata->boot_on)
206                 goto retdev;
207
208         ret = regulator_set_enable(dev, true);
209         if (setting_failed(ret, v, "; enabling", uc_pdata->min_uA))
210                 goto exit;
211
212 retdev:
213         if (devp)
214                 *devp = dev;
215 exit:
216         if (v)
217                 printf("\n");
218         return ret;
219 }
220
221 int regulator_by_platname_list_autoset_and_enable(const char *list_platname[],
222                                                   int list_entries,
223                                                   struct udevice *list_devp[],
224                                                   bool verbose)
225 {
226         struct udevice *dev;
227         int i, ret, success = 0;
228
229         for (i = 0; i < list_entries; i++) {
230                 ret = regulator_autoset(list_platname[i], &dev, verbose);
231                 if (!ret)
232                         success++;
233
234                 if (!list_devp)
235                         continue;
236
237                 if (ret)
238                         list_devp[i] = NULL;
239                 else
240                         list_devp[i] = dev;
241         }
242
243         return (success != list_entries);
244 }
245
246 static int regulator_post_bind(struct udevice *dev)
247 {
248         struct dm_regulator_uclass_platdata *uc_pdata;
249         int offset = dev->of_offset;
250         const void *blob = gd->fdt_blob;
251
252         uc_pdata = dev_get_uclass_platdata(dev);
253         if (!uc_pdata)
254                 return -ENXIO;
255
256         /* Regulator's mandatory constraint */
257         uc_pdata->name = fdt_getprop(blob, offset, "regulator-name", NULL);
258         if (!uc_pdata->name) {
259                 debug("%s: dev: %s has no property 'regulator-name'\n",
260                       __func__, dev->name);
261                 return -ENXIO;
262         }
263
264         return 0;
265 }
266
267 static int regulator_pre_probe(struct udevice *dev)
268 {
269         struct dm_regulator_uclass_platdata *uc_pdata;
270         int offset = dev->of_offset;
271
272         uc_pdata = dev_get_uclass_platdata(dev);
273         if (!uc_pdata)
274                 return -ENXIO;
275
276         /* Regulator's optional constraints */
277         uc_pdata->min_uV = fdtdec_get_int(gd->fdt_blob, offset,
278                                           "regulator-min-microvolt", -ENODATA);
279         uc_pdata->max_uV = fdtdec_get_int(gd->fdt_blob, offset,
280                                           "regulator-max-microvolt", -ENODATA);
281         uc_pdata->min_uA = fdtdec_get_int(gd->fdt_blob, offset,
282                                           "regulator-min-microamp", -ENODATA);
283         uc_pdata->max_uA = fdtdec_get_int(gd->fdt_blob, offset,
284                                           "regulator-max-microamp", -ENODATA);
285         uc_pdata->always_on = fdtdec_get_bool(gd->fdt_blob, offset,
286                                               "regulator-always-on");
287         uc_pdata->boot_on = fdtdec_get_bool(gd->fdt_blob, offset,
288                                             "regulator-boot-on");
289
290         return 0;
291 }
292
293 UCLASS_DRIVER(regulator) = {
294         .id             = UCLASS_REGULATOR,
295         .name           = "regulator",
296         .post_bind      = regulator_post_bind,
297         .pre_probe      = regulator_pre_probe,
298         .per_device_platdata_auto_alloc_size =
299                                 sizeof(struct dm_regulator_uclass_platdata),
300 };