diff options
Diffstat (limited to 'drivers/serial/pxa.c')
-rw-r--r-- | drivers/serial/pxa.c | 163 |
1 files changed, 82 insertions, 81 deletions
diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c index e9c6cb391a23..af3a011b2b24 100644 --- a/drivers/serial/pxa.c +++ b/drivers/serial/pxa.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include <linux/tty.h> | 42 | #include <linux/tty.h> |
43 | #include <linux/tty_flip.h> | 43 | #include <linux/tty_flip.h> |
44 | #include <linux/serial_core.h> | 44 | #include <linux/serial_core.h> |
45 | #include <linux/clk.h> | ||
45 | 46 | ||
46 | #include <asm/io.h> | 47 | #include <asm/io.h> |
47 | #include <asm/hardware.h> | 48 | #include <asm/hardware.h> |
@@ -55,7 +56,7 @@ struct uart_pxa_port { | |||
55 | unsigned char lcr; | 56 | unsigned char lcr; |
56 | unsigned char mcr; | 57 | unsigned char mcr; |
57 | unsigned int lsr_break_flag; | 58 | unsigned int lsr_break_flag; |
58 | unsigned int cken; | 59 | struct clk *clk; |
59 | char *name; | 60 | char *name; |
60 | }; | 61 | }; |
61 | 62 | ||
@@ -351,6 +352,8 @@ static int serial_pxa_startup(struct uart_port *port) | |||
351 | else | 352 | else |
352 | up->mcr = 0; | 353 | up->mcr = 0; |
353 | 354 | ||
355 | up->port.uartclk = clk_get_rate(up->clk); | ||
356 | |||
354 | /* | 357 | /* |
355 | * Allocate the IRQ | 358 | * Allocate the IRQ |
356 | */ | 359 | */ |
@@ -546,9 +549,11 @@ serial_pxa_pm(struct uart_port *port, unsigned int state, | |||
546 | unsigned int oldstate) | 549 | unsigned int oldstate) |
547 | { | 550 | { |
548 | struct uart_pxa_port *up = (struct uart_pxa_port *)port; | 551 | struct uart_pxa_port *up = (struct uart_pxa_port *)port; |
549 | pxa_set_cken(up->cken, !state); | 552 | |
550 | if (!state) | 553 | if (!state) |
551 | udelay(1); | 554 | clk_enable(up->clk); |
555 | else | ||
556 | clk_disable(up->clk); | ||
552 | } | 557 | } |
553 | 558 | ||
554 | static void serial_pxa_release_port(struct uart_port *port) | 559 | static void serial_pxa_release_port(struct uart_port *port) |
@@ -582,7 +587,7 @@ serial_pxa_type(struct uart_port *port) | |||
582 | 587 | ||
583 | #ifdef CONFIG_SERIAL_PXA_CONSOLE | 588 | #ifdef CONFIG_SERIAL_PXA_CONSOLE |
584 | 589 | ||
585 | static struct uart_pxa_port serial_pxa_ports[]; | 590 | static struct uart_pxa_port *serial_pxa_ports[4]; |
586 | static struct uart_driver serial_pxa_reg; | 591 | static struct uart_driver serial_pxa_reg; |
587 | 592 | ||
588 | #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) | 593 | #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) |
@@ -632,9 +637,11 @@ static void serial_pxa_console_putchar(struct uart_port *port, int ch) | |||
632 | static void | 637 | static void |
633 | serial_pxa_console_write(struct console *co, const char *s, unsigned int count) | 638 | serial_pxa_console_write(struct console *co, const char *s, unsigned int count) |
634 | { | 639 | { |
635 | struct uart_pxa_port *up = &serial_pxa_ports[co->index]; | 640 | struct uart_pxa_port *up = serial_pxa_ports[co->index]; |
636 | unsigned int ier; | 641 | unsigned int ier; |
637 | 642 | ||
643 | clk_enable(up->clk); | ||
644 | |||
638 | /* | 645 | /* |
639 | * First save the IER then disable the interrupts | 646 | * First save the IER then disable the interrupts |
640 | */ | 647 | */ |
@@ -649,6 +656,8 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count) | |||
649 | */ | 656 | */ |
650 | wait_for_xmitr(up); | 657 | wait_for_xmitr(up); |
651 | serial_out(up, UART_IER, ier); | 658 | serial_out(up, UART_IER, ier); |
659 | |||
660 | clk_disable(up->clk); | ||
652 | } | 661 | } |
653 | 662 | ||
654 | static int __init | 663 | static int __init |
@@ -662,7 +671,9 @@ serial_pxa_console_setup(struct console *co, char *options) | |||
662 | 671 | ||
663 | if (co->index == -1 || co->index >= serial_pxa_reg.nr) | 672 | if (co->index == -1 || co->index >= serial_pxa_reg.nr) |
664 | co->index = 0; | 673 | co->index = 0; |
665 | up = &serial_pxa_ports[co->index]; | 674 | up = serial_pxa_ports[co->index]; |
675 | if (!up) | ||
676 | return -ENODEV; | ||
666 | 677 | ||
667 | if (options) | 678 | if (options) |
668 | uart_parse_options(options, &baud, &parity, &bits, &flow); | 679 | uart_parse_options(options, &baud, &parity, &bits, &flow); |
@@ -680,15 +691,6 @@ static struct console serial_pxa_console = { | |||
680 | .data = &serial_pxa_reg, | 691 | .data = &serial_pxa_reg, |
681 | }; | 692 | }; |
682 | 693 | ||
683 | static int __init | ||
684 | serial_pxa_console_init(void) | ||
685 | { | ||
686 | register_console(&serial_pxa_console); | ||
687 | return 0; | ||
688 | } | ||
689 | |||
690 | console_initcall(serial_pxa_console_init); | ||
691 | |||
692 | #define PXA_CONSOLE &serial_pxa_console | 694 | #define PXA_CONSOLE &serial_pxa_console |
693 | #else | 695 | #else |
694 | #define PXA_CONSOLE NULL | 696 | #define PXA_CONSOLE NULL |
@@ -714,73 +716,13 @@ struct uart_ops serial_pxa_pops = { | |||
714 | .verify_port = serial_pxa_verify_port, | 716 | .verify_port = serial_pxa_verify_port, |
715 | }; | 717 | }; |
716 | 718 | ||
717 | static struct uart_pxa_port serial_pxa_ports[] = { | ||
718 | { /* FFUART */ | ||
719 | .name = "FFUART", | ||
720 | .cken = CKEN_FFUART, | ||
721 | .port = { | ||
722 | .type = PORT_PXA, | ||
723 | .iotype = UPIO_MEM, | ||
724 | .membase = (void *)&FFUART, | ||
725 | .mapbase = __PREG(FFUART), | ||
726 | .irq = IRQ_FFUART, | ||
727 | .uartclk = 921600 * 16, | ||
728 | .fifosize = 64, | ||
729 | .ops = &serial_pxa_pops, | ||
730 | .line = 0, | ||
731 | }, | ||
732 | }, { /* BTUART */ | ||
733 | .name = "BTUART", | ||
734 | .cken = CKEN_BTUART, | ||
735 | .port = { | ||
736 | .type = PORT_PXA, | ||
737 | .iotype = UPIO_MEM, | ||
738 | .membase = (void *)&BTUART, | ||
739 | .mapbase = __PREG(BTUART), | ||
740 | .irq = IRQ_BTUART, | ||
741 | .uartclk = 921600 * 16, | ||
742 | .fifosize = 64, | ||
743 | .ops = &serial_pxa_pops, | ||
744 | .line = 1, | ||
745 | }, | ||
746 | }, { /* STUART */ | ||
747 | .name = "STUART", | ||
748 | .cken = CKEN_STUART, | ||
749 | .port = { | ||
750 | .type = PORT_PXA, | ||
751 | .iotype = UPIO_MEM, | ||
752 | .membase = (void *)&STUART, | ||
753 | .mapbase = __PREG(STUART), | ||
754 | .irq = IRQ_STUART, | ||
755 | .uartclk = 921600 * 16, | ||
756 | .fifosize = 64, | ||
757 | .ops = &serial_pxa_pops, | ||
758 | .line = 2, | ||
759 | }, | ||
760 | }, { /* HWUART */ | ||
761 | .name = "HWUART", | ||
762 | .cken = CKEN_HWUART, | ||
763 | .port = { | ||
764 | .type = PORT_PXA, | ||
765 | .iotype = UPIO_MEM, | ||
766 | .membase = (void *)&HWUART, | ||
767 | .mapbase = __PREG(HWUART), | ||
768 | .irq = IRQ_HWUART, | ||
769 | .uartclk = 921600 * 16, | ||
770 | .fifosize = 64, | ||
771 | .ops = &serial_pxa_pops, | ||
772 | .line = 3, | ||
773 | }, | ||
774 | } | ||
775 | }; | ||
776 | |||
777 | static struct uart_driver serial_pxa_reg = { | 719 | static struct uart_driver serial_pxa_reg = { |
778 | .owner = THIS_MODULE, | 720 | .owner = THIS_MODULE, |
779 | .driver_name = "PXA serial", | 721 | .driver_name = "PXA serial", |
780 | .dev_name = "ttyS", | 722 | .dev_name = "ttyS", |
781 | .major = TTY_MAJOR, | 723 | .major = TTY_MAJOR, |
782 | .minor = 64, | 724 | .minor = 64, |
783 | .nr = ARRAY_SIZE(serial_pxa_ports), | 725 | .nr = 4, |
784 | .cons = PXA_CONSOLE, | 726 | .cons = PXA_CONSOLE, |
785 | }; | 727 | }; |
786 | 728 | ||
@@ -806,10 +748,68 @@ static int serial_pxa_resume(struct platform_device *dev) | |||
806 | 748 | ||
807 | static int serial_pxa_probe(struct platform_device *dev) | 749 | static int serial_pxa_probe(struct platform_device *dev) |
808 | { | 750 | { |
809 | serial_pxa_ports[dev->id].port.dev = &dev->dev; | 751 | struct uart_pxa_port *sport; |
810 | uart_add_one_port(&serial_pxa_reg, &serial_pxa_ports[dev->id].port); | 752 | struct resource *mmres, *irqres; |
811 | platform_set_drvdata(dev, &serial_pxa_ports[dev->id]); | 753 | int ret; |
754 | |||
755 | mmres = platform_get_resource(dev, IORESOURCE_MEM, 0); | ||
756 | irqres = platform_get_resource(dev, IORESOURCE_IRQ, 0); | ||
757 | if (!mmres || !irqres) | ||
758 | return -ENODEV; | ||
759 | |||
760 | sport = kzalloc(sizeof(struct uart_pxa_port), GFP_KERNEL); | ||
761 | if (!sport) | ||
762 | return -ENOMEM; | ||
763 | |||
764 | sport->clk = clk_get(&dev->dev, "UARTCLK"); | ||
765 | if (IS_ERR(sport->clk)) { | ||
766 | ret = PTR_ERR(sport->clk); | ||
767 | goto err_free; | ||
768 | } | ||
769 | |||
770 | sport->port.type = PORT_PXA; | ||
771 | sport->port.iotype = UPIO_MEM; | ||
772 | sport->port.mapbase = mmres->start; | ||
773 | sport->port.irq = irqres->start; | ||
774 | sport->port.fifosize = 64; | ||
775 | sport->port.ops = &serial_pxa_pops; | ||
776 | sport->port.line = dev->id; | ||
777 | sport->port.dev = &dev->dev; | ||
778 | sport->port.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF; | ||
779 | sport->port.uartclk = clk_get_rate(sport->clk); | ||
780 | |||
781 | /* | ||
782 | * Is it worth keeping this? | ||
783 | */ | ||
784 | if (mmres->start == __PREG(FFUART)) | ||
785 | sport->name = "FFUART"; | ||
786 | else if (mmres->start == __PREG(BTUART)) | ||
787 | sport->name = "BTUART"; | ||
788 | else if (mmres->start == __PREG(STUART)) | ||
789 | sport->name = "STUART"; | ||
790 | else if (mmres->start == __PREG(HWUART)) | ||
791 | sport->name = "HWUART"; | ||
792 | else | ||
793 | sport->name = "???"; | ||
794 | |||
795 | sport->port.membase = ioremap(mmres->start, mmres->end - mmres->start + 1); | ||
796 | if (!sport->port.membase) { | ||
797 | ret = -ENOMEM; | ||
798 | goto err_clk; | ||
799 | } | ||
800 | |||
801 | serial_pxa_ports[dev->id] = sport; | ||
802 | |||
803 | uart_add_one_port(&serial_pxa_reg, &sport->port); | ||
804 | platform_set_drvdata(dev, sport); | ||
805 | |||
812 | return 0; | 806 | return 0; |
807 | |||
808 | err_clk: | ||
809 | clk_put(sport->clk); | ||
810 | err_free: | ||
811 | kfree(sport); | ||
812 | return ret; | ||
813 | } | 813 | } |
814 | 814 | ||
815 | static int serial_pxa_remove(struct platform_device *dev) | 815 | static int serial_pxa_remove(struct platform_device *dev) |
@@ -818,8 +818,9 @@ static int serial_pxa_remove(struct platform_device *dev) | |||
818 | 818 | ||
819 | platform_set_drvdata(dev, NULL); | 819 | platform_set_drvdata(dev, NULL); |
820 | 820 | ||
821 | if (sport) | 821 | uart_remove_one_port(&serial_pxa_reg, &sport->port); |
822 | uart_remove_one_port(&serial_pxa_reg, &sport->port); | 822 | clk_put(sport->clk); |
823 | kfree(sport); | ||
823 | 824 | ||
824 | return 0; | 825 | return 0; |
825 | } | 826 | } |