blob: 07ce2869e6f4603f7c74b718ec667aaa84881f60 [file] [log] [blame]
Przemyslaw Marczak08edd002015-04-20 20:07:42 +02001/*
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
15DECLARE_GLOBAL_DATA_PTR;
16
17int 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
31int 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
41int 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
51int 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
61int 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
71bool 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
81int 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
91int 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
101int 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
111int 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
133int regulator_by_devname(const char *devname, struct udevice **devp)
134{
135 return uclass_get_device_by_name(UCLASS_REGULATOR, devname, devp);
136}
137
138static 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
160int 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
212retdev:
213 if (devp)
214 *devp = dev;
215exit:
216 if (v)
217 printf("\n");
218 return ret;
219}
220
221int 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
246static 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
267static 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
293UCLASS_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};