summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRahul Bansal <rbansal@nvidia.com>2010-08-20 18:22:12 +0530
committerBharat Nihalani <bnihalani@nvidia.com>2010-08-31 05:31:16 -0700
commit30d90c8af0bb790e4ce2cf256dcb4ff87ad9e3a8 (patch)
tree54ebe7051949ba59860023bd33c980781e6d891e
parent9b19c94aafed014ce68ee16df37897c437dd8c68 (diff)
tegra sdhci: Restore SDHCI interrupts on resume
On resume restore SDHCI interrupts to the state which was before entering into suspend for SDIO (always_pwr_on) slot. Also, in suspend keep CARD_INT enabled if it was before going to suspend, so that it can be used as wake source. Broadcom wifi driver does not disable/enable SDIO_INT on early_suspend/late_resume, it requires SDIO INTs to be enabled on resume, as even before broadcom driver's late_resume is called which puts wifi is high_pwr, it needs to communicate with MAC for incoming IOCTLs from wpa_supplicant. Bug: 723708 Change-Id: Id1bfe67f415080eeb7563428322dbec3df0f27d2 Reviewed-on: http://git-master/r/5407 Reviewed-by: Rahul Bansal <rbansal@nvidia.com> Tested-by: Rahul Bansal <rbansal@nvidia.com> Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
-rwxr-xr-xdrivers/mmc/host/sdhci-tegra.c63
1 files changed, 35 insertions, 28 deletions
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index fa85df14b962..6061d713e7ca 100755
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -55,6 +55,7 @@ struct tegra_sdhci {
bool card_present;
bool clk_enable;
bool card_always_on;
+ u32 sdhci_ints;
};
static inline unsigned long res_size(struct resource *res)
@@ -386,31 +387,24 @@ static int tegra_sdhci_remove(struct platform_device *pdev)
#if defined(CONFIG_PM)
#define dev_to_host(_dev) platform_get_drvdata(to_platform_device(_dev))
-static void tegra_sdhci_configure_interrupts(struct sdhci_host *sdhost, bool enable)
+static void tegra_sdhci_restore_interrupts(struct sdhci_host *sdhost)
{
u32 ierr;
u32 clear = SDHCI_INT_ALL_MASK;
- u32 set;
-
- if (enable) {
- /* enable required MMC INTs */
- set = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
- SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX |
- SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |
- SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE;
-
- ierr = sdhci_readl(sdhost, SDHCI_INT_ENABLE);
- ierr &= clear;
- ierr |= set;
- sdhci_writel(sdhost, ierr, SDHCI_INT_ENABLE);
- sdhci_writel(sdhost, ierr, SDHCI_SIGNAL_ENABLE);
- } else {
- /* disable the interrupts */
- ierr = sdhci_readl(sdhost, SDHCI_INT_ENABLE);
- /* Card interrupt masking is done by sdio client driver */
- ierr &= SDHCI_INT_CARD_INT;
- sdhci_writel(sdhost, ierr, SDHCI_INT_ENABLE);
- sdhci_writel(sdhost, ierr, SDHCI_SIGNAL_ENABLE);
+ struct tegra_sdhci *host = sdhci_priv(sdhost);
+
+ /* enable required interrupts */
+ ierr = sdhci_readl(sdhost, SDHCI_INT_ENABLE);
+ ierr &= ~clear;
+ ierr |= host->sdhci_ints;
+ sdhci_writel(sdhost, ierr, SDHCI_INT_ENABLE);
+ sdhci_writel(sdhost, ierr, SDHCI_SIGNAL_ENABLE);
+
+ if ( (host->sdhci_ints & SDHCI_INT_CARD_INT) &&
+ (sdhost->quirks & SDHCI_QUIRK_ENABLE_INTERRUPT_AT_BLOCK_GAP)) {
+ u8 gap_ctrl = sdhci_readb(sdhost, SDHCI_BLOCK_GAP_CONTROL);
+ gap_ctrl |= 0x8;
+ sdhci_writeb(sdhost, gap_ctrl, SDHCI_BLOCK_GAP_CONTROL);
}
}
@@ -437,7 +431,7 @@ static int tegra_sdhci_restore(struct sdhci_host *sdhost)
mdelay(1);
}
- tegra_sdhci_configure_interrupts(sdhost, true);
+ tegra_sdhci_restore_interrupts(sdhost);
sdhost->last_clk = 0;
return 0;
}
@@ -449,17 +443,30 @@ static int tegra_sdhci_suspend(struct device *dev)
struct pm_message event = { PM_EVENT_SUSPEND };
int ret = 0;
- if(host->card_always_on && is_card_sdio(sdhost->mmc->card)) {
+ if (host->card_always_on && is_card_sdio(sdhost->mmc->card)) {
struct mmc_ios ios;
ios.clock = 0;
ios.vdd = 0;
ios.power_mode = MMC_POWER_OFF;
ios.bus_width = MMC_BUS_WIDTH_1;
ios.timing = MMC_TIMING_LEGACY;
- sdhost->mmc->ops->set_ios(sdhost->mmc, &ios);
- /* Disable the interrupts */
- tegra_sdhci_configure_interrupts(sdhost, false);
+ /* save interrupt status before suspending */
+ host->sdhci_ints = sdhci_readl(sdhost, SDHCI_INT_ENABLE);
+ sdhost->mmc->ops->set_ios(sdhost->mmc, &ios);
+ /* keep CARD_INT enabled - if used as wakeup source */
+ if (host->sdhci_ints & SDHCI_INT_CARD_INT) {
+ u32 ier = sdhci_readl(host, SDHCI_INT_ENABLE);
+ ier |= SDHCI_INT_CARD_INT;
+ sdhci_writel(host, ier, SDHCI_INT_ENABLE);
+ sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE);
+
+ if (sdhost->quirks & SDHCI_QUIRK_ENABLE_INTERRUPT_AT_BLOCK_GAP) {
+ u8 gap_ctrl = sdhci_readb(sdhost, SDHCI_BLOCK_GAP_CONTROL);
+ gap_ctrl |= 0x8;
+ sdhci_writeb(sdhost, gap_ctrl, SDHCI_BLOCK_GAP_CONTROL);
+ }
+ }
return ret;
}
@@ -489,7 +496,7 @@ static int tegra_sdhci_resume(struct device *dev)
if(host->card_always_on && is_card_sdio(sdhost->mmc->card)) {
int ret = 0;
- /* soft reset SD host controller and enable MMC INTs */
+ /* soft reset SD host controller and enable interrupts */
ret = tegra_sdhci_restore(sdhost);
if (ret) {
dev_err(dev, "failed to resume host\n");