Kinetis lpc sdcard (#719)

* Check return of nxsem_wait_uninterruptible
* Fix nxstyle reported errors

Note: It will not pass on CI tests because of it:

    .recvR1           = lpc17_40_recvshortcrc,
    .recvR2           = lpc17_40_recvlong,
    .recvR3           = lpc17_40_recvshort,
    .recvR4           = lpc17_40_recvnotimpl,
    .recvR5           = lpc17_40_recvnotimpl,
    .recvR6           = lpc17_40_recvshortcrc,
    .recvR7           = lpc17_40_recvshort,
This commit is contained in:
Alan Carvalho de Assis 2020-04-03 23:25:14 -03:00 committed by Gregory Nutt
parent df1eeb8e3f
commit 460124629c

View File

@ -74,6 +74,7 @@
****************************************************************************/ ****************************************************************************/
/* Configuration ************************************************************/ /* Configuration ************************************************************/
/* Required system configuration options: /* Required system configuration options:
* *
* CONFIG_ARCH_DMA - Enable architecture-specific DMA subsystem * CONFIG_ARCH_DMA - Enable architecture-specific DMA subsystem
@ -87,9 +88,10 @@
* CONFIG_SDIO_MUXBUS - Setting this configuration enables some locking * CONFIG_SDIO_MUXBUS - Setting this configuration enables some locking
* APIs to manage concurrent accesses on the SD card bus. This is not * APIs to manage concurrent accesses on the SD card bus. This is not
* needed for the simple case of a single SD card, for example. * needed for the simple case of a single SD card, for example.
* CONFIG_LPC17_40_SDCARD_DMA - Enable SD card DMA. This is a marginally optional. * CONFIG_LPC17_40_SDCARD_DMA - Enable SD card DMA. This is a marginally
* For most usages, SD accesses will cause data overruns if used without DMA. * optional.
* NOTE the above system DMA configuration options. * For most usages, SD accesses will cause data overruns if used without
* DMA. NOTE the above system DMA configuration options.
* CONFIG_LPC17_40_SDCARD_WIDTH_D1_ONLY - This may be selected to force the * CONFIG_LPC17_40_SDCARD_WIDTH_D1_ONLY - This may be selected to force the
* driver operate with only a single data line (the default is to use * driver operate with only a single data line (the default is to use
* all 4 SD data lines). * all 4 SD data lines).
@ -239,6 +241,7 @@ struct lpc17_40_dev_s
struct sdio_dev_s dev; /* Standard, base SD card interface */ struct sdio_dev_s dev; /* Standard, base SD card interface */
/* LPC17XX_40XX-specific extensions */ /* LPC17XX_40XX-specific extensions */
/* Event support */ /* Event support */
sem_t waitsem; /* Implements event waiting */ sem_t waitsem; /* Implements event waiting */
@ -302,12 +305,14 @@ struct lpc17_40_sampleregs_s
/* Low-level helpers ********************************************************/ /* Low-level helpers ********************************************************/
static void lpc17_40_takesem(struct lpc17_40_dev_s *priv); static int lpc17_40_takesem(struct lpc17_40_dev_s *priv);
#define lpc17_40_givesem(priv) (nxsem_post(&priv->waitsem)) #define lpc17_40_givesem(priv) (nxsem_post(&priv->waitsem))
static inline void lpc17_40_setclock(uint32_t clkcr); static inline void lpc17_40_setclock(uint32_t clkcr);
static void lpc17_40_configwaitints(struct lpc17_40_dev_s *priv, uint32_t waitmask, static void lpc17_40_configwaitints(struct lpc17_40_dev_s *priv,
sdio_eventset_t waitevents, sdio_eventset_t wkupevents); uint32_t waitmask, sdio_eventset_t waitevents,
static void lpc17_40_configxfrints(struct lpc17_40_dev_s *priv, uint32_t xfrmask); sdio_eventset_t wkupevents);
static void lpc17_40_configxfrints(struct lpc17_40_dev_s *priv,
uint32_t xfrmask);
static void lpc17_40_setpwrctrl(uint32_t pwrctrl); static void lpc17_40_setpwrctrl(uint32_t pwrctrl);
static inline uint32_t lpc17_40_getpwrctrl(void); static inline uint32_t lpc17_40_getpwrctrl(void);
@ -317,7 +322,8 @@ static inline uint32_t lpc17_40_getpwrctrl(void);
static void lpc17_40_sampleinit(void); static void lpc17_40_sampleinit(void);
static void lpc17_40_sdcard_sample(struct lpc17_40_sdcard_regs_s *regs); static void lpc17_40_sdcard_sample(struct lpc17_40_sdcard_regs_s *regs);
static void lpc17_40_sample(struct lpc17_40_dev_s *priv, int index); static void lpc17_40_sample(struct lpc17_40_dev_s *priv, int index);
static void lpc17_40_sdcard_dump(struct lpc17_40_sdcard_regs_s *regs, const char *msg); static void lpc17_40_sdcard_dump(struct lpc17_40_sdcard_regs_s *regs,
const char *msg);
static void lpc17_40_dumpsample(struct lpc17_40_dev_s *priv, static void lpc17_40_dumpsample(struct lpc17_40_dev_s *priv,
struct lpc17_40_sampleregs_s *regs, const char *msg); struct lpc17_40_sampleregs_s *regs, const char *msg);
static void lpc17_40_dumpsamples(struct lpc17_40_dev_s *priv); static void lpc17_40_dumpsamples(struct lpc17_40_dev_s *priv);
@ -334,13 +340,16 @@ static void lpc17_40_dmacallback(DMA_HANDLE handle, void *arg, int status);
/* Data Transfer Helpers ****************************************************/ /* Data Transfer Helpers ****************************************************/
static uint8_t lpc17_40_log2(uint16_t value); static uint8_t lpc17_40_log2(uint16_t value);
static void lpc17_40_dataconfig(uint32_t timeout, uint32_t dlen, uint32_t dctrl); static void lpc17_40_dataconfig(uint32_t timeout, uint32_t dlen,
uint32_t dctrl);
static void lpc17_40_datadisable(void); static void lpc17_40_datadisable(void);
static void lpc17_40_sendfifo(struct lpc17_40_dev_s *priv); static void lpc17_40_sendfifo(struct lpc17_40_dev_s *priv);
static void lpc17_40_recvfifo(struct lpc17_40_dev_s *priv); static void lpc17_40_recvfifo(struct lpc17_40_dev_s *priv);
static void lpc17_40_eventtimeout(int argc, uint32_t arg); static void lpc17_40_eventtimeout(int argc, uint32_t arg);
static void lpc17_40_endwait(struct lpc17_40_dev_s *priv, sdio_eventset_t wkupevent); static void lpc17_40_endwait(struct lpc17_40_dev_s *priv,
static void lpc17_40_endtransfer(struct lpc17_40_dev_s *priv, sdio_eventset_t wkupevent); sdio_eventset_t wkupevent);
static void lpc17_40_endtransfer(struct lpc17_40_dev_s *priv,
sdio_eventset_t wkupevent);
/* Interrupt Handling *******************************************************/ /* Interrupt Handling *******************************************************/
@ -368,8 +377,8 @@ static int lpc17_40_attach(FAR struct sdio_dev_s *dev);
static int lpc17_40_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd, static int lpc17_40_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd,
uint32_t arg); uint32_t arg);
static int lpc17_40_recvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer, static int lpc17_40_recvsetup(FAR struct sdio_dev_s *dev,
size_t nbytes); FAR uint8_t *buffer, size_t nbytes);
static int lpc17_40_sendsetup(FAR struct sdio_dev_s *dev, static int lpc17_40_sendsetup(FAR struct sdio_dev_s *dev,
FAR const uint8_t *buffer, uint32_t nbytes); FAR const uint8_t *buffer, uint32_t nbytes);
static int lpc17_40_cancel(FAR struct sdio_dev_s *dev); static int lpc17_40_cancel(FAR struct sdio_dev_s *dev);
@ -467,6 +476,7 @@ static struct lpc17_40_sampleregs_s g_sampleregs[DEBUG_NSAMPLES];
/**************************************************************************** /****************************************************************************
* Low-level Helpers * Low-level Helpers
****************************************************************************/ ****************************************************************************/
/**************************************************************************** /****************************************************************************
* Name: lpc17_40_takesem * Name: lpc17_40_takesem
* *
@ -482,9 +492,9 @@ static struct lpc17_40_sampleregs_s g_sampleregs[DEBUG_NSAMPLES];
* *
****************************************************************************/ ****************************************************************************/
static void lpc17_40_takesem(struct lpc17_40_dev_s *priv) static int lpc17_40_takesem(struct lpc17_40_dev_s *priv)
{ {
nxsem_wait_uninterruptible(&priv->waitsem); return nxsem_wait_uninterruptible(&priv->waitsem);
} }
/**************************************************************************** /****************************************************************************
@ -545,7 +555,8 @@ static inline void lpc17_40_setclock(uint32_t clkcr)
* *
****************************************************************************/ ****************************************************************************/
static void lpc17_40_configwaitints(struct lpc17_40_dev_s *priv, uint32_t waitmask, static void lpc17_40_configwaitints(struct lpc17_40_dev_s *priv,
uint32_t waitmask,
sdio_eventset_t waitevents, sdio_eventset_t waitevents,
sdio_eventset_t wkupevent) sdio_eventset_t wkupevent)
{ {
@ -581,7 +592,8 @@ static void lpc17_40_configwaitints(struct lpc17_40_dev_s *priv, uint32_t waitma
* *
****************************************************************************/ ****************************************************************************/
static void lpc17_40_configxfrints(struct lpc17_40_dev_s *priv, uint32_t xfrmask) static void lpc17_40_configxfrints(struct lpc17_40_dev_s *priv,
uint32_t xfrmask)
{ {
irqstate_t flags; irqstate_t flags;
flags = enter_critical_section(); flags = enter_critical_section();
@ -594,8 +606,8 @@ static void lpc17_40_configxfrints(struct lpc17_40_dev_s *priv, uint32_t xfrmask
* Name: lpc17_40_setpwrctrl * Name: lpc17_40_setpwrctrl
* *
* Description: * Description:
* Change the PWRCTRL field of the SD card POWER register to turn the SD card * Change the PWRCTRL field of the SD card POWER register to turn the
* ON or OFF * SD card ON or OFF
* *
* Input Parameters: * Input Parameters:
* clkcr - A new PWRCTRL setting * clkcr - A new PWRCTRL setting
@ -657,7 +669,8 @@ static inline uint32_t lpc17_40_getpwrctrl(void)
#ifdef CONFIG_DEBUG_MEMCARD_INFO #ifdef CONFIG_DEBUG_MEMCARD_INFO
static void lpc17_40_sampleinit(void) static void lpc17_40_sampleinit(void)
{ {
memset(g_sampleregs, 0xff, DEBUG_NSAMPLES * sizeof(struct lpc17_40_sampleregs_s)); memset(g_sampleregs, 0xff, DEBUG_NSAMPLES *
sizeof(struct lpc17_40_sampleregs_s));
} }
#endif #endif
@ -716,7 +729,8 @@ static void lpc17_40_sample(struct lpc17_40_dev_s *priv, int index)
****************************************************************************/ ****************************************************************************/
#ifdef CONFIG_DEBUG_MEMCARD_INFO #ifdef CONFIG_DEBUG_MEMCARD_INFO
static void lpc17_40_sdcard_dump(struct lpc17_40_sdcard_regs_s *regs, const char *msg) static void lpc17_40_sdcard_dump(struct lpc17_40_sdcard_regs_s *regs,
const char *msg)
{ {
mcinfo("SD Card Registers: %s\n", msg); mcinfo("SD Card Registers: %s\n", msg);
mcinfo(" POWER[%08x]: %08x\n", LPC17_40_SDCARD_PWR, regs->pwr); mcinfo(" POWER[%08x]: %08x\n", LPC17_40_SDCARD_PWR, regs->pwr);
@ -741,7 +755,8 @@ static void lpc17_40_sdcard_dump(struct lpc17_40_sdcard_regs_s *regs, const char
#ifdef CONFIG_DEBUG_MEMCARD_INFO #ifdef CONFIG_DEBUG_MEMCARD_INFO
static void lpc17_40_dumpsample(struct lpc17_40_dev_s *priv, static void lpc17_40_dumpsample(struct lpc17_40_dev_s *priv,
struct lpc17_40_sampleregs_s *regs, const char *msg) struct lpc17_40_sampleregs_s *regs,
const char *msg)
{ {
#if defined(CONFIG_DEBUG_DMA) && defined(CONFIG_LPC17_40_SDCARD_DMA) #if defined(CONFIG_DEBUG_DMA) && defined(CONFIG_LPC17_40_SDCARD_DMA)
if (priv->dmamode) if (priv->dmamode)
@ -749,6 +764,7 @@ static void lpc17_40_dumpsample(struct lpc17_40_dev_s *priv,
lpc17_40_dmadump(priv->dma, &regs->dma, msg); lpc17_40_dmadump(priv->dma, &regs->dma, msg);
} }
#endif #endif
lpc17_40_sdcard_dump(&regs->sdcard, msg); lpc17_40_sdcard_dump(&regs->sdcard, msg);
} }
#endif #endif
@ -764,19 +780,25 @@ static void lpc17_40_dumpsample(struct lpc17_40_dev_s *priv,
#ifdef CONFIG_DEBUG_MEMCARD_INFO #ifdef CONFIG_DEBUG_MEMCARD_INFO
static void lpc17_40_dumpsamples(struct lpc17_40_dev_s *priv) static void lpc17_40_dumpsamples(struct lpc17_40_dev_s *priv)
{ {
lpc17_40_dumpsample(priv, &g_sampleregs[SAMPLENDX_BEFORE_SETUP], "Before setup"); lpc17_40_dumpsample(priv, &g_sampleregs[SAMPLENDX_BEFORE_SETUP],
"Before setup");
#if defined(CONFIG_DEBUG_DMA) && defined(CONFIG_LPC17_40_SDCARD_DMA) #if defined(CONFIG_DEBUG_DMA) && defined(CONFIG_LPC17_40_SDCARD_DMA)
if (priv->dmamode) if (priv->dmamode)
{ {
lpc17_40_dumpsample(priv, &g_sampleregs[SAMPLENDX_BEFORE_ENABLE], "Before DMA enable"); lpc17_40_dumpsample(priv, &g_sampleregs[SAMPLENDX_BEFORE_ENABLE],
"Before DMA enable");
} }
#endif #endif
lpc17_40_dumpsample(priv, &g_sampleregs[SAMPLENDX_AFTER_SETUP], "After setup");
lpc17_40_dumpsample(priv, &g_sampleregs[SAMPLENDX_END_TRANSFER], "End of transfer"); lpc17_40_dumpsample(priv, &g_sampleregs[SAMPLENDX_AFTER_SETUP],
"After setup");
lpc17_40_dumpsample(priv, &g_sampleregs[SAMPLENDX_END_TRANSFER],
"End of transfer");
#if defined(CONFIG_DEBUG_DMA) && defined(CONFIG_LPC17_40_SDCARD_DMA) #if defined(CONFIG_DEBUG_DMA) && defined(CONFIG_LPC17_40_SDCARD_DMA)
if (priv->dmamode) if (priv->dmamode)
{ {
lpc17_40_dumpsample(priv, &g_sampleregs[SAMPLENDX_DMA_CALLBACK], "DMA Callback"); lpc17_40_dumpsample(priv, &g_sampleregs[SAMPLENDX_DMA_CALLBACK],
"DMA Callback");
} }
#endif #endif
} }
@ -797,9 +819,9 @@ static void lpc17_40_dmacallback(DMA_HANDLE handle, void *arg, int status)
DEBUGASSERT(priv->dmamode); DEBUGASSERT(priv->dmamode);
sdio_eventset_t result; sdio_eventset_t result;
/* In the normal case, SD card appears to handle the End-Of-Transfer interrupt /* In the normal case, SD card appears to handle the End-Of-Transfer
* first with the End-Of-DMA event occurring significantly later. On * interrupt first with the End-Of-DMA event occurring significantly later.
* transfer errors, however, the DMA error will occur before the End-of- * On transfer errors, however, the DMA error will occur before the End-of-
* Transfer. * Transfer.
*/ */
@ -809,7 +831,8 @@ static void lpc17_40_dmacallback(DMA_HANDLE handle, void *arg, int status)
if (status < 0) if (status < 0)
{ {
dmaerr("ERROR: DMA error %d, remaining: %d\n", status, priv->remaining); dmaerr("ERROR: DMA error %d, remaining: %d\n", status,
priv->remaining);
result = SDIOWAIT_ERROR; result = SDIOWAIT_ERROR;
} }
else else
@ -874,7 +897,8 @@ static uint8_t lpc17_40_log2(uint16_t value)
* *
****************************************************************************/ ****************************************************************************/
static void lpc17_40_dataconfig(uint32_t timeout, uint32_t dlen, uint32_t dctrl) static void lpc17_40_dataconfig(uint32_t timeout, uint32_t dlen,
uint32_t dctrl)
{ {
uint32_t regval = 0; uint32_t regval = 0;
@ -1067,7 +1091,8 @@ static void lpc17_40_eventtimeout(int argc, uint32_t arg)
/* There is always race conditions with timer expirations. */ /* There is always race conditions with timer expirations. */
DEBUGASSERT((priv->waitevents & SDIOWAIT_TIMEOUT) != 0 || priv->wkupevent != 0); DEBUGASSERT((priv->waitevents & SDIOWAIT_TIMEOUT) != 0 ||
priv->wkupevent != 0);
/* Is a data transfer complete event expected? */ /* Is a data transfer complete event expected? */
@ -1098,7 +1123,8 @@ static void lpc17_40_eventtimeout(int argc, uint32_t arg)
* *
****************************************************************************/ ****************************************************************************/
static void lpc17_40_endwait(struct lpc17_40_dev_s *priv, sdio_eventset_t wkupevent) static void lpc17_40_endwait(struct lpc17_40_dev_s *priv,
sdio_eventset_t wkupevent)
{ {
/* Cancel the watchdog timeout */ /* Cancel the watchdog timeout */
@ -1133,7 +1159,8 @@ static void lpc17_40_endwait(struct lpc17_40_dev_s *priv, sdio_eventset_t wkupev
* *
****************************************************************************/ ****************************************************************************/
static void lpc17_40_endtransfer(struct lpc17_40_dev_s *priv, sdio_eventset_t wkupevent) static void lpc17_40_endtransfer(struct lpc17_40_dev_s *priv,
sdio_eventset_t wkupevent)
{ {
/* Disable all transfer related interrupts */ /* Disable all transfer related interrupts */
@ -1153,8 +1180,8 @@ static void lpc17_40_endtransfer(struct lpc17_40_dev_s *priv, sdio_eventset_t wk
lpc17_40_sample(priv, SAMPLENDX_END_TRANSFER); lpc17_40_sample(priv, SAMPLENDX_END_TRANSFER);
/* Make sure that the DMA is stopped (it will be stopped automatically /* Make sure that the DMA is stopped (it will be stopped automatically
* on normal transfers, but not necessarily when the transfer terminates * on normal transfers, but not necessarily when the transfer
* on an error condition). * terminates on an error condition).
*/ */
lpc17_40_dmastop(priv->dma); lpc17_40_dmastop(priv->dma);
@ -1206,7 +1233,8 @@ static int lpc17_40_interrupt(int irq, void *context, FAR void *arg)
* bits remaining, then we have work to do here. * bits remaining, then we have work to do here.
*/ */
while ((enabled = getreg32(LPC17_40_SDCARD_STATUS) & getreg32(LPC17_40_SDCARD_MASK0)) != 0) while ((enabled = getreg32(LPC17_40_SDCARD_STATUS) &
getreg32(LPC17_40_SDCARD_MASK0)) != 0)
{ {
/* Handle in progress, interrupt driven data transfers ****************/ /* Handle in progress, interrupt driven data transfers ****************/
@ -1228,9 +1256,9 @@ static int lpc17_40_interrupt(int irq, void *context, FAR void *arg)
lpc17_40_recvfifo(priv); lpc17_40_recvfifo(priv);
} }
/* Otherwise, Is the transmit FIFO half empty or less? If so we must /* Otherwise, Is the transmit FIFO half empty or less? If so
* be processing a send transaction. NOTE: We can't be processing * we must be processing a send transaction. NOTE: We can't be
* both! * processing both!
*/ */
else if ((pending & SDCARD_STATUS_TXFIFOHE) != 0) else if ((pending & SDCARD_STATUS_TXFIFOHE) != 0)
@ -1293,8 +1321,10 @@ static int lpc17_40_interrupt(int irq, void *context, FAR void *arg)
{ {
/* Terminate the transfer with an error */ /* Terminate the transfer with an error */
mcerr("ERROR: Data block CRC failure, remaining: %d\n", priv->remaining); mcerr("ERROR: Data block CRC failure, remaining: %d\n",
lpc17_40_endtransfer(priv, SDIOWAIT_TRANSFERDONE | SDIOWAIT_ERROR); priv->remaining);
lpc17_40_endtransfer(priv, SDIOWAIT_TRANSFERDONE |
SDIOWAIT_ERROR);
} }
/* Handle data timeout error */ /* Handle data timeout error */
@ -1304,7 +1334,8 @@ static int lpc17_40_interrupt(int irq, void *context, FAR void *arg)
/* Terminate the transfer with an error */ /* Terminate the transfer with an error */
mcerr("ERROR: Data timeout, remaining: %d\n", priv->remaining); mcerr("ERROR: Data timeout, remaining: %d\n", priv->remaining);
lpc17_40_endtransfer(priv, SDIOWAIT_TRANSFERDONE | SDIOWAIT_TIMEOUT); lpc17_40_endtransfer(priv, SDIOWAIT_TRANSFERDONE |
SDIOWAIT_TIMEOUT);
} }
/* Handle RX FIFO overrun error */ /* Handle RX FIFO overrun error */
@ -1313,8 +1344,10 @@ static int lpc17_40_interrupt(int irq, void *context, FAR void *arg)
{ {
/* Terminate the transfer with an error */ /* Terminate the transfer with an error */
mcerr("ERROR: RX FIFO overrun, remaining: %d\n", priv->remaining); mcerr("ERROR: RX FIFO overrun, remaining: %d\n",
lpc17_40_endtransfer(priv, SDIOWAIT_TRANSFERDONE | SDIOWAIT_ERROR); priv->remaining);
lpc17_40_endtransfer(priv, SDIOWAIT_TRANSFERDONE |
SDIOWAIT_ERROR);
} }
/* Handle TX FIFO underrun error */ /* Handle TX FIFO underrun error */
@ -1323,8 +1356,10 @@ static int lpc17_40_interrupt(int irq, void *context, FAR void *arg)
{ {
/* Terminate the transfer with an error */ /* Terminate the transfer with an error */
mcerr("ERROR: TX FIFO underrun, remaining: %d\n", priv->remaining); mcerr("ERROR: TX FIFO underrun, remaining: %d\n",
lpc17_40_endtransfer(priv, SDIOWAIT_TRANSFERDONE | SDIOWAIT_ERROR); priv->remaining);
lpc17_40_endtransfer(priv, SDIOWAIT_TRANSFERDONE |
SDIOWAIT_ERROR);
} }
/* Handle start bit error */ /* Handle start bit error */
@ -1334,7 +1369,8 @@ static int lpc17_40_interrupt(int irq, void *context, FAR void *arg)
/* Terminate the transfer with an error */ /* Terminate the transfer with an error */
mcerr("ERROR: Start bit, remaining: %d\n", priv->remaining); mcerr("ERROR: Start bit, remaining: %d\n", priv->remaining);
lpc17_40_endtransfer(priv, SDIOWAIT_TRANSFERDONE | SDIOWAIT_ERROR); lpc17_40_endtransfer(priv, SDIOWAIT_TRANSFERDONE |
SDIOWAIT_ERROR);
} }
} }
@ -1353,7 +1389,8 @@ static int lpc17_40_interrupt(int irq, void *context, FAR void *arg)
{ {
/* Yes.. wake the thread up */ /* Yes.. wake the thread up */
putreg32(SDCARD_RESPDONE_ICR | SDCARD_CMDDONE_ICR, LPC17_40_SDCARD_CLEAR); putreg32(SDCARD_RESPDONE_ICR | SDCARD_CMDDONE_ICR,
LPC17_40_SDCARD_CLEAR);
lpc17_40_endwait(priv, SDIOWAIT_RESPONSEDONE); lpc17_40_endwait(priv, SDIOWAIT_RESPONSEDONE);
} }
} }
@ -1566,7 +1603,8 @@ static void lpc17_40_widebus(FAR struct sdio_dev_s *dev, bool wide)
* *
****************************************************************************/ ****************************************************************************/
static void lpc17_40_clock(FAR struct sdio_dev_s *dev, enum sdio_clock_e rate) static void lpc17_40_clock(FAR struct sdio_dev_s *dev,
enum sdio_clock_e rate)
{ {
uint32_t clkcr; uint32_t clkcr;
@ -1635,7 +1673,6 @@ static int lpc17_40_attach(FAR struct sdio_dev_s *dev)
ret = irq_attach(LPC17_40_IRQ_MCI, lpc17_40_interrupt, NULL); ret = irq_attach(LPC17_40_IRQ_MCI, lpc17_40_interrupt, NULL);
if (ret == OK) if (ret == OK)
{ {
/* Disable all interrupts at the SD card controller and clear static /* Disable all interrupts at the SD card controller and clear static
* interrupt flags * interrupt flags
*/ */
@ -1669,7 +1706,8 @@ static int lpc17_40_attach(FAR struct sdio_dev_s *dev)
* *
****************************************************************************/ ****************************************************************************/
static int lpc17_40_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t arg) static int lpc17_40_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd,
uint32_t arg)
{ {
uint32_t regval; uint32_t regval;
uint32_t cmdidx; uint32_t cmdidx;
@ -1730,8 +1768,9 @@ static int lpc17_40_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t a
* (interrupt driven mode). This method will do whatever controller setup * (interrupt driven mode). This method will do whatever controller setup
* is necessary. This would be called for SD memory just BEFORE sending * is necessary. This would be called for SD memory just BEFORE sending
* CMD13 (SEND_STATUS), CMD17 (READ_SINGLE_BLOCK), CMD18 * CMD13 (SEND_STATUS), CMD17 (READ_SINGLE_BLOCK), CMD18
* (READ_MULTIPLE_BLOCKS), ACMD51 (SEND_SCR), etc. Normally, SDCARD_WAITEVENT * (READ_MULTIPLE_BLOCKS), ACMD51 (SEND_SCR), etc. Normally,
* will be called to receive the indication that the transfer is complete. * SDCARD_WAITEVENT will be called to receive the indication that the
* transfer is complete.
* *
* Input Parameters: * Input Parameters:
* dev - An instance of the SD card device interface * dev - An instance of the SD card device interface
@ -1743,7 +1782,8 @@ static int lpc17_40_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t a
* *
****************************************************************************/ ****************************************************************************/
static int lpc17_40_recvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer, static int lpc17_40_recvsetup(FAR struct sdio_dev_s *dev,
FAR uint8_t *buffer,
size_t nbytes) size_t nbytes)
{ {
struct lpc17_40_dev_s *priv = (struct lpc17_40_dev_s *)dev; struct lpc17_40_dev_s *priv = (struct lpc17_40_dev_s *)dev;
@ -1783,10 +1823,11 @@ static int lpc17_40_recvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
* Name: lpc17_40_sendsetup * Name: lpc17_40_sendsetup
* *
* Description: * Description:
* Setup hardware in preparation for data transfer from the card. This method * Setup hardware in preparation for data transfer from the card.
* will do whatever controller setup is necessary. This would be called * This method will do whatever controller setup is necessary.
* for SD memory just AFTER sending CMD24 (WRITE_BLOCK), CMD25 * This would be called for SD memory just AFTER sending
* (WRITE_MULTIPLE_BLOCK), ... and before SDCARD_SENDDATA is called. * CMD24 (WRITE_BLOCK), CMD25 (WRITE_MULTIPLE_BLOCK), ... and before
* SDCARD_SENDDATA is called.
* *
* Input Parameters: * Input Parameters:
* dev - An instance of the SD card device interface * dev - An instance of the SD card device interface
@ -1798,7 +1839,8 @@ static int lpc17_40_recvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
* *
****************************************************************************/ ****************************************************************************/
static int lpc17_40_sendsetup(FAR struct sdio_dev_s *dev, FAR const uint8_t *buffer, static int lpc17_40_sendsetup(FAR struct sdio_dev_s *dev,
FAR const uint8_t *buffer,
size_t nbytes) size_t nbytes)
{ {
struct lpc17_40_dev_s *priv = (struct lpc17_40_dev_s *)dev; struct lpc17_40_dev_s *priv = (struct lpc17_40_dev_s *)dev;
@ -1838,9 +1880,9 @@ static int lpc17_40_sendsetup(FAR struct sdio_dev_s *dev, FAR const uint8_t *buf
* *
* Description: * Description:
* Cancel the data transfer setup of SDCARD_RECVSETUP, SDCARD_SENDSETUP, * Cancel the data transfer setup of SDCARD_RECVSETUP, SDCARD_SENDSETUP,
* SDCARD_DMARECVSETUP or SDCARD_DMASENDSETUP. This must be called to cancel * SDCARD_DMARECVSETUP or SDCARD_DMASENDSETUP. This must be called to
* the data transfer setup if, for some reason, you cannot perform the * cancel the data transfer setup if, for some reason, you cannot perform
* transfer. * the transfer.
* *
* Input Parameters: * Input Parameters:
* dev - An instance of the SD card device interface * dev - An instance of the SD card device interface
@ -1875,8 +1917,8 @@ static int lpc17_40_cancel(FAR struct sdio_dev_s *dev)
if (priv->dmamode) if (priv->dmamode)
{ {
/* Make sure that the DMA is stopped (it will be stopped automatically /* Make sure that the DMA is stopped (it will be stopped automatically
* on normal transfers, but not necessarily when the transfer terminates * on normal transfers, but not necessarily when the transfer
* on an error condition. * terminates on an error condition.
*/ */
lpc17_40_dmastop(priv->dma); lpc17_40_dmastop(priv->dma);
@ -1977,7 +2019,8 @@ static int lpc17_40_waitresponse(FAR struct sdio_dev_s *dev, uint32_t cmd)
* *
****************************************************************************/ ****************************************************************************/
static int lpc17_40_recvshortcrc(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t *rshort) static int lpc17_40_recvshortcrc(FAR struct sdio_dev_s *dev, uint32_t cmd,
uint32_t *rshort)
{ {
#ifdef CONFIG_DEBUG_FEATURES #ifdef CONFIG_DEBUG_FEATURES
uint32_t respcmd; uint32_t respcmd;
@ -2007,7 +2050,6 @@ static int lpc17_40_recvshortcrc(FAR struct sdio_dev_s *dev, uint32_t cmd, uint3
* 0 1 End bit * 0 1 End bit
*/ */
#ifdef CONFIG_DEBUG_FEATURES #ifdef CONFIG_DEBUG_FEATURES
if (!rshort) if (!rshort)
{ {
@ -2046,7 +2088,8 @@ static int lpc17_40_recvshortcrc(FAR struct sdio_dev_s *dev, uint32_t cmd, uint3
/* Check response received is of desired command */ /* Check response received is of desired command */
respcmd = getreg32(LPC17_40_SDCARD_RESPCMD); respcmd = getreg32(LPC17_40_SDCARD_RESPCMD);
if ((uint8_t)(respcmd & SDCARD_RESPCMD_MASK) != (cmd & MMCSD_CMDIDX_MASK)) if ((uint8_t)(respcmd & SDCARD_RESPCMD_MASK) !=
(cmd & MMCSD_CMDIDX_MASK))
{ {
mcerr("ERROR: RESCMD=%02x CMD=%08x\n", respcmd, cmd); mcerr("ERROR: RESCMD=%02x CMD=%08x\n", respcmd, cmd);
ret = -EINVAL; ret = -EINVAL;
@ -2062,7 +2105,8 @@ static int lpc17_40_recvshortcrc(FAR struct sdio_dev_s *dev, uint32_t cmd, uint3
return ret; return ret;
} }
static int lpc17_40_recvlong(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t rlong[4]) static int lpc17_40_recvlong(FAR struct sdio_dev_s *dev, uint32_t cmd,
uint32_t rlong[4])
{ {
uint32_t regval; uint32_t regval;
int ret = OK; int ret = OK;
@ -2116,7 +2160,8 @@ static int lpc17_40_recvlong(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t
return ret; return ret;
} }
static int lpc17_40_recvshort(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t *rshort) static int lpc17_40_recvshort(FAR struct sdio_dev_s *dev, uint32_t cmd,
uint32_t *rshort)
{ {
uint32_t regval; uint32_t regval;
int ret = OK; int ret = OK;
@ -2159,12 +2204,14 @@ static int lpc17_40_recvshort(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t
{ {
*rshort = getreg32(LPC17_40_SDCARD_RESP0); *rshort = getreg32(LPC17_40_SDCARD_RESP0);
} }
return ret; return ret;
} }
/* MMC responses not supported */ /* MMC responses not supported */
static int lpc17_40_recvnotimpl(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t *rnotimpl) static int lpc17_40_recvnotimpl(FAR struct sdio_dev_s *dev, uint32_t cmd,
uint32_t *rnotimpl)
{ {
putreg32(SDCARD_RESPDONE_ICR | SDCARD_CMDDONE_ICR, LPC17_40_SDCARD_CLEAR); putreg32(SDCARD_RESPDONE_ICR | SDCARD_CMDDONE_ICR, LPC17_40_SDCARD_CLEAR);
return -ENOSYS; return -ENOSYS;
@ -2237,9 +2284,9 @@ static void lpc17_40_waitenable(FAR struct sdio_dev_s *dev,
* *
* Description: * Description:
* Wait for one of the enabled events to occur (or a timeout). Note that * Wait for one of the enabled events to occur (or a timeout). Note that
* all events enabled by SDCARD_WAITEVENTS are disabled when lpc17_40_eventwait * all events enabled by SDCARD_WAITEVENTS are disabled when
* returns. SDCARD_WAITEVENTS must be called again before lpc17_40_eventwait * lpc17_40_eventwait returns. SDCARD_WAITEVENTS must be called again
* can be used again. * before lpc17_40_eventwait can be used again.
* *
* Input Parameters: * Input Parameters:
* dev - An instance of the SD card device interface * dev - An instance of the SD card device interface
@ -2290,7 +2337,8 @@ static sdio_eventset_t lpc17_40_eventwait(FAR struct sdio_dev_s *dev,
/* Start the watchdog timer */ /* Start the watchdog timer */
delay = MSEC2TICK(timeout); delay = MSEC2TICK(timeout);
ret = wd_start(priv->waitwdog, delay, (wdentry_t)lpc17_40_eventtimeout, ret = wd_start(priv->waitwdog, delay,
(wdentry_t) lpc17_40_eventtimeout,
1, (uint32_t)priv); 1, (uint32_t)priv);
if (ret < 0) if (ret < 0)
{ {
@ -2298,24 +2346,35 @@ static sdio_eventset_t lpc17_40_eventwait(FAR struct sdio_dev_s *dev,
} }
} }
/* Loop until the event (or the timeout occurs). Race conditions are avoided /* Loop until the event (or the timeout occurs). Race conditions are
* by calling lpc17_40_waitenable prior to triggering the logic that will cause * avoided by calling lpc17_40_waitenable prior to triggering the logic
* the wait to terminate. Under certain race conditions, the waited-for * that will cause the wait to terminate. Under certain race conditions,
* may have already occurred before this function was called! * the waited-for may have already occurred before this function was
* called!
*/ */
for (; ; ) for (; ; )
{ {
/* Wait for an event in event set to occur. If this the event has already /* Wait for an event in event set to occur. If this the event has
* occurred, then the semaphore will already have been incremented and * already occurred, then the semaphore will already have been
* there will be no wait. * incremented and there will be no wait.
*/ */
lpc17_40_takesem(priv); ret = lpc17_40_takesem(priv);
if (ret < 0)
{
wd_cancel(priv->waitwdog);
leave_critical_section(flags);
return SDIOWAIT_ERROR;
}
wkupevent = priv->wkupevent; wkupevent = priv->wkupevent;
/* Check if the event has occurred. When the event has occurred, then /* Check if the event has occurred. When the event has occurred, then
* evenset will be set to 0 and wkupevent will be set to a nonzero value. * evenset will be set to 0 and wkupevent will be set to a nonzero
* value.
*/ */
if (wkupevent != 0) if (wkupevent != 0)
@ -2344,8 +2403,8 @@ errout:
* *
* Description: * Description:
* Enable/disable of a set of SD card callback events. This is part of the * Enable/disable of a set of SD card callback events. This is part of the
* the SD card callback sequence. The set of events is configured to enabled * the SD card callback sequence. The set of events is configured to
* callbacks to the function provided in lpc17_40_registercallback. * enabled callbacks to the function provided in lpc17_40_registercallback.
* *
* Events are automatically disabled once the callback is performed and no * Events are automatically disabled once the callback is performed and no
* further callback events will occur until they are again enabled by * further callback events will occur until they are again enabled by
@ -2431,7 +2490,8 @@ static int lpc17_40_registercallback(FAR struct sdio_dev_s *dev,
****************************************************************************/ ****************************************************************************/
#ifdef CONFIG_LPC17_40_SDCARD_DMA #ifdef CONFIG_LPC17_40_SDCARD_DMA
static int lpc17_40_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer, static int lpc17_40_dmarecvsetup(FAR struct sdio_dev_s *dev,
FAR uint8_t *buffer,
size_t buflen) size_t buflen)
{ {
struct lpc17_40_dev_s *priv = (struct lpc17_40_dev_s *)dev; struct lpc17_40_dev_s *priv = (struct lpc17_40_dev_s *)dev;
@ -2574,6 +2634,7 @@ static int lpc17_40_dmasendsetup(FAR struct sdio_dev_s *dev,
/**************************************************************************** /****************************************************************************
* Initialization/uninitialization/reset * Initialization/uninitialization/reset
****************************************************************************/ ****************************************************************************/
/**************************************************************************** /****************************************************************************
* Name: lpc17_40_callback * Name: lpc17_40_callback
* *
@ -2630,17 +2691,19 @@ static void lpc17_40_callback(void *arg)
priv->cbevents = 0; priv->cbevents = 0;
/* Callbacks cannot be performed in the context of an interrupt handler. /* Callbacks cannot be performed in the context of an interrupt
* If we are in an interrupt handler, then queue the callback to be * handler. If we are in an interrupt handler, then queue the
* performed later on the work thread. * callback to be performed later on the work thread.
*/ */
if (up_interrupt_context()) if (up_interrupt_context())
{ {
/* Yes.. queue it */ /* Yes.. queue it */
mcinfo("Queuing callback to %p(%p)\n", priv->callback, priv->cbarg); mcinfo("Queuing callback to %p(%p)\n", priv->callback,
work_queue(HPWORK, &priv->cbwork, (worker_t)priv->callback, priv->cbarg, 0); priv->cbarg);
work_queue(HPWORK, &priv->cbwork, (worker_t)priv->callback,
priv->cbarg, 0);
} }
else else
{ {
@ -2687,7 +2750,8 @@ static void lpc17_40_default(void)
* slotno - Not used. * slotno - Not used.
* *
* Returned Value: * Returned Value:
* A reference to an SD card interface structure. NULL is returned on failures. * A reference to an SD card interface structure. NULL is returned on
* failures.
* *
****************************************************************************/ ****************************************************************************/
@ -2706,6 +2770,7 @@ FAR struct sdio_dev_s *sdio_initialize(int slotno)
putreg32(regval, LPC17_40_SYSCON_PCONP); putreg32(regval, LPC17_40_SYSCON_PCONP);
/* Initialize the SD card slot structure */ /* Initialize the SD card slot structure */
/* Initialize semaphores */ /* Initialize semaphores */
nxsem_init(&priv->waitsem, 0, 0); nxsem_init(&priv->waitsem, 0, 0);
@ -2795,6 +2860,7 @@ void sdio_mediachange(FAR struct sdio_dev_s *dev, bool cardinslot)
{ {
priv->cdstatus &= ~SDIO_STATUS_PRESENT; priv->cdstatus &= ~SDIO_STATUS_PRESENT;
} }
mcinfo("cdstatus OLD: %02x NEW: %02x\n", cdstatus, priv->cdstatus); mcinfo("cdstatus OLD: %02x NEW: %02x\n", cdstatus, priv->cdstatus);
/* Perform any requested callback if the status has changed */ /* Perform any requested callback if the status has changed */