diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index 56afe0a00f56..aae39125b8d7 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -171,6 +171,7 @@ struct mmc_davinci_host { #define DAVINCI_MMC_DATADIR_READ 1 #define DAVINCI_MMC_DATADIR_WRITE 2 unsigned char data_dir; + unsigned char suspended; /* buffer is used during PIO of one scatterlist segment, and * is updated along with buffer_bytes_left. bytes_left applies @@ -1332,32 +1333,66 @@ static int __exit davinci_mmcsd_remove(struct platform_device *pdev) } #ifdef CONFIG_PM -static int davinci_mmcsd_suspend(struct platform_device *pdev, pm_message_t msg) +static int davinci_mmcsd_suspend(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct mmc_davinci_host *host = platform_get_drvdata(pdev); + struct pm_message msg = { PM_EVENT_SUSPEND }; + int ret; - return mmc_suspend_host(host->mmc, msg); + mmc_host_enable(host->mmc); + ret = mmc_suspend_host(host->mmc, msg); + if (!ret) { + writel(0, host->base + DAVINCI_MMCIM); + mmc_davinci_reset_ctrl(host, 1); + mmc_host_disable(host->mmc); + clk_disable(host->clk); + host->suspended = 1; + } else { + host->suspended = 0; + mmc_host_disable(host->mmc); + } + + return ret; } -static int davinci_mmcsd_resume(struct platform_device *pdev) +static int davinci_mmcsd_resume(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct mmc_davinci_host *host = platform_get_drvdata(pdev); + int ret; - return mmc_resume_host(host->mmc); + if (!host->suspended) + return 0; + + clk_enable(host->clk); + mmc_host_enable(host->mmc); + + mmc_davinci_reset_ctrl(host, 0); + ret = mmc_resume_host(host->mmc); + if (!ret) + host->suspended = 0; + + return ret; } + +static const struct dev_pm_ops davinci_mmcsd_pm = { + .suspend = davinci_mmcsd_suspend, + .resume = davinci_mmcsd_resume, +}; + +#define davinci_mmcsd_pm_ops (&davinci_mmcsd_pm) #else -#define davinci_mmcsd_suspend NULL -#define davinci_mmcsd_resume NULL +#define davinci_mmcsd_pm_ops NULL #endif static struct platform_driver davinci_mmcsd_driver = { .driver = { .name = "davinci_mmc", .owner = THIS_MODULE, + .pm = davinci_mmcsd_pm_ops, }, .remove = __exit_p(davinci_mmcsd_remove), - .suspend = davinci_mmcsd_suspend, - .resume = davinci_mmcsd_resume, }; static int __init davinci_mmcsd_init(void)