diff options
author | Linus Walleij <linus.walleij@stericsson.com> | 2010-06-02 15:40:22 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-07-27 05:43:47 -0400 |
commit | ac3e3fb424d44109dda3b1a3459e1b30fa60ac4a (patch) | |
tree | b7e537c307e8fe2ed9a2bf0828b4e9f933adb31d /drivers | |
parent | ec489aa8f993f8d2ec962ce113071faac482aa27 (diff) |
ARM: 6158/2: PL011 baudrate extension for ST-Ericssons derivative
Implementation of the ST-Ericsson baudrate extension in the PL011
block. In this modified variant it is possible to change the
sampling factor from 16 to 8, and thanks to this we can get higher
baudrates while still using the same peripheral clock.
Also replace the simple division to determine the baud divisor
with DIV_ROUND_CLOSEST() rather than a simple integer division.
Cc: Alessandro Rubini <rubini@unipv.it>
Cc: Jerzy Kasenberg <jerzy.kasenberg@tieto.com>
Signed-off-by: Marcin Mielczarczyk <marcin.mielczarczyk@tieto.com>
Signed-off-by: Linus Walleij <linus.walleij@stericsson.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/serial/amba-pl011.c | 27 |
1 files changed, 25 insertions, 2 deletions
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index 5644cf2385bb..f67e09da6d33 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c | |||
@@ -74,6 +74,7 @@ struct uart_amba_port { | |||
74 | unsigned int ifls; /* vendor-specific */ | 74 | unsigned int ifls; /* vendor-specific */ |
75 | unsigned int lcrh_tx; /* vendor-specific */ | 75 | unsigned int lcrh_tx; /* vendor-specific */ |
76 | unsigned int lcrh_rx; /* vendor-specific */ | 76 | unsigned int lcrh_rx; /* vendor-specific */ |
77 | bool oversampling; /* vendor-specific */ | ||
77 | bool autorts; | 78 | bool autorts; |
78 | }; | 79 | }; |
79 | 80 | ||
@@ -83,6 +84,7 @@ struct vendor_data { | |||
83 | unsigned int fifosize; | 84 | unsigned int fifosize; |
84 | unsigned int lcrh_tx; | 85 | unsigned int lcrh_tx; |
85 | unsigned int lcrh_rx; | 86 | unsigned int lcrh_rx; |
87 | bool oversampling; | ||
86 | }; | 88 | }; |
87 | 89 | ||
88 | static struct vendor_data vendor_arm = { | 90 | static struct vendor_data vendor_arm = { |
@@ -90,6 +92,7 @@ static struct vendor_data vendor_arm = { | |||
90 | .fifosize = 16, | 92 | .fifosize = 16, |
91 | .lcrh_tx = UART011_LCRH, | 93 | .lcrh_tx = UART011_LCRH, |
92 | .lcrh_rx = UART011_LCRH, | 94 | .lcrh_rx = UART011_LCRH, |
95 | .oversampling = false, | ||
93 | }; | 96 | }; |
94 | 97 | ||
95 | static struct vendor_data vendor_st = { | 98 | static struct vendor_data vendor_st = { |
@@ -97,6 +100,7 @@ static struct vendor_data vendor_st = { | |||
97 | .fifosize = 64, | 100 | .fifosize = 64, |
98 | .lcrh_tx = ST_UART011_LCRH_TX, | 101 | .lcrh_tx = ST_UART011_LCRH_TX, |
99 | .lcrh_rx = ST_UART011_LCRH_RX, | 102 | .lcrh_rx = ST_UART011_LCRH_RX, |
103 | .oversampling = true, | ||
100 | }; | 104 | }; |
101 | 105 | ||
102 | static void pl011_stop_tx(struct uart_port *port) | 106 | static void pl011_stop_tx(struct uart_port *port) |
@@ -499,8 +503,13 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, | |||
499 | /* | 503 | /* |
500 | * Ask the core to calculate the divisor for us. | 504 | * Ask the core to calculate the divisor for us. |
501 | */ | 505 | */ |
502 | baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); | 506 | baud = uart_get_baud_rate(port, termios, old, 0, |
503 | quot = port->uartclk * 4 / baud; | 507 | port->uartclk/(uap->oversampling ? 8 : 16)); |
508 | |||
509 | if (baud > port->uartclk/16) | ||
510 | quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud); | ||
511 | else | ||
512 | quot = DIV_ROUND_CLOSEST(port->uartclk * 4, baud); | ||
504 | 513 | ||
505 | switch (termios->c_cflag & CSIZE) { | 514 | switch (termios->c_cflag & CSIZE) { |
506 | case CS5: | 515 | case CS5: |
@@ -579,6 +588,13 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, | |||
579 | uap->autorts = false; | 588 | uap->autorts = false; |
580 | } | 589 | } |
581 | 590 | ||
591 | if (uap->oversampling) { | ||
592 | if (baud > port->uartclk/16) | ||
593 | old_cr |= ST_UART011_CR_OVSFACT; | ||
594 | else | ||
595 | old_cr &= ~ST_UART011_CR_OVSFACT; | ||
596 | } | ||
597 | |||
582 | /* Set baud rate */ | 598 | /* Set baud rate */ |
583 | writew(quot & 0x3f, port->membase + UART011_FBRD); | 599 | writew(quot & 0x3f, port->membase + UART011_FBRD); |
584 | writew(quot >> 6, port->membase + UART011_IBRD); | 600 | writew(quot >> 6, port->membase + UART011_IBRD); |
@@ -744,6 +760,12 @@ pl011_console_get_options(struct uart_amba_port *uap, int *baud, | |||
744 | fbrd = readw(uap->port.membase + UART011_FBRD); | 760 | fbrd = readw(uap->port.membase + UART011_FBRD); |
745 | 761 | ||
746 | *baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd); | 762 | *baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd); |
763 | |||
764 | if (uap->oversampling) { | ||
765 | if (readw(uap->port.membase + UART011_CR) | ||
766 | & ST_UART011_CR_OVSFACT) | ||
767 | *baud *= 2; | ||
768 | } | ||
747 | } | 769 | } |
748 | } | 770 | } |
749 | 771 | ||
@@ -839,6 +861,7 @@ static int pl011_probe(struct amba_device *dev, struct amba_id *id) | |||
839 | uap->ifls = vendor->ifls; | 861 | uap->ifls = vendor->ifls; |
840 | uap->lcrh_rx = vendor->lcrh_rx; | 862 | uap->lcrh_rx = vendor->lcrh_rx; |
841 | uap->lcrh_tx = vendor->lcrh_tx; | 863 | uap->lcrh_tx = vendor->lcrh_tx; |
864 | uap->oversampling = vendor->oversampling; | ||
842 | uap->port.dev = &dev->dev; | 865 | uap->port.dev = &dev->dev; |
843 | uap->port.mapbase = dev->res.start; | 866 | uap->port.mapbase = dev->res.start; |
844 | uap->port.membase = base; | 867 | uap->port.membase = base; |