lkml.org 
[lkml]   [2022]   [Oct]   [19]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 6.0 091/862] serial: stm32: Deassert Transmit Enable on ->rs485_config()
    Date
    From: Lukas Wunner <lukas@wunner.de>

    commit adafbbf6895eb0ce41a313c6ee68870ab9aa93cd upstream.

    The STM32 USART can control RS-485 Transmit Enable in hardware. Since
    commit 7df5081cbf5e ("serial: stm32: Add RS485 RTS GPIO control"),
    it can alternatively be controlled in software. That was done to allow
    RS-485 even if the RTS pin is unavailable because it's pinmuxed to a
    different function.

    However the commit neglected to deassert Transmit Enable upon invocation
    of the ->rs485_config() callback. Fix it.

    Avoid forward declarations by moving stm32_usart_tx_empty(),
    stm32_usart_rs485_rts_enable() and stm32_usart_rs485_rts_disable()
    further up in the driver.

    Fixes: 7df5081cbf5e ("serial: stm32: Add RS485 RTS GPIO control")
    Cc: stable@vger.kernel.org # v5.9+
    Cc: Marek Vasut <marex@denx.de>
    Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
    Signed-off-by: Lukas Wunner <lukas@wunner.de>
    Link: https://lore.kernel.org/r/6059eab35dba394468335ef640df8b0050fd9dbd.1662886616.git.lukas@wunner.de
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    drivers/tty/serial/stm32-usart.c | 100 ++++++++++++++++++++-------------------
    1 file changed, 53 insertions(+), 47 deletions(-)

    --- a/drivers/tty/serial/stm32-usart.c
    +++ b/drivers/tty/serial/stm32-usart.c
    @@ -131,6 +131,53 @@ static void stm32_usart_clr_bits(struct
    writel_relaxed(val, port->membase + reg);
    }

    +static unsigned int stm32_usart_tx_empty(struct uart_port *port)
    +{
    + struct stm32_port *stm32_port = to_stm32_port(port);
    + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
    +
    + if (readl_relaxed(port->membase + ofs->isr) & USART_SR_TC)
    + return TIOCSER_TEMT;
    +
    + return 0;
    +}
    +
    +static void stm32_usart_rs485_rts_enable(struct uart_port *port)
    +{
    + struct stm32_port *stm32_port = to_stm32_port(port);
    + struct serial_rs485 *rs485conf = &port->rs485;
    +
    + if (stm32_port->hw_flow_control ||
    + !(rs485conf->flags & SER_RS485_ENABLED))
    + return;
    +
    + if (rs485conf->flags & SER_RS485_RTS_ON_SEND) {
    + mctrl_gpio_set(stm32_port->gpios,
    + stm32_port->port.mctrl | TIOCM_RTS);
    + } else {
    + mctrl_gpio_set(stm32_port->gpios,
    + stm32_port->port.mctrl & ~TIOCM_RTS);
    + }
    +}
    +
    +static void stm32_usart_rs485_rts_disable(struct uart_port *port)
    +{
    + struct stm32_port *stm32_port = to_stm32_port(port);
    + struct serial_rs485 *rs485conf = &port->rs485;
    +
    + if (stm32_port->hw_flow_control ||
    + !(rs485conf->flags & SER_RS485_ENABLED))
    + return;
    +
    + if (rs485conf->flags & SER_RS485_RTS_ON_SEND) {
    + mctrl_gpio_set(stm32_port->gpios,
    + stm32_port->port.mctrl & ~TIOCM_RTS);
    + } else {
    + mctrl_gpio_set(stm32_port->gpios,
    + stm32_port->port.mctrl | TIOCM_RTS);
    + }
    +}
    +
    static void stm32_usart_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE,
    u32 delay_DDE, u32 baud)
    {
    @@ -214,6 +261,12 @@ static int stm32_usart_config_rs485(stru

    stm32_usart_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));

    + /* Adjust RTS polarity in case it's driven in software */
    + if (stm32_usart_tx_empty(port))
    + stm32_usart_rs485_rts_disable(port);
    + else
    + stm32_usart_rs485_rts_enable(port);
    +
    return 0;
    }

    @@ -529,42 +582,6 @@ static void stm32_usart_tc_interrupt_dis
    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);
    - struct serial_rs485 *rs485conf = &port->rs485;
    -
    - if (stm32_port->hw_flow_control ||
    - !(rs485conf->flags & SER_RS485_ENABLED))
    - return;
    -
    - if (rs485conf->flags & SER_RS485_RTS_ON_SEND) {
    - mctrl_gpio_set(stm32_port->gpios,
    - stm32_port->port.mctrl | TIOCM_RTS);
    - } else {
    - mctrl_gpio_set(stm32_port->gpios,
    - stm32_port->port.mctrl & ~TIOCM_RTS);
    - }
    -}
    -
    -static void stm32_usart_rs485_rts_disable(struct uart_port *port)
    -{
    - struct stm32_port *stm32_port = to_stm32_port(port);
    - struct serial_rs485 *rs485conf = &port->rs485;
    -
    - if (stm32_port->hw_flow_control ||
    - !(rs485conf->flags & SER_RS485_ENABLED))
    - return;
    -
    - if (rs485conf->flags & SER_RS485_RTS_ON_SEND) {
    - mctrl_gpio_set(stm32_port->gpios,
    - stm32_port->port.mctrl & ~TIOCM_RTS);
    - } else {
    - mctrl_gpio_set(stm32_port->gpios,
    - stm32_port->port.mctrl | TIOCM_RTS);
    - }
    -}
    -
    static void stm32_usart_transmit_chars_pio(struct uart_port *port)
    {
    struct stm32_port *stm32_port = to_stm32_port(port);
    @@ -807,17 +824,6 @@ static irqreturn_t stm32_usart_threaded_
    return IRQ_HANDLED;
    }

    -static unsigned int stm32_usart_tx_empty(struct uart_port *port)
    -{
    - struct stm32_port *stm32_port = to_stm32_port(port);
    - const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
    -
    - if (readl_relaxed(port->membase + ofs->isr) & USART_SR_TC)
    - return TIOCSER_TEMT;
    -
    - return 0;
    -}
    -
    static void stm32_usart_set_mctrl(struct uart_port *port, unsigned int mctrl)
    {
    struct stm32_port *stm32_port = to_stm32_port(port);

    \
     
     \ /
      Last update: 2022-10-19 13:12    [W:4.034 / U:0.488 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site