On 20 December 2012 12:11, Kevin Liu <kliu5@xxxxxxxxxxx> wrote: > Signed-off-by: Jialing Fu <jlfu@xxxxxxxxxxx> > Signed-off-by: Kevin Liu <kliu5@xxxxxxxxxxx> > --- > drivers/mmc/host/sdhci-pxav3.c | 89 ++++++++++++++++++++++++++++++++++++++- > 1 files changed, 86 insertions(+), 3 deletions(-) > > diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c > index fad0966..ba3a524 100644 > --- a/drivers/mmc/host/sdhci-pxav3.c > +++ b/drivers/mmc/host/sdhci-pxav3.c > @@ -32,10 +32,15 @@ > #include <linux/of.h> > #include <linux/of_device.h> > #include <linux/of_gpio.h> > +#include <linux/pm.h> > +#include <linux/pm_runtime.h> > +#include <plat/pm.h> > > #include "sdhci.h" > #include "sdhci-pltfm.h" > > +#define PXAV3_RPM_DELAY_MS 50 > + > #define SD_CLOCK_BURST_SIZE_SETUP 0x10A > #define SDCLK_SEL 0x100 > #define SDCLK_DELAY_SHIFT 9 > @@ -253,8 +258,9 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) > goto err_clk_get; > } > pltfm_host->clk = clk; > +#ifndef CONFIG_PM_RUNTIME I think it would be better to always enable the clk and the resourses you need in the probe function. To reflect that in runtime PM you shall use: pm_runtime_enable pm_runtime_get_noresume pm_runtime_set_active When you leave your probe function do pm_runtime_put*, to put back your resources and maybe enter Thus you can get rid of the ifdefs in the probe function. > clk_prepare_enable(clk); > - > +#endif > host->quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL > | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC > | SDHCI_QUIRK_32BIT_ADMA_SIZE > @@ -303,9 +309,17 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) > > sdhci_get_of_property(pdev); > > + pm_runtime_enable(&pdev->dev); > + pm_runtime_set_autosuspend_delay(&pdev->dev, > + PXAV3_RPM_DELAY_MS); > + pm_runtime_use_autosuspend(&pdev->dev); > + pm_suspend_ignore_children(&pdev->dev, 1); > + > ret = sdhci_add_host(host); > if (ret) { > dev_err(&pdev->dev, "failed to add host\n"); > + pm_runtime_forbid(&pdev->dev); > + pm_runtime_get_noresume(&pdev->dev); > goto err_add_host; > } > > @@ -314,7 +328,9 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) > return 0; > > err_add_host: > +#ifndef CONFIG_PM_RUNTIME > clk_disable_unprepare(clk); > +#endif > clk_put(clk); > mmc_gpio_free_cd(host->mmc); > err_cd_req: > @@ -332,8 +348,10 @@ static int sdhci_pxav3_remove(struct platform_device *pdev) > struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data; > > sdhci_remove_host(host, 1); > - > + pm_runtime_disable(&pdev->dev); > +#ifndef CONFIG_PM_RUNTIME > clk_disable_unprepare(pltfm_host->clk); > +#endif > clk_put(pltfm_host->clk); > > if (gpio_is_valid(pdata->ext_cd_gpio)) > @@ -347,6 +365,71 @@ static int sdhci_pxav3_remove(struct platform_device *pdev) > return 0; > } > > +#ifdef CONFIG_PM_SLEEP > +static int sdhci_pxav3_suspend(struct device *dev) > +{ > + struct sdhci_host *host = dev_get_drvdata(dev); > + > + return sdhci_suspend_host(host); > +} > + > +static int sdhci_pxav3_resume(struct device *dev) > +{ > + struct sdhci_host *host = dev_get_drvdata(dev); > + > + return sdhci_resume_host(host); > +} > +#endif > + > +#ifdef CONFIG_PM_RUNTIME > +static int sdhci_pxav3_runtime_suspend(struct device *dev) > +{ > + struct sdhci_host *host = dev_get_drvdata(dev); > + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); > + unsigned long flags; > + > + if (pltfm_host->clk) { > + spin_lock_irqsave(&host->lock, flags); > + host->runtime_suspended = true; > + spin_unlock_irqrestore(&host->lock, flags); > + > + clk_disable_unprepare(pltfm_host->clk); > + } > + > + return 0; > +} > + > +static int sdhci_pxav3_runtime_resume(struct device *dev) > +{ > + struct sdhci_host *host = dev_get_drvdata(dev); > + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); > + unsigned long flags; > + > + if (pltfm_host->clk) { > + clk_prepare_enable(pltfm_host->clk); > + > + spin_lock_irqsave(&host->lock, flags); > + host->runtime_suspended = false; > + spin_unlock_irqrestore(&host->lock, flags); > + } > + > + return 0; > +} > +#endif > + > +#ifdef CONFIG_PM > +static const struct dev_pm_ops sdhci_pxav3_pmops = { > + SET_SYSTEM_SLEEP_PM_OPS(sdhci_pxav3_suspend, sdhci_pxav3_resume) > + SET_RUNTIME_PM_OPS(sdhci_pxav3_runtime_suspend, > + sdhci_pxav3_runtime_resume, NULL) > +}; > + > +#define SDHCI_PXAV3_PMOPS (&sdhci_pxav3_pmops) > + > +#else > +#define SDHCI_PXAV3_PMOPS NULL > +#endif > + > static struct platform_driver sdhci_pxav3_driver = { > .driver = { > .name = "sdhci-pxav3", > @@ -354,7 +437,7 @@ static struct platform_driver sdhci_pxav3_driver = { > .of_match_table = sdhci_pxav3_of_match, > #endif > .owner = THIS_MODULE, > - .pm = SDHCI_PLTFM_PMOPS, > + .pm = SDHCI_PXAV3_PMOPS, > }, > .probe = sdhci_pxav3_probe, > .remove = sdhci_pxav3_remove, > -- > 1.7.0.4 > Kind regards Ulf Hansson -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html