disable IMQ on 2.6.28 as well -- people should use IFB..
[openwrt.git] / target / linux / s3c24xx / patches / 0214-fix-force-sdcard-clk-off-when-idle.patch.patch
1 From ee83ea40a3a1d1cb6447fdd345384d9cabf21c83 Mon Sep 17 00:00:00 2001
2 From: Andy Green <andy@openmoko.com>
3 Date: Fri, 25 Jul 2008 23:06:20 +0100
4 Subject: [PATCH] fix-force-sdcard-clk-off-when-idle.patch
5
6 Existing Glamo bit for stopping SD Card Clock when there is no
7 transfer taking place does not work.  This patch adds stuff around
8 the transfer code to force the SD clock up when something is going on
9 and down when it is idle.  This'll save a little power and noise ;-)
10
11 I tested it briefly and was able to SD Boot normally on Sandisk 512M.
12 Wider testing is appreciated.
13
14 Signed-off-by: Andy Green <andy@openmoko.com>
15 ---
16  drivers/mfd/glamo/glamo-mci.c |  126 +++++++++++++++++++++++++++++------------
17  1 files changed, 89 insertions(+), 37 deletions(-)
18
19 diff --git a/drivers/mfd/glamo/glamo-mci.c b/drivers/mfd/glamo/glamo-mci.c
20 index 37e3d3c..b53827e 100644
21 --- a/drivers/mfd/glamo/glamo-mci.c
22 +++ b/drivers/mfd/glamo/glamo-mci.c
23 @@ -20,6 +20,7 @@
24  #include <linux/pcf50633.h>
25  #include <linux/delay.h>
26  #include <linux/interrupt.h>
27 +#include <linux/spinlock.h>
28  
29  #include <asm/dma.h>
30  #include <asm/dma-mapping.h>
31 @@ -32,6 +33,7 @@
32  /* from glamo-core.c */
33  extern struct glamo_mci_pdata glamo_mci_def_pdata;
34  
35 +static spinlock_t clock_lock;
36  
37  #define DRIVER_NAME "glamo-mci"
38  #define RESSIZE(ressource) (((ressource)->end - (ressource)->start) + 1)
39 @@ -164,6 +166,67 @@ static int do_pio_write(struct glamo_mci_host *host)
40         return err;
41  }
42  
43 +static void __glamo_mci_fix_card_div(struct glamo_mci_host *host, int div)
44 +{
45 +       unsigned long flags;
46 +
47 +       spin_lock_irqsave(&clock_lock, flags);
48 +
49 +       if (div < 0) {
50 +               /* stop clock - remove clock from divider input */
51 +               writew(readw(glamo_mci_def_pdata.pglamo->base +
52 +                    GLAMO_REG_CLOCK_GEN5_1) & (~GLAMO_CLOCK_GEN51_EN_DIV_TCLK),
53 +                    glamo_mci_def_pdata.pglamo->base + GLAMO_REG_CLOCK_GEN5_1);
54 +       } else {
55 +               /* set the nearest prescaler factor
56 +               *
57 +               * register shared with SCLK divisor -- no chance of race because
58 +               * we don't use sensor interface
59 +               */
60 +               writew_dly((readw(glamo_mci_def_pdata.pglamo->base +
61 +                               GLAMO_REG_CLOCK_GEN8) & 0xff00) | div,
62 +                      glamo_mci_def_pdata.pglamo->base + GLAMO_REG_CLOCK_GEN8);
63 +               /* enable clock to divider input */
64 +               writew_dly(readw(glamo_mci_def_pdata.pglamo->base +
65 +                       GLAMO_REG_CLOCK_GEN5_1) | GLAMO_CLOCK_GEN51_EN_DIV_TCLK,
66 +                    glamo_mci_def_pdata.pglamo->base + GLAMO_REG_CLOCK_GEN5_1);
67 +       }
68 +
69 +       spin_unlock_irqrestore(&clock_lock, flags);
70 +}
71 +
72 +static int __glamo_mci_set_card_clock(struct glamo_mci_host *host, int freq,
73 +                                                                 int *division)
74 +{
75 +       int div = 0;
76 +       int real_rate = 0;
77 +
78 +       if (freq) {
79 +               /* Set clock */
80 +               for (div = 0; div < 256; div++) {
81 +                       real_rate = host->clk_rate / (div + 1);
82 +                       if (real_rate <= freq)
83 +                               break;
84 +               }
85 +               if (div > 255)
86 +                       div = 255;
87 +
88 +               if (division)
89 +                       *division = div;
90 +
91 +               __glamo_mci_fix_card_div(host, div);
92 +
93 +       } else {
94 +               /* stop clock */
95 +               if (division)
96 +                       *division = 0xff;
97 +
98 +               __glamo_mci_fix_card_div(host, -1); /* clock off */
99 +       }
100 +
101 +       return real_rate;
102 +}
103 +
104  static void glamo_mci_irq(unsigned int irq, struct irq_desc *desc)
105  {
106         struct glamo_mci_host *host = (struct glamo_mci_host *)
107 @@ -212,6 +275,10 @@ static void glamo_mci_irq(unsigned int irq, struct irq_desc *desc)
108                 glamo_mci_send_request(host->mmc);
109                 host->cmd_is_stop = 0;
110         }
111 +
112 +       /* clock off */
113 +       __glamo_mci_fix_card_div(host, -1);
114 +
115  done:
116         host->complete_what = COMPLETION_NONE;
117         host->mrq = NULL;
118 @@ -441,8 +508,11 @@ static void glamo_mci_send_request(struct mmc_host *mmc)
119                  cmd->opcode, cmd->arg, cmd->data, cmd->mrq->stop,
120                  cmd->flags);
121  
122 +       /* resume requested clock rate */
123 +       __glamo_mci_fix_card_div(host, host->clk_div);
124 +
125         if (glamo_mci_send_command(host, cmd))
126 -               return;
127 +               goto bail;
128         /*
129          * we must spin until response is ready or timed out
130          * -- we don't get interrupts unless there is a bulk rx
131 @@ -464,7 +534,7 @@ static void glamo_mci_send_request(struct mmc_host *mmc)
132                 cmd->error = -EILSEQ;
133  
134         if (host->cmd_is_stop)
135 -               return;
136 +               goto bail;
137  
138         if (cmd->error) {
139                 dev_err(&host->pdev->dev, "Error after cmd: 0x%x\n", status);
140 @@ -516,10 +586,12 @@ static void glamo_mci_send_request(struct mmc_host *mmc)
141                         if (cmd->data->error)
142                                 cmd->data->error = -ETIMEDOUT;
143                         dev_err(&host->pdev->dev, "Payload timeout\n");
144 -                       return;
145 +                       goto bail;
146                 }
147  
148 -               /* yay we are an interrupt controller! -- call the ISR */
149 +               /* yay we are an interrupt controller! -- call the ISR
150 +                * it will stop clock to card
151 +                */
152                 glamo_mci_irq(IRQ_GLAMO(GLAMO_IRQIDX_MMC),
153                               irq_desc + IRQ_GLAMO(GLAMO_IRQIDX_MMC));
154         }
155 @@ -529,6 +601,12 @@ done:
156         host->complete_what = COMPLETION_NONE;
157         host->mrq = NULL;
158         mmc_request_done(host->mmc, cmd->mrq);
159 +       return;
160 +
161 +bail:
162 +       /* stop the clock to card */
163 +       __glamo_mci_fix_card_div(host, -1);
164 +       return;
165  }
166  
167  static void glamo_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
168 @@ -556,11 +634,12 @@ static void glamo_mci_reset(struct glamo_mci_host *host)
169                    glamo_mci_def_pdata.pglamo->base + GLAMO_REG_CLOCK_MMC);
170  }
171  
172 +
173  static void glamo_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
174  {
175         struct glamo_mci_host *host = mmc_priv(mmc);
176 -       int mci_psc = 0;
177         int n = 0;
178 +       int div;
179  
180         /* Set power */
181         switch(ios->power_mode) {
182 @@ -590,43 +669,15 @@ static void glamo_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
183         }
184         host->power_mode_current = ios->power_mode;
185  
186 -        /* Set clock */
187 -/*     if (ios->clock) { */
188 -       for (mci_psc = 0; mci_psc < 256; mci_psc++) {
189 -               host->real_rate = host->clk_rate / (mci_psc + 1);
190 -               if (host->real_rate <= ios->clock)
191 -                       break;
192 -       }
193 -       if (mci_psc > 255)
194 -               mci_psc = 255;
195 -       host->clk_div = mci_psc;
196 -       /* set the nearest prescaler factor
197 -       *
198 -       * register shared with SCLK divisor -- no chance of race because
199 -       * we don't use sensor interface
200 -       */
201 -       writew_dly((readw(glamo_mci_def_pdata.pglamo->base +
202 -                       GLAMO_REG_CLOCK_GEN8) & 0xff00) | host->clk_div,
203 -               glamo_mci_def_pdata.pglamo->base + GLAMO_REG_CLOCK_GEN8);
204 -       /* enable clock to divider input */
205 -       writew_dly(readw(glamo_mci_def_pdata.pglamo->base +
206 -               GLAMO_REG_CLOCK_GEN5_1) | GLAMO_CLOCK_GEN51_EN_DIV_TCLK,
207 -               glamo_mci_def_pdata.pglamo->base + GLAMO_REG_CLOCK_GEN5_1);
208 -#if 0
209 -       } else { /* stop clock */
210 -               host->real_rate = 0;
211 -               /* remove clock from divider input */
212 -               writew(readw(glamo_mci_def_pdata.pglamo->base +
213 -                    GLAMO_REG_CLOCK_GEN5_1) & (~GLAMO_CLOCK_GEN51_EN_DIV_TCLK),
214 -                    glamo_mci_def_pdata.pglamo->base + GLAMO_REG_CLOCK_GEN5_1);
215 -       }
216 -#endif
217 +       host->real_rate = __glamo_mci_set_card_clock(host, ios->clock, &div);
218 +       host->clk_div = div;
219 +
220         if ((ios->power_mode == MMC_POWER_ON) ||
221             (ios->power_mode == MMC_POWER_UP)) {
222                 dev_info(&host->pdev->dev,
223                         "powered (vdd = %d) clk: %lukHz div=%d (req: %ukHz). "
224                         "Bus width=%d\n",ios->vdd,
225 -                       host->real_rate / 1000, mci_psc,
226 +                       host->real_rate / 1000, host->real_rate,
227                         ios->clock / 1000, ios->bus_width);
228         } else
229                 dev_info(&host->pdev->dev, "glamo_mci_set_ios: power down.\n");
230 @@ -856,6 +907,7 @@ static struct platform_driver glamo_mci_driver =
231  
232  static int __init glamo_mci_init(void)
233  {
234 +       spin_lock_init(&clock_lock);
235         platform_driver_register(&glamo_mci_driver);
236         return 0;
237  }
238 -- 
239 1.5.6.3
240