serial: 8250: reset uart when set baud rate

If external device sends data continuously, then uart is
always busy, and baud rate can't be set. It is useful
to reset uart and set loop back mode to make sure it is
idle.

Change-Id: I87286711870ff685ea29e36e61c97d45be5a6d08
Signed-off-by: Huibin Hong <huibin.hong@rock-chips.com>
This commit is contained in:
Huibin Hong
2018-06-26 15:07:05 +08:00
committed by Tao Huang
parent 0f27d1cbb4
commit 45de5af8a8

View File

@@ -2587,6 +2587,10 @@ void serial8250_do_set_divisor(struct uart_port *port, unsigned int baud,
{
struct uart_8250_port *up = up_to_u8250p(port);
#ifdef CONFIG_ARCH_ROCKCHIP
serial_port_out(port, UART_MCR, UART_MCR_LOOP);
#endif
/* Workaround to enable 115200 baud on OMAP1510 internal ports */
if (is_omap1510_8250(up)) {
if (baud == 115200) {
@@ -2607,6 +2611,13 @@ void serial8250_do_set_divisor(struct uart_port *port, unsigned int baud,
serial_dl_write(up, quot);
#ifdef CONFIG_ARCH_ROCKCHIP
serial_port_out(port, UART_MCR, up->mcr);
if (quot != serial_dl_read(up))
pr_warn_ratelimited("ttyS%d set divisor fail, quot:%d != dll,dlh:%d\n",
serial_index(port), quot, serial_dl_read(up));
#endif
/* XR17V35x UARTs have an extra fractional divisor register (DLD) */
if (up->port.type == PORT_XR17V35X) {
/* Preserve bits not related to baudrate; DLD[7:4]. */
@@ -2721,6 +2732,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
if ((termios->c_cflag & CREAD) == 0)
port->ignore_status_mask |= UART_LSR_DR;
#ifndef CONFIG_ARCH_ROCKCHIP
/*
* CTS flow control flag and modem status interrupts
*/
@@ -2734,6 +2746,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
up->ier |= UART_IER_RTOIE;
serial_port_out(port, UART_IER, up->ier);
#endif
if (up->capabilities & UART_CAP_EFR) {
unsigned char efr = 0;
@@ -2752,7 +2765,13 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
serial_port_out(port, UART_EFR, efr);
}
#ifdef CONFIG_ARCH_ROCKCHIP
/* Reset uart to make sure it is idle, then set buad rate */
serial_port_out(port, 0x88 >> 2, 0x7);
#endif
serial8250_set_divisor(port, baud, quot, frac);
#ifdef CONFIG_ARCH_ROCKCHIP
up->fcr = UART_FCR_ENABLE_FIFO | UART_FCR_T_TRIG_10 | UART_FCR_R_TRIG_10;
#endif
@@ -2771,6 +2790,23 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
serial_port_out(port, UART_FCR, up->fcr); /* set fcr */
}
serial8250_set_mctrl(port, port->mctrl);
#ifdef CONFIG_ARCH_ROCKCHIP
/*
* CTS flow control flag and modem status interrupts
*/
up->ier &= ~UART_IER_MSI;
if (!(up->bugs & UART_BUG_NOMSR) &&
UART_ENABLE_MS(&up->port, termios->c_cflag))
up->ier |= UART_IER_MSI;
if (up->capabilities & UART_CAP_UUE)
up->ier |= UART_IER_UUE;
if (up->capabilities & UART_CAP_RTOIE)
up->ier |= UART_IER_RTOIE;
serial_port_out(port, UART_IER, up->ier);
#endif
spin_unlock_irqrestore(&port->lock, flags);
serial8250_rpm_put(up);