2,832
社区成员




在 Linux 驱动中实现电源管理(如设备休眠和唤醒)需要结合内核的 Runtime Power Management (Runtime PM) 和 System Suspend/Resume 机制。以下是详细的实现步骤和代码示例:
在驱动的 file_operations
或设备树节点中注册 suspend
和 resume
回调:
#include <linux/pm.h>
static int my_device_suspend(struct device *dev)
{
// 关闭设备时钟、禁用中断等
disable_irq(dev->irq);
clk_disable_unprepare(my_clk);
printk(KERN_INFO "Device suspended\n");
return 0;
}
static int my_device_resume(struct device *dev)
{
// 重新启用中断、启动时钟等
enable_irq(dev->irq);
clk_prepare_enable(my_clk);
printk(KERN_INFO "Device resumed\n");
return 0;
}
static const struct dev_pm_ops my_pm_ops = {
.suspend = my_device_suspend,
.resume = my_device_resume,
.freeze = my_device_suspend, // 用于 hibernation
.thaw = my_device_resume, // 用于 hibernation
};
在驱动初始化时,将 dev_pm_ops
绑定到设备:
static struct platform_driver my_driver = {
.probe = my_device_probe,
.remove = my_device_remove,
.driver = {
.name = "my_device",
.pm = &my_pm_ops, // 绑定电源管理
},
};
在设备探测时启用运行时电源管理:
static int my_device_probe(struct platform_device *pdev)
{
pm_runtime_enable(&pdev->dev); // 启用 Runtime PM
return 0;
}
static int my_device_remove(struct platform_device *pdev)
{
pm_runtime_disable(&pdev->dev); // 禁用 Runtime PM
return 0;
}
若设备需要唤醒系统,需配置中断和唤醒能力:
static irqreturn_t my_irq_handler(int irq, void *dev_id)
{
// 处理中断事件
printk(KERN_INFO "Interrupt occurred, waking up device\n");
return IRQ_HANDLED;
}
static int my_device_probe(struct platform_device *pdev)
{
// 注册中断
int irq = platform_get_irq(pdev, 0);
request_irq(irq, my_irq_handler, IRQF_TRIGGER_FALLING | IRQF_NO_SUSPEND, "my_irq", dev);
// 标记设备支持唤醒
device_set_wakeup_capable(&pdev->dev, true);
device_set_wakeup_enable(&pdev->dev, true); // 启用唤醒功能
return 0;
}
通过 sysfs 接口手动控制电源状态:
# 查看设备电源状态
cat /sys/devices/platform/my_device/power/runtime_status
# 强制挂起设备(Runtime PM)
echo suspend > /sys/devices/platform/my_device/power/control
# 触发系统挂起
echo mem > /sys/power/state
pm_runtime_enable(dev)
:启用运行时电源管理。pm_runtime_get(dev)
:增加设备引用计数,阻止休眠。pm_runtime_put(dev)
:减少引用计数,允许休眠。device_suspend()
和 device_resume()
:内核内部调用的回调。systemctl suspend
或 echo mem > /sys/power/state
。irq_set_irq_wake(irq, 1)
:标记中断为唤醒源。device_set_wakeup_enable(dev, true)
:启用设备唤醒能力。# 查看系统电源状态
cat /sys/power/state
# 查看设备 Runtime PM 状态
cat /sys/devices/platform/my_device/power/runtime_status
# 挂起系统
sudo bash -c "echo mem > /sys/power/state"
# 唤醒后检查设备日志
dmesg | grep "Device resumed"
# 查看哪些设备触发了唤醒
cat /proc/acpi/wakeup
irq_set_irq_wake(irq, 1); // 在驱动中标记中断为唤醒源
device_set_wakeup_enable(dev, true);
resume
回调未正确重新初始化硬件。resume
中恢复寄存器、时钟和中断状态。pm_runtime_get/put
。pm_runtime_get()
,空闲时调用 pm_runtime_put()
。通过 device_add锦标赛
定义复杂电源状态(如低功耗模式)。
使用 pm_runtime_set_autosuspend_delay()
设置自动挂起延迟。
实现 Linux 驱动的电源管理需结合 Runtime PM 和 System Suspend/Resume,核心步骤包括:
suspend/resume
回调。通过合理设计,可显著降低设备功耗并提升系统能效。