Nothing but Embedded systems

Controlling Power with the Linux kernel Regulator Framework

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: 

#include <linux/platform_device.h> 
#include <linux/regulator/driver.h> 
#include <linux/regulator/of_regulator.h> 

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: 

struct regulator_desc { 
    const char *name; 
    const char *of_match; 
    const char *regulators_node; 

    int id; 
    unsigned n_voltages; 
    const struct regulator_ops *ops; 
    int irq; 
    enum regulator_type type; 
    struct module *owner; 

    unsigned int min_uV; 
    unsigned int uV_step; 
    const unsigned int *volt_table; 
    const unsigned int *curr_table; 

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. If NULL, 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 is of_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 to THIS_MODULE.
  • type indicates if the regulator is a voltage regulator or a current regulator. It can either be REGULATOR_VOLTAGE or REGULATOR_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 to 1. 
  • 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: 

struct regulator_config { 
    struct device *dev; 
    const struct regulator_init_data *init_data; 
    void *driver_data; 
    struct device_node *of_node; 
    struct regmap *regmap; 
    struct gpio_desc *ena_gpiod; 

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 using rdev_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 be NULL 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: 

struct regulator_ops { 
    /* enumerate supported voltages */ 
    int (*list_voltage) (struct regulator_dev *, unsigned selector); 

    /* get/set regulator voltage */ 
    int (*set_voltage) (struct regulator_dev *, int min_uV, int max_uV, 
                        unsigned *selector);
    int (*set_voltage_sel) (struct regulator_dev *, unsigned selector); 
    int (*get_voltage) (struct regulator_dev *); 
    int (*get_voltage_sel) (struct regulator_dev *);  

    /* get/set regulator current */ 
    int (*set_current_limit) (struct regulator_dev *,
							  int min_uA, int max_uA); 
    int (*get_current_limit) (struct regulator_dev *); 

	int (*set_input_current_limit) (struct regulator_dev *, int lim_uA); 
    int (*set_over_current_protection) (struct regulator_dev *); 
    int (*set_active_discharge) (struct regulator_dev *, bool enable); 

    /* enable/disable regulator */
	int (*enable) (struct regulator_dev *);
	int (*disable) (struct regulator_dev *);
	int (*is_enabled) (struct regulator_dev *); 

    /* get/set regulator operating mode
	 * (defined in consumer.h)
    int (*set_mode) (struct regulator_dev *, unsigned int mode); 
    unsigned int (*get_mode) (struct regulator_dev *); 

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 any 
  • struct 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: 

struct regulator_init_data { 
	const char *supply_regulator; 
	struct regulation_constraints constraints; 
	int num_consumer_supplies; 
	struct regulator_consumer_supply *consumer_supplies; 
	int (*regulator_init)(void *driver_data); 
	void *driver_data; 

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 ( 
  • constraints represent the regulator constraints or limitations 
  • num_consumer_supplies: Number of directly powered devices of the regulator
  • consumer_supplies contain the regulator’s powered device description array 
  • regulator_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 callback
  • driver_data represents the data passed to regulator_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: 

struct regulator_consumer_supply { 
	const char *dev_name;  
	const char *supply;  

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: 

struct regulation_constraints { 
    const char *name;
	int min_uV;
	int max_uV;
	int uV_offset;
	int min_uA;
	int max_uA; 

    /*valid regulator operating modes for this machine*/
    unsigned int valid_modes_mask;
    /* valid operations for regulator on this machine */
    unsigned int valid_ops_mask; 

    struct regulator_state state_disk; 
    struct regulator_state state_mem; 
    struct regulator_state state_standby; 
    suspend_state_t initial_state;  

    /* mode to set on startup */ 
    unsigned int initial_mode; 

    /* constraint flags */ 
    unsigned always_on:1; 
    unsigned boot_on:1; 

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 regulator 
  • valid_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 machine 
    • REGULATOR_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 machine
    • REGULATOR_CHANGE_STATUS: allows gating (enabling/disabling) the regulator 
    • REGULATOR_CHANGE_DRMS: Can dynamically change the working mode. It also means that Dynamic Regulator Mode Switching is enabled for this regulator 
    • REGULATOR_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, and state_standby defines the state for the regulator when the system is suspended in the disk mode, mem mode, or in standby 
  • initial_state indicates the suspended state is set by default. It indicates the suspend state to set at initialization 
  • initial_mode is the mode to set at startup. 
  • always_on tells is regulator never off when system is on 
  • boot_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 (struct regulator_desc) for each regulator device. This is where each regulator is assigned its hooks, its type (voltage or current), and a name. 
  • 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: 

static struct regulator_init_data isl_init_data[] = { 
   [0] = { 
      .constraints = { 
         .name           = "Core Buck", 
         .min_uV         = 850000, 
         .max_uV         = 1600000, 
         .valid_modes_mask   = REGULATOR_MODE_NORMAL 
                             | REGULATOR_MODE_STANDBY, 
         .valid_ops_mask     = REGULATOR_CHANGE_MODE 
                             | REGULATOR_CHANGE_STATUS, 
   [1] = { 
      .constraints = { 
         .name           = "LDO1", 
         .min_uV         = 1100000, 
         .max_uV         = 1100000, 
         .always_on      = true, 
         .valid_modes_mask   = REGULATOR_MODE_NORMAL 
                             | REGULATOR_MODE_STANDBY, 
         .valid_ops_mask     = REGULATOR_CHANGE_MODE 
                             | REGULATOR_CHANGE_STATUS, 
   [2] = { 
      .constraints = { 
         .name           = "LDO2", 
         .min_uV         = 1300000, 
         .max_uV         = 1300000, 
         .always_on      = true, 
         .valid_modes_mask   = REGULATOR_MODE_NORMAL 
                             | REGULATOR_MODE_STANDBY, 
         .valid_ops_mask     = REGULATOR_CHANGE_MODE 
                             | REGULATOR_CHANGE_STATUS, 

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: 

struct isl_pdata { 
    struct regulator_init_data *init_data; 
    int num_data; /* number of entries in init_data */ 

Using the previous hard coded initialization data array, we can build the platform data as the following: 

struct isl_pdata islpdata { 
    .init_data = isl_init_data, 
    .num_data = ARRAY_SIZE(isl_init_data), 

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: 

static struct i2c_board_info __initdata board_info[] = { 
		I2C_BOARD_INFO("isl6271a", 0x3C), 
		.platform_data = (void *)&islpdata, 


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: 

static void __init myboard_init(void) 
	i2c_register_board_info(0, board_info, ARRAY_SIZE(board_info)); 

After we have populated the I2C board info from the board file, driver can reference platform data in the probe method as the following: 

static int static int own_isl6271a_probe(struct i2c_client *i2c) 

    struct regulator_config config = { }; 
    struct isl9305_pdata *pdata =  dev_get_platdata(&client->dev); 


    if (!pdata)
		return -EINVAL; 

    /* now driver can play with pdata->init_data[i] */ 

static struct i2c_driver isl6271a_i2c_driver = { 
    .driver = { 
        .name = "isl6271a", 
    .probe = own_isl6271a_probe, 

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: 

int of_regulator_match(struct device *dev,
              struct device_node *node, 
              struct of_regulator_match *matches, 
              unsigned int num_matches);

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: 

struct of_regulator_match { 
	const char *name; 
	void *driver_data; 
	struct regulator_init_data *init_data; 
	struct device_node *of_node; 
	const struct regulator_desc *desc; 

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 than regulator_desc.of_match element. However, in case the driver uses this structure with of_regulator_match(), it should not set regulator_desc.of_match anymore, else the device node will be parsed twice: once with of_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 core 
  • init_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: 

pmic-node { 

	regulators { /*regulators container node */ 

		reg1: core_buck { 

		reg2: ldo1 { 

		reg3: ldo2 { 

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 outputs 
  • regulator-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 drops 
  • regulator-min-microamp: This is the smallest current consumers may set 
  • regulator-max-microamp: This is the largest current consumers may set 
  • regulator-always-on: This is a Boolean value, indicated if the regulator should never be disabled 
  • regulator-boot-on: This is bootloader/firmware enabled regulator 
  • <name>-supply: This is a phandle to the parent supply/regulator node 
  • regulator-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 the mem mode (in which case the sub-node would be named regulator-state-mem) or in disk (in which case the sub-node would be named regulator-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: 

xyzreg: regulator@0 { 
	regulator-min-microvolt = <1000000>; 
	regulator-max-microvolt = <2500000>; 

	regulator-state-mem { 


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: 

isl6271a@3c { /* PMIC node */ 
    compatible = "isl6271a";
	reg = <0x3c>;
	interrupts = <0 86 0x4>; 

    regulators { /*regulators container node */
		reg1: core_buck { /* first regulator node */
		    regulator-name = "Core Buck";
            regulator-min-microvolt = <850000>; 
            regulator-max-microvolt = <1600000>; 

            regulator-state-mem {


    	reg2: ldo1 {
			regulator-name = "LDO1";
			regulator-min-microvolt = <1100000>;
			regulator-max-microvolt = <1100000>;

    	/* third and last regulator node */ 
    	reg3: ldo2 {
			regulator-name = "LDO2";
			regulator-min-microvolt = <1300000>;
			regulator-max-microvolt = <1300000>;

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: 

static struct of_regulator_match isl6271a_matches[] = { 
	{ .name = "core_buck", }, 
	{ .name = "ldo1", }, 
	{ .name = "ldo2", }, 

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(): 

static int isl6271a_get_voltage_sel(struct regulator_dev *rdev) 

	struct isl_pmic *pmic = rdev_get_drvdata(dev); 
	int idx = rdev_get_id(rdev); 

Then, comes the callback allowing to handle set_voltage_sel() operation. 

static int isl6271a_set_voltage_sel(struct regulator_dev *dev, 

unsigned selector) 


	struct isl_pmic *pmic = rdev_get_drvdata(dev); 
	int err; 

	return err; 

Now that we are done with the callback definition, we can build a struct regulator_ops as the following: 

static struct regulator_ops isl_core_ops = { 
	.get_voltage_sel = isl6271a_get_voltage_sel, 
	.set_voltage_sel = isl6271a_set_voltage_sel, 
	.list_voltage = regulator_list_voltage_linear, 
	.map_voltage = regulator_map_voltage_linear, 

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: 

static struct regulator_ops isl_fixed_ops = { 
	.list_voltage = regulator_list_voltage_linear, 

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: 

static const struct regulator_desc isl_rd[] = { 
		.name = "Core Buck", 
		.id = 0, 
		.n_voltages = 16, 
		.ops = &isl_core_ops, 
		.owner = THIS_MODULE, 
		.min_uV = ISL6271A_VOLTAGE_MIN, 
		.uV_step = ISL6271A_VOLTAGE_STEP, 
	}, { 
		.name = "LDO1", 
		.id = 1, 
		.n_voltages = 1, 
		.ops = &isl_fixed_ops, 
		.owner = THIS_MODULE, 
		.min_uV = 1100000, 
	}, { 
		.name = "LDO2", 
		.id = 2, 
		.n_voltages = 1, 
		.ops = &isl_fixed_ops, 
		.owner = THIS_MODULE, 
		.min_uV = 1300000, 


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: 

devm_regulator_register(struct device *dev, 
           const struct regulator_desc *regulator_desc, 
           const struct regulator_config *config); 

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 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: 

void regulator_unregister(struct regulator_dev *rdev) 

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: 

struct isl_pmic { 
	struct i2c_client *client; 
	struct regulator_dev *rdev[3]; 
	struct mutex mtx; 

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: 

static int isl6271a_probe(struct i2c_client *i2c) 
	int i, ret;
	struct isl_pmic *pmic;
	struct isl_pdata *pdata = dev_get_platdata(&i2c->dev);
	struct device *dev = &i2c->dev; 

	struct device_node *np, *parent; 

	if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
		return -EIO;

	pmic = devm_kzalloc(dev, sizeof(struct isl_pmic), GFP_KERNEL); 
	if (!pmic)
		return -ENOMEM; 

	pmic->client = i2c;

So far, only some sanity checks have been done, as well as main data structure allocation. Now come the device tree related part:

	/* Get the device (PMIC) node */ 
	np = dev->of_node; 
	if (!np) 
		return -EINVAL; 
	/* Get 'regulators' container node */ 
	parent = of_get_child_by_name(np, "regulators"); 
	if (!parent) { 
		dev_err(dev, "regulators node not found\n"); 
		return -EINVAL; 

Now that the driver has all the nodes it needs within arm reach, it can attempt the match, as the following:

	/* fills isl6271a_matches array */
	ret = of_regulator_match(dev, parent, isl6271a_matches, 


	if (ret < 0) {
		dev_err(dev, "Error parsing regulator init data: %d\n", ret); 
		return ret;

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.

	for (i = 0; i < 3; i++) { 
		struct regulator_init_data *initdata; 
		struct regulator_config config = {}; 
		struct regulator_desec *rdesc; 

		rdesc = &isl_rd[i]; 

		if (pdata)
			/* Given as platform data */
			config.init_data = pdata->init_data[i];
			/* Fetched from device tree */
			initdata = isl6271a_matches[i].init_data; = dev;
		config.init_data = initdata;
		config.of_node = isl6271a_matches[i].of_node;
		config.ena_gpio = -EINVAL; 

		/* config is passed by reference because the
		 * kernel internally duplicates it to create
		 * its own copy so that it can override some
		 * fields
		pmic->rdev[i] = devm_regulator_register(dev, rdesc, &config); 
		if (IS_ERR(pmic->rdev[i])) {
			dev_err(dev, "failed to register %s\n", id->name);
			return PTR_ERR(pmic->rdev[i]);

	i2c_set_clientdata(i2c, pmic);
	return 0; 

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. 

	for (i = 0; i < 3; i++) {
		if (i == 0)
			/* assign init_data */
			config.init_data = NULL;

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: 

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/err.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h> 

#define DUMMY_VOLTAGE_MIN    850000
#define DUMMY_VOLTAGE_MAX    1600000
#define DUMMY_VOLTAGE_STEP   50000

Then we define the table that will be used to match our driver from the device tree as the following: 

static const struct of_device_id regulator_dummy_ids[] = {
    { .compatible = "packt,regulator-dummy", },
    { /* sentinel */ }

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: 

Static struct regulator_dev *dummy_regulator_rdev[2]; 

static struct regulator_init_data dummy_initdata[] = {
    [0] = {
        .constraints = {
            .always_on = 0,
            .min_uV = DUMMY_VOLTAGE_MIN,
            .max_uV = DUMMY_VOLTAGE_MAX,
    [1] = {
        .constraints = {
            .always_on = 1,
            .min_uV = 1300000,
            .max_uV = 1300000,

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: 

static int isl6271a_get_voltage_sel(struct regulator_dev *dev) 
    return 0; 

static int isl6271a_set_voltage_sel(struct regulator_dev *dev,
									unsigned selector) 
    return 0;

static struct regulator_ops dummy_fixed_ops = { 
    .list_voltage   = regulator_list_voltage_linear,

static struct regulator_ops dummy_core_ops = { 
    .get_voltage_sel = isl6271a_get_voltage_sel, 
    .set_voltage_sel = isl6271a_set_voltage_sel, 
    .list_voltage   = regulator_list_voltage_linear, 
    .map_voltage    = regulator_map_voltage_linear, 

After having done with the regulator operations, they can be used while building the regulator description structure as the following: 

static const struct regulator_desc dummy_desc[] = {
        .name       = "Dummy Core",
        .id         = 0,
        .n_voltages = 16,
        .ops        = &dummy_core_ops,
        .type       = REGULATOR_VOLTAGE,
        .owner      = THIS_MODULE,
        .min_uV     = DUMMY_VOLTAGE_MIN,
        .uV_step    = DUMMY_VOLTAGE_STEP,
    }, {
        .name       = "Dummy Fixed",
        .id         = 1,
        .n_voltages = 1, 
        .ops        = &dummy_fixed_ops, 
        .type       = REGULATOR_VOLTAGE, 
        .owner      = THIS_MODULE, 
        .min_uV     = 1300000, 

Now we are done with data structure and callback definition. Let’s then jump to the probe function implementation. 

static int my_pdrv_probe (struct platform_device *pdev)
    struct regulator_config config = { }; = &pdev->dev; 
    int ret, i;

    for (i = 0; i < 2; i++){ 
        config.init_data = &dummy_initdata[i]; 

        dummy_regulator_rdev[i] =
                                &dummy_desc[i], &config);

        if (IS_ERR(dummy_regulator_rdev[i])) {
            ret = PTR_ERR(dummy_regulator_rdev[i]);
              "Failed to register regulator: %d\n", ret);
            return ret;

    platform_set_drvdata(pdev, dummy_regulator_rdev);
    return 0;

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: 

dummy_node {
    compatible = "simple-bus";
    #address-cells = <1>;
    #size-cells = <0>;

    fake_pmic: fakepmic@1 { 
        compatible = "packt,regulator-dummy"; 
        reg = <1>;

        regulators { 
            fake_one_reg: reg1 { 
                regulator-name = "Dummy Core"; 
                regulator-min-microvolt = <850000>; 
                regulator-max-microvolt = <1600000>;
           fake_to_reg: reg2 { 
                regulator-name = "Dummy Fixed"; 
                regulator-min-microvolt = <1300000>; 
                regulator-max-microvolt = <1300000>; 

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. 

static struct of_regulator_match dummy_matches[] = { 
	{ .name = "reg1", }, 
	{ .name = "reg2", }, 

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: 

static void my_pdrv_probe(struct platform_device *pdev) 
    struct device *dev = &pdev->dev; 
    struct device_node *np, *parent; 
    int ret, i; 

    np = of_node_get(dev->of_node); 
    parent = of_get_child_by_name(np, "regulators"); 
    if (!parent) { 
        dev_err(dev, "regulators node not found\n"); 
        return -EINVAL; 

    ret = of_regulator_match(dev, parent, dummy_matches,


    if (ret < 0) {
		dev_err(dev, "Error parsing regulator init data: %d\n",
		return ret; 

    for (i = 0; i < ARRAY_SIZE(dummy_matches) i++) { 
        struct regulator_desc *desc; 
        struct regulator_config config = { }; 
        desc = &dummy_desc[i] = dev; 
        config.init_data = dummy_matches[i].init_data; 
        config.of_node = dummy_matches[i].of_node; 

        dummy_regulator_rdev[i] = 
            devm_regulator_register(dev, desc, &config); 
        if (IS_ERR(dummy_regulator_rdev[i])) { 
            dev_err(dev, "register regulator%s failed\n", desc->name); 
            return PTR_ERR(dummy_regulator_rdev[i]); 
    return 0; 

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: 

static struct platform_driver mypdrv = { 
   .probe      = my_pdrv_probe,
   .driver     = {
     .name     = "regulator-dummy",
     .of_match_table = of_match_ptr(regulator_dummy_ids),  
     .owner    = THIS_MODULE,

MODULE_AUTHOR("John Madieu <>");

Once the module loaded and the device matched, the kernel print something like: 

Dummy Core: at 850 mV  
Dummy Fixed: 1300 mV 

One can then check what happened under the hood: 

# ls /sys/class/regulator/ 
regulator.0   regulator.11  regulator.14  regulator.4   regulator.7 
regulator.1   regulator.12  regulator.2   regulator.5   regulator.8 
regulator.10  regulator.13  regulator.3   regulator.6   regulator.9 

regulator.13 and regulator.14 have been added by our driver. Let us now check their properties: 

# cd /sys/class/regulator 
# cat regulator.13/name  
Dummy Core 
# cat regulator.14/name  
Dummy Fixed 
# cat regulator.14/type  
# cat regulator.14/microvolts  
# cat regulator.13/microvolts  

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 

#include <linux/regulator/consumer.h>

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:

struct regulator { 
	struct device *dev; 
	struct list_head list; 
	unsigned int always_on:1; 
	char *supply_name; 
	struct regulator_dev *rdev; 
	struct dentry *debugfs; 

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: 

struct regulator * devm_regulator_get(struct device *dev, const char *id); 

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: 

struct regulator *reg; 

reg = devm_regulator_get(&spi->dev, "vcc"); 
if (IS_ERR(reg))
	return PTR_ERR(reg); 

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: 

struct regulator *reg; 
reg = devm_regulator_get_exclusive(&spi->dev, "vcc"); 

if (IS_ERR(reg)) 
	return PTR_ERR(reg); 

What really happens is that, when requesting a regulator device, the requesting API perform the following operations: 

  1. It looks for the corresponding struct regulator_dev; let’s call it regdev. 
  2. once found, the function checks whether the requesting method is exclusive or not.  
    1. If exclusive, 
      1. it makes sure that the exclusive flag  in regdev 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. 
      2. After that, it sets regdev.exclusive flag and increases the usage counter  of regdev.
    2. If not exclusive 
      1. 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.  
      2. Then, it increases usage counter of regdev.
  3. In the last step, the requesting API generates a struct regulator structure and makes its rdev field pointing to the struct regulator_dev previously found (regdev); finally, it returns the generated struct 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: 

int regulator_enable(struct regulator *regulator); 
int regulator_disable(struct regulator *regulator); 
int regulator_force_disable(struct regulator *regulator); 

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: 

int regulator_is_enabled(struct regulator *regulator);

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:  

int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) 

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: 

int regulator_get_voltage(struct regulator *regulator); 

An example of usage is the following: 

pr_info ("Regulator Voltage = %d\n", regulator_get_voltage(reg)); 

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: 

int regulator_set_current_limit(struct regulator *regulator,
                                int min_uA, int max_uA)

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: 

int regulator_get_current_limit(struct regulator *regulator) 

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: 

int regulator_set_optimum_mode(struct regulator *regulator, int load_uA);
int regulator_set_mode(struct regulator *regulator, unsigned int mode);

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: 

unsigned int regulator_get_mode(struct regulator *regulator); 

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: 

twl_reg1: regulator@0 {

twl_reg2: regulator@1 {

mmc: mmc@0x0 {
	vmmc-supply = <&twl_reg1>; 
	vmmcaux-supply = <&twl_reg2>;

The consumer code (which is the MMC driver) that requests its supplies could look like: 

	struct regulator *main_regulator;
	struct regulator *aux_regulator;
	int ret;
	main_regulator = devm_regulator_get(dev, "vmmc");

	 * It is a good practive to apply the config before
	 * enabling the regulator
	if (!IS_ERR(io_regulator)) {
		regulator_set_voltage(main_regulator, MMC_VOLTAGE_DIGITAL,
		ret = regulator_enable(io_regulator);


	aux_regulator = devm_regulator_get(dev, "vmmcaux"); 


In the above code example, we can notice that regulators are requested using the <name> part of device tree declaration. 


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.  

Your email address will not be published.