diff --git a/hal/targets/hal/TARGET_Maxim/TARGET_MAX32620/sleep.c b/hal/targets/hal/TARGET_Maxim/TARGET_MAX32620/sleep.c index 0ab40fa518..311325d932 100644 --- a/hal/targets/hal/TARGET_Maxim/TARGET_MAX32620/sleep.c +++ b/hal/targets/hal/TARGET_Maxim/TARGET_MAX32620/sleep.c @@ -38,12 +38,23 @@ #include "clkman_regs.h" #include "ioman_regs.h" #include "rtc_regs.h" +#include "usb_regs.h" #include "wait_api.h" #define REVISION_A3 2 #define REVISION_A4 3 +// USB state to be restored upon wakeup +typedef struct { + uint32_t dev_cn; + uint32_t dev_inten; + uint32_t ep_base; + uint32_t ep[MXC_USB_NUM_EP]; +} usb_state_t; + static mxc_uart_regs_t *stdio_uart = (mxc_uart_regs_t*)STDIO_UART; +static int restore_usb; +static usb_state_t usb_state; void sleep(void) { @@ -54,28 +65,79 @@ void sleep(void) __WFI(); } +static void usb_sleep(void) +{ + int i; + + if (MXC_USB->cn & MXC_F_USB_CN_USB_EN) { + // The USB module will not survive Deep Sleep. + + // Save the USB state to restore it upon wakeup + usb_state.dev_cn = MXC_USB->dev_cn; + usb_state.dev_inten = MXC_USB->dev_inten; + usb_state.ep_base = MXC_USB->ep_base; + for (i = 0; i < MXC_USB_NUM_EP; i++) { + usb_state.ep[i] = MXC_USB->ep[i] & (MXC_F_USB_EP_DIR | MXC_F_USB_EP_BUF2 | MXC_F_USB_EP_INT_EN | MXC_F_USB_EP_NAK_EN); + } + restore_usb = 1; + + // Shut down the USB module. + MXC_USB->dev_inten = 0; + MXC_USB->dev_cn = 0; + MXC_USB->cn = 0; + restore_usb = 1; // USB should be restored upon wakeup + } + else { + restore_usb = 0; + } +} + +// Restore the USB module state. +static void usb_wakeup(void) +{ + int i; + + if (restore_usb) { + MXC_USB->cn = MXC_F_USB_CN_USB_EN; + MXC_USB->dev_cn = MXC_F_USB_DEV_CN_URST; + MXC_USB->dev_cn = 0; + for (i = 0; i < MXC_USB_NUM_EP; i++) { + MXC_USB->ep[i] = usb_state.ep[i]; + } + MXC_USB->ep_base = usb_state.ep_base; + MXC_USB->dev_cn = usb_state.dev_cn; + MXC_USB->dev_inten = usb_state.dev_inten; + restore_usb = 0; + } +} + // Low-power stop mode void deepsleep(void) { - /* Deep Sleep is not yet supported. */ - sleep(); - -#if 0 unsigned int part_rev = MXC_PWRMAN->mask_id0 & MXC_F_PWRMAN_MASK_ID0_REVISION_ID; - // Deep sleep is not working properly on Revisions A3 and earlier + // Deep Sleep is not working properly on Revisions A3 and earlier if (part_rev <= REVISION_A3) { sleep(); return; } // Wait for all STDIO characters to be sent. The UART clock will stop. - while ( (((stdio_uart->tx_fifo_ctrl & MXC_F_UART_TX_FIFO_CTRL_FIFO_ENTRY) - >> MXC_F_UART_TX_FIFO_CTRL_FIFO_ENTRY_POS) > 0) || - (!(stdio_uart->intfl & MXC_F_UART_INTFL_TX_DONE)) ); + while ((stdio_uart->tx_fifo_ctrl & MXC_F_UART_TX_FIFO_CTRL_FIFO_ENTRY) || + !(stdio_uart->intfl & MXC_F_UART_INTFL_TX_DONE)); __disable_irq(); + // Do not enter Deep Sleep if connected to VBUS + if (MXC_USB->dev_intfl & MXC_F_USB_DEV_INTFL_VBUS_ST) { + __enable_irq(); + sleep(); + return; + } + + // The USB module will not survive Deep Sleep. Shut it down. + usb_sleep(); + // Make sure RTC is not pending before sleeping, if its still synchronizing // we might not wake up. while (MXC_RTCTMR->ctrl & MXC_F_RTC_CTRL_PENDING); @@ -104,17 +166,20 @@ void deepsleep(void) MXC_PWRSEQ->msk_flags |= MXC_F_PWRSEQ_MSK_FLAGS_PWR_TVDD12_RST_BAD; MXC_PWRSEQ->reg0 &= ~(MXC_F_PWRSEQ_REG0_PWR_SVMTVDD12EN_RUN); MXC_PWRSEQ->reg0 |= MXC_F_PWRSEQ_REG0_PWR_SVMTVDD12EN_RUN; - MXC_PWRSEQ->msk_flags &= ~(MXC_F_PWRSEQ_MSK_FLAGS_PWR_TVDD12_RST_BAD); + MXC_PWRSEQ->msk_flags &= ~MXC_F_PWRSEQ_MSK_FLAGS_PWR_TVDD12_RST_BAD; } // Enable Retention controller MXC_PWRSEQ->retn_ctrl0 |= MXC_F_PWRSEQ_RETN_CTRL0_RETN_CTRL_EN; + // Clear the firstboot bit, which is generated by a POR event and locks out LPx modes + MXC_PWRSEQ->reg0 &= ~MXC_F_PWRSEQ_REG0_PWR_FIRST_BOOT; + // Freeze GPIO using MBUS so that it doesn't flail while digital core is asleep MXC_PWRSEQ->reg1 |= MXC_F_PWRSEQ_REG1_PWR_MBUS_GATE; // Dummy read to make sure SSB writes are complete - if (MXC_PWRSEQ->reg0 & MXC_F_PWRSEQ_REG0_PWR_SYS_REBOOT) {} + MXC_PWRSEQ->reg0; if (part_rev == REVISION_A4) { // Note: ARM deep-sleep requires a specific sequence to clear event latches, @@ -134,7 +199,9 @@ void deepsleep(void) // We'll wakeup here ... // Unfreeze the GPIO by clearing MBUS_GATE - MXC_PWRSEQ->reg1 &= ~(MXC_F_PWRSEQ_REG1_PWR_MBUS_GATE); + MXC_PWRSEQ->reg1 &= ~MXC_F_PWRSEQ_REG1_PWR_MBUS_GATE; + + usb_wakeup(); // Clear power sequencer event flags (write-1-to-clear) // RTC and GPIO flags are cleared in their interrupts handlers @@ -153,5 +220,4 @@ void deepsleep(void) MXC_F_PWRSEQ_FLAGS_PWR_TVDD12_BAD); __enable_irq(); -#endif } diff --git a/libraries/USBDevice/USBDevice/USBHAL_Maxim.cpp b/libraries/USBDevice/USBDevice/USBHAL_Maxim.cpp index d8fc0756d8..f23322f005 100644 --- a/libraries/USBDevice/USBDevice/USBHAL_Maxim.cpp +++ b/libraries/USBDevice/USBDevice/USBHAL_Maxim.cpp @@ -99,7 +99,7 @@ USBHAL::USBHAL(void) // reset the device MXC_USB->cn = 0; - MXC_USB->cn = 1; + MXC_USB->cn = MXC_F_USB_CN_USB_EN; MXC_USB->dev_inten = 0; MXC_USB->dev_cn = 0; MXC_USB->dev_cn = MXC_F_USB_DEV_CN_URST; @@ -129,6 +129,9 @@ USBHAL::USBHAL(void) // set the descriptor location MXC_USB->ep_base = (uint32_t)&ep_buffer_descriptor; + // enable VBUS interrupts + MXC_USB->dev_inten = MXC_F_USB_DEV_INTEN_NO_VBUS | MXC_F_USB_DEV_INTEN_VBUS; + // attach IRQ handler and enable interrupts instance = this; NVIC_SetVector(USB_IRQn, (uint32_t)&_usbisr);