diff options
author | Philippe Schenker <philippe.schenker@toradex.com> | 2019-10-10 19:02:09 +0200 |
---|---|---|
committer | Max Krummenacher <max.krummenacher@toradex.com> | 2022-12-07 10:01:16 +0100 |
commit | 737e98e5f6ff1040f1a77dc1e89fa7558f393995 (patch) | |
tree | c1fad8ec91df161d1651fde5e66a5a3e0c033700 /drivers | |
parent | 22138351a53fe3ca3c77fa6f0fdc98498d43b962 (diff) |
tty: serial: lpuart: Disable transmitter on setting modem register
Signed-off-by: Philippe Schenker <philippe.schenker@toradex.com>
Conflicts:
drivers/tty/serial/fsl_lpuart.c
Upstream-Status: Inappropriate [Downstream specific, it requires additional patches on fsl_lpuart not available in upstream]
Signed-off-by: Max Krummenacher <max.krummenacher@toradex.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/tty/serial/fsl_lpuart.c | 67 |
1 files changed, 49 insertions, 18 deletions
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 49d643705c9b..37b89b426276 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -1462,6 +1462,48 @@ static void lpuart_dma_rx_free(struct uart_port *port, bool dma_terminate) sport->dma_rx_cookie = -EINVAL; } +static void __maybe_unused lpuart_setup_rs485(struct lpuart_port *sport) +{ + /* Todo implement for 8-bit registers */ +} + +static void lpuart32_setup_rs485(struct lpuart_port *sport) +{ + struct serial_rs485 *rs485 = &sport->port.rs485; + unsigned long val, ctrl, ctrl_saved; + + val = lpuart32_read(&sport->port, UARTMODIR) & + ~(UARTMODIR_TXRTSPOL | UARTMODIR_TXRTSE); + + /* Make sure transmitter is disabled */ + ctrl = lpuart32_read(&sport->port, UARTCTRL); + ctrl_saved = ctrl; + ctrl &= ~(UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_TE | + UARTCTRL_RIE | UARTCTRL_RE); + lpuart32_write(&sport->port, ctrl, UARTCTRL); + + if (rs485->flags & SER_RS485_ENABLED) { + /* Enable auto RS-485 RTS mode */ + val |= UARTMODIR_TXRTSE; + + /* + * The hardware defaults to RTS logic HIGH while transfer. + * Switch polarity in case RTS shall be logic HIGH + * after transfer. + * Note: UART is assumed to be active high. + */ + if (rs485->flags & SER_RS485_RTS_ON_SEND) + val &= ~UARTMODIR_TXRTSPOL; + else if (rs485->flags & SER_RS485_RTS_AFTER_SEND) + val |= UARTMODIR_TXRTSPOL; + } + + lpuart32_write(&sport->port, val, UARTMODIR); + + /* Restore cr2 */ + lpuart32_write(&sport->port, ctrl_saved, UARTCTRL); +} + static int lpuart_config_rs485(struct uart_port *port, struct serial_rs485 *rs485) { @@ -1519,18 +1561,12 @@ static int lpuart32_config_rs485(struct uart_port *port, struct lpuart_port *sport = container_of(port, struct lpuart_port, port); - unsigned long modem = lpuart32_read(&sport->port, UARTMODIR) - & ~(UARTMODEM_TXRTSPOL | UARTMODEM_TXRTSE); - lpuart32_write(&sport->port, modem, UARTMODIR); - /* clear unsupported configurations */ rs485->delay_rts_before_send = 0; rs485->delay_rts_after_send = 0; rs485->flags &= ~SER_RS485_RX_DURING_TX; if (rs485->flags & SER_RS485_ENABLED) { - /* Enable auto RS-485 RTS mode */ - modem |= UARTMODEM_TXRTSE; /* * RTS needs to be logic HIGH either during transfer _or_ after @@ -1544,23 +1580,14 @@ static int lpuart32_config_rs485(struct uart_port *port, if (rs485->flags & SER_RS485_RTS_ON_SEND && rs485->flags & SER_RS485_RTS_AFTER_SEND) rs485->flags &= ~SER_RS485_RTS_AFTER_SEND; - - /* - * The hardware defaults to RTS logic HIGH while transfer. - * Switch polarity in case RTS shall be logic HIGH - * after transfer. - * Note: UART is assumed to be active high. - */ - if (rs485->flags & SER_RS485_RTS_ON_SEND) - modem |= UARTMODEM_TXRTSPOL; - else if (rs485->flags & SER_RS485_RTS_AFTER_SEND) - modem &= ~UARTMODEM_TXRTSPOL; } /* Store the new configuration */ sport->port.rs485 = *rs485; - lpuart32_write(&sport->port, modem, UARTMODIR); + /* config_rs485 gets called in irqsave context so do not lock again */ + lpuart32_setup_rs485(sport); + return 0; } @@ -1911,6 +1938,7 @@ static void lpuart32_hw_setup(struct lpuart_port *sport) lpuart_rx_dma_startup(sport); lpuart_tx_dma_startup(sport); + lpuart32_setup_rs485(sport); lpuart32_setup_watermark_enable(sport); lpuart32_configure(sport); @@ -2873,6 +2901,7 @@ static int lpuart_probe(struct platform_device *pdev) struct lpuart_port *sport; struct resource *res; irq_handler_t handler; + unsigned long flags; int ret; sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL); @@ -2982,7 +3011,9 @@ static int lpuart_probe(struct platform_device *pdev) if (ret) goto failed_reset; + spin_lock_irqsave(&sport->port.lock, flags); sport->port.rs485_config(&sport->port, &sport->port.rs485); + spin_unlock_irqrestore(&sport->port.lock, flags); ret = devm_request_irq(&pdev->dev, sport->port.irq, handler, 0, DRIVER_NAME, sport); |