diff options
Diffstat (limited to 'drivers/mmc/host/sdhci.c')
-rw-r--r-- | drivers/mmc/host/sdhci.c | 45 |
1 files changed, 33 insertions, 12 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 8d66706824a6..ccefdebeff14 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -147,7 +147,7 @@ static void sdhci_set_card_detection(struct sdhci_host *host, bool enable) u32 present, irqs; if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) || - !mmc_card_is_removable(host->mmc)) + (host->mmc->caps & MMC_CAP_NONREMOVABLE)) return; present = sdhci_readl(host, SDHCI_PRESENT_STATE) & @@ -2267,8 +2267,8 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) { irqreturn_t result; struct sdhci_host *host = dev_id; - u32 intmask; - int cardint = 0; + u32 intmask, unexpected = 0; + int cardint = 0, max_loops = 16; spin_lock(&host->lock); @@ -2286,6 +2286,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) goto out; } +again: DBG("*** %s got interrupt: 0x%08x\n", mmc_hostname(host->mmc), intmask); @@ -2344,19 +2345,23 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) intmask &= ~SDHCI_INT_CARD_INT; if (intmask) { - pr_err("%s: Unexpected interrupt 0x%08x.\n", - mmc_hostname(host->mmc), intmask); - sdhci_dumpregs(host); - + unexpected |= intmask; sdhci_writel(host, intmask, SDHCI_INT_STATUS); } result = IRQ_HANDLED; - mmiowb(); + intmask = sdhci_readl(host, SDHCI_INT_STATUS); + if (intmask && --max_loops) + goto again; out: spin_unlock(&host->lock); + if (unexpected) { + pr_err("%s: Unexpected interrupt 0x%08x.\n", + mmc_hostname(host->mmc), unexpected); + sdhci_dumpregs(host); + } /* * We have to delay this as it calls back into the driver. */ @@ -2379,6 +2384,9 @@ int sdhci_suspend_host(struct sdhci_host *host) int ret; bool has_tuning_timer; + if (host->ops->platform_suspend) + host->ops->platform_suspend(host); + sdhci_disable_card_detection(host); /* Disable tuning since we are suspending */ @@ -2423,12 +2431,24 @@ int sdhci_resume_host(struct sdhci_host *host) if (ret) return ret; - sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER)); - mmiowb(); + if ((host->mmc->pm_flags & MMC_PM_KEEP_POWER) && + (host->quirks2 & SDHCI_QUIRK2_HOST_OFF_CARD_ON)) { + /* Card keeps power but host controller does not */ + sdhci_init(host, 0); + host->pwr = 0; + host->clock = 0; + sdhci_do_set_ios(host, &host->mmc->ios); + } else { + sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER)); + mmiowb(); + } ret = mmc_resume_host(host->mmc); sdhci_enable_card_detection(host); + if (host->ops->platform_resume) + host->ops->platform_resume(host); + /* Set the re-tuning expiration flag */ if ((host->version >= SDHCI_SPEC_300) && host->tuning_count && (host->tuning_mode == SDHCI_TUNING_MODE_1)) @@ -2762,8 +2782,9 @@ int sdhci_add_host(struct sdhci_host *host) mmc_card_is_removable(mmc)) mmc->caps |= MMC_CAP_NEEDS_POLL; - /* UHS-I mode(s) supported by the host controller. */ - if (host->version >= SDHCI_SPEC_300) + /* Any UHS-I mode in caps implies SDR12 and SDR25 support. */ + if (caps[1] & (SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | + SDHCI_SUPPORT_DDR50)) mmc->caps |= MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25; /* SDR104 supports also implies SDR50 support */ |