From cffc9592fde309deafce12362e0a285108cfa3c8 Mon Sep 17 00:00:00 2001
From: Axel Lin <axel.lin@gmail.com>
Date: Sun, 20 May 2012 10:30:21 +0800
Subject: regulator: core: Allow drivers to set voltage mapping table in
 regulator_desc

Some regulator hardware use table based mapping can set volt_table in
regulator_desc and use regulator_list_voltage_table() for their list_voltage
callback.

Signed-off-by: Axel Lin <axel.lin@gmail.com>
Acked-by: Liam Girdwood <lrg@ti.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 drivers/regulator/core.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

(limited to 'drivers/regulator/core.c')

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 7584a74eec8a..333b7ebe7cae 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1882,6 +1882,31 @@ int regulator_list_voltage_linear(struct regulator_dev *rdev,
 }
 EXPORT_SYMBOL_GPL(regulator_list_voltage_linear);
 
+/**
+ * regulator_list_voltage_table - List voltages with table based mapping
+ *
+ * @rdev: Regulator device
+ * @selector: Selector to convert into a voltage
+ *
+ * Regulators with table based mapping between voltages and
+ * selectors can set volt_table in the regulator descriptor
+ * and then use this function as their list_voltage() operation.
+ */
+int regulator_list_voltage_table(struct regulator_dev *rdev,
+				 unsigned int selector)
+{
+	if (!rdev->desc->volt_table) {
+		BUG_ON(!rdev->desc->volt_table);
+		return -EINVAL;
+	}
+
+	if (selector >= rdev->desc->n_voltages)
+		return -EINVAL;
+
+	return rdev->desc->volt_table[selector];
+}
+EXPORT_SYMBOL_GPL(regulator_list_voltage_table);
+
 /**
  * regulator_list_voltage - enumerate supported voltages
  * @regulator: regulator source
-- 
cgit v1.2.3


From 8b7485ef623b9171e5a58c67eef5912a27db5822 Mon Sep 17 00:00:00 2001
From: Axel Lin <axel.lin@gmail.com>
Date: Mon, 21 May 2012 09:37:52 +0800
Subject: regulator: core: Call set_voltage_time_sel() only when the regulator
 is on

If the regulator is not on, it won't take time setting new voltage.
So only call set_voltage_time_sel() to get the necessary delay when
the regulator is on.

Signed-off-by: Axel Lin <axel.lin@gmail.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 drivers/regulator/core.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

(limited to 'drivers/regulator/core.c')

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 333b7ebe7cae..58a4749c6347 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -2106,7 +2106,8 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
 	 * If we can't obtain the old selector there is not enough
 	 * info to call set_voltage_time_sel().
 	 */
-	if (rdev->desc->ops->set_voltage_time_sel &&
+	if (_regulator_is_enabled(rdev) &&
+	    rdev->desc->ops->set_voltage_time_sel &&
 	    rdev->desc->ops->get_voltage_sel) {
 		old_selector = rdev->desc->ops->get_voltage_sel(rdev);
 		if (old_selector < 0)
@@ -2138,7 +2139,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
 		best_val = -1;
 
 	/* Call set_voltage_time_sel if successfully obtained old_selector */
-	if (ret == 0 && old_selector >= 0 &&
+	if (_regulator_is_enabled(rdev) && ret == 0 && old_selector >= 0 &&
 	    rdev->desc->ops->set_voltage_time_sel) {
 
 		delay = rdev->desc->ops->set_voltage_time_sel(rdev,
-- 
cgit v1.2.3


From 361ff5017446605dca8b0a084c826e3d2a0d0a99 Mon Sep 17 00:00:00 2001
From: Mark Brown <broonie@opensource.wolfsonmicro.com>
Date: Mon, 7 May 2012 14:14:30 +0100
Subject: regulator: Use newly added devres_release() rather than open coding

devres_release() will call the destructor for the resource as well as
freeing the devres data.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Acked-by: Liam Girdwood <lrg@ti.com>
---
 drivers/regulator/core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'drivers/regulator/core.c')

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 58a4749c6347..7965e86a3fbb 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1459,7 +1459,7 @@ void devm_regulator_put(struct regulator *regulator)
 {
 	int rc;
 
-	rc = devres_destroy(regulator->dev, devm_regulator_release,
+	rc = devres_release(regulator->dev, devm_regulator_release,
 			    devm_regulator_match, regulator);
 	if (rc == 0)
 		regulator_put(regulator);
-- 
cgit v1.2.3


From 3a4b0a07fa69cbfbdd4bc2ebe769cf789949db46 Mon Sep 17 00:00:00 2001
From: Mark Brown <broonie@opensource.wolfsonmicro.com>
Date: Tue, 8 May 2012 18:10:45 +0100
Subject: regulator: core: Use dev_get_regmap() to find the regmap

If no regmap is explicitly specified then use dev_get_regmap() to obtain
one. The driver must explicitly enable any actual usage of the regmap
so there's no concern with unwanted usage.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Acked-by: Liam Girdwood <lrg@ti.com>
---
 drivers/regulator/core.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

(limited to 'drivers/regulator/core.c')

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 7965e86a3fbb..8521e0d6b3bc 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -3128,7 +3128,10 @@ regulator_register(const struct regulator_desc *regulator_desc,
 	rdev->reg_data = config->driver_data;
 	rdev->owner = regulator_desc->owner;
 	rdev->desc = regulator_desc;
-	rdev->regmap = config->regmap;
+	if (config->regmap)
+		rdev->regmap = config->regmap;
+	else
+		rdev->regmap = dev_get_regmap(dev, NULL);
 	INIT_LIST_HEAD(&rdev->consumer_list);
 	INIT_LIST_HEAD(&rdev->list);
 	BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier);
-- 
cgit v1.2.3


From 9152c36a3b37a95c1161508dc105719456d7f7d0 Mon Sep 17 00:00:00 2001
From: Axel Lin <axel.lin@gmail.com>
Date: Mon, 4 Jun 2012 09:41:38 +0800
Subject: regulator: core: Use map_voltage_linear() if list_voltage_linear() is
 in use and nothing is set

Signed-off-by: Axel Lin <axel.lin@gmail.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 drivers/regulator/core.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

(limited to 'drivers/regulator/core.c')

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 8521e0d6b3bc..3cbe3129ed3b 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -2118,12 +2118,18 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
 		ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV,
 						   &selector);
 	} else if (rdev->desc->ops->set_voltage_sel) {
-		if (rdev->desc->ops->map_voltage)
+		if (rdev->desc->ops->map_voltage) {
 			ret = rdev->desc->ops->map_voltage(rdev, min_uV,
 							   max_uV);
-		else
-			ret = regulator_map_voltage_iterate(rdev, min_uV,
-							    max_uV);
+		} else {
+			if (rdev->desc->ops->list_voltage ==
+			    regulator_list_voltage_linear)
+				ret = regulator_map_voltage_linear(rdev,
+								min_uV, max_uV);
+			else
+				ret = regulator_map_voltage_iterate(rdev,
+								min_uV, max_uV);
+		}
 
 		if (ret >= 0) {
 			selector = ret;
-- 
cgit v1.2.3


From 5a6881e8e134ea636bbc8423049e84638dbb7106 Mon Sep 17 00:00:00 2001
From: Axel Lin <axel.lin@gmail.com>
Date: Thu, 7 Jun 2012 10:05:14 +0800
Subject: regulator: core: Handle fixed voltage in map_voltage_linear

Fixed voltage is a kind of linear mapping where n_voltages is 1.
This change allows [list|map]_voltage_linear to be used for fixed
voltage.

For fixed voltage, n_voltages is 1 and the only valid selector is 0.
Thus we actually don't care the uV_step setting.

Signed-off-by: Axel Lin <axel.lin@gmail.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 drivers/regulator/core.c | 8 ++++++++
 1 file changed, 8 insertions(+)

(limited to 'drivers/regulator/core.c')

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 8521e0d6b3bc..5c6aedaa934d 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -2070,6 +2070,14 @@ int regulator_map_voltage_linear(struct regulator_dev *rdev,
 {
 	int ret, voltage;
 
+	/* Allow uV_step to be 0 for fixed voltage */
+	if (rdev->desc->n_voltages == 1 && rdev->desc->uV_step == 0) {
+		if (min_uV <= rdev->desc->min_uV && rdev->desc->min_uV <= max_uV)
+			return 0;
+		else
+			return -EINVAL;
+	}
+
 	if (!rdev->desc->uV_step) {
 		BUG_ON(!rdev->desc->uV_step);
 		return -EINVAL;
-- 
cgit v1.2.3


From 98a175b60f46a80dfa44fb0e0807f2e5a351f35f Mon Sep 17 00:00:00 2001
From: Yadwinder Singh Brar <yadi.brar01@gmail.com>
Date: Sat, 9 Jun 2012 16:40:38 +0530
Subject: regulator: core: Add regulator_set_voltage_time_sel to calculate ramp
 delay.

This patch adds regulator_set_voltage_time_sel(), to move into core, the
commonly used code by drivers to provide the .set_voltage_time_sel callback.
It will also allow us to configure different ramp delay for different
regulators easily.

Signed-off-by: Yadwinder Singh Brar <yadi.brar@samsung.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 drivers/regulator/core.c         | 24 ++++++++++++++++++++++++
 include/linux/regulator/driver.h |  5 +++++
 2 files changed, 29 insertions(+)

(limited to 'drivers/regulator/core.c')

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 5c6aedaa934d..ff76abde3ab3 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -2279,6 +2279,30 @@ int regulator_set_voltage_time(struct regulator *regulator,
 }
 EXPORT_SYMBOL_GPL(regulator_set_voltage_time);
 
+/**
+ *regulator_set_voltage_time_sel - get raise/fall time
+ * @regulator: regulator source
+ * @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 uV_step in their regulator_desc and 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)
+{
+	if (rdev->desc->ramp_delay && rdev->desc->uV_step)
+		return DIV_ROUND_UP(rdev->desc->uV_step *
+			abs(new_selector - old_selector),
+			rdev->desc->ramp_delay) * 1000;
+	return 0;
+}
+
 /**
  * regulator_sync_voltage - re-apply last regulator output voltage
  * @regulator: regulator source
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index 80226383e561..ae5c25379237 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -170,6 +170,7 @@ enum regulator_type {
  *
  * @min_uV: Voltage given by the lowest selector (if linear mapping)
  * @uV_step: Voltage increase with each selector (if linear mapping)
+ * @ramp_delay: Time to settle down after voltage change (unit: mV/us)
  * @volt_table: Voltage mapping table (if table based mapping)
  *
  * @vsel_reg: Register for selector when using regulator_regmap_X_voltage_
@@ -189,6 +190,7 @@ struct regulator_desc {
 
 	unsigned int min_uV;
 	unsigned int uV_step;
+	unsigned int ramp_delay;
 
 	const unsigned int *volt_table;
 
@@ -285,6 +287,9 @@ 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_sel(struct regulator_dev *rdev,
+				   unsigned int old_selector,
+				   unsigned int new_selector);
 
 void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data);
 
-- 
cgit v1.2.3


From 578df8babf3b1895d562e1ea0d3a81d1e77e0182 Mon Sep 17 00:00:00 2001
From: Axel Lin <axel.lin@gmail.com>
Date: Mon, 11 Jun 2012 13:14:50 +0800
Subject: regulator: core: Return correct delay time in
 regulator_set_voltage_time_sel

rdev->desc->uV_step * abs(new_selector - old_selector) returns uV.
The unit of ramp_delay is mV/us.

Current code multiples 1000 at wrong place.

Signed-off-by: Axel Lin <axel.lin@gmail.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 drivers/regulator/core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'drivers/regulator/core.c')

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index ff76abde3ab3..6ffca9b32388 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -2299,7 +2299,7 @@ int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
 	if (rdev->desc->ramp_delay && rdev->desc->uV_step)
 		return DIV_ROUND_UP(rdev->desc->uV_step *
 			abs(new_selector - old_selector),
-			rdev->desc->ramp_delay) * 1000;
+			rdev->desc->ramp_delay * 1000);
 	return 0;
 }
 
-- 
cgit v1.2.3


From d8493d210b69b2965236a8a02f5f6e2835ad5e30 Mon Sep 17 00:00:00 2001
From: Mark Brown <broonie@opensource.wolfsonmicro.com>
Date: Fri, 15 Jun 2012 19:09:09 +0100
Subject: regulator: core: Actually use the data in _notifier_call_chain()

Reported-by: Pankaj Jangra <jangra.pankaj9@gmail.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 drivers/regulator/core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'drivers/regulator/core.c')

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 3cbe3129ed3b..52a9bae10393 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -2657,7 +2657,7 @@ static void _notifier_call_chain(struct regulator_dev *rdev,
 				  unsigned long event, void *data)
 {
 	/* call rdev chain first */
-	blocking_notifier_call_chain(&rdev->notifier, event, NULL);
+	blocking_notifier_call_chain(&rdev->notifier, event, data);
 }
 
 /**
-- 
cgit v1.2.3


From 2f7baf89d3e4ed787989168cf31f2fdc04067586 Mon Sep 17 00:00:00 2001
From: Philip Rakity <prakity@marvell.com>
Date: Fri, 15 Jun 2012 11:27:36 -0700
Subject: regulator: core.c Pass voltage to notifier when setting voltage

The voltage being set should be passed to the call in handler
requesting the callback.  Currently this is not done.

The calling handler cannot call regulator_get_voltage() to get the
information since the mutex is held by the regulator and
deadlock occurs.

Without this change the receiver of the call in cannot know what
action to take.  This is used, for example, to set PAD voltages
when doing SD vccq voltage changes.

[Review and spelling fix in the commit log from Pankaj Jangra]

Signed-off-by: Philip Rakity <prakity@marvell.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 drivers/regulator/core.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

(limited to 'drivers/regulator/core.c')

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 52a9bae10393..ebdd9e0e14d4 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -2142,7 +2142,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
 	if (rdev->desc->ops->list_voltage)
 		best_val = rdev->desc->ops->list_voltage(rdev, selector);
 	else
-		best_val = -1;
+		best_val = _regulator_get_voltage(rdev);
 
 	/* Call set_voltage_time_sel if successfully obtained old_selector */
 	if (_regulator_is_enabled(rdev) && ret == 0 && old_selector >= 0 &&
@@ -2165,9 +2165,9 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
 		udelay(delay);
 	}
 
-	if (ret == 0)
+	if (ret == 0 && best_val >= 0)
 		_notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE,
-				     NULL);
+				     (void *)best_val);
 
 	trace_regulator_set_voltage_complete(rdev_get_name(rdev), best_val);
 
-- 
cgit v1.2.3


From 8b96de31b0cf190fb6b21c4ab1ce310c430b72ae Mon Sep 17 00:00:00 2001
From: Philip Rakity <prakity@marvell.com>
Date: Thu, 14 Jun 2012 15:07:56 -0700
Subject: regulator: core.c Only delay when setting voltage requires this

minor optimization: move delay code to where delay is set and
thus where it is used vs in the main line path.

Signed-off-by: Philip Rakity <prakity@marvell.com>
Acked-by: Axel Lin <axel.lin@gmail.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 drivers/regulator/core.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

(limited to 'drivers/regulator/core.c')

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index ebdd9e0e14d4..663ebd534ef9 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -2155,14 +2155,14 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
 				  delay);
 			delay = 0;
 		}
-	}
 
-	/* Insert any necessary delays */
-	if (delay >= 1000) {
-		mdelay(delay / 1000);
-		udelay(delay % 1000);
-	} else if (delay) {
-		udelay(delay);
+		/* Insert any necessary delays */
+		if (delay >= 1000) {
+			mdelay(delay / 1000);
+			udelay(delay % 1000);
+		} else if (delay) {
+			udelay(delay);
+		}
 	}
 
 	if (ret == 0 && best_val >= 0)
-- 
cgit v1.2.3


From 6f0b2c696ca340cc2da381fe693fda3f8fdb2149 Mon Sep 17 00:00:00 2001
From: Yadwinder Singh Brar <yadi.brar01@gmail.com>
Date: Mon, 11 Jun 2012 17:41:08 +0530
Subject: regulator: Add ramp_delay configuration to constraints

For some hardwares ramp_delay for BUCKs is a configurable parameter which can
be configured through DT or board file.This patch adds ramp_delay to regulator
constraints and allow user to configure it for regulators which supports this
feature, through DT or board file. It will provide two ways of setting the
ramp_delay for a regulator:
	First, by setting it as constraints in board file(for configurable
regulators) and set_machine_constraints() will take care of setting it on
hardware by calling(the provided) .set_ramp_delay() operation(callback).
	Second, by setting it as data in regulator_desc(as fixed/default
ramp_delay rate) for a regulator in driver.

regulator_set_voltage_time_sel() will give preference to
constraints->ramp_delay while reading ramp_delay rate for regulator. Similarly
users should also take care accordingly while refering ramp_delay rate(in case
of implementing their private .set_voltage_time_sel() callbacks for different
regulators).

[Rewrote subject for 80 columns -- broonie]

Signed-off-by: Yadwinder Singh Brar <yadi.brar@samsung.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 .../devicetree/bindings/regulator/regulator.txt    |  1 +
 drivers/regulator/core.c                           | 23 ++++++++++++++++++----
 drivers/regulator/of_regulator.c                   |  6 +++++-
 include/linux/regulator/driver.h                   |  3 +++
 include/linux/regulator/machine.h                  |  3 +++
 5 files changed, 31 insertions(+), 5 deletions(-)

(limited to 'drivers/regulator/core.c')

diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt
index 5b7a408acdaa..d0a7b1296a36 100644
--- a/Documentation/devicetree/bindings/regulator/regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/regulator.txt
@@ -10,6 +10,7 @@ Optional properties:
 - regulator-always-on: boolean, regulator should never be disabled
 - regulator-boot-on: bootloader/firmware enabled regulator
 - <name>-supply: phandle to the parent supply/regulator node
+- regulator-ramp-delay: ramp delay for regulator(in mV/uS)
 
 Example:
 
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 6ffca9b32388..b615ae6606db 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -967,6 +967,14 @@ static int set_machine_constraints(struct regulator_dev *rdev,
 		}
 	}
 
+	if (rdev->constraints->ramp_delay && ops->set_ramp_delay) {
+		ret = ops->set_ramp_delay(rdev, rdev->constraints->ramp_delay);
+		if (ret < 0) {
+			rdev_err(rdev, "failed to set ramp_delay\n");
+			goto out;
+		}
+	}
+
 	print_constraints(rdev);
 	return 0;
 out:
@@ -2296,10 +2304,17 @@ int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
 				   unsigned int old_selector,
 				   unsigned int new_selector)
 {
-	if (rdev->desc->ramp_delay && rdev->desc->uV_step)
-		return DIV_ROUND_UP(rdev->desc->uV_step *
-			abs(new_selector - old_selector),
-			rdev->desc->ramp_delay * 1000);
+	if (rdev->desc->uV_step) {
+		if (rdev->constraints->ramp_delay)
+			return DIV_ROUND_UP(rdev->desc->uV_step *
+				abs(new_selector - old_selector),
+				rdev->constraints->ramp_delay * 1000);
+		if (rdev->desc->ramp_delay)
+			return DIV_ROUND_UP(rdev->desc->uV_step *
+				abs(new_selector - old_selector),
+				rdev->desc->ramp_delay * 1000);
+		rdev_warn(rdev, "ramp_delay not set\n");
+	}
 	return 0;
 }
 
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
index 56593b75168a..e2a731079066 100644
--- a/drivers/regulator/of_regulator.c
+++ b/drivers/regulator/of_regulator.c
@@ -20,7 +20,7 @@ static void of_get_regulation_constraints(struct device_node *np,
 					struct regulator_init_data **init_data)
 {
 	const __be32 *min_uV, *max_uV, *uV_offset;
-	const __be32 *min_uA, *max_uA;
+	const __be32 *min_uA, *max_uA, *ramp_delay;
 	struct regulation_constraints *constraints = &(*init_data)->constraints;
 
 	constraints->name = of_get_property(np, "regulator-name", NULL);
@@ -60,6 +60,10 @@ static void of_get_regulation_constraints(struct device_node *np,
 		constraints->always_on = true;
 	else /* status change should be possible if not always on. */
 		constraints->valid_ops_mask |= REGULATOR_CHANGE_STATUS;
+
+	ramp_delay = of_get_property(np, "regulator-ramp-delay", NULL);
+	if (ramp_delay)
+		constraints->min_uV = be32_to_cpu(*ramp_delay);
 }
 
 /**
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index ae5c25379237..ddc155d262da 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -67,6 +67,8 @@ enum regulator_status {
  *
  * @enable_time: Time taken for the regulator voltage output voltage to
  *               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_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
@@ -113,6 +115,7 @@ 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_sel) (struct regulator_dev *,
 				     unsigned int old_selector,
 				     unsigned int new_selector);
diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h
index b02108446be7..5f37ad3cc172 100644
--- a/include/linux/regulator/machine.h
+++ b/include/linux/regulator/machine.h
@@ -92,6 +92,7 @@ struct regulator_state {
  *                 mode.
  * @initial_state: Suspend state to set by default.
  * @initial_mode: Mode to set at startup.
+ * @ramp_delay: Time to settle down after voltage change (unit: mV/us)
  */
 struct regulation_constraints {
 
@@ -125,6 +126,8 @@ struct regulation_constraints {
 	/* mode to set on startup */
 	unsigned int initial_mode;
 
+	unsigned int ramp_delay;
+
 	/* constraint flags */
 	unsigned always_on:1;	/* regulator never off when system is on */
 	unsigned boot_on:1;	/* bootloader/firmware enabled regulator */
-- 
cgit v1.2.3


From 398715ab9414b3b7741c8239c254111f5016821c Mon Sep 17 00:00:00 2001
From: Axel Lin <axel.lin@gmail.com>
Date: Mon, 18 Jun 2012 10:11:28 +0800
Subject: regulator: core: Support table based mapping in
 regulator_set_voltage_time_sel

For table based mapping, we can calculate voltage difference by below equation:
abs(rdev->desc->volt_table[new_selector] - rdev->desc->volt_table[old_selector])

Thus we can make regulator_set_voltage_time_sel work for table based mapping.

regulator_set_voltage_time_sel() only supports linear or table based mapping.
In case it is misused, also warn if neither linear nor table based mapping
is used with regulator_set_voltage_time_sel().

Signed-off-by: Axel Lin <axel.lin@gmail.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 drivers/regulator/core.c | 37 +++++++++++++++++++++++++------------
 1 file changed, 25 insertions(+), 12 deletions(-)

(limited to 'drivers/regulator/core.c')

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index b615ae6606db..73a3d874ca6e 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -2296,25 +2296,38 @@ EXPORT_SYMBOL_GPL(regulator_set_voltage_time);
  * 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 uV_step in their regulator_desc and ramp_delay in
- * regulation_constraints can use this as their set_voltage_time_sel()
- * operation.
+ * Drivers providing uV_step or volt_table in their regulator_desc and
+ * 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)
 {
-	if (rdev->desc->uV_step) {
-		if (rdev->constraints->ramp_delay)
-			return DIV_ROUND_UP(rdev->desc->uV_step *
-				abs(new_selector - old_selector),
-				rdev->constraints->ramp_delay * 1000);
-		if (rdev->desc->ramp_delay)
-			return DIV_ROUND_UP(rdev->desc->uV_step *
-				abs(new_selector - old_selector),
-				rdev->desc->ramp_delay * 1000);
+	unsigned int ramp_delay = 0;
+
+	if (rdev->constraints->ramp_delay)
+		ramp_delay = rdev->constraints->ramp_delay;
+	else if (rdev->desc->ramp_delay)
+		ramp_delay = rdev->desc->ramp_delay;
+
+	if (ramp_delay == 0) {
 		rdev_warn(rdev, "ramp_delay not set\n");
+		return 0;
 	}
+
+	if (rdev->desc->uV_step) {
+		return DIV_ROUND_UP(rdev->desc->uV_step *
+				    abs(new_selector - old_selector),
+				    ramp_delay * 1000);
+	} else if (rdev->desc->volt_table) {
+		return DIV_ROUND_UP(abs(rdev->desc->volt_table[new_selector] -
+					rdev->desc->volt_table[old_selector]),
+				    ramp_delay * 1000);
+	} else {
+		rdev_warn(rdev, "Unsupported voltage mapping settings\n");
+	}
+
 	return 0;
 }
 
-- 
cgit v1.2.3


From ea38d13fd1666bc030cb1c0feec5b0da2f89f9b2 Mon Sep 17 00:00:00 2001
From: Axel Lin <axel.lin@gmail.com>
Date: Mon, 18 Jun 2012 14:03:16 +0800
Subject: regulator: core: Change the unit of ramp_delay from mV/uS to uV/uS

This change makes it possible to set ramp_delay with 0.xxx mV/uS without
truncation issue.

Signed-off-by: Axel Lin <axel.lin@gmail.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 Documentation/devicetree/bindings/regulator/regulator.txt | 2 +-
 drivers/regulator/core.c                                  | 4 ++--
 include/linux/regulator/driver.h                          | 2 +-
 include/linux/regulator/machine.h                         | 2 +-
 4 files changed, 5 insertions(+), 5 deletions(-)

(limited to 'drivers/regulator/core.c')

diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt
index d0a7b1296a36..bec5d5747411 100644
--- a/Documentation/devicetree/bindings/regulator/regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/regulator.txt
@@ -10,7 +10,7 @@ Optional properties:
 - regulator-always-on: boolean, regulator should never be disabled
 - regulator-boot-on: bootloader/firmware enabled regulator
 - <name>-supply: phandle to the parent supply/regulator node
-- regulator-ramp-delay: ramp delay for regulator(in mV/uS)
+- regulator-ramp-delay: ramp delay for regulator(in uV/uS)
 
 Example:
 
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 73a3d874ca6e..ce0a3462e0de 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -2319,11 +2319,11 @@ int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
 	if (rdev->desc->uV_step) {
 		return DIV_ROUND_UP(rdev->desc->uV_step *
 				    abs(new_selector - old_selector),
-				    ramp_delay * 1000);
+				    ramp_delay);
 	} else if (rdev->desc->volt_table) {
 		return DIV_ROUND_UP(abs(rdev->desc->volt_table[new_selector] -
 					rdev->desc->volt_table[old_selector]),
-				    ramp_delay * 1000);
+				    ramp_delay);
 	} else {
 		rdev_warn(rdev, "Unsupported voltage mapping settings\n");
 	}
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index ddc155d262da..84f999ed394b 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -173,7 +173,7 @@ enum regulator_type {
  *
  * @min_uV: Voltage given by the lowest selector (if linear mapping)
  * @uV_step: Voltage increase with each selector (if linear mapping)
- * @ramp_delay: Time to settle down after voltage change (unit: mV/us)
+ * @ramp_delay: Time to settle down after voltage change (unit: uV/us)
  * @volt_table: Voltage mapping table (if table based mapping)
  *
  * @vsel_reg: Register for selector when using regulator_regmap_X_voltage_
diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h
index 5f37ad3cc172..40dd0a394cfa 100644
--- a/include/linux/regulator/machine.h
+++ b/include/linux/regulator/machine.h
@@ -92,7 +92,7 @@ struct regulator_state {
  *                 mode.
  * @initial_state: Suspend state to set by default.
  * @initial_mode: Mode to set at startup.
- * @ramp_delay: Time to settle down after voltage change (unit: mV/us)
+ * @ramp_delay: Time to settle down after voltage change (unit: uV/us)
  */
 struct regulation_constraints {
 
-- 
cgit v1.2.3


From 230a5a1c41464f7fe5b676c21280ae4effa222c8 Mon Sep 17 00:00:00 2001
From: Mark Brown <broonie@opensource.wolfsonmicro.com>
Date: Fri, 15 Jun 2012 18:25:08 +0100
Subject: regulator: Fix double free in devm_regulator_put()

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 drivers/regulator/core.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

(limited to 'drivers/regulator/core.c')

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 663ebd534ef9..729b20d1c1de 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1461,9 +1461,7 @@ void devm_regulator_put(struct regulator *regulator)
 
 	rc = devres_release(regulator->dev, devm_regulator_release,
 			    devm_regulator_match, regulator);
-	if (rc == 0)
-		regulator_put(regulator);
-	else
+	if (rc != 0)
 		WARN_ON(rc);
 }
 EXPORT_SYMBOL_GPL(devm_regulator_put);
-- 
cgit v1.2.3


From b19dbf711e8dae026f8d014eae90d766d02f4acb Mon Sep 17 00:00:00 2001
From: Mark Brown <broonie@opensource.wolfsonmicro.com>
Date: Sat, 23 Jun 2012 11:34:20 +0100
Subject: regulator: core: Add export of regulator_set_voltage_time_sel()

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 drivers/regulator/core.c | 1 +
 1 file changed, 1 insertion(+)

(limited to 'drivers/regulator/core.c')

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index ce0a3462e0de..26b71048709b 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -2330,6 +2330,7 @@ int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(regulator_set_voltage_time_sel);
 
 /**
  * regulator_sync_voltage - re-apply last regulator output voltage
-- 
cgit v1.2.3


From f11d08c3d611d6f2845677caabe13b2c58f95658 Mon Sep 17 00:00:00 2001
From: Axel Lin <axel.lin@gmail.com>
Date: Tue, 19 Jun 2012 09:38:45 +0800
Subject: regulator: Use list_voltage() to get voltage in
 regulator_set_voltage_time_sel

With this change, regulator_set_voltage_time_sel() can be more generic and not
limited to linear and table based mapping now.
One side-effect of this change is that list_voltage() must be implemented.

Signed-off-by: Axel Lin <axel.lin@gmail.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 drivers/regulator/core.c | 23 +++++++++--------------
 1 file changed, 9 insertions(+), 14 deletions(-)

(limited to 'drivers/regulator/core.c')

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 26b71048709b..e3597ab09be3 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -2296,8 +2296,7 @@ EXPORT_SYMBOL_GPL(regulator_set_voltage_time);
  * 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 uV_step or volt_table in their regulator_desc and
- * ramp_delay in regulation_constraints can use this as their
+ * 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,
@@ -2305,6 +2304,7 @@ int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
 				   unsigned int new_selector)
 {
 	unsigned int ramp_delay = 0;
+	int old_volt, new_volt;
 
 	if (rdev->constraints->ramp_delay)
 		ramp_delay = rdev->constraints->ramp_delay;
@@ -2316,19 +2316,14 @@ int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
 		return 0;
 	}
 
-	if (rdev->desc->uV_step) {
-		return DIV_ROUND_UP(rdev->desc->uV_step *
-				    abs(new_selector - old_selector),
-				    ramp_delay);
-	} else if (rdev->desc->volt_table) {
-		return DIV_ROUND_UP(abs(rdev->desc->volt_table[new_selector] -
-					rdev->desc->volt_table[old_selector]),
-				    ramp_delay);
-	} else {
-		rdev_warn(rdev, "Unsupported voltage mapping settings\n");
-	}
+	/* sanity check */
+	if (!rdev->desc->ops->list_voltage)
+		return -EINVAL;
 
-	return 0;
+	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);
 }
 EXPORT_SYMBOL_GPL(regulator_set_voltage_time_sel);
 
-- 
cgit v1.2.3


From 5aff3a8b20c54888e199e863744848007f1f4120 Mon Sep 17 00:00:00 2001
From: Mark Brown <broonie@opensource.wolfsonmicro.com>
Date: Tue, 26 Jun 2012 11:16:58 +0100
Subject: regulator: core: Check for failed voltage sets before checking for
 delay

There is no need to consider waiting for the voltage to ramp if we
didn't manage to set it and looking at the return value is going to be
cheaper than is_enabled().

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 drivers/regulator/core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'drivers/regulator/core.c')

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 729b20d1c1de..890fa5eb770d 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -2143,7 +2143,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
 		best_val = _regulator_get_voltage(rdev);
 
 	/* Call set_voltage_time_sel if successfully obtained old_selector */
-	if (_regulator_is_enabled(rdev) && ret == 0 && old_selector >= 0 &&
+	if (ret == 0 && _regulator_is_enabled(rdev) && old_selector >= 0 &&
 	    rdev->desc->ops->set_voltage_time_sel) {
 
 		delay = rdev->desc->ops->set_voltage_time_sel(rdev,
-- 
cgit v1.2.3


From 222cc7b1cefbab1287ed5d5e3cce1f45aec60d39 Mon Sep 17 00:00:00 2001
From: Mark Brown <broonie@opensource.wolfsonmicro.com>
Date: Fri, 22 Jun 2012 11:39:16 +0100
Subject: regulator: core: Allow multiple requests of a single supply mapping

Sometimes it may be useful to allow a device to request a supply multiple
times, for example in order to allow framework management of some uses of
the supply with some additional driver specific management or in order to
allow multiple children of an MFD to work with the supply. Currently this
is not possible due to the creation of

Solve this by removing the requested_uA entry (we have no current users
of this feature anyway) and ignoring errors creating the symlink to the
consumer. We should do something nicer than this as this causes sysfs to
spew enormous warnings but it allows users to run for now.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Acked-by: Liam Girdwood <lrg@ti.com>
---
 drivers/regulator/core.c | 49 +++++-------------------------------------------
 1 file changed, 5 insertions(+), 44 deletions(-)

(limited to 'drivers/regulator/core.c')

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 890fa5eb770d..00c787c01f3b 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -303,18 +303,6 @@ static int regulator_check_drms(struct regulator_dev *rdev)
 	return 0;
 }
 
-static ssize_t device_requested_uA_show(struct device *dev,
-			     struct device_attribute *attr, char *buf)
-{
-	struct regulator *regulator;
-
-	regulator = get_device_regulator(dev);
-	if (regulator == NULL)
-		return 0;
-
-	return sprintf(buf, "%d\n", regulator->uA_load);
-}
-
 static ssize_t regulator_uV_show(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
@@ -1097,48 +1085,27 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
 	list_add(&regulator->list, &rdev->consumer_list);
 
 	if (dev) {
-		/* create a 'requested_microamps_name' sysfs entry */
-		size = scnprintf(buf, REG_STR_SIZE,
-				 "microamps_requested_%s-%s",
-				 dev_name(dev), supply_name);
-		if (size >= REG_STR_SIZE)
-			goto overflow_err;
-
-		regulator->dev = dev;
-		sysfs_attr_init(&regulator->dev_attr.attr);
-		regulator->dev_attr.attr.name = kstrdup(buf, GFP_KERNEL);
-		if (regulator->dev_attr.attr.name == NULL)
-			goto attr_name_err;
-
-		regulator->dev_attr.attr.mode = 0444;
-		regulator->dev_attr.show = device_requested_uA_show;
-		err = device_create_file(dev, &regulator->dev_attr);
-		if (err < 0) {
-			rdev_warn(rdev, "could not add regulator_dev requested microamps sysfs entry\n");
-			goto attr_name_err;
-		}
-
-		/* also add a link to the device sysfs entry */
+		/* Add a link to the device sysfs entry */
 		size = scnprintf(buf, REG_STR_SIZE, "%s-%s",
 				 dev->kobj.name, supply_name);
 		if (size >= REG_STR_SIZE)
-			goto attr_err;
+			goto overflow_err;
 
 		regulator->supply_name = kstrdup(buf, GFP_KERNEL);
 		if (regulator->supply_name == NULL)
-			goto attr_err;
+			goto overflow_err;
 
 		err = sysfs_create_link(&rdev->dev.kobj, &dev->kobj,
 					buf);
 		if (err) {
 			rdev_warn(rdev, "could not add device link %s err %d\n",
 				  dev->kobj.name, err);
-			goto link_name_err;
+			/* non-fatal */
 		}
 	} else {
 		regulator->supply_name = kstrdup(supply_name, GFP_KERNEL);
 		if (regulator->supply_name == NULL)
-			goto attr_err;
+			goto overflow_err;
 	}
 
 	regulator->debugfs = debugfs_create_dir(regulator->supply_name,
@@ -1165,12 +1132,6 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
 
 	mutex_unlock(&rdev->mutex);
 	return regulator;
-link_name_err:
-	kfree(regulator->supply_name);
-attr_err:
-	device_remove_file(regulator->dev, &regulator->dev_attr);
-attr_name_err:
-	kfree(regulator->dev_attr.attr.name);
 overflow_err:
 	list_del(&regulator->list);
 	kfree(regulator);
-- 
cgit v1.2.3


From bf2516cd020dbf80ed2f1750ac1f4b0da3549c91 Mon Sep 17 00:00:00 2001
From: Fabio Estevam <fabio.estevam@freescale.com>
Date: Wed, 27 Jun 2012 10:40:28 -0300
Subject: regulator: core: Remove unused get_device_regulator

commit 222cc7b1 (regulator: core: Allow multiple requests of a single supply mapping)
removed the usage of get_device_regulator().

Remove the function definition too amd get rid of the following warning:

drivers/regulator/core.c:112:26: warning: 'get_device_regulator' defined but not used [-Wunused-function]

Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 drivers/regulator/core.c | 22 ----------------------
 1 file changed, 22 deletions(-)

(limited to 'drivers/regulator/core.c')

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 00c787c01f3b..d886ee265e47 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -108,28 +108,6 @@ static const char *rdev_get_name(struct regulator_dev *rdev)
 		return "";
 }
 
-/* gets the regulator for a given consumer device */
-static struct regulator *get_device_regulator(struct device *dev)
-{
-	struct regulator *regulator = NULL;
-	struct regulator_dev *rdev;
-
-	mutex_lock(&regulator_list_mutex);
-	list_for_each_entry(rdev, &regulator_list, list) {
-		mutex_lock(&rdev->mutex);
-		list_for_each_entry(regulator, &rdev->consumer_list, list) {
-			if (regulator->dev == dev) {
-				mutex_unlock(&rdev->mutex);
-				mutex_unlock(&regulator_list_mutex);
-				return regulator;
-			}
-		}
-		mutex_unlock(&rdev->mutex);
-	}
-	mutex_unlock(&regulator_list_mutex);
-	return NULL;
-}
-
 /**
  * of_get_regulator - get a regulator device node based on supply name
  * @dev: Device pointer for the consumer (of regulator) device
-- 
cgit v1.2.3


From c5f3939b8fe0c358d35397982e5afdef112afc81 Mon Sep 17 00:00:00 2001
From: Mark Brown <broonie@opensource.wolfsonmicro.com>
Date: Mon, 2 Jul 2012 15:00:18 +0100
Subject: regulator: core: Support fixed voltages in
 regulator_is_supported_voltage()

Currently regulator_is_supported_voltage() works by enumerating the set
of voltages which can be set by the regulator but the checks we're doing
to impose constraints mean that if we can't vary the voltage we'll not
report any voltages as supported even though the regulator is actually
set at that voltage.

We could fix the voltage listing but this would mean that list_voltage()
could end up going to the hardware to get the current voltage which isn't
expected (it's supposed to be very cheap) so instead special case things
when we can't change the voltage and compare the requested range against
the current voltage.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 drivers/regulator/core.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

(limited to 'drivers/regulator/core.c')

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index d886ee265e47..a80886626230 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1890,8 +1890,18 @@ EXPORT_SYMBOL_GPL(regulator_list_voltage);
 int regulator_is_supported_voltage(struct regulator *regulator,
 				   int min_uV, int max_uV)
 {
+	struct regulator_dev *rdev = regulator->rdev;
 	int i, voltages, ret;
 
+	/* If we can't change voltage check the current voltage */
+	if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) {
+		ret = regulator_get_voltage(regulator);
+		if (ret >= 0)
+			return (min_uV >= ret && ret <= max_uV);
+		else
+			return ret;
+	}
+
 	ret = regulator_count_voltages(regulator);
 	if (ret < 0)
 		return ret;
-- 
cgit v1.2.3


From e113d792d56d4b720b3d84c122b6af84c3bfa094 Mon Sep 17 00:00:00 2001
From: Mark Brown <broonie@opensource.wolfsonmicro.com>
Date: Tue, 26 Jun 2012 10:57:51 +0100
Subject: regulator: core: Check that the selector from map_voltage() is valid

Lots of regulator drivers have checks in their map_voltage() functions
to verify that the result of the mapping is in the range originally
specified. Factor these out in the core and provide a bit of extra
defensiveness for other drivers by doing the check in the core.

Since we're now doing a list_voltage() earlier move the current mapping
back to a voltage out into the set_voltage() call to save redoing it.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 drivers/regulator/core.c | 26 ++++++++++++++++++--------
 1 file changed, 18 insertions(+), 8 deletions(-)

(limited to 'drivers/regulator/core.c')

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index a80886626230..f98a8ee29933 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -2040,7 +2040,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
 {
 	int ret;
 	int delay = 0;
-	int best_val;
+	int best_val = 0;
 	unsigned int selector;
 	int old_selector = -1;
 
@@ -2064,6 +2064,15 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
 	if (rdev->desc->ops->set_voltage) {
 		ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV,
 						   &selector);
+
+		if (ret >= 0) {
+			if (rdev->desc->ops->list_voltage)
+				best_val = rdev->desc->ops->list_voltage(rdev,
+									 selector);
+			else
+				best_val = _regulator_get_voltage(rdev);
+		}
+
 	} else if (rdev->desc->ops->set_voltage_sel) {
 		if (rdev->desc->ops->map_voltage) {
 			ret = rdev->desc->ops->map_voltage(rdev, min_uV,
@@ -2079,18 +2088,19 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
 		}
 
 		if (ret >= 0) {
-			selector = ret;
-			ret = rdev->desc->ops->set_voltage_sel(rdev, ret);
+			best_val = rdev->desc->ops->list_voltage(rdev, ret);
+			if (min_uV <= best_val && max_uV >= best_val) {
+				selector = ret;
+				ret = rdev->desc->ops->set_voltage_sel(rdev,
+								       ret);
+			} else {
+				ret = -EINVAL;
+			}
 		}
 	} else {
 		ret = -EINVAL;
 	}
 
-	if (rdev->desc->ops->list_voltage)
-		best_val = rdev->desc->ops->list_voltage(rdev, selector);
-	else
-		best_val = _regulator_get_voltage(rdev);
-
 	/* Call set_voltage_time_sel if successfully obtained old_selector */
 	if (ret == 0 && _regulator_is_enabled(rdev) && old_selector >= 0 &&
 	    rdev->desc->ops->set_voltage_time_sel) {
-- 
cgit v1.2.3


From 79511ed3225a64f6b7fc749f4f9c1ed82f24f729 Mon Sep 17 00:00:00 2001
From: Mark Brown <broonie@opensource.wolfsonmicro.com>
Date: Wed, 27 Jun 2012 14:23:10 +0100
Subject: regulator: core: Allow fixed enable_time to be set in the
 regulator_desc

Many regulators have a fixed specification for their enable time. Allow
this to be set in the regulator_desc as a number to save them having to
implement an explicit operation.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 drivers/regulator/core.c         | 2 +-
 include/linux/regulator/driver.h | 4 ++++
 2 files changed, 5 insertions(+), 1 deletion(-)

(limited to 'drivers/regulator/core.c')

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index aa82c0465f4f..6e488aa6f1e8 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1189,7 +1189,7 @@ overflow_err:
 static int _regulator_get_enable_time(struct regulator_dev *rdev)
 {
 	if (!rdev->desc->ops->enable_time)
-		return 0;
+		return rdev->desc->enable_time;
 	return rdev->desc->ops->enable_time(rdev);
 }
 
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index 84f999ed394b..176bd4335581 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -180,6 +180,8 @@ enum regulator_type {
  * @vsel_mask: Mask for register bitfield used for selector
  * @enable_reg: Register for control when using regmap enable/disable ops
  * @enable_mask: Mask for control when using regmap enable/disable ops
+ *
+ * @enable_time: Time taken for initial enable of regulator (in uS).
  */
 struct regulator_desc {
 	const char *name;
@@ -201,6 +203,8 @@ struct regulator_desc {
 	unsigned int vsel_mask;
 	unsigned int enable_reg;
 	unsigned int enable_mask;
+
+	unsigned int enable_time;
 };
 
 /**
-- 
cgit v1.2.3


From 5c5659d0a22ec4f947ef4faa3055767572f15e74 Mon Sep 17 00:00:00 2001
From: Mark Brown <broonie@opensource.wolfsonmicro.com>
Date: Wed, 27 Jun 2012 13:21:26 +0100
Subject: regulator: core: Factor out enable and disable operations some more

Create new _regulator_do_enable() and _regulator_do_disable() operations
which deal with the mechanics of performing the enable and disable, partly
to cut down on the levels of indentation and partly to support some future
work.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 drivers/regulator/core.c | 110 +++++++++++++++++++++++++++++------------------
 1 file changed, 68 insertions(+), 42 deletions(-)

(limited to 'drivers/regulator/core.c')

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 6e488aa6f1e8..82650a16a975 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1476,10 +1476,50 @@ void devm_regulator_put(struct regulator *regulator)
 }
 EXPORT_SYMBOL_GPL(devm_regulator_put);
 
+static int _regulator_do_enable(struct regulator_dev *rdev)
+{
+	int ret, delay;
+
+	/* Query before enabling in case configuration dependent.  */
+	ret = _regulator_get_enable_time(rdev);
+	if (ret >= 0) {
+		delay = ret;
+	} else {
+		rdev_warn(rdev, "enable_time() failed: %d\n", ret);
+		delay = 0;
+	}
+
+	trace_regulator_enable(rdev_get_name(rdev));
+
+	if (rdev->desc->ops->enable) {
+		ret = rdev->desc->ops->enable(rdev);
+		if (ret < 0)
+			return ret;
+	} else {
+		return -EINVAL;
+	}
+
+	/* Allow the regulator to ramp; it would be useful to extend
+	 * this for bulk operations so that the regulators can ramp
+	 * together.  */
+	trace_regulator_enable_delay(rdev_get_name(rdev));
+
+	if (delay >= 1000) {
+		mdelay(delay / 1000);
+		udelay(delay % 1000);
+	} else if (delay) {
+		udelay(delay);
+	}
+
+	trace_regulator_enable_complete(rdev_get_name(rdev));
+
+	return 0;
+}
+
 /* locks held by regulator_enable() */
 static int _regulator_enable(struct regulator_dev *rdev)
 {
-	int ret, delay;
+	int ret;
 
 	/* check voltage and requested load before enabling */
 	if (rdev->constraints &&
@@ -1493,40 +1533,10 @@ static int _regulator_enable(struct regulator_dev *rdev)
 			if (!_regulator_can_change_status(rdev))
 				return -EPERM;
 
-			if (!rdev->desc->ops->enable)
-				return -EINVAL;
-
-			/* Query before enabling in case configuration
-			 * dependent.  */
-			ret = _regulator_get_enable_time(rdev);
-			if (ret >= 0) {
-				delay = ret;
-			} else {
-				rdev_warn(rdev, "enable_time() failed: %d\n",
-					   ret);
-				delay = 0;
-			}
-
-			trace_regulator_enable(rdev_get_name(rdev));
-
-			/* Allow the regulator to ramp; it would be useful
-			 * to extend this for bulk operations so that the
-			 * regulators can ramp together.  */
-			ret = rdev->desc->ops->enable(rdev);
+			ret = _regulator_do_enable(rdev);
 			if (ret < 0)
 				return ret;
 
-			trace_regulator_enable_delay(rdev_get_name(rdev));
-
-			if (delay >= 1000) {
-				mdelay(delay / 1000);
-				udelay(delay % 1000);
-			} else if (delay) {
-				udelay(delay);
-			}
-
-			trace_regulator_enable_complete(rdev_get_name(rdev));
-
 		} else if (ret < 0) {
 			rdev_err(rdev, "is_enabled() failed: %d\n", ret);
 			return ret;
@@ -1575,6 +1585,30 @@ int regulator_enable(struct regulator *regulator)
 }
 EXPORT_SYMBOL_GPL(regulator_enable);
 
+static int _regulator_do_disable(struct regulator_dev *rdev)
+{
+	int ret;
+
+	trace_regulator_disable(rdev_get_name(rdev));
+
+	if (rdev->ena_gpio) {
+		gpio_set_value_cansleep(rdev->ena_gpio,
+					rdev->ena_gpio_invert);
+		rdev->ena_gpio_state = 0;
+
+	} else if (rdev->desc->ops->disable) {
+		ret = rdev->desc->ops->disable(rdev);
+		if (ret != 0)
+			return ret;
+	}
+
+	trace_regulator_disable_complete(rdev_get_name(rdev));
+
+	_notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE,
+			     NULL);
+	return 0;
+}
+
 /* locks held by regulator_disable() */
 static int _regulator_disable(struct regulator_dev *rdev)
 {
@@ -1589,20 +1623,12 @@ static int _regulator_disable(struct regulator_dev *rdev)
 	    (rdev->constraints && !rdev->constraints->always_on)) {
 
 		/* we are last user */
-		if (_regulator_can_change_status(rdev) &&
-		    rdev->desc->ops->disable) {
-			trace_regulator_disable(rdev_get_name(rdev));
-
-			ret = rdev->desc->ops->disable(rdev);
+		if (_regulator_can_change_status(rdev)) {
+			ret = _regulator_do_disable(rdev);
 			if (ret < 0) {
 				rdev_err(rdev, "failed to disable\n");
 				return ret;
 			}
-
-			trace_regulator_disable_complete(rdev_get_name(rdev));
-
-			_notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE,
-					     NULL);
 		}
 
 		rdev->use_count = 0;
-- 
cgit v1.2.3


From 65f735082de35aa4d44e8d0afe862798d0e09e29 Mon Sep 17 00:00:00 2001
From: Mark Brown <broonie@opensource.wolfsonmicro.com>
Date: Wed, 27 Jun 2012 14:14:38 +0100
Subject: regulator: core: Add core support for GPIO controlled enable lines

It is very common for regulators to support having their enable signal
controlled by a GPIO. Since there are a bunch of fiddly things to get
right like handling the operations when the enable signal is tied to
a rail and it's just replicated code add support for this to the core.

Drivers should set ena_gpio in their config if they have a GPIO control,
using ena_gpio_flags to specify any flags (including GPIOF_OUT_INIT_ for
the initial state) and ena_gpio_invert if the GPIO is active low. The
core will then override any enable and disable operations the driver has
and instead control the specified GPIO.

This will in the future also allow us to further extend the core by
identifying when several enable signals have been tied together and
handling this properly.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 drivers/regulator/core.c         | 35 ++++++++++++++++++++++++++++++++++-
 include/linux/regulator/driver.h | 11 +++++++++++
 2 files changed, 45 insertions(+), 1 deletion(-)

(limited to 'drivers/regulator/core.c')

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 82650a16a975..8d81bafcb721 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -23,6 +23,7 @@
 #include <linux/mutex.h>
 #include <linux/suspend.h>
 #include <linux/delay.h>
+#include <linux/gpio.h>
 #include <linux/of.h>
 #include <linux/regmap.h>
 #include <linux/regulator/of_regulator.h>
@@ -1491,7 +1492,11 @@ static int _regulator_do_enable(struct regulator_dev *rdev)
 
 	trace_regulator_enable(rdev_get_name(rdev));
 
-	if (rdev->desc->ops->enable) {
+	if (rdev->ena_gpio) {
+		gpio_set_value_cansleep(rdev->ena_gpio,
+					!rdev->ena_gpio_invert);
+		rdev->ena_gpio_state = 1;
+	} else if (rdev->desc->ops->enable) {
 		ret = rdev->desc->ops->enable(rdev);
 		if (ret < 0)
 			return ret;
@@ -1846,6 +1851,10 @@ EXPORT_SYMBOL_GPL(regulator_disable_regmap);
 
 static int _regulator_is_enabled(struct regulator_dev *rdev)
 {
+	/* A GPIO control always takes precedence */
+	if (rdev->ena_gpio)
+		return rdev->ena_gpio_state;
+
 	/* If we don't know then assume that the regulator is always on */
 	if (!rdev->desc->ops->is_enabled)
 		return 1;
@@ -3243,6 +3252,26 @@ regulator_register(const struct regulator_desc *regulator_desc,
 
 	dev_set_drvdata(&rdev->dev, rdev);
 
+	if (config->ena_gpio) {
+		ret = gpio_request_one(config->ena_gpio,
+				       GPIOF_DIR_OUT | config->ena_gpio_flags,
+				       rdev_get_name(rdev));
+		if (ret != 0) {
+			rdev_err(rdev, "Failed to request enable GPIO%d: %d\n",
+				 config->ena_gpio, ret);
+			goto clean;
+		}
+
+		rdev->ena_gpio = config->ena_gpio;
+		rdev->ena_gpio_invert = config->ena_gpio_invert;
+
+		if (config->ena_gpio_flags & GPIOF_OUT_INIT_HIGH)
+			rdev->ena_gpio_state = 1;
+
+		if (rdev->ena_gpio_invert)
+			rdev->ena_gpio_state = !rdev->ena_gpio_state;
+	}
+
 	/* set regulator constraints */
 	if (init_data)
 		constraints = &init_data->constraints;
@@ -3311,6 +3340,8 @@ unset_supplies:
 scrub:
 	if (rdev->supply)
 		regulator_put(rdev->supply);
+	if (rdev->ena_gpio)
+		gpio_free(rdev->ena_gpio);
 	kfree(rdev->constraints);
 	device_unregister(&rdev->dev);
 	/* device core frees rdev */
@@ -3344,6 +3375,8 @@ void regulator_unregister(struct regulator_dev *rdev)
 	unset_regulator_supplies(rdev);
 	list_del(&rdev->list);
 	kfree(rdev->constraints);
+	if (rdev->ena_gpio)
+		gpio_free(rdev->ena_gpio);
 	device_unregister(&rdev->dev);
 	mutex_unlock(&regulator_list_mutex);
 }
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index 176bd4335581..b1b7b8b43ece 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -220,6 +220,9 @@ struct regulator_desc {
  * @of_node: OpenFirmware node to parse for device tree bindings (may be
  *           NULL).
  * @regmap: regmap to use for core regmap helpers
+ * @ena_gpio: GPIO controlling regulator enable.
+ * @ena_gpio_invert: Sense for GPIO enable control.
+ * @ena_gpio_flags: Flags to use when calling gpio_request_one()
  */
 struct regulator_config {
 	struct device *dev;
@@ -227,6 +230,10 @@ struct regulator_config {
 	void *driver_data;
 	struct device_node *of_node;
 	struct regmap *regmap;
+
+	int ena_gpio;
+	unsigned int ena_gpio_invert:1;
+	unsigned int ena_gpio_flags;
 };
 
 /*
@@ -265,6 +272,10 @@ struct regulator_dev {
 	void *reg_data;		/* regulator_dev data */
 
 	struct dentry *debugfs;
+
+	int ena_gpio;
+	unsigned int ena_gpio_invert:1;
+	unsigned int ena_gpio_state:1;
 };
 
 struct regulator_dev *
-- 
cgit v1.2.3


From e2c98eaf928a2a0ecaca1db9aa5dc56a36699d9f Mon Sep 17 00:00:00 2001
From: Shawn Guo <shawn.guo@linaro.org>
Date: Thu, 5 Jul 2012 14:19:42 +0800
Subject: regulator: core: remove sysfs entry properly in regulator_put

With changes introduced by commit 222cc7b (regulator: core: Allow
multiple requests of a single supply mapping) on create_regulator,
regulator_put needs a corresponding update on sysfs entry removing.

Also regulator->dev still needs to get assigned in create_regulator,
otherwise, sysfs_remove_link call in regulator_put will get bypassed.

Reported-by: Fabio Estevam <festevam@gmail.com>
Tested-by: Dong Aisheng <dong.aisheng@linaro.org>
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 drivers/regulator/core.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

(limited to 'drivers/regulator/core.c')

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index f98a8ee29933..974276afd1f0 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1063,6 +1063,8 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
 	list_add(&regulator->list, &rdev->consumer_list);
 
 	if (dev) {
+		regulator->dev = dev;
+
 		/* Add a link to the device sysfs entry */
 		size = scnprintf(buf, REG_STR_SIZE, "%s-%s",
 				 dev->kobj.name, supply_name);
@@ -1359,11 +1361,8 @@ void regulator_put(struct regulator *regulator)
 	debugfs_remove_recursive(regulator->debugfs);
 
 	/* remove any sysfs entries */
-	if (regulator->dev) {
+	if (regulator->dev)
 		sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name);
-		device_remove_file(regulator->dev, &regulator->dev_attr);
-		kfree(regulator->dev_attr.attr.name);
-	}
 	kfree(regulator->supply_name);
 	list_del(&regulator->list);
 	kfree(regulator);
-- 
cgit v1.2.3


From 86f5fcfc3e400b2ac1562cb0fd6aabc9f83ee3e2 Mon Sep 17 00:00:00 2001
From: Mark Brown <broonie@opensource.wolfsonmicro.com>
Date: Fri, 6 Jul 2012 18:19:13 +0100
Subject: regulator: core: Mark all DT based boards as having full constraints

Since DT doesn't provide an idiomatic mechanism for enabling full
constraints and since it's much more natural with DT to provide them
just assume that a DT enabled system has full constraints.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Acked-by: Liam Girdwood <lrg@ti.com>
---
 drivers/regulator/core.c | 9 +++++++++
 1 file changed, 9 insertions(+)

(limited to 'drivers/regulator/core.c')

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 09a737c868b5..4c53b39b92a6 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -3472,6 +3472,15 @@ static int __init regulator_init_complete(void)
 	struct regulation_constraints *c;
 	int enabled, ret;
 
+	/*
+	 * Since DT doesn't provide an idiomatic mechanism for
+	 * enabling full constraints and since it's much more natural
+	 * with DT to provide them just assume that a DT enabled
+	 * system has full constraints.
+	 */
+	if (of_have_populated_dt())
+		has_full_constraints = true;
+
 	mutex_lock(&regulator_list_mutex);
 
 	/* If we have a full configuration then disable any regulators
-- 
cgit v1.2.3


From 03ffcf3d0838bd5e693cd4520becfb22577cf34d Mon Sep 17 00:00:00 2001
From: Krystian Garbaciak <krystian.garbaciak@diasemi.com>
Date: Thu, 12 Jul 2012 11:50:38 +0100
Subject: regulator: Fix a typo in regulator_mode_to_status() core function.

Case REGULATOR_STATUS_STANDBY -> REGULATOR_MODE_STANDBY.

Signed-off-by: Krystian Garbaciak <krystian.garbaciak@diasemi.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 drivers/regulator/core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'drivers/regulator/core.c')

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 974276afd1f0..4b136f8cb99f 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -2894,7 +2894,7 @@ int regulator_mode_to_status(unsigned int mode)
 		return REGULATOR_STATUS_NORMAL;
 	case REGULATOR_MODE_IDLE:
 		return REGULATOR_STATUS_IDLE;
-	case REGULATOR_STATUS_STANDBY:
+	case REGULATOR_MODE_STANDBY:
 		return REGULATOR_STATUS_STANDBY;
 	default:
 		return 0;
-- 
cgit v1.2.3


From 1beaf762b4ad5f53876f790bb6cfbd3bac072985 Mon Sep 17 00:00:00 2001
From: Krystian Garbaciak <krystian.garbaciak@diasemi.com>
Date: Thu, 12 Jul 2012 13:53:35 +0100
Subject: regulator: Add REGULATOR_STATUS_UNDEFINED.

REGULATOR_STATUS_UNDEFINED is to be returned by regulator, if any other state
doesn't really apply.

Signed-off-by: Krystian Garbaciak <krystian.garbaciak@diasemi.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 drivers/regulator/core.c         | 5 ++++-
 include/linux/regulator/driver.h | 2 ++
 2 files changed, 6 insertions(+), 1 deletion(-)

(limited to 'drivers/regulator/core.c')

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 4b136f8cb99f..01a67c50c4ea 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -393,6 +393,9 @@ static ssize_t regulator_status_show(struct device *dev,
 	case REGULATOR_STATUS_STANDBY:
 		label = "standby";
 		break;
+	case REGULATOR_STATUS_UNDEFINED:
+		label = "undefined";
+		break;
 	default:
 		return -ERANGE;
 	}
@@ -2897,7 +2900,7 @@ int regulator_mode_to_status(unsigned int mode)
 	case REGULATOR_MODE_STANDBY:
 		return REGULATOR_STATUS_STANDBY;
 	default:
-		return 0;
+		return REGULATOR_STATUS_UNDEFINED;
 	}
 }
 EXPORT_SYMBOL_GPL(regulator_mode_to_status);
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index 80226383e561..2513a54ca2e8 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -32,6 +32,8 @@ enum regulator_status {
 	REGULATOR_STATUS_NORMAL,
 	REGULATOR_STATUS_IDLE,
 	REGULATOR_STATUS_STANDBY,
+	/* in case that any other status doesn't apply */
+	REGULATOR_STATUS_UNDEFINED,
 };
 
 /**
-- 
cgit v1.2.3


From 2955b47d2c1983998a8c5915cb96884e67f7cb53 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Mon, 9 Jul 2012 19:33:25 -0700
Subject: [SCSI] async: introduce 'async_domain' type

This is in preparation for teaching async_synchronize_full() to sync all
pending async work, and not just on the async_running domain.  This
conversion is functionally equivalent, just embedding the existing list
in a new async_domain type.

The .registered attribute is used in a later patch to distinguish
between domains that want to be flushed by async_synchronize_full()
versus those that only expect async_synchronize_{full|cookie}_domain to
be used for flushing.

[jejb: add async.h to scsi_priv.h for struct async_domain]
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Acked-by: Arjan van de Ven <arjan@linux.intel.com>
Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Tested-by: Eldad Zack <eldad@fogrefinery.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
---
 drivers/regulator/core.c      |  2 +-
 drivers/scsi/libsas/sas_ata.c |  2 +-
 drivers/scsi/scsi.c           |  3 ++-
 drivers/scsi/scsi_priv.h      |  3 ++-
 include/linux/async.h         | 35 +++++++++++++++++++++++++++++++----
 kernel/async.c                | 35 +++++++++++++++++------------------
 sound/soc/soc-dapm.c          |  2 +-
 7 files changed, 55 insertions(+), 27 deletions(-)

(limited to 'drivers/regulator/core.c')

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 8b4b3829d9e7..6c74546fc3cd 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -2744,7 +2744,7 @@ static void regulator_bulk_enable_async(void *data, async_cookie_t cookie)
 int regulator_bulk_enable(int num_consumers,
 			  struct regulator_bulk_data *consumers)
 {
-	LIST_HEAD(async_domain);
+	ASYNC_DOMAIN_EXCLUSIVE(async_domain);
 	int i;
 	int ret = 0;
 
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index bec3bc8aab0c..a59fcdc8fd63 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -742,7 +742,7 @@ static void async_sas_ata_eh(void *data, async_cookie_t cookie)
 void sas_ata_strategy_handler(struct Scsi_Host *shost)
 {
 	struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
-	LIST_HEAD(async);
+	ASYNC_DOMAIN_EXCLUSIVE(async);
 	int i;
 
 	/* it's ok to defer revalidation events during ata eh, these
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index bbbc9c918d4c..4cade886a50a 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -54,6 +54,7 @@
 #include <linux/notifier.h>
 #include <linux/cpu.h>
 #include <linux/mutex.h>
+#include <linux/async.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -91,7 +92,7 @@ EXPORT_SYMBOL(scsi_logging_level);
 #endif
 
 /* sd, scsi core and power management need to coordinate flushing async actions */
-LIST_HEAD(scsi_sd_probe_domain);
+ASYNC_DOMAIN(scsi_sd_probe_domain);
 EXPORT_SYMBOL(scsi_sd_probe_domain);
 
 /* NB: These are exposed through /proc/scsi/scsi and form part of the ABI.
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index 13d74da5dfab..8f9a0cadc296 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -2,6 +2,7 @@
 #define _SCSI_PRIV_H
 
 #include <linux/device.h>
+#include <linux/async.h>
 #include <scsi/scsi_device.h>
 
 struct request_queue;
@@ -163,7 +164,7 @@ static inline int scsi_autopm_get_host(struct Scsi_Host *h) { return 0; }
 static inline void scsi_autopm_put_host(struct Scsi_Host *h) {}
 #endif /* CONFIG_PM_RUNTIME */
 
-extern struct list_head scsi_sd_probe_domain;
+extern struct async_domain scsi_sd_probe_domain;
 
 /* 
  * internal scsi timeout functions: for use by mid-layer and transport
diff --git a/include/linux/async.h b/include/linux/async.h
index 68a9530196f2..364e7ff16c08 100644
--- a/include/linux/async.h
+++ b/include/linux/async.h
@@ -9,19 +9,46 @@
  * as published by the Free Software Foundation; version 2
  * of the License.
  */
+#ifndef __ASYNC_H__
+#define __ASYNC_H__
 
 #include <linux/types.h>
 #include <linux/list.h>
 
 typedef u64 async_cookie_t;
 typedef void (async_func_ptr) (void *data, async_cookie_t cookie);
+struct async_domain {
+	struct list_head node;
+	struct list_head domain;
+	int count;
+	unsigned registered:1;
+};
+
+/*
+ * domain participates in global async_synchronize_full
+ */
+#define ASYNC_DOMAIN(_name) \
+	struct async_domain _name = { .node = LIST_HEAD_INIT(_name.node), \
+				      .domain = LIST_HEAD_INIT(_name.domain), \
+				      .count = 0, \
+				      .registered = 1 }
+
+/*
+ * domain is free to go out of scope as soon as all pending work is
+ * complete, this domain does not participate in async_synchronize_full
+ */
+#define ASYNC_DOMAIN_EXCLUSIVE(_name) \
+	struct async_domain _name = { .node = LIST_HEAD_INIT(_name.node), \
+				      .domain = LIST_HEAD_INIT(_name.domain), \
+				      .count = 0, \
+				      .registered = 0 }
 
 extern async_cookie_t async_schedule(async_func_ptr *ptr, void *data);
 extern async_cookie_t async_schedule_domain(async_func_ptr *ptr, void *data,
-					    struct list_head *list);
+					    struct async_domain *domain);
 extern void async_synchronize_full(void);
-extern void async_synchronize_full_domain(struct list_head *list);
+extern void async_synchronize_full_domain(struct async_domain *domain);
 extern void async_synchronize_cookie(async_cookie_t cookie);
 extern void async_synchronize_cookie_domain(async_cookie_t cookie,
-					    struct list_head *list);
-
+					    struct async_domain *domain);
+#endif
diff --git a/kernel/async.c b/kernel/async.c
index bd0c168a3bbe..ba5491dfa991 100644
--- a/kernel/async.c
+++ b/kernel/async.c
@@ -62,7 +62,7 @@ static async_cookie_t next_cookie = 1;
 #define MAX_WORK	32768
 
 static LIST_HEAD(async_pending);
-static LIST_HEAD(async_running);
+static ASYNC_DOMAIN(async_running);
 static DEFINE_SPINLOCK(async_lock);
 
 struct async_entry {
@@ -71,7 +71,7 @@ struct async_entry {
 	async_cookie_t		cookie;
 	async_func_ptr		*func;
 	void			*data;
-	struct list_head	*running;
+	struct async_domain	*running;
 };
 
 static DECLARE_WAIT_QUEUE_HEAD(async_done);
@@ -82,13 +82,12 @@ static atomic_t entry_count;
 /*
  * MUST be called with the lock held!
  */
-static async_cookie_t  __lowest_in_progress(struct list_head *running)
+static async_cookie_t  __lowest_in_progress(struct async_domain *running)
 {
 	struct async_entry *entry;
 
-	if (!list_empty(running)) {
-		entry = list_first_entry(running,
-			struct async_entry, list);
+	if (!list_empty(&running->domain)) {
+		entry = list_first_entry(&running->domain, typeof(*entry), list);
 		return entry->cookie;
 	}
 
@@ -99,7 +98,7 @@ static async_cookie_t  __lowest_in_progress(struct list_head *running)
 	return next_cookie;	/* "infinity" value */
 }
 
-static async_cookie_t  lowest_in_progress(struct list_head *running)
+static async_cookie_t  lowest_in_progress(struct async_domain *running)
 {
 	unsigned long flags;
 	async_cookie_t ret;
@@ -119,10 +118,11 @@ static void async_run_entry_fn(struct work_struct *work)
 		container_of(work, struct async_entry, work);
 	unsigned long flags;
 	ktime_t uninitialized_var(calltime), delta, rettime;
+	struct async_domain *running = entry->running;
 
 	/* 1) move self to the running queue */
 	spin_lock_irqsave(&async_lock, flags);
-	list_move_tail(&entry->list, entry->running);
+	list_move_tail(&entry->list, &running->domain);
 	spin_unlock_irqrestore(&async_lock, flags);
 
 	/* 2) run (and print duration) */
@@ -156,7 +156,7 @@ static void async_run_entry_fn(struct work_struct *work)
 	wake_up(&async_done);
 }
 
-static async_cookie_t __async_schedule(async_func_ptr *ptr, void *data, struct list_head *running)
+static async_cookie_t __async_schedule(async_func_ptr *ptr, void *data, struct async_domain *running)
 {
 	struct async_entry *entry;
 	unsigned long flags;
@@ -223,7 +223,7 @@ EXPORT_SYMBOL_GPL(async_schedule);
  * Note: This function may be called from atomic or non-atomic contexts.
  */
 async_cookie_t async_schedule_domain(async_func_ptr *ptr, void *data,
-				     struct list_head *running)
+				     struct async_domain *running)
 {
 	return __async_schedule(ptr, data, running);
 }
@@ -238,20 +238,20 @@ void async_synchronize_full(void)
 {
 	do {
 		async_synchronize_cookie(next_cookie);
-	} while (!list_empty(&async_running) || !list_empty(&async_pending));
+	} while (!list_empty(&async_running.domain) || !list_empty(&async_pending));
 }
 EXPORT_SYMBOL_GPL(async_synchronize_full);
 
 /**
  * async_synchronize_full_domain - synchronize all asynchronous function within a certain domain
- * @list: running list to synchronize on
+ * @domain: running list to synchronize on
  *
  * This function waits until all asynchronous function calls for the
- * synchronization domain specified by the running list @list have been done.
+ * synchronization domain specified by the running list @domain have been done.
  */
-void async_synchronize_full_domain(struct list_head *list)
+void async_synchronize_full_domain(struct async_domain *domain)
 {
-	async_synchronize_cookie_domain(next_cookie, list);
+	async_synchronize_cookie_domain(next_cookie, domain);
 }
 EXPORT_SYMBOL_GPL(async_synchronize_full_domain);
 
@@ -261,11 +261,10 @@ EXPORT_SYMBOL_GPL(async_synchronize_full_domain);
  * @running: running list to synchronize on
  *
  * This function waits until all asynchronous function calls for the
- * synchronization domain specified by the running list @list submitted
+ * synchronization domain specified by running list @running submitted
  * prior to @cookie have been done.
  */
-void async_synchronize_cookie_domain(async_cookie_t cookie,
-				     struct list_head *running)
+void async_synchronize_cookie_domain(async_cookie_t cookie, struct async_domain *running)
 {
 	ktime_t uninitialized_var(starttime), delta, endtime;
 
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 89eae93445cf..fa1e31206892 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -1545,7 +1545,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
 	struct snd_soc_dapm_context *d;
 	LIST_HEAD(up_list);
 	LIST_HEAD(down_list);
-	LIST_HEAD(async_domain);
+	ASYNC_DOMAIN_EXCLUSIVE(async_domain);
 	enum snd_soc_bias_level bias;
 
 	trace_snd_soc_dapm_start(card);
-- 
cgit v1.2.3