@@ -1089,6 +1089,9 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev,
chip->slots[i] = slot;
}
+ pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_suspend_ignore_children(&pdev->dev, 1);
pm_runtime_put_noidle(&pdev->dev);
return 0;
@@ -20,6 +20,7 @@
#include <linux/slab.h>
#include <linux/scatterlist.h>
#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
#include <linux/leds.h>
@@ -1161,6 +1162,7 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct sdhci_host *host;
unsigned long flags;
+ unsigned int lastclock;
u8 ctrl;
host = mmc_priv(mmc);
@@ -1171,6 +1173,27 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
goto out;
/*
+ * get/put runtime_pm usage counter at ios->clock transitions
+ * We need to do it before any other chip access, as sdhci could
+ * be power gated
+ */
+ lastclock = host->iosclock;
+ host->iosclock = ios->clock;
+ if (lastclock == 0 && ios->clock != 0) {
+ spin_unlock_irqrestore(&host->lock, flags);
+ pm_runtime_get_sync(host->mmc->parent);
+ spin_lock_irqsave(&host->lock, flags);
+ } else if (lastclock != 0 && ios->clock == 0) {
+ spin_unlock_irqrestore(&host->lock, flags);
+ pm_runtime_mark_last_busy(host->mmc->parent);
+ pm_runtime_put_autosuspend(host->mmc->parent);
+ spin_lock_irqsave(&host->lock, flags);
+ }
+ /* no need to configure the rest.. */
+ if (host->iosclock == 0)
+ goto out;
+
+ /*
* Reset the chip on each power off.
* Should clear out any weird states.
*/
@@ -1244,6 +1267,8 @@ static int sdhci_get_ro(struct mmc_host *mmc)
int is_readonly;
host = mmc_priv(mmc);
+ /* this function is called before set_ios... */
+ pm_runtime_get_sync(mmc->parent);
spin_lock_irqsave(&host->lock, flags);
@@ -1257,6 +1282,7 @@ static int sdhci_get_ro(struct mmc_host *mmc)
spin_unlock_irqrestore(&host->lock, flags);
+ pm_runtime_put_autosuspend(mmc->parent);
/* This quirk needs to be replaced by a callback-function later */
return host->quirks & SDHCI_QUIRK_INVERTED_WRITE_PROTECT ?
!is_readonly : is_readonly;
@@ -1268,6 +1294,7 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
unsigned long flags;
host = mmc_priv(mmc);
+ pm_runtime_get_sync(mmc->parent);
spin_lock_irqsave(&host->lock, flags);
@@ -1282,6 +1309,7 @@ out:
mmiowb();
spin_unlock_irqrestore(&host->lock, flags);
+ pm_runtime_put_autosuspend(mmc->parent);
}
static const struct mmc_host_ops sdhci_ops = {
@@ -1766,6 +1794,7 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev,
host = mmc_priv(mmc);
host->mmc = mmc;
+ host->iosclock = 0;
return host;
}
@@ -116,6 +116,7 @@ struct sdhci_host {
unsigned int timeout_clk; /* Timeout freq (KHz) */
unsigned int clock; /* Current clock (MHz) */
+ unsigned int iosclock; /* Last clock asked via set_ios */
u8 pwr; /* Current voltage */
struct mmc_request *mrq; /* Current request */