summaryrefslogtreecommitdiff
path: root/drivers/tty/serial/stm32-usart.c
diff options
context:
space:
mode:
authorMarek Vasut <marex@denx.de>2022-04-30 19:28:45 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2022-05-05 23:37:47 +0300
commitd7c76716169ddc37cf6316ff381d34ea807fbfd7 (patch)
tree94de2018a6c5f95b27da9838510180b7344b54e8 /drivers/tty/serial/stm32-usart.c
parent3bcea529b295a993b1b05db63f245ae8030c5acf (diff)
downloadlinux-d7c76716169ddc37cf6316ff381d34ea807fbfd7.tar.xz
serial: stm32: Use TC interrupt to deassert GPIO RTS in RS485 mode
In case the RS485 mode is emulated using GPIO RTS, use the TC interrupt to deassert the GPIO RTS, otherwise the GPIO RTS stays asserted after a transmission ended and the RS485 cannot work. Signed-off-by: Marek Vasut <marex@denx.de> Cc: Alexandre Torgue <alexandre.torgue@foss.st.com> Cc: Erwan Le Ray <erwan.leray@foss.st.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jean Philippe Romain <jean-philippe.romain@foss.st.com> Cc: Valentin Caron <valentin.caron@foss.st.com> Cc: linux-arm-kernel@lists.infradead.org Cc: linux-stm32@st-md-mailman.stormreply.com To: linux-serial@vger.kernel.org Link: https://lore.kernel.org/r/20220430162845.244655-2-marex@denx.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/serial/stm32-usart.c')
-rw-r--r--drivers/tty/serial/stm32-usart.c42
1 files changed, 40 insertions, 2 deletions
diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 224f359c6051..764415b8e8f0 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -417,6 +417,14 @@ static void stm32_usart_tx_interrupt_enable(struct uart_port *port)
stm32_usart_set_bits(port, ofs->cr1, USART_CR1_TXEIE);
}
+static void stm32_usart_tc_interrupt_enable(struct uart_port *port)
+{
+ struct stm32_port *stm32_port = to_stm32_port(port);
+ const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
+
+ stm32_usart_set_bits(port, ofs->cr1, USART_CR1_TCIE);
+}
+
static void stm32_usart_rx_dma_complete(void *arg)
{
struct uart_port *port = arg;
@@ -442,6 +450,14 @@ static void stm32_usart_tx_interrupt_disable(struct uart_port *port)
stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_TXEIE);
}
+static void stm32_usart_tc_interrupt_disable(struct uart_port *port)
+{
+ struct stm32_port *stm32_port = to_stm32_port(port);
+ const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
+
+ stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_TCIE);
+}
+
static void stm32_usart_rs485_rts_enable(struct uart_port *port)
{
struct stm32_port *stm32_port = to_stm32_port(port);
@@ -585,6 +601,13 @@ static void stm32_usart_transmit_chars(struct uart_port *port)
u32 isr;
int ret;
+ if (!stm32_port->hw_flow_control &&
+ port->rs485.flags & SER_RS485_ENABLED) {
+ stm32_port->txdone = false;
+ stm32_usart_tc_interrupt_disable(port);
+ stm32_usart_rs485_rts_enable(port);
+ }
+
if (port->x_char) {
if (stm32_usart_tx_dma_started(stm32_port) &&
stm32_usart_tx_dma_enabled(stm32_port))
@@ -625,8 +648,14 @@ static void stm32_usart_transmit_chars(struct uart_port *port)
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
- if (uart_circ_empty(xmit))
+ if (uart_circ_empty(xmit)) {
stm32_usart_tx_interrupt_disable(port);
+ if (!stm32_port->hw_flow_control &&
+ port->rs485.flags & SER_RS485_ENABLED) {
+ stm32_port->txdone = true;
+ stm32_usart_tc_interrupt_enable(port);
+ }
+ }
}
static irqreturn_t stm32_usart_interrupt(int irq, void *ptr)
@@ -640,6 +669,13 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr)
sr = readl_relaxed(port->membase + ofs->isr);
+ if (!stm32_port->hw_flow_control &&
+ port->rs485.flags & SER_RS485_ENABLED &&
+ (sr & USART_SR_TC)) {
+ stm32_usart_tc_interrupt_disable(port);
+ stm32_usart_rs485_rts_disable(port);
+ }
+
if ((sr & USART_SR_RTOF) && ofs->icr != UNDEF_REG)
writel_relaxed(USART_ICR_RTOCF,
port->membase + ofs->icr);
@@ -763,8 +799,10 @@ static void stm32_usart_start_tx(struct uart_port *port)
{
struct circ_buf *xmit = &port->state->xmit;
- if (uart_circ_empty(xmit) && !port->x_char)
+ if (uart_circ_empty(xmit) && !port->x_char) {
+ stm32_usart_rs485_rts_disable(port);
return;
+ }
stm32_usart_rs485_rts_enable(port);