a22:uart:add uart busy judgement before set the baud rate
authorhhb <hhb@rock-chips.com>
Tue, 9 Aug 2011 01:58:04 +0000 (09:58 +0800)
committerroot <root@lw.(none)>
Tue, 9 Aug 2011 06:11:41 +0000 (14:11 +0800)
drivers/serial/rk_serial.c

index a1e1c5af6082ff14486c9c94b7229d5cdf71d4e2..cc31fb048f93dd78e8cb34df929572803e5c2a11 100644 (file)
@@ -56,9 +56,6 @@
 #define UART_USR       0x1F    /* UART Status Register */\r
 #define UART_USR_BUSY (1)\r
 #define UART_IER_PTIME 0x80    /* Programmable THRE Interrupt Mode Enable */\r
-#define UART_LSR_RFE   0x80    /* receive fifo error */\r
-\r
-\r
 #define RX_TIMEOUT             (3000*10)  //uint ms\r
 \r
 #define BOTH_EMPTY     (UART_LSR_TEMT | UART_LSR_THRE)\r
@@ -106,9 +103,9 @@ static struct uart_driver serial_rk_reg;
 #define uart_console(port)     (0)\r
 #endif\r
 \r
-#define DEBUG 0\r
-\r
+#ifdef DEBUG\r
 extern void printascii(const char *);\r
+\r
 static void dbg(const char *fmt, ...)\r
 {\r
        va_list va;\r
@@ -121,7 +118,6 @@ static void dbg(const char *fmt, ...)
        printascii(buff);\r
 }\r
 \r
-#if DEBUG\r
 #define DEBUG_INTR(fmt...)     if (!uart_console(&up->port)) dbg(fmt)\r
 #else\r
 #define DEBUG_INTR(fmt...)     do { } while (0)\r
@@ -236,28 +232,26 @@ static inline void serial_dl_write(struct uart_rk_port *up, unsigned int value)
        serial_out(up, UART_DLM, value >> 8 & 0xff);\r
 }\r
 \r
-static int serial_lcr_write(struct uart_rk_port *up, unsigned char value)\r
+static void serial_lcr_write(struct uart_rk_port *up, unsigned char value)\r
 {\r
-       unsigned int tmout = 10000;\r
-       unsigned char lcr;\r
-\r
-       lcr = serial_in(up, UART_LCR);\r
-       if (lcr == value)\r
-               return -1;\r
-\r
-       while(serial_in(up, UART_USR) & UART_USR_BUSY){\r
+       unsigned int tmout = 15000;\r
 \r
+       for (;;) {\r
+               unsigned char lcr;\r
+               serial_out(up, UART_LCR, value);\r
+               lcr = serial_in(up, UART_LCR);\r
+               if (lcr == value)\r
+                       break;\r
+               /* Read the USR to clear any busy interrupts */\r
+               serial_in(up, UART_USR);\r
+               serial_in(up, UART_RX);\r
                if (--tmout == 0){\r
-                       dbg("set serial.%d lcr timeout\n", up->port.line);\r
-                       return -1;\r
+                       dev_info(up->port.dev, "set lcr timeout\n");\r
+                       break;\r
                }\r
-               udelay(1);\r
-       }\r
 \r
-       if (tmout != 0){\r
-               serial_out(up, UART_LCR, value);\r
+               udelay(1);\r
        }\r
-       return 0;\r
 }\r
 \r
 static inline void serial_rk_enable_ier_thri(struct uart_rk_port *up)\r
@@ -277,26 +271,6 @@ static inline void serial_rk_disable_ier_thri(struct uart_rk_port *up)
        }\r
 }\r
 \r
-static int rk29_uart_dump_register(struct uart_rk_port *up){\r
-\r
-       unsigned int reg_value = 0;\r
-\r
-       reg_value = serial_in(up, UART_IER);\r
-       dbg("UART_IER = 0x%0x\n", reg_value);\r
-       reg_value = serial_in(up, UART_IIR);\r
-       dbg("UART_IIR = 0x%0x\n", reg_value);\r
-//     reg_value = serial_in(up, 0X25);\r
-//     dbg("DMA_MODE = 0x%0x\n", reg_value);\r
-    reg_value = serial_in(up, UART_LSR);\r
-    dbg("UART_LSR = 0x%0x\n", reg_value);\r
-    reg_value = serial_in(up, 0x21);\r
-    dbg("UART_RFL = 0x%0x\n", reg_value);\r
-       return 0;\r
-\r
-}\r
-\r
-\r
-\r
 /*\r
  * FIFO support.\r
  */\r
@@ -755,9 +729,8 @@ receive_chars(struct uart_rk_port *up, unsigned int *status)
        char flag;\r
 \r
        do {\r
-               if (likely(lsr & UART_LSR_DR)){\r
+               if (likely(lsr & UART_LSR_DR))\r
                        ch = serial_in(up, UART_RX);\r
-               }\r
                else\r
                        /*\r
                         * Intel 82571 has a Serial Over Lan device that will\r
@@ -897,14 +870,14 @@ static void serial_rk_handle_port(struct uart_rk_port *up)
        unsigned long flags;\r
        spin_lock_irqsave(&up->port.lock, flags);\r
 \r
-       /* reading UART_LSR can automatically clears PE FE OE bits, except receive fifo error bit*/\r
        status = serial_in(up, UART_LSR);\r
-       \r
+\r
        DEBUG_INTR("status = %x...", status);\r
-       /* DMA mode enable */\r
+\r
        if(up->prk29_uart_dma_t->use_dma == 1) {\r
 \r
                if(up->iir & UART_IIR_RLSI){\r
+\r
                        if (status & (UART_LSR_DR | UART_LSR_BI)) {\r
                                up->port_activity = jiffies;\r
                                up->ier &= ~UART_IER_RLSI;\r
@@ -912,28 +885,21 @@ static void serial_rk_handle_port(struct uart_rk_port *up)
                                serial_out(up, UART_IER, up->ier);\r
                                //receive_chars(up, &status);\r
                                //mod_timer(&up->prk29_uart_dma_t->rx_timer, jiffies +\r
-                               //msecs_to_jiffies(up->prk29_uart_dma_t->rx_timeout));\r
+                                                               //msecs_to_jiffies(up->prk29_uart_dma_t->rx_timeout));\r
                                if(serial_rk_start_rx_dma(&up->port) == -1){\r
                                        receive_chars(up, &status);\r
                                }\r
                        }\r
                }\r
 \r
+/*\r
+               if (status & UART_LSR_THRE) {\r
+                       transmit_chars(up);\r
+               }\r
+*/\r
+\r
        }else {   //dma mode disable\r
 \r
-               /*\r
-                * when uart receive a serial of data which doesn't have stop bit and so on, that causes frame error,and\r
-                * set UART_LSR_RFE to one,what is worse,we couldn't read the data in the receive fifo. So if\r
-                * wo don't clear this bit and reset the receive fifo, the received data available interrupt would\r
-                * occur continuously.  added by hhb@rock-chips.com 2011-08-05\r
-                */\r
-               if(status & UART_LSR_RFE){\r
-                       dbg("serial.%d LSR = 0x%02x...\n", up->port.line, status);\r
-                       serial_out(up, UART_FCR, serial_in(up, UART_FCR) | UART_FCR_CLEAR_RCVR);\r
-                       //dsb();   //dsb is an instruction that make sure write the UART_FCR in time\r
-                       serial_in(up, UART_RX);\r
-                       rk29_uart_dump_register(up);\r
-               }\r
                if (status & (UART_LSR_DR | UART_LSR_BI)) {\r
                        receive_chars(up, &status);\r
                }\r
@@ -958,24 +924,23 @@ static irqreturn_t serial_rk_interrupt(int irq, void *dev_id)
 \r
        iir = serial_in(up, UART_IIR);\r
        DEBUG_INTR("%s(%d) iir = 0x%02x ", __func__, irq, iir);\r
-\r
        up->iir = iir;\r
 \r
        if (!(iir & UART_IIR_NO_INT)) {\r
                serial_rk_handle_port(up);\r
                handled = 1;\r
        } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {\r
-\r
                /* The DesignWare APB UART has an Busy Detect (0x07)\r
                 * interrupt meaning an LCR write attempt occured while the\r
                 * UART was busy. The interrupt must be cleared by reading\r
                 * the UART status register (USR) and the LCR re-written. */\r
                                 \r
                if(!(serial_in(up, UART_USR) & UART_USR_BUSY)){\r
-                       serial_out(up, UART_LCR, up->lcr);\r
+                       //serial_out(up, UART_LCR, up->lcr);\r
                }\r
+\r
                handled = 1;\r
-               dbg("the serial.%d is busy\n", up->port.line);\r
+               dev_info(up->port.dev, "the serial is busy\n");\r
        }\r
        DEBUG_INTR("end(%d).\n", handled);\r
 \r
@@ -1154,6 +1119,8 @@ static int serial_rk_startup(struct uart_port *port)
 \r
        up->mcr = 0;\r
 \r
+       clk_enable(up->clk);  // enable the config uart clock\r
+\r
        /*\r
         * Clear the FIFO buffers and disable them.\r
         * (they will be reenabled in set_termios())\r
@@ -1190,11 +1157,11 @@ static int serial_rk_startup(struct uart_port *port)
         * saved flags to avoid getting false values from polling\r
         * routines or the previous session.\r
         */\r
-       (void) serial_in(up, UART_LSR);\r
-       (void) serial_in(up, UART_RX);\r
-       (void) serial_in(up, UART_IIR);\r
-       (void) serial_in(up, UART_MSR);\r
-       (void) serial_in(up, UART_USR);\r
+       serial_in(up, UART_LSR);\r
+       serial_in(up, UART_RX);\r
+       serial_in(up, UART_IIR);\r
+       serial_in(up, UART_MSR);\r
+       serial_in(up, UART_USR);\r
        up->lsr_saved_flags = 0;\r
 #if 0\r
        up->msr_saved_flags = 0;\r
@@ -1270,7 +1237,7 @@ serial_rk_set_termios(struct uart_port *port, struct ktermios *termios,
 {\r
        struct uart_rk_port *up =\r
                container_of(port, struct uart_rk_port, port);\r
-       unsigned char cval, fcr = 0;\r
+       unsigned char cval=0, fcr = 0;\r
        unsigned long flags, bits;\r
        unsigned int baud, quot;\r
 \r
@@ -1292,7 +1259,6 @@ serial_rk_set_termios(struct uart_port *port, struct ktermios *termios,
                bits += 7;\r
                break;\r
        default:\r
-       case CS8:\r
                cval = UART_LCR_WLEN8;\r
                bits += 8;\r
                break;\r
@@ -1327,9 +1293,19 @@ serial_rk_set_termios(struct uart_port *port, struct ktermios *termios,
        quot = uart_get_divisor(port, baud);\r
 \r
 \r
-//     dev_info(up->port.dev, "*****baud:%d*******\n", baud);\r
+       dev_info(up->port.dev, "*****baud:%d*******\n", baud);\r
 //     dev_info(up->port.dev, "*****quot:%d*******\n", quot);\r
 \r
+       int timeout = 10000000;\r
+       while(serial_in(up, UART_USR)&UART_USR_BUSY){\r
+       if(timeout-- == 0){\r
+       printk("rk29_serial_set_termios uart timeout,uart%d,ret=0x%x\n",up->port.line,serial_in(up, UART_USR));\r
+       break;\r
+       }\r
+       cpu_relax();\r
+       }\r
+       printk("%s:timeout=%d\n",__FUNCTION__,timeout);\r
+\r
        if (baud < 2400){\r
                fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;\r
        }\r
@@ -1356,6 +1332,7 @@ serial_rk_set_termios(struct uart_port *port, struct ktermios *termios,
                up->mcr |= UART_MCR_AFE;\r
        }\r
 \r
+\r
        /*\r
         * Ok, we're now changing the port state.  Do it with\r
         * interrupts disabled.\r
@@ -1411,15 +1388,13 @@ serial_rk_set_termios(struct uart_port *port, struct ktermios *termios,
        serial_lcr_write(up, cval);             /* reset DLAB */\r
        up->lcr = cval;                         /* Save LCR */\r
 \r
-       serial_out(up, UART_FCR, fcr);          /* set fcr */\r
-\r
        serial_rk_set_mctrl(&up->port, up->port.mctrl);\r
-       \r
-       /* enable the uart interrupt last */\r
+\r
+       serial_out(up, UART_FCR, fcr);          /* set fcr */\r
        up->ier |= UART_IER_RDI;\r
        up->ier |= UART_IER_RLSI;\r
        serial_out(up, UART_IER, up->ier);\r
-       \r
+\r
        spin_unlock_irqrestore(&up->port.lock, flags);\r
        /* Don't rewrite B0 */\r
        if (tty_termios_baud_rate(termios))\r
@@ -1696,7 +1671,7 @@ static int __devinit serial_rk_probe(struct platform_device *pdev)
                goto do_put_clk;\r
        }\r
        up->port.mapbase = mem->start;\r
-       up->port.irqflags = IRQF_DISABLED;\r
+       up->port.irqflags = 0;\r
        up->port.uartclk = clk_get_rate(up->clk);\r
 \r
        /* set dma config */\r