Merge remote-tracking branch 'regulator/topic/core' into regulator-next
[linux-2.6-block.git] / drivers / regulator / core.c
index e0b7642847731390ed44bbc3e8718fd5dd9e7116..aa98f114cacf83d18abdf0a60b4dc6b6567e7d9a 100644 (file)
@@ -808,8 +808,6 @@ static int suspend_set_state(struct regulator_dev *rdev,
 /* locks held by caller */
 static int suspend_prepare(struct regulator_dev *rdev, suspend_state_t state)
 {
-       lockdep_assert_held_once(&rdev->mutex);
-
        if (!rdev->constraints)
                return -EINVAL;
 
@@ -906,7 +904,8 @@ 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) {
+           rdev->constraints->min_uV && rdev->constraints->max_uV) {
+               int target_min, target_max;
                int current_uV = _regulator_get_voltage(rdev);
                if (current_uV < 0) {
                        rdev_err(rdev,
@@ -914,15 +913,32 @@ static int machine_constraints_voltage(struct regulator_dev *rdev,
                                 current_uV);
                        return current_uV;
                }
-               if (current_uV < rdev->constraints->min_uV ||
-                   current_uV > rdev->constraints->max_uV) {
+
+               /*
+                * If we're below the minimum voltage move up to the
+                * minimum voltage, if we're above the maximum voltage
+                * then move down to the maximum.
+                */
+               target_min = current_uV;
+               target_max = current_uV;
+
+               if (current_uV < rdev->constraints->min_uV) {
+                       target_min = rdev->constraints->min_uV;
+                       target_max = rdev->constraints->min_uV;
+               }
+
+               if (current_uV > rdev->constraints->max_uV) {
+                       target_min = rdev->constraints->max_uV;
+                       target_max = rdev->constraints->max_uV;
+               }
+
+               if (target_min != current_uV || target_max != current_uV) {
                        ret = _regulator_do_set_voltage(
-                               rdev, rdev->constraints->min_uV,
-                               rdev->constraints->max_uV);
+                               rdev, target_min, target_max);
                        if (ret < 0) {
                                rdev_err(rdev,
-                                       "failed to apply %duV constraint(%d)\n",
-                                       rdev->constraints->min_uV, ret);
+                                       "failed to apply %d-%duV constraint(%d)\n",
+                                       target_min, target_max, ret);
                                return ret;
                        }
                }
@@ -1150,17 +1166,6 @@ static int set_machine_constraints(struct regulator_dev *rdev,
                }
        }
 
-       if (rdev->constraints->active_discharge && ops->set_active_discharge) {
-               bool ad_state = (rdev->constraints->active_discharge ==
-                             REGULATOR_ACTIVE_DISCHARGE_ENABLE) ? true : false;
-
-               ret = ops->set_active_discharge(rdev, ad_state);
-               if (ret < 0) {
-                       rdev_err(rdev, "failed to set active discharge\n");
-                       return ret;
-               }
-       }
-
        print_constraints(rdev);
        return 0;
 }
@@ -1532,7 +1537,7 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
        }
 
        /* Cascade always-on state to supply */
-       if (_regulator_is_enabled(rdev) && rdev->supply) {
+       if (_regulator_is_enabled(rdev)) {
                ret = regulator_enable(rdev->supply);
                if (ret < 0) {
                        _regulator_put(rdev->supply);
@@ -3109,6 +3114,20 @@ EXPORT_SYMBOL_GPL(regulator_sync_voltage);
 static int _regulator_get_voltage(struct regulator_dev *rdev)
 {
        int sel, ret;
+       bool bypassed;
+
+       if (rdev->desc->ops->get_bypass) {
+               ret = rdev->desc->ops->get_bypass(rdev, &bypassed);
+               if (ret < 0)
+                       return ret;
+               if (bypassed) {
+                       /* if bypassed the regulator must have a supply */
+                       if (!rdev->supply)
+                               return -EINVAL;
+
+                       return _regulator_get_voltage(rdev->supply->rdev);
+               }
+       }
 
        if (rdev->desc->ops->get_voltage_sel) {
                sel = rdev->desc->ops->get_voltage_sel(rdev);
@@ -3840,6 +3859,11 @@ static void rdev_init_debugfs(struct regulator_dev *rdev)
                           &rdev->bypass_count);
 }
 
+static int regulator_register_resolve_supply(struct device *dev, void *data)
+{
+       return regulator_resolve_supply(dev_to_rdev(dev));
+}
+
 /**
  * regulator_register - register regulator
  * @regulator_desc: regulator to register
@@ -3986,8 +4010,11 @@ regulator_register(const struct regulator_desc *regulator_desc,
        }
 
        rdev_init_debugfs(rdev);
-out:
        mutex_unlock(&regulator_list_mutex);
+
+       /* try to resolve regulators supply since a new one was registered */
+       class_for_each_device(&regulator_class, NULL, NULL,
+                             regulator_register_resolve_supply);
        kfree(config);
        return rdev;
 
@@ -3998,15 +4025,16 @@ scrub:
        regulator_ena_gpio_free(rdev);
        device_unregister(&rdev->dev);
        /* device core frees rdev */
-       rdev = ERR_PTR(ret);
        goto out;
 
 wash:
        regulator_ena_gpio_free(rdev);
 clean:
        kfree(rdev);
-       rdev = ERR_PTR(ret);
-       goto out;
+out:
+       mutex_unlock(&regulator_list_mutex);
+       kfree(config);
+       return ERR_PTR(ret);
 }
 EXPORT_SYMBOL_GPL(regulator_register);
 
@@ -4032,8 +4060,8 @@ void regulator_unregister(struct regulator_dev *rdev)
        WARN_ON(rdev->open_count);
        unset_regulator_supplies(rdev);
        list_del(&rdev->list);
-       mutex_unlock(&regulator_list_mutex);
        regulator_ena_gpio_free(rdev);
+       mutex_unlock(&regulator_list_mutex);
        device_unregister(&rdev->dev);
 }
 EXPORT_SYMBOL_GPL(regulator_unregister);