serial: 8250_dw: Report CTS asserted for auto flow
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / tty / serial / 8250 / 8250_dw.c
index 5d880917850f632fce58244662081b54686d6e36..37a68278290d59f75069fe6f1d0e6c6f6154beee 100644 (file)
 
 struct dw8250_data {
        int             last_lcr;
+       int             last_mcr;
        int             line;
        struct clk      *clk;
 };
 
+static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
+{
+       struct dw8250_data *d = p->private_data;
+
+       /* If reading MSR, report CTS asserted when auto-CTS/RTS enabled */
+       if (offset == UART_MSR && d->last_mcr & UART_MCR_AFE) {
+               value |= UART_MSR_CTS;
+               value &= ~UART_MSR_DCTS;
+       }
+
+       return value;
+}
+
 static void dw8250_serial_out(struct uart_port *p, int offset, int value)
 {
        struct dw8250_data *d = p->private_data;
@@ -66,15 +80,17 @@ static void dw8250_serial_out(struct uart_port *p, int offset, int value)
        if (offset == UART_LCR)
                d->last_lcr = value;
 
-       offset <<= p->regshift;
-       writeb(value, p->membase + offset);
+       if (offset == UART_MCR)
+               d->last_mcr = value;
+
+       writeb(value, p->membase + (offset << p->regshift));
 }
 
 static unsigned int dw8250_serial_in(struct uart_port *p, int offset)
 {
-       offset <<= p->regshift;
+       unsigned int value = readb(p->membase + (offset << p->regshift));
 
-       return readb(p->membase + offset);
+       return dw8250_modify_msr(p, offset, value);
 }
 
 static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
@@ -84,15 +100,17 @@ static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
        if (offset == UART_LCR)
                d->last_lcr = value;
 
-       offset <<= p->regshift;
-       writel(value, p->membase + offset);
+       if (offset == UART_MCR)
+               d->last_mcr = value;
+
+       writel(value, p->membase + (offset << p->regshift));
 }
 
 static unsigned int dw8250_serial_in32(struct uart_port *p, int offset)
 {
-       offset <<= p->regshift;
+       unsigned int value = readl(p->membase + (offset << p->regshift));
 
-       return readl(p->membase + offset);
+       return dw8250_modify_msr(p, offset, value);
 }
 
 static int dw8250_handle_irq(struct uart_port *p)