upload
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.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

suspend.c 3.0KB

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