在Linux Platform驱动注册过程中,我们要第一步关注的结构体有2个:
struct of_device_id
struct platform_drive
前者负责告诉内核这个驱动可以支持什么样的设备,后者告诉内核支持了些什么。
本文关注下后者中与电源管理相关的部分,先放一个示例驱动代码片段:
static struct platform_driver rk_gmac_dwmac_driver = {
.probe = rk_gmac_probe,
.remove = rk_gmac_remove,
.driver = {
.name = "rk_gmac-dwmac",
.pm = &rk_gmac_pm_ops,
.of_match_table = rk_gmac_dwmac_match,
},
};
module_platform_driver(rk_gmac_dwmac_driver);
在这段代码中,分别告诉内核:
- 当匹配到驱动时我的probe探测函数是
rk_gmac_probe
- remove卸载函数是
rk_gmac_remove
- 驱动的名称叫
rk_gmac-dwmac
- 电源管理操作方法是
rk_gmac_pm_ops
- 驱动支持的设备有
rk_gmac_dwmac_match
。
struct platform_driver
在Kernel5.10中是这样子的:
struct platform_driver {
int (*probe)(struct platform_device *);
int (*remove)(struct platform_device *);
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
int (*resume)(struct platform_device *);
struct device_driver driver;
const struct platform_device_id *id_table;
bool prevent_deferred_probe;
ANDROID_KABI_RESERVE(1);
};
可以看到上述的结构中其中是有电源管理函数suspend
和resume
,那为什么驱动还要再在.driver.pm
再注册一下呢?或者说为什么还要在driver
中再定义一次pm呢?这两者之间有什么关系呢?是有什么不同的地方吗?
在Linux内核中,struct platform_driver
和struct device_driver
中的电源管理字段有一些关键区别:
- struct platform_driver中的suspend和resume:
- 这些字段是平台驱动程序特定的电源管理回调函数,用于处理设备进入和退出低功耗状态的操作。它们通常定义为:
int (*suspend)(struct device *dev, pm_message_t state);
int (*resume)(struct device *dev);
- 这些回调函数在系统进入和退出休眠状态时被调用,主要用于保存和恢复设备的状态。
- struct device_driver中的pm:
这个字段是一个指向struct dev_pm_ops
的指针,定义了更通用的电源管理操作。struct dev_pm_ops
包含多个回调函数,用于处理不同的电源管理事件,包括系统休眠和运行时电源管理。例如:const struct dev_pm_ops *pm;
struct dev_pm_ops
中的回调函数包括:struct dev_pm_ops { int (*suspend)(struct device *dev); int (*resume)(struct device *dev); int (*runtime_suspend)(struct device *dev); int (*runtime_resume)(struct device *dev); int (*runtime_idle)(struct device *dev); };
- 这些回调函数不仅处理系统休眠,还处理设备在系统运行时的电源管理¹²。
总结来说,struct platform_driver
中的suspend
和resume
回调函数主要用于平台设备的系统休眠管理,而struct device_driver
中的pm
字段提供了更全面的电源管理接口,涵盖了系统休眠和运行时电源管理。