Merge remote-tracking branches 'regulator/topic/can-change', 'regulator/topic/constra...
[cascardo/linux.git] / drivers / regulator / core.c
index bca9167..ec8184d 100644 (file)
@@ -783,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;
 
@@ -1145,17 +1143,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;
 }
@@ -1267,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,
@@ -1322,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);
        }
 
        /*
@@ -1527,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;
                }
        }
@@ -3100,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);
@@ -3830,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
@@ -3901,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;
@@ -3927,7 +3992,9 @@ regulator_register(const struct regulator_desc *regulator_desc,
 
        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);
@@ -3940,63 +4007,73 @@ regulator_register(const struct regulator_desc *regulator_desc,
        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 wash;
-       }
-
-       dev_set_drvdata(&rdev->dev, rdev);
 
        /* 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);
-       device_unregister(&rdev->dev);
-       /* device core frees rdev */
-       rdev = ERR_PTR(ret);
-       goto out;
-
+       mutex_unlock(&regulator_list_mutex);
 wash:
+       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);
 
@@ -4022,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);