Loading drivers/regulator/core.c +164 −91 Original line number Diff line number Diff line Loading @@ -51,7 +51,6 @@ pr_debug("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) static DEFINE_MUTEX(regulator_list_mutex); static LIST_HEAD(regulator_list); static LIST_HEAD(regulator_map_list); static LIST_HEAD(regulator_ena_gpio_list); static LIST_HEAD(regulator_supply_alias_list); Loading @@ -59,6 +58,8 @@ static bool has_full_constraints; static struct dentry *debugfs_root; static struct class regulator_class; /* * struct regulator_map * Loading Loading @@ -1325,6 +1326,47 @@ static void regulator_supply_alias(struct device **dev, const char **supply) } } static int of_node_match(struct device *dev, const void *data) { return dev->of_node == data; } static struct regulator_dev *of_find_regulator_by_node(struct device_node *np) { struct device *dev; dev = class_find_device(®ulator_class, NULL, np, of_node_match); return dev ? dev_to_rdev(dev) : NULL; } static int regulator_match(struct device *dev, const void *data) { struct regulator_dev *r = dev_to_rdev(dev); return strcmp(rdev_get_name(r), data) == 0; } static struct regulator_dev *regulator_lookup_by_name(const char *name) { struct device *dev; dev = class_find_device(®ulator_class, NULL, name, regulator_match); return dev ? dev_to_rdev(dev) : NULL; } /** * regulator_dev_lookup - lookup a regulator device. * @dev: device for regulator "consumer". * @supply: Supply name or regulator ID. * @ret: 0 on success, -ENODEV if lookup fails permanently, -EPROBE_DEFER if * lookup could succeed in the future. * * If successful, returns a struct regulator_dev that corresponds to the name * @supply and with the embedded struct device refcount incremented by one, * or NULL on failure. The refcount must be dropped by calling put_device(). */ static struct regulator_dev *regulator_dev_lookup(struct device *dev, const char *supply, int *ret) Loading @@ -1340,9 +1382,8 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev, if (dev && dev->of_node) { node = of_get_regulator(dev, supply); if (node) { list_for_each_entry(r, ®ulator_list, list) if (r->dev.parent && node == r->dev.of_node) r = of_find_regulator_by_node(node); if (r) return r; *ret = -EPROBE_DEFER; return NULL; Loading @@ -1361,20 +1402,24 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev, if (dev) devname = dev_name(dev); list_for_each_entry(r, ®ulator_list, list) if (strcmp(rdev_get_name(r), supply) == 0) r = regulator_lookup_by_name(supply); if (r) return r; mutex_lock(®ulator_list_mutex); list_for_each_entry(map, ®ulator_map_list, list) { /* If the mapping has a device set up it must match */ if (map->dev_name && (!devname || strcmp(map->dev_name, devname))) continue; if (strcmp(map->supply, supply) == 0) if (strcmp(map->supply, supply) == 0 && get_device(&map->regulator->dev)) { mutex_unlock(®ulator_list_mutex); return map->regulator; } } mutex_unlock(®ulator_list_mutex); return NULL; } Loading Loading @@ -1409,6 +1454,7 @@ static int regulator_resolve_supply(struct regulator_dev *rdev) if (have_full_constraints()) { r = dummy_regulator_rdev; get_device(&r->dev); } else { dev_err(dev, "Failed to resolve %s-supply for %s\n", rdev->supply_name, rdev->desc->name); Loading @@ -1418,12 +1464,16 @@ static int regulator_resolve_supply(struct regulator_dev *rdev) /* Recursively resolve the supply of the supply */ ret = regulator_resolve_supply(r); if (ret < 0) if (ret < 0) { put_device(&r->dev); return ret; } ret = set_supply(rdev, r); if (ret < 0) if (ret < 0) { put_device(&r->dev); return ret; } /* Cascade always-on state to supply */ if (_regulator_is_enabled(rdev) && rdev->supply) { Loading Loading @@ -1459,8 +1509,6 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, else ret = -EPROBE_DEFER; mutex_lock(®ulator_list_mutex); rdev = regulator_dev_lookup(dev, id, &ret); if (rdev) goto found; Loading @@ -1472,7 +1520,7 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, * succeed, so, quit with appropriate error value */ if (ret && ret != -ENODEV) goto out; return regulator; if (!devname) devname = "deviceless"; Loading @@ -1486,40 +1534,46 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, devname, id); rdev = dummy_regulator_rdev; get_device(&rdev->dev); goto found; /* Don't log an error when called from regulator_get_optional() */ } else if (!have_full_constraints() || exclusive) { dev_warn(dev, "dummy supplies not allowed\n"); } mutex_unlock(®ulator_list_mutex); return regulator; found: if (rdev->exclusive) { regulator = ERR_PTR(-EPERM); goto out; put_device(&rdev->dev); return regulator; } if (exclusive && rdev->open_count) { regulator = ERR_PTR(-EBUSY); goto out; put_device(&rdev->dev); return regulator; } ret = regulator_resolve_supply(rdev); if (ret < 0) { regulator = ERR_PTR(ret); goto out; put_device(&rdev->dev); return regulator; } if (!try_module_get(rdev->owner)) goto out; if (!try_module_get(rdev->owner)) { put_device(&rdev->dev); return regulator; } regulator = create_regulator(rdev, dev, id); if (regulator == NULL) { regulator = ERR_PTR(-ENOMEM); put_device(&rdev->dev); module_put(rdev->owner); goto out; return regulator; } rdev->open_count++; Loading @@ -1533,9 +1587,6 @@ found: rdev->use_count = 0; } out: mutex_unlock(®ulator_list_mutex); return regulator; } Loading Loading @@ -1633,6 +1684,7 @@ static void _regulator_put(struct regulator *regulator) rdev->open_count--; rdev->exclusive = 0; put_device(&rdev->dev); mutex_unlock(&rdev->mutex); kfree(regulator->supply_name); Loading Loading @@ -3810,8 +3862,6 @@ regulator_register(const struct regulator_desc *regulator_desc, } } list_add(&rdev->list, ®ulator_list); rdev_init_debugfs(rdev); out: mutex_unlock(®ulator_list_mutex); Loading Loading @@ -3865,6 +3915,19 @@ void regulator_unregister(struct regulator_dev *rdev) } EXPORT_SYMBOL_GPL(regulator_unregister); static int _regulator_suspend_prepare(struct device *dev, void *data) { struct regulator_dev *rdev = dev_to_rdev(dev); const suspend_state_t *state = data; int ret; mutex_lock(&rdev->mutex); ret = suspend_prepare(rdev, *state); mutex_unlock(&rdev->mutex); return ret; } /** * regulator_suspend_prepare - prepare regulators for system wide suspend * @state: system suspend state Loading @@ -3874,50 +3937,28 @@ EXPORT_SYMBOL_GPL(regulator_unregister); */ int regulator_suspend_prepare(suspend_state_t state) { struct regulator_dev *rdev; int ret = 0; /* ON is handled by regulator active state */ if (state == PM_SUSPEND_ON) return -EINVAL; mutex_lock(®ulator_list_mutex); list_for_each_entry(rdev, ®ulator_list, list) { mutex_lock(&rdev->mutex); ret = suspend_prepare(rdev, state); mutex_unlock(&rdev->mutex); if (ret < 0) { rdev_err(rdev, "failed to prepare\n"); goto out; } } out: mutex_unlock(®ulator_list_mutex); return ret; return class_for_each_device(®ulator_class, NULL, &state, _regulator_suspend_prepare); } EXPORT_SYMBOL_GPL(regulator_suspend_prepare); /** * regulator_suspend_finish - resume regulators from system wide suspend * * Turn on regulators that might be turned off by regulator_suspend_prepare * and that should be turned on according to the regulators properties. */ int regulator_suspend_finish(void) static int _regulator_suspend_finish(struct device *dev, void *data) { struct regulator_dev *rdev; int ret = 0, error; struct regulator_dev *rdev = dev_to_rdev(dev); int ret; mutex_lock(®ulator_list_mutex); list_for_each_entry(rdev, ®ulator_list, list) { mutex_lock(&rdev->mutex); if (rdev->use_count > 0 || rdev->constraints->always_on) { if (!_regulator_is_enabled(rdev)) { error = _regulator_do_enable(rdev); if (error) ret = error; ret = _regulator_do_enable(rdev); if (ret) dev_err(dev, "Failed to resume regulator %d\n", ret); } } else { if (!have_full_constraints()) Loading @@ -3925,15 +3966,27 @@ int regulator_suspend_finish(void) if (!_regulator_is_enabled(rdev)) goto unlock; error = _regulator_do_disable(rdev); if (error) ret = error; ret = _regulator_do_disable(rdev); if (ret) dev_err(dev, "Failed to suspend regulator %d\n", ret); } unlock: mutex_unlock(&rdev->mutex); /* Keep processing regulators in spite of any errors */ return 0; } mutex_unlock(®ulator_list_mutex); return ret; /** * regulator_suspend_finish - resume regulators from system wide suspend * * Turn on regulators that might be turned off by regulator_suspend_prepare * and that should be turned on according to the regulators properties. */ int regulator_suspend_finish(void) { return class_for_each_device(®ulator_class, NULL, NULL, _regulator_suspend_finish); } EXPORT_SYMBOL_GPL(regulator_suspend_finish); Loading Loading @@ -4053,14 +4106,35 @@ static const struct file_operations supply_map_fops = { }; #ifdef CONFIG_DEBUG_FS struct summary_data { struct seq_file *s; struct regulator_dev *parent; int level; }; static void regulator_summary_show_subtree(struct seq_file *s, struct regulator_dev *rdev, int level); static int regulator_summary_show_children(struct device *dev, void *data) { struct regulator_dev *rdev = dev_to_rdev(dev); struct summary_data *summary_data = data; if (rdev->supply && rdev->supply->rdev == summary_data->parent) regulator_summary_show_subtree(summary_data->s, rdev, summary_data->level + 1); return 0; } static void regulator_summary_show_subtree(struct seq_file *s, struct regulator_dev *rdev, int level) { struct list_head *list = s->private; struct regulator_dev *child; struct regulation_constraints *c; struct regulator *consumer; struct summary_data summary_data; if (!rdev) return; Loading Loading @@ -4110,33 +4184,32 @@ static void regulator_summary_show_subtree(struct seq_file *s, seq_puts(s, "\n"); } list_for_each_entry(child, list, list) { /* handle only non-root regulators supplied by current rdev */ if (!child->supply || child->supply->rdev != rdev) continue; summary_data.s = s; summary_data.level = level; summary_data.parent = rdev; regulator_summary_show_subtree(s, child, level + 1); class_for_each_device(®ulator_class, NULL, &summary_data, regulator_summary_show_children); } static int regulator_summary_show_roots(struct device *dev, void *data) { struct regulator_dev *rdev = dev_to_rdev(dev); struct seq_file *s = data; if (!rdev->supply) regulator_summary_show_subtree(s, rdev, 0); return 0; } static int regulator_summary_show(struct seq_file *s, void *data) { struct list_head *list = s->private; struct regulator_dev *rdev; seq_puts(s, " regulator use open bypass voltage current min max\n"); seq_puts(s, "-------------------------------------------------------------------------------\n"); mutex_lock(®ulator_list_mutex); list_for_each_entry(rdev, list, list) { if (rdev->supply) continue; regulator_summary_show_subtree(s, rdev, 0); } mutex_unlock(®ulator_list_mutex); class_for_each_device(®ulator_class, NULL, s, regulator_summary_show_roots); return 0; } Loading Loading @@ -4170,7 +4243,7 @@ static int __init regulator_init(void) &supply_map_fops); debugfs_create_file("regulator_summary", 0444, debugfs_root, ®ulator_list, ®ulator_summary_fops); NULL, ®ulator_summary_fops); regulator_dummy_init(); Loading Loading
drivers/regulator/core.c +164 −91 Original line number Diff line number Diff line Loading @@ -51,7 +51,6 @@ pr_debug("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) static DEFINE_MUTEX(regulator_list_mutex); static LIST_HEAD(regulator_list); static LIST_HEAD(regulator_map_list); static LIST_HEAD(regulator_ena_gpio_list); static LIST_HEAD(regulator_supply_alias_list); Loading @@ -59,6 +58,8 @@ static bool has_full_constraints; static struct dentry *debugfs_root; static struct class regulator_class; /* * struct regulator_map * Loading Loading @@ -1325,6 +1326,47 @@ static void regulator_supply_alias(struct device **dev, const char **supply) } } static int of_node_match(struct device *dev, const void *data) { return dev->of_node == data; } static struct regulator_dev *of_find_regulator_by_node(struct device_node *np) { struct device *dev; dev = class_find_device(®ulator_class, NULL, np, of_node_match); return dev ? dev_to_rdev(dev) : NULL; } static int regulator_match(struct device *dev, const void *data) { struct regulator_dev *r = dev_to_rdev(dev); return strcmp(rdev_get_name(r), data) == 0; } static struct regulator_dev *regulator_lookup_by_name(const char *name) { struct device *dev; dev = class_find_device(®ulator_class, NULL, name, regulator_match); return dev ? dev_to_rdev(dev) : NULL; } /** * regulator_dev_lookup - lookup a regulator device. * @dev: device for regulator "consumer". * @supply: Supply name or regulator ID. * @ret: 0 on success, -ENODEV if lookup fails permanently, -EPROBE_DEFER if * lookup could succeed in the future. * * If successful, returns a struct regulator_dev that corresponds to the name * @supply and with the embedded struct device refcount incremented by one, * or NULL on failure. The refcount must be dropped by calling put_device(). */ static struct regulator_dev *regulator_dev_lookup(struct device *dev, const char *supply, int *ret) Loading @@ -1340,9 +1382,8 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev, if (dev && dev->of_node) { node = of_get_regulator(dev, supply); if (node) { list_for_each_entry(r, ®ulator_list, list) if (r->dev.parent && node == r->dev.of_node) r = of_find_regulator_by_node(node); if (r) return r; *ret = -EPROBE_DEFER; return NULL; Loading @@ -1361,20 +1402,24 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev, if (dev) devname = dev_name(dev); list_for_each_entry(r, ®ulator_list, list) if (strcmp(rdev_get_name(r), supply) == 0) r = regulator_lookup_by_name(supply); if (r) return r; mutex_lock(®ulator_list_mutex); list_for_each_entry(map, ®ulator_map_list, list) { /* If the mapping has a device set up it must match */ if (map->dev_name && (!devname || strcmp(map->dev_name, devname))) continue; if (strcmp(map->supply, supply) == 0) if (strcmp(map->supply, supply) == 0 && get_device(&map->regulator->dev)) { mutex_unlock(®ulator_list_mutex); return map->regulator; } } mutex_unlock(®ulator_list_mutex); return NULL; } Loading Loading @@ -1409,6 +1454,7 @@ static int regulator_resolve_supply(struct regulator_dev *rdev) if (have_full_constraints()) { r = dummy_regulator_rdev; get_device(&r->dev); } else { dev_err(dev, "Failed to resolve %s-supply for %s\n", rdev->supply_name, rdev->desc->name); Loading @@ -1418,12 +1464,16 @@ static int regulator_resolve_supply(struct regulator_dev *rdev) /* Recursively resolve the supply of the supply */ ret = regulator_resolve_supply(r); if (ret < 0) if (ret < 0) { put_device(&r->dev); return ret; } ret = set_supply(rdev, r); if (ret < 0) if (ret < 0) { put_device(&r->dev); return ret; } /* Cascade always-on state to supply */ if (_regulator_is_enabled(rdev) && rdev->supply) { Loading Loading @@ -1459,8 +1509,6 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, else ret = -EPROBE_DEFER; mutex_lock(®ulator_list_mutex); rdev = regulator_dev_lookup(dev, id, &ret); if (rdev) goto found; Loading @@ -1472,7 +1520,7 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, * succeed, so, quit with appropriate error value */ if (ret && ret != -ENODEV) goto out; return regulator; if (!devname) devname = "deviceless"; Loading @@ -1486,40 +1534,46 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, devname, id); rdev = dummy_regulator_rdev; get_device(&rdev->dev); goto found; /* Don't log an error when called from regulator_get_optional() */ } else if (!have_full_constraints() || exclusive) { dev_warn(dev, "dummy supplies not allowed\n"); } mutex_unlock(®ulator_list_mutex); return regulator; found: if (rdev->exclusive) { regulator = ERR_PTR(-EPERM); goto out; put_device(&rdev->dev); return regulator; } if (exclusive && rdev->open_count) { regulator = ERR_PTR(-EBUSY); goto out; put_device(&rdev->dev); return regulator; } ret = regulator_resolve_supply(rdev); if (ret < 0) { regulator = ERR_PTR(ret); goto out; put_device(&rdev->dev); return regulator; } if (!try_module_get(rdev->owner)) goto out; if (!try_module_get(rdev->owner)) { put_device(&rdev->dev); return regulator; } regulator = create_regulator(rdev, dev, id); if (regulator == NULL) { regulator = ERR_PTR(-ENOMEM); put_device(&rdev->dev); module_put(rdev->owner); goto out; return regulator; } rdev->open_count++; Loading @@ -1533,9 +1587,6 @@ found: rdev->use_count = 0; } out: mutex_unlock(®ulator_list_mutex); return regulator; } Loading Loading @@ -1633,6 +1684,7 @@ static void _regulator_put(struct regulator *regulator) rdev->open_count--; rdev->exclusive = 0; put_device(&rdev->dev); mutex_unlock(&rdev->mutex); kfree(regulator->supply_name); Loading Loading @@ -3810,8 +3862,6 @@ regulator_register(const struct regulator_desc *regulator_desc, } } list_add(&rdev->list, ®ulator_list); rdev_init_debugfs(rdev); out: mutex_unlock(®ulator_list_mutex); Loading Loading @@ -3865,6 +3915,19 @@ void regulator_unregister(struct regulator_dev *rdev) } EXPORT_SYMBOL_GPL(regulator_unregister); static int _regulator_suspend_prepare(struct device *dev, void *data) { struct regulator_dev *rdev = dev_to_rdev(dev); const suspend_state_t *state = data; int ret; mutex_lock(&rdev->mutex); ret = suspend_prepare(rdev, *state); mutex_unlock(&rdev->mutex); return ret; } /** * regulator_suspend_prepare - prepare regulators for system wide suspend * @state: system suspend state Loading @@ -3874,50 +3937,28 @@ EXPORT_SYMBOL_GPL(regulator_unregister); */ int regulator_suspend_prepare(suspend_state_t state) { struct regulator_dev *rdev; int ret = 0; /* ON is handled by regulator active state */ if (state == PM_SUSPEND_ON) return -EINVAL; mutex_lock(®ulator_list_mutex); list_for_each_entry(rdev, ®ulator_list, list) { mutex_lock(&rdev->mutex); ret = suspend_prepare(rdev, state); mutex_unlock(&rdev->mutex); if (ret < 0) { rdev_err(rdev, "failed to prepare\n"); goto out; } } out: mutex_unlock(®ulator_list_mutex); return ret; return class_for_each_device(®ulator_class, NULL, &state, _regulator_suspend_prepare); } EXPORT_SYMBOL_GPL(regulator_suspend_prepare); /** * regulator_suspend_finish - resume regulators from system wide suspend * * Turn on regulators that might be turned off by regulator_suspend_prepare * and that should be turned on according to the regulators properties. */ int regulator_suspend_finish(void) static int _regulator_suspend_finish(struct device *dev, void *data) { struct regulator_dev *rdev; int ret = 0, error; struct regulator_dev *rdev = dev_to_rdev(dev); int ret; mutex_lock(®ulator_list_mutex); list_for_each_entry(rdev, ®ulator_list, list) { mutex_lock(&rdev->mutex); if (rdev->use_count > 0 || rdev->constraints->always_on) { if (!_regulator_is_enabled(rdev)) { error = _regulator_do_enable(rdev); if (error) ret = error; ret = _regulator_do_enable(rdev); if (ret) dev_err(dev, "Failed to resume regulator %d\n", ret); } } else { if (!have_full_constraints()) Loading @@ -3925,15 +3966,27 @@ int regulator_suspend_finish(void) if (!_regulator_is_enabled(rdev)) goto unlock; error = _regulator_do_disable(rdev); if (error) ret = error; ret = _regulator_do_disable(rdev); if (ret) dev_err(dev, "Failed to suspend regulator %d\n", ret); } unlock: mutex_unlock(&rdev->mutex); /* Keep processing regulators in spite of any errors */ return 0; } mutex_unlock(®ulator_list_mutex); return ret; /** * regulator_suspend_finish - resume regulators from system wide suspend * * Turn on regulators that might be turned off by regulator_suspend_prepare * and that should be turned on according to the regulators properties. */ int regulator_suspend_finish(void) { return class_for_each_device(®ulator_class, NULL, NULL, _regulator_suspend_finish); } EXPORT_SYMBOL_GPL(regulator_suspend_finish); Loading Loading @@ -4053,14 +4106,35 @@ static const struct file_operations supply_map_fops = { }; #ifdef CONFIG_DEBUG_FS struct summary_data { struct seq_file *s; struct regulator_dev *parent; int level; }; static void regulator_summary_show_subtree(struct seq_file *s, struct regulator_dev *rdev, int level); static int regulator_summary_show_children(struct device *dev, void *data) { struct regulator_dev *rdev = dev_to_rdev(dev); struct summary_data *summary_data = data; if (rdev->supply && rdev->supply->rdev == summary_data->parent) regulator_summary_show_subtree(summary_data->s, rdev, summary_data->level + 1); return 0; } static void regulator_summary_show_subtree(struct seq_file *s, struct regulator_dev *rdev, int level) { struct list_head *list = s->private; struct regulator_dev *child; struct regulation_constraints *c; struct regulator *consumer; struct summary_data summary_data; if (!rdev) return; Loading Loading @@ -4110,33 +4184,32 @@ static void regulator_summary_show_subtree(struct seq_file *s, seq_puts(s, "\n"); } list_for_each_entry(child, list, list) { /* handle only non-root regulators supplied by current rdev */ if (!child->supply || child->supply->rdev != rdev) continue; summary_data.s = s; summary_data.level = level; summary_data.parent = rdev; regulator_summary_show_subtree(s, child, level + 1); class_for_each_device(®ulator_class, NULL, &summary_data, regulator_summary_show_children); } static int regulator_summary_show_roots(struct device *dev, void *data) { struct regulator_dev *rdev = dev_to_rdev(dev); struct seq_file *s = data; if (!rdev->supply) regulator_summary_show_subtree(s, rdev, 0); return 0; } static int regulator_summary_show(struct seq_file *s, void *data) { struct list_head *list = s->private; struct regulator_dev *rdev; seq_puts(s, " regulator use open bypass voltage current min max\n"); seq_puts(s, "-------------------------------------------------------------------------------\n"); mutex_lock(®ulator_list_mutex); list_for_each_entry(rdev, list, list) { if (rdev->supply) continue; regulator_summary_show_subtree(s, rdev, 0); } mutex_unlock(®ulator_list_mutex); class_for_each_device(®ulator_class, NULL, s, regulator_summary_show_roots); return 0; } Loading Loading @@ -4170,7 +4243,7 @@ static int __init regulator_init(void) &supply_map_fops); debugfs_create_file("regulator_summary", 0444, debugfs_root, ®ulator_list, ®ulator_summary_fops); NULL, ®ulator_summary_fops); regulator_dummy_init(); Loading