All of lore.kernel.org
 help / color / mirror / Atom feed
From: Adrian Hunter <adrian.hunter@nokia.com>
To: Pierre Ossman <pierre@ossman.eu>
Cc: Jarkko Lavinen <jarkko.lavinen@nokia.com>,
	Denis Karpov <ext-denis.2.karpov@nokia.com>,
	Adrian Hunter <adrian.hunter@nokia.com>,
	linux-omap Mailing List <linux-omap@vger.kernel.org>,
	lkml <linux-kernel@vger.kernel.org>
Subject: [PATCH 13/32] omap_hsmmc: context save/restore support
Date: Fri, 10 Jul 2009 15:41:37 +0300	[thread overview]
Message-ID: <20090710124137.1262.63323.sendpatchset@ahunter-tower> (raw)
In-Reply-To: <20090710124004.1262.10422.sendpatchset@ahunter-tower>

>From 3eb49df725b26329e85db6e4fc6f72fc029501a3 Mon Sep 17 00:00:00 2001
From: Denis Karpov <ext-denis.2.karpov@nokia.com>
Date: Wed, 22 Apr 2009 16:04:25 +0200
Subject: [PATCH] omap_hsmmc: context save/restore support

Keep the context over PM dynamic OFF states.

Signed-off-by: Denis Karpov <ext-denis.2.karpov@nokia.com>
Signed-off-by: Adrian Hunter <adrian.hunter@nokia.com>
---
 drivers/mmc/host/omap_hsmmc.c |  194 ++++++++++++++++++++++++++++++++++++++--
 1 files changed, 184 insertions(+), 10 deletions(-)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index dad0548..762aa01 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -37,6 +37,7 @@
 
 /* OMAP HSMMC Host Controller Registers */
 #define OMAP_HSMMC_SYSCONFIG	0x0010
+#define OMAP_HSMMC_SYSSTATUS	0x0014
 #define OMAP_HSMMC_CON		0x002C
 #define OMAP_HSMMC_BLK		0x0104
 #define OMAP_HSMMC_ARG		0x0108
@@ -94,6 +95,8 @@
 #define DUAL_VOLT_OCR_BIT	7
 #define SRC			(1 << 25)
 #define SRD			(1 << 26)
+#define SOFTRESET		(1 << 1)
+#define RESETDONE		(1 << 0)
 
 /*
  * FIXME: Most likely all the data using these _DEVID defines should come
@@ -152,6 +155,8 @@ struct mmc_omap_host {
 	int			slot_id;
 	int			dbclk_enabled;
 	int			response_busy;
+	int			context_loss;
+
 	struct	omap_mmc_platform_data	*pdata;
 };
 
@@ -166,6 +171,166 @@ static void omap_mmc_stop_clock(struct mmc_omap_host *host)
 		dev_dbg(mmc_dev(host->mmc), "MMC Clock is not stoped\n");
 }
 
+#ifdef CONFIG_PM
+
+/*
+ * Restore the MMC host context, if it was lost as result of a
+ * power state change.
+ */
+static int omap_mmc_restore_ctx(struct mmc_omap_host *host)
+{
+	struct mmc_ios *ios = &host->mmc->ios;
+	struct omap_mmc_platform_data *pdata = host->pdata;
+	int context_loss = 0;
+	u32 hctl, capa, con;
+	u16 dsor = 0;
+	unsigned long timeout;
+
+	if (pdata->get_context_loss_count) {
+		context_loss = pdata->get_context_loss_count(host->dev);
+		if (context_loss < 0)
+			return 1;
+	}
+
+	dev_dbg(mmc_dev(host->mmc), "context was %slost\n",
+		context_loss == host->context_loss ? "not " : "");
+	if (host->context_loss == context_loss)
+		return 1;
+
+	/* Wait for hardware reset */
+	timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
+	while ((OMAP_HSMMC_READ(host->base, SYSSTATUS) & RESETDONE) != RESETDONE
+		&& time_before(jiffies, timeout))
+		;
+
+	/* Do software reset */
+	OMAP_HSMMC_WRITE(host->base, SYSCONFIG, SOFTRESET);
+	timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
+	while ((OMAP_HSMMC_READ(host->base, SYSSTATUS) & RESETDONE) != RESETDONE
+		&& time_before(jiffies, timeout))
+		;
+
+	OMAP_HSMMC_WRITE(host->base, SYSCONFIG,
+			OMAP_HSMMC_READ(host->base, SYSCONFIG) | AUTOIDLE);
+
+	if (host->id == OMAP_MMC1_DEVID) {
+		if (host->power_mode != MMC_POWER_OFF &&
+		    (1 << ios->vdd) <= MMC_VDD_23_24)
+			hctl = SDVS18;
+		else
+			hctl = SDVS30;
+		capa = VS30 | VS18;
+	} else {
+		hctl = SDVS18;
+		capa = VS18;
+	}
+
+	OMAP_HSMMC_WRITE(host->base, HCTL,
+			OMAP_HSMMC_READ(host->base, HCTL) | hctl);
+
+	OMAP_HSMMC_WRITE(host->base, CAPA,
+			OMAP_HSMMC_READ(host->base, CAPA) | capa);
+
+	OMAP_HSMMC_WRITE(host->base, HCTL,
+			OMAP_HSMMC_READ(host->base, HCTL) | SDBP);
+
+	timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
+	while ((OMAP_HSMMC_READ(host->base, HCTL) & SDBP) != SDBP
+		&& time_before(jiffies, timeout))
+		;
+
+	OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
+	OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
+	OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
+
+	/* Do not initialize card-specific things if the power is off */
+	if (host->power_mode == MMC_POWER_OFF)
+		goto out;
+
+	con = OMAP_HSMMC_READ(host->base, CON);
+	switch (ios->bus_width) {
+	case MMC_BUS_WIDTH_8:
+		OMAP_HSMMC_WRITE(host->base, CON, con | DW8);
+		break;
+	case MMC_BUS_WIDTH_4:
+		OMAP_HSMMC_WRITE(host->base, CON, con & ~DW8);
+		OMAP_HSMMC_WRITE(host->base, HCTL,
+			OMAP_HSMMC_READ(host->base, HCTL) | FOUR_BIT);
+		break;
+	case MMC_BUS_WIDTH_1:
+		OMAP_HSMMC_WRITE(host->base, CON, con & ~DW8);
+		OMAP_HSMMC_WRITE(host->base, HCTL,
+			OMAP_HSMMC_READ(host->base, HCTL) & ~FOUR_BIT);
+		break;
+	}
+
+	if (ios->clock) {
+		dsor = OMAP_MMC_MASTER_CLOCK / ios->clock;
+		if (dsor < 1)
+			dsor = 1;
+
+		if (OMAP_MMC_MASTER_CLOCK / dsor > ios->clock)
+			dsor++;
+
+		if (dsor > 250)
+			dsor = 250;
+	}
+
+	OMAP_HSMMC_WRITE(host->base, SYSCTL,
+		OMAP_HSMMC_READ(host->base, SYSCTL) & ~CEN);
+	OMAP_HSMMC_WRITE(host->base, SYSCTL, (dsor << 6) | (DTO << 16));
+	OMAP_HSMMC_WRITE(host->base, SYSCTL,
+		OMAP_HSMMC_READ(host->base, SYSCTL) | ICE);
+
+	timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
+	while ((OMAP_HSMMC_READ(host->base, SYSCTL) & ICS) != ICS
+		&& time_before(jiffies, timeout))
+		;
+
+	OMAP_HSMMC_WRITE(host->base, SYSCTL,
+		OMAP_HSMMC_READ(host->base, SYSCTL) | CEN);
+
+	con = OMAP_HSMMC_READ(host->base, CON);
+	if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
+		OMAP_HSMMC_WRITE(host->base, CON, con | OD);
+	else
+		OMAP_HSMMC_WRITE(host->base, CON, con & ~OD);
+out:
+	host->context_loss = context_loss;
+
+	dev_dbg(mmc_dev(host->mmc), "context is restored\n");
+	return 0;
+}
+
+/*
+ * Save the MMC host context (store the number of power state changes so far).
+ */
+static void omap_mmc_save_ctx(struct mmc_omap_host *host)
+{
+	struct omap_mmc_platform_data *pdata = host->pdata;
+	int context_loss;
+
+	if (pdata->get_context_loss_count) {
+		context_loss = pdata->get_context_loss_count(host->dev);
+		if (context_loss < 0)
+			return;
+		host->context_loss = context_loss;
+	}
+}
+
+#else
+
+static int omap_mmc_restore_ctx(struct mmc_omap_host *host)
+{
+	return 0;
+}
+
+static void omap_mmc_save_ctx(struct mmc_omap_host *host)
+{
+}
+
+#endif
+
 /*
  * Send init stream sequence to card
  * before sending IDLE command
@@ -823,6 +988,7 @@ static int omap_mmc_enable(struct mmc_host *mmc)
 	if (err)
 		return err;
 	dev_dbg(mmc_dev(host->mmc), "mmc_fclk: enabled\n");
+	omap_mmc_restore_ctx(host);
 	return 0;
 }
 
@@ -830,6 +996,7 @@ static int omap_mmc_disable(struct mmc_host *mmc, int lazy)
 {
 	struct mmc_omap_host *host = mmc_priv(mmc);
 
+	omap_mmc_save_ctx(host);
 	clk_disable(host->fclk);
 	dev_dbg(mmc_dev(host->mmc), "mmc_fclk: disabled\n");
 	return 0;
@@ -934,7 +1101,7 @@ static void omap_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 
 	/* Wait till the ICS bit is set */
 	timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
-	while ((OMAP_HSMMC_READ(host->base, SYSCTL) & ICS) != 0x2
+	while ((OMAP_HSMMC_READ(host->base, SYSCTL) & ICS) != ICS
 		&& time_before(jiffies, timeout))
 		msleep(1);
 
@@ -1014,12 +1181,19 @@ static int mmc_regs_show(struct seq_file *s, void *data)
 {
 	struct mmc_host *mmc = s->private;
 	struct mmc_omap_host *host = mmc_priv(mmc);
+	struct omap_mmc_platform_data *pdata = host->pdata;
+	int context_loss = 0;
+
+	if (pdata->get_context_loss_count)
+		context_loss = pdata->get_context_loss_count(host->dev);
 
 	seq_printf(s, "mmc%d:\n"
 			" enabled:\t%d\n"
 			" nesting_cnt:\t%d\n"
+			" ctx_loss:\t%d:%d\n"
 			"\nregs:\n",
-			mmc->index, mmc->enabled ? 1 : 0, mmc->nesting_cnt);
+			mmc->index, mmc->enabled ? 1 : 0, mmc->nesting_cnt,
+			host->context_loss, context_loss);
 
 	if (clk_enable(host->fclk) != 0) {
 		seq_printf(s, "can't read the regs\n");
@@ -1144,6 +1318,8 @@ static int __init omap_mmc_probe(struct platform_device *pdev)
 		goto err1;
 	}
 
+	omap_mmc_save_ctx(host);
+
 	mmc->caps |= MMC_CAP_DISABLE;
 	mmc_set_disable_delay(mmc, msecs_to_jiffies(100));
 	if (mmc_host_enable(host->mmc) != 0) {
@@ -1378,21 +1554,19 @@ static int omap_mmc_resume(struct platform_device *pdev)
 		return 0;
 
 	if (host) {
-
-		if (mmc_host_enable(host->mmc) != 0)
-			goto clk_en_err;
-
 		ret = clk_enable(host->iclk);
-		if (ret) {
-			mmc_host_disable(host->mmc);
-			clk_put(host->fclk);
+		if (ret)
 			goto clk_en_err;
-		}
 
 		if (clk_enable(host->dbclk) != 0)
 			dev_dbg(mmc_dev(host->mmc),
 					"Enabling debounce clk failed\n");
 
+		if (mmc_host_enable(host->mmc) != 0) {
+			clk_disable(host->iclk);
+			goto clk_en_err;
+		}
+
 		omap_hsmmc_init(host);
 
 		if (host->pdata->resume) {
-- 
1.5.6.3


  parent reply	other threads:[~2009-07-10 12:41 UTC|newest]

Thread overview: 58+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-07-10 12:40 [PATCH 0/32] mmc and omap_hsmmc patches Adrian Hunter
2009-07-10 12:40 ` [PATCH 1/32] mmc: add 'enable' and 'disable' methods to mmc host Adrian Hunter
2009-07-10 17:15   ` Madhusudhan
2009-07-10 19:12     ` Adrian Hunter
2009-07-23 20:37   ` Linus Walleij
2009-07-23 20:37     ` Linus Walleij
2009-07-10 12:40 ` [PATCH 2/32] mmc: allow host claim / release nesting Adrian Hunter
2009-07-10 12:40 ` [PATCH 3/32] mmc: add MMC_CAP_NONREMOVABLE host capability Adrian Hunter
2009-07-10 12:40 ` [PATCH 4/32] mmc: add ability to save power by powering off cards Adrian Hunter
2009-07-10 12:40 ` [PATCH 5/32] mmc: add mmc card sleep and awake support Adrian Hunter
2009-07-10 12:40 ` [PATCH 6/32] mmc: power off once at removal Adrian Hunter
2009-07-10 12:40 ` [PATCH 7/32] mmc: add host capabilities for SD only and MMC only Adrian Hunter
2009-07-25 15:53   ` Matt Fleming
2009-07-25 16:17     ` Adrian Hunter
2009-07-25 18:40       ` Matt Fleming
2009-07-25 19:45         ` Adrian Hunter
2009-07-25 23:51           ` Matt Fleming
2009-07-26  6:14             ` Adrian Hunter
2009-07-10 12:41 ` [PATCH 8/32] mmc: check status after MMC SWITCH command Adrian Hunter
2009-07-10 12:41 ` [PATCH 9/32] omap_hsmmc: add debugfs entry (host registers) Adrian Hunter
2009-07-10 12:41 ` [PATCH 10/32] omap_hsmmc: make use of new enable/disable interface Adrian Hunter
2009-07-10 12:41 ` [PATCH 11/32] ARM: OMAP: mmc-twl4030: add context loss counter support Adrian Hunter
2009-07-10 12:41 ` [PATCH 12/32] omap_hsmmc: keep track of power mode Adrian Hunter
2009-07-10 12:41 ` Adrian Hunter [this message]
2009-07-10 12:41 ` [PATCH 14/32] omap_hsmmc: set open drain bit correctly Adrian Hunter
2009-07-10 12:41 ` [PATCH 15/32] omap_hsmmc: ensure workqueues are empty before suspend Adrian Hunter
2009-07-10 12:41 ` [PATCH 16/32] omap_hsmmc: fix scatter-gather list sanity checking Adrian Hunter
2009-07-10 12:42 ` [PATCH 17/32] omap_hsmmc: make use of new MMC_CAP_NONREMOVABLE host capability Adrian Hunter
2009-07-10 12:42 ` [PATCH 18/32] omap_hsmmc: support for deeper power saving states Adrian Hunter
2009-07-10 12:42 ` [PATCH 19/32] ARM: OMAP: mmc-twl4030: add regulator sleep / wake function Adrian Hunter
2009-07-10 12:42 ` [PATCH 20/32] omap_hsmmc: put MMC regulator to sleep Adrian Hunter
2009-07-24 22:51   ` Andrew Morton
2009-07-24 22:51     ` Andrew Morton
2009-07-26  6:34     ` Adrian Hunter
2009-07-10 12:42 ` [PATCH 21/32] omap_hsmmc: add mmc card sleep and awake support Adrian Hunter
2009-07-10 12:42 ` [PATCH 22/32] omap_hsmmc: fix NULL pointer dereference Adrian Hunter
2009-07-10 12:42 ` [PATCH 23/32] omap_hsmmc: cleanup macro usage Adrian Hunter
2009-07-10 12:42 ` [PATCH 24/32] omap_hsmmc: clear interrupt status after init sequence Adrian Hunter
2009-07-10 12:43 ` [PATCH 25/32] omap_hsmmc: cater for weird CMD6 behaviour Adrian Hunter
2009-07-10 12:43 ` [PATCH 26/32] omap_hsmmc: prevent races with irq handler Adrian Hunter
2009-07-24 22:53   ` Andrew Morton
2009-07-24 22:53     ` Andrew Morton
2009-07-27  9:06     ` Adrian Hunter
2009-07-10 12:43 ` [PATCH 27/32] omap_hsmmc: pass host capabilities for SD only and MMC only Adrian Hunter
2009-07-10 12:43 ` [PATCH 28/32] omap_hsmmc: code refactoring Adrian Hunter
2009-07-10 12:43 ` [PATCH 29/32] omap_hsmmc: protect the card when the cover is open Adrian Hunter
2009-07-10 12:43 ` [PATCH 30/32] omap_hsmmc: ensure all clock enables and disables are paired Adrian Hunter
2009-07-10 12:43 ` [PATCH 31/32] omap_hsmmc: set a large data timeout for commands with busy signal Adrian Hunter
2009-07-10 12:43 ` [PATCH 32/32] ARM: OMAP: RX51: set MMC capabilities and power-saving flag Adrian Hunter
2009-07-25 23:53   ` Matt Fleming
2009-07-27  7:58     ` Adrian Hunter
2009-07-27  8:27       ` Matt Fleming
2009-07-27  8:58         ` Adrian Hunter
2009-07-27  9:15           ` Matt Fleming
     [not found]             ` <20090727102111.GI12665@console-pimps.org>
2009-07-27 11:02               ` Adrian Hunter
2009-07-27 18:14                 ` Andrew Morton
2009-07-27 19:32                   ` Matt Fleming
2009-07-26 19:57 ` [PATCH 0/32] mmc and omap_hsmmc patches Matt Fleming

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20090710124137.1262.63323.sendpatchset@ahunter-tower \
    --to=adrian.hunter@nokia.com \
    --cc=ext-denis.2.karpov@nokia.com \
    --cc=jarkko.lavinen@nokia.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-omap@vger.kernel.org \
    --cc=pierre@ossman.eu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.