summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorJean-Jacques Hiblot <jjhiblot@ti.com>2019-07-02 10:53:56 +0200
committerPeng Fan <peng.fan@nxp.com>2019-07-15 10:16:49 +0800
commitbb98b8c5c06a5a9befb74aef843f7cd698c52d5d (patch)
treecd46206f7e099dac7eabba328906d3481f151e72 /drivers
parent513e00b64e63c277ad6dd667b823282ef4d177c1 (diff)
mmc: During a switch, poll on dat0 if available and check the final status
The switch operation can sometimes make the bus unreliable, in that case the send_status parameter should be false to indicate not to poll using CMD13. If polling on dat0 is possible, we should use it to detect the end of the operation. At the end of the operation it is safe to use CMD13 to get the status of the card. It is important to do so because the operation may have failed. Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mmc/mmc.c49
1 files changed, 36 insertions, 13 deletions
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index e5cee7dbc8..1ad35fff7d 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -746,6 +746,7 @@ static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value,
bool send_status)
{
+ unsigned int status, start;
struct mmc_cmd cmd;
int timeout = DEFAULT_CMD6_TIMEOUT_MS;
bool is_part_switch = (set == EXT_CSD_CMD_SET_NORMAL) &&
@@ -765,25 +766,47 @@ static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value,
(index << 16) |
(value << 8);
- while (retries > 0) {
+ do {
ret = mmc_send_cmd(mmc, &cmd, NULL);
+ } while (ret && retries-- > 0);
- if (ret) {
- retries--;
- continue;
- }
+ if (ret)
+ return ret;
- if (!send_status) {
- mdelay(50);
- return 0;
- }
+ start = get_timer(0);
- /* Waiting for the ready status */
- return mmc_poll_for_busy(mmc, timeout);
- }
+ /* poll dat0 for rdy/buys status */
+ ret = mmc_wait_dat0(mmc, 1, timeout);
+ if (ret && ret != -ENOSYS)
+ return ret;
- return ret;
+ /*
+ * In cases when not allowed to poll by using CMD13 or because we aren't
+ * capable of polling by using mmc_wait_dat0, then rely on waiting the
+ * stated timeout to be sufficient.
+ */
+ if (ret == -ENOSYS && !send_status)
+ mdelay(timeout);
+
+ /* Finally wait until the card is ready or indicates a failure
+ * to switch. It doesn't hurt to use CMD13 here even if send_status
+ * is false, because by now (after 'timeout' ms) the bus should be
+ * reliable.
+ */
+ do {
+ ret = mmc_send_status(mmc, &status);
+
+ if (!ret && (status & MMC_STATUS_SWITCH_ERROR)) {
+ pr_debug("switch failed %d/%d/0x%x !\n", set, index,
+ value);
+ return -EIO;
+ }
+ if (!ret && (status & MMC_STATUS_RDY_FOR_DATA))
+ return 0;
+ udelay(100);
+ } while (get_timer(start) < timeout);
+ return -ETIMEDOUT;
}
int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)