设备电源管理驱动

其实之前我们在将设备驱动模型的时候有有一个参数我们一直没说,那就电源管理控制函数。
我们在注册驱动的时候时需要提供一个设备电源管理函数的。

  1. #define DEVICE_DEFINE(dev_name, drv_name, init_fn, pm_control_fn, \
  2. data_ptr, cfg_ptr, level, prio, api_ptr) \

其中:pm_control_fn就是设备管理控制函数。
函数原型如下:

  1. int dummy_device_pm_ctrl(const struct device *dev,
  2. enum pm_device_action action)

其中pm_device_action为设备电源管理操作类型:

  1. /** @brief Device PM actions. */
  2. enum pm_device_action {
  3. /** Suspend. */
  4. PM_DEVICE_ACTION_SUSPEND,
  5. /** Resume. */
  6. PM_DEVICE_ACTION_RESUME,
  7. /** Turn off. */
  8. PM_DEVICE_ACTION_TURN_OFF,
  9. /** Force suspend. */
  10. PM_DEVICE_ACTION_FORCE_SUSPEND,
  11. /** Low power. */
  12. PM_DEVICE_ACTION_LOW_POWER,
  13. };

设备电源管理驱动示例

  1. /*
  2. * Copyright (c) 2018 Intel Corporation
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <pm/device_runtime.h>
  7. #include <sys/printk.h>
  8. #include "dummy_parent.h"
  9. static uint32_t store_value;
  10. static int dummy_transfer(const struct device *dev, uint32_t cmd,
  11. uint32_t *val)
  12. {
  13. printk("transfer()\n");
  14. if (cmd == DUMMY_PARENT_WR) {
  15. store_value = *val;
  16. } else {
  17. *val = store_value;
  18. }
  19. return 0;
  20. }
  21. static int dummy_parent_pm_ctrl(const struct device *dev,
  22. enum pm_device_action action)
  23. {
  24. switch (action) {
  25. case PM_DEVICE_ACTION_RESUME:
  26. printk("parent resuming..\n");
  27. break;
  28. case PM_DEVICE_ACTION_SUSPEND:
  29. printk("parent suspending..\n");
  30. break;
  31. default:
  32. return -ENOTSUP;
  33. }
  34. return 0;
  35. }
  36. static const struct dummy_parent_api funcs = {
  37. .transfer = dummy_transfer,
  38. };
  39. int dummy_parent_init(const struct device *dev)
  40. {
  41. //使能设备运行时设备管理
  42. pm_device_enable(dev);
  43. return 0;
  44. }
  45. DEVICE_DEFINE(dummy_parent, DUMMY_PARENT_NAME, &dummy_parent_init,
  46. dummy_parent_pm_ctrl, NULL, NULL, POST_KERNEL,
  47. CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &funcs);

控制设备电源

系统为我们提供了主动控制设备电源管理的函数:

  1. /**
  2. * @brief Set the power state of a device.
  3. *
  4. * This function calls the device PM control callback so that the device does
  5. * the necessary operations to put the device into the given state.
  6. *
  7. * @note Some devices may not support all device power states.
  8. *
  9. * @param dev Device instance.
  10. * @param state Device power state to be set.
  11. *
  12. * @retval 0 If successful.
  13. * @retval -ENOTSUP If requested state is not supported.
  14. * @retval -EALREADY If device is already at (or transitioning to) the requested
  15. * state.
  16. * @retval Errno Other negative errno on failure.
  17. */
  18. int pm_device_state_set(const struct device *dev,
  19. enum pm_device_state state);
  20. /**
  21. * @brief Obtain the power state of a device.
  22. *
  23. * @param dev Device instance.
  24. * @param state Pointer where device power state will be stored.
  25. *
  26. * @retval 0 If successful.
  27. * @retval -ENOSYS If device does not implement power management.
  28. */
  29. int pm_device_state_get(const struct device *dev,
  30. enum pm_device_state *state);
  31. /**
  32. * @brief Force usage of given power state.
  33. *
  34. * This function overrides decision made by PM policy forcing
  35. * usage of given power state immediately.
  36. *
  37. * @note This function can only run in thread context
  38. *
  39. * @param info Power state which should be used in the ongoing
  40. * suspend operation.
  41. */
  42. void pm_power_state_force(struct pm_state_info info);
  • pm_device_state_set: 设置设备的电源管理状态
  • pm_device_state_get: 获取设备的电源管理状态
  • pm_power_state_force: 强制设置电源管理的策略信息

控制设备电源示例

  1. void main(void)
  2. {
  3. int rc;
  4. const struct device *cons = device_get_binding(CONSOLE_LABEL);
  5. printk("\n%s system off demo\n", CONFIG_BOARD);
  6. /* Configure to generate PORT event (wakeup) on button 1 press. */
  7. nrf_gpio_cfg_input(DT_GPIO_PIN(DT_NODELABEL(button0), gpios),
  8. NRF_GPIO_PIN_PULLUP);
  9. nrf_gpio_cfg_sense_set(DT_GPIO_PIN(DT_NODELABEL(button0), gpios),
  10. NRF_GPIO_PIN_SENSE_LOW);
  11. printk("Busy-wait %u s\n", BUSY_WAIT_S);
  12. k_busy_wait(BUSY_WAIT_S * USEC_PER_SEC);
  13. printk("Busy-wait %u s with UART off\n", BUSY_WAIT_S);
  14. rc = pm_device_state_set(cons, PM_DEVICE_STATE_SUSPENDED);
  15. k_busy_wait(BUSY_WAIT_S * USEC_PER_SEC);
  16. rc = pm_device_state_set(cons, PM_DEVICE_STATE_ACTIVE);
  17. printk("Sleep %u s\n", SLEEP_S);
  18. k_sleep(K_SECONDS(SLEEP_S));
  19. printk("Sleep %u s with UART off\n", SLEEP_S);
  20. rc = pm_device_state_set(cons, PM_DEVICE_STATE_SUSPENDED);
  21. k_sleep(K_SECONDS(SLEEP_S));
  22. rc = pm_device_state_set(cons, PM_DEVICE_STATE_ACTIVE);
  23. printk("Entering system off; press BUTTON1 to restart\n");
  24. /* Above we disabled entry to deep sleep based on duration of
  25. * controlled delay. Here we need to override that, then
  26. * force entry to deep sleep on any delay.
  27. */
  28. pm_power_state_force((struct pm_state_info){PM_STATE_SOFT_OFF, 0, 0});
  29. printk("ERROR: System off failed\n");
  30. while (true) {
  31. /* spin to avoid fall-off behavior */
  32. }
  33. }