aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugen Hristev <eugen.hristev@collabora.com>2023-04-19 16:45:24 +0300
committerJaehoon Chung <jh80.chung@samsung.com>2023-07-04 11:20:56 +0900
commit4fcba5d556b4224ad65a249801e4c9594d1054e8 (patch)
tree125ce902241179e38ac7a0a7a26b758df4c35a19
parent67d8b46e6efa306403e45f4c76f24b86a5e63b75 (diff)
downloadu-boot-4fcba5d556b4224ad65a249801e4c9594d1054e8.zip
u-boot-4fcba5d556b4224ad65a249801e4c9594d1054e8.tar.gz
u-boot-4fcba5d556b4224ad65a249801e4c9594d1054e8.tar.bz2
regulator: implement basic reference counter
Some devices share a regulator supply, when the first one will request regulator disable, the second device will have it's supply cut off before graciously shutting down. Hence there will be timeouts and other failed operations. Implement a reference counter mechanism similar with what is done in Linux, to keep track of enable and disable requests, and only disable the regulator when the last of the consumers has requested shutdown. Signed-off-by: Eugen Hristev <eugen.hristev@collabora.com> Reviewed-by: Simon Glass <sjg@chromium.org> Reviewed-by: Patrice Chotard <patrice.chotard@foss.st.com>
-rw-r--r--drivers/power/regulator/regulator_common.c22
-rw-r--r--drivers/power/regulator/regulator_common.h21
2 files changed, 43 insertions, 0 deletions
diff --git a/drivers/power/regulator/regulator_common.c b/drivers/power/regulator/regulator_common.c
index 93d8196..484a4fc 100644
--- a/drivers/power/regulator/regulator_common.c
+++ b/drivers/power/regulator/regulator_common.c
@@ -73,6 +73,23 @@ int regulator_common_set_enable(const struct udevice *dev,
return 0;
}
+ /* If previously enabled, increase count */
+ if (enable && dev_pdata->enable_count > 0) {
+ dev_pdata->enable_count++;
+ return -EALREADY;
+ }
+
+ if (!enable) {
+ if (dev_pdata->enable_count > 1) {
+ /* If enabled multiple times, decrease count */
+ dev_pdata->enable_count--;
+ return -EBUSY;
+ } else if (!dev_pdata->enable_count) {
+ /* If already disabled, do nothing */
+ return -EALREADY;
+ }
+ }
+
ret = dm_gpio_set_value(&dev_pdata->gpio, enable);
if (ret) {
pr_err("Can't set regulator : %s gpio to: %d\n", dev->name,
@@ -87,5 +104,10 @@ int regulator_common_set_enable(const struct udevice *dev,
if (!enable && dev_pdata->off_on_delay_us)
udelay(dev_pdata->off_on_delay_us);
+ if (enable)
+ dev_pdata->enable_count++;
+ else
+ dev_pdata->enable_count--;
+
return 0;
}
diff --git a/drivers/power/regulator/regulator_common.h b/drivers/power/regulator/regulator_common.h
index c10492f..0faab44 100644
--- a/drivers/power/regulator/regulator_common.h
+++ b/drivers/power/regulator/regulator_common.h
@@ -13,6 +13,7 @@ struct regulator_common_plat {
struct gpio_desc gpio; /* GPIO for regulator enable control */
unsigned int startup_delay_us;
unsigned int off_on_delay_us;
+ unsigned int enable_count;
};
int regulator_common_of_to_plat(struct udevice *dev,
@@ -20,6 +21,26 @@ int regulator_common_of_to_plat(struct udevice *dev,
char *enable_gpio_name);
int regulator_common_get_enable(const struct udevice *dev,
struct regulator_common_plat *dev_pdata);
+/*
+ * Enable or Disable a regulator
+ *
+ * This is a reentrant function and subsequent calls that enable will
+ * increase an internal counter, and disable calls will decrease the counter.
+ * The actual resource will be enabled when the counter gets to 1 coming from 0,
+ * and disabled when it reaches 0 coming from 1.
+ *
+ * @dev: regulator device
+ * @dev_pdata: Platform data
+ * @enable: bool indicating whether to enable or disable the regulator
+ * @return:
+ * 0 on Success
+ * -EBUSY if the regulator cannot be disabled because it's requested by
+ * another device
+ * -EALREADY if the regulator has already been enabled or has already been
+ * disabled
+ * -EACCES if there is no possibility to enable/disable the regulator
+ * -ve on different error situation
+ */
int regulator_common_set_enable(const struct udevice *dev,
struct regulator_common_plat *dev_pdata, bool enable);