diff options
-rw-r--r-- | drivers/serial/amba-pl011.c | 27 | ||||
-rw-r--r-- | include/linux/amba/serial.h | 1 |
2 files changed, 26 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; |
diff --git a/include/linux/amba/serial.h b/include/linux/amba/serial.h index 93c96a66c518..e1b634b635f2 100644 --- a/include/linux/amba/serial.h +++ b/include/linux/amba/serial.h | |||
@@ -86,6 +86,7 @@ | |||
86 | #define UART010_CR_TIE 0x0020 | 86 | #define UART010_CR_TIE 0x0020 |
87 | #define UART010_CR_RIE 0x0010 | 87 | #define UART010_CR_RIE 0x0010 |
88 | #define UART010_CR_MSIE 0x0008 | 88 | #define UART010_CR_MSIE 0x0008 |
89 | #define ST_UART011_CR_OVSFACT 0x0008 /* Oversampling factor */ | ||
89 | #define UART01x_CR_IIRLP 0x0004 /* SIR low power mode */ | 90 | #define UART01x_CR_IIRLP 0x0004 /* SIR low power mode */ |
90 | #define UART01x_CR_SIREN 0x0002 /* SIR enable */ | 91 | #define UART01x_CR_SIREN 0x0002 /* SIR enable */ |
91 | #define UART01x_CR_UARTEN 0x0001 /* UART enable */ | 92 | #define UART01x_CR_UARTEN 0x0001 /* UART enable */ |