* [PATCH v6 0/3] mmc: dw_mmc: fixes for suspend/resume on exynos
@ 2013-08-22 16:19 Doug Anderson
  2013-08-22 16:19 ` [PATCH v6 1/3] mmc: dw_mmc: Add exynos resume_noirq callback to clear WAKEUP_INT Doug Anderson
  2013-08-29 16:39 ` [PATCH v7 0/3] mmc: dw_mmc: fixes for suspend/resume on exynos Doug Anderson
  0 siblings, 2 replies; 4+ messages in thread
From: Doug Anderson @ 2013-08-22 16:19 UTC (permalink / raw)
  To: linux-arm-kernel
This series of patches addresses some suspend/resume problems with
dw_mmc on exynos platforms, espeically exynos5420.  This patchset was
tested on the current ToT Chromeos 3.8 tree (which has lots of
backports from 3.10/3.11) and on ToT Linux (v3.11-rc6).  I have
confirmed basic booting and that SD cards work across suspend/resume
(both if they are plugged in and if they are not plugged in).
I have received confirmation from Samsung that the problem solved for
exynos5420 is a silicon errata and that this is a good fix.
Changes in v6:
- Took out TODO comment copied from main platform code.
- Replaces previous pathes that ensured saving/restoring clocks.
Changes in v5:
- Cleaned up dw_mci_exynos_resume_noirq() comment as per Seungwon.
- Don't memcpy dev_pm_ops structure, define a new one.
Changes in v4:
- Take Seungwon's suggestion and don't add any dw_mmc-pltfm code.
Changes in v3:
- Add freeze/thaw and poweroff/restore noirq entries.
Changes in v2:
- Use suspend_noirq as per James Hogan.
Doug Anderson (3):
  mmc: dw_mmc: Add exynos resume_noirq callback to clear WAKEUP_INT
  mmc: dw_mmc: Honor requests to set the clock to 0 (turn off clock)
  mmc: dw_mmc: Set timeout to max upon resume
 drivers/mmc/host/dw_mmc-exynos.c | 53 +++++++++++++++++++++++++++++++++++++++-
 drivers/mmc/host/dw_mmc.c        | 24 ++++++++++--------
 2 files changed, 66 insertions(+), 11 deletions(-)
-- 
1.8.3
^ permalink raw reply	[flat|nested] 4+ messages in thread
* [PATCH v6 1/3] mmc: dw_mmc: Add exynos resume_noirq callback to clear WAKEUP_INT
  2013-08-22 16:19 [PATCH v6 0/3] mmc: dw_mmc: fixes for suspend/resume on exynos Doug Anderson
@ 2013-08-22 16:19 ` Doug Anderson
  2013-08-29 16:39 ` [PATCH v7 0/3] mmc: dw_mmc: fixes for suspend/resume on exynos Doug Anderson
  1 sibling, 0 replies; 4+ messages in thread
From: Doug Anderson @ 2013-08-22 16:19 UTC (permalink / raw)
  To: linux-arm-kernel
If the WAKEUP_INT is asserted at wakeup and not cleared, we'll end up
looping around forever.  This has been seen to happen on exynos5420
silicon despite the fact that we haven't enabled any wakeup events due
to a silicon errata.  It is safe to do on all exynos variants.
Signed-off-by: Doug Anderson <dianders@chromium.org>
---
Changes in v6:
- Took out TODO comment copied from main platform code.
Changes in v5:
- Cleaned up dw_mci_exynos_resume_noirq() comment as per Seungwon.
- Don't memcpy dev_pm_ops structure, define a new one.
Changes in v4:
- Take Seungwon's suggestion and don't add any dw_mmc-pltfm code.
Changes in v3:
- Add freeze/thaw and poweroff/restore noirq entries.
Changes in v2:
- Use suspend_noirq as per James Hogan.
 drivers/mmc/host/dw_mmc-exynos.c | 53 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 52 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
index 866edef..e8c6cc9 100644
--- a/drivers/mmc/host/dw_mmc-exynos.c
+++ b/drivers/mmc/host/dw_mmc-exynos.c
@@ -30,6 +30,7 @@
 #define SDMMC_CLKSEL_TIMING(x, y, z)	(SDMMC_CLKSEL_CCLK_SAMPLE(x) |	\
 					SDMMC_CLKSEL_CCLK_DRIVE(y) |	\
 					SDMMC_CLKSEL_CCLK_DIVIDER(z))
+#define SDMMC_CLKSEL_WAKEUP_INT		BIT(11)
 
 #define EXYNOS4210_FIXED_CIU_CLK_DIV	2
 #define EXYNOS4412_FIXED_CIU_CLK_DIV	4
@@ -100,6 +101,49 @@ static int dw_mci_exynos_setup_clock(struct dw_mci *host)
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int dw_mci_exynos_suspend(struct device *dev)
+{
+	struct dw_mci *host = dev_get_drvdata(dev);
+
+	return dw_mci_suspend(host);
+}
+
+static int dw_mci_exynos_resume(struct device *dev)
+{
+	struct dw_mci *host = dev_get_drvdata(dev);
+
+	return dw_mci_resume(host);
+}
+
+/**
+ * dw_mci_exynos_resume_noirq - Exynos-specific resume code
+ *
+ * On exynos5420 there is a silicon errata that will sometimes leave the
+ * WAKEUP_INT bit in the CLKSEL register asserted.  This bit is 1 to indicate
+ * that it fired and we can clear it by writing a 1 back.  Clear it to prevent
+ * interrupts from going off constantly.
+ *
+ * We run this code on all exynos variants because it doesn't hurt.
+ */
+
+static int dw_mci_exynos_resume_noirq(struct device *dev)
+{
+	struct dw_mci *host = dev_get_drvdata(dev);
+	u32 clksel;
+
+	clksel = mci_readl(host, CLKSEL);
+	if (clksel & SDMMC_CLKSEL_WAKEUP_INT)
+		mci_writel(host, CLKSEL, clksel);
+
+	return 0;
+}
+#else
+#define dw_mci_exynos_suspend		NULL
+#define dw_mci_exynos_resume		NULL
+#define dw_mci_exynos_resume_noirq	NULL
+#endif /* CONFIG_PM_SLEEP */
+
 static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr)
 {
 	/*
@@ -187,13 +231,20 @@ static int dw_mci_exynos_probe(struct platform_device *pdev)
 	return dw_mci_pltfm_register(pdev, drv_data);
 }
 
+const struct dev_pm_ops dw_mci_exynos_pmops = {
+	SET_SYSTEM_SLEEP_PM_OPS(dw_mci_exynos_suspend, dw_mci_exynos_resume)
+	.resume_noirq = dw_mci_exynos_resume_noirq,
+	.thaw_noirq = dw_mci_exynos_resume_noirq,
+	.restore_noirq = dw_mci_exynos_resume_noirq,
+};
+
 static struct platform_driver dw_mci_exynos_pltfm_driver = {
 	.probe		= dw_mci_exynos_probe,
 	.remove		= __exit_p(dw_mci_pltfm_remove),
 	.driver		= {
 		.name		= "dwmmc_exynos",
 		.of_match_table	= dw_mci_exynos_match,
-		.pm		= &dw_mci_pltfm_pmops,
+		.pm		= &dw_mci_exynos_pmops,
 	},
 };
 
-- 
1.8.3
^ permalink raw reply related	[flat|nested] 4+ messages in thread
* [PATCH v7 0/3] mmc: dw_mmc: fixes for suspend/resume on exynos
  2013-08-22 16:19 [PATCH v6 0/3] mmc: dw_mmc: fixes for suspend/resume on exynos Doug Anderson
  2013-08-22 16:19 ` [PATCH v6 1/3] mmc: dw_mmc: Add exynos resume_noirq callback to clear WAKEUP_INT Doug Anderson
@ 2013-08-29 16:39 ` Doug Anderson
  2013-08-29 16:39   ` [PATCH v7 1/3] mmc: dw_mmc: Add exynos resume_noirq callback to clear WAKEUP_INT Doug Anderson
  1 sibling, 1 reply; 4+ messages in thread
From: Doug Anderson @ 2013-08-29 16:39 UTC (permalink / raw)
  To: linux-arm-kernel
This series of patches addresses some suspend/resume problems with
dw_mmc on exynos platforms, espeically exynos5420.  This patchset was
tested on the current ToT Chromeos 3.8 tree (which has lots of
backports from 3.10/3.11) and on ToT Linux (v3.11-rc6).  I have
confirmed basic booting and that SD cards work across suspend/resume
(both if they are plugged in and if they are not plugged in).
I have received confirmation from Samsung that the problem solved for
exynos5420 is a silicon errata and that this is a good fix.
Changes in v7:
- Avoid printing the same clock over and over again w/ MMC_CLKGATE.
Changes in v6:
- Took out TODO comment copied from main platform code.
- Replaces previous pathes that ensured saving/restoring clocks.
Changes in v5:
- Cleaned up dw_mci_exynos_resume_noirq() comment as per Seungwon.
- Don't memcpy dev_pm_ops structure, define a new one.
Changes in v4:
- Take Seungwon's suggestion and don't add any dw_mmc-pltfm code.
Changes in v3:
- Add freeze/thaw and poweroff/restore noirq entries.
Changes in v2:
- Use suspend_noirq as per James Hogan.
Doug Anderson (3):
  mmc: dw_mmc: Add exynos resume_noirq callback to clear WAKEUP_INT
  mmc: dw_mmc: Honor requests to set the clock to 0 (turn off clock)
  mmc: dw_mmc: Set timeout to max upon resume
 drivers/mmc/host/dw_mmc-exynos.c | 53 +++++++++++++++++++++++++++++++++++++++-
 drivers/mmc/host/dw_mmc.c        | 39 ++++++++++++++++++-----------
 2 files changed, 77 insertions(+), 15 deletions(-)
-- 
1.8.4
^ permalink raw reply	[flat|nested] 4+ messages in thread
* [PATCH v7 1/3] mmc: dw_mmc: Add exynos resume_noirq callback to clear WAKEUP_INT
  2013-08-29 16:39 ` [PATCH v7 0/3] mmc: dw_mmc: fixes for suspend/resume on exynos Doug Anderson
@ 2013-08-29 16:39   ` Doug Anderson
  0 siblings, 0 replies; 4+ messages in thread
From: Doug Anderson @ 2013-08-29 16:39 UTC (permalink / raw)
  To: linux-arm-kernel
If the WAKEUP_INT is asserted at wakeup and not cleared, we'll end up
looping around forever.  This has been seen to happen on exynos5420
silicon despite the fact that we haven't enabled any wakeup events due
to a silicon errata.  It is safe to do on all exynos variants.
Signed-off-by: Doug Anderson <dianders@chromium.org>
---
Changes in v7: None
Changes in v6:
- Took out TODO comment copied from main platform code.
Changes in v5:
- Cleaned up dw_mci_exynos_resume_noirq() comment as per Seungwon.
- Don't memcpy dev_pm_ops structure, define a new one.
Changes in v4:
- Take Seungwon's suggestion and don't add any dw_mmc-pltfm code.
Changes in v3:
- Add freeze/thaw and poweroff/restore noirq entries.
Changes in v2:
- Use suspend_noirq as per James Hogan.
 drivers/mmc/host/dw_mmc-exynos.c | 53 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 52 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
index 866edef..e8c6cc9 100644
--- a/drivers/mmc/host/dw_mmc-exynos.c
+++ b/drivers/mmc/host/dw_mmc-exynos.c
@@ -30,6 +30,7 @@
 #define SDMMC_CLKSEL_TIMING(x, y, z)	(SDMMC_CLKSEL_CCLK_SAMPLE(x) |	\
 					SDMMC_CLKSEL_CCLK_DRIVE(y) |	\
 					SDMMC_CLKSEL_CCLK_DIVIDER(z))
+#define SDMMC_CLKSEL_WAKEUP_INT		BIT(11)
 
 #define EXYNOS4210_FIXED_CIU_CLK_DIV	2
 #define EXYNOS4412_FIXED_CIU_CLK_DIV	4
@@ -100,6 +101,49 @@ static int dw_mci_exynos_setup_clock(struct dw_mci *host)
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int dw_mci_exynos_suspend(struct device *dev)
+{
+	struct dw_mci *host = dev_get_drvdata(dev);
+
+	return dw_mci_suspend(host);
+}
+
+static int dw_mci_exynos_resume(struct device *dev)
+{
+	struct dw_mci *host = dev_get_drvdata(dev);
+
+	return dw_mci_resume(host);
+}
+
+/**
+ * dw_mci_exynos_resume_noirq - Exynos-specific resume code
+ *
+ * On exynos5420 there is a silicon errata that will sometimes leave the
+ * WAKEUP_INT bit in the CLKSEL register asserted.  This bit is 1 to indicate
+ * that it fired and we can clear it by writing a 1 back.  Clear it to prevent
+ * interrupts from going off constantly.
+ *
+ * We run this code on all exynos variants because it doesn't hurt.
+ */
+
+static int dw_mci_exynos_resume_noirq(struct device *dev)
+{
+	struct dw_mci *host = dev_get_drvdata(dev);
+	u32 clksel;
+
+	clksel = mci_readl(host, CLKSEL);
+	if (clksel & SDMMC_CLKSEL_WAKEUP_INT)
+		mci_writel(host, CLKSEL, clksel);
+
+	return 0;
+}
+#else
+#define dw_mci_exynos_suspend		NULL
+#define dw_mci_exynos_resume		NULL
+#define dw_mci_exynos_resume_noirq	NULL
+#endif /* CONFIG_PM_SLEEP */
+
 static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr)
 {
 	/*
@@ -187,13 +231,20 @@ static int dw_mci_exynos_probe(struct platform_device *pdev)
 	return dw_mci_pltfm_register(pdev, drv_data);
 }
 
+const struct dev_pm_ops dw_mci_exynos_pmops = {
+	SET_SYSTEM_SLEEP_PM_OPS(dw_mci_exynos_suspend, dw_mci_exynos_resume)
+	.resume_noirq = dw_mci_exynos_resume_noirq,
+	.thaw_noirq = dw_mci_exynos_resume_noirq,
+	.restore_noirq = dw_mci_exynos_resume_noirq,
+};
+
 static struct platform_driver dw_mci_exynos_pltfm_driver = {
 	.probe		= dw_mci_exynos_probe,
 	.remove		= __exit_p(dw_mci_pltfm_remove),
 	.driver		= {
 		.name		= "dwmmc_exynos",
 		.of_match_table	= dw_mci_exynos_match,
-		.pm		= &dw_mci_pltfm_pmops,
+		.pm		= &dw_mci_exynos_pmops,
 	},
 };
 
-- 
1.8.4
^ permalink raw reply related	[flat|nested] 4+ messages in thread
end of thread, other threads:[~2013-08-29 16:39 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-08-22 16:19 [PATCH v6 0/3] mmc: dw_mmc: fixes for suspend/resume on exynos Doug Anderson
2013-08-22 16:19 ` [PATCH v6 1/3] mmc: dw_mmc: Add exynos resume_noirq callback to clear WAKEUP_INT Doug Anderson
2013-08-29 16:39 ` [PATCH v7 0/3] mmc: dw_mmc: fixes for suspend/resume on exynos Doug Anderson
2013-08-29 16:39   ` [PATCH v7 1/3] mmc: dw_mmc: Add exynos resume_noirq callback to clear WAKEUP_INT Doug Anderson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).