Commit be138554 authored by Russell King's avatar Russell King Committed by Chris Ball

mmc: sdhci: allow sdio interrupts while sdhci runtime suspended

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: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
Tested-by: default avatarMarkus Pargmann <mpa@pengutronix.de>
Tested-by: default avatarStephen Warren <swarren@nvidia.com>
Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
Signed-off-by: default avatarChris Ball <chris@printf.net>
parent 3560db8e
...@@ -1170,8 +1170,10 @@ static int sdhci_esdhc_runtime_suspend(struct device *dev) ...@@ -1170,8 +1170,10 @@ static int sdhci_esdhc_runtime_suspend(struct device *dev)
ret = sdhci_runtime_suspend_host(host); ret = sdhci_runtime_suspend_host(host);
clk_disable_unprepare(imx_data->clk_per); if (!sdhci_sdio_irq_enabled(host)) {
clk_disable_unprepare(imx_data->clk_ipg); clk_disable_unprepare(imx_data->clk_per);
clk_disable_unprepare(imx_data->clk_ipg);
}
clk_disable_unprepare(imx_data->clk_ahb); clk_disable_unprepare(imx_data->clk_ahb);
return ret; return ret;
...@@ -1183,8 +1185,10 @@ static int sdhci_esdhc_runtime_resume(struct device *dev) ...@@ -1183,8 +1185,10 @@ static int sdhci_esdhc_runtime_resume(struct device *dev)
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = pltfm_host->priv; struct pltfm_imx_data *imx_data = pltfm_host->priv;
clk_prepare_enable(imx_data->clk_per); if (!sdhci_sdio_irq_enabled(host)) {
clk_prepare_enable(imx_data->clk_ipg); clk_prepare_enable(imx_data->clk_per);
clk_prepare_enable(imx_data->clk_ipg);
}
clk_prepare_enable(imx_data->clk_ahb); clk_prepare_enable(imx_data->clk_ahb);
return sdhci_runtime_resume_host(host); return sdhci_runtime_resume_host(host);
......
...@@ -1711,8 +1711,7 @@ static int sdhci_get_ro(struct mmc_host *mmc) ...@@ -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) 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)) {
if (!(host->flags & SDHCI_DEVICE_DEAD) || host->runtime_suspended) {
if (enable) if (enable)
sdhci_unmask_irqs(host, SDHCI_INT_CARD_INT); sdhci_unmask_irqs(host, SDHCI_INT_CARD_INT);
else else
...@@ -2426,7 +2425,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) ...@@ -2426,7 +2425,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
spin_lock(&host->lock); spin_lock(&host->lock);
if (host->runtime_suspended) { if (host->runtime_suspended && !sdhci_sdio_irq_enabled(host)) {
spin_unlock(&host->lock); spin_unlock(&host->lock);
return IRQ_NONE; return IRQ_NONE;
} }
...@@ -2692,7 +2691,7 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host) ...@@ -2692,7 +2691,7 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host)
} }
spin_lock_irqsave(&host->lock, flags); 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); spin_unlock_irqrestore(&host->lock, flags);
synchronize_hardirq(host->irq); synchronize_hardirq(host->irq);
......
...@@ -397,6 +397,11 @@ extern void sdhci_remove_host(struct sdhci_host *host, int dead); ...@@ -397,6 +397,11 @@ extern void sdhci_remove_host(struct sdhci_host *host, int dead);
extern void sdhci_send_command(struct sdhci_host *host, extern void sdhci_send_command(struct sdhci_host *host,
struct mmc_command *cmd); 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 #ifdef CONFIG_PM
extern int sdhci_suspend_host(struct sdhci_host *host); extern int sdhci_suspend_host(struct sdhci_host *host);
extern int sdhci_resume_host(struct sdhci_host *host); extern int sdhci_resume_host(struct sdhci_host *host);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment