e3bce37c85ff816f2469d6f5d61700d39e23d923
[librecmc/librecmc.git] / target / linux / pxa / patches-2.6.21 / 005-compact-flash.patch
1 Index: linux-2.6.21gum/drivers/pcmcia/Makefile
2 ===================================================================
3 --- linux-2.6.21gum.orig/drivers/pcmcia/Makefile
4 +++ linux-2.6.21gum/drivers/pcmcia/Makefile
5 @@ -69,4 +69,4 @@ sa1100_cs-$(CONFIG_SA1100_SIMPAD)             += sa
6  pxa2xx_cs-$(CONFIG_ARCH_LUBBOCK)               += pxa2xx_lubbock.o sa1111_generic.o
7  pxa2xx_cs-$(CONFIG_MACH_MAINSTONE)             += pxa2xx_mainstone.o
8  pxa2xx_cs-$(CONFIG_PXA_SHARPSL)                        += pxa2xx_sharpsl.o
9 -
10 +pxa2xx_cs-$(CONFIG_ARCH_GUMSTIX)               += pxa2xx_gumstix.o
11 Index: linux-2.6.21gum/drivers/pcmcia/pxa2xx_gumstix.c
12 ===================================================================
13 --- /dev/null
14 +++ linux-2.6.21gum/drivers/pcmcia/pxa2xx_gumstix.c
15 @@ -0,0 +1,272 @@
16 +/*
17 + * linux/drivers/pcmcia/pxa2xx_gumstix.c
18 + *
19 + * Gumstix PCMCIA specific routines. Based on Mainstone
20 + *
21 + * Copyright 2004, Craig Hughes <craig@gumstix.com>
22 + *
23 + * This program is free software; you can redistribute it and/or modify
24 + * it under the terms of the GNU General Public License version 2 as
25 + * published by the Free Software Foundation.
26 + */
27 +
28 +#include <linux/module.h>
29 +#include <linux/init.h>
30 +#include <linux/kernel.h>
31 +#include <linux/errno.h>
32 +#include <linux/interrupt.h>
33 +#include <linux/device.h>
34 +#include <linux/platform_device.h>
35 +
36 +#include <pcmcia/ss.h>
37 +
38 +#include <asm/hardware.h>
39 +#include <asm/delay.h>
40 +#include <asm/arch/pxa-regs.h>
41 +#include <asm/irq.h>
42 +#include <asm/io.h>
43 +
44 +#include <asm/arch/gumstix.h>
45 +
46 +#include "soc_common.h"
47 +
48 +static struct pcmcia_irqs gumstix_pcmcia_irqs0[] = {
49 +       { 0, GUMSTIX_S0_nCD_IRQ,        "CF0 nCD"     },
50 +       { 0, GUMSTIX_S0_nSTSCHG_IRQ,    "CF0 nSTSCHG" },
51 +};
52 +
53 +static struct pcmcia_irqs gumstix_pcmcia_irqs1[] = {
54 +       { 1, GUMSTIX_S1_nCD_IRQ,        "CF1 nCD"     },
55 +       { 1, GUMSTIX_S1_nSTSCHG_IRQ,    "CF1 nSTSCHG" },
56 +};
57 +
58 +static int net_cf_vx_mode = 0;
59 +
60 +static int gumstix_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
61 +{
62 +       if(skt->nr == 0)
63 +       {
64 +               pxa_gpio_mode(GPIO_GUMSTIX_nSTSCHG_0_MD);
65 +               pxa_gpio_mode(GPIO_GUMSTIX_nCD_0_MD);
66 +               if(net_cf_vx_mode)
67 +                       pxa_gpio_mode(GPIO_GUMSTIX_PRDY_nBSY_0_OLD_MD);
68 +               else
69 +                       pxa_gpio_mode(GPIO_GUMSTIX_PRDY_nBSY_0_MD);
70 +       } else {
71 +               pxa_gpio_mode(GPIO_GUMSTIX_nSTSCHG_1_MD);
72 +               pxa_gpio_mode(GPIO_GUMSTIX_nCD_1_MD);
73 +               pxa_gpio_mode(GPIO_GUMSTIX_PRDY_nBSY_1_MD);
74 +       }
75 +
76 +       pxa_gpio_mode(GPIO_GUMSTIX_nPOE_MD);
77 +       pxa_gpio_mode(GPIO_GUMSTIX_nPWE_MD);
78 +       pxa_gpio_mode(GPIO_GUMSTIX_nPIOR_MD);
79 +       pxa_gpio_mode(GPIO_GUMSTIX_nPIOW_MD);
80 +       pxa_gpio_mode(GPIO_GUMSTIX_nPCE_1_MD);
81 +       pxa_gpio_mode(GPIO_GUMSTIX_nPCE_2_MD);
82 +       pxa_gpio_mode(GPIO_GUMSTIX_pSKTSEL_MD);
83 +       pxa_gpio_mode(GPIO_GUMSTIX_nPREG_MD);
84 +       pxa_gpio_mode(GPIO_GUMSTIX_nPWAIT_MD);
85 +       pxa_gpio_mode(GPIO_GUMSTIX_nIOIS16_MD);                                                                                                                                                              
86 +
87 +       skt->irq = (skt->nr == 0) ? ((net_cf_vx_mode == 0) ? GUMSTIX_S0_PRDY_nBSY_IRQ : GUMSTIX_S0_PRDY_nBSY_OLD_IRQ) : GUMSTIX_S1_PRDY_nBSY_IRQ;
88 +
89 +       return (skt->nr == 0) ? soc_pcmcia_request_irqs(skt, gumstix_pcmcia_irqs0, ARRAY_SIZE(gumstix_pcmcia_irqs0)) :
90 +                               soc_pcmcia_request_irqs(skt, gumstix_pcmcia_irqs1, ARRAY_SIZE(gumstix_pcmcia_irqs1));
91 +}
92 +
93 +static void gumstix_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
94 +{
95 +       if(skt->nr == 0)
96 +       {
97 +               soc_pcmcia_free_irqs(skt, gumstix_pcmcia_irqs0, ARRAY_SIZE(gumstix_pcmcia_irqs0));
98 +       } else {
99 +               soc_pcmcia_free_irqs(skt, gumstix_pcmcia_irqs1, ARRAY_SIZE(gumstix_pcmcia_irqs1));
100 +       }
101 +}
102 +
103 +static void gumstix_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
104 +                                   struct pcmcia_state *state)
105 +{
106 +       unsigned int cd, prdy_nbsy, nbvd1;
107 +       if(skt->nr == 0)
108 +       {
109 +               cd = GPIO_GUMSTIX_nCD_0;
110 +               if(net_cf_vx_mode)
111 +                       prdy_nbsy = GPIO_GUMSTIX_PRDY_nBSY_0_OLD;
112 +               else
113 +                       prdy_nbsy = GPIO_GUMSTIX_PRDY_nBSY_0;
114 +               nbvd1 = GPIO_GUMSTIX_nBVD1_0;
115 +       } else {
116 +               cd = GPIO_GUMSTIX_nCD_1;
117 +               prdy_nbsy = GPIO_GUMSTIX_PRDY_nBSY_1;
118 +               nbvd1 = GPIO_GUMSTIX_nBVD1_1;
119 +       }
120 +       state->detect = !(GPLR(cd) & GPIO_bit(cd));
121 +       state->ready  = !!(GPLR(prdy_nbsy) & GPIO_bit(prdy_nbsy));
122 +       state->bvd1   = !!(GPLR(nbvd1) & GPIO_bit(nbvd1));
123 +       state->bvd2   = 1;
124 +       state->vs_3v  = 0;
125 +       state->vs_Xv  = 0;
126 +       state->wrprot = 0;
127 +}
128 +
129 +static int gumstix_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
130 +                                      const socket_state_t *state)
131 +{
132 +       return 0;
133 +}
134 +
135 +static void gumstix_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
136 +{
137 +       if(skt->nr) {
138 +               soc_pcmcia_enable_irqs(skt, gumstix_pcmcia_irqs0, ARRAY_SIZE(gumstix_pcmcia_irqs0));
139 +       } else {
140 +               soc_pcmcia_enable_irqs(skt, gumstix_pcmcia_irqs1, ARRAY_SIZE(gumstix_pcmcia_irqs1));
141 +       }
142 +}
143 +
144 +static void gumstix_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
145 +{
146 +       if(skt->nr) {
147 +               soc_pcmcia_disable_irqs(skt, gumstix_pcmcia_irqs0, ARRAY_SIZE(gumstix_pcmcia_irqs0));
148 +       } else {
149 +               soc_pcmcia_disable_irqs(skt, gumstix_pcmcia_irqs1, ARRAY_SIZE(gumstix_pcmcia_irqs1));
150 +       }
151 +}
152 +
153 +static struct pcmcia_low_level gumstix_pcmcia_ops = {
154 +       .owner                  = THIS_MODULE,
155 +       .hw_init                = gumstix_pcmcia_hw_init,
156 +       .hw_shutdown            = gumstix_pcmcia_hw_shutdown,
157 +       .socket_state           = gumstix_pcmcia_socket_state,
158 +       .configure_socket       = gumstix_pcmcia_configure_socket,
159 +       .socket_init            = gumstix_pcmcia_socket_init,
160 +       .socket_suspend         = gumstix_pcmcia_socket_suspend,
161 +       .nr                     = 2,
162 +};
163 +
164 +static struct platform_device *gumstix_pcmcia_device;
165 +
166 +inline void __init gumstix_pcmcia_cpld_clk(void)
167 +{
168 +       GPCR(GPIO_GUMSTIX_nPOE) = GPIO_bit(GPIO_GUMSTIX_nPOE);
169 +       GPSR(GPIO_GUMSTIX_nPOE) = GPIO_bit(GPIO_GUMSTIX_nPOE);
170 +}
171 +
172 +inline unsigned char __init gumstix_pcmcia_cpld_read_bits(int bits)
173 +{
174 +       unsigned char result = 0;
175 +       unsigned int shift = 0;
176 +       while(bits--)
177 +       {
178 +               result |= !!(GPLR(GPIO_GUMSTIX_nCD_0) & GPIO_bit(GPIO_GUMSTIX_nCD_0)) << shift;
179 +               shift ++;
180 +               gumstix_pcmcia_cpld_clk();
181 +       }
182 +       printk("CPLD responded with: %02x\n",result);
183 +       return result;
184 +}
185 +
186 +/* We use the CPLD on the CF-CF card to read a value from a shift register.  If we can read that
187 + * magic sequence, then we have 2 CF cards; otherwise we assume just one
188 + * The CPLD will send the value of the shift register on GPIO11 (the CD line for slot 0)
189 + * when RESET is held in reset.  We use GPIO48 (nPOE) as a clock signal,
190 + * GPIO52/53 (card enable for both cards) to control read/write to the shift register
191 + */
192 +static void __init gumstix_count_cards(void)
193 +{
194 +       pxa_gpio_mode(GPIO_GUMSTIX_nPOE | GPIO_OUT);
195 +       pxa_gpio_mode(GPIO_GUMSTIX_nPCE_1 | GPIO_OUT);
196 +       pxa_gpio_mode(GPIO_GUMSTIX_nPCE_2 | GPIO_OUT);
197 +       pxa_gpio_mode(GPIO_GUMSTIX_nCD_0 | GPIO_IN);
198 +       if(net_cf_vx_mode)
199 +               pxa_gpio_mode(GPIO_GUMSTIX_CF_OLD_RESET | GPIO_OUT);
200 +       else
201 +               pxa_gpio_mode(GPIO_GUMSTIX_CF_RESET  | GPIO_OUT);
202 +
203 +       // Enter reset
204 +       if(net_cf_vx_mode)
205 +               GPSR(GPIO_GUMSTIX_CF_OLD_RESET) = GPIO_bit(GPIO_GUMSTIX_CF_OLD_RESET);
206 +       else
207 +               GPSR(GPIO_GUMSTIX_CF_RESET) = GPIO_bit(GPIO_GUMSTIX_CF_RESET);
208 +
209 +       // Setup the shift register
210 +       GPSR(GPIO_GUMSTIX_nPCE_1) = GPIO_bit(GPIO_GUMSTIX_nPCE_1);
211 +       GPCR(GPIO_GUMSTIX_nPCE_2) = GPIO_bit(GPIO_GUMSTIX_nPCE_2);
212 +
213 +       // Tick the clock to program the shift register
214 +       gumstix_pcmcia_cpld_clk();
215 +
216 +       // Now set shift register into read mode
217 +       GPCR(GPIO_GUMSTIX_nPCE_1) = GPIO_bit(GPIO_GUMSTIX_nPCE_1);
218 +       GPSR(GPIO_GUMSTIX_nPCE_2) = GPIO_bit(GPIO_GUMSTIX_nPCE_2);
219 +
220 +       // We can read the bits now -- 0xC2 means "Dual compact flash"
221 +       if(gumstix_pcmcia_cpld_read_bits(8) != 0xC2)
222 +       {
223 +               // We do not have 2 CF slots
224 +               gumstix_pcmcia_ops.nr = 1;
225 +       }
226 +}
227 +
228 +#ifdef CONFIG_ARCH_GUMSTIX_VERDEX
229 +static void __init gumstix_check_if_netCF_vx(void)
230 +{
231 +       void *network_controller_memory = ioremap(0x04000300,16);
232 +       // Look for the special 91c111 value in the bank select register
233 +       if((0xff00 & readw(network_controller_memory+0x0e)) == 0x3300) {
234 +               printk("Detected netCF-vx board: using older GPIO configuration\n");
235 +               net_cf_vx_mode = 1;
236 +       } else {
237 +               printk("Not netCF-vx board: using newer GPIO configuration\n");
238 +               net_cf_vx_mode = 0;
239 +       }
240 +       iounmap(network_controller_memory);
241 +}
242 +#endif
243 +
244 +static int __init gumstix_pcmcia_init(void)
245 +{
246 +       int ret;
247 +
248 +#ifdef CONFIG_ARCH_GUMSTIX_VERDEX
249 +       gumstix_check_if_netCF_vx();
250 +#endif
251 +
252 +       gumstix_count_cards();
253 +
254 +       udelay(50);
255 +       if(net_cf_vx_mode)
256 +               GPCR(GPIO_GUMSTIX_CF_OLD_RESET) = GPIO_bit(GPIO_GUMSTIX_CF_OLD_RESET);
257 +       else
258 +               GPCR(GPIO_GUMSTIX_CF_RESET) = GPIO_bit(GPIO_GUMSTIX_CF_RESET);
259 +
260 +       gumstix_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
261 +       if (!gumstix_pcmcia_device)
262 +               return -ENOMEM;
263 +
264 +       gumstix_pcmcia_device->dev.platform_data = &gumstix_pcmcia_ops;
265 +
266 +       ret = platform_device_add(gumstix_pcmcia_device);
267 +       if (ret)
268 +               platform_device_put(gumstix_pcmcia_device);
269 +
270 +       return ret;
271 +}
272 +
273 +static void __exit gumstix_pcmcia_exit(void)
274 +{
275 +       /*
276 +        * This call is supposed to free our gumstix_pcmcia_device.
277 +        * Unfortunately platform_device don't have a free method, and
278 +        * we can't assume it's free of any reference at this point so we
279 +        * can't free it either.
280 +        */
281 +       platform_device_unregister(gumstix_pcmcia_device);
282 +}
283 +
284 +fs_initcall(gumstix_pcmcia_init);
285 +module_exit(gumstix_pcmcia_exit);
286 +
287 +MODULE_LICENSE("GPL");