supply-daemon.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2023-02-25 GuEe-GUI the first version
  9. */
  10. #include <rtdevice.h>
  11. #define DBG_TAG "power_supply.daemon"
  12. #define DBG_LVL DBG_INFO
  13. #include <rtdbg.h>
  14. #ifdef RT_USING_PM
  15. static rt_bool_t low_power_mode = RT_FALSE;
  16. static rt_uint8_t raw_pm_run_mode = PM_RUN_MODE_MAX;
  17. static rt_uint8_t raw_pm_sleep_mode = PM_RUN_MODE_MAX;
  18. static rt_uint8_t last_pm_sleep_mode;
  19. #endif
  20. static rt_err_t daemon_power_supply_notify(struct rt_power_supply_notifier *notifier,
  21. struct rt_power_supply *psy)
  22. {
  23. union rt_power_supply_property_val propval;
  24. rt_uint32_t voltage_now, voltage_min, voltage_max;
  25. if (!rt_power_supply_get_property(psy, RT_POWER_SUPPLY_PROP_CAPACITY, &propval))
  26. {
  27. goto _capacity_check;
  28. }
  29. if (rt_power_supply_get_property(psy, RT_POWER_SUPPLY_PROP_VOLTAGE_NOW, &propval))
  30. {
  31. return -RT_ENOSYS;
  32. }
  33. voltage_now = propval.intval / 1000000;
  34. if (rt_power_supply_get_property(psy, RT_POWER_SUPPLY_PROP_VOLTAGE_MIN, &propval))
  35. {
  36. return -RT_ENOSYS;
  37. }
  38. voltage_min = propval.intval / 1000000;
  39. if (rt_power_supply_get_property(psy, RT_POWER_SUPPLY_PROP_VOLTAGE_MAX, &propval))
  40. {
  41. return -RT_ENOSYS;
  42. }
  43. voltage_max = propval.intval / 1000000;
  44. propval.intval = (voltage_now - voltage_min) * 100 / (voltage_max - voltage_min);
  45. _capacity_check:
  46. if (propval.intval >= 80)
  47. {
  48. rt_bool_t full_power = propval.intval == 100;
  49. if (rt_power_supply_get_property(psy, RT_POWER_SUPPLY_PROP_STATUS, &propval))
  50. {
  51. return -RT_ENOSYS;
  52. }
  53. if (propval.intval == RT_POWER_SUPPLY_STATUS_CHARGING)
  54. {
  55. if (full_power)
  56. {
  57. LOG_I("%s: Power is full", rt_dm_dev_get_name(psy->dev));
  58. }
  59. else
  60. {
  61. LOG_I("%s: Power is sufficient", rt_dm_dev_get_name(psy->dev));
  62. }
  63. }
  64. }
  65. else if (propval.intval <= 20)
  66. {
  67. #ifdef RT_USING_PM
  68. rt_uint8_t pm_sleep_mode;
  69. struct rt_pm *pm = rt_pm_get_handle();
  70. RT_ASSERT(pm != RT_NULL);
  71. low_power_mode = RT_TRUE;
  72. if (raw_pm_run_mode == PM_RUN_MODE_MAX)
  73. {
  74. raw_pm_run_mode = pm->run_mode;
  75. }
  76. if (raw_pm_sleep_mode == PM_SLEEP_MODE_MAX)
  77. {
  78. last_pm_sleep_mode = raw_pm_sleep_mode = pm->sleep_mode;
  79. }
  80. pm_sleep_mode = pm->sleep_mode;
  81. #endif /* RT_USING_PM */
  82. if (propval.intval <= 5)
  83. {
  84. do {
  85. #ifdef RT_USING_PM
  86. if (pm_sleep_mode != PM_SLEEP_MODE_SHUTDOWN && propval.intval > 1)
  87. {
  88. pm_sleep_mode = PM_SLEEP_MODE_SHUTDOWN;
  89. break;
  90. }
  91. #endif
  92. if (!rt_power_supply_get_property(psy, RT_POWER_SUPPLY_PROP_SCOPE, &propval) &&
  93. propval.intval == RT_POWER_SUPPLY_SCOPE_SYSTEM)
  94. {
  95. LOG_E("%s: Power is critical, poweroff now", rt_dm_dev_get_name(psy->dev));
  96. rt_hw_cpu_shutdown();
  97. }
  98. } while (0);
  99. LOG_E("%s: Power is critical", rt_dm_dev_get_name(psy->dev));
  100. }
  101. else if (propval.intval <= 10)
  102. {
  103. #ifdef RT_USING_PM
  104. pm_sleep_mode = PM_SLEEP_MODE_STANDBY;
  105. rt_pm_run_enter(PM_RUN_MODE_LOW_SPEED);
  106. #endif
  107. }
  108. else if (propval.intval <= 15)
  109. {
  110. #ifdef RT_USING_PM
  111. pm_sleep_mode = PM_SLEEP_MODE_DEEP;
  112. rt_pm_run_enter(PM_RUN_MODE_MEDIUM_SPEED);
  113. #endif
  114. }
  115. else if (propval.intval <= 20)
  116. {
  117. #ifdef RT_USING_PM
  118. pm_sleep_mode = PM_SLEEP_MODE_LIGHT;
  119. rt_pm_run_enter(PM_RUN_MODE_NORMAL_SPEED);
  120. #endif
  121. LOG_W("%s: Power is low", rt_dm_dev_get_name(psy->dev));
  122. }
  123. #ifdef RT_USING_PM
  124. if (pm_sleep_mode != last_pm_sleep_mode)
  125. {
  126. rt_pm_release(last_pm_sleep_mode);
  127. rt_pm_request(pm_sleep_mode);
  128. last_pm_sleep_mode = pm_sleep_mode;
  129. }
  130. #endif /* RT_USING_PM */
  131. }
  132. else
  133. {
  134. #ifdef RT_USING_PM
  135. if (low_power_mode)
  136. {
  137. rt_pm_release(last_pm_sleep_mode);
  138. rt_pm_request(raw_pm_sleep_mode);
  139. rt_pm_run_enter(raw_pm_run_mode);
  140. low_power_mode = RT_FALSE;
  141. }
  142. #endif /* RT_USING_PM */
  143. }
  144. return RT_EOK;
  145. }
  146. static int power_supply_daemon_init(void)
  147. {
  148. static struct rt_power_supply_notifier daemon_notifier;
  149. daemon_notifier.callback = daemon_power_supply_notify;
  150. rt_power_supply_notifier_register(&daemon_notifier);
  151. return 0;
  152. }
  153. INIT_ENV_EXPORT(power_supply_daemon_init);