[MAX32620HSP] Added Deep Sleep support with USB.

pull/2528/head
Jeremy Brodt 2016-08-24 16:17:53 -05:00
parent 59f04b4771
commit 67b556b648
2 changed files with 82 additions and 13 deletions

View File

@ -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
}

View File

@ -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);