[ar71xx] preliminary support for the Ubiquiti RouterStation Pro
[openwrt.git] / target / linux / s3c24xx / patches-2.6.24 / 1322-fix-gta01-s3c-mci-stop-clock-when-idle.patch.patch
1 From ff31834cfaac386f94ddd65fab8b87d090c69bcc Mon Sep 17 00:00:00 2001
2 From: Mike Westerhof <mwester@dls.net>
3 Date: Thu, 13 Nov 2008 20:38:35 +0000
4 Subject: [PATCH] fix-gta01-s3c-mci-stop-clock-when-idle.patch
5
6 This patch, based on the work done by Andy Green for the Glamo mci
7 driver, makes sure that the SD clock only runs during data transfers.
8 This can be overridden on the kernel command line if desired. Also
9 added is the ability for the maximum SD clock speed to be limited.
10
11 Signed-off-by: Mike Westerhof (mwester@dls.net)
12 ---
13 drivers/mmc/host/s3cmci.c | 113 +++++++++++++++++++++++++++++++++++++++++++--
14 1 files changed, 109 insertions(+), 4 deletions(-)
15
16 diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c
17 index edba055..8f88721 100644
18 --- a/drivers/mmc/host/s3cmci.c
19 +++ b/drivers/mmc/host/s3cmci.c
20 @@ -15,6 +15,8 @@
21 #include <linux/mmc/host.h>
22 #include <linux/platform_device.h>
23 #include <linux/irq.h>
24 +#include <linux/delay.h>
25 +#include <linux/spinlock.h>
26
27 #include <asm/dma.h>
28 #include <asm/dma-mapping.h>
29 @@ -29,6 +31,37 @@
30
31 #define DRIVER_NAME "s3c-mci"
32
33 +static spinlock_t clock_lock;
34 +
35 +/*
36 + * Max SD clock rate (in Hz)
37 + *
38 + * you can override this on the kernel command line using
39 + *
40 + * s3cmci.sd_max_clk=10000000
41 + *
42 + * for example.
43 + */
44 +
45 +static int sd_max_clk = 25000000;
46 +module_param(sd_max_clk, int, 0644);
47 +
48 +/*
49 + * SD allow SD clock to run while idle
50 + *
51 + * you can override this on kernel commandline using
52 + *
53 + * s3cmci.sd_idleclk=0
54 + *
55 + * for example.
56 + */
57 +
58 +static int sd_idleclk; /* disallow idle clock by default */
59 +module_param(sd_idleclk, int, 0644);
60 +
61 +/* used to stash real idleclk state in suspend: we force it to run in there */
62 +static int suspend_sd_idleclk;
63 +
64 enum dbg_channels {
65 dbg_err = (1 << 0),
66 dbg_debug = (1 << 1),
67 @@ -368,6 +401,40 @@ static void pio_tasklet(unsigned long data)
68 enable_irq(host->irq);
69 }
70
71 +static void __s3cmci_enable_clock(struct s3cmci_host *host)
72 +{
73 + u32 mci_con;
74 + unsigned long flags;
75 +
76 + /* enable the clock if clock rate is > 0 */
77 + if (host->real_rate) {
78 + spin_lock_irqsave(&clock_lock, flags);
79 +
80 + mci_con = readl(host->base + S3C2410_SDICON);
81 + mci_con |= S3C2410_SDICON_CLOCKTYPE;
82 + writel(mci_con, host->base + S3C2410_SDICON);
83 +
84 + spin_unlock_irqrestore(&clock_lock, flags);
85 + }
86 +}
87 +
88 +static void __s3cmci_disable_clock(struct s3cmci_host *host)
89 +{
90 + u32 mci_con;
91 + unsigned long flags;
92 +
93 + if (!sd_idleclk) {
94 + spin_lock_irqsave(&clock_lock, flags);
95 +
96 + mci_con = readl(host->base + S3C2410_SDICON);
97 + mci_con &= ~S3C2410_SDICON_CLOCKTYPE;
98 + writel(mci_con, host->base + S3C2410_SDICON);
99 +
100 + spin_unlock_irqrestore(&clock_lock, flags);
101 + }
102 +}
103 +
104 +
105 /*
106 * ISR for SDI Interface IRQ
107 * Communication between driver and ISR works as follows:
108 @@ -749,6 +816,7 @@ static void finalize_request(struct s3cmci_host *host)
109 }
110
111 request_done:
112 + __s3cmci_disable_clock(host);
113 host->complete_what = COMPLETION_NONE;
114 host->mrq = NULL;
115 mmc_request_done(host->mmc, mrq);
116 @@ -1005,6 +1073,7 @@ static void s3cmci_send_request(struct mmc_host *mmc)
117
118 }
119
120 + __s3cmci_enable_clock(host);
121 s3cmci_send_command(host, cmd);
122 enable_irq(host->irq);
123 }
124 @@ -1087,14 +1156,30 @@ static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
125 if ((ios->power_mode == MMC_POWER_ON)
126 || (ios->power_mode == MMC_POWER_UP)) {
127
128 - dbg(host, dbg_conf, "running at %lukHz (requested: %ukHz).\n",
129 - host->real_rate/1000, ios->clock/1000);
130 + dbg(host, dbg_conf,
131 + "powered (vdd: %d), clk: %lukHz div=%lu (req: %ukHz),"
132 + " bus width: %d\n", ios->vdd, host->real_rate / 1000,
133 + host->clk_div * (host->prescaler + 1),
134 + ios->clock / 1000, ios->bus_width);
135 +
136 + /* After power-up, we need to give the card 74 clocks to
137 + * initialize, so sleep just a moment before we disable
138 + * the clock again.
139 + */
140 + if (ios->clock)
141 + msleep(1);
142 +
143 } else {
144 dbg(host, dbg_conf, "powered down.\n");
145 }
146
147 host->bus_width = ios->bus_width;
148
149 + /* No need to run the clock until we have data to move */
150 + if (!sd_idleclk) {
151 + __s3cmci_disable_clock(host);
152 + dbg(host, dbg_conf, "SD clock disabled when idle.\n");
153 + }
154 }
155
156 static void s3cmci_reset(struct s3cmci_host *host)
157 @@ -1267,7 +1352,7 @@ static int s3cmci_probe(struct platform_device *pdev, int is2440)
158 mmc->ocr_avail = host->pdata->ocr_avail;
159 mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
160 mmc->f_min = host->clk_rate / (host->clk_div * 256);
161 - mmc->f_max = host->clk_rate / host->clk_div;
162 + mmc->f_max = sd_max_clk;
163
164 mmc->max_blk_count = 4095;
165 mmc->max_blk_size = 4095;
166 @@ -1354,14 +1439,33 @@ static int s3cmci_probe_2440(struct platform_device *dev)
167 static int s3cmci_suspend(struct platform_device *dev, pm_message_t state)
168 {
169 struct mmc_host *mmc = platform_get_drvdata(dev);
170 + struct s3cmci_host *host = mmc_priv(mmc);
171 + int ret;
172 +
173 + /* Ensure clock is running so it will be running on resume */
174 + __s3cmci_enable_clock(host);
175
176 - return mmc_suspend_host(mmc, state);
177 + /* We will do more commands, make sure the clock stays running,
178 + * and save our state so that we can restore it on resume.
179 + */
180 + suspend_sd_idleclk = sd_idleclk;
181 + sd_idleclk = 1;
182 +
183 + ret = mmc_suspend_host(mmc, state);
184 +
185 + /* so that when we resume, we use any modified max rate */
186 + mmc->f_max = sd_max_clk;
187 +
188 + return ret;
189 }
190
191 static int s3cmci_resume(struct platform_device *dev)
192 {
193 struct mmc_host *mmc = platform_get_drvdata(dev);
194
195 + /* Put the sd_idleclk state back to what it was */
196 + sd_idleclk = suspend_sd_idleclk;
197 +
198 return mmc_resume_host(mmc);
199 }
200
201 @@ -1398,6 +1502,7 @@ static struct platform_driver s3cmci_driver_2440 = {
202
203 static int __init s3cmci_init(void)
204 {
205 + spin_lock_init(&clock_lock);
206 platform_driver_register(&s3cmci_driver_2410);
207 platform_driver_register(&s3cmci_driver_2412);
208 platform_driver_register(&s3cmci_driver_2440);
209 --
210 1.5.6.5
211
This page took 0.049134 seconds and 5 git commands to generate.