diff options
Diffstat (limited to 'drivers/tty/serial/fsl_lpuart.c')
-rw-r--r-- | drivers/tty/serial/fsl_lpuart.c | 67 |
1 files changed, 39 insertions, 28 deletions
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 0d6e62f6bb07..f6c33cd228c8 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -274,6 +274,8 @@ struct lpuart_port { int rx_dma_rng_buf_len; unsigned int dma_tx_nents; wait_queue_head_t dma_wait; + bool is_cs7; /* Set to true when character size is 7 */ + /* and the parity is enabled */ }; struct lpuart_soc_data { @@ -990,12 +992,12 @@ static void lpuart32_rxint(struct lpuart_port *sport) if (sr & (UARTSTAT_PE | UARTSTAT_OR | UARTSTAT_FE)) { if (sr & UARTSTAT_PE) { + sport->port.icount.parity++; + } else if (sr & UARTSTAT_FE) { if (is_break) sport->port.icount.brk++; else - sport->port.icount.parity++; - } else if (sr & UARTSTAT_FE) { - sport->port.icount.frame++; + sport->port.icount.frame++; } if (sr & UARTSTAT_OR) @@ -1010,18 +1012,21 @@ static void lpuart32_rxint(struct lpuart_port *sport) sr &= sport->port.read_status_mask; if (sr & UARTSTAT_PE) { + flg = TTY_PARITY; + } else if (sr & UARTSTAT_FE) { if (is_break) flg = TTY_BREAK; else - flg = TTY_PARITY; - } else if (sr & UARTSTAT_FE) { - flg = TTY_FRAME; + flg = TTY_FRAME; } if (sr & UARTSTAT_OR) flg = TTY_OVERRUN; } + if (sport->is_cs7) + rx &= 0x7F; + if (tty_insert_flip_char(port, rx, flg) == 0) sport->port.icount.buf_overrun++; } @@ -1107,6 +1112,17 @@ static void lpuart_handle_sysrq(struct lpuart_port *sport) } } +static int lpuart_tty_insert_flip_string(struct tty_port *port, + unsigned char *chars, size_t size, bool is_cs7) +{ + int i; + + if (is_cs7) + for (i = 0; i < size; i++) + chars[i] &= 0x7F; + return tty_insert_flip_string(port, chars, size); +} + static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) { struct tty_port *port = &sport->port.state->port; @@ -1217,7 +1233,8 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) if (ring->head < ring->tail) { count = sport->rx_sgl.length - ring->tail; - copied = tty_insert_flip_string(port, ring->buf + ring->tail, count); + copied = lpuart_tty_insert_flip_string(port, ring->buf + ring->tail, + count, sport->is_cs7); if (copied != count) sport->port.icount.buf_overrun++; ring->tail = 0; @@ -1227,7 +1244,8 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) /* Finally we read data from tail to head */ if (ring->tail < ring->head) { count = ring->head - ring->tail; - copied = tty_insert_flip_string(port, ring->buf + ring->tail, count); + copied = lpuart_tty_insert_flip_string(port, ring->buf + ring->tail, + count, sport->is_cs7); if (copied != count) sport->port.icount.buf_overrun++; /* Wrap ring->head if needed */ @@ -1355,7 +1373,7 @@ static void lpuart_dma_rx_free(struct uart_port *port) sport->dma_rx_cookie = -EINVAL; } -static int lpuart_config_rs485(struct uart_port *port, +static int lpuart_config_rs485(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485) { struct lpuart_port *sport = container_of(port, @@ -1365,11 +1383,6 @@ static int lpuart_config_rs485(struct uart_port *port, ~(UARTMODEM_TXRTSPOL | UARTMODEM_TXRTSE); writeb(modem, sport->port.membase + UARTMODEM); - /* 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; @@ -1390,7 +1403,7 @@ static int lpuart_config_rs485(struct uart_port *port, return 0; } -static int lpuart32_config_rs485(struct uart_port *port, +static int lpuart32_config_rs485(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485) { struct lpuart_port *sport = container_of(port, @@ -1400,11 +1413,6 @@ static int lpuart32_config_rs485(struct uart_port *port, & ~(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; @@ -2076,6 +2084,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, ctrl = old_ctrl = lpuart32_read(&sport->port, UARTCTRL); bd = lpuart32_read(&sport->port, UARTBAUD); modem = lpuart32_read(&sport->port, UARTMODIR); + sport->is_cs7 = false; /* * only support CS8 and CS7, and for CS7 must enable PE. * supported mode: @@ -2194,6 +2203,9 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, lpuart32_write(&sport->port, ctrl, UARTCTRL); /* restore control register */ + if ((ctrl & (UARTCTRL_PE | UARTCTRL_M)) == UARTCTRL_PE) + sport->is_cs7 = true; + if (old && sport->lpuart_dma_rx_use) { if (!lpuart_start_rx_dma(sport)) rx_dma_timer_init(sport); @@ -2621,6 +2633,11 @@ static struct uart_driver lpuart_reg = { .cons = LPUART_CONSOLE, }; +static const struct serial_rs485 lpuart_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND, + /* delay_rts_* and RX_DURING_TX are not supported */ +}; + static int lpuart_probe(struct platform_device *pdev) { const struct lpuart_soc_data *sdata = of_device_get_match_data(&pdev->dev); @@ -2660,6 +2677,7 @@ static int lpuart_probe(struct platform_device *pdev) sport->port.rs485_config = lpuart32_config_rs485; else sport->port.rs485_config = lpuart_config_rs485; + sport->port.rs485_supported = lpuart_rs485_supported; sport->ipg_clk = devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(sport->ipg_clk)) { @@ -2717,14 +2735,7 @@ static int lpuart_probe(struct platform_device *pdev) if (ret) goto failed_get_rs485; - if (sport->port.rs485.flags & SER_RS485_RX_DURING_TX) - dev_err(&pdev->dev, "driver doesn't support RX during TX\n"); - - if (sport->port.rs485.delay_rts_before_send || - sport->port.rs485.delay_rts_after_send) - dev_err(&pdev->dev, "driver doesn't support RTS delays\n"); - - sport->port.rs485_config(&sport->port, &sport->port.rs485); + uart_rs485_config(&sport->port); ret = devm_request_irq(&pdev->dev, sport->port.irq, handler, 0, DRIVER_NAME, sport); |