Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tty/serial: atmel: Prevent a warning on suspend

The atmel serial port driver reported the following warning on suspend:
atmel_usart f8020000.serial: ttyS1: Unable to drain transmitter

As the ATMEL_US_TXEMPTY status bit in ATMEL_US_CSR is always cleared
when the transmitter is disabled, we need to know the transmitter's
state to return the real fifo state. And as ATMEL_US_CR is write-only,
it is necessary to save the state of the transmitter in a local
variable, and update the variable when TXEN and TXDIS is written in
ATMEL_US_CR.

After those changes, atmel_tx_empty can return "empty" on suspend, the
warning in uart_suspend_port disappears, and suspending is 20ms shorter
for each enabled Atmel serial port.

Signed-off-by: Romain Izard <romain.izard.pro@gmail.com>
Tested-by: Nicolas Ferre <nicolas.ferre@microchip.com>
Acked-by: Nicolas Ferre <nicolas.ferre@microchip.com>
Acked-by: Richard Genoud <richard.genoud@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Romain Izard and committed by
Greg Kroah-Hartman
ea04f82a fa2abb03

+13
+13
drivers/tty/serial/atmel_serial.c
··· 171 171 bool has_hw_timer; 172 172 struct timer_list uart_timer; 173 173 174 + bool tx_stopped; 174 175 bool suspended; 175 176 unsigned int pending; 176 177 unsigned int pending_status; ··· 381 380 */ 382 381 static u_int atmel_tx_empty(struct uart_port *port) 383 382 { 383 + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 384 + 385 + if (atmel_port->tx_stopped) 386 + return TIOCSER_TEMT; 384 387 return (atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXEMPTY) ? 385 388 TIOCSER_TEMT : 386 389 0; ··· 490 485 * is fully transmitted. 491 486 */ 492 487 atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS); 488 + atmel_port->tx_stopped = true; 493 489 494 490 /* Disable interrupts */ 495 491 atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask); ··· 527 521 528 522 /* re-enable the transmitter */ 529 523 atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN); 524 + atmel_port->tx_stopped = false; 530 525 } 531 526 532 527 /* ··· 1850 1843 atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); 1851 1844 /* enable xmit & rcvr */ 1852 1845 atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN); 1846 + atmel_port->tx_stopped = false; 1853 1847 1854 1848 setup_timer(&atmel_port->uart_timer, 1855 1849 atmel_uart_timer_callback, ··· 2107 2099 2108 2100 /* disable receiver and transmitter */ 2109 2101 atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS | ATMEL_US_RXDIS); 2102 + atmel_port->tx_stopped = true; 2110 2103 2111 2104 /* mode */ 2112 2105 if (port->rs485.flags & SER_RS485_ENABLED) { ··· 2193 2184 atmel_uart_writel(port, ATMEL_US_BRGR, quot); 2194 2185 atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); 2195 2186 atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN); 2187 + atmel_port->tx_stopped = false; 2196 2188 2197 2189 /* restore interrupts */ 2198 2190 atmel_uart_writel(port, ATMEL_US_IER, imr); ··· 2437 2427 2438 2428 /* Make sure that tx path is actually able to send characters */ 2439 2429 atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN); 2430 + atmel_port->tx_stopped = false; 2440 2431 2441 2432 uart_console_write(port, s, count, atmel_console_putchar); 2442 2433 ··· 2499 2488 { 2500 2489 int ret; 2501 2490 struct uart_port *port = &atmel_ports[co->index].uart; 2491 + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 2502 2492 int baud = 115200; 2503 2493 int bits = 8; 2504 2494 int parity = 'n'; ··· 2517 2505 atmel_uart_writel(port, ATMEL_US_IDR, -1); 2518 2506 atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); 2519 2507 atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN); 2508 + atmel_port->tx_stopped = false; 2520 2509 2521 2510 if (options) 2522 2511 uart_parse_options(options, &baud, &parity, &bits, &flow);