Attached is a patch to port Andy's "slow down the SD clock when the GPS
is on" technique to the GTA01.
I have no figures (how did the Om team come up with the measurements for
the GTA02 and GPS interference?). However, anecdotal evidence very
strongly suggests that the SD clock on the GTA01 does adversely affect
the GPS on that device as well, so it seems to be reasonable to port
this patch back to the GTA01 as well. (Specifically, my GTA01 can
reliably get a fix in a few minutes from startup when lying flat on my
desktop, booted from the SD card -- whereas previously getting a fix
required clear skies and an outdoor location if an SD card was even
installed. That's only one data point, of course...)
NOTE! As presented, this patch does not actually do anything(!) so as
to not change any user-visible behavior. The default value value for
sd_slow_ratio is 1 by default. Distros or users that wish this to be
different will have to change the default, or do something like this at
boot time or before powering up the gps:
echo "8" >/sys/module/s3cmci/parameters/sd_slow_ratio
(Or, of course, a simple source code change to the default value is also
possible).
Regards,
Mike (mwester)
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 <[EMAIL PROTECTED]>
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 <asm/plat-s3c24xx/neo1973.h>
#include <asm/arch-s3c2410/neo1973-pm-gsm.h>
+#include "../plat-s3c24xx/neo1973_pm_gps.h"
+
#include <linux/jbt6k74.h>
#include <linux/neospy.h>
@@ -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 */