From a1b13b4e18d62ea60aad9554f35d79c51328b8b6 Mon Sep 17 00:00:00 2001 From: Chris Ball Date: Mon, 6 Feb 2012 00:43:59 -0500 Subject: mmc: sdhci: Add platform suspend/resume hooks. Some platforms require saving/restoring registers across suspend/resume; this hook allows them to do that inside their driver. Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/mmc/host/sdhci.c') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 8d66706824a6..1f5888b42b2c 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2379,6 +2379,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 */ @@ -2429,6 +2432,9 @@ int sdhci_resume_host(struct sdhci_host *host) 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)) -- cgit v1.2.3 From 6308d2905bd30290d90f28730828fd572161dd11 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 7 Feb 2012 14:48:54 +0200 Subject: mmc: sdhci: add quirk for keeping card power during suspend Add quirk SDHCI_QUIRK2_HOST_OFF_CARD_ON to cater for the case when the card keeps power during suspend but the host controller does not i.e. the card power is not controlled by the host controller. In that case, the controller must be fully reset on resume. Signed-off-by: Adrian Hunter Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers/mmc/host/sdhci.c') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 1f5888b42b2c..80cc7847c531 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2426,8 +2426,17 @@ 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); -- cgit v1.2.3 From 6379b2375a0c5a6ad437616a4018e6b8fd95e97c Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Wed, 14 Mar 2012 09:52:10 +0100 Subject: mmc: sdhci: check interrupt flags in ISR again When using MSI it is possible that a new MSI is sent while an earlier MSI is currently handled. In this case SDHCI_INT_STATUS only contains SDHCI_INT_RESPONSE and the ISR would not be called again. But at the end of the ISR SDHCI_INT_DATA_END is now also pending which would be ignored. Fix this by rereading the interrupt flags in the ISR until no interrupt we care is pending. Signed-off-by: Alexander Stein Acked-by: Adrian Hunter Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'drivers/mmc/host/sdhci.c') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 80cc7847c531..8262cadfdab7 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -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. */ -- cgit v1.2.3 From 4188bba0e9e7ba58d231b528df495666f2742b74 Mon Sep 17 00:00:00 2001 From: Al Cooper Date: Fri, 16 Mar 2012 15:54:17 -0400 Subject: mmc: Prevent 1.8V switch for SD hosts that don't support UHS modes. The driver should not try to switch to 1.8V when the SD 3.0 host controller does not have any UHS capabilities bits set (SDR50, DDR50 or SDR104). See page 72 of "SD Specifications Part A2 SD Host Controller Simplified Specification Version 3.00" under "1.8V Signaling Enable". Instead of setting SDR12 and SDR25 in the host capabilities data structure for all V3.0 host controllers, only set them if SDR104, SDR50 or DDR50 is set in the host capabilities register. This will prevent the switch to 1.8V later. Signed-off-by: Al Cooper Acked-by: Arindam Nath Acked-by: Philip Rakity Acked-by: Girish K S Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/mmc/host/sdhci.c') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 8262cadfdab7..9aa77f3f04a8 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2782,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 */ -- cgit v1.2.3