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