diff options
author | James Hogan <james.hogan@imgtec.com> | 2015-09-25 15:36:10 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-10-04 19:12:25 +0100 |
commit | 4f56f3fdca43c9a18339b6e0c3b1aa2f57f6d0b0 (patch) | |
tree | 4cc3ba6f84127d0b79630f48eb24d47f06d4c648 /drivers/tty | |
parent | d215d80957ce98c318064c249ad0b7800c63a19d (diff) |
serial: 8250: Tolerate clock variance for max baud rate
When the UART clock is set slightly under 1.8432MHz, the 8250 driver
core doesn't permit the 115200 baud rate since it calculates the maximum
frequency to pass to uart_get_baud_rate by simply dividing the uart
clock by 16 which yields a value slightly under 115200, even though the
frequency is close enough for the UART to operate reliably.
Therefore add some tolerance in the calculation of the maximum baud
rate. 1% tolerance allows for marginally slower uart clk than nominal
without introducing transmission errors.
Signed-off-by: James Hogan <james.hogan@imgtec.com>
[pjh: Forward-port & refactor original patch; change tolerance to 1%]
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty')
-rw-r--r-- | drivers/tty/serial/8250/8250_port.c | 28 |
1 files changed, 19 insertions, 9 deletions
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 554a63e4c4a0..e54de0037df4 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -2225,6 +2225,23 @@ static void serial8250_set_divisor(struct uart_port *port, unsigned int baud, serial_port_out(port, 0x2, quot_frac); } +static unsigned int +serial8250_get_baud_rate(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + unsigned int tolerance = port->uartclk / 100; + + /* + * Ask the core to calculate the divisor for us. + * Allow 1% tolerance at the upper limit so uart clks marginally + * slower than nominal still match standard baud rates without + * causing transmission errors. + */ + return uart_get_baud_rate(port, termios, old, + port->uartclk / 16 / 0xffff, + (port->uartclk + tolerance) / 16); +} + void serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) @@ -2236,12 +2253,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, cval = serial8250_compute_lcr(up, termios->c_cflag); - /* - * Ask the core to calculate the divisor for us. - */ - baud = uart_get_baud_rate(port, termios, old, - port->uartclk / 16 / 0xffff, - port->uartclk / 16); + baud = serial8250_get_baud_rate(port, termios, old); quot = serial8250_get_divisor(up, baud, &frac); /* @@ -2834,9 +2846,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, if (port->state->port.tty && termios.c_cflag == 0) termios.c_cflag = port->state->port.tty->termios.c_cflag; - baud = uart_get_baud_rate(port, &termios, NULL, - port->uartclk / 16 / 0xffff, - port->uartclk / 16); + baud = serial8250_get_baud_rate(port, &termios, NULL); quot = serial8250_get_divisor(up, baud, &frac); serial8250_set_divisor(port, baud, quot, frac); |