From: Matthias Kaehlcke <mka@chromium.org>
To: Mark Brown <broonie@kernel.org>, lgirdwood@gmail.com
Cc: Douglas Anderson <dianders@chromium.org>,
briannorris@chromium.org, javier@dowhile0.org,
robh+dt@kernel.org, mark.rutland@arm.com,
linux-kernel@vger.kernel.org, devicetree@vger.kernel.org
Subject: [PATCH v4 1/4] regulator: Add set_voltage_time op
Date: Tue, 6 Sep 2016 14:01:25 -0700 [thread overview]
Message-ID: <20160906210125.GE79728@google.com> (raw)
The new op is analogous to set_voltage_time_sel. It can be used by
regulators that don't have a table of discrete voltages. The function
returns the time for the regulator voltage output voltage to stabilize
after being set to a new value, in microseconds. The actual calculation
of the stabilization time is done in the same place for both types of
regulators.
Signed-off-by: Matthias Kaehlcke <mka@chromium.org>
---
Changes in v4:
- This patch is new for v4.
drivers/regulator/core.c | 140 +++++++++++++++++++++++++--------------
include/linux/regulator/driver.h | 8 +++
2 files changed, 97 insertions(+), 51 deletions(-)
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index db320e8..b1cef47 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -2751,6 +2751,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
int best_val = 0;
unsigned int selector;
int old_selector = -1;
+ int old_uV = _regulator_get_voltage(rdev);
trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV);
@@ -2800,27 +2801,38 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
ret = -EINVAL;
}
- /* Call set_voltage_time_sel if successfully obtained old_selector */
- if (ret == 0 && !rdev->constraints->ramp_disable && old_selector >= 0
- && old_selector != selector) {
+ if (ret != 0 || rdev->constraints->ramp_disable)
+ goto no_delay;
- delay = rdev->desc->ops->set_voltage_time_sel(rdev,
- old_selector, selector);
- if (delay < 0) {
- rdev_warn(rdev, "set_voltage_time_sel() failed: %d\n",
- delay);
- delay = 0;
- }
+ if (rdev->desc->ops->set_voltage_time) {
+ int new_uV = _regulator_get_voltage(rdev);
- /* Insert any necessary delays */
- if (delay >= 1000) {
- mdelay(delay / 1000);
- udelay(delay % 1000);
- } else if (delay) {
- udelay(delay);
- }
+ if (old_uV == new_uV)
+ goto no_delay;
+
+ delay = rdev->desc->ops->set_voltage_time(rdev, old_uV, new_uV);
+ } else if (rdev->desc->ops->set_voltage_time_sel) {
+ if (old_selector < 0 || old_selector == selector)
+ goto no_delay;
+
+ delay = rdev->desc->ops->set_voltage_time_sel(
+ rdev, old_selector, selector);
+ }
+
+ if (delay < 0) {
+ rdev_warn(rdev, "failed to get delay: %d\n", delay);
+ delay = 0;
}
+ /* Insert any necessary delays */
+ if (delay >= 1000) {
+ mdelay(delay / 1000);
+ udelay(delay % 1000);
+ } else if (delay) {
+ udelay(delay);
+ }
+
+no_delay:
if (ret == 0 && best_val >= 0) {
unsigned long data = best_val;
@@ -2993,54 +3005,58 @@ int regulator_set_voltage_time(struct regulator *regulator,
{
struct regulator_dev *rdev = regulator->rdev;
const struct regulator_ops *ops = rdev->desc->ops;
- int old_sel = -1;
- int new_sel = -1;
- int voltage;
- int i;
- /* Currently requires operations to do this */
- if (!ops->list_voltage || !ops->set_voltage_time_sel
- || !rdev->desc->n_voltages)
- return -EINVAL;
+ if (ops->set_voltage_time) {
+ return ops->set_voltage_time(rdev, old_uV, new_uV);
+ } else if (ops->set_voltage_time_sel) {
+ int old_sel = -1;
+ int new_sel = -1;
+ int voltage;
+ int i;
- for (i = 0; i < rdev->desc->n_voltages; i++) {
- /* We only look for exact voltage matches here */
- voltage = regulator_list_voltage(regulator, i);
- if (voltage < 0)
+ /* Currently requires operations to do this */
+ if (!ops->list_voltage || !rdev->desc->n_voltages)
return -EINVAL;
- if (voltage == 0)
- continue;
- if (voltage == old_uV)
- old_sel = i;
- if (voltage == new_uV)
- new_sel = i;
- }
- if (old_sel < 0 || new_sel < 0)
- return -EINVAL;
+ for (i = 0; i < rdev->desc->n_voltages; i++) {
+ /* We only look for exact voltage matches here */
+ voltage = regulator_list_voltage(regulator, i);
+ if (voltage < 0)
+ return -EINVAL;
+ if (voltage == 0)
+ continue;
+ if (voltage == old_uV)
+ old_sel = i;
+ if (voltage == new_uV)
+ new_sel = i;
+ }
+
+ if (old_sel < 0 || new_sel < 0)
+ return -EINVAL;
+
+ return ops->set_voltage_time_sel(rdev, old_sel, new_sel);
+ }
- return ops->set_voltage_time_sel(rdev, old_sel, new_sel);
+ return -EINVAL;
}
EXPORT_SYMBOL_GPL(regulator_set_voltage_time);
/**
- * regulator_set_voltage_time_sel - get raise/fall time
- * @rdev: regulator source device
- * @old_selector: selector for starting voltage
- * @new_selector: selector for target voltage
+ * regulator_set_voltage_time_op - get raise/fall time
+ * @regulator: regulator source
+ * @old_uV: starting voltage in microvolts
+ * @new_uV: target voltage in microvolts
*
- * Provided with the starting and target voltage selectors, this function
- * returns time in microseconds required to rise or fall to this new voltage
+ * Provided with the starting and ending voltage, this function calculates
+ * the time in microseconds required to rise or fall to this new voltage.
*
* Drivers providing ramp_delay in regulation_constraints can use this as their
- * set_voltage_time_sel() operation.
+ * set_voltage_time() operation.
*/
-int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
- unsigned int old_selector,
- unsigned int new_selector)
+int regulator_set_voltage_time_op(struct regulator_dev *rdev,
+ int old_uV, int new_uV)
{
unsigned int ramp_delay = 0;
- int old_volt, new_volt;
if (rdev->constraints->ramp_delay)
ramp_delay = rdev->constraints->ramp_delay;
@@ -3052,6 +3068,28 @@ int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
return 0;
}
+ return DIV_ROUND_UP(abs(new_uV - old_uV), ramp_delay);
+}
+EXPORT_SYMBOL_GPL(regulator_set_voltage_time_op);
+
+/**
+ * regulator_set_voltage_time_sel - get raise/fall time
+ * @rdev: regulator source device
+ * @old_selector: selector for starting voltage
+ * @new_selector: selector for target voltage
+ *
+ * Provided with the starting and target voltage selectors, this function
+ * returns time in microseconds required to rise or fall to this new voltage
+ *
+ * Drivers providing ramp_delay in regulation_constraints can use this as their
+ * set_voltage_time_sel() operation.
+ */
+int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
+ unsigned int old_selector,
+ unsigned int new_selector)
+{
+ int old_volt, new_volt;
+
/* sanity check */
if (!rdev->desc->ops->list_voltage)
return -EINVAL;
@@ -3059,7 +3097,7 @@ int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
old_volt = rdev->desc->ops->list_voltage(rdev, old_selector);
new_volt = rdev->desc->ops->list_voltage(rdev, new_selector);
- return DIV_ROUND_UP(abs(new_volt - old_volt), ramp_delay);
+ return regulator_set_voltage_time_op(rdev, old_volt, new_volt);
}
EXPORT_SYMBOL_GPL(regulator_set_voltage_time_sel);
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index fcfa40a..537ca7f 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -113,6 +113,10 @@ struct regulator_linear_range {
* stabilise after being enabled, in microseconds.
* @set_ramp_delay: Set the ramp delay for the regulator. The driver should
* select ramp delay equal to or less than(closest) ramp_delay.
+ * @set_voltage_time: Time taken for the regulator voltage output voltage
+ * to stabilise after being set to a new value, in microseconds.
+ * The function provides the from and to voltage, the function
+ * should return the worst case.
* @set_voltage_time_sel: Time taken for the regulator voltage output voltage
* to stabilise after being set to a new value, in microseconds.
* The function provides the from and to voltage selector, the
@@ -168,6 +172,8 @@ struct regulator_ops {
/* Time taken to enable or set voltage on the regulator */
int (*enable_time) (struct regulator_dev *);
int (*set_ramp_delay) (struct regulator_dev *, int ramp_delay);
+ int (*set_voltage_time) (struct regulator_dev *,
+ int old_uV, int new_uV);
int (*set_voltage_time_sel) (struct regulator_dev *,
unsigned int old_selector,
unsigned int new_selector);
@@ -461,6 +467,8 @@ int regulator_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned sel);
int regulator_is_enabled_regmap(struct regulator_dev *rdev);
int regulator_enable_regmap(struct regulator_dev *rdev);
int regulator_disable_regmap(struct regulator_dev *rdev);
+int regulator_set_voltage_time_op(struct regulator_dev *rdev,
+ int old_uV, int new_uV);
int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
unsigned int old_selector,
unsigned int new_selector);
--
2.8.0.rc3.226.g39d4020
next reply other threads:[~2016-09-06 21:01 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-09-06 21:01 Matthias Kaehlcke [this message]
[not found] ` <20160906210125.GE79728-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
2016-09-06 22:40 ` [PATCH v4 1/4] regulator: Add set_voltage_time op Mark Brown
2016-09-06 22:40 ` Mark Brown
[not found] ` <20160906224054.GX3950-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
2016-09-06 23:38 ` Mark Brown
2016-09-06 23:38 ` Mark Brown
2016-09-06 23:46 ` Matthias Kaehlcke
-- strict thread matches above, loose matches on Subject: below --
2016-09-06 20:14 Matthias Kaehlcke
2016-09-06 19:03 Matthias Kaehlcke
[not found] ` <20160906190315.GC92391-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
2016-09-12 18:32 ` Mark Brown
2016-09-12 18:32 ` Mark Brown
[not found] ` <20160912183230.GF27946-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
2016-09-12 23:18 ` Matthias Kaehlcke
2016-09-12 23:18 ` Matthias Kaehlcke
2016-09-12 23:57 ` Mark Brown
[not found] ` <20160912235758.GO27946-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
2016-09-13 1:18 ` Matthias Kaehlcke
2016-09-13 1:18 ` Matthias Kaehlcke
[not found] ` <20160913011831.GB62872-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
2016-09-13 19:12 ` Matthias Kaehlcke
2016-09-13 19:12 ` Matthias Kaehlcke
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20160906210125.GE79728@google.com \
--to=mka@chromium.org \
--cc=briannorris@chromium.org \
--cc=broonie@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=dianders@chromium.org \
--cc=javier@dowhile0.org \
--cc=lgirdwood@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=robh+dt@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.