diff options
-rw-r--r-- | drivers/mmc/host/omap.c | 79 |
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 | ||
329 | static void | 329 | static void |
330 | mmc_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 | |||
348 | static void | ||
330 | mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data) | 349 | mmc_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 | ||
365 | static void | 375 | static void |
376 | mmc_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 | |||
401 | static void | ||
366 | mmc_omap_end_of_data(struct mmc_omap_host *host, struct mmc_data *data) | 402 | mmc_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 | ||