summaryrefslogtreecommitdiff
path: root/drivers/mmc/host/sdhci-pltfm.c
diff options
context:
space:
mode:
authorStefan Agner <stefan@agner.ch>2015-05-18 15:27:18 +0200
committerStefan Agner <stefan@agner.ch>2016-02-10 18:42:27 -0800
commit2a2ac993a772107d21a2c70fecd2032327366043 (patch)
treedf77a8e1c6f5b7f5171a62ffe640e27705c69fc0 /drivers/mmc/host/sdhci-pltfm.c
parent71148de4f7e42bbe3d4a76de00365f541c6bd485 (diff)
mmc: sdhci: fix abort due to missing runtime PM
When using i.MX ESDHC driver, while entering suspend while the device is in runtime PM, the sdhci_(suspend|resume)_host function are called with disabled clocks. Since this functions access the SDHC host registers, this leads to an external abort on Vybrid SoC: [ 37.772967] Unhandled fault: imprecise external abort (0x1c06) at 0x76f5f000 [ 37.780304] Internal error: : 1c06 [#1] ARM [ 37.784670] Modules linked in: [ 37.787908] CPU: 0 PID: 428 Comm: sh Not tainted 3.18.0-rc5-00119-geefd097-dirty #1540 [ 37.796142] task: 8e246c00 ti: 8ca6c000 task.ti: 8ca6c000 [ 37.801785] PC is at esdhc_writel_le+0x40/0xec [ 37.806431] LR is at sdhci_set_card_detection+0xe0/0xe4 [ 37.811877] pc : [<803f0584>] lr : [<803eaaa0>] psr: 400f0013 [ 37.811877] sp : 8ca6dd28 ip : 00000001 fp : 8ca6dd3c [ 37.823766] r10: 807a233c r9 : 00000000 r8 : 8e8b7210 [ 37.829194] r7 : 802d8a08 r6 : 8082e928 r5 : 00000000 r4 : 00000002 [ 37.835974] r3 : 8ea34e90 r2 : 00000038 r1 : 00000000 r0 : 8ea32ac0 ... Clocks need to be enabled to access the registers. Fix the issue by add runtime PM enabled pltfm implementation of suspend/resume which take care of clocks by using the runtime PM API properly.
Diffstat (limited to 'drivers/mmc/host/sdhci-pltfm.c')
-rw-r--r--drivers/mmc/host/sdhci-pltfm.c36
1 files changed, 36 insertions, 0 deletions
diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
index 87fb5ea8ebe7..714ffb5a6929 100644
--- a/drivers/mmc/host/sdhci-pltfm.c
+++ b/drivers/mmc/host/sdhci-pltfm.c
@@ -31,6 +31,7 @@
#include <linux/err.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/pm_runtime.h>
#ifdef CONFIG_PPC
#include <asm/machdep.h>
#endif
@@ -252,6 +253,41 @@ const struct dev_pm_ops sdhci_pltfm_pmops = {
.resume = sdhci_pltfm_resume,
};
EXPORT_SYMBOL_GPL(sdhci_pltfm_pmops);
+
+int sdhci_pltfm_rpm_suspend(struct device *dev)
+{
+ int ret;
+ struct sdhci_host *host = dev_get_drvdata(dev);
+
+ pm_runtime_get_sync(dev);
+ ret = sdhci_suspend_host(host);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+ if (ret)
+ return ret;
+
+ return pm_runtime_force_suspend(dev);
+}
+EXPORT_SYMBOL_GPL(sdhci_pltfm_rpm_suspend);
+
+int sdhci_pltfm_rpm_resume(struct device *dev)
+{
+ int ret;
+ struct sdhci_host *host = dev_get_drvdata(dev);
+
+ ret = pm_runtime_force_resume(dev);
+
+ if (ret)
+ return ret;
+
+ pm_runtime_get_sync(dev);
+ ret = sdhci_resume_host(host);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(sdhci_pltfm_rpm_resume);
#endif /* CONFIG_PM */
static int __init sdhci_pltfm_drv_init(void)