[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-Id: <20190704163255.2611D2742EB1@ypsilon.sirena.org.uk>
Date: Thu, 4 Jul 2019 17:32:55 +0100 (BST)
From: Mark Brown <broonie@...nel.org>
To: Bartosz Golaszewski <bgolaszewski@...libre.com>
Cc: Liam Girdwood <lgirdwood@...il.com>, linux-kernel@...r.kernel.org,
Mark Brown <broonie@...nel.org>
Subject: Applied "regulator: implement selector stepping" to the regulator tree
The patch
regulator: implement selector stepping
has been applied to the regulator tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git for-5.3
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
>From 2da8d9473e20a2f6645dcb0cea4848a2c1e83af9 Mon Sep 17 00:00:00 2001
From: Bartosz Golaszewski <bgolaszewski@...libre.com>
Date: Wed, 3 Jul 2019 18:10:34 +0200
Subject: [PATCH] regulator: implement selector stepping
Some regulators require that the requested voltage be reached gradually
by setting all or some of the intermediate values. Implement a new field
in the regulator description struct that allows users to specify the
number of selectors by which the regulator API should step when ramping
the voltage up/down.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@...libre.com>
Link: https://lore.kernel.org/r/20190703161035.31808-2-brgl@bgdev.pl
Signed-off-by: Mark Brown <broonie@...nel.org>
---
drivers/regulator/core.c | 63 ++++++++++++++++++++++++++++++++
include/linux/regulator/driver.h | 6 +++
2 files changed, 69 insertions(+)
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 9d3ed13b7f12..df82e2a8442a 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -3106,6 +3106,66 @@ static int _regulator_call_set_voltage_sel(struct regulator_dev *rdev,
return ret;
}
+static int _regulator_set_voltage_sel_step(struct regulator_dev *rdev,
+ int uV, int new_selector)
+{
+ const struct regulator_ops *ops = rdev->desc->ops;
+ int diff, old_sel, curr_sel, ret;
+
+ /* Stepping is only needed if the regulator is enabled. */
+ if (!_regulator_is_enabled(rdev))
+ goto final_set;
+
+ if (!ops->get_voltage_sel)
+ return -EINVAL;
+
+ old_sel = ops->get_voltage_sel(rdev);
+ if (old_sel < 0)
+ return old_sel;
+
+ diff = new_selector - old_sel;
+ if (diff == 0)
+ return 0; /* No change needed. */
+
+ if (diff > 0) {
+ /* Stepping up. */
+ for (curr_sel = old_sel + rdev->desc->vsel_step;
+ curr_sel < new_selector;
+ curr_sel += rdev->desc->vsel_step) {
+ /*
+ * Call the callback directly instead of using
+ * _regulator_call_set_voltage_sel() as we don't
+ * want to notify anyone yet. Same in the branch
+ * below.
+ */
+ ret = ops->set_voltage_sel(rdev, curr_sel);
+ if (ret)
+ goto try_revert;
+ }
+ } else {
+ /* Stepping down. */
+ for (curr_sel = old_sel - rdev->desc->vsel_step;
+ curr_sel > new_selector;
+ curr_sel -= rdev->desc->vsel_step) {
+ ret = ops->set_voltage_sel(rdev, curr_sel);
+ if (ret)
+ goto try_revert;
+ }
+ }
+
+final_set:
+ /* The final selector will trigger the notifiers. */
+ return _regulator_call_set_voltage_sel(rdev, uV, new_selector);
+
+try_revert:
+ /*
+ * At least try to return to the previous voltage if setting a new
+ * one failed.
+ */
+ (void)ops->set_voltage_sel(rdev, old_sel);
+ return ret;
+}
+
static int _regulator_set_voltage_time(struct regulator_dev *rdev,
int old_uV, int new_uV)
{
@@ -3179,6 +3239,9 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
selector = ret;
if (old_selector == selector)
ret = 0;
+ else if (rdev->desc->vsel_step)
+ ret = _regulator_set_voltage_sel_step(
+ rdev, best_val, selector);
else
ret = _regulator_call_set_voltage_sel(
rdev, best_val, selector);
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index 377da2357118..f0d7b0496e54 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -286,6 +286,11 @@ enum regulator_type {
* @vsel_range_mask: Mask for register bitfield used for range selector
* @vsel_reg: Register for selector when using regulator_regmap_X_voltage_
* @vsel_mask: Mask for register bitfield used for selector
+ * @vsel_step: Specify the resolution of selector stepping when setting
+ * voltage. If 0, then no stepping is done (requested selector is
+ * set directly), if >0 then the regulator API will ramp the
+ * voltage up/down gradually each time increasing/decreasing the
+ * selector by the specified step value.
* @csel_reg: Register for current limit selector using regmap set_current_limit
* @csel_mask: Mask for register bitfield used for current limit selector
* @apply_reg: Register for initiate voltage change on the output when
@@ -360,6 +365,7 @@ struct regulator_desc {
unsigned int vsel_range_mask;
unsigned int vsel_reg;
unsigned int vsel_mask;
+ unsigned int vsel_step;
unsigned int csel_reg;
unsigned int csel_mask;
unsigned int apply_reg;
--
2.20.1
Powered by blists - more mailing lists