aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Purdie <rpurdie@rpsys.net>2005-09-05 15:49:54 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2005-09-05 15:49:54 -0400
commit0ce7625f3c1e3f921f6b83f7e944e00031a39dfa (patch)
treebf04a478adbad082fe4689cecd02c2cd8c1f6031
parent027da01d734db0ca9dd1a084339dab07ab576935 (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.c6
-rw-r--r--arch/arm/mach-pxa/corgi.c12
-rw-r--r--arch/arm/mach-pxa/poodle.c12
-rw-r--r--drivers/pcmcia/pxa2xx_sharpsl.c114
-rw-r--r--include/asm-arm/hardware/scoop.h13
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 */
23int scoop_num;
24struct scoop_pcmcia_dev *scoop_devs;
25
20struct scoop_dev { 26struct 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
63static 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
63struct platform_device corgiscoop_device = { 72struct 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
65static 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 */
67static struct resource locomo_resources[] = { 76static 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
32static unsigned char keep_vs; 30static void sharpsl_pcmcia_init_reset(struct scoop_pcmcia_dev *scoopdev)
33static unsigned char keep_rd;
34
35static struct pcmcia_irqs irqs[] = {
36 { 0, CORGI_IRQ_GPIO_CF_CD, "PCMCIA0 CD"},
37};
38
39static 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
46static int sharpsl_pcmcia_hw_init(struct soc_pcmcia_socket *skt) 37static 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
91static void sharpsl_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) 84static 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
209static void sharpsl_pcmcia_socket_init(struct soc_pcmcia_socket *skt) 208static 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
213static void sharpsl_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) 218static 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
217static struct pcmcia_low_level sharpsl_pcmcia_ops = { 224static 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
229static struct platform_device *sharpsl_pcmcia_device; 236static 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 */
44struct 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
53extern int scoop_num;
54extern struct scoop_pcmcia_dev *scoop_devs;
55
43void reset_scoop(struct device *dev); 56void reset_scoop(struct device *dev);
44unsigned short set_scoop_gpio(struct device *dev, unsigned short bit); 57unsigned short set_scoop_gpio(struct device *dev, unsigned short bit);
45unsigned short reset_scoop_gpio(struct device *dev, unsigned short bit); 58unsigned short reset_scoop_gpio(struct device *dev, unsigned short bit);