aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/serial/imx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/serial/imx.c')
-rw-r--r--drivers/tty/serial/imx.c88
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) {