serial: Test/disable MSIs if switching from N_PPS
authorPeter Hurley <peter@hurleysoftware.com>
Wed, 5 Nov 2014 18:11:45 +0000 (13:11 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 6 Nov 2014 22:57:27 +0000 (14:57 -0800)
Switching to the N_PPS line discipline may require enabling
modem status interrupts; conversely switching from N_PPS may
require disabling modem status interrupts.

Affected drivers:
8250
amba-pl010
atmel

Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
Cc: Russell King <linux@arm.linux.org.uk>
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/8250/8250_core.c
drivers/tty/serial/amba-pl010.c
drivers/tty/serial/atmel_serial.c

index f0f35e782bc3e28dad618583da189d94d93c426c..25eb8e93615d35b63f09fd4a7e17a79ee141c46e 100644 (file)
@@ -1402,6 +1402,19 @@ static void serial8250_stop_rx(struct uart_port *port)
        serial8250_rpm_put(up);
 }
 
+static void serial8250_disable_ms(struct uart_port *port)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+
+       /* no MSR capabilities */
+       if (up->bugs & UART_BUG_NOMSR)
+               return;
+
+       up->ier &= ~UART_IER_MSI;
+       serial_port_out(port, UART_IER, up->ier);
+}
+
 static void serial8250_enable_ms(struct uart_port *port)
 {
        struct uart_8250_port *up = up_to_u8250p(port);
@@ -2616,8 +2629,14 @@ serial8250_set_ldisc(struct uart_port *port, struct ktermios *termios)
                spin_lock_irq(&port->lock);
                serial8250_enable_ms(port);
                spin_unlock_irq(&port->lock);
-       } else
+       } else {
                port->flags &= ~UPF_HARDPPS_CD;
+               if (!UART_ENABLE_MS(port, termios->c_cflag)) {
+                       spin_lock_irq(&port->lock);
+                       serial8250_disable_ms(port);
+                       spin_unlock_irq(&port->lock);
+               }
+       }
 }
 
 
index 194108b0de84249490390f955692c7e05b81842f..5d41d5b92619ad32512e83311e302652bae94969 100644 (file)
@@ -106,6 +106,16 @@ static void pl010_stop_rx(struct uart_port *port)
        writel(cr, uap->port.membase + UART010_CR);
 }
 
+static void pl010_disable_ms(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned int cr;
+
+       cr = readb(uap->port.membase + UART010_CR);
+       cr &= ~UART010_CR_MSIE;
+       writel(cr, uap->port.membase + UART010_CR);
+}
+
 static void pl010_enable_ms(struct uart_port *port)
 {
        struct uart_amba_port *uap =
@@ -486,8 +496,14 @@ static void pl010_set_ldisc(struct uart_port *port, struct ktermios *termios)
                spin_lock_irq(&port->lock);
                pl010_enable_ms(port);
                spin_unlock_irq(&port->lock);
-       } else
+       } else {
                port->flags &= ~UPF_HARDPPS_CD;
+               if (!UART_ENABLE_MS(port, termios->c_cflag)) {
+                       spin_lock_irq(&port->lock);
+                       pl010_disable_ms(port);
+                       spin_unlock_irq(&port->lock);
+               }
+       }
 }
 
 static const char *pl010_type(struct uart_port *port)
index e67cb38312800ed9e2b8d0f67bcd8a0f85da186c..b1d61dc3fc1b23e3182eccb44a3b1c908990deb9 100644 (file)
@@ -2065,6 +2065,11 @@ static void atmel_set_ldisc(struct uart_port *port, struct ktermios *termios)
                spin_unlock_irq(&port->lock);
        } else {
                port->flags &= ~UPF_HARDPPS_CD;
+               if (!UART_ENABLE_MS(port, termios->c_cflag)) {
+                       spin_lock_irq(&port->lock);
+                       atmel_disable_ms(port);
+                       spin_unlock_irq(&port->lock);
+               }
        }
 }