]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/regulator/core.c
Merge remote-tracking branches 'regulator/topic/fixed', 'regulator/topic/id-const...
[karo-tx-linux.git] / drivers / regulator / core.c
index afca1bc24f262251abf3352d2e09d6452959805b..4c1f999041dd1fe74433d7769e18fc3cde7d7804 100644 (file)
@@ -844,13 +844,22 @@ static int machine_constraints_voltage(struct regulator_dev *rdev,
        /* do we need to apply the constraint voltage */
        if (rdev->constraints->apply_uV &&
            rdev->constraints->min_uV == rdev->constraints->max_uV) {
-               ret = _regulator_do_set_voltage(rdev,
-                                               rdev->constraints->min_uV,
-                                               rdev->constraints->max_uV);
-               if (ret < 0) {
-                       rdev_err(rdev, "failed to apply %duV constraint\n",
-                                rdev->constraints->min_uV);
-                       return ret;
+               int current_uV = _regulator_get_voltage(rdev);
+               if (current_uV < 0) {
+                       rdev_err(rdev, "failed to get the current voltage\n");
+                       return current_uV;
+               }
+               if (current_uV < rdev->constraints->min_uV ||
+                   current_uV > rdev->constraints->max_uV) {
+                       ret = _regulator_do_set_voltage(
+                               rdev, rdev->constraints->min_uV,
+                               rdev->constraints->max_uV);
+                       if (ret < 0) {
+                               rdev_err(rdev,
+                                       "failed to apply %duV constraint\n",
+                                       rdev->constraints->min_uV);
+                               return ret;
+                       }
                }
        }
 
@@ -1430,9 +1439,9 @@ EXPORT_SYMBOL_GPL(regulator_get);
  *
  * Returns a struct regulator corresponding to the regulator producer,
  * or IS_ERR() condition containing errno.  Other consumers will be
- * unable to obtain this reference is held and the use count for the
- * regulator will be initialised to reflect the current state of the
- * regulator.
+ * unable to obtain this regulator while this reference is held and the
+ * use count for the regulator will be initialised to reflect the current
+ * state of the regulator.
  *
  * This is intended for use by consumers which cannot tolerate shared
  * use of the regulator such as those which need to force the
@@ -1456,10 +1465,7 @@ EXPORT_SYMBOL_GPL(regulator_get_exclusive);
  * @id: Supply name or regulator ID.
  *
  * Returns a struct regulator corresponding to the regulator producer,
- * or IS_ERR() condition containing errno.  Other consumers will be
- * unable to obtain this reference is held and the use count for the
- * regulator will be initialised to reflect the current state of the
- * regulator.
+ * or IS_ERR() condition containing errno.
  *
  * This is intended for use by consumers for devices which can have
  * some supplies unconnected in normal use, such as some MMC devices.
@@ -1597,9 +1603,10 @@ EXPORT_SYMBOL_GPL(regulator_unregister_supply_alias);
  * registered any aliases that were registered will be removed
  * before returning to the caller.
  */
-int regulator_bulk_register_supply_alias(struct device *dev, const char **id,
+int regulator_bulk_register_supply_alias(struct device *dev,
+                                        const char *const *id,
                                         struct device *alias_dev,
-                                        const char **alias_id,
+                                        const char *const *alias_id,
                                         int num_id)
 {
        int i;
@@ -1637,7 +1644,7 @@ EXPORT_SYMBOL_GPL(regulator_bulk_register_supply_alias);
  * aliases in one operation.
  */
 void regulator_bulk_unregister_supply_alias(struct device *dev,
-                                           const char **id,
+                                           const char *const *id,
                                            int num_id)
 {
        int i;
@@ -2138,7 +2145,7 @@ EXPORT_SYMBOL_GPL(regulator_is_enabled);
  * @regulator: regulator source
  *
  * Returns positive if the regulator driver backing the source/client
- * can change its voltage, false otherwise. Usefull for detecting fixed
+ * can change its voltage, false otherwise. Useful for detecting fixed
  * or dummy regulators and disabling voltage change logic in the client
  * driver.
  */
@@ -2321,6 +2328,10 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
                            regulator_list_voltage_linear)
                                ret = regulator_map_voltage_linear(rdev,
                                                                min_uV, max_uV);
+                       else if (rdev->desc->ops->list_voltage ==
+                                regulator_list_voltage_linear_range)
+                               ret = regulator_map_voltage_linear_range(rdev,
+                                                               min_uV, max_uV);
                        else
                                ret = regulator_map_voltage_iterate(rdev,
                                                                min_uV, max_uV);
@@ -2399,6 +2410,7 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
        struct regulator_dev *rdev = regulator->rdev;
        int ret = 0;
        int old_min_uV, old_max_uV;
+       int current_uV;
 
        mutex_lock(&rdev->mutex);
 
@@ -2409,6 +2421,19 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
        if (regulator->min_uV == min_uV && regulator->max_uV == max_uV)
                goto out;
 
+       /* If we're trying to set a range that overlaps the current voltage,
+        * return succesfully even though the regulator does not support
+        * changing the voltage.
+        */
+       if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) {
+               current_uV = _regulator_get_voltage(rdev);
+               if (min_uV <= current_uV && current_uV <= max_uV) {
+                       regulator->min_uV = min_uV;
+                       regulator->max_uV = max_uV;
+                       goto out;
+               }
+       }
+
        /* sanity check */
        if (!rdev->desc->ops->set_voltage &&
            !rdev->desc->ops->set_voltage_sel) {
@@ -3433,7 +3458,7 @@ regulator_register(const struct regulator_desc *regulator_desc,
 
        /* register with sysfs */
        rdev->dev.class = &regulator_class;
-       rdev->dev.of_node = config->of_node;
+       rdev->dev.of_node = of_node_get(config->of_node);
        rdev->dev.parent = dev;
        dev_set_name(&rdev->dev, "regulator.%d",
                     atomic_inc_return(&regulator_no) - 1);
@@ -3575,6 +3600,7 @@ void regulator_unregister(struct regulator_dev *rdev)
        list_del(&rdev->list);
        kfree(rdev->constraints);
        regulator_ena_gpio_free(rdev);
+       of_node_put(rdev->dev.of_node);
        device_unregister(&rdev->dev);
        mutex_unlock(&regulator_list_mutex);
 }
@@ -3805,8 +3831,9 @@ static int __init regulator_init_complete(void)
        mutex_lock(&regulator_list_mutex);
 
        /* If we have a full configuration then disable any regulators
-        * which are not in use or always_on.  This will become the
-        * default behaviour in the future.
+        * we have permission to change the status for and which are
+        * not in use or always_on.  This is effectively the default
+        * for DT and ACPI as they have full constraints.
         */
        list_for_each_entry(rdev, &regulator_list, list) {
                ops = rdev->desc->ops;
@@ -3815,6 +3842,9 @@ static int __init regulator_init_complete(void)
                if (c && c->always_on)
                        continue;
 
+               if (c && !(c->valid_ops_mask & REGULATOR_CHANGE_STATUS))
+                       continue;
+
                mutex_lock(&rdev->mutex);
 
                if (rdev->use_count)
@@ -3853,4 +3883,4 @@ unlock:
 
        return 0;
 }
-late_initcall(regulator_init_complete);
+late_initcall_sync(regulator_init_complete);