diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
commit | fcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch) | |
tree | a57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/pcmcia | |
parent | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff) |
Diffstat (limited to 'drivers/pcmcia')
-rw-r--r-- | drivers/pcmcia/au1000_generic.c | 545 | ||||
-rw-r--r-- | drivers/pcmcia/au1000_generic.h | 135 | ||||
-rw-r--r-- | drivers/pcmcia/au1000_pb1x00.c | 294 | ||||
-rw-r--r-- | drivers/pcmcia/pxa2xx_lubbock.c | 237 | ||||
-rw-r--r-- | drivers/pcmcia/sa1100_badge4.c | 167 | ||||
-rw-r--r-- | drivers/pcmcia/sa1100_jornada720.c | 120 | ||||
-rw-r--r-- | drivers/pcmcia/sa1100_neponset.c | 143 |
7 files changed, 1641 insertions, 0 deletions
diff --git a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c new file mode 100644 index 00000000000..95dd7c62741 --- /dev/null +++ b/drivers/pcmcia/au1000_generic.c | |||
@@ -0,0 +1,545 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Alchemy Semi Au1000 pcmcia driver | ||
4 | * | ||
5 | * Copyright 2001-2003 MontaVista Software Inc. | ||
6 | * Author: MontaVista Software, Inc. | ||
7 | * ppopov@embeddedalley.com or source@mvista.com | ||
8 | * | ||
9 | * Copyright 2004 Pete Popov, Embedded Alley Solutions, Inc. | ||
10 | * Updated the driver to 2.6. Followed the sa11xx API and largely | ||
11 | * copied many of the hardware independent functions. | ||
12 | * | ||
13 | * ######################################################################## | ||
14 | * | ||
15 | * This program is free software; you can distribute it and/or modify it | ||
16 | * under the terms of the GNU General Public License (Version 2) as | ||
17 | * published by the Free Software Foundation. | ||
18 | * | ||
19 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
20 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
22 | * for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License along | ||
25 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
26 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
27 | * | ||
28 | * ######################################################################## | ||
29 | * | ||
30 | * | ||
31 | */ | ||
32 | |||
33 | #include <linux/module.h> | ||
34 | #include <linux/moduleparam.h> | ||
35 | #include <linux/init.h> | ||
36 | #include <linux/cpufreq.h> | ||
37 | #include <linux/ioport.h> | ||
38 | #include <linux/kernel.h> | ||
39 | #include <linux/timer.h> | ||
40 | #include <linux/mm.h> | ||
41 | #include <linux/notifier.h> | ||
42 | #include <linux/interrupt.h> | ||
43 | #include <linux/spinlock.h> | ||
44 | #include <linux/mutex.h> | ||
45 | #include <linux/platform_device.h> | ||
46 | #include <linux/slab.h> | ||
47 | |||
48 | #include <asm/io.h> | ||
49 | #include <asm/irq.h> | ||
50 | #include <asm/system.h> | ||
51 | |||
52 | #include <asm/mach-au1x00/au1000.h> | ||
53 | #include "au1000_generic.h" | ||
54 | |||
55 | MODULE_LICENSE("GPL"); | ||
56 | MODULE_AUTHOR("Pete Popov <ppopov@embeddedalley.com>"); | ||
57 | MODULE_DESCRIPTION("Linux PCMCIA Card Services: Au1x00 Socket Controller"); | ||
58 | |||
59 | #if 0 | ||
60 | #define debug(x,args...) printk(KERN_DEBUG "%s: " x, __func__ , ##args) | ||
61 | #else | ||
62 | #define debug(x,args...) | ||
63 | #endif | ||
64 | |||
65 | #define MAP_SIZE 0x100000 | ||
66 | extern struct au1000_pcmcia_socket au1000_pcmcia_socket[]; | ||
67 | #define PCMCIA_SOCKET(x) (au1000_pcmcia_socket + (x)) | ||
68 | #define to_au1000_socket(x) container_of(x, struct au1000_pcmcia_socket, socket) | ||
69 | |||
70 | /* Some boards like to support CF cards as IDE root devices, so they | ||
71 | * grab pcmcia sockets directly. | ||
72 | */ | ||
73 | u32 *pcmcia_base_vaddrs[2]; | ||
74 | extern const unsigned long mips_io_port_base; | ||
75 | |||
76 | static DEFINE_MUTEX(pcmcia_sockets_lock); | ||
77 | |||
78 | static int (*au1x00_pcmcia_hw_init[])(struct device *dev) = { | ||
79 | au1x_board_init, | ||
80 | }; | ||
81 | |||
82 | static int | ||
83 | au1x00_pcmcia_skt_state(struct au1000_pcmcia_socket *skt) | ||
84 | { | ||
85 | struct pcmcia_state state; | ||
86 | unsigned int stat; | ||
87 | |||
88 | memset(&state, 0, sizeof(struct pcmcia_state)); | ||
89 | |||
90 | skt->ops->socket_state(skt, &state); | ||
91 | |||
92 | stat = state.detect ? SS_DETECT : 0; | ||
93 | stat |= state.ready ? SS_READY : 0; | ||
94 | stat |= state.wrprot ? SS_WRPROT : 0; | ||
95 | stat |= state.vs_3v ? SS_3VCARD : 0; | ||
96 | stat |= state.vs_Xv ? SS_XVCARD : 0; | ||
97 | stat |= skt->cs_state.Vcc ? SS_POWERON : 0; | ||
98 | |||
99 | if (skt->cs_state.flags & SS_IOCARD) | ||
100 | stat |= state.bvd1 ? SS_STSCHG : 0; | ||
101 | else { | ||
102 | if (state.bvd1 == 0) | ||
103 | stat |= SS_BATDEAD; | ||
104 | else if (state.bvd2 == 0) | ||
105 | stat |= SS_BATWARN; | ||
106 | } | ||
107 | return stat; | ||
108 | } | ||
109 | |||
110 | /* | ||
111 | * au100_pcmcia_config_skt | ||
112 | * | ||
113 | * Convert PCMCIA socket state to our socket configure structure. | ||
114 | */ | ||
115 | static int | ||
116 | au1x00_pcmcia_config_skt(struct au1000_pcmcia_socket *skt, socket_state_t *state) | ||
117 | { | ||
118 | int ret; | ||
119 | |||
120 | ret = skt->ops->configure_socket(skt, state); | ||
121 | if (ret == 0) { | ||
122 | skt->cs_state = *state; | ||
123 | } | ||
124 | |||
125 | if (ret < 0) | ||
126 | debug("unable to configure socket %d\n", skt->nr); | ||
127 | |||
128 | return ret; | ||
129 | } | ||
130 | |||
131 | /* au1x00_pcmcia_sock_init() | ||
132 | * | ||
133 | * (Re-)Initialise the socket, turning on status interrupts | ||
134 | * and PCMCIA bus. This must wait for power to stabilise | ||
135 | * so that the card status signals report correctly. | ||
136 | * | ||
137 | * Returns: 0 | ||
138 | */ | ||
139 | static int au1x00_pcmcia_sock_init(struct pcmcia_socket *sock) | ||
140 | { | ||
141 | struct au1000_pcmcia_socket *skt = to_au1000_socket(sock); | ||
142 | |||
143 | debug("initializing socket %u\n", skt->nr); | ||
144 | |||
145 | skt->ops->socket_init(skt); | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | /* | ||
150 | * au1x00_pcmcia_suspend() | ||
151 | * | ||
152 | * Remove power on the socket, disable IRQs from the card. | ||
153 | * Turn off status interrupts, and disable the PCMCIA bus. | ||
154 | * | ||
155 | * Returns: 0 | ||
156 | */ | ||
157 | static int au1x00_pcmcia_suspend(struct pcmcia_socket *sock) | ||
158 | { | ||
159 | struct au1000_pcmcia_socket *skt = to_au1000_socket(sock); | ||
160 | |||
161 | debug("suspending socket %u\n", skt->nr); | ||
162 | |||
163 | skt->ops->socket_suspend(skt); | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | static DEFINE_SPINLOCK(status_lock); | ||
169 | |||
170 | /* | ||
171 | * au1x00_check_status() | ||
172 | */ | ||
173 | static void au1x00_check_status(struct au1000_pcmcia_socket *skt) | ||
174 | { | ||
175 | unsigned int events; | ||
176 | |||
177 | debug("entering PCMCIA monitoring thread\n"); | ||
178 | |||
179 | do { | ||
180 | unsigned int status; | ||
181 | unsigned long flags; | ||
182 | |||
183 | status = au1x00_pcmcia_skt_state(skt); | ||
184 | |||
185 | spin_lock_irqsave(&status_lock, flags); | ||
186 | events = (status ^ skt->status) & skt->cs_state.csc_mask; | ||
187 | skt->status = status; | ||
188 | spin_unlock_irqrestore(&status_lock, flags); | ||
189 | |||
190 | debug("events: %s%s%s%s%s%s\n", | ||
191 | events == 0 ? "<NONE>" : "", | ||
192 | events & SS_DETECT ? "DETECT " : "", | ||
193 | events & SS_READY ? "READY " : "", | ||
194 | events & SS_BATDEAD ? "BATDEAD " : "", | ||
195 | events & SS_BATWARN ? "BATWARN " : "", | ||
196 | events & SS_STSCHG ? "STSCHG " : ""); | ||
197 | |||
198 | if (events) | ||
199 | pcmcia_parse_events(&skt->socket, events); | ||
200 | } while (events); | ||
201 | } | ||
202 | |||
203 | /* | ||
204 | * au1x00_pcmcia_poll_event() | ||
205 | * Let's poll for events in addition to IRQs since IRQ only is unreliable... | ||
206 | */ | ||
207 | static void au1x00_pcmcia_poll_event(unsigned long dummy) | ||
208 | { | ||
209 | struct au1000_pcmcia_socket *skt = (struct au1000_pcmcia_socket *)dummy; | ||
210 | debug("polling for events\n"); | ||
211 | |||
212 | mod_timer(&skt->poll_timer, jiffies + AU1000_PCMCIA_POLL_PERIOD); | ||
213 | |||
214 | au1x00_check_status(skt); | ||
215 | } | ||
216 | |||
217 | /* au1x00_pcmcia_get_status() | ||
218 | * | ||
219 | * From the sa11xx_core.c: | ||
220 | * Implements the get_status() operation for the in-kernel PCMCIA | ||
221 | * service (formerly SS_GetStatus in Card Services). Essentially just | ||
222 | * fills in bits in `status' according to internal driver state or | ||
223 | * the value of the voltage detect chipselect register. | ||
224 | * | ||
225 | * As a debugging note, during card startup, the PCMCIA core issues | ||
226 | * three set_socket() commands in a row the first with RESET deasserted, | ||
227 | * the second with RESET asserted, and the last with RESET deasserted | ||
228 | * again. Following the third set_socket(), a get_status() command will | ||
229 | * be issued. The kernel is looking for the SS_READY flag (see | ||
230 | * setup_socket(), reset_socket(), and unreset_socket() in cs.c). | ||
231 | * | ||
232 | * Returns: 0 | ||
233 | */ | ||
234 | static int | ||
235 | au1x00_pcmcia_get_status(struct pcmcia_socket *sock, unsigned int *status) | ||
236 | { | ||
237 | struct au1000_pcmcia_socket *skt = to_au1000_socket(sock); | ||
238 | |||
239 | skt->status = au1x00_pcmcia_skt_state(skt); | ||
240 | *status = skt->status; | ||
241 | |||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | /* au1x00_pcmcia_set_socket() | ||
246 | * Implements the set_socket() operation for the in-kernel PCMCIA | ||
247 | * service (formerly SS_SetSocket in Card Services). We more or | ||
248 | * less punt all of this work and let the kernel handle the details | ||
249 | * of power configuration, reset, &c. We also record the value of | ||
250 | * `state' in order to regurgitate it to the PCMCIA core later. | ||
251 | * | ||
252 | * Returns: 0 | ||
253 | */ | ||
254 | static int | ||
255 | au1x00_pcmcia_set_socket(struct pcmcia_socket *sock, socket_state_t *state) | ||
256 | { | ||
257 | struct au1000_pcmcia_socket *skt = to_au1000_socket(sock); | ||
258 | |||
259 | debug("for sock %u\n", skt->nr); | ||
260 | |||
261 | debug("\tmask: %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n", | ||
262 | (state->csc_mask==0)?"<NONE>":"", | ||
263 | (state->csc_mask&SS_DETECT)?"DETECT ":"", | ||
264 | (state->csc_mask&SS_READY)?"READY ":"", | ||
265 | (state->csc_mask&SS_BATDEAD)?"BATDEAD ":"", | ||
266 | (state->csc_mask&SS_BATWARN)?"BATWARN ":"", | ||
267 | (state->csc_mask&SS_STSCHG)?"STSCHG ":"", | ||
268 | (state->flags==0)?"<NONE>":"", | ||
269 | (state->flags&SS_PWR_AUTO)?"PWR_AUTO ":"", | ||
270 | (state->flags&SS_IOCARD)?"IOCARD ":"", | ||
271 | (state->flags&SS_RESET)?"RESET ":"", | ||
272 | (state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"", | ||
273 | (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":""); | ||
274 | debug("\tVcc %d Vpp %d irq %d\n", | ||
275 | state->Vcc, state->Vpp, state->io_irq); | ||
276 | |||
277 | return au1x00_pcmcia_config_skt(skt, state); | ||
278 | } | ||
279 | |||
280 | int | ||
281 | au1x00_pcmcia_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *map) | ||
282 | { | ||
283 | struct au1000_pcmcia_socket *skt = to_au1000_socket(sock); | ||
284 | unsigned int speed; | ||
285 | |||
286 | if(map->map>=MAX_IO_WIN){ | ||
287 | debug("map (%d) out of range\n", map->map); | ||
288 | return -1; | ||
289 | } | ||
290 | |||
291 | if(map->flags&MAP_ACTIVE){ | ||
292 | speed=(map->speed>0)?map->speed:AU1000_PCMCIA_IO_SPEED; | ||
293 | skt->spd_io[map->map] = speed; | ||
294 | } | ||
295 | |||
296 | map->start=(unsigned int)(u32)skt->virt_io; | ||
297 | map->stop=map->start+MAP_SIZE; | ||
298 | return 0; | ||
299 | |||
300 | } /* au1x00_pcmcia_set_io_map() */ | ||
301 | |||
302 | |||
303 | static int | ||
304 | au1x00_pcmcia_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *map) | ||
305 | { | ||
306 | struct au1000_pcmcia_socket *skt = to_au1000_socket(sock); | ||
307 | unsigned short speed = map->speed; | ||
308 | |||
309 | if(map->map>=MAX_WIN){ | ||
310 | debug("map (%d) out of range\n", map->map); | ||
311 | return -1; | ||
312 | } | ||
313 | |||
314 | if (map->flags & MAP_ATTRIB) { | ||
315 | skt->spd_attr[map->map] = speed; | ||
316 | skt->spd_mem[map->map] = 0; | ||
317 | } else { | ||
318 | skt->spd_attr[map->map] = 0; | ||
319 | skt->spd_mem[map->map] = speed; | ||
320 | } | ||
321 | |||
322 | if (map->flags & MAP_ATTRIB) { | ||
323 | map->static_start = skt->phys_attr + map->card_start; | ||
324 | } | ||
325 | else { | ||
326 | map->static_start = skt->phys_mem + map->card_start; | ||
327 | } | ||
328 | |||
329 | debug("set_mem_map %d start %08lx card_start %08x\n", | ||
330 | map->map, map->static_start, map->card_start); | ||
331 | return 0; | ||
332 | |||
333 | } /* au1x00_pcmcia_set_mem_map() */ | ||
334 | |||
335 | static struct pccard_operations au1x00_pcmcia_operations = { | ||
336 | .init = au1x00_pcmcia_sock_init, | ||
337 | .suspend = au1x00_pcmcia_suspend, | ||
338 | .get_status = au1x00_pcmcia_get_status, | ||
339 | .set_socket = au1x00_pcmcia_set_socket, | ||
340 | .set_io_map = au1x00_pcmcia_set_io_map, | ||
341 | .set_mem_map = au1x00_pcmcia_set_mem_map, | ||
342 | }; | ||
343 | |||
344 | static const char *skt_names[] = { | ||
345 | "PCMCIA socket 0", | ||
346 | "PCMCIA socket 1", | ||
347 | }; | ||
348 | |||
349 | struct skt_dev_info { | ||
350 | int nskt; | ||
351 | }; | ||
352 | |||
353 | int au1x00_pcmcia_socket_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr) | ||
354 | { | ||
355 | struct skt_dev_info *sinfo; | ||
356 | struct au1000_pcmcia_socket *skt; | ||
357 | int ret, i; | ||
358 | |||
359 | sinfo = kzalloc(sizeof(struct skt_dev_info), GFP_KERNEL); | ||
360 | if (!sinfo) { | ||
361 | ret = -ENOMEM; | ||
362 | goto out; | ||
363 | } | ||
364 | |||
365 | sinfo->nskt = nr; | ||
366 | |||
367 | /* | ||
368 | * Initialise the per-socket structure. | ||
369 | */ | ||
370 | for (i = 0; i < nr; i++) { | ||
371 | skt = PCMCIA_SOCKET(i); | ||
372 | memset(skt, 0, sizeof(*skt)); | ||
373 | |||
374 | skt->socket.resource_ops = &pccard_static_ops; | ||
375 | skt->socket.ops = &au1x00_pcmcia_operations; | ||
376 | skt->socket.owner = ops->owner; | ||
377 | skt->socket.dev.parent = dev; | ||
378 | |||
379 | init_timer(&skt->poll_timer); | ||
380 | skt->poll_timer.function = au1x00_pcmcia_poll_event; | ||
381 | skt->poll_timer.data = (unsigned long)skt; | ||
382 | skt->poll_timer.expires = jiffies + AU1000_PCMCIA_POLL_PERIOD; | ||
383 | |||
384 | skt->nr = first + i; | ||
385 | skt->irq = 255; | ||
386 | skt->dev = dev; | ||
387 | skt->ops = ops; | ||
388 | |||
389 | skt->res_skt.name = skt_names[skt->nr]; | ||
390 | skt->res_io.name = "io"; | ||
391 | skt->res_io.flags = IORESOURCE_MEM | IORESOURCE_BUSY; | ||
392 | skt->res_mem.name = "memory"; | ||
393 | skt->res_mem.flags = IORESOURCE_MEM; | ||
394 | skt->res_attr.name = "attribute"; | ||
395 | skt->res_attr.flags = IORESOURCE_MEM; | ||
396 | |||
397 | /* | ||
398 | * PCMCIA client drivers use the inb/outb macros to access the | ||
399 | * IO registers. Since mips_io_port_base is added to the | ||
400 | * access address of the mips implementation of inb/outb, | ||
401 | * we need to subtract it here because we want to access the | ||
402 | * I/O or MEM address directly, without going through this | ||
403 | * "mips_io_port_base" mechanism. | ||
404 | */ | ||
405 | if (i == 0) { | ||
406 | skt->virt_io = (void *) | ||
407 | (ioremap((phys_t)AU1X_SOCK0_IO, 0x1000) - | ||
408 | (u32)mips_io_port_base); | ||
409 | skt->phys_attr = AU1X_SOCK0_PHYS_ATTR; | ||
410 | skt->phys_mem = AU1X_SOCK0_PHYS_MEM; | ||
411 | } | ||
412 | else { | ||
413 | skt->virt_io = (void *) | ||
414 | (ioremap((phys_t)AU1X_SOCK1_IO, 0x1000) - | ||
415 | (u32)mips_io_port_base); | ||
416 | skt->phys_attr = AU1X_SOCK1_PHYS_ATTR; | ||
417 | skt->phys_mem = AU1X_SOCK1_PHYS_MEM; | ||
418 | } | ||
419 | pcmcia_base_vaddrs[i] = (u32 *)skt->virt_io; | ||
420 | ret = ops->hw_init(skt); | ||
421 | |||
422 | skt->socket.features = SS_CAP_STATIC_MAP|SS_CAP_PCCARD; | ||
423 | skt->socket.irq_mask = 0; | ||
424 | skt->socket.map_size = MAP_SIZE; | ||
425 | skt->socket.pci_irq = skt->irq; | ||
426 | skt->socket.io_offset = (unsigned long)skt->virt_io; | ||
427 | |||
428 | skt->status = au1x00_pcmcia_skt_state(skt); | ||
429 | |||
430 | ret = pcmcia_register_socket(&skt->socket); | ||
431 | if (ret) | ||
432 | goto out_err; | ||
433 | |||
434 | WARN_ON(skt->socket.sock != i); | ||
435 | |||
436 | add_timer(&skt->poll_timer); | ||
437 | } | ||
438 | |||
439 | dev_set_drvdata(dev, sinfo); | ||
440 | return 0; | ||
441 | |||
442 | |||
443 | out_err: | ||
444 | ops->hw_shutdown(skt); | ||
445 | while (i-- > 0) { | ||
446 | skt = PCMCIA_SOCKET(i); | ||
447 | |||
448 | del_timer_sync(&skt->poll_timer); | ||
449 | pcmcia_unregister_socket(&skt->socket); | ||
450 | if (i == 0) { | ||
451 | iounmap(skt->virt_io + (u32)mips_io_port_base); | ||
452 | skt->virt_io = NULL; | ||
453 | } | ||
454 | #ifndef CONFIG_MIPS_XXS1500 | ||
455 | else { | ||
456 | iounmap(skt->virt_io + (u32)mips_io_port_base); | ||
457 | skt->virt_io = NULL; | ||
458 | } | ||
459 | #endif | ||
460 | ops->hw_shutdown(skt); | ||
461 | |||
462 | } | ||
463 | kfree(sinfo); | ||
464 | out: | ||
465 | return ret; | ||
466 | } | ||
467 | |||
468 | int au1x00_drv_pcmcia_remove(struct platform_device *dev) | ||
469 | { | ||
470 | struct skt_dev_info *sinfo = platform_get_drvdata(dev); | ||
471 | int i; | ||
472 | |||
473 | mutex_lock(&pcmcia_sockets_lock); | ||
474 | platform_set_drvdata(dev, NULL); | ||
475 | |||
476 | for (i = 0; i < sinfo->nskt; i++) { | ||
477 | struct au1000_pcmcia_socket *skt = PCMCIA_SOCKET(i); | ||
478 | |||
479 | del_timer_sync(&skt->poll_timer); | ||
480 | pcmcia_unregister_socket(&skt->socket); | ||
481 | skt->ops->hw_shutdown(skt); | ||
482 | au1x00_pcmcia_config_skt(skt, &dead_socket); | ||
483 | iounmap(skt->virt_io + (u32)mips_io_port_base); | ||
484 | skt->virt_io = NULL; | ||
485 | } | ||
486 | |||
487 | kfree(sinfo); | ||
488 | mutex_unlock(&pcmcia_sockets_lock); | ||
489 | return 0; | ||
490 | } | ||
491 | |||
492 | |||
493 | /* | ||
494 | * PCMCIA "Driver" API | ||
495 | */ | ||
496 | |||
497 | static int au1x00_drv_pcmcia_probe(struct platform_device *dev) | ||
498 | { | ||
499 | int i, ret = -ENODEV; | ||
500 | |||
501 | mutex_lock(&pcmcia_sockets_lock); | ||
502 | for (i=0; i < ARRAY_SIZE(au1x00_pcmcia_hw_init); i++) { | ||
503 | ret = au1x00_pcmcia_hw_init[i](&dev->dev); | ||
504 | if (ret == 0) | ||
505 | break; | ||
506 | } | ||
507 | mutex_unlock(&pcmcia_sockets_lock); | ||
508 | return ret; | ||
509 | } | ||
510 | |||
511 | static struct platform_driver au1x00_pcmcia_driver = { | ||
512 | .driver = { | ||
513 | .name = "au1x00-pcmcia", | ||
514 | .owner = THIS_MODULE, | ||
515 | }, | ||
516 | .probe = au1x00_drv_pcmcia_probe, | ||
517 | .remove = au1x00_drv_pcmcia_remove, | ||
518 | }; | ||
519 | |||
520 | |||
521 | /* au1x00_pcmcia_init() | ||
522 | * | ||
523 | * This routine performs low-level PCMCIA initialization and then | ||
524 | * registers this socket driver with Card Services. | ||
525 | * | ||
526 | * Returns: 0 on success, -ve error code on failure | ||
527 | */ | ||
528 | static int __init au1x00_pcmcia_init(void) | ||
529 | { | ||
530 | int error = 0; | ||
531 | error = platform_driver_register(&au1x00_pcmcia_driver); | ||
532 | return error; | ||
533 | } | ||
534 | |||
535 | /* au1x00_pcmcia_exit() | ||
536 | * Invokes the low-level kernel service to free IRQs associated with this | ||
537 | * socket controller and reset GPIO edge detection. | ||
538 | */ | ||
539 | static void __exit au1x00_pcmcia_exit(void) | ||
540 | { | ||
541 | platform_driver_unregister(&au1x00_pcmcia_driver); | ||
542 | } | ||
543 | |||
544 | module_init(au1x00_pcmcia_init); | ||
545 | module_exit(au1x00_pcmcia_exit); | ||
diff --git a/drivers/pcmcia/au1000_generic.h b/drivers/pcmcia/au1000_generic.h new file mode 100644 index 00000000000..5c36bda2963 --- /dev/null +++ b/drivers/pcmcia/au1000_generic.h | |||
@@ -0,0 +1,135 @@ | |||
1 | /* | ||
2 | * Alchemy Semi Au1000 pcmcia driver include file | ||
3 | * | ||
4 | * Copyright 2001 MontaVista Software Inc. | ||
5 | * Author: MontaVista Software, Inc. | ||
6 | * ppopov@mvista.com or source@mvista.com | ||
7 | * | ||
8 | * This program is free software; you can distribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License (Version 2) as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
15 | * for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along | ||
18 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
20 | */ | ||
21 | #ifndef __ASM_AU1000_PCMCIA_H | ||
22 | #define __ASM_AU1000_PCMCIA_H | ||
23 | |||
24 | /* include the world */ | ||
25 | |||
26 | #include <pcmcia/ss.h> | ||
27 | #include <pcmcia/cistpl.h> | ||
28 | #include "cs_internal.h" | ||
29 | |||
30 | #define AU1000_PCMCIA_POLL_PERIOD (2*HZ) | ||
31 | #define AU1000_PCMCIA_IO_SPEED (255) | ||
32 | #define AU1000_PCMCIA_MEM_SPEED (300) | ||
33 | |||
34 | #define AU1X_SOCK0_IO 0xF00000000ULL | ||
35 | #define AU1X_SOCK0_PHYS_ATTR 0xF40000000ULL | ||
36 | #define AU1X_SOCK0_PHYS_MEM 0xF80000000ULL | ||
37 | |||
38 | /* pcmcia socket 1 needs external glue logic so the memory map | ||
39 | * differs from board to board. | ||
40 | */ | ||
41 | #if defined(CONFIG_MIPS_PB1000) | ||
42 | #define AU1X_SOCK1_IO 0xF08000000ULL | ||
43 | #define AU1X_SOCK1_PHYS_ATTR 0xF48000000ULL | ||
44 | #define AU1X_SOCK1_PHYS_MEM 0xF88000000ULL | ||
45 | #endif | ||
46 | |||
47 | struct pcmcia_state { | ||
48 | unsigned detect: 1, | ||
49 | ready: 1, | ||
50 | wrprot: 1, | ||
51 | bvd1: 1, | ||
52 | bvd2: 1, | ||
53 | vs_3v: 1, | ||
54 | vs_Xv: 1; | ||
55 | }; | ||
56 | |||
57 | struct pcmcia_configure { | ||
58 | unsigned sock: 8, | ||
59 | vcc: 8, | ||
60 | vpp: 8, | ||
61 | output: 1, | ||
62 | speaker: 1, | ||
63 | reset: 1; | ||
64 | }; | ||
65 | |||
66 | struct pcmcia_irqs { | ||
67 | int sock; | ||
68 | int irq; | ||
69 | const char *str; | ||
70 | }; | ||
71 | |||
72 | |||
73 | struct au1000_pcmcia_socket { | ||
74 | struct pcmcia_socket socket; | ||
75 | |||
76 | /* | ||
77 | * Info from low level handler | ||
78 | */ | ||
79 | struct device *dev; | ||
80 | unsigned int nr; | ||
81 | unsigned int irq; | ||
82 | |||
83 | /* | ||
84 | * Core PCMCIA state | ||
85 | */ | ||
86 | struct pcmcia_low_level *ops; | ||
87 | |||
88 | unsigned int status; | ||
89 | socket_state_t cs_state; | ||
90 | |||
91 | unsigned short spd_io[MAX_IO_WIN]; | ||
92 | unsigned short spd_mem[MAX_WIN]; | ||
93 | unsigned short spd_attr[MAX_WIN]; | ||
94 | |||
95 | struct resource res_skt; | ||
96 | struct resource res_io; | ||
97 | struct resource res_mem; | ||
98 | struct resource res_attr; | ||
99 | |||
100 | void * virt_io; | ||
101 | unsigned int phys_io; | ||
102 | unsigned int phys_attr; | ||
103 | unsigned int phys_mem; | ||
104 | unsigned short speed_io, speed_attr, speed_mem; | ||
105 | |||
106 | unsigned int irq_state; | ||
107 | |||
108 | struct timer_list poll_timer; | ||
109 | }; | ||
110 | |||
111 | struct pcmcia_low_level { | ||
112 | struct module *owner; | ||
113 | |||
114 | int (*hw_init)(struct au1000_pcmcia_socket *); | ||
115 | void (*hw_shutdown)(struct au1000_pcmcia_socket *); | ||
116 | |||
117 | void (*socket_state)(struct au1000_pcmcia_socket *, struct pcmcia_state *); | ||
118 | int (*configure_socket)(struct au1000_pcmcia_socket *, struct socket_state_t *); | ||
119 | |||
120 | /* | ||
121 | * Enable card status IRQs on (re-)initialisation. This can | ||
122 | * be called at initialisation, power management event, or | ||
123 | * pcmcia event. | ||
124 | */ | ||
125 | void (*socket_init)(struct au1000_pcmcia_socket *); | ||
126 | |||
127 | /* | ||
128 | * Disable card status IRQs and PCMCIA bus on suspend. | ||
129 | */ | ||
130 | void (*socket_suspend)(struct au1000_pcmcia_socket *); | ||
131 | }; | ||
132 | |||
133 | extern int au1x_board_init(struct device *dev); | ||
134 | |||
135 | #endif /* __ASM_AU1000_PCMCIA_H */ | ||
diff --git a/drivers/pcmcia/au1000_pb1x00.c b/drivers/pcmcia/au1000_pb1x00.c new file mode 100644 index 00000000000..b2396647a16 --- /dev/null +++ b/drivers/pcmcia/au1000_pb1x00.c | |||
@@ -0,0 +1,294 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Alchemy Semi Pb1000 boards specific pcmcia routines. | ||
4 | * | ||
5 | * Copyright 2002 MontaVista Software Inc. | ||
6 | * Author: MontaVista Software, Inc. | ||
7 | * ppopov@mvista.com or source@mvista.com | ||
8 | * | ||
9 | * ######################################################################## | ||
10 | * | ||
11 | * This program is free software; you can distribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License (Version 2) as | ||
13 | * published by the Free Software Foundation. | ||
14 | * | ||
15 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
16 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
18 | * for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License along | ||
21 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
22 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
23 | */ | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/ioport.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/timer.h> | ||
30 | #include <linux/mm.h> | ||
31 | #include <linux/proc_fs.h> | ||
32 | #include <linux/types.h> | ||
33 | |||
34 | #include <pcmcia/ss.h> | ||
35 | #include <pcmcia/cistpl.h> | ||
36 | |||
37 | #include <asm/io.h> | ||
38 | #include <asm/irq.h> | ||
39 | #include <asm/system.h> | ||
40 | |||
41 | #include <asm/au1000.h> | ||
42 | #include <asm/au1000_pcmcia.h> | ||
43 | |||
44 | #define debug(fmt, arg...) do { } while (0) | ||
45 | |||
46 | #include <asm/pb1000.h> | ||
47 | #define PCMCIA_IRQ AU1000_GPIO_15 | ||
48 | |||
49 | static int pb1x00_pcmcia_init(struct pcmcia_init *init) | ||
50 | { | ||
51 | u16 pcr; | ||
52 | pcr = PCR_SLOT_0_RST | PCR_SLOT_1_RST; | ||
53 | |||
54 | au_writel(0x8000, PB1000_MDR); /* clear pcmcia interrupt */ | ||
55 | au_sync_delay(100); | ||
56 | au_writel(0x4000, PB1000_MDR); /* enable pcmcia interrupt */ | ||
57 | au_sync(); | ||
58 | |||
59 | pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,0); | ||
60 | pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,1); | ||
61 | au_writel(pcr, PB1000_PCR); | ||
62 | au_sync_delay(20); | ||
63 | |||
64 | return PCMCIA_NUM_SOCKS; | ||
65 | } | ||
66 | |||
67 | static int pb1x00_pcmcia_shutdown(void) | ||
68 | { | ||
69 | u16 pcr; | ||
70 | pcr = PCR_SLOT_0_RST | PCR_SLOT_1_RST; | ||
71 | pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,0); | ||
72 | pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,1); | ||
73 | au_writel(pcr, PB1000_PCR); | ||
74 | au_sync_delay(20); | ||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | static int | ||
79 | pb1x00_pcmcia_socket_state(unsigned sock, struct pcmcia_state *state) | ||
80 | { | ||
81 | u32 inserted0, inserted1; | ||
82 | u16 vs0, vs1; | ||
83 | |||
84 | vs0 = vs1 = (u16)au_readl(PB1000_ACR1); | ||
85 | inserted0 = !(vs0 & (ACR1_SLOT_0_CD1 | ACR1_SLOT_0_CD2)); | ||
86 | inserted1 = !(vs1 & (ACR1_SLOT_1_CD1 | ACR1_SLOT_1_CD2)); | ||
87 | vs0 = (vs0 >> 4) & 0x3; | ||
88 | vs1 = (vs1 >> 12) & 0x3; | ||
89 | |||
90 | state->ready = 0; | ||
91 | state->vs_Xv = 0; | ||
92 | state->vs_3v = 0; | ||
93 | state->detect = 0; | ||
94 | |||
95 | if (sock == 0) { | ||
96 | if (inserted0) { | ||
97 | switch (vs0) { | ||
98 | case 0: | ||
99 | case 2: | ||
100 | state->vs_3v=1; | ||
101 | break; | ||
102 | case 3: /* 5V */ | ||
103 | break; | ||
104 | default: | ||
105 | /* return without setting 'detect' */ | ||
106 | printk(KERN_ERR "pb1x00 bad VS (%d)\n", | ||
107 | vs0); | ||
108 | return 0; | ||
109 | } | ||
110 | state->detect = 1; | ||
111 | } | ||
112 | } | ||
113 | else { | ||
114 | if (inserted1) { | ||
115 | switch (vs1) { | ||
116 | case 0: | ||
117 | case 2: | ||
118 | state->vs_3v=1; | ||
119 | break; | ||
120 | case 3: /* 5V */ | ||
121 | break; | ||
122 | default: | ||
123 | /* return without setting 'detect' */ | ||
124 | printk(KERN_ERR "pb1x00 bad VS (%d)\n", | ||
125 | vs1); | ||
126 | return 0; | ||
127 | } | ||
128 | state->detect = 1; | ||
129 | } | ||
130 | } | ||
131 | |||
132 | if (state->detect) { | ||
133 | state->ready = 1; | ||
134 | } | ||
135 | |||
136 | state->bvd1=1; | ||
137 | state->bvd2=1; | ||
138 | state->wrprot=0; | ||
139 | return 1; | ||
140 | } | ||
141 | |||
142 | |||
143 | static int pb1x00_pcmcia_get_irq_info(struct pcmcia_irq_info *info) | ||
144 | { | ||
145 | |||
146 | if(info->sock > PCMCIA_MAX_SOCK) return -1; | ||
147 | |||
148 | /* | ||
149 | * Even in the case of the Pb1000, both sockets are connected | ||
150 | * to the same irq line. | ||
151 | */ | ||
152 | info->irq = PCMCIA_IRQ; | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | |||
158 | static int | ||
159 | pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure) | ||
160 | { | ||
161 | u16 pcr; | ||
162 | |||
163 | if(configure->sock > PCMCIA_MAX_SOCK) return -1; | ||
164 | |||
165 | pcr = au_readl(PB1000_PCR); | ||
166 | |||
167 | if (configure->sock == 0) { | ||
168 | pcr &= ~(PCR_SLOT_0_VCC0 | PCR_SLOT_0_VCC1 | | ||
169 | PCR_SLOT_0_VPP0 | PCR_SLOT_0_VPP1); | ||
170 | } | ||
171 | else { | ||
172 | pcr &= ~(PCR_SLOT_1_VCC0 | PCR_SLOT_1_VCC1 | | ||
173 | PCR_SLOT_1_VPP0 | PCR_SLOT_1_VPP1); | ||
174 | } | ||
175 | |||
176 | pcr &= ~PCR_SLOT_0_RST; | ||
177 | debug("Vcc %dV Vpp %dV, pcr %x\n", | ||
178 | configure->vcc, configure->vpp, pcr); | ||
179 | switch(configure->vcc){ | ||
180 | case 0: /* Vcc 0 */ | ||
181 | switch(configure->vpp) { | ||
182 | case 0: | ||
183 | pcr |= SET_VCC_VPP(VCC_HIZ,VPP_GND, | ||
184 | configure->sock); | ||
185 | break; | ||
186 | case 12: | ||
187 | pcr |= SET_VCC_VPP(VCC_HIZ,VPP_12V, | ||
188 | configure->sock); | ||
189 | break; | ||
190 | case 50: | ||
191 | pcr |= SET_VCC_VPP(VCC_HIZ,VPP_5V, | ||
192 | configure->sock); | ||
193 | break; | ||
194 | case 33: | ||
195 | pcr |= SET_VCC_VPP(VCC_HIZ,VPP_3V, | ||
196 | configure->sock); | ||
197 | break; | ||
198 | default: | ||
199 | pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ, | ||
200 | configure->sock); | ||
201 | printk("%s: bad Vcc/Vpp (%d:%d)\n", | ||
202 | __func__, | ||
203 | configure->vcc, | ||
204 | configure->vpp); | ||
205 | break; | ||
206 | } | ||
207 | break; | ||
208 | case 50: /* Vcc 5V */ | ||
209 | switch(configure->vpp) { | ||
210 | case 0: | ||
211 | pcr |= SET_VCC_VPP(VCC_5V,VPP_GND, | ||
212 | configure->sock); | ||
213 | break; | ||
214 | case 50: | ||
215 | pcr |= SET_VCC_VPP(VCC_5V,VPP_5V, | ||
216 | configure->sock); | ||
217 | break; | ||
218 | case 12: | ||
219 | pcr |= SET_VCC_VPP(VCC_5V,VPP_12V, | ||
220 | configure->sock); | ||
221 | break; | ||
222 | case 33: | ||
223 | pcr |= SET_VCC_VPP(VCC_5V,VPP_3V, | ||
224 | configure->sock); | ||
225 | break; | ||
226 | default: | ||
227 | pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ, | ||
228 | configure->sock); | ||
229 | printk("%s: bad Vcc/Vpp (%d:%d)\n", | ||
230 | __func__, | ||
231 | configure->vcc, | ||
232 | configure->vpp); | ||
233 | break; | ||
234 | } | ||
235 | break; | ||
236 | case 33: /* Vcc 3.3V */ | ||
237 | switch(configure->vpp) { | ||
238 | case 0: | ||
239 | pcr |= SET_VCC_VPP(VCC_3V,VPP_GND, | ||
240 | configure->sock); | ||
241 | break; | ||
242 | case 50: | ||
243 | pcr |= SET_VCC_VPP(VCC_3V,VPP_5V, | ||
244 | configure->sock); | ||
245 | break; | ||
246 | case 12: | ||
247 | pcr |= SET_VCC_VPP(VCC_3V,VPP_12V, | ||
248 | configure->sock); | ||
249 | break; | ||
250 | case 33: | ||
251 | pcr |= SET_VCC_VPP(VCC_3V,VPP_3V, | ||
252 | configure->sock); | ||
253 | break; | ||
254 | default: | ||
255 | pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ, | ||
256 | configure->sock); | ||
257 | printk("%s: bad Vcc/Vpp (%d:%d)\n", | ||
258 | __func__, | ||
259 | configure->vcc, | ||
260 | configure->vpp); | ||
261 | break; | ||
262 | } | ||
263 | break; | ||
264 | default: /* what's this ? */ | ||
265 | pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,configure->sock); | ||
266 | printk(KERN_ERR "%s: bad Vcc %d\n", | ||
267 | __func__, configure->vcc); | ||
268 | break; | ||
269 | } | ||
270 | |||
271 | if (configure->sock == 0) { | ||
272 | pcr &= ~(PCR_SLOT_0_RST); | ||
273 | if (configure->reset) | ||
274 | pcr |= PCR_SLOT_0_RST; | ||
275 | } | ||
276 | else { | ||
277 | pcr &= ~(PCR_SLOT_1_RST); | ||
278 | if (configure->reset) | ||
279 | pcr |= PCR_SLOT_1_RST; | ||
280 | } | ||
281 | au_writel(pcr, PB1000_PCR); | ||
282 | au_sync_delay(300); | ||
283 | |||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | |||
288 | struct pcmcia_low_level pb1x00_pcmcia_ops = { | ||
289 | pb1x00_pcmcia_init, | ||
290 | pb1x00_pcmcia_shutdown, | ||
291 | pb1x00_pcmcia_socket_state, | ||
292 | pb1x00_pcmcia_get_irq_info, | ||
293 | pb1x00_pcmcia_configure_socket | ||
294 | }; | ||
diff --git a/drivers/pcmcia/pxa2xx_lubbock.c b/drivers/pcmcia/pxa2xx_lubbock.c new file mode 100644 index 00000000000..c21888eebb5 --- /dev/null +++ b/drivers/pcmcia/pxa2xx_lubbock.c | |||
@@ -0,0 +1,237 @@ | |||
1 | /* | ||
2 | * linux/drivers/pcmcia/pxa2xx_lubbock.c | ||
3 | * | ||
4 | * Author: George Davis | ||
5 | * Created: Jan 10, 2002 | ||
6 | * Copyright: MontaVista Software Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * Originally based upon linux/drivers/pcmcia/sa1100_neponset.c | ||
13 | * | ||
14 | * Lubbock PCMCIA specific routines. | ||
15 | * | ||
16 | */ | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/device.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/delay.h> | ||
23 | |||
24 | #include <mach/hardware.h> | ||
25 | #include <asm/hardware/sa1111.h> | ||
26 | #include <asm/mach-types.h> | ||
27 | #include <mach/lubbock.h> | ||
28 | |||
29 | #include "sa1111_generic.h" | ||
30 | |||
31 | static int | ||
32 | lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, | ||
33 | const socket_state_t *state) | ||
34 | { | ||
35 | struct sa1111_pcmcia_socket *s = to_skt(skt); | ||
36 | unsigned int pa_dwr_mask, pa_dwr_set, misc_mask, misc_set; | ||
37 | int ret = 0; | ||
38 | |||
39 | pa_dwr_mask = pa_dwr_set = misc_mask = misc_set = 0; | ||
40 | |||
41 | /* Lubbock uses the Maxim MAX1602, with the following connections: | ||
42 | * | ||
43 | * Socket 0 (PCMCIA): | ||
44 | * MAX1602 Lubbock Register | ||
45 | * Pin Signal | ||
46 | * ----- ------- ---------------------- | ||
47 | * A0VPP S0_PWR0 SA-1111 GPIO A<0> | ||
48 | * A1VPP S0_PWR1 SA-1111 GPIO A<1> | ||
49 | * A0VCC S0_PWR2 SA-1111 GPIO A<2> | ||
50 | * A1VCC S0_PWR3 SA-1111 GPIO A<3> | ||
51 | * VX VCC | ||
52 | * VY +3.3V | ||
53 | * 12IN +12V | ||
54 | * CODE +3.3V Cirrus Code, CODE = High (VY) | ||
55 | * | ||
56 | * Socket 1 (CF): | ||
57 | * MAX1602 Lubbock Register | ||
58 | * Pin Signal | ||
59 | * ----- ------- ---------------------- | ||
60 | * A0VPP GND VPP is not connected | ||
61 | * A1VPP GND VPP is not connected | ||
62 | * A0VCC S1_PWR0 MISC_WR<14> | ||
63 | * A1VCC S1_PWR1 MISC_WR<15> | ||
64 | * VX VCC | ||
65 | * VY +3.3V | ||
66 | * 12IN GND VPP is not connected | ||
67 | * CODE +3.3V Cirrus Code, CODE = High (VY) | ||
68 | * | ||
69 | */ | ||
70 | |||
71 | again: | ||
72 | switch (skt->nr) { | ||
73 | case 0: | ||
74 | pa_dwr_mask = GPIO_A0 | GPIO_A1 | GPIO_A2 | GPIO_A3; | ||
75 | |||
76 | switch (state->Vcc) { | ||
77 | case 0: /* Hi-Z */ | ||
78 | break; | ||
79 | |||
80 | case 33: /* VY */ | ||
81 | pa_dwr_set |= GPIO_A3; | ||
82 | break; | ||
83 | |||
84 | case 50: /* VX */ | ||
85 | pa_dwr_set |= GPIO_A2; | ||
86 | break; | ||
87 | |||
88 | default: | ||
89 | printk(KERN_ERR "%s(): unrecognized Vcc %u\n", | ||
90 | __func__, state->Vcc); | ||
91 | ret = -1; | ||
92 | } | ||
93 | |||
94 | switch (state->Vpp) { | ||
95 | case 0: /* Hi-Z */ | ||
96 | break; | ||
97 | |||
98 | case 120: /* 12IN */ | ||
99 | pa_dwr_set |= GPIO_A1; | ||
100 | break; | ||
101 | |||
102 | default: /* VCC */ | ||
103 | if (state->Vpp == state->Vcc) | ||
104 | pa_dwr_set |= GPIO_A0; | ||
105 | else { | ||
106 | printk(KERN_ERR "%s(): unrecognized Vpp %u\n", | ||
107 | __func__, state->Vpp); | ||
108 | ret = -1; | ||
109 | break; | ||
110 | } | ||
111 | } | ||
112 | break; | ||
113 | |||
114 | case 1: | ||
115 | misc_mask = (1 << 15) | (1 << 14); | ||
116 | |||
117 | switch (state->Vcc) { | ||
118 | case 0: /* Hi-Z */ | ||
119 | break; | ||
120 | |||
121 | case 33: /* VY */ | ||
122 | misc_set |= 1 << 15; | ||
123 | break; | ||
124 | |||
125 | case 50: /* VX */ | ||
126 | misc_set |= 1 << 14; | ||
127 | break; | ||
128 | |||
129 | default: | ||
130 | printk(KERN_ERR "%s(): unrecognized Vcc %u\n", | ||
131 | __func__, state->Vcc); | ||
132 | ret = -1; | ||
133 | break; | ||
134 | } | ||
135 | |||
136 | if (state->Vpp != state->Vcc && state->Vpp != 0) { | ||
137 | printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", | ||
138 | __func__, state->Vpp); | ||
139 | ret = -1; | ||
140 | break; | ||
141 | } | ||
142 | break; | ||
143 | |||
144 | default: | ||
145 | ret = -1; | ||
146 | } | ||
147 | |||
148 | if (ret == 0) | ||
149 | ret = sa1111_pcmcia_configure_socket(skt, state); | ||
150 | |||
151 | if (ret == 0) { | ||
152 | lubbock_set_misc_wr(misc_mask, misc_set); | ||
153 | sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set); | ||
154 | } | ||
155 | |||
156 | #if 1 | ||
157 | if (ret == 0 && state->Vcc == 33) { | ||
158 | struct pcmcia_state new_state; | ||
159 | |||
160 | /* | ||
161 | * HACK ALERT: | ||
162 | * We can't sense the voltage properly on Lubbock before | ||
163 | * actually applying some power to the socket (catch 22). | ||
164 | * Resense the socket Voltage Sense pins after applying | ||
165 | * socket power. | ||
166 | * | ||
167 | * Note: It takes about 2.5ms for the MAX1602 VCC output | ||
168 | * to rise. | ||
169 | */ | ||
170 | mdelay(3); | ||
171 | |||
172 | sa1111_pcmcia_socket_state(skt, &new_state); | ||
173 | |||
174 | if (!new_state.vs_3v && !new_state.vs_Xv) { | ||
175 | /* | ||
176 | * Switch to 5V, Configure socket with 5V voltage | ||
177 | */ | ||
178 | lubbock_set_misc_wr(misc_mask, 0); | ||
179 | sa1111_set_io(s->dev, pa_dwr_mask, 0); | ||
180 | |||
181 | /* | ||
182 | * It takes about 100ms to turn off Vcc. | ||
183 | */ | ||
184 | mdelay(100); | ||
185 | |||
186 | /* | ||
187 | * We need to hack around the const qualifier as | ||
188 | * well to keep this ugly workaround localized and | ||
189 | * not force it to the rest of the code. Barf bags | ||
190 | * available in the seat pocket in front of you! | ||
191 | */ | ||
192 | ((socket_state_t *)state)->Vcc = 50; | ||
193 | ((socket_state_t *)state)->Vpp = 50; | ||
194 | goto again; | ||
195 | } | ||
196 | } | ||
197 | #endif | ||
198 | |||
199 | return ret; | ||
200 | } | ||
201 | |||
202 | static struct pcmcia_low_level lubbock_pcmcia_ops = { | ||
203 | .owner = THIS_MODULE, | ||
204 | .configure_socket = lubbock_pcmcia_configure_socket, | ||
205 | .socket_init = sa1111_pcmcia_socket_init, | ||
206 | .first = 0, | ||
207 | .nr = 2, | ||
208 | }; | ||
209 | |||
210 | #include "pxa2xx_base.h" | ||
211 | |||
212 | int pcmcia_lubbock_init(struct sa1111_dev *sadev) | ||
213 | { | ||
214 | int ret = -ENODEV; | ||
215 | |||
216 | if (machine_is_lubbock()) { | ||
217 | /* | ||
218 | * Set GPIO_A<3:0> to be outputs for the MAX1600, | ||
219 | * and switch to standby mode. | ||
220 | */ | ||
221 | sa1111_set_io_dir(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0, 0); | ||
222 | sa1111_set_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0); | ||
223 | sa1111_set_sleep_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0); | ||
224 | |||
225 | /* Set CF Socket 1 power to standby mode. */ | ||
226 | lubbock_set_misc_wr((1 << 15) | (1 << 14), 0); | ||
227 | |||
228 | pxa2xx_drv_pcmcia_ops(&lubbock_pcmcia_ops); | ||
229 | pxa2xx_configure_sockets(&sadev->dev); | ||
230 | ret = sa1111_pcmcia_add(sadev, &lubbock_pcmcia_ops, | ||
231 | pxa2xx_drv_pcmcia_add_one); | ||
232 | } | ||
233 | |||
234 | return ret; | ||
235 | } | ||
236 | |||
237 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/pcmcia/sa1100_badge4.c b/drivers/pcmcia/sa1100_badge4.c new file mode 100644 index 00000000000..1ce53f493be --- /dev/null +++ b/drivers/pcmcia/sa1100_badge4.c | |||
@@ -0,0 +1,167 @@ | |||
1 | /* | ||
2 | * linux/drivers/pcmcia/sa1100_badge4.c | ||
3 | * | ||
4 | * BadgePAD 4 PCMCIA specific routines | ||
5 | * | ||
6 | * Christopher Hoover <ch@hpl.hp.com> | ||
7 | * | ||
8 | * Copyright (C) 2002 Hewlett-Packard Company | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | */ | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/device.h> | ||
18 | #include <linux/errno.h> | ||
19 | #include <linux/init.h> | ||
20 | |||
21 | #include <mach/hardware.h> | ||
22 | #include <asm/mach-types.h> | ||
23 | #include <mach/badge4.h> | ||
24 | #include <asm/hardware/sa1111.h> | ||
25 | |||
26 | #include "sa1111_generic.h" | ||
27 | |||
28 | /* | ||
29 | * BadgePAD 4 Details | ||
30 | * | ||
31 | * PCM Vcc: | ||
32 | * | ||
33 | * PCM Vcc on BadgePAD 4 can be jumpered for 3v3 (short pins 1 and 3 | ||
34 | * on JP6) or 5v0 (short pins 3 and 5 on JP6). | ||
35 | * | ||
36 | * PCM Vpp: | ||
37 | * | ||
38 | * PCM Vpp on BadgePAD 4 can be jumpered for 12v0 (short pins 4 and 6 | ||
39 | * on JP6) or tied to PCM Vcc (short pins 2 and 4 on JP6). N.B., | ||
40 | * 12v0 operation requires that the power supply actually supply 12v0 | ||
41 | * via pin 7 of JP7. | ||
42 | * | ||
43 | * CF Vcc: | ||
44 | * | ||
45 | * CF Vcc on BadgePAD 4 can be jumpered either for 3v3 (short pins 1 | ||
46 | * and 2 on JP10) or 5v0 (short pins 2 and 3 on JP10). | ||
47 | * | ||
48 | * Unfortunately there's no way programmatically to determine how a | ||
49 | * given board is jumpered. This code assumes a default jumpering | ||
50 | * as described below. | ||
51 | * | ||
52 | * If the defaults aren't correct, you may override them with a pcmv | ||
53 | * setup argument: pcmv=<pcm vcc>,<pcm vpp>,<cf vcc>. The units are | ||
54 | * tenths of volts; e.g. pcmv=33,120,50 indicates 3v3 PCM Vcc, 12v0 | ||
55 | * PCM Vpp, and 5v0 CF Vcc. | ||
56 | * | ||
57 | */ | ||
58 | |||
59 | static int badge4_pcmvcc = 50; /* pins 3 and 5 jumpered on JP6 */ | ||
60 | static int badge4_pcmvpp = 50; /* pins 2 and 4 jumpered on JP6 */ | ||
61 | static int badge4_cfvcc = 33; /* pins 1 and 2 jumpered on JP10 */ | ||
62 | |||
63 | static void complain_about_jumpering(const char *whom, | ||
64 | const char *supply, | ||
65 | int given, int wanted) | ||
66 | { | ||
67 | printk(KERN_ERR | ||
68 | "%s: %s %d.%dV wanted but board is jumpered for %s %d.%dV operation" | ||
69 | "; re-jumper the board and/or use pcmv=xx,xx,xx\n", | ||
70 | whom, supply, | ||
71 | wanted / 10, wanted % 10, | ||
72 | supply, | ||
73 | given / 10, given % 10); | ||
74 | } | ||
75 | |||
76 | static int | ||
77 | badge4_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) | ||
78 | { | ||
79 | int ret; | ||
80 | |||
81 | switch (skt->nr) { | ||
82 | case 0: | ||
83 | if ((state->Vcc != 0) && | ||
84 | (state->Vcc != badge4_pcmvcc)) { | ||
85 | complain_about_jumpering(__func__, "pcmvcc", | ||
86 | badge4_pcmvcc, state->Vcc); | ||
87 | // Apply power regardless of the jumpering. | ||
88 | // return -1; | ||
89 | } | ||
90 | if ((state->Vpp != 0) && | ||
91 | (state->Vpp != badge4_pcmvpp)) { | ||
92 | complain_about_jumpering(__func__, "pcmvpp", | ||
93 | badge4_pcmvpp, state->Vpp); | ||
94 | return -1; | ||
95 | } | ||
96 | break; | ||
97 | |||
98 | case 1: | ||
99 | if ((state->Vcc != 0) && | ||
100 | (state->Vcc != badge4_cfvcc)) { | ||
101 | complain_about_jumpering(__func__, "cfvcc", | ||
102 | badge4_cfvcc, state->Vcc); | ||
103 | return -1; | ||
104 | } | ||
105 | break; | ||
106 | |||
107 | default: | ||
108 | return -1; | ||
109 | } | ||
110 | |||
111 | ret = sa1111_pcmcia_configure_socket(skt, state); | ||
112 | if (ret == 0) { | ||
113 | unsigned long flags; | ||
114 | int need5V; | ||
115 | |||
116 | local_irq_save(flags); | ||
117 | |||
118 | need5V = ((state->Vcc == 50) || (state->Vpp == 50)); | ||
119 | |||
120 | badge4_set_5V(BADGE4_5V_PCMCIA_SOCK(skt->nr), need5V); | ||
121 | |||
122 | local_irq_restore(flags); | ||
123 | } | ||
124 | |||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static struct pcmcia_low_level badge4_pcmcia_ops = { | ||
129 | .owner = THIS_MODULE, | ||
130 | .configure_socket = badge4_pcmcia_configure_socket, | ||
131 | .socket_init = sa1111_pcmcia_socket_init, | ||
132 | .first = 0, | ||
133 | .nr = 2, | ||
134 | }; | ||
135 | |||
136 | int pcmcia_badge4_init(struct device *dev) | ||
137 | { | ||
138 | int ret = -ENODEV; | ||
139 | |||
140 | if (machine_is_badge4()) { | ||
141 | printk(KERN_INFO | ||
142 | "%s: badge4_pcmvcc=%d, badge4_pcmvpp=%d, badge4_cfvcc=%d\n", | ||
143 | __func__, | ||
144 | badge4_pcmvcc, badge4_pcmvpp, badge4_cfvcc); | ||
145 | |||
146 | sa11xx_drv_pcmcia_ops(&badge4_pcmcia_ops); | ||
147 | ret = sa1111_pcmcia_add(dev, &badge4_pcmcia_ops, | ||
148 | sa11xx_drv_pcmcia_add_one); | ||
149 | } | ||
150 | |||
151 | return ret; | ||
152 | } | ||
153 | |||
154 | static int __init pcmv_setup(char *s) | ||
155 | { | ||
156 | int v[4]; | ||
157 | |||
158 | s = get_options(s, ARRAY_SIZE(v), v); | ||
159 | |||
160 | if (v[0] >= 1) badge4_pcmvcc = v[1]; | ||
161 | if (v[0] >= 2) badge4_pcmvpp = v[2]; | ||
162 | if (v[0] >= 3) badge4_cfvcc = v[3]; | ||
163 | |||
164 | return 1; | ||
165 | } | ||
166 | |||
167 | __setup("pcmv=", pcmv_setup); | ||
diff --git a/drivers/pcmcia/sa1100_jornada720.c b/drivers/pcmcia/sa1100_jornada720.c new file mode 100644 index 00000000000..6bcabee6bde --- /dev/null +++ b/drivers/pcmcia/sa1100_jornada720.c | |||
@@ -0,0 +1,120 @@ | |||
1 | /* | ||
2 | * drivers/pcmcia/sa1100_jornada720.c | ||
3 | * | ||
4 | * Jornada720 PCMCIA specific routines | ||
5 | * | ||
6 | */ | ||
7 | #include <linux/module.h> | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/device.h> | ||
10 | #include <linux/errno.h> | ||
11 | #include <linux/init.h> | ||
12 | |||
13 | #include <mach/hardware.h> | ||
14 | #include <asm/hardware/sa1111.h> | ||
15 | #include <asm/mach-types.h> | ||
16 | |||
17 | #include "sa1111_generic.h" | ||
18 | |||
19 | /* Does SOCKET1_3V actually do anything? */ | ||
20 | #define SOCKET0_POWER GPIO_GPIO0 | ||
21 | #define SOCKET0_3V GPIO_GPIO2 | ||
22 | #define SOCKET1_POWER (GPIO_GPIO1 | GPIO_GPIO3) | ||
23 | #define SOCKET1_3V GPIO_GPIO3 | ||
24 | |||
25 | static int | ||
26 | jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) | ||
27 | { | ||
28 | struct sa1111_pcmcia_socket *s = to_skt(skt); | ||
29 | unsigned int pa_dwr_mask, pa_dwr_set; | ||
30 | int ret; | ||
31 | |||
32 | printk(KERN_INFO "%s(): config socket %d vcc %d vpp %d\n", __func__, | ||
33 | skt->nr, state->Vcc, state->Vpp); | ||
34 | |||
35 | switch (skt->nr) { | ||
36 | case 0: | ||
37 | pa_dwr_mask = SOCKET0_POWER | SOCKET0_3V; | ||
38 | |||
39 | switch (state->Vcc) { | ||
40 | default: | ||
41 | case 0: | ||
42 | pa_dwr_set = 0; | ||
43 | break; | ||
44 | case 33: | ||
45 | pa_dwr_set = SOCKET0_POWER | SOCKET0_3V; | ||
46 | break; | ||
47 | case 50: | ||
48 | pa_dwr_set = SOCKET0_POWER; | ||
49 | break; | ||
50 | } | ||
51 | break; | ||
52 | |||
53 | case 1: | ||
54 | pa_dwr_mask = SOCKET1_POWER; | ||
55 | |||
56 | switch (state->Vcc) { | ||
57 | default: | ||
58 | case 0: | ||
59 | pa_dwr_set = 0; | ||
60 | break; | ||
61 | case 33: | ||
62 | pa_dwr_set = SOCKET1_POWER; | ||
63 | break; | ||
64 | case 50: | ||
65 | pa_dwr_set = SOCKET1_POWER; | ||
66 | break; | ||
67 | } | ||
68 | break; | ||
69 | |||
70 | default: | ||
71 | return -1; | ||
72 | } | ||
73 | |||
74 | if (state->Vpp != state->Vcc && state->Vpp != 0) { | ||
75 | printk(KERN_ERR "%s(): slot cannot support VPP %u\n", | ||
76 | __func__, state->Vpp); | ||
77 | return -EPERM; | ||
78 | } | ||
79 | |||
80 | ret = sa1111_pcmcia_configure_socket(skt, state); | ||
81 | if (ret == 0) { | ||
82 | unsigned long flags; | ||
83 | |||
84 | local_irq_save(flags); | ||
85 | sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set); | ||
86 | local_irq_restore(flags); | ||
87 | } | ||
88 | |||
89 | return ret; | ||
90 | } | ||
91 | |||
92 | static struct pcmcia_low_level jornada720_pcmcia_ops = { | ||
93 | .owner = THIS_MODULE, | ||
94 | .configure_socket = jornada720_pcmcia_configure_socket, | ||
95 | .socket_init = sa1111_pcmcia_socket_init, | ||
96 | .first = 0, | ||
97 | .nr = 2, | ||
98 | }; | ||
99 | |||
100 | int __devinit pcmcia_jornada720_init(struct device *dev) | ||
101 | { | ||
102 | int ret = -ENODEV; | ||
103 | |||
104 | if (machine_is_jornada720()) { | ||
105 | unsigned int pin = GPIO_A0 | GPIO_A1 | GPIO_A2 | GPIO_A3; | ||
106 | |||
107 | GRER |= 0x00000002; | ||
108 | |||
109 | /* Set GPIO_A<3:1> to be outputs for PCMCIA/CF power controller: */ | ||
110 | sa1111_set_io_dir(dev, pin, 0, 0); | ||
111 | sa1111_set_io(dev, pin, 0); | ||
112 | sa1111_set_sleep_io(dev, pin, 0); | ||
113 | |||
114 | sa11xx_drv_pcmcia_ops(&jornada720_pcmcia_ops); | ||
115 | ret = sa1111_pcmcia_add(dev, &jornada720_pcmcia_ops, | ||
116 | sa11xx_drv_pcmcia_add_one); | ||
117 | } | ||
118 | |||
119 | return ret; | ||
120 | } | ||
diff --git a/drivers/pcmcia/sa1100_neponset.c b/drivers/pcmcia/sa1100_neponset.c new file mode 100644 index 00000000000..c95639b5f2a --- /dev/null +++ b/drivers/pcmcia/sa1100_neponset.c | |||
@@ -0,0 +1,143 @@ | |||
1 | /* | ||
2 | * linux/drivers/pcmcia/sa1100_neponset.c | ||
3 | * | ||
4 | * Neponset PCMCIA specific routines | ||
5 | */ | ||
6 | #include <linux/module.h> | ||
7 | #include <linux/kernel.h> | ||
8 | #include <linux/device.h> | ||
9 | #include <linux/errno.h> | ||
10 | #include <linux/init.h> | ||
11 | |||
12 | #include <mach/hardware.h> | ||
13 | #include <asm/mach-types.h> | ||
14 | #include <mach/neponset.h> | ||
15 | #include <asm/hardware/sa1111.h> | ||
16 | |||
17 | #include "sa1111_generic.h" | ||
18 | |||
19 | /* | ||
20 | * Neponset uses the Maxim MAX1600, with the following connections: | ||
21 | * | ||
22 | * MAX1600 Neponset | ||
23 | * | ||
24 | * A0VCC SA-1111 GPIO A<1> | ||
25 | * A1VCC SA-1111 GPIO A<0> | ||
26 | * A0VPP CPLD NCR A0VPP | ||
27 | * A1VPP CPLD NCR A1VPP | ||
28 | * B0VCC SA-1111 GPIO A<2> | ||
29 | * B1VCC SA-1111 GPIO A<3> | ||
30 | * B0VPP ground (slot B is CF) | ||
31 | * B1VPP ground (slot B is CF) | ||
32 | * | ||
33 | * VX VCC (5V) | ||
34 | * VY VCC3_3 (3.3V) | ||
35 | * 12INA 12V | ||
36 | * 12INB ground (slot B is CF) | ||
37 | * | ||
38 | * The MAX1600 CODE pin is tied to ground, placing the device in | ||
39 | * "Standard Intel code" mode. Refer to the Maxim data sheet for | ||
40 | * the corresponding truth table. | ||
41 | */ | ||
42 | |||
43 | static int | ||
44 | neponset_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) | ||
45 | { | ||
46 | struct sa1111_pcmcia_socket *s = to_skt(skt); | ||
47 | unsigned int ncr_mask, ncr_set, pa_dwr_mask, pa_dwr_set; | ||
48 | int ret; | ||
49 | |||
50 | switch (skt->nr) { | ||
51 | case 0: | ||
52 | pa_dwr_mask = GPIO_A0 | GPIO_A1; | ||
53 | ncr_mask = NCR_A0VPP | NCR_A1VPP; | ||
54 | |||
55 | if (state->Vpp == 0) | ||
56 | ncr_set = 0; | ||
57 | else if (state->Vpp == 120) | ||
58 | ncr_set = NCR_A1VPP; | ||
59 | else if (state->Vpp == state->Vcc) | ||
60 | ncr_set = NCR_A0VPP; | ||
61 | else { | ||
62 | printk(KERN_ERR "%s(): unrecognized VPP %u\n", | ||
63 | __func__, state->Vpp); | ||
64 | return -1; | ||
65 | } | ||
66 | break; | ||
67 | |||
68 | case 1: | ||
69 | pa_dwr_mask = GPIO_A2 | GPIO_A3; | ||
70 | ncr_mask = 0; | ||
71 | ncr_set = 0; | ||
72 | |||
73 | if (state->Vpp != state->Vcc && state->Vpp != 0) { | ||
74 | printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n", | ||
75 | __func__, state->Vpp); | ||
76 | return -1; | ||
77 | } | ||
78 | break; | ||
79 | |||
80 | default: | ||
81 | return -1; | ||
82 | } | ||
83 | |||
84 | /* | ||
85 | * pa_dwr_set is the mask for selecting Vcc on both sockets. | ||
86 | * pa_dwr_mask selects which bits (and therefore socket) we change. | ||
87 | */ | ||
88 | switch (state->Vcc) { | ||
89 | default: | ||
90 | case 0: pa_dwr_set = 0; break; | ||
91 | case 33: pa_dwr_set = GPIO_A1|GPIO_A2; break; | ||
92 | case 50: pa_dwr_set = GPIO_A0|GPIO_A3; break; | ||
93 | } | ||
94 | |||
95 | ret = sa1111_pcmcia_configure_socket(skt, state); | ||
96 | if (ret == 0) { | ||
97 | unsigned long flags; | ||
98 | |||
99 | local_irq_save(flags); | ||
100 | NCR_0 = (NCR_0 & ~ncr_mask) | ncr_set; | ||
101 | |||
102 | local_irq_restore(flags); | ||
103 | sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set); | ||
104 | } | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static void neponset_pcmcia_socket_init(struct soc_pcmcia_socket *skt) | ||
110 | { | ||
111 | if (skt->nr == 0) | ||
112 | NCR_0 &= ~(NCR_A0VPP | NCR_A1VPP); | ||
113 | |||
114 | sa1111_pcmcia_socket_init(skt); | ||
115 | } | ||
116 | |||
117 | static struct pcmcia_low_level neponset_pcmcia_ops = { | ||
118 | .owner = THIS_MODULE, | ||
119 | .configure_socket = neponset_pcmcia_configure_socket, | ||
120 | .socket_init = neponset_pcmcia_socket_init, | ||
121 | .first = 0, | ||
122 | .nr = 2, | ||
123 | }; | ||
124 | |||
125 | int pcmcia_neponset_init(struct sa1111_dev *sadev) | ||
126 | { | ||
127 | int ret = -ENODEV; | ||
128 | |||
129 | if (machine_is_assabet()) { | ||
130 | /* | ||
131 | * Set GPIO_A<3:0> to be outputs for the MAX1600, | ||
132 | * and switch to standby mode. | ||
133 | */ | ||
134 | sa1111_set_io_dir(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0, 0); | ||
135 | sa1111_set_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0); | ||
136 | sa1111_set_sleep_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0); | ||
137 | sa11xx_drv_pcmcia_ops(&neponset_pcmcia_ops); | ||
138 | ret = sa1111_pcmcia_add(sadev, &neponset_pcmcia_ops, | ||
139 | sa11xx_drv_pcmcia_add_one); | ||
140 | } | ||
141 | |||
142 | return ret; | ||
143 | } | ||