aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan <fauxpark@gmail.com>2021-02-25 15:54:25 +1100
committerGitHub <noreply@github.com>2021-02-25 15:54:25 +1100
commit39694d5eb0b7e48e06f9544600041fbbedfff956 (patch)
tree2427bbf89b955330f793fd7dad3502cfc1e19de9
parent46f4422a87bf7e3aa52bd8770b14f8361d198e06 (diff)
downloadqmk_firmware-39694d5eb0b7e48e06f9544600041fbbedfff956.tar.gz
qmk_firmware-39694d5eb0b7e48e06f9544600041fbbedfff956.zip
V-USB suspend refactor (#11891)
-rw-r--r--quantum/mcu_selection.mk13
-rw-r--r--tmk_core/common/avr/sleep_led.c2
-rw-r--r--tmk_core/common/avr/suspend.c95
-rw-r--r--tmk_core/common/avr/suspend_avr.h25
-rw-r--r--tmk_core/protocol/vusb/main.c54
-rw-r--r--tmk_core/protocol/vusb/vusb.h3
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
340endif 337endif
341 338
342ifneq (,$(filter $(MCU),atmega328p)) 339ifneq (,$(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
357endif 351endif
358 352
359ifneq (,$(filter $(MCU),atmega328)) 353ifneq (,$(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
375endif 365endif
376 366
377ifneq (,$(filter $(MCU),attiny85)) 367ifneq (,$(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
389endif 376endif
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 */
96static 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}; 96static 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 */
76static void power_down(uint8_t wdto) { 96static 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 */
129void suspend_power_down(void) { 123void 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
164void suspend_wakeup_init(void) { 194void 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 */
179ISR(WDT_vect) { 216ISR(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
56static void usb_remote_wakeup(void) { 56static 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
73bool vusb_suspended = false;
74
75static 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
85static 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 */
88int main(void) __attribute__((weak)); 109int main(void) __attribute__((weak));
89int main(void) { 110int 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
22typedef struct usbDescriptorHeader { 23typedef 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
123extern bool vusb_suspended;
124
122host_driver_t *vusb_driver(void); 125host_driver_t *vusb_driver(void);
123void vusb_transfer_keyboard(void); 126void vusb_transfer_keyboard(void);