aboutsummaryrefslogtreecommitdiff
path: root/drivers/mfd/glamo/glamo-mci.c
diff options
context:
space:
mode:
authorAndy Green <andy@openmoko.com>2008-11-19 17:10:53 +0000
committerAndy Green <agreen@pads.home.warmcat.com>2008-11-19 17:10:53 +0000
commitabf08dec77817f58705505004b7a62f444ddba7f (patch)
treedd496d63cbe8253c4fe1de9317ad0906b4e95d72 /drivers/mfd/glamo/glamo-mci.c
parent32fb968be66e32a10c6eec27b33155a9c335d0d4 (diff)
fix-glamo-mci-slow-clock-until-first-bulk.patch
This patch adds another module parameter to glamo-mci which sets the SD Card clock rate used inbetween powering the card and the completion of the first bulk transfer. You can set it from kernel commandline like this. glamo_mci.sd_post_power_clock=1000000 The period between changing the power state and the first bulk transfer completion is critical because larger SDHC cards take longer to initialize before they can service the bulk transfer, and the Glamo MMC unit has a fixed timeout length of a maximum of 4095 x 16 x SD Card clocks. Large cards like 8GB Sandisk SDHC are not ready before this timeout is used up at default 16MHz. Subsequently, the card can handle 16MHz SD Clock and timeout durations okay. By default this patch operates the SD Clock at only 1MHz until the first bulk transfer is completed after each powerup action from the MCI stack. It also keeps the SD Clock running during this time, and disables the SD Clock if the card is not present and the MCI stack removes power. Signed-off-by: Andy Green <andy@openmoko.com>
Diffstat (limited to 'drivers/mfd/glamo/glamo-mci.c')
-rw-r--r--drivers/mfd/glamo/glamo-mci.c108
1 files changed, 66 insertions, 42 deletions
diff --git a/drivers/mfd/glamo/glamo-mci.c b/drivers/mfd/glamo/glamo-mci.c
index 66cfd357459..b22f84aedfe 100644
--- a/drivers/mfd/glamo/glamo-mci.c
+++ b/drivers/mfd/glamo/glamo-mci.c
@@ -74,6 +74,23 @@ static int sd_slow_ratio = 8;
module_param(sd_slow_ratio, int, 0644);
/*
+ * Post-power SD clock rate
+ *
+ * you can override this on kernel commandline using
+ *
+ * glamo_mci.sd_post_power_clock=1000000
+ *
+ * for example
+ *
+ * After changing power to card, clock is held at this rate until first bulk
+ * transfer completes
+ */
+
+static int sd_post_power_clock = 1000000;
+module_param(sd_post_power_clock, int, 0644);
+
+
+/*
* SD Signal drive strength
*
* you can override this on kernel commandline using
@@ -240,21 +257,35 @@ static void __glamo_mci_fix_card_div(struct glamo_mci_host *host, int div)
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);
+
+ goto done;
}
+ if (host->force_slow_during_powerup)
+ div = host->clk_rate / sd_post_power_clock;
+ else
+ if (host->pdata->glamo_mci_use_slow)
+ if ((host->pdata->glamo_mci_use_slow)())
+ div = div * sd_slow_ratio;
+
+ if (div > 255)
+ div = 255;
+
+ /*
+ * 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);
+
+done:
spin_unlock_irqrestore(&clock_lock, flags);
}
@@ -284,7 +315,7 @@ static int __glamo_mci_set_card_clock(struct glamo_mci_host *host, int freq,
if (division)
*division = 0xff;
- if (!sd_idleclk)
+ if (!sd_idleclk && !host->force_slow_during_powerup)
/* clock off */
__glamo_mci_fix_card_div(host, -1);
}
@@ -327,6 +358,10 @@ static void glamo_mci_irq(unsigned int irq, struct irq_desc *desc)
goto done;
}
+ /* disable the initial slow start after first bulk transfer */
+ if (host->force_slow_during_powerup)
+ host->force_slow_during_powerup--;
+
if (host->pio_active == XFER_READ)
do_pio_read(host);
@@ -341,7 +376,7 @@ static void glamo_mci_irq(unsigned int irq, struct irq_desc *desc)
host->cmd_is_stop = 0;
}
- if (!sd_idleclk)
+ if (!sd_idleclk && !host->force_slow_during_powerup)
/* clock off */
__glamo_mci_fix_card_div(host, -1);
@@ -357,7 +392,6 @@ static int glamo_mci_send_command(struct glamo_mci_host *host,
{
u8 u8a[6];
u16 fire = 0;
- u16 timeout = 0xfff; /* max glamo MMC timeout, in units of 16 clocks */
/* if we can't do it, reject as busy */
if (!readw_dly(host->base + GLAMO_REG_MMC_RB_STAT1) &
@@ -467,15 +501,9 @@ static int glamo_mci_send_command(struct glamo_mci_host *host,
fire |= GLAMO_FIRE_MMC_CC_BASIC; /* "basic command" */
break;
}
- /* enforce timeout, clipping at default 65520 clocks if larger */
- if (cmd->data)
- /* so long as there is one... */
- if (cmd->data->timeout_clks &&
- /* ... and it is not longer than we can handle */
- (cmd->data->timeout_clks <= 0xffff))
- timeout = cmd->data->timeout_clks >> 4; /* / 16 clks */
- writew(timeout, host->base + GLAMO_REG_MMC_TIMEOUT);
+ /* always largest timeout */
+ writew(0xfff, host->base + GLAMO_REG_MMC_TIMEOUT);
/* Generate interrupt on txfer */
writew_dly((readw_dly(host->base + GLAMO_REG_MMC_BASIC) & 0x3e) |
@@ -576,14 +604,7 @@ static void glamo_mci_send_request(struct mmc_host *mmc)
/* resume requested clock rate
* scale it down by sd_slow_ratio if platform requests it
*/
- if (host->pdata->glamo_mci_use_slow)
- if ((host->pdata->glamo_mci_use_slow)())
- __glamo_mci_fix_card_div(host, host->clk_div *
- sd_slow_ratio);
- else
- __glamo_mci_fix_card_div(host, host->clk_div);
- else
- __glamo_mci_fix_card_div(host, host->clk_div);
+ __glamo_mci_fix_card_div(host, host->clk_div);
if (glamo_mci_send_command(host, cmd))
goto bail;
@@ -633,6 +654,7 @@ static void glamo_mci_send_request(struct mmc_host *mmc)
goto done;
if (!(cmd->data->flags & (MMC_DATA_READ | MMC_DATA_WRITE)))
goto done;
+
/*
* Otherwise can can use the interrupt as async completion --
* if there is read data coming, or we wait for write data to complete,
@@ -676,7 +698,7 @@ done:
host->mrq = NULL;
mmc_request_done(host->mmc, cmd->mrq);
bail:
- if (!sd_idleclk)
+ if (!sd_idleclk && !host->force_slow_during_powerup)
/* stop the clock to card */
__glamo_mci_fix_card_div(host, -1);
}
@@ -718,6 +740,12 @@ static void glamo_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
switch(ios->power_mode) {
case MMC_POWER_ON:
case MMC_POWER_UP:
+ /*
+ * we should use very slow clock until first bulk
+ * transfer completes OK
+ */
+ host->force_slow_during_powerup = 1;
+
if (host->vdd_current != ios->vdd) {
host->pdata->glamo_set_mci_power(ios->power_mode,
ios->vdd);
@@ -734,6 +762,9 @@ static void glamo_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
default:
if (host->power_mode_current == MMC_POWER_OFF)
break;
+ /* never want clocking with dead card */
+ __glamo_mci_fix_card_div(host, -1);
+
glamo_engine_disable(glamo_mci_def_pdata.pglamo,
GLAMO_ENGINE_MMC);
host->pdata->glamo_set_mci_power(MMC_POWER_OFF, 0);
@@ -751,7 +782,7 @@ static void glamo_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
if (powering)
msleep(1);
- if (!sd_idleclk)
+ if (!sd_idleclk && !host->force_slow_during_powerup)
/* stop the clock to card, because we are idle until transfer */
__glamo_mci_fix_card_div(host, -1);
@@ -953,14 +984,7 @@ static int glamo_mci_suspend(struct platform_device *dev, pm_message_t state)
* make sure the clock was running during suspend and consequently
* resume
*/
- if (host->pdata->glamo_mci_use_slow)
- if ((host->pdata->glamo_mci_use_slow)())
- __glamo_mci_fix_card_div(host, host->clk_div *
- sd_slow_ratio);
- else
- __glamo_mci_fix_card_div(host, host->clk_div);
- else
- __glamo_mci_fix_card_div(host, host->clk_div);
+ __glamo_mci_fix_card_div(host, host->clk_div);
/* we are going to do more commands to override this in
* mmc_suspend_host(), so we need to change sd_idleclk for the