Merge tag 'lsk-v4.4-17.03-android' of git://git.linaro.org/kernel/linux-linaro-stable.git
[firefly-linux-kernel-4.4.55.git] / drivers / regulator / core.c
index 88dbbeb8569ba89a9002b9c775bb37c299ba4ee3..b01fe96b14fe2f74836a0aec6d39bdb898702bb2 100644 (file)
@@ -132,6 +132,19 @@ static bool have_full_constraints(void)
        return has_full_constraints || of_have_populated_dt();
 }
 
+static bool regulator_ops_is_valid(struct regulator_dev *rdev, int ops)
+{
+       if (!rdev->constraints) {
+               rdev_err(rdev, "no constraints\n");
+               return false;
+       }
+
+       if (rdev->constraints->valid_ops_mask & ops)
+               return true;
+
+       return false;
+}
+
 static inline struct regulator_dev *rdev_get_supply(struct regulator_dev *rdev)
 {
        if (rdev && rdev->supply)
@@ -198,28 +211,13 @@ 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)
 {
        BUG_ON(*min_uV > *max_uV);
 
-       if (!rdev->constraints) {
-               rdev_err(rdev, "no constraints\n");
-               return -ENODEV;
-       }
-       if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) {
+       if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) {
                rdev_err(rdev, "voltage operation not allowed\n");
                return -EPERM;
        }
@@ -275,11 +273,7 @@ static int regulator_check_current_limit(struct regulator_dev *rdev,
 {
        BUG_ON(*min_uA > *max_uA);
 
-       if (!rdev->constraints) {
-               rdev_err(rdev, "no constraints\n");
-               return -ENODEV;
-       }
-       if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_CURRENT)) {
+       if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_CURRENT)) {
                rdev_err(rdev, "current operation not allowed\n");
                return -EPERM;
        }
@@ -312,11 +306,7 @@ static int regulator_mode_constrain(struct regulator_dev *rdev, int *mode)
                return -EINVAL;
        }
 
-       if (!rdev->constraints) {
-               rdev_err(rdev, "no constraints\n");
-               return -ENODEV;
-       }
-       if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_MODE)) {
+       if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_MODE)) {
                rdev_err(rdev, "mode operation not allowed\n");
                return -EPERM;
        }
@@ -333,20 +323,6 @@ static int regulator_mode_constrain(struct regulator_dev *rdev, int *mode)
        return -EINVAL;
 }
 
-/* dynamic regulator mode switching constraint check */
-static int regulator_check_drms(struct regulator_dev *rdev)
-{
-       if (!rdev->constraints) {
-               rdev_err(rdev, "no constraints\n");
-               return -ENODEV;
-       }
-       if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS)) {
-               rdev_dbg(rdev, "drms operation not allowed\n");
-               return -EPERM;
-       }
-       return 0;
-}
-
 static ssize_t regulator_uV_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
@@ -692,8 +668,7 @@ static int drms_uA_update(struct regulator_dev *rdev)
         * first check to see if we can set modes at all, otherwise just
         * tell the consumer everything is OK.
         */
-       err = regulator_check_drms(rdev);
-       if (err < 0)
+       if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_DRMS))
                return 0;
 
        if (!rdev->desc->ops->get_optimum_mode &&
@@ -808,8 +783,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;
 
@@ -893,7 +866,7 @@ static void print_constraints(struct regulator_dev *rdev)
        rdev_dbg(rdev, "%s\n", buf);
 
        if ((constraints->min_uV != constraints->max_uV) &&
-           !(constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE))
+           !regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE))
                rdev_warn(rdev,
                          "Voltage range but no REGULATOR_CHANGE_VOLTAGE\n");
 }
@@ -906,7 +879,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 +888,34 @@ 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) {
+                       rdev_info(rdev, "Bringing %duV into %d-%duV\n",
+                                 current_uV, target_min, target_max);
                        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;
                        }
                }
@@ -1057,18 +1050,18 @@ static int set_machine_constraints(struct regulator_dev *rdev,
 
        ret = machine_constraints_voltage(rdev, rdev->constraints);
        if (ret != 0)
-               goto out;
+               return ret;
 
        ret = machine_constraints_current(rdev, rdev->constraints);
        if (ret != 0)
-               goto out;
+               return ret;
 
        if (rdev->constraints->ilim_uA && ops->set_input_current_limit) {
                ret = ops->set_input_current_limit(rdev,
                                                   rdev->constraints->ilim_uA);
                if (ret < 0) {
                        rdev_err(rdev, "failed to set input limit\n");
-                       goto out;
+                       return ret;
                }
        }
 
@@ -1077,21 +1070,20 @@ static int set_machine_constraints(struct regulator_dev *rdev,
                ret = suspend_prepare(rdev, rdev->constraints->initial_state);
                if (ret < 0) {
                        rdev_err(rdev, "failed to set suspend state\n");
-                       goto out;
+                       return ret;
                }
        }
 
        if (rdev->constraints->initial_mode) {
                if (!ops->set_mode) {
                        rdev_err(rdev, "no set_mode operation\n");
-                       ret = -EINVAL;
-                       goto out;
+                       return -EINVAL;
                }
 
                ret = ops->set_mode(rdev, rdev->constraints->initial_mode);
                if (ret < 0) {
                        rdev_err(rdev, "failed to set initial mode: %d\n", ret);
-                       goto out;
+                       return ret;
                }
        }
 
@@ -1102,7 +1094,7 @@ static int set_machine_constraints(struct regulator_dev *rdev,
                ret = _regulator_do_enable(rdev);
                if (ret < 0 && ret != -EINVAL) {
                        rdev_err(rdev, "failed to enable\n");
-                       goto out;
+                       return ret;
                }
        }
 
@@ -1111,7 +1103,7 @@ static int set_machine_constraints(struct regulator_dev *rdev,
                ret = ops->set_ramp_delay(rdev, rdev->constraints->ramp_delay);
                if (ret < 0) {
                        rdev_err(rdev, "failed to set ramp_delay\n");
-                       goto out;
+                       return ret;
                }
        }
 
@@ -1119,7 +1111,7 @@ static int set_machine_constraints(struct regulator_dev *rdev,
                ret = ops->set_pull_down(rdev);
                if (ret < 0) {
                        rdev_err(rdev, "failed to set pull down\n");
-                       goto out;
+                       return ret;
                }
        }
 
@@ -1127,7 +1119,7 @@ static int set_machine_constraints(struct regulator_dev *rdev,
                ret = ops->set_soft_start(rdev);
                if (ret < 0) {
                        rdev_err(rdev, "failed to set soft start\n");
-                       goto out;
+                       return ret;
                }
        }
 
@@ -1136,16 +1128,23 @@ static int set_machine_constraints(struct regulator_dev *rdev,
                ret = ops->set_over_current_protection(rdev);
                if (ret < 0) {
                        rdev_err(rdev, "failed to set over current protection\n");
-                       goto out;
+                       return ret;
+               }
+       }
+
+       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;
-out:
-       kfree(rdev->constraints);
-       rdev->constraints = NULL;
-       return ret;
 }
 
 /**
@@ -1255,6 +1254,55 @@ static void unset_regulator_supplies(struct regulator_dev *rdev)
        }
 }
 
+#ifdef CONFIG_DEBUG_FS
+static ssize_t constraint_flags_read_file(struct file *file,
+                                         char __user *user_buf,
+                                         size_t count, loff_t *ppos)
+{
+       const struct regulator *regulator = file->private_data;
+       const struct regulation_constraints *c = regulator->rdev->constraints;
+       char *buf;
+       ssize_t ret;
+
+       if (!c)
+               return 0;
+
+       buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       ret = snprintf(buf, PAGE_SIZE,
+                       "always_on: %u\n"
+                       "boot_on: %u\n"
+                       "apply_uV: %u\n"
+                       "ramp_disable: %u\n"
+                       "soft_start: %u\n"
+                       "pull_down: %u\n"
+                       "over_current_protection: %u\n",
+                       c->always_on,
+                       c->boot_on,
+                       c->apply_uV,
+                       c->ramp_disable,
+                       c->soft_start,
+                       c->pull_down,
+                       c->over_current_protection);
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+       kfree(buf);
+
+       return ret;
+}
+
+#endif
+
+static const struct file_operations constraint_flags_fops = {
+#ifdef CONFIG_DEBUG_FS
+       .open = simple_open,
+       .read = constraint_flags_read_file,
+       .llseek = default_llseek,
+#endif
+};
+
 #define REG_STR_SIZE   64
 
 static struct regulator *create_regulator(struct regulator_dev *rdev,
@@ -1310,6 +1358,9 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
                                   &regulator->min_uV);
                debugfs_create_u32("max_uV", 0444, regulator->debugfs,
                                   &regulator->max_uV);
+               debugfs_create_file("constraint_flags", 0444,
+                                   regulator->debugfs, regulator,
+                                   &constraint_flags_fops);
        }
 
        /*
@@ -1317,7 +1368,7 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
         * it is then we don't need to do nearly so much work for
         * enable/disable calls.
         */
-       if (!_regulator_can_change_status(rdev) &&
+       if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_STATUS) &&
            _regulator_is_enabled(rdev))
                regulator->always_on = true;
 
@@ -1515,10 +1566,11 @@ 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);
+                       rdev->supply = NULL;
                        return ret;
                }
        }
@@ -2094,15 +2146,15 @@ static int _regulator_enable(struct regulator_dev *rdev)
        lockdep_assert_held_once(&rdev->mutex);
 
        /* check voltage and requested load before enabling */
-       if (rdev->constraints &&
-           (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS))
+       if (regulator_ops_is_valid(rdev, REGULATOR_CHANGE_DRMS))
                drms_uA_update(rdev);
 
        if (rdev->use_count == 0) {
                /* The regulator may on if it's not switchable or left on */
                ret = _regulator_is_enabled(rdev);
                if (ret == -EINVAL || ret == 0) {
-                       if (!_regulator_can_change_status(rdev))
+                       if (!regulator_ops_is_valid(rdev,
+                                       REGULATOR_CHANGE_STATUS))
                                return -EPERM;
 
                        ret = _regulator_do_enable(rdev);
@@ -2204,7 +2256,7 @@ static int _regulator_disable(struct regulator_dev *rdev)
            (rdev->constraints && !rdev->constraints->always_on)) {
 
                /* we are last user */
-               if (_regulator_can_change_status(rdev)) {
+               if (regulator_ops_is_valid(rdev, REGULATOR_CHANGE_STATUS)) {
                        ret = _notifier_call_chain(rdev,
                                                   REGULATOR_EVENT_PRE_DISABLE,
                                                   NULL);
@@ -2225,10 +2277,7 @@ static int _regulator_disable(struct regulator_dev *rdev)
 
                rdev->use_count = 0;
        } else if (rdev->use_count > 1) {
-
-               if (rdev->constraints &&
-                       (rdev->constraints->valid_ops_mask &
-                       REGULATOR_CHANGE_DRMS))
+               if (regulator_ops_is_valid(rdev, REGULATOR_CHANGE_DRMS))
                        drms_uA_update(rdev);
 
                rdev->use_count--;
@@ -2368,7 +2417,6 @@ static void regulator_disable_work(struct work_struct *work)
 int regulator_disable_deferred(struct regulator *regulator, int ms)
 {
        struct regulator_dev *rdev = regulator->rdev;
-       int ret;
 
        if (regulator->always_on)
                return 0;
@@ -2380,13 +2428,9 @@ int regulator_disable_deferred(struct regulator *regulator, int ms)
        rdev->deferred_disables++;
        mutex_unlock(&rdev->mutex);
 
-       ret = queue_delayed_work(system_power_efficient_wq,
-                                &rdev->disable_work,
-                                msecs_to_jiffies(ms));
-       if (ret < 0)
-               return ret;
-       else
-               return 0;
+       queue_delayed_work(system_power_efficient_wq, &rdev->disable_work,
+                          msecs_to_jiffies(ms));
+       return 0;
 }
 EXPORT_SYMBOL_GPL(regulator_disable_deferred);
 
@@ -2477,8 +2521,7 @@ int regulator_can_change_voltage(struct regulator *regulator)
 {
        struct regulator_dev    *rdev = regulator->rdev;
 
-       if (rdev->constraints &&
-           (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) {
+       if (regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) {
                if (rdev->desc->n_voltages - rdev->desc->linear_min_sel > 1)
                        return 1;
 
@@ -2632,7 +2675,7 @@ int regulator_is_supported_voltage(struct regulator *regulator,
        int i, voltages, ret;
 
        /* If we can't change voltage check the current voltage */
-       if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) {
+       if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) {
                ret = regulator_get_voltage(regulator);
                if (ret >= 0)
                        return min_uV <= ret && ret <= max_uV;
@@ -2838,7 +2881,7 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
         * return successfully even though the regulator does not support
         * changing the voltage.
         */
-       if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) {
+       if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) {
                current_uV = _regulator_get_voltage(rdev);
                if (min_uV <= current_uV && current_uV <= max_uV) {
                        regulator->min_uV = min_uV;
@@ -3097,6 +3140,23 @@ 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) {
+                               rdev_err(rdev,
+                                        "bypassed regulator has no supply!\n");
+                               return -EPROBE_DEFER;
+                       }
+
+                       return _regulator_get_voltage(rdev->supply->rdev);
+               }
+       }
 
        if (rdev->desc->ops->get_voltage_sel) {
                sel = rdev->desc->ops->get_voltage_sel(rdev);
@@ -3353,8 +3413,7 @@ int regulator_allow_bypass(struct regulator *regulator, bool enable)
        if (!rdev->desc->ops->set_bypass)
                return 0;
 
-       if (rdev->constraints &&
-           !(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_BYPASS))
+       if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_BYPASS))
                return 0;
 
        mutex_lock(&rdev->mutex);
@@ -3451,8 +3510,10 @@ int regulator_bulk_get(struct device *dev, int num_consumers,
                consumers[i].consumer = NULL;
 
        for (i = 0; i < num_consumers; i++) {
-               consumers[i].consumer = regulator_get(dev,
-                                                     consumers[i].supply);
+               consumers[i].consumer = _regulator_get(dev,
+                                                      consumers[i].supply,
+                                                      false,
+                                                      !consumers[i].optional);
                if (IS_ERR(consumers[i].consumer)) {
                        ret = PTR_ERR(consumers[i].consumer);
                        dev_err(dev, "Failed to get supply '%s': %d\n",
@@ -3708,7 +3769,7 @@ static umode_t regulator_attr_is_visible(struct kobject *kobj,
                                         struct attribute *attr, int idx)
 {
        struct device *dev = kobj_to_dev(kobj);
-       struct regulator_dev *rdev = container_of(dev, struct regulator_dev, dev);
+       struct regulator_dev *rdev = dev_to_rdev(dev);
        const struct regulator_ops *ops = rdev->desc->ops;
        umode_t mode = attr->mode;
 
@@ -3826,6 +3887,16 @@ static void rdev_init_debugfs(struct regulator_dev *rdev)
                           &rdev->bypass_count);
 }
 
+static int regulator_register_resolve_supply(struct device *dev, void *data)
+{
+       struct regulator_dev *rdev = dev_to_rdev(dev);
+
+       if (regulator_resolve_supply(rdev))
+               rdev_dbg(rdev, "unable to resolve supply\n");
+
+       return 0;
+}
+
 /**
  * regulator_register - register regulator
  * @regulator_desc: regulator to register
@@ -3897,8 +3968,6 @@ regulator_register(const struct regulator_desc *regulator_desc,
                rdev->dev.of_node = of_node_get(config->of_node);
        }
 
-       mutex_lock(&regulator_list_mutex);
-
        mutex_init(&rdev->mutex);
        rdev->reg_data = config->driver_data;
        rdev->owner = regulator_desc->owner;
@@ -3921,78 +3990,90 @@ regulator_register(const struct regulator_desc *regulator_desc,
                        goto clean;
        }
 
-       /* register with sysfs */
-       rdev->dev.class = &regulator_class;
-       rdev->dev.parent = dev;
-       dev_set_name(&rdev->dev, "regulator.%lu",
-                   (unsigned long) atomic_inc_return(&regulator_no));
-       ret = device_register(&rdev->dev);
-       if (ret != 0) {
-               put_device(&rdev->dev);
-               goto clean;
-       }
-
-       dev_set_drvdata(&rdev->dev, rdev);
-
        if ((config->ena_gpio || config->ena_gpio_initialized) &&
            gpio_is_valid(config->ena_gpio)) {
+               mutex_lock(&regulator_list_mutex);
                ret = regulator_ena_gpio_request(rdev, config);
+               mutex_unlock(&regulator_list_mutex);
                if (ret != 0) {
                        rdev_err(rdev, "Failed to request enable GPIO%d: %d\n",
                                 config->ena_gpio, ret);
-                       goto wash;
+                       goto clean;
                }
        }
 
+       /* register with sysfs */
+       rdev->dev.class = &regulator_class;
+       rdev->dev.parent = dev;
+       dev_set_name(&rdev->dev, "regulator.%lu",
+                   (unsigned long) atomic_inc_return(&regulator_no));
+
        /* set regulator constraints */
        if (init_data)
                constraints = &init_data->constraints;
 
-       ret = set_machine_constraints(rdev, constraints);
-       if (ret < 0)
-               goto scrub;
-
        if (init_data && init_data->supply_regulator)
                rdev->supply_name = init_data->supply_regulator;
        else if (regulator_desc->supply_name)
                rdev->supply_name = regulator_desc->supply_name;
 
+       /*
+        * Attempt to resolve the regulator supply, if specified,
+        * but don't return an error if we fail because we will try
+        * to resolve it again later as more regulators are added.
+        */
+       if (regulator_resolve_supply(rdev))
+               rdev_dbg(rdev, "unable to resolve supply\n");
+
+       ret = set_machine_constraints(rdev, constraints);
+       if (ret < 0)
+               goto wash;
+
        /* add consumers devices */
        if (init_data) {
+               mutex_lock(&regulator_list_mutex);
                for (i = 0; i < init_data->num_consumer_supplies; i++) {
                        ret = set_consumer_device_supply(rdev,
                                init_data->consumer_supplies[i].dev_name,
                                init_data->consumer_supplies[i].supply);
                        if (ret < 0) {
+                               mutex_unlock(&regulator_list_mutex);
                                dev_err(dev, "Failed to set supply %s\n",
                                        init_data->consumer_supplies[i].supply);
                                goto unset_supplies;
                        }
                }
+               mutex_unlock(&regulator_list_mutex);
        }
 
+       ret = device_register(&rdev->dev);
+       if (ret != 0) {
+               put_device(&rdev->dev);
+               goto unset_supplies;
+       }
+
+       dev_set_drvdata(&rdev->dev, rdev);
        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;
 
 unset_supplies:
+       mutex_lock(&regulator_list_mutex);
        unset_regulator_supplies(rdev);
-
-scrub:
-       regulator_ena_gpio_free(rdev);
-       kfree(rdev->constraints);
+       mutex_unlock(&regulator_list_mutex);
 wash:
-       device_unregister(&rdev->dev);
-       /* device core frees rdev */
-       rdev = ERR_PTR(ret);
-       goto out;
-
+       kfree(rdev->constraints);
+       mutex_lock(&regulator_list_mutex);
+       regulator_ena_gpio_free(rdev);
+       mutex_unlock(&regulator_list_mutex);
 clean:
        kfree(rdev);
-       rdev = ERR_PTR(ret);
-       goto out;
+       kfree(config);
+       return ERR_PTR(ret);
 }
 EXPORT_SYMBOL_GPL(regulator_register);
 
@@ -4018,8 +4099,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);
@@ -4373,7 +4454,7 @@ static int __init regulator_late_cleanup(struct device *dev, void *data)
        if (c && c->always_on)
                return 0;
 
-       if (c && !(c->valid_ops_mask & REGULATOR_CHANGE_STATUS))
+       if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_STATUS))
                return 0;
 
        mutex_lock(&rdev->mutex);