summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorPhilippe Schenker <philippe.schenker@toradex.com>2019-10-10 19:02:09 +0200
committerMax Krummenacher <max.krummenacher@toradex.com>2022-12-07 10:01:16 +0100
commit737e98e5f6ff1040f1a77dc1e89fa7558f393995 (patch)
treec1fad8ec91df161d1651fde5e66a5a3e0c033700 /drivers
parent22138351a53fe3ca3c77fa6f0fdc98498d43b962 (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.c67
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);