summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2013-08-29 17:34:05 -0600
committerGregory Nutt <gnutt@nuttx.org>2013-08-29 17:34:05 -0600
commita3dbc581d78f662eb48509a888492a6f046510aa (patch)
treeda30914666866dc68cdcadb7ad594cd56fe45708
parent44642e236374b7969cbd208894ce51ad2baeaffe (diff)
downloadnuttx-a3dbc581d78f662eb48509a888492a6f046510aa.tar.gz
nuttx-a3dbc581d78f662eb48509a888492a6f046510aa.tar.bz2
nuttx-a3dbc581d78f662eb48509a888492a6f046510aa.zip
SAMA5 UDPHS interrupt decoding logic
-rw-r--r--nuttx/arch/arm/src/sama5/chip/sam_udphs.h54
-rw-r--r--nuttx/arch/arm/src/sama5/sam_udphs.c244
2 files changed, 161 insertions, 137 deletions
diff --git a/nuttx/arch/arm/src/sama5/chip/sam_udphs.h b/nuttx/arch/arm/src/sama5/chip/sam_udphs.h
index 9e90cc963..c205945ef 100644
--- a/nuttx/arch/arm/src/sama5/chip/sam_udphs.h
+++ b/nuttx/arch/arm/src/sama5/chip/sam_udphs.h
@@ -220,31 +220,35 @@
/* UDPHS Interrupt Enable Register and UDPHS Interrupt Status Register */
-#define UDPHS_IEN_EPT(ep) (1 << +((ep)+8)) /* Endpoint ep Interrupt */
-# define UDPHS_IEN_EPT0 (1 << 8) /* Bit 8: Endpoint 0 Interrupt */
-# define UDPHS_IEN_EPT1 (1 << 9) /* Bit 9: Endpoint 1 Interrupt */
-# define UDPHS_IEN_EPT2 (1 << 10) /* Bit 0: Endpoint 2 Interrupt */
-# define UDPHS_IEN_EPT3 (1 << 11) /* Bit 1: Endpoint 3 Interrupt */
-# define UDPHS_IEN_EPT4 (1 << 12) /* Bit 2: Endpoint 4 Interrupt */
-# define UDPHS_IEN_EPT5 (1 << 13) /* Bit 3: Endpoint 5 Interrupt */
-# define UDPHS_IEN_EPT6 (1 << 14) /* Bit 4: Endpoint 6 Interrupt */
-# define UDPHS_IEN_EPT7 (1 << 15) /* Bit 5: Endpoint 7 Interrupt */
-# define UDPHS_IEN_EPT8 (1 << 16) /* Bit 6: Endpoint 8 Interrupt */
-# define UDPHS_IEN_EPT9 (1 << 17) /* Bit 7: Endpoint 9 Interrupt */
-# define UDPHS_IEN_EPT10 (1 << 18) /* Bit 8: Endpoint 10 Interrupt */
-# define UDPHS_IEN_EPT11 (1 << 19) /* Bit 9: Endpoint 11 Interrupt */
-# define UDPHS_IEN_EPT12 (1 << 20) /* Bit 0: Endpoint 12 Interrupt */
-# define UDPHS_IEN_EPT13 (1 << 21) /* Bit 1: Endpoint 13 Interrupt */
-# define UDPHS_IEN_EPT14 (1 << 22) /* Bit 2: Endpoint 14 Interrupt */
-# define UDPHS_IEN_EPT15 (1 << 23) /* Bit 3: Endpoint 15 Interrupt */
-#define UDPHS_IEN_DMA(ch) (1 << ((ch)+24) /* DMA Channel ch Interrupt */
-# define UDPHS_IEN_DMA1 (1 << 25) /* Bit 5: DMA Channel 1 Interrupt */
-# define UDPHS_IEN_DMA2 (1 << 26) /* Bit 6: DMA Channel 2 Interrupt */
-# define UDPHS_IEN_DMA3 (1 << 27) /* Bit 7: DMA Channel 3 Interrupt */
-# define UDPHS_IEN_DMA4 (1 << 28) /* Bit 8: DMA Channel 4 Interrupt */
-# define UDPHS_IEN_DMA5 (1 << 29) /* Bit 9: DMA Channel 5 Interrupt */
-# define UDPHS_IEN_DMA6 (1 << 30) /* Bit 0: DMA Channel 6 Interrupt */
-# define UDPHS_IEN_DMA7 (1 << 31) /* Bit 1: DMA Channel 7 Interrupt */
+#define UDPHS_INT_EPT_SHIFT (8) /* Bits 8-23: Endpoint interrupts */
+#define UDPHS_INT_EPT_MASK (0xffff << UDPHS_INT_EPT_SHIFT)
+#define UDPHS_INT_EPT(ep) (1 << +((ep)+8)) /* Endpoint ep Interrupt */
+# define UDPHS_INT_EPT0 (1 << 8) /* Bit 8: Endpoint 0 Interrupt */
+# define UDPHS_INT_EPT1 (1 << 9) /* Bit 9: Endpoint 1 Interrupt */
+# define UDPHS_INT_EPT2 (1 << 10) /* Bit 10: Endpoint 2 Interrupt */
+# define UDPHS_INT_EPT3 (1 << 11) /* Bit 11: Endpoint 3 Interrupt */
+# define UDPHS_INT_EPT4 (1 << 12) /* Bit 12: Endpoint 4 Interrupt */
+# define UDPHS_INT_EPT5 (1 << 13) /* Bit 13: Endpoint 5 Interrupt */
+# define UDPHS_INT_EPT6 (1 << 14) /* Bit 14: Endpoint 6 Interrupt */
+# define UDPHS_INT_EPT7 (1 << 15) /* Bit 15: Endpoint 7 Interrupt */
+# define UDPHS_INT_EPT8 (1 << 16) /* Bit 16: Endpoint 8 Interrupt */
+# define UDPHS_INT_EPT9 (1 << 17) /* Bit 17: Endpoint 9 Interrupt */
+# define UDPHS_INT_EPT10 (1 << 18) /* Bit 18: Endpoint 10 Interrupt */
+# define UDPHS_INT_EPT11 (1 << 19) /* Bit 19: Endpoint 11 Interrupt */
+# define UDPHS_INT_EPT12 (1 << 20) /* Bit 20: Endpoint 12 Interrupt */
+# define UDPHS_INT_EPT13 (1 << 21) /* Bit 21: Endpoint 13 Interrupt */
+# define UDPHS_INT_EPT14 (1 << 22) /* Bit 22: Endpoint 14 Interrupt */
+# define UDPHS_INT_EPT15 (1 << 23) /* Bit 23: Endpoint 15 Interrupt */
+#define UDPHS_INT_DMA_SHIFT (25) /* Bits 25-31: Endpoint interrupts */
+#define UDPHS_INT_DMA_MASK (0x7f << UDPHS_INT_DMA_SHIFT)
+#define UDPHS_INT_DMA(ch) (1 << ((ch)+24) /* DMA Channel ch Interrupt */
+# define UDPHS_INT_DMA1 (1 << 25) /* Bit 25: DMA Channel 1 Interrupt */
+# define UDPHS_INT_DMA2 (1 << 26) /* Bit 26: DMA Channel 2 Interrupt */
+# define UDPHS_INT_DMA3 (1 << 27) /* Bit 27: DMA Channel 3 Interrupt */
+# define UDPHS_INT_DMA4 (1 << 28) /* Bit 28: DMA Channel 4 Interrupt */
+# define UDPHS_INT_DMA5 (1 << 29) /* Bit 29: DMA Channel 5 Interrupt */
+# define UDPHS_INT_DMA6 (1 << 30) /* Bit 30: DMA Channel 6 Interrupt */
+# define UDPHS_INT_DMA7 (1 << 31) /* Bit 31: DMA Channel 7 Interrupt */
/* UDPHS Endpoints Reset Register */
diff --git a/nuttx/arch/arm/src/sama5/sam_udphs.c b/nuttx/arch/arm/src/sama5/sam_udphs.c
index 0cc05a75f..4fde302dd 100644
--- a/nuttx/arch/arm/src/sama5/sam_udphs.c
+++ b/nuttx/arch/arm/src/sama5/sam_udphs.c
@@ -441,9 +441,9 @@ static void sam_ep0setup(struct sam_usbdev_s *priv);
static void sam_ep0out(struct sam_usbdev_s *priv);
static void sam_ep0in(struct sam_usbdev_s *priv);
static inline void
- sam_ep0done(struct sam_usbdev_s *priv, uint16_t istr);
+ sam_ep0done(struct sam_usbdev_s *priv, uint16_t intsta);
static void sam_lptransfer(struct sam_usbdev_s *priv);
-static int sam_uhphs_interrupt(int irq, void *context);
+static int sam_udphs_interrupt(int irq, void *context);
/* Endpoint helpers *********************************************************/
@@ -688,7 +688,7 @@ static void sam_dumpep(struct sam_usbdev_s *priv, int epno)
/* Common registers */
lldbg("CNTR: %04x\n", getreg16(SAM_USB_CNTR));
- lldbg("ISTR: %04x\n", getreg16(SAM_USB_ISTR));
+ lldbg("ISTR: %04x\n", getreg16(SAM_UDPHS_INTSTA));
lldbg("FNR: %04x\n", getreg16(SAM_USB_FNR));
lldbg("DADDR: %04x\n", getreg16(SAM_USB_DADDR));
lldbg("BTABLE: %04x\n", getreg16(SAM_USB_BTABLE));
@@ -1741,7 +1741,7 @@ static void sam_ep0out(struct sam_usbdev_s *priv)
* Name: sam_ep0done
****************************************************************************/
-static inline void sam_ep0done(struct sam_usbdev_s *priv, uint32_t istr)
+static inline void sam_ep0done(struct sam_usbdev_s *priv, uint32_t intsta)
{
uint32_t epr;
@@ -1762,11 +1762,11 @@ static inline void sam_ep0done(struct sam_usbdev_s *priv, uint32_t istr)
* packet sent to or received from the host PC.
*/
- if ((istr & USB_ISTR_DIR) == 0)
+ if ((intsta & USB_ISTR_DIR) == 0)
{
/* EP0 IN: device-to-host (DIR=0) */
- usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_EP0IN), istr);
+ usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_EP0IN), intsta);
sam_clrepctrtx(EP0);
sam_ep0in(priv);
}
@@ -1867,23 +1867,23 @@ static inline void sam_ep0done(struct sam_usbdev_s *priv, uint32_t istr)
static void sam_lptransfer(struct sam_usbdev_s *priv)
{
uint8_t epno;
- uint32_t istr;
+ uint32_t intsta;
/* Stay in loop while LP interrupts are pending */
- while (((istr = sam_getreg(SAM_USB_ISTR)) & USB_ISTR_CTR) != 0)
+ while (((intsta = sam_getreg(SAM_UDPHS_INTSTA)) & USB_ISTR_CTR) != 0)
{
- sam_putreg((uint32_t)~USB_ISTR_CTR, SAM_USB_ISTR);
+ sam_putreg((uint32_t)~USB_ISTR_CTR, SAM_UDPHS_INTSTA);
/* Extract highest priority endpoint number */
- epno = (uint8_t)(istr & USB_ISTR_EPID_MASK);
+ epno = (uint8_t)(intsta & USB_ISTR_EPID_MASK);
/* Handle EP0 completion events */
if (epno == 0)
{
- sam_ep0done(priv, istr);
+ sam_ep0done(priv, intsta);
}
/* Handle other endpoint completion events */
@@ -1896,118 +1896,154 @@ static void sam_lptransfer(struct sam_usbdev_s *priv)
}
/****************************************************************************
- * Name: sam_uhphs_interrupt
+ * Name: sam_udphs_interrupt
****************************************************************************/
-static int sam_uhphs_interrupt(int irq, void *context)
+static int sam_udphs_interrupt(int irq, void *context)
{
/* For now there is only one USB controller, but we will always refer to
- * it using a pointer to make any future ports to multiple USB controllers
+ * it using a pointer to make any future ports to multiple UDPHS controllers
* easier.
*/
struct sam_usbdev_s *priv = &g_usbdev;
- uint32_t istr;
- uint8_t epno;
+ uint32_t intsta;
+ uint32_t ien;
+ uint32_t pending;
+ int i;
+
+ /* Get the set of pending interrupts */
- /* Handle correct transfer event for isochronous and double-buffer bulk transfers. */
+ intsta = sam_getreg(SAM_UDPHS_INTSTA);
+ usbtrace(TRACE_INTENTRY(SAM_TRACEINTID_INTERRUPT), intsta);
- istr = sam_getreg(SAM_USB_ISTR);
- usbtrace(TRACE_INTENTRY(SAM_TRACEINTID_INTERRUPT), istr);
- while ((istr & USB_ISTR_CTR) != 0)
+ inten = sam_getreg(SAM_UDPHS_IEN);
+ pending = insta & inten;
+
+ /* Handle all pending UDPHS interrupts (and new interrupts that become
+ * pending)
+ */
+
+ while (pending)
{
- sam_putreg((uint32_t)~USB_ISTR_CTR, SAM_USB_ISTR);
-
- /* Extract highest priority endpoint number */
+ usbtrace(TRACE_INTENTRY(SAM_TRACEINTID_INTERRUPT), intsta);
- epno = (uint8_t)(istr & USB_ISTR_EPID_MASK);
+ /* Suspend, treated last */
- /* And handle the completion event */
+ if ((pending == UDPHS_INT_DETSUSPD) != 0)
+ {
+ usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_DETSUSPD), (uint16_t)pending);
- sam_epdone(priv, epno);
+ /* Enable wakeup interrupts */
- /* Fetch the status again for the next time through the loop */
+ regval = inten;
+ regval &= ~UDPHS_INT_DETSUSPD;
+ regval |= (UDPHS_INT_WAKEUP | UDPHS_INT_ENDOFRSM);
+ sam_putreg(regval, SAM_UDPHS_IEN);
- istr = sam_getreg(SAM_USB_ISTR);
- }
+ /* Acknowledge interrupt */
- /* Handle Reset interrupts. When this event occurs, the peripheral is left
- * in the same conditions it is left by the system reset (but with the
- * USB controller enabled).
- */
+ sam_putreg(UDPHS_INT_DETSUSPD | UDPHS_INT_WAKEUP, SAM_UDPHS_CLRINT);
+ sam_suspend(priv);
+ }
- if ((istr & USB_ISTR_RESET) != 0)
- {
- /* Reset interrupt received. Clear the RESET interrupt status. */
+ /* SOF interrupt*/
- sam_putreg(~USB_ISTR_RESET, SAM_USB_ISTR);
- usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_RESET), istr);
+ else if ((pending & UDPHS_INT_INTSOF) != 0)
+ {
+ /* Acknowledge interrupt */
- /* Restore our power-up state and exit now because istr is no longer
- * valid.
- */
+ usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_INTSOF), (uint16_t)pending);
+ sam_putreg(UDPHS_INT_INTSOF, SAM_UDPHS_CLRINT);
+ }
- sam_reset(priv);
- goto exit_lpinterrupt;
- }
+ /* Resume */
- /* Handle Wakeup interrupts. This interrupt is only enable while the USB is
- * suspended.
- */
+ else if ((pending & UDPHS_INT_WAKEUP) != 0 ||
+ (pending & UDPHS_INT_ENDOFRSM) != 0)
+ {
+ usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_WAKEUP), (uint16_t)pending);
+ sam_resume(priv);
- if ((istr & USB_ISTR_WKUP & priv->imask) != 0)
- {
- /* Wakeup interrupt received. Clear the WKUP interrupt status. The
- * cause of the resume is indicated in the FNR register
- */
+ /* Acknowledge interrupt */
- sam_putreg(~USB_ISTR_WKUP, SAM_USB_ISTR);
- usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_WKUP), sam_getreg(SAM_USB_FNR));
+ sam_putreg(UDPHS_INT_WAKEUP | UDPHS_INT_ENDOFRSM | UDPHS_INT_DETSUSPD,
+ SAM_UDPHS_CLRINT);
- /* Perform the wakeup action */
+ /* Enable suspend interrupts */
- sam_initresume(priv);
- priv->rsmstate = RSMSTATE_IDLE;
+ inten &= ~UDPHS_INT_WAKEUP;
+ inten |= (UDPHS_INT_ENDOFRSM | UDPHS_INT_DETSUSPD);
+ sam_putreg(inten, SAM_UDPHS_IEN);
+ }
- /* Disable ESOF polling, disable the wakeup interrupt, and
- * re-enable the suspend interrupt. Clear any pending SUSP
- * interrupts.
- */
+ /* Bus reset */
- sam_setimask(priv, USB_CNTR_SUSPM, USB_CNTR_ESOFM|USB_CNTR_WKUPM);
- sam_putreg(~USB_CNTR_SUSPM, SAM_USB_ISTR);
- }
+ if ((pending & UDPHS_INT_ENDRESET) != 0)
+ {
+ usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_ENDRESET), (uint16_t)pending);
- if ((istr & USB_ISTR_SUSP & priv->imask) != 0)
- {
- usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_SUSP), 0);
- sam_suspend(priv);
+ /* Clear and enable the suspend interrupt */
- /* Clear of the ISTR bit must be done after setting of USB_CNTR_FSUSP */
+ sam_putreg(UDPHS_INT_WAKEUP | UDPHS_INT_DETSUSPD, SAM_UDPHS_CLRINT);
- sam_putreg(~USB_ISTR_SUSP, SAM_USB_ISTR);
- }
+ inten |= UDPHS_INT_DETSUSPD;
+ sam_putreg(inten, SAM_UDPHS_IEN);
- if ((istr & USB_ISTR_ESOF & priv->imask) != 0)
- {
- sam_putreg(~USB_ISTR_ESOF, SAM_USB_ISTR);
-
- /* Resume handling timing is made with ESOFs */
+ /* Handle the reset */
- usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_ESOF), 0);
- sam_esofpoll(priv);
- }
+ sam_reset();
- if ((istr & USB_ISTR_CTR & priv->imask) != 0)
- {
- /* Low priority endpoint correct transfer interrupt */
+ /* Acknowledge the interrupt */
- usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_LPCTR), istr);
- sam_lptransfer(priv);
+ sam_putreg(UDPHS_INT_ENDRESET, SAM_UDPHS_CLRINT);
+ }
+
+ /* Upstream resume */
+
+ else if ((pending & UDPHS_INT_UPSTRRES) != 0)
+ {
+ /* Acknowledge interrupt */
+
+ usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_UPSTRRES), (uint16_t)pending);
+ sam_putreg(UDPHS_INT_ENDRESET, SAM_UDPHS_CLRINT);
+ pUdp->UDPHS_CLRINT = UDPHS_INT_UPSTRRES;
+ }
+
+ /* DMA interrupts */
+
+ if ((pending & UDPHS_INT_DMA_MASK) != 0)
+ {
+ for (i = 1; i <= SAM_UDPHS_NDMACHANNELS; i++)
+ {
+ if ((pending & UDPHS_INT_DMA(i)) != 0)
+ {
+ sam_dma_interrupt(priv, i);
+ }
+ }
+ }
+
+ /* Endpoint Interrupts */
+
+ if ((pending & UDPHS_INT_EPT_MASK) != 0)
+ {
+ for (i = 1; i <= SAM_UDPHS_NENDPOINTS; i++)
+ {
+ if ((pending & UDPHS_INT_EPT(i)) != 0)
+ {
+ sam_ep_interrupt(priv, i);
+ }
+ }
+ }
+
+ /* Re-sample the set of pending interrupts */
+
+ intsta = sam_getreg(SAM_UDPHS_INTSTA);
+ inten = sam_getreg(SAM_UDPHS_IEN);
+ pending = insta & inten;
}
-exit_lpinterrupt:
- usbtrace(TRACE_INTEXIT(SAM_TRACEINTID_INTERRUPT), sam_getreg(SAM_USB_EP0R));
+ usbtrace(TRACE_INTEXIT(SAM_TRACEINTID_INTERRUPT), insta);
return OK;
}
@@ -2871,7 +2907,7 @@ static int sam_wakeup(struct usbdev_s *dev)
*/
sam_setimask(priv, USB_CNTR_ESOFM, USB_CNTR_WKUPM|USB_CNTR_SUSPM);
- sam_putreg(~USB_ISTR_ESOF, SAM_USB_ISTR);
+ sam_putreg(~USB_ISTR_ESOF, SAM_UDPHS_INTSTA);
irqrestore(flags);
return OK;
}
@@ -2991,7 +3027,7 @@ static void sam_hw_reset(struct sam_usbdev_s *priv)
/* Clear any pending interrupts */
- sam_putreg(0, SAM_USB_ISTR);
+ sam_putreg(0, SAM_UDPHS_INTSTA);
/* Enable interrupts at the USB controller */
@@ -3227,7 +3263,7 @@ static void sam_hw_shutdown(struct sam_usbdev_s *priv)
/* Clear any pending interrupts */
- sam_putreg(0, SAM_USB_ISTR);
+ sam_putreg(0, SAM_UDPHS_INTSTA);
/* Disconnect the device / disable the pull-up */
@@ -3290,17 +3326,10 @@ void up_usbinitialize(void)
* them when we need them later.
*/
- if (irq_attach(SAM_IRQ_UHPHS, sam_uhphs_interrupt) != 0)
+ if (irq_attach(SAM_IRQ_UHPHS, sam_udphs_interrupt) != 0)
{
usbtrace(TRACE_DEVERROR(SAM_TRACEERR_IRQREGISTRATION),
- (uint16_t)SAM_IRQ_USBHP);
- goto errout;
- }
-
- if (irq_attach(SAM_IRQ_USBLP, sam_lpinterrupt) != 0)
- {
- usbtrace(TRACE_DEVERROR(SAM_TRACEERR_IRQREGISTRATION),
- (uint16_t)SAM_IRQ_USBLP);
+ (uint16_t)SAM_IRQ_UDPHS);
goto errout;
}
@@ -3335,12 +3364,10 @@ void up_usbuninitialize(void)
flags = irqsave();
usbtrace(TRACE_DEVUNINIT, 0);
- /* Disable and detach the USB IRQs */
+ /* Disable and detach the UDPHS IRQ */
- up_disable_irq(SAM_IRQ_USBHP);
- up_disable_irq(SAM_IRQ_USBLP);
- irq_detach(SAM_IRQ_USBHP);
- irq_detach(SAM_IRQ_USBLP);
+ up_disable_irq(SAM_IRQ_UDPHS);
+ irq_detach(SAM_IRQ_UDPHS);
if (priv->driver)
{
@@ -3411,13 +3438,7 @@ int usbdev_register(struct usbdevclass_driver_s *driver)
/* Enable USB controller interrupts at the NVIC */
- up_enable_irq(SAM_IRQ_USBHP);
- up_enable_irq(SAM_IRQ_USBLP);
-
- /* Set the interrrupt priority */
-
- up_prioritize_irq(SAM_IRQ_USBHP, CONFIG_USB_PRI);
- up_prioritize_irq(SAM_IRQ_USBLP, CONFIG_USB_PRI);
+ up_enable_irq(SAM_IRQ_UDPHS);
/* Enable pull-up to connect the device. The host should enumerate us
* some time after this
@@ -3473,8 +3494,7 @@ int usbdev_unregister(struct usbdevclass_driver_s *driver)
/* Disable USB controller interrupts (but keep them attached) */
- up_disable_irq(SAM_IRQ_USBHP);
- up_disable_irq(SAM_IRQ_USBLP);
+ up_disable_irq(SAM_IRQ_UDPHS);
/* Put the hardware in an inactive state. Then bring the hardware back up
* in the reset state (this is probably not necessary, the sam_reset()