aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/s3c24xx/patches-2.6.24/1323-GTA01-use-slow-SD-clock-when-gps-on.patch.patch
blob: 3e16c6edfedf60e6a2d95dde0568685f43ad596c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
From d944934bbddc281938fb1905a69e35c0581937c2 Mon Sep 17 00:00:00 2001
From: Mike Westerhof <mwester@dls.net>
Date: Thu, 13 Nov 2008 20:39:36 +0000
Subject: [PATCH] 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 <mwester@dls.net>
---
 arch/arm/mach-s3c2410/mach-gta01.c |    8 ++++++
 drivers/mmc/host/s3cmci.c          |   43 ++++++++++++++++++++++++++++++++++-
 drivers/mmc/host/s3cmci.h          |    1 +
 include/asm-arm/arch-s3c2410/mci.h |    1 +
 4 files changed, 51 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-s3c2410/mach-gta01.c b/arch/arm/mach-s3c2410/mach-gta01.c
index a364b76..c0817dc 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>
 
 static struct map_desc gta01_iodesc[] __initdata = {
@@ -432,9 +434,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	= &gta01_mmc_set_power,
+	.use_slow	= &gta01_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 = 8;
+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 */
-- 
1.5.6.5