aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/serial/pxa.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-15 19:08:50 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-15 19:08:50 -0400
commit65a6ec0d72a07f16719e9b7a96e1c4bae044b591 (patch)
tree344e03a5039a44982c1b78d6113633b21b434820 /drivers/serial/pxa.c
parent541010e4b8921cd781ff02ae68028501457045b6 (diff)
parent0181b61a988424b5cc44fe09e6968142359c815e (diff)
Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm
* 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm: (95 commits) [ARM] 4578/1: CM-x270: PCMCIA support [ARM] 4577/1: ITE 8152 PCI bridge support [ARM] 4576/1: CM-X270 machine support [ARM] pxa: Avoid pxa_gpio_mode() in gpio_direction_{in,out}put() [ARM] pxa: move pxa_set_mode() from pxa2xx_mainstone.c to mainstone.c [ARM] pxa: move pxa_set_mode() from pxa2xx_lubbock.c to lubbock.c [ARM] pxa: Make cpu_is_pxaXXX dependent on configuration symbols [ARM] pxa: PXA3xx base support [NET] smc91x: fix PXA DMA support code [SERIAL] Fix console initialisation ordering [ARM] pxa: tidy up arch/arm/mach-pxa/Makefile [ARM] Update arch/arm/Kconfig for drivers/Kconfig changes [ARM] 4600/1: fix kernel build failure with build-id-supporting binutils [ARM] 4599/1: Preserve ATAG list for use with kexec (2.6.23) [ARM] Rename consistent_sync() as dma_cache_maint() [ARM] 4572/1: ep93xx: add cirrus logic edb9307 support [ARM] 4596/1: S3C2412: Correct IRQs for SDI+CF and add decoding support [ARM] 4595/1: ns9xxx: define registers as void __iomem * instead of volatile u32 [ARM] 4594/1: ns9xxx: use the new gpio functions [ARM] 4593/1: ns9xxx: implement generic clockevents ...
Diffstat (limited to 'drivers/serial/pxa.c')
-rw-r--r--drivers/serial/pxa.c163
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
554static void serial_pxa_release_port(struct uart_port *port) 559static 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
585static struct uart_pxa_port serial_pxa_ports[]; 590static struct uart_pxa_port *serial_pxa_ports[4];
586static struct uart_driver serial_pxa_reg; 591static 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)
632static void 637static void
633serial_pxa_console_write(struct console *co, const char *s, unsigned int count) 638serial_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
654static int __init 663static 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
683static int __init
684serial_pxa_console_init(void)
685{
686 register_console(&serial_pxa_console);
687 return 0;
688}
689
690console_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
717static 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
777static struct uart_driver serial_pxa_reg = { 719static 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
807static int serial_pxa_probe(struct platform_device *dev) 749static 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
815static int serial_pxa_remove(struct platform_device *dev) 815static 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}