Keyboard firmwares for Atmel AVR and Cortex-M
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

suspend.c 2.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. #include <stdbool.h>
  2. #include <avr/sleep.h>
  3. #include <avr/wdt.h>
  4. #include <avr/interrupt.h>
  5. #include "matrix.h"
  6. #include "action.h"
  7. #include "backlight.h"
  8. #include "suspend_avr.h"
  9. #include "suspend.h"
  10. #include "timer.h"
  11. #ifdef PROTOCOL_LUFA
  12. #include "lufa.h"
  13. #endif
  14. #define wdt_intr_enable(value) \
  15. __asm__ __volatile__ ( \
  16. "in __tmp_reg__,__SREG__" "\n\t" \
  17. "cli" "\n\t" \
  18. "wdr" "\n\t" \
  19. "sts %0,%1" "\n\t" \
  20. "out __SREG__,__tmp_reg__" "\n\t" \
  21. "sts %0,%2" "\n\t" \
  22. : /* no outputs */ \
  23. : "M" (_SFR_MEM_ADDR(_WD_CONTROL_REG)), \
  24. "r" (_BV(_WD_CHANGE_BIT) | _BV(WDE)), \
  25. "r" ((uint8_t) ((value & 0x08 ? _WD_PS3_MASK : 0x00) | \
  26. _BV(WDIE) | (value & 0x07)) ) \
  27. : "r0" \
  28. )
  29. /* Power down MCU with watchdog timer
  30. * wdto: watchdog timer timeout defined in <avr/wdt.h>
  31. * WDTO_15MS
  32. * WDTO_30MS
  33. * WDTO_60MS
  34. * WDTO_120MS
  35. * WDTO_250MS
  36. * WDTO_500MS
  37. * WDTO_1S
  38. * WDTO_2S
  39. * WDTO_4S
  40. * WDTO_8S
  41. */
  42. static uint8_t wdt_timeout = 0;
  43. static void power_down(uint8_t wdto)
  44. {
  45. #ifdef PROTOCOL_LUFA
  46. if (USB_DeviceState == DEVICE_STATE_Configured) return;
  47. #endif
  48. wdt_timeout = wdto;
  49. // Watchdog Interrupt Mode
  50. wdt_intr_enable(wdto);
  51. // TODO: more power saving
  52. // See PicoPower application note
  53. // - I/O port input with pullup
  54. // - prescale clock
  55. // - BOD disable
  56. // - Power Reduction Register PRR
  57. set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  58. sleep_enable();
  59. sei();
  60. sleep_cpu();
  61. sleep_disable();
  62. // Disable watchdog after sleep
  63. wdt_disable();
  64. }
  65. static void standby(void)
  66. {
  67. set_sleep_mode(SLEEP_MODE_STANDBY);
  68. sleep_enable();
  69. sei();
  70. sleep_cpu();
  71. sleep_disable();
  72. }
  73. static void idle(void)
  74. {
  75. set_sleep_mode(SLEEP_MODE_IDLE);
  76. sleep_enable();
  77. sei();
  78. sleep_cpu();
  79. sleep_disable();
  80. }
  81. void suspend_idle(uint8_t time)
  82. {
  83. idle();
  84. }
  85. void suspend_power_down(void)
  86. {
  87. #ifdef NO_SUSPEND_POWER_DOWN
  88. ;
  89. #elif defined(SUSPEND_MODE_NOPOWERSAVE)
  90. ;
  91. #elif defined(SUSPEND_MODE_STANDBY)
  92. standby();
  93. #elif defined(SUSPEND_MODE_IDLE)
  94. idle();
  95. #else
  96. power_down(WDTO_15MS);
  97. #endif
  98. }
  99. bool suspend_wakeup_condition(void)
  100. {
  101. matrix_power_up();
  102. matrix_scan();
  103. matrix_power_down();
  104. for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
  105. if (matrix_get_row(r)) return true;
  106. }
  107. return false;
  108. }
  109. // run immediately after wakeup
  110. void suspend_wakeup_init(void)
  111. {
  112. // clear keyboard state
  113. matrix_clear();
  114. clear_keyboard();
  115. #ifdef BACKLIGHT_ENABLE
  116. backlight_init();
  117. #endif
  118. }
  119. #ifndef NO_SUSPEND_POWER_DOWN
  120. /* watchdog timeout */
  121. ISR(WDT_vect)
  122. {
  123. // compensate timer for sleep
  124. switch (wdt_timeout) {
  125. case WDTO_15MS:
  126. timer_count += 15 + 2; // WDTO_15MS + 2(from observation)
  127. break;
  128. default:
  129. ;
  130. }
  131. }
  132. #endif