Power Sequencing API¶
- Author:
Bartosz Golaszewski
Introduction¶
This framework is designed to abstract complex power-up sequences that areshared between multiple logical devices in the Linux kernel.
The intention is to allow consumers to obtain a power sequencing handleexposed by the power sequence provider and delegate the actual requesting andcontrol of the underlying resources as well as to allow the provider tomitigate any potential conflicts between multiple users behind the scenes.
Glossary¶
The power sequencing API uses a number of terms specific to the subsystem:
Unit
A unit is a discrete chunk of a power sequence. For instance one unit mayenable a set of regulators, another may enable a specific GPIO. Units candefine dependencies in the form of other units that must be enabled beforeit itself can be.
Target
A target is a set of units (composed of the “final” unit and itsdependencies) that a consumer selects by its name when requesting a handleto the power sequencer. Via the dependency system, multiple targets mayshare the same parts of a power sequence but ignore parts that areirrelevant.
Descriptor
A handle passed by the pwrseq core to every consumer that serves as theentry point to the provider layer. It ensures coherence between differentusers and keeps reference counting consistent.
Consumer interface¶
The consumer API is aimed to be as simple as possible. The driver interested ingetting a descriptor from the power sequencer should callpwrseq_get() andspecify the name of the target it wants to reach in the sequence after callingpwrseq_power_up(). The descriptor can be released by callingpwrseq_put() andthe consumer can request the powering down of its target withpwrseq_power_off(). Note that there is no guarantee thatpwrseq_power_off()will have any effect as there may be multiple users of the underlying resourceswho may keep them active.
Provider interface¶
The provider API is admittedly not nearly as straightforward as the one forconsumers but it makes up for it in flexibility.
Each provider can logically split the power-up sequence into discrete chunks(units) and define their dependencies. They can then expose named targets thatconsumers may use as the final point in the sequence that they wish to reach.
To that end the providers fill out a set of configuration structures andregister with the pwrseq subsystem by callingpwrseq_device_register().
Dynamic consumer matching¶
The main difference between pwrseq and other Linux kernel providers is themechanism for dynamic matching of consumers and providers. Every power sequenceprovider driver must implement thematch() callback and pass it to the pwrseqcore when registering with the subsystems.
When a client requests a sequencer handle, the core will call this callback forevery registered provider and let it flexibly figure out whether the proposedclient device is indeed its consumer. For example: if the provider binds to thedevice-tree node representing a power management unit of a chipset and theconsumer driver controls one of its modules, the provider driver may parse therelevant regulator supply properties in device tree and see if they lead fromthe PMU to the consumer.
API reference¶
- structpwrseq_unit_data¶
Configuration of a single power sequencing unit.
Definition:
struct pwrseq_unit_data { const char *name; const struct pwrseq_unit_data **deps; pwrseq_power_state_func enable; pwrseq_power_state_func disable;};Members
nameName of the unit.
depsUnits that must be enabled before this one and disabled after itin the order they come in this array. Must be NULL-terminated.
enableCallback running the part of the power-on sequence provided bythis unit.
disableCallback running the part of the power-off sequence providedby this unit.
- structpwrseq_target_data¶
Configuration of a power sequencing target.
Definition:
struct pwrseq_target_data { const char *name; const struct pwrseq_unit_data *unit; pwrseq_power_state_func post_enable;};Members
nameName of the target.
unitFinal unit that this target must reach in order to be consideredenabled.
post_enableCallback run after the target unit has been enabled,afterthe state lock has been released. It’s useful for implementingboot-up delays without blocking other users from powering upusing the same power sequencer.
- structpwrseq_config¶
Configuration used for registering a new provider.
Definition:
struct pwrseq_config { struct device *parent; struct module *owner; void *drvdata; pwrseq_match_func match; const struct pwrseq_target_data **targets;};Members
parentParent device for the sequencer. Must be set.
ownerModule providing this device.
drvdataPrivate driver data.
matchProvider callback used to match the consumer device to the sequencer.
targetsArray of targets for this power sequencer. Must be NULL-terminated.
- structpwrseq_device*pwrseq_device_register(conststructpwrseq_config*config)¶
Register a new power sequencer.
Parameters
conststructpwrseq_config*configConfiguration of the new power sequencing device.
Description
The config structure is only used during the call and can be freed afterthe function returns. The config structuremust have the parent deviceas well as thematch() callback and at least one target set.
Return
Returns the address of the new pwrseq device orERR_PTR() on failure.
- voidpwrseq_device_unregister(structpwrseq_device*pwrseq)¶
Unregister the power sequencer.
Parameters
structpwrseq_device*pwrseqPower sequencer to unregister.
- structpwrseq_device*devm_pwrseq_device_register(structdevice*dev,conststructpwrseq_config*config)¶
Managed variant of
pwrseq_device_register().
Parameters
structdevice*devManaging device.
conststructpwrseq_config*configConfiguration of the new power sequencing device.
Return
Returns the address of the new pwrseq device orERR_PTR() on failure.
- void*pwrseq_device_get_drvdata(structpwrseq_device*pwrseq)¶
Get the driver private data associated with this sequencer.
Parameters
structpwrseq_device*pwrseqPower sequencer object.
Return
Address of the private driver data.
- structpwrseq_desc*pwrseq_get(structdevice*dev,constchar*target)¶
Get the power sequencer associated with this device.
Parameters
structdevice*devDevice for which to get the sequencer.
constchar*targetName of the target exposed by the sequencer this device wants toreach.
Return
New power sequencer descriptor for use by the consumer driver orERR_PTR()on failure.
- voidpwrseq_put(structpwrseq_desc*desc)¶
Release the power sequencer descriptor.
Parameters
structpwrseq_desc*descDescriptor to release.
- structpwrseq_desc*devm_pwrseq_get(structdevice*dev,constchar*target)¶
Managed variant of
pwrseq_get().
Parameters
structdevice*devDevice for which to get the sequencer and which also manages itslifetime.
constchar*targetName of the target exposed by the sequencer this device wants toreach.
Return
New power sequencer descriptor for use by the consumer driver orERR_PTR()on failure.
- intpwrseq_power_on(structpwrseq_desc*desc)¶
Issue a power-on request on behalf of the consumer device.
Parameters
structpwrseq_desc*descDescriptor referencing the power sequencer.
Description
This function tells the power sequencer that the consumer wants to bepowered-up. The sequencer may already have powered-up the device in whichcase the function returns 0. If the power-up sequence is already inprogress, the function will block until it’s done and return 0. If this isthe first request, the device will be powered up.
Return
0 on success, negative error number on failure.
- intpwrseq_power_off(structpwrseq_desc*desc)¶
Issue a power-off request on behalf of the consumer device.
Parameters
structpwrseq_desc*descDescriptor referencing the power sequencer.
Description
This undoes the effects ofpwrseq_power_on(). It issues a power-off requeston behalf of the consumer and when the last remaining user does so, thepower-down sequence will be started. If one is in progress, the functionwill block until it’s complete and then return.
Return
0 on success, negative error number on failure.