linux 电源管理

Linux内核中电源管理是个比较庞大系统,本次仅记录电源状态管理相关部分。

linux 四种睡眠状态

State in Linux Label state ACPI 备注
PM_SUSPEND_ON 正常 正常 正常 正常运行状态
PM_SUSPEND_FREEZE freeze suspend-to-idle S0 冻结进程+挂起设备+CPU空闲
PM_SUSPEND_STANDBY standby power-on suspend S1 冻结进程+挂起设备+关闭nonbootCPU
PM_SUSPEND_MEM mem suspend-to-ram S3 仅保留RAM自刷新
PM_SUSPEND_MAX disk suspend-to-disk S4 关闭所有设备包括RAM,也被称为Hibernate

对应源码:/kernel/kernel/power/suspend.c

  • Suspend-To-Idle: 轻量级睡眠状态,冻结用户空间进程并将 I/O 设备置于低功耗状态,具有较低的恢复延迟。
  • Power-On Suspend: Standby 状态,进一步关闭非启动 CPU,相较于 Idle 状态节省更多功耗。
  • Suspend-to-RAM: 待机状态,将系统状态存放在 RAM 中,其他设备进入低功耗状态。
  • Suspend-to-disk: 休眠状态,数据写入磁盘,关闭所有设备,包括 RAM,最省功耗。

查看当前系统支持的睡眠状态

1
2
cat /sys/power/state 

会显示出以上”Label”对应的状态

Linux内核suspend过程函数流程如下:

1
2
3
4
5
6
7
 state_store()
-->pm_suspend()
-->enter_state()
-->suspend_prepare()
-->suspend_devices_and_enter()
-->suspend_enter()
-->suspend_finish()
  • state_store(): 解析用户输入,转换为 state 参数。
  • pm_suspend(): 处理不同类型的 suspend(freeze、standby、mem)。
  • enter_state(): 进行系统睡眠的公共准备工作。
  • suspend_prepare(): 进行挂起前的准备工作,如冻结控制台和进程。
  • suspend_devices_and_enter(): 进行设备挂起与恢复的对称操作。
  • suspend_enter(): 所有设备挂起后调用,处理不同的 suspend 类型。
  • suspend_finish(): 解冻进程,恢复系统。

Regulator 框架与驱动

Regulator 框架概述

Regulator 框架是 Linux 内核中用于管理电压和电流调节器(如 LDO、DCDC 转换器等)的一个子系统。它提供了一个抽象层,使得驱动程序和内核的其他部分可以以一致的方式与调节器进行交互,而无需了解底层硬件的细节。

主要功能包括:

  • 控制电压的启停。
  • 调整输出电压。
  • 查询当前电压状态。
  • 保护系统不受过流或过压的影响。

Regulator 框架结构

Regulator 框架由三个主要部分组成:

  • Consumer(消费者): 使用调节器的设备或驱动程序。例如,处理器、显示设备等都可能是消费者。消费者通过框架 API 向调节器请求所需的电压或电流。

  • Regulator Driver(调节器驱动): 直接控制硬件调节器的驱动程序。它实现了特定调节器的操作,如打开或关闭调节器、设置电压、读取状态等。

  • Core(核心): 提供 API 和基础设施,将 Consumer 和 Regulator Driver 连接起来,并负责管理调节器的状态和配置。

Regulator API

开发者可以通过 Regulator API 与调节器交互,常用的 API 函数包括:
regulator_get():获取一个调节器的句柄。
regulator_enable(): 启用调节器。
regulator_disable(): 禁用调节器。
regulator_set_voltage(): 设置调节器的输出电压。
regulator_get_voltage(): 获取当前调节器的输出电压。
regulator_is_enabled(): 检查调节器是否已启用。

Regulator 驱动开发

编写一个新的调节器驱动程序通常包括以下步骤:

定义 regulator_ops: 首先,定义一个 regulator_ops 结构体,列出所有需要实现的操作函数,如启用、禁用、设置电压等。

1
2
3
4
5
6
7
static struct regulator_ops my_regulator_ops = {
.enable = my_regulator_enable,
.disable = my_regulator_disable,
.set_voltage = my_regulator_set_voltage,
.get_voltage = my_regulator_get_voltage,
.is_enabled = my_regulator_is_enabled,
};

注册调节器: 然后,使用 regulator_register() 函数将调节器驱动注册到内核中。

1
2
regulator_register(&my_regulator_desc, &my_regulator_config);

实现调节器的操作函数: 最后,开发者需要实现 regulator_ops 中列出的函数来控制实际的硬件。

设备树示例

以RK平台为例,以下是给定的 LCD的供电配置:

1
2
3
4
5
6
7
8
vcc3v3_lcd_n: vcc3v3-lcd0-n {
compatible = "regulator-fixed";
regulator-name = "vcc3v3_lcd0_n";
regulator-boot-on;
enable-active-high;
gpio = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>;
vin-supply = <&vcc_1v8_s3>;
};

regulator-name:用于标识调节器的名称
regulator-min-microvolt 和 regulator-max-microvolt 定义了调节器的输出电压范围
regulator-boot-on:指定跟随boot启用
gpio:描述了用于控制调节器的 GPIO。
vin-supply:指名供电的源