blob: 5792bd5c54f93a4a3a3394d665145209b2f5c5e8 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*======================================================================
2
3 Device driver for Databook TCIC-2 PCMCIA controller
4
5 tcic.c 1.111 2000/02/15 04:13:12
6
7 The contents of this file are subject to the Mozilla Public
8 License Version 1.1 (the "License"); you may not use this file
9 except in compliance with the License. You may obtain a copy of
10 the License at http://www.mozilla.org/MPL/
11
12 Software distributed under the License is distributed on an "AS
13 IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 implied. See the License for the specific language governing
15 rights and limitations under the License.
16
17 The initial developer of the original code is David A. Hinds
18 <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
19 are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
20
21 Alternatively, the contents of this file may be used under the
22 terms of the GNU General Public License version 2 (the "GPL"), in which
23 case the provisions of the GPL are applicable instead of the
24 above. If you wish to allow the use of your version of this file
25 only under the terms of the GPL and not to allow others to use
26 your version of this file under the MPL, indicate your decision
27 by deleting the provisions above and replace them with the notice
28 and other provisions required by the GPL. If you do not delete
29 the provisions above, a recipient may use your version of this
30 file under either the MPL or the GPL.
31
32======================================================================*/
33
34#include <linux/module.h>
35#include <linux/moduleparam.h>
36#include <linux/init.h>
37#include <linux/types.h>
38#include <linux/fcntl.h>
39#include <linux/string.h>
40#include <linux/errno.h>
41#include <linux/interrupt.h>
42#include <linux/slab.h>
43#include <linux/timer.h>
44#include <linux/ioport.h>
45#include <linux/delay.h>
46#include <linux/workqueue.h>
Russell Kingd052d1b2005-10-29 19:07:23 +010047#include <linux/platform_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#include <linux/bitops.h>
49
50#include <asm/io.h>
51#include <asm/system.h>
52
Linus Torvalds1da177e2005-04-16 15:20:36 -070053#include <pcmcia/cs_types.h>
54#include <pcmcia/cs.h>
55#include <pcmcia/ss.h>
56#include "tcic.h"
57
58#ifdef DEBUG
59static int pc_debug;
60
61module_param(pc_debug, int, 0644);
62static const char version[] =
63"tcic.c 1.111 2000/02/15 04:13:12 (David Hinds)";
64
65#define debug(lvl, fmt, arg...) do { \
66 if (pc_debug > (lvl)) \
67 printk(KERN_DEBUG "tcic: " fmt , ## arg); \
68} while (0)
69#else
70#define debug(lvl, fmt, arg...) do { } while (0)
71#endif
72
73MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
74MODULE_DESCRIPTION("Databook TCIC-2 PCMCIA socket driver");
75MODULE_LICENSE("Dual MPL/GPL");
76
77/*====================================================================*/
78
79/* Parameters that can be set with 'insmod' */
80
81/* The base port address of the TCIC-2 chip */
82static unsigned long tcic_base = TCIC_BASE;
83
84/* Specify a socket number to ignore */
85static int ignore = -1;
86
87/* Probe for safe interrupts? */
88static int do_scan = 1;
89
90/* Bit map of interrupts to choose from */
91static u_int irq_mask = 0xffff;
92static int irq_list[16];
Al Viro64a6f952007-10-14 19:35:30 +010093static unsigned int irq_list_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
95/* The card status change interrupt -- 0 means autoselect */
96static int cs_irq;
97
98/* Poll status interval -- 0 means default to interrupt */
99static int poll_interval;
100
101/* Delay for card status double-checking */
102static int poll_quick = HZ/20;
103
104/* CCLK external clock time, in nanoseconds. 70 ns = 14.31818 MHz */
105static int cycle_time = 70;
106
107module_param(tcic_base, ulong, 0444);
108module_param(ignore, int, 0444);
109module_param(do_scan, int, 0444);
110module_param(irq_mask, int, 0444);
111module_param_array(irq_list, int, &irq_list_count, 0444);
112module_param(cs_irq, int, 0444);
113module_param(poll_interval, int, 0444);
114module_param(poll_quick, int, 0444);
115module_param(cycle_time, int, 0444);
116
117/*====================================================================*/
118
David Howells7d12e782006-10-05 14:55:46 +0100119static irqreturn_t tcic_interrupt(int irq, void *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120static void tcic_timer(u_long data);
121static struct pccard_operations tcic_operations;
122
123struct tcic_socket {
124 u_short psock;
125 u_char last_sstat;
126 u_char id;
127 struct pcmcia_socket socket;
128};
129
130static struct timer_list poll_timer;
131static int tcic_timer_pending;
132
133static int sockets;
134static struct tcic_socket socket_table[2];
135
136/*====================================================================*/
137
138/* Trick when selecting interrupts: the TCIC sktirq pin is supposed
139 to map to irq 11, but is coded as 0 or 1 in the irq registers. */
140#define TCIC_IRQ(x) ((x) ? (((x) == 11) ? 1 : (x)) : 15)
141
142#ifdef DEBUG_X
143static u_char tcic_getb(u_char reg)
144{
145 u_char val = inb(tcic_base+reg);
146 printk(KERN_DEBUG "tcic_getb(%#lx) = %#x\n", tcic_base+reg, val);
147 return val;
148}
149
150static u_short tcic_getw(u_char reg)
151{
152 u_short val = inw(tcic_base+reg);
153 printk(KERN_DEBUG "tcic_getw(%#lx) = %#x\n", tcic_base+reg, val);
154 return val;
155}
156
157static void tcic_setb(u_char reg, u_char data)
158{
159 printk(KERN_DEBUG "tcic_setb(%#lx, %#x)\n", tcic_base+reg, data);
160 outb(data, tcic_base+reg);
161}
162
163static void tcic_setw(u_char reg, u_short data)
164{
165 printk(KERN_DEBUG "tcic_setw(%#lx, %#x)\n", tcic_base+reg, data);
166 outw(data, tcic_base+reg);
167}
168#else
169#define tcic_getb(reg) inb(tcic_base+reg)
170#define tcic_getw(reg) inw(tcic_base+reg)
171#define tcic_setb(reg, data) outb(data, tcic_base+reg)
172#define tcic_setw(reg, data) outw(data, tcic_base+reg)
173#endif
174
175static void tcic_setl(u_char reg, u_int data)
176{
177#ifdef DEBUG_X
178 printk(KERN_DEBUG "tcic_setl(%#x, %#lx)\n", tcic_base+reg, data);
179#endif
180 outw(data & 0xffff, tcic_base+reg);
181 outw(data >> 16, tcic_base+reg+2);
182}
183
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184static void tcic_aux_setb(u_short reg, u_char data)
185{
186 u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg;
187 tcic_setb(TCIC_MODE, mode);
188 tcic_setb(TCIC_AUX, data);
189}
190
191static u_short tcic_aux_getw(u_short reg)
192{
193 u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg;
194 tcic_setb(TCIC_MODE, mode);
195 return tcic_getw(TCIC_AUX);
196}
197
198static void tcic_aux_setw(u_short reg, u_short data)
199{
200 u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg;
201 tcic_setb(TCIC_MODE, mode);
202 tcic_setw(TCIC_AUX, data);
203}
204
205/*====================================================================*/
206
207/* Time conversion functions */
208
209static int to_cycles(int ns)
210{
211 if (ns < 14)
212 return 0;
213 else
214 return 2*(ns-14)/cycle_time;
215}
216
217/*====================================================================*/
218
219static volatile u_int irq_hits;
220
David Howells7d12e782006-10-05 14:55:46 +0100221static irqreturn_t __init tcic_irq_count(int irq, void *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222{
223 irq_hits++;
224 return IRQ_HANDLED;
225}
226
227static u_int __init try_irq(int irq)
228{
229 u_short cfg;
230
231 irq_hits = 0;
232 if (request_irq(irq, tcic_irq_count, 0, "irq scan", tcic_irq_count) != 0)
233 return -1;
234 mdelay(10);
235 if (irq_hits) {
236 free_irq(irq, tcic_irq_count);
237 return -1;
238 }
239
240 /* Generate one interrupt */
241 cfg = TCIC_SYSCFG_AUTOBUSY | 0x0a00;
242 tcic_aux_setw(TCIC_AUX_SYSCFG, cfg | TCIC_IRQ(irq));
243 tcic_setb(TCIC_IENA, TCIC_IENA_ERR | TCIC_IENA_CFG_HIGH);
244 tcic_setb(TCIC_ICSR, TCIC_ICSR_ERR | TCIC_ICSR_JAM);
245
246 udelay(1000);
247 free_irq(irq, tcic_irq_count);
248
249 /* Turn off interrupts */
250 tcic_setb(TCIC_IENA, TCIC_IENA_CFG_OFF);
251 while (tcic_getb(TCIC_ICSR))
252 tcic_setb(TCIC_ICSR, TCIC_ICSR_JAM);
253 tcic_aux_setw(TCIC_AUX_SYSCFG, cfg);
254
255 return (irq_hits != 1);
256}
257
258static u_int __init irq_scan(u_int mask0)
259{
260 u_int mask1;
261 int i;
262
263#ifdef __alpha__
264#define PIC 0x4d0
265 /* Don't probe level-triggered interrupts -- reserved for PCI */
266 int level_mask = inb_p(PIC) | (inb_p(PIC+1) << 8);
267 if (level_mask)
268 mask0 &= ~level_mask;
269#endif
270
271 mask1 = 0;
272 if (do_scan) {
273 for (i = 0; i < 16; i++)
274 if ((mask0 & (1 << i)) && (try_irq(i) == 0))
275 mask1 |= (1 << i);
276 for (i = 0; i < 16; i++)
277 if ((mask1 & (1 << i)) && (try_irq(i) != 0)) {
278 mask1 ^= (1 << i);
279 }
280 }
281
282 if (mask1) {
283 printk("scanned");
284 } else {
285 /* Fallback: just find interrupts that aren't in use */
286 for (i = 0; i < 16; i++)
287 if ((mask0 & (1 << i)) &&
288 (request_irq(i, tcic_irq_count, 0, "x", tcic_irq_count) == 0)) {
289 mask1 |= (1 << i);
290 free_irq(i, tcic_irq_count);
291 }
292 printk("default");
293 }
294
295 printk(") = ");
296 for (i = 0; i < 16; i++)
297 if (mask1 & (1<<i))
298 printk("%s%d", ((mask1 & ((1<<i)-1)) ? "," : ""), i);
299 printk(" ");
300
301 return mask1;
302}
303
304/*======================================================================
305
306 See if a card is present, powered up, in IO mode, and already
307 bound to a (non-PCMCIA) Linux driver.
308
309 We make an exception for cards that look like serial devices.
310
311======================================================================*/
312
313static int __init is_active(int s)
314{
315 u_short scf1, ioctl, base, num;
316 u_char pwr, sstat;
317 u_int addr;
318
319 tcic_setl(TCIC_ADDR, (s << TCIC_ADDR_SS_SHFT)
320 | TCIC_ADDR_INDREG | TCIC_SCF1(s));
321 scf1 = tcic_getw(TCIC_DATA);
322 pwr = tcic_getb(TCIC_PWR);
323 sstat = tcic_getb(TCIC_SSTAT);
324 addr = TCIC_IWIN(s, 0);
325 tcic_setw(TCIC_ADDR, addr + TCIC_IBASE_X);
326 base = tcic_getw(TCIC_DATA);
327 tcic_setw(TCIC_ADDR, addr + TCIC_ICTL_X);
328 ioctl = tcic_getw(TCIC_DATA);
329
330 if (ioctl & TCIC_ICTL_TINY)
331 num = 1;
332 else {
333 num = (base ^ (base-1));
334 base = base & (base-1);
335 }
336
337 if ((sstat & TCIC_SSTAT_CD) && (pwr & TCIC_PWR_VCC(s)) &&
338 (scf1 & TCIC_SCF1_IOSTS) && (ioctl & TCIC_ICTL_ENA) &&
339 ((base & 0xfeef) != 0x02e8)) {
340 struct resource *res = request_region(base, num, "tcic-2");
341 if (!res) /* region is busy */
342 return 1;
343 release_region(base, num);
344 }
345
346 return 0;
347}
348
349/*======================================================================
350
351 This returns the revision code for the specified socket.
352
353======================================================================*/
354
355static int __init get_tcic_id(void)
356{
357 u_short id;
358
359 tcic_aux_setw(TCIC_AUX_TEST, TCIC_TEST_DIAG);
360 id = tcic_aux_getw(TCIC_AUX_ILOCK);
361 id = (id & TCIC_ILOCKTEST_ID_MASK) >> TCIC_ILOCKTEST_ID_SH;
362 tcic_aux_setw(TCIC_AUX_TEST, 0);
363 return id;
364}
365
366/*====================================================================*/
367
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368static struct device_driver tcic_driver = {
369 .name = "tcic-pcmcia",
370 .bus = &platform_bus_type,
Russell King9480e302005-10-28 09:52:56 -0700371 .suspend = pcmcia_socket_dev_suspend,
372 .resume = pcmcia_socket_dev_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373};
374
375static struct platform_device tcic_device = {
376 .name = "tcic-pcmcia",
377 .id = 0,
378};
379
380
381static int __init init_tcic(void)
382{
383 int i, sock, ret = 0;
384 u_int mask, scan;
385
386 if (driver_register(&tcic_driver))
387 return -1;
388
389 printk(KERN_INFO "Databook TCIC-2 PCMCIA probe: ");
390 sock = 0;
391
392 if (!request_region(tcic_base, 16, "tcic-2")) {
393 printk("could not allocate ports,\n ");
394 driver_unregister(&tcic_driver);
395 return -ENODEV;
396 }
397 else {
398 tcic_setw(TCIC_ADDR, 0);
399 if (tcic_getw(TCIC_ADDR) == 0) {
400 tcic_setw(TCIC_ADDR, 0xc3a5);
401 if (tcic_getw(TCIC_ADDR) == 0xc3a5) sock = 2;
402 }
403 if (sock == 0) {
404 /* See if resetting the controller does any good */
405 tcic_setb(TCIC_SCTRL, TCIC_SCTRL_RESET);
406 tcic_setb(TCIC_SCTRL, 0);
407 tcic_setw(TCIC_ADDR, 0);
408 if (tcic_getw(TCIC_ADDR) == 0) {
409 tcic_setw(TCIC_ADDR, 0xc3a5);
410 if (tcic_getw(TCIC_ADDR) == 0xc3a5) sock = 2;
411 }
412 }
413 }
414 if (sock == 0) {
415 printk("not found.\n");
416 release_region(tcic_base, 16);
417 driver_unregister(&tcic_driver);
418 return -ENODEV;
419 }
420
421 sockets = 0;
422 for (i = 0; i < sock; i++) {
423 if ((i == ignore) || is_active(i)) continue;
424 socket_table[sockets].psock = i;
425 socket_table[sockets].id = get_tcic_id();
426
427 socket_table[sockets].socket.owner = THIS_MODULE;
428 /* only 16-bit cards, memory windows must be size-aligned */
429 /* No PCI or CardBus support */
430 socket_table[sockets].socket.features = SS_CAP_PCCARD | SS_CAP_MEM_ALIGN;
431 /* irq 14, 11, 10, 7, 6, 5, 4, 3 */
432 socket_table[sockets].socket.irq_mask = 0x4cf8;
433 /* 4K minimum window size */
434 socket_table[sockets].socket.map_size = 0x1000;
435 sockets++;
436 }
437
438 switch (socket_table[0].id) {
439 case TCIC_ID_DB86082:
440 printk("DB86082"); break;
441 case TCIC_ID_DB86082A:
442 printk("DB86082A"); break;
443 case TCIC_ID_DB86084:
444 printk("DB86084"); break;
445 case TCIC_ID_DB86084A:
446 printk("DB86084A"); break;
447 case TCIC_ID_DB86072:
448 printk("DB86072"); break;
449 case TCIC_ID_DB86184:
450 printk("DB86184"); break;
451 case TCIC_ID_DB86082B:
452 printk("DB86082B"); break;
453 default:
454 printk("Unknown ID 0x%02x", socket_table[0].id);
455 }
456
457 /* Set up polling */
458 poll_timer.function = &tcic_timer;
459 poll_timer.data = 0;
460 init_timer(&poll_timer);
461
462 /* Build interrupt mask */
463 printk(", %d sockets\n" KERN_INFO " irq list (", sockets);
464 if (irq_list_count == 0)
465 mask = irq_mask;
466 else
467 for (i = mask = 0; i < irq_list_count; i++)
468 mask |= (1<<irq_list[i]);
469
470 /* irq 14, 11, 10, 7, 6, 5, 4, 3 */
471 mask &= 0x4cf8;
472 /* Scan interrupts */
473 mask = irq_scan(mask);
474 for (i=0;i<sockets;i++)
475 socket_table[i].socket.irq_mask = mask;
476
477 /* Check for only two interrupts available */
478 scan = (mask & (mask-1));
479 if (((scan & (scan-1)) == 0) && (poll_interval == 0))
480 poll_interval = HZ;
481
482 if (poll_interval == 0) {
483 /* Avoid irq 12 unless it is explicitly requested */
484 u_int cs_mask = mask & ((cs_irq) ? (1<<cs_irq) : ~(1<<12));
485 for (i = 15; i > 0; i--)
486 if ((cs_mask & (1 << i)) &&
487 (request_irq(i, tcic_interrupt, 0, "tcic",
488 tcic_interrupt) == 0))
489 break;
490 cs_irq = i;
491 if (cs_irq == 0) poll_interval = HZ;
492 }
493
494 if (socket_table[0].socket.irq_mask & (1 << 11))
495 printk("sktirq is irq 11, ");
496 if (cs_irq != 0)
497 printk("status change on irq %d\n", cs_irq);
498 else
499 printk("polled status, interval = %d ms\n",
500 poll_interval * 1000 / HZ);
501
502 for (i = 0; i < sockets; i++) {
503 tcic_setw(TCIC_ADDR+2, socket_table[i].psock << TCIC_SS_SHFT);
504 socket_table[i].last_sstat = tcic_getb(TCIC_SSTAT);
505 }
506
507 /* jump start interrupt handler, if needed */
David Howells7d12e782006-10-05 14:55:46 +0100508 tcic_interrupt(0, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
510 platform_device_register(&tcic_device);
511
512 for (i = 0; i < sockets; i++) {
513 socket_table[i].socket.ops = &tcic_operations;
514 socket_table[i].socket.resource_ops = &pccard_nonstatic_ops;
Greg Kroah-Hartman87373312006-09-12 17:00:10 +0200515 socket_table[i].socket.dev.parent = &tcic_device.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 ret = pcmcia_register_socket(&socket_table[i].socket);
517 if (ret && i)
518 pcmcia_unregister_socket(&socket_table[0].socket);
519 }
520
521 return ret;
522
523 return 0;
524
525} /* init_tcic */
526
527/*====================================================================*/
528
529static void __exit exit_tcic(void)
530{
531 int i;
532
533 del_timer_sync(&poll_timer);
534 if (cs_irq != 0) {
535 tcic_aux_setw(TCIC_AUX_SYSCFG, TCIC_SYSCFG_AUTOBUSY|0x0a00);
536 free_irq(cs_irq, tcic_interrupt);
537 }
538 release_region(tcic_base, 16);
539
540 for (i = 0; i < sockets; i++) {
541 pcmcia_unregister_socket(&socket_table[i].socket);
542 }
543
544 platform_device_unregister(&tcic_device);
545 driver_unregister(&tcic_driver);
546} /* exit_tcic */
547
548/*====================================================================*/
549
David Howells7d12e782006-10-05 14:55:46 +0100550static irqreturn_t tcic_interrupt(int irq, void *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551{
552 int i, quick = 0;
553 u_char latch, sstat;
554 u_short psock;
555 u_int events;
556 static volatile int active = 0;
557
558 if (active) {
559 printk(KERN_NOTICE "tcic: reentered interrupt handler!\n");
560 return IRQ_NONE;
561 } else
562 active = 1;
563
564 debug(2, "tcic_interrupt()\n");
565
566 for (i = 0; i < sockets; i++) {
567 psock = socket_table[i].psock;
568 tcic_setl(TCIC_ADDR, (psock << TCIC_ADDR_SS_SHFT)
569 | TCIC_ADDR_INDREG | TCIC_SCF1(psock));
570 sstat = tcic_getb(TCIC_SSTAT);
571 latch = sstat ^ socket_table[psock].last_sstat;
572 socket_table[i].last_sstat = sstat;
573 if (tcic_getb(TCIC_ICSR) & TCIC_ICSR_CDCHG) {
574 tcic_setb(TCIC_ICSR, TCIC_ICSR_CLEAR);
575 quick = 1;
576 }
577 if (latch == 0)
578 continue;
579 events = (latch & TCIC_SSTAT_CD) ? SS_DETECT : 0;
580 events |= (latch & TCIC_SSTAT_WP) ? SS_WRPROT : 0;
581 if (tcic_getw(TCIC_DATA) & TCIC_SCF1_IOSTS) {
582 events |= (latch & TCIC_SSTAT_LBAT1) ? SS_STSCHG : 0;
583 } else {
584 events |= (latch & TCIC_SSTAT_RDY) ? SS_READY : 0;
585 events |= (latch & TCIC_SSTAT_LBAT1) ? SS_BATDEAD : 0;
586 events |= (latch & TCIC_SSTAT_LBAT2) ? SS_BATWARN : 0;
587 }
588 if (events) {
589 pcmcia_parse_events(&socket_table[i].socket, events);
590 }
591 }
592
593 /* Schedule next poll, if needed */
594 if (((cs_irq == 0) || quick) && (!tcic_timer_pending)) {
595 poll_timer.expires = jiffies + (quick ? poll_quick : poll_interval);
596 add_timer(&poll_timer);
597 tcic_timer_pending = 1;
598 }
599 active = 0;
600
601 debug(2, "interrupt done\n");
602 return IRQ_HANDLED;
603} /* tcic_interrupt */
604
605static void tcic_timer(u_long data)
606{
607 debug(2, "tcic_timer()\n");
608 tcic_timer_pending = 0;
David Howells7d12e782006-10-05 14:55:46 +0100609 tcic_interrupt(0, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610} /* tcic_timer */
611
612/*====================================================================*/
613
614static int tcic_get_status(struct pcmcia_socket *sock, u_int *value)
615{
616 u_short psock = container_of(sock, struct tcic_socket, socket)->psock;
617 u_char reg;
618
619 tcic_setl(TCIC_ADDR, (psock << TCIC_ADDR_SS_SHFT)
620 | TCIC_ADDR_INDREG | TCIC_SCF1(psock));
621 reg = tcic_getb(TCIC_SSTAT);
622 *value = (reg & TCIC_SSTAT_CD) ? SS_DETECT : 0;
623 *value |= (reg & TCIC_SSTAT_WP) ? SS_WRPROT : 0;
624 if (tcic_getw(TCIC_DATA) & TCIC_SCF1_IOSTS) {
625 *value |= (reg & TCIC_SSTAT_LBAT1) ? SS_STSCHG : 0;
626 } else {
627 *value |= (reg & TCIC_SSTAT_RDY) ? SS_READY : 0;
628 *value |= (reg & TCIC_SSTAT_LBAT1) ? SS_BATDEAD : 0;
629 *value |= (reg & TCIC_SSTAT_LBAT2) ? SS_BATWARN : 0;
630 }
631 reg = tcic_getb(TCIC_PWR);
632 if (reg & (TCIC_PWR_VCC(psock)|TCIC_PWR_VPP(psock)))
633 *value |= SS_POWERON;
634 debug(1, "GetStatus(%d) = %#2.2x\n", psock, *value);
635 return 0;
636} /* tcic_get_status */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637
638/*====================================================================*/
639
640static int tcic_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
641{
642 u_short psock = container_of(sock, struct tcic_socket, socket)->psock;
643 u_char reg;
644 u_short scf1, scf2;
645
646 debug(1, "SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
647 "io_irq %d, csc_mask %#2.2x)\n", psock, state->flags,
648 state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
649 tcic_setw(TCIC_ADDR+2, (psock << TCIC_SS_SHFT) | TCIC_ADR2_INDREG);
650
651 reg = tcic_getb(TCIC_PWR);
652 reg &= ~(TCIC_PWR_VCC(psock) | TCIC_PWR_VPP(psock));
653
654 if (state->Vcc == 50) {
655 switch (state->Vpp) {
656 case 0: reg |= TCIC_PWR_VCC(psock) | TCIC_PWR_VPP(psock); break;
657 case 50: reg |= TCIC_PWR_VCC(psock); break;
658 case 120: reg |= TCIC_PWR_VPP(psock); break;
659 default: return -EINVAL;
660 }
661 } else if (state->Vcc != 0)
662 return -EINVAL;
663
664 if (reg != tcic_getb(TCIC_PWR))
665 tcic_setb(TCIC_PWR, reg);
666
667 reg = TCIC_ILOCK_HOLD_CCLK | TCIC_ILOCK_CWAIT;
668 if (state->flags & SS_OUTPUT_ENA) {
669 tcic_setb(TCIC_SCTRL, TCIC_SCTRL_ENA);
670 reg |= TCIC_ILOCK_CRESENA;
671 } else
672 tcic_setb(TCIC_SCTRL, 0);
673 if (state->flags & SS_RESET)
674 reg |= TCIC_ILOCK_CRESET;
675 tcic_aux_setb(TCIC_AUX_ILOCK, reg);
676
677 tcic_setw(TCIC_ADDR, TCIC_SCF1(psock));
678 scf1 = TCIC_SCF1_FINPACK;
679 scf1 |= TCIC_IRQ(state->io_irq);
680 if (state->flags & SS_IOCARD) {
681 scf1 |= TCIC_SCF1_IOSTS;
682 if (state->flags & SS_SPKR_ENA)
683 scf1 |= TCIC_SCF1_SPKR;
684 if (state->flags & SS_DMA_MODE)
685 scf1 |= TCIC_SCF1_DREQ2 << TCIC_SCF1_DMA_SHIFT;
686 }
687 tcic_setw(TCIC_DATA, scf1);
688
689 /* Some general setup stuff, and configure status interrupt */
690 reg = TCIC_WAIT_ASYNC | TCIC_WAIT_SENSE | to_cycles(250);
691 tcic_aux_setb(TCIC_AUX_WCTL, reg);
692 tcic_aux_setw(TCIC_AUX_SYSCFG, TCIC_SYSCFG_AUTOBUSY|0x0a00|
693 TCIC_IRQ(cs_irq));
694
695 /* Card status change interrupt mask */
696 tcic_setw(TCIC_ADDR, TCIC_SCF2(psock));
697 scf2 = TCIC_SCF2_MALL;
698 if (state->csc_mask & SS_DETECT) scf2 &= ~TCIC_SCF2_MCD;
699 if (state->flags & SS_IOCARD) {
700 if (state->csc_mask & SS_STSCHG) reg &= ~TCIC_SCF2_MLBAT1;
701 } else {
702 if (state->csc_mask & SS_BATDEAD) reg &= ~TCIC_SCF2_MLBAT1;
703 if (state->csc_mask & SS_BATWARN) reg &= ~TCIC_SCF2_MLBAT2;
704 if (state->csc_mask & SS_READY) reg &= ~TCIC_SCF2_MRDY;
705 }
706 tcic_setw(TCIC_DATA, scf2);
707 /* For the ISA bus, the irq should be active-high totem-pole */
708 tcic_setb(TCIC_IENA, TCIC_IENA_CDCHG | TCIC_IENA_CFG_HIGH);
709
710 return 0;
711} /* tcic_set_socket */
712
713/*====================================================================*/
714
715static int tcic_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io)
716{
717 u_short psock = container_of(sock, struct tcic_socket, socket)->psock;
718 u_int addr;
719 u_short base, len, ioctl;
720
721 debug(1, "SetIOMap(%d, %d, %#2.2x, %d ns, "
Olof Johansson906da802008-02-04 22:27:35 -0800722 "%#x-%#x)\n", psock, io->map, io->flags,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 io->speed, io->start, io->stop);
724 if ((io->map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) ||
725 (io->stop < io->start)) return -EINVAL;
726 tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT));
727 addr = TCIC_IWIN(psock, io->map);
728
729 base = io->start; len = io->stop - io->start;
730 /* Check to see that len+1 is power of two, etc */
731 if ((len & (len+1)) || (base & len)) return -EINVAL;
732 base |= (len+1)>>1;
733 tcic_setw(TCIC_ADDR, addr + TCIC_IBASE_X);
734 tcic_setw(TCIC_DATA, base);
735
736 ioctl = (psock << TCIC_ICTL_SS_SHFT);
737 ioctl |= (len == 0) ? TCIC_ICTL_TINY : 0;
738 ioctl |= (io->flags & MAP_ACTIVE) ? TCIC_ICTL_ENA : 0;
739 ioctl |= to_cycles(io->speed) & TCIC_ICTL_WSCNT_MASK;
740 if (!(io->flags & MAP_AUTOSZ)) {
741 ioctl |= TCIC_ICTL_QUIET;
742 ioctl |= (io->flags & MAP_16BIT) ? TCIC_ICTL_BW_16 : TCIC_ICTL_BW_8;
743 }
744 tcic_setw(TCIC_ADDR, addr + TCIC_ICTL_X);
745 tcic_setw(TCIC_DATA, ioctl);
746
747 return 0;
748} /* tcic_set_io_map */
749
750/*====================================================================*/
751
752static int tcic_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *mem)
753{
754 u_short psock = container_of(sock, struct tcic_socket, socket)->psock;
755 u_short addr, ctl;
756 u_long base, len, mmap;
757
758 debug(1, "SetMemMap(%d, %d, %#2.2x, %d ns, "
Greg Kroah-Hartman490ab722006-06-12 15:17:34 -0700759 "%#llx-%#llx, %#x)\n", psock, mem->map, mem->flags,
760 mem->speed, (unsigned long long)mem->res->start,
761 (unsigned long long)mem->res->end, mem->card_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 if ((mem->map > 3) || (mem->card_start > 0x3ffffff) ||
763 (mem->res->start > 0xffffff) || (mem->res->end > 0xffffff) ||
764 (mem->res->start > mem->res->end) || (mem->speed > 1000))
765 return -EINVAL;
766 tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT));
767 addr = TCIC_MWIN(psock, mem->map);
768
769 base = mem->res->start; len = mem->res->end - mem->res->start;
770 if ((len & (len+1)) || (base & len)) return -EINVAL;
771 if (len == 0x0fff)
772 base = (base >> TCIC_MBASE_HA_SHFT) | TCIC_MBASE_4K_BIT;
773 else
774 base = (base | (len+1)>>1) >> TCIC_MBASE_HA_SHFT;
775 tcic_setw(TCIC_ADDR, addr + TCIC_MBASE_X);
776 tcic_setw(TCIC_DATA, base);
777
778 mmap = mem->card_start - mem->res->start;
779 mmap = (mmap >> TCIC_MMAP_CA_SHFT) & TCIC_MMAP_CA_MASK;
780 if (mem->flags & MAP_ATTRIB) mmap |= TCIC_MMAP_REG;
781 tcic_setw(TCIC_ADDR, addr + TCIC_MMAP_X);
782 tcic_setw(TCIC_DATA, mmap);
783
784 ctl = TCIC_MCTL_QUIET | (psock << TCIC_MCTL_SS_SHFT);
785 ctl |= to_cycles(mem->speed) & TCIC_MCTL_WSCNT_MASK;
786 ctl |= (mem->flags & MAP_16BIT) ? 0 : TCIC_MCTL_B8;
787 ctl |= (mem->flags & MAP_WRPROT) ? TCIC_MCTL_WP : 0;
788 ctl |= (mem->flags & MAP_ACTIVE) ? TCIC_MCTL_ENA : 0;
789 tcic_setw(TCIC_ADDR, addr + TCIC_MCTL_X);
790 tcic_setw(TCIC_DATA, ctl);
791
792 return 0;
793} /* tcic_set_mem_map */
794
795/*====================================================================*/
796
797static int tcic_init(struct pcmcia_socket *s)
798{
799 int i;
800 struct resource res = { .start = 0, .end = 0x1000 };
801 pccard_io_map io = { 0, 0, 0, 0, 1 };
802 pccard_mem_map mem = { .res = &res, };
803
804 for (i = 0; i < 2; i++) {
805 io.map = i;
806 tcic_set_io_map(s, &io);
807 }
808 for (i = 0; i < 5; i++) {
809 mem.map = i;
810 tcic_set_mem_map(s, &mem);
811 }
812 return 0;
813}
814
815static struct pccard_operations tcic_operations = {
816 .init = tcic_init,
817 .get_status = tcic_get_status,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 .set_socket = tcic_set_socket,
819 .set_io_map = tcic_set_io_map,
820 .set_mem_map = tcic_set_mem_map,
821};
822
823/*====================================================================*/
824
825module_init(init_tcic);
826module_exit(exit_tcic);