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 | } |
