aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/mmc/host/omap.c79
1 files changed, 60 insertions, 19 deletions
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c
index 712a9608acf7..90e9d68e7998 100644
--- a/drivers/mmc/host/omap.c
+++ b/drivers/mmc/host/omap.c
@@ -327,26 +327,32 @@ mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd)
327} 327}
328 328
329static void 329static void
330mmc_omap_release_dma(struct mmc_omap_host *host, struct mmc_data *data,
331 int abort)
332{
333 enum dma_data_direction dma_data_dir;
334
335 BUG_ON(host->dma_ch < 0);
336 if (data->error)
337 omap_stop_dma(host->dma_ch);
338 /* Release DMA channel lazily */
339 mod_timer(&host->dma_timer, jiffies + HZ);
340 if (data->flags & MMC_DATA_WRITE)
341 dma_data_dir = DMA_TO_DEVICE;
342 else
343 dma_data_dir = DMA_FROM_DEVICE;
344 dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len,
345 dma_data_dir);
346}
347
348static void
330mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data) 349mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data)
331{ 350{
332 if (host->dma_in_use) { 351 if (host->dma_in_use)
333 enum dma_data_direction dma_data_dir; 352 mmc_omap_release_dma(host, data, data->error);
334 353
335 BUG_ON(host->dma_ch < 0);
336 if (data->error)
337 omap_stop_dma(host->dma_ch);
338 /* Release DMA channel lazily */
339 mod_timer(&host->dma_timer, jiffies + HZ);
340 if (data->flags & MMC_DATA_WRITE)
341 dma_data_dir = DMA_TO_DEVICE;
342 else
343 dma_data_dir = DMA_FROM_DEVICE;
344 dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len,
345 dma_data_dir);
346 }
347 host->data = NULL; 354 host->data = NULL;
348 host->sg_len = 0; 355 host->sg_len = 0;
349 clk_disable(host->fclk);
350 356
351 /* NOTE: MMC layer will sometimes poll-wait CMD13 next, issuing 357 /* NOTE: MMC layer will sometimes poll-wait CMD13 next, issuing
352 * dozens of requests until the card finishes writing data. 358 * dozens of requests until the card finishes writing data.
@@ -354,8 +360,12 @@ mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data)
354 */ 360 */
355 361
356 if (!data->stop) { 362 if (!data->stop) {
363 struct mmc_host *mmc;
364
357 host->mrq = NULL; 365 host->mrq = NULL;
358 mmc_request_done(host->mmc, data->mrq); 366 mmc = host->mmc;
367 mmc_omap_release_slot(host->current_slot);
368 mmc_request_done(mmc, data->mrq);
359 return; 369 return;
360 } 370 }
361 371
@@ -363,6 +373,32 @@ mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data)
363} 373}
364 374
365static void 375static void
376mmc_omap_abort_xfer(struct mmc_omap_host *host, struct mmc_data *data)
377{
378 int loops;
379 u16 ie;
380
381 if (host->dma_in_use)
382 mmc_omap_release_dma(host, data, 1);
383
384 host->data = NULL;
385 host->sg_len = 0;
386
387 ie = OMAP_MMC_READ(host, IE);
388 OMAP_MMC_WRITE(host, IE, 0);
389 OMAP_MMC_WRITE(host, CMD, 1 << 7);
390 loops = 0;
391 while (!(OMAP_MMC_READ(host, STAT) & OMAP_MMC_STAT_END_OF_CMD)) {
392 udelay(1);
393 loops++;
394 if (loops == 100000)
395 break;
396 }
397 OMAP_MMC_WRITE(host, STAT, OMAP_MMC_STAT_END_OF_CMD);
398 OMAP_MMC_WRITE(host, IE, ie);
399}
400
401static void
366mmc_omap_end_of_data(struct mmc_omap_host *host, struct mmc_data *data) 402mmc_omap_end_of_data(struct mmc_omap_host *host, struct mmc_data *data)
367{ 403{
368 unsigned long flags; 404 unsigned long flags;
@@ -439,9 +475,14 @@ mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd)
439 } 475 }
440 476
441 if (host->data == NULL || cmd->error) { 477 if (host->data == NULL || cmd->error) {
478 struct mmc_host *mmc;
479
480 if (host->data != NULL)
481 mmc_omap_abort_xfer(host, host->data);
442 host->mrq = NULL; 482 host->mrq = NULL;
443 clk_disable(host->fclk); 483 mmc = host->mmc;
444 mmc_request_done(host->mmc, cmd->mrq); 484 mmc_omap_release_slot(host->current_slot);
485 mmc_request_done(mmc, cmd->mrq);
445 } 486 }
446} 487}
447 488