作者
QQ群:852283276
微信:arm80x86
微信公众号:青儿创客基地
B站:主页 https://space.bilibili.com/208826118
参考
linux系统的休眠与唤醒简介
Android电源管理-休眠简要分析
linux电源管理系列(一)
linux系统的休眠与唤醒简介
Linux Kernel and Android 休眠与唤醒(中文版)
1.Linux电源管理-休眠与唤醒
休眠
查看内核支持哪几种休眠方式,常用的休眠方式有,
- freeze 冻结IO设备,将它们置于低功耗状态,使处理器进入空闲状态,唤醒最快,耗电比其它standby/mem/disk方式高
- standby 除了冻结IO设备外,还会暂停系统,唤醒较快,耗电比其它 mem/disk方式高
- mem 将运行状态数据存到内存,并关闭外设,进入等待模式,唤醒较慢,耗电比disk方式高
- disk 将运行状态数据存到硬盘,然后关机,唤醒最慢
root@zynq:~# cat /sys/power/state
freeze mem
进入休眠模式,
# echo standby > /sys/power/state
唤醒
唤醒需要添加中断唤醒源,使得在休眠时,这些中断是设为开启的,当有中断来,则会退出唤醒。
static struct platform_driver driver = {
.probe = probe,
.remove = remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = of_match,
.pm = dev_pm_ops,
},
};
设备驱动必须支持dev_pm_ops
,
/**
* struct dev_pm_ops - device PM callbacks
*
* Several device power state transitions are externally visible, affecting
* the state of pending I/O queues and (for drivers that touch hardware)
* interrupts, wakeups, DMA, and other hardware state. There may also be
* internal transitions to various low-power modes which are transparent
* to the rest of the driver stack (such as a driver that's ON gating off
* clocks which are not in active use).
*
* The externally visible transitions are handled with the help of callbacks
* included in this structure in such a way that two levels of callbacks are
* involved. First, the PM core executes callbacks provided by PM domains,
* device types, classes and bus types. They are the subsystem-level callbacks
* supposed to execute callbacks provided by device drivers, although they may
* choose not to do that. If the driver callbacks are executed, they have to
* collaborate with the subsystem-level callbacks to achieve the goals
* appropriate for the given system transition, given transition phase and the
* subsystem the device belongs to.
*
* @prepare: The principal role of this callback is to prevent new children of
* the device from being registered after it has returned (the driver's
* subsystem and generally the rest of the kernel is supposed to prevent
* new calls to the probe method from being made too once @prepare() has
* succeeded). If @prepare() detects a situation it cannot handle (e.g.
* registration of a child already in progress), it may return -EAGAIN, so
* that the PM core can execute it once again (e.g. after a new child has
* been registered) to recover from the race condition.
* This method is executed for all kinds of suspend transitions and is
* followed by one of the suspend callbacks: @suspend(), @freeze(), or
* @poweroff(). If the transition is a suspend to memory or standby (that
* is, not related to hibernation), the return value of @prepare() may be
* used to indicate to the PM core to leave the device in runtime suspend
* if applicable. Namely, if @prepare() returns a positive number, the PM
* core will understand that as a declaration that the device appears to be
* runtime-suspended and it may be left in that state during the entire
* transition and during the subsequent resume if all of its descendants
* are left in runtime suspend too. If that happens, @complete() will be
* executed directly after @prepare() and it must ensure the proper
* functioning of the device after the system resume.
* The PM core executes subsystem-level @prepare() for all devices before
* starting to invoke suspend callbacks for any of them, so generally
* devices may be assumed to be functional or to respond to runtime resume
* requests while @prepare() is being executed. However, device drivers
* may NOT assume anything about the availability of user space at that
* time and it is NOT valid to request firmware from within @prepare()
* (it's too late to do that). It also is NOT valid to allocate
* substantial amounts of memory from @prepare() in the GFP_KERNEL mode.
* [To work around these limitations, drivers may register suspend and
* hibernation notifiers to be executed before the freezing of tasks.]
...
*/
struct dev_pm_ops {
int (*prepare)(struct device *dev);
void (*complete)(struct device *dev);
int (*suspend)(struct device *dev);
int (*resume)(struct device *dev);
int (*freeze)(struct device *dev);
int (*thaw)(struct device *dev);
int (*poweroff)(struct device *dev);
int (*restore)(struct device *dev);
int (*suspend_late)(struct device *dev);
int (*resume_early)(struct device *dev);
int (*freeze_late)(struct device *dev);
int (*thaw_early)(struct device *dev);
int (*poweroff_late)(struct device *dev);
int (*restore_early)(struct device *dev);
int (*suspend_noirq)(struct device *dev);
int (*resume_noirq)(struct device *dev);
int (*freeze_noirq)(struct device *dev);
int (*thaw_noirq)(struct device *dev);
int (*poweroff_noirq)(struct device *dev);
int (*restore_noirq)(struct device *dev);
int (*runtime_suspend)(struct device *dev);
int (*runtime_resume)(struct device *dev);
int (*runtime_idle)(struct device *dev);
};
suspend是休眠函数,休眠之前会被调用,调用enable_irq_wake
把要睡眠的中断号屏蔽掉,实现休眠时保持中断唤醒,resume是唤醒函数,唤醒之前被调用,在中断入口调用pm_stay_awake
启动唤醒,在中断出口调用pm_relax
结束唤醒。