xref: /rk3399_rockchip-uboot/drivers/power/regulator/regulator-uclass.c (revision 54c0dba4a182b13f90b1e5e0dbf000e8e776981d)
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 
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 
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 
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 
57b29e2b63SJoseph Chen 	if (uc_pdata->ramp_delay != -ENODATA) {
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)) {
68b29e2b63SJoseph Chen 		us = DIV_ROUND_UP(abs(uV - old_uV), uc_pdata->ramp_delay);
69b29e2b63SJoseph Chen 		udelay(us);
70b29e2b63SJoseph Chen 		debug("%s: ramp=%d, old_uV=%d, uV=%d, us=%d\n",
71b29e2b63SJoseph Chen 		      uc_pdata->name, uc_pdata->ramp_delay, old_uV, uV, us);
72b29e2b63SJoseph Chen 	}
73b29e2b63SJoseph Chen 
74b29e2b63SJoseph Chen 	return ret;
75af41e8dbSPrzemyslaw Marczak }
76af41e8dbSPrzemyslaw Marczak 
77fbc6dab9SJoseph Chen int regulator_set_suspend_value(struct udevice *dev, int uV)
78fbc6dab9SJoseph Chen {
79fbc6dab9SJoseph Chen 	const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
80fbc6dab9SJoseph Chen 
81fbc6dab9SJoseph Chen 	if (!ops || !ops->set_suspend_value)
82fbc6dab9SJoseph Chen 		return -ENOSYS;
83fbc6dab9SJoseph Chen 
84fbc6dab9SJoseph Chen 	return ops->set_suspend_value(dev, uV);
85fbc6dab9SJoseph Chen }
86fbc6dab9SJoseph Chen 
8771aebe78SJoseph Chen int regulator_get_suspend_value(struct udevice *dev)
8871aebe78SJoseph Chen {
8971aebe78SJoseph Chen 	const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
9071aebe78SJoseph Chen 
9171aebe78SJoseph Chen 	if (!ops || !ops->get_suspend_value)
9271aebe78SJoseph Chen 		return -ENOSYS;
9371aebe78SJoseph Chen 
9471aebe78SJoseph Chen 	return ops->get_suspend_value(dev);
9571aebe78SJoseph Chen }
9671aebe78SJoseph Chen 
972f5d532fSKeerthy /*
982f5d532fSKeerthy  * To be called with at most caution as there is no check
992f5d532fSKeerthy  * before setting the actual voltage value.
1002f5d532fSKeerthy  */
1012f5d532fSKeerthy int regulator_set_value_force(struct udevice *dev, int uV)
1022f5d532fSKeerthy {
1032f5d532fSKeerthy 	const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
1042f5d532fSKeerthy 
1052f5d532fSKeerthy 	if (!ops || !ops->set_value)
1062f5d532fSKeerthy 		return -ENOSYS;
1072f5d532fSKeerthy 
1082f5d532fSKeerthy 	return ops->set_value(dev, uV);
1092f5d532fSKeerthy }
1102f5d532fSKeerthy 
111af41e8dbSPrzemyslaw Marczak int regulator_get_current(struct udevice *dev)
112af41e8dbSPrzemyslaw Marczak {
113af41e8dbSPrzemyslaw Marczak 	const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
114af41e8dbSPrzemyslaw Marczak 
115af41e8dbSPrzemyslaw Marczak 	if (!ops || !ops->get_current)
116af41e8dbSPrzemyslaw Marczak 		return -ENOSYS;
117af41e8dbSPrzemyslaw Marczak 
118af41e8dbSPrzemyslaw Marczak 	return ops->get_current(dev);
119af41e8dbSPrzemyslaw Marczak }
120af41e8dbSPrzemyslaw Marczak 
121af41e8dbSPrzemyslaw Marczak int regulator_set_current(struct udevice *dev, int uA)
122af41e8dbSPrzemyslaw Marczak {
123af41e8dbSPrzemyslaw Marczak 	const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
1245483456eSKeerthy 	struct dm_regulator_uclass_platdata *uc_pdata;
1255483456eSKeerthy 
1265483456eSKeerthy 	uc_pdata = dev_get_uclass_platdata(dev);
1275483456eSKeerthy 	if (uc_pdata->min_uA != -ENODATA && uA < uc_pdata->min_uA)
1285483456eSKeerthy 		return -EINVAL;
1295483456eSKeerthy 	if (uc_pdata->max_uA != -ENODATA && uA > uc_pdata->max_uA)
1305483456eSKeerthy 		return -EINVAL;
131af41e8dbSPrzemyslaw Marczak 
132af41e8dbSPrzemyslaw Marczak 	if (!ops || !ops->set_current)
133af41e8dbSPrzemyslaw Marczak 		return -ENOSYS;
134af41e8dbSPrzemyslaw Marczak 
135af41e8dbSPrzemyslaw Marczak 	return ops->set_current(dev, uA);
136af41e8dbSPrzemyslaw Marczak }
137af41e8dbSPrzemyslaw Marczak 
13806bdf600SKeerthy int regulator_get_enable(struct udevice *dev)
139af41e8dbSPrzemyslaw Marczak {
140af41e8dbSPrzemyslaw Marczak 	const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
141af41e8dbSPrzemyslaw Marczak 
142af41e8dbSPrzemyslaw Marczak 	if (!ops || !ops->get_enable)
143af41e8dbSPrzemyslaw Marczak 		return -ENOSYS;
144af41e8dbSPrzemyslaw Marczak 
145af41e8dbSPrzemyslaw Marczak 	return ops->get_enable(dev);
146af41e8dbSPrzemyslaw Marczak }
147af41e8dbSPrzemyslaw Marczak 
148af41e8dbSPrzemyslaw Marczak int regulator_set_enable(struct udevice *dev, bool enable)
149af41e8dbSPrzemyslaw Marczak {
150af41e8dbSPrzemyslaw Marczak 	const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
151af41e8dbSPrzemyslaw Marczak 
152af41e8dbSPrzemyslaw Marczak 	if (!ops || !ops->set_enable)
153af41e8dbSPrzemyslaw Marczak 		return -ENOSYS;
154af41e8dbSPrzemyslaw Marczak 
155af41e8dbSPrzemyslaw Marczak 	return ops->set_enable(dev, enable);
156af41e8dbSPrzemyslaw Marczak }
157af41e8dbSPrzemyslaw Marczak 
158fbc6dab9SJoseph Chen int regulator_set_suspend_enable(struct udevice *dev, bool enable)
159fbc6dab9SJoseph Chen {
160fbc6dab9SJoseph Chen 	const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
161fbc6dab9SJoseph Chen 
162fbc6dab9SJoseph Chen 	if (!ops || !ops->set_suspend_enable)
163fbc6dab9SJoseph Chen 		return -ENOSYS;
164fbc6dab9SJoseph Chen 
165fbc6dab9SJoseph Chen 	return ops->set_suspend_enable(dev, enable);
166fbc6dab9SJoseph Chen }
167fbc6dab9SJoseph Chen 
16871aebe78SJoseph Chen int regulator_get_suspend_enable(struct udevice *dev)
16971aebe78SJoseph Chen {
17071aebe78SJoseph Chen 	const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
17171aebe78SJoseph Chen 
17271aebe78SJoseph Chen 	if (!ops || !ops->get_suspend_enable)
17371aebe78SJoseph Chen 		return -ENOSYS;
17471aebe78SJoseph Chen 
17571aebe78SJoseph Chen 	return ops->get_suspend_enable(dev);
17671aebe78SJoseph Chen }
17771aebe78SJoseph Chen 
178b29e2b63SJoseph Chen int regulator_set_ramp_delay(struct udevice *dev, u32 ramp_delay)
179b29e2b63SJoseph Chen {
180b29e2b63SJoseph Chen 	const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
181b29e2b63SJoseph Chen 
182b29e2b63SJoseph Chen 	if (!ops || !ops->set_ramp_delay)
183b29e2b63SJoseph Chen 		return -ENOSYS;
184b29e2b63SJoseph Chen 
185b29e2b63SJoseph Chen 	return ops->set_ramp_delay(dev, ramp_delay);
186b29e2b63SJoseph Chen }
187b29e2b63SJoseph Chen 
188af41e8dbSPrzemyslaw Marczak int regulator_get_mode(struct udevice *dev)
189af41e8dbSPrzemyslaw Marczak {
190af41e8dbSPrzemyslaw Marczak 	const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
191af41e8dbSPrzemyslaw Marczak 
192af41e8dbSPrzemyslaw Marczak 	if (!ops || !ops->get_mode)
193af41e8dbSPrzemyslaw Marczak 		return -ENOSYS;
194af41e8dbSPrzemyslaw Marczak 
195af41e8dbSPrzemyslaw Marczak 	return ops->get_mode(dev);
196af41e8dbSPrzemyslaw Marczak }
197af41e8dbSPrzemyslaw Marczak 
198af41e8dbSPrzemyslaw Marczak int regulator_set_mode(struct udevice *dev, int mode)
199af41e8dbSPrzemyslaw Marczak {
200af41e8dbSPrzemyslaw Marczak 	const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
201af41e8dbSPrzemyslaw Marczak 
202af41e8dbSPrzemyslaw Marczak 	if (!ops || !ops->set_mode)
203af41e8dbSPrzemyslaw Marczak 		return -ENOSYS;
204af41e8dbSPrzemyslaw Marczak 
205af41e8dbSPrzemyslaw Marczak 	return ops->set_mode(dev, mode);
206af41e8dbSPrzemyslaw Marczak }
207af41e8dbSPrzemyslaw Marczak 
2083b880757SPrzemyslaw Marczak int regulator_get_by_platname(const char *plat_name, struct udevice **devp)
209af41e8dbSPrzemyslaw Marczak {
210af41e8dbSPrzemyslaw Marczak 	struct dm_regulator_uclass_platdata *uc_pdata;
211af41e8dbSPrzemyslaw Marczak 	struct udevice *dev;
2123b880757SPrzemyslaw Marczak 	int ret;
213af41e8dbSPrzemyslaw Marczak 
214af41e8dbSPrzemyslaw Marczak 	*devp = NULL;
215af41e8dbSPrzemyslaw Marczak 
2163b880757SPrzemyslaw Marczak 	for (ret = uclass_find_first_device(UCLASS_REGULATOR, &dev); dev;
2173b880757SPrzemyslaw Marczak 	     ret = uclass_find_next_device(&dev)) {
218422f04b6SSimon Glass 		if (ret) {
219422f04b6SSimon Glass 			debug("regulator %s, ret=%d\n", dev->name, ret);
2203b880757SPrzemyslaw Marczak 			continue;
221422f04b6SSimon Glass 		}
2223b880757SPrzemyslaw Marczak 
223af41e8dbSPrzemyslaw Marczak 		uc_pdata = dev_get_uclass_platdata(dev);
224af41e8dbSPrzemyslaw Marczak 		if (!uc_pdata || strcmp(plat_name, uc_pdata->name))
225af41e8dbSPrzemyslaw Marczak 			continue;
226af41e8dbSPrzemyslaw Marczak 
227af41e8dbSPrzemyslaw Marczak 		return uclass_get_device_tail(dev, 0, devp);
228af41e8dbSPrzemyslaw Marczak 	}
229af41e8dbSPrzemyslaw Marczak 
230422f04b6SSimon Glass 	debug("%s: can't find: %s, ret=%d\n", __func__, plat_name, ret);
231af41e8dbSPrzemyslaw Marczak 
232af41e8dbSPrzemyslaw Marczak 	return -ENODEV;
233af41e8dbSPrzemyslaw Marczak }
234af41e8dbSPrzemyslaw Marczak 
2353b880757SPrzemyslaw Marczak int regulator_get_by_devname(const char *devname, struct udevice **devp)
236af41e8dbSPrzemyslaw Marczak {
237af41e8dbSPrzemyslaw Marczak 	return uclass_get_device_by_name(UCLASS_REGULATOR, devname, devp);
238af41e8dbSPrzemyslaw Marczak }
239af41e8dbSPrzemyslaw Marczak 
2407c816e24SPrzemyslaw Marczak int device_get_supply_regulator(struct udevice *dev, const char *supply_name,
2417c816e24SPrzemyslaw Marczak 				struct udevice **devp)
2427c816e24SPrzemyslaw Marczak {
2437c816e24SPrzemyslaw Marczak 	return uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
2447c816e24SPrzemyslaw Marczak 					    supply_name, devp);
2457c816e24SPrzemyslaw Marczak }
2467c816e24SPrzemyslaw Marczak 
2470ae9790cSJoseph Chen static int regulator_init_suspend(struct udevice *dev)
2480ae9790cSJoseph Chen {
2490ae9790cSJoseph Chen 	struct dm_regulator_uclass_platdata *uc_pdata;
2500ae9790cSJoseph Chen 	int ret;
2510ae9790cSJoseph Chen 
2520ae9790cSJoseph Chen 	uc_pdata = dev_get_uclass_platdata(dev);
2530ae9790cSJoseph Chen 
2540ae9790cSJoseph Chen 	ret = regulator_set_suspend_enable(dev, uc_pdata->suspend_on);
2550ae9790cSJoseph Chen 	if (!ret && uc_pdata->suspend_on)
2560ae9790cSJoseph Chen 		return regulator_set_suspend_value(dev, uc_pdata->suspend_uV);
2570ae9790cSJoseph Chen 
2580ae9790cSJoseph Chen 	return 0;
2590ae9790cSJoseph Chen }
2600ae9790cSJoseph Chen 
2613b55d30fSSimon Glass int regulator_autoset(struct udevice *dev)
262af41e8dbSPrzemyslaw Marczak {
2633b55d30fSSimon Glass 	struct dm_regulator_uclass_platdata *uc_pdata;
2643b55d30fSSimon Glass 	int ret = 0;
265af41e8dbSPrzemyslaw Marczak 
2663b55d30fSSimon Glass 	uc_pdata = dev_get_uclass_platdata(dev);
267fbc6dab9SJoseph Chen 
2686999767bSJoseph Chen 	if (uc_pdata->ignore)
2696999767bSJoseph Chen 		return ret;
2706999767bSJoseph Chen 
271b29e2b63SJoseph Chen 	if (uc_pdata->ramp_delay != -ENODATA)
272b29e2b63SJoseph Chen 		regulator_set_ramp_delay(dev, uc_pdata->ramp_delay);
273b29e2b63SJoseph Chen 
2743b55d30fSSimon Glass 	if (!uc_pdata->always_on && !uc_pdata->boot_on)
2753b55d30fSSimon Glass 		return -EMEDIUMTYPE;
276af41e8dbSPrzemyslaw Marczak 
27732db71f8SJoseph Chen 	if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UV) {
2783b55d30fSSimon Glass 		ret = regulator_set_value(dev, uc_pdata->min_uV);
27932db71f8SJoseph Chen 	} else {
28032db71f8SJoseph Chen 		if ((uc_pdata->type == REGULATOR_TYPE_BUCK) &&
28132db71f8SJoseph Chen 		    (uc_pdata->min_uV != -ENODATA) &&
28245ec5783SJoseph Chen 		    (uc_pdata->max_uV != -ENODATA) &&
28345ec5783SJoseph Chen 		    (uc_pdata->init_uV <= 0))
28432db71f8SJoseph Chen 			printf("%s %d uV\n",
28532db71f8SJoseph Chen 			       uc_pdata->name, regulator_get_value(dev));
28632db71f8SJoseph Chen 	}
28732db71f8SJoseph Chen 
288a538876eSJoseph Chen 	if (uc_pdata->init_uV > 0) {
2890e1b20c5SJoseph Chen 		ret = regulator_set_value(dev, uc_pdata->init_uV);
290a538876eSJoseph Chen 		if (!ret)
29171ebef54SJoseph Chen 			printf("%s init %d uV\n",
292*54c0dba4SJoseph Chen 			       uc_pdata->name, uc_pdata->init_uV);
293a538876eSJoseph Chen 	}
294a538876eSJoseph Chen 
2953b55d30fSSimon Glass 	if (!ret && (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UA))
2963b55d30fSSimon Glass 		ret = regulator_set_current(dev, uc_pdata->min_uA);
297af41e8dbSPrzemyslaw Marczak 
298af41e8dbSPrzemyslaw Marczak 	if (!ret)
2993b55d30fSSimon Glass 		ret = regulator_set_enable(dev, true);
300af41e8dbSPrzemyslaw Marczak 
301af41e8dbSPrzemyslaw Marczak 	return ret;
302af41e8dbSPrzemyslaw Marczak }
303af41e8dbSPrzemyslaw Marczak 
3043b55d30fSSimon Glass static void regulator_show(struct udevice *dev, int ret)
305af41e8dbSPrzemyslaw Marczak {
306af41e8dbSPrzemyslaw Marczak 	struct dm_regulator_uclass_platdata *uc_pdata;
3078152d3f6SJoseph Chen 	int uV = 0;
3083b55d30fSSimon Glass 
3093b55d30fSSimon Glass 	uc_pdata = dev_get_uclass_platdata(dev);
3108152d3f6SJoseph Chen 	uV = regulator_get_value(dev);
3113b55d30fSSimon Glass 
3128152d3f6SJoseph Chen 	printf("%25s@%15s: ", dev->name, uc_pdata->name);
3138152d3f6SJoseph Chen 	printf("%7duV <-> %7duV, set %7duV, %s",
3148152d3f6SJoseph Chen 	       uc_pdata->min_uV, uc_pdata->max_uV, uV,
315f98160cbSJoseph Chen 	       (uc_pdata->always_on || uc_pdata->boot_on) ?
3168152d3f6SJoseph Chen 	       "enabling" : "disabled");
3178152d3f6SJoseph Chen 
3188152d3f6SJoseph Chen 	printf(" | supsend %7duV, %s",
3198152d3f6SJoseph Chen 	       uc_pdata->suspend_uV,
3208152d3f6SJoseph Chen 	       uc_pdata->suspend_on ? "enabling" : "disabled");
3218152d3f6SJoseph Chen 	if (uc_pdata->init_uV != -ENODATA)
3228152d3f6SJoseph Chen 		printf(" ; init %7duV", uc_pdata->init_uV);
3238152d3f6SJoseph Chen 
3243b55d30fSSimon Glass 	if (ret)
3257d577999SSimon Glass 		printf(" (ret: %d)", ret);
326f98160cbSJoseph Chen 
3273b55d30fSSimon Glass 	printf("\n");
3283b55d30fSSimon Glass }
3293b55d30fSSimon Glass 
3303b55d30fSSimon Glass int regulator_autoset_by_name(const char *platname, struct udevice **devp)
3313b55d30fSSimon Glass {
332af41e8dbSPrzemyslaw Marczak 	struct udevice *dev;
333af41e8dbSPrzemyslaw Marczak 	int ret;
334af41e8dbSPrzemyslaw Marczak 
3353b880757SPrzemyslaw Marczak 	ret = regulator_get_by_platname(platname, &dev);
336af41e8dbSPrzemyslaw Marczak 	if (devp)
337af41e8dbSPrzemyslaw Marczak 		*devp = dev;
3383b55d30fSSimon Glass 	if (ret) {
339422f04b6SSimon Glass 		debug("Can get the regulator: %s (err=%d)\n", platname, ret);
340af41e8dbSPrzemyslaw Marczak 		return ret;
341af41e8dbSPrzemyslaw Marczak 	}
342af41e8dbSPrzemyslaw Marczak 
3433b55d30fSSimon Glass 	return regulator_autoset(dev);
3443b55d30fSSimon Glass }
3453b55d30fSSimon Glass 
3463b880757SPrzemyslaw Marczak int regulator_list_autoset(const char *list_platname[],
347af41e8dbSPrzemyslaw Marczak 			   struct udevice *list_devp[],
348af41e8dbSPrzemyslaw Marczak 			   bool verbose)
349af41e8dbSPrzemyslaw Marczak {
350af41e8dbSPrzemyslaw Marczak 	struct udevice *dev;
3513b880757SPrzemyslaw Marczak 	int error = 0, i = 0, ret;
352af41e8dbSPrzemyslaw Marczak 
3533b880757SPrzemyslaw Marczak 	while (list_platname[i]) {
3543b55d30fSSimon Glass 		ret = regulator_autoset_by_name(list_platname[i], &dev);
3553b55d30fSSimon Glass 		if (ret != -EMEDIUMTYPE && verbose)
3563b55d30fSSimon Glass 			regulator_show(dev, ret);
3573b880757SPrzemyslaw Marczak 		if (ret & !error)
3583b880757SPrzemyslaw Marczak 			error = ret;
359af41e8dbSPrzemyslaw Marczak 
3603b880757SPrzemyslaw Marczak 		if (list_devp)
361af41e8dbSPrzemyslaw Marczak 			list_devp[i] = dev;
3623b880757SPrzemyslaw Marczak 
3633b880757SPrzemyslaw Marczak 		i++;
364af41e8dbSPrzemyslaw Marczak 	}
365af41e8dbSPrzemyslaw Marczak 
3663b880757SPrzemyslaw Marczak 	return error;
3673b880757SPrzemyslaw Marczak }
3683b880757SPrzemyslaw Marczak 
3693b880757SPrzemyslaw Marczak static bool regulator_name_is_unique(struct udevice *check_dev,
3703b880757SPrzemyslaw Marczak 				     const char *check_name)
3713b880757SPrzemyslaw Marczak {
3723b880757SPrzemyslaw Marczak 	struct dm_regulator_uclass_platdata *uc_pdata;
3733b880757SPrzemyslaw Marczak 	struct udevice *dev;
3743b880757SPrzemyslaw Marczak 	int check_len = strlen(check_name);
3753b880757SPrzemyslaw Marczak 	int ret;
3763b880757SPrzemyslaw Marczak 	int len;
3773b880757SPrzemyslaw Marczak 
3783b880757SPrzemyslaw Marczak 	for (ret = uclass_find_first_device(UCLASS_REGULATOR, &dev); dev;
3793b880757SPrzemyslaw Marczak 	     ret = uclass_find_next_device(&dev)) {
3803b880757SPrzemyslaw Marczak 		if (ret || dev == check_dev)
3813b880757SPrzemyslaw Marczak 			continue;
3823b880757SPrzemyslaw Marczak 
3833b880757SPrzemyslaw Marczak 		uc_pdata = dev_get_uclass_platdata(dev);
3843b880757SPrzemyslaw Marczak 		len = strlen(uc_pdata->name);
3853b880757SPrzemyslaw Marczak 		if (len != check_len)
3863b880757SPrzemyslaw Marczak 			continue;
3873b880757SPrzemyslaw Marczak 
3883b880757SPrzemyslaw Marczak 		if (!strcmp(uc_pdata->name, check_name))
3893b880757SPrzemyslaw Marczak 			return false;
3903b880757SPrzemyslaw Marczak 	}
3913b880757SPrzemyslaw Marczak 
3923b880757SPrzemyslaw Marczak 	return true;
393af41e8dbSPrzemyslaw Marczak }
394af41e8dbSPrzemyslaw Marczak 
395af41e8dbSPrzemyslaw Marczak static int regulator_post_bind(struct udevice *dev)
396af41e8dbSPrzemyslaw Marczak {
397af41e8dbSPrzemyslaw Marczak 	struct dm_regulator_uclass_platdata *uc_pdata;
3983b880757SPrzemyslaw Marczak 	const char *property = "regulator-name";
399af41e8dbSPrzemyslaw Marczak 
400af41e8dbSPrzemyslaw Marczak 	uc_pdata = dev_get_uclass_platdata(dev);
401af41e8dbSPrzemyslaw Marczak 
402af41e8dbSPrzemyslaw Marczak 	/* Regulator's mandatory constraint */
403f15cd4f1SSimon Glass 	uc_pdata->name = dev_read_string(dev, property);
404af41e8dbSPrzemyslaw Marczak 	if (!uc_pdata->name) {
405f15cd4f1SSimon Glass 		debug("%s: dev '%s' has no property '%s'\n",
406f15cd4f1SSimon Glass 		      __func__, dev->name, property);
407f15cd4f1SSimon Glass 		uc_pdata->name = dev_read_name(dev);
408cf260011SPeng Fan 		if (!uc_pdata->name)
4093b880757SPrzemyslaw Marczak 			return -EINVAL;
410af41e8dbSPrzemyslaw Marczak 	}
411af41e8dbSPrzemyslaw Marczak 
4123b880757SPrzemyslaw Marczak 	if (regulator_name_is_unique(dev, uc_pdata->name))
413af41e8dbSPrzemyslaw Marczak 		return 0;
4143b880757SPrzemyslaw Marczak 
415f15cd4f1SSimon Glass 	debug("'%s' of dev: '%s', has nonunique value: '%s\n",
4163b880757SPrzemyslaw Marczak 	      property, dev->name, uc_pdata->name);
4173b880757SPrzemyslaw Marczak 
4183b880757SPrzemyslaw Marczak 	return -EINVAL;
419af41e8dbSPrzemyslaw Marczak }
420af41e8dbSPrzemyslaw Marczak 
421af41e8dbSPrzemyslaw Marczak static int regulator_pre_probe(struct udevice *dev)
422af41e8dbSPrzemyslaw Marczak {
423af41e8dbSPrzemyslaw Marczak 	struct dm_regulator_uclass_platdata *uc_pdata;
424fbc6dab9SJoseph Chen 	ofnode node;
425af41e8dbSPrzemyslaw Marczak 
426af41e8dbSPrzemyslaw Marczak 	uc_pdata = dev_get_uclass_platdata(dev);
427af41e8dbSPrzemyslaw Marczak 	if (!uc_pdata)
428af41e8dbSPrzemyslaw Marczak 		return -ENXIO;
429af41e8dbSPrzemyslaw Marczak 
430af41e8dbSPrzemyslaw Marczak 	/* Regulator's optional constraints */
431f15cd4f1SSimon Glass 	uc_pdata->min_uV = dev_read_u32_default(dev, "regulator-min-microvolt",
432f15cd4f1SSimon Glass 						-ENODATA);
433f15cd4f1SSimon Glass 	uc_pdata->max_uV = dev_read_u32_default(dev, "regulator-max-microvolt",
434f15cd4f1SSimon Glass 						-ENODATA);
4350e1b20c5SJoseph Chen 	uc_pdata->init_uV = dev_read_u32_default(dev, "regulator-init-microvolt",
4360e1b20c5SJoseph Chen 						-ENODATA);
437f15cd4f1SSimon Glass 	uc_pdata->min_uA = dev_read_u32_default(dev, "regulator-min-microamp",
438f15cd4f1SSimon Glass 						-ENODATA);
439f15cd4f1SSimon Glass 	uc_pdata->max_uA = dev_read_u32_default(dev, "regulator-max-microamp",
440f15cd4f1SSimon Glass 						-ENODATA);
441f15cd4f1SSimon Glass 	uc_pdata->always_on = dev_read_bool(dev, "regulator-always-on");
442f15cd4f1SSimon Glass 	uc_pdata->boot_on = dev_read_bool(dev, "regulator-boot-on");
4436999767bSJoseph Chen 	uc_pdata->ignore = dev_read_bool(dev, "regulator-loader-ignore");
444b29e2b63SJoseph Chen 	uc_pdata->ramp_delay = dev_read_u32_default(dev, "regulator-ramp-delay",
445b29e2b63SJoseph Chen 						    -ENODATA);
446fbc6dab9SJoseph Chen 	node = dev_read_subnode(dev, "regulator-state-mem");
447fbc6dab9SJoseph Chen 	if (ofnode_valid(node)) {
448fbc6dab9SJoseph Chen 		uc_pdata->suspend_on = !ofnode_read_bool(node, "regulator-off-in-suspend");
449fbc6dab9SJoseph Chen 		if (ofnode_read_u32(node, "regulator-suspend-microvolt", &uc_pdata->suspend_uV))
450fbc6dab9SJoseph Chen 			uc_pdata->suspend_uV = uc_pdata->max_uA;
451fbc6dab9SJoseph Chen 	} else {
452fbc6dab9SJoseph Chen 		uc_pdata->suspend_on = true;
453fbc6dab9SJoseph Chen 		uc_pdata->suspend_uV = uc_pdata->max_uA;
454fbc6dab9SJoseph Chen 	}
455fbc6dab9SJoseph Chen 
4567837ceabSSimon Glass 	/* Those values are optional (-ENODATA if unset) */
4577837ceabSSimon Glass 	if ((uc_pdata->min_uV != -ENODATA) &&
4587837ceabSSimon Glass 	    (uc_pdata->max_uV != -ENODATA) &&
4597837ceabSSimon Glass 	    (uc_pdata->min_uV == uc_pdata->max_uV))
4607837ceabSSimon Glass 		uc_pdata->flags |= REGULATOR_FLAG_AUTOSET_UV;
4617837ceabSSimon Glass 
4627837ceabSSimon Glass 	/* Those values are optional (-ENODATA if unset) */
4637837ceabSSimon Glass 	if ((uc_pdata->min_uA != -ENODATA) &&
4647837ceabSSimon Glass 	    (uc_pdata->max_uA != -ENODATA) &&
4657837ceabSSimon Glass 	    (uc_pdata->min_uA == uc_pdata->max_uA))
4667837ceabSSimon Glass 		uc_pdata->flags |= REGULATOR_FLAG_AUTOSET_UA;
4677837ceabSSimon Glass 
4682f22a22fSJoseph Chen 	debug("dev.name=%s: min_uV=%d, max_uV=%d, boot-on=%d, always-on=%d, "
4692f22a22fSJoseph Chen 	      "off-in-suspend=%d, suspend_volt=%d\n",
4702f22a22fSJoseph Chen 	      dev->name, uc_pdata->min_uV, uc_pdata->max_uV, uc_pdata->boot_on,
4712f22a22fSJoseph Chen 	      uc_pdata->always_on, !uc_pdata->suspend_on, uc_pdata->suspend_uV);
4722f22a22fSJoseph Chen 
473af41e8dbSPrzemyslaw Marczak 	return 0;
474af41e8dbSPrzemyslaw Marczak }
475af41e8dbSPrzemyslaw Marczak 
4760ae9790cSJoseph Chen int regulators_enable_state_mem(bool verbose)
4770ae9790cSJoseph Chen {
4780ae9790cSJoseph Chen 	struct udevice *dev;
4790ae9790cSJoseph Chen 	struct uclass *uc;
4800ae9790cSJoseph Chen 	int ret;
4810ae9790cSJoseph Chen 
4820ae9790cSJoseph Chen 	ret = uclass_get(UCLASS_REGULATOR, &uc);
4830ae9790cSJoseph Chen 	if (ret)
4840ae9790cSJoseph Chen 		return ret;
4850ae9790cSJoseph Chen 	for (uclass_first_device(UCLASS_REGULATOR, &dev);
4860ae9790cSJoseph Chen 	     dev;
4870ae9790cSJoseph Chen 	     uclass_next_device(&dev)) {
4880ae9790cSJoseph Chen 		ret = regulator_init_suspend(dev);
4890ae9790cSJoseph Chen 
4900ae9790cSJoseph Chen 		if (ret == -EMEDIUMTYPE)
4910ae9790cSJoseph Chen 			ret = 0;
4920ae9790cSJoseph Chen 		if (verbose)
4930ae9790cSJoseph Chen 			regulator_show(dev, ret);
4940ae9790cSJoseph Chen 		if (ret == -ENOSYS)
4950ae9790cSJoseph Chen 			ret = 0;
4960ae9790cSJoseph Chen 	}
4970ae9790cSJoseph Chen 
4980ae9790cSJoseph Chen 	return ret;
4990ae9790cSJoseph Chen }
5000ae9790cSJoseph Chen 
501083fc83aSSimon Glass int regulators_enable_boot_on(bool verbose)
502083fc83aSSimon Glass {
503083fc83aSSimon Glass 	struct udevice *dev;
504083fc83aSSimon Glass 	struct uclass *uc;
505083fc83aSSimon Glass 	int ret;
506083fc83aSSimon Glass 
507083fc83aSSimon Glass 	ret = uclass_get(UCLASS_REGULATOR, &uc);
508083fc83aSSimon Glass 	if (ret)
509083fc83aSSimon Glass 		return ret;
510083fc83aSSimon Glass 	for (uclass_first_device(UCLASS_REGULATOR, &dev);
5113f603cbbSSimon Glass 	     dev;
512083fc83aSSimon Glass 	     uclass_next_device(&dev)) {
513083fc83aSSimon Glass 		ret = regulator_autoset(dev);
5140ae9790cSJoseph Chen 
515f98160cbSJoseph Chen 		if (ret == -EMEDIUMTYPE)
516d08504d1SSimon Glass 			ret = 0;
517083fc83aSSimon Glass 		if (verbose)
518083fc83aSSimon Glass 			regulator_show(dev, ret);
519364809deSSimon Glass 		if (ret == -ENOSYS)
520364809deSSimon Glass 			ret = 0;
521083fc83aSSimon Glass 	}
522083fc83aSSimon Glass 
523083fc83aSSimon Glass 	return ret;
524083fc83aSSimon Glass }
525083fc83aSSimon Glass 
526af41e8dbSPrzemyslaw Marczak UCLASS_DRIVER(regulator) = {
527af41e8dbSPrzemyslaw Marczak 	.id		= UCLASS_REGULATOR,
528af41e8dbSPrzemyslaw Marczak 	.name		= "regulator",
529af41e8dbSPrzemyslaw Marczak 	.post_bind	= regulator_post_bind,
530af41e8dbSPrzemyslaw Marczak 	.pre_probe	= regulator_pre_probe,
531af41e8dbSPrzemyslaw Marczak 	.per_device_platdata_auto_alloc_size =
532af41e8dbSPrzemyslaw Marczak 				sizeof(struct dm_regulator_uclass_platdata),
533af41e8dbSPrzemyslaw Marczak };
534