diff options
| -rw-r--r-- | drivers/mmc/host/omap_hsmmc.c | 54 |
1 files changed, 30 insertions, 24 deletions
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 8d21a07f63de..a631c81dce12 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c | |||
| @@ -376,6 +376,32 @@ static void mmc_omap_report_irq(struct mmc_omap_host *host, u32 status) | |||
| 376 | } | 376 | } |
| 377 | #endif /* CONFIG_MMC_DEBUG */ | 377 | #endif /* CONFIG_MMC_DEBUG */ |
| 378 | 378 | ||
| 379 | /* | ||
| 380 | * MMC controller internal state machines reset | ||
| 381 | * | ||
| 382 | * Used to reset command or data internal state machines, using respectively | ||
| 383 | * SRC or SRD bit of SYSCTL register | ||
| 384 | * Can be called from interrupt context | ||
| 385 | */ | ||
| 386 | static inline void mmc_omap_reset_controller_fsm(struct mmc_omap_host *host, | ||
| 387 | unsigned long bit) | ||
| 388 | { | ||
| 389 | unsigned long i = 0; | ||
| 390 | unsigned long limit = (loops_per_jiffy * | ||
| 391 | msecs_to_jiffies(MMC_TIMEOUT_MS)); | ||
| 392 | |||
| 393 | OMAP_HSMMC_WRITE(host->base, SYSCTL, | ||
| 394 | OMAP_HSMMC_READ(host->base, SYSCTL) | bit); | ||
| 395 | |||
| 396 | while ((OMAP_HSMMC_READ(host->base, SYSCTL) & bit) && | ||
| 397 | (i++ < limit)) | ||
| 398 | cpu_relax(); | ||
| 399 | |||
| 400 | if (OMAP_HSMMC_READ(host->base, SYSCTL) & bit) | ||
| 401 | dev_err(mmc_dev(host->mmc), | ||
| 402 | "Timeout waiting on controller reset in %s\n", | ||
| 403 | __func__); | ||
| 404 | } | ||
| 379 | 405 | ||
| 380 | /* | 406 | /* |
| 381 | * MMC controller IRQ handler | 407 | * MMC controller IRQ handler |
| @@ -404,13 +430,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) | |||
| 404 | (status & CMD_CRC)) { | 430 | (status & CMD_CRC)) { |
| 405 | if (host->cmd) { | 431 | if (host->cmd) { |
| 406 | if (status & CMD_TIMEOUT) { | 432 | if (status & CMD_TIMEOUT) { |
| 407 | OMAP_HSMMC_WRITE(host->base, SYSCTL, | 433 | mmc_omap_reset_controller_fsm(host, SRC); |
| 408 | OMAP_HSMMC_READ(host->base, | ||
| 409 | SYSCTL) | SRC); | ||
| 410 | while (OMAP_HSMMC_READ(host->base, | ||
| 411 | SYSCTL) & SRC) | ||
| 412 | ; | ||
| 413 | |||
| 414 | host->cmd->error = -ETIMEDOUT; | 434 | host->cmd->error = -ETIMEDOUT; |
| 415 | } else { | 435 | } else { |
| 416 | host->cmd->error = -EILSEQ; | 436 | host->cmd->error = -EILSEQ; |
| @@ -419,12 +439,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) | |||
| 419 | } | 439 | } |
| 420 | if (host->data) { | 440 | if (host->data) { |
| 421 | mmc_dma_cleanup(host); | 441 | mmc_dma_cleanup(host); |
| 422 | OMAP_HSMMC_WRITE(host->base, SYSCTL, | 442 | mmc_omap_reset_controller_fsm(host, SRD); |
| 423 | OMAP_HSMMC_READ(host->base, | ||
| 424 | SYSCTL) | SRD); | ||
| 425 | while (OMAP_HSMMC_READ(host->base, | ||
| 426 | SYSCTL) & SRD) | ||
| 427 | ; | ||
| 428 | } | 443 | } |
| 429 | } | 444 | } |
| 430 | if ((status & DATA_TIMEOUT) || | 445 | if ((status & DATA_TIMEOUT) || |
| @@ -434,12 +449,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) | |||
| 434 | mmc_dma_cleanup(host); | 449 | mmc_dma_cleanup(host); |
| 435 | else | 450 | else |
| 436 | host->data->error = -EILSEQ; | 451 | host->data->error = -EILSEQ; |
| 437 | OMAP_HSMMC_WRITE(host->base, SYSCTL, | 452 | mmc_omap_reset_controller_fsm(host, SRD); |
| 438 | OMAP_HSMMC_READ(host->base, | ||
| 439 | SYSCTL) | SRD); | ||
| 440 | while (OMAP_HSMMC_READ(host->base, | ||
| 441 | SYSCTL) & SRD) | ||
| 442 | ; | ||
| 443 | end_trans = 1; | 453 | end_trans = 1; |
| 444 | } | 454 | } |
| 445 | } | 455 | } |
| @@ -547,11 +557,7 @@ static void mmc_omap_detect(struct work_struct *work) | |||
| 547 | if (host->carddetect) { | 557 | if (host->carddetect) { |
| 548 | mmc_detect_change(host->mmc, (HZ * 200) / 1000); | 558 | mmc_detect_change(host->mmc, (HZ * 200) / 1000); |
| 549 | } else { | 559 | } else { |
| 550 | OMAP_HSMMC_WRITE(host->base, SYSCTL, | 560 | mmc_omap_reset_controller_fsm(host, SRD); |
| 551 | OMAP_HSMMC_READ(host->base, SYSCTL) | SRD); | ||
| 552 | while (OMAP_HSMMC_READ(host->base, SYSCTL) & SRD) | ||
| 553 | ; | ||
| 554 | |||
| 555 | mmc_detect_change(host->mmc, (HZ * 50) / 1000); | 561 | mmc_detect_change(host->mmc, (HZ * 50) / 1000); |
| 556 | } | 562 | } |
| 557 | } | 563 | } |
