在Linux内核中,Runtime机制是一种电源管理机制,它允许设备在空闲时进入低功耗状态,减少能源消耗。在runtime 的实际使用中需要在设备驱动实现Runtime_idle()、Runtime_suspend()和Runtime_resume()等函数。它用于控制设备的低功耗状态和恢复工作状态。
首先rumtime的回调函数定义在如下结构体中
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);
};
struct 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 */
enum probe_type probe_type;
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;
};
从上可以看出如需要使用runtime时 可以在实现设备驱动实现相应的回调函数。
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/pm_runtime.h>
static ssize_t test_runtime_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return 0;
}
static ssize_t test_runtime_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
int ret = -EINVAL;
int runtime_status;
ret = kstrtouint(buf, 16, &runtime_status);
if (ret < 0) {
return ret;
}
if(runtime_status)
{
pm_runtime_get_sync(dev);
}
else
{
pm_runtime_put_sync(dev);
}
return count;
}
static DEVICE_ATTR_RW(test_runtime);
#ifdef CONFIG_PM
static int test_runtime_suspend(struct device *dev)
{
return 0;
}
static int test_runtime_resume(struct device *dev)
{
return 0;
}
static int test_runtime_idle(struct device *dev)
{
return 0;
}
#endif
static const struct dev_pm_ops test_dev_pm_ops = {
SET_RUNTIME_PM_OPS(test_runtime_suspend,
test_runtime_resume, test_runtime_idle)
};
static int test_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
int ret = 0;
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
ret = device_create_file(dev, &dev_attr_test_runtime);
return ret;
}
static int test_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
pm_runtime_disable(dev);
pm_runtime_set_suspended(dev);
return 0;
}
static const struct of_device_id test_of_match[] = {
{.compatible = "test,test_driver", },
{ }
};
static struct platform_driver test_driver = {
.driver = {
.name = "test_driver",
.owner = THIS_MODULE,
.of_match_table = test_of_match,
.pm = &test_dev_pm_ops,
},
.probe = test_probe,
.remove = test_remove,
};
static int __init test_init(void)
{
int ret;
ret = platform_driver_register(&test_driver);
return ret;
}
static void __exit test_exit(void)
{
platform_driver_unregister(&test_driver);
}
module_init(test_init);
module_exit(test_exit);
MODULE_DESCRIPTION("test driver");
MODULE_AUTHOR("xxxxxxxxxx");
MODULE_LICENSE("GPL");
代码会生成如下节点,对其进行操作实现runtime的调用:
/sys/bus/platform/devices/soc:test_driver/test_runtime