X-Git-Url: http://git.openwrt.org/?p=openwrt%2Fstaging%2Fwigyori.git;a=blobdiff_plain;f=target%2Flinux%2Flayerscape%2Fpatches-5.4%2F819-uart-0009-MLK-17133-02-tty-serial-lpuart-add-runtime-pm-suppor.patch;fp=target%2Flinux%2Flayerscape%2Fpatches-5.4%2F819-uart-0009-MLK-17133-02-tty-serial-lpuart-add-runtime-pm-suppor.patch;h=457b4836db2831728a7f50ccc6fae19a8c265fe8;hp=0000000000000000000000000000000000000000;hb=cddd4591404fb4c53dc0b3c0b15b942cdbed4356;hpb=d1d2c0b5579ea4f69a42246c9318539d61ba1999 diff --git a/target/linux/layerscape/patches-5.4/819-uart-0009-MLK-17133-02-tty-serial-lpuart-add-runtime-pm-suppor.patch b/target/linux/layerscape/patches-5.4/819-uart-0009-MLK-17133-02-tty-serial-lpuart-add-runtime-pm-suppor.patch new file mode 100644 index 0000000000..457b4836db --- /dev/null +++ b/target/linux/layerscape/patches-5.4/819-uart-0009-MLK-17133-02-tty-serial-lpuart-add-runtime-pm-suppor.patch @@ -0,0 +1,199 @@ +From ff3d8063eed907bed728a14e1519dc659036315a Mon Sep 17 00:00:00 2001 +From: Fugang Duan +Date: Wed, 11 Sep 2019 16:36:48 +0800 +Subject: [PATCH] MLK-17133-02 tty: serial: lpuart: add runtime pm support + +Add runtime pm support to manage lpuart clock and its power domain +to save power in system idle and system suspend stages. + +Signed-off-by: Fugang Duan +Reviewed-by: Robin Gong +--- + drivers/tty/serial/fsl_lpuart.c | 80 ++++++++++++++++++++++++++++++++++++----- + 1 file changed, 72 insertions(+), 8 deletions(-) + +--- a/drivers/tty/serial/fsl_lpuart.c ++++ b/drivers/tty/serial/fsl_lpuart.c +@@ -245,6 +245,7 @@ + + /* Rx DMA timeout in ms, which is used to calculate Rx ring buffer size */ + #define DMA_RX_TIMEOUT (10) ++#define UART_AUTOSUSPEND_TIMEOUT 3000 + + #define DRIVER_NAME "fsl-lpuart" + #define DEV_NAME "ttyLP" +@@ -846,6 +847,20 @@ static void lpuart32_start_tx(struct uar + } + } + ++static void ++lpuart_uart_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) ++{ ++ switch (state) { ++ case UART_PM_STATE_OFF: ++ pm_runtime_mark_last_busy(port->dev); ++ pm_runtime_put_autosuspend(port->dev); ++ break; ++ default: ++ pm_runtime_get_sync(port->dev); ++ break; ++ } ++} ++ + /* return TIOCSER_TEMT when transmitter is not busy */ + static unsigned int lpuart_tx_empty(struct uart_port *port) + { +@@ -2259,6 +2274,7 @@ static const struct uart_ops lpuart_pops + .break_ctl = lpuart_break_ctl, + .startup = lpuart_startup, + .shutdown = lpuart_shutdown, ++ .pm = lpuart_uart_pm, + .set_termios = lpuart_set_termios, + .type = lpuart_type, + .request_port = lpuart_request_port, +@@ -2283,6 +2299,7 @@ static const struct uart_ops lpuart32_po + .break_ctl = lpuart32_break_ctl, + .startup = lpuart32_startup, + .shutdown = lpuart32_shutdown, ++ .pm = lpuart_uart_pm, + .set_termios = lpuart32_set_termios, + .type = lpuart_type, + .request_port = lpuart_request_port, +@@ -2742,6 +2759,11 @@ static int lpuart_probe(struct platform_ + if (ret) + goto failed_irq_request; + ++ pm_runtime_use_autosuspend(&pdev->dev); ++ pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT); ++ pm_runtime_set_active(&pdev->dev); ++ pm_runtime_enable(&pdev->dev); ++ + ret = uart_add_one_port(&lpuart_reg, &sport->port); + if (ret) + goto failed_attach_port; +@@ -2776,6 +2798,9 @@ static int lpuart_probe(struct platform_ + failed_reset: + uart_remove_one_port(&lpuart_reg, &sport->port); + failed_attach_port: ++ pm_runtime_disable(&pdev->dev); ++ pm_runtime_set_suspended(&pdev->dev); ++ pm_runtime_dont_use_autosuspend(&pdev->dev); + failed_irq_request: + lpuart_disable_clks(sport); + failed_clock_enable: +@@ -2802,15 +2827,41 @@ static int lpuart_remove(struct platform + if (sport->dma_rx_chan) + dma_release_channel(sport->dma_rx_chan); + ++ pm_runtime_disable(&pdev->dev); ++ pm_runtime_set_suspended(&pdev->dev); ++ pm_runtime_dont_use_autosuspend(&pdev->dev); + return 0; + } + + #ifdef CONFIG_PM_SLEEP ++static int lpuart_runtime_suspend(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct lpuart_port *sport = platform_get_drvdata(pdev); ++ ++ lpuart_disable_clks(sport); ++ ++ return 0; ++}; ++ ++static int lpuart_runtime_resume(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct lpuart_port *sport = platform_get_drvdata(pdev); ++ ++ return lpuart_enable_clks(sport); ++}; ++ + static int lpuart_suspend(struct device *dev) + { + struct lpuart_port *sport = dev_get_drvdata(dev); + unsigned long temp; + bool irq_wake; ++ int ret; ++ ++ ret = clk_prepare_enable(sport->ipg_clk); ++ if (ret) ++ return ret; + + if (lpuart_is_32(sport)) { + /* disable Rx/Tx and interrupts */ +@@ -2824,10 +2875,14 @@ static int lpuart_suspend(struct device + writeb(temp, sport->port.membase + UARTCR2); + } + ++ clk_disable_unprepare(sport->ipg_clk); ++ + uart_suspend_port(&lpuart_reg, &sport->port); + + /* uart_suspend_port() might set wakeup flag */ + irq_wake = irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq)); ++ if (sport->port.suspended && !irq_wake) ++ return 0; + + if (sport->lpuart_dma_rx_use) { + /* +@@ -2858,9 +2913,6 @@ static int lpuart_suspend(struct device + dmaengine_terminate_all(sport->dma_tx_chan); + } + +- if (sport->port.suspended && !irq_wake) +- lpuart_disable_clks(sport); +- + return 0; + } + +@@ -2868,9 +2920,11 @@ static int lpuart_resume(struct device * + { + struct lpuart_port *sport = dev_get_drvdata(dev); + bool irq_wake = irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq)); ++ int ret; + +- if (sport->port.suspended && !irq_wake) +- lpuart_enable_clks(sport); ++ ret = clk_prepare_enable(sport->ipg_clk); ++ if (ret) ++ return ret; + + if (lpuart_is_32(sport)) + lpuart32_setup_watermark_enable(sport); +@@ -2891,13 +2945,23 @@ static int lpuart_resume(struct device * + if (lpuart_is_32(sport)) + lpuart32_configure(sport); + ++ clk_disable_unprepare(sport->ipg_clk); ++ + uart_resume_port(&lpuart_reg, &sport->port); + + return 0; + } +-#endif ++static const struct dev_pm_ops lpuart_pm_ops = { ++ SET_RUNTIME_PM_OPS(lpuart_runtime_suspend, ++ lpuart_runtime_resume, NULL) ++ SET_SYSTEM_SLEEP_PM_OPS(lpuart_suspend, lpuart_resume) ++}; ++#define SERIAL_LPUART_PM_OPS (&lpuart_pm_ops) + +-static SIMPLE_DEV_PM_OPS(lpuart_pm_ops, lpuart_suspend, lpuart_resume); ++#else /* !CONFIG_PM_SLEEP */ ++ ++#define SERIAL_LPUART_PM_OPS NULL ++#endif + + static struct platform_driver lpuart_driver = { + .probe = lpuart_probe, +@@ -2905,7 +2969,7 @@ static struct platform_driver lpuart_dri + .driver = { + .name = "fsl-lpuart", + .of_match_table = lpuart_dt_ids, +- .pm = &lpuart_pm_ops, ++ .pm = SERIAL_LPUART_PM_OPS, + }, + }; +