A regulator is an electronic device that supplies power to other devices. Devices powered by regulators are called consumers. They consume power provided by regulators. Most regulators can enable and disable their outputs, and some can also control their output voltage or current. The driver should expose those capabilities to consumers by means of specific functions and data structures, which we will discuss in this chapter. The chip that physically provides regulators is called Power Management Integrated Circuit (PMIC); it is worth mentioning that there is such a chip in pretty much every cell phone, making power management a leading branch in embedded systems.
This chapter will introduce you to the PMIC/producer driver interface, the consumer APIs as well as their respective bindings. In other words, we will cover the following topics in this chapter:
- Overview of the regulator framework
- Walking through the PMIC/producer driver interface
- Dealing with the regulator machine driver interface
- Writing a PMIC device driver
- Leveraging the regulator consumer interface
Overview of the regulator framework
Given the following diagram representing a PMIC along with other devices:
Figure 1 – Regulator producer and consumers
From the above diagram, we can enumerate a basis terminology before going further into software and technical aspects:
- Regulator: Electronic device that supplies power to other devices (the consumers). A regulator can be either fixed (enable and disable its output) or can control its output voltage and or current.
- PMIC: it is the controller, the enclosing chip, the Integrated Circuit (IC). It may contain one or more regulators, and often contains other functional modules. Its driver is sometimes referred to as “regulator driver” but I think it would make more sense to call it “PMIC driver”, even if it contains or expose only one regulator.
- Consumer: this is a regulator client. It is an electronic device that is supplied power by a regulator (some consumers can be supplied my several regulators). Consumers are divided into two types:
- Static: Consumer does not change its supply voltage or current limit; thus they remain static. It only needs to enable or disable its power supply. Its supply voltage is set by the hardware, bootloader, firmware, or kernel board initialization code.
- Dynamic: Consumer needs to modify its supply voltage or current limit to meet operation demands.
The Linux regulator framework has been designed to interface and control voltage and current regulators. It is divided into four separate interfaces which are the followings:
- PMIC driver interface: It directly interfaces with the PMIC, exposing its regulator devices each with a set of callbacks allowing to control the regulator.
- Consumer driver interface: It provides necessary APIs and data structure to consumer device drivers. From the consumer side a regulator is represented as an instance of struct regulator.
- Machine interface, for board configuration. It may set regulator constraints which would prevent device damage caused by buggy client drivers. Such damages might be over-voltage or over-current
- Sysfs interface: Which is the user space interface to monitor device power consumption and status.
Now that we have a better overview of the global framework, let’s get deeper in specificities, starting with the producer interface.
The PMIC/producer driver interface
The producer is the device exposing regulators device, which generate the regulated voltage or current. The name of such a device is PMIC and can be used for power sequencing, battery management, DC-to-DC conversion, or simple power switches (on/off). It regulates the output power from the input power, with the help of (and under) software control.
This interface deals with regulator drivers, and especially the producer PMIC side. The followings are the required headers:
From the above headers, are defined lot of data structure on top of which the producer interface is built. In the next section, we introduce those data structures.
Introduction to the regulator producer data structures
Each regulator registered with the core is described with two main data structures. The struct regulator_desc
which represents the static (i.e: non-varying) configuration of the regulator, and a struct regulator_config
which represents the dynamic parts of the configuration.
The struct regulator_desc structure
The kernel describes every regulator provided by a PMIC by means of struct regulator_desc
structure, which characterizes the static parameters of the regulator. This structure, which contains fixed properties of a regulator is defined as the following:
Some fields in the excerpt above have been intentionally omitted for simplicity reasons. The complete structure definition is available in include/linux/regulator/driver.h
. The followings are the meaning of each element present above:
name
holds the name of the regulator.of_match
holds the name used to identify the regulator in device tree. It must match with the regulator node’s name. This is used by the regulator core to match the node from which initialization data must be collected. IfNULL
, then initialization data collection from device tree won’t be supported for this regulator.regulators_node
: Name of sub-node containing regulator definitions in the PMIC’s device tree node. In most case it isof_match_ptr("regulators")
.id
is a numerical identifier for the regulator.owner
represents the module providing the regulator for proper reference counting. It should be toTHIS_MODULE
.type
indicates if the regulator is a voltage regulator or a current regulator. It can either beREGULATOR_VOLTAGE
orREGULATOR_CURRENT
. Any other value will result in a regulator registering failure.n_voltages
indicate the number of selectors available for this regulator. It represents the number of values the regulator can output. For fixed output voltage,n_voltages
should be set to1
.min_uV
indicates the minimum voltage value this regulator can provide. It is the voltage given by the lowest selector.uV_step
represents the voltage increase with each selector.ops
represent the regulator operations table. It is a structure pointing to a set of operation callbacks that the regulator supports. This field is discussed later.irq
is the interrupt number of the regulator.
You should see a regulator as any independent regulated output. For example, the ISL6271A from Intersil is a PMIC with three independent regulated outputs. There should then be three instances of struct regulator_desc
in its driver.
The struct regulator_config structure
After the struct regulator_desc
, this is the other mandatory data structure to be provided when registering a regulator. This structure contains the runtime variable parts of the regulator description and is defined as the following:
The meanings of elements in this data structure are detailed below:
dev
represents the struct device structure the regulator belongs to. It should be set with the underlying device structure of the PMIC providing this regulator (i.e:&pdev->dev
).init_data
is the most important field of the structure since it hosts the regulator constraints (a machine specific structure).driver_data
holds the regulator’s private data, which can be obtained usingrdev_get_drvdata()
.of_node
is for DT capable drivers. It is the node to parse for DT bindings. It is up to the developer to set this field. It may beNULL
also.ena_gpiod
: A Regulator can be enabled by external GPIO pin.
After the runtime parameter definition, we need to introduce an important data structure, mandatory to the regulator core so that it can driver the regulator devices.
The struct regulator_ops structure
The struct regulator_ops
structure is a list of callbacks representing all the operations the regulator core and consumers can use to control a regulator. This data structure has the following definition:
There are other callback functions that are not listed here, for which the driver must enable the appropriate mask in valid_ops_mask
or valid_modes_mask
of the regulator’s constraints before the consumer can use them. Available operation mask flags are defined in include/linux/regulator/machine.h
We can notice that all the above callback functions have a parameter of type struct regulator_dev
. For the short story, from the consumer side, a regulator device is represented by an instance of type struct regulator. While a regulator device can be shared, each consumer will have its own copy of struct regulator. However, all these copies will be backed by the same struct regulator_dev
, which represents the underlying regulator hardware from within the core.
Now that we are familiar with the producer driver data structure, we can switch to the machine driver data structure, thanks to which constraints are applied to the PMIC for prevention reasons.
Dealing with the regulator machine driver interface
The regulator machine driver interface is mainly used to configure the regulator subsystem by the board-/machine- specific initialization code. Its main purpose is to prevent machine damage by providing some regulator limitations, or some machine specific initialization routines.
Introduction to the machine interface data structures
On some specific boards, the relationship between the regulator and the consumer needs to be initialized at the board level and the regulator core needs to be informed of that. Because it concerns specific board, it is said to be machine specific. The regulator core provides a set of data structures to describe this relationship between the regulators and the consumers and to describe valid operating parameters for the system.
The followings are these data structures:
struct regulator_consumer_supply
: Describes the power receiving equipment if anystruct regulator_init_data
: Describes the regulator’s restriction information and the corresponding relationship between the regulator and its power supply ratio
Even though those are machine structures, they can be defined either in the driver or in the device tree.
The struct regulator_init_data
The struct regulator_init_data
is used during initialization to describe the regulator power limit and to establish the tree structure between the parent-child regulator, the power receiving module (the consumer, if any), and some limitation parameters of the regulator, also known as its constraints. It has the following definition:
The below are the meanings of elements in the structure:
supply_regulator
: If this regulator is powered by a parent regulator, this field should be set to the parent regulator name as it appears in the name field in sysfs (/sys/class/regulator/regulator.x/name
). It is usually set using the constraints field name (regulation_constraints.name).constraints
represent the regulator constraints or limitationsnum_consumer_supplies
: Number of directly powered devices of the regulatorconsumer_supplies
contain the regulator’s powered device description arrayregulator_init
is an optional callback invoked at a given moment when the core registers the regulator. Driver can set it with a regulator machine specific initialization callbackdriver_data
represents the data passed toregulator_init
. This field is not touched by the core
This data structure gathers the whole set of data structure used by the machine interface.
The struct regulator_consumer_supply
This is a machine data structure used to describe a device supplied by a regulator and build the supply and device chain. This data structure is defined as the following:
In the above data structure, dev_name
is the powered device name. Most of time, it is the result of dev_name()
for the consumer. supply is the name for the supply, such as Vcc.
The struct regulation_constraints structure
When a PMIC exposes a regulator to consumers, it must impose some nominal limits for this regulator with the help of the struct regulation_constraints
structure. It is a structure gathering security limits of the regulator and defining boundaries the consumers cannot cross. It is a kind of a contract between the regulator driver and the consumer driver. The following is its data structure:
The followings describe each element in the structure:
min_uV
,min_uA
,max_uA
,max_uV
are the smallest voltage/current values that the consumers may set. They can be different from what the device/driver does implements. For instance,max_uV
could be lower than the max voltage value that could be provided by the regulator.
uV_offset
is the offset applied to voltages from the consumer to compensate for voltage drops.valid_modes_mask
defines the modes supported by the regulatorvalid_ops_mask
respectively are masks of modes/operations which may be configured/performed by consumers.REGULATOR_CHANGE_VOLTAGE
: allows changing the output voltage by software on this machineREGULATOR_CHANGE_CURRENT
: allows changing the output current by software on this machine
REGULATOR_CHANGE_MODE
: allows operating mode to be changed by software on this machineREGULATOR_CHANGE_STATUS
: allows gating (enabling/disabling) the regulatorREGULATOR_CHANGE_DRMS
: Can dynamically change the working mode. It also means that Dynamic Regulator Mode Switching is enabled for this regulatorREGULATOR_CHANGE_BYPASS
: Can be put into to bypass mode
always_on
should be set if the regulator should never be disabled hen system is on.boot_on
should be set if the regulator is enabled when the system is initially started. It also means that the regulator will be enabled the constraints are applied unless it has already been enabled by the hardware or bootloader then it will be enabled when the constraints are applied.name
is a descriptive name for the constraints used for display purposes.apply_uV
applies the voltage constraint when initializing.input_uV
represents the input voltage for this regulator when it is supplied by another regulator.state_disk
,state_mem
, andstate_standby
defines the state for the regulator when the system is suspended in the disk mode, mem mode, or in standbyinitial_state
indicates the suspended state is set by default. It indicates the suspend state to set at initializationinitial_mode
is the mode to set at startup.always_on
tells is regulator never off when system is onboot_on
tells if this regulator is bootloader/firmware enabled
Constraints are registered by defining a struct regulator_init_data
for each regulator so that consumers do not use the regulator inappropriately. This structure also maps the consumers to their supply regulators as we will see in the next section.
Writing a PMIC device driver
Writing a PMIC driver would consist in setting up the whole data structures we have introduced so far according to the PMIC capability and registering each regulator device of the PMIC with the regulator core.
All the steps can be enumerated as the following:
- Defining machine interface data (which is the same as providing initialization data) for each regulator device, which consists of:
- Providing operating constraints for the regulator
- Providing the array of consumers this regulator supplies if any
- Providing a bitmask defining the operations that clients are allowed to perform on this regulator
- These data can be provided either in the current driver, either as legacy platform data (mostly for MFD devices), or the new device-tree way.
- Defining driver interface data structure, which consists of:
- Defining necessary set of hooks to enable/disable regulator, to get/set the current/voltage values and/or limit and build appropriate
struct regulator_ops
data structures. Regulators that are controlled with the same logic can use the same set of hooks. - Defining description (
s
truct regulator_desc
) for each regulator device. This is where each regulator is assigned its hooks, its type (voltage or current), and a name.
- Defining necessary set of hooks to enable/disable regulator, to get/set the current/voltage values and/or limit and build appropriate
- Defining bus-specific probe method for the PMIC, which should:
- Identify the PMIC
- Loop over the regulators exposed by the PMIC, and for each of them:
- grabbing initialization data (either defined in the current driver, provided as platform data, or fetched from the device tree)
- Building a regulator config (a
struct regulator_config
, given the initialization data) - Identifying description associated with this regulator (let’s call it
desc
) - Register the regulator using both config and
desc
:devm_regulator_register(dev, &desc, &config)
.
Now that we have an overview of the driver interface, we can start by the beginning of its implementation, that is, providing initialization data.
Providing initialization data
Initialization data can be fetched either from the device tree, from platform data, or hard coded in the driver. The driver will optionally check for platform data or device tree before falling back to the hard coded regulator_init_data
as a default. This method consists of filling an array of constraints and the following is a sample based on the binding of ISL6271A from Intersil:
The above can be used as is, as the hard coded initialization data. We have defined min and max values, along with mask of valid operations for each regulator.
The above data structure is intended for demonstration purpose for the needs of the chapter, because in the real word, most of time, fixed regulators do not need initialization data (unless there are some state constraints to be applied, such as always-on, and so on). Thus, we could have had a single entry in the array, corresponding to the non-fixed regulator.
When it comes to platform data, data can come either from board/machine file or from another driver. Because platform data type may vary according to the data structure expected by the driver, it may be necessary to define the custom data structure the driver expects in a separated header and including this header both in the PMIC driver and in the board file (of the driver intended to provide platform data).
The following is an example of data structure our driver might expect:
Using the previous hard coded initialization data array, we can build the platform data as the following:
According to the above, driver could fetch each regulator initialization data using pdata->init_data[i]
.
Assuming the PMIC sits on an I2C bus, we need to declare the device from board file as well, as the following:
The above I2C device define the I2C driver name to match with and the I2C device address of this PMIC. Now we can register the I2C device, still in the board file, as the following:
After we have populated the I2C board info from the board file, driver can reference platform data in the probe method as the following:
The drawback with this method is that, for any parameter change, the whole kernel needs to be recompiled and updated. That said, platform data is the legacy method, and we will focus on the recommended approach, the DT, which is described in the next section.
Fetching initialization data from device tree
Looking up initialization data for regulators found on PMICs is a common operation that can be handled in a generic way. This sounds good because the device tree is a generic approach. To achieve this, a new helper function has been introduced: of_regulator_match()
. This function has the following prototype:
This function parses regulator startup data present in the device tree by using a match table provided by the regulator driver. In parameters, dev
is the underlying device structure requesting the data, node
is the containing node of the regulators (that is, their parent node). Finally, matches
is the matches table for the regulators and num_matches
is the number of entries in match table. node
is expected to contain a set of child nodes, each providing the initialization data for a single regulator. The data parsed from a child node will be matched to a regulator based on two exclusive factors: either the deprecated property regulator-compatible
if present, or otherwise the child node’s name. When it succeeds, this function returns the number of matches hit, or a negative error code on failure.
With this API, came a new data structure of the same name: the struct of_regulator_match
data structure, which looks like the following:
The followings are the meanings of element in this data structure:
name
: this is the name used to match with a regulator node’s name in the device tree. This must be set by the driver. It has the same purpose thanregulator_desc.of_match
element. However, in case the driver uses this structure withof_regulator_match()
, it should not setregulator_desc.of_match
anymore, else the device node will be parsed twice: once withof_regulator_match()
, and then by the regulator core when registering the regulator.driver_data
: driver can set this with the regulator’s private data. This is untouched by the coreinit_data
: initialization data populated by the regulator core with data that have been collected from device tree.of_node
: the matched regulator device’s node. Filled by the core after a match.desc
: the regulator descriptor structure
In the device tree, each regulator device must be represented with a node, which would contain the necessary properties to build the regulator’s constraints. For a given PMIC, when populating its regulator constraints in the device tree, it is common to gather regulators of the same PMIC in a same container node. It is also common (and recommended) for this container node to be named regulators
. Though it is a recommendation, it is mandatory for this name to be the same as what has been assigned to regulator_desc.regulators_node
. Finally, it is recommended to make this container node a child of the PMIC node, so that it is easy to identify what regulators belong to what PMIC.
The following is a rough demonstration of the PMIC – container node – regulators tree:
In the above, the PMIC node is declared first along with its properties, then the regulators container node, and then each regulator node. core_buck
, ldo1
, and ldo2
are the names which should be provided in the match table as they match regulator node names.
Let us now see in the following the standardized properties you can define in a regulator node, all of which are mapped onto elements in the struct regulator_constraints data structure:
regulator-name
: This is a string used as a descriptive name for regulator outputsregulator-min-microvolt
: This is the smallest voltage that consumers may set- regulator-max-microvolt: This is the largest voltage consumers may set
regulator-microvolt-offset
: This is the offset applied to voltages to compensate for voltage dropsregulator-min-microamp
: This is the smallest current consumers may setregulator-max-microamp
: This is the largest current consumers may setregulator-always-on
: This is a Boolean value, indicated if the regulator should never be disabledregulator-boot-on
: This is bootloader/firmware enabled regulator<name>-supply
: This is a phandle to the parent supply/regulator noderegulator-ramp-delay
: This is the ramp delay for regulator (in uV/uS)regulator-state-[mem/disk]
: each regulator node can contain a sub-node defining the regulator state when the system is suspended in themem
mode (in which case the sub-node would be namedregulator-state-mem
) or in disk (in which case the sub-node would be namedregulator-state-disk
). The followings are common properties which can be used in those sub-nodes:regulator-on-in-suspend
: If present, this property means that the regulator should not be turned off in suspend state, assuming it was on before the system suspend.regulator-off-in-suspend
: If present, this property means that the regulator should be (turned) off in suspend state.regulator-suspend-microvolt
: this property specifies the consign voltage the regulator should be set to in suspend state.regulator-mode
: this property specifies the operating the mode into which the regulator should be put in the given suspend state. However, because the number of possible operating modes varies depending on the capabilities of every hardware, the valid modes are listed on each regulator device tree binding document.
The following is an example:
Now that we have enumerated all the valid properties in a regulator node, we can translate our previous isl_init_data
in the device tree as the following:
Using the kernel helper function of_regulator_match()
given the regulators sub-node as parameter, this function will walk through each regulator device node and will build a struct init_data
structure for each of them.
The following is the match table which would correspond to the above device tree declaration:
Note that of_regulator_match()
looks up regulator child nodes and inside a given parent node invokes of_get_regulator_init_data()
on each sub-node found. of_get_regulator_init_data()
is a function which, given a regulator node, will extract the initialization data corresponding to this regulator.
Providing driver interface data
This step consists of providing the set of hooks allowing to control each regulator and feed these hooks to a data structure allowing to describe each regulator. The followings are rough excerpt of hooks allowing to control our PMIC’s regulator devices.
First, the callback that is the backend of get_voltage_sel()
:
Then, comes the callback allowing to handle set_voltage_sel()
operation.
Now that we are done with the callback definition, we can build a struct regulator_ops as the following:
In the above, regulator_list_voltage_linear
and regulator_list_voltage_linear
are defined in drivers/regulator/helpers.c
, provided by the core to handle linear output regulator, as it is the case of the ISL6271A.
Because the second and third regulators are fixed regulators, they need their own hooks:
Now that all the callbacks have been defined, we can build an array or regulator descriptors, to describe each regulator device and assign their corresponding hooks as the following:
LDO1
and LDO2
have a fixed output voltage. Therefore, their n_voltages
properties are set to 1, and their ops only provide regulator_list_voltage_linear
mapping and no hook to change their output values.
Implementing the driver methods
Driver methods consist of probe()
and remove()
methods. Please refer to the preceding data structure if this section seems unclear to you. The probe function of a PMIC driver consists in a few operations, essentially identifying regulators and registering each of them with the core.
In case the driver needed to fetch init data from the device tree, it would have used isl6271a_matches
match table that we have defined earlier as a parameter to of_regulator_match()
.
Registering a regulator device
After looking up for regulators, fetching their regulator_init_data
and their regulator_desc
, driver must build struct regulator_config
. Then, driver must call devm_regulator_register()
to register the regulator with the core, giving the previous regulator_desc
and regulator_config
as parameters.
The following is the prototype of the registration API:
This function returns NULL
on error or a pointer to an object of type regulator_dev
on success, which represents the underlying regulator device. There is only one instance of this type for a given regulator. If regulator_config.data
has been set before registration, this data will be assigned to the returned regulator, on which you can use rdev_get_drvdata()
to get back this data. It is common for drivers to keep track of these struct regulator_dev
returned in order to ease their identification in their regulator hooks or for a later use when need for unregistering be. However, instances of struct regulator_dev
structure should not be used directly by anything except the regulator core.
Because the managed registration is used, the core will take care of unregistering the regulator when necessary. Nothing has been done by the driver, otherwise it would have been necessary to use the following:
In the above, rdev
is the regulator device returned while registering.
Example of probing method
As a recall, the PMIC example we have used so far provides three regulator devices, among which only one can have its output value changed. The two others provide fixed voltages. Let’s define the driver data structure:
Since registering should be done on a regulator basis (not PMIC basis), the driver needs to call devm_regulator_register()
function three times, as in the following probe demonstration:
So far, only some sanity checks have been done, as well as main data structure allocation. Now come the device tree related part:
Now that the driver has all the nodes it needs within arm reach, it can attempt the match, as the following:
If the code reaches here, it means no error occurred and the match was successful. Registration can be done on a regulator basis. To do that, a for
loop is used, with the upper bound corresponding to the number of regulators.
In the above registration loop, initialization data is fetched to build a regulator config to be passed at registration, along with the respective regulator descriptor.
For the sake of readability and to highlight some point addressed in the chapter, the original probe method has been slightly modified. The most important change is the fact that fixed regulators do not necessarily need (but there is no restriction in doing so) initialization data as no output value can change (everything is fixed), but in our implementation, we assumed each regulator is given an init_data
.
It could make sense to provide constraints (thus initialization data) for a fixed regulator, if need be, for example, to define the regulator as always-on or to define suspend-related states. However, it could be a good practice in always providing it, at least for information purpose, as this can be seen from sysfs.
With all the above, we have demonstrated how straightforward it could be to write a PMIC device driver. To confirm these words, let’s put everything together and let’s try to write a complete PMIC driver from scratch.
Writing a PMIC driver from scratch
Let’s summarize things discussed above in a real driver, for a dummy PMIC having two regulators, where the first one has a voltage range from 850000µV
to 1600000µV
with a step of 50000µV
, and the second regulator has a fixed voltage of 1300000µV
.
First, we deal with preprocessor related part by including the necessary headers and defining some macro:
Then we define the table that will be used to match our driver from the device tree as the following:
The regulator related code starts at this point. We make the choice of defining our constraints in the driver and we do it as the following:
In the above, we have two constraints defined, one for each regulator. Next, we define some callback functions, two of them actually, since we will use some other provided by the regulator framework:
After having done with the regulator operations, they can be used while building the regulator description structure as the following:
Now we are done with data structure and callback definition. Let’s then jump to the probe function implementation.
In the above probe function, we used a loop to iterate over the regulators to register. However, the initialization data were hard-coded in the driver; thus, updating any parameter would require in the best-case rebuilding and updating the module, or the whole kernel it our driver is built in.
Let’s do some efforts to migrate this driver to device tree. In this case, we would have got rid of the dummy_initdata
variable which contain initialization data, in favor of device tree.
In the device tree, our node could look as the following:
From what you can see, properties defined in each regulator node correspond to their respective constraints. Now that our node has been defined, we can start populating de regulator-related device tree-based data structures, starting with an of_regulator_match
instance.
The above structure is used to match the regulators init_data
from the device tree. To achieve that, the name elements must correspond to the regulator node names, that is, reg1
and reg2
in our case.
Now we can implement the new device tree-based probe function:
In the above probe function, of_regulator_match()
is used along with dummy_matches
to fetch regulator initialization data from the device tree. The above approach is more flexible and customizable. If need bee to update some constraint, only the device tree should be updated.
Finally, whatever our probe function implementation is, the remove function of our driver would consist in unregistering regulators that have previously been registered. That said, I’m happy to announce we don’t need to, because we used the managed registration variant (devm_*
).
We can then register our driver as the following:
Once the module loaded and the device matched, the kernel print something like:
One can then check what happened under the hood:
regulator.13 and regulator.14 have been added by our driver. Let us now check their properties:
The above console output shows some regulator properties. Right at this moment, you should be able to understand any existing PMIC driver, and eventually to write one from scratch.
Now that the PMIC driver is ready, consumers can request for the kernel to control its regulator lines. Those consumers are other device drivers requesting for regulator lines to supply the devices they driver. To achieve this, dedicated APIs need to be used, as we will see in the next section.
Leveraging the regulator consumer interface
The regulator consumer interface requires the driver to include the following header
The struct regulator is the data structure by which the core abstracts a regulator device for a consumer, while the physical device is backed by an instance of struct regulator_dev
. Given a regulator used by one or more consumers, each consumer will have its own copy of struct regulator instance, but they all will be backed by the same struct regulator_dev
in the core.
The struct regulator
is defined in drivers/regulator/internal.h
as the following:
Each consumer of a given regulator line will have its own copy of this data structure, all backed in the core by the same struct regulator_dev
, pointed to by the rdev
field which will be the same for all those consumers.
Requesting and releasing a regulator
When the consumer driver needs to operate a regulator, it needs to obtain its handle first.
Prior to gaining access to a regulator, the consumer has to request the kernel by means of the devm_regulator_get()
function, which is the managed version of regulator_get()
and which is defined as the following:
The consumer passes in its struct device pointer and the power supply ID. The core will try to find the correct regulator by consulting the device tree or a machine specific lookup table. If we focus only on the device tree, id
should match the <name>
pattern of the regulator supply in the device tree. This method will return a pointer to the struct regulator
that supplies this consumer if the lookup is successful, otherwise, a pointer error is returned.
An example of using this function is the following:
Because a regulator can be shared (note that each consumer has its copy of struct regulator_dev
), the consumer interface makes it possible to gain exclusive access to a regulator. This is done using devm_regulator_get_exclusive()
. This is meant for use by consumers which need to gain exclusive access and which cannot tolerate shared use of the regulator. Such consumers might need for instance to forcibly turning the regulator off (using regulator_force_disable()
) for the hardware they are controlling to work properly.
To see how easy, it is to gain exclusive access to a regulator, we can use the following example:
What really happens is that, when requesting a regulator device, the requesting API perform the following operations:
- It looks for the corresponding
struct regulator_dev
; let’s call itregdev
. - once found, the function checks whether the requesting method is exclusive or not.
- If exclusive,
- it makes sure that the
exclusive
flag inregdev
is not set and that its usage count is zero. If both conditions are met, the function jumps to the next step, else it returns here with a pointer error. - After that, it sets
regdev.
exclusive
flag and increases the usage counter ofregdev
.
- it makes sure that the
- If not exclusive
- The function checks whether
regdev.
exclusive
flag is set or not. If set (meaning that this regulator is subject to exclusive access), a pointer error is returned, and the function stops here. If not set, it jumps to the next step. - Then, it increases usage counter of
regdev
.
- The function checks whether
- If exclusive,
- In the last step, the requesting API generates a
struct regulator
structure and makes itsrdev
field pointing to thestruct regulator_dev
previously found (regdev
); finally, it returns the generatedstruct regulator
to the consumer.
Now that we are familiar with the way a regulator request works, we can try to control this regulator. In the next section, we learn how to achieve that.
Controlling the regulator device
Regulator control consists of enabling, disabling, and setting output values of a regulator. The regulator is turned on and off one of the following APIs:
The consumer enables its power supply by calling regulator_enable()
. This function returns 0 on success. The reverse operation consists of disabling the power supply, by calling regulator_disable()
.
These functions ultimately call the corresponding members in struct regulator_ops
. While regulator_disable()
will only disable the regulator output if no other consumer devices have it enabled (its enabled reference counter is zero), regulator_force_disable()
will forcibly disable the regulator output voltage or current even if other consumer devices have it enabled. The forcing method should be used for situations when device damage will likely occur if the regulator is not disabled (e.g. over temperature).
To check whether a regulator is already enabled or not, the consumer should call regulator_is_enabled()
, defined as the following:
This function returns a value greater than 0 if the regulator is enabled, 0 if not enabled, or a negative error number if an error occurred. Because the underlying regulator device (struct regulator_dev
) can have multiple users, a regulator might be enabled even if regulator_enable()
was never called for this particular source. Same if the regulator was early enabled by a bootloader for example.
Voltage control and status
A consumer can be static or dynamic. Static one requires only a fixed supply, whereas dynamic one requires active management of the regulator at runtime. For consumers that need to adapt their power supply according to their operating mode, the kernel provides the following APIs:
In the previous API, min_uV
and max_uV
are the minimum and maximum acceptable voltages in microvolts.
If called when the regulator is disabled, this function will change the voltage configuration so that the voltage is physically set when the regulator is next enabled. That said, consumer can get the regulator configured voltage output by calling regulator_get_voltage()
, which will return the configured output voltage whether the regulator is enabled or not:
An example of usage is the following:
Now that we are done with voltage control, the other unit we need to control is the current, which se learn in the next section.
Current limit control and status
What we have discussed in the voltage section also applies here. Consumers can control their supply current limit by calling:
min_uA
and max_uA
are the minimum and maximum acceptable current limit in microamps.
In the same way, consumers can get the regulator configured current limit by calling regulator_get_current_limit()
, which will return the current limit whether the regulator is enabled or not:
The above API returns the current supplied by the specified current sink in uA.
Operating mode control and status
For efficient power management, some consumers may change the operating mode of their supply when their own operating state changes. Consumer drivers can request a change in their supply regulator operating mode by calling:
If the Regulator system constraints of the concerned regulator is not set before regulator_set_mode()
is called, the function call will fail. This can be used for example to allow device power supply to enter low-power mode if device will do nothing to save more power
To get the regulator operating mode, drivers can use the following:
Dealing with the regulator operating modes was the last control operation we needed to learn in the chapter. Now that we are able to control a regulator to supply our device safely, let’s see how to assign a regulator line to our device from the driver.
Regulator consumer binding
This section only deals with the consumer interface binding. Because PMIC binding consists of providing initialization data for regulators that this PMIC provides, you should refer to Fetching initialization data from device tree section to understand the producer binding.
Consumer nodes can reference one or more of their supplies/regulators using <name>-supply
property binding which should be assigned a phandle to the regulator node. <name>
should be meaningful enough, so that the driver can easily refer to it when requesting the regulator. Moreover, while gaining access to the regulator, <name>
must match the id
parameter of devm_regulator_get()
function:
The consumer code (which is the MMC driver) that requests its supplies could look like:
In the above code example, we can notice that regulators are requested using the <name>
part of device tree declaration.
Summary
In this tutorial, we have learned to handle regulator controllers and to leverage the regulator lines with the consumer APIs. What makes me confident are all the aspects of the regulator framework we have walked through, after which, you should be familiar with both sides of the framework, that is, consumer and producer (PMIC) interfaces as well as their data structures. Moreover, you should be able to write PMIC driver from scratch and rely on the device tree to build the constraints.
PMIC devices usually sit on SPI or I2C buses. Consequently, we will certainly have another tutorial discussing I2C and SPI device drivers. You might not have occasion to write your own PMIC driver from scratch. In this case you can stay from the client side and consuming regulator lines exposed by existing PMIC drivers.