mmc: sdhci: allow sdio interrupts while sdhci runtime suspended
authorRussell King <rmk+kernel@arm.linux.org.uk>
Fri, 25 Apr 2014 11:55:56 +0000 (12:55 +0100)
committerChris Ball <chris@printf.net>
Thu, 22 May 2014 11:26:26 +0000 (07:26 -0400)
Allow SDIO interrupts to be received while the SDHCI host is runtime
suspended.  We do this by leaving the AHB clock enabled while the
host is runtime suspended so we can access the SDHCI registers, and
so read and raise the SDIO card interrupt.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Tested-by: Markus Pargmann <mpa@pengutronix.de>
Tested-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Chris Ball <chris@printf.net>
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h

index b841bb7cd3714c11982a7f2b652a946dfb5e811c..b0b4eea8d232b9235d9edd41ab98d319e501db44 100644 (file)
@@ -1170,8 +1170,10 @@ static int sdhci_esdhc_runtime_suspend(struct device *dev)
 
        ret = sdhci_runtime_suspend_host(host);
 
-       clk_disable_unprepare(imx_data->clk_per);
-       clk_disable_unprepare(imx_data->clk_ipg);
+       if (!sdhci_sdio_irq_enabled(host)) {
+               clk_disable_unprepare(imx_data->clk_per);
+               clk_disable_unprepare(imx_data->clk_ipg);
+       }
        clk_disable_unprepare(imx_data->clk_ahb);
 
        return ret;
@@ -1183,8 +1185,10 @@ static int sdhci_esdhc_runtime_resume(struct device *dev)
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct pltfm_imx_data *imx_data = pltfm_host->priv;
 
-       clk_prepare_enable(imx_data->clk_per);
-       clk_prepare_enable(imx_data->clk_ipg);
+       if (!sdhci_sdio_irq_enabled(host)) {
+               clk_prepare_enable(imx_data->clk_per);
+               clk_prepare_enable(imx_data->clk_ipg);
+       }
        clk_prepare_enable(imx_data->clk_ahb);
 
        return sdhci_runtime_resume_host(host);
index 8def3919b32c7deb975e20fbef3cb56c5c452799..0ecbcc4c29d217a7062bbeb1ecf961024c3e97ff 100644 (file)
@@ -1711,8 +1711,7 @@ static int sdhci_get_ro(struct mmc_host *mmc)
 
 static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable)
 {
-       /* SDIO IRQ will be enabled as appropriate in runtime resume */
-       if (!(host->flags & SDHCI_DEVICE_DEAD) || host->runtime_suspended) {
+       if (!(host->flags & SDHCI_DEVICE_DEAD)) {
                if (enable)
                        sdhci_unmask_irqs(host, SDHCI_INT_CARD_INT);
                else
@@ -2426,7 +2425,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
 
        spin_lock(&host->lock);
 
-       if (host->runtime_suspended) {
+       if (host->runtime_suspended && !sdhci_sdio_irq_enabled(host)) {
                spin_unlock(&host->lock);
                return IRQ_NONE;
        }
@@ -2692,7 +2691,7 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host)
        }
 
        spin_lock_irqsave(&host->lock, flags);
-       sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
+       sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK & ~SDHCI_INT_CARD_INT);
        spin_unlock_irqrestore(&host->lock, flags);
 
        synchronize_hardirq(host->irq);
index 0a3ed01887db824da03a66f103ef4b4948fc074f..fc6f81d2f377f5d4500d3ddfc20e6fed5a62a641 100644 (file)
@@ -397,6 +397,11 @@ extern void sdhci_remove_host(struct sdhci_host *host, int dead);
 extern void sdhci_send_command(struct sdhci_host *host,
                                struct mmc_command *cmd);
 
+static inline bool sdhci_sdio_irq_enabled(struct sdhci_host *host)
+{
+       return !!(host->flags & SDHCI_SDIO_IRQ_ENABLED);
+}
+
 #ifdef CONFIG_PM
 extern int sdhci_suspend_host(struct sdhci_host *host);
 extern int sdhci_resume_host(struct sdhci_host *host);