当前位置:   article > 正文

linux Regulator电源设备驱动框架_regulator-always-on

regulator-always-on

        调节器Regulator是为其他设备供电的设备。由regulator供电的设备称为消费者。提供调节器的芯片称为电源集成电路PMIC。调节器可以启用/禁用其输出,也可以控制其输出电压和电流。

一、PMIC/生产者驱动程序

        生产者是产生调节电压电流的设备,这个设备的名称是PMIC,可用于控制加电时序、电池管理、DC-DC转换或简单的电源开关。

1. 驱动程序数据结构

i). 调节器描述结构regulator_desc

        内核通过struct regulator_desc{}描述PMIC提供的每个调节器。所谓的调节器是一个可以独立调节的输出,例如Intersil的ISL6217A是一款具有3个独立调节输出的PMIC,因此其驱动程序应该有3个regulator_desc{}实例。

  1. struct regulator_desc {
  2. const char* name;
  3. const char *of_match;
  4. int id; // 调节器的数字标识
  5. unsigned n_voltages; // 调节器可输出的数值数量,如果是固定输出电压,则为1.
  6. const struct regulator_ops *ops;
  7. int irq; // 调节器的中断号
  8. enum regulator_type type; // 是电压调节器还是电流调节器,REGULATOR_VOLTAGE, REGULATOR_CURRENT
  9. struct module *owner;
  10. uint min_uV; // 调节器可以输出的最小电压值
  11. uint uV_step; // 每个选择器的电压增量
  12. };

ii). 调节器限制结构regulator_reconstraints{}

        当PMIC向消费者公开调节器时,它必须借助于struct regulator_restraints{}结构为调节器加一些名义上的限制。这个结构收集调节器的安全限制,定义消费者不能跨越的边界。这是调节器驱动程序和消费者驱动程序之间的一种约定:

  1. struct regulator_constraints {
  2. const char *name;
  3. //电压输出范围
  4. int min_uV;
  5. int max_uV;
  6. int uV_offset; // 应用于消费者的电压偏移量,以补偿电压下降
  7. // 电流输出范围
  8. int min_uA;
  9. int max_uA;
  10. uint valid_modes_mask; // 消费者可能配置的模式的掩码
  11. uint valid_ops_mask; // 消费者可能执行的操作的掩码
  12. // 系统位于磁盘模式、内存模式、待机模式时regulator的状态;
  13. struct regulator_state state_disk;
  14. struct regulator_state state_mem;
  15. struct regulator_state state_standby;
  16. suspend_state_t initial_state; // 在init处设置挂起状态
  17. uint initial_mode; // 启动时要设置的模式
  18. unsigned always_on:1;
  19. unsigned boot_on:1;
  20. unsigned apply_uV:1; //
  21. };

iii). regulator初始化结构regulator_init_data{}

初始化数据结构struct regulator_init_data{},可以通过SoC文件或DT树把初始化数据结构传递给驱动程序,在DT树模式下可以用of_get_regulator_init_data()获取数据结构:

  1. struct regulator_init_data {
  2. struct regulation_constraints constraints;
  3. int (*regulator_init)(void *driver_data);
  4. void *driver_data;
  5. };
  6. // 将初始化数据放入SoC的开发板文件中,示例intersil的ISL6271A
  7. static struct regulator_init_data isl_init_data[] = {
  8. [0] = { .constraints = { .name = "Core Buck",
  9. .min_uV = 850000,
  10. .max_uV = 1600000,
  11. .valid_modes_mask = REGULATOR_MODE_NORMAL | REGULATOR_MODE_STANDBY,
  12. .valid_ops_mask = REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS,
  13. },
  14. },
  15. [1] = { .constraints = { .name = "LDO1",
  16. .min_uV = 1100000,
  17. .max_uV = 1100000,
  18. .always_on = true,
  19. .valid_modes_mask = REGULATOR_MODE_NORMAL | REGULATOR_MODE_STANDBY,
  20. .valid_ops_mask = REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS,
  21. },
  22. },
  23. [0] = { .constraints = { .name = "LDO2",
  24. .min_uV = 1300000,
  25. .max_uV = 1300000,
  26. .always_on = true,
  27. .valid_modes_mask = REGULATOR_MODE_NORMAL | REGULATOR_MODE_STANDBY,
  28. .valid_ops_mask = REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS,
  29. },
  30. },
  31. };

iv). 在DT文件中绑定regulator

DT文件中绑定,每个PMIC设备的节点都需要有一个名为regulators的子节点,在子节点regulators中声明PMIC的每个调节器regulator。各个调节器具体DT节点属性和具体示例如下:

  1. // 和regulator相关的标准属性
  2. /*
  3. regulator-name:字符串,作为调节器输出的描述性名称;
  4. regulator-min-microvolt:消费者可以设置的最低电压
  5. regulator-max-microvolt:消费者可以设置的最高电压
  6. regulator-microvolt-offset:应用于电压的偏移量,以补偿消费者的电压下降
  7. regulator-min-microamp:消费者可以设置的最小电流
  8. regulator-max-microamp:消费者可以设置的最大电流
  9. regulator-always-on:bool值,说明调节器永不禁用
  10. regulator-boot-on:由引导加载程序/固件启用的调节器
  11. <name>-handler : 指向父节点/调节器节点的phandle
  12. regulator-ramp-delay:调节器的斜坡延迟(单位uV/uS)
  13. 这些属性和regulator_init_data{}.regulator_constraints{}中的字段基本相同
  14. */
  15. // 示例,ISL6271A的驱动程序的DT如下:
  16. isl6271a@3c {
  17. compatible = "isl6271a";
  18. reg = <0x3c>;
  19. interrupts = <0 86 0x4>;
  20. in-v1-supply = <&some_reg>; // 假设该PMIC由另一个调节器供电
  21. [...]
  22. regulators {
  23. reg1: core_buck {
  24. regulator-name="Core Buck";
  25. regulator-min-microvolt = <850000>;
  26. regulator-max-microvolt = <1600000>;
  27. };
  28. reg2: ldo1 {
  29. regulator-name="LDO1";
  30. regulator-min-microvolt = <1100000>;
  31. regulator-max-microvolt = <1100000>;
  32. regulator-always-on;
  33. };
  34. reg3: ldo2 {
  35. regulator-name="LDO1";
  36. regulator-min-microvolt = <1300000>;
  37. regulator-max-microvolt = <1300000>;
  38. regulator-always-on;
  39. };
  40. };
  41. };

        使用DT文件的方式把初始化数据引入到regulator驱动程序中:

  1. // 为了使用DT,首先需要引入数据结构struct struct_regulator_match{}
  2. struct struct_regulator_match{
  3. const char *name;
  4. void *driver_data;
  5. struct regulator_init_data *init_data;
  6. struct device_node *of_node;
  7. const struct regulator_desc *desc;
  8. };

        在PMIC驱动程序的probe函数中,使用内核辅助函数of_regulator_match()时,将regulators的子节点作为参数传递给它,该函数将遍历每个调节器的节点,并为其建立一个struct regulator_init_data{}结构;

v). regulator配置结构regulator_config{}

调节器设备通过struct regulator_config{}结构进行配置。在向内核注册调节器时,该结构被传递给regulator框架:

  1. struct regulator_config {
  2. struct device *dev; // 调节器设备所属的struct device
  3. const struct regulator_init_data *init_data;
  4. void *driver_data; // 保存调节器的私有数据
  5. struct device_node *of_node;
  6. };

vi). regulator设备操作结构

        调节器设备通过struct regulator_config{}是表示调节器可执行的所有操作的回调列表。

  1. struct regulator_ops {
  2. // 枚举支持的电压值
  3. int (*list_voltage)(struct regulator_dev *reg, unsigned selector);
  4. // 获取或设置电压调节器
  5. int (*set_voltage)(struct regulator_dev *reg, int min_uV,
  6. int max_uV, uint *selector);
  7. int (*map_voltage)(struct regulator_dev *reg, int min_uV,
  8. int max_uV);
  9. int (*set_voltage_sel)(struct regulator_dev *reg, uint selector);
  10. int (*get_voltage)(struct regulator_dev *reg);
  11. int (*get_voltage_sel)(struct regulator_dev *reg);
  12. // 获取或设置电流调节器
  13. int (*set_current_limit)(struct regulator_dev *reg, int min_uA, int max_uA);
  14. int (*get_current_limit)(struct regulator_dev *reg);
  15. int (*set_input_current_limit)(struct regulator_dev *reg, int lim_uA);
  16. int (*set_owner_current_protection)(struct regulator_dev *reg);
  17. int (*set_active_discharge)(struct regulator_dev *reg, bool enable);
  18. int (*enable)(struct regulator_dev *reg);
  19. int (*disable)(struct regulator_dev *reg);
  20. int (*is_enabled)(struct regulator_dev *reg);
  21. int (*set_mode)(struct regulator_dev *reg, uint mode);
  22. uint (*get_mode)(struct regulator_dev *reg);
  23. };
  24. // 在这些回调函数中参数为regulator_dev{},调用rdev_get_id()可获得对应调节器的id,
  25. int rdev_get_id(struct regulator_dev *rdev);

2. 驱动程序方法

1. probe函数的实现

PMIC驱动程序的实现可分为几个步骤:

  • 为该PMIC提供的所有调节器定义为regulator_desc{}对象数组。并确保已经定义了有效的struct regulator_ops{}实例。假设所有的调节器都支持相同的操作,则它们都有相同的regulator_ops{}示例。
  • 在probe函数中,从平台数据中获取合适的struct regulator_init_data{},且平台中已经包含了有效的struct regulator_constraints{}。或者从DT中构建struct regulator_constraints{}实例,以构建合适的struct regulator_init_data{}实例。
  • 接着使用前面的struct regulator_init_data{}对象来设置struct regulator_config{}结构;如果驱动程序支持DT,则可以将regulator_config.of_node指向用于获取调节器属性的节点。
  • 调用regulator_register()(或者devres版本的devm_regulator_register)将调节器注册到内核,并用regulator_desc和regulator_config作为参数。

其中regulator_register()函数的原型:

  1. struct regulator_dev *regulator_register(const struct regulator_desc *desc,
  2. const struct regulator_config *cfg);

函数regulator_register()返回struct regulator_dev{},这个结构体代表regulator生产者一端的调节器设备实例。

2. remove函数的实现

        驱动程序的remove回调函数回滚probe函数期间的每个操作。其中从内核中删除调节器的函数是:

void regulator_unregister(struct regulator_dev *rdev);

3. 示例:Inter ISL6271A驱动的实现

        该PMIC提供3个调节器,其中一个可以改变输出值,两个提供固定电压:

  i). PMIC驱动的内部结构

  1. struct isl_pmic {
  2. struct i2c_client *client;
  3. struct regulator_dev *rdev[3];
  4. struct mutex mtx;
  5. };

ii). 实现regulator_ops的回调函数

  1. static int isl6271a_get_voltage_sel(struct regulator_dev *rdev) {
  2. struct isl_pmic *pmic = rdev_get_drvdata(rdev);
  3. int idx = rdev_get_id(rdev);
  4. int ret = i2c_smbu_read_byte(pmic->client);
  5. if (ret<0) [...]; // 错误处理
  6. return ret;
  7. }
  8. static int isl6271a_set_voltage_sel(struct regulator_dev *rdev, uint selector) {
  9. struct isl_pmic *pmic = rdev_get_drvdata(rdev);
  10. int ret = i2c_smbu_write_byte(pmic->client, selector);
  11. if (ret<0) [...]; // 错误处理
  12. return ret;
  13. }

iii). 完成回调定义后,可以构建struct regulator_ops{}

  1. static struct regulator_ops isl_core_ops = {
  2. .get_voltage_sel = isl6271a_get_voltage_sel,
  3. .set_voltage_sel = isl6271a_set_voltage_sel,
  4. .list_voltage = regulator_list_voltage_linear,
  5. .map_voltage = regulator_map_voltage_linear,
  6. };
  7. static struct regulator_ops isl_fixed_ops = {
  8. .list_voltage = regulator_list_voltage_linear,
  9. };
  10. // 为所有的调节器构建struct regulator_desc{}数组
  11. static struct regulator_desc isl_rd[] = {
  12. {
  13. .name = "Core Buck",
  14. .id = 0,
  15. .n_voltages = 16,
  16. .ops = &isl_core_ops,
  17. .type = REGULATOR_VOLTAGE,
  18. .owner = THIS_MODULE,
  19. .min_uV = ISL6217A_VOLTAGE_MIN,
  20. .uV_step = ISL6217A_VOLTAGE_STEP,
  21. },
  22. {
  23. .name = "LDO1",
  24. .id = 1,
  25. .n_voltages = 1,
  26. .ops = &isl_fixed_ops,
  27. .type = REGULATOR_VOLTAGE,
  28. .owner = THIS_MODULE,
  29. .min_uV = 1100000,
  30. },
  31. {
  32. .name = "LDO2",
  33. .id = 1,
  34. .n_voltages = 1,
  35. .ops = &isl_fixed_ops,
  36. .type = REGULATOR_VOLTAGE,
  37. .owner = THIS_MODULE,
  38. .min_uV = 1300000,
  39. },
  40. };

LDO1和LDO2具有固定输出电压,其n_voltages属性为1。

iv). 接着在probe函数中构建struct regulator_init_data结构,这将使用前面接收的struct of_regulator_match{},下面是声明的类型:

  1. static struct of_regulator_match isl6217a_matches[] = {
  2. {.name = "Core_buck",}, {.name="ldo1",},{.name="ldo2",},
  3. };

v). 下面是probe函数的实现,

        PMIC由3个调节器,在probe()中需要调用3次regulator_register()。

  1. static int isl_6271a_probe(struct i2c_client *i2c,
  2. const struct i2c_device_id *id) {
  3. struct regulator_config config = {};
  4. struct regulator_init_data *init_data =
  5. dev_get_platdata(&i2c->dev);
  6. struct isl_pmic *pmic;
  7. int i, ret;
  8. struct device *dev = &i2c->dev;
  9. struct device_node *np, *parent;
  10. if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
  11. return -EIO;
  12. pmic = devm_kzalloc(&i2c->dev, sizeof(*pmic), GFP_KERNEL);
  13. if (!pmic) return -ENOMEM;
  14. np = of_node_get(dev->of_node);
  15. parent = of_get_child_by_name(np, "regulators");
  16. // 1. 此处会给isl6217a_matches赋值
  17. ret = of_regulator_match(dev, parent, isl6217a_matches,
  18. ARRAY_SIZE(isl6217a_matches));
  19. pmic->client = i2c;
  20. mutex_init(&pmic->mtx);
  21. // 2. 循环注册3个调节器
  22. for (i=0;i<3;i++) {
  23. struct regulator_init_data *init_data;
  24. struct regulator_desc *desc;
  25. int val;
  26. // 2.1 此处要区分是否使用DT, 获取regulator_init_data{}
  27. if (pdata) config.init_data = pdata->init_data[i];
  28. else config.init_data = isl6217a_matches[i].init_data;
  29. config.dev = &i2c->dev;
  30. config.of_node = isl6217a_matches[i].of_node;
  31. config.ena_gpio = -EINVAL;
  32. // 2.2 注册regulator
  33. pmic->rdev[i] = devm_regulator_register(&i2c->dev, &isl_rd[i], &config);
  34. }
  35. i2c_set_clientdata(i2c, pmic);
  36. return 0;
  37. }

二、调节器消费者接口

        调节器消费者可以是静态和动态的,静态消费者只需要固定电源,动态消费者则需要在运行时对调节器进行主动管理。从消费者角度来看,调节器在内核中表示为struct regulator{}

  1. struct regulator {
  2. struct device *dev;
  3. struct list_head list;
  4. uint always_on:1;
  5. uint bypass:1;
  6. int uA_load;
  7. int min _uV;
  8. int max_uV;
  9. char *supply_name;
  10. struct device_attribute dev_attr;
  11. struct regulator_dev *dev;
  12. struct dentry *debugfs;
  13. };

1 消费者调节器设备请求

        调用regulator_get()获取regulator消费者实例;

  1. // 其中id是regulator在DT中的名称
  2. struct regulator *regulator_get(struct device *dev, const char *id);
  3. //释放regultaor,在释放之前必须确保所有的regulator必须被调用了regulator_disable();
  4. void regulator_put(struct regulator *reg);
  5. //如下示例,一个消费者有可能有多个电源
  6. digital = regulator_get(dev, "vcc");
  7. analog = regulator_get(dev, "Avdd");

2. 控制调节器设备

  1. // 使能或禁止regulator
  2. int regulator_enable(struct regulator *reg);
  3. int regulator_disable(struct regulator *reg);
  4. int regulator_is_enabled(struct regulator *reg);
  5. // 对应共享的调节器,只有其引用计数为0时,才真正会禁用reg
  6. // 设置电压
  7. int regulato_set_voltage(struct regulator *reg, int min_uV, int max_uV);
  8. int regulato_get_voltage(struct regulator *reg);
  9. // 设置电流
  10. int regulato_set_current_limit(struct regulator *reg, int min_uA, int max_uA);
  11. int regulato_get_current_limit(struct regulator *reg);
  12. // 设置regulator的状态
  13. int regulator_set_optimum_mode(struct regulator *reg, int load_uA); // 间接模式,根据电流确定需要的模式
  14. int regulator_set_mode(struct regulator *reg, uint mode);
  15. uint regulator_get_mode(struct regulator *reg);

三、调节器绑定

  1. // 消费者可以使用以下方式绑定若干个电源
  2. <name>-supply: phandle to regulator mode;
  3. // 示例
  4. twl_reg1: {};
  5. twl_reg2: {};
  6. mmc: mmc@0x0 {
  7. vmmc-supply = <&twl_reg1>;
  8. vmmcaux-supply = <&twl_reg2>;
  9. };
  10. // 在probe函数中获取regulator
  11. struct regulator *main_regulator = regulator_get(dev, "vmmc");
  12. struct regulator *aux_regulator = regulator_get(dev, "vmmcaux");

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/826820
推荐阅读
相关标签
  

闽ICP备14008679号