diff options
author | Philippe Schenker <philippe.schenker@toradex.com> | 2019-10-10 19:02:09 +0200 |
---|---|---|
committer | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2020-02-12 11:06:06 +0100 |
commit | cdb1eb1c7a8304a237b4a806dc939193ab034d5e (patch) | |
tree | b40671a8cd75debef3aa5024e723289a6375ccba /drivers | |
parent | 114f4a73030fcdcef60564762b2d40b9d1ca9c40 (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.c | 71 |
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); |