在嵌入式系统中,Power(电源)管理驱动既关乎系统稳定性,又直接影响功耗与续航,是系统设计中绕不开的核心模块。今天我们通过理论+实战的形式,一次性讲清楚:
Linux 电源管理分为以下三个层次:
层次 | 内容 | 说明 |
---|---|---|
系统级管理 | suspend/resume,runtime PM | 由电源管理核心子系统协调进行 |
子系统级管理 | CPUFreq、Devfreq、Regulator | 管理不同类别设备的电源行为 |
驱动级控制 | PMIC 驱动、电源域、GPIO 控制 | 对具体硬件进行控制、管理寄存器 |
我们今天的重点是regulator 框架下的电源驱动,常用于处理 LDO、BUCK 这类片上 PMIC 模块的控制逻辑。
Regulator 框架是 Linux 电源管理子系统的一部分,主要用来:
它的核心结构包括:
struct regulator_desc {
const char *name; // 电源名称,如 buck1
int id; // 电源编号
const struct regulator_ops *ops; // 驱动操作集
...
};
驱动需要实现一组 regulator_ops
接口,如下:
struct regulator_ops {
int (*enable)(struct regulator_dev *rdev);
int (*disable)(struct regulator_dev *rdev);
int (*is_enabled)(struct regulator_dev *rdev);
int (*set_voltage_sel)(...);
int (*get_voltage_sel)(...);
...
};
在设备树中,设备的电源依赖使用 phandle
来建立连接。例如:
buck2: regulator@2 {
compatible = "regulator-fixed";
regulator-name = "buck2";
regulator-min-microvolt = <900000>;
regulator-max-microvolt = <900000>;
};
cpu0: cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a53";
cpu-supply = <&buck2>; // 使用 phandle 引用 buck2 节点
};
这代表:cpu0
的供电依赖 buck2
。
在驱动中通过 of_parse_phandle()
获取电源节点,并用 devm_regulator_get()
接口建立依赖:
supply = devm_regulator_get(&pdev->dev, "cpu");
regulator_enable(supply);
在 NXP 的 i.MX8MP 平台中,PCA9450 是一个典型的 PMIC 芯片,提供多个 BUCK 和 LDO 通道。
设备树部分如下:
pmic: pca9450@25 {
compatible = "nxp,pca9450a";
reg = <0x25>;
regulators {
buck1_reg: BUCK1 {
regulator-name = "buck1";
regulator-min-microvolt = <700000>;
regulator-max-microvolt = <1400000>;
regulator-boot-on;
};
...
};
};
驱动中注册每个电源通道:
rdev = devm_regulator_register(pca9450->dev, desc, &config);
并实现每个通道的操作逻辑,包括电压调节、开关控制、DVS 支持等。
电源树(Power Tree)是整个板级系统的供电架构图。例如:
在设备树中通过 <&buckX>
建立这些依赖关系,确保在设备 probe 时自动 enable 对应电源。
Linux 内核通过 regulator 框架实现:
regulator_enable()
自动打开电源regulator_set_voltage()
设置需要的电压# 查看注册的 regulator
cat /sys/class/regulator/*/name
cat /sys/class/regulator/*/state
cat /sys/class/regulator/*/microvolts
# 查看绑定信息
ls /sys/bus/i2c/devices/0-0025/regulator.*
如果在设备树中添加了 regulator-always-on
或 regulator-boot-on
,则系统启动时该电源会自动打开。
Q1:设备树中 regulator-name 有什么作用?
这是注册到内核中的 regulator 名称,供 regulator_get()
使用。
Q2:没有硬件是否能模拟 regulator ?
可以通过 regulator-dummy
模拟一个虚拟供电器,常用于测试场景。
dummy_reg: dummy {
compatible = "regulator-dummy";
regulator-name = "dummy";
};
Q3:BUCK 与 LDO 有何区别?
项目 | BUCK(降压) | LDO(线性稳压) |
---|---|---|
原理 | 开关控制、效率高 | 电阻电流分压、简单 |
效率 | 高(>80%) | 低(50~70%) |
用途 | 核心供电 | IO、低电流场景 |
关键点 | 说明 |
---|---|
Regulator 框架 | 管理系统中电源开关、调压、依赖关系 |
设备树配合 | 使用 <&buckX> + cpu-supply 实现供电绑定 |
驱动实现 | 实现 regulator_desc + regulator_ops 注册每个电源 |
实战关键 | 理解 power tree 与驱动初始化之间的供电依赖 |
《设备树深度解析:理论 + 实践全指南》
《驱动开发硬核特训 · Day 8:平台 vs 总线驱动模型》
《驱动开发硬核特训 · Day 11:虚拟总线驱动模型原理与实践》
视频教程请关注 B 站:“嵌入式 Jerry”