serial: omap: fix the reciever line error case
[pandora-kernel.git] / drivers / tty / serial / omap-serial.c
index 6a58f4f..ccc2f35 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/slab.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
+#include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/clk.h>
 #include <linux/serial_core.h>
@@ -39,8 +40,8 @@
 #include <linux/pm_runtime.h>
 #include <linux/of.h>
 #include <linux/gpio.h>
+#include <linux/pinctrl/consumer.h>
 
-#include <plat/dmtimer.h>
 #include <plat/omap-serial.h>
 
 #define UART_BUILD_REVISION(x, y)      (((x) << 8) | (y))
@@ -56,8 +57,8 @@
 #define OMAP_UART_SCR_RX_TRIG_GRANU1_MASK              (1 << 7)
 
 /* FCR register bitmasks */
-#define OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT               6
 #define OMAP_UART_FCR_RX_FIFO_TRIG_MASK                        (0x3 << 6)
+#define OMAP_UART_FCR_TX_FIFO_TRIG_MASK                        (0x3 << 4)
 
 /* MVR register bitmasks */
 #define OMAP_UART_MVR_SCHEME_SHIFT     30
 #define OMAP_UART_MVR_MAJ_SHIFT                8
 #define OMAP_UART_MVR_MIN_MASK         0x3f
 
+struct uart_omap_port {
+       struct uart_port        port;
+       struct uart_omap_dma    uart_dma;
+       struct device           *dev;
+
+       unsigned char           ier;
+       unsigned char           lcr;
+       unsigned char           mcr;
+       unsigned char           fcr;
+       unsigned char           efr;
+       unsigned char           dll;
+       unsigned char           dlh;
+       unsigned char           mdr1;
+       unsigned char           scr;
+
+       int                     use_dma;
+       /*
+        * Some bits in registers are cleared on a read, so they must
+        * be saved whenever the register is read but the bits will not
+        * be immediately processed.
+        */
+       unsigned int            lsr_break_flag;
+       unsigned char           msr_saved_flags;
+       char                    name[20];
+       unsigned long           port_activity;
+       u32                     context_loss_cnt;
+       u32                     errata;
+       u8                      wakeups_enabled;
+       unsigned int            irq_pending:1;
+
+       int                     DTR_gpio;
+       int                     DTR_inverted;
+       int                     DTR_active;
+
+       struct pm_qos_request   pm_qos_request;
+       u32                     latency;
+       u32                     calc_latency;
+       struct work_struct      qos_work;
+       struct pinctrl          *pins;
+};
+
+#define to_uart_omap_port(p)   ((container_of((p), struct uart_omap_port, port)))
+
 static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
 
 /* Forward declaration of functions */
@@ -101,7 +145,7 @@ static int serial_omap_get_context_loss_count(struct uart_omap_port *up)
 {
        struct omap_uart_port_info *pdata = up->dev->platform_data;
 
-       if (!pdata->get_context_loss_count)
+       if (!pdata || !pdata->get_context_loss_count)
                return 0;
 
        return pdata->get_context_loss_count(up->dev);
@@ -111,24 +155,30 @@ static void serial_omap_set_forceidle(struct uart_omap_port *up)
 {
        struct omap_uart_port_info *pdata = up->dev->platform_data;
 
-       if (pdata->set_forceidle)
-               pdata->set_forceidle(up->dev);
+       if (!pdata || !pdata->set_forceidle)
+               return;
+
+       pdata->set_forceidle(up->dev);
 }
 
 static void serial_omap_set_noidle(struct uart_omap_port *up)
 {
        struct omap_uart_port_info *pdata = up->dev->platform_data;
 
-       if (pdata->set_noidle)
-               pdata->set_noidle(up->dev);
+       if (!pdata || !pdata->set_noidle)
+               return;
+
+       pdata->set_noidle(up->dev);
 }
 
 static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable)
 {
        struct omap_uart_port_info *pdata = up->dev->platform_data;
 
-       if (pdata->enable_wakeup)
-               pdata->enable_wakeup(up->dev, enable);
+       if (!pdata || !pdata->enable_wakeup)
+               return;
+
+       pdata->enable_wakeup(up->dev, enable);
 }
 
 /*
@@ -284,6 +334,10 @@ static unsigned int check_modem_status(struct uart_omap_port *up)
 static void serial_omap_rlsi(struct uart_omap_port *up, unsigned int lsr)
 {
        unsigned int flag;
+       unsigned char ch = 0;
+
+       if (likely(lsr & UART_LSR_DR))
+               ch = serial_in(up, UART_RX);
 
        up->port.icount.rx++;
        flag = TTY_NORMAL;
@@ -617,19 +671,19 @@ serial_omap_configure_xonxoff
 
        /*
         * IXON Flag:
-        * Enable XON/XOFF flow control on output.
-        * Transmit XON1, XOFF1
+        * Flow control for OMAP.TX
+        * OMAP.RX should listen for XON/XOFF
         */
        if (termios->c_iflag & IXON)
-               up->efr |= OMAP_UART_SW_TX;
+               up->efr |= OMAP_UART_SW_RX;
 
        /*
         * IXOFF Flag:
-        * Enable XON/XOFF flow control on input.
-        * Receiver compares XON1, XOFF1.
+        * Flow control for OMAP.RX
+        * OMAP.TX should send XON/XOFF
         */
        if (termios->c_iflag & IXOFF)
-               up->efr |= OMAP_UART_SW_RX;
+               up->efr |= OMAP_UART_SW_TX;
 
        serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
        serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
@@ -796,9 +850,13 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
 
        up->scr |= OMAP_UART_SCR_RX_TRIG_GRANU1_MASK;
 
-       /* Set receive FIFO threshold to 1 byte */
+       /* Set receive FIFO threshold to 16 characters and
+        * transmit FIFO threshold to 16 spaces
+        */
        up->fcr &= ~OMAP_UART_FCR_RX_FIFO_TRIG_MASK;
-       up->fcr |= (0x1 << OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT);
+       up->fcr &= ~OMAP_UART_FCR_TX_FIFO_TRIG_MASK;
+       up->fcr |= UART_FCR6_R_TRIGGER_16 | UART_FCR6_T_TRIGGER_24 |
+               UART_FCR_ENABLE_FIFO;
 
        serial_out(up, UART_FCR, up->fcr);
        serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
@@ -1168,10 +1226,8 @@ static int serial_omap_suspend(struct device *dev)
 {
        struct uart_omap_port *up = dev_get_drvdata(dev);
 
-       if (up) {
-               uart_suspend_port(&serial_omap_reg, &up->port);
-               flush_work_sync(&up->qos_work);
-       }
+       uart_suspend_port(&serial_omap_reg, &up->port);
+       flush_work_sync(&up->qos_work);
 
        return 0;
 }
@@ -1180,8 +1236,8 @@ static int serial_omap_resume(struct device *dev)
 {
        struct uart_omap_port *up = dev_get_drvdata(dev);
 
-       if (up)
-               uart_resume_port(&serial_omap_reg, &up->port);
+       uart_resume_port(&serial_omap_reg, &up->port);
+
        return 0;
 }
 #endif
@@ -1325,6 +1381,13 @@ static int __devinit serial_omap_probe(struct platform_device *pdev)
                goto err_port_line;
        }
 
+       up->pins = devm_pinctrl_get_select_default(&pdev->dev);
+       if (IS_ERR(up->pins)) {
+               dev_warn(&pdev->dev, "did not get pins for uart%i error: %li\n",
+                        up->port.line, PTR_ERR(up->pins));
+               up->pins = NULL;
+       }
+
        sprintf(up->name, "OMAP UART%d", up->port.line);
        up->port.mapbase = mem->start;
        up->port.membase = devm_ioremap(&pdev->dev, mem->start,
@@ -1492,17 +1555,14 @@ static int serial_omap_runtime_suspend(struct device *dev)
 static int serial_omap_runtime_resume(struct device *dev)
 {
        struct uart_omap_port *up = dev_get_drvdata(dev);
-       struct omap_uart_port_info *pdata = dev->platform_data;
 
-       if (up && pdata) {
-                       u32 loss_cnt = serial_omap_get_context_loss_count(up);
+       u32 loss_cnt = serial_omap_get_context_loss_count(up);
 
-                       if (up->context_loss_cnt != loss_cnt)
-                               serial_omap_restore_context(up);
+       if (up->context_loss_cnt != loss_cnt)
+               serial_omap_restore_context(up);
 
-               up->latency = up->calc_latency;
-               schedule_work(&up->qos_work);
-       }
+       up->latency = up->calc_latency;
+       schedule_work(&up->qos_work);
 
        return 0;
 }