]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/regulator/core.c
regulator: core: Allow to get voltage count and list from parent
[karo-tx-linux.git] / drivers / regulator / core.c
index 9a09f3cdbabb85cec71e7afece30308e4ccead7b..5299456d07eef8c6defa2dd6c48f83384f78109a 100644 (file)
@@ -844,13 +844,24 @@ 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(%d)\n",
+                                current_uV);
+                       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(%d)\n",
+                                       rdev->constraints->min_uV, ret);
+                               return ret;
+                       }
                }
        }
 
@@ -1430,9 +1441,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 +1467,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 +1605,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 +1646,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;
@@ -2173,7 +2182,13 @@ int regulator_count_voltages(struct regulator *regulator)
 {
        struct regulator_dev    *rdev = regulator->rdev;
 
-       return rdev->desc->n_voltages ? : -EINVAL;
+       if (rdev->desc->n_voltages)
+               return rdev->desc->n_voltages;
+
+       if (!rdev->supply)
+               return -EINVAL;
+
+       return regulator_count_voltages(rdev->supply);
 }
 EXPORT_SYMBOL_GPL(regulator_count_voltages);
 
@@ -2196,12 +2211,17 @@ int regulator_list_voltage(struct regulator *regulator, unsigned selector)
        if (rdev->desc->fixed_uV && rdev->desc->n_voltages == 1 && !selector)
                return rdev->desc->fixed_uV;
 
-       if (!ops->list_voltage || selector >= rdev->desc->n_voltages)
+       if (ops->list_voltage) {
+               if (selector >= rdev->desc->n_voltages)
+                       return -EINVAL;
+               mutex_lock(&rdev->mutex);
+               ret = ops->list_voltage(rdev, selector);
+               mutex_unlock(&rdev->mutex);
+       } else if (rdev->supply) {
+               ret = regulator_list_voltage(rdev->supply, selector);
+       } else {
                return -EINVAL;
-
-       mutex_lock(&rdev->mutex);
-       ret = ops->list_voltage(rdev, selector);
-       mutex_unlock(&rdev->mutex);
+       }
 
        if (ret > 0) {
                if (ret < rdev->constraints->min_uV)
@@ -2321,6 +2341,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);
@@ -2607,6 +2631,8 @@ static int _regulator_get_voltage(struct regulator_dev *rdev)
                ret = rdev->desc->ops->list_voltage(rdev, 0);
        } else if (rdev->desc->fixed_uV && (rdev->desc->n_voltages == 1)) {
                ret = rdev->desc->fixed_uV;
+       } else if (rdev->supply) {
+               ret = regulator_get_voltage(rdev->supply);
        } else {
                return -EINVAL;
        }
@@ -3447,7 +3473,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);
@@ -3589,6 +3615,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);
 }
@@ -3819,8 +3846,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;
@@ -3829,6 +3857,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)
@@ -3867,4 +3898,4 @@ unlock:
 
        return 0;
 }
-late_initcall(regulator_init_complete);
+late_initcall_sync(regulator_init_complete);