After a runtime or system-wide suspend the clock frequency can change, therefore it must be re-read.
Signed-off-by: Guennadi Liakhovetski <g.liakhovet...@gmx.de> --- v2: move updating the clock frequency from .runtime_resume() to .start(), since the former is not called, when power domains are used and when the domain is not powered off and on - thanks to Magnus for pointing out. This version requires my patch from several minutes ago "PM: provide a dummy dev_gpd_data() when generic domains are not used." http://article.gmane.org/gmane.linux.ports.sh.devel/13487 drivers/mmc/host/sh_mobile_sdhi.c | 20 ++++++++++++++++++++ drivers/mmc/host/tmio_mmc.h | 1 + drivers/mmc/host/tmio_mmc_pio.c | 26 +++++++++++++++++++++----- include/linux/mfd/tmio.h | 1 + 4 files changed, 43 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 2c3a9d3..2842ab9 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -23,6 +23,7 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/pm_domain.h> #include <linux/mmc/host.h> #include <linux/mmc/sh_mobile_sdhi.h> #include <linux/mfd/tmio.h> @@ -47,6 +48,15 @@ static void sh_mobile_sdhi_set_pwr(struct platform_device *pdev, int state) p->set_pwr(pdev, state); } +static unsigned int sh_mobile_sdhi_get_clk_rate(struct platform_device *pdev) +{ + struct mmc_host *mmc = platform_get_drvdata(pdev); + struct tmio_mmc_host *host = mmc_priv(mmc); + struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data); + + return clk_get_rate(priv->clk); +} + static int sh_mobile_sdhi_get_cd(struct platform_device *pdev) { struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; @@ -95,6 +105,7 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) struct sh_mobile_sdhi *priv; struct tmio_mmc_data *mmc_data; struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; + struct generic_pm_domain_data *gpdd; struct tmio_mmc_host *host; char clk_name[8]; int irq, ret, i = 0; @@ -120,6 +131,7 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) mmc_data->hclk = clk_get_rate(priv->clk); mmc_data->set_pwr = sh_mobile_sdhi_set_pwr; mmc_data->get_cd = sh_mobile_sdhi_get_cd; + mmc_data->get_clk_rate = sh_mobile_sdhi_get_clk_rate; mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED; if (p) { mmc_data->flags = p->tmio_flags; @@ -208,6 +220,10 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) goto eirq_multiplexed; } + gpdd = dev_gpd_data(&pdev->dev); + if (gpdd) + gpdd->ops.start = tmio_mmc_host_start; + dev_info(&pdev->dev, "%s base at 0x%08lx clock rate %u MHz\n", mmc_hostname(host->mmc), (unsigned long) (platform_get_resource(pdev, IORESOURCE_MEM, 0)->start), @@ -243,8 +259,12 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev) struct tmio_mmc_host *host = mmc_priv(mmc); struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data); struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; + struct generic_pm_domain_data *gpdd = dev_gpd_data(&pdev->dev); int i = 0, irq; + if (gpdd) + gpdd->ops.start = NULL; + p->pdata = NULL; tmio_mmc_host_remove(host); diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index d857f5c..3943647 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -156,6 +156,7 @@ int tmio_mmc_host_resume(struct device *dev); int tmio_mmc_host_runtime_suspend(struct device *dev); int tmio_mmc_host_runtime_resume(struct device *dev); +int tmio_mmc_host_start(struct device *dev); static inline u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr) { diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 08f3e67..69b826a 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -900,7 +900,10 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host, mmc->ops = &tmio_mmc_ops; mmc->caps = MMC_CAP_4_BIT_DATA | pdata->capabilities; - mmc->f_max = pdata->hclk; + if (pdata->get_clk_rate) + mmc->f_max = pdata->get_clk_rate(pdev); + else + mmc->f_max = pdata->hclk; mmc->f_min = mmc->f_max / 512; mmc->max_segs = 32; mmc->max_blk_size = 512; @@ -1034,16 +1037,14 @@ EXPORT_SYMBOL(tmio_mmc_host_suspend); int tmio_mmc_host_resume(struct device *dev) { struct mmc_host *mmc = dev_get_drvdata(dev); - struct tmio_mmc_host *host = mmc_priv(mmc); - tmio_mmc_reset(host); - tmio_mmc_enable_dma(host, true); + tmio_mmc_host_start(dev); + tmio_mmc_host_runtime_resume(dev); /* The MMC core will perform the complete set up */ return mmc_resume_host(mmc); } EXPORT_SYMBOL(tmio_mmc_host_resume); - #endif /* CONFIG_PM */ int tmio_mmc_host_runtime_suspend(struct device *dev) @@ -1064,4 +1065,19 @@ int tmio_mmc_host_runtime_resume(struct device *dev) } EXPORT_SYMBOL(tmio_mmc_host_runtime_resume); +int tmio_mmc_host_start(struct device *dev) +{ + struct mmc_host *mmc = dev_get_drvdata(dev); + struct tmio_mmc_host *host = mmc_priv(mmc); + struct tmio_mmc_data *pdata = host->pdata; + + if (pdata->get_clk_rate) { + mmc->f_max = pdata->get_clk_rate(host->pdev); + mmc->f_min = mmc->f_max / 512; + } + + return 0; +} +EXPORT_SYMBOL(tmio_mmc_host_start); + MODULE_LICENSE("GPL v2"); diff --git a/include/linux/mfd/tmio.h b/include/linux/mfd/tmio.h index f5171db..020a737 100644 --- a/include/linux/mfd/tmio.h +++ b/include/linux/mfd/tmio.h @@ -108,6 +108,7 @@ struct tmio_mmc_data { unsigned int cd_gpio; void (*set_pwr)(struct platform_device *host, int state); void (*set_clk_div)(struct platform_device *host, int state); + unsigned int (*get_clk_rate)(struct platform_device *host); int (*get_cd)(struct platform_device *host); int (*write16_hook)(struct tmio_mmc_host *host, int addr); }; -- 1.7.2.5 -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html