]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/tty/serial/imx.c
serial: imx: change the wait even to interruptiable
[karo-tx-linux.git] / drivers / tty / serial / imx.c
index c86f1538bfddd90e730bcd95a0efa9789d4968db..8f62a3cec23ef89d27217779f3cf9e378241f4b1 100644 (file)
@@ -80,6 +80,7 @@
 #define URXD_FRMERR    (1<<12)
 #define URXD_BRK       (1<<11)
 #define URXD_PRERR     (1<<10)
+#define URXD_RX_DATA   (0xFF<<0)
 #define UCR1_ADEN      (1<<15) /* Auto detect interrupt */
 #define UCR1_ADBR      (1<<14) /* Auto detect baud rate */
 #define UCR1_TRDYEN    (1<<13) /* Transmitter ready interrupt enable */
@@ -435,12 +436,14 @@ static void imx_stop_rx(struct uart_port *port)
        struct imx_port *sport = (struct imx_port *)port;
        unsigned long temp;
 
-       /*
-        * We are maybe in the SMP context, so if the DMA TX thread is running
-        * on other cpu, we have to wait for it to finish.
-        */
-       if (sport->dma_is_enabled && sport->dma_is_rxing)
-               return;
+       if (sport->dma_is_enabled && sport->dma_is_rxing) {
+               if (sport->port.suspended) {
+                       dmaengine_terminate_all(sport->dma_chan_rx);
+                       sport->dma_is_rxing = 0;
+               } else {
+                       return;
+               }
+       }
 
        temp = readl(sport->port.membase + UCR2);
        writel(temp & ~UCR2_RXEN, sport->port.membase + UCR2);
@@ -816,11 +819,9 @@ static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
        struct imx_port *sport = (struct imx_port *)port;
        unsigned long temp;
 
-       temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS;
-
+       temp = readl(sport->port.membase + UCR2) & ~(UCR2_CTS | UCR2_CTSC);
        if (mctrl & TIOCM_RTS)
-               if (!sport->dma_is_enabled)
-                       temp |= UCR2_CTS;
+               temp |= UCR2_CTS | UCR2_CTSC;
 
        writel(temp, sport->port.membase + UCR2);
 
@@ -1218,9 +1219,18 @@ static void imx_shutdown(struct uart_port *port)
        unsigned long flags;
 
        if (sport->dma_is_enabled) {
+               int ret;
+
                /* We have to wait for the DMA to finish. */
-               wait_event(sport->dma_wait,
+               ret = wait_event_interruptible(sport->dma_wait,
                        !sport->dma_is_rxing && !sport->dma_is_txing);
+               if (ret != 0) {
+                       sport->dma_is_rxing = 0;
+                       sport->dma_is_txing = 0;
+                       dmaengine_terminate_all(sport->dma_chan_tx);
+                       dmaengine_terminate_all(sport->dma_chan_rx);
+               }
+               imx_stop_tx(port);
                imx_stop_rx(port);
                imx_disable_dma(sport);
                imx_uart_dma_exit(sport);
@@ -1499,32 +1509,10 @@ imx_verify_port(struct uart_port *port, struct serial_struct *ser)
 #if defined(CONFIG_CONSOLE_POLL)
 static int imx_poll_get_char(struct uart_port *port)
 {
-       struct imx_port_ucrs old_ucr;
-       unsigned int status;
-       unsigned char c;
-
-       /* save control registers */
-       imx_port_ucrs_save(port, &old_ucr);
-
-       /* disable interrupts */
-       writel(UCR1_UARTEN, port->membase + UCR1);
-       writel(old_ucr.ucr2 & ~(UCR2_ATEN | UCR2_RTSEN | UCR2_ESCI),
-              port->membase + UCR2);
-       writel(old_ucr.ucr3 & ~(UCR3_DCD | UCR3_RI | UCR3_DTREN),
-              port->membase + UCR3);
-
-       /* poll */
-       do {
-               status = readl(port->membase + USR2);
-       } while (~status & USR2_RDR);
-
-       /* read */
-       c = readl(port->membase + URXD0);
-
-       /* restore control registers */
-       imx_port_ucrs_restore(port, &old_ucr);
+       if (!(readl(port->membase + USR2) & USR2_RDR))
+               return NO_POLL_CHAR;
 
-       return c;
+       return readl(port->membase + URXD0) & URXD_RX_DATA;
 }
 
 static void imx_poll_put_char(struct uart_port *port, unsigned char c)