diff options
Diffstat (limited to 'target/linux/s3c24xx/patches/0214-fix-force-sdcard-clk-off-when-idle.patch.patch')
-rwxr-xr-x | target/linux/s3c24xx/patches/0214-fix-force-sdcard-clk-off-when-idle.patch.patch | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/target/linux/s3c24xx/patches/0214-fix-force-sdcard-clk-off-when-idle.patch.patch b/target/linux/s3c24xx/patches/0214-fix-force-sdcard-clk-off-when-idle.patch.patch new file mode 100755 index 0000000..13dc940 --- /dev/null +++ b/target/linux/s3c24xx/patches/0214-fix-force-sdcard-clk-off-when-idle.patch.patch @@ -0,0 +1,240 @@ +From ee83ea40a3a1d1cb6447fdd345384d9cabf21c83 Mon Sep 17 00:00:00 2001 +From: Andy Green <andy@openmoko.com> +Date: Fri, 25 Jul 2008 23:06:20 +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 37e3d3c..b53827e 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_err(&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.3 + |