Don't set use_count for regulators that are enabled at boot since this
stops the supply being disabled by well-behaved consumers which do
balanced enables and disabled. Any consumers which don't do disables
which are not matched by enables are unable to share regulators - shared
regulators are the common case so the API should facilitate them.
Consumers that want to disable regulators that are enabled when they
start have two options:
- Do a regulator_enable() prior to the disable to bring the use count
in sync with the hardware state; this will ensure that if the
regulator was enabled by another driver then this consumer will play
nicely with it.
- Use regulator_force_disable(); this explicitly bypasses any checks
done by the core and documents the inability of the driver to share
the supply.
Signed-off-by: Mark Brown <[email protected]>
---
drivers/regulator/core.c | 1 -
1 files changed, 0 insertions(+), 1 deletions(-)
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 9448875..8588a24 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -814,7 +814,6 @@ static int set_machine_constraints(struct regulator_dev *rdev,
rdev->constraints = NULL;
goto out;
}
- rdev->use_count = 1;
}
print_constraints(rdev);
--
1.6.2
At present it is not possible for machine constraints to disable
regulators which have been left on when the system starts, for example
as a result of fixed default configurations in hardware. This means that
power may be wasted by these regulators if they are not in use.
Provide intial support for this with a late_initcall which will disable
any unused regulators if the machine has enabled this feature by calling
regulator_has_full_constraints(). If this has not been called then print
a warning to encourage users to fully specify their constraints so that
we can change this to be the default behaviour in future.
Signed-off-by: Mark Brown <[email protected]>
---
drivers/regulator/core.c | 92 +++++++++++++++++++++++++++++++++++++
include/linux/regulator/machine.h | 2 +
2 files changed, 94 insertions(+), 0 deletions(-)
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 8588a24..01f7702 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -28,6 +28,7 @@
static DEFINE_MUTEX(regulator_list_mutex);
static LIST_HEAD(regulator_list);
static LIST_HEAD(regulator_map_list);
+static int has_full_constraints;
/*
* struct regulator_map
@@ -2143,6 +2144,23 @@ out:
EXPORT_SYMBOL_GPL(regulator_suspend_prepare);
/**
+ * regulator_has_full_constraints - the system has fully specified constraints
+ *
+ * Calling this function will cause the regulator API to disable all
+ * regulators which have a zero use count and don't have an always_on
+ * constraint in a late_initcall.
+ *
+ * The intention is that this will become the default behaviour in a
+ * future kernel release so users are encouraged to use this facility
+ * now.
+ */
+void regulator_has_full_constraints(void)
+{
+ has_full_constraints = 1;
+}
+EXPORT_SYMBOL_GPL(regulator_has_full_constraints);
+
+/**
* rdev_get_drvdata - get rdev regulator driver data
* @rdev: regulator
*
@@ -2209,3 +2227,77 @@ static int __init regulator_init(void)
/* init early to allow our consumers to complete system booting */
core_initcall(regulator_init);
+
+static int __init regulator_init_complete(void)
+{
+ struct regulator_dev *rdev;
+ struct regulator_ops *ops;
+ struct regulation_constraints *c;
+ int enabled, ret;
+ const char *name;
+
+ mutex_lock(®ulator_list_mutex);
+
+ /* If we have a full configuration then disable any regulators
+ * which are not in use or always_on. This will become the
+ * default behaviour in the future.
+ */
+ list_for_each_entry(rdev, ®ulator_list, list) {
+ ops = rdev->desc->ops;
+ c = rdev->constraints;
+
+ if (c->name)
+ name = c->name;
+ else if (rdev->desc->name)
+ name = rdev->desc->name;
+ else
+ name = "regulator";
+
+ if (!ops->disable || c->always_on)
+ continue;
+
+ mutex_lock(&rdev->mutex);
+
+ if (rdev->use_count)
+ goto unlock;
+
+ /* If we can't read the status assume it's on. */
+ if (ops->is_enabled)
+ enabled = ops->is_enabled(rdev);
+ else
+ enabled = 1;
+
+ if (!enabled)
+ goto unlock;
+
+ if (has_full_constraints) {
+ /* We log since this may kill the system if it
+ * goes wrong. */
+ printk(KERN_INFO "%s: disabling %s\n",
+ __func__, name);
+ ret = ops->disable(rdev);
+ if (ret != 0) {
+ printk(KERN_ERR
+ "%s: couldn't disable %s: %d\n",
+ __func__, name, ret);
+ }
+ } else {
+ /* The intention is that in future we will
+ * assume that full constraints are provided
+ * so warn even if we aren't going to do
+ * anything here.
+ */
+ printk(KERN_WARNING
+ "%s: incomplete constraints, leaving %s on\n",
+ __func__, name);
+ }
+
+unlock:
+ mutex_unlock(&rdev->mutex);
+ }
+
+ mutex_unlock(®ulator_list_mutex);
+
+ return 0;
+}
+late_initcall(regulator_init_complete);
diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h
index 5de7aa3..bac64fa 100644
--- a/include/linux/regulator/machine.h
+++ b/include/linux/regulator/machine.h
@@ -166,4 +166,6 @@ struct regulator_init_data {
int regulator_suspend_prepare(suspend_state_t state);
+void regulator_has_full_constraints(void);
+
#endif
--
1.6.2
On Mon, 2009-03-16 at 19:36 +0000, Mark Brown wrote:
> Don't set use_count for regulators that are enabled at boot since this
> stops the supply being disabled by well-behaved consumers which do
> balanced enables and disabled. Any consumers which don't do disables
> which are not matched by enables are unable to share regulators - shared
> regulators are the common case so the API should facilitate them.
>
> Consumers that want to disable regulators that are enabled when they
> start have two options:
>
> - Do a regulator_enable() prior to the disable to bring the use count
> in sync with the hardware state; this will ensure that if the
> regulator was enabled by another driver then this consumer will play
> nicely with it.
> - Use regulator_force_disable(); this explicitly bypasses any checks
> done by the core and documents the inability of the driver to share
> the supply.
>
> Signed-off-by: Mark Brown <[email protected]>
> ---
> drivers/regulator/core.c | 1 -
> 1 files changed, 0 insertions(+), 1 deletions(-)
Applied.
Thanks
Liam
On Mon, 2009-03-16 at 19:36 +0000, Mark Brown wrote:
> At present it is not possible for machine constraints to disable
> regulators which have been left on when the system starts, for example
> as a result of fixed default configurations in hardware. This means that
> power may be wasted by these regulators if they are not in use.
>
> Provide intial support for this with a late_initcall which will disable
> any unused regulators if the machine has enabled this feature by calling
> regulator_has_full_constraints(). If this has not been called then print
> a warning to encourage users to fully specify their constraints so that
> we can change this to be the default behaviour in future.
>
> Signed-off-by: Mark Brown <[email protected]>
> ---
> drivers/regulator/core.c | 92 +++++++++++++++++++++++++++++++++++++
> include/linux/regulator/machine.h | 2 +
> 2 files changed, 94 insertions(+), 0 deletions(-)
>
Applied.
Thanks
Liam