diff options
author | Jaehoon Chung <jh80.chung@samsung.com> | 2013-09-10 17:43:03 +0900 |
---|---|---|
committer | MyungJoo Ham <myungjoo.ham@samsung.com> | 2013-11-15 13:52:20 +0900 |
commit | e07f849566a05d85e31b69fa00cf0cf0f407316b (patch) | |
tree | 7409913fa3296e2cf75087c9f87714ff34baf051 /drivers/mmc | |
parent | 8e6b648a3c013b4a9f11d67d339504ee6bffba4b (diff) | |
download | linux-3.10-e07f849566a05d85e31b69fa00cf0cf0f407316b.tar.gz linux-3.10-e07f849566a05d85e31b69fa00cf0cf0f407316b.tar.bz2 linux-3.10-e07f849566a05d85e31b69fa00cf0cf0f407316b.zip |
mmc: dw-mmc: check whether card is busy or not, before clock disabled.
Before disable the clock, must check whether card is busy or not.
(Refer to DesignWare TRM)
Signed-off-by: Jaehoon Chung <jh80.chung@samsung.com>
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/host/dw_mmc.c | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 564c9fbd5c7..c6deb2bd49d 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -310,6 +310,27 @@ static void dw_mci_stop_dma(struct dw_mci *host) } } +static bool dw_mci_wait_reset(struct device *dev, struct dw_mci *host, + unsigned int reset_val) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(500); + unsigned int ctrl; + + ctrl = mci_readl(host, CTRL); + ctrl |= reset_val; + mci_writel(host, CTRL, ctrl); + + /* wait till resets clear */ + do { + if (!(mci_readl(host, CTRL) & reset_val)) + return true; + } while (time_before(jiffies, timeout)); + + dev_err(dev, "Timeout resetting block (ctrl %#x)\n", ctrl); + + return false; +} + static int dw_mci_get_dma_dir(struct mmc_data *data) { if (data->flags & MMC_DATA_WRITE) @@ -634,6 +655,7 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) struct dw_mci *host = slot->host; u32 div; u32 clk_en_a; + int timeout = 1000; if (slot->clock != host->current_speed || force_clkinit) { div = host->bus_hz / slot->clock; @@ -651,6 +673,23 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) " div = %d)\n", slot->id, host->bus_hz, slot->clock, div ? ((host->bus_hz / div) >> 1) : host->bus_hz, div); + /* + * Before disable the clock, + * must check whether the card is busy or not. + */ + do { + if (!(mci_readl(host, STATUS) & BIT(9))) + break; + if (timeout-- < 0) { + dev_err(host->dev, "Can't disable clock" + "because Card is busy!!\n"); + return; + } + host->cur_slot = slot; + dw_mci_wait_reset(host->dev, host, SDMMC_CTRL_RESET); + + } while (1); + /* disable clock */ mci_writel(host, CLKENA, 0); mci_writel(host, CLKSRC, 0); |