From a560d8579b4b009f847972667b7597c89030e26c Mon Sep 17 00:00:00 2001 From: merge Date: Thu, 27 Nov 2008 08:37:56 +0000 Subject: MERGE-via-balaji-tracking-hist-MERGE-via-stable-tracking-hist-config-gta02-uplevel-patch balaji-tracking-hist top was MERGE-via-stable-tracking-hist-config-gta02-uplevel-patch / eb381acecca375d0a7b88cfe640504a8a1fa4c39 ... parent commitmessage: From: merge MERGE-via-stable-tracking-hist-config-gta02-uplevel-patch stable-tracking-hist top was config-gta02-uplevel-patch / 0e07e39074bbdb938cfefaea6ad7823282cc914c ... parent commitmessage: From: Andy Green config-gta02-uplevel.patch Signed-off-by: Andy Green --- drivers/mmc/core/core.c | 3 ++- drivers/mmc/host/s3cmci.c | 48 +++++++++++++++++++++++++++++++++++++++++++++-- drivers/mmc/host/s3cmci.h | 10 ++++++++++ 3 files changed, 58 insertions(+), 3 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index f7284b905eb..b76667e36e8 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -57,10 +57,11 @@ static int mmc_schedule_delayed_work(struct delayed_work *work, /* * Internal function. Flush all scheduled work from the MMC work queue. */ -static void mmc_flush_scheduled_work(void) +void mmc_flush_scheduled_work(void) { flush_workqueue(workqueue); } +EXPORT_SYMBOL_GPL(mmc_flush_scheduled_work); /** * mmc_request_done - finish processing an MMC request diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index a2bb2129bfd..45c5192869b 100644 --- a/drivers/mmc/host/s3cmci.c +++ b/drivers/mmc/host/s3cmci.c @@ -57,6 +57,7 @@ static const int dbgmap_info = dbg_info | dbg_conf; 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 @@ static int __devinit s3cmci_2440_probe(struct platform_device *dev) #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_init(s3cmci_init); 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"); diff --git a/drivers/mmc/host/s3cmci.h b/drivers/mmc/host/s3cmci.h index ca1ba3d58cf..c2b65b3488b 100644 --- a/drivers/mmc/host/s3cmci.h +++ b/drivers/mmc/host/s3cmci.h @@ -8,6 +8,9 @@ * published by the Free Software Foundation. */ + +#include + /* FIXME: DMA Resource management ?! */ #define S3CMCI_DMA 0 @@ -68,6 +71,13 @@ struct s3cmci_host { 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 -- cgit v1.2.3