Skip to content

Commit

Permalink
serial: stm32: Use TC interrupt to deassert GPIO RTS in RS485 mode
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Marek Vasut authored and Greg Kroah-Hartman committed May 5, 2022
1 parent 3bcea52 commit d7c7671
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 2 deletions.
42 changes: 40 additions & 2 deletions drivers/tty/serial/stm32-usart.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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)
Expand All @@ -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);
Expand Down Expand Up @@ -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);

Expand Down
1 change: 1 addition & 0 deletions drivers/tty/serial/stm32-usart.h
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ struct stm32_port {
bool hw_flow_control;
bool swap; /* swap RX & TX pins */
bool fifoen;
bool txdone;
int rxftcfg; /* RX FIFO threshold CFG */
int txftcfg; /* TX FIFO threshold CFG */
bool wakeup_src;
Expand Down

0 comments on commit d7c7671

Please sign in to comment.