Yunpeng, As we already discussed off-list, I disagree with the architecture of this patchset.
Sdhci host controller should be able to manage his own power management by taking usage counter of itself whenever there it gets a low level request. Please base on upstream in mmc-next commit 42b3ad66862a4e23bbe546bcd34a9a0c5218a987 Author: Linus Walleij <[email protected]> Date: Mon Nov 8 21:36:50 2010 -0500 mmc: Aggressive clock gating framework And use something like what I attach here (its just a poc, not a submission!) Pierre >From 8ac4fb50defd6181b38194d850d2ad3eb09c4acd Mon Sep 17 00:00:00 2001 From: Pierre Tardy <[email protected]> Date: Mon, 13 Dec 2010 18:21:47 +0100 Subject: [PATCH] sdhci-pci: implement runtime_pm We use aggressive clock gating patch to implement runtime_pm for sdhci Change-Id: I76d167116fa00575da9a58a0451d7e4058687aab Signed-off-by: Pierre Tardy <[email protected]> --- drivers/mmc/host/sdhci-pci.c | 86 ++++++++++++++++++++++++++++++++++++++++++ drivers/mmc/host/sdhci.c | 35 +++++++++++++++++ include/linux/mmc/sdhci.h | 1 + 3 files changed, 122 insertions(+), 0 deletions(-) diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index d2638ff..144af20 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -18,6 +18,7 @@ #include <linux/dma-mapping.h> #include <linux/slab.h> #include <linux/device.h> +#include <linux/pm_runtime.h> #include <linux/mmc/host.h> @@ -1081,6 +1082,10 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev, chip->slots[i] = slot; } + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + pm_runtime_allow(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev,100); return 0; free: @@ -1107,8 +1112,86 @@ static void __devexit sdhci_pci_remove(struct pci_dev *pdev) kfree(chip); } + pm_runtime_disable(&pdev->dev); + pm_runtime_forbid(&pdev->dev); + pci_disable_device(pdev); } +#ifdef CONFIG_PM_RUNTIME + +static int sdhci_pci_runtime_suspend(struct device *dev) +{ + struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); + struct sdhci_pci_chip *chip; + struct sdhci_pci_slot *slot; + int i; + mmc_pm_flag_t pm_flags = 0; + + chip = pci_get_drvdata(pdev); + if (!chip) + return 0; + + for (i = 0;i < chip->num_slots;i++) { + slot = chip->slots[i]; + if (!slot) + continue; + pm_flags |= slot->host->mmc->pm_flags; + } + + pci_save_state(pdev); + if (pm_flags & MMC_PM_KEEP_POWER) { + if (pm_flags & MMC_PM_WAKE_SDIO_IRQ) + pci_enable_wake(pdev, PCI_D3hot, 1); + } else { + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_disable_device(pdev); + } + pci_set_power_state(pdev, PCI_D3hot); + + return 0; +} + +static int sdhci_pci_runtime_resume(struct device *dev) +{ + struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); + struct sdhci_pci_chip *chip; + struct sdhci_pci_slot *slot; + int ret, i; + + chip = pci_get_drvdata(pdev); + if (!chip) + return 0; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + ret = pci_enable_device(pdev); + if (ret) + return ret; + + for (i = 0;i < chip->num_slots;i++) { + slot = chip->slots[i]; + if (!slot) + continue; + + ret = sdhci_runtime_init(slot->host); + if (ret) + return ret; + } + + return 0; +} + +#else + +#define sdhci_pci_runtime_suspend NULL +#define sdhci_pci_runtime_resume NULL + +#endif + +static const struct dev_pm_ops sdhci_pci_pm_ops = { + .runtime_suspend = sdhci_pci_runtime_suspend, + .runtime_resume = sdhci_pci_runtime_resume, +}; static struct pci_driver sdhci_driver = { .name = "sdhci-pci", @@ -1117,6 +1200,9 @@ static struct pci_driver sdhci_driver = { .remove = __devexit_p(sdhci_pci_remove), .suspend = sdhci_pci_suspend, .resume = sdhci_pci_resume, + .driver = { + .pm = &sdhci_pci_pm_ops + }, }; /*****************************************************************************\ diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 508ea5a..7a01831 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -991,6 +991,23 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) u16 clk; unsigned long timeout; + /* + * Turn on clock whenever ios->clock transitions + * from 0 to !=0 and gate it off whenever ios->clock + * transitions from !=0 to 0. + */ + if (host->iosclock == 0 && ios->clock != 0) { + pm_runtime_get_sync(host->mmc->parent); + /* make sure we reconfigure the clock */ + host->clock = 0; + } + else if (host->iosclock != 0 && ios->clock == 0) { + pm_runtime_put_autosuspend(host->mmc->parent); + return; + } + + host->iosclock = ios->clock; + if (clock == host->clock) return; @@ -1376,6 +1393,7 @@ static void sdhci_tasklet_finish(unsigned long param) mmiowb(); spin_unlock_irqrestore(&host->lock, flags); + pm_runtime_mark_last_busy(host->mmc->parent); mmc_request_done(host->mmc, mrq); } @@ -1709,6 +1727,23 @@ void sdhci_enable_irq_wakeups(struct sdhci_host *host) EXPORT_SYMBOL_GPL(sdhci_enable_irq_wakeups); #endif /* CONFIG_PM */ +#ifdef CONFIG_PM_RUNTIME +int sdhci_runtime_init(struct sdhci_host *host) +{ + struct mmc_host *mmc = host->mmc; + + if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { + if (host->ops->enable_dma) + host->ops->enable_dma(host); + } + sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER)); + + mmiowb(); + + return 0; +} +EXPORT_SYMBOL_GPL(sdhci_runtime_init); +#endif /*****************************************************************************\ * * diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h index 0d953f5..e801776 100644 --- a/include/linux/mmc/sdhci.h +++ b/include/linux/mmc/sdhci.h @@ -114,6 +114,7 @@ struct sdhci_host { unsigned int timeout_clk; /* Timeout freq (KHz) */ unsigned int clock; /* Current clock (MHz) */ + unsigned int iosclock; /* last iosclock (MHz) */ u8 pwr; /* Current voltage */ struct mmc_request *mrq; /* Current request */ -- 1.7.0.4 --------------------------------------------------------------------- Intel Corporation SAS (French simplified joint stock company) Registered headquarters: "Les Montalets"- 2, rue de Paris, 92196 Meudon Cedex, France Registration Number: 302 456 199 R.C.S. NANTERRE Capital: 4,572,000 Euros This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). Any review or distribution by others is strictly prohibited. If you are not the intended recipient, please contact the sender and delete all copies. _______________________________________________ MeeGo-kernel mailing list [email protected] http://lists.meego.com/listinfo/meego-kernel
