
更多内容可以加入Linux系统知识库套餐(教程+视频+答疑)

休眠唤醒(Power Management)是嵌入式驱动的常见痛点------板子睡死了、唤不醒、唤醒后外设不正常...本文从原理到调试工具,带你搞定 Linux standby 休眠唤醒调试。
一、Linux 休眠方式
Linux 支持多种休眠状态,从浅到深:
| 状态 | 说明 | 功耗 | 唤醒速度 |
|---|---|---|---|
freeze |
冻结用户态 + 停止 I/O,CPU 还在运行 | 高 | 最快 |
standby |
待机,CPU 断电,内存保持 | 中 | 快 |
mem |
Suspend to RAM,内存自刷新,CPU/外设断电 | 低 | 较快 |
disk |
Suspend to Disk,内存写入磁盘,完全断电 | 最低 | 最慢 |
嵌入式常用的是 mem(STR,Suspend to RAM),也就是我们常说的"待机"。
二、休眠唤醒流程
🌙 休眠过程:
用户空间触发休眠 (echo mem > /sys/power/state)
↓
冻结用户态进程
↓
调用各设备驱动的 .suspend 回调
↓
关闭非唤醒中断
↓
CPU 进入低功耗状态
↓
内存自刷新,板子进入待机
☀️ 唤醒过程:
唤醒源触发中断(按键/定时器/网络等)
↓
CPU 恢复运行
↓
调用各设备驱动的 .resume 回调
↓
恢复用户态进程
↓
系统恢复正常运行
三、驱动 PM 操作接口
驱动通过 dev_pm_ops 结构体实现休眠唤醒回调:
static const struct dev_pm_ops my_dev_pm_ops = {
.suspend = my_suspend, // 休眠
.resume = my_resume, // 唤醒
.freeze = my_freeze, // 冻结
.thaw = my_thaw, // 解冻
.prepare = my_prepare, // 休眠前准备
.complete = my_complete, // 唤醒后完成
};
static struct platform_driver my_driver = {
.probe = my_probe,
.remove = my_remove,
.driver = {
.name = "my_device",
.pm = &my_dev_pm_ops, // 关联 PM 操作
},
};
四、常用调试手段
🔧 1. no_console_suspend
休眠时控制台默认会关闭,导致你看不到休眠过程中的打印。在 bootargs 中添加:
no_console_suspend
这样休眠过程中串口控制台保持开启,可以看到完整的休眠唤醒日志。
🔧 2. initcall_debug + no_console_suspend
更详细的设备休眠/唤醒调试信息:
initcall_debug no_console_suspend ignore_loglevel
🔧 3. wakeup_sources 唤醒源
查看哪些设备可以唤醒系统,以及是谁唤醒了系统:
# 查看所有唤醒源
cat /sys/kernel/debug/wakeup_sources
# 查看唤醒计数
cat /sys/power/wakeup_count
# 查看最后一次唤醒原因(平台相关)
cat /sys/kernel/debug/suspend_stats
🔧 4. wake_lock 唤醒锁
系统持有唤醒锁时不会进入休眠。调试"睡不下去"的问题:
# 查看当前持有的唤醒锁
cat /sys/power/wake_lock
cat /sys/power/wake_unlock
# Android 系统常用
dumpsys power | grep WAKE_LOCK
五、休眠失败常见原因
| 问题 | 可能原因 | 排查方向 |
|---|---|---|
| 睡不下去 | 有唤醒锁未释放 | 查看 /sys/power/wake_lock |
| 睡不下去 | 某个驱动 suspend 返回失败 | 开 no_console_suspend 看日志 |
| 睡死了 | 唤醒源未正确配置 | 检查唤醒源是否使能、极性是否正确 |
| 唤醒后外设异常 | 驱动 resume 有问题 | 检查寄存器是否恢复、时钟是否重新使能 |
| 自动唤醒 | 有干扰信号触发中断 | 查看 wakeup_sources 中的 event_count |
六、autosleep 自动休眠
Android 等系统使用 autosleep 机制,没有唤醒锁时自动进入休眠:
# 查看/设置自动休眠模式
cat /sys/power/autosleep
echo mem > /sys/power/autosleep
# 唤醒锁阻止休眠
echo my_wakelock > /sys/power/wake_lock
# 释放唤醒锁
echo my_wakelock > /sys/power/wake_unlock
七、调试步骤总结
第1步:确认能否正常休眠
echo mem > /sys/power/state
第2步:如果睡不下去,开启调试日志
# bootargs 添加
no_console_suspend initcall_debug ignore_loglevel
第3步:检查唤醒源
cat /sys/kernel/debug/wakeup_sources
第4步:逐个驱动排查
# 去掉驱动的 suspend/resume 函数,二分法定位问题