[ar71xx] create firmware image for the Ubiquiti LS-SR71 board
[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