aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty
diff options
context:
space:
mode:
authorCyrille Pitchen <cyrille.pitchen@atmel.com>2014-12-09 08:31:35 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-01-09 17:20:49 -0500
commit1cf6e8fc8341e54f28aad706544a1d50c3a82ddc (patch)
tree6343f8b9e5b708821ef82e4cf907e621238f0b7c /drivers/tty
parent6fbb9bdf0f3fbe23aeff806489791aa876adaffb (diff)
tty/serial: at91: fix RTS line management when hardware handshake is enabled
This patch fixes many bugs in the code dealing with the hardware handshake. As an example, in atmel_set_termios(), we used to test whether the CRTSCTS c_cflag was set. If so, we selected the "Hardware Handshake" mode through the Mode Register. However, few lines below the mode was reset to "Normal" (0). So there was no way to select the "Hardware Handshake" mode. To fix this issue, we moved the CRTSCRTS c_cflag test AFTER the mode has been reset to "Normal". Also setting the RTSEN and RTSDIS bits in the Control Register has different results whether the USART is set in "Normal" or "Hardware Handshake" mode: 1) "Normal" mode - the RTSEN bit forces the RTS line to low level, which tells the remote peer that we are ready to received new data. - the RTSDIS bit forces the RTS line to high level, which tells the remote peer to stop sending new data. 2) "Hardware Handshake" mode - the RTSEN bit forces the RTS line to high level. - the RTSDIS bit lets the hardware control the RTS line. WARNING: when FIFOs are not available or not enabled, the RTS line is controlled by the PDC. This is why using the Hardware Handshake mode requires using the PDC channel for reception. However the Hardware Handshake mode DOES NOT work with DMA controller since it cannot control the RTS line. Future designs with FIFOs will introduce a new feature: the RTS line will be controlled by the RX FIFO using thresholds. This patch was tested with this new design. Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com> Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/serial/atmel_serial.c91
1 files changed, 61 insertions, 30 deletions
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 92a8b263735a..9e0c63676f0a 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -341,13 +341,37 @@ static u_int atmel_tx_empty(struct uart_port *port)
341static void atmel_set_mctrl(struct uart_port *port, u_int mctrl) 341static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
342{ 342{
343 unsigned int control = 0; 343 unsigned int control = 0;
344 unsigned int mode; 344 unsigned int mode = UART_GET_MR(port);
345 unsigned int rts_paused, rts_ready;
345 struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 346 struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
346 347
348 /* override mode to RS485 if needed, otherwise keep the current mode */
349 if (port->rs485.flags & SER_RS485_ENABLED) {
350 if ((port->rs485.delay_rts_after_send) > 0)
351 UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
352 mode &= ~ATMEL_US_USMODE;
353 mode |= ATMEL_US_USMODE_RS485;
354 }
355
356 /* set the RTS line state according to the mode */
357 if ((mode & ATMEL_US_USMODE) == ATMEL_US_USMODE_HWHS) {
358 /* force RTS line to high level */
359 rts_paused = ATMEL_US_RTSEN;
360
361 /* give the control of the RTS line back to the hardware */
362 rts_ready = ATMEL_US_RTSDIS;
363 } else {
364 /* force RTS line to high level */
365 rts_paused = ATMEL_US_RTSDIS;
366
367 /* force RTS line to low level */
368 rts_ready = ATMEL_US_RTSEN;
369 }
370
347 if (mctrl & TIOCM_RTS) 371 if (mctrl & TIOCM_RTS)
348 control |= ATMEL_US_RTSEN; 372 control |= rts_ready;
349 else 373 else
350 control |= ATMEL_US_RTSDIS; 374 control |= rts_paused;
351 375
352 if (mctrl & TIOCM_DTR) 376 if (mctrl & TIOCM_DTR)
353 control |= ATMEL_US_DTREN; 377 control |= ATMEL_US_DTREN;
@@ -359,23 +383,12 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
359 mctrl_gpio_set(atmel_port->gpios, mctrl); 383 mctrl_gpio_set(atmel_port->gpios, mctrl);
360 384
361 /* Local loopback mode? */ 385 /* Local loopback mode? */
362 mode = UART_GET_MR(port) & ~ATMEL_US_CHMODE; 386 mode &= ~ATMEL_US_CHMODE;
363 if (mctrl & TIOCM_LOOP) 387 if (mctrl & TIOCM_LOOP)
364 mode |= ATMEL_US_CHMODE_LOC_LOOP; 388 mode |= ATMEL_US_CHMODE_LOC_LOOP;
365 else 389 else
366 mode |= ATMEL_US_CHMODE_NORMAL; 390 mode |= ATMEL_US_CHMODE_NORMAL;
367 391
368 /* Resetting serial mode to RS232 (0x0) */
369 mode &= ~ATMEL_US_USMODE;
370
371 if (port->rs485.flags & SER_RS485_ENABLED) {
372 dev_dbg(port->dev, "Setting UART to RS485\n");
373 if ((port->rs485.delay_rts_after_send) > 0)
374 UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
375 mode |= ATMEL_US_USMODE_RS485;
376 } else {
377 dev_dbg(port->dev, "Setting UART to RS232\n");
378 }
379 UART_PUT_MR(port, mode); 392 UART_PUT_MR(port, mode);
380} 393}
381 394
@@ -1921,12 +1934,14 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
1921 struct ktermios *old) 1934 struct ktermios *old)
1922{ 1935{
1923 unsigned long flags; 1936 unsigned long flags;
1924 unsigned int mode, imr, quot, baud; 1937 unsigned int old_mode, mode, imr, quot, baud;
1938
1939 /* save the current mode register */
1940 mode = old_mode = UART_GET_MR(port);
1925 1941
1926 /* Get current mode register */ 1942 /* reset the mode, clock divisor, parity, stop bits and data size */
1927 mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL 1943 mode &= ~(ATMEL_US_USCLKS | ATMEL_US_CHRL | ATMEL_US_NBSTOP |
1928 | ATMEL_US_NBSTOP | ATMEL_US_PAR 1944 ATMEL_US_PAR | ATMEL_US_USMODE);
1929 | ATMEL_US_USMODE);
1930 1945
1931 baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); 1946 baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
1932 quot = uart_get_divisor(port, baud); 1947 quot = uart_get_divisor(port, baud);
@@ -1971,12 +1986,6 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
1971 } else 1986 } else
1972 mode |= ATMEL_US_PAR_NONE; 1987 mode |= ATMEL_US_PAR_NONE;
1973 1988
1974 /* hardware handshake (RTS/CTS) */
1975 if (termios->c_cflag & CRTSCTS)
1976 mode |= ATMEL_US_USMODE_HWHS;
1977 else
1978 mode |= ATMEL_US_USMODE_NORMAL;
1979
1980 spin_lock_irqsave(&port->lock, flags); 1989 spin_lock_irqsave(&port->lock, flags);
1981 1990
1982 port->read_status_mask = ATMEL_US_OVRE; 1991 port->read_status_mask = ATMEL_US_OVRE;
@@ -2020,18 +2029,40 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
2020 /* disable receiver and transmitter */ 2029 /* disable receiver and transmitter */
2021 UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS); 2030 UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS);
2022 2031
2023 /* Resetting serial mode to RS232 (0x0) */ 2032 /* mode */
2024 mode &= ~ATMEL_US_USMODE;
2025
2026 if (port->rs485.flags & SER_RS485_ENABLED) { 2033 if (port->rs485.flags & SER_RS485_ENABLED) {
2027 if ((port->rs485.delay_rts_after_send) > 0) 2034 if ((port->rs485.delay_rts_after_send) > 0)
2028 UART_PUT_TTGR(port, port->rs485.delay_rts_after_send); 2035 UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
2029 mode |= ATMEL_US_USMODE_RS485; 2036 mode |= ATMEL_US_USMODE_RS485;
2037 } else if (termios->c_cflag & CRTSCTS) {
2038 /* RS232 with hardware handshake (RTS/CTS) */
2039 mode |= ATMEL_US_USMODE_HWHS;
2040 } else {
2041 /* RS232 without hadware handshake */
2042 mode |= ATMEL_US_USMODE_NORMAL;
2030 } 2043 }
2031 2044
2032 /* set the parity, stop bits and data size */ 2045 /* set the mode, clock divisor, parity, stop bits and data size */
2033 UART_PUT_MR(port, mode); 2046 UART_PUT_MR(port, mode);
2034 2047
2048 /*
2049 * when switching the mode, set the RTS line state according to the
2050 * new mode, otherwise keep the former state
2051 */
2052 if ((old_mode & ATMEL_US_USMODE) != (mode & ATMEL_US_USMODE)) {
2053 unsigned int rts_state;
2054
2055 if ((mode & ATMEL_US_USMODE) == ATMEL_US_USMODE_HWHS) {
2056 /* let the hardware control the RTS line */
2057 rts_state = ATMEL_US_RTSDIS;
2058 } else {
2059 /* force RTS line to low level */
2060 rts_state = ATMEL_US_RTSEN;
2061 }
2062
2063 UART_PUT_CR(port, rts_state);
2064 }
2065
2035 /* set the baud rate */ 2066 /* set the baud rate */
2036 UART_PUT_BRGR(port, quot); 2067 UART_PUT_BRGR(port, quot);
2037 UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); 2068 UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);