1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#include <linux/delay.h>
25#include <linux/gpio.h>
26#include <linux/interrupt.h>
27#include <linux/pm.h>
28#include <linux/module.h>
29#include <linux/platform_device.h>
30#include <linux/resource.h>
31#include <linux/slab.h>
32#include <linux/spinlock.h>
33
34#include <pcmcia/ss.h>
35
36#include <asm/mach-au1x00/au1000.h>
37#include <asm/mach-db1x00/bcsr.h>
38
39#define MEM_MAP_SIZE 0x400000
40#define IO_MAP_SIZE 0x1000
41
42struct db1x_pcmcia_sock {
43 struct pcmcia_socket socket;
44 int nr;
45 void *virt_io;
46
47 phys_addr_t phys_io;
48 phys_addr_t phys_attr;
49 phys_addr_t phys_mem;
50
51
52 unsigned int old_flags;
53
54
55 int insert_irq;
56 int stschg_irq;
57 int card_irq;
58 int eject_irq;
59
60#define BOARD_TYPE_DEFAULT 0
61#define BOARD_TYPE_DB1200 1
62#define BOARD_TYPE_PB1100 2
63#define BOARD_TYPE_DB1300 3
64 int board_type;
65};
66
67#define to_db1x_socket(x) container_of(x, struct db1x_pcmcia_sock, socket)
68
69static int db1300_card_inserted(struct db1x_pcmcia_sock *sock)
70{
71 return bcsr_read(BCSR_SIGSTAT) & (1 << 8);
72}
73
74
75static int db1200_card_inserted(struct db1x_pcmcia_sock *sock)
76{
77 unsigned short sigstat;
78
79 sigstat = bcsr_read(BCSR_SIGSTAT);
80 return sigstat & 1 << (8 + 2 * sock->nr);
81}
82
83
84static int db1000_card_inserted(struct db1x_pcmcia_sock *sock)
85{
86 return !gpio_get_value(irq_to_gpio(sock->insert_irq));
87}
88
89static int db1x_card_inserted(struct db1x_pcmcia_sock *sock)
90{
91 switch (sock->board_type) {
92 case BOARD_TYPE_DB1200:
93 return db1200_card_inserted(sock);
94 case BOARD_TYPE_DB1300:
95 return db1300_card_inserted(sock);
96 default:
97 return db1000_card_inserted(sock);
98 }
99}
100
101
102
103
104
105static inline void set_stschg(struct db1x_pcmcia_sock *sock, int en)
106{
107 if (sock->stschg_irq != -1) {
108 if (en)
109 enable_irq(sock->stschg_irq);
110 else
111 disable_irq(sock->stschg_irq);
112 }
113}
114
115static irqreturn_t db1000_pcmcia_cdirq(int irq, void *data)
116{
117 struct db1x_pcmcia_sock *sock = data;
118
119 pcmcia_parse_events(&sock->socket, SS_DETECT);
120
121 return IRQ_HANDLED;
122}
123
124static irqreturn_t db1000_pcmcia_stschgirq(int irq, void *data)
125{
126 struct db1x_pcmcia_sock *sock = data;
127
128 pcmcia_parse_events(&sock->socket, SS_STSCHG);
129
130 return IRQ_HANDLED;
131}
132
133static irqreturn_t db1200_pcmcia_cdirq(int irq, void *data)
134{
135 struct db1x_pcmcia_sock *sock = data;
136
137
138
139
140
141
142 if (irq == sock->insert_irq) {
143 disable_irq_nosync(sock->insert_irq);
144 enable_irq(sock->eject_irq);
145 } else {
146 disable_irq_nosync(sock->eject_irq);
147 enable_irq(sock->insert_irq);
148 }
149
150 pcmcia_parse_events(&sock->socket, SS_DETECT);
151
152 return IRQ_HANDLED;
153}
154
155static int db1x_pcmcia_setup_irqs(struct db1x_pcmcia_sock *sock)
156{
157 int ret;
158
159 if (sock->stschg_irq != -1) {
160 ret = request_irq(sock->stschg_irq, db1000_pcmcia_stschgirq,
161 0, "pcmcia_stschg", sock);
162 if (ret)
163 return ret;
164 }
165
166
167
168
169
170
171
172 if ((sock->board_type == BOARD_TYPE_DB1200) ||
173 (sock->board_type == BOARD_TYPE_DB1300)) {
174 ret = request_irq(sock->insert_irq, db1200_pcmcia_cdirq,
175 0, "pcmcia_insert", sock);
176 if (ret)
177 goto out1;
178
179 ret = request_irq(sock->eject_irq, db1200_pcmcia_cdirq,
180 0, "pcmcia_eject", sock);
181 if (ret) {
182 free_irq(sock->insert_irq, sock);
183 goto out1;
184 }
185
186
187 if (db1x_card_inserted(sock))
188 enable_irq(sock->eject_irq);
189 else
190 enable_irq(sock->insert_irq);
191 } else {
192
193
194
195 irq_set_irq_type(sock->insert_irq, IRQ_TYPE_EDGE_BOTH);
196 ret = request_irq(sock->insert_irq, db1000_pcmcia_cdirq,
197 0, "pcmcia_carddetect", sock);
198
199 if (ret)
200 goto out1;
201 }
202
203 return 0;
204
205out1:
206 if (sock->stschg_irq != -1)
207 free_irq(sock->stschg_irq, sock);
208
209 return ret;
210}
211
212static void db1x_pcmcia_free_irqs(struct db1x_pcmcia_sock *sock)
213{
214 if (sock->stschg_irq != -1)
215 free_irq(sock->stschg_irq, sock);
216
217 free_irq(sock->insert_irq, sock);
218 if (sock->eject_irq != -1)
219 free_irq(sock->eject_irq, sock);
220}
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235static int db1x_pcmcia_configure(struct pcmcia_socket *skt,
236 struct socket_state_t *state)
237{
238 struct db1x_pcmcia_sock *sock = to_db1x_socket(skt);
239 unsigned short cr_clr, cr_set;
240 unsigned int changed;
241 int v, p, ret;
242
243
244 cr_clr = (0xf << (sock->nr * 8));
245 cr_set = 0;
246 v = p = ret = 0;
247
248 switch (state->Vcc) {
249 case 50:
250 ++v;
251 case 33:
252 ++v;
253 case 0:
254 break;
255 default:
256 printk(KERN_INFO "pcmcia%d unsupported Vcc %d\n",
257 sock->nr, state->Vcc);
258 }
259
260 switch (state->Vpp) {
261 case 12:
262 ++p;
263 case 33:
264 case 50:
265 ++p;
266 case 0:
267 break;
268 default:
269 printk(KERN_INFO "pcmcia%d unsupported Vpp %d\n",
270 sock->nr, state->Vpp);
271 }
272
273
274 if (((state->Vcc == 33) && (state->Vpp == 50)) ||
275 ((state->Vcc == 50) && (state->Vpp == 33))) {
276 printk(KERN_INFO "pcmcia%d bad Vcc/Vpp combo (%d %d)\n",
277 sock->nr, state->Vcc, state->Vpp);
278 v = p = 0;
279 ret = -EINVAL;
280 }
281
282
283 if (sock->board_type != BOARD_TYPE_DB1300)
284 cr_set |= ((v << 2) | p) << (sock->nr * 8);
285
286 changed = state->flags ^ sock->old_flags;
287
288 if (changed & SS_RESET) {
289 if (state->flags & SS_RESET) {
290 set_stschg(sock, 0);
291
292 cr_clr |= (1 << (7 + (sock->nr * 8)));
293 cr_clr |= (1 << (4 + (sock->nr * 8)));
294 } else {
295
296 cr_set |= 1 << (7 + (sock->nr * 8));
297 cr_set |= 1 << (4 + (sock->nr * 8));
298 }
299 }
300
301
302 bcsr_mod(BCSR_PCMCIA, cr_clr, cr_set);
303
304 sock->old_flags = state->flags;
305
306
307 if ((changed & SS_RESET) && !(state->flags & SS_RESET)) {
308 msleep(500);
309 set_stschg(sock, 1);
310 }
311
312 return ret;
313}
314
315
316#define GET_VCC(cr, socknr) \
317 ((((cr) >> 2) >> ((socknr) * 8)) & 3)
318
319
320#define GET_VS(sr, socknr) \
321 (((sr) >> (2 * (socknr))) & 3)
322
323
324#define GET_RESET(cr, socknr) \
325 ((cr) & (1 << (7 + (8 * (socknr)))))
326
327static int db1x_pcmcia_get_status(struct pcmcia_socket *skt,
328 unsigned int *value)
329{
330 struct db1x_pcmcia_sock *sock = to_db1x_socket(skt);
331 unsigned short cr, sr;
332 unsigned int status;
333
334 status = db1x_card_inserted(sock) ? SS_DETECT : 0;
335
336 cr = bcsr_read(BCSR_PCMCIA);
337 sr = bcsr_read(BCSR_STATUS);
338
339
340 if (sock->board_type == BOARD_TYPE_PB1100)
341 sr >>= 4;
342
343
344 switch (GET_VS(sr, sock->nr)) {
345 case 0:
346 case 2:
347 status |= SS_3VCARD;
348 case 3:
349 break;
350 default:
351 status |= SS_XVCARD;
352 }
353
354
355 status |= GET_VCC(cr, sock->nr) ? SS_POWERON : 0;
356
357
358 if ((sock->board_type == BOARD_TYPE_DB1300) && (status & SS_DETECT))
359 status = SS_POWERON | SS_3VCARD | SS_DETECT;
360
361
362 status |= (GET_RESET(cr, sock->nr)) ? SS_READY : SS_RESET;
363
364 *value = status;
365
366 return 0;
367}
368
369static int db1x_pcmcia_sock_init(struct pcmcia_socket *skt)
370{
371 return 0;
372}
373
374static int db1x_pcmcia_sock_suspend(struct pcmcia_socket *skt)
375{
376 return 0;
377}
378
379static int au1x00_pcmcia_set_io_map(struct pcmcia_socket *skt,
380 struct pccard_io_map *map)
381{
382 struct db1x_pcmcia_sock *sock = to_db1x_socket(skt);
383
384 map->start = (u32)sock->virt_io;
385 map->stop = map->start + IO_MAP_SIZE;
386
387 return 0;
388}
389
390static int au1x00_pcmcia_set_mem_map(struct pcmcia_socket *skt,
391 struct pccard_mem_map *map)
392{
393 struct db1x_pcmcia_sock *sock = to_db1x_socket(skt);
394
395 if (map->flags & MAP_ATTRIB)
396 map->static_start = sock->phys_attr + map->card_start;
397 else
398 map->static_start = sock->phys_mem + map->card_start;
399
400 return 0;
401}
402
403static struct pccard_operations db1x_pcmcia_operations = {
404 .init = db1x_pcmcia_sock_init,
405 .suspend = db1x_pcmcia_sock_suspend,
406 .get_status = db1x_pcmcia_get_status,
407 .set_socket = db1x_pcmcia_configure,
408 .set_io_map = au1x00_pcmcia_set_io_map,
409 .set_mem_map = au1x00_pcmcia_set_mem_map,
410};
411
412static int db1x_pcmcia_socket_probe(struct platform_device *pdev)
413{
414 struct db1x_pcmcia_sock *sock;
415 struct resource *r;
416 int ret, bid;
417
418 sock = kzalloc(sizeof(struct db1x_pcmcia_sock), GFP_KERNEL);
419 if (!sock)
420 return -ENOMEM;
421
422 sock->nr = pdev->id;
423
424 bid = BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI));
425 switch (bid) {
426 case BCSR_WHOAMI_PB1500:
427 case BCSR_WHOAMI_PB1500R2:
428 case BCSR_WHOAMI_PB1100:
429 sock->board_type = BOARD_TYPE_PB1100;
430 break;
431 case BCSR_WHOAMI_DB1000 ... BCSR_WHOAMI_PB1550_SDR:
432 sock->board_type = BOARD_TYPE_DEFAULT;
433 break;
434 case BCSR_WHOAMI_PB1200 ... BCSR_WHOAMI_DB1200:
435 sock->board_type = BOARD_TYPE_DB1200;
436 break;
437 case BCSR_WHOAMI_DB1300:
438 sock->board_type = BOARD_TYPE_DB1300;
439 break;
440 default:
441 printk(KERN_INFO "db1xxx-ss: unknown board %d!\n", bid);
442 ret = -ENODEV;
443 goto out0;
444 };
445
446
447
448
449
450
451
452
453
454
455
456
457 r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "card");
458 sock->card_irq = r ? r->start : 0;
459
460
461 r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "insert");
462 sock->insert_irq = r ? r->start : -1;
463
464
465 r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "stschg");
466 sock->stschg_irq = r ? r->start : -1;
467
468
469 r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "eject");
470 sock->eject_irq = r ? r->start : -1;
471
472 ret = -ENODEV;
473
474
475 r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcmcia-attr");
476 if (!r) {
477 printk(KERN_ERR "pcmcia%d has no 'pseudo-attr' resource!\n",
478 sock->nr);
479 goto out0;
480 }
481 sock->phys_attr = r->start;
482
483
484 r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcmcia-mem");
485 if (!r) {
486 printk(KERN_ERR "pcmcia%d has no 'pseudo-mem' resource!\n",
487 sock->nr);
488 goto out0;
489 }
490 sock->phys_mem = r->start;
491
492
493 r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcmcia-io");
494 if (!r) {
495 printk(KERN_ERR "pcmcia%d has no 'pseudo-io' resource!\n",
496 sock->nr);
497 goto out0;
498 }
499 sock->phys_io = r->start;
500
501
502
503
504
505
506
507
508
509 sock->virt_io = (void *)(ioremap(sock->phys_io, IO_MAP_SIZE) -
510 mips_io_port_base);
511
512 if (!sock->virt_io) {
513 printk(KERN_ERR "pcmcia%d: cannot remap IO area\n",
514 sock->nr);
515 ret = -ENOMEM;
516 goto out0;
517 }
518
519 sock->socket.ops = &db1x_pcmcia_operations;
520 sock->socket.owner = THIS_MODULE;
521 sock->socket.pci_irq = sock->card_irq;
522 sock->socket.features = SS_CAP_STATIC_MAP | SS_CAP_PCCARD;
523 sock->socket.map_size = MEM_MAP_SIZE;
524 sock->socket.io_offset = (unsigned long)sock->virt_io;
525 sock->socket.dev.parent = &pdev->dev;
526 sock->socket.resource_ops = &pccard_static_ops;
527
528 platform_set_drvdata(pdev, sock);
529
530 ret = db1x_pcmcia_setup_irqs(sock);
531 if (ret) {
532 printk(KERN_ERR "pcmcia%d cannot setup interrupts\n",
533 sock->nr);
534 goto out1;
535 }
536
537 set_stschg(sock, 0);
538
539 ret = pcmcia_register_socket(&sock->socket);
540 if (ret) {
541 printk(KERN_ERR "pcmcia%d failed to register\n", sock->nr);
542 goto out2;
543 }
544
545 printk(KERN_INFO "Alchemy Db/Pb1xxx pcmcia%d @ io/attr/mem %09llx"
546 "(%p) %09llx %09llx card/insert/stschg/eject irqs @ %d "
547 "%d %d %d\n", sock->nr, sock->phys_io, sock->virt_io,
548 sock->phys_attr, sock->phys_mem, sock->card_irq,
549 sock->insert_irq, sock->stschg_irq, sock->eject_irq);
550
551 return 0;
552
553out2:
554 db1x_pcmcia_free_irqs(sock);
555out1:
556 iounmap((void *)(sock->virt_io + (u32)mips_io_port_base));
557out0:
558 kfree(sock);
559 return ret;
560}
561
562static int db1x_pcmcia_socket_remove(struct platform_device *pdev)
563{
564 struct db1x_pcmcia_sock *sock = platform_get_drvdata(pdev);
565
566 db1x_pcmcia_free_irqs(sock);
567 pcmcia_unregister_socket(&sock->socket);
568 iounmap((void *)(sock->virt_io + (u32)mips_io_port_base));
569 kfree(sock);
570
571 return 0;
572}
573
574static struct platform_driver db1x_pcmcia_socket_driver = {
575 .driver = {
576 .name = "db1xxx_pcmcia",
577 },
578 .probe = db1x_pcmcia_socket_probe,
579 .remove = db1x_pcmcia_socket_remove,
580};
581
582module_platform_driver(db1x_pcmcia_socket_driver);
583
584MODULE_LICENSE("GPL");
585MODULE_DESCRIPTION("PCMCIA Socket Services for Alchemy Db/Pb1x00 boards");
586MODULE_AUTHOR("Manuel Lauss");
587