From: Carlos Aguiar <carlos.aguiar@indt.org.br>
To: ext Pierre Ossman <drzeus-list@drzeus.cx>
Cc: Tony Lindgren <tony@atomide.com>, linux-kernel@vger.kernel.org
Subject: [PATCH 16/18] MMC: OMAP: Lazy clock shutdown
Date: Wed, 26 Mar 2008 16:09:52 -0400 [thread overview]
Message-ID: <47EAAD90.1080707@indt.org.br> (raw)
In-Reply-To: <20080324132631.1e0d2125@mjolnir.drzeus.cx>
From: Jarkko Lavinen <jarkko.lavinen@nokia.com>
MMCA spec says the mmc clock should be kept running for at least
8 cycles after the last RW request. Ensure this with lazy clock
disable after a request, or with an explicit delay before
switching a slot.
Signed-off-by: Jarkko Lavinen <jarkko.lavinen@nokia.com>
---
drivers/mmc/host/omap.c | 89 +++++++++++++++++++++++++++++++++++++++-------
1 files changed, 75 insertions(+), 14 deletions(-)
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c
index aaecf4d..19001d3 100644
--- a/drivers/mmc/host/omap.c
+++ b/drivers/mmc/host/omap.c
@@ -161,9 +161,38 @@ struct mmc_omap_host {
wait_queue_head_t slot_wq;
int nr_slots;
+ struct timer_list clk_timer;
+ spinlock_t clk_lock; /* for changing enabled state */
+ unsigned int fclk_enabled:1;
+
struct omap_mmc_platform_data *pdata;
};
+void mmc_omap_fclk_offdelay(struct mmc_omap_slot *slot)
+{
+ unsigned long tick_ns;
+
+ if (slot != NULL && slot->host->fclk_enabled && slot->fclk_freq > 0) {
+ tick_ns = (1000000000 + slot->fclk_freq - 1) / slot->fclk_freq;
+ ndelay(8 * tick_ns);
+ }
+}
+
+void mmc_omap_fclk_enable(struct mmc_omap_host *host, unsigned int enable)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->clk_lock, flags);
+ if (host->fclk_enabled != enable) {
+ host->fclk_enabled = enable;
+ if (enable)
+ clk_enable(host->fclk);
+ else
+ clk_disable(host->fclk);
+ }
+ spin_unlock_irqrestore(&host->clk_lock, flags);
+}
+
static void mmc_omap_select_slot(struct mmc_omap_slot *slot, int claimed)
{
struct mmc_omap_host *host = slot->host;
@@ -180,32 +209,49 @@ static void mmc_omap_select_slot(struct mmc_omap_slot *slot, int claimed)
host->mmc = slot->mmc;
spin_unlock_irqrestore(&host->slot_lock, flags);
no_claim:
- clk_enable(host->fclk);
+ del_timer(&host->clk_timer);
+ if (host->current_slot != slot || !claimed)
+ mmc_omap_fclk_offdelay(host->current_slot);
+
if (host->current_slot != slot) {
+ OMAP_MMC_WRITE(host, CON, slot->saved_con & 0xFC00);
if (host->pdata->switch_slot != NULL)
host->pdata->switch_slot(mmc_dev(slot->mmc), slot->id);
host->current_slot = slot;
}
- /* Doing the dummy read here seems to work around some bug
- * at least in OMAP24xx silicon where the command would not
- * start after writing the CMD register. Sigh. */
- OMAP_MMC_READ(host, CON);
+ if (claimed) {
+ mmc_omap_fclk_enable(host, 1);
+
+ /* Doing the dummy read here seems to work around some bug
+ * at least in OMAP24xx silicon where the command would not
+ * start after writing the CMD register. Sigh. */
+ OMAP_MMC_READ(host, CON);
- OMAP_MMC_WRITE(host, CON, slot->saved_con);
+ OMAP_MMC_WRITE(host, CON, slot->saved_con);
+ } else
+ mmc_omap_fclk_enable(host, 0);
}
static void mmc_omap_start_request(struct mmc_omap_host *host,
struct mmc_request *req);
-static void mmc_omap_release_slot(struct mmc_omap_slot *slot)
+static void mmc_omap_release_slot(struct mmc_omap_slot *slot, int clk_enabled)
{
struct mmc_omap_host *host = slot->host;
unsigned long flags;
int i;
BUG_ON(slot == NULL || host->mmc == NULL);
- clk_disable(host->fclk);
+
+ if (clk_enabled)
+ /* Keeps clock running for at least 8 cycles on valid freq */
+ mod_timer(&host->clk_timer, jiffies + HZ/10);
+ else {
+ del_timer(&host->clk_timer);
+ mmc_omap_fclk_offdelay(slot);
+ mmc_omap_fclk_enable(host, 0);
+ }
spin_lock_irqsave(&host->slot_lock, flags);
/* Check for any pending requests */
@@ -373,7 +419,7 @@ mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data)
host->mrq = NULL;
mmc = host->mmc;
- mmc_omap_release_slot(host->current_slot);
+ mmc_omap_release_slot(host->current_slot, 1);
mmc_request_done(mmc, data->mrq);
return;
}
@@ -507,7 +553,7 @@ mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd)
mmc_omap_abort_xfer(host, host->data);
host->mrq = NULL;
mmc = host->mmc;
- mmc_omap_release_slot(host->current_slot);
+ mmc_omap_release_slot(host->current_slot, 1);
mmc_request_done(mmc, cmd->mrq);
}
}
@@ -538,7 +584,7 @@ static void mmc_omap_abort_command(struct work_struct *work)
host->mrq = NULL;
mmc = host->mmc;
- mmc_omap_release_slot(host->current_slot);
+ mmc_omap_release_slot(host->current_slot, 1);
mmc_request_done(mmc, cmd->mrq);
} else
mmc_omap_cmd_done(host, host->cmd);
@@ -576,6 +622,14 @@ mmc_omap_sg_to_buf(struct mmc_omap_host *host)
host->buffer_bytes_left = host->total_bytes_left;
}
+static void
+mmc_omap_clk_timer(unsigned long data)
+{
+ struct mmc_omap_host *host = (struct mmc_omap_host *) data;
+
+ mmc_omap_fclk_enable(host, 0);
+}
+
/* PIO only */
static void
mmc_omap_xfer_data(struct mmc_omap_host *host, int write)
@@ -1149,14 +1203,16 @@ static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
struct mmc_omap_slot *slot = mmc_priv(mmc);
struct mmc_omap_host *host = slot->host;
int i, dsor;
-
- dsor = mmc_omap_calc_divisor(mmc, ios);
+ int clk_enabled;
mmc_omap_select_slot(slot, 0);
+ dsor = mmc_omap_calc_divisor(mmc, ios);
+
if (ios->vdd != slot->vdd)
slot->vdd = ios->vdd;
+ clk_enabled = 0;
switch (ios->power_mode) {
case MMC_POWER_OFF:
mmc_omap_set_power(slot, 0, ios->vdd);
@@ -1166,6 +1222,8 @@ static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
mmc_omap_set_power(slot, 1, ios->vdd);
goto exit;
case MMC_POWER_ON:
+ mmc_omap_fclk_enable(host, 1);
+ clk_enabled = 1;
dsor |= 1 << 11;
break;
}
@@ -1194,7 +1252,7 @@ static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
}
exit:
- mmc_omap_release_slot(slot);
+ mmc_omap_release_slot(slot, clk_enabled);
}
static const struct mmc_host_ops mmc_omap_ops = {
@@ -1335,6 +1393,9 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
setup_timer(&host->cmd_abort_timer, mmc_omap_cmd_timer,
(unsigned long) host);
+ spin_lock_init(&host->clk_lock);
+ setup_timer(&host->clk_timer, mmc_omap_clk_timer, (unsigned long) host);
+
spin_lock_init(&host->dma_lock);
setup_timer(&host->dma_timer, mmc_omap_dma_timer, (unsigned long) host);
spin_lock_init(&host->slot_lock);
-- 1.5.3.GIT
next prev parent reply other threads:[~2008-03-26 20:17 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-03-14 19:35 [PATCH 00/18] MMC: OMAP: Sync MMC OMAP driver with mainline tree Carlos Aguiar
2008-03-24 12:26 ` Pierre Ossman
2008-03-26 20:08 ` Carlos Aguiar
2008-03-30 16:10 ` Pierre Ossman
2008-03-26 20:08 ` [PATCH 01/18] MMC: OMAP: Remove some opcodes from host driver Carlos Aguiar
2008-03-26 20:08 ` [PATCH 02/18] MMC: OMAP: Remove extra divisor increase Carlos Aguiar
2008-03-26 20:08 ` [PATCH 03/18] MMC: OMAP: Fix the BYTEBLOCK capability removal Carlos Aguiar
2008-03-26 20:08 ` [PATCH 04/18] MMC: OMAP: Remove cover switch handling to allow adding multislot support Carlos Aguiar
2008-03-26 20:08 ` [PATCH 05/18] MMC: OMAP: Introduce new multislot structure and change driver to use it Carlos Aguiar
2008-03-26 20:09 ` [PATCH 06/18] MMC: OMAP: Add back cover switch support Carlos Aguiar
2008-03-26 20:09 ` [PATCH 07/18] MMC: OMAP: New release dma and abort xfer functions Carlos Aguiar
2008-03-26 20:09 ` [PATCH 08/18] MMC: OMAP: Fix timeout calculation for MMC multislot support Carlos Aguiar
2008-03-26 20:09 ` [PATCH 09/18] MMC: OMAP: Power functions modified to " Carlos Aguiar
2008-03-26 20:09 ` [PATCH 10/18] MMC: OMAP: General cleanup for " Carlos Aguiar
2008-03-26 20:09 ` [PATCH 11/18] MMC: OMAP: Abort stuck commands Carlos Aguiar
2008-03-26 20:09 ` [PATCH 12/18] MMC: OMAP: Using setup_timer instead of init_timer Carlos Aguiar
2008-03-26 20:09 ` [PATCH 13/18] MMC: OMAP: Check the get_cover_state function pointer if not set Carlos Aguiar
2008-03-26 20:09 ` [PATCH 14/18] MMC: OMAP: Use tasklet instead of workqueue for cover switch notification Carlos Aguiar
2008-03-26 20:09 ` [PATCH 15/18] MMC: OMAP: Move failing command abortion to workqueue Carlos Aguiar
2008-03-26 20:09 ` Carlos Aguiar [this message]
2008-03-26 20:09 ` [PATCH 17/18] MMC: OMAP: Start new commands from work queue instead of irq Carlos Aguiar
2008-03-26 20:10 ` [PATCH 18/18] MMC: OMAP: Do not busy wait for end of command for ever Carlos Aguiar
-- strict thread matches above, loose matches on Subject: below --
2008-03-14 19:36 [PATCH 16/18] MMC: OMAP: Lazy clock shutdown Carlos Aguiar
2008-01-28 19:08 Carlos Aguiar
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=47EAAD90.1080707@indt.org.br \
--to=carlos.aguiar@indt.org.br \
--cc=drzeus-list@drzeus.cx \
--cc=linux-kernel@vger.kernel.org \
--cc=tony@atomide.com \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox