aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty
diff options
context:
space:
mode:
authorPeter Hurley <peter@hurleysoftware.com>2014-12-30 20:28:15 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-01-09 17:10:46 -0500
commit4bf4ea9dca4ba1984abeb592f429265b9bacac42 (patch)
tree104bf2aa066b9fd105013f0fa8262722a77ce525 /drivers/tty
parentfbf7ebe4d9faf2225d15edb9ebc66bf99800776a (diff)
serial: omap_8250: Fix RTS handling
The OMAP3 UART ignores MCR[1] (ie., UART_MCR_RTS) when in autoRTS mode (UPF_HARD_FLOW + CRTSCTS). This makes it impossible for either the serial core or userspace to manually flow control the sender. Disable autoRTS mode when RTS is lowered and restore the previous mode when RTS is raised. Note that the OMAP3 UART provides no mechanism for switching from autoRTS mode without corrupting incoming data; to access the necessary register, the line control settings must be set to 8-e-2 and thus any data received during that time will be interpreted with those settings. This corruption has been observed in practice. Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/serial/8250/8250_core.c12
-rw-r--r--drivers/tty/serial/8250/8250_omap.c25
2 files changed, 33 insertions, 4 deletions
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 11c66856ba2f..3bfcfdb57d05 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -1924,7 +1924,7 @@ static unsigned int serial8250_get_mctrl(struct uart_port *port)
1924 return ret; 1924 return ret;
1925} 1925}
1926 1926
1927static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl) 1927void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl)
1928{ 1928{
1929 struct uart_8250_port *up = up_to_u8250p(port); 1929 struct uart_8250_port *up = up_to_u8250p(port);
1930 unsigned char mcr = 0; 1930 unsigned char mcr = 0;
@@ -1944,6 +1944,14 @@ static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
1944 1944
1945 serial_port_out(port, UART_MCR, mcr); 1945 serial_port_out(port, UART_MCR, mcr);
1946} 1946}
1947EXPORT_SYMBOL_GPL(serial8250_do_set_mctrl);
1948
1949static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
1950{
1951 if (port->set_mctrl)
1952 return port->set_mctrl(port, mctrl);
1953 return serial8250_do_set_mctrl(port, mctrl);
1954}
1947 1955
1948static void serial8250_break_ctl(struct uart_port *port, int break_state) 1956static void serial8250_break_ctl(struct uart_port *port, int break_state)
1949{ 1957{
@@ -3605,6 +3613,8 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
3605 /* Possibly override set_termios call */ 3613 /* Possibly override set_termios call */
3606 if (up->port.set_termios) 3614 if (up->port.set_termios)
3607 uart->port.set_termios = up->port.set_termios; 3615 uart->port.set_termios = up->port.set_termios;
3616 if (up->port.set_mctrl)
3617 uart->port.set_mctrl = up->port.set_mctrl;
3608 if (up->port.startup) 3618 if (up->port.startup)
3609 uart->port.startup = up->port.startup; 3619 uart->port.startup = up->port.startup;
3610 if (up->port.shutdown) 3620 if (up->port.shutdown)
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index 273f37c6b493..227033db214b 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -106,6 +106,27 @@ static u32 uart_read(struct uart_8250_port *up, u32 reg)
106 return readl(up->port.membase + (reg << up->port.regshift)); 106 return readl(up->port.membase + (reg << up->port.regshift));
107} 107}
108 108
109static void omap8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
110{
111 struct uart_8250_port *up = up_to_u8250p(port);
112 struct omap8250_priv *priv = up->port.private_data;
113 u8 lcr;
114
115 serial8250_do_set_mctrl(port, mctrl);
116
117 /*
118 * Turn off autoRTS if RTS is lowered and restore autoRTS setting
119 * if RTS is raised
120 */
121 lcr = serial_in(up, UART_LCR);
122 serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
123 if (mctrl & TIOCM_RTS)
124 serial_out(up, UART_EFR, priv->efr);
125 else
126 serial_out(up, UART_EFR, priv->efr & ~UART_EFR_RTS);
127 serial_out(up, UART_LCR, lcr);
128}
129
109/* 130/*
110 * Work Around for Errata i202 (2430, 3430, 3630, 4430 and 4460) 131 * Work Around for Errata i202 (2430, 3430, 3630, 4430 and 4460)
111 * The access to uart register after MDR1 Access 132 * The access to uart register after MDR1 Access
@@ -400,9 +421,6 @@ static void omap_8250_set_termios(struct uart_port *port,
400 if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) { 421 if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) {
401 /* Enable AUTORTS and AUTOCTS */ 422 /* Enable AUTORTS and AUTOCTS */
402 priv->efr |= UART_EFR_CTS | UART_EFR_RTS; 423 priv->efr |= UART_EFR_CTS | UART_EFR_RTS;
403
404 /* Ensure MCR RTS is asserted */
405 up->mcr |= UART_MCR_RTS;
406 } else if (up->port.flags & UPF_SOFT_FLOW) { 424 } else if (up->port.flags & UPF_SOFT_FLOW) {
407 /* 425 /*
408 * IXON Flag: 426 * IXON Flag:
@@ -1007,6 +1025,7 @@ static int omap8250_probe(struct platform_device *pdev)
1007 up.capabilities |= UART_CAP_RPM; 1025 up.capabilities |= UART_CAP_RPM;
1008#endif 1026#endif
1009 up.port.set_termios = omap_8250_set_termios; 1027 up.port.set_termios = omap_8250_set_termios;
1028 up.port.set_mctrl = omap8250_set_mctrl;
1010 up.port.pm = omap_8250_pm; 1029 up.port.pm = omap_8250_pm;
1011 up.port.startup = omap_8250_startup; 1030 up.port.startup = omap_8250_startup;
1012 up.port.shutdown = omap_8250_shutdown; 1031 up.port.shutdown = omap_8250_shutdown;