aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Hurley <peter@hurleysoftware.com>2015-01-25 14:44:53 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-02-02 13:11:28 -0500
commit348f9bb31c56909f9098a598b6ecdc94a560816e (patch)
tree596e59be8c982acd179d7781b433b8d8285c3aba
parent9719acce37803d179fc94884c8d50b883fc8186e (diff)
serial: omap: Fix RTS handling
The OMAP UART ignores MCR[1] (ie., RTS) when in autoRTS mode. 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. Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/tty/serial/omap-serial.c22
1 files changed, 14 insertions, 8 deletions
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 6129fe515932..10256fa04b40 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -681,7 +681,7 @@ static unsigned int serial_omap_get_mctrl(struct uart_port *port)
681static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl) 681static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
682{ 682{
683 struct uart_omap_port *up = to_uart_omap_port(port); 683 struct uart_omap_port *up = to_uart_omap_port(port);
684 unsigned char mcr = 0, old_mcr; 684 unsigned char mcr = 0, old_mcr, lcr;
685 685
686 dev_dbg(up->port.dev, "serial_omap_set_mctrl+%d\n", up->port.line); 686 dev_dbg(up->port.dev, "serial_omap_set_mctrl+%d\n", up->port.line);
687 if (mctrl & TIOCM_RTS) 687 if (mctrl & TIOCM_RTS)
@@ -701,6 +701,17 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
701 UART_MCR_DTR | UART_MCR_RTS); 701 UART_MCR_DTR | UART_MCR_RTS);
702 up->mcr = old_mcr | mcr; 702 up->mcr = old_mcr | mcr;
703 serial_out(up, UART_MCR, up->mcr); 703 serial_out(up, UART_MCR, up->mcr);
704
705 /* Turn off autoRTS if RTS is lowered; restore autoRTS if RTS raised */
706 lcr = serial_in(up, UART_LCR);
707 serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
708 if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
709 up->efr |= UART_EFR_RTS;
710 else
711 up->efr &= UART_EFR_RTS;
712 serial_out(up, UART_EFR, up->efr);
713 serial_out(up, UART_LCR, lcr);
714
704 pm_runtime_mark_last_busy(up->dev); 715 pm_runtime_mark_last_busy(up->dev);
705 pm_runtime_put_autosuspend(up->dev); 716 pm_runtime_put_autosuspend(up->dev);
706} 717}
@@ -756,8 +767,6 @@ static int serial_omap_startup(struct uart_port *port)
756 * (they will be reenabled in set_termios()) 767 * (they will be reenabled in set_termios())
757 */ 768 */
758 serial_omap_clear_fifos(up); 769 serial_omap_clear_fifos(up);
759 /* For Hardware flow control */
760 serial_out(up, UART_MCR, UART_MCR_RTS);
761 770
762 /* 771 /*
763 * Clear the interrupt registers. 772 * Clear the interrupt registers.
@@ -1056,12 +1065,9 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
1056 up->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF); 1065 up->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF);
1057 1066
1058 if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) { 1067 if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) {
1059 /* Enable AUTORTS and AUTOCTS */ 1068 /* Enable AUTOCTS (autoRTS is enabled when RTS is raised) */
1060 up->port.status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS; 1069 up->port.status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
1061 up->efr |= UART_EFR_CTS | UART_EFR_RTS; 1070 up->efr |= UART_EFR_CTS;
1062
1063 /* Ensure MCR RTS is asserted */
1064 up->mcr |= UART_MCR_RTS;
1065 } else { 1071 } else {
1066 /* Disable AUTORTS and AUTOCTS */ 1072 /* Disable AUTORTS and AUTOCTS */
1067 up->efr &= ~(UART_EFR_CTS | UART_EFR_RTS); 1073 up->efr &= ~(UART_EFR_CTS | UART_EFR_RTS);