summaryrefslogtreecommitdiff
path: root/nuttx/arch
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2015-03-24 14:07:20 -0600
committerGregory Nutt <gnutt@nuttx.org>2015-03-24 14:07:20 -0600
commitc4613bbae60372416f4cd8413d65a7d72a7b92b5 (patch)
tree22efa011bf829dc728cb77b1593b2f20285817d3 /nuttx/arch
parent3299a93723bfc0476b5969bb8de8e034c8411159 (diff)
downloadpx4-nuttx-c4613bbae60372416f4cd8413d65a7d72a7b92b5.tar.gz
px4-nuttx-c4613bbae60372416f4cd8413d65a7d72a7b92b5.tar.bz2
px4-nuttx-c4613bbae60372416f4cd8413d65a7d72a7b92b5.zip
SAMV7 USB: Updates to interrupt handling logic
Diffstat (limited to 'nuttx/arch')
-rw-r--r--nuttx/arch/arm/src/samv7/sam_usbdevhs.c264
1 files changed, 154 insertions, 110 deletions
diff --git a/nuttx/arch/arm/src/samv7/sam_usbdevhs.c b/nuttx/arch/arm/src/samv7/sam_usbdevhs.c
index e0d0d129e..1c28f1597 100644
--- a/nuttx/arch/arm/src/samv7/sam_usbdevhs.c
+++ b/nuttx/arch/arm/src/samv7/sam_usbdevhs.c
@@ -135,6 +135,10 @@
#define EPR_TXDTOG_MASK (USB_EPR_STATTX_MASK | EPR_NOTOG_MASK)
#define EPR_RXDTOG_MASK (USB_EPR_STATRX_MASK | EPR_NOTOG_MASK)
+/* Cache-related */
+
+#define MEMORY_SYNC() do { ARM_DSB();ARM_ISB(); } while (0)
+
/* Request queue operations *************************************************/
#define sam_rqempty(q) ((q)->head == NULL)
@@ -161,7 +165,7 @@
#define SAM_TRACEERR_DMAERR 0x0010
#define SAM_TRACEERR_DRIVER 0x0011
#define SAM_TRACEERR_DRIVERREGISTERED 0x0012
-#define SAM_TRACEERR_ENDBUFST 0x0013
+#define SAM_TRACERR_REMAINING 0x0013
#define SAM_TRACEERR_EP0SETUPOUTSIZE 0x0014
#define SAM_TRACEERR_EP0SETUPSTALLED 0x0015
#define SAM_TRACEERR_EPOUTNULLPACKET 0x0016
@@ -178,7 +182,7 @@
#define SAM_TRACEINTID_ADDRESSED 0x0001
#define SAM_TRACEINTID_CLEARFEATURE 0x0002
-#define SAM_TRACEINTID_DETSUSPD 0x0003
+#define SAM_TRACEINTID_INTSUSPD 0x0003
#define SAM_TRACEINTID_DEVGETSTATUS 0x0004
#define SAM_TRACEINTID_DISPATCH 0x0005
#define SAM_TRACEINTID_DMA 0x0006
@@ -199,17 +203,18 @@
#define SAM_TRACEINTID_IFGETSTATUS 0x0015
#define SAM_TRACEINTID_INTERRUPT 0x0016
#define SAM_TRACEINTID_INTSOF 0x0017
-#define SAM_TRACEINTID_NOSTDREQ 0x0018
-#define SAM_TRACEINTID_PENDING 0x0019
-#define SAM_TRACEINTID_RXRDY 0x001a
-#define SAM_TRACEINTID_RXSETUP 0x001b
-#define SAM_TRACEINTID_SETCONFIG 0x001c
-#define SAM_TRACEINTID_SETFEATURE 0x001d
-#define SAM_TRACEINTID_STALLSNT 0x001e
-#define SAM_TRACEINTID_SYNCHFRAME 0x001f
-#define SAM_TRACEINTID_TXRDY 0x0020
-#define SAM_TRACEINTID_UPSTRRES 0x0021
-#define SAM_TRACEINTID_WAKEUP 0x0022
+#define SAM_TRACEINTID_INTMSOF 0x0018
+#define SAM_TRACEINTID_NOSTDREQ 0x0019
+#define SAM_TRACEINTID_PENDING 0x001a
+#define SAM_TRACEINTID_RXRDY 0x001b
+#define SAM_TRACEINTID_RXSETUP 0x001c
+#define SAM_TRACEINTID_SETCONFIG 0x001d
+#define SAM_TRACEINTID_SETFEATURE 0x001e
+#define SAM_TRACEINTID_STALLSNT 0x001f
+#define SAM_TRACEINTID_SYNCHFRAME 0x0020
+#define SAM_TRACEINTID_TXINI 0x0021
+#define SAM_TRACEINTID_UPSTRRES 0x0022
+#define SAM_TRACEINTID_WAKEUP 0x0023
/* Ever-present MIN and MAX macros */
@@ -452,12 +457,15 @@ static void sam_ep0_wrstatus(const uint8_t *buffer, size_t buflen);
static void sam_ep0_dispatch(struct sam_usbdev_s *priv);
static void sam_setdevaddr(struct sam_usbdev_s *priv, uint8_t value);
static void sam_ep0_setup(struct sam_usbdev_s *priv);
-static void sam_dma_interrupt(struct sam_usbdev_s *priv, int chan);
+#ifdef CONFIG_USBDEV_DMA
+static void sam_dma_interrupt(struct sam_usbdev_s *priv, int epno);
+#endif
static void sam_ep_interrupt(struct sam_usbdev_s *priv, int epno);
static int sam_usbhs_interrupt(int irq, void *context);
/* Endpoint helpers *********************************************************/
+static void sam_ep_halt(struct usbdev_ep_s *ep, bool resume);
static void sam_ep_reset(struct sam_usbdev_s *priv, uint8_t epno);
static void sam_epset_reset(struct sam_usbdev_s *priv, uint16_t epset);
static inline struct sam_ep_s *
@@ -590,7 +598,7 @@ const struct trace_msg_t g_usb_trace_strings_deverror[] =
TRACE_STR(SAM_TRACEERR_DMAERR),
TRACE_STR(SAM_TRACEERR_DRIVER),
TRACE_STR(SAM_TRACEERR_DRIVERREGISTERED),
- TRACE_STR(SAM_TRACEERR_ENDBUFST),
+ TRACE_STR(SAM_TRACERR_REMAINING),
TRACE_STR(SAM_TRACEERR_EP0SETUPOUTSIZE),
TRACE_STR(SAM_TRACEERR_EP0SETUPSTALLED),
TRACE_STR(SAM_TRACEERR_EPOUTNULLPACKET),
@@ -615,7 +623,7 @@ const struct trace_msg_t g_usb_trace_strings_intdecode[] =
{
TRACE_STR(SAM_TRACEINTID_ADDRESSED),
TRACE_STR(SAM_TRACEINTID_CLEARFEATURE),
- TRACE_STR(SAM_TRACEINTID_DETSUSPD),
+ TRACE_STR(SAM_TRACEINTID_INTSUSPD),
TRACE_STR(SAM_TRACEINTID_DEVGETSTATUS),
TRACE_STR(SAM_TRACEINTID_DISPATCH),
TRACE_STR(SAM_TRACEINTID_DMA),
@@ -636,6 +644,7 @@ const struct trace_msg_t g_usb_trace_strings_intdecode[] =
TRACE_STR(SAM_TRACEINTID_IFGETSTATUS),
TRACE_STR(SAM_TRACEINTID_INTERRUPT),
TRACE_STR(SAM_TRACEINTID_INTSOF),
+ TRACE_STR(SAM_TRACEINTID_INTMSOF),
TRACE_STR(SAM_TRACEINTID_NOSTDREQ),
TRACE_STR(SAM_TRACEINTID_PENDING),
TRACE_STR(SAM_TRACEINTID_RXRDY),
@@ -644,7 +653,7 @@ const struct trace_msg_t g_usb_trace_strings_intdecode[] =
TRACE_STR(SAM_TRACEINTID_SETFEATURE),
TRACE_STR(SAM_TRACEINTID_STALLSNT),
TRACE_STR(SAM_TRACEINTID_SYNCHFRAME),
- TRACE_STR(SAM_TRACEINTID_TXRDY),
+ TRACE_STR(SAM_TRACEINTID_TXINI),
TRACE_STR(SAM_TRACEINTID_UPSTRRES),
TRACE_STR(SAM_TRACEINTID_WAKEUP),
TRACE_STR_END
@@ -2301,6 +2310,7 @@ static void sam_ep0_setup(struct sam_usbdev_s *priv)
*
****************************************************************************/
+#ifdef CONFIG_USBDEV_DMA
static void sam_dma_interrupt(struct sam_usbdev_s *priv, int epno)
{
struct sam_ep_s *privep;
@@ -2326,6 +2336,13 @@ static void sam_dma_interrupt(struct sam_usbdev_s *priv, int epno)
privreq = sam_rqpeek(&privep->reqq);
DEBUGASSERT(privreq);
+ /* Disable DMA interrupt to avoid receiving 2 (B_EN and TR_EN) */
+
+ regaddr = SAM_USBHS_DEVDMACTRL(epno);
+ regval = sam_getreg(regaddr);
+ regval &= ~(USBHS_DEVDMACTRL_ENDTREN | USBHS_DEVDMACTRL_ENDBEN);
+ sam_putreg(regval, regaddr);
+
/* Get the result of the DMA operation */
dmastatus = sam_getreg(SAM_USBHS_DEVDMASTA(epno));
@@ -2353,7 +2370,7 @@ static void sam_dma_interrupt(struct sam_usbdev_s *priv, int epno)
*/
/* This is just debug logic that only does any if USB debug or tracing
- * are enabled. This just verifies taht BUFF_COUNT is zero.
+ * are enabled. This just verifies that BUFF_COUNT is zero.
*/
bufcnt = (dmastatus & USBHS_DEVDMASTA_BUFCNT_MASK)
@@ -2361,7 +2378,7 @@ static void sam_dma_interrupt(struct sam_usbdev_s *priv, int epno)
if (bufcnt != 0)
{
- usbtrace(TRACE_DEVERROR(SAM_TRACEERR_ENDBUFST), bufcnt);
+ usbtrace(TRACE_DEVERROR(SAM_TRACERR_REMAINING), bufcnt);
}
/* Were we sending? Or receiving? */
@@ -2387,6 +2404,9 @@ static void sam_dma_interrupt(struct sam_usbdev_s *priv, int epno)
/* This is an OUT endpoint. Invalidate the data cache for
* region that just completed DMA. This will force the
* buffer data to be reloaded from RAM when it is accessed.
+ *
+ * REVISIT: If the buffer is not aligned to the cacheline
+ * size the cached data might be lost at the boundaries.
*/
DEBUGASSERT(USB_ISEPOUT(privep->ep.eplog));
@@ -2411,7 +2431,7 @@ static void sam_dma_interrupt(struct sam_usbdev_s *priv, int epno)
/* Check for end of channel transfer. END_TR_ST is set by hardware when
* the last packet transfer is complete iff END_TR_EN is set in the
- * DMACONTROL rgister. The request is complete.
+ * DMACONTROL register. The request is complete.
*
* "Used for OUT transfers only.
*
@@ -2444,6 +2464,9 @@ static void sam_dma_interrupt(struct sam_usbdev_s *priv, int epno)
/* Invalidate the data cache for region that just completed DMA.
* This will force the buffer data to be reloaded from RAM.
+ *
+ * REVISIT: If the buffer is not aligned to the cacheline size the
+ * cached data might be lost at the boundaries.
*/
buf = &privreq->req.buf[privreq->req.xfrd];
@@ -2467,6 +2490,7 @@ static void sam_dma_interrupt(struct sam_usbdev_s *priv, int epno)
sam_req_complete(privep, -EIO);
}
}
+#endif
/****************************************************************************
* Name: sam_ep_interrupt
@@ -2479,7 +2503,7 @@ static void sam_dma_interrupt(struct sam_usbdev_s *priv, int epno)
static void sam_ep_interrupt(struct sam_usbdev_s *priv, int epno)
{
struct sam_ep_s *privep;
- uint32_t eptsta;
+ uint32_t eptisr;
uint32_t eptype;
uint32_t regval;
uint16_t pktsize;
@@ -2492,7 +2516,7 @@ static void sam_ep_interrupt(struct sam_usbdev_s *priv, int epno)
/* Get the endpoint status */
- eptsta = sam_getreg(SAM_USBHS_DEVEPTISR(epno));
+ eptisr = sam_getreg(SAM_USBHS_DEVEPTISR(epno));
/* Get the endpoint type */
@@ -2501,9 +2525,10 @@ static void sam_ep_interrupt(struct sam_usbdev_s *priv, int epno)
/* IN packet sent */
- if ((eptsta & USBHS_DEVEPTINT_TXINI) == 0)
+ if ((eptisr & USBHS_DEVEPTINT_TXINI) == 0 &&
+ (sam_getreg(SAM_USBHS_DEVEPTIMR(epno)) & USBHS_DEVEPTINT_TXINI) != 0)
{
- usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_TXRDY), (uint16_t)eptsta);
+ usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_TXINI), (uint16_t)eptisr);
/* Sending state. This is the completion of a "normal" write request
* transfer. In this case, we need to resume request processing in
@@ -2519,6 +2544,7 @@ static void sam_ep_interrupt(struct sam_usbdev_s *priv, int epno)
privep->epstate = USBHS_EPSTATE_IDLE;
(void)sam_req_write(priv, privep);
+ sam_putreg(USBHS_DEVEPTINT_TXINI, SAM_USBHS_DEVEPTICR(epno));
}
/* Setting of the device address is a special case. The address was
@@ -2538,22 +2564,24 @@ static void sam_ep_interrupt(struct sam_usbdev_s *priv, int epno)
privep->epstate = USBHS_EPSTATE_IDLE;
sam_setdevaddr(priv, priv->devaddr);
- /* Disable the further TXIN interrupts on EP0. */
+ /* Acknowledge then disable the further TXIN interrupts on EP0. */
+ sam_putreg(USBHS_DEVEPTINT_TXINI, SAM_USBHS_DEVEPTICR(epno));
sam_putreg(USBHS_DEVEPTINT_TXINI, SAM_USBHS_DEVEPTIDR(epno));
}
else
{
usbtrace(TRACE_DEVERROR(SAM_TRACEERR_TXINERR), privep->epstate);
+ sam_putreg(USBHS_DEVEPTINT_TXINI, SAM_USBHS_DEVEPTICR(epno));
sam_putreg(USBHS_DEVEPTINT_TXINI, SAM_USBHS_DEVEPTIDR(epno));
}
}
/* OUT packet received */
- if ((eptsta & USBHS_DEVEPTINT_RXOUTI) != 0)
+ if ((eptisr & USBHS_DEVEPTINT_RXOUTI) != 0)
{
- usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_RXRDY), (uint16_t)eptsta);
+ usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_RXRDY), (uint16_t)eptisr);
/* Are we receiving data for a read request? */
@@ -2562,7 +2590,7 @@ static void sam_ep_interrupt(struct sam_usbdev_s *priv, int epno)
/* Yes, get the size of the packet that we just received */
pktsize = (uint16_t)
- ((eptsta & USBHS_DEVEPTISR_BYCT_MASK) >> USBHS_DEVEPTISR_BYCT_SHIFT);
+ ((eptisr & USBHS_DEVEPTISR_BYCT_MASK) >> USBHS_DEVEPTISR_BYCT_SHIFT);
/* And continue processing the read request, clearing RXOUT in
* order to receive more data.
@@ -2586,7 +2614,7 @@ static void sam_ep_interrupt(struct sam_usbdev_s *priv, int epno)
/* Get the size of the packet that we just received */
pktsize = (uint16_t)
- ((eptsta & USBHS_DEVEPTISR_BYCT_MASK) >> USBHS_DEVEPTISR_BYCT_SHIFT);
+ ((eptisr & USBHS_DEVEPTISR_BYCT_MASK) >> USBHS_DEVEPTISR_BYCT_SHIFT);
/* Get the size that we expected to receive */
@@ -2619,13 +2647,13 @@ static void sam_ep_interrupt(struct sam_usbdev_s *priv, int epno)
/* Check if ACK received on a Control EP */
if (eptype == USBHS_DEVEPTCFG_EPTYPE_CTRL &&
- (eptsta & USBHS_DEVEPTISR_BYCT_MASK) == 0)
+ (eptisr & USBHS_DEVEPTISR_BYCT_MASK) == 0)
{
}
/* Data has been STALLed */
- else if ((eptsta & USBHS_DEVEPTINT_STALLEDI) != 0)
+ else if ((eptisr & USBHS_DEVEPTINT_STALLEDI) != 0)
{
}
@@ -2636,9 +2664,7 @@ static void sam_ep_interrupt(struct sam_usbdev_s *priv, int epno)
sam_putreg(USBHS_DEVINT_PEP(epno), SAM_USBHS_DEVIDR);
}
- /* Discard any received data and clear USBHS_DEVEPTINT_RXOUTI so that we
- * may receive more data.
- */
+ /* Acknowledge the interrupt. */
sam_putreg(USBHS_DEVEPTINT_RXOUTI, SAM_USBHS_DEVEPTICR(epno));
}
@@ -2646,9 +2672,9 @@ static void sam_ep_interrupt(struct sam_usbdev_s *priv, int epno)
/* STALL sent */
- if ((eptsta & USBHS_DEVEPTINT_STALLEDI) != 0)
+ if ((eptisr & USBHS_DEVEPTINT_STALLEDI) != 0)
{
- usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_STALLSNT), (uint16_t)eptsta);
+ usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_STALLSNT), (uint16_t)eptisr);
/* Acknowledge */
@@ -2666,15 +2692,15 @@ static void sam_ep_interrupt(struct sam_usbdev_s *priv, int epno)
else if (privep->epstate != USBHS_EPSTATE_STALLED)
{
- sam_putreg(USBHS_DEVEPTINT_STALLEDI, SAM_USBHS_DEVEPTICR(epno));
+ sam_putreg(USBHS_DEVEPTINT_STALLEDI, SAM_USBHS_DEVEPTIDR(epno));
}
}
/* SETUP packet received */
- if ((eptsta & USBHS_DEVEPTINT_RXSTPI) != 0)
+ if ((eptisr & USBHS_DEVEPTINT_RXSTPI) != 0)
{
- usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_RXSETUP), (uint16_t)eptsta);
+ usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_RXSETUP), (uint16_t)eptisr);
/* If a request transfer was pending, complete it. Handle the case
* where during the status phase of a control write transfer, the host
@@ -2750,18 +2776,18 @@ static int sam_usbhs_interrupt(int irq, void *context)
*/
struct sam_usbdev_s *priv = &g_usbhs;
- uint32_t intsta;
+ uint32_t devisr;
uint32_t pending;
uint32_t regval;
int i;
/* Get the set of pending interrupts */
- intsta = sam_getreg(SAM_USBHS_DEVISR);
- usbtrace(TRACE_INTENTRY(SAM_TRACEINTID_INTERRUPT), intsta);
+ devisr = sam_getreg(SAM_USBHS_DEVISR);
+ usbtrace(TRACE_INTENTRY(SAM_TRACEINTID_INTERRUPT), devisr);
regval = sam_getreg(SAM_USBHS_DEVIMR);
- pending = intsta & regval;
+ pending = devisr & regval;
/* Handle all pending USBHS interrupts (and new interrupts that become
* pending)
@@ -2773,29 +2799,53 @@ static int sam_usbhs_interrupt(int irq, void *context)
/* Suspend, treated last */
- if ((pending == USBHS_DEVINT_SUSPD) != 0)
+ if (pending == USBHS_DEVINT_SUSPD)
{
- usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_DETSUSPD), (uint16_t)pending);
+ usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_INTSUSPD), (uint16_t)pending);
- /* Enable wakeup interrupts */
+ /* Un-freeze the clock */
+
+ regval = sam_getreg(SAM_USBHS_CTRL);
+ regval &= ~USBHS_CTRL_FRZCLK;
+ sam_putreg(regval, SAM_USBHS_CTRL);
+
+ /* Disable suspend interrupts */
sam_putreg(USBHS_DEVINT_SUSPD, SAM_USBHS_DEVIDR);
+
+ /* Enable wakeup interrupts */
+
sam_putreg(USBHS_DEVINT_WAKEUP | USBHS_DEVINT_EORSM, SAM_USBHS_DEVIER);
+ /* Re-freeze the clock */
+
+ regval |= USBHS_CTRL_FRZCLK;
+ sam_putreg(regval, SAM_USBHS_CTRL);
+
/* Acknowledge interrupt */
- sam_putreg(USBHS_DEVINT_SUSPD | USBHS_DEVINT_WAKEUP, SAM_USBHS_DEVICR);
+ sam_putreg(USBHS_DEVINT_SUSPD | USBHS_DEVINT_WAKEUP, SAM_USBHS_DEVIFR);
sam_suspend(priv);
}
- /* SOF interrupt*/
+ /* SOF interrupt */
else if ((pending & USBHS_DEVINT_SOF) != 0)
{
/* Acknowledge interrupt */
usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_INTSOF), (uint16_t)pending);
- sam_putreg(USBHS_DEVINT_SOF, SAM_USBHS_DEVICR);
+ sam_putreg(USBHS_DEVINT_SOF, SAM_USBHS_DEVIFR);
+ }
+
+ /* MSOF interrupt */
+
+ else if ((pending & USBHS_DEVINT_MSOF) != 0)
+ {
+ /* Acknowledge interrupt */
+
+ usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_INTMSOF), (uint16_t)pending);
+ sam_putreg(USBHS_DEVINT_MSOF, SAM_USBHS_DEVIFR);
}
/* Resume */
@@ -2806,80 +2856,48 @@ static int sam_usbhs_interrupt(int irq, void *context)
usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_WAKEUP), (uint16_t)pending);
sam_resume(priv);
+ /* Un-freeze the clock */
+
+ regval = sam_getreg(SAM_USBHS_CTRL);
+ regval &= ~USBHS_CTRL_FRZCLK;
+ sam_putreg(regval, SAM_USBHS_CTRL);
+
/* Acknowledge interrupt */
sam_putreg(USBHS_DEVINT_WAKEUP | USBHS_DEVINT_EORSM | USBHS_DEVINT_SUSPD,
- SAM_USBHS_DEVICR);
+ SAM_USBHS_DEVIFR);
- /* Enable suspend interrupts */
+ /* Disable wakeup interrupts */
sam_putreg(USBHS_DEVINT_WAKEUP, SAM_USBHS_DEVIDR);
+
+ /* Enable suspend interrupts and clear */
+
sam_putreg(USBHS_DEVINT_EORSM | USBHS_DEVINT_SUSPD, SAM_USBHS_DEVIER);
}
/* End of Reset. Set by hardware when an End Of Reset has been
* detected by the USBHS controller. Automatically enabled after USB
* reset.
- *
- * Paragraph 32.6.11, Speed Identification
- *
- * "The high speed reset is managed by the hardware.
- *
- * "At the connection, the host makes a reset which could be a
- * classic reset (full speed) or a high speed reset.
- *
- * "At the end of the reset process (full or high), the ENDRESET
- * interrupt is generated.
- *
- * "Then the CPU should read the SPEED bit in USBHS_INTSTAx to
- * ascertain the speed mode of the device."
- *
- * Paragraph 32.6.14.4 From Powered State to Default State (reset)
- * "After its connection to a USB host, the USB device waits for an
- * end-of-bus reset. The unmasked flag ENDRESET is set in the
- * USBHS_IEN register and an interrupt is triggered.
- *
- * "Once the ENDRESET interrupt has been triggered, the device
- * enters Default State. In this state, the USBHS software must:
- *
- * - Enable the default endpoint, setting the EPT_ENABL flag in
- * the SAM_USBHS_DEVEPTIER[0] register and, optionally, enabling
- * the interrupt for endpoint 0 by writing 1 in EPT_0 of the
- * USBHS_IEN register. The enumeration then begins by a control
- * transfer.
- * - Configure the Interrupt Mask Register which has been reset
- * by the USB reset detection
- * - Enable the transceiver.
- *
- * "In this state, the EN_USBHS bit in USBHS_CTRL register must be
- * enabled."
*/
if ((pending & USBHS_DEVINT_EORST) != 0)
{
usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_ENDRESET), (uint16_t)pending);
- /* Handle the reset */
-
- sam_reset(priv);
+ /* Acknowledge the interrupt, clear pednding wakeup and suspend
+ * status as we..
+ */
- /* Get the device speed */
+ sam_putreg(USBHS_DEVINT_WAKEUP | USBHS_DEVINT_SUSPD | USBHS_DEVINT_EORST,
+ SAM_USBHS_DEVIFR);
- switch (sam_getreg(SAM_USBHS_SR) & USBHS_SR_SPEED_MASK)
- {
- default:
- case USBHS_SR_SPEED_FULL: /* Full-Speed mode */
- priv->usbdev.speed = USB_SPEED_FULL;
- break;
+ /* Enable suspend interrupts */
- case USBHS_SR_SPEED_HIGH: /* High-Speed mode */
- priv->usbdev.speed = USB_SPEED_HIGH;
- break;
+ sam_putreg(USBHS_DEVINT_SUSPD, SAM_USBHS_DEVIER);
+ /* Handle the reset */
- case USBHS_SR_SPEED_LOW: /* Low-Speed mode */
- priv->usbdev.speed = USB_SPEED_LOW;
- break;
- }
+ sam_reset(priv);
}
/* Upstream resume */
@@ -2889,9 +2907,10 @@ static int sam_usbhs_interrupt(int irq, void *context)
/* Acknowledge interrupt */
usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_UPSTRRES), (uint16_t)pending);
- sam_putreg(USBHS_DEVINT_UPRSM, SAM_USBHS_DEVICR);
+ sam_putreg(USBHS_DEVINT_UPRSM, SAM_USBHS_DEVIFR);
}
+#ifdef CONFIG_USBDEV_DMA
/* DMA interrupts */
else if ((pending & USBHS_DEVINT_DMA_MASK) != 0)
@@ -2905,6 +2924,7 @@ static int sam_usbhs_interrupt(int irq, void *context)
}
}
}
+#endif
/* Endpoint Interrupts */
@@ -2922,12 +2942,13 @@ static int sam_usbhs_interrupt(int irq, void *context)
/* Re-sample the set of pending interrupts */
- intsta = sam_getreg(SAM_USBHS_DEVISR);
+ devisr = sam_getreg(SAM_USBHS_DEVISR);
regval = sam_getreg(SAM_USBHS_DEVIMR);
- pending = intsta & regval;
+ pending = devisr & regval;
}
- usbtrace(TRACE_INTEXIT(SAM_TRACEINTID_INTERRUPT), intsta);
+ usbtrace(TRACE_INTEXIT(SAM_TRACEINTID_INTERRUPT), devisr);
+ MEMORY_SYNC();
return OK;
}
@@ -3712,6 +3733,7 @@ static int sam_ep_stall(struct usbdev_ep_s *ep, bool resume)
struct sam_ep_s *privep;
struct sam_usbdev_s *priv;
uint8_t epno = USB_EPNO(ep->eplog);
+ uintptr_t regaddr;
uint32_t regval;
irqstate_t flags;
@@ -3756,7 +3778,14 @@ static int sam_ep_stall(struct usbdev_ep_s *ep, bool resume)
* endpoints.
*/
- sam_putreg(USBHS_DEVEPTINT_STALLEDI, SAM_USBHS_DEVEPTICR(epno));
+ /* Clear FORCESTALL flag */
+
+ sam_putreg(USBHS_DEVEPTINT_STALLEDI, SAM_USBHS_DEVEPTIDR(epno));
+
+ regaddr = SAM_USBHS_DEVEPCFG(epno);
+ regval = sam_getreg(regaddr);
+ regval |= USBHS_DEVEPTCFG_AUTOSW;
+ sam_putreg(regval, regaddr);
/* Reset the endpoint */
@@ -3818,9 +3847,14 @@ static int sam_ep_stall(struct usbdev_ep_s *ep, bool resume)
privep->epstate = USBHS_EPSTATE_STALLED;
privep->stalled = true;
- sam_putreg(USBHS_DEVEPTINT_STALLRQI, SAM_USBHS_DEVEPTIFR(epno));
+ regaddr = AM_USBHS_DEVEPCTG(epno);
+ regval = sam_getreg(regaddr);
+ regval &= ~USBHS_DEVEPTCFG_AUTOSW;
+ sam_putreg(regval, regaddr);
+
+ sam_putreg(USBHS_DEVEPTINT_STALLRQI, SAM_USBHS_DEVEPTIER(epno));
- /* Disable endpoint/DMA interrupts. The not be re-enabled until
+ /* Disable endpoint/DMA interrupts. They not be re-enabled until
* the stall is cleared and the next transfer is started. It
* would, of course, be a bad idea to do this on EP0 since it is
* a SETUP request that is going to clear the STALL.
@@ -3828,8 +3862,18 @@ static int sam_ep_stall(struct usbdev_ep_s *ep, bool resume)
if (epno != 0)
{
- sam_putreg(USBHS_DEVINT_DMA(epno) | USBHS_DEVINT_PEP(epno),
- SAM_USBHS_DEVIDR);
+ regval = sam_getreg(SAM_USBHS_DEVIDR);
+ regval |= USBHS_DEVINT_PEP(epno);
+
+#ifdef CONFIG_USBDEV_DMA
+ if (SAM_USBHS_DMA(epno))
+ {
+ /* Disable the endpoint DMA interrupt */
+
+ regval |= USBHS_DEVINT_DMA(epno);
+ }
+#endif
+ sam_putreg(regval, SAM_USBHS_DEVIDR);
}
}
}