Add support for Moxa PCIe multiport serial boards to switch serial
interfaces via the ioctl() command "TIOCSRS485" using the following
flags in the "serial_rs485" struct:
- 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 dynamically configure the serial mode without
requiring additional hardware modifications.
Signed-off-by: Crescent Hsieh <crescentcy.hsieh@moxa.com>
---
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 90ce522fe40f..5d1097c166e4 100644
--- a/drivers/tty/serial/8250/8250_mxpcie.c
+++ b/drivers/tty/serial/8250/8250_mxpcie.c
@@ -105,6 +105,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 ||
@@ -166,6 +170,38 @@ static int mxpcie8250_set_interface(struct mxpcie8250 *priv,
return 0;
}
+/*
+ * 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 pci_dev *pdev = to_pci_dev(port->dev);
+ struct mxpcie8250 *priv = pci_get_drvdata(pdev);
+ 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;
+ }
+
+ return mxpcie8250_set_interface(priv, port->port_id, mode);
+}
+
static void mxpcie8250_set_termios(struct uart_port *port,
struct ktermios *new,
const struct ktermios *old)
@@ -392,9 +428,14 @@ static int mxpcie8250_setup(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.45.2