|
|
@@ -111,6 +111,11 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
|
|
|
const char *supply_name);
|
|
|
static void _regulator_put(struct regulator *regulator);
|
|
|
|
|
|
+static struct regulator_dev *dev_to_rdev(struct device *dev)
|
|
|
+{
|
|
|
+ return container_of(dev, struct regulator_dev, dev);
|
|
|
+}
|
|
|
+
|
|
|
static const char *rdev_get_name(struct regulator_dev *rdev)
|
|
|
{
|
|
|
if (rdev->constraints && rdev->constraints->name)
|
|
|
@@ -1612,14 +1617,15 @@ static void _regulator_put(struct regulator *regulator)
|
|
|
if (regulator->dev)
|
|
|
sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name);
|
|
|
mutex_lock(&rdev->mutex);
|
|
|
- kfree(regulator->supply_name);
|
|
|
list_del(®ulator->list);
|
|
|
- kfree(regulator);
|
|
|
|
|
|
rdev->open_count--;
|
|
|
rdev->exclusive = 0;
|
|
|
mutex_unlock(&rdev->mutex);
|
|
|
|
|
|
+ kfree(regulator->supply_name);
|
|
|
+ kfree(regulator);
|
|
|
+
|
|
|
module_put(rdev->owner);
|
|
|
}
|
|
|
|
|
|
@@ -3608,6 +3614,9 @@ static const struct attribute_group *regulator_dev_groups[] = {
|
|
|
static void regulator_dev_release(struct device *dev)
|
|
|
{
|
|
|
struct regulator_dev *rdev = dev_get_drvdata(dev);
|
|
|
+
|
|
|
+ kfree(rdev->constraints);
|
|
|
+ of_node_put(rdev->dev.of_node);
|
|
|
kfree(rdev);
|
|
|
}
|
|
|
|
|
|
@@ -3839,9 +3848,7 @@ void regulator_unregister(struct regulator_dev *rdev)
|
|
|
unset_regulator_supplies(rdev);
|
|
|
list_del(&rdev->list);
|
|
|
mutex_unlock(®ulator_list_mutex);
|
|
|
- kfree(rdev->constraints);
|
|
|
regulator_ena_gpio_free(rdev);
|
|
|
- of_node_put(rdev->dev.of_node);
|
|
|
device_unregister(&rdev->dev);
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(regulator_unregister);
|
|
|
@@ -4161,13 +4168,57 @@ static int __init regulator_init(void)
|
|
|
/* init early to allow our consumers to complete system booting */
|
|
|
core_initcall(regulator_init);
|
|
|
|
|
|
-static int __init regulator_init_complete(void)
|
|
|
+static int __init regulator_late_cleanup(struct device *dev, void *data)
|
|
|
{
|
|
|
- struct regulator_dev *rdev;
|
|
|
- const struct regulator_ops *ops;
|
|
|
- struct regulation_constraints *c;
|
|
|
+ struct regulator_dev *rdev = dev_to_rdev(dev);
|
|
|
+ const struct regulator_ops *ops = rdev->desc->ops;
|
|
|
+ struct regulation_constraints *c = rdev->constraints;
|
|
|
int enabled, ret;
|
|
|
|
|
|
+ if (c && c->always_on)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if (c && !(c->valid_ops_mask & REGULATOR_CHANGE_STATUS))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ mutex_lock(&rdev->mutex);
|
|
|
+
|
|
|
+ if (rdev->use_count)
|
|
|
+ goto unlock;
|
|
|
+
|
|
|
+ /* If we can't read the status assume it's on. */
|
|
|
+ if (ops->is_enabled)
|
|
|
+ enabled = ops->is_enabled(rdev);
|
|
|
+ else
|
|
|
+ enabled = 1;
|
|
|
+
|
|
|
+ if (!enabled)
|
|
|
+ goto unlock;
|
|
|
+
|
|
|
+ if (have_full_constraints()) {
|
|
|
+ /* We log since this may kill the system if it goes
|
|
|
+ * wrong. */
|
|
|
+ rdev_info(rdev, "disabling\n");
|
|
|
+ ret = _regulator_do_disable(rdev);
|
|
|
+ if (ret != 0)
|
|
|
+ rdev_err(rdev, "couldn't disable: %d\n", ret);
|
|
|
+ } else {
|
|
|
+ /* The intention is that in future we will
|
|
|
+ * assume that full constraints are provided
|
|
|
+ * so warn even if we aren't going to do
|
|
|
+ * anything here.
|
|
|
+ */
|
|
|
+ rdev_warn(rdev, "incomplete constraints, leaving on\n");
|
|
|
+ }
|
|
|
+
|
|
|
+unlock:
|
|
|
+ mutex_unlock(&rdev->mutex);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int __init regulator_init_complete(void)
|
|
|
+{
|
|
|
/*
|
|
|
* Since DT doesn't provide an idiomatic mechanism for
|
|
|
* enabling full constraints and since it's much more natural
|
|
|
@@ -4177,58 +4228,13 @@ static int __init regulator_init_complete(void)
|
|
|
if (of_have_populated_dt())
|
|
|
has_full_constraints = true;
|
|
|
|
|
|
- mutex_lock(®ulator_list_mutex);
|
|
|
-
|
|
|
/* If we have a full configuration then disable any regulators
|
|
|
* 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, ®ulator_list, list) {
|
|
|
- ops = rdev->desc->ops;
|
|
|
- c = rdev->constraints;
|
|
|
-
|
|
|
- if (c && c->always_on)
|
|
|
- continue;
|
|
|
-
|
|
|
- if (c && !(c->valid_ops_mask & REGULATOR_CHANGE_STATUS))
|
|
|
- continue;
|
|
|
-
|
|
|
- mutex_lock(&rdev->mutex);
|
|
|
-
|
|
|
- if (rdev->use_count)
|
|
|
- goto unlock;
|
|
|
-
|
|
|
- /* If we can't read the status assume it's on. */
|
|
|
- if (ops->is_enabled)
|
|
|
- enabled = ops->is_enabled(rdev);
|
|
|
- else
|
|
|
- enabled = 1;
|
|
|
-
|
|
|
- if (!enabled)
|
|
|
- goto unlock;
|
|
|
-
|
|
|
- if (have_full_constraints()) {
|
|
|
- /* We log since this may kill the system if it
|
|
|
- * goes wrong. */
|
|
|
- rdev_info(rdev, "disabling\n");
|
|
|
- ret = _regulator_do_disable(rdev);
|
|
|
- if (ret != 0)
|
|
|
- rdev_err(rdev, "couldn't disable: %d\n", ret);
|
|
|
- } else {
|
|
|
- /* The intention is that in future we will
|
|
|
- * assume that full constraints are provided
|
|
|
- * so warn even if we aren't going to do
|
|
|
- * anything here.
|
|
|
- */
|
|
|
- rdev_warn(rdev, "incomplete constraints, leaving on\n");
|
|
|
- }
|
|
|
-
|
|
|
-unlock:
|
|
|
- mutex_unlock(&rdev->mutex);
|
|
|
- }
|
|
|
-
|
|
|
- mutex_unlock(®ulator_list_mutex);
|
|
|
+ class_for_each_device(®ulator_class, NULL, NULL,
|
|
|
+ regulator_late_cleanup);
|
|
|
|
|
|
return 0;
|
|
|
}
|