1 设备注册到dpm_list路径
(Platform_device->device->device_driver指向platform_driver->driver)
2 低功耗接口
dpm_suspend_start():调用注册到dpm_list的设备的回调函数,执行睡眠前的准备和保存工作;
dpm_suspend_end():执行suspend_late和suspend_noirq设备的回调函数,进行睡眠前的准备工作。
睡眠时,设备在链表中的转移:
dpm_list--->dpm_prepared_list-->dpm_suspended_list---->
dpm_late_early_list--->dpm_noirq_list
Dpm_resume_start():执行设备的resume_noirq和resume_early回调,恢复suspend_noirq和suspend_late阶段保存的东西
dpm_resume_end():执行各设备的resume和complete回调接口,做suspend和prepare的逆操作
唤醒时,设备从链表中的转移顺序是上述suspend阶段顺序的逆序。
3 低功耗接口是如何调用到各设备驱动注册的回调函数的
系统进入睡眠前回调设备的回调函数是有选择的:
如果dev->pm_domain域的回调函数注册的话,首选此处的回调函数
否则,如果dev->type域和dev->type->pm域都注册的话,会选择dev->type->pm处的回调函数
否则,如果dev->class 和 dev->class->pm两处都注册回调函数的话,会选择dev->class->pm的回调函数
如果dev->bus 和 dev->bus->pm两处都注册回调函数的话,会选择dev->bus->pm的回调函数
示例方法1和方法4:
3.1 在dev域的电源域进行注册
struct platform_device {
const char * name;
int id;
bool id_auto;
struct device dev;
u32 num_resources;
struct resource * resource;
const struct platform_device_id *id_entry;
/* MFD cell pointer */
struct mfd_cell *mfd_cell;
/* arch specific additions */
struct pdev_archdata archdata;
};
struct device {
struct device *parent;
struct device_private *p;
struct kobject kobj;
const char *init_name; /* initial name of the device */
const struct device_type *type;
struct mutex mutex; /* mutex to synchronize calls to
* its driver.*/
struct bus_type *bus; /* type of bus device is on */
struct device_driver *driver; /* which driver has allocated this device */
void *platform_data; /* Platform specific data, device core doesn't touch it */
struct dev_pm_info power;
struct dev_pm_domain *pm_domain;
…….}
struct dev_pm_domain {
struct dev_pm_ops ops;
};
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);
};
低功耗接口在函数__device_suspend函数内会首先调用在struct device电源域注册的回调函数。
唤醒时调用顺序:
3.2 在bus域的ops电源域进行注册
注册设备和注册驱动进行匹配成功后
Platform_device->device->device_driver指针会指向platform_driver->driver成员
设备注册:
(1)int platform_device_add(struct platform_device *pdev)
{
……………
if (!pdev->dev.parent)
pdev->dev.parent = &platform_bus;
pdev->dev.bus = &platform_bus_type;
…………..
}
(2)struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};
(3)static const struct dev_pm_ops platform_dev_pm_ops = {
.runtime_suspend = pm_generic_runtime_suspend,
.runtime_resume = pm_generic_runtime_resume,
.runtime_idle = pm_generic_runtime_idle,
USE_PLATFORM_PM_SLEEP_OPS
};
(4)#define USE_PLATFORM_PM_SLEEP_OPS \
.suspend = platform_pm_suspend, \
.resume = platform_pm_resume, \
.freeze = platform_pm_freeze, \
.thaw = platform_pm_thaw, \
.poweroff = platform_pm_poweroff, \
.restore = platform_pm_restore,
(5) int platform_pm_suspend(struct device *dev)
{
struct device_driver *drv = dev->driver;
int ret = 0;
if (!drv)
return 0;
if (drv->pm) {
if (drv->pm->suspend)
ret = drv->pm->suspend(dev);
} else {
ret = platform_legacy_suspend(dev, PMSG_SUSPEND);
}
return ret;
}
【作者】张昺华
【微信公众号】 张昺华
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.