// 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 { … }; static struct pwrseq_unit *pwrseq_unit_new(const struct pwrseq_unit_data *data) { … } static struct pwrseq_unit *pwrseq_unit_get(struct pwrseq_unit *unit) { … } static void pwrseq_unit_release(struct kref *ref); static void pwrseq_unit_put(struct pwrseq_unit *unit) { … } /** * 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 { … }; static struct pwrseq_unit_dep *pwrseq_unit_dep_new(struct pwrseq_unit *unit) { … } static void pwrseq_unit_dep_free(struct pwrseq_unit_dep *ref) { … } static void pwrseq_unit_free_deps(struct list_head *list) { … } static void pwrseq_unit_release(struct kref *ref) { … } /** * 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 { … }; static struct pwrseq_target * pwrseq_target_new(const struct pwrseq_target_data *data) { … } static void pwrseq_target_free(struct pwrseq_target *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 { … }; static struct pwrseq_device *to_pwrseq_device(struct device *dev) { … } static struct pwrseq_device *pwrseq_device_get(struct pwrseq_device *pwrseq) { … } static void pwrseq_device_put(struct pwrseq_device *pwrseq) { … } /** * 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 { … }; static const struct bus_type pwrseq_bus = …; static void pwrseq_release(struct device *dev) { … } static const struct device_type pwrseq_device_type = …; static int pwrseq_check_unit_deps(const struct pwrseq_unit_data *data, struct radix_tree_root *visited_units) { … } static int pwrseq_check_target_deps(const struct pwrseq_target_data *data) { … } 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) { … } 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 int pwrseq_do_setup_targets(const struct pwrseq_target_data **data, struct pwrseq_device *pwrseq, struct radix_tree_root *processed_units) { … } static int pwrseq_setup_targets(const struct pwrseq_target_data **targets, struct pwrseq_device *pwrseq) { … } /** * 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) { … } EXPORT_SYMBOL_GPL(…); /** * pwrseq_device_unregister() - Unregister the power sequencer. * @pwrseq: Power sequencer to unregister. */ void pwrseq_device_unregister(struct pwrseq_device *pwrseq) { … } EXPORT_SYMBOL_GPL(…); static void devm_pwrseq_device_unregister(void *data) { … } /** * devm_pwrseq_device_register() - Managed variant of pwrseq_device_register(). * @dev: Managing device. * @config: Configuration of the new power sequencing device. * * Returns: * Returns the address of the new pwrseq device or ERR_PTR() on failure. */ struct pwrseq_device * devm_pwrseq_device_register(struct device *dev, const struct pwrseq_config *config) { … } EXPORT_SYMBOL_GPL(…); /** * pwrseq_device_get_drvdata() - Get the driver private data associated with * this sequencer. * @pwrseq: Power sequencer object. * * Returns: * Address of the private driver data. */ void *pwrseq_device_get_drvdata(struct pwrseq_device *pwrseq) { … } EXPORT_SYMBOL_GPL(…); struct pwrseq_match_data { … }; static int pwrseq_match_device(struct device *pwrseq_dev, void *data) { … } /** * pwrseq_get() - Get the power sequencer associated with this device. * @dev: Device for which to get the sequencer. * @target: Name of the target exposed by the sequencer this device wants to * reach. * * Returns: * New power sequencer descriptor for use by the consumer driver or ERR_PTR() * on failure. */ struct pwrseq_desc *pwrseq_get(struct device *dev, const char *target) { … } EXPORT_SYMBOL_GPL(…); /** * pwrseq_put() - Release the power sequencer descriptor. * @desc: Descriptor to release. */ void pwrseq_put(struct pwrseq_desc *desc) { … } EXPORT_SYMBOL_GPL(…); static void devm_pwrseq_put(void *data) { … } /** * devm_pwrseq_get() - Managed variant of pwrseq_get(). * @dev: Device for which to get the sequencer and which also manages its * lifetime. * @target: Name of the target exposed by the sequencer this device wants to * reach. * * Returns: * New power sequencer descriptor for use by the consumer driver or ERR_PTR() * on failure. */ struct pwrseq_desc *devm_pwrseq_get(struct device *dev, const char *target) { … } EXPORT_SYMBOL_GPL(…); static int pwrseq_unit_enable(struct pwrseq_device *pwrseq, struct pwrseq_unit *target); static int pwrseq_unit_disable(struct pwrseq_device *pwrseq, struct pwrseq_unit *target); static int pwrseq_unit_enable_deps(struct pwrseq_device *pwrseq, struct list_head *list) { … } static int pwrseq_unit_disable_deps(struct pwrseq_device *pwrseq, struct list_head *list) { … } static int pwrseq_unit_enable(struct pwrseq_device *pwrseq, struct pwrseq_unit *unit) { … } static int pwrseq_unit_disable(struct pwrseq_device *pwrseq, struct pwrseq_unit *unit) { … } /** * pwrseq_power_on() - Issue a power-on request on behalf of the consumer * device. * @desc: Descriptor referencing the power sequencer. * * This function tells the power sequencer that the consumer wants to be * powered-up. The sequencer may already have powered-up the device in which * case the function returns 0. If the power-up sequence is already in * progress, the function will block until it's done and return 0. If this is * the first request, the device will be powered up. * * Returns: * 0 on success, negative error number on failure. */ int pwrseq_power_on(struct pwrseq_desc *desc) { … } EXPORT_SYMBOL_GPL(…); /** * pwrseq_power_off() - Issue a power-off request on behalf of the consumer * device. * @desc: Descriptor referencing the power sequencer. * * This undoes the effects of pwrseq_power_on(). It issues a power-off request * on behalf of the consumer and when the last remaining user does so, the * power-down sequence will be started. If one is in progress, the function * will block until it's complete and then return. * * Returns: * 0 on success, negative error number on failure. */ int pwrseq_power_off(struct pwrseq_desc *desc) { … } EXPORT_SYMBOL_GPL(…); #if IS_ENABLED(CONFIG_DEBUG_FS) struct pwrseq_debugfs_count_ctx { … }; static int pwrseq_debugfs_seq_count(struct device *dev, void *data) { … } static void *pwrseq_debugfs_seq_start(struct seq_file *seq, loff_t *pos) { … } static void *pwrseq_debugfs_seq_next(struct seq_file *seq, void *data, loff_t *pos) { … } static void pwrseq_debugfs_seq_show_target(struct seq_file *seq, struct pwrseq_target *target) { … } static void pwrseq_debugfs_seq_show_unit(struct seq_file *seq, struct pwrseq_unit *unit) { … } static int pwrseq_debugfs_seq_show(struct seq_file *seq, void *data) { … } static void pwrseq_debugfs_seq_stop(struct seq_file *seq, void *data) { … } static const struct seq_operations pwrseq_debugfs_sops = …; DEFINE_SEQ_ATTRIBUTE(…); static struct dentry *pwrseq_debugfs_dentry; #endif /* CONFIG_DEBUG_FS */ static int __init pwrseq_init(void) { … } subsys_initcall(pwrseq_init); static void __exit pwrseq_exit(void) { … } module_exit(pwrseq_exit); MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …;