• 了解Linux Regulator Framework

1.概述

  Regulator分为voltage regulator和current。一般PMIC(Power Management IC)中会包含一个或者多个regulator。

  通常的作用是给电子设备供电。大多数regulator可以启用(enable)和禁用(disable)其输出,同时也可以控制其输出电压(voltage)和电流(current)。

1.1.Regulator Basics

Regulates the output power from input power.

  • Voltage control – “input is 5V output is 1.8V”
  • Current limiting – “limit output current to 20mA max”
  • Simple switch – “switch output power on/off

1.2.Regulator Based Systems

  Semiconductor power consumption has two components – static and dynamic : P(Total) = P(static) + P(dynamic) .

  • Static power is leakage current.

    • Smaller than dynamic power when system is active.
    • Main power drain in system standby state.
  • Dynamic power is active current.

    • Signals switching. (e.g. clocks)
    • Analog circuits changing state (e.g. audio playback).
      • Power(dynamic) = CV2F
  • Regulators can be used to save static and dynamic power

NOTE:
  Leakage current is the current that flows through the protective ground conductor to ground. In the absence of a grounding connection, it is the current that could flow from any conductive part or the surface of non-conductive parts to ground if a conductive path was available (such as a human body). There are always extraneous currents flowing in the safety ground conductor.
  Leakage current is current that flows in a device that is thought to be in a “off” mode where ideally no current would flow.

2.Regulator cascade connection (级联)

3.Regulator 软件架构

3.1.machine 部分

  machine主要功能是使用struct regulator_init_data,静态的描述regulator在板级SoC的物理状况,包括:

  • 前级regulator(即该regulator的输出是另一个regulator的输入,简称supply regulator 和后级regulator(即该regulator的输入是其它regulator的输出,简称consumer regulator)。

  这主要用于描述regulator在板级的级联关系,需要留意的是,它和clock不同,这种级联关系是非常确定的,以至于需要使用静态的方式描述,而不是像clock那样,在注册的时候动态指定并形成。

3.1.1. Structures

struct regulator_init_data:

 177 struct regulator_init_data {178     const char *supply_regulator;        /* or NULL for system supply */179 180     struct regulation_constraints constraints;181 182     int num_consumer_supplies;183     struct regulator_consumer_supply *consumer_supplies;184 185     /* optional regulator machine specific init */186     int (*regulator_init)(void *driver_data);187     void *driver_data;  /* core does not touch this */                                                 188 };

The following are the meanings of elements in the structure:

  • constraints represents the regulator constraints
  • regulator_init is an optional callback invoked at a given moment when the core registers the regulator
  • driver_data represents the data passed to regulator_init

struct regulation_constraints:

  99 struct regulation_constraints {100 101     const char *name;102 103     /* voltage output range (inclusive) - for voltage control */104     int min_uV;105     int max_uV;106 107     int uV_offset;108 109     /* current output range (inclusive) - for current control */110     int min_uA;111     int max_uA;112 113     /* valid regulator operating modes for this machine */114     unsigned int valid_modes_mask;115 116     /* valid operations for regulator on this machine */117     unsigned int valid_ops_mask;118 119     /* regulator input voltage - only if supply is another regulator */120     int input_uV;121 122     /* regulator suspend states for global PMIC STANDBY/HIBERNATE */123     struct regulator_state state_disk;124     struct regulator_state state_mem;125     struct regulator_state state_standby;126     suspend_state_t initial_state; /* suspend state to set at init */127 128     /* mode to set on startup */129     unsigned int initial_mode;130 131     unsigned int ramp_delay;132                                                                                                        133     /* constraint flags */134     unsigned always_on:1;   /* regulator never off when system is on */135     unsigned boot_on:1; /* bootloader/firmware enabled regulator */136     unsigned apply_uV:1;    /* apply uV constraint if min == max */137 };

该regulator的物理限制(struct regulation_constraints),包括:

  • 输出电压的最大值和最小值(voltage regulator);
  • 输出电流的最大值和最小值(current regulator);
  • 允许的操作(修改电压值、修改电流限制、enable、disable等等);
  • 输入电压是多少(当输入是另一个regulator时);
  • 是否不允许关闭(always_on);
  • 是否启动时就要打开(always_on);

  这些限制关系到系统安全,因此必须小心配置。配置完成后,在系统运行的整个过程中,它们都不会再改变了。函数of_get_regulation_constraints解析device tree,填充该结构体。

3.1.2.init data structure

  There are two ways to pass regulator_init_data to a driver:

  • by platform data in the board initialization file
  • by a node in the device tree using the of_get_regulator_init_data function.

3.1.2.1.Feeding init data into a board file

  This method consists of filling an array of constraints, either from within the driver, or in the board file, and using it as part of the platform data.

  For example:

 133 static struct regulator_init_data axp_regl_init_data[] = {134     [rtcldo] = {135         .constraints = {136             .name = "rtcldo",137             .min_uV =  AXP_LDO1_MIN,138             .max_uV =  AXP_LDO1_MAX,139         },140         .num_consumer_supplies = ARRAY_SIZE(rtcldo_data),141         .consumer_supplies = rtcldo_data,142     },143     [aldo1] = {144         .constraints = {145             .name = "ALDO1",146             .min_uV = AXP_ALDO1_MIN,147             .max_uV = AXP_ALDO1_MAX,148             .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE149 #if defined (CONFIG_KP_OUTPUTINIT)150             .initial_state = PM_SUSPEND_STANDBY,151             .state_standby = {152                 .uV = AXP_ALDO1_VALUE * 1000,153                 .enabled = 1,154             }                                                                                          155 #endif

Note:
  This method is now depreciated, though it is presented here for your information. The new and recommended approach is the DT.

3.1.2.2.Feeding init data into the DT

  In order to extract init data passed from within the DT, there is a new data type that we need to introduce, struct of_regulator_match, which looks like this:

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;
};

Dtsi settings:

isl6271a@3c {compatible = "isl6271a";reg = <0x3c>;interrupts = <0 86 0x4>;/* supposing our regulator is powered by another regulator */in-v1-supply = <&some_reg>;[...]regulators {reg1: core_buck {regulator-name = "Core Buck";regulator-min-microvolt = <850000>;regulator-max-microvolt = <1600000>;};reg2: ldo1 {regulator-name = "LDO1";regulator-min-microvolt = <1100000>;regulator-max-microvolt = <1100000>;regulator-always-on;};};
};
  • 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 a 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 the regulator (in uV/uS)

Note:
  Those properties really look like fields in struct regulator_init_data.

  Using the kernel helper function of_regulator_match(), given the regulators sub-node as the parameter, the function will walk through each regulator device node and build a struct regulator_init_data structure for each of them in the driver probe function.

/*** of_regulator_match - extract multiple regulator init data from device tree.* @dev: device requesting the data* @node: parent device node of the regulators* @matches: match table for the regulators* @num_matches: number of entries in match table** This function uses a match table specified by the regulator driver to* parse regulator init data from the device tree. @node is expected to* contain a set of child nodes, each providing the init data for one* regulator. The data parsed from a child node will be matched to a regulator* based on either the deprecated property regulator-compatible if present,* or otherwise the child node's name. Note that the match table is modified* in place and an additional of_node reference is taken for each matched* regulator.

For example:

The same table can be used for multiple instance of pdev, so we don't need to
allocate memory for of_regulator_match table per pdev. Signed-off-by: Axel Lin <axe...@ingics.com>
--- drivers/regulator/as3711-regulator.c |   46 ++++++++++++++-------------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/drivers/regulator/as3711-regulator.c b/drivers/regulator/as3711-regulator.c
index 0539b3e..dd1a089 100644
--- a/drivers/regulator/as3711-regulator.c
+++ b/drivers/regulator/as3711-regulator.c
@@ -278,52 +278,44 @@ static struct as3711_regulator_info as3711_reg_info[] = { #define AS3711_REGULATOR_NUM ARRAY_SIZE(as3711_reg_info) -static const char *as3711_regulator_of_names[AS3711_REGULATOR_NUM] = {
-        [AS3711_REGULATOR_SD_1] = "sd1",
-        [AS3711_REGULATOR_SD_2] = "sd2",
-        [AS3711_REGULATOR_SD_3] = "sd3",
-        [AS3711_REGULATOR_SD_4] = "sd4",
-        [AS3711_REGULATOR_LDO_1] = "ldo1",
-        [AS3711_REGULATOR_LDO_2] = "ldo2",
-        [AS3711_REGULATOR_LDO_3] = "ldo3",
-        [AS3711_REGULATOR_LDO_4] = "ldo4",
-        [AS3711_REGULATOR_LDO_5] = "ldo5",
-        [AS3711_REGULATOR_LDO_6] = "ldo6",
-        [AS3711_REGULATOR_LDO_7] = "ldo7",
-        [AS3711_REGULATOR_LDO_8] = "ldo8",
+static struct of_regulator_match as3711_regulator_matches[] = {
+        { .name = "sd1" },
+        { .name = "sd2" },
+        { .name = "sd3" },
+        { .name = "sd4" },
+        { .name = "ldo1" },
+        { .name = "ldo2" },
+        { .name = "ldo3" },
+        { .name = "ldo4" },
+        { .name = "ldo5" },
+        { .name = "ldo6" },
+        { .name = "ldo7" },
+        { .name = "ldo8" }, }; static int as3711_regulator_parse_dt(struct device *dev, struct device_node **of_node, const int count) { struct as3711_regulator_pdata *pdata = dev_get_platdata(dev);
-        struct device_node *regulators =
-                of_find_node_by_name(dev->parent->of_node, "regulators");
-        struct of_regulator_match *matches, *match;
+        struct device_node *regulators;
+        struct of_regulator_match *match; int ret, i; +        regulators = of_find_node_by_name(dev->parent->of_node, "regulators"); if (!regulators) { dev_err(dev, "regulator node not found\n"); return -ENODEV; } -        matches = devm_kzalloc(dev, sizeof(*matches) * count, GFP_KERNEL);
-        if (!matches)
-                return -ENOMEM;
-
-        for (i = 0, match = matches; i < count; i++, match++) {
-                match->name = as3711_regulator_of_names[i];
-                match->driver_data = as3711_reg_info + i;
-        }
-
-        ret = of_regulator_match(dev->parent, regulators, matches, count);
+        ret = of_regulator_match(dev->parent, regulators,
+                                 as3711_regulator_matches, count); of_node_put(regulators); if (ret < 0) { dev_err(dev, "Error parsing regulator init data: %d\n", ret); return ret; } -        for (i = 0, match = matches; i < count; i++, match++)
+        for (i = 0, match = as3711_regulator_matches; i < count; i++, match++) if (match->of_node) { pdata->init_data[i] = match->init_data; of_node[i] = match->of_node;

3.2.Driver

  从regulator driver的角度,抽象出regulator设备,设备信息通过两个结构体进行描述,分别是struct regulator_desc和struct regulator_config。

3.2.1.Configuration structure:

1).使用struct regulator_desc,描述regulator的静态信息,包括:名字、supply regulator的名字、中断号、操作函数集(struct regulator_ops)、使用regmap时相应的寄存器即bitmap等等。

//struct regulator_desc - Static regulator descriptor
210 struct regulator_desc {211     const char *name;212     const char *supply_name;213     int id;214     bool continuous_voltage_range;215     unsigned n_voltages;216     struct regulator_ops *ops;217     int irq;218     enum regulator_type type;219     struct module *owner;220 221     unsigned int min_uV;222     unsigned int uV_step;223     unsigned int linear_min_sel;224     unsigned int ramp_delay;225 226     const unsigned int *volt_table;227     ...                                                                        239 };

2).使用struct regulator_config,描述regulator的动态信息(所谓的动态信息,体现在struct regulator_config变量都是局部变量,因此不会永久保存),包括struct regulator_init_data指针、设备指针、enable gpio等等。

 struct regulator_config - Dynamic regulator descriptor  259 struct regulator_config {260     struct device *dev;261     const struct regulator_init_data *init_data;262     void *driver_data;263     struct device_node *of_node;264     struct regmap *regmap;265 266     int ena_gpio;267     unsigned int ena_gpio_invert:1;268     unsigned int ena_gpio_flags;                                                                       269 };
  • dev represents the struct device structure the regulator belongs to.
  • init_data is the most important field of the structure, since it contains an element holding the regulator constraints (a machine specific structure).
  • driver_data holds the regulator’s private data.
  • 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.

3.2.2.Device operation structure:

  The struct regulator_ops structure is a list of callbacks representing all operations a regulator can perform.

  98 struct regulator_ops {99 100     /* enumerate supported voltages */                                                                 101     int (*list_voltage) (struct regulator_dev *, unsigned selector);102 103     /* get/set regulator voltage */104     int (*set_voltage) (struct regulator_dev *, int min_uV, int max_uV,105                 unsigned *selector);106     int (*map_voltage)(struct regulator_dev *, int min_uV, int max_uV);107     int (*set_voltage_sel) (struct regulator_dev *, unsigned selector);108     int (*get_voltage) (struct regulator_dev *);109     int (*get_voltage_sel) (struct regulator_dev *);110 111     /* get/set regulator current  */112     int (*set_current_limit) (struct regulator_dev *,113                  int min_uA, int max_uA);114     int (*get_current_limit) (struct regulator_dev *);116     /* enable/disable regulator */117     int (*enable) (struct regulator_dev *);118     int (*disable) (struct regulator_dev *);131        ...132  }

3.2.3.Register regulator

  调用注册接口regulator_register/devm_regulator_register进行注册regulator,该接口的两个参数是:struct regulator_desc和struct regulator_config;最终分配一个新的数据结构struct regulator_dev(从设备的角度描述regulator),并把静态指针(struct regulator_desc)和动态指针(struct regulator_config)提供的信息保存在其中。

 281 struct regulator_dev {282     const struct regulator_desc *desc;283     int exclusive;284     u32 use_count;285     u32 open_count;286     u32 bypass_count;287 288     /* lists we belong to */289     struct list_head list; /* list of all regulators */290 291     /* lists we own */292     struct list_head consumer_list; /* consumers we supply */293 294     struct blocking_notifier_head notifier;295     struct mutex mutex; /* consumer lock */296     struct module *owner;                                                                              297     struct device dev;298     struct regulation_constraints *constraints;299     struct regulator *supply;   /* for tree */300     struct regmap *regmap;301 }

  struct regulator_dev是regulator设备的抽象,当driver以struct regulator_desc、struct regulator_config两个类型的参数,调用regulator_register将regulator注册到kernel之后,regulator就会分配一个struct regulator_dev变量,后续所有的regulator操作,都将以该变量为对象。

3.3.consumer

  从regulator consumer的角度,抽象regulator设备(struct regulator),并提供regulator操作相关的接口,接口位于“include/linux/regulator/consumer.h”中。

3.3.1. struct regulator

  The consumer interface only requires the driver to include one header:

#include <linux/regulator/consumer.h>

  consumer can be static or dynamic. A static one requires only a fixed supply, whereas a dynamic one requires active management of the regulator at runtime. From the consumer point side, a regulator device is represented in the kernel as an instance of a struct regulator structure.

  39 struct regulator {40     struct device *dev;41     struct list_head list;42     unsigned int always_on:1;43     unsigned int bypass:1;44     int uA_load;45     struct regulator_voltage voltage[REGULATOR_STATES_NUM];46     const char *supply_name;47     struct device_attribute dev_attr;                                                                  48     struct regulator_dev *rdev;49     struct dentry *debugfs;50 };

3.3.2.Regulators consumer interface

1).获取regulator/释放regulator

   1: struct regulator *__must_check regulator_get(struct device *dev,2:                                              const char *id);3: struct regulator *__must_check devm_regulator_get(struct device *dev,4:                                              const char *id);5: struct regulator *__must_check regulator_get_exclusive(struct device *dev,6:                                                        const char *id);7: struct regulator *__must_check devm_regulator_get_exclusive(struct device *dev,8:                                                         const char *id);9: struct regulator *__must_check regulator_get_optional(struct device *dev,10:                                                       const char *id);11: struct regulator *__must_check devm_regulator_get_optional(struct device *dev,12:                                                            const char *id);13: void regulator_put(struct regulator *regulator);14: void devm_regulator_put(struct regulator *regulator);

  如上所示,根据是否独占regulator、是否可以多次get regulator,regulator get接口分为三类:

  107 enum regulator_get_type {                                                                              108     NORMAL_GET,  109     EXCLUSIVE_GET,110     OPTIONAL_GET,111     MAX_GET_TYPE112 };
  • 正常的get,非独占、可以重复get

    • regulator_get/devm_regulator_get;
  • 独占性质的get,独占、不可get
    • regulator_get_exclusive/devm_regulator_get_exclusive;
  • optional的get,非独占、不可重复get
    • regulator_get_optional/devm_regulator_get_optional。

EXCLUSIVE_GET:

   consumers require complete control of the regulator and can’t tolerate sharing it with other consumers, most commonly because they need to have the regulator actually disabled so can’t have other consumers forcing it on. This new regulator_get_exclusive() API call allows these consumers to explicitly request this, documenting the assumptions that they are making.

Example of how a consumer acquires a regulator:

struct regulator *reg;
const char *supply = "vdd1";
int min_uV, max_uV;
reg = regulator_get(dev, supply);tor *regulator);

2).supply alias interface

   1: int regulator_register_supply_alias(struct device *dev, const char *id,2:                                     struct device *alias_dev,3:                                     const char *alias_id);4: void regulator_unregister_supply_alias(struct device *dev, const char *id);5:  6: int devm_regulator_register_supply_alias(struct device *dev, const char *id,7:                                          struct device *alias_dev,8:                                          const char *alias_id);9: void devm_regulator_unregister_supply_alias(struct device *dev,10:                                             const char *id);11:  12: int devm_regulator_bulk_register_supply_alias(struct device *dev,13:                                               const char *const *id,14:                                               struct device *alias_dev,15:                                               const char *const *alias_id,16:                                               int num_id);17: void devm_regulator_bulk_unregister_supply_alias(struct device *dev,18:                                                  const char *const *id,19:                                                  int num_id);

3).Enable and disable

   1: int __must_check regulator_enable(struct regulator *regulator);2: int regulator_disable(struct regulator *regulator);//To check whether a regulator is already enabled or not3: int regulator_is_enabled(struct regulator *regulator);//For a shared regulator, regulator_disable() will actually disable the regulator onlywhen the enabled reference count is zero. That said, you can force disabling incase of an emergency4: int regulator_force_disable(struct regulator *regulator);

4).设置regulator的电压,获得regulator的电压状态

   9: int regulator_list_voltage(struct regulator *regulator, unsigned selector);//min_uV and max_uV are the minimum and maximum acceptable voltages in microvolts13: int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV);14: int regulator_set_voltage_time(struct regulator *regulator, int old_uV, int new_uV);16: int regulator_get_voltage(struct regulator *regulator);

5).设置regulator的电流,获得regulator的电流状态

  18: int regulator_set_current_limit(struct regulator *regulator,int min_uA, int max_uA);19: int regulator_get_current_limit(struct regulator *regulator);

6).regulator的模式设置,间接(通过负载),直接设置

  22: int regulator_set_mode(struct regulator *regulator, unsigned int mode);23: unsigned int regulator_get_mode(struct regulator *regulator);24: int regulator_set_optimum_mode(struct regulator *regulator, int load_uA);

Note:
  Consumers should use regulator_set_mode() on a regulator only when it knows about the regulator and does not share the regulator with other consumers. This is known as direct mode. regulator_set_uptimum_mode() causes the core to undertake some background work in order to determine what operating mode is best for the requested current. This is called the indirect mode.

7).bulk型的操作(一次操作多个regulator)

   1: int regulator_bulk_register_supply_alias(struct device *dev,2:                                          const char *const *id,3:                                          struct device *alias_dev,4:                                          const char *const *alias_id,5:                                          int num_id);6: void regulator_bulk_unregister_supply_alias(struct device *dev,7:                                             const char * const *id, int num_id);8: int __must_check regulator_bulk_get(struct device *dev, int num_consumers,9:                                     struct regulator_bulk_data *consumers);10: int __must_check devm_regulator_bulk_get(struct device *dev, int num_consumers,11:                                          struct regulator_bulk_data *consumers);12: int __must_check regulator_bulk_enable(int num_consumers,13:                                        struct regulator_bulk_data *consumers);14: int regulator_bulk_disable(int num_consumers,15:                            struct regulator_bulk_data *consumers);16: int regulator_bulk_force_disable(int num_consumers,17:                            struct regulator_bulk_data *consumers);18: void regulator_bulk_free(int num_consumers,19:                          struct regulator_bulk_data *consumers);

8).notifier相关的接口

   1: int regulator_register_notifier(struct regulator *regulator,2:                               struct notifier_block *nb);3: int regulator_unregister_notifier(struct regulator *regulator,4:                                 struct notifier_block *nb);

3.3.3. 向用户空间consumer提供接口

  用户空间程序通过sysfs接口,可以使用regulator。由“drivers/regulator/userspace-consumer.c”实现该功能,主要包括:

  • sysfs目录:/sys/devices/platform/reg-userspace-consumer;
  • name,获取该regulator的名字。
  • state,获取该regulator的状态(enabled/disabled);写入可以改变regulator的状态(enabled或者1使能,disabled或者0禁止)。

4.core

  core负责上述逻辑的具体实现,并以sysfs的形式,向用户空间提供接口。

4.1.regulator core的初始化

  regulator core的初始化操作由regulator_init接口负责,主要工作包括:

  • 注册regulator class(/sys/class/regulator/);

  • 注册用于调试的debugfs。

  regulator framework也是一种class,称作regulator class。

4.2 regulator register

  regulator的注册,由regulator_register/devm_regulator_register接口负责。

4.3 regulator的操作模式(operation mode)

  regulator的主要功能,是输出电压/电流的调整(或改变)。由于模拟器件的特性,电压/电流的改变,是需要一定的时间的。对有些regulator而言,可以工作在不同的模式,这些模式有不同的改变速度,较快的速度,有较大的功耗。模式如下所示:

include/linux/regulator/consumer.h:1: /*2:  * Regulator operating modes.3:  *4:  * Regulators can run in a variety of different operating modes depending on5:  * output load. This allows further system power savings by selecting the6:  * best (and most efficient) regulator mode for a desired load.7:  *8:  * Most drivers will only care about NORMAL. The modes below are generic and9:  * will probably not match the naming convention of your regulator data sheet10:  * but should match the use cases in the datasheet.11:  *12:  * In order of power efficiency (least efficient at top).13:  *14:  *  Mode       Description15:  *  FAST       Regulator can handle fast changes in it's load.16:  *             e.g. useful in CPU voltage & frequency scaling where17:  *             load can quickly increase with CPU frequency increases.18:  *19:  *  NORMAL     Normal regulator power supply mode. Most drivers will20:  *             use this mode.21:  *22:  *  IDLE       Regulator runs in a more efficient mode for light23:  *             loads. Can be used for devices that have a low power24:  *             requirement during periods of inactivity. This mode25:  *             may be more noisy than NORMAL and may not be able26:  *             to handle fast load switching.27:  *28:  *  STANDBY    Regulator runs in the most efficient mode for very29:  *             light loads. Can be used by devices when they are30:  *             in a sleep/standby state. This mode is likely to be31:  *             the most noisy and may not be able to handle fast load32:  *             switching.33:  *34:  * NOTE: Most regulators will only support a subset of these modes. Some35:  * will only just support NORMAL.36:  *37:  * These modes can be OR'ed together to make up a mask of valid register modes.38:  */39:  40: #define REGULATOR_MODE_FAST                     0x141: #define REGULATOR_MODE_NORMAL                   0x242: #define REGULATOR_MODE_IDLE                     0x443: #define REGULATOR_MODE_STANDBY                  0x8

  相应regulator framework提供了一些机制,用于operation mode的操作,包括:

  • struct regulation_constraints中用于表示初始模式的字段initial_mode。
  • regulator ops中的set_mode/get_mode回调函数。

4.4.电压操作两种方式

  kernel抽象出两种电压操作的方法:

  • 直接操作电压,对应struct regulator_ops中的如下回调函数:
  1: /* get/set regulator voltage */2: int (*list_voltage) (struct regulator_dev *, unsigned selector);3: int (*set_voltage) (struct regulator_dev *, int min_uV, int max_uV, unsigned *selector);4: int (*get_voltage) (struct regulator_dev *);
  • set_voltage用于将电压设置为min_uV和max_uV范围内、和min_uV最接近的电压。该接口可以返回一个selector参数,用于告知调用者,实际的电压值;

  • get_voltage,用于返回当前的电压值;

  • list_voltage,以selector为参数,获取对应的电压值。

  • selector的形式

  regulator driver以selector的形式,反映电压值。selector是一个从0开始的整数,driver提供如下的接口:

   1: /* enumerate supported voltages */2: int (*list_voltage) (struct regulator_dev *, unsigned selector);3:  4: int (*map_voltage)(struct regulator_dev *, int min_uV, int max_uV);5: int (*set_voltage_sel) (struct regulator_dev *, unsigned selector);6: int (*get_voltage_sel) (struct regulator_dev *);
  • list_voltage,如上;
  • map_voltage,是和list_voltage相对的接口,用于将电压范围map成一个selector值;
  • set_voltage_sel/get_voltage_sel,以selector的形式,操作电压。

Note:
  regulator driver可以根据实际情况,选择一种实现方式。

5.5.sysfs接口

  regulator framework通过sysfs提供多种attribute,它们位于/sys/class/regulator/…/目录下,可参考:

[root@xxx ]# cd /sys/class/regulator/
[root@xxx regulator]#ls
regulator.0   regulator.11  regulator.3   regulator.6   regulator.9
regulator.1   regulator.12  regulator.4   regulator.7
regulator.10  regulator.2   regulator.5   regulator.8

其他调试接口如下:

cd /sys/kernel/debug/regulator
[root@xxx regulator]# ls
ALDO1                      ELDO1
ALDO2                      ELDO2
ALDO3                      GPIO_LDO1
DCDC1                      LDORTC
DCDC2                      reg-dummy-regulator-dummy
DCDC3                      regulator_summary
DCDC4                      supply_map
DCDC5[root@xxx ALDO1]# ls
bypass_count  open_count    use_count

supply_map :

[root@xxx regulator]# cat supply_map
GPIO_LDO1 -> 1-0034.gpio_ldo1
DCDC5 -> 1-0034.dcdc5
DCDC4 -> 1-0034.dcdc4
DCDC3 -> 1-0034.dcdc3
DCDC2 -> 1-0034.dcdc2
DCDC1 -> 1-0034.dcdc1
ELDO2 -> 1-0034.eldo2
ELDO1 -> 1-0034.eldo1
ALDO3 -> 1-0034.aldo3
ALDO2 -> 1-0034.aldo2
ALDO1 -> 1-0034.aldo1
LDORTC -> 1-0034.ldortc

regulator_summary :

[root@xxx regulator]# cat regulator_summary regulator                      use open bypass voltage current     min     max
-------------------------------------------------------------------------------regulator-dummy                  0    9      0     0mV     0mA     0mV     0mV d4018000.serial                                                 0mV     0mVd4018000.serial                                                 0mV     0mVd4018000.serial                                                 0mV     0mVd4017800.serial                                                 0mV     0mVd4017800.serial                                                 0mV     0mVd4017800.serial                                                 0mV     0mVd4017000.serial                                                 0mV     0mVd4017000.serial                                                 0mV     0mVd4017000.serial                                                 0mV     0mVLDORTC                           0    0      0  3000mV     0mA  3000mV  3000mV ALDO1                            0    0      0  1000mV     0mA   700mV  3300mV ALDO2                            0    0      0   900mV     0mA   700mV  3300mV ALDO3                            0    0      0  3000mV     0mA   700mV  3300mV ELDO1                            0    0      0  2000mV     0mA   700mV  3300mV ELDO2                            0    0      0  3000mV     0mA   700mV  3300mV DCDC1                            0    0      0  3300mV     0mA  1600mV  3400mV DCDC2                            0    0      0  1000mV     0mA   600mV  1540mV DCDC3                            0    0      0  1000mV     0mA   600mV  1860mV DCDC4                            0    0      0  2400mV     0mA   600mV  1540mV DCDC5                            0    0      0  1200mV     0mA  1000mV  2550mV GPIO_LDO1                        0    0      0  3800mV     0mA   700mV  3300mV
cd /sys/devices/platform/d4010c00.i2c/i2c-1/1-0034
[root@xxx 1-0034]# ls
axp216-charger.12    axp216-regulator.7   axp_pekopen
axp216-regulator.0   axp216-regulator.8   axp_reg
axp216-regulator.1   axp216-regulator.9   axp_regs
axp216-regulator.10  axp_noedelay         driver
axp216-regulator.11  axp_offvol           megahunt_i2c
axp216-regulator.2   axp_ovtemclsen       modalias
axp216-regulator.3   axp_pekclose         name
axp216-regulator.4   axp_pekdelay         power
axp216-regulator.5   axp_peken            subsystem
axp216-regulator.6   axp_peklong          uevent

如果使用sysfs_create_group创建sysfs节点,则节点位于:

  • /sys/devices/platform/d4010c00.i2c/i2c-1/1-0034/axp216-regulator.7/workmode

refer to

  • drivers/regulator/core.c
  • Documentation/devicetree/bindings/regulator/regulator.txt
  • Documentation/ABI/testing/sysfs-class-regulator
  • linux-device-drivers-development.pdf

Linux Regulator Framework(1) - Framework相关推荐

  1. linux卸载veil,Kali Linux中的VEIL Framework绕过防病毒软件实验

    原标题:Kali Linux中的VEIL Framework绕过防病毒软件实验 在进行渗透测试的过程中,绕过反病毒产品一直是一个"令人头疼"的事情.今天,我们将跟大家如何绕过目前市 ...

  2. 更新xcode至12.3,编译报错Building for iOS, but the linked and embedded framework ‘xxx.framework’ was buil...

    更新xcode至12.3,编译报错Building for iOS, but the linked and embedded framework 'xxx.framework' was buil... ...

  3. iOS-Building for iOS Simulator, but the linked and embedded framework ‘XX.framework‘ was built for

    一.报错 运行一个以前的项目报错如下: /Users/XX/Desktop/XX.xcodeproj Building for iOS Simulator, but the linked and em ...

  4. 报错 Building for iOS, but the embedded framework ‘xxx.framework‘ was built for iOS + iOS Simulator

    1.问题描述 我在Xcode13.4上面运行一个集成了.a文件的工程之后报错,上一周还是好好的,突然就不行了,不知道咋回事 报错信息如下: Building for iOS, but the embe ...

  5. 【Linux kernel/cpufreq】framework ----初识

    CMOS电路中分为动态功耗和静态功耗,公式为 power=Σ(CV²αf + VI). C 代表负载电容的容值,V 是工作电压,α 是当前频率下的翻转率,f为工作频率,I代表静态电流.公式中加号前面部 ...

  6. 【Linux kernel/cpufreq】framework ----cpufreq core

    cpufreq framework提供机制(cpufreq driver)与策略(cpufreq governor),此外提供了cpufreq core来对机制和策略进行管理. 主要代码路径: dri ...

  7. 【Linux kernel/cpufreq】framework ----big Little driver

    Linux kernel支持ARM big·Lttile框架的解决方案 一般ARM SOC包含能效和性能两个cluster,共8个 core,可以把这8个core统统开放给kernel,让kernel ...

  8. 进程 Android架构  Android Runtime  Libraries framework简介 Framework的范围 framework简介范围基础 Linux入门介绍

    目录 FrameWork框架之进程 Android简介 Android架构 Android Runtime Libraries framework简介

  9. Kali Linux中的VEIL Framework绕过防病毒软件实验

    在进行渗透测试的过程中,绕过反病毒产品一直是一个"令人头疼"的事情.今天,我们将跟大家如何绕过目前市面上大部分的免费反病毒产品. 由于很多新手用户喜欢使用AVAST或AVG这样的轻 ...

  10. zend framework mysql_Zend Framework连接Mysql数据库实例分析

    这篇文章主要介绍了Zend Framework连接Mysql数据库的方法,以完整实例形式分析了Zend Framework连接MySQL数据库的具体步骤与相关实现技巧,需要的朋友可以参考下 本文实例讲 ...

最新文章

  1. 读《大规模敏捷开发实践》
  2. Spring原理简述
  3. 缓冲区 cin() getline() getchar()
  4. html5访问本地资源,HTML5实现一个访问本地文件的实例今
  5. flash builder4.7 for Mac升级AIRSDK详解
  6. FusionCharts-堆栈图、xml格式、刷新数据、添加事件link、传参
  7. vm14远程连接服务器,VisualVM 远程连接服务器
  8. SAP计划策略40测试
  9. Spring-01-HelloWorld
  10. 黑盒测试——边界值分析
  11. 基于51单片机的gps定位系统
  12. php 禁止抓取,禁止抓取.php的写法哪个对:Disallow: /*.php$和Disallow: /.php$ - 搜外SEO问答...
  13. VMware虚拟机无法连接外网怎么解决
  14. 显示单月的日历c语言编程,显示单月的日历的C程序
  15. Python 位置名称通过高德API获取行政区划信息ByMySQL
  16. 轻量级Linux系统Ubuntu20.04安装(win11下)
  17. Zookeeper到底是AP还是CP?
  18. 百度地图api不支持windows平板 双指放大缩小解决方案
  19. Gearbox变速器
  20. 最大报销额java_何为字节码?采用字节码的最大好处是什么?_学小易找答案

热门文章

  1. go html桌面,用 Go 开发桌面应用程序(GUI):Webview、Lorca 与 Electron
  2. 三种设计满足需求 网吧网络解决方案(转)
  3. solr和elasticsearch
  4. 【历史上的今天】2 月 23 日:英格玛密码机申请专利;戴尔电脑创始人出生;Mellanox 收购 EZchip
  5. 营业执照如何完整的转为Word格式?
  6. java大作穿越arpg_动作与角色扮演完美结合 精品ARPG游戏盘点
  7. 计算机命令清除所有,电脑深度清理命令设置方法
  8. 安装Microsoft Visual Studio 2010 Service Pack 1 ,系统无法找到指定的对象
  9. es - elasticsearch mapping - parameters - norms
  10. nest 模拟器_如何将Nest Thermostat用作运动探测器