aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorSahitya Tummala <stummala@codeaurora.org>2010-12-08 04:33:05 -0500
committerDavid Brown <davidb@codeaurora.org>2010-12-20 15:28:31 -0500
commitb08bb35d1a5ee5426198eb3a2861008c2e9e6fc4 (patch)
treeb721ec64e16b9197322b15833f301604fe52aa85 /drivers/mmc
parentd5137bdd91b8267ada3973806443013f4bf079f6 (diff)
mmc: msm_sdcc: Reset SDCC in case of data transfer errors
SDCC uses an asynchronous FIFOs for data synchronization (one for TX and one for RX). For any error when DPSM (Data path state machine) is involved the transfer is terminated with the remaining data stuck inside FIFOs. Reset the controller in case of data errors to ensure that any left over data in FIFOs is flushed out and DPSM is in good state. The following problems are observed without this reset functionality - 1. After the card is removed in an unsafe way (removed when there is an on going data transfer), the card will not be detected upon its next insertion. This is because the controller wouldn't respond to few initialization commands. 2. When an error occurs for a data transfer in non-DMA mode, sometimes we get spurious PIO interrupt after the request is processed. Signed-off-by: Sahitya Tummala <stummala@codeaurora.org> Signed-off-by: David Brown <davidb@codeaurora.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/host/msm_sdcc.c39
1 files changed, 39 insertions, 0 deletions
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 67f536ca31d3..81ed16fb42b5 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -44,6 +44,7 @@
44#include <mach/mmc.h> 44#include <mach/mmc.h>
45#include <mach/msm_iomap.h> 45#include <mach/msm_iomap.h>
46#include <mach/dma.h> 46#include <mach/dma.h>
47#include <mach/clk.h>
47 48
48#include "msm_sdcc.h" 49#include "msm_sdcc.h"
49 50
@@ -126,6 +127,40 @@ static void
126msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, 127msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
127 u32 c); 128 u32 c);
128 129
130static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
131{
132 u32 mci_clk = 0;
133 u32 mci_mask0 = 0;
134 int ret = 0;
135
136 /* Save the controller state */
137 mci_clk = readl(host->base + MMCICLOCK);
138 mci_mask0 = readl(host->base + MMCIMASK0);
139
140 /* Reset the controller */
141 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
142 if (ret)
143 pr_err("%s: Clock assert failed at %u Hz with err %d\n",
144 mmc_hostname(host->mmc), host->clk_rate, ret);
145
146 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
147 if (ret)
148 pr_err("%s: Clock deassert failed at %u Hz with err %d\n",
149 mmc_hostname(host->mmc), host->clk_rate, ret);
150
151 pr_info("%s: Controller has been re-initialiazed\n",
152 mmc_hostname(host->mmc));
153
154 /* Restore the contoller state */
155 writel(host->pwr, host->base + MMCIPOWER);
156 writel(mci_clk, host->base + MMCICLOCK);
157 writel(mci_mask0, host->base + MMCIMASK0);
158 ret = clk_set_rate(host->clk, host->clk_rate);
159 if (ret)
160 pr_err("%s: Failed to set clk rate %u Hz (%d)\n",
161 mmc_hostname(host->mmc), host->clk_rate, ret);
162}
163
129static void 164static void
130msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) 165msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
131{ 166{
@@ -223,6 +258,8 @@ msmsdcc_dma_complete_tlet(unsigned long data)
223 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n", 258 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
224 err.flush[0], err.flush[1], err.flush[2], 259 err.flush[0], err.flush[1], err.flush[2],
225 err.flush[3], err.flush[4], err.flush[5]); 260 err.flush[3], err.flush[4], err.flush[5]);
261
262 msmsdcc_reset_and_restore(host);
226 if (!mrq->data->error) 263 if (!mrq->data->error)
227 mrq->data->error = -EIO; 264 mrq->data->error = -EIO;
228 } 265 }
@@ -723,6 +760,7 @@ static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
723 msm_dmov_stop_cmd(host->dma.channel, 760 msm_dmov_stop_cmd(host->dma.channel,
724 &host->dma.hdr, 0); 761 &host->dma.hdr, 0);
725 else if (host->curr.data) { /* Non DMA */ 762 else if (host->curr.data) { /* Non DMA */
763 msmsdcc_reset_and_restore(host);
726 msmsdcc_stop_data(host); 764 msmsdcc_stop_data(host);
727 msmsdcc_request_end(host, cmd->mrq); 765 msmsdcc_request_end(host, cmd->mrq);
728 } else { /* host->data == NULL */ 766 } else { /* host->data == NULL */
@@ -771,6 +809,7 @@ msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status,
771 msm_dmov_stop_cmd(host->dma.channel, 809 msm_dmov_stop_cmd(host->dma.channel,
772 &host->dma.hdr, 0); 810 &host->dma.hdr, 0);
773 else { 811 else {
812 msmsdcc_reset_and_restore(host);
774 if (host->curr.data) 813 if (host->curr.data)
775 msmsdcc_stop_data(host); 814 msmsdcc_stop_data(host);
776 if (!data->stop) 815 if (!data->stop)