Merge remote-tracking branches 'regulator/topic/core', 'regulator/topic/regmap' and...
[firefly-linux-kernel-4.4.55.git] / drivers / regulator / core.c
index 10fb252323fbb007ba6183f2ea0ae5cefed39e1f..aec7ad5cb2d326e798a395e2beadf8554c799136 100644 (file)
@@ -75,6 +75,7 @@ struct regulator_map {
 struct regulator {
        struct device *dev;
        struct list_head list;
+       unsigned int always_on:1;
        int uA_load;
        int min_uV;
        int max_uV;
@@ -156,6 +157,17 @@ static struct device_node *of_get_regulator(struct device *dev, const char *supp
        return regnode;
 }
 
+static int _regulator_can_change_status(struct regulator_dev *rdev)
+{
+       if (!rdev->constraints)
+               return 0;
+
+       if (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_STATUS)
+               return 1;
+       else
+               return 0;
+}
+
 /* Platform voltage constraint check */
 static int regulator_check_voltage(struct regulator_dev *rdev,
                                   int *min_uV, int *max_uV)
@@ -650,7 +662,7 @@ static void drms_uA_update(struct regulator_dev *rdev)
        /* get input voltage */
        input_uV = 0;
        if (rdev->supply)
-               input_uV = _regulator_get_voltage(rdev);
+               input_uV = regulator_get_voltage(rdev->supply);
        if (input_uV <= 0)
                input_uV = rdev->constraints->input_uV;
        if (input_uV <= 0)
@@ -674,17 +686,14 @@ static int suspend_set_state(struct regulator_dev *rdev,
        struct regulator_state *rstate)
 {
        int ret = 0;
-       bool can_set_state;
-
-       can_set_state = rdev->desc->ops->set_suspend_enable &&
-               rdev->desc->ops->set_suspend_disable;
 
        /* If we have no suspend mode configration don't set anything;
-        * only warn if the driver actually makes the suspend mode
-        * configurable.
+        * only warn if the driver implements set_suspend_voltage or
+        * set_suspend_mode callback.
         */
        if (!rstate->enabled && !rstate->disabled) {
-               if (can_set_state)
+               if (rdev->desc->ops->set_suspend_voltage ||
+                   rdev->desc->ops->set_suspend_mode)
                        rdev_warn(rdev, "No configuration\n");
                return 0;
        }
@@ -694,15 +703,13 @@ static int suspend_set_state(struct regulator_dev *rdev,
                return -EINVAL;
        }
 
-       if (!can_set_state) {
-               rdev_err(rdev, "no way to set suspend state\n");
-               return -EINVAL;
-       }
-
-       if (rstate->enabled)
+       if (rstate->enabled && rdev->desc->ops->set_suspend_enable)
                ret = rdev->desc->ops->set_suspend_enable(rdev);
-       else
+       else if (rstate->disabled && rdev->desc->ops->set_suspend_disable)
                ret = rdev->desc->ops->set_suspend_disable(rdev);
+       else /* OK if set_suspend_enable or set_suspend_disable is NULL */
+               ret = 0;
+
        if (ret < 0) {
                rdev_err(rdev, "failed to enabled/disable\n");
                return ret;
@@ -1147,6 +1154,15 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
                                   &regulator->max_uV);
        }
 
+       /*
+        * Check now if the regulator is an always on regulator - if
+        * it is then we don't need to do nearly so much work for
+        * enable/disable calls.
+        */
+       if (!_regulator_can_change_status(rdev) &&
+           _regulator_is_enabled(rdev))
+               regulator->always_on = true;
+
        mutex_unlock(&rdev->mutex);
        return regulator;
 link_name_err:
@@ -1170,26 +1186,52 @@ static int _regulator_get_enable_time(struct regulator_dev *rdev)
 }
 
 static struct regulator_dev *regulator_dev_lookup(struct device *dev,
-                                                        const char *supply)
+                                                 const char *supply,
+                                                 int *ret)
 {
        struct regulator_dev *r;
        struct device_node *node;
+       struct regulator_map *map;
+       const char *devname = NULL;
 
        /* first do a dt based lookup */
        if (dev && dev->of_node) {
                node = of_get_regulator(dev, supply);
-               if (node)
+               if (node) {
                        list_for_each_entry(r, &regulator_list, list)
                                if (r->dev.parent &&
                                        node == r->dev.of_node)
                                        return r;
+               } else {
+                       /*
+                        * If we couldn't even get the node then it's
+                        * not just that the device didn't register
+                        * yet, there's no node and we'll never
+                        * succeed.
+                        */
+                       *ret = -ENODEV;
+               }
        }
 
        /* if not found, try doing it non-dt way */
+       if (dev)
+               devname = dev_name(dev);
+
        list_for_each_entry(r, &regulator_list, list)
                if (strcmp(rdev_get_name(r), supply) == 0)
                        return r;
 
+       list_for_each_entry(map, &regulator_map_list, list) {
+               /* If the mapping has a device set up it must match */
+               if (map->dev_name &&
+                   (!devname || strcmp(map->dev_name, devname)))
+                       continue;
+
+               if (strcmp(map->supply, supply) == 0)
+                       return map->regulator;
+       }
+
+
        return NULL;
 }
 
@@ -1198,7 +1240,6 @@ static struct regulator *_regulator_get(struct device *dev, const char *id,
                                        int exclusive)
 {
        struct regulator_dev *rdev;
-       struct regulator_map *map;
        struct regulator *regulator = ERR_PTR(-EPROBE_DEFER);
        const char *devname = NULL;
        int ret;
@@ -1213,22 +1254,10 @@ static struct regulator *_regulator_get(struct device *dev, const char *id,
 
        mutex_lock(&regulator_list_mutex);
 
-       rdev = regulator_dev_lookup(dev, id);
+       rdev = regulator_dev_lookup(dev, id, &ret);
        if (rdev)
                goto found;
 
-       list_for_each_entry(map, &regulator_map_list, list) {
-               /* If the mapping has a device set up it must match */
-               if (map->dev_name &&
-                   (!devname || strcmp(map->dev_name, devname)))
-                       continue;
-
-               if (strcmp(map->supply, id) == 0) {
-                       rdev = map->regulator;
-                       goto found;
-               }
-       }
-
        if (board_wants_dummy_regulator) {
                rdev = dummy_regulator_rdev;
                goto found;
@@ -1436,17 +1465,6 @@ void devm_regulator_put(struct regulator *regulator)
 }
 EXPORT_SYMBOL_GPL(devm_regulator_put);
 
-static int _regulator_can_change_status(struct regulator_dev *rdev)
-{
-       if (!rdev->constraints)
-               return 0;
-
-       if (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_STATUS)
-               return 1;
-       else
-               return 0;
-}
-
 /* locks held by regulator_enable() */
 static int _regulator_enable(struct regulator_dev *rdev)
 {
@@ -1526,6 +1544,9 @@ int regulator_enable(struct regulator *regulator)
        struct regulator_dev *rdev = regulator->rdev;
        int ret = 0;
 
+       if (regulator->always_on)
+               return 0;
+
        if (rdev->supply) {
                ret = regulator_enable(rdev->supply);
                if (ret != 0)
@@ -1604,6 +1625,9 @@ int regulator_disable(struct regulator *regulator)
        struct regulator_dev *rdev = regulator->rdev;
        int ret = 0;
 
+       if (regulator->always_on)
+               return 0;
+
        mutex_lock(&rdev->mutex);
        ret = _regulator_disable(rdev);
        mutex_unlock(&rdev->mutex);
@@ -1712,6 +1736,9 @@ int regulator_disable_deferred(struct regulator *regulator, int ms)
        struct regulator_dev *rdev = regulator->rdev;
        int ret;
 
+       if (regulator->always_on)
+               return 0;
+
        mutex_lock(&rdev->mutex);
        rdev->deferred_disables++;
        mutex_unlock(&rdev->mutex);
@@ -1805,6 +1832,9 @@ int regulator_is_enabled(struct regulator *regulator)
 {
        int ret;
 
+       if (regulator->always_on)
+               return 1;
+
        mutex_lock(&regulator->rdev->mutex);
        ret = _regulator_is_enabled(regulator->rdev);
        mutex_unlock(&regulator->rdev->mutex);
@@ -1943,23 +1973,35 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
        int ret;
        int delay = 0;
        unsigned int selector;
+       int old_selector = -1;
+       int best_val = INT_MAX;
 
        trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV);
 
        min_uV += rdev->constraints->uV_offset;
        max_uV += rdev->constraints->uV_offset;
 
+       /*
+        * 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 &&
+           rdev->desc->ops->get_voltage_sel) {
+               old_selector = rdev->desc->ops->get_voltage_sel(rdev);
+               if (old_selector < 0)
+                       return old_selector;
+       }
+
        if (rdev->desc->ops->set_voltage) {
                ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV,
                                                   &selector);
 
                if (rdev->desc->ops->list_voltage)
-                       selector = rdev->desc->ops->list_voltage(rdev,
+                       best_val = rdev->desc->ops->list_voltage(rdev,
                                                                 selector);
                else
-                       selector = -1;
+                       best_val = -1;
        } else if (rdev->desc->ops->set_voltage_sel) {
-               int best_val = INT_MAX;
                int i;
 
                selector = 0;
@@ -1978,36 +2020,27 @@ 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 &&
-                   rdev->desc->ops->get_voltage_sel) {
-                       unsigned int old_selector = 0;
-
-                       ret = rdev->desc->ops->get_voltage_sel(rdev);
-                       if (ret < 0)
-                               return ret;
-                       old_selector = ret;
-                       ret = rdev->desc->ops->set_voltage_time_sel(rdev,
-                                               old_selector, selector);
-                       if (ret < 0)
-                               rdev_warn(rdev, "set_voltage_time_sel() failed: %d\n", ret);
-                       else
-                               delay = ret;
-               }
-
-               if (best_val != INT_MAX) {
+               if (best_val != INT_MAX)
                        ret = rdev->desc->ops->set_voltage_sel(rdev, selector);
-                       selector = best_val;
-               } else {
+               else
                        ret = -EINVAL;
-               }
        } else {
                ret = -EINVAL;
        }
 
+       /* Call set_voltage_time_sel if successfully obtained old_selector */
+       if (ret == 0 && old_selector >= 0 &&
+           rdev->desc->ops->set_voltage_time_sel) {
+
+               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;
+               }
+       }
+
        /* Insert any necessary delays */
        if (delay >= 1000) {
                mdelay(delay / 1000);
@@ -2020,7 +2053,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
                _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE,
                                     NULL);
 
-       trace_regulator_set_voltage_complete(rdev_get_name(rdev), selector);
+       trace_regulator_set_voltage_complete(rdev_get_name(rdev), best_val);
 
        return ret;
 }
@@ -2424,6 +2457,9 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
         */
        ret = -EINVAL;
 
+       if (!rdev->desc->ops->set_mode)
+               goto out;
+
        /* get output voltage */
        output_uV = _regulator_get_voltage(rdev);
        if (output_uV <= 0) {
@@ -2625,9 +2661,13 @@ int regulator_bulk_enable(int num_consumers,
        int i;
        int ret = 0;
 
-       for (i = 0; i < num_consumers; i++)
-               async_schedule_domain(regulator_bulk_enable_async,
-                                     &consumers[i], &async_domain);
+       for (i = 0; i < num_consumers; i++) {
+               if (consumers[i].consumer->always_on)
+                       consumers[i].ret = 0;
+               else
+                       async_schedule_domain(regulator_bulk_enable_async,
+                                             &consumers[i], &async_domain);
+       }
 
        async_synchronize_full_domain(&async_domain);
 
@@ -2666,7 +2706,7 @@ int regulator_bulk_disable(int num_consumers,
                           struct regulator_bulk_data *consumers)
 {
        int i;
-       int ret;
+       int ret, r;
 
        for (i = num_consumers - 1; i >= 0; --i) {
                ret = regulator_disable(consumers[i].consumer);
@@ -2678,8 +2718,12 @@ 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)
-               regulator_enable(consumers[i].consumer);
+       for (++i; i < num_consumers; ++i) {
+               r = regulator_enable(consumers[i].consumer);
+               if (r != 0)
+                       pr_err("Failed to reename %s: %d\n",
+                              consumers[i].supply, r);
+       }
 
        return ret;
 }
@@ -2856,10 +2900,6 @@ static int add_regulator_attributes(struct regulator_dev *rdev)
                        return status;
        }
 
-       /* suspend mode constraints need multiple supporting methods */
-       if (!(ops->set_suspend_enable && ops->set_suspend_disable))
-               return status;
-
        status = device_create_file(dev, &dev_attr_suspend_standby_state);
        if (status < 0)
                return status;
@@ -3026,7 +3066,7 @@ regulator_register(const struct regulator_desc *regulator_desc,
        if (supply) {
                struct regulator_dev *r;
 
-               r = regulator_dev_lookup(dev, supply);
+               r = regulator_dev_lookup(dev, supply, &ret);
 
                if (!r) {
                        dev_err(dev, "Failed to find supply %s\n", supply);