转自蜗窝科技: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位于“arch\arm\boot\dts\tegra114-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. : /* arch\arm\boot\dts\tegra114-dalmore.dts */
  2. : i2c@7000d000 {
  3. : status = "okay";
  4. : clock-frequency = <>;
  5. :
  6. : tps51632@ {
  7. : compatible = "ti,tps51632";
  8. : reg = <0x43>;
  9. : regulator-name = "vdd-cpu";
  10. : regulator-min-microvolt = <>;
  11. : regulator-max-microvolt = <>;
  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@ {
  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 = <>;
  4. : #size-cells = <>;
  5. :
  6. : vdd_ac_bat_reg: regulator@ {
  7. : compatible = "regulator-fixed";
  8. : reg = <>;
  9. : regulator-name = "vdd_ac_bat";
  10. : regulator-min-microvolt = <>;
  11. : regulator-max-microvolt = <>;
  12. : regulator-always-on;
  13. : };
  14. :
  15. : dvdd_ts_reg: regulator@ {
  16. : compatible = "regulator-fixed";
  17. : reg = <>;
  18. : regulator-name = "dvdd_ts";
  19. : regulator-min-microvolt = <>;
  20. : regulator-max-microvolt = <>;
  21. : enable-active-high;
  22. : gpio = <&gpio TEGRA_GPIO(H, ) 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. 2: * struct regulator_init_data - regulator platform initialisation data.
  3. 3: *
  4. 4: * Initialisation constraints, our supply and consumers supplies.
  5. 5: *
  6. 6: * @supply_regulator: Parent regulator. Specified using the regulator name
  7. 7: * as it appears in the name field in sysfs, which can
  8. 8: * be explicitly set using the constraints field 'name'.
  9. 9: *
  10. 10: * @constraints: Constraints. These must be specified for the regulator to
  11. 11: * be usable.
  12. 12: * @num_consumer_supplies: Number of consumer device supplies.
  13. 13: * @consumer_supplies: Consumer device supply configuration.
  14. 14: *
  15. 15: * @regulator_init: Callback invoked when the regulator has been registered.
  16. 16: * @driver_data: Data passed to regulator_init.
  17. 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:; /* regulator never off when system is on */
  38. : unsigned boot_on:; /* bootloader/firmware enabled regulator */
  39. : unsigned apply_uV:; /* apply uV constraint if min == max */
  40. : unsigned ramp_disable:; /* 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'\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

  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:;
  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:;
  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. 2: * regulator_register - register regulator
  3. 3: * @regulator_desc: regulator to register
  4. 4: * @config: runtime configuration for regulator
  5. 5: *
  6. 6: * Called by regulator drivers to register a regulator.
  7. 7: * Returns a valid pointer to struct regulator_dev on success
  8. 8: * or an ERR_PTR() on error.
  9. 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();
  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_lockulator_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 < )
  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_returnulator_no) - );
  91. : ret = device_register(&rdev->dev);
  92. : if (ret != ) {
  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 != ) {
  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 = ;
  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 < )
  120. : goto scrub;
  121. :
  122. : /* add attributes supported by this regulator */
  123. : ret = add_regulator_attributes(rdev);
  124. : if (ret < )
  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. 139: * No supply was specified for this regulator and
  140. 140: * there will never be one.
  141. 141: */
  142. : ret = ;
  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 < )
  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 < )
  158. : goto scrub;
  159. : }
  160. : }
  161. :
  162. : add_dev:
  163. : /* add consumers devices */
  164. : if (init_data) {
  165. : for (i = ; 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 < ) {
  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_unlockulator_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. 2: * Regulator operating modes.
  3. 3: *
  4. 4: * Regulators can run in a variety of different operating modes depending on
  5. 5: * output load. This allows further system power savings by selecting the
  6. 6: * best (and most efficient) regulator mode for a desired load.
  7. 7: *
  8. 8: * Most drivers will only care about NORMAL. The modes below are generic and
  9. 9: * will probably not match the naming convention of your regulator data sheet
  10. 10: * but should match the use cases in the datasheet.
  11. 11: *
  12. 12: * In order of power efficiency (least efficient at top).
  13. 13: *
  14. 14: * Mode Description
  15. 15: * FAST Regulator can handle fast changes in it's load.
  16. 16: * e.g. useful in CPU voltage & frequency scaling where
  17. 17: * load can quickly increase with CPU frequency increases.
  18. 18: *
  19. 19: * NORMAL Normal regulator power supply mode. Most drivers will
  20. 20: * use this mode.
  21. 21: *
  22. 22: * IDLE Regulator runs in a more efficient mode for light
  23. 23: * loads. Can be used for devices that have a low power
  24. 24: * requirement during periods of inactivity. This mode
  25. 25: * may be more noisy than NORMAL and may not be able
  26. 26: * to handle fast load switching.
  27. 27: *
  28. 28: * STANDBY Regulator runs in the most efficient mode for very
  29. 29: * light loads. Can be used by devices when they are
  30. 30: * in a sleep/standby state. This mode is likely to be
  31. 31: * the most noisy and may not be able to handle fast load
  32. 32: * switching.
  33. 33: *
  34. 34: * NOTE: Most regulators will only support a subset of these modes. Some
  35. 35: * will only just support NORMAL.
  36. 36: *
  37. 37: * These modes can be OR'ed together to make up a mask of valid register modes.
  38. 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. 后记

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

Linux Regulator Framework(2)_regulator driver的更多相关文章

  1. Linux regulator framework(1) - 概述【转】

    转自蜗窝科技:http://www.wowotech.net/pm_subsystem/regulator_framework_overview.html 1. 前言 Regulator,中文名翻译为 ...

  2. Linux电源管理-Linux regulator framework概述

    前言 1.  什么是regulator?      regulator翻译为"调节器",分为voltage regulator(电压调节器)和current(电流调节器).一般电源 ...

  3. Linux PWM framework简介和API描述【转】

    本文转载自:https://blog.csdn.net/mike8825/article/details/51656400 1. 前言 PWM是Pulse Width Modulation(脉冲宽度调 ...

  4. Linux regulator系统

    1. 概念:Regulator : 电源芯片, 比如电压转换芯片Consumer : 消费者,使用电源的部件, Regulator是给Consumer供电的machine : 单板,上面焊接有Regu ...

  5. 【原创】Linux cpufreq framework

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  6. 【原创】Linux cpuidle framework

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  7. Linux Thermal Framework分析及实施

    关键词:Zone.Cooling.Governor.Step Wise.Fair Share.trip等等. Linux Thermal的目的是控制系统运行过程中采样点温度,避免温度过高造成器件损坏, ...

  8. Linux kernel support docker storage driver aufs

    How to make docker use aufs in CentOS 7? - Server Faulthttps://serverfault.com/questions/650208/how- ...

  9. linux regulator之浅见【转】

    转自:http://blog.csdn.net/batoom/article/details/17081651 1: 校准器的基本概念 所谓校准器实际是在软件控制下把输入的电源调节精心输出. Regu ...

随机推荐

  1. numpy中pad函数的常用方法

    一.参数解释 ndarray = numpy.pad(array, pad_width, mode, **kwargs) array为要填补的数组 pad_width是在各维度的各个方向上想要填补的长 ...

  2. Docker总结(脑图图片)

  3. Ubuntu编译安装最新的webkit

    好久都没更新webkit 源码在ubuntu上编译了,网上搜了一下,基本上都是早期编译的webkit版本.可能是大家都去搞高大上的谷歌浏览器了吧. 今天就以ubuntu14.04版本作为编译环境来讲讲 ...

  4. salesforce lightning零基础学习(八) Aura Js 浅谈一: Component篇

    我们在开发lightning的时候,常常会在controller.js中写 component.get('v.label'), component.set('v.label','xxValue'); ...

  5. android ART hook

    0x00 前言 之前一直都是在Dalvik 虚拟机上在折腾,从Android 4.4开始开始引入ART,到5.0已经成为默认选择.而且最近看到阿里开源的 Dexposed 框架,已经提供了对于andr ...

  6. Haproxy+Heartbeat 高可用集群方案操作记录

    之前详细介绍了haproxy的基础知识点, 下面记录下Haproxy+Heartbeat高可用web集群方案实现过程, 以加深理解. 架构草图如下: 1) 基本环境准备 (centos6.9系统) 1 ...

  7. delete attempted to return null from a method with a primitive return type (int)

    今天被自己给蠢死了 今天在代码中遇到这个错误, 百度翻译一下:映射方法,从一org.system.mapper.child.chmorganizationexaminationmapper.delet ...

  8. 三、TortoiseGit之配置密钥

    TortoiseGit使用扩展名为ppk的密钥,而不是ssh-keygen生成的rsa密钥. 也就是说使用 ssh-keygen  -t rsa  -C "username@email.co ...

  9. SpringMVC入门学习(一)

    SpringMVC入门学习(一) ssm框架 spring  SpringMVC是一个Java WEB框架,现在我们知道Spring了,那么,何为MVC呢? MVC是一种设计模式,其分为3个方面 mo ...

  10. Django之模型层(多表操作)

    一.创建模型 1,一对多关系 一本书只有一个出版社,一个出版社可以出版多本书,从而书与出版社之间就构成一对多关系,书是‘多’的一方,出版社是‘一’的一方,我们在建立模型的时候,把外键写在‘多’的一方, ...