设备电源管理驱动
其实之前我们在将设备驱动模型
的时候有有一个参数我们一直没说,那就电源管理控制函数。
我们在注册驱动的时候时需要提供一个设备电源管理函数的。
#define DEVICE_DEFINE(dev_name, drv_name, init_fn, pm_control_fn, \
data_ptr, cfg_ptr, level, prio, api_ptr) \
其中:pm_control_fn
就是设备管理控制函数。
函数原型如下:
int dummy_device_pm_ctrl(const struct device *dev,
enum pm_device_action action)
其中pm_device_action
为设备电源管理操作类型:
/** @brief Device PM actions. */
enum pm_device_action {
/** Suspend. */
PM_DEVICE_ACTION_SUSPEND,
/** Resume. */
PM_DEVICE_ACTION_RESUME,
/** Turn off. */
PM_DEVICE_ACTION_TURN_OFF,
/** Force suspend. */
PM_DEVICE_ACTION_FORCE_SUSPEND,
/** Low power. */
PM_DEVICE_ACTION_LOW_POWER,
};
设备电源管理驱动示例
/*
* Copyright (c) 2018 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <pm/device_runtime.h>
#include <sys/printk.h>
#include "dummy_parent.h"
static uint32_t store_value;
static int dummy_transfer(const struct device *dev, uint32_t cmd,
uint32_t *val)
{
printk("transfer()\n");
if (cmd == DUMMY_PARENT_WR) {
store_value = *val;
} else {
*val = store_value;
}
return 0;
}
static int dummy_parent_pm_ctrl(const struct device *dev,
enum pm_device_action action)
{
switch (action) {
case PM_DEVICE_ACTION_RESUME:
printk("parent resuming..\n");
break;
case PM_DEVICE_ACTION_SUSPEND:
printk("parent suspending..\n");
break;
default:
return -ENOTSUP;
}
return 0;
}
static const struct dummy_parent_api funcs = {
.transfer = dummy_transfer,
};
int dummy_parent_init(const struct device *dev)
{
//使能设备运行时设备管理
pm_device_enable(dev);
return 0;
}
DEVICE_DEFINE(dummy_parent, DUMMY_PARENT_NAME, &dummy_parent_init,
dummy_parent_pm_ctrl, NULL, NULL, POST_KERNEL,
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &funcs);
控制设备电源
系统为我们提供了主动控制设备电源管理的函数:
/**
* @brief Set the power state of a device.
*
* This function calls the device PM control callback so that the device does
* the necessary operations to put the device into the given state.
*
* @note Some devices may not support all device power states.
*
* @param dev Device instance.
* @param state Device power state to be set.
*
* @retval 0 If successful.
* @retval -ENOTSUP If requested state is not supported.
* @retval -EALREADY If device is already at (or transitioning to) the requested
* state.
* @retval Errno Other negative errno on failure.
*/
int pm_device_state_set(const struct device *dev,
enum pm_device_state state);
/**
* @brief Obtain the power state of a device.
*
* @param dev Device instance.
* @param state Pointer where device power state will be stored.
*
* @retval 0 If successful.
* @retval -ENOSYS If device does not implement power management.
*/
int pm_device_state_get(const struct device *dev,
enum pm_device_state *state);
/**
* @brief Force usage of given power state.
*
* This function overrides decision made by PM policy forcing
* usage of given power state immediately.
*
* @note This function can only run in thread context
*
* @param info Power state which should be used in the ongoing
* suspend operation.
*/
void pm_power_state_force(struct pm_state_info info);
- pm_device_state_set: 设置设备的电源管理状态
- pm_device_state_get: 获取设备的电源管理状态
- pm_power_state_force: 强制设置电源管理的策略信息
控制设备电源示例
void main(void)
{
int rc;
const struct device *cons = device_get_binding(CONSOLE_LABEL);
printk("\n%s system off demo\n", CONFIG_BOARD);
/* Configure to generate PORT event (wakeup) on button 1 press. */
nrf_gpio_cfg_input(DT_GPIO_PIN(DT_NODELABEL(button0), gpios),
NRF_GPIO_PIN_PULLUP);
nrf_gpio_cfg_sense_set(DT_GPIO_PIN(DT_NODELABEL(button0), gpios),
NRF_GPIO_PIN_SENSE_LOW);
printk("Busy-wait %u s\n", BUSY_WAIT_S);
k_busy_wait(BUSY_WAIT_S * USEC_PER_SEC);
printk("Busy-wait %u s with UART off\n", BUSY_WAIT_S);
rc = pm_device_state_set(cons, PM_DEVICE_STATE_SUSPENDED);
k_busy_wait(BUSY_WAIT_S * USEC_PER_SEC);
rc = pm_device_state_set(cons, PM_DEVICE_STATE_ACTIVE);
printk("Sleep %u s\n", SLEEP_S);
k_sleep(K_SECONDS(SLEEP_S));
printk("Sleep %u s with UART off\n", SLEEP_S);
rc = pm_device_state_set(cons, PM_DEVICE_STATE_SUSPENDED);
k_sleep(K_SECONDS(SLEEP_S));
rc = pm_device_state_set(cons, PM_DEVICE_STATE_ACTIVE);
printk("Entering system off; press BUTTON1 to restart\n");
/* Above we disabled entry to deep sleep based on duration of
* controlled delay. Here we need to override that, then
* force entry to deep sleep on any delay.
*/
pm_power_state_force((struct pm_state_info){PM_STATE_SOFT_OFF, 0, 0});
printk("ERROR: System off failed\n");
while (true) {
/* spin to avoid fall-off behavior */
}
}