diff mbox series

[V9,2/2] serial: exar: Add RS-485 support for Sealevel XR17V35X based cards

Message ID 4b8ad8ab6728742464c4e048fdeecb2b40522aef.camel@sealevel.com
State New
Headers show
Series [V9,1/2] serial: exar: Revert "serial: exar: Add support for Sealevel 7xxxC serial cards" | expand

Commit Message

Matthew Howell Sept. 29, 2023, 5:40 p.m. UTC
From: Matthew Howell <matthew.howell@sealevel.com>

Sealevel XR17V35X based cards utilize DTR to control RS-485 Enable, but
the current implementation of 8250_exar uses RTS for the auto-RS485-Enable
mode of the XR17V35X UARTs. This patch implements DTR Auto-RS485 on
Sealevel cards.

Signed-off-by: Matthew Howell <matthew.howell@sealevel.com>
---
V8->V9
Changed implementation to use pci_xr17v35x_setup() instead of creating
separate startup functions.

Comments

Andy Shevchenko Oct. 1, 2023, 8:56 a.m. UTC | #1
On Fri, Sep 29, 2023 at 05:40:55PM +0000, Matthew Howell wrote:
> From: Matthew Howell <matthew.howell@sealevel.com>
> 
> Sealevel XR17V35X based cards utilize DTR to control RS-485 Enable, but
> the current implementation of 8250_exar uses RTS for the auto-RS485-Enable
> mode of the XR17V35X UARTs. This patch implements DTR Auto-RS485 on
> Sealevel cards.

Looks good, thank you!
Reviewed-by: Andy Shevchenko <andriy.shevchenkoa@linux.intel.com>
diff mbox series

Patch

diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c
index 3886f78ecbbf..f4a467d5b6aa 100644
--- a/drivers/tty/serial/8250/8250_exar.c
+++ b/drivers/tty/serial/8250/8250_exar.c
@@ -78,6 +78,9 @@ 
 
 #define UART_EXAR_RS485_DLY(x)	((x) << 4)
 
+#define UART_EXAR_DLD			0x02 /* Divisor Fractional */
+#define UART_EXAR_DLD_485_POLARITY	0x80 /* RS-485 Enable Signal Polarity */
+
 /*
  * IOT2040 MPIO wiring semantics:
  *
@@ -439,6 +442,44 @@  static int generic_rs485_config(struct uart_port *port, struct ktermios *termios
 	return 0;
 }
 
+static int sealevel_rs485_config(struct uart_port *port, struct ktermios *termios,
+				  struct serial_rs485 *rs485)
+{
+	u8 __iomem *p = port->membase;
+	u8 old_lcr;
+	u8 efr;
+	u8 dld;
+	int ret;
+
+	ret = generic_rs485_config(port, termios, rs485);
+	if (ret)
+		return ret;
+
+	if (rs485->flags & SER_RS485_ENABLED) {
+		old_lcr = readb(p + UART_LCR);
+
+		/* Set EFR[4]=1 to enable enhanced feature registers */
+		efr = readb(p + UART_XR_EFR);
+		efr |= UART_EFR_ECB;
+		writeb(efr, p + UART_XR_EFR);
+
+		/* Set MCR to use DTR as Auto-RS485 Enable signal */
+		writeb(UART_MCR_OUT1, p + UART_MCR);
+
+		/* Set LCR[7]=1 to enable access to DLD register */
+		writeb(old_lcr | UART_LCR_DLAB, p + UART_LCR);
+
+		/* Set DLD[7]=1 for inverted RS485 Enable logic */
+		dld = readb(p + UART_EXAR_DLD);
+		dld |= UART_EXAR_DLD_485_POLARITY;
+		writeb(dld, p + UART_EXAR_DLD);
+
+		writeb(old_lcr, p + UART_LCR);
+	}
+
+	return 0;
+}
+
 static const struct serial_rs485 generic_rs485_supported = {
 	.flags = SER_RS485_ENABLED,
 };
@@ -560,6 +601,9 @@  pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev,
 	port->port.rs485_config = platform->rs485_config;
 	port->port.rs485_supported = *(platform->rs485_supported);
 
+	if (pcidev->subsystem_vendor == PCI_VENDOR_ID_SEALEVEL)
+		port->port.rs485_config = sealevel_rs485_config;
+
 	/*
 	 * Setup the UART clock for the devices on expansion slot to
 	 * half the clock speed of the main chip (which is 125MHz)