summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2009-11-16 23:22:36 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2009-11-16 23:22:36 +0000
commit3b4c9d31951c6a5ed15cd47f2f17fe8fd573a6c3 (patch)
treee4a22840d64c749cceee8699414372268746bfdd
parenta4b3688eff63f62a34dc4fc5a3e6f6666c4fdf38 (diff)
downloadnuttx-3b4c9d31951c6a5ed15cd47f2f17fe8fd573a6c3.tar.gz
nuttx-3b4c9d31951c6a5ed15cd47f2f17fe8fd573a6c3.tar.bz2
nuttx-3b4c9d31951c6a5ed15cd47f2f17fe8fd573a6c3.zip
Add SDIO interrupt handling
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@2263 42af7a65-404d-4744-a932-0658087f49c3
-rw-r--r--nuttx/arch/arm/src/stm32/stm32_sdio.c885
-rwxr-xr-xnuttx/arch/arm/src/stm32/stm32_sdio.h4
-rw-r--r--nuttx/drivers/mmcsd/mmcsd_sdio.c15
-rwxr-xr-xnuttx/include/nuttx/sdio.h181
4 files changed, 725 insertions, 360 deletions
diff --git a/nuttx/arch/arm/src/stm32/stm32_sdio.c b/nuttx/arch/arm/src/stm32/stm32_sdio.c
index 3a128da10..c491395e5 100644
--- a/nuttx/arch/arm/src/stm32/stm32_sdio.c
+++ b/nuttx/arch/arm/src/stm32/stm32_sdio.c
@@ -39,12 +39,16 @@
#include <nuttx/config.h>
#include <sys/types.h>
-
+
+#include <semaphore.h>
+#include <assert.h>
#include <debug.h>
#include <errno.h>
#include <nuttx/sdio.h>
-#include <nuttx/mmcsd.h>
+#include <nuttx/mmcsd.h>
+#include <nuttx/arch.h>
+#include <arch/irq.h>
#include "chip.h"
#include "up_arch.h"
@@ -65,8 +69,12 @@
# undef CONFIG_SDIO_DMA
#endif
+#ifndef CONFIG_SDIO_PRI
+# define CONFIG_SDIO_PRI DMA_CCR_PRIMED
+#endif
+
#ifndef CONFIG_SDIO_DMAPRIO
-# define CONFIG_SDIO_DMAPRIO DMA_CCR_PRIMED
+# define CONFIG_SDIO_DMAPRIO DMA_CCR_PRIMED
#endif
/* Friendly CLKCR bit re-definitions ****************************************/
@@ -83,22 +91,31 @@
/* HCLK=72 MHz, SDIOCLK=72MHz, SDIO_CK=HCLK/(1+2)=24 MHz */
#define SDIO_TRANSFER_CLKDIV (1 << SDIO_CLKCR_CLKDIV_SHIFT)
-#define STM32_CLCKCR_TRANSFER \
- (SDIO_TRANSFER_CLKDIV|SDIO_CLKCR_RISINGEDGE|SDIO_CLKCR_WIDBUS_D1)
-#define STM32_CLKCR_WIDETRANSFER \
- (SDIO_TRANSFER_CLKDIV|SDIO_CLKCR_RISINGEDGE|SDIO_CLKCR_WIDBUS_D4)
+#define STM32_CLCKCR_TRANSFER (SDIO_TRANSFER_CLKDIV|SDIO_CLKCR_RISINGEDGE|\
+ SDIO_CLKCR_WIDBUS_D1)
+#define STM32_CLKCR_WIDETRANSFER (SDIO_TRANSFER_CLKDIV|SDIO_CLKCR_RISINGEDGE|\
+ SDIO_CLKCR_WIDBUS_D4)
/* Timing */
-#define SDIO_CMDTIMEOUT 100000
-#define SDIO_LONGTIMEOUT 0x7fffffff
+#define SDIO_CMDTIMEOUT (100000)
+#define SDIO_LONGTIMEOUT (0x7fffffff)
+
+/* Big DTIMER setting */
+
+#define SDIO_DTIMER_DATATIMEOUT (0x000fffff)
/* DMA CCR register settings */
-#define SDIO_RXDMA16_CONFIG (CONFIG_SDIO_DMAPRIO|DMA_CCR_MSIZE_16BITS|\
- DMA_CCR_PSIZE_16BITS|DMA_CCR_MINC)
-#define SDIO_TXDMA16_CONFIG (CONFIG_SDIO_DMAPRIO|DMA_CCR_MSIZE_16BITS|\
- DMA_CCR_PSIZE_16BITS|DMA_CCR_MINC|DMA_CCR_DIR)
+#define SDIO_RXDMA16_CONFIG (CONFIG_SDIO_DMAPRIO|DMA_CCR_MSIZE_16BITS|\
+ DMA_CCR_PSIZE_16BITS|DMA_CCR_MINC)
+#define SDIO_TXDMA16_CONFIG (CONFIG_SDIO_DMAPRIO|DMA_CCR_MSIZE_16BITS|\
+ DMA_CCR_PSIZE_16BITS|DMA_CCR_MINC|DMA_CCR_DIR)
+
+/* FIFO sizes */
+
+#define SDIO_HALFFIFO_WORDS (8)
+#define SDIO_HALFFIFO_BYTES (8*4)
/****************************************************************************
* Private Types
@@ -108,20 +125,30 @@
struct stm32_dev_s
{
- struct sdio_dev_s dev; /* Standard, base MMC/SD interface */
+ struct sdio_dev_s dev; /* Standard, base SDIO interface */
/* STM32-specific extensions */
- sem_t eventsem; /* Implements event waiting */
- sdio_event_t waitevents; /* Set of events to be waited for */
- volatile sdio_event_t wkupevents; /* Set of events that caused the wakeup */
- sdio_event_t cbevents; /* Set of events to be cause callbacks */
- sdio_mediachange_t callback; /* Registered callback function */
+ sem_t waitsem; /* Implements event waiting */
+ sdio_eventset_t waitevents; /* Set of events to be waited for */
+ volatile sdio_eventset_t wkupevent; /* The event that caused the wakeup */
+ sdio_eventset_t cbevents; /* Set of events to be cause callbacks */
+ sdio_mediachange_t callback; /* Registered callback function */
+ void *cbarg; /* Registered callback argument */
+
+ /* Interrupt mode data transfer support */
- /* DMA support */
+ uint32 *buffer; /* Address of current R/W buffer */
+ size_t remaining; /* Number of bytes remaining in the transfer */
+ int result; /* Result of the transfer */
+ boolean stopxfr; /* TRUE: Send STOP_TRANSMISSION */
+ /* DMA data transfer support */
+
+ boolean widebus; /* Required for DMA support */
#ifdef CONFIG_SDIO_DMA
- DMA_HANDLE dma; /* Handle for DMA channel */
+ boolean dmamode; /* TRUE: DMA mode transfer */
+ DMA_HANDLE dma; /* Handle for DMA channel */
#endif
};
@@ -138,8 +165,8 @@ static inline void stm32_enableint(uint32 bitset);
static inline void stm32_disableint(uint32 bitset);
static void stm32_setpwrctrl(uint32 pwrctrl);
static inline uint32 stm32_getpwrctrl(void);
-static inline void stm32_clkenable(void)
-static inline void stm32_clkdisable(void)
+static inline void stm32_clkenable(void);
+static inline void stm32_clkdisable(void);
/* DMA Helpers **************************************************************/
@@ -151,7 +178,15 @@ static void stm32_dmacallback(DMA_HANDLE handle, ubyte isr, void *arg);
static ubyte stm32_log2(uint16 value);
static void stm32_dataconfig(uint32 timeout, uint32 dlen, uint32 dctrl);
-static void stm32_datadisable(void);
+static void stm32_datadisable(void);
+static void stm32_sendfifo(struct stm32_dev_s *priv);
+static void stm32_recvfifo(struct stm32_dev_s *priv);
+static int stm32_stoptransmission(struct stm32_dev_s *priv);
+static void stm32_endtransfer(struct stm32_dev_s *priv, int result);
+
+/* Interrupt Handling *******************************************************/
+
+static int stm32_interrupt(int irq, void *context);
/* SDIO interface methods ***************************************************/
@@ -166,40 +201,43 @@ static int stm32_attach(FAR struct sdio_dev_s *dev);
/* Command/Status/Data Transfer */
-static void stm32_sendcmd(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 arg);
-static int stm32_sendsetup(FAR struct sdio_dev_s *dev, uint32 nbytes);
-static int stm32_senddata(FAR struct sdio_dev_s *dev,
- FAR const ubyte *buffer);
-
-static int stm32_waitresponseFAR struct sdio_dev_s *dev, uint32 cmd);
-static int stm32_recvshortcrc(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 *rshort);
-static int stm32_recvlong(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 rlong[4]);
-static int stm32_recvshort(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 *rshort);
-static int stm32_recvnotimpl(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 *rnotimpl);
-static int stm32_recvsetup(FAR struct sdio_dev_s *dev, uint32 nbytes);
-static int stm32_recvdata(FAR struct sdio_dev_s *dev, FAR ubyte *buffer);
+static void stm32_sendcmd(FAR struct sdio_dev_s *dev, uint32 cmd,
+ uint32 arg);
+static int stm32_recvsetup(FAR struct sdio_dev_s *dev, FAR ubyte *buffer,
+ size_t nbytes);
+static int stm32_sendsetup(FAR struct sdio_dev_s *dev,
+ FAR const ubyte *buffer, uint32 nbytes);
+
+static int stm32_waitresponse(FAR struct sdio_dev_s *dev, uint32 cmd);
+static int stm32_recvshortcrc(FAR struct sdio_dev_s *dev, uint32 cmd,
+ uint32 *rshort);
+static int stm32_recvlong(FAR struct sdio_dev_s *dev, uint32 cmd,
+ uint32 rlong[4]);
+static int stm32_recvshort(FAR struct sdio_dev_s *dev, uint32 cmd,
+ uint32 *rshort);
+static int stm32_recvnotimpl(FAR struct sdio_dev_s *dev, uint32 cmd,
+ uint32 *rnotimpl);
/* EVENT handler */
-static void stm32_waitenable(FAR struct sdio_dev_s *dev, sdio_event_t eventset,
- boolean enable);
+static void stm32_waitenable(FAR struct sdio_dev_s *dev,
+ sdio_eventset_t eventset);
static ubyte stm32_eventwait(FAR struct sdio_dev_s *dev, uint32 timeout);
static ubyte stm32_events(FAR struct sdio_dev_s *dev);
-static void stm32_callbackenable(FAR struct sdio_dev_s *dev, sdio_event_t eventset);
+static void stm32_callbackenable(FAR struct sdio_dev_s *dev,
+ sdio_eventset_t eventset);
static int stm32_registercallback(FAR struct sdio_dev_s *dev,
- sdio_mediachange_t callback, void *arg)
+ sdio_mediachange_t callback, void *arg);
/* DMA */
#ifdef CONFIG_SDIO_DMA
static boolean stm32_dmasupported(FAR struct sdio_dev_s *dev);
-static int stm32_dmareadsetup(FAR struct sdio_dev_s *dev,
+static int stm32_dmarecvsetup(FAR struct sdio_dev_s *dev,
FAR ubyte *buffer, size_t buflen);
-static int stm32_dmawritesetup(FAR struct sdio_dev_s *dev,
+static int stm32_dmasendsetup(FAR struct sdio_dev_s *dev,
FAR const ubyte *buffer, size_t buflen);
-static int stm32_dmastart(FAR struct sdio_dev_s *dev);
-static int stm32_dmastatus(FAR struct sdio_dev_s *dev,
- size_t *remaining);
+static int stm32_sdiodmastart(FAR struct sdio_dev_s *dev);
#endif
/* Initialization/uninitialization/reset ************************************/
@@ -211,7 +249,7 @@ static void stm32_default(void);
* Private Data
****************************************************************************/
-struct stm32_dev_s g_mmcsd =
+struct stm32_dev_s g_sdiodev =
{
.dev =
{
@@ -221,8 +259,8 @@ struct stm32_dev_s g_mmcsd =
.clock = stm32_clock,
.attach = stm32_attach,
.sendcmd = stm32_sendcmd,
+ .recvsetup = stm32_recvsetup,
.sendsetup = stm32_sendsetup,
- .senddata = stm32_senddata,
.waitresponse = stm32_waitresponse,
.recvR1 = stm32_recvshortcrc,
.recvR2 = stm32_recvlong,
@@ -231,8 +269,6 @@ struct stm32_dev_s g_mmcsd =
.recvR5 = stm32_recvnotimpl,
.recvR6 = stm32_recvshortcrc,
.recvR7 = stm32_recvshort,
- .recvsetup = stm32_recvsetup,
- .recvdata = stm32_recvdata,
.waitenable = stm32_waitenable,
.eventwait = stm32_eventwait,
.events = stm32_events,
@@ -240,10 +276,9 @@ struct stm32_dev_s g_mmcsd =
.registercallback = stm32_registercallback,
#ifdef CONFIG_SDIO_DMA
.dmasupported = stm32_dmasupported,
- .dmareadsetup = stm32_dmareadsetup,
- .dmawritesetup = stm32_dmawritesetup,
- .dmastart = stm32_dmastart,
- .dmastatus = stm32_dmastatus,
+ .dmarecvsetup = stm32_dmarecvsetup,
+ .dmasendsetup = stm32_dmasendsetup,
+ .dmastart = stm32_sdiodmastart,
#endif
},
};
@@ -436,15 +471,9 @@ static void stm32_dmacallback(DMA_HANDLE handle, ubyte isr, void *arg)
{
FAR struct stm32_spidev_s *priv = (FAR struct stm32_spidev_s *)arg;
- /* Is a data transfer complete event expected? */
-
- if ((priv->waitevents & SDIOWAIT_TRANSFERDONE) != 0)
- {
- /* Yes, wake up the waiting thread */
-
- priv->wkupevent = SDIOWAIT_TRANSFERDONE;
- sdio_semgive(priv);
- }
+ /* We don't really do anything at the completion of DMA. The termination
+ * of the transfer is driven by the SDIO interrupts.
+ */
}
#endif
@@ -506,7 +535,7 @@ static void stm32_dataconfig(uint32 timeout, uint32 dlen, uint32 dctrl)
regval = getreg32(STM32_SDIO_DCTRL);
regval &= ~(SDIO_DCTRL_DTDIR|SDIO_DCTRL_DTMODE|SDIO_DCTRL_DBLOCKSIZE_MASK);
dctrl &= (SDIO_DCTRL_DTDIR|SDIO_DCTRL_DTMODE|SDIO_DCTRL_DBLOCKSIZE_MASK);
- regval |= (dctrl|DIO_DCTRL_DTEN);
+ regval |= (dctrl|SDIO_DCTRL_DTEN);
putreg32(regval, STM32_SDIO_DCTRL);
}
@@ -525,7 +554,7 @@ static void stm32_datadisable(void)
/* Disable the data path */
- putreg32(SD_DATATIMEOUT, STM32_SDIO_DTIMER); /* Reset DTIMER */
+ putreg32(SDIO_DTIMER_DATATIMEOUT, STM32_SDIO_DTIMER); /* Reset DTIMER */
putreg32(0, STM32_SDIO_DLEN); /* Reset DLEN */
/* Reset DCTRL DTEN, DTDIR, DTMODE, DMAEN, and DBLOCKSIZE fields */
@@ -537,16 +566,346 @@ static void stm32_datadisable(void)
}
/****************************************************************************
+ * Name: stm32_sendfifo
+ *
+ * Description:
+ * Send SDIO data in interrupt mode
+ *
+ * Input Parameters:
+ * priv - An instance of the SDIO device interface
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void stm32_sendfifo(struct stm32_dev_s *priv)
+{
+ union
+ {
+ uint32 w;
+ ubyte b[2];
+ } data;
+
+ /* Loop while there is more data to be sent and the RX FIFO is not full */
+
+ while (priv->remaining > 0 &&
+ (getreg32(STM32_SDIO_STA) & SDIO_STA_TXFIFOF) == 0)
+ {
+ /* Is there a full word remaining in the user buffer? */
+
+ if (priv->remaining >= sizeof(uint32))
+ {
+ /* Yes, transfer the word to the TX FIFO */
+
+ data.w = *priv->buffer++;
+ priv->remaining -= sizeof(uint32);
+ }
+ else
+ {
+ /* No.. transfer just the bytes remaining in the user buffer,
+ * padding with zero as necessary to extend to a full word.
+ */
+
+ ubyte *ptr = (ubyte *)priv->remaining;
+ int i;
+
+ data.w = 0;
+ for (i = 0; i < priv->remaining; i++)
+ {
+ data.b[i] = *ptr++;
+ }
+
+ /* Now the transfer is finished */
+
+ priv->remaining = 0;
+ }
+
+ /* Put the word in the FIFO */
+
+ putreg32(data.w, STM32_SDIO_FIFO);
+ }
+}
+
+/****************************************************************************
+ * Name: stm32_recvfifo
+ *
+ * Description:
+ * Receive SDIO data in interrupt mode
+ *
+ * Input Parameters:
+ * priv - An instance of the SDIO device interface
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void stm32_recvfifo(struct stm32_dev_s *priv)
+{
+ union
+ {
+ uint32 w;
+ ubyte b[2];
+ } data;
+
+ /* Loop while there is space to store the data and there is more
+ * data available in the RX FIFO.
+ */
+
+ while (priv->remaining > 0 &&
+ (getreg32(STM32_SDIO_STA) & SDIO_STA_RXDAVL) == 0)
+ {
+ /* Read the next word from the RX FIFO */
+
+ data.w = getreg32(STM32_SDIO_FIFO);
+ if (priv->remaining >= sizeof(uint32))
+ {
+ /* Transfer the whole word to the user buffer */
+
+ *priv->buffer++ = data.w;
+ priv->remaining -= sizeof(uint32);
+ }
+ else
+ {
+ /* Transfer any trailing fractional word */
+
+ ubyte *ptr = (ubyte*)priv->buffer;
+ int i;
+
+ for (i = 0; i < priv->remaining; i++)
+ {
+ *ptr++ = data.b[i];
+ }
+
+ /* Now the transfer is finished */
+
+ priv->remaining = 0;
+ }
+ }
+}
+
+/****************************************************************************
+ * Name: stm32_stoptransmission
+ *
+ * Description:
+ * Send STOP_TRANSMISSION
+ *
+ * Input Parameters:
+ * dev - An instance of the SDIO device interface
+ *
+ * Returned Value:
+ * OK on success; A negated errno on failure.
+ *
+ ****************************************************************************/
+
+static int stm32_stoptransmission(struct stm32_dev_s *priv)
+{
+# warning "Not implemented"
+ return -ENOSYS;
+}
+
+/****************************************************************************
+ * Name: stm32_endtransfer
+ *
+ * Description:
+ * Terminate a transfer with the provided status
+ *
+ * Input Parameters:
+ * dev - An instance of the SDIO device interface
+ * result - The result status of the transfer
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void stm32_endtransfer(struct stm32_dev_s *priv, int result)
+{
+ /* Disable interrupts */
+
+ stm32_disableint(SDIO_MASK_DCRCFAILIE|SDIO_MASK_DTIMEOUTIE|
+ SDIO_MASK_DATAENDIE|SDIO_MASK_TXFIFOHEIE|
+ SDIO_MASK_RXFIFOHFIE|SDIO_MASK_TXUNDERRIE|
+ SDIO_MASK_RXOVERRIE|SDIO_MASK_STBITERRIE);
+
+ /* Mark the transfer finished with the provided status */
+
+ priv->remaining = 0;
+ priv->result = result;
+
+ /* Is a data transfer complete event expected? */
+
+ if ((priv->waitevents & SDIOWAIT_TRANSFERDONE) != 0)
+ {
+ /* Yes, wake up the waiting thread */
+
+ priv->wkupevent = SDIOWAIT_TRANSFERDONE;
+ stm32_givesem(priv);
+ }
+}
+
+/****************************************************************************
+ * Interrrupt Handling
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: stm32_interrupt
+ *
+ * Description:
+ * SDIO interrupt handler
+ *
+ * Input Parameters:
+ * dev - An instance of the SDIO device interface
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static int stm32_interrupt(int irq, void *context)
+{
+ struct stm32_dev_s *priv = &g_sdiodev;
+ uint32 sta;
+
+ /* Loop while there are pending interrupts. Check the SDIO status
+ * register. Mask out all bits that don't correspond to enabled
+ * interrupts. (This depends on the fact that bits are ordered
+ * the same in both the STA and MASK register). If there are non-zero
+ * bits remaining, then we have work to do here.
+ */
+
+ while ((sta = getreg32(STM32_SDIO_STA) & getreg32(STM32_SDIO_MASK)) != 0)
+ {
+ /* Handle in progress, interrupt driven data transfers */
+
+#ifdef CONFIG_SDIO_DMA
+ if (!priv->dmamode)
+#endif
+ {
+ /* Is the RX FIFO half full or more? Is so then we must be
+ * processing a receive transaction.
+ */
+
+ if ((sta & SDIO_STA_RXFIFOHF) != 0)
+ {
+ /* Receive data from the RX FIFO */
+
+ stm32_recvfifo(priv);
+ }
+
+ /* Otherwise, Is the transmit FIFO half empty or less? If so we must
+ * be processing a send transaction. NOTE: We can't be processing
+ * both!
+ */
+
+ else if ((sta & SDIO_STA_TXFIFOHE) != 0)
+ {
+ /* Send data via the TX FIFO */
+
+ stm32_sendfifo(priv);
+ }
+ }
+
+ /* Handle data end events */
+
+ if ((sta & SDIO_STA_DATAEND) != 0)
+ {
+ int result;
+
+ /* Handle any data remaining the RX FIFO. If the RX FIFO is
+ * less than half full at the end of the transfer, then no
+ * half-full interrupt will be received.
+ */
+
+#ifdef CONFIG_SDIO_DMA
+ if (!priv->dmamode)
+#endif
+ {
+ /* Receive data from the RX FIFO */
+
+ stm32_recvfifo(priv);
+ }
+
+ /* Check if we are supposed to send STOP_TRANSMISSION now */
+
+ result = OK;
+ if (priv->stopxfr)
+ {
+ result = stm32_stoptransmission(priv);
+ }
+
+ /* Then terminate the transfer */
+
+ putreg32(SDIO_ICR_DATAENDC, STM32_SDIO_ICR);
+ stm32_endtransfer(priv, result);
+ }
+
+ /* Handler data block send/receive CRC failure */
+
+ else if ((sta & SDIO_STA_DCRCFAIL) != 0)
+ {
+ /* Terminate the transfer with an error */
+
+ putreg32(SDIO_ICR_DCRCFAILC, STM32_SDIO_ICR);
+ stm32_endtransfer(priv, -EIO);
+ }
+
+ /* Handle data timeout error */
+
+ else if ((sta & SDIO_STA_DTIMEOUT) != 0)
+ {
+ /* Terminate the transfer with an error */
+
+ putreg32(SDIO_ICR_DTIMEOUTC, STM32_SDIO_ICR);
+ stm32_endtransfer(priv, -ETIMEDOUT);
+ }
+
+ /* Handle RX FIFO overrun error */
+
+ else if ((sta & SDIO_STA_RXOVERR) != 0)
+ {
+ /* Terminate the transfer with an error */
+
+ putreg32(SDIO_ICR_RXOVERRC, STM32_SDIO_ICR);
+ stm32_endtransfer(priv, -EOVERFLOW);
+ }
+
+ /* Handle TX FIFO underrun error */
+
+ else if ((sta & SDIO_STA_TXUNDERR) != 0)
+ {
+ /* Terminate the transfer with an error */
+
+ putreg32(SDIO_ICR_TXUNDERRC, STM32_SDIO_ICR);
+ stm32_endtransfer(priv, -EOVERFLOW);
+ }
+
+ /* Handle start bit error */
+
+ else if ((sta & SDIO_STA_STBITERR) != 0)
+ {
+ /* Terminate the transfer with an error */
+
+ putreg32(SDIO_ICR_STBITERRC, STM32_SDIO_ICR);
+ stm32_endtransfer(priv, -EIO);
+ }
+ }
+
+ return OK;
+}
+
+/****************************************************************************
* SDIO Interface Methods
****************************************************************************/
/****************************************************************************
* Name: stm32_reset
*
* Description:
- * Reset the MMC/SD controller. Undo all setup and initialization.
+ * Reset the SDIO controller. Undo all setup and initialization.
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
+ * dev - An instance of the SDIO device interface
*
* Returned Value:
* None
@@ -561,7 +920,7 @@ static void stm32_reset(FAR struct sdio_dev_s *dev)
* Name: stm32_status
*
* Description:
- * Get MMC/SD status.
+ * Get SDIO status.
*
* Input Parameters:
* dev - Device-specific state data
@@ -585,7 +944,7 @@ static ubyte stm32_status(FAR struct sdio_dev_s *dev)
* correctly in the new bus mode.
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
+ * dev - An instance of the SDIO device interface
* wide - TRUE: wide bus (4-bit) bus mode enabled
*
* Returned Value:
@@ -595,20 +954,18 @@ static ubyte stm32_status(FAR struct sdio_dev_s *dev)
static void stm32_widebus(FAR struct sdio_dev_s *dev, boolean wide)
{
- if (wide)
- {
- priv->mode = MMCSDMODE_DMA;
- }
+ struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
+ priv->widebus = wide;
}
/****************************************************************************
* Name: stm32_clock
*
* Description:
- * Enable/disable MMC/SD clocking
+ * Enable/disable SDIO clocking
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
+ * dev - An instance of the SDIO device interface
* rate - Specifies the clocking to use (see enum sdio_clock_e)
*
* Returned Value:
@@ -627,7 +984,7 @@ static void stm32_clock(FAR struct sdio_dev_s *dev, enum sdio_clock_e rate)
* Attach and prepare interrupts
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
+ * dev - An instance of the SDIO device interface
*
* Returned Value:
* OK on success; A negated errno on failure.
@@ -635,18 +992,44 @@ static void stm32_clock(FAR struct sdio_dev_s *dev, enum sdio_clock_e rate)
****************************************************************************/
static int stm32_attach(FAR struct sdio_dev_s *dev)
-{
- return -ENOSYS;
+{
+ int ret;
+
+ /* Attach the SDIO interrupt handler */
+
+ ret = irq_attach(STM32_IRQ_SDIO, stm32_interrupt);
+ if (ret == OK)
+ {
+
+ /* Disable all interrupts at the SDIO controller and clear static
+ * interrupt flags
+ */
+
+ putreg32(SDIO_MASK_RESET, STM32_SDIO_MASK);
+ putreg32(SDIO_ICR_STATICFLAGS, STM32_SDIO_ICR);
+
+ /* Enable SDIO interrupts at the NVIC. They can now be enabled at
+ * the SDIO controller as needed.
+ */
+
+ up_enable_irq(STM32_IRQ_SDIO);
+
+ /* Set the interrrupt priority */
+
+ up_prioritize_irq(STM32_IRQ_SDIO, CONFIG_SDIO_PRI);
+ }
+
+ return ret;
}
/****************************************************************************
* Name: stm32_sendcmd
*
* Description:
- * Send the MMC/SD command
+ * Send the SDIO command
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
+ * dev - An instance of the SDIO device interface
* cmd - The command to send (32-bits, encoded)
* arg - 32-bit argument required with some commands
*
@@ -704,6 +1087,58 @@ static void stm32_sendcmd(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 arg)
}
/****************************************************************************
+ * Name: stm32_recvsetup
+ *
+ * Description:
+ * Setup hardware in preparation for data trasfer from the card in non-DMA
+ * (interrupt driven mode). This method will do whatever controller setup
+ * is necessary. This would be called for SD memory just BEFORE sending
+ * CMD13 (SEND_STATUS), CMD17 (READ_SINGLE_BLOCK), CMD18
+ * (READ_MULTIPLE_BLOCKS), ACMD51 (SEND_SCR), etc. Normally, SDIO_WAITEVENT
+ * will be called to receive the indication that the transfer is complete.
+ *
+ * Input Parameters:
+ * dev - An instance of the SDIO device interface
+ * buffer - Address of the buffer in which to receive the data
+ * nbytes - The number of bytes in the transfer
+ *
+ * Returned Value:
+ * Number of bytes sent on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+static int stm32_recvsetup(FAR struct sdio_dev_s *dev, FAR ubyte *buffer,
+ size_t nbytes)
+{
+ struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
+ uint32 dblocksize;
+
+ DEBUGASSERT(priv != NULL && buffer != NULL && nbytes > 0);
+ DEBUGASSERT(((uint32)buffer & 3) == 0);
+
+ /* Save the destination buffer information for use by the interrupt handler */
+
+ priv->buffer = (uint32*)buffer;
+ priv->remaining = nbytes;
+ priv->result = -EBUSY;
+#ifdef CONFIG_SDIO_DMA
+ priv->dmamode = FALSE;
+#endif
+
+ /* Then set up the SDIO data path */
+
+ dblocksize = stm32_log2(nbytes) << SDIO_DCTRL_DBLOCKSIZE_SHIFT;
+ stm32_dataconfig(SDIO_DTIMER_DATATIMEOUT, nbytes, dblocksize|SDIO_DCTRL_DTDIR);
+
+ /* And enable interrupts */
+
+ stm32_enableint(SDIO_MASK_DCRCFAILIE|SDIO_MASK_DTIMEOUTIE|
+ SDIO_MASK_DATAENDIE|SDIO_MASK_RXOVERRIE|
+ SDIO_MASK_RXFIFOHFIE|SDIO_MASK_STBITERRIE);
+ return OK;
+}
+
+/****************************************************************************
* Name: stm32_sendsetup
*
* Description:
@@ -713,7 +1148,8 @@ static void stm32_sendcmd(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 arg)
* (WRITE_MULTIPLE_BLOCK), ... and before SDIO_SENDDATA is called.
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
+ * dev - An instance of the SDIO device interface
+ * buffer - Address of the buffer containing the data to send
* nbytes - The number of bytes in the transfer
*
* Returned Value:
@@ -721,33 +1157,37 @@ static void stm32_sendcmd(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 arg)
*
****************************************************************************/
-static int stm32_sendsetup(FAR struct sdio_dev_s *dev, uint32 nbytes)
+static int stm32_sendsetup(FAR struct sdio_dev_s *dev, FAR const ubyte *buffer,
+ size_t nbytes)
{
- uint32 dctrl = stm32_log2(nbytes) << SDIO_DCTRL_DBLOCKSIZE_SHIFT);
- stm32_dataconfig(SD_DATATIMEOUT, nbytes, dctrl);
+ struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
+ uint32 dblocksize;
+
+ DEBUGASSERT(priv != NULL && buffer != NULL && nbytes > 0);
+ DEBUGASSERT(((uint32)buffer & 3) == 0);
+
+ /* Save the source buffer information for use by the interrupt handler */
+
+ priv->buffer = (uint32*)buffer;
+ priv->remaining = nbytes;
+ priv->result = -EBUSY;
+#ifdef CONFIG_SDIO_DMA
+ priv->dmamode = FALSE;
+#endif
+
+ /* Then set up the SDIO data path */
+
+ dblocksize = stm32_log2(nbytes) << SDIO_DCTRL_DBLOCKSIZE_SHIFT;
+ stm32_dataconfig(SDIO_DTIMER_DATATIMEOUT, nbytes, dblocksize);
+
+ /* Enable TX interrrupts */
+
+ stm32_enableint(SDIO_MASK_DCRCFAILIE|SDIO_MASK_DTIMEOUTIE|
+ SDIO_MASK_DATAENDIE|SDIO_MASK_TXUNDERRIE|
+ SDIO_MASK_TXFIFOHEIE|SDIO_MASK_STBITERRIE);
return OK;
}
-/****************************************************************************
- * Name: stm32_senddata
- *
- * Description:
- * Send more MMC/SD data
- *
- * Input Parameters:
- * dev - An instance of the MMC/SD device interface
- * data - Data to be sent
- *
- * Returned Value:
- * Number of bytes sent on success; a negated errno on failure
- *
- ****************************************************************************/
-
-static int stm32_senddata(FAR struct sdio_dev_s *dev, FAR const ubyte *buffer)
-{
- return -ENOSYS;
-}
-
/****************************************************************************
* Name: stm32_waitresponse
*
@@ -755,7 +1195,7 @@ static int stm32_senddata(FAR struct sdio_dev_s *dev, FAR const ubyte *buffer)
* Poll-wait for the response to the last command to be ready.
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
+ * dev - An instance of the SDIO device interface
* cmd - The command that was sent. See 32-bit command definitions above.
*
* Returned Value:
@@ -763,7 +1203,7 @@ static int stm32_senddata(FAR struct sdio_dev_s *dev, FAR const ubyte *buffer)
*
****************************************************************************/
-static int stm32_waitresponseFAR struct sdio_dev_s *dev, uint32 cmd)
+static int stm32_waitresponse(FAR struct sdio_dev_s *dev, uint32 cmd)
{
sint32 timeout = SDIO_LONGTIMEOUT;
uint32 events;
@@ -817,13 +1257,13 @@ static int stm32_waitresponseFAR struct sdio_dev_s *dev, uint32 cmd)
* Name: stm32_recvRx
*
* Description:
- * Receive response to MMC/SD command. Only the critical payload is
+ * Receive response to SDIO command. Only the critical payload is
* returned -- that is 32 bits for 48 bit status and 128 bits for 136 bit
* status. The driver implementation should verify the correctness of
* the remaining, non-returned bits (CRCs, CMD index, etc.).
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
+ * dev - An instance of the SDIO device interface
* Rx - Buffer in which to receive the response
*
* Returned Value:
@@ -876,7 +1316,7 @@ static int stm32_recvshortcrc(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 *rs
if ((cmd & MMCSD_RESPONSE_MASK) != MMCSD_R1_RESPONSE &&
(cmd & MMCSD_RESPONSE_MASK) != MMCSD_R1B_RESPONSE &&
- cmd & MMCSD_RESPONSE_MASK |= MMCSD_R6_RESPONSE)
+ (cmd & MMCSD_RESPONSE_MASK) != MMCSD_R6_RESPONSE)
{
fdbg("ERROR: Wrong response CMD=%08x\n", cmd);
return -EINVAL;
@@ -994,7 +1434,7 @@ static int stm32_recvshort(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 *rshor
#ifdef CONFIG_DEBUG
if ((cmd & MMCSD_RESPONSE_MASK) != MMCSD_R3_RESPONSE &&
- cmd & MMCSD_RESPONSE_MASK |= MMCSD_R7_RESPONSE)
+ (cmd & MMCSD_RESPONSE_MASK) != MMCSD_R7_RESPONSE)
{
fdbg("ERROR: Wrong response CMD=%08x\n", cmd);
return -EINVAL;
@@ -1030,57 +1470,11 @@ static int stm32_recvnotimpl(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 *rno
return -ENOSYS;
}
-/****************************************************************************
- * Name: stm32_recvsetup
- *
- * Description:
- * Setup hardware in preparation for data trasfer from the card. This method
- * will do whatever controller setup is necessary. This would be called
- * for SD memory just BEFORE sending CMD13 (SEND_STATUS), CMD17
- * (READ_SINGLE_BLOCK), CMD18 (READ_MULTIPLE_BLOCKS), ACMD51 (SEND_SCR), ...
- * and before SDIO_RECVDATA is called.
- *
- * Input Parameters:
- * dev - An instance of the MMC/SD device interface
- * nbytes - The number of bytes in the transfer
- *
- * Returned Value:
- * Number of bytes sent on success; a negated errno on failure
- *
- ****************************************************************************/
-
-static int stm32_recvsetup(FAR struct sdio_dev_s *dev, uint32 nbytes)
-{
- uint32 dctrl = (stm32_log2(nbytes) << SDIO_DCTRL_DBLOCKSIZE_SHIFT)) | SDIO_DCTRL_DTDIR;
- stm32_dataconfig(SD_DATATIMEOUT, nbytes, dctrl);
- return OK;
-}
-
-/****************************************************************************
- * Name: stm32_recvdata
- *
- * Description:
- * Receive data from MMC/SD
- *
- * Input Parameters:
- * dev - An instance of the MMC/SD device interface
- * buffer - Buffer in which to receive the data
- *
- * Returned Value:
- * Number of bytes sent on success; a negated errno on failure
- *
- ****************************************************************************/
-
-static int stm32_recvdata(FAR struct sdio_dev_s *dev, FAR ubyte *buffer)
-{
- return -ENOSYS;
-}
-
/****************************************************************************
* Name: stm32_waitenable
*
* Description:
- * Enable/disable of a set of MMC/SD wait events. This is part of the
+ * Enable/disable of a set of SDIO wait events. This is part of the
* the SDIO_WAITEVENT sequence. The set of to-be-waited-for events is
* configured before calling stm32_waitevent. This is done in this way
* to help the driver to eliminate race conditions between the command
@@ -1091,7 +1485,7 @@ static int stm32_recvdata(FAR struct sdio_dev_s *dev, FAR ubyte *buffer)
* returns.
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
+ * dev - An instance of the SDIO device interface
* eventset - A bitset of events to enable or disable (see SDIOWAIT_*
* definitions). 0=disable; 1=enable.
*
@@ -1100,7 +1494,8 @@ static int stm32_recvdata(FAR struct sdio_dev_s *dev, FAR ubyte *buffer)
*
****************************************************************************/
-static void stm32_waitenable(FAR struct sdio_dev_s *dev, sdio_event_t eventset)
+static void stm32_waitenable(FAR struct sdio_dev_s *dev,
+ sdio_eventset_t eventset)
{
struct stm32_dev_s *priv = (struct stm32_dev_s*)dev;
@@ -1108,7 +1503,7 @@ static void stm32_waitenable(FAR struct sdio_dev_s *dev, sdio_event_t eventset)
DEBUGASSERT(priv != NULL);
priv->waitevents = 0;
- priv->wkupevents = 0;
+ priv->wkupevent = 0;
priv->waitevents = eventset;
}
@@ -1122,7 +1517,7 @@ static void stm32_waitenable(FAR struct sdio_dev_s *dev, sdio_event_t eventset)
* can be used again.
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
+ * dev - An instance of the SDIO device interface
* timeout - Maximum time in milliseconds to wait. Zero means no timeout.
*
* Returned Value:
@@ -1134,7 +1529,8 @@ static void stm32_waitenable(FAR struct sdio_dev_s *dev, sdio_event_t eventset)
static ubyte stm32_eventwait(FAR struct sdio_dev_s *dev, uint32 timeout)
{
- ubyte wkupevents = 0;
+ struct stm32_dev_s *priv = (struct stm32_dev_s*)dev;
+ ubyte wkupevent = 0;
DEBUGASSERT(priv->waitevents != 0);
@@ -1155,10 +1551,10 @@ static ubyte stm32_eventwait(FAR struct sdio_dev_s *dev, uint32 timeout)
/* Check if the event has occurred. */
- wkupevents = (ubyte)(priv->wkupevents & priv->waitevents)
- if (wkupevents != 0)
+ wkupevent = (ubyte)(priv->wkupevent & priv->waitevents);
+ if (wkupevent != 0)
{
- /* Yes... break out of the loop with wkupevents non-zero */
+ /* Yes... break out of the loop with wkupevent non-zero */
break;
}
@@ -1167,19 +1563,19 @@ static ubyte stm32_eventwait(FAR struct sdio_dev_s *dev, uint32 timeout)
/* Clear all enabled wait events before returning */
priv->waitevents = 0;
- priv->wkupevents = 0;
- return wkupevents;
+ priv->wkupevent = 0;
+ return wkupevent;
}
/****************************************************************************
* Name: stm32_events
*
* Description:
- * Return the current event set. This supports polling for MMC/SD (vs.
+ * Return the current event set. This supports polling for SDIO (vs.
* waiting). Only enabled events need be reported.
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
+ * dev - An instance of the SDIO device interface
*
* Returned Value:
* Event set containing the current events (All pending events are cleared
@@ -1196,7 +1592,7 @@ static ubyte stm32_events(FAR struct sdio_dev_s *dev)
* Name: stm32_callbackenable
*
* Description:
- * Enable/disable of a set of MMC/SD callback events. This is part of the
+ * Enable/disable of a set of SDIO callback events. This is part of the
* the SDIO callback sequence. The set of events is configured to enabled
* callbacks to the function provided in stm32_registercallback.
*
@@ -1205,7 +1601,7 @@ static ubyte stm32_events(FAR struct sdio_dev_s *dev)
* calling this methos.
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
+ * dev - An instance of the SDIO device interface
* eventset - A bitset of events to enable or disable (see SDIOMEDIA_*
* definitions). 0=disable; 1=enable.
*
@@ -1214,7 +1610,8 @@ static ubyte stm32_events(FAR struct sdio_dev_s *dev)
*
****************************************************************************/
-static void stm32_callbackenable(FAR struct sdio_dev_s *dev, sdio_event_t eventset)
+static void stm32_callbackenable(FAR struct sdio_dev_s *dev,
+ sdio_eventset_t eventset)
{
struct stm32_dev_s *priv = (struct stm32_dev_s*)dev;
DEBUGASSERT(priv != NULL);
@@ -1265,7 +1662,7 @@ static int stm32_registercallback(FAR struct sdio_dev_s *dev,
* Return TRUE if the hardware can support DMA
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
+ * dev - An instance of the SDIO device interface
*
* Returned Value:
* TRUE if DMA is supported.
@@ -1280,7 +1677,7 @@ static boolean stm32_dmasupported(FAR struct sdio_dev_s *dev)
#endif
/****************************************************************************
- * Name: stm32_dmareadsetup
+ * Name: stm32_dmarecvsetup
*
* Description:
* Setup to perform a read DMA. If the processor supports a data cache,
@@ -1289,7 +1686,7 @@ static boolean stm32_dmasupported(FAR struct sdio_dev_s *dev)
* invalidating the data cache.
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
+ * dev - An instance of the SDIO device interface
* buffer - The memory to DMA from
* buflen - The size of the DMA transfer in bytes
*
@@ -1299,20 +1696,49 @@ static boolean stm32_dmasupported(FAR struct sdio_dev_s *dev)
****************************************************************************/
#ifdef CONFIG_SDIO_DMA
-static int tm32_dmareadsetup(FAR struct sdio_dev_s *dev, FAR ubyte *buffer, size_t buflen)
+static int stm32_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR ubyte *buffer,
+ size_t buflen)
{
- /* Configure the RX DMA */
+ struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
+ uint32 dblocksize;
+ int ret = -EINVAL;
+
+ DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0);
+ DEBUGASSERT(((uint32)buffer & 3) == 0);
- stm32_enableint(SDIO_MASK_DCRCFAILIE|SDIO_MASK_DTIMEOUTIE|SDIO_MASK_DATAENDIE|
- SDIO_MASK_RXOVERRIE|SDIO_MASK_STBITERRIE);
- putreg32(1, SDIO_DCTRL_DMAEN_BB)
- stm32_dmasetup(priv->dma, STM32_SDIO_FIFO, (uint32)buffer,
- (buflen + 3) >> 2, SDIO_RXDMA16_CONFIG);
+ /* Wide bus operation is required for DMA */
+
+ if (priv->widebus)
+ {
+ /* Save the destination buffer information for use by the interrupt handler */
+
+ priv->buffer = (uint32*)buffer;
+ priv->remaining = buflen;
+ priv->result = -EBUSY;
+ priv->dmamode = TRUE;
+
+ /* Then set up the SDIO data path */
+
+ dblocksize = stm32_log2(buflen) << SDIO_DCTRL_DBLOCKSIZE_SHIFT;
+ stm32_dataconfig(SDIO_DTIMER_DATATIMEOUT, buflen, dblocksize|SDIO_DCTRL_DTDIR);
+
+ /* Configure the RX DMA */
+
+ stm32_enableint(SDIO_MASK_DCRCFAILIE|SDIO_MASK_DTIMEOUTIE|
+ SDIO_MASK_DATAENDIE|SDIO_MASK_RXOVERRIE|
+ SDIO_MASK_STBITERRIE);
+
+ putreg32(1, SDIO_DCTRL_DMAEN_BB);
+ stm32_dmasetup(priv->dma, STM32_SDIO_FIFO, (uint32)buffer,
+ (buflen + 3) >> 2, SDIO_RXDMA16_CONFIG);
+ ret = OK;
+ }
+ return ret;
}
#endif
/****************************************************************************
- * Name: stm32_dmawritesetup
+ * Name: stm32_dmasendsetup
*
* Description:
* Setup to perform a write DMA. If the processor supports a data cache,
@@ -1321,7 +1747,7 @@ static int tm32_dmareadsetup(FAR struct sdio_dev_s *dev, FAR ubyte *buffer, siz
* flushing the data cache.
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
+ * dev - An instance of the SDIO device interface
* buffer - The memory to DMA into
* buflen - The size of the DMA transfer in bytes
*
@@ -1331,27 +1757,57 @@ static int tm32_dmareadsetup(FAR struct sdio_dev_s *dev, FAR ubyte *buffer, siz
****************************************************************************/
#ifdef CONFIG_SDIO_DMA
-static int stm32_dmawritesetup(FAR struct sdio_dev_s *dev,
+static int stm32_dmasendsetup(FAR struct sdio_dev_s *dev,
FAR const ubyte *buffer, size_t buflen)
{
- /* Configure the TX DMA */
+ struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
+ uint32 dblocksize;
+ int ret = -EINVAL;
+
+ DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0);
+ DEBUGASSERT(((uint32)buffer & 3) == 0);
+
+ /* Wide bus operation is required for DMA */
- stm32_enableint(SDIO_MASK_DCRCFAILIE|SDIO_MASK_DTIMEOUTIE|SDIO_MASK_DATAENDIE|
- SDIO_MASK_TXUNDERRIE|SDIO_MASK_STBITERRIE);
- stm32_dmasetup(priv->dma, STM32_SDIO_FIFO, (uint32)buffer,
- (buflen + 3) >> 2, SDIO_TXDMA16_CONFIG);
- putreg32(1, SDIO_DCTRL_DMAEN_BB)
+ if (priv->widebus)
+ {
+ /* Save the source buffer information for use by the interrupt handler */
+
+ priv->buffer = (uint32*)buffer;
+ priv->remaining = buflen;
+ priv->result = -EBUSY;
+ priv->dmamode = TRUE;
+
+ /* Then set up the SDIO data path */
+
+ dblocksize = stm32_log2(buflen) << SDIO_DCTRL_DBLOCKSIZE_SHIFT;
+ stm32_dataconfig(SDIO_DTIMER_DATATIMEOUT, buflen, dblocksize);
+
+ /* Enable TX interrrupts */
+
+ stm32_enableint(SDIO_MASK_DCRCFAILIE|SDIO_MASK_DTIMEOUTIE|
+ SDIO_MASK_DATAENDIE|SDIO_MASK_TXUNDERRIE|
+ SDIO_MASK_STBITERRIE);
+
+ /* Configure the TX DMA */
+
+ stm32_dmasetup(priv->dma, STM32_SDIO_FIFO, (uint32)buffer,
+ (buflen + 3) >> 2, SDIO_TXDMA16_CONFIG);
+ putreg32(1, SDIO_DCTRL_DMAEN_BB);
+ ret = OK;
+ }
+ return ret;
}
#endif
/****************************************************************************
- * Name: stm32_dmastart
+ * Name: stm32_sdiodmastart
*
* Description:
* Start the DMA
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
+ * dev - An instance of the SDIO device interface
*
* Returned Value:
* OK on success; a negated errno on failure
@@ -1359,42 +1815,11 @@ static int stm32_dmawritesetup(FAR struct sdio_dev_s *dev,
****************************************************************************/
#ifdef CONFIG_SDIO_DMA
-static int stm32_dmastart(FAR struct sdio_dev_s *dev)
+static int stm32_sdiodmastart(FAR struct sdio_dev_s *dev)
{
- stm32_dmastart(priv->dma, sdio_dmacallback, priv, FALSE);
-}
-#endif
-
-/****************************************************************************
- * Name: stm32_dmastatus
- *
- * Description:
- * Return the number of bytes remaining in the DMA transfer
- *
- * Input Parameters:
- * dev - An instance of the MMC/SD device interface
- * remaining - A pointer to location in which to return the number of bytes
- * remaining in the transfer.
- *
- * Returned Value:
- * OK on success; a negated errno on failure
- *
- ****************************************************************************/
-
-#ifdef CONFIG_SDIO_DMA
-static int stm32_dmastatus(FAR struct sdio_dev_s *dev, size_t *remaining)
-{
-#ifdef CONFIG_DEBUG
- if (remaining)
- {
- *remaining = getreg32(STM32_SDIO_DCOUNT);
- return OK;
- }
- return -EINVAL;
-#else
- *remaining = getreg32(STM32_SDIO_DCOUNT);
- return OK;
-#endif
+ struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
+ stm32_dmastart(priv->dma, stm32_dmacallback, priv, FALSE);
+ return OK;
}
#endif
@@ -1497,7 +1922,7 @@ static void stm32_default(void)
*
****************************************************************************/
-FAR sdio_dev_s *mmcsd_slotinitialize(int slotno)
+FAR struct sdio_dev_s *sdio_initialize(int slotno)
{
/* There is only one, slot */
@@ -1505,7 +1930,7 @@ FAR sdio_dev_s *mmcsd_slotinitialize(int slotno)
/* Initialize the SDIO slot structure */
- sem_init(&priv->eventsem, 0, 0);
+ sem_init(&priv->waitsem, 0, 0);
/* Allocate a DMA channel */
@@ -1532,7 +1957,7 @@ FAR sdio_dev_s *mmcsd_slotinitialize(int slotno)
stm32_setclkcr(STM32_CLCKCR_INIT);
stm32_setpwrctrl(SDIO_POWER_PWRCTRL_ON);
- stm32_clkenable(ENABLE);
+ stm32_clkenable();
return &g_sdiodev.dev;
}
diff --git a/nuttx/arch/arm/src/stm32/stm32_sdio.h b/nuttx/arch/arm/src/stm32/stm32_sdio.h
index d276be8cf..977b428d5 100755
--- a/nuttx/arch/arm/src/stm32/stm32_sdio.h
+++ b/nuttx/arch/arm/src/stm32/stm32_sdio.h
@@ -224,8 +224,8 @@
#define SDIO_DATACOUNT_SHIFT (0)
#define SDIO_DATACOUNT_MASK (0x01ffffff << SDIO_DATACOUNT_SHIFT)
-#define SDIO_STA_CCRCFAIL (1 << 0) /* Bit 0: Command response received (CRC fail) */
-#define SDIO_STA_DCRCFAIL (1 << 1) /* Bit 1: Data block sent/received */
+#define SDIO_STA_CCRCFAIL (1 << 0) /* Bit 0: Command response CRC fail */
+#define SDIO_STA_DCRCFAIL (1 << 1) /* Bit 1: Data block CRC fail */
#define SDIO_STA_CTIMEOUT (1 << 2) /* Bit 2: Command response timeout */
#define SDIO_STA_DTIMEOUT (1 << 3) /* Bit 3: Data timeout */
#define SDIO_STA_TXUNDERR (1 << 4) /* Bit 4: Transmit FIFO underrun error */
diff --git a/nuttx/drivers/mmcsd/mmcsd_sdio.c b/nuttx/drivers/mmcsd/mmcsd_sdio.c
index 76663c8c5..cd32e1dae 100644
--- a/nuttx/drivers/mmcsd/mmcsd_sdio.c
+++ b/nuttx/drivers/mmcsd/mmcsd_sdio.c
@@ -366,9 +366,9 @@ static int mmcsd_getSCR(struct mmcsd_state_s *priv, uint32 scr[2])
return ret;
}
- /* Setup up to receive data */
+ /* Setup up to receive data with interrupt mode */
- SDIO_RECVSETUP(priv->dev, 8);
+ SDIO_RECVSETUP(priv->dev, (FAR ubyte*)scr, 8);
/* Send ACMD51 SD_APP_SEND_SCR with argument as 0 to start data receipt */
@@ -381,21 +381,14 @@ static int mmcsd_getSCR(struct mmcsd_state_s *priv, uint32 scr[2])
return ret;
}
- /* Wait for data available */
+ /* Wait for data to be transferred */
ret = SDIO_EVENTWAIT(priv->dev, MMCSD_SCR_DATADELAY);
if (ret != OK)
{
fdbg("ERROR: WAITEVENT for READ DATA failed: %d\n", ret);
- return ret;
}
-
- /* Receive the SCR data from the SD card. Card data is sent big-endian;
- * if we are running on a little-endian machine, then we need to swap
- * some bytes (should this be a configuration option?)
- */
-
- return SDIO_RECVDATA(priv->dev, (FAR ubyte *)scr);
+ return ret;
}
/****************************************************************************
diff --git a/nuttx/include/nuttx/sdio.h b/nuttx/include/nuttx/sdio.h
index cf3470585..490128180 100755
--- a/nuttx/include/nuttx/sdio.h
+++ b/nuttx/include/nuttx/sdio.h
@@ -47,7 +47,7 @@
* Pre-Processor Definitions
****************************************************************************/
-/* MMC/SD events needed by the driver
+/* SDIO events needed by the driver
*
* Wait events are used for event-waiting by SDIO_WAITENABLE and SDIO_EVENTWAIT
*/
@@ -290,10 +290,10 @@
* Name: SDIO_RESET
*
* Description:
- * Reset the MMC/SD controller. Undo all setup and initialization.
+ * Reset the SDIO controller. Undo all setup and initialization.
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
+ * dev - An instance of the SDIO device interface
*
* Returned Value:
* None
@@ -306,7 +306,7 @@
* Name: SDIO_STATUS
*
* Description:
- * Get MMC/SD status.
+ * Get SDIO status.
*
* Input Parameters:
* dev - Device-specific state data
@@ -318,10 +318,10 @@
#define SDIO_STATUS(dev) ((dev)->status(dev))
-/* MMC/SD status bits */
+/* SDIO status bits */
-#define SDIO_STATUS_PRESENT 0x01 /* Bit 0=1: MMC/SD card present */
-#define SDIO_STATUS_WRPROTECTED 0x02 /* Bit 1=1: MMC/SD card write protected */
+#define SDIO_STATUS_PRESENT 0x01 /* Bit 0=1: SDIO card present */
+#define SDIO_STATUS_WRPROTECTED 0x02 /* Bit 1=1: SDIO card write protected */
#define SDIO_PRESENT(dev) ((SDIO_STATUS(dev) & SDIO_STATUS_PRESENT) != 0)
#define SDIO_WRPROTECTED(dev) ((SDIO_STATUS(dev) & SDIO_STATUS_WRPROTECTED) != 0)
@@ -335,7 +335,7 @@
* correctly in the new bus mode.
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
+ * dev - An instance of the SDIO device interface
* wide - TRUE: wide bus (4-bit) bus mode enabled
*
* Returned Value:
@@ -349,10 +349,10 @@
* Name: SDIO_CLOCK
*
* Description:
- * Enable/disable MMC/SD clocking
+ * Enable/disable SDIO clocking
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
+ * dev - An instance of the SDIO device interface
* rate - Specifies the clocking to use (see enum sdio_clock_e)
*
* Returned Value:
@@ -369,7 +369,7 @@
* Attach and prepare interrupts
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
+ * dev - An instance of the SDIO device interface
*
* Returned Value:
* OK on success; A negated errno on failure.
@@ -382,10 +382,10 @@
* Name: SDIO_SENDCMD
*
* Description:
- * Send the MMC/SD command
+ * Send the SDIO command
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
+ * dev - An instance of the SDIO device interface
* cmd - The command to send. See 32-bit command definitions above.
* arg - 32-bit argument required with some commands
* data - A reference to data required with some commands
@@ -398,16 +398,19 @@
#define SDIO_SENDCMD(dev,cmd,arg) ((dev)->sendcmd(dev,cmd,arg))
/****************************************************************************
- * Name: SDIO_SENDSETUP
+ * Name: SDIO_RECVSETUP
*
* Description:
- * Setup hardware in preparation for data trasfer from the card. This method
- * will do whatever controller setup is necessary. This would be called
- * for SD memory just AFTER sending CMD24 (WRITE_BLOCK), CMD25
- * (WRITE_MULTIPLE_BLOCK), ... and before SDIO_SENDDATA is called.
+ * Setup hardware in preparation for data trasfer from the card in non-DMA
+ * (interrupt driven mode). This method will do whatever controller setup
+ * is necessary. This would be called for SD memory just BEFORE sending
+ * CMD13 (SEND_STATUS), CMD17 (READ_SINGLE_BLOCK), CMD18
+ * (READ_MULTIPLE_BLOCKS), ACMD51 (SEND_SCR), etc. Normally, SDIO_WAITEVENT
+ * will be called to receive the indication that the transfer is complete.
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
+ * dev - An instance of the SDIO device interface
+ * buffer - Address of the buffer in which to receive the data
* nbytes - The number of bytes in the transfer
*
* Returned Value:
@@ -415,24 +418,28 @@
*
****************************************************************************/
-#define SDIO_SENDSETUP(dev,nbytes) ((dev)->sendsetup(dev,nbytes))
+#define SDIO_RECVSETUP(dev,buffer,nbytes) ((dev)->recvsetup(dev,buffer,nbytes))
/****************************************************************************
- * Name: SDIO_SENDDATA
+ * Name: SDIO_SENDSETUP
*
* Description:
- * Send more MMC/SD data
+ * Setup hardware in preparation for data trasfer from the card. This method
+ * will do whatever controller setup is necessary. This would be called
+ * for SD memory just AFTER sending CMD24 (WRITE_BLOCK), CMD25
+ * (WRITE_MULTIPLE_BLOCK), ... and before SDIO_SENDDATA is called.
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
- * data - Data to be sent
+ * dev - An instance of the SDIO device interface
+ * buffer - Address of the buffer containing the data to send
+ * nbytes - The number of bytes in the transfer
*
* Returned Value:
* Number of bytes sent on success; a negated errno on failure
*
****************************************************************************/
-#define SDIO_SENDDATA(dev,data) ((dev)->senddata(dev,data))
+#define SDIO_SENDSETUP(dev,buffer,nbytes) ((dev)->sendsetup(dev,buffer,nbytes))
/****************************************************************************
* Name: SDIO_WAITRESPONSE
@@ -441,7 +448,7 @@
* Poll-wait for the response to the last command to be ready.
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
+ * dev - An instance of the SDIO device interface
* cmd - The command that was sent. See 32-bit command definitions above.
*
* Returned Value:
@@ -455,13 +462,13 @@
* Name: SDIO_RECVRx
*
* Description:
- * Receive response to MMC/SD command. Only the critical payload is
+ * Receive response to SDIO command. Only the critical payload is
* returned -- that is 32 bits for 48 bit status and 128 bits for 136 bit
* status. The driver implementation should verify the correctness of
* the remaining, non-returned bits (CRCs, CMD index, etc.).
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
+ * dev - An instance of the SDIO device interface
* Rx - Buffer in which to receive the response
*
* Returned Value:
@@ -482,48 +489,10 @@
#define SDIO_RECVR7(dev,cmd,R7) ((dev)->recvR7(dev,cmd,R7)) /* 48-bit */
/****************************************************************************
- * Name: SDIO_RECVSETUP
- *
- * Description:
- * Setup hardware in preparation for data trasfer from the card. This method
- * will do whatever controller setup is necessary. This would be called
- * for SD memory just BEFORE sending CMD13 (SEND_STATUS), CMD17
- * (READ_SINGLE_BLOCK), CMD18 (READ_MULTIPLE_BLOCKS), ACMD51 (SEND_SCR), ...
- * and before SDIO_RECVDATA is called.
- *
- * Input Parameters:
- * dev - An instance of the MMC/SD device interface
- * nbytes - The number of bytes in the transfer
- *
- * Returned Value:
- * Number of bytes sent on success; a negated errno on failure
- *
- ****************************************************************************/
-
-#define SDIO_RECVSETUP(dev,nbytes) ((dev)->recvsetup(dev,nbytes))
-
-/****************************************************************************
- * Name: SDIO_RECVDATA
- *
- * Description:
- * Receive data from MMC/SD
- *
- * Input Parameters:
- * dev - An instance of the MMC/SD device interface
- * buffer - Buffer in which to receive the data
- *
- * Returned Value:
- * Number of bytes sent on success; a negated errno on failure
- *
- ****************************************************************************/
-
-#define SDIO_RECVDATA(dev,buffer) ((dev)->recvdata(dev,buffer))
-
-/****************************************************************************
* Name: SDIO_WAITENABLE
*
* Description:
- * Enable/disable of a set of MMC/SD wait events. This is part of the
+ * Enable/disable of a set of SDIO wait events. This is part of the
* the SDIO_WAITEVENT sequence. The set of to-be-waited-for events is
* configured before calling SDIO_EVENTWAIT. This is done in this way
* to help the driver to eliminate race conditions between the command
@@ -534,7 +503,7 @@
* returns.
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
+ * dev - An instance of the SDIO device interface
* eventset - A bitset of events to enable or disable (see SDIOWAIT_*
* definitions). 0=disable; 1=enable.
*
@@ -555,7 +524,7 @@
* can be used again.
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
+ * dev - An instance of the SDIO device interface
* timeout - Maximum time in milliseconds to wait. Zero means no timeout.
*
* Returned Value:
@@ -571,11 +540,11 @@
* Name: SDIO_EVENTS
*
* Description:
- * Return the current event set. This supports polling for MMC/SD (vs.
+ * Return the current event set. This supports polling for SDIO (vs.
* waiting). Only enabled events need be reported.
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
+ * dev - An instance of the SDIO device interface
*
* Returned Value:
* Event set containing the current events (All pending events are cleared
@@ -589,7 +558,7 @@
* Name: SDIO_CALLBACKENABLE
*
* Description:
- * Enable/disable of a set of MMC/SD callback events. This is part of the
+ * Enable/disable of a set of SDIO callback events. This is part of the
* the SDIO callback sequence. The set of events is configured to enabled
* callbacks to the function provided in SDIO_REGISTERCALLBACK.
*
@@ -598,7 +567,7 @@
* calling this methos.
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
+ * dev - An instance of the SDIO device interface
* eventset - A bitset of events to enable or disable (see SDIOMEDIA_*
* definitions). 0=disable; 1=enable.
*
@@ -640,7 +609,7 @@
* Return TRUE if the hardware can support DMA
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
+ * dev - An instance of the SDIO device interface
*
* Returned Value:
* TRUE if DMA is supported.
@@ -654,7 +623,7 @@
#endif
/****************************************************************************
- * Name: SDIO_DMAREADSETUP
+ * Name: SDIO_DMARECVSETUP
*
* Description:
* Setup to perform a read DMA. If the processor supports a data cache,
@@ -663,7 +632,7 @@
* invalidating the data cache.
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
+ * dev - An instance of the SDIO device interface
* buffer - The memory to DMA from
* buflen - The size of the DMA transfer in bytes
*
@@ -673,13 +642,13 @@
****************************************************************************/
#ifdef CONFIG_SDIO_DMA
-# define SDIO_DMAREADSETUP(dev,buffer,len) ((dev)->dmareadsetup(dev,buffer,len))
+# define SDIO_DMARECVSETUP(dev,buffer,len) ((dev)->dmarecvsetup(dev,buffer,len))
#else
-# define SDIO_DMAREADSETUP(dev,buffer,len) (-ENOSYS)
+# define SDIO_DMARECVSETUP(dev,buffer,len) (-ENOSYS)
#endif
/****************************************************************************
- * Name: SDIO_DMAWRITESETUP
+ * Name: SDIO_DMASENDSETUP
*
* Description:
* Setup to perform a write DMA. If the processor supports a data cache,
@@ -688,7 +657,7 @@
* flushing the data cache.
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
+ * dev - An instance of the SDIO device interface
* buffer - The memory to DMA into
* buflen - The size of the DMA transfer in bytes
*
@@ -698,9 +667,9 @@
****************************************************************************/
#ifdef CONFIG_SDIO_DMA
-# define SDIO_DMAWRITESETUP(dev,buffer,len) ((dev)->dmawritesetup(dev,buffer,len))
+# define SDIO_DMASENDSETUP(dev,buffer,len) ((dev)->dmasendsetup(dev,buffer,len))
#else
-# define SDIO_DMAWRITESETUP(dev,buffer,len) (-ENOSYS)
+# define SDIO_DMASENDSETUP(dev,buffer,len) (-ENOSYS)
#endif
/****************************************************************************
@@ -710,7 +679,7 @@
* Start the DMA
*
* Input Parameters:
- * dev - An instance of the MMC/SD device interface
+ * dev - An instance of the SDIO device interface
*
* Returned Value:
* OK on success; a negated errno on failure
@@ -724,28 +693,6 @@
#endif
/****************************************************************************
- * Name: SDIO_DMASTATUS
- *
- * Description:
- * Return the number of bytes remaining in the DMA transfer
- *
- * Input Parameters:
- * dev - An instance of the MMC/SD device interface
- * remaining - A pointer to location in which to return the number of bytes
- * remaining in the transfer.
- *
- * Returned Value:
- * OK on success; a negated errno on failure
- *
- ****************************************************************************/
-
-#ifdef CONFIG_SDIO_DMA
-# define SDIO_DMASTATUS(dev,remaining) ((dev)->dmastatus(dev,remaining))
-#else
-# define SDIO_DMASTATUS(dev,remaining) (-ENOSYS)
-#endif
-
-/****************************************************************************
* Public Types
****************************************************************************/
@@ -753,7 +700,7 @@
typedef void (*sdio_mediachange_t)(FAR void *arg);
-/* Various clocking used by the MMC/SD driver */
+/* Various clocking used by the SDIO driver */
enum sdio_clock_e
{
@@ -770,11 +717,11 @@ enum sdio_clock_e
typedef ubyte sdio_eventset_t;
-/* This structure defines the interface between the NuttX MMC/SD
- * driver and the chip- or board-specific MMC/SD interface. This
+/* This structure defines the interface between the NuttX SDIO
+ * driver and the chip- or board-specific SDIO interface. This
* interface is only used in architectures that support SDIO
- * 1- or 4-bit data busses. For MMC/SD support this interface is
- * registered with the NuttX MMC/SD driver by calling
+ * 1- or 4-bit data busses. For SDIO support this interface is
+ * registered with the NuttX SDIO driver by calling
* sdio_slotinitialize().
*/
@@ -795,8 +742,10 @@ struct sdio_dev_s
/* Command/Status/Data Transfer */
void (*sendcmd)(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 arg);
- int (*sendsetup)(FAR struct sdio_dev_s *dev, uint32 nbytes);
- int (*senddata)(FAR struct sdio_dev_s *dev, FAR const ubyte *buffer);
+ int (*recvsetup)(FAR struct sdio_dev_s *dev, FAR ubyte *buffer,
+ size_t nbytes);
+ int (*sendsetup)(FAR struct sdio_dev_s *dev, FAR const ubyte *buffer,
+ size_t nbytes);
int (*waitresponse)(FAR struct sdio_dev_s *dev, uint32 cmd);
int (*recvR1)(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 *R1);
@@ -806,26 +755,24 @@ struct sdio_dev_s
int (*recvR5)(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 *R5);
int (*recvR6)(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 *R6);
int (*recvR7)(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 *R7);
- int (*recvsetup)(FAR struct sdio_dev_s *dev, uint32 nbytes);
- int (*recvdata)(FAR struct sdio_dev_s *dev, FAR ubyte *buffer);
/* EVENT handler */
void (*waitenable)(FAR struct sdio_dev_s *dev, sdio_eventset_t eventset);
ubyte (*eventwait)(FAR struct sdio_dev_s *dev, uint32 timeout);
ubyte (*events)(FAR struct sdio_dev_s *dev);
+ void (*callbackenable)(FAR struct sdio_dev_s *dev, sdio_eventset_t eventset);
int (*registercallback)(FAR struct sdio_dev_s *dev, sdio_mediachange_t callback, void *arg);
/* DMA */
#ifdef CONFIG_SDIO_DMA
boolean (*dmasupported)(FAR struct sdio_dev_s *dev);
- int (*dmareadsetup)(FAR struct sdio_dev_s *dev, FAR ubyte *buffer,
+ int (*dmarecvsetup)(FAR struct sdio_dev_s *dev, FAR ubyte *buffer,
size_t buflen);
- int (*dmawritesetup)(FAR struct sdio_dev_s *dev, FAR const ubyte *buffer,
+ int (*dmasendsetup)(FAR struct sdio_dev_s *dev, FAR const ubyte *buffer,
size_t buflen);
int (*dmastart)(FAR struct sdio_dev_s *dev);
- int (*dmastatus)(FAR struct sdio_dev_s *dev, size_t *remaining);
#endif
};