From 45de5af8a85a56405bf089ebf902f39260d4842f Mon Sep 17 00:00:00 2001 From: Huibin Hong Date: Tue, 26 Jun 2018 15:07:05 +0800 Subject: [PATCH] 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 --- drivers/tty/serial/8250/8250_port.c | 36 +++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 6b6909d9c005..bc968143fb97 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -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);