From 8820c52609e8930e7f8d85f96348dc0fd91a3973 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Boczar?= Date: Thu, 10 Nov 2022 20:25:49 +0100 Subject: [PATCH 1/3] Cleanup: remove redundant interrupt::free --- src/bus.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/bus.rs b/src/bus.rs index 657d8f8..11e0510 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -218,10 +218,7 @@ impl usb_device::bus::UsbBus for UsbBus { if v.ctr_tx().bit_is_set() { ep_in_complete |= bit; - - interrupt::free(|cs| { - ep.clear_ctr_tx(cs); - }); + ep.clear_ctr_tx(cs); } bit <<= 1; From 3507c24187837daa8a42958240ba355a57ff5588 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Boczar?= Date: Thu, 10 Nov 2022 22:01:12 +0100 Subject: [PATCH 2/3] Do not auto-enter low-power suspend, expose method to user Setting LP_MODE instantly does not allow user application to prepare for the low power mode, disable clocks, peripherals, etc. Also, self-powered devices may not want to enter low-power mode during host suspend. --- src/bus.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/bus.rs b/src/bus.rs index 11e0510..c6bbd56 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -71,6 +71,27 @@ impl UsbBus { regs.cntr.modify(|_, w| w.pdwn().bit(pdwn)); }); } + + /// Enter suspend low-power mode + /// + /// This should be used when in suspend mode if low-power mode needs to be entered during + /// suspend (bus-powered device). Application should call this when it is ready to decrease + /// power consumption to meet power consumption requirements of the USB suspend condition + /// (e.g. disable system clocks or reduce their frequency). When wake up event is received + /// low power mode will be automatically disabled. + /// + /// Will not enter low-power mode if not in suspend state. Returns `true` if entered. + pub fn suspend_low_power_mode(&self) -> bool { + interrupt::free(|cs| { + let regs = self.regs.borrow(cs); + if regs.cntr.read().fsusp().is_suspend() { + regs.cntr.modify(|_, w| w.lpmode().set_bit()); + true + } else { + false + } + }) + } } impl usb_device::bus::UsbBus for UsbBus { @@ -285,7 +306,7 @@ impl usb_device::bus::UsbBus for UsbBus { self.regs .borrow(cs) .cntr - .modify(|_, w| w.fsusp().set_bit().lpmode().set_bit()); + .modify(|_, w| w.fsusp().set_bit()); }); } From c6f7d12c524fff31c9f0de0baea0bcdeffcfbddc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Boczar?= Date: Thu, 10 Nov 2022 23:34:26 +0100 Subject: [PATCH 3/3] Add method for implementing remote wakeup method --- src/bus.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/bus.rs b/src/bus.rs index c6bbd56..3b3d927 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -92,6 +92,23 @@ impl UsbBus { } }) } + + /// Set/clear remote wakeup bit + /// + /// Allows to modify CNTR.RESUME bit from device to perform remote wake up from suspend + /// (e.g. on keyboard/mouse input). To perform remote wake up: when a condition is met + /// during suspend mode, use this method with `true` to set the RESUME bit. Then, after + /// waiting between 1-15 ms (see reference manual) call it again with `false` to clear + /// the bit. + /// + /// This method will not set the bit if device is not suspended because performing remote + /// wake up in other mode is invalid and host will most likely disable such a device. + pub fn remote_wakeup(&self, resume: bool) { + interrupt::free(|cs| { + self.regs.borrow(cs) + .cntr.modify(|r, w| w.resume().bit(resume && r.fsusp().is_suspend())); + }) + } } impl usb_device::bus::UsbBus for UsbBus {