GTA01-use-slow-SD-clock-when-gps-on.patch This patch implements Andy Green's SD clock slow-down code for the GTA01 device. Signed-off-by: Mike Westerhof diff --git a/arch/arm/mach-s3c2410/mach-gta01.c b/arch/arm/mach-s3c2410/mach-gta01.c index 283a7ab..782b509 100644 --- a/arch/arm/mach-s3c2410/mach-gta01.c +++ b/arch/arm/mach-s3c2410/mach-gta01.c @@ -75,6 +75,8 @@ #include #include +#include "../plat-s3c24xx/neo1973_pm_gps.h" + #include #include @@ -433,9 +435,15 @@ static void gta01_mmc_set_power(unsigned char power_mode, unsigned short vdd) } } +static int gta01_mmc_use_slow(void) +{ + return neo1973_pm_gps_is_on(); +} + static struct s3c24xx_mci_pdata gta01_mmc_cfg = { .gpio_detect = GTA01_GPIO_nSD_DETECT, .set_power = >a01_mmc_set_power, + .use_slow = >a01_mmc_use_slow, .ocr_avail = MMC_VDD_165_195|MMC_VDD_20_21| MMC_VDD_21_22|MMC_VDD_22_23|MMC_VDD_23_24| MMC_VDD_24_25|MMC_VDD_25_26|MMC_VDD_26_27| diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index 8f88721..87d24b2 100644 --- a/drivers/mmc/host/s3cmci.c +++ b/drivers/mmc/host/s3cmci.c @@ -59,6 +59,23 @@ module_param(sd_max_clk, int, 0644); static int sd_idleclk; /* disallow idle clock by default */ module_param(sd_idleclk, int, 0644); +/* + * Slow SD clock rate + * + * you can override this on kernel commandline using + * + * s3cmci.sd_slow_ratio=8 + * + * for example. + * + * A platform callback is used to decide effective clock rate. If not + * defined, then the max is used, if defined and the callback returns + * nonzero, the rate is divided by this factor. + */ + +static int sd_slow_ratio = 1; +module_param(sd_slow_ratio, int, 0644); + /* used to stash real idleclk state in suspend: we force it to run in there */ static int suspend_sd_idleclk; @@ -252,7 +269,7 @@ static inline void do_pio_read(struct s3cmci_host *host) void __iomem *from_ptr; /* write real prescaler to host, it might be set slow to fix */ - writel(host->prescaler, host->base + S3C2410_SDIPRE); + writel(host->sdipre, host->base + S3C2410_SDIPRE); from_ptr = host->base + host->sdidata; @@ -755,7 +772,7 @@ static void finalize_request(struct s3cmci_host *host) cmd->resp[3] = readl(host->base + S3C2410_SDIRSP3); /* reset clock speed, as it could still be set low for */ - writel(host->prescaler, host->base + S3C2410_SDIPRE); + writel(host->sdipre, host->base + S3C2410_SDIPRE); if (cmd->error) debug_as_failure = 1; @@ -1032,6 +1049,7 @@ static void s3cmci_send_request(struct mmc_host *mmc) struct s3cmci_host *host = mmc_priv(mmc); struct mmc_request *mrq = host->mrq; struct mmc_command *cmd = host->cmd_is_stop?mrq->stop:mrq->cmd; + int pre; host->ccnt++; #ifdef CONFIG_MMC_DEBUG @@ -1073,6 +1091,26 @@ static void s3cmci_send_request(struct mmc_host *mmc) } + /* establish the correct prescaler depending on the sd_slow_ratio */ + + if ((sd_slow_ratio > 1) && + host->pdata->use_slow && (host->pdata->use_slow)()) { + /* compute the slower speed */ + pre = host->prescaler * sd_slow_ratio; + if (pre > 255) + pre = 255; + } else { + /* use the normal speed */ + pre = host->prescaler; + } + + if (host->sdipre != pre) { + dbg(host, dbg_conf, "prescaler changed: %d -> %d\n", + (int)host->sdipre, pre); + host->sdipre = pre; + writel(host->sdipre, host->base + S3C2410_SDIPRE); + } + __s3cmci_enable_clock(host); s3cmci_send_command(host, cmd); enable_irq(host->irq); @@ -1138,6 +1176,7 @@ static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (mci_psc > 255) mci_psc = 255; host->prescaler = mci_psc; + host->sdipre = mci_psc; writel(host->prescaler, host->base + S3C2410_SDIPRE); diff --git a/drivers/mmc/host/s3cmci.h b/drivers/mmc/host/s3cmci.h index 9644b45..11974ff 100644 --- a/drivers/mmc/host/s3cmci.h +++ b/drivers/mmc/host/s3cmci.h @@ -32,6 +32,7 @@ struct s3cmci_host { unsigned long clk_div; unsigned long real_rate; u8 prescaler; + u8 sdipre; int is2440; unsigned sdiimsk; diff --git a/include/asm-arm/arch-s3c2410/mci.h b/include/asm-arm/arch-s3c2410/mci.h index 24e6cd1..f087229 100644 --- a/include/asm-arm/arch-s3c2410/mci.h +++ b/include/asm-arm/arch-s3c2410/mci.h @@ -8,6 +8,7 @@ struct s3c24xx_mci_pdata { unsigned int do_dma; void (*set_power)(unsigned char power_mode, unsigned short vdd); + int (*use_slow)(void); }; #endif /* _ARCH_NCI_H */