[PATCH 11/15] serial: 8250_mxpcie: support serial interface mode switching
From: Crescent Hsieh
Date: Mon May 04 2026 - 04:52:44 EST
Moxa PCIe multiport serial boards support switching the serial interface
mode between RS232, RS422, RS485-2W, and RS485-4W via on-board control
registers.
Implement an rs485_config() callback and map TIOCSRS485 requests to the
corresponding hardware modes using serial_rs485 flags:
- RS232 = (no flags set)
- RS422 = SER_RS485_ENABLED | SER_RS485_MODE_RS422
- RS485_2W (half-duplex) = SER_RS485_ENABLED
- RS485_4W (full-duplex) = SER_RS485_ENABLED | SER_RS485_RX_DURING_TX
This allows users to reconfigure the serial mode at runtime via ioctl().
Signed-off-by: Crescent Hsieh <crescentcy.hsieh@xxxxxxxx>
---
drivers/tty/serial/8250/8250_mxpcie.c | 45 +++++++++++++++++++++++++--
1 file changed, 43 insertions(+), 2 deletions(-)
diff --git a/drivers/tty/serial/8250/8250_mxpcie.c b/drivers/tty/serial/8250/8250_mxpcie.c
index 8dc1b7b0af04..94c3552b9798 100644
--- a/drivers/tty/serial/8250/8250_mxpcie.c
+++ b/drivers/tty/serial/8250/8250_mxpcie.c
@@ -129,6 +129,10 @@ enum {
MOXA_SUPP_RS485 = BIT(2),
};
+static const struct serial_rs485 mxpcie8250_rs485_supported = {
+ .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RX_DURING_TX | SER_RS485_MODE_RS422,
+};
+
static bool mxpcie8250_is_mini_pcie(unsigned short device)
{
if (device == PCI_DEVICE_ID_MOXA_CP102N ||
@@ -185,6 +189,38 @@ static void mxpcie8250_set_interface(struct mxpcie8250 *priv,
iowrite8(cval, uir_addr);
}
+/*
+ * Moxa PCIe multiport serial boards support switching serial interfaces
+ * via the ioctl() command "TIOCSRS485". Supported modes and corresponding
+ * flags in "serial_rs485":
+ *
+ * RS232 = (no flags set)
+ * RS422 = SER_RS485_ENABLED | SER_RS485_MODE_RS422
+ * RS485_2W (half-duplex) = SER_RS485_ENABLED
+ * RS485_4W (full-duplex) = SER_RS485_ENABLED | SER_RS485_RX_DURING_TX
+ */
+static int mxpcie8250_rs485_config(struct uart_port *port,
+ struct ktermios *termios,
+ struct serial_rs485 *rs485)
+{
+ struct mxpcie8250 *priv = dev_get_drvdata(port->dev);
+ u8 mode = MOXA_UIR_RS232;
+
+ if (rs485->flags & SER_RS485_ENABLED) {
+ if (rs485->flags & SER_RS485_MODE_RS422)
+ mode = MOXA_UIR_RS422;
+ else if (rs485->flags & SER_RS485_RX_DURING_TX)
+ mode = MOXA_UIR_RS485_4W;
+ else
+ mode = MOXA_UIR_RS485_2W;
+ } else if (!(priv->supp_rs & MOXA_SUPP_RS232)) {
+ return -ENODEV;
+ }
+ mxpcie8250_set_interface(priv, port->port_id, mode);
+
+ return 0;
+}
+
static void mxpcie8250_set_termios(struct uart_port *port,
struct ktermios *new,
const struct ktermios *old)
@@ -435,9 +471,14 @@ static void mxpcie8250_setup_port(struct pci_dev *pdev,
int offset = idx * MOXA_PUART_OFFSET;
u8 init_mode = MOXA_UIR_RS232;
- if (!(priv->supp_rs & MOXA_SUPP_RS232))
+ if (priv->supp_rs & MOXA_SUPP_RS485) {
+ up->port.rs485_config = mxpcie8250_rs485_config;
+ up->port.rs485_supported = mxpcie8250_rs485_supported;
+ }
+ if (!(priv->supp_rs & MOXA_SUPP_RS232)) {
init_mode = MOXA_UIR_RS422;
-
+ up->port.rs485.flags = SER_RS485_ENABLED | SER_RS485_MODE_RS422;
+ }
mxpcie8250_set_interface(priv, idx, init_mode);
if (idx == 3 &&
--
2.43.0