diff options
author | Richard Purdie <rpurdie@rpsys.net> | 2005-09-05 15:49:54 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2005-09-05 15:49:54 -0400 |
commit | 0ce7625f3c1e3f921f6b83f7e944e00031a39dfa (patch) | |
tree | bf04a478adbad082fe4689cecd02c2cd8c1f6031 | |
parent | 027da01d734db0ca9dd1a084339dab07ab576935 (diff) |
[ARM] 2882/1: pxa2xx_sharpsl: Update PCMCIA driver to support variety of new hardware
Patch from Richard Purdie
This patch updates the PCMCIA pxa2xx_sharpsl driver to support multiple scoop
devices by adding a scoop to pcmcia slot mapping structure. It adds platform
support for poodle, is known to work on spitz (which is dual slot) and
should also support collie with a minor amount of further work.
Signed-off-by: Richard Purdie <rpurdie@rpsys.net>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r-- | arch/arm/common/scoop.c | 6 | ||||
-rw-r--r-- | arch/arm/mach-pxa/corgi.c | 12 | ||||
-rw-r--r-- | arch/arm/mach-pxa/poodle.c | 12 | ||||
-rw-r--r-- | drivers/pcmcia/pxa2xx_sharpsl.c | 114 | ||||
-rw-r--r-- | include/asm-arm/hardware/scoop.h | 13 |
5 files changed, 105 insertions, 52 deletions
diff --git a/arch/arm/common/scoop.c b/arch/arm/common/scoop.c index cfd0d3e550d9..688a595598c8 100644 --- a/arch/arm/common/scoop.c +++ b/arch/arm/common/scoop.c | |||
@@ -17,6 +17,12 @@ | |||
17 | 17 | ||
18 | #define SCOOP_REG(d,adr) (*(volatile unsigned short*)(d +(adr))) | 18 | #define SCOOP_REG(d,adr) (*(volatile unsigned short*)(d +(adr))) |
19 | 19 | ||
20 | /* PCMCIA to Scoop linkage structures for pxa2xx_sharpsl.c | ||
21 | There is no easy way to link multiple scoop devices into one | ||
22 | single entity for the pxa2xx_pcmcia device */ | ||
23 | int scoop_num; | ||
24 | struct scoop_pcmcia_dev *scoop_devs; | ||
25 | |||
20 | struct scoop_dev { | 26 | struct scoop_dev { |
21 | void *base; | 27 | void *base; |
22 | spinlock_t scoop_lock; | 28 | spinlock_t scoop_lock; |
diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c index 86b862f56e7e..06ea730e8675 100644 --- a/arch/arm/mach-pxa/corgi.c +++ b/arch/arm/mach-pxa/corgi.c | |||
@@ -60,6 +60,15 @@ static struct scoop_config corgi_scoop_setup = { | |||
60 | .io_out = CORGI_SCOOP_IO_OUT, | 60 | .io_out = CORGI_SCOOP_IO_OUT, |
61 | }; | 61 | }; |
62 | 62 | ||
63 | static struct scoop_pcmcia_dev corgi_pcmcia_scoop[] = { | ||
64 | { | ||
65 | .dev = &corgiscoop_device.dev, | ||
66 | .irq = CORGI_IRQ_GPIO_CF_IRQ, | ||
67 | .cd_irq = CORGI_IRQ_GPIO_CF_CD, | ||
68 | .cd_irq_str = "PCMCIA0 CD", | ||
69 | }, | ||
70 | }; | ||
71 | |||
63 | struct platform_device corgiscoop_device = { | 72 | struct platform_device corgiscoop_device = { |
64 | .name = "sharp-scoop", | 73 | .name = "sharp-scoop", |
65 | .id = -1, | 74 | .id = -1, |
@@ -241,6 +250,9 @@ static void __init corgi_init(void) | |||
241 | pxa_set_udc_info(&udc_info); | 250 | pxa_set_udc_info(&udc_info); |
242 | pxa_set_mci_info(&corgi_mci_platform_data); | 251 | pxa_set_mci_info(&corgi_mci_platform_data); |
243 | 252 | ||
253 | scoop_num = 1; | ||
254 | scoop_devs = &corgi_pcmcia_scoop[0]; | ||
255 | |||
244 | platform_add_devices(devices, ARRAY_SIZE(devices)); | 256 | platform_add_devices(devices, ARRAY_SIZE(devices)); |
245 | } | 257 | } |
246 | 258 | ||
diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c index 0e4f6fab100a..47cfb8bb8318 100644 --- a/arch/arm/mach-pxa/poodle.c +++ b/arch/arm/mach-pxa/poodle.c | |||
@@ -62,6 +62,15 @@ struct platform_device poodle_scoop_device = { | |||
62 | .resource = poodle_scoop_resources, | 62 | .resource = poodle_scoop_resources, |
63 | }; | 63 | }; |
64 | 64 | ||
65 | static struct scoop_pcmcia_dev poodle_pcmcia_scoop[] = { | ||
66 | { | ||
67 | .dev = &poodle_scoop_device.dev, | ||
68 | .irq = POODLE_IRQ_GPIO_CF_IRQ, | ||
69 | .cd_irq = POODLE_IRQ_GPIO_CF_CD, | ||
70 | .cd_irq_str = "PCMCIA0 CD", | ||
71 | }, | ||
72 | }; | ||
73 | |||
65 | 74 | ||
66 | /* LoCoMo device */ | 75 | /* LoCoMo device */ |
67 | static struct resource locomo_resources[] = { | 76 | static struct resource locomo_resources[] = { |
@@ -147,6 +156,9 @@ static void __init poodle_init(void) | |||
147 | 156 | ||
148 | set_pxa_fb_info(&poodle_fb_info); | 157 | set_pxa_fb_info(&poodle_fb_info); |
149 | 158 | ||
159 | scoop_num = 1; | ||
160 | scoop_devs = &poodle_pcmcia_scoop[0]; | ||
161 | |||
150 | ret = platform_add_devices(devices, ARRAY_SIZE(devices)); | 162 | ret = platform_add_devices(devices, ARRAY_SIZE(devices)); |
151 | if (ret) { | 163 | if (ret) { |
152 | printk(KERN_WARNING "poodle: Unable to register LoCoMo device\n"); | 164 | printk(KERN_WARNING "poodle: Unable to register LoCoMo device\n"); |
diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c index 7bac2f7d8b3f..a1178a600e3c 100644 --- a/drivers/pcmcia/pxa2xx_sharpsl.c +++ b/drivers/pcmcia/pxa2xx_sharpsl.c | |||
@@ -20,27 +20,18 @@ | |||
20 | 20 | ||
21 | #include <asm/hardware.h> | 21 | #include <asm/hardware.h> |
22 | #include <asm/irq.h> | 22 | #include <asm/irq.h> |
23 | |||
24 | #include <asm/hardware/scoop.h> | 23 | #include <asm/hardware/scoop.h> |
25 | #include <asm/arch/corgi.h> | ||
26 | #include <asm/arch/pxa-regs.h> | 24 | #include <asm/arch/pxa-regs.h> |
27 | 25 | ||
28 | #include "soc_common.h" | 26 | #include "soc_common.h" |
29 | 27 | ||
30 | #define NO_KEEP_VS 0x0001 | 28 | #define NO_KEEP_VS 0x0001 |
31 | 29 | ||
32 | static unsigned char keep_vs; | 30 | static void sharpsl_pcmcia_init_reset(struct scoop_pcmcia_dev *scoopdev) |
33 | static unsigned char keep_rd; | ||
34 | |||
35 | static struct pcmcia_irqs irqs[] = { | ||
36 | { 0, CORGI_IRQ_GPIO_CF_CD, "PCMCIA0 CD"}, | ||
37 | }; | ||
38 | |||
39 | static void sharpsl_pcmcia_init_reset(void) | ||
40 | { | 31 | { |
41 | reset_scoop(&corgiscoop_device.dev); | 32 | reset_scoop(scoopdev->dev); |
42 | keep_vs = NO_KEEP_VS; | 33 | scoopdev->keep_vs = NO_KEEP_VS; |
43 | keep_rd = 0; | 34 | scoopdev->keep_rd = 0; |
44 | } | 35 | } |
45 | 36 | ||
46 | static int sharpsl_pcmcia_hw_init(struct soc_pcmcia_socket *skt) | 37 | static int sharpsl_pcmcia_hw_init(struct soc_pcmcia_socket *skt) |
@@ -71,29 +62,35 @@ static int sharpsl_pcmcia_hw_init(struct soc_pcmcia_socket *skt) | |||
71 | pxa_gpio_mode(GPIO57_nIOIS16_MD); | 62 | pxa_gpio_mode(GPIO57_nIOIS16_MD); |
72 | 63 | ||
73 | /* Register interrupts */ | 64 | /* Register interrupts */ |
74 | ret = soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); | 65 | if (scoop_devs[skt->nr].cd_irq >= 0) { |
75 | 66 | struct pcmcia_irqs cd_irq; | |
76 | if (ret) { | 67 | |
77 | printk(KERN_ERR "Request for Compact Flash IRQ failed\n"); | 68 | cd_irq.sock = skt->nr; |
78 | return ret; | 69 | cd_irq.irq = scoop_devs[skt->nr].cd_irq; |
70 | cd_irq.str = scoop_devs[skt->nr].cd_irq_str; | ||
71 | ret = soc_pcmcia_request_irqs(skt, &cd_irq, 1); | ||
72 | |||
73 | if (ret) { | ||
74 | printk(KERN_ERR "Request for Compact Flash IRQ failed\n"); | ||
75 | return ret; | ||
76 | } | ||
79 | } | 77 | } |
80 | 78 | ||
81 | /* Enable interrupt */ | 79 | skt->irq = scoop_devs[skt->nr].irq; |
82 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_IMR, 0x00C0); | ||
83 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_MCR, 0x0101); | ||
84 | keep_vs = NO_KEEP_VS; | ||
85 | |||
86 | skt->irq = CORGI_IRQ_GPIO_CF_IRQ; | ||
87 | 80 | ||
88 | return 0; | 81 | return 0; |
89 | } | 82 | } |
90 | 83 | ||
91 | static void sharpsl_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) | 84 | static void sharpsl_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) |
92 | { | 85 | { |
93 | soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); | 86 | if (scoop_devs[skt->nr].cd_irq >= 0) { |
87 | struct pcmcia_irqs cd_irq; | ||
94 | 88 | ||
95 | /* CF_BUS_OFF */ | 89 | cd_irq.sock = skt->nr; |
96 | sharpsl_pcmcia_init_reset(); | 90 | cd_irq.irq = scoop_devs[skt->nr].cd_irq; |
91 | cd_irq.str = scoop_devs[skt->nr].cd_irq_str; | ||
92 | soc_pcmcia_free_irqs(skt, &cd_irq, 1); | ||
93 | } | ||
97 | } | 94 | } |
98 | 95 | ||
99 | 96 | ||
@@ -101,31 +98,32 @@ static void sharpsl_pcmcia_socket_state(struct soc_pcmcia_socket *skt, | |||
101 | struct pcmcia_state *state) | 98 | struct pcmcia_state *state) |
102 | { | 99 | { |
103 | unsigned short cpr, csr; | 100 | unsigned short cpr, csr; |
101 | struct device *scoop = scoop_devs[skt->nr].dev; | ||
104 | 102 | ||
105 | cpr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CPR); | 103 | cpr = read_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_CPR); |
106 | 104 | ||
107 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_IRM, 0x00FF); | 105 | write_scoop_reg(scoop, SCOOP_IRM, 0x00FF); |
108 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_ISR, 0x0000); | 106 | write_scoop_reg(scoop, SCOOP_ISR, 0x0000); |
109 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_IRM, 0x0000); | 107 | write_scoop_reg(scoop, SCOOP_IRM, 0x0000); |
110 | csr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CSR); | 108 | csr = read_scoop_reg(scoop, SCOOP_CSR); |
111 | if (csr & 0x0004) { | 109 | if (csr & 0x0004) { |
112 | /* card eject */ | 110 | /* card eject */ |
113 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0000); | 111 | write_scoop_reg(scoop, SCOOP_CDR, 0x0000); |
114 | keep_vs = NO_KEEP_VS; | 112 | scoop_devs[skt->nr].keep_vs = NO_KEEP_VS; |
115 | } | 113 | } |
116 | else if (!(keep_vs & NO_KEEP_VS)) { | 114 | else if (!(scoop_devs[skt->nr].keep_vs & NO_KEEP_VS)) { |
117 | /* keep vs1,vs2 */ | 115 | /* keep vs1,vs2 */ |
118 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0000); | 116 | write_scoop_reg(scoop, SCOOP_CDR, 0x0000); |
119 | csr |= keep_vs; | 117 | csr |= scoop_devs[skt->nr].keep_vs; |
120 | } | 118 | } |
121 | else if (cpr & 0x0003) { | 119 | else if (cpr & 0x0003) { |
122 | /* power on */ | 120 | /* power on */ |
123 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0000); | 121 | write_scoop_reg(scoop, SCOOP_CDR, 0x0000); |
124 | keep_vs = (csr & 0x00C0); | 122 | scoop_devs[skt->nr].keep_vs = (csr & 0x00C0); |
125 | } | 123 | } |
126 | else { | 124 | else { |
127 | /* card detect */ | 125 | /* card detect */ |
128 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0002); | 126 | write_scoop_reg(scoop, SCOOP_CDR, 0x0002); |
129 | } | 127 | } |
130 | 128 | ||
131 | state->detect = (csr & 0x0004) ? 0 : 1; | 129 | state->detect = (csr & 0x0004) ? 0 : 1; |
@@ -147,6 +145,7 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, | |||
147 | const socket_state_t *state) | 145 | const socket_state_t *state) |
148 | { | 146 | { |
149 | unsigned long flags; | 147 | unsigned long flags; |
148 | struct device *scoop = scoop_devs[skt->nr].dev; | ||
150 | 149 | ||
151 | unsigned short cpr, ncpr, ccr, nccr, mcr, nmcr, imr, nimr; | 150 | unsigned short cpr, ncpr, ccr, nccr, mcr, nmcr, imr, nimr; |
152 | 151 | ||
@@ -166,10 +165,10 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, | |||
166 | 165 | ||
167 | local_irq_save(flags); | 166 | local_irq_save(flags); |
168 | 167 | ||
169 | nmcr = (mcr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_MCR)) & ~0x0010; | 168 | nmcr = (mcr = read_scoop_reg(scoop, SCOOP_MCR)) & ~0x0010; |
170 | ncpr = (cpr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CPR)) & ~0x0083; | 169 | ncpr = (cpr = read_scoop_reg(scoop, SCOOP_CPR)) & ~0x0083; |
171 | nccr = (ccr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CCR)) & ~0x0080; | 170 | nccr = (ccr = read_scoop_reg(scoop, SCOOP_CCR)) & ~0x0080; |
172 | nimr = (imr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_IMR)) & ~0x003E; | 171 | nimr = (imr = read_scoop_reg(scoop, SCOOP_IMR)) & ~0x003E; |
173 | 172 | ||
174 | ncpr |= (state->Vcc == 33) ? 0x0001 : | 173 | ncpr |= (state->Vcc == 33) ? 0x0001 : |
175 | (state->Vcc == 50) ? 0x0002 : 0; | 174 | (state->Vcc == 50) ? 0x0002 : 0; |
@@ -184,22 +183,22 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, | |||
184 | ((skt->status&SS_WRPROT) ? 0x0008 : 0); | 183 | ((skt->status&SS_WRPROT) ? 0x0008 : 0); |
185 | 184 | ||
186 | if (!(ncpr & 0x0003)) { | 185 | if (!(ncpr & 0x0003)) { |
187 | keep_rd = 0; | 186 | scoop_devs[skt->nr].keep_rd = 0; |
188 | } else if (!keep_rd) { | 187 | } else if (!scoop_devs[skt->nr].keep_rd) { |
189 | if (nccr & 0x0080) | 188 | if (nccr & 0x0080) |
190 | keep_rd = 1; | 189 | scoop_devs[skt->nr].keep_rd = 1; |
191 | else | 190 | else |
192 | nccr |= 0x0080; | 191 | nccr |= 0x0080; |
193 | } | 192 | } |
194 | 193 | ||
195 | if (mcr != nmcr) | 194 | if (mcr != nmcr) |
196 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_MCR, nmcr); | 195 | write_scoop_reg(scoop, SCOOP_MCR, nmcr); |
197 | if (cpr != ncpr) | 196 | if (cpr != ncpr) |
198 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_CPR, ncpr); | 197 | write_scoop_reg(scoop, SCOOP_CPR, ncpr); |
199 | if (ccr != nccr) | 198 | if (ccr != nccr) |
200 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_CCR, nccr); | 199 | write_scoop_reg(scoop, SCOOP_CCR, nccr); |
201 | if (imr != nimr) | 200 | if (imr != nimr) |
202 | write_scoop_reg(&corgiscoop_device.dev, SCOOP_IMR, nimr); | 201 | write_scoop_reg(scoop, SCOOP_IMR, nimr); |
203 | 202 | ||
204 | local_irq_restore(flags); | 203 | local_irq_restore(flags); |
205 | 204 | ||
@@ -208,10 +207,18 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, | |||
208 | 207 | ||
209 | static void sharpsl_pcmcia_socket_init(struct soc_pcmcia_socket *skt) | 208 | static void sharpsl_pcmcia_socket_init(struct soc_pcmcia_socket *skt) |
210 | { | 209 | { |
210 | sharpsl_pcmcia_init_reset(&scoop_devs[skt->nr]); | ||
211 | |||
212 | /* Enable interrupt */ | ||
213 | write_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_IMR, 0x00C0); | ||
214 | write_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_MCR, 0x0101); | ||
215 | scoop_devs[skt->nr].keep_vs = NO_KEEP_VS; | ||
211 | } | 216 | } |
212 | 217 | ||
213 | static void sharpsl_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) | 218 | static void sharpsl_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) |
214 | { | 219 | { |
220 | /* CF_BUS_OFF */ | ||
221 | sharpsl_pcmcia_init_reset(&scoop_devs[skt->nr]); | ||
215 | } | 222 | } |
216 | 223 | ||
217 | static struct pcmcia_low_level sharpsl_pcmcia_ops = { | 224 | static struct pcmcia_low_level sharpsl_pcmcia_ops = { |
@@ -223,7 +230,7 @@ static struct pcmcia_low_level sharpsl_pcmcia_ops = { | |||
223 | .socket_init = sharpsl_pcmcia_socket_init, | 230 | .socket_init = sharpsl_pcmcia_socket_init, |
224 | .socket_suspend = sharpsl_pcmcia_socket_suspend, | 231 | .socket_suspend = sharpsl_pcmcia_socket_suspend, |
225 | .first = 0, | 232 | .first = 0, |
226 | .nr = 1, | 233 | .nr = 0, |
227 | }; | 234 | }; |
228 | 235 | ||
229 | static struct platform_device *sharpsl_pcmcia_device; | 236 | static struct platform_device *sharpsl_pcmcia_device; |
@@ -232,12 +239,15 @@ static int __init sharpsl_pcmcia_init(void) | |||
232 | { | 239 | { |
233 | int ret; | 240 | int ret; |
234 | 241 | ||
242 | sharpsl_pcmcia_ops.nr=scoop_num; | ||
235 | sharpsl_pcmcia_device = kmalloc(sizeof(*sharpsl_pcmcia_device), GFP_KERNEL); | 243 | sharpsl_pcmcia_device = kmalloc(sizeof(*sharpsl_pcmcia_device), GFP_KERNEL); |
236 | if (!sharpsl_pcmcia_device) | 244 | if (!sharpsl_pcmcia_device) |
237 | return -ENOMEM; | 245 | return -ENOMEM; |
246 | |||
238 | memset(sharpsl_pcmcia_device, 0, sizeof(*sharpsl_pcmcia_device)); | 247 | memset(sharpsl_pcmcia_device, 0, sizeof(*sharpsl_pcmcia_device)); |
239 | sharpsl_pcmcia_device->name = "pxa2xx-pcmcia"; | 248 | sharpsl_pcmcia_device->name = "pxa2xx-pcmcia"; |
240 | sharpsl_pcmcia_device->dev.platform_data = &sharpsl_pcmcia_ops; | 249 | sharpsl_pcmcia_device->dev.platform_data = &sharpsl_pcmcia_ops; |
250 | sharpsl_pcmcia_device->dev.parent=scoop_devs[0].dev; | ||
241 | 251 | ||
242 | ret = platform_device_register(sharpsl_pcmcia_device); | 252 | ret = platform_device_register(sharpsl_pcmcia_device); |
243 | if (ret) | 253 | if (ret) |
diff --git a/include/asm-arm/hardware/scoop.h b/include/asm-arm/hardware/scoop.h index 7ea771ff6144..527404b5a8df 100644 --- a/include/asm-arm/hardware/scoop.h +++ b/include/asm-arm/hardware/scoop.h | |||
@@ -40,6 +40,19 @@ struct scoop_config { | |||
40 | unsigned short io_dir; | 40 | unsigned short io_dir; |
41 | }; | 41 | }; |
42 | 42 | ||
43 | /* Structure for linking scoop devices to PCMCIA sockets */ | ||
44 | struct scoop_pcmcia_dev { | ||
45 | struct device *dev; /* Pointer to this socket's scoop device */ | ||
46 | int irq; /* irq for socket */ | ||
47 | int cd_irq; | ||
48 | const char *cd_irq_str; | ||
49 | unsigned char keep_vs; | ||
50 | unsigned char keep_rd; | ||
51 | }; | ||
52 | |||
53 | extern int scoop_num; | ||
54 | extern struct scoop_pcmcia_dev *scoop_devs; | ||
55 | |||
43 | void reset_scoop(struct device *dev); | 56 | void reset_scoop(struct device *dev); |
44 | unsigned short set_scoop_gpio(struct device *dev, unsigned short bit); | 57 | unsigned short set_scoop_gpio(struct device *dev, unsigned short bit); |
45 | unsigned short reset_scoop_gpio(struct device *dev, unsigned short bit); | 58 | unsigned short reset_scoop_gpio(struct device *dev, unsigned short bit); |