diff options
Diffstat (limited to 'recipes-kernel/linux/linux-at91-5.4.81/mtcdt/linux-5.4-rs485-atmel-crtscts.patch')
-rw-r--r-- | recipes-kernel/linux/linux-at91-5.4.81/mtcdt/linux-5.4-rs485-atmel-crtscts.patch | 115 |
1 files changed, 112 insertions, 3 deletions
diff --git a/recipes-kernel/linux/linux-at91-5.4.81/mtcdt/linux-5.4-rs485-atmel-crtscts.patch b/recipes-kernel/linux/linux-at91-5.4.81/mtcdt/linux-5.4-rs485-atmel-crtscts.patch index d17ed37..30cc7d5 100644 --- a/recipes-kernel/linux/linux-at91-5.4.81/mtcdt/linux-5.4-rs485-atmel-crtscts.patch +++ b/recipes-kernel/linux/linux-at91-5.4.81/mtcdt/linux-5.4-rs485-atmel-crtscts.patch @@ -2,19 +2,128 @@ This patch allows RS485 Half Duplex (ATMEL_US_USMODE_RS485 is half duplex) to work even if handshaking is turned on. This mimics the behavior of the EXAR USB/Serial driver known as Vizzini. It is impossible to use handshaking when using ATMEL_US_USMODE_RS485. This provides compatibility between MTCDT-0.1 and -MTCDT-0.2. +MTCDT-0.2. Note that frequently the state of the driver will be stopped if +handshaking was turned on before RS485 was set. We need to take steps to enable +transmit and receive when we go to RS485 mode, or the driver will be blocked. ======================================================================================= diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c -index 28d4a92c0d63..2d17558a807d 100644 +index 2d17558a807d..e721e2028b4a 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c -@@ -2250,6 +2250,9 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, +@@ -62,6 +62,7 @@ + + static void atmel_start_rx(struct uart_port *port); + static void atmel_stop_rx(struct uart_port *port); ++static void atmel_start_tx(struct uart_port *port); + + #ifdef CONFIG_SERIAL_ATMEL_TTYAT + +@@ -300,6 +301,7 @@ static int atmel_config_rs485(struct uart_port *port, + { + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + unsigned int mode; ++ unsigned int sav_c_cflag = 0; + + /* Disable interrupts */ + atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask); +@@ -312,15 +314,33 @@ static int atmel_config_rs485(struct uart_port *port, + port->rs485 = *rs485conf; + + if (rs485conf->flags & SER_RS485_ENABLED) { +- dev_dbg(port->dev, "Setting UART to RS485\n"); +- if (port->rs485.flags & SER_RS485_RX_DURING_TX) +- atmel_port->tx_done_mask = ATMEL_US_TXRDY; +- else +- atmel_port->tx_done_mask = ATMEL_US_TXEMPTY; ++ struct uart_state *state_p = port->state; ++ struct tty_struct *tty_struct_p = NULL; + +- atmel_uart_writel(port, ATMEL_US_TTGR, ++ dev_dbg(port->dev, "Setting UART to RS485\n"); ++ if (state_p) ++ tty_struct_p = state_p->port.tty; ++ ++ if(tty_struct_p) { ++ struct ktermios *termios = &(tty_struct_p->termios); ++ sav_c_cflag = termios->c_cflag; ++ termios->c_cflag &= ~CRTSCTS; ++ } ++ ++ atmel_port->tx_done_mask = ATMEL_US_TXEMPTY; ++ atmel_uart_writel(port, ATMEL_US_TTGR, + rs485conf->delay_rts_after_send); ++ dev_dbg(port->dev, ++ "atmel_config_rs485: orig: c_cflag 0x%x port status 0x%x, hw_stopped %d\n", ++ sav_c_cflag,port->status,port->hw_stopped ++ ); ++ ++ port->status &= ~UPSTAT_CTS_ENABLE; + mode |= ATMEL_US_USMODE_RS485; ++ port->hw_stopped = 0; // No longer possible ++ if (atmel_port->tx_stopped == true) ++ atmel_start_tx(port); ++ atmel_start_rx(port); + } else { + dev_dbg(port->dev, "Setting UART to RS232\n"); + if (atmel_use_pdc_tx(port)) +@@ -481,13 +501,36 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl) + unsigned int mode = atmel_uart_readl(port, ATMEL_US_MR); + unsigned int rts_paused, rts_ready; + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); ++ unsigned int sav_c_cflag = 0; + + /* override mode to RS485 if needed, otherwise keep the current mode */ + if (port->rs485.flags & SER_RS485_ENABLED) { +- atmel_uart_writel(port, ATMEL_US_TTGR, +- port->rs485.delay_rts_after_send); +- mode &= ~ATMEL_US_USMODE; +- mode |= ATMEL_US_USMODE_RS485; ++ struct uart_state *state_p = port->state; ++ struct tty_struct *tty_struct_p = NULL; ++ ++ if (state_p) ++ tty_struct_p = state_p->port.tty; ++ ++ if(tty_struct_p) { ++ struct ktermios *termios = &(tty_struct_p->termios); ++ ++ sav_c_cflag = termios->c_cflag; ++ termios->c_cflag &= ~CRTSCTS; ++ } ++ ++ atmel_uart_writel(port, ATMEL_US_TTGR, ++ port->rs485.delay_rts_after_send); ++ mode &= ~ATMEL_US_USMODE; ++ mode |= ATMEL_US_USMODE_RS485; ++ dev_dbg(port->dev, ++ "atmel_set_mctrl: SER_RS485_ENABLED: c_cflag 0x%x port status 0x%x, hw_stopped %d\n", ++ sav_c_cflag,port->status,port->hw_stopped ++ ); ++ port->status &= ~UPSTAT_CTS_ENABLE; ++ port->hw_stopped = 0; // No longer possible ++ if (atmel_port->tx_stopped == true) ++ atmel_start_tx(port); ++ atmel_start_rx(port); + } + + /* set the RTS line state according to the mode */ +@ -2250,6 +2250,19 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, atmel_uart_writel(port, ATMEL_US_TTGR, port->rs485.delay_rts_after_send); mode |= ATMEL_US_USMODE_RS485; + /* CRTSCTS is impossible in RS485 mode, and breaks the driver + * so we cannot do a send. */ ++ dev_dbg(port->dev, ++ "atmel_set_termios: SER_RS485_ENABLED: original: c_cflag 0x%x status 0x%x, hw_stopped %d\n", ++ termios->c_cflag,port->status,port->hw_stopped ++ ); ++ + termios->c_cflag &= ~CRTSCTS; ++ port->status &= ~UPSTAT_CTS_ENABLE; ++ port->hw_stopped = 0; // Not possible ++ if (atmel_port->tx_stopped == true) ++ atmel_start_tx(port); ++ atmel_start_rx(port); } else if (port->iso7816.flags & SER_ISO7816_ENABLED) { atmel_uart_writel(port, ATMEL_US_TTGR, port->iso7816.tg); /* select mck clock, and output */ |