From a914ded23565d8688e2b7e435916630def5bdd19 Mon Sep 17 00:00:00 2001 From: Juha Yrjola Date: Wed, 26 Mar 2008 16:09:12 -0400 Subject: MMC: OMAP: New release dma and abort xfer functions New functions to support MMC multislot: mmc_omap_release_dma() and mmc_omap_abort_xfer(). Signed-off-by: Juha Yrjola Signed-off-by: Carlos Eduardo Aguiar Signed-off-by: Tony Lindgren Signed-off-by: Pierre Ossman --- drivers/mmc/host/omap.c | 79 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 60 insertions(+), 19 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 712a9608acf..90e9d68e799 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -326,27 +326,33 @@ mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd) OMAP_MMC_WRITE(host, CMD, cmdreg); } +static void +mmc_omap_release_dma(struct mmc_omap_host *host, struct mmc_data *data, + int abort) +{ + enum dma_data_direction dma_data_dir; + + BUG_ON(host->dma_ch < 0); + if (data->error) + omap_stop_dma(host->dma_ch); + /* Release DMA channel lazily */ + mod_timer(&host->dma_timer, jiffies + HZ); + if (data->flags & MMC_DATA_WRITE) + dma_data_dir = DMA_TO_DEVICE; + else + dma_data_dir = DMA_FROM_DEVICE; + dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len, + dma_data_dir); +} + static void mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data) { - if (host->dma_in_use) { - enum dma_data_direction dma_data_dir; - - BUG_ON(host->dma_ch < 0); - if (data->error) - omap_stop_dma(host->dma_ch); - /* Release DMA channel lazily */ - mod_timer(&host->dma_timer, jiffies + HZ); - if (data->flags & MMC_DATA_WRITE) - dma_data_dir = DMA_TO_DEVICE; - else - dma_data_dir = DMA_FROM_DEVICE; - dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len, - dma_data_dir); - } + if (host->dma_in_use) + mmc_omap_release_dma(host, data, data->error); + host->data = NULL; host->sg_len = 0; - clk_disable(host->fclk); /* NOTE: MMC layer will sometimes poll-wait CMD13 next, issuing * dozens of requests until the card finishes writing data. @@ -354,14 +360,44 @@ mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data) */ if (!data->stop) { + struct mmc_host *mmc; + host->mrq = NULL; - mmc_request_done(host->mmc, data->mrq); + mmc = host->mmc; + mmc_omap_release_slot(host->current_slot); + mmc_request_done(mmc, data->mrq); return; } mmc_omap_start_command(host, data->stop); } +static void +mmc_omap_abort_xfer(struct mmc_omap_host *host, struct mmc_data *data) +{ + int loops; + u16 ie; + + if (host->dma_in_use) + mmc_omap_release_dma(host, data, 1); + + host->data = NULL; + host->sg_len = 0; + + ie = OMAP_MMC_READ(host, IE); + OMAP_MMC_WRITE(host, IE, 0); + OMAP_MMC_WRITE(host, CMD, 1 << 7); + loops = 0; + while (!(OMAP_MMC_READ(host, STAT) & OMAP_MMC_STAT_END_OF_CMD)) { + udelay(1); + loops++; + if (loops == 100000) + break; + } + OMAP_MMC_WRITE(host, STAT, OMAP_MMC_STAT_END_OF_CMD); + OMAP_MMC_WRITE(host, IE, ie); +} + static void mmc_omap_end_of_data(struct mmc_omap_host *host, struct mmc_data *data) { @@ -439,9 +475,14 @@ mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd) } if (host->data == NULL || cmd->error) { + struct mmc_host *mmc; + + if (host->data != NULL) + mmc_omap_abort_xfer(host, host->data); host->mrq = NULL; - clk_disable(host->fclk); - mmc_request_done(host->mmc, cmd->mrq); + mmc = host->mmc; + mmc_omap_release_slot(host->current_slot); + mmc_request_done(mmc, cmd->mrq); } } -- cgit v1.2.3-70-g09d2