Linux 电源管理 - Linux regulator framework
前言
Regulator 翻译为 “调节器,稳压器”,分为 voltage regulator (电压调节器)和 current regulator (电流调节器),指可以自动维持恒定电压(或电流)的装置。一般电源管理芯片(Power Management IC)中会包含一个甚至多个regulator。
Regulator 通常的作用是给电子设备供电。大多数 regulator 可以启用(enable) 和禁用(disable) 其输出,同时也可以控制其输出电压(voltage) 和电流(current)。 从上图可以看出,input power会经过 regulator 转化为output power,regulator会做如下的约束:
- Voltage control: 输入5V输出1.8V
- Current limiting: 电流的输出最大为20MA
- Power switch: 可以控制电压enable/disable
一、Linux regulator framework 概述
1、简介
Linux Regulator Framework 设计出主要是提供一个标准的内核接口来控制电压和电流调节器。目的是允许系统动态控制 regulator power 输出以节省能源延长电池寿命。这适用于voltage regulator 和current regulator (其中电压和电流都是可控的)。
2、相关专业术语
-
Regulator 如上所述,regulator 用于向其他设备提供电源,可以 enable/disable 其输出,有些可以控制输出 voltage 和 current; Input Voltage -> Regulator -> Output Voltage -
PMIC Power Management IC,一个电源管理芯片可包含多个regulator; -
Consumer 表示一个 regulator 使用者,regulator 是电源的提供者,而 consumer 则是电源的消费者,一个 regulator 可供多个 consumer 使用; Consumer 可以分为两类: Static :consumer does not change its supply voltage or current limit. It only needs to enable or disable its power supply. Its supply voltage is set by the hardware, bootloader, firmware or kernel board initialisation code. Dynamic : consumer needs to change its supply voltage or current limit to meet operation demands. -
Power Domain 电源域,Consumer 被提供输入电源可以由 the output power of a regulator,switch 或 another power domain,如下 one regulators & three power domains: - Domain 1: Switch-1, Consumers D & E. - Domain 2: Switch-2, Consumers B & C. - Domain 3: Consumer A. “supplies” relationship: Domain-1 --> Domain-2 --> Domain-3. -
Constraints 表示regulator的约束,而针对regulator约束也包含三个层次: Regulator Level : 这属于regulator相关的约束信息,可通过regulator的datasheet中获取该regulator的约束信息; Power Domain Level :这属于该regulator下不同电源域的约束信息,这些约束信息时regulator自身约束信息的子集(如regulator的电压输出约束为1v-3.5v;而domain1的约束信息为2v-3v;domain2的约束信息为2.5v等); Consumer Level :可动态设置该consumer所需的输入电压或电流约束等。
3、Framework 组成部分
Linux Regulator Framework 的设计主要分为如下四个部分: [ 具体内容见下方 ]
- Consumer driver interface:
- Regulator driver interface
- Machine interface
- Userspace ABI
参考 See Documentation/power/regulator/overview.rst
二、Linux regulator framework 驱动分析
1、Machine
Regulator Machine 驱动接口用于特定于板级的初始化代码,可以理解为 regulator 在板级的硬件配置,使用 regulator_init_data 结构体代表 regulator 板级的配置,位于 /include/linux/regulator/machine.h ,详细如下:
描述参考 See Documentation/power/regulator/machine.rst
struct regulator_init_data {
const char *supply_regulator;
struct regulation_constraints constraints;
int num_consumer_supplies;
struct regulator_consumer_supply *consumer_supplies;
int (*regulator_init)(void *driver_data);
void *driver_data;
};
对于 regulator 板级配置的约束,定义在 regulator_constraints 结构体中,位于 /include/linux/regulator/machine.h ,详细如下:
struct regulation_constraints {
const char *name;
int min_uV;
int max_uV;
int uV_offset;
int min_uA;
int max_uA;
int ilim_uA;
int max_uV_step;
int input_uV;
struct regulator_state state_disk;
struct regulator_state state_mem;
struct regulator_state state_standby;
suspend_state_t initial_state;
unsigned int initial_mode;
unsigned int ramp_delay;
unsigned int enable_time;
unsigned always_on:1;
unsigned boot_on:1;
unsigned apply_uV:1;
unsigned ramp_disable:1;
};
举例使用:
struct regulator_consumer_supply {
const char *dev_name;
const char *supply;
};
#define REGULATOR_SUPPLY(_name, _dev_name) \
{ \
.supply = _name, \
.dev_name = _dev_name, \
}
static struct regulator_consumer_supply regulator1_consumers[] = {
REGULATOR_SUPPLY("Vcc", "consumer B"),
};
static struct regulator_consumer_supply regulator2_consumers[] = {
REGULATOR_SUPPLY("Vcc", "consumer A"),
};
static struct regulator_init_data regulator1_data = {
.constraints = {
.name = "Regulator-1",
.min_uV = 3300000,
.max_uV = 3300000,
.valid_modes_mask = REGULATOR_MODE_NORMAL,
},
.num_consumer_supplies = ARRAY_SIZE(regulator1_consumers),
.consumer_supplies = regulator1_consumers,
};
static struct regulator_init_data regulator2_data = {
.supply_regulator = "Regulator-1",
.constraints = {
.min_uV = 1800000,
.max_uV = 2000000,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
.valid_modes_mask = REGULATOR_MODE_NORMAL,
},
.num_consumer_supplies = ARRAY_SIZE(regulator2_consumers),
.consumer_supplies = regulator2_consumers,
};
static struct platform_device regulator_devices[] = {
{
.name = "regulator",
.id = DCDC_1,
.dev = {
.platform_data = ®ulator1_data,
},
},
{
.name = "regulator",
.id = DCDC_2,
.dev = {
.platform_data = ®ulator2_data,
},
},
};
platform_device_register(®ulator_devices[0]);
platform_device_register(®ulator_devices[1]);
再如 Linux 内核中 mt6323.dtsi 中使用如下:
mt6323_vproc_reg: buck_vproc{
regulator-name = "vproc";
regulator-min-microvolt = < 700000>;
regulator-max-microvolt = <1350000>;
regulator-ramp-delay = <12500>;
regulator-always-on;
regulator-boot-on;
};
2、Regulator
Regulator 可以理解为 regulator driver,允许 regulator driver 注册到 regulator core framework 中,给 consumer 提供服务。
regulator driver 通过r egulator_register 函数注册 regulator operation 到 regulator core。其中第一个参数 struct regulator_desc 代表静态的regulator 配置,所谓静态就是不再会改变的配置。第二个参数代表 regulator 的动态配置信息。
描述参考 See Documentation/power/regulator/regulator.rst
struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, const struct regulator_config *config);
void regulator_unregister(struct regulator_dev *rdev);
第一个参数定义在 /include/linux/regulator/driver.h ,如下:
struct regulator_desc {
const char *name;
const char *supply_name;
const char *of_match;
bool of_match_full_name;
const char *regulators_node;
int (*of_parse_cb)(struct device_node *,
const struct regulator_desc *,
struct regulator_config *);
int id;
unsigned int continuous_voltage_range:1;
unsigned n_voltages;
unsigned int n_current_limits;
const struct regulator_ops *ops;
int irq;
enum regulator_type type;
struct module *owner;
unsigned int min_uV;
unsigned int uV_step;
unsigned int linear_min_sel;
int fixed_uV;
unsigned int ramp_delay;
const struct linear_range *linear_ranges;
const unsigned int *linear_range_selectors;
int n_linear_ranges;
const unsigned int *volt_table;
const unsigned int *curr_table;
unsigned int vsel_range_reg;
unsigned int vsel_range_mask;
unsigned int vsel_reg;
unsigned int vsel_mask;
unsigned int vsel_step;
unsigned int csel_reg;
unsigned int csel_mask;
unsigned int apply_reg;
unsigned int apply_bit;
unsigned int enable_reg;
unsigned int enable_mask;
unsigned int enable_val;
unsigned int disable_val;
bool enable_is_inverted;
unsigned int bypass_reg;
unsigned int bypass_mask;
unsigned int bypass_val_on;
unsigned int bypass_val_off;
unsigned int active_discharge_on;
unsigned int active_discharge_off;
unsigned int active_discharge_mask;
unsigned int active_discharge_reg;
unsigned int soft_start_reg;
unsigned int soft_start_mask;
unsigned int soft_start_val_on;
unsigned int pull_down_reg;
unsigned int pull_down_mask;
unsigned int pull_down_val_on;
unsigned int ramp_reg;
unsigned int ramp_mask;
const unsigned int *ramp_delay_table;
unsigned int n_ramp_values;
unsigned int enable_time;
unsigned int off_on_delay;
unsigned int poll_enabled_time;
unsigned int (*of_map_mode)(unsigned int mode);
};
其中 struct regulator_ops 是对此 regulator 硬件操作的封装,其中包含获取电压、设置电压等的成员函数,
struct regulator_ops {
int (*list_voltage) (struct regulator_dev *, unsigned selector);
int (*set_voltage) (struct regulator_dev *, int min_uV, int max_uV,
unsigned *selector);
int (*map_voltage)(struct regulator_dev *, int min_uV, int max_uV);
int (*set_voltage_sel) (struct regulator_dev *, unsigned selector);
int (*get_voltage) (struct regulator_dev *);
int (*get_voltage_sel) (struct regulator_dev *);
int (*set_current_limit) (struct regulator_dev *,
int min_uA, int max_uA);
int (*get_current_limit) (struct regulator_dev *);
int (*set_input_current_limit) (struct regulator_dev *, int lim_uA);
int (*set_over_current_protection)(struct regulator_dev *, int lim_uA,
int severity, bool enable);
int (*set_over_voltage_protection)(struct regulator_dev *, int lim_uV,
int severity, bool enable);
int (*set_under_voltage_protection)(struct regulator_dev *, int lim_uV,
int severity, bool enable);
int (*set_thermal_protection)(struct regulator_dev *, int lim,
int severity, bool enable);
int (*set_active_discharge)(struct regulator_dev *, bool enable);
int (*enable) (struct regulator_dev *);
int (*disable) (struct regulator_dev *);
int (*is_enabled) (struct regulator_dev *);
int (*set_mode) (struct regulator_dev *, unsigned int mode);
unsigned int (*get_mode) (struct regulator_dev *);
int (*get_error_flags)(struct regulator_dev *, unsigned int *flags);
int (*enable_time) (struct regulator_dev *);
int (*set_ramp_delay) (struct regulator_dev *, int ramp_delay);
int (*set_voltage_time) (struct regulator_dev *, int old_uV,
int new_uV);
int (*set_voltage_time_sel) (struct regulator_dev *,
unsigned int old_selector,
unsigned int new_selector);
int (*set_soft_start) (struct regulator_dev *);
int (*get_status)(struct regulator_dev *);
unsigned int (*get_optimum_mode) (struct regulator_dev *, int input_uV,
int output_uV, int load_uA);
int (*set_load)(struct regulator_dev *, int load_uA);
int (*set_bypass)(struct regulator_dev *dev, bool enable);
int (*get_bypass)(struct regulator_dev *dev, bool *enable);
int (*set_suspend_voltage) (struct regulator_dev *, int uV);
int (*set_suspend_enable) (struct regulator_dev *);
int (*set_suspend_disable) (struct regulator_dev *);
int (*set_suspend_mode) (struct regulator_dev *, unsigned int mode);
int (*resume)(struct regulator_dev *rdev);
int (*set_pull_down) (struct regulator_dev *);
};
此结构体详细描述可以直接查看 /include/linux/regulator/driver.h 。
第二个参数为 struct regulator_config,代表 regulator 的动态配置信息,位于 /include/linux/regulator/driver.h ,如下:
struct regulator_config {
struct device *dev;
const struct regulator_init_data *init_data;
void *driver_data;
struct device_node *of_node;
struct regmap *regmap;
struct gpio_desc *ena_gpiod;
};
当调用 regulator_register 函数之后,传入静态和动态参数之后,就会返回一个 regulator_dev 结构(位于 /include/linux/regulator/driver.h )。此结构可以认为是 regulator 设备的一个抽象描述。
struct regulator_dev {
const struct regulator_desc *desc;
int exclusive;
u32 use_count;
u32 open_count;
u32 bypass_count;
struct list_head list;
struct list_head consumer_list;
struct coupling_desc coupling_desc;
struct blocking_notifier_head notifier;
struct ww_mutex mutex;
struct task_struct *mutex_owner;
int ref_cnt;
struct module *owner;
struct device dev;
struct regulation_constraints *constraints;
struct regulator *supply;
const char *supply_name;
struct regmap *regmap;
struct delayed_work disable_work;
void *reg_data;
struct dentry *debugfs;
struct regulator_enable_gpio *ena_pin;
unsigned int ena_gpio_state:1;
unsigned int is_switch:1;
ktime_t last_off;
int cached_err;
bool use_cached_err;
spinlock_t err_lock;
};
3、Consumer
Consumer drivers can get and put a regulator (like they can with clocks atm) and get/set voltage , current limit , mode , enable and disable .
详细描述参考 See Documentation/power/regulator/consumer.rst
4、sysfs-class-regulator
regulator core framework 通过sysfs文件系统导出了一些 "voltage/current/opmode" 相关的信息,此将很有帮忙监控设备的功耗使用情况。
详细描述参考 See Documentation/ABI/testing/sysfs-class-regulator
三、Linux regulator 常见 API
Linux 的 Regulator 子系统提供消费者 (Consumer) API 以便其他的驱动获取、设置、关闭和使能 regulator 等。
1、获取/释放regulator
struct regulator * regulator_get(struct device *dev,
const char *id);
struct regulator * devm_regulator_get(struct device *dev,
const char *id);
void regulator_put(struct regulator *regulator);
void devm_regulator_put(struct regulator *regulator);
2、Enable and disable regulator
int regulator_enable(regulator);
int regulator_disable(regulator);
int regulator_force_disable(regulator);
3、设置 regulator 的电压,获得 regulator 的电压状态、设置 regulator 的电流,获得 regulator 的电流状态
int regulator_set_voltage(regulator, min_uV, max_uV);
int regulator_get_voltage(regulator);
int regulator_set_current_limit(regulator, min_uA, max_uA);
int regulator_get_current_limit(regulator);
4、regulator的模式设置,间接(通过负载),直接设置
int regulator_set_optimum_mode(struct regulator *regulator, int load_uA);
int regulator_set_mode(struct regulator *regulator, unsigned int mode);
unsigned int regulator_get_mode(struct regulator *regulator);
5、Regulator Driver interface
struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
const struct regulator_config *config);
void regulator_unregister(struct regulator_dev *rdev);
int regulator_notifier_call_chain(struct regulator_dev *rdev,
unsigned long event, void *data);
四、Linux regulator 使用举例
在内核 drivers/regulator/dummy.c 文件中构造了一个虚拟的 regulator 可以参考,如下: drivers/regulator/dummy.c
对于使用可以参考 mt6323 的 regulator 使用, (1) dts: arch/arm/boot/dts/mt6323.dtsi (2) driver:drivers/regulator/mt6323-regulator.c
参考链接 - Linux电源管理-Linux regulator framework概述 参考链接 - Linux电源管理-Linux Regulator Framework代码分析
|