diff options
Diffstat (limited to 'drivers/tty/serial/arc_uart.c')
-rw-r--r-- | drivers/tty/serial/arc_uart.c | 106 |
1 files changed, 70 insertions, 36 deletions
diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index 3e0b3fac6a0e..6f7eadc424a3 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c | |||
@@ -37,6 +37,8 @@ | |||
37 | #include <linux/tty_flip.h> | 37 | #include <linux/tty_flip.h> |
38 | #include <linux/serial_core.h> | 38 | #include <linux/serial_core.h> |
39 | #include <linux/io.h> | 39 | #include <linux/io.h> |
40 | #include <linux/of.h> | ||
41 | #include <linux/of_platform.h> | ||
40 | 42 | ||
41 | /************************************* | 43 | /************************************* |
42 | * ARC UART Hardware Specs | 44 | * ARC UART Hardware Specs |
@@ -209,12 +211,8 @@ static void arc_serial_start_tx(struct uart_port *port) | |||
209 | 211 | ||
210 | static void arc_serial_rx_chars(struct arc_uart_port *uart) | 212 | static void arc_serial_rx_chars(struct arc_uart_port *uart) |
211 | { | 213 | { |
212 | struct tty_struct *tty = tty_port_tty_get(&uart->port.state->port); | ||
213 | unsigned int status, ch, flg = 0; | 214 | unsigned int status, ch, flg = 0; |
214 | 215 | ||
215 | if (!tty) | ||
216 | return; | ||
217 | |||
218 | /* | 216 | /* |
219 | * UART has 4 deep RX-FIFO. Driver's recongnition of this fact | 217 | * UART has 4 deep RX-FIFO. Driver's recongnition of this fact |
220 | * is very subtle. Here's how ... | 218 | * is very subtle. Here's how ... |
@@ -250,10 +248,8 @@ static void arc_serial_rx_chars(struct arc_uart_port *uart) | |||
250 | uart_insert_char(&uart->port, status, RXOERR, ch, flg); | 248 | uart_insert_char(&uart->port, status, RXOERR, ch, flg); |
251 | 249 | ||
252 | done: | 250 | done: |
253 | tty_flip_buffer_push(tty); | 251 | tty_flip_buffer_push(&uart->port.state->port); |
254 | } | 252 | } |
255 | |||
256 | tty_kref_put(tty); | ||
257 | } | 253 | } |
258 | 254 | ||
259 | /* | 255 | /* |
@@ -526,18 +522,37 @@ static struct uart_ops arc_serial_pops = { | |||
526 | }; | 522 | }; |
527 | 523 | ||
528 | static int | 524 | static int |
529 | arc_uart_init_one(struct platform_device *pdev, struct arc_uart_port *uart) | 525 | arc_uart_init_one(struct platform_device *pdev, int dev_id) |
530 | { | 526 | { |
531 | struct resource *res, *res2; | 527 | struct resource *res, *res2; |
532 | unsigned long *plat_data; | 528 | unsigned long *plat_data; |
533 | 529 | struct arc_uart_port *uart = &arc_uart_ports[dev_id]; | |
534 | if (pdev->id < 0 || pdev->id >= CONFIG_SERIAL_ARC_NR_PORTS) { | ||
535 | dev_err(&pdev->dev, "Wrong uart platform device id.\n"); | ||
536 | return -ENOENT; | ||
537 | } | ||
538 | 530 | ||
539 | plat_data = ((unsigned long *)(pdev->dev.platform_data)); | 531 | plat_data = ((unsigned long *)(pdev->dev.platform_data)); |
540 | uart->baud = plat_data[0]; | 532 | if (!plat_data) |
533 | return -ENODEV; | ||
534 | |||
535 | uart->is_emulated = !!plat_data[0]; /* workaround ISS bug */ | ||
536 | |||
537 | if (is_early_platform_device(pdev)) { | ||
538 | uart->port.uartclk = plat_data[1]; | ||
539 | uart->baud = plat_data[2]; | ||
540 | } else { | ||
541 | struct device_node *np = pdev->dev.of_node; | ||
542 | u32 val; | ||
543 | |||
544 | if (of_property_read_u32(np, "clock-frequency", &val)) { | ||
545 | dev_err(&pdev->dev, "clock-frequency property NOTset\n"); | ||
546 | return -EINVAL; | ||
547 | } | ||
548 | uart->port.uartclk = val; | ||
549 | |||
550 | if (of_property_read_u32(np, "baud", &val)) { | ||
551 | dev_err(&pdev->dev, "baud property NOT set\n"); | ||
552 | return -EINVAL; | ||
553 | } | ||
554 | uart->baud = val; | ||
555 | } | ||
541 | 556 | ||
542 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 557 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
543 | if (!res) | 558 | if (!res) |
@@ -557,10 +572,9 @@ arc_uart_init_one(struct platform_device *pdev, struct arc_uart_port *uart) | |||
557 | uart->port.dev = &pdev->dev; | 572 | uart->port.dev = &pdev->dev; |
558 | uart->port.iotype = UPIO_MEM; | 573 | uart->port.iotype = UPIO_MEM; |
559 | uart->port.flags = UPF_BOOT_AUTOCONF; | 574 | uart->port.flags = UPF_BOOT_AUTOCONF; |
560 | uart->port.line = pdev->id; | 575 | uart->port.line = dev_id; |
561 | uart->port.ops = &arc_serial_pops; | 576 | uart->port.ops = &arc_serial_pops; |
562 | 577 | ||
563 | uart->port.uartclk = plat_data[1]; | ||
564 | uart->port.fifosize = ARC_UART_TX_FIFO_SIZE; | 578 | uart->port.fifosize = ARC_UART_TX_FIFO_SIZE; |
565 | 579 | ||
566 | /* | 580 | /* |
@@ -569,9 +583,6 @@ arc_uart_init_one(struct platform_device *pdev, struct arc_uart_port *uart) | |||
569 | */ | 583 | */ |
570 | uart->port.ignore_status_mask = 0; | 584 | uart->port.ignore_status_mask = 0; |
571 | 585 | ||
572 | /* Real Hardware vs. emulated to work around a bug */ | ||
573 | uart->is_emulated = !!plat_data[2]; | ||
574 | |||
575 | return 0; | 586 | return 0; |
576 | } | 587 | } |
577 | 588 | ||
@@ -648,45 +659,52 @@ static __init void early_serial_write(struct console *con, const char *s, | |||
648 | } | 659 | } |
649 | } | 660 | } |
650 | 661 | ||
651 | static struct __initdata console arc_early_serial_console = { | 662 | static struct console arc_early_serial_console __initdata = { |
652 | .name = "early_ARCuart", | 663 | .name = "early_ARCuart", |
653 | .write = early_serial_write, | 664 | .write = early_serial_write, |
654 | .flags = CON_PRINTBUFFER | CON_BOOT, | 665 | .flags = CON_PRINTBUFFER | CON_BOOT, |
655 | .index = -1 | 666 | .index = -1 |
656 | }; | 667 | }; |
657 | 668 | ||
658 | static int arc_serial_probe_earlyprintk(struct platform_device *pdev) | 669 | static int __init arc_serial_probe_earlyprintk(struct platform_device *pdev) |
659 | { | 670 | { |
660 | arc_early_serial_console.index = pdev->id; | 671 | int dev_id = pdev->id < 0 ? 0 : pdev->id; |
672 | int rc; | ||
673 | |||
674 | arc_early_serial_console.index = dev_id; | ||
661 | 675 | ||
662 | arc_uart_init_one(pdev, &arc_uart_ports[pdev->id]); | 676 | rc = arc_uart_init_one(pdev, dev_id); |
677 | if (rc) | ||
678 | panic("early console init failed\n"); | ||
663 | 679 | ||
664 | arc_serial_console_setup(&arc_early_serial_console, NULL); | 680 | arc_serial_console_setup(&arc_early_serial_console, NULL); |
665 | 681 | ||
666 | register_console(&arc_early_serial_console); | 682 | register_console(&arc_early_serial_console); |
667 | return 0; | 683 | return 0; |
668 | } | 684 | } |
669 | #else | ||
670 | static int arc_serial_probe_earlyprintk(struct platform_device *pdev) | ||
671 | { | ||
672 | return -ENODEV; | ||
673 | } | ||
674 | #endif /* CONFIG_SERIAL_ARC_CONSOLE */ | 685 | #endif /* CONFIG_SERIAL_ARC_CONSOLE */ |
675 | 686 | ||
676 | static int arc_serial_probe(struct platform_device *pdev) | 687 | static int arc_serial_probe(struct platform_device *pdev) |
677 | { | 688 | { |
678 | struct arc_uart_port *uart; | 689 | int rc, dev_id; |
679 | int rc; | 690 | struct device_node *np = pdev->dev.of_node; |
691 | |||
692 | /* no device tree device */ | ||
693 | if (!np) | ||
694 | return -ENODEV; | ||
680 | 695 | ||
681 | if (is_early_platform_device(pdev)) | 696 | dev_id = of_alias_get_id(np, "serial"); |
682 | return arc_serial_probe_earlyprintk(pdev); | 697 | if (dev_id < 0) { |
698 | dev_err(&pdev->dev, "failed to get alias id: %d\n", dev_id); | ||
699 | return dev_id; | ||
700 | } | ||
683 | 701 | ||
684 | uart = &arc_uart_ports[pdev->id]; | 702 | rc = arc_uart_init_one(pdev, dev_id); |
685 | rc = arc_uart_init_one(pdev, uart); | ||
686 | if (rc) | 703 | if (rc) |
687 | return rc; | 704 | return rc; |
688 | 705 | ||
689 | return uart_add_one_port(&arc_uart_driver, &uart->port); | 706 | rc = uart_add_one_port(&arc_uart_driver, &arc_uart_ports[dev_id].port); |
707 | return rc; | ||
690 | } | 708 | } |
691 | 709 | ||
692 | static int arc_serial_remove(struct platform_device *pdev) | 710 | static int arc_serial_remove(struct platform_device *pdev) |
@@ -695,16 +713,32 @@ static int arc_serial_remove(struct platform_device *pdev) | |||
695 | return 0; | 713 | return 0; |
696 | } | 714 | } |
697 | 715 | ||
716 | static const struct of_device_id arc_uart_dt_ids[] = { | ||
717 | { .compatible = "snps,arc-uart" }, | ||
718 | { /* Sentinel */ } | ||
719 | }; | ||
720 | MODULE_DEVICE_TABLE(of, arc_uart_dt_ids); | ||
721 | |||
698 | static struct platform_driver arc_platform_driver = { | 722 | static struct platform_driver arc_platform_driver = { |
699 | .probe = arc_serial_probe, | 723 | .probe = arc_serial_probe, |
700 | .remove = arc_serial_remove, | 724 | .remove = arc_serial_remove, |
701 | .driver = { | 725 | .driver = { |
702 | .name = DRIVER_NAME, | 726 | .name = DRIVER_NAME, |
703 | .owner = THIS_MODULE, | 727 | .owner = THIS_MODULE, |
728 | .of_match_table = arc_uart_dt_ids, | ||
704 | }, | 729 | }, |
705 | }; | 730 | }; |
706 | 731 | ||
707 | #ifdef CONFIG_SERIAL_ARC_CONSOLE | 732 | #ifdef CONFIG_SERIAL_ARC_CONSOLE |
733 | |||
734 | static struct platform_driver early_arc_platform_driver __initdata = { | ||
735 | .probe = arc_serial_probe_earlyprintk, | ||
736 | .remove = arc_serial_remove, | ||
737 | .driver = { | ||
738 | .name = DRIVER_NAME, | ||
739 | .owner = THIS_MODULE, | ||
740 | }, | ||
741 | }; | ||
708 | /* | 742 | /* |
709 | * Register an early platform driver of "earlyprintk" class. | 743 | * Register an early platform driver of "earlyprintk" class. |
710 | * ARCH platform code installs the driver and probes the early devices | 744 | * ARCH platform code installs the driver and probes the early devices |
@@ -712,7 +746,7 @@ static struct platform_driver arc_platform_driver = { | |||
712 | * or it could be done independently, for all "earlyprintk" class drivers. | 746 | * or it could be done independently, for all "earlyprintk" class drivers. |
713 | * [see arch/arc/plat-arcfpga/platform.c] | 747 | * [see arch/arc/plat-arcfpga/platform.c] |
714 | */ | 748 | */ |
715 | early_platform_init("earlyprintk", &arc_platform_driver); | 749 | early_platform_init("earlyprintk", &early_arc_platform_driver); |
716 | 750 | ||
717 | #endif /* CONFIG_SERIAL_ARC_CONSOLE */ | 751 | #endif /* CONFIG_SERIAL_ARC_CONSOLE */ |
718 | 752 | ||