Linux Regulator Framework(2)_regulator driver

作者:wowo 发布于:2015-4-16 22:18 分类:电源管理子系统

1. 前言

本文从regulator driver的角度,描述怎样基于regulator framework编写regulator驱动。同时,以此为契机,学习、理解regulator有关的物理特性,以便能够更好的使用它们。

2. regulator driver的实现步骤

2.1 确定系统中regulator有关的硬件组成

提起硬件,最好能有个例子,好在有device tree,一个活生生的硬件拓扑结构。这里以NVIDIA Tegra Dalmore A04开发板为例(regulator有关的device tree位于“arch\arm\boot\dts\tegra114-dalmore.dts”):

regulator hardware block这里的regulator结构是相当复杂的,其中彩色框代表最终的regulator抽象,它的前一级表示regulator的载体(可以是PMIC、CPU、等等)。下面将会详细说明:

a)CPU通过I2C controller,连接一个降压控制器(TI tps51632),该控制器输出名称为“vdd-cpu”的电压,就称作vdd-cpu regulator吧(因此,在kernel中,regulator是一个虚拟设备)。

b)CPU通过I2C controller,连接一个前端电源管理芯片(TI tps65090),该芯片除了具备充电管理功能外,内置了多个regulator,例如dcdc1、dcdc2等等。

c)CPU通过I2C controller,连接另一个电源管理芯片(TI tps65913),该芯片具有两个功能:GPIO输出和PMIC。PMIC内置了多个regulator,如vddio-ddr、vdd-core等等。

d)CPU内部也集成了一些regulator,如vdd_ac_bat等等。

注1:单纯从硬件的角度看,是不存在图中"regulators“、PMIC等实体的,它们的出现,已经包含了软件设计的思路。之所以画在这里,是方便后面的描述。

2.2 使用DTS,将硬件拓扑呈现出来

我们都知道,DTS的功能是描述设备的拓扑结构,并在系统初始化的时候,为被描述的设备创建并注册对应的platform device,最终和相应的platform driver相遇,执行其probe接口,实现设备的枚举功能。但是,在这些基本原则之外,还需要一些更深的思考:

DTS节点(node)怎么和设备对应?是以设备的“物理界限”为单位,还是以设备的“功能”为单位?

是不是所有的“设备”都应该在kernel中创建一个platform device?如果不是,创建的依据是什么?

这些思考在本文的例子(NVIDIA Tegra Dalmore A04的regulator)中体现尤为突出,它的本质是软件设计中的模块划分,从而决定了regulator在DTS中的呈现方式和层次。

1)tps51632

tps51632是一个简单的器件,位于i2c总线下面,包含一个regulator器件,因此其DTS比较简单,如下:

   1: /* arch\arm\boot\dts\tegra114-dalmore.dts */
   2: i2c@7000d000 {
   3:         status = "okay";
   4:         clock-frequency = <400000>;
   5:  
   6:         tps51632@43 {
   7:                 compatible = "ti,tps51632";
   8:                 reg = <0x43>;
   9:                 regulator-name = "vdd-cpu";
  10:                 regulator-min-microvolt = <500000>;
  11:                 regulator-max-microvolt = <1520000>;
  12:                 regulator-boot-on;
  13:                 regulator-always-on;
  14:         };
  15:         ...
  16: }

i2c控制器的node为“i2c@7000d000”,tps51632是其下的一个子node,名称为“tps51632@43”,compatible为“ti,tps51632”。tps51632下面以“regulator-”为前缀的字段,是regulator特有的字段,后面会统一介绍。

注2:为什么“i2c@7000d000”中没有compatible字段?其实是有的,可参考“arch\arm\boot\dts\tegra114.dtsi”,DTC在编译DTS时,会将这两个文件中的node合并。

注3:kernel在初始化时,只会为二级node(即“/”下面的节点,本文的例子是“i2c@7000d000”)创建platform设备,至于三级node(这里的“tps51632@43”),则由其bus(i2c)创建。后面我们会遇到其它的情况,到时再介绍。

2)tps65090

tps65090相对比较复杂,它位于相同的i2c总线下面,但包含两个相对复杂的功能实体,charger和PMIC,我们看看其DTS怎么写的:

   1: i2c@7000d000 {
   2:         status = "okay";
   3:         ...
   4:  
   5:         tps65090@48 {
   6:                 compatible = "ti,tps65090";
   7:                 reg = <0x48>;
   8:                 ...
   9:  
  10:                 charger: charger {
  11:                         compatible = "ti,tps65090-charger";
  12:                         ti,enable-low-current-chrg;
  13:                 };
  14:                 
  15:                 regulators {
  16:                         tps65090_dcdc1_reg: dcdc1 {
  17:                                 regulator-name = "vdd-sys-5v0";
  18:                                 regulator-always-on;
  19:                                 regulator-boot-on;
  20:                         };
  21:                 
  22:                         tps65090_dcdc2_reg: dcdc2 {
  23:                                 regulator-name = "vdd-sys-3v3";
  24:                                 regulator-always-on;
  25:                                 regulator-boot-on;
  26:                         };
  27:                         ...
  28:                 }
  29:         }
  30: }

和tps51632类似,但它下面又包含了两个子node:charger和regulators。其中charger竟然还有compatible字段。

回忆一下上面“注3”,kernel只会为"i2c@7000d000”创建platform device,“tps65090@48”则由i2c core创建,那么它下面的子node呢?一定是tps65090 driver处理了,感兴趣的读者可以阅读“drivers/mfd/tps65090.c”、“drivers/power/tps65090-charger.c”和“drivers/regulator/tps65090-regulator.c”,这里面还涉及了MFD(multi-function device,多功能设备),很有意思。

回到本文的主题上,虽然这里的regulators没有compatible字段,也会创建相应的platform device(具体可参考“drivers/mfd/tps65090.c”),这从侧面回答了上面的一个思考:从物理范畴,tps65090是一个独立的设备,但它内部有两个功能模块,因此会存在两个platform device

再来看regulators中子node----regulator,由于数量比较多,就没必要创建platform device了。同样,“regulator-”为前缀的字段,是regulator特有的字段,后面统一介绍。

3)tps65913,和tps65090类似,不再介绍。

4)CPU中的regulator

这一类regulator比较特殊,直接集成在CPU内部,DTS如下:

   1: regulators {
   2:         compatible = "simple-bus";
   3:         #address-cells = <1>;
   4:         #size-cells = <0>;
   5:  
   6:         vdd_ac_bat_reg: regulator@0 {
   7:                 compatible = "regulator-fixed";
   8:                 reg = <0>;
   9:                 regulator-name = "vdd_ac_bat";
  10:                 regulator-min-microvolt = <5000000>;
  11:                 regulator-max-microvolt = <5000000>;
  12:                 regulator-always-on;
  13:         };
  14:  
  15:         dvdd_ts_reg: regulator@1 {
  16:                 compatible = "regulator-fixed";
  17:                 reg = <1>;
  18:                 regulator-name = "dvdd_ts";
  19:                 regulator-min-microvolt = <1800000>;
  20:                 regulator-max-microvolt = <1800000>;
  21:                 enable-active-high;
  22:                 gpio = <&gpio TEGRA_GPIO(H, 5) GPIO_ACTIVE_HIGH>;
  23:         };
  24:         ...
  25: };

在回到刚才的话题上,kernel只为二级node创建platform device(这里的“regulators”),那三级node(一个个的regulator)呢?没有相对标准的bus帮它们创建怎么办?借助“simple-bus”,具体可以参考of_platform_bus_create(“Device Tree(三):代码分析”)。

另外,这里的例子比较简单,都是fixed regulator,regulator framework core可以帮忙实现fixed类型的regulator的驱动,后面会说明。

2.3 编写与DTS节点对应的driver

这些driver的存在形式是多种多样的,但所做的工作基本类似:

1)初始化regulator的宿主(如上面的tps5163、PMIC、等等),最终的目的是,通过宿主提供的接口,修改regulator的输出。

2)初始化用于描述regulator的静态信息(struct regulator_desc)和动态信息(struct regulator_config),并以这二者为参数,调用regulator_register接口,将regulator注册到kernel中。

3)静态信息中包含regulator的操作函数集(struct regulator_ops),后续regulator的控制,将会由regulator framework core直接调用这些回调函数完成。

4)后面的事情,例如sysfs attribute创建等,就交给regulator framework core了。

3. DTS相关的实现逻辑

3.1 DTS的内容

回忆一下“Linux Regulator Framework(1)_概述”中介绍的machine的主要功能:使用软件语言(struct regulator_init_data),静态的描述regulator在板级的物理现状。对regulator driver而言,DTS主要用于配置regulator的init data。先看一下struct regulator_init_data:

   1: /**
   2:  * struct regulator_init_data - regulator platform initialisation data.
   3:  *
   4:  * Initialisation constraints, our supply and consumers supplies.
   5:  *
   6:  * @supply_regulator: Parent regulator.  Specified using the regulator name
   7:  *                    as it appears in the name field in sysfs, which can
   8:  *                    be explicitly set using the constraints field 'name'.
   9:  *
  10:  * @constraints: Constraints.  These must be specified for the regulator to
  11:  *               be usable.
  12:  * @num_consumer_supplies: Number of consumer device supplies.
  13:  * @consumer_supplies: Consumer device supply configuration.
  14:  *
  15:  * @regulator_init: Callback invoked when the regulator has been registered.
  16:  * @driver_data: Data passed to regulator_init.
  17:  */
  18: struct regulator_init_data {
  19:         const char *supply_regulator;        /* or NULL for system supply */
  20:  
  21:         struct regulation_constraints constraints;
  22:  
  23:         int num_consumer_supplies;
  24:         struct regulator_consumer_supply *consumer_supplies;
  25:  
  26:         /* optional regulator machine specific init */
  27:         int (*regulator_init)(void *driver_data);
  28:         void *driver_data;      /* core does not touch this */
  29: };

supply_regulator,该regulator的前级regulator,一般在regulator driver中直接指定;

constraints,该regulator的使用限制,由DTS配置,并可以借助regulator core提供的辅助API(regulator_of_get_init_data)自动解析。后面会详细介绍;

num_consumer_supplies、consumer_supplies,使用该regulator的consumer的个数,及其设备名和supply名的map。用于建立consumer设备和regulator之间的关联,后面介绍consumer DTS时再详细说明;

regulator_init,regulator的init回调,由regulator driver提供,并在regulator注册时调用;

driver_data,保存driver的私有数据,并在调用regulator_init时传入。

看来DTS的内容都在struct regulation_constraints中,该结构保存了该regulator所有的物理限制,如下:

   1: struct regulation_constraints {
   2:  
   3:         const char *name;
   4:  
   5:         /* voltage output range (inclusive) - for voltage control */
   6:         int min_uV;
   7:         int max_uV;
   8:  
   9:         int uV_offset;
  10:  
  11:         /* current output range (inclusive) - for current control */
  12:         int min_uA;
  13:         int max_uA;
  14:  
  15:         /* valid regulator operating modes for this machine */
  16:         unsigned int valid_modes_mask;
  17:  
  18:         /* valid operations for regulator on this machine */
  19:         unsigned int valid_ops_mask;
  20:  
  21:         /* regulator input voltage - only if supply is another regulator */
  22:         int input_uV;
  23:  
  24:         /* regulator suspend states for global PMIC STANDBY/HIBERNATE */
  25:         struct regulator_state state_disk;
  26:         struct regulator_state state_mem;
  27:         struct regulator_state state_standby;
  28:         suspend_state_t initial_state; /* suspend state to set at init */
  29:  
  30:         /* mode to set on startup */
  31:         unsigned int initial_mode;
  32:  
  33:         unsigned int ramp_delay;
  34:         unsigned int enable_time;
  35:  
  36:         /* constraint flags */
  37:         unsigned always_on:1;   /* regulator never off when system is on */
  38:         unsigned boot_on:1;     /* bootloader/firmware enabled regulator */
  39:         unsigned apply_uV:1;    /* apply uV constraint if min == max */
  40:         unsigned ramp_disable:1; /* disable ramp delay */
  41: };

name,用于描述该constraints;

min_uV、max_uV,输出电压的范围,[min_uV, max_uV],单位为uV。只对voltage regulator有效;

uV_offset,consumer看到的电压和实际电压之间的偏移值。通常用于补偿压降。只对voltage regulator有效;

min_uA、max_uA,输出电流的范围,[min_uA, max_uA],单位为uA。只对current regulator有效;

valid_modes_mask,regulator mode相关的内容,和DTS无关,后面再解释;

valid_ops_mask,该regulator支持哪些操作,以bit mask的形式提供,包括:
        REGULATOR_CHANGE_VOLTAGE,可以改变输出电压;
        REGULATOR_CHANGE_CURRENT,可以改变输出电流;
        REGULATOR_CHANGE_MODE,可以修改mode,后面再介绍;
        REGULATOR_CHANGE_STATUS,可以enable/disable;
        REGULATOR_CHANGE_DRMS,支持Dynamic Regulator Mode Switching(DRMS),可以动态的调整regulator的mode,有关mode描述可参考5.3章节;
        REGULATOR_CHANGE_BYPASS,支持bypass模式。

input_uV,如果该regulator的输入是另一个regulator,该字段指定regulator期望的输入电压;

state_xxx、initial_state,regulator电源管理有关的字段,后面会专门介绍;

initial_mode,初始mode,具体请参考5.3节的介绍;

always_on,是否一直保持使能状态;

boot_on,是否在启动时使能;

rapm_delay,由于模拟器件的特性,电压改变,需要一定的生效时间。在一定的范围内,生效时间和电压的变化值成比例。该变量就是描述regulator器件的这个特性,单位为uV/us,即1us可以产生多大的电压变化。在rapm_disable不为1的情况下,当consumer要求改变电压时,regulator framework core会根据该变量,以及电压改变量,计算出需要等待的时间,进行延时操作;

rapm_disable,是否禁止延时操作;

enable time,regulator的开启时间,单位为us。consumer enable regulator时,regulator framework会根据该变量进行延时操作;

apply_uV,如果min_uV和max_uV相同,该变量指示“在regulator注册到kernel时,是否将电压设置为min_uV/max_uV。

结合struct regulation_constraints结构,我们解释一下2.2小节中tps51632的DTS:

   1: tps51632@43 {
   2:         compatible = "ti,tps51632";
   3:         reg = <0x43>;
   4:         regulator-name = "vdd-cpu";
   5:         regulator-min-microvolt = <500000>;
   6:         regulator-max-microvolt = <1520000>;
   7:         regulator-boot-on;
   8:         regulator-always-on;
   9: };

regulator-name,对应struct regulation_constraints中name;

regulator-min-microvolt,对应struct regulation_constraints中的min_uV;

regulator-max-microvolt,对应struct regulation_constraints中的max_uV;

regulator-boot-on,对应struct regulation_constraints中的boot_on;

regulator-always-on,对应struct regulation_constraints中的always_on。

其它的字段,可以根据实际情况,自行添加,具体可参考“Documentation/devicetree/bindings/regulator/regulator.txt”中的描述。

3.2 DTS的解析

regulator的DTS信息,可以通过两种方法解析:

1)在regulator注册前,调用of_get_regulator_init_data接口自行解析,该接口的实现如下:

   1: struct regulator_init_data *of_get_regulator_init_data(struct device *dev,
   2:                                                 struct device_node *node)
   3: {
   4:         struct regulator_init_data *init_data;
   5:  
   6:         if (!node)
   7:                 return NULL;
   8:  
   9:         init_data = devm_kzalloc(dev, sizeof(*init_data), GFP_KERNEL);
  10:         if (!init_data)
  11:                 return NULL; /* Out of memory? */
  12:  
  13:         of_get_regulation_constraints(node, &init_data);
  14:         return init_data;
  15: }
  16: EXPORT_SYMBOL_GPL(of_get_regulator_init_data);

该接口有两个输入参数:设备指针,以及包含了DTS信息的node指针(以3.1中的例子,即“tps51632@43”所在的node)。

它会分配一个struct regulator_init_data变量,并调用of_get_regulation_constraints解析DTS,把结果保存在该变量中。

最后返回struct regulator_init_data变量的地址。

2)在regulator注册时,由regulator_register调用regulator_of_get_init_data帮忙解析,该接口的实现如下:

   1: struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
   2:                                             const struct regulator_desc *desc,
   3:                                             struct device_node **node)
   4: {
   5:         struct device_node *search, *child;
   6:         struct regulator_init_data *init_data = NULL;
   7:         const char *name;
   8:  
   9:         if (!dev->of_node || !desc->of_match)
  10:                 return NULL;
  11:  
  12:         if (desc->regulators_node)
  13:                 search = of_get_child_by_name(dev->of_node,
  14:                                               desc->regulators_node);
  15:         else
  16:                 search = dev->of_node;
  17:  
  18:         if (!search) {
  19:                 dev_dbg(dev, "Failed to find regulator container node '%s'\n",
  20:                         desc->regulators_node);
  21:                 return NULL;
  22:         }
  23:  
  24:         for_each_child_of_node(search, child) {
  25:                 name = of_get_property(child, "regulator-compatible", NULL);
  26:                 if (!name)
  27:                         name = child->name;
  28:  
  29:                 if (strcmp(desc->of_match, name))
  30:                         continue;
  31:  
  32:                 init_data = of_get_regulator_init_data(dev, child);
  33:                 if (!init_data) {
  34:                         dev_err(dev,
  35:                                 "failed to parse DT for regulator %s\n",
  36:                                 child->name);
  37:                         break;
  38:                 }
  39:  
  40:                 of_node_get(child);
  41:                 *node = child;
  42:                 break;
  43:         }
  44:         of_node_put(search);
  45:  
  46:         return init_data;
  47: }

与of_get_regulator_init_data不同的是,该接口以struct regulator_desc指针为参数,该参数提供了regulator DTS有关的搜索信息(desc->of_match),根据这些信息,可以获得包含regulator信息的DTS node。

它本质上是一种通用的DTS匹配逻辑(和kernel解析platform device的标准资源类似),大致如下:

a)调用者提供parent node(struct device指针中,代表regulators的宿主设备,如上面的tps65090@48),以及该regulator在DTS中的名称(由desc->of_match提供)。

b)还可以在struct regulator_desc中提供包含regulator DTS信息的node名称(可选,用于regulator不直接在parent node下的情况)。

c)以parent device的node,或者指定的子node为基准,查找其下所有的node,如果node的名字或者“regulator-compatible”字段和desc->of_match匹配,则调用of_get_regulator_init_data从中解析DTS信息。

总结:1、2两种DTS解析的方法,各有优缺点:1直接,方便,容易理解,但会有冗余代码;2简洁,但需要regulator driver开发者非常熟悉解析的原理,并以此设计DTS和struct regulator_desc变量。大家可以根据实际情况,灵活使用。

4. 主要数据结构

4.1 struct regulator_desc

在注册regulator的时候,需要使用struct regulator_desc结构提供该regulator的静态描述。所谓的静态,是指这些描述不会在运行时改变,代表了设备的一种属性,如下:

   1: /* include/linux/regulator/driver.h */
   2:  
   3: struct regulator_desc {
   4:         const char *name;
   5:         const char *supply_name;
   6:         const char *of_match;
   7:         const char *regulators_node;
   8:         int id;
   9:         bool continuous_voltage_range;
  10:         unsigned n_voltages;
  11:         const struct regulator_ops *ops;
  12:         int irq;
  13:         enum regulator_type type;
  14:         struct module *owner;
  15:  
  16:         unsigned int min_uV;
  17:         unsigned int uV_step;
  18:         unsigned int linear_min_sel;
  19:         int fixed_uV;
  20:         unsigned int ramp_delay;
  21:  
  22:         const struct regulator_linear_range *linear_ranges;
  23:         int n_linear_ranges;
  24:  
  25:         const unsigned int *volt_table;
  26:  
  27:         unsigned int vsel_reg;
  28:         unsigned int vsel_mask;
  29:         unsigned int apply_reg;
  30:         unsigned int apply_bit;
  31:         unsigned int enable_reg;
  32:         unsigned int enable_mask;
  33:         unsigned int enable_val;
  34:         unsigned int disable_val;
  35:         bool enable_is_inverted;
  36:         unsigned int bypass_reg;
  37:         unsigned int bypass_mask;
  38:         unsigned int bypass_val_on;
  39:         unsigned int bypass_val_off;
  40:  
  41:         unsigned int enable_time;
  42:  
  43:         unsigned int off_on_delay;
  44: };

name,该regulator的名称,唯一标识该regulator,必须提供;

supply_name,该regulator的输入regulator的名称;

of_match、regulators_node,提供信息,以便在注册的时候自动从DTS中解析init_data,具体可参考3.2小节的描述;

id,标识该regulator的一个数字;

continuous_voltage_range,为true时,表示该regulator可以在一定范围输出连续的电压;

n_voltages,consumer可以通过ops.list_voltage()接口,获取该regulator可以输出的电压值。该变量指定可以获取的电压值的个数,后面讲到ops时,再介绍;

ops,该regulator的操作函数集,见后面;

irq,该regulator的中断号(有的话);

type,该regulator的类型,包括REGULATOR_VOLTAGE和REGULATOR_CURRENT两种;

其它字段,和regulator的输出控制有关,后面会以专题的形式介绍。

struct regulator_ops提供了regulator的所有操作,如下:

   1: struct regulator_ops {
   2:  
   3:         /* enumerate supported voltages */
   4:         int (*list_voltage) (struct regulator_dev *, unsigned selector);
   5:  
   6:         /* get/set regulator voltage */
   7:         int (*set_voltage) (struct regulator_dev *, int min_uV, int max_uV,
   8:                             unsigned *selector);
   9:         int (*map_voltage)(struct regulator_dev *, int min_uV, int max_uV);
  10:         int (*set_voltage_sel) (struct regulator_dev *, unsigned selector);
  11:         int (*get_voltage) (struct regulator_dev *);
  12:         int (*get_voltage_sel) (struct regulator_dev *);
  13:  
  14:         /* get/set regulator current  */
  15:         int (*set_current_limit) (struct regulator_dev *,
  16:                                  int min_uA, int max_uA);
  17:         int (*get_current_limit) (struct regulator_dev *);
  18:  
  19:         /* enable/disable regulator */
  20:         int (*enable) (struct regulator_dev *);
  21:         int (*disable) (struct regulator_dev *);
  22:         int (*is_enabled) (struct regulator_dev *);
  23:  
  24:         /* get/set regulator operating mode (defined in consumer.h) */
  25:         int (*set_mode) (struct regulator_dev *, unsigned int mode);
  26:         unsigned int (*get_mode) (struct regulator_dev *);
  27:  
  28:         /* Time taken to enable or set voltage on the regulator */
  29:         int (*enable_time) (struct regulator_dev *);
  30:         int (*set_ramp_delay) (struct regulator_dev *, int ramp_delay);
  31:         int (*set_voltage_time_sel) (struct regulator_dev *,
  32:                                      unsigned int old_selector,
  33:                                      unsigned int new_selector);
  34:  
  35:         /* report regulator status ... most other accessors report
  36:          * control inputs, this reports results of combining inputs
  37:          * from Linux (and other sources) with the actual load.
  38:          * returns REGULATOR_STATUS_* or negative errno.
  39:          */
  40:         int (*get_status)(struct regulator_dev *);
  41:  
  42:         /* get most efficient regulator operating mode for load */
  43:         unsigned int (*get_optimum_mode) (struct regulator_dev *, int input_uV,
  44:                                           int output_uV, int load_uA);
  45:  
  46:         /* control and report on bypass mode */
  47:         int (*set_bypass)(struct regulator_dev *dev, bool enable);
  48:         int (*get_bypass)(struct regulator_dev *dev, bool *enable);
  49:         
  50:         /* the operations below are for configuration of regulator state when
  51:          * its parent PMIC enters a global STANDBY/HIBERNATE state */
  52:         
  53:         /* set regulator suspend voltage */
  54:         int (*set_suspend_voltage) (struct regulator_dev *, int uV);
  55:         
  56:         /* enable/disable regulator in suspend state */
  57:         int (*set_suspend_enable) (struct regulator_dev *);
  58:         int (*set_suspend_disable) (struct regulator_dev *);
  59:         
  60:         /* set regulator suspend operating mode (defined in consumer.h) */
  61:         int (*set_suspend_mode) (struct regulator_dev *, unsigned int mode);
  62: };

这些回调函数的具体意义,请参考后续的描述。

4.2 struct regulator_config

struct regulator_config保存了regulator的动态信息,所谓的动态信息,是指那些会在driver运行过程中改变、或者driver运行后才会确定的信息,如下:

   1: struct regulator_config {
   2:         struct device *dev;
   3:         const struct regulator_init_data *init_data;
   4:         void *driver_data;
   5:         struct device_node *of_node;
   6:         struct regmap *regmap;
   7:  
   8:         int ena_gpio;
   9:         unsigned int ena_gpio_invert:1;
  10:         unsigned int ena_gpio_flags;
  11: };

dev,对应的struct device指针。会在regulator_register时,由regulator core分配,保存在此,以便后续使用;

init_data,init data指针,在解析DTS后,保存在此,以便后续使用;

of_node,可以为空;

regmap,参考后续描述;

ena_gpio、ena_gpio_invert、ena_gpio_flags,控制regulator使能的GPIO及其active极性。

4.3 struct regulator_dev

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

   1: struct regulator_dev {
   2:         const struct regulator_desc *desc;
   3:         int exclusive;
   4:         u32 use_count;
   5:         u32 open_count;
   6:         u32 bypass_count;
   7:  
   8:         /* lists we belong to */
   9:         struct list_head list; /* list of all regulators */
  10:  
  11:         /* lists we own */
  12:         struct list_head consumer_list; /* consumers we supply */
  13:  
  14:         struct blocking_notifier_head notifier;
  15:         struct mutex mutex; /* consumer lock */
  16:         struct module *owner;
  17:         struct device dev;
  18:         struct regulation_constraints *constraints;
  19:         struct regulator *supply;       /* for tree */
  20:         struct regmap *regmap;
  21:  
  22:         struct delayed_work disable_work;
  23:         int deferred_disables;
  24:  
  25:         void *reg_data;         /* regulator_dev data */
  26:  
  27:         struct dentry *debugfs;
  28:  
  29:         struct regulator_enable_gpio *ena_pin;
  30:         unsigned int ena_gpio_state:1;
  31:  
  32:         /* time when this regulator was disabled last time */
  33:         unsigned long last_off_jiffy;
  34: };

desc,保存了regulator静态描述信息的指针(从这个角度看,所谓的静态描述,其变量必须为全局变量);

exclusive、use_count、open_count、bypass_count,一些状态记录;

constraints,保存了regulator的constraints指针;

supply,该regulator的supply;

等等。

5 实现逻辑分析

本章简单的分析一下regulator driver相关的实现逻辑。如果要理解有些逻辑,必须具备一些regulator的基础知识,因此在需要的时候,会穿插介绍这些知识。

5.1 regulator core的初始化

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

1)注册regulator class(/sys/class/regulator/)。

2)注册用于调试的debugfs。

和power switch class、input class等类似,regulator framework也是一种class,可以称作regulator class。

5.2 regulator register

regulator的注册,由regulator_register/devm_regulator_register接口负责,如下:

   1: /**
   2:  * regulator_register - register regulator
   3:  * @regulator_desc: regulator to register
   4:  * @config: runtime configuration for regulator
   5:  *
   6:  * Called by regulator drivers to register a regulator.
   7:  * Returns a valid pointer to struct regulator_dev on success
   8:  * or an ERR_PTR() on error.
   9:  */
  10: struct regulator_dev *
  11: regulator_register(const struct regulator_desc *regulator_desc,
  12:            const struct regulator_config *config)
  13: {
  14:     const struct regulation_constraints *constraints = NULL;
  15:     const struct regulator_init_data *init_data;
  16:     static atomic_t regulator_no = ATOMIC_INIT(0);
  17:     struct regulator_dev *rdev;
  18:     struct device *dev;
  19:     int ret, i;
  20:     const char *supply = NULL;
  21:  
  22:     if (regulator_desc == NULL || config == NULL)
  23:         return ERR_PTR(-EINVAL);
  24:  
  25:     dev = config->dev;
  26:     WARN_ON(!dev);
  27:  
  28:     if (regulator_desc->name == NULL || regulator_desc->ops == NULL)
  29:         return ERR_PTR(-EINVAL);
  30:  
  31:     if (regulator_desc->type != REGULATOR_VOLTAGE &&
  32:         regulator_desc->type != REGULATOR_CURRENT)
  33:         return ERR_PTR(-EINVAL);
  34:  
  35:     /* Only one of each should be implemented */
  36:     WARN_ON(regulator_desc->ops->get_voltage &&
  37:         regulator_desc->ops->get_voltage_sel);
  38:     WARN_ON(regulator_desc->ops->set_voltage &&
  39:         regulator_desc->ops->set_voltage_sel);
  40:  
  41:     /* If we're using selectors we must implement list_voltage. */
  42:     if (regulator_desc->ops->get_voltage_sel &&
  43:         !regulator_desc->ops->list_voltage) {
  44:         return ERR_PTR(-EINVAL);
  45:     }
  46:     if (regulator_desc->ops->set_voltage_sel &&
  47:         !regulator_desc->ops->list_voltage) {
  48:         return ERR_PTR(-EINVAL);
  49:     }
  50:  
  51:     rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL);
  52:     if (rdev == NULL)
  53:         return ERR_PTR(-ENOMEM);
  54:  
  55:     init_data = regulator_of_get_init_data(dev, regulator_desc,
  56:                            &rdev->dev.of_node);
  57:     if (!init_data) {
  58:         init_data = config->init_data;
  59:         rdev->dev.of_node = of_node_get(config->of_node);
  60:     }
  61:  
  62:     mutex_lock(®ulator_list_mutex);
  63:  
  64:     mutex_init(&rdev->mutex);
  65:     rdev->reg_data = config->driver_data;
  66:     rdev->owner = regulator_desc->owner;
  67:     rdev->desc = regulator_desc;
  68:     if (config->regmap)
  69:         rdev->regmap = config->regmap;
  70:     else if (dev_get_regmap(dev, NULL))
  71:         rdev->regmap = dev_get_regmap(dev, NULL);
  72:     else if (dev->parent)
  73:         rdev->regmap = dev_get_regmap(dev->parent, NULL);
  74:     INIT_LIST_HEAD(&rdev->consumer_list);
  75:     INIT_LIST_HEAD(&rdev->list);
  76:     BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier);
  77:     INIT_DELAYED_WORK(&rdev->disable_work, regulator_disable_work);
  78:  
  79:     /* preform any regulator specific init */
  80:     if (init_data && init_data->regulator_init) {
  81:         ret = init_data->regulator_init(rdev->reg_data);
  82:         if (ret < 0)
  83:             goto clean;
  84:     }
  85:  
  86:     /* register with sysfs */
  87:     rdev->dev.class = ®ulator_class;
  88:     rdev->dev.parent = dev;
  89:     dev_set_name(&rdev->dev, "regulator.%d",
  90:              atomic_inc_return(®ulator_no) - 1);
  91:     ret = device_register(&rdev->dev);
  92:     if (ret != 0) {
  93:         put_device(&rdev->dev);
  94:         goto clean;
  95:     }
  96:  
  97:     dev_set_drvdata(&rdev->dev, rdev);
  98:  
  99:     if (config->ena_gpio && gpio_is_valid(config->ena_gpio)) {
 100:         ret = regulator_ena_gpio_request(rdev, config);
 101:         if (ret != 0) {
 102:             rdev_err(rdev, "Failed to request enable GPIO%d: %d\n",
 103:                  config->ena_gpio, ret);
 104:             goto wash;
 105:         }
 106:  
 107:         if (config->ena_gpio_flags & GPIOF_OUT_INIT_HIGH)
 108:             rdev->ena_gpio_state = 1;
 109:  
 110:         if (config->ena_gpio_invert)
 111:             rdev->ena_gpio_state = !rdev->ena_gpio_state;
 112:     }
 113:  
 114:     /* set regulator constraints */
 115:     if (init_data)
 116:         constraints = &init_data->constraints;
 117:  
 118:     ret = set_machine_constraints(rdev, constraints);
 119:     if (ret < 0)
 120:         goto scrub;
 121:  
 122:     /* add attributes supported by this regulator */
 123:     ret = add_regulator_attributes(rdev);
 124:     if (ret < 0)
 125:         goto scrub;
 126:  
 127:     if (init_data && init_data->supply_regulator)
 128:         supply = init_data->supply_regulator;
 129:     else if (regulator_desc->supply_name)
 130:         supply = regulator_desc->supply_name;
 131:  
 132:     if (supply) {
 133:         struct regulator_dev *r;
 134:  
 135:         r = regulator_dev_lookup(dev, supply, &ret);
 136:  
 137:         if (ret == -ENODEV) {
 138:             /*
 139:              * No supply was specified for this regulator and
 140:              * there will never be one.
 141:              */
 142:             ret = 0;
 143:             goto add_dev;
 144:         } else if (!r) {
 145:             dev_err(dev, "Failed to find supply %s\n", supply);
 146:             ret = -EPROBE_DEFER;
 147:             goto scrub;
 148:         }
 149:  
 150:         ret = set_supply(rdev, r);
 151:         if (ret < 0)
 152:             goto scrub;
 153:  
 154:         /* Enable supply if rail is enabled */
 155:         if (_regulator_is_enabled(rdev)) {
 156:             ret = regulator_enable(rdev->supply);
 157:             if (ret < 0)
 158:                 goto scrub;
 159:         }
 160:     }
 161:  
 162: add_dev:
 163:     /* add consumers devices */
 164:     if (init_data) {
 165:         for (i = 0; i < init_data->num_consumer_supplies; i++) {
 166:             ret = set_consumer_device_supply(rdev,
 167:                 init_data->consumer_supplies[i].dev_name,
 168:                 init_data->consumer_supplies[i].supply);
 169:             if (ret < 0) {
 170:                 dev_err(dev, "Failed to set supply %s\n",
 171:                     init_data->consumer_supplies[i].supply);
 172:                 goto unset_supplies;
 173:             }
 174:         }
 175:     }
 176:  
 177:     list_add(&rdev->list, ®ulator_list);
 178:  
 179:     rdev_init_debugfs(rdev);
 180: out:
 181:     mutex_unlock(®ulator_list_mutex);
 182:     return rdev;
 183:  
 184: unset_supplies:
 185:     unset_regulator_supplies(rdev);
 186:  
 187: scrub:
 188:     if (rdev->supply)
 189:         _regulator_put(rdev->supply);
 190:     regulator_ena_gpio_free(rdev);
 191:     kfree(rdev->constraints);
 192: wash:
 193:     device_unregister(&rdev->dev);
 194:     /* device core frees rdev */
 195:     rdev = ERR_PTR(ret);
 196:     goto out;
 197:  
 198: clean:
 199:     kfree(rdev);
 200:     rdev = ERR_PTR(ret);
 201:     goto out;
 202: }
 203: EXPORT_SYMBOL_GPL(regulator_register);

主要工作包括:

22~49,检查参数的合法性。其中35~49行,涉及到电压控制的方式,后面后详细说明;

55~60,协助从DTS解析init data,如果解析不到,则使用config中的;

68~73,协助获取regulator的register map(有的话),并保存在register device指针中。regulator driver会在需要的时候使用(通常是在ops回调函数中);

74~77,初始化一些全局变量,consumer_list用于保存所有的consumer,list用于将自己添加到一个全局的regulator链表(regulator_list)上,disable_work是用于disable regulator的work queue;

86~95,将regulator device注册到kernel;

99~112,申请regulator enable gpio(有的话),并将相应的信息保存在regulator device指针中;

114~120,将从DTS中解析的constraints,应用起来(这个过程比较复杂,就不介绍了,感兴趣的读者可以自行分析);

123,根据regulator的操作函数集,注册相应的attribute(和PSY class类似);

127~160,如果该regulator有supply,根据supply的名字,获取相应的regulator device指针,同时根据supply指针,分配一个struct regulator结构,保存在该regulator的supply指针中。最后,如果该regulator处于使能状态,则需要使能其supply(这些动作,需要以consumer的视角操作,因而需要一个struct regulator变量);

162~175,add consumer devices,等到介绍consumer时,再详细描述。

注4:register map是kernel提供的一种管理寄存器的机制,特别是较为复杂的寄存器,如codec等。本文不会过多描述,如需要,会专门写一篇文章介绍该机制。

5.3 regulator的操作模式(operation mode)

regulator的主要功能,是输出电压/电流的调整(或改变)。由于模拟器件的特性,电压/电流的改变,是需要一定的时间的。对有些regulator而言,可以工作在不同的模式,这些模式有不同的改变速度,可想而知,较快的速度,有较大的功耗。下面是operation mode定义(位于include/linux/regulator/consumer.h中):

   1: /*
   2:  * Regulator operating modes.
   3:  *
   4:  * Regulators can run in a variety of different operating modes depending on
   5:  * output load. This allows further system power savings by selecting the
   6:  * best (and most efficient) regulator mode for a desired load.
   7:  *
   8:  * Most drivers will only care about NORMAL. The modes below are generic and
   9:  * will probably not match the naming convention of your regulator data sheet
  10:  * but should match the use cases in the datasheet.
  11:  *
  12:  * In order of power efficiency (least efficient at top).
  13:  *
  14:  *  Mode       Description
  15:  *  FAST       Regulator can handle fast changes in it's load.
  16:  *             e.g. useful in CPU voltage & frequency scaling where
  17:  *             load can quickly increase with CPU frequency increases.
  18:  *
  19:  *  NORMAL     Normal regulator power supply mode. Most drivers will
  20:  *             use this mode.
  21:  *
  22:  *  IDLE       Regulator runs in a more efficient mode for light
  23:  *             loads. Can be used for devices that have a low power
  24:  *             requirement during periods of inactivity. This mode
  25:  *             may be more noisy than NORMAL and may not be able
  26:  *             to handle fast load switching.
  27:  *
  28:  *  STANDBY    Regulator runs in the most efficient mode for very
  29:  *             light loads. Can be used by devices when they are
  30:  *             in a sleep/standby state. This mode is likely to be
  31:  *             the most noisy and may not be able to handle fast load
  32:  *             switching.
  33:  *
  34:  * NOTE: Most regulators will only support a subset of these modes. Some
  35:  * 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                     0x1
  41: #define REGULATOR_MODE_NORMAL                   0x2
  42: #define REGULATOR_MODE_IDLE                     0x4
  43: #define REGULATOR_MODE_STANDBY                  0x8

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

1)struct regulation_constraints中用于表示初始模式的字段initial_mode。

2)regulator ops中的set_mode/get_mode回调函数。

5.4 电压操作的两种方式

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

1)直接操作电压,对应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,
   4:                     unsigned *selector);
   5: int (*get_voltage) (struct regulator_dev *);

其中set_voltage用于将电压设置为min_uV和max_uV范围内、和min_uV最接近的电压。该接口可以返回一个selector参数,用于告知调用者,实际的电压值;

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

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

注5:有关selector的描述,可参考下面的介绍。

2)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的形式,操作电压。

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

5.5 regulator framework提供的sysfs接口

根据regulator提供的ops情况,regulator framework可以通过sysfs提供多种attribute,它们位于/sys/class/regulator/.../目录下,数量相当多,这里就不一一描述了,具体可参考:

https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-class-regulator

6. 后记

这篇文章写的相当纠结,相当混乱,我相信读者很难看懂……

本以为会很容易写,但里面的知识点太零碎了,以至于无法很好的归纳、抽象、突出重点。崩溃!

时间原因,就先这样了,有机会再回头来整理,希望读者谅解。

 

原创文章,转发请注明出处。蜗窝科技www.wowotech.net

标签: Linux driver framework regulator

评论:

小学生
2020-02-14 17:32
hi wowo,
请问regulator-min-microamp可以等于0吗?内核代码中machine_constraints_voltage()中,cmin = constraints->min_uV,下面函数有个判断if(cmin<=0 || cmax<=0 || cmax<cmin)->return -EINVAL,
tiem
2018-01-18 10:36
@wowo:
有个疑问能否解答一下:
如果app打开了某个LDO(比如camera app),如果没来得及退出就crash了,那么LDO怎么释放?

Thanks.
xyaw
2017-09-27 17:44
你好
我想請教:
1.
/sys/class/regulator/regulator.14 # ls

device         min_microvolts of_node   suspend_disk_state    type  
max_microvolts name           power     suspend_mem_state     uevent
microvolts     num_users      subsystem suspend_standby_state

我在此沒有看到regulator_ops (我想調整電壓 set_voltage_sel/ set_voltage)相關的東西
請問要enable是regular定義時候要加什麼參數?
wowo
2017-09-27 18:49
@xyaw:實際上,regulator framework提供的sysfs api都是readonly的。
這也很好理解:register framework的consumer大部分都是kernel space的其它driver,需要由usersapce軟體直接控制的可能性比較小。
不過,可能小並不代表沒有可能,如果真有這樣的需求,也是有解決方法的:使用userspace consumer(drivers/regulator/userspace-consumer.c)。這其實是一個簡單的驅動程式,可以把需要由userspace軟體控制的regulator開放給userspace(可以簡單的enable、disable),kernel中有相應的例子,例如arch/arm/mach-pxa/em-x270.c,供你參考。
最後,如果實在不想使用已有的框架,你完全可以自己寫一個driver,將需要由userspace控制regulator導出,至於格式嘛,完全取決於您咯~~
xingxing.wang
2017-06-30 17:51
Hi Wowo:
   您说的struct regulator_ops里面的所有回调由regulator core统一管控,能否讲解一下具体的实现方式,regulator core是主动调节还是被动调节的?感谢。
wowo
2017-07-03 08:40
@xingxing.wang:一般情况下都是被动调用(core不会自作主张),实现方式,你可以参考这篇文章(http://www.wowotech.net/pm_subsystem/regulator_framework_overview.html)然后对着代码看看(细节的东西,不是一句两句话能说明白的,见谅)。
cym
2016-03-14 13:35
hi wowo
    请问下是否知道voltage tolerance是什么意思呢??
wowo
2016-03-14 14:00
@cym:我的理解是:
假如系统中某个器件(例如CPU),要求一个1.8v的供电。但是,基于电压转换电路(通常是PMU)的特性,不可能输出一个精确的、误差为0的、1.8v的电压。
于是PMU的设计者会问CPU的设计者,一定要1.8吗?多一点、少一点不行吗?
通常情况下,考虑到电源系统设计的难度,器件都会打个折扣,允许输入电压有一定的误差,例如正负10%,这个就叫做voltage tolerance。
如有不对的地方,还请高手指正。
cym
2016-03-14 14:03
@wowo:应该是这样的,多谢wowo大虾
cracker
2016-01-21 18:37
hi wowo:
  这两天看了retulator的文章,不知到下面我的理解是不是正确的:
  1:regulator和cpufreq都可以动态调节电压,但cpu在内核中是特殊的设备,所以对于普通的设备提供regulator机制,而cpu提供了cpufreq机制;
  2:regulator是linux的设备抽象,在注册regulator需要初始化真正的设备属性(regulator_config和regulator_desc),然后注册时将上面初始化的变量交给boss regulator_dev,并让boss和dev绑定;
  3:设备使用与其绑定的regulator时,通过regulator_get函数获取regulator,然后执行regulator_ops的各种回调;
  4:regulator_constraints(regulator_config)与cpufreq_policy;regulator_desc与regulator_driver在思想上是不是一样的呢?
wowo
2016-01-21 20:55
@cracker:不是这样的,regulator和cpufreq是两个事情,没有可比性,具体可参考这个图片:http://www.wowotech.net/content/uploadfile/201506/a4cf6b6a89f45ea76d69dcb9ea0738c720150613141951.gif
passerby
2016-03-17 10:50
@wowo:我理解cpufreq和requlator是分开的,但也有联系。不同的cpufreq的CPU的性能不同,cpufreq高的时候,功耗相应的就大,所以就需要requlator调高CPU电压,以保证CPU有足够的POWER稳定的运行。所以一般CPU都会有一个cpufreq和voltage的对应表,DVFS就是按照这个对应表来调节频率和这个频率对应的电压。不知道我这样理解的对不对?
wowo
2016-03-17 13:34
@passerby:regulator framework只是一个调整电压的工具(无论是CPU的电压还是其它模块的电压),他和clock framework位于一个level。你和上面cracker同学说的都没有问题,但我整不明白的是:
大家理解一个东西的时候,为什么要和其它东西缠绕在一起?
例如理解regulator framework的时候,为什么会想到cpufreq?
而理解cpufreq framework的时候,为什么这么纠结regulator和clock?把这二位当作一个工具就ok了,重点还是要看cpufreq framework的设计思想。
cracker
2016-01-19 17:55
hi wowo
之前学习cpufreq了解是它主动获取cpu工作繁忙程度,实现动态调频。请问regulator如何知道设备是否在用或者是否suspend?
wowo
2016-01-19 18:37
@cracker:regulator只是一个工具,就像一把刀一样,无论让它砍谁,敌人、友军还是自己,它都执行。因此是否suspend,regulator不会关心,需要关心的是使用regulator的driver。
至于regulator driver本身,只需要保证其启动顺序(包括resume顺序)在其它正常的driver之前即可。
tigger
2015-04-27 14:30
为什么第一张图里面,他们用几个器件来提供regular,而不是合成一个呢?
降压控制器(TI tps51632),该控制器输出名称为“vdd-cpu”
是因为vdd-cpu需要特别稳定还是?不知道wowo思考过没有
wowo
2015-04-27 15:40
@tigger:这里面有几个考量:
1. 可配置性。
这个例子,是Tegra的一个开发板,所谓的开发板,需要满足不同类型的产品需求,这些产品所需的电源域的多少可能千差万别(对芯片厂而言,会经常遇到这样的问题)。因此需要可以灵活配置。
2. 体积、功耗和发热。
如果把所有的regulator都集成在一个片子中,会不会发热很严重?如果分开,会不会增大体积?等等。
话又说回来,这只是一个开发板,如果使用这个片子做产品的时候,设计者可能会考虑不同的方案。
3. 灵活的可控性。
对vdd-cpu而言,我猜“更稳定”不是主要的考量因素,因为稳定很容易做到。反而需要重点考虑的是:每个模块的regulator调整,不会影响其它模块。一个模块一个regulator最好,但代价太大。退而求其次,重点照顾CPU吧。
tigger
2015-04-27 14:26
hi wowo
最开始一张图
vdd与dcdc 这样描述是为什么?
还有vdd 跟avdd 数字/模拟怎么理解呢?有什么不同呢?
蜗蜗
2015-04-27 14:55
@tigger:这是我根据它的DTS抄出来的,我的理解是:
VDD和DCDC,表示这两个电压,是由两类不同类型的regulator器件输出的,LDO和DC/DC。LDO噪声小,但输出效率低;DC/DC输出效率高,但噪声大。
对于VDD和AVDD,是电路布线上的一种考虑,尽量将数字电路(CPU、MEM等)和模拟电路(Audio等)在电源域上隔离开(当然,不可能完全隔离,最终还是要共地),以减少干扰。
tigger
2015-04-27 15:30
@蜗蜗:有道理
tigger
2015-04-27 14:13
我有个疑问
比如tegra,他们把他们的充电参数放到了哪里呢?
没看到放到dts里面
蜗蜗
2015-04-27 14:54
@tigger:这和具体的版型有关,我们需要知道确切的版型,才能去找。总体来说,无外乎两个地方:DTS和代码中。另外Tegra的DTS文件很多,通过include包含起来了,可能你没有找到。

发表评论:

Copyright @ 2013-2015 蜗窝科技 All rights reserved. Powered by emlog