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.

158 lines
3.2 KiB

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