|
@@ -23,6 +23,40 @@
|
|
|
|
|
|
#define MMC_OPS_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */
|
|
|
|
|
|
+static inline int __mmc_send_status(struct mmc_card *card, u32 *status,
|
|
|
+ bool ignore_crc)
|
|
|
+{
|
|
|
+ int err;
|
|
|
+ struct mmc_command cmd = {0};
|
|
|
+
|
|
|
+ BUG_ON(!card);
|
|
|
+ BUG_ON(!card->host);
|
|
|
+
|
|
|
+ cmd.opcode = MMC_SEND_STATUS;
|
|
|
+ if (!mmc_host_is_spi(card->host))
|
|
|
+ cmd.arg = card->rca << 16;
|
|
|
+ cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
|
|
|
+ if (ignore_crc)
|
|
|
+ cmd.flags &= ~MMC_RSP_CRC;
|
|
|
+
|
|
|
+ err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ /* NOTE: callers are required to understand the difference
|
|
|
+ * between "native" and SPI format status words!
|
|
|
+ */
|
|
|
+ if (status)
|
|
|
+ *status = cmd.resp[0];
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int mmc_send_status(struct mmc_card *card, u32 *status)
|
|
|
+{
|
|
|
+ return __mmc_send_status(card, status, false);
|
|
|
+}
|
|
|
+
|
|
|
static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
|
|
|
{
|
|
|
int err;
|
|
@@ -380,6 +414,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
|
|
|
struct mmc_command cmd = {0};
|
|
|
unsigned long timeout;
|
|
|
u32 status;
|
|
|
+ bool ignore_crc = false;
|
|
|
|
|
|
BUG_ON(!card);
|
|
|
BUG_ON(!card->host);
|
|
@@ -408,10 +443,18 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
|
|
|
if (!use_busy_signal)
|
|
|
return 0;
|
|
|
|
|
|
- /* Must check status to be sure of no errors */
|
|
|
+ /*
|
|
|
+ * Must check status to be sure of no errors
|
|
|
+ * If CMD13 is to check the busy completion of the timing change,
|
|
|
+ * disable the check of CRC error.
|
|
|
+ */
|
|
|
+ if (index == EXT_CSD_HS_TIMING &&
|
|
|
+ !(card->host->caps & MMC_CAP_WAIT_WHILE_BUSY))
|
|
|
+ ignore_crc = true;
|
|
|
+
|
|
|
timeout = jiffies + msecs_to_jiffies(MMC_OPS_TIMEOUT_MS);
|
|
|
do {
|
|
|
- err = mmc_send_status(card, &status);
|
|
|
+ err = __mmc_send_status(card, &status, ignore_crc);
|
|
|
if (err)
|
|
|
return err;
|
|
|
if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY)
|
|
@@ -449,32 +492,6 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(mmc_switch);
|
|
|
|
|
|
-int mmc_send_status(struct mmc_card *card, u32 *status)
|
|
|
-{
|
|
|
- int err;
|
|
|
- struct mmc_command cmd = {0};
|
|
|
-
|
|
|
- BUG_ON(!card);
|
|
|
- BUG_ON(!card->host);
|
|
|
-
|
|
|
- cmd.opcode = MMC_SEND_STATUS;
|
|
|
- if (!mmc_host_is_spi(card->host))
|
|
|
- cmd.arg = card->rca << 16;
|
|
|
- cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
|
|
|
-
|
|
|
- err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
|
|
|
- if (err)
|
|
|
- return err;
|
|
|
-
|
|
|
- /* NOTE: callers are required to understand the difference
|
|
|
- * between "native" and SPI format status words!
|
|
|
- */
|
|
|
- if (status)
|
|
|
- *status = cmd.resp[0];
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
static int
|
|
|
mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
|
|
|
u8 len)
|