tty: serial: fsl_lpuart: Update suspend/resume for DMA mode

This change “tty: serial: fsl_lpuart: Update suspend/resume for DMA mode” (commit c05efd6) in Linux kernel is authored by Bhuvanchandra DV <bhuvanchandra.dv [at] toradex.com> on Tue Jul 19 13:13:09 2016 +0530.

Description of "tty: serial: fsl_lpuart: Update suspend/resume for DMA mode"

The change “tty: serial: fsl_lpuart: Update suspend/resume for DMA mode” introduces changes as follows.

tty: serial: fsl_lpuart: Update suspend/resume for DMA mode

When DMA mode is enabled one need to make sure the DMA channels are idle before
entering suspend mode especially when UART ports which are set as wakeup source
and console port with no_console_suspend is set. This patch takes care of
gracefully releasing DMA channels for the above two cases and start the DMA at
resume.

Signed-off-by: Bhuvanchandra DV <bhuvanchandra.dv@toradex.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

Linux kernel releases containing commit c05efd6

The Linux kernel releases containing this commit are as follows.

Linux kernel code changes from "tty: serial: fsl_lpuart: Update suspend/resume for DMA mode"

There are 44 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 drivers/tty/serial/fsl_lpuart.c | 44 +++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)
 
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 93e7589893d2..6ab4b25583d7 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -1949,6 +1949,30 @@ static int lpuart_suspend(struct device *dev)
 	}
 
 	uart_suspend_port(&lpuart_reg, &sport->port);
+
+	if (sport->lpuart_dma_rx_use) {
+		/*
+		 * EDMA driver during suspend will forcefully release any
+		 * non-idle DMA channels. If port wakeup is enabled or if port
+		 * is console port or 'no_console_suspend' is set the Rx DMA
+		 * cannot resume as as expected, hence gracefully release the
+		 * Rx DMA path before suspend and start Rx DMA path on resume.
+		 */
+		if (sport->port.irq_wake) {
+			del_timer_sync(&sport->lpuart_timer);
+			lpuart_dma_rx_free(&sport->port);
+		}
+
+		/* Disable Rx DMA to use UART port as wakeup source */
+		writeb(readb(sport->port.membase + UARTCR5) & ~UARTCR5_RDMAS,
+					sport->port.membase + UARTCR5);
+	}
+
+	if (sport->lpuart_dma_tx_use) {
+		sport->dma_tx_in_progress = false;
+		dmaengine_terminate_all(sport->dma_tx_chan);
+	}
+
 	if (sport->port.suspended && !sport->port.irq_wake)
 		clk_disable_unprepare(sport->clk);
 
@@ -1976,6 +2000,26 @@ static int lpuart_resume(struct device *dev)
 		writeb(temp, sport->port.membase + UARTCR2);
 	}
 
+	if (sport->lpuart_dma_rx_use) {
+		if (sport->port.irq_wake) {
+			if (!lpuart_start_rx_dma(sport)) {
+				sport->lpuart_dma_rx_use = true;
+				rx_dma_timer_init(sport);
+			} else {
+				sport->lpuart_dma_rx_use = false;
+			}
+		}
+	}
+
+	if (sport->dma_tx_chan && !lpuart_dma_tx_request(&sport->port)) {
+			init_waitqueue_head(&sport->dma_wait);
+			sport->lpuart_dma_tx_use = true;
+			writeb(readb(sport->port.membase + UARTCR5) |
+				UARTCR5_TDMAS, sport->port.membase + UARTCR5);
+	} else {
+		sport->lpuart_dma_tx_use = false;
+	}
+
 	uart_resume_port(&lpuart_reg, &sport->port);
 
 	return 0;

The commit for this change in Linux stable tree is c05efd6 (patch).

Last modified: 2020/02/09