Skip to content

Commit 6373ab4

Browse files
Jiri Slaby (SUSE)gregkh
authored andcommitted
serial: atmel: don't stop the transmitter when doing PIO
Writing ATMEL_US_TXDIS to ATMEL_US_CR makes the transmitter NOT to send the just queued character. This means when the character is last and uart calls ops->stop_tx(), the character is not sent at all. The usart datasheet is not much specific on this, it just says the transmitter is stopped. But apparently, the character is dropped. So we should stop the transmitter only for DMA and PDC transfers to not send any more characters. For PIO, this is unexpected and deviates from other drivers. In particular, the below referenced commit broke TX as it added a call to ->stop_tx() after the very last character written to the transmitter. So fix this by limiting the write of ATMEL_US_TXDIS to DMA transfers only. Even there, I don't know if it is correctly implemented. Are all the queued characters sent once ->start_tx() is called? Anyone tested flow control -- be it hard (RTSCTS) or the soft (XOFF/XON) one? Fixes: 2d141e6 ("tty: serial: use uart_port_tx() helper") Cc: Richard Genoud <[email protected]> Cc: Nicolas Ferre <[email protected]> Cc: Alexandre Belloni <[email protected]> Cc: Claudiu Beznea <[email protected]> Cc: [email protected] Reported-by: Michael Walle <[email protected]> Signed-off-by: Jiri Slaby (SUSE) <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 94ec165 commit 6373ab4

File tree

1 file changed

+15
-10
lines changed

1 file changed

+15
-10
lines changed

drivers/tty/serial/atmel_serial.c

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -553,19 +553,22 @@ static void atmel_stop_tx(struct uart_port *port)
553553
{
554554
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
555555
bool is_pdc = atmel_use_pdc_tx(port);
556+
bool is_dma = is_pdc || atmel_use_dma_tx(port);
556557

557558
if (is_pdc) {
558559
/* disable PDC transmit */
559560
atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS);
560561
}
561562

562-
/*
563-
* Disable the transmitter.
564-
* This is mandatory when DMA is used, otherwise the DMA buffer
565-
* is fully transmitted.
566-
*/
567-
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS);
568-
atmel_port->tx_stopped = true;
563+
if (is_dma) {
564+
/*
565+
* Disable the transmitter.
566+
* This is mandatory when DMA is used, otherwise the DMA buffer
567+
* is fully transmitted.
568+
*/
569+
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS);
570+
atmel_port->tx_stopped = true;
571+
}
569572

570573
/* Disable interrupts */
571574
atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask);
@@ -601,9 +604,11 @@ static void atmel_start_tx(struct uart_port *port)
601604
/* Enable interrupts */
602605
atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask);
603606

604-
/* re-enable the transmitter */
605-
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN);
606-
atmel_port->tx_stopped = false;
607+
if (is_dma) {
608+
/* re-enable the transmitter */
609+
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN);
610+
atmel_port->tx_stopped = false;
611+
}
607612
}
608613

609614
/*

0 commit comments

Comments
 (0)