]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/serial/bfin_5xx.c
serial: fix platform driver hotplug/coldplug
[linux-2.6-omap-h63xx.git] / drivers / serial / bfin_5xx.c
index af866ab3f5a1611264b633abe6c60036a0aef355..46bb47f37b9a276089332cf23dbb5462eea8c47e 100644 (file)
@@ -48,7 +48,7 @@
 #define DMA_RX_XCOUNT          512
 #define DMA_RX_YCOUNT          (PAGE_SIZE / DMA_RX_XCOUNT)
 
-#define DMA_RX_FLUSH_JIFFIES   5
+#define DMA_RX_FLUSH_JIFFIES   (HZ / 50)
 
 #ifdef CONFIG_SERIAL_BFIN_DMA
 static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart);
@@ -64,15 +64,20 @@ static void bfin_serial_mctrl_check(struct bfin_serial_port *uart);
 static void bfin_serial_stop_tx(struct uart_port *port)
 {
        struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+       struct circ_buf *xmit = &uart->port.info->xmit;
 #if !defined(CONFIG_BF54x) && !defined(CONFIG_SERIAL_BFIN_DMA)
        unsigned short ier;
 #endif
 
        while (!(UART_GET_LSR(uart) & TEMT))
-               continue;
+               cpu_relax();
 
 #ifdef CONFIG_SERIAL_BFIN_DMA
        disable_dma(uart->tx_dma_channel);
+       xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
+       uart->port.icount.tx += uart->tx_count;
+       uart->tx_count = 0;
+       uart->tx_done = 1;
 #else
 #ifdef CONFIG_BF54x
        /* Clear TFI bit */
@@ -94,7 +99,8 @@ static void bfin_serial_start_tx(struct uart_port *port)
        struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
 
 #ifdef CONFIG_SERIAL_BFIN_DMA
-       bfin_serial_dma_tx_chars(uart);
+       if (uart->tx_done)
+               bfin_serial_dma_tx_chars(uart);
 #else
 #ifdef CONFIG_BF54x
        UART_SET_IER(uart, ETBEI);
@@ -387,14 +393,11 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
 {
        struct circ_buf *xmit = &uart->port.info->xmit;
        unsigned short ier;
-       int flags = 0;
 
-       if (!uart->tx_done)
-               return;
        uart->tx_done = 0;
 
        if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
-               bfin_serial_stop_tx(&uart->port);
+               uart->tx_count = 0;
                uart->tx_done = 1;
                return;
        }
@@ -411,7 +414,6 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
         */
        bfin_serial_mctrl_check(uart);
 
-       spin_lock_irqsave(&uart->port.lock, flags);
        uart->tx_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE);
        if (uart->tx_count > (UART_XMIT_SIZE - xmit->tail))
                uart->tx_count = UART_XMIT_SIZE - xmit->tail;
@@ -428,9 +430,6 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
        set_dma_x_modify(uart->tx_dma_channel, 1);
        enable_dma(uart->tx_dma_channel);
 
-       xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
-       uart->port.icount.tx += uart->tx_count;
-
 #ifdef CONFIG_BF54x
        UART_SET_IER(uart, ETBEI);
 #else
@@ -438,7 +437,6 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
        ier |= ETBEI;
        UART_PUT_IER(uart, ier);
 #endif
-       spin_unlock_irqrestore(&uart->port.lock, flags);
 }
 
 static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
@@ -449,7 +447,9 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
        status = UART_GET_LSR(uart);
        UART_CLEAR_LSR(uart);
 
-       uart->port.icount.rx += CIRC_CNT(uart->rx_dma_buf.head, uart->rx_dma_buf.tail, UART_XMIT_SIZE);;
+       uart->port.icount.rx +=
+               CIRC_CNT(uart->rx_dma_buf.head, uart->rx_dma_buf.tail,
+               UART_XMIT_SIZE);
 
        if (status & BI) {
                uart->port.icount.brk++;
@@ -475,10 +475,12 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
        else
                flg = TTY_NORMAL;
 
-       for (i = uart->rx_dma_buf.head; i < uart->rx_dma_buf.tail; i++) {
-               if (uart_handle_sysrq_char(&uart->port, uart->rx_dma_buf.buf[i]))
-                       goto dma_ignore_char;
-               uart_insert_char(&uart->port, status, OE, uart->rx_dma_buf.buf[i], flg);
+       for (i = uart->rx_dma_buf.tail; i != uart->rx_dma_buf.head; i++) {
+               if (i >= UART_XMIT_SIZE)
+                       i = 0;
+               if (!uart_handle_sysrq_char(&uart->port, uart->rx_dma_buf.buf[i]))
+                       uart_insert_char(&uart->port, status, OE,
+                               uart->rx_dma_buf.buf[i], flg);
        }
 
  dma_ignore_char:
@@ -488,21 +490,23 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
 void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
 {
        int x_pos, pos;
-       int flags = 0;
 
-       spin_lock_irqsave(&uart->port.lock, flags);
-       x_pos = DMA_RX_XCOUNT - get_dma_curr_xcount(uart->rx_dma_channel);
+       uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel);
+       x_pos = get_dma_curr_xcount(uart->rx_dma_channel);
+       uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows;
+       if (uart->rx_dma_nrows == DMA_RX_YCOUNT)
+               uart->rx_dma_nrows = 0;
+       x_pos = DMA_RX_XCOUNT - x_pos;
        if (x_pos == DMA_RX_XCOUNT)
                x_pos = 0;
 
        pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos;
-
-       if (pos>uart->rx_dma_buf.tail) {
-               uart->rx_dma_buf.tail = pos;
+       if (pos != uart->rx_dma_buf.tail) {
+               uart->rx_dma_buf.head = pos;
                bfin_serial_dma_rx_chars(uart);
-               uart->rx_dma_buf.head = uart->rx_dma_buf.tail;
+               uart->rx_dma_buf.tail = uart->rx_dma_buf.head;
        }
-       spin_unlock_irqrestore(&uart->port.lock, flags);
+
        uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES;
        add_timer(&(uart->rx_dma_timer));
 }
@@ -515,8 +519,8 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
 
        spin_lock(&uart->port.lock);
        if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) {
-               clear_dma_irqstat(uart->tx_dma_channel);
                disable_dma(uart->tx_dma_channel);
+               clear_dma_irqstat(uart->tx_dma_channel);
 #ifdef CONFIG_BF54x
                UART_CLEAR_IER(uart, ETBEI);
 #else
@@ -524,11 +528,12 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
                ier &= ~ETBEI;
                UART_PUT_IER(uart, ier);
 #endif
+               xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
+               uart->port.icount.tx += uart->tx_count;
+
                if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
                        uart_write_wakeup(&uart->port);
 
-               uart->tx_done = 1;
-
                bfin_serial_dma_tx_chars(uart);
        }
 
@@ -541,18 +546,15 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)
        struct bfin_serial_port *uart = dev_id;
        unsigned short irqstat;
 
-       uart->rx_dma_nrows++;
-       if (uart->rx_dma_nrows == DMA_RX_YCOUNT) {
-               uart->rx_dma_nrows = 0;
-               uart->rx_dma_buf.tail = DMA_RX_XCOUNT*DMA_RX_YCOUNT;
-               bfin_serial_dma_rx_chars(uart);
-               uart->rx_dma_buf.head = uart->rx_dma_buf.tail = 0;
-       }
        spin_lock(&uart->port.lock);
        irqstat = get_dma_curr_irqstat(uart->rx_dma_channel);
        clear_dma_irqstat(uart->rx_dma_channel);
-
        spin_unlock(&uart->port.lock);
+
+       del_timer(&(uart->rx_dma_timer));
+       uart->rx_dma_timer.expires = jiffies;
+       add_timer(&(uart->rx_dma_timer));
+
        return IRQ_HANDLED;
 }
 #endif
@@ -579,7 +581,11 @@ static unsigned int bfin_serial_get_mctrl(struct uart_port *port)
        if (uart->cts_pin < 0)
                return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
 
+# ifdef BF54x
+       if (UART_GET_MSR(uart) & CTS)
+# else
        if (gpio_get_value(uart->cts_pin))
+# endif
                return TIOCM_DSR | TIOCM_CAR;
        else
 #endif
@@ -594,9 +600,17 @@ static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
                return;
 
        if (mctrl & TIOCM_RTS)
+# ifdef BF54x
+               UART_PUT_MCR(uart, UART_GET_MCR(uart) & ~MRTS);
+# else
                gpio_set_value(uart->rts_pin, 0);
+# endif
        else
+# ifdef BF54x
+               UART_PUT_MCR(uart, UART_GET_MCR(uart) | MRTS);
+# else
                gpio_set_value(uart->rts_pin, 1);
+# endif
 #endif
 }
 
@@ -1229,6 +1243,7 @@ static struct platform_driver bfin_serial_driver = {
        .resume         = bfin_serial_resume,
        .driver         = {
                .name   = "bfin-uart",
+               .owner  = THIS_MODULE,
        },
 };
 
@@ -1287,3 +1302,4 @@ MODULE_AUTHOR("Aubrey.Li <aubrey.li@analog.com>");
 MODULE_DESCRIPTION("Blackfin generic serial port driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_CHARDEV_MAJOR(BFIN_SERIAL_MAJOR);
+MODULE_ALIAS("platform:bfin-uart");