[PATCH v5 11/14] serial: 8250_mxpcie: add break support for RS485 using MUEx50 features
Crescent Hsieh <[email protected]> Fri, 31 Jul 2026 15:48:17 +0800
| Newsgroups | org.kernel.vger.linux-serial,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
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 <[email protected]> --- drivers/tty/serial/8250/8250_mxpcie.c | 48 +++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/drivers/tty/serial/8250/8250_mxpcie.c b/drivers/tty/serial/8250/8250_mxpcie.c index 93f0af958d11..6f44a557a6d6 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) */ @@ -382,6 +383,52 @@ 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 int baud, quot; + u8 sfr, tx_byte = 0x01; + + guard(uart_port_lock_irqsave)(port); + + if (break_state == -1) { + serial_out(up, UART_LCR, up->lcr | UART_LCR_DLAB); + serial_dl_write(up, 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); + } +} + +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_init_board(struct pci_dev *pdev, struct mxpcie8250 *priv) { void __iomem *bar2_base = priv->bar2_base; @@ -487,6 +534,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 (unsigned int i = 0; i < num_ports; i++) { mxpcie8250_setup_port(pdev, priv, &up, i); -- 2.45.2