最近在看Linux电源管理模块,发现在platform_driver下有suspend/resume函数,在platform_driver->pm-下也有suspend/resume函数。下面分析一下他们的区别。
先看两段代码。
static const struct dev_pm_ops s_atc260x_irkeypad_pm_ops = { .suspend = atc260x_irkeypad_suspend, .resume = atc260x_irkeypad_resume, }; static struct platform_driver atc260x_irkeypad_driver = { .driver = { .name = "atc260x-irkeypad", .owner = THIS_MODULE, .pm = &s_atc260x_irkeypad_pm_ops, .of_match_table = of_match_ptr(atc260x_irkey_of_match), }, .probe = atc260x_irkeypad_probe, .remove = atc260x_irkeypad_remove, .shutdown = atc260x_irkeypad_shutdown, };
static struct platform_driver atc260x_adckeypad_driver = { .driver = { .name = "atc260x-adckeypad", .owner = THIS_MODULE, .of_match_table = of_match_ptr(atc260x_adckey_of_match), }, .probe = atc260x_adckeypad_probe, .remove = atc260x_adckeypad_remove, .suspend = atc260x_adckeypad_suspend, .resume = atc260x_adckeypad_resume, };
其中我们可以看到这两个驱动程序中对电源管理的方式不太一样。
接着我们去看下Linux源代码中对platform_driver结构体的定义。
Platform_device.h (kernel\include\linux) 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; }; structDevice.h (kernel\include\linux) device_driver { const char *name; struct bus_type *bus; struct module *owner; const char *mod_name; /* used for built-in modules */ bool suppress_bind_attrs; /* disables bind/unbind via sysfs */ const struct of_device_id *of_match_table; const struct acpi_device_id *acpi_match_table; int (*probe) (struct device *dev); int (*remove) (struct device *dev); void (*shutdown) (struct device *dev); int (*suspend) (struct device *dev, pm_message_t state); int (*resume) (struct device *dev); const struct attribute_group **groups; const struct dev_pm_ops *pm; struct driver_private *p; };在这platform_driver 和device_driver中都定义了probe remove等函数。其中device_driver结构体又包含在platform_driver中,至此还是不明白为什么这样做。
接着去看下platform_driver_register(struct platform_driver *drv) 函数吧。
Platform.c (kernel\drivers\base) int platform_driver_register(struct platform_driver *drv) { drv->driver.bus = &platform_bus_type; if (drv->probe) drv->driver.probe = platform_drv_probe; if (drv->remove) drv->driver.remove = platform_drv_remove; if (drv->shutdown) drv->driver.shutdown = platform_drv_shutdown; return driver_register(&drv->driver); }是不是很有意思,这里你会发现,最后device_driver中的probe remove等又指向了platform_driver的probe remove。
具体看下两个结构中的probe定义
int (*probe)(struct platform_device *); int (*probe) (struct device *dev);
plaPlatform.c (kernel\drivers\base) 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; }可以发现,如果driver->pm为空的话就回去调用platform_legacy_suspend,如果不为空的话就调用driver->pm。
static int platform_legacy_suspend(struct device *dev, pm_message_t mesg) { struct platform_driver *pdrv = to_platform_driver(dev->driver); struct platform_device *pdev = to_platform_device(dev); int ret = 0; if (dev->driver && pdrv->suspend) ret = pdrv->suspend(pdev, mesg); return ret; }platform_legacy_suspend则是去调用platform_driver中的suspend。
第二方式是一种比较旧的方式,建议使用最新的dev_pm_ops方式来进行电源管理。
参考:https://www.cnblogs.com/swnuwangyun/p/4233821.html