mirror of https://github.com/ARMmbed/mbed-os.git
[MAX32620HSP] Added Deep Sleep support with USB.
parent
59f04b4771
commit
67b556b648
|
@ -38,12 +38,23 @@
|
||||||
#include "clkman_regs.h"
|
#include "clkman_regs.h"
|
||||||
#include "ioman_regs.h"
|
#include "ioman_regs.h"
|
||||||
#include "rtc_regs.h"
|
#include "rtc_regs.h"
|
||||||
|
#include "usb_regs.h"
|
||||||
#include "wait_api.h"
|
#include "wait_api.h"
|
||||||
|
|
||||||
#define REVISION_A3 2
|
#define REVISION_A3 2
|
||||||
#define REVISION_A4 3
|
#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 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)
|
void sleep(void)
|
||||||
{
|
{
|
||||||
|
@ -54,28 +65,79 @@ void sleep(void)
|
||||||
__WFI();
|
__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
|
// Low-power stop mode
|
||||||
void deepsleep(void)
|
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;
|
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) {
|
if (part_rev <= REVISION_A3) {
|
||||||
sleep();
|
sleep();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for all STDIO characters to be sent. The UART clock will stop.
|
// 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)
|
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));
|
||||||
(!(stdio_uart->intfl & MXC_F_UART_INTFL_TX_DONE)) );
|
|
||||||
|
|
||||||
__disable_irq();
|
__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
|
// Make sure RTC is not pending before sleeping, if its still synchronizing
|
||||||
// we might not wake up.
|
// we might not wake up.
|
||||||
while (MXC_RTCTMR->ctrl & MXC_F_RTC_CTRL_PENDING);
|
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->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->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
|
// Enable Retention controller
|
||||||
MXC_PWRSEQ->retn_ctrl0 |= MXC_F_PWRSEQ_RETN_CTRL0_RETN_CTRL_EN;
|
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
|
// 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;
|
MXC_PWRSEQ->reg1 |= MXC_F_PWRSEQ_REG1_PWR_MBUS_GATE;
|
||||||
|
|
||||||
// Dummy read to make sure SSB writes are complete
|
// 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) {
|
if (part_rev == REVISION_A4) {
|
||||||
// Note: ARM deep-sleep requires a specific sequence to clear event latches,
|
// Note: ARM deep-sleep requires a specific sequence to clear event latches,
|
||||||
|
@ -134,7 +199,9 @@ void deepsleep(void)
|
||||||
// We'll wakeup here ...
|
// We'll wakeup here ...
|
||||||
|
|
||||||
// Unfreeze the GPIO by clearing MBUS_GATE
|
// 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)
|
// Clear power sequencer event flags (write-1-to-clear)
|
||||||
// RTC and GPIO flags are cleared in their interrupts handlers
|
// RTC and GPIO flags are cleared in their interrupts handlers
|
||||||
|
@ -153,5 +220,4 @@ void deepsleep(void)
|
||||||
MXC_F_PWRSEQ_FLAGS_PWR_TVDD12_BAD);
|
MXC_F_PWRSEQ_FLAGS_PWR_TVDD12_BAD);
|
||||||
|
|
||||||
__enable_irq();
|
__enable_irq();
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,7 @@ USBHAL::USBHAL(void)
|
||||||
|
|
||||||
// reset the device
|
// reset the device
|
||||||
MXC_USB->cn = 0;
|
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_inten = 0;
|
||||||
MXC_USB->dev_cn = 0;
|
MXC_USB->dev_cn = 0;
|
||||||
MXC_USB->dev_cn = MXC_F_USB_DEV_CN_URST;
|
MXC_USB->dev_cn = MXC_F_USB_DEV_CN_URST;
|
||||||
|
@ -129,6 +129,9 @@ USBHAL::USBHAL(void)
|
||||||
// set the descriptor location
|
// set the descriptor location
|
||||||
MXC_USB->ep_base = (uint32_t)&ep_buffer_descriptor;
|
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
|
// attach IRQ handler and enable interrupts
|
||||||
instance = this;
|
instance = this;
|
||||||
NVIC_SetVector(USB_IRQn, (uint32_t)&_usbisr);
|
NVIC_SetVector(USB_IRQn, (uint32_t)&_usbisr);
|
||||||
|
|
Loading…
Reference in New Issue