]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/serial/bfin_5xx.c
tty: Blackin CTS/RTS
[linux-2.6-omap-h63xx.git] / drivers / serial / bfin_5xx.c
index 569f0e2476c690259e6234911db7c33c4998c4b9..18ba812a4f84bc6b3aea2c5818613a811a681387 100644 (file)
@@ -22,7 +22,8 @@
 #include <linux/tty_flip.h>
 #include <linux/serial_core.h>
 
-#ifdef CONFIG_KGDB_UART
+#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
 #include <linux/kgdb.h>
 #include <asm/irq_regs.h>
 #endif
 static struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
 static int nr_active_ports = ARRAY_SIZE(bfin_serial_resource);
 
+#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
+
+# ifndef CONFIG_SERIAL_BFIN_PIO
+#  error KGDB only support UART in PIO mode.
+# endif
+
+static int kgdboc_port_line;
+static int kgdboc_break_enabled;
+#endif
 /*
  * Setup for console. Argument comes from the menuconfig
  */
@@ -52,7 +63,6 @@ static int nr_active_ports = ARRAY_SIZE(bfin_serial_resource);
 #define DMA_RX_YCOUNT          (PAGE_SIZE / DMA_RX_XCOUNT)
 
 #define DMA_RX_FLUSH_JIFFIES   (HZ / 50)
-#define CTS_CHECK_JIFFIES      (HZ / 50)
 
 #ifdef CONFIG_SERIAL_BFIN_DMA
 static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart);
@@ -60,7 +70,64 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart);
 static void bfin_serial_tx_chars(struct bfin_serial_port *uart);
 #endif
 
-static void bfin_serial_mctrl_check(struct bfin_serial_port *uart);
+static void bfin_serial_reset_irda(struct uart_port *port);
+
+#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
+       defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
+static unsigned int bfin_serial_get_mctrl(struct uart_port *port)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+       if (uart->cts_pin < 0)
+               return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+
+       /* CTS PIN is negative assertive. */
+       if (UART_GET_CTS(uart))
+               return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+       else
+               return TIOCM_DSR | TIOCM_CAR;
+}
+
+static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+       if (uart->rts_pin < 0)
+               return;
+
+       /* RTS PIN is negative assertive. */
+       if (mctrl & TIOCM_RTS)
+               UART_ENABLE_RTS(uart);
+       else
+               UART_DISABLE_RTS(uart);
+}
+
+/*
+ * Handle any change of modem status signal.
+ */
+static irqreturn_t bfin_serial_mctrl_cts_int(int irq, void *dev_id)
+{
+       struct bfin_serial_port *uart = dev_id;
+       unsigned int status;
+
+       status = bfin_serial_get_mctrl(&uart->port);
+       uart_handle_cts_change(&uart->port, status & TIOCM_CTS);
+#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
+       uart->scts = 1;
+       UART_CLEAR_SCTS(uart);
+       UART_CLEAR_IER(uart, EDSSI);
+#endif
+
+       return IRQ_HANDLED;
+}
+#else
+static unsigned int bfin_serial_get_mctrl(struct uart_port *port)
+{
+       return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+}
+
+static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+#endif
 
 /*
  * interrupts are disabled on entry
@@ -68,7 +135,9 @@ 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;
+#ifdef CONFIG_SERIAL_BFIN_DMA
        struct circ_buf *xmit = &uart->port.info->xmit;
+#endif
 
        while (!(UART_GET_LSR(uart) & TEMT))
                cpu_relax();
@@ -94,6 +163,21 @@ static void bfin_serial_stop_tx(struct uart_port *port)
 static void bfin_serial_start_tx(struct uart_port *port)
 {
        struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+       struct tty_struct *tty = uart->port.info->port.tty;
+
+#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
+       if (uart->scts && (!bfin_serial_get_mctrl(&uart->port)&TIOCM_CTS)) {
+               uart->scts = 0;
+               uart_handle_cts_change(&uart->port, uart->scts);
+       }
+#endif
+
+       /*
+        * To avoid losting RX interrupt, we reset IR function
+        * before sending data.
+        */
+       if (tty->termios->c_line == N_IRDA)
+               bfin_serial_reset_irda(port);
 
 #ifdef CONFIG_SERIAL_BFIN_DMA
        if (uart->tx_done)
@@ -110,9 +194,7 @@ static void bfin_serial_start_tx(struct uart_port *port)
 static void bfin_serial_stop_rx(struct uart_port *port)
 {
        struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-#ifdef CONFIG_KGDB_UART
-       if (uart->port.line != CONFIG_KGDB_UART_PORT)
-#endif
+
        UART_CLEAR_IER(uart, ERBFI);
 }
 
@@ -123,49 +205,6 @@ static void bfin_serial_enable_ms(struct uart_port *port)
 {
 }
 
-#ifdef CONFIG_KGDB_UART
-static int kgdb_entry_state;
-
-void kgdb_put_debug_char(int chr)
-{
-       struct bfin_serial_port *uart;
-
-       if (CONFIG_KGDB_UART_PORT < 0
-               || CONFIG_KGDB_UART_PORT >= BFIN_UART_NR_PORTS)
-               uart = &bfin_serial_ports[0];
-       else
-               uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
-
-       while (!(UART_GET_LSR(uart) & THRE)) {
-               SSYNC();
-       }
-
-       UART_CLEAR_DLAB(uart);
-       UART_PUT_CHAR(uart, (unsigned char)chr);
-       SSYNC();
-}
-
-int kgdb_get_debug_char(void)
-{
-       struct bfin_serial_port *uart;
-       unsigned char chr;
-
-       if (CONFIG_KGDB_UART_PORT < 0
-               || CONFIG_KGDB_UART_PORT >= BFIN_UART_NR_PORTS)
-               uart = &bfin_serial_ports[0];
-       else
-               uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
-
-       while(!(UART_GET_LSR(uart) & DR)) {
-               SSYNC();
-       }
-       UART_CLEAR_DLAB(uart);
-       chr = UART_GET_CHAR(uart);
-       SSYNC();
-
-       return chr;
-}
-#endif
 
 #if ANOMALY_05000363 && defined(CONFIG_SERIAL_BFIN_PIO)
 # define UART_GET_ANOMALY_THRESHOLD(uart)    ((uart)->anomaly_threshold)
@@ -178,7 +217,7 @@ int kgdb_get_debug_char(void)
 #ifdef CONFIG_SERIAL_BFIN_PIO
 static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
 {
-       struct tty_struct *tty = uart->port.info->port.tty;
+       struct tty_struct *tty = NULL;
        unsigned int status, ch, flg;
        static struct timeval anomaly_start = { .tv_sec = 0 };
 
@@ -188,27 +227,18 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
        ch = UART_GET_CHAR(uart);
        uart->port.icount.rx++;
 
-#ifdef CONFIG_KGDB_UART
-       if (uart->port.line == CONFIG_KGDB_UART_PORT) {
-               struct pt_regs *regs = get_irq_regs();
-               if (uart->port.cons->index == CONFIG_KGDB_UART_PORT && ch == 0x1) { /* Ctrl + A */
-                       kgdb_breakkey_pressed(regs);
-                       return;
-               } else if (kgdb_entry_state == 0 && ch == '$') {/* connection from KGDB */
-                       kgdb_entry_state = 1;
-               } else if (kgdb_entry_state == 1 && ch == 'q') {
-                       kgdb_entry_state = 0;
-                       kgdb_breakkey_pressed(regs);
+#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
+       if (kgdb_connected && kgdboc_port_line == uart->port.line)
+               if (ch == 0x3) {/* Ctrl + C */
+                       kgdb_breakpoint();
                        return;
-               } else if (ch == 0x3) {/* Ctrl + C */
-                       kgdb_entry_state = 0;
-                       kgdb_breakkey_pressed(regs);
-                       return;
-               } else {
-                       kgdb_entry_state = 0;
                }
-       }
+
+       if (!uart->port.info || !uart->port.info->port.tty)
+               return;
 #endif
+       tty = uart->port.info->port.tty;
 
        if (ANOMALY_05000363) {
                /* The BF533 (and BF561) family of processors have a nice anomaly
@@ -250,6 +280,7 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
                        return;
 
  known_good_char:
+                       status &= ~BI;
                        anomaly_start.tv_sec = 0;
                }
        }
@@ -294,12 +325,6 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
 {
        struct circ_buf *xmit = &uart->port.info->xmit;
 
-       /*
-        * Check the modem control lines before
-        * transmitting anything.
-        */
-       bfin_serial_mctrl_check(uart);
-
        if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
 #ifdef CONFIG_BF54x
                /* Clear TFI bit */
@@ -342,6 +367,12 @@ static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id)
 {
        struct bfin_serial_port *uart = dev_id;
 
+#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
+       if (uart->scts && (!bfin_serial_get_mctrl(&uart->port)&TIOCM_CTS)) {
+               uart->scts = 0;
+               uart_handle_cts_change(&uart->port, uart->scts);
+       }
+#endif
        spin_lock(&uart->port.lock);
        if (UART_GET_LSR(uart) & THRE)
                bfin_serial_tx_chars(uart);
@@ -358,12 +389,6 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
 
        uart->tx_done = 0;
 
-       /*
-        * Check the modem control lines before
-        * transmitting anything.
-        */
-       bfin_serial_mctrl_check(uart);
-
        if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
                uart->tx_count = 0;
                uart->tx_done = 1;
@@ -431,9 +456,11 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
        else
                flg = TTY_NORMAL;
 
-       for (i = uart->rx_dma_buf.tail; i != uart->rx_dma_buf.head; i++) {
+       for (i = uart->rx_dma_buf.tail; ; i++) {
                if (i >= UART_XMIT_SIZE)
                        i = 0;
+               if (i == uart->rx_dma_buf.head)
+                       break;
                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);
@@ -446,6 +473,9 @@ 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;
+       unsigned long flags;
+
+       spin_lock_irqsave(&uart->port.lock, flags);
 
        uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel);
        x_pos = get_dma_curr_xcount(uart->rx_dma_channel);
@@ -463,6 +493,8 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
                uart->rx_dma_buf.tail = uart->rx_dma_buf.head;
        }
 
+       spin_unlock_irqrestore(&uart->port.lock, flags);
+
        mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES);
 }
 
@@ -471,6 +503,13 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
        struct bfin_serial_port *uart = dev_id;
        struct circ_buf *xmit = &uart->port.info->xmit;
 
+#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
+       if (uart->scts && (!bfin_serial_get_mctrl(&uart->port)&TIOCM_CTS)) {
+               uart->scts = 0;
+               uart_handle_cts_change(&uart->port, uart->scts);
+       }
+#endif
+
        spin_lock(&uart->port.lock);
        if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) {
                disable_dma(uart->tx_dma_channel);
@@ -497,10 +536,9 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)
        spin_lock(&uart->port.lock);
        irqstat = get_dma_curr_irqstat(uart->rx_dma_channel);
        clear_dma_irqstat(uart->rx_dma_channel);
+       bfin_serial_dma_rx_chars(uart);
        spin_unlock(&uart->port.lock);
 
-       mod_timer(&(uart->rx_dma_timer), jiffies);
-
        return IRQ_HANDLED;
 }
 #endif
@@ -520,61 +558,6 @@ static unsigned int bfin_serial_tx_empty(struct uart_port *port)
                return 0;
 }
 
-static unsigned int bfin_serial_get_mctrl(struct uart_port *port)
-{
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-       if (uart->cts_pin < 0)
-               return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
-
-       if (UART_GET_CTS(uart))
-               return TIOCM_DSR | TIOCM_CAR;
-       else
-#endif
-               return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
-}
-
-static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
-       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-       if (uart->rts_pin < 0)
-               return;
-
-       if (mctrl & TIOCM_RTS)
-               UART_CLEAR_RTS(uart);
-       else
-               UART_SET_RTS(uart);
-#endif
-}
-
-/*
- * Handle any change of modem status signal since we were last called.
- */
-static void bfin_serial_mctrl_check(struct bfin_serial_port *uart)
-{
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
-       unsigned int status;
-       struct uart_info *info = uart->port.info;
-       struct tty_struct *tty = info->port.tty;
-
-       status = bfin_serial_get_mctrl(&uart->port);
-       uart_handle_cts_change(&uart->port, status & TIOCM_CTS);
-       if (!(status & TIOCM_CTS)) {
-               tty->hw_stopped = 1;
-               uart->cts_timer.data = (unsigned long)(uart);
-               uart->cts_timer.function = (void *)bfin_serial_mctrl_check;
-               uart->cts_timer.expires = jiffies + CTS_CHECK_JIFFIES;
-               add_timer(&(uart->cts_timer));
-       } else {
-               tty->hw_stopped = 0;
-       }
-#endif
-}
-
-/*
- * Interrupts are always disabled.
- */
 static void bfin_serial_break_ctl(struct uart_port *port, int break_state)
 {
        struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
@@ -630,16 +613,16 @@ static int bfin_serial_startup(struct uart_port *port)
        uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES;
        add_timer(&(uart->rx_dma_timer));
 #else
+# if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
+       if (kgdboc_port_line == uart->port.line && kgdboc_break_enabled)
+               kgdboc_break_enabled = 0;
+       else {
+# endif
        if (request_irq(uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED,
             "BFIN_UART_RX", uart)) {
-# ifdef        CONFIG_KGDB_UART
-               if (uart->port.line != CONFIG_KGDB_UART_PORT) {
-# endif
                printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n");
                return -EBUSY;
-# ifdef        CONFIG_KGDB_UART
-               }
-# endif
        }
 
        if (request_irq
@@ -685,7 +668,50 @@ static int bfin_serial_startup(struct uart_port *port)
                }
        }
 # endif
+# if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
+       }
+# endif
+#endif
+
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+       if (uart->cts_pin >= 0) {
+               if (request_irq(gpio_to_irq(uart->cts_pin),
+                       bfin_serial_mctrl_cts_int,
+                       IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+                       IRQF_DISABLED, "BFIN_UART_CTS", uart)) {
+                       uart->cts_pin = -1;
+                       pr_info("Unable to attach BlackFin UART CTS interrupt.\
+                                So, disable it.\n");
+               }
+       }
+       if (uart->rts_pin >= 0) {
+               gpio_request(uart->rts_pin, DRIVER_NAME);
+               gpio_direction_output(uart->rts_pin, 0);
+       }
+#endif
+#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
+       if (request_irq(uart->status_irq,
+               bfin_serial_mctrl_cts_int,
+               IRQF_DISABLED, "BFIN_UART_MODEM_STATUS", uart)) {
+               pr_info("Unable to attach BlackFin UART Modem \
+                       Status interrupt.\n");
+       }
+
+       if (uart->cts_pin >= 0) {
+               gpio_request(uart->cts_pin, DRIVER_NAME);
+               gpio_direction_output(uart->cts_pin, 1);
+       }
+       if (uart->rts_pin >= 0) {
+               gpio_request(uart->rts_pin, DRIVER_NAME);
+               gpio_direction_output(uart->rts_pin, 0);
+       }
+
+       /* CTS RTS PINs are negative assertive. */
+       UART_PUT_MCR(uart, ACTS);
+       UART_SET_IER(uart, EDSSI);
 #endif
+
        UART_SET_IER(uart, ERBFI);
        return 0;
 }
@@ -715,13 +741,25 @@ static void bfin_serial_shutdown(struct uart_port *port)
        default:
                break;
        };
-#endif
-#ifdef CONFIG_KGDB_UART
-       if (uart->port.line != CONFIG_KGDB_UART_PORT)
 #endif
        free_irq(uart->port.irq, uart);
        free_irq(uart->port.irq+1, uart);
 #endif
+
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+       if (uart->cts_pin >= 0)
+               free_irq(gpio_to_irq(uart->cts_pin), uart);
+       if (uart->rts_pin >= 0)
+               gpio_free(uart->rts_pin);
+#endif
+#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
+       if (uart->cts_pin >= 0)
+               gpio_free(uart->cts_pin);
+       if (uart->rts_pin >= 0)
+               gpio_free(uart->rts_pin);
+       if (UART_GET_IER(uart) && EDSSI)
+               free_irq(uart->status_irq, uart);
+#endif
 }
 
 static void
@@ -783,7 +821,7 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
        }
 
        baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
-       quot = uart_get_divisor(port, baud);
+       quot = uart_get_divisor(port, baud) - ANOMALY_05000230;
        spin_lock_irqsave(&uart->port.lock, flags);
 
        UART_SET_ANOMALY_THRESHOLD(uart, USEC_PER_SEC / baud * 15);
@@ -887,6 +925,65 @@ static void bfin_serial_set_ldisc(struct uart_port *port)
        }
 }
 
+static void bfin_serial_reset_irda(struct uart_port *port)
+{
+       int line = port->line;
+       unsigned short val;
+
+       val = UART_GET_GCTL(&bfin_serial_ports[line]);
+       val &= ~(IREN | RPOLC);
+       UART_PUT_GCTL(&bfin_serial_ports[line], val);
+       SSYNC();
+       val |= (IREN | RPOLC);
+       UART_PUT_GCTL(&bfin_serial_ports[line], val);
+       SSYNC();
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+static void bfin_serial_poll_put_char(struct uart_port *port, unsigned char chr)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+
+       while (!(UART_GET_LSR(uart) & THRE))
+               cpu_relax();
+
+       UART_CLEAR_DLAB(uart);
+       UART_PUT_CHAR(uart, (unsigned char)chr);
+}
+
+static int bfin_serial_poll_get_char(struct uart_port *port)
+{
+       struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+       unsigned char chr;
+
+       while (!(UART_GET_LSR(uart) & DR))
+               cpu_relax();
+
+       UART_CLEAR_DLAB(uart);
+       chr = UART_GET_CHAR(uart);
+
+       return chr;
+}
+#endif
+
+#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
+static void bfin_kgdboc_port_shutdown(struct uart_port *port)
+{
+       if (kgdboc_break_enabled) {
+               kgdboc_break_enabled = 0;
+               bfin_serial_shutdown(port);
+       }
+}
+
+static int bfin_kgdboc_port_startup(struct uart_port *port)
+{
+       kgdboc_port_line = port->line;
+       kgdboc_break_enabled = !bfin_serial_startup(port);
+       return 0;
+}
+#endif
+
 static struct uart_ops bfin_serial_pops = {
        .tx_empty       = bfin_serial_tx_empty,
        .set_mctrl      = bfin_serial_set_mctrl,
@@ -905,8 +1002,50 @@ static struct uart_ops bfin_serial_pops = {
        .request_port   = bfin_serial_request_port,
        .config_port    = bfin_serial_config_port,
        .verify_port    = bfin_serial_verify_port,
+#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+       defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
+       .kgdboc_port_startup    = bfin_kgdboc_port_startup,
+       .kgdboc_port_shutdown   = bfin_kgdboc_port_shutdown,
+#endif
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_put_char  = bfin_serial_poll_put_char,
+       .poll_get_char  = bfin_serial_poll_get_char,
+#endif
 };
 
+static void __init bfin_serial_hw_init(void)
+{
+#ifdef CONFIG_SERIAL_BFIN_UART0
+       peripheral_request(P_UART0_TX, DRIVER_NAME);
+       peripheral_request(P_UART0_RX, DRIVER_NAME);
+#endif
+
+#ifdef CONFIG_SERIAL_BFIN_UART1
+       peripheral_request(P_UART1_TX, DRIVER_NAME);
+       peripheral_request(P_UART1_RX, DRIVER_NAME);
+
+# if defined(CONFIG_BFIN_UART1_CTSRTS) && defined(CONFIG_BF54x)
+       peripheral_request(P_UART1_RTS, DRIVER_NAME);
+       peripheral_request(P_UART1_CTS, DRIVER_NAME);
+# endif
+#endif
+
+#ifdef CONFIG_SERIAL_BFIN_UART2
+       peripheral_request(P_UART2_TX, DRIVER_NAME);
+       peripheral_request(P_UART2_RX, DRIVER_NAME);
+#endif
+
+#ifdef CONFIG_SERIAL_BFIN_UART3
+       peripheral_request(P_UART3_TX, DRIVER_NAME);
+       peripheral_request(P_UART3_RX, DRIVER_NAME);
+
+# if defined(CONFIG_BFIN_UART3_CTSRTS) && defined(CONFIG_BF54x)
+       peripheral_request(P_UART3_RTS, DRIVER_NAME);
+       peripheral_request(P_UART3_CTS, DRIVER_NAME);
+# endif
+#endif
+}
+
 static void __init bfin_serial_init_ports(void)
 {
        static int first = 1;
@@ -916,6 +1055,8 @@ static void __init bfin_serial_init_ports(void)
                return;
        first = 0;
 
+       bfin_serial_hw_init();
+
        for (i = 0; i < nr_active_ports; i++) {
                bfin_serial_ports[i].port.uartclk   = get_sclk();
                bfin_serial_ports[i].port.fifosize  = BFIN_UART_TX_FIFO_SIZE;
@@ -928,6 +1069,8 @@ static void __init bfin_serial_init_ports(void)
                        bfin_serial_resource[i].uart_base_addr;
                bfin_serial_ports[i].port.irq       =
                        bfin_serial_resource[i].uart_irq;
+               bfin_serial_ports[i].status_irq     =
+                       bfin_serial_resource[i].uart_status_irq;
                bfin_serial_ports[i].port.flags     = UPF_BOOT_AUTOCONF;
 #ifdef CONFIG_SERIAL_BFIN_DMA
                bfin_serial_ports[i].tx_done        = 1;
@@ -938,19 +1081,17 @@ static void __init bfin_serial_init_ports(void)
                        bfin_serial_resource[i].uart_rx_dma_channel;
                init_timer(&(bfin_serial_ports[i].rx_dma_timer));
 #endif
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
-               init_timer(&(bfin_serial_ports[i].cts_timer));
+#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
+       defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
                bfin_serial_ports[i].cts_pin        =
                        bfin_serial_resource[i].uart_cts_pin;
                bfin_serial_ports[i].rts_pin        =
                        bfin_serial_resource[i].uart_rts_pin;
 #endif
-               bfin_serial_hw_init(&bfin_serial_ports[i]);
        }
-
 }
 
-#ifdef CONFIG_SERIAL_BFIN_CONSOLE
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
 /*
  * If the port was already initialised (eg, by a boot loader),
  * try to determine the current setup.
@@ -994,24 +1135,21 @@ bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,
        }
        pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __func__, *baud, *parity, *bits);
 }
-#endif
 
-#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
 static struct uart_driver bfin_serial_reg;
 
 static int __init
 bfin_serial_console_setup(struct console *co, char *options)
 {
        struct bfin_serial_port *uart;
-# ifdef CONFIG_SERIAL_BFIN_CONSOLE
        int baud = 57600;
        int bits = 8;
        int parity = 'n';
-#  ifdef CONFIG_SERIAL_BFIN_CTSRTS
+# if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
+       defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
        int flow = 'r';
-#  else
+# else
        int flow = 'n';
-#  endif
 # endif
 
        /*
@@ -1023,16 +1161,12 @@ bfin_serial_console_setup(struct console *co, char *options)
                co->index = 0;
        uart = &bfin_serial_ports[co->index];
 
-# ifdef CONFIG_SERIAL_BFIN_CONSOLE
        if (options)
                uart_parse_options(options, &baud, &parity, &bits, &flow);
        else
                bfin_serial_console_get_options(uart, &baud, &parity, &bits);
 
        return uart_set_options(&uart->port, co, baud, parity, bits, flow);
-# else
-       return 0;
-# endif
 }
 #endif /* defined (CONFIG_SERIAL_BFIN_CONSOLE) ||
                                 defined (CONFIG_EARLY_PRINTK) */
@@ -1054,7 +1188,7 @@ static void
 bfin_serial_console_write(struct console *co, const char *s, unsigned int count)
 {
        struct bfin_serial_port *uart = &bfin_serial_ports[co->index];
-       int flags = 0;
+       unsigned long flags;
 
        spin_lock_irqsave(&uart->port.lock, flags);
        uart_console_write(&uart->port, s, count, bfin_serial_console_putchar);
@@ -1076,10 +1210,7 @@ static int __init bfin_serial_rs_console_init(void)
 {
        bfin_serial_init_ports();
        register_console(&bfin_serial_console);
-#ifdef CONFIG_KGDB_UART
-       kgdb_entry_state = 0;
-       init_kgdb_uart();
-#endif
+
        return 0;
 }
 console_initcall(bfin_serial_rs_console_init);
@@ -1144,7 +1275,7 @@ struct console __init *bfin_earlyserial_init(unsigned int port,
        return &bfin_early_serial_console;
 }
 
-#endif /* CONFIG_SERIAL_BFIN_CONSOLE */
+#endif /* CONFIG_EARLY_PRINTK */
 
 static struct uart_driver bfin_serial_reg = {
        .owner                  = THIS_MODULE,
@@ -1212,7 +1343,8 @@ static int bfin_serial_remove(struct platform_device *dev)
                        continue;
                uart_remove_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
                bfin_serial_ports[i].port.dev = NULL;
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
+       defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
                gpio_free(bfin_serial_ports[i].cts_pin);
                gpio_free(bfin_serial_ports[i].rts_pin);
 #endif
@@ -1235,10 +1367,6 @@ static struct platform_driver bfin_serial_driver = {
 static int __init bfin_serial_init(void)
 {
        int ret;
-#ifdef CONFIG_KGDB_UART
-       struct bfin_serial_port *uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
-       struct ktermios t;
-#endif
 
        pr_info("Serial: Blackfin serial driver\n");
 
@@ -1252,21 +1380,6 @@ static int __init bfin_serial_init(void)
                        uart_unregister_driver(&bfin_serial_reg);
                }
        }
-#ifdef CONFIG_KGDB_UART
-       if (uart->port.cons->index != CONFIG_KGDB_UART_PORT) {
-               request_irq(uart->port.irq, bfin_serial_rx_int,
-                       IRQF_DISABLED, "BFIN_UART_RX", uart);
-               pr_info("Request irq for kgdb uart port\n");
-               UART_SET_IER(uart, ERBFI);
-               SSYNC();
-               t.c_cflag = CS8|B57600;
-               t.c_iflag = 0;
-               t.c_oflag = 0;
-               t.c_lflag = ICANON;
-               t.c_line = CONFIG_KGDB_UART_PORT;
-               bfin_serial_set_termios(&uart->port, &t, &t);
-       }
-#endif
        return ret;
 }
 
@@ -1276,6 +1389,7 @@ static void __exit bfin_serial_exit(void)
        uart_unregister_driver(&bfin_serial_reg);
 }
 
+
 module_init(bfin_serial_init);
 module_exit(bfin_serial_exit);