赞
踩
调节器Regulator是为其他设备供电的设备。由regulator供电的设备称为消费者。提供调节器的芯片称为电源集成电路PMIC。调节器可以启用/禁用其输出,也可以控制其输出电压和电流。
生产者是产生调节电压电流的设备,这个设备的名称是PMIC,可用于控制加电时序、电池管理、DC-DC转换或简单的电源开关。
内核通过struct regulator_desc{}描述PMIC提供的每个调节器。所谓的调节器是一个可以独立调节的输出,例如Intersil的ISL6217A是一款具有3个独立调节输出的PMIC,因此其驱动程序应该有3个regulator_desc{}实例。
- struct regulator_desc {
- const char* name;
- const char *of_match;
- int id; // 调节器的数字标识
- unsigned n_voltages; // 调节器可输出的数值数量,如果是固定输出电压,则为1.
- const struct regulator_ops *ops;
- int irq; // 调节器的中断号
- enum regulator_type type; // 是电压调节器还是电流调节器,REGULATOR_VOLTAGE, REGULATOR_CURRENT
- struct module *owner;
- uint min_uV; // 调节器可以输出的最小电压值
- uint uV_step; // 每个选择器的电压增量
- };
当PMIC向消费者公开调节器时,它必须借助于struct regulator_restraints{}结构为调节器加一些名义上的限制。这个结构收集调节器的安全限制,定义消费者不能跨越的边界。这是调节器驱动程序和消费者驱动程序之间的一种约定:
- struct regulator_constraints {
- const char *name;
- //电压输出范围
- int min_uV;
- int max_uV;
- int uV_offset; // 应用于消费者的电压偏移量,以补偿电压下降
- // 电流输出范围
- int min_uA;
- int max_uA;
-
- uint valid_modes_mask; // 消费者可能配置的模式的掩码
- uint valid_ops_mask; // 消费者可能执行的操作的掩码
-
- // 系统位于磁盘模式、内存模式、待机模式时regulator的状态;
- struct regulator_state state_disk;
- struct regulator_state state_mem;
- struct regulator_state state_standby;
- suspend_state_t initial_state; // 在init处设置挂起状态
-
- uint initial_mode; // 启动时要设置的模式
- unsigned always_on:1;
- unsigned boot_on:1;
- unsigned apply_uV:1; //
- };
初始化数据结构struct regulator_init_data{},可以通过SoC文件或DT树把初始化数据结构传递给驱动程序,在DT树模式下可以用of_get_regulator_init_data()获取数据结构:
- struct regulator_init_data {
- struct regulation_constraints constraints;
- int (*regulator_init)(void *driver_data);
- void *driver_data;
- };
-
- // 将初始化数据放入SoC的开发板文件中,示例intersil的ISL6271A
- static struct regulator_init_data isl_init_data[] = {
- [0] = { .constraints = { .name = "Core Buck",
- .min_uV = 850000,
- .max_uV = 1600000,
- .valid_modes_mask = REGULATOR_MODE_NORMAL | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS,
- },
- },
- [1] = { .constraints = { .name = "LDO1",
- .min_uV = 1100000,
- .max_uV = 1100000,
- .always_on = true,
- .valid_modes_mask = REGULATOR_MODE_NORMAL | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS,
- },
- },
- [0] = { .constraints = { .name = "LDO2",
- .min_uV = 1300000,
- .max_uV = 1300000,
- .always_on = true,
- .valid_modes_mask = REGULATOR_MODE_NORMAL | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS,
- },
- },
- };
DT文件中绑定,每个PMIC设备的节点都需要有一个名为regulators的子节点,在子节点regulators中声明PMIC的每个调节器regulator。各个调节器具体DT节点属性和具体示例如下:
- // 和regulator相关的标准属性
- /*
- regulator-name:字符串,作为调节器输出的描述性名称;
- regulator-min-microvolt:消费者可以设置的最低电压
- regulator-max-microvolt:消费者可以设置的最高电压
- regulator-microvolt-offset:应用于电压的偏移量,以补偿消费者的电压下降
- regulator-min-microamp:消费者可以设置的最小电流
- regulator-max-microamp:消费者可以设置的最大电流
- regulator-always-on:bool值,说明调节器永不禁用
- regulator-boot-on:由引导加载程序/固件启用的调节器
- <name>-handler : 指向父节点/调节器节点的phandle
- regulator-ramp-delay:调节器的斜坡延迟(单位uV/uS)
- 这些属性和regulator_init_data{}.regulator_constraints{}中的字段基本相同
- */
-
- // 示例,ISL6271A的驱动程序的DT如下:
- isl6271a@3c {
- compatible = "isl6271a";
- reg = <0x3c>;
- interrupts = <0 86 0x4>;
-
- in-v1-supply = <&some_reg>; // 假设该PMIC由另一个调节器供电
- [...]
-
- regulators {
- reg1: core_buck {
- regulator-name="Core Buck";
- regulator-min-microvolt = <850000>;
- regulator-max-microvolt = <1600000>;
- };
- reg2: ldo1 {
- regulator-name="LDO1";
- regulator-min-microvolt = <1100000>;
- regulator-max-microvolt = <1100000>;
- regulator-always-on;
- };
- reg3: ldo2 {
- regulator-name="LDO1";
- regulator-min-microvolt = <1300000>;
- regulator-max-microvolt = <1300000>;
- regulator-always-on;
- };
- };
- };
使用DT文件的方式把初始化数据引入到regulator驱动程序中:
- // 为了使用DT,首先需要引入数据结构struct struct_regulator_match{}
- struct struct_regulator_match{
- const char *name;
- void *driver_data;
- struct regulator_init_data *init_data;
- struct device_node *of_node;
- const struct regulator_desc *desc;
- };
在PMIC驱动程序的probe函数中,使用内核辅助函数of_regulator_match()时,将regulators的子节点作为参数传递给它,该函数将遍历每个调节器的节点,并为其建立一个struct regulator_init_data{}结构;
调节器设备通过struct regulator_config{}结构进行配置。在向内核注册调节器时,该结构被传递给regulator框架:
- struct regulator_config {
- struct device *dev; // 调节器设备所属的struct device
- const struct regulator_init_data *init_data;
- void *driver_data; // 保存调节器的私有数据
- struct device_node *of_node;
- };
调节器设备通过struct regulator_config{}是表示调节器可执行的所有操作的回调列表。
- struct regulator_ops {
- // 枚举支持的电压值
- int (*list_voltage)(struct regulator_dev *reg, unsigned selector);
- // 获取或设置电压调节器
- int (*set_voltage)(struct regulator_dev *reg, int min_uV,
- int max_uV, uint *selector);
- int (*map_voltage)(struct regulator_dev *reg, int min_uV,
- int max_uV);
- int (*set_voltage_sel)(struct regulator_dev *reg, uint selector);
- int (*get_voltage)(struct regulator_dev *reg);
- int (*get_voltage_sel)(struct regulator_dev *reg);
-
- // 获取或设置电流调节器
- int (*set_current_limit)(struct regulator_dev *reg, int min_uA, int max_uA);
- int (*get_current_limit)(struct regulator_dev *reg);
- int (*set_input_current_limit)(struct regulator_dev *reg, int lim_uA);
- int (*set_owner_current_protection)(struct regulator_dev *reg);
- int (*set_active_discharge)(struct regulator_dev *reg, bool enable);
-
- int (*enable)(struct regulator_dev *reg);
- int (*disable)(struct regulator_dev *reg);
- int (*is_enabled)(struct regulator_dev *reg);
-
- int (*set_mode)(struct regulator_dev *reg, uint mode);
- uint (*get_mode)(struct regulator_dev *reg);
- };
-
-
- // 在这些回调函数中参数为regulator_dev{},调用rdev_get_id()可获得对应调节器的id,
- int rdev_get_id(struct regulator_dev *rdev);
PMIC驱动程序的实现可分为几个步骤:
其中regulator_register()函数的原型:
- struct regulator_dev *regulator_register(const struct regulator_desc *desc,
- const struct regulator_config *cfg);
函数regulator_register()返回struct regulator_dev{},这个结构体代表regulator生产者一端的调节器设备实例。
驱动程序的remove回调函数回滚probe函数期间的每个操作。其中从内核中删除调节器的函数是:
void regulator_unregister(struct regulator_dev *rdev);
该PMIC提供3个调节器,其中一个可以改变输出值,两个提供固定电压:
i). PMIC驱动的内部结构
- struct isl_pmic {
- struct i2c_client *client;
- struct regulator_dev *rdev[3];
- struct mutex mtx;
- };
ii). 实现regulator_ops的回调函数
- static int isl6271a_get_voltage_sel(struct regulator_dev *rdev) {
- struct isl_pmic *pmic = rdev_get_drvdata(rdev);
- int idx = rdev_get_id(rdev);
- int ret = i2c_smbu_read_byte(pmic->client);
- if (ret<0) [...]; // 错误处理
- return ret;
- }
-
- static int isl6271a_set_voltage_sel(struct regulator_dev *rdev, uint selector) {
- struct isl_pmic *pmic = rdev_get_drvdata(rdev);
- int ret = i2c_smbu_write_byte(pmic->client, selector);
- if (ret<0) [...]; // 错误处理
- return ret;
- }
iii). 完成回调定义后,可以构建struct regulator_ops{}
- static struct regulator_ops isl_core_ops = {
- .get_voltage_sel = isl6271a_get_voltage_sel,
- .set_voltage_sel = isl6271a_set_voltage_sel,
- .list_voltage = regulator_list_voltage_linear,
- .map_voltage = regulator_map_voltage_linear,
- };
-
- static struct regulator_ops isl_fixed_ops = {
- .list_voltage = regulator_list_voltage_linear,
- };
-
- // 为所有的调节器构建struct regulator_desc{}数组
- static struct regulator_desc isl_rd[] = {
- {
- .name = "Core Buck",
- .id = 0,
- .n_voltages = 16,
- .ops = &isl_core_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
- .min_uV = ISL6217A_VOLTAGE_MIN,
- .uV_step = ISL6217A_VOLTAGE_STEP,
- },
- {
- .name = "LDO1",
- .id = 1,
- .n_voltages = 1,
- .ops = &isl_fixed_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
- .min_uV = 1100000,
- },
- {
- .name = "LDO2",
- .id = 1,
- .n_voltages = 1,
- .ops = &isl_fixed_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
- .min_uV = 1300000,
- },
- };
LDO1和LDO2具有固定输出电压,其n_voltages属性为1。
iv). 接着在probe函数中构建struct regulator_init_data结构,这将使用前面接收的struct of_regulator_match{},下面是声明的类型:
- static struct of_regulator_match isl6217a_matches[] = {
- {.name = "Core_buck",}, {.name="ldo1",},{.name="ldo2",},
- };
v). 下面是probe函数的实现,
PMIC由3个调节器,在probe()中需要调用3次regulator_register()。
- static int isl_6271a_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id) {
- struct regulator_config config = {};
- struct regulator_init_data *init_data =
- dev_get_platdata(&i2c->dev);
- struct isl_pmic *pmic;
- int i, ret;
- struct device *dev = &i2c->dev;
- struct device_node *np, *parent;
-
- if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- return -EIO;
- pmic = devm_kzalloc(&i2c->dev, sizeof(*pmic), GFP_KERNEL);
- if (!pmic) return -ENOMEM;
- np = of_node_get(dev->of_node);
- parent = of_get_child_by_name(np, "regulators");
- // 1. 此处会给isl6217a_matches赋值
- ret = of_regulator_match(dev, parent, isl6217a_matches,
- ARRAY_SIZE(isl6217a_matches));
- pmic->client = i2c;
- mutex_init(&pmic->mtx);
- // 2. 循环注册3个调节器
- for (i=0;i<3;i++) {
- struct regulator_init_data *init_data;
- struct regulator_desc *desc;
- int val;
- // 2.1 此处要区分是否使用DT, 获取regulator_init_data{}
- if (pdata) config.init_data = pdata->init_data[i];
- else config.init_data = isl6217a_matches[i].init_data;
- config.dev = &i2c->dev;
- config.of_node = isl6217a_matches[i].of_node;
- config.ena_gpio = -EINVAL;
- // 2.2 注册regulator
- pmic->rdev[i] = devm_regulator_register(&i2c->dev, &isl_rd[i], &config);
- }
- i2c_set_clientdata(i2c, pmic);
- return 0;
- }
调节器消费者可以是静态和动态的,静态消费者只需要固定电源,动态消费者则需要在运行时对调节器进行主动管理。从消费者角度来看,调节器在内核中表示为struct regulator{}
- struct regulator {
- struct device *dev;
- struct list_head list;
- uint always_on:1;
- uint bypass:1;
- int uA_load;
- int min _uV;
- int max_uV;
- char *supply_name;
- struct device_attribute dev_attr;
- struct regulator_dev *dev;
- struct dentry *debugfs;
- };
调用regulator_get()获取regulator消费者实例;
- // 其中id是regulator在DT中的名称
- struct regulator *regulator_get(struct device *dev, const char *id);
-
- //释放regultaor,在释放之前必须确保所有的regulator必须被调用了regulator_disable();
- void regulator_put(struct regulator *reg);
-
- //如下示例,一个消费者有可能有多个电源
- digital = regulator_get(dev, "vcc");
- analog = regulator_get(dev, "Avdd");
- // 使能或禁止regulator
- int regulator_enable(struct regulator *reg);
- int regulator_disable(struct regulator *reg);
-
- int regulator_is_enabled(struct regulator *reg);
-
- // 对应共享的调节器,只有其引用计数为0时,才真正会禁用reg
-
- // 设置电压
- int regulato_set_voltage(struct regulator *reg, int min_uV, int max_uV);
- int regulato_get_voltage(struct regulator *reg);
-
- // 设置电流
- int regulato_set_current_limit(struct regulator *reg, int min_uA, int max_uA);
- int regulato_get_current_limit(struct regulator *reg);
-
- // 设置regulator的状态
- int regulator_set_optimum_mode(struct regulator *reg, int load_uA); // 间接模式,根据电流确定需要的模式
- int regulator_set_mode(struct regulator *reg, uint mode);
- uint regulator_get_mode(struct regulator *reg);
- // 消费者可以使用以下方式绑定若干个电源
- <name>-supply: phandle to regulator mode;
-
- // 示例
- twl_reg1: {};
- twl_reg2: {};
-
- mmc: mmc@0x0 {
- vmmc-supply = <&twl_reg1>;
- vmmcaux-supply = <&twl_reg2>;
- };
-
- // 在probe函数中获取regulator
- struct regulator *main_regulator = regulator_get(dev, "vmmc");
- struct regulator *aux_regulator = regulator_get(dev, "vmmcaux");
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。