简介
设备运行时电源管理框架是一种主动电源管理机制,它通过挂起空闲或未使用的设备来降低整体系统功耗。可以通过设置CONFIG_PM_DEVICE_RUNTIME来启用它。在此模型中,设备驱动程序负责指示何时需要设备,何时不需要设备。此信息用于根据使用情况计数确定何时挂起或恢复设备。
启用设备运行时电源管理后,其状态最初将设置为PM_DEVICE_STATE_SUSPENDED指示未使用它。在第一个设备请求时,它将恢复,因此将其置于PM_DEVICE_STATE_ACTIVE状态。设备将保持此状态,直到不再使用。如果同步执行挂起,则设备将立即进入PM_DEVICE_STATE_SUSPENDED状态,而如果以异步方式执行,则将首先将其置于PM_DEVICE_STATE_SUSPENDING状态,然后在操作运行时进入PM_DEVICE_STATE_SUSPENDED状态。
同步和异步操作
设备驱动程序可以使用pm_device_get()函数来指示它需要设备处于活动状态或可操作。此功能将增加设备使用计数,并在必要时恢复设备。同样,pm_device_put()函数可用于指示不再需要该设备。此功能将减少设备使用计数,并在必要时挂起设备。值得注意的是,在这两种情况下,操作是同步执行的。同步模型非常简单。但是,它可能会引入不必要的延迟,因为在设备挂起之前,应用程序将无法获得操作结果。如果操作速度很快,例如寄存器切换,则可能不会有问题。但是,如果挂起涉及通过慢速总线发送数据包,则情况将不同。因此,设备驱动程序还可以利用pm_device_put_async()函数。如果设备不再使用,此功能将再次计划挂起操作。然后,当系统工作队列有机会运行时,将执行暂停。
示例
电源管理的驱动函数实现:
static int mydev_pm_action(const struct device *dev,enum pm_device_action *action){switch (action) {case PM_DEVICE_ACTION_SUSPEND:/* suspend the device */...break;case PM_DEVICE_ACTION_RESUME:/* resume the device */...break;default:return -ENOTSUP;}return 0;}
若要在设备上启用设备运行时电源管理,驱动程序需要在初始化时调用pm_device_enable()。请注意,如果设备的状态为PM_DEVICE_STATE_ACTIVE,则此功能将挂起设备。如果设备在物理上挂起,init函数应在调用pm_device_enable()之前调用pm_device_runtime_init_suspended()。
/* device driver initialization function */static int mydev_init(const struct device *dev){int ret;.../* OPTIONAL: mark device as suspended if it is physically suspended */pm_device_runtime_init_suspended(dev);/* enable device runtime power management */ret = pm_device_enable(dev);if ((ret < 0) && (ret != -ENOSYS)) {return ret;}}
在操作设备时,以同步的方式进行电源管理:
static int mydev_operation(const struct device *dev){int ret;/* "get" device (increases usage count, resumes device if suspended) */ret = pm_device_runtime_get(dev);if (ret < 0) {return ret;}/* do something with the device */.../* "put" device (decreases usage count, suspends device if no more users) */return pm_device_runtime_put(dev);}
在设备操作时以异步的方式进行电源管理:
static int mydev_operation(const struct device *dev){int ret;/* "get" device (increases usage count, resumes device if suspended) */ret = pm_device_runtime_get(dev);if (ret < 0) {return ret;}/* do something with the device */.../* "put" device (decreases usage count, schedule suspend if no more users) */return pm_device_runtime_put_async(dev);}
