summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorPhilippe Schenker <philippe.schenker@toradex.com>2019-10-10 19:02:09 +0200
committerMarcel Ziswiler <marcel.ziswiler@toradex.com>2020-02-12 11:06:06 +0100
commitcdb1eb1c7a8304a237b4a806dc939193ab034d5e (patch)
treeb40671a8cd75debef3aa5024e723289a6375ccba /drivers
parent114f4a73030fcdcef60564762b2d40b9d1ca9c40 (diff)
tty: serial: lpuart: Disable transmitter on setting modem register
Signed-off-by: Philippe Schenker <philippe.schenker@toradex.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/tty/serial/fsl_lpuart.c71
1 files changed, 51 insertions, 20 deletions
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 36baca0ee12e..3d19bcbfff47 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -1213,6 +1213,48 @@ static inline void lpuart_prepare_rx(struct lpuart_port *sport)
spin_unlock_irqrestore(&sport->port.lock, flags);
}
+static void 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)
{
@@ -1270,19 +1312,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)
- & ~(UARTMODIR_TXRTSPOL | UARTMODIR_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 |= UARTMODIR_TXRTSE;
-
/*
* RTS needs to be logic HIGH either during transer _or_ after
* transfer, other variants are not supported by the hardware.
@@ -1295,23 +1330,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 &= ~UARTMODIR_TXRTSPOL;
- else if (rs485->flags & SER_RS485_RTS_AFTER_SEND)
- modem |= UARTMODIR_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;
}
@@ -1629,6 +1655,7 @@ static int lpuart32_startup(struct uart_port *port)
spin_lock_irqsave(&sport->port.lock, flags);
+ lpuart32_setup_rs485(sport);
lpuart32_setup_watermark(sport);
temp = lpuart32_read(&sport->port, UARTCTRL);
@@ -2490,7 +2517,7 @@ static int lpuart_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
struct lpuart_port *sport;
struct resource *res;
- unsigned long cr_32;
+ unsigned long cr_32, flags;
unsigned char cr_8;
int ret;
@@ -2616,7 +2643,10 @@ static int lpuart_probe(struct platform_device *pdev)
if (of_property_read_bool(np, "linux,rs485-enabled-at-boot-time")) {
sport->port.rs485.flags |= SER_RS485_ENABLED;
sport->port.rs485.flags |= SER_RS485_RTS_ON_SEND;
+
+ spin_lock_irqsave(&sport->port.lock, flags);
sport->port.rs485_config(&sport->port, &sport->port.rs485);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
}
return 0;
@@ -2854,6 +2884,7 @@ static inline void lpuart32_resume_init(struct lpuart_port *sport)
unsigned long flags;
spin_lock_irqsave(&sport->port.lock, flags);
+ lpuart32_setup_rs485(sport);
lpuart32_setup_watermark(sport);
temp = lpuart32_read(&sport->port, UARTCTRL);