#define pl011_dma_flush_buffer NULL
#endif
-static void pl011_rs485_tx_stop(struct uart_amba_port *uap)
+static void pl011_rs485_tx_stop_now(struct uart_amba_port *uap)
{
struct uart_port *port = &uap->port;
u32 cr;
+ cr = pl011_read(uap, REG_CR);
+
+ if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
+ cr &= ~UART011_CR_RTS;
+ else
+ cr |= UART011_CR_RTS;
+
+ /* Disable the transmitter and reenable the transceiver */
+ cr &= ~UART011_CR_TXE;
+ cr |= UART011_CR_RXE;
+ pl011_write(cr, uap, REG_CR);
+
+ uap->rs485_tx_state = OFF;
+}
+
+static void pl011_rs485_tx_stop(struct uart_amba_port *uap)
+{
+ struct uart_port *port = &uap->port;
+
if (uap->rs485_tx_state == SEND)
uap->rs485_tx_state = WAIT_AFTER_SEND;
hrtimer_try_to_cancel(&uap->trigger_start_tx);
}
- cr = pl011_read(uap, REG_CR);
-
- if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
- cr &= ~UART011_CR_RTS;
- else
- cr |= UART011_CR_RTS;
-
- /* Disable the transmitter and reenable the transceiver */
- cr &= ~UART011_CR_TXE;
- cr |= UART011_CR_RXE;
- pl011_write(cr, uap, REG_CR);
-
- uap->rs485_tx_state = OFF;
+ pl011_rs485_tx_stop_now(uap);
}
static void pl011_stop_tx(struct uart_port *port)
pl011_dma_shutdown(uap);
- if ((port->rs485.flags & SER_RS485_ENABLED && uap->rs485_tx_state != OFF))
- pl011_rs485_tx_stop(uap);
-
free_irq(uap->port.irq, uap);
+ /*
+ * free_irq() drains the UART interrupt handler, which can arm either
+ * timer. Cancel the timers afterwards to drain their callbacks too.
+ */
+ hrtimer_cancel(&uap->trigger_start_tx);
+ hrtimer_cancel(&uap->trigger_stop_tx);
+
+ uart_port_lock_irq(port);
+ if (uap->rs485_tx_state != OFF)
+ pl011_rs485_tx_stop_now(uap);
+ uart_port_unlock_irq(port);
+
pl011_disable_uart(uap);
/*
struct uart_amba_port *uap = amba_get_drvdata(dev);
uart_remove_one_port(&amba_reg, &uap->port);
+ hrtimer_cancel(&uap->trigger_start_tx);
+ hrtimer_cancel(&uap->trigger_stop_tx);
pl011_unregister_port(uap);
}