[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