aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@stericsson.com>2010-06-02 15:40:22 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2010-07-27 05:43:47 -0400
commitac3e3fb424d44109dda3b1a3459e1b30fa60ac4a (patch)
treeb7e537c307e8fe2ed9a2bf0828b4e9f933adb31d /drivers
parentec489aa8f993f8d2ec962ce113071faac482aa27 (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.c27
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
88static struct vendor_data vendor_arm = { 90static 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
95static struct vendor_data vendor_st = { 98static 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
102static void pl011_stop_tx(struct uart_port *port) 106static 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;