1af41e8dbSPrzemyslaw Marczak /*
2af41e8dbSPrzemyslaw Marczak * Copyright (C) 2014-2015 Samsung Electronics
3af41e8dbSPrzemyslaw Marczak * Przemyslaw Marczak <p.marczak@samsung.com>
4af41e8dbSPrzemyslaw Marczak *
5af41e8dbSPrzemyslaw Marczak * SPDX-License-Identifier: GPL-2.0+
6af41e8dbSPrzemyslaw Marczak */
7f15cd4f1SSimon Glass
8af41e8dbSPrzemyslaw Marczak #include <common.h>
9af41e8dbSPrzemyslaw Marczak #include <errno.h>
10af41e8dbSPrzemyslaw Marczak #include <dm.h>
11af41e8dbSPrzemyslaw Marczak #include <dm/uclass-internal.h>
12af41e8dbSPrzemyslaw Marczak #include <power/pmic.h>
13af41e8dbSPrzemyslaw Marczak #include <power/regulator.h>
14af41e8dbSPrzemyslaw Marczak
15af41e8dbSPrzemyslaw Marczak DECLARE_GLOBAL_DATA_PTR;
16af41e8dbSPrzemyslaw Marczak
regulator_mode(struct udevice * dev,struct dm_regulator_mode ** modep)17af41e8dbSPrzemyslaw Marczak int regulator_mode(struct udevice *dev, struct dm_regulator_mode **modep)
18af41e8dbSPrzemyslaw Marczak {
19af41e8dbSPrzemyslaw Marczak struct dm_regulator_uclass_platdata *uc_pdata;
20af41e8dbSPrzemyslaw Marczak
21af41e8dbSPrzemyslaw Marczak *modep = NULL;
22af41e8dbSPrzemyslaw Marczak
23af41e8dbSPrzemyslaw Marczak uc_pdata = dev_get_uclass_platdata(dev);
24af41e8dbSPrzemyslaw Marczak if (!uc_pdata)
25af41e8dbSPrzemyslaw Marczak return -ENXIO;
26af41e8dbSPrzemyslaw Marczak
27af41e8dbSPrzemyslaw Marczak *modep = uc_pdata->mode;
28af41e8dbSPrzemyslaw Marczak return uc_pdata->mode_count;
29af41e8dbSPrzemyslaw Marczak }
30af41e8dbSPrzemyslaw Marczak
regulator_get_value(struct udevice * dev)31af41e8dbSPrzemyslaw Marczak int regulator_get_value(struct udevice *dev)
32af41e8dbSPrzemyslaw Marczak {
33af41e8dbSPrzemyslaw Marczak const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
34af41e8dbSPrzemyslaw Marczak
35af41e8dbSPrzemyslaw Marczak if (!ops || !ops->get_value)
36af41e8dbSPrzemyslaw Marczak return -ENOSYS;
37af41e8dbSPrzemyslaw Marczak
38af41e8dbSPrzemyslaw Marczak return ops->get_value(dev);
39af41e8dbSPrzemyslaw Marczak }
40af41e8dbSPrzemyslaw Marczak
regulator_set_value(struct udevice * dev,int uV)41af41e8dbSPrzemyslaw Marczak int regulator_set_value(struct udevice *dev, int uV)
42af41e8dbSPrzemyslaw Marczak {
43af41e8dbSPrzemyslaw Marczak const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
44eaadcf38SKeerthy struct dm_regulator_uclass_platdata *uc_pdata;
45b29e2b63SJoseph Chen u32 old_uV = -ENODATA, us;
46b29e2b63SJoseph Chen int ret;
47eaadcf38SKeerthy
48eaadcf38SKeerthy uc_pdata = dev_get_uclass_platdata(dev);
49eaadcf38SKeerthy if (uc_pdata->min_uV != -ENODATA && uV < uc_pdata->min_uV)
50eaadcf38SKeerthy return -EINVAL;
51eaadcf38SKeerthy if (uc_pdata->max_uV != -ENODATA && uV > uc_pdata->max_uV)
52eaadcf38SKeerthy return -EINVAL;
53af41e8dbSPrzemyslaw Marczak
54af41e8dbSPrzemyslaw Marczak if (!ops || !ops->set_value)
55af41e8dbSPrzemyslaw Marczak return -ENOSYS;
56af41e8dbSPrzemyslaw Marczak
57*d5e408adSJoseph Chen if ((uc_pdata->ramp_delay != -ENODATA) || ops->get_ramp_delay) {
58b29e2b63SJoseph Chen if (!ops->get_value)
59b29e2b63SJoseph Chen return -ENOSYS;
60b29e2b63SJoseph Chen old_uV = ops->get_value(dev);
61b29e2b63SJoseph Chen if (old_uV < 0)
62b29e2b63SJoseph Chen return -EINVAL;
63b29e2b63SJoseph Chen }
64b29e2b63SJoseph Chen
65b29e2b63SJoseph Chen ret = ops->set_value(dev, uV);
66b29e2b63SJoseph Chen
67b29e2b63SJoseph Chen if (!ret && (old_uV != -ENODATA) && (old_uV != uV)) {
68*d5e408adSJoseph Chen if (ops->get_ramp_delay)
69*d5e408adSJoseph Chen us = ops->get_ramp_delay(dev, old_uV, uV);
70*d5e408adSJoseph Chen else
71b29e2b63SJoseph Chen us = DIV_ROUND_UP(abs(uV - old_uV), uc_pdata->ramp_delay);
72b29e2b63SJoseph Chen udelay(us);
73b29e2b63SJoseph Chen debug("%s: ramp=%d, old_uV=%d, uV=%d, us=%d\n",
74b29e2b63SJoseph Chen uc_pdata->name, uc_pdata->ramp_delay, old_uV, uV, us);
75b29e2b63SJoseph Chen }
76b29e2b63SJoseph Chen
77b29e2b63SJoseph Chen return ret;
78af41e8dbSPrzemyslaw Marczak }
79af41e8dbSPrzemyslaw Marczak
regulator_set_suspend_value(struct udevice * dev,int uV)80fbc6dab9SJoseph Chen int regulator_set_suspend_value(struct udevice *dev, int uV)
81fbc6dab9SJoseph Chen {
82fbc6dab9SJoseph Chen const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
83fbc6dab9SJoseph Chen
84fbc6dab9SJoseph Chen if (!ops || !ops->set_suspend_value)
85fbc6dab9SJoseph Chen return -ENOSYS;
86fbc6dab9SJoseph Chen
87fbc6dab9SJoseph Chen return ops->set_suspend_value(dev, uV);
88fbc6dab9SJoseph Chen }
89fbc6dab9SJoseph Chen
regulator_get_suspend_value(struct udevice * dev)9071aebe78SJoseph Chen int regulator_get_suspend_value(struct udevice *dev)
9171aebe78SJoseph Chen {
9271aebe78SJoseph Chen const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
9371aebe78SJoseph Chen
9471aebe78SJoseph Chen if (!ops || !ops->get_suspend_value)
9571aebe78SJoseph Chen return -ENOSYS;
9671aebe78SJoseph Chen
9771aebe78SJoseph Chen return ops->get_suspend_value(dev);
9871aebe78SJoseph Chen }
9971aebe78SJoseph Chen
1002f5d532fSKeerthy /*
1012f5d532fSKeerthy * To be called with at most caution as there is no check
1022f5d532fSKeerthy * before setting the actual voltage value.
1032f5d532fSKeerthy */
regulator_set_value_force(struct udevice * dev,int uV)1042f5d532fSKeerthy int regulator_set_value_force(struct udevice *dev, int uV)
1052f5d532fSKeerthy {
1062f5d532fSKeerthy const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
1072f5d532fSKeerthy
1082f5d532fSKeerthy if (!ops || !ops->set_value)
1092f5d532fSKeerthy return -ENOSYS;
1102f5d532fSKeerthy
1112f5d532fSKeerthy return ops->set_value(dev, uV);
1122f5d532fSKeerthy }
1132f5d532fSKeerthy
regulator_get_current(struct udevice * dev)114af41e8dbSPrzemyslaw Marczak int regulator_get_current(struct udevice *dev)
115af41e8dbSPrzemyslaw Marczak {
116af41e8dbSPrzemyslaw Marczak const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
117af41e8dbSPrzemyslaw Marczak
118af41e8dbSPrzemyslaw Marczak if (!ops || !ops->get_current)
119af41e8dbSPrzemyslaw Marczak return -ENOSYS;
120af41e8dbSPrzemyslaw Marczak
121af41e8dbSPrzemyslaw Marczak return ops->get_current(dev);
122af41e8dbSPrzemyslaw Marczak }
123af41e8dbSPrzemyslaw Marczak
regulator_set_current(struct udevice * dev,int uA)124af41e8dbSPrzemyslaw Marczak int regulator_set_current(struct udevice *dev, int uA)
125af41e8dbSPrzemyslaw Marczak {
126af41e8dbSPrzemyslaw Marczak const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
1275483456eSKeerthy struct dm_regulator_uclass_platdata *uc_pdata;
1285483456eSKeerthy
1295483456eSKeerthy uc_pdata = dev_get_uclass_platdata(dev);
1305483456eSKeerthy if (uc_pdata->min_uA != -ENODATA && uA < uc_pdata->min_uA)
1315483456eSKeerthy return -EINVAL;
1325483456eSKeerthy if (uc_pdata->max_uA != -ENODATA && uA > uc_pdata->max_uA)
1335483456eSKeerthy return -EINVAL;
134af41e8dbSPrzemyslaw Marczak
135af41e8dbSPrzemyslaw Marczak if (!ops || !ops->set_current)
136af41e8dbSPrzemyslaw Marczak return -ENOSYS;
137af41e8dbSPrzemyslaw Marczak
138af41e8dbSPrzemyslaw Marczak return ops->set_current(dev, uA);
139af41e8dbSPrzemyslaw Marczak }
140af41e8dbSPrzemyslaw Marczak
regulator_get_enable(struct udevice * dev)14106bdf600SKeerthy int regulator_get_enable(struct udevice *dev)
142af41e8dbSPrzemyslaw Marczak {
143af41e8dbSPrzemyslaw Marczak const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
144af41e8dbSPrzemyslaw Marczak
145af41e8dbSPrzemyslaw Marczak if (!ops || !ops->get_enable)
146af41e8dbSPrzemyslaw Marczak return -ENOSYS;
147af41e8dbSPrzemyslaw Marczak
148af41e8dbSPrzemyslaw Marczak return ops->get_enable(dev);
149af41e8dbSPrzemyslaw Marczak }
150af41e8dbSPrzemyslaw Marczak
regulator_set_enable(struct udevice * dev,bool enable)151af41e8dbSPrzemyslaw Marczak int regulator_set_enable(struct udevice *dev, bool enable)
152af41e8dbSPrzemyslaw Marczak {
153af41e8dbSPrzemyslaw Marczak const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
154b270c27cSShengfei Xu struct dm_regulator_uclass_platdata *uc_pdata;
155af41e8dbSPrzemyslaw Marczak
156af41e8dbSPrzemyslaw Marczak if (!ops || !ops->set_enable)
157af41e8dbSPrzemyslaw Marczak return -ENOSYS;
158af41e8dbSPrzemyslaw Marczak
159b270c27cSShengfei Xu uc_pdata = dev_get_uclass_platdata(dev);
160b270c27cSShengfei Xu if (!enable && uc_pdata->always_on) {
161b270c27cSShengfei Xu printf("the always on regulator (%s) should never be disabled!\n", dev->name);
162b270c27cSShengfei Xu return -EACCES;
163b270c27cSShengfei Xu }
164b270c27cSShengfei Xu
165af41e8dbSPrzemyslaw Marczak return ops->set_enable(dev, enable);
166af41e8dbSPrzemyslaw Marczak }
167af41e8dbSPrzemyslaw Marczak
regulator_set_suspend_enable(struct udevice * dev,bool enable)168fbc6dab9SJoseph Chen int regulator_set_suspend_enable(struct udevice *dev, bool enable)
169fbc6dab9SJoseph Chen {
170fbc6dab9SJoseph Chen const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
171fbc6dab9SJoseph Chen
172fbc6dab9SJoseph Chen if (!ops || !ops->set_suspend_enable)
173fbc6dab9SJoseph Chen return -ENOSYS;
174fbc6dab9SJoseph Chen
175fbc6dab9SJoseph Chen return ops->set_suspend_enable(dev, enable);
176fbc6dab9SJoseph Chen }
177fbc6dab9SJoseph Chen
regulator_get_suspend_enable(struct udevice * dev)17871aebe78SJoseph Chen int regulator_get_suspend_enable(struct udevice *dev)
17971aebe78SJoseph Chen {
18071aebe78SJoseph Chen const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
18171aebe78SJoseph Chen
18271aebe78SJoseph Chen if (!ops || !ops->get_suspend_enable)
18371aebe78SJoseph Chen return -ENOSYS;
18471aebe78SJoseph Chen
18571aebe78SJoseph Chen return ops->get_suspend_enable(dev);
18671aebe78SJoseph Chen }
18771aebe78SJoseph Chen
regulator_set_ramp_delay(struct udevice * dev,u32 ramp_delay)188b29e2b63SJoseph Chen int regulator_set_ramp_delay(struct udevice *dev, u32 ramp_delay)
189b29e2b63SJoseph Chen {
190b29e2b63SJoseph Chen const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
191b29e2b63SJoseph Chen
192b29e2b63SJoseph Chen if (!ops || !ops->set_ramp_delay)
193b29e2b63SJoseph Chen return -ENOSYS;
194b29e2b63SJoseph Chen
195b29e2b63SJoseph Chen return ops->set_ramp_delay(dev, ramp_delay);
196b29e2b63SJoseph Chen }
197b29e2b63SJoseph Chen
regulator_get_mode(struct udevice * dev)198af41e8dbSPrzemyslaw Marczak int regulator_get_mode(struct udevice *dev)
199af41e8dbSPrzemyslaw Marczak {
200af41e8dbSPrzemyslaw Marczak const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
201af41e8dbSPrzemyslaw Marczak
202af41e8dbSPrzemyslaw Marczak if (!ops || !ops->get_mode)
203af41e8dbSPrzemyslaw Marczak return -ENOSYS;
204af41e8dbSPrzemyslaw Marczak
205af41e8dbSPrzemyslaw Marczak return ops->get_mode(dev);
206af41e8dbSPrzemyslaw Marczak }
207af41e8dbSPrzemyslaw Marczak
regulator_set_mode(struct udevice * dev,int mode)208af41e8dbSPrzemyslaw Marczak int regulator_set_mode(struct udevice *dev, int mode)
209af41e8dbSPrzemyslaw Marczak {
210af41e8dbSPrzemyslaw Marczak const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
211af41e8dbSPrzemyslaw Marczak
212af41e8dbSPrzemyslaw Marczak if (!ops || !ops->set_mode)
213af41e8dbSPrzemyslaw Marczak return -ENOSYS;
214af41e8dbSPrzemyslaw Marczak
215af41e8dbSPrzemyslaw Marczak return ops->set_mode(dev, mode);
216af41e8dbSPrzemyslaw Marczak }
217af41e8dbSPrzemyslaw Marczak
regulator_get_by_platname(const char * plat_name,struct udevice ** devp)2183b880757SPrzemyslaw Marczak int regulator_get_by_platname(const char *plat_name, struct udevice **devp)
219af41e8dbSPrzemyslaw Marczak {
220af41e8dbSPrzemyslaw Marczak struct dm_regulator_uclass_platdata *uc_pdata;
221af41e8dbSPrzemyslaw Marczak struct udevice *dev;
2223b880757SPrzemyslaw Marczak int ret;
223af41e8dbSPrzemyslaw Marczak
224af41e8dbSPrzemyslaw Marczak *devp = NULL;
225af41e8dbSPrzemyslaw Marczak
2263b880757SPrzemyslaw Marczak for (ret = uclass_find_first_device(UCLASS_REGULATOR, &dev); dev;
2273b880757SPrzemyslaw Marczak ret = uclass_find_next_device(&dev)) {
228422f04b6SSimon Glass if (ret) {
229422f04b6SSimon Glass debug("regulator %s, ret=%d\n", dev->name, ret);
2303b880757SPrzemyslaw Marczak continue;
231422f04b6SSimon Glass }
2323b880757SPrzemyslaw Marczak
233af41e8dbSPrzemyslaw Marczak uc_pdata = dev_get_uclass_platdata(dev);
234af41e8dbSPrzemyslaw Marczak if (!uc_pdata || strcmp(plat_name, uc_pdata->name))
235af41e8dbSPrzemyslaw Marczak continue;
236af41e8dbSPrzemyslaw Marczak
237af41e8dbSPrzemyslaw Marczak return uclass_get_device_tail(dev, 0, devp);
238af41e8dbSPrzemyslaw Marczak }
239af41e8dbSPrzemyslaw Marczak
240422f04b6SSimon Glass debug("%s: can't find: %s, ret=%d\n", __func__, plat_name, ret);
241af41e8dbSPrzemyslaw Marczak
242af41e8dbSPrzemyslaw Marczak return -ENODEV;
243af41e8dbSPrzemyslaw Marczak }
244af41e8dbSPrzemyslaw Marczak
regulator_get_by_devname(const char * devname,struct udevice ** devp)2453b880757SPrzemyslaw Marczak int regulator_get_by_devname(const char *devname, struct udevice **devp)
246af41e8dbSPrzemyslaw Marczak {
247af41e8dbSPrzemyslaw Marczak return uclass_get_device_by_name(UCLASS_REGULATOR, devname, devp);
248af41e8dbSPrzemyslaw Marczak }
249af41e8dbSPrzemyslaw Marczak
device_get_supply_regulator(struct udevice * dev,const char * supply_name,struct udevice ** devp)2507c816e24SPrzemyslaw Marczak int device_get_supply_regulator(struct udevice *dev, const char *supply_name,
2517c816e24SPrzemyslaw Marczak struct udevice **devp)
2527c816e24SPrzemyslaw Marczak {
2537c816e24SPrzemyslaw Marczak return uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
2547c816e24SPrzemyslaw Marczak supply_name, devp);
2557c816e24SPrzemyslaw Marczak }
2567c816e24SPrzemyslaw Marczak
regulator_init_suspend(struct udevice * dev)2570ae9790cSJoseph Chen static int regulator_init_suspend(struct udevice *dev)
2580ae9790cSJoseph Chen {
2590ae9790cSJoseph Chen struct dm_regulator_uclass_platdata *uc_pdata;
2600ae9790cSJoseph Chen int ret;
2610ae9790cSJoseph Chen
2620ae9790cSJoseph Chen uc_pdata = dev_get_uclass_platdata(dev);
2630ae9790cSJoseph Chen
2640ae9790cSJoseph Chen ret = regulator_set_suspend_enable(dev, uc_pdata->suspend_on);
2650ae9790cSJoseph Chen if (!ret && uc_pdata->suspend_on)
2660ae9790cSJoseph Chen return regulator_set_suspend_value(dev, uc_pdata->suspend_uV);
2670ae9790cSJoseph Chen
2680ae9790cSJoseph Chen return 0;
2690ae9790cSJoseph Chen }
2700ae9790cSJoseph Chen
regulator_autoset(struct udevice * dev)2713b55d30fSSimon Glass int regulator_autoset(struct udevice *dev)
272af41e8dbSPrzemyslaw Marczak {
2733b55d30fSSimon Glass struct dm_regulator_uclass_platdata *uc_pdata;
2743b55d30fSSimon Glass int ret = 0;
275af41e8dbSPrzemyslaw Marczak
2763b55d30fSSimon Glass uc_pdata = dev_get_uclass_platdata(dev);
277fbc6dab9SJoseph Chen
2786999767bSJoseph Chen if (uc_pdata->ignore)
2796999767bSJoseph Chen return ret;
2806999767bSJoseph Chen
281b29e2b63SJoseph Chen if (uc_pdata->ramp_delay != -ENODATA)
282b29e2b63SJoseph Chen regulator_set_ramp_delay(dev, uc_pdata->ramp_delay);
283b29e2b63SJoseph Chen
2843b55d30fSSimon Glass if (!uc_pdata->always_on && !uc_pdata->boot_on)
2853b55d30fSSimon Glass return -EMEDIUMTYPE;
286af41e8dbSPrzemyslaw Marczak
287219e0f93SJoseph Chen /*
288219e0f93SJoseph Chen * To compatible the old possible failure before adding this code,
289219e0f93SJoseph Chen * ignore the result.
290219e0f93SJoseph Chen */
291219e0f93SJoseph Chen if (uc_pdata->type == REGULATOR_TYPE_FIXED) {
292219e0f93SJoseph Chen regulator_set_enable(dev, true);
293219e0f93SJoseph Chen return 0;
294219e0f93SJoseph Chen }
295219e0f93SJoseph Chen
29632db71f8SJoseph Chen if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UV) {
2973b55d30fSSimon Glass ret = regulator_set_value(dev, uc_pdata->min_uV);
29832db71f8SJoseph Chen } else {
29932db71f8SJoseph Chen if ((uc_pdata->type == REGULATOR_TYPE_BUCK) &&
30032db71f8SJoseph Chen (uc_pdata->min_uV != -ENODATA) &&
30145ec5783SJoseph Chen (uc_pdata->max_uV != -ENODATA) &&
30245ec5783SJoseph Chen (uc_pdata->init_uV <= 0))
30332db71f8SJoseph Chen printf("%s %d uV\n",
30432db71f8SJoseph Chen uc_pdata->name, regulator_get_value(dev));
30532db71f8SJoseph Chen }
30632db71f8SJoseph Chen
307a538876eSJoseph Chen if (uc_pdata->init_uV > 0) {
3080e1b20c5SJoseph Chen ret = regulator_set_value(dev, uc_pdata->init_uV);
309a538876eSJoseph Chen if (!ret)
31071ebef54SJoseph Chen printf("%s init %d uV\n",
31154c0dba4SJoseph Chen uc_pdata->name, uc_pdata->init_uV);
312a538876eSJoseph Chen }
313a538876eSJoseph Chen
3143b55d30fSSimon Glass if (!ret && (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UA))
3153b55d30fSSimon Glass ret = regulator_set_current(dev, uc_pdata->min_uA);
316af41e8dbSPrzemyslaw Marczak
317af41e8dbSPrzemyslaw Marczak if (!ret)
3183b55d30fSSimon Glass ret = regulator_set_enable(dev, true);
319af41e8dbSPrzemyslaw Marczak
320af41e8dbSPrzemyslaw Marczak return ret;
321af41e8dbSPrzemyslaw Marczak }
322af41e8dbSPrzemyslaw Marczak
regulator_show(struct udevice * dev,int ret)3233b55d30fSSimon Glass static void regulator_show(struct udevice *dev, int ret)
324af41e8dbSPrzemyslaw Marczak {
325af41e8dbSPrzemyslaw Marczak struct dm_regulator_uclass_platdata *uc_pdata;
3268152d3f6SJoseph Chen int uV = 0;
3273b55d30fSSimon Glass
3283b55d30fSSimon Glass uc_pdata = dev_get_uclass_platdata(dev);
3298152d3f6SJoseph Chen uV = regulator_get_value(dev);
3303b55d30fSSimon Glass
3318152d3f6SJoseph Chen printf("%25s@%15s: ", dev->name, uc_pdata->name);
3328152d3f6SJoseph Chen printf("%7duV <-> %7duV, set %7duV, %s",
3338152d3f6SJoseph Chen uc_pdata->min_uV, uc_pdata->max_uV, uV,
334f98160cbSJoseph Chen (uc_pdata->always_on || uc_pdata->boot_on) ?
3358152d3f6SJoseph Chen "enabling" : "disabled");
3368152d3f6SJoseph Chen
3378152d3f6SJoseph Chen printf(" | supsend %7duV, %s",
3388152d3f6SJoseph Chen uc_pdata->suspend_uV,
3398152d3f6SJoseph Chen uc_pdata->suspend_on ? "enabling" : "disabled");
3408152d3f6SJoseph Chen if (uc_pdata->init_uV != -ENODATA)
3418152d3f6SJoseph Chen printf(" ; init %7duV", uc_pdata->init_uV);
3428152d3f6SJoseph Chen
3433b55d30fSSimon Glass if (ret)
3447d577999SSimon Glass printf(" (ret: %d)", ret);
345f98160cbSJoseph Chen
3463b55d30fSSimon Glass printf("\n");
3473b55d30fSSimon Glass }
3483b55d30fSSimon Glass
regulator_autoset_by_name(const char * platname,struct udevice ** devp)3493b55d30fSSimon Glass int regulator_autoset_by_name(const char *platname, struct udevice **devp)
3503b55d30fSSimon Glass {
351af41e8dbSPrzemyslaw Marczak struct udevice *dev;
352af41e8dbSPrzemyslaw Marczak int ret;
353af41e8dbSPrzemyslaw Marczak
3543b880757SPrzemyslaw Marczak ret = regulator_get_by_platname(platname, &dev);
355af41e8dbSPrzemyslaw Marczak if (devp)
356af41e8dbSPrzemyslaw Marczak *devp = dev;
3573b55d30fSSimon Glass if (ret) {
358422f04b6SSimon Glass debug("Can get the regulator: %s (err=%d)\n", platname, ret);
359af41e8dbSPrzemyslaw Marczak return ret;
360af41e8dbSPrzemyslaw Marczak }
361af41e8dbSPrzemyslaw Marczak
3623b55d30fSSimon Glass return regulator_autoset(dev);
3633b55d30fSSimon Glass }
3643b55d30fSSimon Glass
regulator_list_autoset(const char * list_platname[],struct udevice * list_devp[],bool verbose)3653b880757SPrzemyslaw Marczak int regulator_list_autoset(const char *list_platname[],
366af41e8dbSPrzemyslaw Marczak struct udevice *list_devp[],
367af41e8dbSPrzemyslaw Marczak bool verbose)
368af41e8dbSPrzemyslaw Marczak {
369af41e8dbSPrzemyslaw Marczak struct udevice *dev;
3703b880757SPrzemyslaw Marczak int error = 0, i = 0, ret;
371af41e8dbSPrzemyslaw Marczak
3723b880757SPrzemyslaw Marczak while (list_platname[i]) {
3733b55d30fSSimon Glass ret = regulator_autoset_by_name(list_platname[i], &dev);
3743b55d30fSSimon Glass if (ret != -EMEDIUMTYPE && verbose)
3753b55d30fSSimon Glass regulator_show(dev, ret);
3763b880757SPrzemyslaw Marczak if (ret & !error)
3773b880757SPrzemyslaw Marczak error = ret;
378af41e8dbSPrzemyslaw Marczak
3793b880757SPrzemyslaw Marczak if (list_devp)
380af41e8dbSPrzemyslaw Marczak list_devp[i] = dev;
3813b880757SPrzemyslaw Marczak
3823b880757SPrzemyslaw Marczak i++;
383af41e8dbSPrzemyslaw Marczak }
384af41e8dbSPrzemyslaw Marczak
3853b880757SPrzemyslaw Marczak return error;
3863b880757SPrzemyslaw Marczak }
3873b880757SPrzemyslaw Marczak
regulator_name_is_unique(struct udevice * check_dev,const char * check_name)3883b880757SPrzemyslaw Marczak static bool regulator_name_is_unique(struct udevice *check_dev,
3893b880757SPrzemyslaw Marczak const char *check_name)
3903b880757SPrzemyslaw Marczak {
3913b880757SPrzemyslaw Marczak struct dm_regulator_uclass_platdata *uc_pdata;
3923b880757SPrzemyslaw Marczak struct udevice *dev;
3933b880757SPrzemyslaw Marczak int check_len = strlen(check_name);
3943b880757SPrzemyslaw Marczak int ret;
3953b880757SPrzemyslaw Marczak int len;
3963b880757SPrzemyslaw Marczak
3973b880757SPrzemyslaw Marczak for (ret = uclass_find_first_device(UCLASS_REGULATOR, &dev); dev;
3983b880757SPrzemyslaw Marczak ret = uclass_find_next_device(&dev)) {
3993b880757SPrzemyslaw Marczak if (ret || dev == check_dev)
4003b880757SPrzemyslaw Marczak continue;
4013b880757SPrzemyslaw Marczak
4023b880757SPrzemyslaw Marczak uc_pdata = dev_get_uclass_platdata(dev);
4033b880757SPrzemyslaw Marczak len = strlen(uc_pdata->name);
4043b880757SPrzemyslaw Marczak if (len != check_len)
4053b880757SPrzemyslaw Marczak continue;
4063b880757SPrzemyslaw Marczak
4073b880757SPrzemyslaw Marczak if (!strcmp(uc_pdata->name, check_name))
4083b880757SPrzemyslaw Marczak return false;
4093b880757SPrzemyslaw Marczak }
4103b880757SPrzemyslaw Marczak
4113b880757SPrzemyslaw Marczak return true;
412af41e8dbSPrzemyslaw Marczak }
413af41e8dbSPrzemyslaw Marczak
regulator_post_bind(struct udevice * dev)414af41e8dbSPrzemyslaw Marczak static int regulator_post_bind(struct udevice *dev)
415af41e8dbSPrzemyslaw Marczak {
416af41e8dbSPrzemyslaw Marczak struct dm_regulator_uclass_platdata *uc_pdata;
4173b880757SPrzemyslaw Marczak const char *property = "regulator-name";
418af41e8dbSPrzemyslaw Marczak
419af41e8dbSPrzemyslaw Marczak uc_pdata = dev_get_uclass_platdata(dev);
420af41e8dbSPrzemyslaw Marczak
421af41e8dbSPrzemyslaw Marczak /* Regulator's mandatory constraint */
422f15cd4f1SSimon Glass uc_pdata->name = dev_read_string(dev, property);
423af41e8dbSPrzemyslaw Marczak if (!uc_pdata->name) {
424f15cd4f1SSimon Glass debug("%s: dev '%s' has no property '%s'\n",
425f15cd4f1SSimon Glass __func__, dev->name, property);
426f15cd4f1SSimon Glass uc_pdata->name = dev_read_name(dev);
427cf260011SPeng Fan if (!uc_pdata->name)
4283b880757SPrzemyslaw Marczak return -EINVAL;
429af41e8dbSPrzemyslaw Marczak }
430af41e8dbSPrzemyslaw Marczak
4313b880757SPrzemyslaw Marczak if (regulator_name_is_unique(dev, uc_pdata->name))
432af41e8dbSPrzemyslaw Marczak return 0;
4333b880757SPrzemyslaw Marczak
434f15cd4f1SSimon Glass debug("'%s' of dev: '%s', has nonunique value: '%s\n",
4353b880757SPrzemyslaw Marczak property, dev->name, uc_pdata->name);
4363b880757SPrzemyslaw Marczak
4373b880757SPrzemyslaw Marczak return -EINVAL;
438af41e8dbSPrzemyslaw Marczak }
439af41e8dbSPrzemyslaw Marczak
regulator_pre_probe(struct udevice * dev)440af41e8dbSPrzemyslaw Marczak static int regulator_pre_probe(struct udevice *dev)
441af41e8dbSPrzemyslaw Marczak {
442af41e8dbSPrzemyslaw Marczak struct dm_regulator_uclass_platdata *uc_pdata;
443fbc6dab9SJoseph Chen ofnode node;
444af41e8dbSPrzemyslaw Marczak
445af41e8dbSPrzemyslaw Marczak uc_pdata = dev_get_uclass_platdata(dev);
446af41e8dbSPrzemyslaw Marczak if (!uc_pdata)
447af41e8dbSPrzemyslaw Marczak return -ENXIO;
448af41e8dbSPrzemyslaw Marczak
449af41e8dbSPrzemyslaw Marczak /* Regulator's optional constraints */
450f15cd4f1SSimon Glass uc_pdata->min_uV = dev_read_u32_default(dev, "regulator-min-microvolt",
451f15cd4f1SSimon Glass -ENODATA);
452f15cd4f1SSimon Glass uc_pdata->max_uV = dev_read_u32_default(dev, "regulator-max-microvolt",
453f15cd4f1SSimon Glass -ENODATA);
4540e1b20c5SJoseph Chen uc_pdata->init_uV = dev_read_u32_default(dev, "regulator-init-microvolt",
4550e1b20c5SJoseph Chen -ENODATA);
456f15cd4f1SSimon Glass uc_pdata->min_uA = dev_read_u32_default(dev, "regulator-min-microamp",
457f15cd4f1SSimon Glass -ENODATA);
458f15cd4f1SSimon Glass uc_pdata->max_uA = dev_read_u32_default(dev, "regulator-max-microamp",
459f15cd4f1SSimon Glass -ENODATA);
460f15cd4f1SSimon Glass uc_pdata->always_on = dev_read_bool(dev, "regulator-always-on");
461f15cd4f1SSimon Glass uc_pdata->boot_on = dev_read_bool(dev, "regulator-boot-on");
4626999767bSJoseph Chen uc_pdata->ignore = dev_read_bool(dev, "regulator-loader-ignore");
463b29e2b63SJoseph Chen uc_pdata->ramp_delay = dev_read_u32_default(dev, "regulator-ramp-delay",
464b29e2b63SJoseph Chen -ENODATA);
465fbc6dab9SJoseph Chen node = dev_read_subnode(dev, "regulator-state-mem");
466fbc6dab9SJoseph Chen if (ofnode_valid(node)) {
467fbc6dab9SJoseph Chen uc_pdata->suspend_on = !ofnode_read_bool(node, "regulator-off-in-suspend");
468fbc6dab9SJoseph Chen if (ofnode_read_u32(node, "regulator-suspend-microvolt", &uc_pdata->suspend_uV))
469fbc6dab9SJoseph Chen uc_pdata->suspend_uV = uc_pdata->max_uA;
470fbc6dab9SJoseph Chen } else {
471fbc6dab9SJoseph Chen uc_pdata->suspend_on = true;
472fbc6dab9SJoseph Chen uc_pdata->suspend_uV = uc_pdata->max_uA;
473fbc6dab9SJoseph Chen }
474fbc6dab9SJoseph Chen
4757837ceabSSimon Glass /* Those values are optional (-ENODATA if unset) */
4767837ceabSSimon Glass if ((uc_pdata->min_uV != -ENODATA) &&
4777837ceabSSimon Glass (uc_pdata->max_uV != -ENODATA) &&
4787837ceabSSimon Glass (uc_pdata->min_uV == uc_pdata->max_uV))
4797837ceabSSimon Glass uc_pdata->flags |= REGULATOR_FLAG_AUTOSET_UV;
4807837ceabSSimon Glass
4817837ceabSSimon Glass /* Those values are optional (-ENODATA if unset) */
4827837ceabSSimon Glass if ((uc_pdata->min_uA != -ENODATA) &&
4837837ceabSSimon Glass (uc_pdata->max_uA != -ENODATA) &&
4847837ceabSSimon Glass (uc_pdata->min_uA == uc_pdata->max_uA))
4857837ceabSSimon Glass uc_pdata->flags |= REGULATOR_FLAG_AUTOSET_UA;
4867837ceabSSimon Glass
4872f22a22fSJoseph Chen debug("dev.name=%s: min_uV=%d, max_uV=%d, boot-on=%d, always-on=%d, "
4882f22a22fSJoseph Chen "off-in-suspend=%d, suspend_volt=%d\n",
4892f22a22fSJoseph Chen dev->name, uc_pdata->min_uV, uc_pdata->max_uV, uc_pdata->boot_on,
4902f22a22fSJoseph Chen uc_pdata->always_on, !uc_pdata->suspend_on, uc_pdata->suspend_uV);
4912f22a22fSJoseph Chen
492af41e8dbSPrzemyslaw Marczak return 0;
493af41e8dbSPrzemyslaw Marczak }
494af41e8dbSPrzemyslaw Marczak
regulators_enable_state_mem(bool verbose)4950ae9790cSJoseph Chen int regulators_enable_state_mem(bool verbose)
4960ae9790cSJoseph Chen {
4970ae9790cSJoseph Chen struct udevice *dev;
4980ae9790cSJoseph Chen struct uclass *uc;
4990ae9790cSJoseph Chen int ret;
5000ae9790cSJoseph Chen
5010ae9790cSJoseph Chen ret = uclass_get(UCLASS_REGULATOR, &uc);
5020ae9790cSJoseph Chen if (ret)
5030ae9790cSJoseph Chen return ret;
5040ae9790cSJoseph Chen for (uclass_first_device(UCLASS_REGULATOR, &dev);
5050ae9790cSJoseph Chen dev;
5060ae9790cSJoseph Chen uclass_next_device(&dev)) {
5070ae9790cSJoseph Chen ret = regulator_init_suspend(dev);
5080ae9790cSJoseph Chen
5090ae9790cSJoseph Chen if (ret == -EMEDIUMTYPE)
5100ae9790cSJoseph Chen ret = 0;
5110ae9790cSJoseph Chen if (verbose)
5120ae9790cSJoseph Chen regulator_show(dev, ret);
5130ae9790cSJoseph Chen if (ret == -ENOSYS)
5140ae9790cSJoseph Chen ret = 0;
5150ae9790cSJoseph Chen }
5160ae9790cSJoseph Chen
5170ae9790cSJoseph Chen return ret;
5180ae9790cSJoseph Chen }
5190ae9790cSJoseph Chen
regulators_enable_boot_on(bool verbose)520083fc83aSSimon Glass int regulators_enable_boot_on(bool verbose)
521083fc83aSSimon Glass {
522083fc83aSSimon Glass struct udevice *dev;
523083fc83aSSimon Glass struct uclass *uc;
524083fc83aSSimon Glass int ret;
525083fc83aSSimon Glass
526083fc83aSSimon Glass ret = uclass_get(UCLASS_REGULATOR, &uc);
527083fc83aSSimon Glass if (ret)
528083fc83aSSimon Glass return ret;
529083fc83aSSimon Glass for (uclass_first_device(UCLASS_REGULATOR, &dev);
5303f603cbbSSimon Glass dev;
531083fc83aSSimon Glass uclass_next_device(&dev)) {
532083fc83aSSimon Glass ret = regulator_autoset(dev);
5330ae9790cSJoseph Chen
534f98160cbSJoseph Chen if (ret == -EMEDIUMTYPE)
535d08504d1SSimon Glass ret = 0;
536083fc83aSSimon Glass if (verbose)
537083fc83aSSimon Glass regulator_show(dev, ret);
538364809deSSimon Glass if (ret == -ENOSYS)
539364809deSSimon Glass ret = 0;
540083fc83aSSimon Glass }
541083fc83aSSimon Glass
542083fc83aSSimon Glass return ret;
543083fc83aSSimon Glass }
544083fc83aSSimon Glass
545af41e8dbSPrzemyslaw Marczak UCLASS_DRIVER(regulator) = {
546af41e8dbSPrzemyslaw Marczak .id = UCLASS_REGULATOR,
547af41e8dbSPrzemyslaw Marczak .name = "regulator",
548af41e8dbSPrzemyslaw Marczak .post_bind = regulator_post_bind,
549af41e8dbSPrzemyslaw Marczak .pre_probe = regulator_pre_probe,
550af41e8dbSPrzemyslaw Marczak .per_device_platdata_auto_alloc_size =
551af41e8dbSPrzemyslaw Marczak sizeof(struct dm_regulator_uclass_platdata),
552af41e8dbSPrzemyslaw Marczak };
553