Make it possible to use the bulk API with optional supplies, by allowing
the consumer to marking supplies as optional in the regulator_bulk_data.

Based on earlier patch by Bjorn Andersson <bjorn.anders...@sonymobile.com>

Signed-off-by: Dmitry Torokhov <dmitry.torok...@gmail.com>
---
 drivers/regulator/core.c           | 41 ++++++++++++++++++++++++--------------
 include/linux/regulator/consumer.h |  3 +++
 2 files changed, 29 insertions(+), 15 deletions(-)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 9eb2e04f1219..540d1dec6e06 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -3546,20 +3546,22 @@ static int _notifier_call_chain(struct regulator_dev 
*rdev,
 int regulator_bulk_get(struct device *dev, int num_consumers,
                       struct regulator_bulk_data *consumers)
 {
+       struct regulator *r;
        int i;
        int ret;
 
-       for (i = 0; i < num_consumers; i++)
-               consumers[i].consumer = NULL;
-
        for (i = 0; i < num_consumers; i++) {
-               consumers[i].consumer = regulator_get(dev,
-                                                     consumers[i].supply);
-               if (IS_ERR(consumers[i].consumer)) {
-                       ret = PTR_ERR(consumers[i].consumer);
+               r = _regulator_get(dev, consumers[i].supply,
+                                  consumers[i].optional ?
+                                       OPTIONAL_GET : NORMAL_GET);
+               ret = PTR_ERR_OR_ZERO(r);
+               if (!ret) {
+                       consumers[i].consumer = r;
+               } else if (ret == -ENODEV && consumers[i].optional) {
+                       consumers[i].consumer = NULL;
+               } else {
                        dev_err(dev, "Failed to get supply '%s': %d\n",
                                consumers[i].supply, ret);
-                       consumers[i].consumer = NULL;
                        goto err;
                }
        }
@@ -3568,7 +3570,8 @@ int regulator_bulk_get(struct device *dev, int 
num_consumers,
 
 err:
        while (--i >= 0)
-               regulator_put(consumers[i].consumer);
+               if (consumers[i].consumer)
+                       regulator_put(consumers[i].consumer);
 
        return ret;
 }
@@ -3601,7 +3604,7 @@ int regulator_bulk_enable(int num_consumers,
        int ret = 0;
 
        for (i = 0; i < num_consumers; i++) {
-               if (consumers[i].consumer->always_on)
+               if (!consumers[i].consumer || consumers[i].consumer->always_on)
                        consumers[i].ret = 0;
                else
                        async_schedule_domain(regulator_bulk_enable_async,
@@ -3625,7 +3628,7 @@ int regulator_bulk_enable(int num_consumers,
                if (consumers[i].ret < 0)
                        pr_err("Failed to enable %s: %d\n", consumers[i].supply,
                               consumers[i].ret);
-               else
+               else if (consumers[i].consumer)
                        regulator_disable(consumers[i].consumer);
        }
 
@@ -3652,6 +3655,9 @@ int regulator_bulk_disable(int num_consumers,
        int ret, r;
 
        for (i = num_consumers - 1; i >= 0; --i) {
+               if (!consumers[i].consumer)
+                       continue;
+
                ret = regulator_disable(consumers[i].consumer);
                if (ret != 0)
                        goto err;
@@ -3662,6 +3668,9 @@ int regulator_bulk_disable(int num_consumers,
 err:
        pr_err("Failed to disable %s: %d\n", consumers[i].supply, ret);
        for (++i; i < num_consumers; ++i) {
+               if (!consumers[i].consumer)
+                       continue;
+
                r = regulator_enable(consumers[i].consumer);
                if (r != 0)
                        pr_err("Failed to re-enable %s: %d\n",
@@ -3693,8 +3702,8 @@ int regulator_bulk_force_disable(int num_consumers,
        int ret = 0;
 
        for (i = 0; i < num_consumers; i++) {
-               consumers[i].ret =
-                           regulator_force_disable(consumers[i].consumer);
+               consumers[i].ret = consumers[i].consumer ?
+                       regulator_force_disable(consumers[i].consumer) : 0;
 
                /* Store first error for reporting */
                if (consumers[i].ret && !ret)
@@ -3720,8 +3729,10 @@ void regulator_bulk_free(int num_consumers,
        int i;
 
        for (i = 0; i < num_consumers; i++) {
-               regulator_put(consumers[i].consumer);
-               consumers[i].consumer = NULL;
+               if (consumers[i].consumer) {
+                       regulator_put(consumers[i].consumer);
+                       consumers[i].consumer = NULL;
+               }
        }
 }
 EXPORT_SYMBOL_GPL(regulator_bulk_free);
diff --git a/include/linux/regulator/consumer.h 
b/include/linux/regulator/consumer.h
index ea0fffa5faeb..acaeeec279af 100644
--- a/include/linux/regulator/consumer.h
+++ b/include/linux/regulator/consumer.h
@@ -159,6 +159,8 @@ struct regulator;
  *
  * @supply:   The name of the supply.  Initialised by the user before
  *            using the bulk regulator APIs.
+ * @optional: The supply should be considered optional. Initialised by the user
+ *            before using the bulk regulator APIs.
  * @consumer: The regulator consumer for the supply.  This will be managed
  *            by the bulk API.
  *
@@ -168,6 +170,7 @@ struct regulator;
  */
 struct regulator_bulk_data {
        const char *supply;
+       bool optional;
        struct regulator *consumer;
 
        /* private: Internal use */
-- 
2.11.0.483.g087da7b7c-goog

Reply via email to