diff options
Diffstat (limited to 'drivers/serial/uartlite.c')
-rw-r--r-- | drivers/serial/uartlite.c | 286 |
1 files changed, 239 insertions, 47 deletions
diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index f5051cf1a0c8..dfef83f14960 100644 --- a/drivers/serial/uartlite.c +++ b/drivers/serial/uartlite.c | |||
@@ -1,7 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * uartlite.c: Serial driver for Xilinx uartlite serial controller | 2 | * uartlite.c: Serial driver for Xilinx uartlite serial controller |
3 | * | 3 | * |
4 | * Peter Korsgaard <jacmet@sunsite.dk> | 4 | * Copyright (C) 2006 Peter Korsgaard <jacmet@sunsite.dk> |
5 | * Copyright (C) 2007 Secret Lab Technologies Ltd. | ||
5 | * | 6 | * |
6 | * This file is licensed under the terms of the GNU General Public License | 7 | * This file is licensed under the terms of the GNU General Public License |
7 | * version 2. This program is licensed "as is" without any warranty of any | 8 | * version 2. This program is licensed "as is" without any warranty of any |
@@ -17,14 +18,23 @@ | |||
17 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
18 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
19 | #include <asm/io.h> | 20 | #include <asm/io.h> |
21 | #if defined(CONFIG_OF) | ||
22 | #include <linux/of_device.h> | ||
23 | #include <linux/of_platform.h> | ||
24 | #endif | ||
20 | 25 | ||
26 | #define ULITE_NAME "ttyUL" | ||
21 | #define ULITE_MAJOR 204 | 27 | #define ULITE_MAJOR 204 |
22 | #define ULITE_MINOR 187 | 28 | #define ULITE_MINOR 187 |
23 | #define ULITE_NR_UARTS 4 | 29 | #define ULITE_NR_UARTS 4 |
24 | 30 | ||
25 | /* For register details see datasheet: | 31 | /* --------------------------------------------------------------------- |
26 | http://www.xilinx.com/bvdocs/ipcenter/data_sheet/opb_uartlite.pdf | 32 | * Register definitions |
27 | */ | 33 | * |
34 | * For register details see datasheet: | ||
35 | * http://www.xilinx.com/bvdocs/ipcenter/data_sheet/opb_uartlite.pdf | ||
36 | */ | ||
37 | |||
28 | #define ULITE_RX 0x00 | 38 | #define ULITE_RX 0x00 |
29 | #define ULITE_TX 0x04 | 39 | #define ULITE_TX 0x04 |
30 | #define ULITE_STATUS 0x08 | 40 | #define ULITE_STATUS 0x08 |
@@ -46,7 +56,11 @@ | |||
46 | #define ULITE_CONTROL_IE 0x10 | 56 | #define ULITE_CONTROL_IE 0x10 |
47 | 57 | ||
48 | 58 | ||
49 | static struct uart_port ports[ULITE_NR_UARTS]; | 59 | static struct uart_port ulite_ports[ULITE_NR_UARTS]; |
60 | |||
61 | /* --------------------------------------------------------------------- | ||
62 | * Core UART driver operations | ||
63 | */ | ||
50 | 64 | ||
51 | static int ulite_receive(struct uart_port *port, int stat) | 65 | static int ulite_receive(struct uart_port *port, int stat) |
52 | { | 66 | { |
@@ -307,6 +321,10 @@ static struct uart_ops ulite_ops = { | |||
307 | .verify_port = ulite_verify_port | 321 | .verify_port = ulite_verify_port |
308 | }; | 322 | }; |
309 | 323 | ||
324 | /* --------------------------------------------------------------------- | ||
325 | * Console driver operations | ||
326 | */ | ||
327 | |||
310 | #ifdef CONFIG_SERIAL_UARTLITE_CONSOLE | 328 | #ifdef CONFIG_SERIAL_UARTLITE_CONSOLE |
311 | static void ulite_console_wait_tx(struct uart_port *port) | 329 | static void ulite_console_wait_tx(struct uart_port *port) |
312 | { | 330 | { |
@@ -329,7 +347,7 @@ static void ulite_console_putchar(struct uart_port *port, int ch) | |||
329 | static void ulite_console_write(struct console *co, const char *s, | 347 | static void ulite_console_write(struct console *co, const char *s, |
330 | unsigned int count) | 348 | unsigned int count) |
331 | { | 349 | { |
332 | struct uart_port *port = &ports[co->index]; | 350 | struct uart_port *port = &ulite_ports[co->index]; |
333 | unsigned long flags; | 351 | unsigned long flags; |
334 | unsigned int ier; | 352 | unsigned int ier; |
335 | int locked = 1; | 353 | int locked = 1; |
@@ -355,6 +373,31 @@ static void ulite_console_write(struct console *co, const char *s, | |||
355 | spin_unlock_irqrestore(&port->lock, flags); | 373 | spin_unlock_irqrestore(&port->lock, flags); |
356 | } | 374 | } |
357 | 375 | ||
376 | #if defined(CONFIG_OF) | ||
377 | static inline void __init ulite_console_of_find_device(int id) | ||
378 | { | ||
379 | struct device_node *np; | ||
380 | struct resource res; | ||
381 | const unsigned int *of_id; | ||
382 | int rc; | ||
383 | |||
384 | for_each_compatible_node(np, NULL, "xilinx,uartlite") { | ||
385 | of_id = of_get_property(np, "port-number", NULL); | ||
386 | if ((!of_id) || (*of_id != id)) | ||
387 | continue; | ||
388 | |||
389 | rc = of_address_to_resource(np, 0, &res); | ||
390 | if (rc) | ||
391 | continue; | ||
392 | |||
393 | ulite_ports[id].mapbase = res.start; | ||
394 | return; | ||
395 | } | ||
396 | } | ||
397 | #else /* CONFIG_OF */ | ||
398 | static inline void __init ulite_console_of_find_device(int id) { /* do nothing */ } | ||
399 | #endif /* CONFIG_OF */ | ||
400 | |||
358 | static int __init ulite_console_setup(struct console *co, char *options) | 401 | static int __init ulite_console_setup(struct console *co, char *options) |
359 | { | 402 | { |
360 | struct uart_port *port; | 403 | struct uart_port *port; |
@@ -366,11 +409,23 @@ static int __init ulite_console_setup(struct console *co, char *options) | |||
366 | if (co->index < 0 || co->index >= ULITE_NR_UARTS) | 409 | if (co->index < 0 || co->index >= ULITE_NR_UARTS) |
367 | return -EINVAL; | 410 | return -EINVAL; |
368 | 411 | ||
369 | port = &ports[co->index]; | 412 | port = &ulite_ports[co->index]; |
370 | 413 | ||
371 | /* not initialized yet? */ | 414 | /* Check if it is an OF device */ |
372 | if (!port->membase) | 415 | if (!port->mapbase) |
416 | ulite_console_of_find_device(co->index); | ||
417 | |||
418 | /* Do we have a device now? */ | ||
419 | if (!port->mapbase) { | ||
420 | pr_debug("console on ttyUL%i not present\n", co->index); | ||
373 | return -ENODEV; | 421 | return -ENODEV; |
422 | } | ||
423 | |||
424 | /* not initialized yet? */ | ||
425 | if (!port->membase) { | ||
426 | if (ulite_request_port(port)) | ||
427 | return -ENODEV; | ||
428 | } | ||
374 | 429 | ||
375 | if (options) | 430 | if (options) |
376 | uart_parse_options(options, &baud, &parity, &bits, &flow); | 431 | uart_parse_options(options, &baud, &parity, &bits, &flow); |
@@ -381,7 +436,7 @@ static int __init ulite_console_setup(struct console *co, char *options) | |||
381 | static struct uart_driver ulite_uart_driver; | 436 | static struct uart_driver ulite_uart_driver; |
382 | 437 | ||
383 | static struct console ulite_console = { | 438 | static struct console ulite_console = { |
384 | .name = "ttyUL", | 439 | .name = ULITE_NAME, |
385 | .write = ulite_console_write, | 440 | .write = ulite_console_write, |
386 | .device = uart_console_device, | 441 | .device = uart_console_device, |
387 | .setup = ulite_console_setup, | 442 | .setup = ulite_console_setup, |
@@ -403,7 +458,7 @@ console_initcall(ulite_console_init); | |||
403 | static struct uart_driver ulite_uart_driver = { | 458 | static struct uart_driver ulite_uart_driver = { |
404 | .owner = THIS_MODULE, | 459 | .owner = THIS_MODULE, |
405 | .driver_name = "uartlite", | 460 | .driver_name = "uartlite", |
406 | .dev_name = "ttyUL", | 461 | .dev_name = ULITE_NAME, |
407 | .major = ULITE_MAJOR, | 462 | .major = ULITE_MAJOR, |
408 | .minor = ULITE_MINOR, | 463 | .minor = ULITE_MINOR, |
409 | .nr = ULITE_NR_UARTS, | 464 | .nr = ULITE_NR_UARTS, |
@@ -412,59 +467,111 @@ static struct uart_driver ulite_uart_driver = { | |||
412 | #endif | 467 | #endif |
413 | }; | 468 | }; |
414 | 469 | ||
415 | static int __devinit ulite_probe(struct platform_device *pdev) | 470 | /* --------------------------------------------------------------------- |
471 | * Port assignment functions (mapping devices to uart_port structures) | ||
472 | */ | ||
473 | |||
474 | /** ulite_assign: register a uartlite device with the driver | ||
475 | * | ||
476 | * @dev: pointer to device structure | ||
477 | * @id: requested id number. Pass -1 for automatic port assignment | ||
478 | * @base: base address of uartlite registers | ||
479 | * @irq: irq number for uartlite | ||
480 | * | ||
481 | * Returns: 0 on success, <0 otherwise | ||
482 | */ | ||
483 | static int __devinit ulite_assign(struct device *dev, int id, u32 base, int irq) | ||
416 | { | 484 | { |
417 | struct resource *res, *res2; | ||
418 | struct uart_port *port; | 485 | struct uart_port *port; |
486 | int rc; | ||
419 | 487 | ||
420 | if (pdev->id < 0 || pdev->id >= ULITE_NR_UARTS) | 488 | /* if id = -1; then scan for a free id and use that */ |
489 | if (id < 0) { | ||
490 | for (id = 0; id < ULITE_NR_UARTS; id++) | ||
491 | if (ulite_ports[id].mapbase == 0) | ||
492 | break; | ||
493 | } | ||
494 | if (id < 0 || id >= ULITE_NR_UARTS) { | ||
495 | dev_err(dev, "%s%i too large\n", ULITE_NAME, id); | ||
421 | return -EINVAL; | 496 | return -EINVAL; |
497 | } | ||
422 | 498 | ||
423 | if (ports[pdev->id].membase) | 499 | if ((ulite_ports[id].mapbase) && (ulite_ports[id].mapbase != base)) { |
500 | dev_err(dev, "cannot assign to %s%i; it is already in use\n", | ||
501 | ULITE_NAME, id); | ||
424 | return -EBUSY; | 502 | return -EBUSY; |
503 | } | ||
425 | 504 | ||
426 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 505 | port = &ulite_ports[id]; |
427 | if (!res) | ||
428 | return -ENODEV; | ||
429 | 506 | ||
430 | res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 507 | spin_lock_init(&port->lock); |
431 | if (!res2) | 508 | port->fifosize = 16; |
432 | return -ENODEV; | 509 | port->regshift = 2; |
510 | port->iotype = UPIO_MEM; | ||
511 | port->iobase = 1; /* mark port in use */ | ||
512 | port->mapbase = base; | ||
513 | port->membase = NULL; | ||
514 | port->ops = &ulite_ops; | ||
515 | port->irq = irq; | ||
516 | port->flags = UPF_BOOT_AUTOCONF; | ||
517 | port->dev = dev; | ||
518 | port->type = PORT_UNKNOWN; | ||
519 | port->line = id; | ||
520 | |||
521 | dev_set_drvdata(dev, port); | ||
522 | |||
523 | /* Register the port */ | ||
524 | rc = uart_add_one_port(&ulite_uart_driver, port); | ||
525 | if (rc) { | ||
526 | dev_err(dev, "uart_add_one_port() failed; err=%i\n", rc); | ||
527 | port->mapbase = 0; | ||
528 | dev_set_drvdata(dev, NULL); | ||
529 | return rc; | ||
530 | } | ||
433 | 531 | ||
434 | port = &ports[pdev->id]; | 532 | return 0; |
533 | } | ||
435 | 534 | ||
436 | port->fifosize = 16; | 535 | /** ulite_release: register a uartlite device with the driver |
437 | port->regshift = 2; | 536 | * |
438 | port->iotype = UPIO_MEM; | 537 | * @dev: pointer to device structure |
439 | port->iobase = 1; /* mark port in use */ | 538 | */ |
440 | port->mapbase = res->start; | 539 | static int __devinit ulite_release(struct device *dev) |
441 | port->membase = NULL; | 540 | { |
442 | port->ops = &ulite_ops; | 541 | struct uart_port *port = dev_get_drvdata(dev); |
443 | port->irq = res2->start; | 542 | int rc = 0; |
444 | port->flags = UPF_BOOT_AUTOCONF; | ||
445 | port->dev = &pdev->dev; | ||
446 | port->type = PORT_UNKNOWN; | ||
447 | port->line = pdev->id; | ||
448 | 543 | ||
449 | uart_add_one_port(&ulite_uart_driver, port); | 544 | if (port) { |
450 | platform_set_drvdata(pdev, port); | 545 | rc = uart_remove_one_port(&ulite_uart_driver, port); |
546 | dev_set_drvdata(dev, NULL); | ||
547 | port->mapbase = 0; | ||
548 | } | ||
451 | 549 | ||
452 | return 0; | 550 | return rc; |
453 | } | 551 | } |
454 | 552 | ||
455 | static int ulite_remove(struct platform_device *pdev) | 553 | /* --------------------------------------------------------------------- |
554 | * Platform bus binding | ||
555 | */ | ||
556 | |||
557 | static int __devinit ulite_probe(struct platform_device *pdev) | ||
456 | { | 558 | { |
457 | struct uart_port *port = platform_get_drvdata(pdev); | 559 | struct resource *res, *res2; |
458 | 560 | ||
459 | platform_set_drvdata(pdev, NULL); | 561 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
562 | if (!res) | ||
563 | return -ENODEV; | ||
460 | 564 | ||
461 | if (port) | 565 | res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
462 | uart_remove_one_port(&ulite_uart_driver, port); | 566 | if (!res2) |
567 | return -ENODEV; | ||
463 | 568 | ||
464 | /* mark port as free */ | 569 | return ulite_assign(&pdev->dev, pdev->id, res->start, res2->start); |
465 | port->membase = NULL; | 570 | } |
466 | 571 | ||
467 | return 0; | 572 | static int ulite_remove(struct platform_device *pdev) |
573 | { | ||
574 | return ulite_release(&pdev->dev); | ||
468 | } | 575 | } |
469 | 576 | ||
470 | static struct platform_driver ulite_platform_driver = { | 577 | static struct platform_driver ulite_platform_driver = { |
@@ -476,24 +583,109 @@ static struct platform_driver ulite_platform_driver = { | |||
476 | }, | 583 | }, |
477 | }; | 584 | }; |
478 | 585 | ||
586 | /* --------------------------------------------------------------------- | ||
587 | * OF bus bindings | ||
588 | */ | ||
589 | #if defined(CONFIG_OF) | ||
590 | static int __devinit | ||
591 | ulite_of_probe(struct of_device *op, const struct of_device_id *match) | ||
592 | { | ||
593 | struct resource res; | ||
594 | const unsigned int *id; | ||
595 | int irq, rc; | ||
596 | |||
597 | dev_dbg(&op->dev, "%s(%p, %p)\n", __FUNCTION__, op, match); | ||
598 | |||
599 | rc = of_address_to_resource(op->node, 0, &res); | ||
600 | if (rc) { | ||
601 | dev_err(&op->dev, "invalid address\n"); | ||
602 | return rc; | ||
603 | } | ||
604 | |||
605 | irq = irq_of_parse_and_map(op->node, 0); | ||
606 | |||
607 | id = of_get_property(op->node, "port-number", NULL); | ||
608 | |||
609 | return ulite_assign(&op->dev, id ? *id : -1, res.start+3, irq); | ||
610 | } | ||
611 | |||
612 | static int __devexit ulite_of_remove(struct of_device *op) | ||
613 | { | ||
614 | return ulite_release(&op->dev); | ||
615 | } | ||
616 | |||
617 | /* Match table for of_platform binding */ | ||
618 | static struct of_device_id __devinit ulite_of_match[] = { | ||
619 | { .type = "serial", .compatible = "xilinx,uartlite", }, | ||
620 | {}, | ||
621 | }; | ||
622 | MODULE_DEVICE_TABLE(of, ulite_of_match); | ||
623 | |||
624 | static struct of_platform_driver ulite_of_driver = { | ||
625 | .owner = THIS_MODULE, | ||
626 | .name = "uartlite", | ||
627 | .match_table = ulite_of_match, | ||
628 | .probe = ulite_of_probe, | ||
629 | .remove = __devexit_p(ulite_of_remove), | ||
630 | .driver = { | ||
631 | .name = "uartlite", | ||
632 | }, | ||
633 | }; | ||
634 | |||
635 | /* Registration helpers to keep the number of #ifdefs to a minimum */ | ||
636 | static inline int __init ulite_of_register(void) | ||
637 | { | ||
638 | pr_debug("uartlite: calling of_register_platform_driver()\n"); | ||
639 | return of_register_platform_driver(&ulite_of_driver); | ||
640 | } | ||
641 | |||
642 | static inline void __exit ulite_of_unregister(void) | ||
643 | { | ||
644 | of_unregister_platform_driver(&ulite_of_driver); | ||
645 | } | ||
646 | #else /* CONFIG_OF */ | ||
647 | /* CONFIG_OF not enabled; do nothing helpers */ | ||
648 | static inline int __init ulite_of_register(void) { return 0; } | ||
649 | static inline void __exit ulite_of_unregister(void) { } | ||
650 | #endif /* CONFIG_OF */ | ||
651 | |||
652 | /* --------------------------------------------------------------------- | ||
653 | * Module setup/teardown | ||
654 | */ | ||
655 | |||
479 | int __init ulite_init(void) | 656 | int __init ulite_init(void) |
480 | { | 657 | { |
481 | int ret; | 658 | int ret; |
482 | 659 | ||
660 | pr_debug("uartlite: calling uart_register_driver()\n"); | ||
483 | ret = uart_register_driver(&ulite_uart_driver); | 661 | ret = uart_register_driver(&ulite_uart_driver); |
484 | if (ret) | 662 | if (ret) |
485 | return ret; | 663 | goto err_uart; |
486 | 664 | ||
665 | ret = ulite_of_register(); | ||
666 | if (ret) | ||
667 | goto err_of; | ||
668 | |||
669 | pr_debug("uartlite: calling platform_driver_register()\n"); | ||
487 | ret = platform_driver_register(&ulite_platform_driver); | 670 | ret = platform_driver_register(&ulite_platform_driver); |
488 | if (ret) | 671 | if (ret) |
489 | uart_unregister_driver(&ulite_uart_driver); | 672 | goto err_plat; |
490 | 673 | ||
674 | return 0; | ||
675 | |||
676 | err_plat: | ||
677 | ulite_of_unregister(); | ||
678 | err_of: | ||
679 | uart_unregister_driver(&ulite_uart_driver); | ||
680 | err_uart: | ||
681 | printk(KERN_ERR "registering uartlite driver failed: err=%i", ret); | ||
491 | return ret; | 682 | return ret; |
492 | } | 683 | } |
493 | 684 | ||
494 | void __exit ulite_exit(void) | 685 | void __exit ulite_exit(void) |
495 | { | 686 | { |
496 | platform_driver_unregister(&ulite_platform_driver); | 687 | platform_driver_unregister(&ulite_platform_driver); |
688 | ulite_of_unregister(); | ||
497 | uart_unregister_driver(&ulite_uart_driver); | 689 | uart_unregister_driver(&ulite_uart_driver); |
498 | } | 690 | } |
499 | 691 | ||