diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2009-11-13 23:30:41 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2009-11-13 23:30:41 +0000 |
commit | c9c788a743c2abe94716f47272144bd7a777e651 (patch) | |
tree | 174e35f4a1a00a6338958557d74daa9293883513 /nuttx | |
parent | 38456bf5b58ebbbffae23762a97e01dcbb0d7569 (diff) | |
download | px4-nuttx-c9c788a743c2abe94716f47272144bd7a777e651.tar.gz px4-nuttx-c9c788a743c2abe94716f47272144bd7a777e651.tar.bz2 px4-nuttx-c9c788a743c2abe94716f47272144bd7a777e651.zip |
Add IOCTLs and card identification logic
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@2253 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx')
-rw-r--r-- | nuttx/arch/arm/src/stm32/stm32_sdio.c | 80 | ||||
-rw-r--r-- | nuttx/drivers/mmcsd/mmcsd_sdio.c | 505 | ||||
-rw-r--r-- | nuttx/drivers/mmcsd/mmcsd_sdio.h | 102 | ||||
-rw-r--r-- | nuttx/include/nuttx/ioctl.h | 13 | ||||
-rwxr-xr-x | nuttx/include/nuttx/sdio.h | 29 |
5 files changed, 701 insertions, 28 deletions
diff --git a/nuttx/arch/arm/src/stm32/stm32_sdio.c b/nuttx/arch/arm/src/stm32/stm32_sdio.c index edcd2bdff..102127e57 100644 --- a/nuttx/arch/arm/src/stm32/stm32_sdio.c +++ b/nuttx/arch/arm/src/stm32/stm32_sdio.c @@ -81,7 +81,12 @@ #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)
+ (SDIO_TRANSFER_CLKDIV|SDIO_CLKCR_RISINGEDGE|SDIO_CLKCR_WIDBUS_D4) + +/* Timing */ + +#define SDIO_CMDTIMEOUT 100000 +#define SDIO_LONGTIMEOUT 0x7fffffff
/****************************************************************************
* Private Types
@@ -139,7 +144,8 @@ static int stm32_attach(FAR struct sdio_dev_s *dev); static void stm32_sendcmd(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 arg);
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);
@@ -191,7 +197,8 @@ struct stm32_dev_s g_mmcsd = .setblocklen = stm32_setblocklen,
.attach = stm32_attach,
.sendcmd = stm32_sendcmd,
- .senddata = stm32_senddata,
+ .senddata = stm32_senddata, + .waitresponse = stm32_waitresponse,
.recvR1 = stm32_recvshortcrc,
.recvR2 = stm32_recvlong,
.recvR3 = stm32_recvshort,
@@ -629,6 +636,71 @@ static int stm32_senddata(FAR struct sdio_dev_s *dev, FAR const ubyte *buffer) return -ENOSYS;
}
+/**************************************************************************** + * Name: stm32_waitresponse + * + * Description: + * Poll-wait for the response to the last command to be ready. + * + * Input Parameters: + * dev - An instance of the MMC/SD device interface + * cmd - The command that was sent. See 32-bit command definitions above. + * + * Returned Value: + * OK is success; a negated errno on failure + * + ****************************************************************************/ + +static int stm32_waitresponseFAR struct sdio_dev_s *dev, uint32 cmd) +{ + sint32 timeout = SDIO_LONGTIMEOUT; + uint32 events; + + switch (cmd & MMCSD_RESPONSE_MASK) + { + case MMCSD_NO_RESPONSE: + timeout = SDIO_CMDTIMEOUT; + events = SDIO_STA_CMDSENT; + break; + + case MMCSD_R1_RESPONSE: + case MMCSD_R1B_RESPONSE: + case MMCSD_R2_RESPONSE: + case MMCSD_R6_RESPONSE: + events = SDIO_STA_CTIMEOUT|SDIO_STA_CCRCFAIL|SDIO_STA_CMDREND; + break; + + case MMCSD_R4_RESPONSE: + case MMCSD_R5_RESPONSE: + return -ENOSYS; + + case MMCSD_R3_RESPONSE: + case MMCSD_R7_RESPONSE: + events = SDIO_STA_CTIMEOUT|SDIO_STA_CMDREND; + timeout = SDIO_CMDTIMEOUT; + break; + + default: + return -EINVAL; + } + + /* Then wait for the response (or timeout) */ + + while ((getreg32(STM32_SDIO_STA) & events) == 0)
+ {
+ if (--timeout <= 0) + { + fdbg("ERROR: Timeout cmd=%04x\n", cmd); + return -ETIMEDOUT; + }
+ }
+ + /* Clear all the static flags */ +
+ putreg32(SDIO_ICR_STATICFLAGS, STM32_SDIO_ICR);
+ return OK;
+} + /****************************************************************************
* Name: stm32_recvRx
*
@@ -817,7 +889,7 @@ static int stm32_recvshort(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 *rshor }
#endif
- regval = getreg32(STM32_SDIO_STA);
+ regval = getreg32(STM32_SDIO_STA);
if (regval & SDIO_STA_CTIMEOUT)
{
putreg32(SDIO_ICR_CTIMEOUTC, STM32_SDIO_ICR);
diff --git a/nuttx/drivers/mmcsd/mmcsd_sdio.c b/nuttx/drivers/mmcsd/mmcsd_sdio.c index c6e4fdb19..ab8bbce7b 100644 --- a/nuttx/drivers/mmcsd/mmcsd_sdio.c +++ b/nuttx/drivers/mmcsd/mmcsd_sdio.c @@ -41,6 +41,7 @@ #include <sys/types.h> #include <sys/ioctl.h> + #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -48,16 +49,38 @@ #include <errno.h> #include <nuttx/fs.h> +#include <nuttx/ioctl.h> +#include <nuttx/clock.h> +#include <nuttx/arch.h> #include <nuttx/rwbuffer.h> #include <nuttx/sdio.h> #include <nuttx/mmcsd.h> +#include "mmcsd_internal.h" +#include "mmcsd_sdio.h" + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ -#define MAX_CREFS 0xff /* Because a ubyte is used. Use a larger - * type if necessary */ +/* The maximum number of references on the driver (because a ubyte is used. + * Use a larger type if more references are needed. + */ + +#define MAX_CREFS 0xff + +/* Timing */ + +#define MMCSD_POWERUP_DELAY 250 /* 74 clock cycles @ 400KHz = 185uS */ +#define MMCSD_IDLE_DELAY 50 /* Short delay to allow change to IDLE state */ + +#define IS_EMPTY(priv) (priv->type == MMCSD_CARDTYPE_UNKNOWN) + +/* Transfer mode */ + +#define MMCSDMODE_POLLED 0 +#define MMCSDMODE_INTERRUPT 1 +#define MMCSDMODE_DMA 2 /**************************************************************************** * Private Types @@ -72,12 +95,27 @@ struct mmcsd_state_s /* Status flags */ + ubyte probed:1; /* TRUE: mmcsd_probe() discovered a card */ ubyte widebus:1; /* TRUE: Wide 4-bit bus selected */ - ubyte mediachange:1; /* TRUE: Media changed since last check */ + ubyte mediachanged:1; /* TRUE: Media changed since last check */ + ubyte wrprotect:1; /* TRUE: Media is write protected */ + ubyte selected:1; /* TRUE: card is selected */ #ifdef CONFIG_SDIO_DMA ubyte dma:1; /* TRUE: hardware supports DMA */ #endif + ubyte type; /* Card type (See MMCSD_CARDTYPE_* definitions) */ + ubyte mode; /* (See MMCSDMODE_* definitions) */ + uint16 selblocklen; /* The currently selected block length */ + uint16 rca; /* Relative Card Address (RCS) register */ + + /* Memory card geometry (extracted from the CSD) */ + + uint16 rdblocklen; /* Read block length (== block size) */ + uint16 wrblocklen; /* Write block length */ + size_t nblocks; /* Number of blocks */ + size_t capacity; /* Total capacity of volume */ + /* Read-ahead and write buffering support */ #if defined(CONFIG_FS_WRITEBUFFER) || defined(CONFIG_FS_READAHEAD) @@ -113,6 +151,14 @@ static int mmcsd_ioctl(FAR struct inode *inode, int cmd, /* Initialization/uninitialization/reset ************************************/ +static inline int + mmcsd_mmcinitialize(struct mmcsd_state_s *priv); +static inline int + mmcsd_sdinitialize(struct mmcsd_state_s *priv); +static inline int + mmcsd_cardidentify(struct mmcsd_state_s *priv); +static int mmcsd_probe(struct mmcsd_state_s *priv); +static int mmcsd_removed(struct mmcsd_state_s *priv); static int mmcsd_hwinitialize(struct mmcsd_state_s *priv); static inline void mmcsd_hwuninitialize(struct mmcsd_state_s *priv); @@ -288,18 +334,47 @@ static ssize_t mmcsd_write(FAR struct inode *inode, const unsigned char *buffer, static int mmcsd_geometry(FAR struct inode *inode, struct geometry *geometry) { struct mmcsd_state_s *priv; + int ret = -EINVAL; fvdbg("Entry\n"); DEBUGASSERT(inode && inode->i_private); if (geometry) { + /* Is there a (supported) card inserted in the slot? */ + priv = (struct mmcsd_state_s *)inode->i_private; -#ifdef CONFIG_CPP_HAVE_WARNING -# warning "Not implemented" + if (IS_EMPTY(priv)) + { + /* No.. return ENODEV */ + + fvdbg("IS_EMPTY\n"); + ret = -ENODEV; + } + else + { + /* Yes.. return the geometry of the card */ + + geometry->geo_available = TRUE; + geometry->geo_mediachanged = priv->mediachanged; +#ifdef CONFIG_FS_WRITABLE + geometry->geo_writeenabled = !priv->wrprotect; +#else + geometry->geo_writeenabled = FALSE; #endif - return -ENOSYS; + geometry->geo_nsectors = priv->nblocks; + geometry->geo_sectorsize = priv->rdblocklen; + + fvdbg("available: TRUE mediachanged: %s writeenabled: %s\n", + geometry->geo_mediachanged ? "TRUE" : "FALSE", + geometry->geo_writeenabled ? "TRUE" : "FALSE"); + fvdbg("nsectors: %ld sectorsize: %d\n", + (long)geometry->geo_nsectors, geometry->geo_sectorsize); + + priv->mediachanged = FALSE; + ret = OK; + } } - return -EINVAL; + return ret; } /**************************************************************************** @@ -311,25 +386,415 @@ static int mmcsd_geometry(FAR struct inode *inode, struct geometry *geometry) static int mmcsd_ioctl(FAR struct inode *inode, int cmd, unsigned long arg) { - struct mmcsd_state_s *priv ; + struct mmcsd_state_s *priv; + int ret; fvdbg("Entry\n"); DEBUGASSERT(inode && inode->i_private); priv = (struct mmcsd_state_s *)inode->i_private; -#ifdef CONFIG_CPP_HAVE_WARNING -# warning "Not implemented" -#endif - return -ENOTTY; + /* Process the IOCTL by command */ + + switch (cmd) + { + case BIOC_PROBE: /* Check for media in the slot */ + { + fvdbg("BIOC_PROBE\n"); + + /* Probe the MMC/SD slot for media */ + + ret = mmcsd_probe(priv); + if (ret != OK) + { + fdbg("ERROR: mmcsd_probe failed: %d\n", ret); + } + } + break; + + case BIOC_EJECT: /* Media has been removed from the slot */ + { + fvdbg("BIOC_EJECT\n"); + + /* Process the removal of the card */ + + ret = mmcsd_removed(priv); + if (ret != OK) + { + fdbg("ERROR: mmcsd_removed failed: %d\n", ret); + } + } + break; + + default: + ret = -ENOTTY; + break; + } + + return ret; } /**************************************************************************** * Initialization/uninitialization/reset ****************************************************************************/ + +/**************************************************************************** + * Name: mmcsd_mmcinitialize + * + * Description: + * We believe that there is an MMC card in the slot. Attempt to initialize + * and configure the MMC card. This is called only from mmcsd_probe(). + * + ****************************************************************************/ + +static inline int mmcsd_mmcinitialize(struct mmcsd_state_s *priv) +{ + return -ENOSYS; +} + +/**************************************************************************** + * Name: mmcsd_sdinitialize + * + * Description: + * We believe that there is an SD card in the slot. Attempt to initialize + * and configure the SD card. This is called only from mmcsd_probe(). + * + ****************************************************************************/ + +static inline int mmcsd_sdinitialize(struct mmcsd_state_s *priv) +{ + return -ENOSYS; +} + +/**************************************************************************** + * Name: mmcsd_cardidentify + * + * Description: + * We believe that there is media in the slot. Attempt to initialize and + * configure the card. This is called only from mmcsd_probe(). + * + ****************************************************************************/ + +static inline int mmcsd_cardidentify(struct mmcsd_state_s *priv) +{ + uint32 response; + uint32 start; + uint32 elapsed; + uint32 state; + uint32 sdcapacity = MMCD_ACMD41_STDCAPACITY; + boolean cardbusy; + int ret; + + /* Assume failure to identify the card */ + + priv->type = MMCSD_CARDTYPE_UNKNOWN; + priv->mode = MMCSDMODE_POLLED; + + /* Check if there is a card present in the slot. This is normally a matter is + * of GPIO sensing. + */ + + if (SDIO_PRESENT(priv->dev)) + { + fvdbg("No card present\n"); + return -ENODEV; + } + + /* Initialize device state structure */ +
+ priv->type = MMCSD_CARDTYPE_SDV1; + priv->mode = MMCSDMODE_POLLED; + + /* Set ID mode clocking (<400KHz) */ + + SDIO_CLOCK(priv->dev, CLOCK_IDMODE); + + /* After power up at least 74 clock cycles are required prior to starting bus + * communication + */ + + up_udelay(MMCSD_POWERUP_DELAY); + + /* Then send CMD0 (twice just to be sure) */ + + SDIO_SENDCMD(priv->dev, MMCSD_CMD0, 0); + SDIO_WAITRESPONSE(priv->dev, MMCSD_CMD0); + SDIO_SENDCMD(priv->dev, MMCSD_CMD0, 0); + up_udelay(MMCSD_IDLE_DELAY); + + /* Check for SDHC Version 2.x. Send CMD8 to verify SD card interface + * operating condition. CMD 8 is reserved on SD version 1.0 and MMC. + * + * CMD8 Argument: + * [31:12]: Reserved (shall be set to '0')
* [11:8]: Supply Voltage (VHS) 0x1 (Range: 2.7-3.6 V)
+ * [7:0]: Check Pattern (recommended 0xaa)
+ * CMD8 Response: R7 + */
+
+ SDIO_SENDCMD(priv->dev, SD_CMD8, MMCSD_CMD8CHECKPATTERN|MMCSD_CMD8VOLTAGE_27);
+ ret = SDIO_RECVR7(priv->dev, SD_CMD8, &response);
+ if (ret == OK)
+ { + /* CMD8 succeeded this is probably a SDHC card. Verify the operating + * voltage and that the check pattern was correctly echoed + */ + + if (((response & MMCSD_R7VOLTAGE_MASK) == MMCSD_R7VOLTAGE_27) && + ((response & MMCSD_R7ECHO_MASK) == MMCSD_R7CHECKPATTERN)) + {
+ fvdbg("SD V2.x card\n"); + priv->type = MMCSD_CARDTYPE_SDV2;
+ sdcapacity = MMCD_ACMD41_HIGHCAPACITY; + } + else + { + fdbg("ERROR: R7: %08x\n", r7); + return -EIO; + }
+ }
+ + /* At this point, type is either UNKNOWN or SDV2. Try sending + * CMD55 and (maybe) ACMD41 for up to 1 second or until the card + * exits the IDLE state. CMD55 is supported by SD V1.x and SD V2.x, + * but not MMC + */ + + start = g_system_timer; + elapsed = 0; + do + { + /* Send CMD55 */ + + SDIO_SENDCMD(priv->dev, SD_CMD55, 0);
+ ret = SDIO_RECVR1(priv->dev, SD_CMD55, &response); + if (ret != OK) + { + /* If the error is a timeout, then it is an MMC card */ + + if (ret == -ETIMEDOUT) + { + fvdbg("ERROR: CMD55 timeout, assuming MMC card\n"); + priv->type = MMCSD_CARDTYPE_MMC;
+ break; + } + else + { + fdbg("ERROR: CMD55 RECVR1: %d\n", ret); + return -EIO; + } + } + else + { + /* CMD55 succeeded. CMD55 is supported by SD V1.x and SD V2.x, + * but not MMC. If we did not previoulsy determine that this is + * an SD V2.x (via CMD8), then this must be SD V1.x + */ + + if (priv->type == MMCSD_CARDTYPE_UNKNOWN) + { + fvdbg("SD V1.x card\n"); + priv->type = MMCSD_CARDTYPE_SDV1;
+ } + + /* Save the state from CMD55 R1 response */ + + state = response & MMCSD_R1_STATE_MASK; + fvdbg("CMD55 R1: %08x\n", response); + + /* Send ACMD41 */ + + SDIO_SENDCMD(priv->dev, SD_ACMD41, MMCD_ACMD41_VOLTAGEWINDOW|sdcapacity); + ret = SDIO_RECVR3(priv->dev, SD_CMD55, &response); + if (ret != OK) + { + fdbg("ERROR: ACMD41 RECVR1: %d\n", ret); + return -EIO; + } + else + { + /* Check if the card is busy */ + + cardbusy = ((response >> 31) == 1); + if (!cardbusy) + { + /* Check if this is a SD V2.x card that supports block addressing */ + + if ((response & MMCD_R3_HIGHCAPACITY) != 0) + { + fvdbg("SD V2.x card with block addressing\n"); + DEBUGASSERT(priv->type == MMCSD_CARDTYPE_SDV2); + priv->type |= MMCSD_CARDTYPE_BLOCK; + } + }
+ } + } + elapsed = g_system_timer - start; + } + while (elapsed < TICK_PER_SEC && (ret != OK || state != MMCSD_R1_STATE_IDLE || cardbusy));
+ + /* We get here when the above loop completes, either (1) because this is + * an MMC card, (2) we could not communicate properly with the card due to + * errors (and the loop times out), or (3) it is an SD card that has successfully + * transitioned to the IDLE state. + */ + + if (elapsed >= TICK_PER_SEC || priv->type == MMCSD_CARDTYPE_UNKNOWN) + { + fdbg("ERROR: Failed to identify card\n"); + return -EIO; + } + + return OK; +} + +/**************************************************************************** + * Name: mmcsd_probe + * + * Description: + * Check for media inserted in a slot. Called (1) during initialization to + * see if there was a card in the slot at power up, (2) when/if a media + * insertion event occurs, or (3) if the BIOC_PROBE ioctl command is + * received. + * + ****************************************************************************/ + +static int mmcsd_probe(struct mmcsd_state_s *priv) +{ + int ret; + + fvdbg("type=%d probed=%d\n", priv->type, priv->probed); + + /* If we have reliable card detection events and if we have + * already probed the card, then we don't need to do anything + * else + */ + +#ifdef CONFIG_MMCSD_HAVECARDDETECT + if (priv->probed && SDIO_PRESENT(priv->dev)) + { + return OK; + } +#endif + + /* Otherwise, we are going to probe the card. There are lots of + * possibilities here: We may think that there is a card in the slot, + * or not. There may be a card in the slot, or not. If there is + * card in the slot, perhaps it is a different card than we one we + * think is there? The safest thing to do is to process the card + * removal first and start from known place. + */ + + mmcsd_removed(priv); + + /* Now.. is there a card in the slot? */ + + if (SDIO_PRESENT(priv->dev)) + { + /* Yes.. probe it. First, what kind of card was inserted? */ + + ret = mmcsd_cardidentify(priv); + if (ret != OK) + { + fdbg("ERROR: Failed to initialize card: %d\n"); + SDIO_EVENTENABLE(priv->dev, SDIOEVENT_INSERTED); + } + else + { + /* Then initialize the driver according to the identified card type */ + + switch (priv->type) + { + case MMCSD_CARDTYPE_MMC: /* MMC card */ + ret = mmcsd_mmcinitialize(priv); + + case MMCSD_CARDTYPE_SDV1: /* Bit 1: SD version 1.x */ + case MMCSD_CARDTYPE_SDV2: /* SD version 2.x with byte addressing */ + case MMCSD_CARDTYPE_SDV2|MMCSD_CARDTYPE_BLOCK: /* SD version 2.x with block addressing */ + ret = mmcsd_sdinitialize(priv); + + case MMCSD_CARDTYPE_UNKNOWN: /* Unknown card type */ + default: + fdbg("ERROR: Internal confusion: %d\n", priv->type); + ret = -EPERM; + }; + + /* Was the card configured successfully? */ + + if (ret == OK) + { + /* Yes... */ + + fvdbg("Capacity: %d Kbytes\n", priv->capacity / 1024); + priv->mediachanged = TRUE; + + /* Set up to receive asynchronous, media removal events */ + + SDIO_EVENTENABLE(priv->dev, SDIOEVENT_EJECTED); + } + } + + /* In any event, we have probed this card */ + + priv->probed = TRUE; + } + else + { + /* There is no card in the slot */ + + fvdbg("No card\n"); + SDIO_EVENTENABLE(priv->dev, SDIOEVENT_INSERTED); + } + + return ret; +} + +/**************************************************************************** + * Name: mmcsd_removed + * + * Description: + * Disable support for media in the slot. Called (1) when/if a media + * removal event occurs, or (2) if the BIOC_EJECT ioctl command is + * received. + * + ****************************************************************************/ + +static int mmcsd_removed(struct mmcsd_state_s *priv) +{ + fvdbg("type: %d present: %d\n", priv->type, SDIO_PRESENT(priv->dev)); + + /* Forget the card geometry, pretend the slot is empty (it might not + * be), and that the card has never been initialized. + */ + + priv->capacity = 0; /* Capacity=0 sometimes means no media */ + priv->rdblocklen = 0; + priv->wrblocklen = 0; + priv->mediachanged = FALSE; + priv->type = MMCSD_CARDTYPE_UNKNOWN; + priv->probed = FALSE; + priv->selected = FALSE; + priv->rca = 0; + priv->selblocklen = 0; + + /* Go back to the default 1-bit data bus. */ + + SDIO_WIDEBUS(priv->dev, FALSE); + priv->widebus = FALSE; + + /* Disable clocking to the card */ + + (void)SDIO_CLOCK(priv->dev, CLOCK_SDIO_DISABLED); + + /* Enable logic to detect if a card is re-inserted */ + + SDIO_EVENTENABLE(priv->dev, SDIOEVENT_INSERTED); + return OK; +} + /**************************************************************************** * Name: mmcsd_hwinitialize * - * Description: One-time hardware initialization + * Description: + * One-time hardware initialization * ****************************************************************************/ @@ -344,13 +809,19 @@ static int mmcsd_hwinitialize(struct mmcsd_state_s *priv) /**************************************************************************** * Name: mmcsd_hwinitialize * - * Description: Restore the MMC/SD slot to the uninitialized state + * Description: + * Restore the MMC/SD slot to the uninitialized state * ****************************************************************************/ static inline void mmcsd_hwuninitialize(struct mmcsd_state_s *priv) { - SDIO_RESET(priv->dev); + if (priv) + { + mmcsd_removed(priv); + SDIO_RESET(priv->dev); + free(priv); + } } /**************************************************************************** @@ -385,7 +856,7 @@ int mmcsd_slotinitialize(int minor, int slotno, FAR struct sdio_dev_s *dev) /* Sanity check */ #ifdef CONFIG_DEBUG - if (minor < 0 || minor > 255 || !dev) + if ((unsigned)slotno >= CONFIG_MMCSD_NSLOTS || minor < 0 || minor > 255 || !dev) { return -EINVAL; } @@ -410,7 +881,7 @@ int mmcsd_slotinitialize(int minor, int slotno, FAR struct sdio_dev_s *dev) /* Was the slot initialized successfully? */ - if (ret != 0) + if (ret != OK) { /* No... But the error ENODEV is returned if hardware initialization * succeeded but no card is inserted in the slot. In this case, the diff --git a/nuttx/drivers/mmcsd/mmcsd_sdio.h b/nuttx/drivers/mmcsd/mmcsd_sdio.h index a4301d002..460360d34 100644 --- a/nuttx/drivers/mmcsd/mmcsd_sdio.h +++ b/nuttx/drivers/mmcsd/mmcsd_sdio.h @@ -47,6 +47,108 @@ * Pre-Processor Definitions ********************************************************************************************/ +/* CMD8 Argument: + * [31:12]: Reserved (shall be set to '0')
* [11:8]: Supply Voltage (VHS) 0x1 (Range: 2.7-3.6 V)
+ * [7:0]: Check Pattern (recommended 0xaa)
+ * CMD8 Response: R7 + */
+ +#define MMCSD_CMD8VOLTAGE_SHIFT 8 /* Bits 8-11: Supply voltage */ +#define MMCSD_CMD8VOLTAGE_MASK (0x0f << MMCSD_CMD8VOLTAGE_SHIFT) +# define MMCSD_CMD8VOLTAGE_27 (0x01 << MMCSD_CMD8VOLTAGE_SHIFT) /* 2.7-3.6V */ +#define MMCSD_CMD8ECHO_SHIFT 0 /* Bits 0-7: Check pattern */ +#define MMCSD_CMD8ECHO_MASK (0xff << MMCSD_CMD8ECHO_SHIFT) +# define MMCSD_CMD8CHECKPATTERN (0xaa << MMCSD_CMD8ECHO_SHIFT) + +/* ACMD41 argument */ + +#define MMCD_ACMD41_VOLTAGEWINDOW 0x80100000
+#define MMCD_ACMD41_HIGHCAPACITY (1 << 30)
+#define MMCD_ACMD41_STDCAPACITY (0)
+ +/* R1 Card Status bit definitions */ + +#define MMCSD_R1_OUTOFRANGE (1 << 31) /* Bad argument */ +#define MMCSD_R1_ADDRESSERROR (1 << 30) /* Bad address */ +#define MMCSD_R1_BLOCKLENERROR (1 << 29) /* Bad block length */ +#define MMCSD_R1_ERASESEQERROR (1 << 28) /* Erase cmd error */ +#define MMCSD_R1_ERASEPARAM (1 << 27) /* Bad write blocks */ +#define MMCSD_R1_WPVIOLATION (1 << 26) /* Erase access failure */ +#define MMCSD_R1_CARDISLOCKED (1 << 25) /* Card is locked */ +#define MMCSD_R1_LOCKUNLOCKFAILED (1 << 24) /* Password error */ +#define MMCSD_R1_COMCRCERROR (1 << 23) /* CRC error */ +#define MMCSD_R1_ILLEGALCOMMAND (1 << 22) /* Bad command */ +#define MMCSD_R1_CARDECCFAILED (1 << 21) /* Failed to correct data */ +#define MMCSD_R1_CCERROR (1 << 20) /* Card controller error */ +#define MMCSD_R1_ERROR (1 << 19) /* General error */ +#define MMCSD_R1_UNDERRUN (1 << 18) /* Underrun (MMC only) */ +#define MMCSD_R1_OVERRRUN (1 << 17) /* Overrun (MMC only) */ +#define MMCSD_R1_CIDCSDOVERWRITE (1 << 16) /* CID/CSD error */ +#define MMCSD_R1_WPERASESKIP (1 << 15) /* Not all erased */ +#define MMCSD_R1_CARDECCDISABLED (1 << 14) /* Internal ECC not used */ +#define MMCSD_R1_ERASERESET (1 << 13) /* Reset sequence cleared */ +#define MMCSD_R1_STATE_SHIFT (9) /* Current card state */ +#define MMCSD_R1_STATE_MASK (15 << MMCSD_R1_STATE_SHIFT) + /* Card identification mode states */ +# define MMCSD_R1_STATE_IDLE (0 << MMCSD_R1_STATE_SHIFT) /* 0=Idle state */ +# define MMCSD_R1_STATE_READY (1 << MMCSD_R1_STATE_SHIFT) /* 1=Ready state */ +# define MMCSD_R1_STATE_IDENT (2 << MMCSD_R1_STATE_SHIFT) /* 2=Identification state */ + /* Data transfer states */ +# define MMCSD_R1_STATE_STBY (3 << MMCSD_R1_STATE_SHIFT) /* 3=Standby state */ +# define MMCSD_R1_STATE_TRAN (4 << MMCSD_R1_STATE_SHIFT) /* 4=Transfer state */ +# define MMCSD_R1_STATE_DATA (5 << MMCSD_R1_STATE_SHIFT) /* 5=Sending data state */ +# define MMCSD_R1_STATE_RCV (6 << MMCSD_R1_STATE_SHIFT) /* 6=Receiving data state */ +# define MMCSD_R1_STATE_PRG (7 << MMCSD_R1_STATE_SHIFT) /* 7=Programming state */ +# define MMCSD_R1_STATE_DIS (8 << MMCSD_R1_STATE_SHIFT) /* 8=Disconnect state */ +#define MMCSD_R1_READYFORDATA (1 << 8) /* Buffer empty */ +#define MMCSD_R1_APPCMD (1 << 5) /* Next CMD is ACMD */ +#define MMCSD_R1_AKESEQERROR (1 << 3) /* Authentication error */ +#define MMCSD_R1_ERRORMASK 0xfdff0008 /* Error mask */ + +#define IS_STATE(v,s) (((v)&MMCSD_R1_CURRENTSTATE_MASK)==(s)) + +/* R3 (OCR) */ + +#define MMC_VDD_20_36 0x00ffff00 /* VDD voltage 2.0-3.6 */ + +#define MMCSD_VDD_145_150 (1 << 0) /* VDD voltage 1.45 - 1.50 */ +#define MMCSD_VDD_150_155 (1 << 1) /* VDD voltage 1.50 - 1.55 */ +#define MMCSD_VDD_155_160 (1 << 2) /* VDD voltage 1.55 - 1.60 */ +#define MMCSD_VDD_160_165 (1 << 3) /* VDD voltage 1.60 - 1.65 */ +#define MMCSD_VDD_165_170 (1 << 4) /* VDD voltage 1.65 - 1.70 */ +#define MMCSD_VDD_17_18 (1 << 5) /* VDD voltage 1.7 - 1.8 */ +#define MMCSD_VDD_18_19 (1 << 6) /* VDD voltage 1.8 - 1.9 */ +#define MMCSD_VDD_19_20 (1 << 7) /* VDD voltage 1.9 - 2.0 */ +#define MMCSD_VDD_20_21 (1 << 8) /* VDD voltage 2.0-2.1 */ +#define MMCSD_VDD_21_22 (1 << 9) /* VDD voltage 2.1-2.2 */ +#define MMCSD_VDD_22_23 (1 << 10) /* VDD voltage 2.2-2.3 */ +#define MMCSD_VDD_23_24 (1 << 11) /* VDD voltage 2.3-2.4 */ +#define MMCSD_VDD_24_25 (1 << 12) /* VDD voltage 2.4-2.5 */ +#define MMCSD_VDD_25_26 (1 << 13) /* VDD voltage 2.5-2.6 */ +#define MMCSD_VDD_26_27 (1 << 14) /* VDD voltage 2.6-2.7 */ +#define MMCSD_VDD_27_28 (1 << 15) /* VDD voltage 2.7-2.8 */ +#define MMCSD_VDD_28_29 (1 << 16) /* VDD voltage 2.8-2.9 */ +#define MMCSD_VDD_29_30 (1 << 17) /* VDD voltage 2.9-3.0 */ +#define MMCSD_VDD_30_31 (1 << 18) /* VDD voltage 3.0-3.1 */ +#define MMCSD_VDD_31_32 (1 << 19) /* VDD voltage 3.1-3.2 */ +#define MMCSD_VDD_32_33 (1 << 20) /* VDD voltage 3.2-3.3 */ +#define MMCSD_VDD_33_34 (1 << 21) /* VDD voltage 3.3-3.4 */ +#define MMCSD_VDD_34_35 (1 << 22) /* VDD voltage 3.4-3.5 */ +#define MMCSD_VDD_35_36 (1 << 23) /* VDD voltage 3.5-3.6 */ +#define MMCD_R3_HIGHCAPACITY (1 << 30) /* TRUE: Card supports block addressing */
+#define MMCSD_CARD_BUSY (1 << 31) /* Card power-up busy bit */ + +/* Last 4 bytes of the 48-bit R7 response */ + +#define MMCSD_R7VERSION_SHIFT 28 /* Bits 28-31: Command version number */ +#define MMCSD_R7VERSION_MASK (0x0f << MMCSD_R7VERSION_SHIFT) +#define MMCSD_R7VOLTAGE_SHIFT 8 /* Bits 8-11: Voltage accepted */ +#define MMCSD_R7VOLTAGE_MASK (0x0f << MMCSD_R7VOLTAGE_SHIFT) +# define MMCSD_R7VOLTAGE_27 (0x01 << MMCSD_R7VOLTAGE_SHIFT) /* 2.7-3.6V */ +#define MMCSD_R7ECHO_SHIFT 0 /* Bits 0-7: Echoed check pattern */ +#define MMCSD_R7ECHO_MASK (0xff << MMCSD_R7ECHO_SHIFT) +# define MMCSD_R7CHECKPATTERN (0xaa << MMCSD_R7ECHO_SHIFT) + /******************************************************************************************** * Public Types ********************************************************************************************/ diff --git a/nuttx/include/nuttx/ioctl.h b/nuttx/include/nuttx/ioctl.h index 5c949692d..1d0219569 100644 --- a/nuttx/include/nuttx/ioctl.h +++ b/nuttx/include/nuttx/ioctl.h @@ -97,12 +97,21 @@ #define _BIOCVALID(c) (_IOC_TYPE(c)==_BIOCBASE) #define _BIOC(nr) _IOC(_BIOCBASE,nr) -#define BIOC_XIPBASE _BIOC(0x0001) /* IN: Pointer to pointer to void in +#define BIOC_XIPBASE _BIOC(0x0001) /* Perform mapping to random access memory. + * IN: Pointer to pointer to void in * which to received the XIP base. * OUT: If media is directly acccesible, * return (void*) base address * of device memory */ - +#define BIOC_PROBE _BIOC(0x0002) /* Re-probe and interface; check for media + * in the slot + * IN: None + * OUT: None (ioctl return value provides + * success/failure indication). */ +#define BIOC_EJECT _BIOC(0x0003) /* Eject/disable media in the slot + * IN: None + * OUT: None (ioctl return value provides + * success/failure indication). */ /* NuttX MTD driver ioctl definitions */ #define _MTDIOCVALID(c) (_IOC_TYPE(c)==_MTDIOCBASE) diff --git a/nuttx/include/nuttx/sdio.h b/nuttx/include/nuttx/sdio.h index 92935f815..5255e69a5 100755 --- a/nuttx/include/nuttx/sdio.h +++ b/nuttx/include/nuttx/sdio.h @@ -313,7 +313,7 @@ * ****************************************************************************/ -#define SDIO_STATUS(dev) ((d)->status(dev)) +#define SDIO_STATUS(dev) ((dev)->status(dev)) /* MMC/SD status bits */ @@ -431,6 +431,23 @@ #define SDIO_SENDDATA(dev,data) ((dev)->senddata(dev,data)) /**************************************************************************** + * Name: SDIO_WAITRESPONSE + * + * Description: + * Poll-wait for the response to the last command to be ready. + * + * Input Parameters: + * dev - An instance of the MMC/SD device interface + * cmd - The command that was sent. See 32-bit command definitions above. + * + * Returned Value: + * OK is success; a negated errno on failure + * + ****************************************************************************/ + +#define SDIO_WAITRESPONSE(dev,cmd) ((dev)->waitresponse(dev,cmd)) + +/**************************************************************************** * Name: SDIO_RECVRx * * Description: @@ -694,10 +711,11 @@ enum sdio_clock_e { CLOCK_SDIO_DISABLED = 0, /* Clock is disabled */ - CLOCK_MMC_SLOW, /* MMC initialization clocking */ - CLOCK_SD_SLOW, /* SD initialization clocking */ - CLOCK_MMC_FAST, /* MMC normal operation clocking */ - CLOCK_SD_FAST /* SD normal operation clocking */ + CLOCK_IDMODE, /* Initial ID mode clocking (<400KHz) */ + CLOCK_MMC_SLOW, /* MMC initialization clocking */ + CLOCK_SD_SLOW, /* SD initialization clocking */ + CLOCK_MMC_FAST, /* MMC normal operation clocking */ + CLOCK_SD_FAST /* SD normal operation clocking */ }; /* This structure defines the interface between the NuttX MMC/SD @@ -728,6 +746,7 @@ struct sdio_dev_s void (*sendcmd)(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 arg); int (*senddata)(FAR struct sdio_dev_s *dev, FAR const ubyte *buffer); + int (*waitresponse)(FAR struct sdio_dev_s *dev, uint32 cmd); int (*recvR1)(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 *R1); int (*recvR2)(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 R2[4]); int (*recvR3)(FAR struct sdio_dev_s *dev, uint32 cmd, uint32 *R3); |