diff options
Diffstat (limited to 'drivers/tty/serial/imx.c')
-rw-r--r-- | drivers/tty/serial/imx.c | 88 |
1 files changed, 48 insertions, 40 deletions
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 57d6e6ba556e..87c58f9f6390 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -402,12 +402,6 @@ static void imx_uart_rts_inactive(struct imx_port *sport, u32 *ucr2) mctrl_gpio_set(sport->gpios, sport->port.mctrl); } -/* called with port.lock taken and irqs caller dependent */ -static void imx_uart_rts_auto(struct imx_port *sport, u32 *ucr2) -{ - *ucr2 |= UCR2_CTSC; -} - /* called with port.lock taken and irqs off */ static void imx_uart_start_rx(struct uart_port *port) { @@ -445,7 +439,7 @@ static void imx_uart_stop_tx(struct uart_port *port) return; ucr1 = imx_uart_readl(sport, UCR1); - imx_uart_writel(sport, ucr1 & ~UCR1_TXMPTYEN, UCR1); + imx_uart_writel(sport, ucr1 & ~UCR1_TRDYEN, UCR1); /* in rs485 mode disable transmitter if shifter is empty */ if (port->rs485.flags & SER_RS485_ENABLED && @@ -523,7 +517,7 @@ static inline void imx_uart_transmit_buffer(struct imx_port *sport) * and the TX IRQ is disabled. **/ ucr1 = imx_uart_readl(sport, UCR1); - ucr1 &= ~UCR1_TXMPTYEN; + ucr1 &= ~UCR1_TRDYEN; if (sport->dma_is_txing) { ucr1 |= UCR1_TXDMAEN; imx_uart_writel(sport, ucr1, UCR1); @@ -685,7 +679,7 @@ static void imx_uart_start_tx(struct uart_port *port) if (!sport->dma_is_enabled) { ucr1 = imx_uart_readl(sport, UCR1); - imx_uart_writel(sport, ucr1 | UCR1_TXMPTYEN, UCR1); + imx_uart_writel(sport, ucr1 | UCR1_TRDYEN, UCR1); } if (sport->dma_is_enabled) { @@ -694,7 +688,7 @@ static void imx_uart_start_tx(struct uart_port *port) * disable TX DMA to let TX interrupt to send X-char */ ucr1 = imx_uart_readl(sport, UCR1); ucr1 &= ~UCR1_TXDMAEN; - ucr1 |= UCR1_TXMPTYEN; + ucr1 |= UCR1_TRDYEN; imx_uart_writel(sport, ucr1, UCR1); return; } @@ -880,7 +874,7 @@ static irqreturn_t imx_uart_int(int irq, void *dev_id) usr1 &= ~USR1_RRDY; if ((ucr2 & UCR2_ATEN) == 0) usr1 &= ~USR1_AGTIM; - if ((ucr1 & UCR1_TXMPTYEN) == 0) + if ((ucr1 & UCR1_TRDYEN) == 0) usr1 &= ~USR1_TRDY; if ((ucr4 & UCR4_TCEN) == 0) usr2 &= ~USR2_TXDC; @@ -969,10 +963,22 @@ static void imx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) if (!(port->rs485.flags & SER_RS485_ENABLED)) { u32 ucr2; + /* + * Turn off autoRTS if RTS is lowered and restore autoRTS + * setting if RTS is raised. + */ ucr2 = imx_uart_readl(sport, UCR2); ucr2 &= ~(UCR2_CTS | UCR2_CTSC); - if (mctrl & TIOCM_RTS) - ucr2 |= UCR2_CTS | UCR2_CTSC; + if (mctrl & TIOCM_RTS) { + ucr2 |= UCR2_CTS; + /* + * UCR2_IRTS is unset if and only if the port is + * configured for CRTSCTS, so we use inverted UCR2_IRTS + * to get the state to restore to. + */ + if (!(ucr2 & UCR2_IRTS)) + ucr2 |= UCR2_CTSC; + } imx_uart_writel(sport, ucr2, UCR2); } @@ -1468,7 +1474,7 @@ static void imx_uart_shutdown(struct uart_port *port) spin_lock_irqsave(&sport->port.lock, flags); ucr1 = imx_uart_readl(sport, UCR1); - ucr1 &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN | UCR1_RXDMAEN | UCR1_ATDMAEN); + ucr1 &= ~(UCR1_TRDYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN | UCR1_RXDMAEN | UCR1_ATDMAEN); imx_uart_writel(sport, ucr1, UCR1); spin_unlock_irqrestore(&sport->port.lock, flags); @@ -1535,11 +1541,11 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios, { struct imx_port *sport = (struct imx_port *)port; unsigned long flags; - u32 ucr2, old_ucr1, old_ucr2, ufcr; + u32 ucr2, old_ucr2, ufcr; unsigned int baud, quot; unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; unsigned long div; - unsigned long num, denom; + unsigned long num, denom, old_ubir, old_ubmr; uint64_t tdiv64; /* @@ -1587,8 +1593,14 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios, else imx_uart_rts_inactive(sport, &ucr2); - } else if (termios->c_cflag & CRTSCTS) - imx_uart_rts_auto(sport, &ucr2); + } else if (termios->c_cflag & CRTSCTS) { + /* + * Only let receiver control RTS output if we were not requested + * to have RTS inactive (which then should take precedence). + */ + if (ucr2 & UCR2_CTS) + ucr2 |= UCR2_CTSC; + } if (termios->c_cflag & CRTSCTS) ucr2 &= ~UCR2_IRTS; @@ -1631,21 +1643,6 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios, */ uart_update_timeout(port, termios->c_cflag, baud); - /* - * disable interrupts and drain transmitter - */ - old_ucr1 = imx_uart_readl(sport, UCR1); - imx_uart_writel(sport, - old_ucr1 & ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN), - UCR1); - imx_uart_writel(sport, old_ucr2 & ~UCR2_ATEN, UCR2); - - while (!(imx_uart_readl(sport, USR2) & USR2_TXDC)) - barrier(); - - /* then, disable everything */ - imx_uart_writel(sport, old_ucr2 & ~(UCR2_TXEN | UCR2_RXEN | UCR2_ATEN), UCR2); - /* custom-baudrate handling */ div = sport->port.uartclk / (baud * 16); if (baud == 38400 && quot != div) @@ -1673,15 +1670,26 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios, ufcr = (ufcr & (~UFCR_RFDIV)) | UFCR_RFDIV_REG(div); imx_uart_writel(sport, ufcr, UFCR); - imx_uart_writel(sport, num, UBIR); - imx_uart_writel(sport, denom, UBMR); + /* + * Two registers below should always be written both and in this + * particular order. One consequence is that we need to check if any of + * them changes and then update both. We do need the check for change + * as even writing the same values seem to "restart" + * transmission/receiving logic in the hardware, that leads to data + * breakage even when rate doesn't in fact change. E.g., user switches + * RTS/CTS handshake and suddenly gets broken bytes. + */ + old_ubir = imx_uart_readl(sport, UBIR); + old_ubmr = imx_uart_readl(sport, UBMR); + if (old_ubir != num || old_ubmr != denom) { + imx_uart_writel(sport, num, UBIR); + imx_uart_writel(sport, denom, UBMR); + } if (!imx_uart_is_imx1(sport)) imx_uart_writel(sport, sport->port.uartclk / div / 1000, IMX21_ONEMS); - imx_uart_writel(sport, old_ucr1, UCR1); - imx_uart_writel(sport, ucr2, UCR2); if (UART_ENABLE_MS(&sport->port, termios->c_cflag)) @@ -1770,7 +1778,7 @@ static int imx_uart_poll_init(struct uart_port *port) ucr1 |= IMX1_UCR1_UARTCLKEN; ucr1 |= UCR1_UARTEN; - ucr1 &= ~(UCR1_TXMPTYEN | UCR1_RTSDEN | UCR1_RRDYEN); + ucr1 &= ~(UCR1_TRDYEN | UCR1_RTSDEN | UCR1_RRDYEN); ucr2 |= UCR2_RXEN; ucr2 &= ~UCR2_ATEN; @@ -1930,7 +1938,7 @@ imx_uart_console_write(struct console *co, const char *s, unsigned int count) if (imx_uart_is_imx1(sport)) ucr1 |= IMX1_UCR1_UARTCLKEN; ucr1 |= UCR1_UARTEN; - ucr1 &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN); + ucr1 &= ~(UCR1_TRDYEN | UCR1_RRDYEN | UCR1_RTSDEN); imx_uart_writel(sport, ucr1, UCR1); @@ -2286,7 +2294,7 @@ static int imx_uart_probe(struct platform_device *pdev) /* Disable interrupts before requesting them */ ucr1 = imx_uart_readl(sport, UCR1); ucr1 &= ~(UCR1_ADEN | UCR1_TRDYEN | UCR1_IDEN | UCR1_RRDYEN | - UCR1_TXMPTYEN | UCR1_RTSDEN); + UCR1_TRDYEN | UCR1_RTSDEN); imx_uart_writel(sport, ucr1, UCR1); if (!imx_uart_is_imx1(sport) && sport->dte_mode) { |