aboutsummaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
authorRaffaele Recalcati <raffaele.recalcati@bticino.it>2011-03-11 02:01:12 +0000
committerAndy Fleming <afleming@freescale.com>2011-04-13 07:08:57 -0500
commit5d4fc8d907ed12844b9c9190601fef2919f3ec25 (patch)
tree20c8c639facdd3ecfbe87d54880b400b68e8981a /drivers/mmc
parent8baf939c2c5e0eb1f3d0cba1067e069e199cbf7f (diff)
mmc: checking status after commands with R1b response
It is recommended to check card status after these kind of commands. This is done using CMD13 (SEND_STATUS) JEDEC command until the card is ready. In case of error the card status field is displayed. Signed-off-by: Raffaele Recalcati <raffaele.recalcati@bticino.it> Signed-off-by: Andy Fleming <afleming@freescale.com>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/mmc.c62
1 files changed, 59 insertions, 3 deletions
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 41c28d48e..3d445c0e2 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -52,6 +52,42 @@ int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
return mmc->send_cmd(mmc, cmd, data);
}
+int mmc_send_status(struct mmc *mmc, int timeout)
+{
+ struct mmc_cmd cmd;
+ int err;
+#ifdef CONFIG_MMC_TRACE
+ int status;
+#endif
+
+ cmd.cmdidx = MMC_CMD_SEND_STATUS;
+ cmd.resp_type = MMC_RSP_R1;
+ cmd.cmdarg = 0;
+ cmd.flags = 0;
+
+ do {
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+ if (err)
+ return err;
+ else if (cmd.response[0] & MMC_STATUS_RDY_FOR_DATA)
+ break;
+
+ udelay(1000);
+
+ if (cmd.response[0] & MMC_STATUS_MASK) {
+ printf("Status Error: 0x%08X\n", cmd.response[0]);
+ return COMM_ERR;
+ }
+ } while (timeout--);
+
+ if (!timeout) {
+ printf("Timeout waiting card ready\n");
+ return TIMEOUT;
+ }
+
+ return 0;
+}
+
int mmc_set_blocklen(struct mmc *mmc, int len)
{
struct mmc_cmd cmd;
@@ -86,6 +122,7 @@ mmc_write_blocks(struct mmc *mmc, ulong start, lbaint_t blkcnt, const void*src)
{
struct mmc_cmd cmd;
struct mmc_data data;
+ int timeout = 1000;
if ((start + blkcnt) > mmc->block_dev.lba) {
printf("MMC: block number 0x%lx exceeds max(0x%lx)\n",
@@ -128,6 +165,9 @@ mmc_write_blocks(struct mmc *mmc, ulong start, lbaint_t blkcnt, const void*src)
printf("mmc fail to send stop cmd\n");
return 0;
}
+
+ /* Waiting for the ready status */
+ mmc_send_status(mmc, timeout);
}
return blkcnt;
@@ -162,6 +202,7 @@ int mmc_read_blocks(struct mmc *mmc, void *dst, ulong start, lbaint_t blkcnt)
{
struct mmc_cmd cmd;
struct mmc_data data;
+ int timeout = 1000;
if (blkcnt > 1)
cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
@@ -193,6 +234,9 @@ int mmc_read_blocks(struct mmc *mmc, void *dst, ulong start, lbaint_t blkcnt)
printf("mmc fail to send stop cmd\n");
return 0;
}
+
+ /* Waiting for the ready status */
+ mmc_send_status(mmc, timeout);
}
return blkcnt;
@@ -396,15 +440,23 @@ int mmc_send_ext_csd(struct mmc *mmc, char *ext_csd)
int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
{
struct mmc_cmd cmd;
+ int timeout = 1000;
+ int ret;
cmd.cmdidx = MMC_CMD_SWITCH;
cmd.resp_type = MMC_RSP_R1b;
cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
- (index << 16) |
- (value << 8);
+ (index << 16) |
+ (value << 8);
cmd.flags = 0;
- return mmc_send_cmd(mmc, &cmd, NULL);
+ ret = mmc_send_cmd(mmc, &cmd, NULL);
+
+ /* Waiting for the ready status */
+ mmc_send_status(mmc, timeout);
+
+ return ret;
+
}
int mmc_change_freq(struct mmc *mmc)
@@ -643,6 +695,7 @@ int mmc_startup(struct mmc *mmc)
u64 cmult, csize;
struct mmc_cmd cmd;
char ext_csd[512];
+ int timeout = 1000;
#ifdef CONFIG_MMC_SPI_CRC_ON
if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
@@ -699,6 +752,9 @@ int mmc_startup(struct mmc *mmc)
err = mmc_send_cmd(mmc, &cmd, NULL);
+ /* Waiting for the ready status */
+ mmc_send_status(mmc, timeout);
+
if (err)
return err;