diff options
-rw-r--r-- | drivers/serial/pxa.c | 28 |
1 files changed, 23 insertions, 5 deletions
diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c index 59889f6a86b2..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) |
@@ -635,6 +640,8 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count) | |||
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 |
@@ -752,6 +761,12 @@ static int serial_pxa_probe(struct platform_device *dev) | |||
752 | if (!sport) | 761 | if (!sport) |
753 | return -ENOMEM; | 762 | return -ENOMEM; |
754 | 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 | |||
755 | sport->port.type = PORT_PXA; | 770 | sport->port.type = PORT_PXA; |
756 | sport->port.iotype = UPIO_MEM; | 771 | sport->port.iotype = UPIO_MEM; |
757 | sport->port.mapbase = mmres->start; | 772 | sport->port.mapbase = mmres->start; |
@@ -761,7 +776,7 @@ static int serial_pxa_probe(struct platform_device *dev) | |||
761 | sport->port.line = dev->id; | 776 | sport->port.line = dev->id; |
762 | sport->port.dev = &dev->dev; | 777 | sport->port.dev = &dev->dev; |
763 | sport->port.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF; | 778 | sport->port.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF; |
764 | sport->port.uartclk = 921600 * 16; | 779 | sport->port.uartclk = clk_get_rate(sport->clk); |
765 | 780 | ||
766 | /* | 781 | /* |
767 | * Is it worth keeping this? | 782 | * Is it worth keeping this? |
@@ -780,7 +795,7 @@ static int serial_pxa_probe(struct platform_device *dev) | |||
780 | sport->port.membase = ioremap(mmres->start, mmres->end - mmres->start + 1); | 795 | sport->port.membase = ioremap(mmres->start, mmres->end - mmres->start + 1); |
781 | if (!sport->port.membase) { | 796 | if (!sport->port.membase) { |
782 | ret = -ENOMEM; | 797 | ret = -ENOMEM; |
783 | goto err_free; | 798 | goto err_clk; |
784 | } | 799 | } |
785 | 800 | ||
786 | serial_pxa_ports[dev->id] = sport; | 801 | serial_pxa_ports[dev->id] = sport; |
@@ -790,6 +805,8 @@ static int serial_pxa_probe(struct platform_device *dev) | |||
790 | 805 | ||
791 | return 0; | 806 | return 0; |
792 | 807 | ||
808 | err_clk: | ||
809 | clk_put(sport->clk); | ||
793 | err_free: | 810 | err_free: |
794 | kfree(sport); | 811 | kfree(sport); |
795 | return ret; | 812 | return ret; |
@@ -802,6 +819,7 @@ static int serial_pxa_remove(struct platform_device *dev) | |||
802 | platform_set_drvdata(dev, NULL); | 819 | platform_set_drvdata(dev, NULL); |
803 | 820 | ||
804 | uart_remove_one_port(&serial_pxa_reg, &sport->port); | 821 | uart_remove_one_port(&serial_pxa_reg, &sport->port); |
822 | clk_put(sport->clk); | ||
805 | kfree(sport); | 823 | kfree(sport); |
806 | 824 | ||
807 | return 0; | 825 | return 0; |