diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2008-07-05 04:02:44 -0400 |
---|---|---|
committer | Robert Schwebel <r.schwebel@pengutronix.de> | 2008-07-05 04:02:44 -0400 |
commit | 036bb15ec94216e28cb1550af0fdcdfb90c549df (patch) | |
tree | 320dd6c0fdc59813f70090190020599304baff96 /drivers/serial | |
parent | 63dd10846d4917534e9ec7bddf43be786effe8b8 (diff) |
IMX UART: do not assume 16MHz reference frequency
We assumed a 16MHz reference frequency for the UART. While this
is true for i.MX1 most of the time it is not true for MX27/MX31.
Also, add handling for the ONEMS register which is present on
newer versions of the chip and pass a sane minimum baudrate to
uart_get_baud_rate().
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers/serial')
-rw-r--r-- | drivers/serial/imx.c | 50 |
1 files changed, 39 insertions, 11 deletions
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 5a375bf0ebf4..6226e66c7966 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c | |||
@@ -589,6 +589,7 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, | |||
589 | unsigned long flags; | 589 | unsigned long flags; |
590 | unsigned int ucr2, old_ucr1, old_txrxen, baud, quot; | 590 | unsigned int ucr2, old_ucr1, old_txrxen, baud, quot; |
591 | unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; | 591 | unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; |
592 | unsigned int div, num, denom, ufcr; | ||
592 | 593 | ||
593 | /* | 594 | /* |
594 | * If we don't support modem control lines, don't allow | 595 | * If we don't support modem control lines, don't allow |
@@ -634,7 +635,7 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, | |||
634 | /* | 635 | /* |
635 | * Ask the core to calculate the divisor for us. | 636 | * Ask the core to calculate the divisor for us. |
636 | */ | 637 | */ |
637 | baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); | 638 | baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16); |
638 | quot = uart_get_divisor(port, baud); | 639 | quot = uart_get_divisor(port, baud); |
639 | 640 | ||
640 | spin_lock_irqsave(&sport->port.lock, flags); | 641 | spin_lock_irqsave(&sport->port.lock, flags); |
@@ -684,14 +685,41 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, | |||
684 | sport->port.membase + UCR2); | 685 | sport->port.membase + UCR2); |
685 | old_txrxen &= (UCR2_TXEN | UCR2_RXEN); | 686 | old_txrxen &= (UCR2_TXEN | UCR2_RXEN); |
686 | 687 | ||
687 | /* set the baud rate. We assume uartclk = 16 MHz | 688 | div = sport->port.uartclk / (baud * 16); |
688 | * | 689 | if (div > 7) |
689 | * baud * 16 UBIR - 1 | 690 | div = 7; |
690 | * --------- = -------- | 691 | if (!div) |
691 | * uartclk UBMR - 1 | 692 | div = 1; |
692 | */ | 693 | |
693 | writel((baud / 100) - 1, sport->port.membase + UBIR); | 694 | num = baud; |
694 | writel(10000 - 1, sport->port.membase + UBMR); | 695 | denom = port->uartclk / div / 16; |
696 | |||
697 | /* shift num and denom right until they fit into 16 bits */ | ||
698 | while (num > 0x10000 || denom > 0x10000) { | ||
699 | num >>= 1; | ||
700 | denom >>= 1; | ||
701 | } | ||
702 | if (num > 0) | ||
703 | num -= 1; | ||
704 | if (denom > 0) | ||
705 | denom -= 1; | ||
706 | |||
707 | writel(num, sport->port.membase + UBIR); | ||
708 | writel(denom, sport->port.membase + UBMR); | ||
709 | |||
710 | if (div == 7) | ||
711 | div = 6; /* 6 in RFDIV means divide by 7 */ | ||
712 | else | ||
713 | div = 6 - div; | ||
714 | |||
715 | ufcr = readl(sport->port.membase + UFCR); | ||
716 | ufcr = (ufcr & (~UFCR_RFDIV)) | | ||
717 | (div << 7); | ||
718 | writel(ufcr, sport->port.membase + UFCR); | ||
719 | |||
720 | #ifdef ONEMS | ||
721 | writel(sport->port.uartclk / div / 1000, sport->port.membase + ONEMS); | ||
722 | #endif | ||
695 | 723 | ||
696 | writel(old_ucr1, sport->port.membase + UCR1); | 724 | writel(old_ucr1, sport->port.membase + UCR1); |
697 | 725 | ||
@@ -812,7 +840,6 @@ static struct imx_port imx_ports[] = { | |||
812 | .membase = (void *)IMX_UART1_BASE, | 840 | .membase = (void *)IMX_UART1_BASE, |
813 | .mapbase = 0x00206000, | 841 | .mapbase = 0x00206000, |
814 | .irq = UART1_MINT_RX, | 842 | .irq = UART1_MINT_RX, |
815 | .uartclk = 16000000, | ||
816 | .fifosize = 32, | 843 | .fifosize = 32, |
817 | .flags = UPF_BOOT_AUTOCONF, | 844 | .flags = UPF_BOOT_AUTOCONF, |
818 | .ops = &imx_pops, | 845 | .ops = &imx_pops, |
@@ -828,7 +855,6 @@ static struct imx_port imx_ports[] = { | |||
828 | .membase = (void *)IMX_UART2_BASE, | 855 | .membase = (void *)IMX_UART2_BASE, |
829 | .mapbase = 0x00207000, | 856 | .mapbase = 0x00207000, |
830 | .irq = UART2_MINT_RX, | 857 | .irq = UART2_MINT_RX, |
831 | .uartclk = 16000000, | ||
832 | .fifosize = 32, | 858 | .fifosize = 32, |
833 | .flags = UPF_BOOT_AUTOCONF, | 859 | .flags = UPF_BOOT_AUTOCONF, |
834 | .ops = &imx_pops, | 860 | .ops = &imx_pops, |
@@ -858,6 +884,8 @@ static void __init imx_init_ports(void) | |||
858 | init_timer(&imx_ports[i].timer); | 884 | init_timer(&imx_ports[i].timer); |
859 | imx_ports[i].timer.function = imx_timeout; | 885 | imx_ports[i].timer.function = imx_timeout; |
860 | imx_ports[i].timer.data = (unsigned long)&imx_ports[i]; | 886 | imx_ports[i].timer.data = (unsigned long)&imx_ports[i]; |
887 | |||
888 | imx_ports[i].port.uartclk = imx_get_perclk1(); | ||
861 | } | 889 | } |
862 | } | 890 | } |
863 | 891 | ||