aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/mfd/glamo/glamo-mci.c108
-rw-r--r--drivers/mfd/glamo/glamo-mci.h2
2 files changed, 68 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
diff --git a/drivers/mfd/glamo/glamo-mci.h b/drivers/mfd/glamo/glamo-mci.h
index f3f170eb6c0..38f6376f438 100644
--- a/drivers/mfd/glamo/glamo-mci.h
+++ b/drivers/mfd/glamo/glamo-mci.h
@@ -44,6 +44,8 @@ struct glamo_mci_host {
unsigned long real_rate;
u8 prescaler;
+ int force_slow_during_powerup;
+
unsigned sdiimsk;
int dodma;