>From 7892ef568d7ca4c1c2a0ed9fb8edbadfe8e70177 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Mon, 15 Sep 2025 15:35:14 +0200 Subject: [PATCH RFC] serial: ar933x: Handle break events Signed-off-by: Sven Eckelmann --- drivers/tty/serial/ar933x_uart.c | 53 ++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c index 5b491db9d2fc..bc0a63e4934b 100644 --- a/drivers/tty/serial/ar933x_uart.c +++ b/drivers/tty/serial/ar933x_uart.c @@ -105,6 +105,30 @@ static inline void ar933x_uart_stop_tx_interrupt(struct ar933x_uart_port *up) ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); } +static inline void ar933x_uart_start_rxbreak_on_interrupt(struct ar933x_uart_port *up) +{ + up->ier |= AR933X_UART_INT_RX_BREAK_ON; + ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); +} + +static inline void ar933x_uart_stop_rxbreak_on_interrupt(struct ar933x_uart_port *up) +{ + up->ier &= ~AR933X_UART_INT_RX_BREAK_ON; + ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); +} + +static inline void ar933x_uart_start_rxbreak_off_interrupt(struct ar933x_uart_port *up) +{ + up->ier |= AR933X_UART_INT_RX_BREAK_OFF; + ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); +} + +static inline void ar933x_uart_stop_rxbreak_off_interrupt(struct ar933x_uart_port *up) +{ + up->ier &= ~AR933X_UART_INT_RX_BREAK_OFF; + ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); +} + static inline void ar933x_uart_start_rx_interrupt(struct ar933x_uart_port *up) { up->ier |= AR933X_UART_INT_RX_VALID; @@ -212,6 +236,7 @@ static void ar933x_uart_stop_rx(struct uart_port *port) container_of(port, struct ar933x_uart_port, port); ar933x_uart_stop_rx_interrupt(up); + ar933x_uart_stop_rxbreak_on_interrupt(up); } static void ar933x_uart_break_ctl(struct uart_port *port, int break_state) @@ -444,11 +469,14 @@ static irqreturn_t ar933x_uart_interrupt(int irq, void *dev_id) { struct ar933x_uart_port *up = dev_id; unsigned int status; + bool is_break; status = ar933x_uart_read(up, AR933X_UART_CS_REG); if ((status & AR933X_UART_CS_HOST_INT) == 0) return IRQ_NONE; + is_break = status & AR933X_UART_CS_RX_BREAK; + uart_port_lock(&up->port); status = ar933x_uart_read(up, AR933X_UART_INT_REG); @@ -467,6 +495,29 @@ static irqreturn_t ar933x_uart_interrupt(int irq, void *dev_id) ar933x_uart_tx_chars(up); } + if (status & AR933X_UART_INT_RX_BREAK_ON) + ar933x_uart_write(up, AR933X_UART_INT_REG, + AR933X_UART_INT_RX_BREAK_ON); + + if (status & AR933X_UART_INT_RX_BREAK_OFF) + ar933x_uart_write(up, AR933X_UART_INT_REG, + AR933X_UART_INT_RX_BREAK_OFF); + + if (is_break) { + /* disable "active break" interrupt */ + ar933x_uart_stop_rxbreak_on_interrupt(up); + ar933x_uart_start_rxbreak_off_interrupt(up); + + /* inform serial core about break */ + up->port.icount.brk++; + if (!up->port.sysrq) + uart_handle_break(&up->port); + } else if (!(up->ier & AR933X_UART_INT_RX_BREAK_ON)) { + /* enable "active break" interrupt */ + ar933x_uart_start_rxbreak_on_interrupt(up); + ar933x_uart_stop_rxbreak_off_interrupt(up); + } + uart_unlock_and_check_sysrq(&up->port); return IRQ_HANDLED; @@ -496,6 +547,7 @@ static int ar933x_uart_startup(struct uart_port *port) /* Enable RX interrupts */ ar933x_uart_start_rx_interrupt(up); + ar933x_uart_start_rxbreak_on_interrupt(up); uart_port_unlock_irqrestore(&up->port, flags); @@ -829,6 +881,7 @@ static int ar933x_uart_probe(struct platform_device *pdev) port->ops = &ar933x_uart_ops; port->rs485_config = ar933x_config_rs485; port->rs485_supported = ar933x_rs485_supported; + port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_AR933X_CONSOLE); baud = ar933x_uart_get_baud(port->uartclk, AR933X_UART_MAX_SCALE, 1); up->min_baud = max_t(unsigned int, baud, AR933X_UART_MIN_BAUD); -- 2.47.3