diff options
Diffstat (limited to 'tmk_core/common/avr/suspend.c')
-rw-r--r-- | tmk_core/common/avr/suspend.c | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/tmk_core/common/avr/suspend.c b/tmk_core/common/avr/suspend.c new file mode 100644 index 000000000..80243f02b --- /dev/null +++ b/tmk_core/common/avr/suspend.c | |||
@@ -0,0 +1,122 @@ | |||
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 | |||
15 | |||
16 | #define wdt_intr_enable(value) \ | ||
17 | __asm__ __volatile__ ( \ | ||
18 | "in __tmp_reg__,__SREG__" "\n\t" \ | ||
19 | "cli" "\n\t" \ | ||
20 | "wdr" "\n\t" \ | ||
21 | "sts %0,%1" "\n\t" \ | ||
22 | "out __SREG__,__tmp_reg__" "\n\t" \ | ||
23 | "sts %0,%2" "\n\t" \ | ||
24 | : /* no outputs */ \ | ||
25 | : "M" (_SFR_MEM_ADDR(_WD_CONTROL_REG)), \ | ||
26 | "r" (_BV(_WD_CHANGE_BIT) | _BV(WDE)), \ | ||
27 | "r" ((uint8_t) ((value & 0x08 ? _WD_PS3_MASK : 0x00) | \ | ||
28 | _BV(WDIE) | (value & 0x07)) ) \ | ||
29 | : "r0" \ | ||
30 | ) | ||
31 | |||
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 | |||
43 | /* Power down MCU with watchdog timer | ||
44 | * wdto: watchdog timer timeout defined in <avr/wdt.h> | ||
45 | * WDTO_15MS | ||
46 | * WDTO_30MS | ||
47 | * WDTO_60MS | ||
48 | * WDTO_120MS | ||
49 | * WDTO_250MS | ||
50 | * WDTO_500MS | ||
51 | * WDTO_1S | ||
52 | * WDTO_2S | ||
53 | * WDTO_4S | ||
54 | * WDTO_8S | ||
55 | */ | ||
56 | static uint8_t wdt_timeout = 0; | ||
57 | static void power_down(uint8_t wdto) | ||
58 | { | ||
59 | #ifdef PROTOCOL_LUFA | ||
60 | if (USB_DeviceState == DEVICE_STATE_Configured) return; | ||
61 | #endif | ||
62 | wdt_timeout = wdto; | ||
63 | |||
64 | // Watchdog Interrupt Mode | ||
65 | wdt_intr_enable(wdto); | ||
66 | |||
67 | // TODO: more power saving | ||
68 | // See PicoPower application note | ||
69 | // - I/O port input with pullup | ||
70 | // - prescale clock | ||
71 | // - BOD disable | ||
72 | // - Power Reduction Register PRR | ||
73 | set_sleep_mode(SLEEP_MODE_PWR_DOWN); | ||
74 | sleep_enable(); | ||
75 | sei(); | ||
76 | sleep_cpu(); | ||
77 | sleep_disable(); | ||
78 | |||
79 | // Disable watchdog after sleep | ||
80 | wdt_disable(); | ||
81 | } | ||
82 | |||
83 | void suspend_power_down(void) | ||
84 | { | ||
85 | power_down(WDTO_15MS); | ||
86 | } | ||
87 | |||
88 | bool suspend_wakeup_condition(void) | ||
89 | { | ||
90 | matrix_power_up(); | ||
91 | matrix_scan(); | ||
92 | matrix_power_down(); | ||
93 | for (uint8_t r = 0; r < MATRIX_ROWS; r++) { | ||
94 | if (matrix_get_row(r)) return true; | ||
95 | } | ||
96 | return false; | ||
97 | } | ||
98 | |||
99 | // run immediately after wakeup | ||
100 | void suspend_wakeup_init(void) | ||
101 | { | ||
102 | // clear keyboard state | ||
103 | clear_keyboard(); | ||
104 | #ifdef BACKLIGHT_ENABLE | ||
105 | backlight_init(); | ||
106 | #endif | ||
107 | } | ||
108 | |||
109 | #ifndef NO_SUSPEND_POWER_DOWN | ||
110 | /* watchdog timeout */ | ||
111 | ISR(WDT_vect) | ||
112 | { | ||
113 | // compensate timer for sleep | ||
114 | switch (wdt_timeout) { | ||
115 | case WDTO_15MS: | ||
116 | timer_count += 15 + 2; // WDTO_15MS + 2(from observation) | ||
117 | break; | ||
118 | default: | ||
119 | ; | ||
120 | } | ||
121 | } | ||
122 | #endif | ||