serial: imx: Fix imx_flush_buffer()
authorFabio Estevam <fabio.estevam@freescale.com>
Tue, 13 Jan 2015 12:00:26 +0000 (10:00 -0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 2 Feb 2015 18:11:24 +0000 (10:11 -0800)
When running an userspace program that does a 'tcflush(fd, TCIOFLUSH)' call
we still see the last received character in the URXD register afterwards.

Clear UCR2_SRST bit so that the UART FIFO is flushed properly.

Since UCR2_SRST also resets some UART registers, we need to save and restore
some of them.

Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
Tested-by: Fugang Duan <B38611@freescale.com>
Acked-by: Jason Liu <r64343@freecale.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/imx.c

index 59d9ef10b085f9102c6a9152be7728b16fa72ff4..0eb29b1c47ac8ea313456df38a45f6720e62246b 100644 (file)
@@ -1320,6 +1320,7 @@ static void imx_flush_buffer(struct uart_port *port)
        struct imx_port *sport = (struct imx_port *)port;
        struct scatterlist *sgl = &sport->tx_sgl[0];
        unsigned long temp;
+       int i = 100, ubir, ubmr, ubrc, uts;
 
        if (!sport->dma_chan_tx)
                return;
@@ -1334,6 +1335,31 @@ static void imx_flush_buffer(struct uart_port *port)
                writel(temp, sport->port.membase + UCR1);
                sport->dma_is_txing = false;
        }
+
+       /*
+        * According to the Reference Manual description of the UART SRST bit:
+        * "Reset the transmit and receive state machines,
+        * all FIFOs and register USR1, USR2, UBIR, UBMR, UBRC, URXD, UTXD
+        * and UTS[6-3]". As we don't need to restore the old values from
+        * USR1, USR2, URXD, UTXD, only save/restore the other four registers
+        */
+       ubir = readl(sport->port.membase + UBIR);
+       ubmr = readl(sport->port.membase + UBMR);
+       ubrc = readl(sport->port.membase + UBRC);
+       uts = readl(sport->port.membase + IMX21_UTS);
+
+       temp = readl(sport->port.membase + UCR2);
+       temp &= ~UCR2_SRST;
+       writel(temp, sport->port.membase + UCR2);
+
+       while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0))
+               udelay(1);
+
+       /* Restore the registers */
+       writel(ubir, sport->port.membase + UBIR);
+       writel(ubmr, sport->port.membase + UBMR);
+       writel(ubrc, sport->port.membase + UBRC);
+       writel(uts, sport->port.membase + IMX21_UTS);
 }
 
 static void