aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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)