diff options
author | Ryan <fauxpark@gmail.com> | 2021-02-25 15:54:25 +1100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-02-25 15:54:25 +1100 |
commit | 39694d5eb0b7e48e06f9544600041fbbedfff956 (patch) | |
tree | 2427bbf89b955330f793fd7dad3502cfc1e19de9 | |
parent | 46f4422a87bf7e3aa52bd8770b14f8361d198e06 (diff) | |
download | qmk_firmware-39694d5eb0b7e48e06f9544600041fbbedfff956.tar.gz qmk_firmware-39694d5eb0b7e48e06f9544600041fbbedfff956.zip |
V-USB suspend refactor (#11891)
-rw-r--r-- | quantum/mcu_selection.mk | 13 | ||||
-rw-r--r-- | tmk_core/common/avr/sleep_led.c | 2 | ||||
-rw-r--r-- | tmk_core/common/avr/suspend.c | 95 | ||||
-rw-r--r-- | tmk_core/common/avr/suspend_avr.h | 25 | ||||
-rw-r--r-- | tmk_core/protocol/vusb/main.c | 54 | ||||
-rw-r--r-- | tmk_core/protocol/vusb/vusb.h | 3 |
6 files changed, 107 insertions, 85 deletions
diff --git a/quantum/mcu_selection.mk b/quantum/mcu_selection.mk index 6b11eb498..65c94b50f 100644 --- a/quantum/mcu_selection.mk +++ b/quantum/mcu_selection.mk | |||
@@ -334,9 +334,6 @@ ifneq (,$(filter $(MCU),atmega32a)) | |||
334 | # calculate timings. Do NOT tack on a 'UL' at the end, this will be done | 334 | # calculate timings. Do NOT tack on a 'UL' at the end, this will be done |
335 | # automatically to create a 32-bit value in your source code. | 335 | # automatically to create a 32-bit value in your source code. |
336 | F_CPU ?= 12000000 | 336 | F_CPU ?= 12000000 |
337 | |||
338 | # unsupported features for now | ||
339 | NO_SUSPEND_POWER_DOWN ?= yes | ||
340 | endif | 337 | endif |
341 | 338 | ||
342 | ifneq (,$(filter $(MCU),atmega328p)) | 339 | ifneq (,$(filter $(MCU),atmega328p)) |
@@ -351,9 +348,6 @@ ifneq (,$(filter $(MCU),atmega328p)) | |||
351 | # calculate timings. Do NOT tack on a 'UL' at the end, this will be done | 348 | # calculate timings. Do NOT tack on a 'UL' at the end, this will be done |
352 | # automatically to create a 32-bit value in your source code. | 349 | # automatically to create a 32-bit value in your source code. |
353 | F_CPU ?= 16000000 | 350 | F_CPU ?= 16000000 |
354 | |||
355 | # unsupported features for now | ||
356 | NO_SUSPEND_POWER_DOWN ?= yes | ||
357 | endif | 351 | endif |
358 | 352 | ||
359 | ifneq (,$(filter $(MCU),atmega328)) | 353 | ifneq (,$(filter $(MCU),atmega328)) |
@@ -368,10 +362,6 @@ ifneq (,$(filter $(MCU),atmega328)) | |||
368 | # calculate timings. Do NOT tack on a 'UL' at the end, this will be done | 362 | # calculate timings. Do NOT tack on a 'UL' at the end, this will be done |
369 | # automatically to create a 32-bit value in your source code. | 363 | # automatically to create a 32-bit value in your source code. |
370 | F_CPU ?= 16000000 | 364 | F_CPU ?= 16000000 |
371 | |||
372 | # unsupported features for now | ||
373 | NO_UART ?= yes | ||
374 | NO_SUSPEND_POWER_DOWN ?= yes | ||
375 | endif | 365 | endif |
376 | 366 | ||
377 | ifneq (,$(filter $(MCU),attiny85)) | 367 | ifneq (,$(filter $(MCU),attiny85)) |
@@ -383,7 +373,4 @@ ifneq (,$(filter $(MCU),attiny85)) | |||
383 | # calculate timings. Do NOT tack on a 'UL' at the end, this will be done | 373 | # calculate timings. Do NOT tack on a 'UL' at the end, this will be done |
384 | # automatically to create a 32-bit value in your source code. | 374 | # automatically to create a 32-bit value in your source code. |
385 | F_CPU ?= 16500000 | 375 | F_CPU ?= 16500000 |
386 | |||
387 | # unsupported features for now | ||
388 | NO_SUSPEND_POWER_DOWN ?= yes | ||
389 | endif | 376 | endif |
diff --git a/tmk_core/common/avr/sleep_led.c b/tmk_core/common/avr/sleep_led.c index 63dcc2afd..9a3b52abe 100644 --- a/tmk_core/common/avr/sleep_led.c +++ b/tmk_core/common/avr/sleep_led.c | |||
@@ -90,7 +90,7 @@ void sleep_led_toggle(void) { | |||
90 | * | 90 | * |
91 | * (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle | 91 | * (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle |
92 | * | 92 | * |
93 | * http://www.wolframalpha.com/input/?i=%28sin%28+x%2F64*pi%29**8+*+255%2C+x%3D0+to+63 | 93 | * https://www.wolframalpha.com/input/?i=sin%28x%2F64*pi%29**8+*+255%2C+x%3D0+to+63 |
94 | * (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i } | 94 | * (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i } |
95 | */ | 95 | */ |
96 | static const uint8_t breathing_table[64] PROGMEM = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 6, 10, 15, 23, 32, 44, 58, 74, 93, 113, 135, 157, 179, 199, 218, 233, 245, 252, 255, 252, 245, 233, 218, 199, 179, 157, 135, 113, 93, 74, 58, 44, 32, 23, 15, 10, 6, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; | 96 | static const uint8_t breathing_table[64] PROGMEM = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 6, 10, 15, 23, 32, 44, 58, 74, 93, 113, 135, 157, 179, 199, 218, 233, 245, 252, 255, 252, 245, 233, 218, 199, 179, 157, 135, 113, 93, 74, 58, 44, 32, 23, 15, 10, 6, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; |
diff --git a/tmk_core/common/avr/suspend.c b/tmk_core/common/avr/suspend.c index 86c3df040..cb505ab32 100644 --- a/tmk_core/common/avr/suspend.c +++ b/tmk_core/common/avr/suspend.c | |||
@@ -4,7 +4,6 @@ | |||
4 | #include <avr/interrupt.h> | 4 | #include <avr/interrupt.h> |
5 | #include "matrix.h" | 5 | #include "matrix.h" |
6 | #include "action.h" | 6 | #include "action.h" |
7 | #include "suspend_avr.h" | ||
8 | #include "suspend.h" | 7 | #include "suspend.h" |
9 | #include "timer.h" | 8 | #include "timer.h" |
10 | #include "led.h" | 9 | #include "led.h" |
@@ -13,6 +12,9 @@ | |||
13 | #ifdef PROTOCOL_LUFA | 12 | #ifdef PROTOCOL_LUFA |
14 | # include "lufa.h" | 13 | # include "lufa.h" |
15 | #endif | 14 | #endif |
15 | #ifdef PROTOCOL_VUSB | ||
16 | # include "vusb.h" | ||
17 | #endif | ||
16 | 18 | ||
17 | #ifdef BACKLIGHT_ENABLE | 19 | #ifdef BACKLIGHT_ENABLE |
18 | # include "backlight.h" | 20 | # include "backlight.h" |
@@ -52,7 +54,25 @@ __attribute__((weak)) void suspend_power_down_user(void) {} | |||
52 | */ | 54 | */ |
53 | __attribute__((weak)) void suspend_power_down_kb(void) { suspend_power_down_user(); } | 55 | __attribute__((weak)) void suspend_power_down_kb(void) { suspend_power_down_user(); } |
54 | 56 | ||
55 | #ifndef NO_SUSPEND_POWER_DOWN | 57 | #if !defined(NO_SUSPEND_POWER_DOWN) && defined(WDT_vect) |
58 | |||
59 | // clang-format off | ||
60 | #define wdt_intr_enable(value) \ | ||
61 | __asm__ __volatile__ ( \ | ||
62 | "in __tmp_reg__,__SREG__" "\n\t" \ | ||
63 | "cli" "\n\t" \ | ||
64 | "wdr" "\n\t" \ | ||
65 | "sts %0,%1" "\n\t" \ | ||
66 | "out __SREG__,__tmp_reg__" "\n\t" \ | ||
67 | "sts %0,%2" "\n\t" \ | ||
68 | : /* no outputs */ \ | ||
69 | : "M" (_SFR_MEM_ADDR(_WD_CONTROL_REG)), \ | ||
70 | "r" (_BV(_WD_CHANGE_BIT) | _BV(WDE)), \ | ||
71 | "r" ((uint8_t) ((value & 0x08 ? _WD_PS3_MASK : 0x00) | _BV(WDIE) | (value & 0x07))) \ | ||
72 | : "r0" \ | ||
73 | ) | ||
74 | // clang-format on | ||
75 | |||
56 | /** \brief Power down MCU with watchdog timer | 76 | /** \brief Power down MCU with watchdog timer |
57 | * | 77 | * |
58 | * wdto: watchdog timer timeout defined in <avr/wdt.h> | 78 | * wdto: watchdog timer timeout defined in <avr/wdt.h> |
@@ -74,37 +94,11 @@ static uint8_t wdt_timeout = 0; | |||
74 | * FIXME: needs doc | 94 | * FIXME: needs doc |
75 | */ | 95 | */ |
76 | static void power_down(uint8_t wdto) { | 96 | static void power_down(uint8_t wdto) { |
77 | # ifdef PROTOCOL_LUFA | ||
78 | if (USB_DeviceState == DEVICE_STATE_Configured) return; | ||
79 | # endif | ||
80 | wdt_timeout = wdto; | 97 | wdt_timeout = wdto; |
81 | 98 | ||
82 | // Watchdog Interrupt Mode | 99 | // Watchdog Interrupt Mode |
83 | wdt_intr_enable(wdto); | 100 | wdt_intr_enable(wdto); |
84 | 101 | ||
85 | # ifdef BACKLIGHT_ENABLE | ||
86 | backlight_set(0); | ||
87 | # endif | ||
88 | |||
89 | // Turn off LED indicators | ||
90 | uint8_t leds_off = 0; | ||
91 | # if defined(BACKLIGHT_CAPS_LOCK) && defined(BACKLIGHT_ENABLE) | ||
92 | if (is_backlight_enabled()) { | ||
93 | // Don't try to turn off Caps Lock indicator as it is backlight and backlight is already off | ||
94 | leds_off |= (1 << USB_LED_CAPS_LOCK); | ||
95 | } | ||
96 | # endif | ||
97 | led_set(leds_off); | ||
98 | |||
99 | # ifdef AUDIO_ENABLE | ||
100 | // This sometimes disables the start-up noise, so it's been disabled | ||
101 | // stop_all_notes(); | ||
102 | # endif /* AUDIO_ENABLE */ | ||
103 | # if defined(RGBLIGHT_SLEEP) && defined(RGBLIGHT_ENABLE) | ||
104 | rgblight_suspend(); | ||
105 | # endif | ||
106 | suspend_power_down_kb(); | ||
107 | |||
108 | // TODO: more power saving | 102 | // TODO: more power saving |
109 | // See PicoPower application note | 103 | // See PicoPower application note |
110 | // - I/O port input with pullup | 104 | // - I/O port input with pullup |
@@ -127,10 +121,46 @@ static void power_down(uint8_t wdto) { | |||
127 | * FIXME: needs doc | 121 | * FIXME: needs doc |
128 | */ | 122 | */ |
129 | void suspend_power_down(void) { | 123 | void suspend_power_down(void) { |
124 | #ifdef PROTOCOL_LUFA | ||
125 | if (USB_DeviceState == DEVICE_STATE_Configured) return; | ||
126 | #endif | ||
127 | #ifdef PROTOCOL_VUSB | ||
128 | if (!vusb_suspended) return; | ||
129 | #endif | ||
130 | |||
130 | suspend_power_down_kb(); | 131 | suspend_power_down_kb(); |
131 | 132 | ||
132 | #ifndef NO_SUSPEND_POWER_DOWN | 133 | #ifndef NO_SUSPEND_POWER_DOWN |
134 | // Turn off backlight | ||
135 | # ifdef BACKLIGHT_ENABLE | ||
136 | backlight_set(0); | ||
137 | # endif | ||
138 | |||
139 | // Turn off LED indicators | ||
140 | uint8_t leds_off = 0; | ||
141 | # if defined(BACKLIGHT_CAPS_LOCK) && defined(BACKLIGHT_ENABLE) | ||
142 | if (is_backlight_enabled()) { | ||
143 | // Don't try to turn off Caps Lock indicator as it is backlight and backlight is already off | ||
144 | leds_off |= (1 << USB_LED_CAPS_LOCK); | ||
145 | } | ||
146 | # endif | ||
147 | led_set(leds_off); | ||
148 | |||
149 | // Turn off audio | ||
150 | # ifdef AUDIO_ENABLE | ||
151 | // This sometimes disables the start-up noise, so it's been disabled | ||
152 | // stop_all_notes(); | ||
153 | # endif | ||
154 | |||
155 | // Turn off underglow | ||
156 | # if defined(RGBLIGHT_SLEEP) && defined(RGBLIGHT_ENABLE) | ||
157 | rgblight_suspend(); | ||
158 | # endif | ||
159 | |||
160 | // Enter sleep state if possible (ie, the MCU has a watchdog timeout interrupt) | ||
161 | # if defined(WDT_vect) | ||
133 | power_down(WDTO_15MS); | 162 | power_down(WDTO_15MS); |
163 | # endif | ||
134 | #endif | 164 | #endif |
135 | } | 165 | } |
136 | 166 | ||
@@ -164,17 +194,24 @@ __attribute__((weak)) void suspend_wakeup_init_kb(void) { suspend_wakeup_init_us | |||
164 | void suspend_wakeup_init(void) { | 194 | void suspend_wakeup_init(void) { |
165 | // clear keyboard state | 195 | // clear keyboard state |
166 | clear_keyboard(); | 196 | clear_keyboard(); |
197 | |||
198 | // Turn on backlight | ||
167 | #ifdef BACKLIGHT_ENABLE | 199 | #ifdef BACKLIGHT_ENABLE |
168 | backlight_init(); | 200 | backlight_init(); |
169 | #endif | 201 | #endif |
202 | |||
203 | // Restore LED indicators | ||
170 | led_set(host_keyboard_leds()); | 204 | led_set(host_keyboard_leds()); |
205 | |||
206 | // Wake up underglow | ||
171 | #if defined(RGBLIGHT_SLEEP) && defined(RGBLIGHT_ENABLE) | 207 | #if defined(RGBLIGHT_SLEEP) && defined(RGBLIGHT_ENABLE) |
172 | rgblight_wakeup(); | 208 | rgblight_wakeup(); |
173 | #endif | 209 | #endif |
210 | |||
174 | suspend_wakeup_init_kb(); | 211 | suspend_wakeup_init_kb(); |
175 | } | 212 | } |
176 | 213 | ||
177 | #ifndef NO_SUSPEND_POWER_DOWN | 214 | #if !defined(NO_SUSPEND_POWER_DOWN) && defined(WDT_vect) |
178 | /* watchdog timeout */ | 215 | /* watchdog timeout */ |
179 | ISR(WDT_vect) { | 216 | ISR(WDT_vect) { |
180 | // compensate timer for sleep | 217 | // compensate timer for sleep |
diff --git a/tmk_core/common/avr/suspend_avr.h b/tmk_core/common/avr/suspend_avr.h deleted file mode 100644 index 6df048f3b..000000000 --- a/tmk_core/common/avr/suspend_avr.h +++ /dev/null | |||
@@ -1,25 +0,0 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include <stdint.h> | ||
4 | #include <stdbool.h> | ||
5 | #include <avr/sleep.h> | ||
6 | #include <avr/wdt.h> | ||
7 | #include <avr/interrupt.h> | ||
8 | |||
9 | // clang-format off | ||
10 | #define wdt_intr_enable(value) \ | ||
11 | __asm__ __volatile__ ( \ | ||
12 | "in __tmp_reg__,__SREG__" "\n\t" \ | ||
13 | "cli" "\n\t" \ | ||
14 | "wdr" "\n\t" \ | ||
15 | "sts %0,%1" "\n\t" \ | ||
16 | "out __SREG__,__tmp_reg__" "\n\t" \ | ||
17 | "sts %0,%2" "\n\t" \ | ||
18 | : /* no outputs */ \ | ||
19 | : "M" (_SFR_MEM_ADDR(_WD_CONTROL_REG)), \ | ||
20 | "r" (_BV(_WD_CHANGE_BIT) | _BV(WDE)), \ | ||
21 | "r" ((uint8_t) ((value & 0x08 ? _WD_PS3_MASK : 0x00) | \ | ||
22 | _BV(WDIE) | (value & 0x07)) ) \ | ||
23 | : "r0" \ | ||
24 | ) | ||
25 | // clang-format on | ||
diff --git a/tmk_core/protocol/vusb/main.c b/tmk_core/protocol/vusb/main.c index 2e8bb2fbb..af64f4e56 100644 --- a/tmk_core/protocol/vusb/main.c +++ b/tmk_core/protocol/vusb/main.c | |||
@@ -53,10 +53,10 @@ static void initForUsbConnectivity(void) { | |||
53 | usbDeviceConnect(); | 53 | usbDeviceConnect(); |
54 | } | 54 | } |
55 | 55 | ||
56 | static void usb_remote_wakeup(void) { | 56 | static void vusb_send_remote_wakeup(void) { |
57 | cli(); | 57 | cli(); |
58 | 58 | ||
59 | int8_t ddr_orig = USBDDR; | 59 | uint8_t ddr_orig = USBDDR; |
60 | USBOUT |= (1 << USBMINUS); | 60 | USBOUT |= (1 << USBMINUS); |
61 | USBDDR = ddr_orig | USBMASK; | 61 | USBDDR = ddr_orig | USBMASK; |
62 | USBOUT ^= USBMASK; | 62 | USBOUT ^= USBMASK; |
@@ -70,6 +70,27 @@ static void usb_remote_wakeup(void) { | |||
70 | sei(); | 70 | sei(); |
71 | } | 71 | } |
72 | 72 | ||
73 | bool vusb_suspended = false; | ||
74 | |||
75 | static void vusb_suspend(void) { | ||
76 | vusb_suspended = true; | ||
77 | |||
78 | #ifdef SLEEP_LED_ENABLE | ||
79 | sleep_led_enable(); | ||
80 | #endif | ||
81 | |||
82 | suspend_power_down(); | ||
83 | } | ||
84 | |||
85 | static void vusb_wakeup(void) { | ||
86 | vusb_suspended = false; | ||
87 | suspend_wakeup_init(); | ||
88 | |||
89 | #ifdef SLEEP_LED_ENABLE | ||
90 | sleep_led_disable(); | ||
91 | #endif | ||
92 | } | ||
93 | |||
73 | /** \brief Setup USB | 94 | /** \brief Setup USB |
74 | * | 95 | * |
75 | * FIXME: Needs doc | 96 | * FIXME: Needs doc |
@@ -87,9 +108,8 @@ static void setup_usb(void) { | |||
87 | */ | 108 | */ |
88 | int main(void) __attribute__((weak)); | 109 | int main(void) __attribute__((weak)); |
89 | int main(void) { | 110 | int main(void) { |
90 | bool suspended = false; | ||
91 | #if USB_COUNT_SOF | 111 | #if USB_COUNT_SOF |
92 | uint16_t last_timer = timer_read(); | 112 | uint16_t sof_timer = timer_read(); |
93 | #endif | 113 | #endif |
94 | 114 | ||
95 | #ifdef CLKPR | 115 | #ifdef CLKPR |
@@ -112,23 +132,24 @@ int main(void) { | |||
112 | while (1) { | 132 | while (1) { |
113 | #if USB_COUNT_SOF | 133 | #if USB_COUNT_SOF |
114 | if (usbSofCount != 0) { | 134 | if (usbSofCount != 0) { |
115 | suspended = false; | ||
116 | usbSofCount = 0; | 135 | usbSofCount = 0; |
117 | last_timer = timer_read(); | 136 | sof_timer = timer_read(); |
118 | # ifdef SLEEP_LED_ENABLE | 137 | if (vusb_suspended) { |
119 | sleep_led_disable(); | 138 | vusb_wakeup(); |
120 | # endif | 139 | } |
121 | } else { | 140 | } else { |
122 | // Suspend when no SOF in 3ms-10ms(7.1.7.4 Suspending of USB1.1) | 141 | // Suspend when no SOF in 3ms-10ms(7.1.7.4 Suspending of USB1.1) |
123 | if (timer_elapsed(last_timer) > 5) { | 142 | if (!vusb_suspended && timer_elapsed(sof_timer) > 5) { |
124 | suspended = true; | 143 | vusb_suspend(); |
125 | # ifdef SLEEP_LED_ENABLE | ||
126 | sleep_led_enable(); | ||
127 | # endif | ||
128 | } | 144 | } |
129 | } | 145 | } |
130 | #endif | 146 | #endif |
131 | if (!suspended) { | 147 | if (vusb_suspended) { |
148 | vusb_suspend(); | ||
149 | if (suspend_wakeup_condition()) { | ||
150 | vusb_send_remote_wakeup(); | ||
151 | } | ||
152 | } else { | ||
132 | usbPoll(); | 153 | usbPoll(); |
133 | 154 | ||
134 | // TODO: configuration process is inconsistent. it sometime fails. | 155 | // TODO: configuration process is inconsistent. it sometime fails. |
@@ -145,6 +166,7 @@ int main(void) { | |||
145 | raw_hid_task(); | 166 | raw_hid_task(); |
146 | } | 167 | } |
147 | #endif | 168 | #endif |
169 | |||
148 | #ifdef CONSOLE_ENABLE | 170 | #ifdef CONSOLE_ENABLE |
149 | usbPoll(); | 171 | usbPoll(); |
150 | 172 | ||
@@ -156,8 +178,6 @@ int main(void) { | |||
156 | // Run housekeeping | 178 | // Run housekeeping |
157 | housekeeping_task_kb(); | 179 | housekeeping_task_kb(); |
158 | housekeeping_task_user(); | 180 | housekeeping_task_user(); |
159 | } else if (suspend_wakeup_condition()) { | ||
160 | usb_remote_wakeup(); | ||
161 | } | 181 | } |
162 | } | 182 | } |
163 | } | 183 | } |
diff --git a/tmk_core/protocol/vusb/vusb.h b/tmk_core/protocol/vusb/vusb.h index b4c73aaba..b1ecc98f3 100644 --- a/tmk_core/protocol/vusb/vusb.h +++ b/tmk_core/protocol/vusb/vusb.h | |||
@@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
18 | #pragma once | 18 | #pragma once |
19 | 19 | ||
20 | #include "host_driver.h" | 20 | #include "host_driver.h" |
21 | #include <usbdrv/usbdrv.h> | ||
21 | 22 | ||
22 | typedef struct usbDescriptorHeader { | 23 | typedef struct usbDescriptorHeader { |
23 | uchar bLength; | 24 | uchar bLength; |
@@ -119,5 +120,7 @@ typedef struct usbConfigurationDescriptor { | |||
119 | 120 | ||
120 | #define USB_STRING_LEN(s) (sizeof(usbDescriptorHeader_t) + ((s) << 1)) | 121 | #define USB_STRING_LEN(s) (sizeof(usbDescriptorHeader_t) + ((s) << 1)) |
121 | 122 | ||
123 | extern bool vusb_suspended; | ||
124 | |||
122 | host_driver_t *vusb_driver(void); | 125 | host_driver_t *vusb_driver(void); |
123 | void vusb_transfer_keyboard(void); | 126 | void vusb_transfer_keyboard(void); |