device.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. /*
  2. * Copyright (c) 2018 Intel Corporation.
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <zephyr.h>
  7. #include <kernel.h>
  8. #include <string.h>
  9. #include <device.h>
  10. #include <pm/policy.h>
  11. #define LOG_LEVEL CONFIG_PM_LOG_LEVEL /* From power module Kconfig */
  12. #include <logging/log.h>
  13. LOG_MODULE_DECLARE(power);
  14. #if defined(CONFIG_PM_DEVICE)
  15. extern const struct device *__pm_device_slots_start[];
  16. #define EARLY_DEV_PM_NUM 20
  17. static const struct device *g_pm_device_early[EARLY_DEV_PM_NUM];
  18. /* Number of devices successfully suspended. */
  19. static size_t num_susp, early_num_susp;
  20. static int _pm_devices(enum pm_device_state state)
  21. {
  22. const struct device *devs;
  23. size_t devc;
  24. devc = z_device_get_all_static(&devs);
  25. num_susp = 0;
  26. for (const struct device *dev = devs + devc - 1; dev >= devs; dev--) {
  27. int ret;
  28. /* ignore busy devices */
  29. if( PM_DEVICE_STATE_OFF != state) { // power off not check dev busy
  30. if (pm_device_is_busy(dev) || pm_device_wakeup_is_enabled(dev)) {
  31. continue;
  32. }
  33. }
  34. ret = pm_device_state_set(dev, state);
  35. /* ignore devices not supporting or already at the given state */
  36. if ((ret == -ENOSYS) || (ret == -ENOTSUP) || (ret == -EALREADY)) {
  37. continue;
  38. } else if (ret < 0) {
  39. LOG_ERR("Device %s did not enter %s state (%d)",
  40. dev->name, pm_device_state_str(state), ret);
  41. return ret;
  42. }
  43. __pm_device_slots_start[num_susp] = dev;
  44. num_susp++;
  45. }
  46. return 0;
  47. }
  48. int pm_suspend_devices(void)
  49. {
  50. return _pm_devices(PM_DEVICE_STATE_SUSPENDED);
  51. }
  52. int pm_low_power_devices(void)
  53. {
  54. return _pm_devices(PM_DEVICE_STATE_LOW_POWER);
  55. }
  56. void pm_resume_devices(void)
  57. {
  58. int32_t i;
  59. for (i = (num_susp - 1); i >= 0; i--) {
  60. pm_device_state_set(__pm_device_slots_start[i],
  61. PM_DEVICE_STATE_ACTIVE);
  62. }
  63. num_susp = 0;
  64. }
  65. #endif /* defined(CONFIG_PM_DEVICE) */
  66. const char *pm_device_state_str(enum pm_device_state state)
  67. {
  68. switch (state) {
  69. case PM_DEVICE_STATE_ACTIVE:
  70. return "active";
  71. case PM_DEVICE_STATE_LOW_POWER:
  72. return "low power";
  73. case PM_DEVICE_STATE_SUSPENDED:
  74. return "suspended";
  75. case PM_DEVICE_STATE_OFF:
  76. return "off";
  77. default:
  78. return "";
  79. }
  80. }
  81. int pm_device_state_set(const struct device *dev,
  82. enum pm_device_state state)
  83. {
  84. int ret;
  85. enum pm_device_action action;
  86. if (dev->pm_control == NULL) {
  87. return -ENOSYS;
  88. }
  89. if (atomic_test_bit(&dev->pm->flags, PM_DEVICE_FLAG_TRANSITIONING)) {
  90. return -EBUSY;
  91. }
  92. switch (state) {
  93. case PM_DEVICE_STATE_SUSPENDED:
  94. if (dev->pm->state == PM_DEVICE_STATE_SUSPENDED) {
  95. return -EALREADY;
  96. } else if (dev->pm->state == PM_DEVICE_STATE_OFF) {
  97. return -ENOTSUP;
  98. }
  99. action = PM_DEVICE_ACTION_SUSPEND;
  100. break;
  101. case PM_DEVICE_STATE_ACTIVE:
  102. if (dev->pm->state == PM_DEVICE_STATE_ACTIVE) {
  103. return -EALREADY;
  104. }
  105. action = PM_DEVICE_ACTION_RESUME;
  106. break;
  107. case PM_DEVICE_STATE_LOW_POWER:
  108. if (dev->pm->state == state) {
  109. return -EALREADY;
  110. }
  111. action = PM_DEVICE_ACTION_LOW_POWER;
  112. break;
  113. case PM_DEVICE_STATE_OFF:
  114. if (dev->pm->state == state) {
  115. return -EALREADY;
  116. }
  117. action = PM_DEVICE_ACTION_TURN_OFF;
  118. break;
  119. default:
  120. return -ENOTSUP;
  121. }
  122. ret = dev->pm_control(dev, action);
  123. if (ret < 0) {
  124. return ret;
  125. }
  126. dev->pm->state = state;
  127. return 0;
  128. }
  129. int pm_device_state_get(const struct device *dev,
  130. enum pm_device_state *state)
  131. {
  132. if (dev->pm_control == NULL) {
  133. return -ENOSYS;
  134. }
  135. *state = dev->pm->state;
  136. return 0;
  137. }
  138. bool pm_device_is_any_busy(void)
  139. {
  140. const struct device *devs;
  141. size_t devc;
  142. devc = z_device_get_all_static(&devs);
  143. for (const struct device *dev = devs; dev < (devs + devc); dev++) {
  144. if (atomic_test_bit(&dev->pm->flags, PM_DEVICE_FLAG_BUSY)) {
  145. return true;
  146. }
  147. }
  148. return false;
  149. }
  150. bool pm_device_is_busy(const struct device *dev)
  151. {
  152. return atomic_test_bit(&dev->pm->flags, PM_DEVICE_FLAG_BUSY);
  153. }
  154. void pm_device_busy_set(const struct device *dev)
  155. {
  156. atomic_set_bit(&dev->pm->flags, PM_DEVICE_FLAG_BUSY);
  157. }
  158. void pm_device_busy_clear(const struct device *dev)
  159. {
  160. atomic_clear_bit(&dev->pm->flags, PM_DEVICE_FLAG_BUSY);
  161. }
  162. bool pm_device_wakeup_enable(struct device *dev, bool enable)
  163. {
  164. atomic_val_t flags, new_flags;
  165. flags = atomic_get(&dev->pm->flags);
  166. if ((flags & BIT(PM_DEVICE_FLAGS_WS_CAPABLE)) == 0U) {
  167. return false;
  168. }
  169. if (enable) {
  170. new_flags = flags |
  171. BIT(PM_DEVICE_FLAGS_WS_ENABLED);
  172. } else {
  173. new_flags = flags & ~BIT(PM_DEVICE_FLAGS_WS_ENABLED);
  174. }
  175. return atomic_cas(&dev->pm->flags, flags, new_flags);
  176. }
  177. bool pm_device_wakeup_is_enabled(const struct device *dev)
  178. {
  179. return atomic_test_bit(&dev->pm->flags,
  180. PM_DEVICE_FLAGS_WS_ENABLED);
  181. }
  182. bool pm_device_wakeup_is_capable(const struct device *dev)
  183. {
  184. return atomic_test_bit(&dev->pm->flags,
  185. PM_DEVICE_FLAGS_WS_CAPABLE);
  186. }
  187. int pm_early_suspend(void)
  188. {
  189. const struct device *devs;
  190. size_t devc;
  191. devc = z_device_get_all_static(&devs);
  192. early_num_susp = 0;
  193. for (const struct device *dev = devs + devc - 1; dev >= devs; dev--) {
  194. int ret;
  195. if (dev->pm_control == NULL) {
  196. continue;
  197. }
  198. ret = dev->pm_control(dev, PM_DEVICE_ACTION_EARLY_SUSPEND);
  199. /* ignore devices not supporting or already at the given state */
  200. if ((ret == -ENOSYS) || (ret == -ENOTSUP) || (ret == -EALREADY)) {
  201. continue;
  202. } else if (ret < 0) {
  203. LOG_ERR("Device %s did not enter early state (%d)",
  204. dev->name, ret);
  205. return ret;
  206. }
  207. g_pm_device_early[early_num_susp] = dev;
  208. early_num_susp++;
  209. }
  210. return 0;
  211. }
  212. void pm_late_resume(void)
  213. {
  214. int32_t i;
  215. for (i = (early_num_susp - 1); i >= 0; i--) {
  216. g_pm_device_early[i]->pm_control(g_pm_device_early[i],
  217. PM_DEVICE_ACTION_LATE_RESUME);
  218. }
  219. early_num_susp = 0;
  220. }
  221. int pm_power_off_devices(void)
  222. {
  223. return _pm_devices(PM_DEVICE_STATE_OFF);
  224. }