summaryrefslogtreecommitdiff
path: root/recipes-kernel/linux/linux-at91-4.9.87/mtcdt/linux-4.9-rs485-atmel-crtscts.patch
diff options
context:
space:
mode:
Diffstat (limited to 'recipes-kernel/linux/linux-at91-4.9.87/mtcdt/linux-4.9-rs485-atmel-crtscts.patch')
-rw-r--r--recipes-kernel/linux/linux-at91-4.9.87/mtcdt/linux-4.9-rs485-atmel-crtscts.patch115
1 files changed, 110 insertions, 5 deletions
diff --git a/recipes-kernel/linux/linux-at91-4.9.87/mtcdt/linux-4.9-rs485-atmel-crtscts.patch b/recipes-kernel/linux/linux-at91-4.9.87/mtcdt/linux-4.9-rs485-atmel-crtscts.patch
index 1cf147e..5642aee 100644
--- a/recipes-kernel/linux/linux-at91-4.9.87/mtcdt/linux-4.9-rs485-atmel-crtscts.patch
+++ b/recipes-kernel/linux/linux-at91-4.9.87/mtcdt/linux-4.9-rs485-atmel-crtscts.patch
@@ -2,19 +2,124 @@ 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 -Naru orig/drivers/tty/serial/atmel_serial.c new/drivers/tty/serial/atmel_serial.c
---- orig/drivers/tty/serial/atmel_serial.c 2021-11-29 12:29:38.472076748 -0600
-+++ new/drivers/tty/serial/atmel_serial.c 2021-11-29 12:26:05.668072459 -0600
-@@ -2171,7 +2171,10 @@
+--- orig/drivers/tty/serial/atmel_serial.c 2021-11-30 14:54:49.313993839 -0600
++++ new/drivers/tty/serial/atmel_serial.c 2021-11-30 16:14:58.430090773 -0600
+@@ -74,6 +74,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
+
+@@ -357,6 +358,7 @@
+ {
+ 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);
+@@ -369,11 +371,33 @@
+ port->rs485 = *rs485conf;
+
+ if (rs485conf->flags & SER_RS485_ENABLED) {
+- dev_dbg(port->dev, "Setting UART to RS485\n");
+- atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
+- atmel_uart_writel(port, ATMEL_US_TTGR,
++ struct uart_state *state_p = port->state;
++ struct tty_struct *tty_struct_p = NULL;
++
++ 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))
+@@ -413,13 +437,36 @@
+ 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 */
+@@ -2168,6 +2215,19 @@
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 (termios->c_cflag & CRTSCTS) {
/* RS232 with hardware handshake (RTS/CTS) */
if (atmel_use_fifo(port) &&
- !mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS)) {