[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251130104222.63077-20-crescentcy.hsieh@moxa.com>
Date: Sun, 30 Nov 2025 18:42:10 +0800
From: Crescent Hsieh <crescentcy.hsieh@...a.com>
To: gregkh@...uxfoundation.org,
jirislaby@...nel.org,
ilpo.jarvinen@...ux.intel.com,
andy.shevchenko@...il.com
Cc: linux-kernel@...r.kernel.org,
linux-serial@...r.kernel.org,
crescentcy.hsieh@...a.com
Subject: [PATCH v1 19/31] serial: 8250_mxpcie: add break signal support under RS485
Moxa PCIe boards require a specific sequence to send break signals in
RS485 mode. This patch implements the required behavior, while falling
back to the default break mechanism in RS232 and RS422 modes.
Signed-off-by: Crescent Hsieh <crescentcy.hsieh@...a.com>
---
drivers/tty/serial/8250/8250_mxpcie.c | 52 +++++++++++++++++++++++++++
1 file changed, 52 insertions(+)
diff --git a/drivers/tty/serial/8250/8250_mxpcie.c b/drivers/tty/serial/8250/8250_mxpcie.c
index 5d1097c166e4..9ba171274221 100644
--- a/drivers/tty/serial/8250/8250_mxpcie.c
+++ b/drivers/tty/serial/8250/8250_mxpcie.c
@@ -40,6 +40,7 @@
/* Special Function Register (SFR) */
#define MOXA_PUART_SFR 0x07
+#define MOXA_PUART_SFR_FORCE_TX BIT(0)
#define MOXA_PUART_SFR_950 BIT(5)
/* Enhanced Function Register (EFR) */
@@ -390,6 +391,56 @@ static int mxpcie8250_handle_irq(struct uart_port *port)
return 1;
}
+static void mxpcie8250_software_break_ctl(struct uart_port *port, int break_state)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+ struct tty_struct *tty = port->state->port.tty;
+ unsigned char tx_byte = 0x01;
+ unsigned int baud, quot;
+ unsigned long flags;
+ u8 sfr;
+
+ uart_port_lock_irqsave(port, &flags);
+
+ if (break_state == -1) {
+ serial_out(up, UART_LCR, up->lcr | UART_LCR_DLAB);
+ serial_out(up, UART_DLL, 0);
+ serial_out(up, UART_DLM, 0);
+ serial_out(up, UART_LCR, up->lcr);
+
+ memcpy(port->membase + MOXA_PUART_TX_FIFO_MEM, &tx_byte, 1);
+
+ sfr = serial_in(up, MOXA_PUART_SFR);
+ serial_out(up, MOXA_PUART_SFR, sfr | MOXA_PUART_SFR_FORCE_TX);
+
+ up->lcr |= UART_LCR_SBC;
+ serial_out(up, UART_LCR, up->lcr);
+ } else {
+ up->lcr &= ~UART_LCR_SBC;
+ serial_out(up, UART_LCR, up->lcr);
+
+ sfr = serial_in(up, MOXA_PUART_SFR);
+ serial_out(up, MOXA_PUART_SFR, sfr &= ~MOXA_PUART_SFR_FORCE_TX);
+
+ serial_out(up, UART_FCR, UART_FCR_CLEAR_XMIT);
+
+ baud = tty_get_baud_rate(tty);
+ quot = uart_get_divisor(port, baud);
+ serial8250_do_set_divisor(port, baud, quot);
+ serial_out(up, UART_LCR, up->lcr);
+ }
+ uart_port_unlock_irqrestore(port, flags);
+}
+
+static void mxpcie8250_break_ctl(struct uart_port *port, int break_state)
+{
+ if (port->rs485.flags & SER_RS485_ENABLED &&
+ !(port->rs485.flags & SER_RS485_MODE_RS422))
+ mxpcie8250_software_break_ctl(port, break_state);
+ else
+ serial8250_do_break_ctl(port, break_state);
+}
+
static int mxpcie8250_init(struct pci_dev *pdev)
{
resource_size_t iobar_addr = pci_resource_start(pdev, 2);
@@ -487,6 +538,7 @@ static int mxpcie8250_probe(struct pci_dev *pdev, const struct pci_device_id *id
up.port.throttle = mxpcie8250_throttle;
up.port.unthrottle = mxpcie8250_unthrottle;
up.port.handle_irq = mxpcie8250_handle_irq;
+ up.port.break_ctl = mxpcie8250_break_ctl;
for (i = 0; i < num_ports; i++) {
if (mxpcie8250_setup(pdev, priv, &up, i))
--
2.45.2
Powered by blists - more mailing lists