• Linux Regulator Framework(2)_regulator driver


    转自蜗窝科技:http://www.wowotech.net/pm_subsystem/regulator_driver.html

    说实话,这篇好难懂啊。。。

    1. 前言

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

    2. regulator driver的实现步骤

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

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

     

    这里的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等等。

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

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

    1)tps51632(是一种电源管理模块)

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

       1: /* archarmootdts	egra114-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字段?其实是有的,可参考“archarmootdts egra114.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

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

    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'
    ",
      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
    ",
      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

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

    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
    ",
     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
    ", 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
    ",
     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);
    View Code

     主要工作包括:

    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. 后记

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

  • 相关阅读:
    使用kendynet构建异步redis访问服务
    使用kendynet编写网关服务
    作为前端,我为什么选择 Angular 2?
    你必须知道的Javascript 系列
    JS日期(Date)处理函数总结
    JS数组(Array)处理函数总结
    消息推送之APNS
    消息推送之GCM
    Linux常用命令大全
    Sequential Container
  • 原文地址:https://www.cnblogs.com/linhaostudy/p/8640107.html
Copyright © 2020-2023  润新知