openwrt/target/linux/s3c24xx/patches-2.6.24/1235-fix-force-sdcard-clk-o...

241 lines
7.1 KiB
Diff
Raw Normal View History

From 5d70edcbe3ff5f6d5aef54ee9e278ad1ce431fd5 Mon Sep 17 00:00:00 2001
From: Andy Green <andy@openmoko.com>
Date: Thu, 17 Jul 2008 10:02:19 +0100
Subject: [PATCH] fix-force-sdcard-clk-off-when-idle.patch
Existing Glamo bit for stopping SD Card Clock when there is no
transfer taking place does not work. This patch adds stuff around
the transfer code to force the SD clock up when something is going on
and down when it is idle. This'll save a little power and noise ;-)
I tested it briefly and was able to SD Boot normally on Sandisk 512M.
Wider testing is appreciated.
Signed-off-by: Andy Green <andy@openmoko.com>
---
drivers/mfd/glamo/glamo-mci.c | 126 +++++++++++++++++++++++++++++------------
1 files changed, 89 insertions(+), 37 deletions(-)
diff --git a/drivers/mfd/glamo/glamo-mci.c b/drivers/mfd/glamo/glamo-mci.c
index f264a6c..350b47d 100644
--- a/drivers/mfd/glamo/glamo-mci.c
+++ b/drivers/mfd/glamo/glamo-mci.c
@@ -20,6 +20,7 @@
#include <linux/pcf50633.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
+#include <linux/spinlock.h>
#include <asm/dma.h>
#include <asm/dma-mapping.h>
@@ -32,6 +33,7 @@
/* from glamo-core.c */
extern struct glamo_mci_pdata glamo_mci_def_pdata;
+static spinlock_t clock_lock;
#define DRIVER_NAME "glamo-mci"
#define RESSIZE(ressource) (((ressource)->end - (ressource)->start) + 1)
@@ -164,6 +166,67 @@ static int do_pio_write(struct glamo_mci_host *host)
return err;
}
+static void __glamo_mci_fix_card_div(struct glamo_mci_host *host, int div)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&clock_lock, flags);
+
+ if (div < 0) {
+ /* stop clock - remove clock from divider input */
+ writew(readw(glamo_mci_def_pdata.pglamo->base +
+ GLAMO_REG_CLOCK_GEN5_1) & (~GLAMO_CLOCK_GEN51_EN_DIV_TCLK),
+ glamo_mci_def_pdata.pglamo->base + GLAMO_REG_CLOCK_GEN5_1);
+ } else {
+ /* set the nearest prescaler factor
+ *
+ * register shared with SCLK divisor -- no chance of race because
+ * we don't use sensor interface
+ */
+ writew_dly((readw(glamo_mci_def_pdata.pglamo->base +
+ GLAMO_REG_CLOCK_GEN8) & 0xff00) | div,
+ glamo_mci_def_pdata.pglamo->base + GLAMO_REG_CLOCK_GEN8);
+ /* enable clock to divider input */
+ writew_dly(readw(glamo_mci_def_pdata.pglamo->base +
+ GLAMO_REG_CLOCK_GEN5_1) | GLAMO_CLOCK_GEN51_EN_DIV_TCLK,
+ glamo_mci_def_pdata.pglamo->base + GLAMO_REG_CLOCK_GEN5_1);
+ }
+
+ spin_unlock_irqrestore(&clock_lock, flags);
+}
+
+static int __glamo_mci_set_card_clock(struct glamo_mci_host *host, int freq,
+ int *division)
+{
+ int div = 0;
+ int real_rate = 0;
+
+ if (freq) {
+ /* Set clock */
+ for (div = 0; div < 256; div++) {
+ real_rate = host->clk_rate / (div + 1);
+ if (real_rate <= freq)
+ break;
+ }
+ if (div > 255)
+ div = 255;
+
+ if (division)
+ *division = div;
+
+ __glamo_mci_fix_card_div(host, div);
+
+ } else {
+ /* stop clock */
+ if (division)
+ *division = 0xff;
+
+ __glamo_mci_fix_card_div(host, -1); /* clock off */
+ }
+
+ return real_rate;
+}
+
static void glamo_mci_irq(unsigned int irq, struct irq_desc *desc)
{
struct glamo_mci_host *host = (struct glamo_mci_host *)
@@ -212,6 +275,10 @@ static void glamo_mci_irq(unsigned int irq, struct irq_desc *desc)
glamo_mci_send_request(host->mmc);
host->cmd_is_stop = 0;
}
+
+ /* clock off */
+ __glamo_mci_fix_card_div(host, -1);
+
done:
host->complete_what = COMPLETION_NONE;
host->mrq = NULL;
@@ -441,8 +508,11 @@ static void glamo_mci_send_request(struct mmc_host *mmc)
cmd->opcode, cmd->arg, cmd->data, cmd->mrq->stop,
cmd->flags);
+ /* resume requested clock rate */
+ __glamo_mci_fix_card_div(host, host->clk_div);
+
if (glamo_mci_send_command(host, cmd))
- return;
+ goto bail;
/*
* we must spin until response is ready or timed out
* -- we don't get interrupts unless there is a bulk rx
@@ -464,7 +534,7 @@ static void glamo_mci_send_request(struct mmc_host *mmc)
cmd->error = -EILSEQ;
if (host->cmd_is_stop)
- return;
+ goto bail;
if (cmd->error) {
dev_info(&host->pdev->dev, "Error after cmd: 0x%x\n", status);
@@ -516,10 +586,12 @@ static void glamo_mci_send_request(struct mmc_host *mmc)
if (cmd->data->error)
cmd->data->error = -ETIMEDOUT;
dev_err(&host->pdev->dev, "Payload timeout\n");
- return;
+ goto bail;
}
- /* yay we are an interrupt controller! -- call the ISR */
+ /* yay we are an interrupt controller! -- call the ISR
+ * it will stop clock to card
+ */
glamo_mci_irq(IRQ_GLAMO(GLAMO_IRQIDX_MMC),
irq_desc + IRQ_GLAMO(GLAMO_IRQIDX_MMC));
}
@@ -529,6 +601,12 @@ done:
host->complete_what = COMPLETION_NONE;
host->mrq = NULL;
mmc_request_done(host->mmc, cmd->mrq);
+ return;
+
+bail:
+ /* stop the clock to card */
+ __glamo_mci_fix_card_div(host, -1);
+ return;
}
static void glamo_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
@@ -556,11 +634,12 @@ static void glamo_mci_reset(struct glamo_mci_host *host)
glamo_mci_def_pdata.pglamo->base + GLAMO_REG_CLOCK_MMC);
}
+
static void glamo_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct glamo_mci_host *host = mmc_priv(mmc);
- int mci_psc = 0;
int n = 0;
+ int div;
/* Set power */
switch(ios->power_mode) {
@@ -590,43 +669,15 @@ static void glamo_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
}
host->power_mode_current = ios->power_mode;
- /* Set clock */
-/* if (ios->clock) { */
- for (mci_psc = 0; mci_psc < 256; mci_psc++) {
- host->real_rate = host->clk_rate / (mci_psc + 1);
- if (host->real_rate <= ios->clock)
- break;
- }
- if (mci_psc > 255)
- mci_psc = 255;
- host->clk_div = mci_psc;
- /* set the nearest prescaler factor
- *
- * register shared with SCLK divisor -- no chance of race because
- * we don't use sensor interface
- */
- writew_dly((readw(glamo_mci_def_pdata.pglamo->base +
- GLAMO_REG_CLOCK_GEN8) & 0xff00) | host->clk_div,
- glamo_mci_def_pdata.pglamo->base + GLAMO_REG_CLOCK_GEN8);
- /* enable clock to divider input */
- writew_dly(readw(glamo_mci_def_pdata.pglamo->base +
- GLAMO_REG_CLOCK_GEN5_1) | GLAMO_CLOCK_GEN51_EN_DIV_TCLK,
- glamo_mci_def_pdata.pglamo->base + GLAMO_REG_CLOCK_GEN5_1);
-#if 0
- } else { /* stop clock */
- host->real_rate = 0;
- /* remove clock from divider input */
- writew(readw(glamo_mci_def_pdata.pglamo->base +
- GLAMO_REG_CLOCK_GEN5_1) & (~GLAMO_CLOCK_GEN51_EN_DIV_TCLK),
- glamo_mci_def_pdata.pglamo->base + GLAMO_REG_CLOCK_GEN5_1);
- }
-#endif
+ host->real_rate = __glamo_mci_set_card_clock(host, ios->clock, &div);
+ host->clk_div = div;
+
if ((ios->power_mode == MMC_POWER_ON) ||
(ios->power_mode == MMC_POWER_UP)) {
dev_info(&host->pdev->dev,
"powered (vdd = %d) clk: %lukHz div=%d (req: %ukHz). "
"Bus width=%d\n",ios->vdd,
- host->real_rate / 1000, mci_psc,
+ host->real_rate / 1000, host->real_rate,
ios->clock / 1000, ios->bus_width);
} else
dev_info(&host->pdev->dev, "glamo_mci_set_ios: power down.\n");
@@ -856,6 +907,7 @@ static struct platform_driver glamo_mci_driver =
static int __init glamo_mci_init(void)
{
+ spin_lock_init(&clock_lock);
platform_driver_register(&glamo_mci_driver);
return 0;
}
--
1.5.6.5