From cb6de0208d05949921121c59617bf6cf4b87c7f2 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 40ad49d562d7..81c1d3a3ad96 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -2603,6 +2603,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) { @@ -2622,6 +2626,13 @@ void serial8250_do_set_divisor(struct uart_port *port, unsigned int baud, serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB); 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 } EXPORT_SYMBOL_GPL(serial8250_do_set_divisor); @@ -2775,6 +2786,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 */ @@ -2788,6 +2800,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; @@ -2806,7 +2819,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 baud 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 @@ -2825,6 +2844,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);