[PATCH 2/2] s3cmci-suspend-persist.patch

Werner Almesberger werner at openmoko.org
Thu Nov 27 01:55:15 CET 2008


Allow s3cmci to preserve its state across suspend/resume without
letting the stack take down and re-scan the interface.

This can be useful for cards that implement their own low-power
mode and that have state that can be preserved and that should
be available quickly after resume. E.g., a WLAN card with an
active association.

This patch does not change the default behaviour. To keep the
interface alive across suspend/resume, set the "persist" option,
either with persist=1 (module loading) or s3cmci.persist=1 (on
the boot parameter line).

Signed-off-by: Werner Almesberger <werner at openmoko.org>

---

Index: ktrack/drivers/mmc/host/s3cmci.c
===================================================================
--- ktrack.orig/drivers/mmc/host/s3cmci.c	2008-11-26 22:17:53.000000000 -0200
+++ ktrack/drivers/mmc/host/s3cmci.c	2008-11-26 22:29:43.000000000 -0200
@@ -57,6 +57,7 @@
 static const int dbgmap_debug = dbg_err | dbg_debug;
 
 static int f_max = -1; /* override maximum frequency limit */
+static int persist; /* keep interface alive across suspend/resume */
 
 #define dbg(host, channels, args...)		  \
 	do {					  \
@@ -1518,18 +1519,60 @@
 
 #ifdef CONFIG_PM
 
+static int save_regs(struct mmc_host *mmc)
+{
+	struct s3cmci_host *host = mmc_priv(mmc);
+	unsigned long flags;
+	unsigned from;
+	u32 *to = host->saved;
+
+	mmc_flush_scheduled_work();
+
+	local_irq_save(flags);
+	for (from = S3C2410_SDICON; from != S3C2410_SDIIMSK+4; from += 4)
+		if (from != host->sdidata)
+			*to++ = readl(host->base + from);
+	BUG_ON(to-host->saved != ARRAY_SIZE(host->saved));
+	local_irq_restore(flags);
+
+	return 0;
+}
+
+static int restore_regs(struct mmc_host *mmc)
+{
+	struct s3cmci_host *host = mmc_priv(mmc);
+	unsigned long flags;
+	unsigned to;
+	u32 *from = host->saved;
+
+	/*
+	 * Before we begin with the necromancy, make sure we don't
+	 * inadvertently start something we'll regret microseconds later.
+	 */
+	from[S3C2410_SDICMDCON - S3C2410_SDICON] = 0;
+
+	local_irq_save(flags);
+	for (to = S3C2410_SDICON; to != S3C2410_SDIIMSK+4; to += 4)
+		if (to != host->sdidata)
+			writel(*from++, host->base + to);
+	BUG_ON(from-host->saved != ARRAY_SIZE(host->saved));
+	local_irq_restore(flags);
+
+	return 0;
+}
+
 static int s3cmci_suspend(struct platform_device *dev, pm_message_t state)
 {
 	struct mmc_host *mmc = platform_get_drvdata(dev);
 
-	return  mmc_suspend_host(mmc, state);
+	return persist ? save_regs(mmc) : mmc_suspend_host(mmc, state);
 }
 
 static int s3cmci_resume(struct platform_device *dev)
 {
 	struct mmc_host *mmc = platform_get_drvdata(dev);
 
-	return mmc_resume_host(mmc);
+	return persist ? restore_regs(mmc) : mmc_resume_host(mmc);
 }
 
 #else /* CONFIG_PM */
@@ -1588,6 +1631,7 @@
 module_exit(s3cmci_exit);
 
 module_param(f_max, int, 0644);
+module_param(persist, int, 0644);
 
 MODULE_DESCRIPTION("Samsung S3C MMC/SD Card Interface driver");
 MODULE_LICENSE("GPL v2");
Index: ktrack/drivers/mmc/host/s3cmci.h
===================================================================
--- ktrack.orig/drivers/mmc/host/s3cmci.h	2008-11-26 22:17:53.000000000 -0200
+++ ktrack/drivers/mmc/host/s3cmci.h	2008-11-26 22:24:26.000000000 -0200
@@ -8,6 +8,9 @@
  * published by the Free Software Foundation.
  */
 
+
+#include <mach/regs-sdi.h>
+
 /* FIXME: DMA Resource management ?! */
 #define S3CMCI_DMA 0
 
@@ -68,6 +71,13 @@
 	unsigned int		ccnt, dcnt;
 	struct tasklet_struct	pio_tasklet;
 
+	/*
+	 * Here's where we save the registers during suspend. Note that we skip
+	 * SDIDATA, which is at different positions on 2410 and 2440, so
+	 * there's no "+1" in the array size.
+	 */
+	u32			saved[(S3C2410_SDIIMSK-S3C2410_SDICON)/4];
+
 #ifdef CONFIG_CPU_FREQ
 	struct notifier_block	freq_transition;
 #endif



More information about the openmoko-kernel mailing list