serial: imx: change the wait even to interruptiable
[linux-2.6-microblaze.git] / drivers / tty / serial / imx.c
index 044e86d..8f62a3c 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);
@@ -464,9 +467,19 @@ static inline void imx_transmit_buffer(struct imx_port *sport)
 {
        struct circ_buf *xmit = &sport->port.state->xmit;
 
+       if (sport->port.x_char) {
+               /* Send next char */
+               writel(sport->port.x_char, sport->port.membase + URTX0);
+               return;
+       }
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
+               imx_stop_tx(&sport->port);
+               return;
+       }
+
        while (!uart_circ_empty(xmit) &&
-                       !(readl(sport->port.membase + uts_reg(sport))
-                               & UTS_TXFULL)) {
+              !(readl(sport->port.membase + uts_reg(sport)) & UTS_TXFULL)) {
                /* send xmit->buf[xmit->tail]
                 * out the port here */
                writel(xmit->buf[xmit->tail], sport->port.membase + URTX0);
@@ -567,9 +580,6 @@ static void imx_start_tx(struct uart_port *port)
        struct imx_port *sport = (struct imx_port *)port;
        unsigned long temp;
 
-       if (uart_circ_empty(&port->state->xmit))
-               return;
-
        if (USE_IRDA(sport)) {
                /* half duplex in IrDA mode; have to disable receive mode */
                temp = readl(sport->port.membase + UCR4);
@@ -604,7 +614,10 @@ static void imx_start_tx(struct uart_port *port)
        }
 
        if (sport->dma_is_enabled) {
-               imx_dma_tx(sport);
+               /* FIXME: port->x_char must be transmitted if != 0 */
+               if (!uart_circ_empty(&port->state->xmit) &&
+                   !uart_tx_stopped(port))
+                       imx_dma_tx(sport);
                return;
        }
 
@@ -632,27 +645,10 @@ static irqreturn_t imx_rtsint(int irq, void *dev_id)
 static irqreturn_t imx_txint(int irq, void *dev_id)
 {
        struct imx_port *sport = dev_id;
-       struct circ_buf *xmit = &sport->port.state->xmit;
        unsigned long flags;
 
        spin_lock_irqsave(&sport->port.lock, flags);
-       if (sport->port.x_char) {
-               /* Send next char */
-               writel(sport->port.x_char, sport->port.membase + URTX0);
-               goto out;
-       }
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
-               imx_stop_tx(&sport->port);
-               goto out;
-       }
-
        imx_transmit_buffer(sport);
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&sport->port);
-
-out:
        spin_unlock_irqrestore(&sport->port.lock, flags);
        return IRQ_HANDLED;
 }
@@ -823,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);
 
@@ -1225,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);
@@ -1506,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)