[PATCH 13/15] serial: 8250_mxpcie: add break support for RS485 using MUEx50 features
From: Crescent Hsieh
Date: Mon May 04 2026 - 04:57:16 EST
On MUEx50, break signaling under RS485 requires a driver-specific
sequence and cannot be handled correctly by the generic 8250 break
implementation alone.
Implement a mxpcie break_ctl callback that performs MUEx50-specific
break handling when RS485 is enabled and fall back to the default 8250
break handling for other modes.
Signed-off-by: Crescent Hsieh <crescentcy.hsieh@xxxxxxxx>
---
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 94c3552b9798..5bf15ca78228 100644
--- a/drivers/tty/serial/8250/8250_mxpcie.c
+++ b/drivers/tty/serial/8250/8250_mxpcie.c
@@ -54,6 +54,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) */
@@ -426,6 +427,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);
+
+ serial_out(up, MOXA_PUART_TX_FIFO_MEM, tx_byte);
+
+ 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 void mxpcie8250_work_handler(struct work_struct *work)
{
struct mxpcie8250_port *priv_port = container_of(work, struct mxpcie8250_port, work);
@@ -539,6 +590,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++) {
mxpcie8250_setup_port(pdev, priv, &up, i);
--
2.43.0