// SPDX-License-Identifier: GPL-2.0-only/* * Copyright (C) 2024 Linaro Ltd. */ #include <linux/bug.h>#include <linux/cleanup.h>#include <linux/debugfs.h>#include <linux/device.h>#include <linux/err.h>#include <linux/export.h>#include <linux/idr.h>#include <linux/kernel.h>#include <linux/kref.h>#include <linux/list.h>#include <linux/lockdep.h>#include <linux/module.h>#include <linux/mutex.h>#include <linux/property.h>#include <linux/pwrseq/consumer.h>#include <linux/pwrseq/provider.h>#include <linux/radix-tree.h>#include <linux/rwsem.h>#include <linux/slab.h> /* * Power-sequencing framework for linux. * * This subsystem allows power sequence providers to register a set of targets * that consumers may request and power-up/down. * * Glossary: * * Unit - a unit is a discreet chunk of a power sequence. For instance one unit * may enable a set of regulators, another may enable a specific GPIO. Units * can define dependencies in the form of other units that must be enabled * before it itself can be. * * Target - a target is a set of units (composed of the "final" unit and its * dependencies) that a consumer selects by its name when requesting a handle * to the power sequencer. Via the dependency system, multiple targets may * share the same parts of a power sequence but ignore parts that are * irrelevant. * * Descriptor - a handle passed by the pwrseq core to every consumer that * serves as the entry point to the provider layer. It ensures coherence * between different users and keeps reference counting consistent. * * Each provider must define a .match() callback whose role is to determine * whether a potential consumer is in fact associated with this sequencer. * This allows creating abstraction layers on top of regular device-tree * resources like regulators, clocks and other nodes connected to the consumer * via phandle. */ static DEFINE_IDA(pwrseq_ida); /* * Protects the device list on the pwrseq bus from concurrent modifications * but allows simultaneous read-only access. */static DECLARE_RWSEM(pwrseq_sem); /** * struct pwrseq_unit - Private power-sequence unit data. * @ref: Reference count for this object. When it goes to 0, the object is * destroyed. * @name: Name of this target. * @list: Link to siblings on the list of all units of a single sequencer. * @deps: List of units on which this unit depends. * @enable: Callback running the part of the power-on sequence provided by * this unit. * @disable: Callback running the part of the power-off sequence provided * by this unit. * @enable_count: Current number of users that enabled this unit. May be the * consumer of the power sequencer or other units that depend * on this one. */struct pwrseq_unit { struct kref ref; const char *name; struct list_head list; struct list_head deps; pwrseq_power_state_func enable; pwrseq_power_state_func disable; unsigned int enable_count;}; static struct pwrseq_unit *pwrseq_unit_new(const struct pwrseq_unit_data *data){ struct pwrseq_unit *unit; unit = kzalloc_obj(*unit); if (!unit) return NULL; unit->name = kstrdup_const(data->name, GFP_KERNEL); if (!unit->name) { kfree(unit); return NULL; } kref_init(&unit->ref); INIT_LIST_HEAD(&unit->deps); unit->enable = data->enable; unit->disable = data->disable; return unit;} static struct pwrseq_unit *pwrseq_unit_get(struct pwrseq_unit *unit){ kref_get(&unit->ref); return unit;} static void pwrseq_unit_release(struct kref *ref); static void pwrseq_unit_put(struct pwrseq_unit *unit){ kref_put(&unit->ref, pwrseq_unit_release);} /** * struct pwrseq_unit_dep - Wrapper around a reference to the unit structure * allowing to keep it on multiple dependency lists * in different units. * @list: Siblings on the list. * @unit: Address of the referenced unit. */struct pwrseq_unit_dep { struct list_head list; struct pwrseq_unit *unit;}; static struct pwrseq_unit_dep *pwrseq_unit_dep_new(struct pwrseq_unit *unit){ struct pwrseq_unit_dep *dep; dep = kzalloc_obj(*dep); if (!dep) return NULL; dep->unit = unit; return dep;} static void pwrseq_unit_dep_free(struct pwrseq_unit_dep *ref){ pwrseq_unit_put(ref->unit); kfree(ref);} static void pwrseq_unit_free_deps(struct list_head *list){ struct pwrseq_unit_dep *dep, *next; list_for_each_entry_safe(dep, next, list, list) { list_del(&dep->list); pwrseq_unit_dep_free(dep); }} static void pwrseq_unit_release(struct kref *ref){ struct pwrseq_unit *unit = container_of(ref, struct pwrseq_unit, ref); pwrseq_unit_free_deps(&unit->deps); list_del(&unit->list); kfree_const(unit->name); kfree(unit);} /** * struct pwrseq_target - Private power-sequence target data. * @list: Siblings on the list of all targets exposed by a power sequencer. * @name: Name of the target. * @unit: Final unit for this target. * @post_enable: Callback run after the target unit has been enabled, *after* * the state lock has been released. It's useful for implementing * boot-up delays without blocking other users from powering up * using the same power sequencer. */struct pwrseq_target { struct list_head list; const char *name; struct pwrseq_unit *unit; pwrseq_power_state_func post_enable;}; static struct pwrseq_target *pwrseq_target_new(const struct pwrseq_target_data *data){ struct pwrseq_target *target; target = kzalloc_obj(*target); if (!target) return NULL; target->name = kstrdup_const(data->name, GFP_KERNEL); if (!target->name) { kfree(target); return NULL; } target->post_enable = data->post_enable; return target;} static void pwrseq_target_free(struct pwrseq_target *target){ if (!IS_ERR_OR_NULL(target->unit)) pwrseq_unit_put(target->unit); kfree_const(target->name); kfree(target);} /** * struct pwrseq_device - Private power sequencing data. * @dev: Device struct associated with this sequencer. * @id: Device ID. * @owner: Prevents removal of active power sequencing providers. * @rw_lock: Protects the device from being unregistered while in use. * @state_lock: Prevents multiple users running the power sequence at the same * time. * @match: Power sequencer matching callback. * @targets: List of targets exposed by this sequencer. * @units: List of all units supported by this sequencer. */struct pwrseq_device { struct device dev; int id; struct module *owner; struct rw_semaphore rw_lock; struct mutex state_lock; pwrseq_match_func match; struct list_head targets; struct list_head units;}; static struct pwrseq_device *to_pwrseq_device(struct device *dev){ return container_of(dev, struct pwrseq_device, dev);} static struct pwrseq_device *pwrseq_device_get(struct pwrseq_device *pwrseq){ get_device(&pwrseq->dev); return pwrseq;} static void pwrseq_device_put(struct pwrseq_device *pwrseq){ put_device(&pwrseq->dev);} /** * struct pwrseq_desc - Wraps access to the pwrseq_device and ensures that one * user cannot break the reference counting for others. * @pwrseq: Reference to the power sequencing device. * @target: Reference to the target this descriptor allows to control. * @powered_on: Power state set by the holder of the descriptor (not necessarily * corresponding to the actual power state of the device). */struct pwrseq_desc { struct pwrseq_device *pwrseq; struct pwrseq_target *target; bool powered_on;}; static const struct bus_type pwrseq_bus = { .name = "pwrseq",}; static void pwrseq_release(struct device *dev){ struct pwrseq_device *pwrseq = to_pwrseq_device(dev); struct pwrseq_target *target, *pos; list_for_each_entry_safe(target, pos, &pwrseq->targets, list) { list_del(&target->list); pwrseq_target_free(target); } mutex_destroy(&pwrseq->state_lock); ida_free(&pwrseq_ida, pwrseq->id); kfree(pwrseq);} static const struct device_type pwrseq_device_type = { .name = "power_sequencer", .release = pwrseq_release,}; static int pwrseq_check_unit_deps(const struct pwrseq_unit_data *data, struct radix_tree_root *visited_units){ const struct pwrseq_unit_data *tmp, **cur; int ret; ret = radix_tree_insert(visited_units, (unsigned long)data, (void *)data); if (ret) return ret; for (cur = data->deps; cur && *cur; cur++) { tmp = radix_tree_lookup(visited_units, (unsigned long)*cur); if (tmp) { WARN(1, "Circular dependency in power sequencing flow detected!\n"); return -EINVAL; } ret = pwrseq_check_unit_deps(*cur, visited_units); if (ret) return ret; } return 0;} static int pwrseq_check_target_deps(const struct pwrseq_target_data *data){ struct radix_tree_root visited_units; struct radix_tree_iter iter; void __rcu **slot; int ret; if (!data->unit) return -EINVAL; INIT_RADIX_TREE(&visited_units, GFP_KERNEL); ret = pwrseq_check_unit_deps(data->unit, &visited_units); radix_tree_for_each_slot(slot, &visited_units, &iter, 0) radix_tree_delete(&visited_units, iter.index); return ret;} static int pwrseq_unit_setup_deps(const struct pwrseq_unit_data **data, struct list_head *dep_list, struct list_head *unit_list, struct radix_tree_root *processed_units); static struct pwrseq_unit *pwrseq_unit_setup(const struct pwrseq_unit_data *data, struct list_head *unit_list, struct radix_tree_root *processed_units){ struct pwrseq_unit *unit; int ret; unit = radix_tree_lookup(processed_units, (unsigned long)data); if (unit) return pwrseq_unit_get(unit); unit = pwrseq_unit_new(data); if (!unit) return ERR_PTR(-ENOMEM); if (data->deps) { ret = pwrseq_unit_setup_deps(data->deps, &unit->deps, unit_list, processed_units); if (ret) { pwrseq_unit_put(unit); return ERR_PTR(ret); } } ret = radix_tree_insert(processed_units, (unsigned long)data, unit); if (ret) { pwrseq_unit_put(unit); return ERR_PTR(ret); } list_add_tail(&unit->list, unit_list); return unit;} static int pwrseq_unit_setup_deps(const struct pwrseq_unit_data **data, struct list_head *dep_list, struct list_head *unit_list, struct radix_tree_root *processed_units){ const struct pwrseq_unit_data *pos; struct pwrseq_unit_dep *dep; struct pwrseq_unit *unit; int i; for (i = 0; data[i]; i++) { pos = data[i]; unit = pwrseq_unit_setup(pos, unit_list, processed_units); if (IS_ERR(unit)) return PTR_ERR(unit); dep = pwrseq_unit_dep_new(unit); if (!dep) { pwrseq_unit_put(unit); return -ENOMEM; } list_add_tail(&dep->list, dep_list); } return 0;} static int pwrseq_do_setup_targets(const struct pwrseq_target_data **data, struct pwrseq_device *pwrseq, struct radix_tree_root *processed_units){ const struct pwrseq_target_data *pos; struct pwrseq_target *target; int ret, i; for (i = 0; data[i]; i++) { pos = data[i]; ret = pwrseq_check_target_deps(pos); if (ret) return ret; target = pwrseq_target_new(pos); if (!target) return -ENOMEM; target->unit = pwrseq_unit_setup(pos->unit, &pwrseq->units, processed_units); if (IS_ERR(target->unit)) { ret = PTR_ERR(target->unit); pwrseq_target_free(target); return ret; } list_add_tail(&target->list, &pwrseq->targets); } return 0;} static int pwrseq_setup_targets(const struct pwrseq_target_data **targets, struct pwrseq_device *pwrseq){ struct radix_tree_root processed_units; struct radix_tree_iter iter; void __rcu **slot; int ret; INIT_RADIX_TREE(&processed_units, GFP_KERNEL); ret = pwrseq_do_setup_targets(targets, pwrseq, &processed_units); radix_tree_for_each_slot(slot, &processed_units, &iter, 0) radix_tree_delete(&processed_units, iter.index); return ret;} /** * pwrseq_device_register() - Register a new power sequencer. * @config: Configuration of the new power sequencing device. * * The config structure is only used during the call and can be freed after * the function returns. The config structure *must* have the parent device * as well as the match() callback and at least one target set. * * Returns: * Returns the address of the new pwrseq device or ERR_PTR() on failure. */struct pwrseq_device *pwrseq_device_register(const struct pwrseq_config *config){ struct pwrseq_device *pwrseq; int ret, id; if (!config->parent || !config->match || !config->targets || !config->targets[0]) return ERR_PTR(-EINVAL); pwrseq = kzalloc_obj(*pwrseq); if (!pwrseq) return ERR_PTR(-ENOMEM); pwrseq->dev.type = &pwrseq_device_type; pwrseq->dev.bus = &pwrseq_bus; pwrseq->dev.parent = config->parent; device_set_node(&pwrseq->dev, dev_fwnode(config->parent)); dev_set_drvdata(&pwrseq->dev, config->drvdata); id = ida_alloc(&pwrseq_ida, GFP_KERNEL); if (id < 0) { kfree(pwrseq); return ERR_PTR(id); } pwrseq->id = id; Lines 1–500 of 1137. Load more
// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2024 Linaro Ltd. */ #include <linux/bug.h> #include <linux/cleanup.h> #include <linux/debugfs.h> #include <linux/device.h> #include <linux/err.h> #include <linux/export.h> #include <linux/idr.h> #include <linux/kernel.h> #include <linux/kref.h> #include <linux/list.h> #include <linux/lockdep.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/property.h> #include <linux/pwrseq/consumer.h> #include <linux/pwrseq/provider.h> #include <linux/radix-tree.h> #include <linux/rwsem.h> #include <linux/slab.h> /* * Power-sequencing framework for linux. * * This subsystem allows power sequence providers to register a set of targets * that consumers may request and power-up/down. * * Glossary: * * Unit - a unit is a discreet chunk of a power sequence. For instance one unit * may enable a set of regulators, another may enable a specific GPIO. Units * can define dependencies in the form of other units that must be enabled * before it itself can be. * * Target - a target is a set of units (composed of the "final" unit and its * dependencies) that a consumer selects by its name when requesting a handle * to the power sequencer. Via the dependency system, multiple targets may * share the same parts of a power sequence but ignore parts that are * irrelevant. * * Descriptor - a handle passed by the pwrseq core to every consumer that * serves as the entry point to the provider layer. It ensures coherence * between different users and keeps reference counting consistent. * * Each provider must define a .match() callback whose role is to determine * whether a potential consumer is in fact associated with this sequencer. * This allows creating abstraction layers on top of regular device-tree * resources like regulators, clocks and other nodes connected to the consumer * via phandle. */ static DEFINE_IDA(pwrseq_ida); /* * Protects the device list on the pwrseq bus from concurrent modifications * but allows simultaneous read-only access. */ static DECLARE_RWSEM(pwrseq_sem); /** * struct pwrseq_unit - Private power-sequence unit data. * @ref: Reference count for this object. When it goes to 0, the object is * destroyed. * @name: Name of this target. * @list: Link to siblings on the list of all units of a single sequencer. * @deps: List of units on which this unit depends. * @enable: Callback running the part of the power-on sequence provided by * this unit. * @disable: Callback running the part of the power-off sequence provided * by this unit. * @enable_count: Current number of users that enabled this unit. May be the * consumer of the power sequencer or other units that depend * on this one. */ struct pwrseq_unit { struct kref ref; const char *name; struct list_head list; struct list_head deps; pwrseq_power_state_func enable; pwrseq_power_state_func disable; unsigned int enable_count; }; static struct pwrseq_unit *pwrseq_unit_new(const struct pwrseq_unit_data *data) { struct pwrseq_unit *unit; unit = kzalloc_obj(*unit); if (!unit) return NULL; unit->name = kstrdup_const(data->name, GFP_KERNEL); if (!unit->name) { kfree(unit); return NULL; } kref_init(&unit->ref); INIT_LIST_HEAD(&unit->deps); unit->enable = data->enable; unit->disable = data->disable; return unit; } static struct pwrseq_unit *pwrseq_unit_get(struct pwrseq_unit *unit) { kref_get(&unit->ref); return unit; } static void pwrseq_unit_release(struct kref *ref); static void pwrseq_unit_put(struct pwrseq_unit *unit) { kref_put(&unit->ref, pwrseq_unit_release); } /** * struct pwrseq_unit_dep - Wrapper around a reference to the unit structure * allowing to keep it on multiple dependency lists * in different units. * @list: Siblings on the list. * @unit: Address of the referenced unit. */ struct pwrseq_unit_dep { struct list_head list; struct pwrseq_unit *unit; }; static struct pwrseq_unit_dep *pwrseq_unit_dep_new(struct pwrseq_unit *unit) { struct pwrseq_unit_dep *dep; dep = kzalloc_obj(*dep); if (!dep) return NULL; dep->unit = unit; return dep; } static void pwrseq_unit_dep_free(struct pwrseq_unit_dep *ref) { pwrseq_unit_put(ref->unit); kfree(ref); } static void pwrseq_unit_free_deps(struct list_head *list) { struct pwrseq_unit_dep *dep, *next; list_for_each_entry_safe(dep, next, list, list) { list_del(&dep->list); pwrseq_unit_dep_free(dep); } } static void pwrseq_unit_release(struct kref *ref) { struct pwrseq_unit *unit = container_of(ref, struct pwrseq_unit, ref); pwrseq_unit_free_deps(&unit->deps); list_del(&unit->list); kfree_const(unit->name); kfree(unit); } /** * struct pwrseq_target - Private power-sequence target data. * @list: Siblings on the list of all targets exposed by a power sequencer. * @name: Name of the target. * @unit: Final unit for this target. * @post_enable: Callback run after the target unit has been enabled, *after* * the state lock has been released. It's useful for implementing * boot-up delays without blocking other users from powering up * using the same power sequencer. */ struct pwrseq_target { struct list_head list; const char *name; struct pwrseq_unit *unit; pwrseq_power_state_func post_enable; }; static struct pwrseq_target * pwrseq_target_new(const struct pwrseq_target_data *data) { struct pwrseq_target *target; target = kzalloc_obj(*target); if (!target) return NULL; target->name = kstrdup_const(data->name, GFP_KERNEL); if (!target->name) { kfree(target); return NULL; } target->post_enable = data->post_enable; return target; } static void pwrseq_target_free(struct pwrseq_target *target) { if (!IS_ERR_OR_NULL(target->unit)) pwrseq_unit_put(target->unit); kfree_const(target->name); kfree(target); } /** * struct pwrseq_device - Private power sequencing data. * @dev: Device struct associated with this sequencer. * @id: Device ID. * @owner: Prevents removal of active power sequencing providers. * @rw_lock: Protects the device from being unregistered while in use. * @state_lock: Prevents multiple users running the power sequence at the same * time. * @match: Power sequencer matching callback. * @targets: List of targets exposed by this sequencer. * @units: List of all units supported by this sequencer. */ struct pwrseq_device { struct device dev; int id; struct module *owner; struct rw_semaphore rw_lock; struct mutex state_lock; pwrseq_match_func match; struct list_head targets; struct list_head units; }; static struct pwrseq_device *to_pwrseq_device(struct device *dev) { return container_of(dev, struct pwrseq_device, dev); } static struct pwrseq_device *pwrseq_device_get(struct pwrseq_device *pwrseq) { get_device(&pwrseq->dev); return pwrseq; } static void pwrseq_device_put(struct pwrseq_device *pwrseq) { put_device(&pwrseq->dev); } /** * struct pwrseq_desc - Wraps access to the pwrseq_device and ensures that one * user cannot break the reference counting for others. * @pwrseq: Reference to the power sequencing device. * @target: Reference to the target this descriptor allows to control. * @powered_on: Power state set by the holder of the descriptor (not necessarily * corresponding to the actual power state of the device). */ struct pwrseq_desc { struct pwrseq_device *pwrseq; struct pwrseq_target *target; bool powered_on; }; static const struct bus_type pwrseq_bus = { .name = "pwrseq", }; static void pwrseq_release(struct device *dev) { struct pwrseq_device *pwrseq = to_pwrseq_device(dev); struct pwrseq_target *target, *pos; list_for_each_entry_safe(target, pos, &pwrseq->targets, list) { list_del(&target->list); pwrseq_target_free(target); } mutex_destroy(&pwrseq->state_lock); ida_free(&pwrseq_ida, pwrseq->id); kfree(pwrseq); } static const struct device_type pwrseq_device_type = { .name = "power_sequencer", .release = pwrseq_release, }; static int pwrseq_check_unit_deps(const struct pwrseq_unit_data *data, struct radix_tree_root *visited_units) { const struct pwrseq_unit_data *tmp, **cur; int ret; ret = radix_tree_insert(visited_units, (unsigned long)data, (void *)data); if (ret) return ret; for (cur = data->deps; cur && *cur; cur++) { tmp = radix_tree_lookup(visited_units, (unsigned long)*cur); if (tmp) { WARN(1, "Circular dependency in power sequencing flow detected!\n"); return -EINVAL; } ret = pwrseq_check_unit_deps(*cur, visited_units); if (ret) return ret; } return 0; } static int pwrseq_check_target_deps(const struct pwrseq_target_data *data) { struct radix_tree_root visited_units; struct radix_tree_iter iter; void __rcu **slot; int ret; if (!data->unit) return -EINVAL; INIT_RADIX_TREE(&visited_units, GFP_KERNEL); ret = pwrseq_check_unit_deps(data->unit, &visited_units); radix_tree_for_each_slot(slot, &visited_units, &iter, 0) radix_tree_delete(&visited_units, iter.index); return ret; } static int pwrseq_unit_setup_deps(const struct pwrseq_unit_data **data, struct list_head *dep_list, struct list_head *unit_list, struct radix_tree_root *processed_units); static struct pwrseq_unit * pwrseq_unit_setup(const struct pwrseq_unit_data *data, struct list_head *unit_list, struct radix_tree_root *processed_units) { struct pwrseq_unit *unit; int ret; unit = radix_tree_lookup(processed_units, (unsigned long)data); if (unit) return pwrseq_unit_get(unit); unit = pwrseq_unit_new(data); if (!unit) return ERR_PTR(-ENOMEM); if (data->deps) { ret = pwrseq_unit_setup_deps(data->deps, &unit->deps, unit_list, processed_units); if (ret) { pwrseq_unit_put(unit); return ERR_PTR(ret); } } ret = radix_tree_insert(processed_units, (unsigned long)data, unit); if (ret) { pwrseq_unit_put(unit); return ERR_PTR(ret); } list_add_tail(&unit->list, unit_list); return unit; } static int pwrseq_unit_setup_deps(const struct pwrseq_unit_data **data, struct list_head *dep_list, struct list_head *unit_list, struct radix_tree_root *processed_units) { const struct pwrseq_unit_data *pos; struct pwrseq_unit_dep *dep; struct pwrseq_unit *unit; int i; for (i = 0; data[i]; i++) { pos = data[i]; unit = pwrseq_unit_setup(pos, unit_list, processed_units); if (IS_ERR(unit)) return PTR_ERR(unit); dep = pwrseq_unit_dep_new(unit); if (!dep) { pwrseq_unit_put(unit); return -ENOMEM; } list_add_tail(&dep->list, dep_list); } return 0; } static int pwrseq_do_setup_targets(const struct pwrseq_target_data **data, struct pwrseq_device *pwrseq, struct radix_tree_root *processed_units) { const struct pwrseq_target_data *pos; struct pwrseq_target *target; int ret, i; for (i = 0; data[i]; i++) { pos = data[i]; ret = pwrseq_check_target_deps(pos); if (ret) return ret; target = pwrseq_target_new(pos); if (!target) return -ENOMEM; target->unit = pwrseq_unit_setup(pos->unit, &pwrseq->units, processed_units); if (IS_ERR(target->unit)) { ret = PTR_ERR(target->unit); pwrseq_target_free(target); return ret; } list_add_tail(&target->list, &pwrseq->targets); } return 0; } static int pwrseq_setup_targets(const struct pwrseq_target_data **targets, struct pwrseq_device *pwrseq) { struct radix_tree_root processed_units; struct radix_tree_iter iter; void __rcu **slot; int ret; INIT_RADIX_TREE(&processed_units, GFP_KERNEL); ret = pwrseq_do_setup_targets(targets, pwrseq, &processed_units); radix_tree_for_each_slot(slot, &processed_units, &iter, 0) radix_tree_delete(&processed_units, iter.index); return ret; } /** * pwrseq_device_register() - Register a new power sequencer. * @config: Configuration of the new power sequencing device. * * The config structure is only used during the call and can be freed after * the function returns. The config structure *must* have the parent device * as well as the match() callback and at least one target set. * * Returns: * Returns the address of the new pwrseq device or ERR_PTR() on failure. */ struct pwrseq_device * pwrseq_device_register(const struct pwrseq_config *config) { struct pwrseq_device *pwrseq; int ret, id; if (!config->parent || !config->match || !config->targets || !config->targets[0]) return ERR_PTR(-EINVAL); pwrseq = kzalloc_obj(*pwrseq); if (!pwrseq) return ERR_PTR(-ENOMEM); pwrseq->dev.type = &pwrseq_device_type; pwrseq->dev.bus = &pwrseq_bus; pwrseq->dev.parent = config->parent; device_set_node(&pwrseq->dev, dev_fwnode(config->parent)); dev_set_drvdata(&pwrseq->dev, config->drvdata); id = ida_alloc(&pwrseq_ida, GFP_KERNEL); if (id < 0) { kfree(pwrseq); return ERR_PTR(id); } pwrseq->id = id;