summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFugang Duan <fugang.duan@nxp.com>2017-07-25 16:42:11 +0800
committerFugang Duan <fugang.duan@nxp.com>2017-07-25 19:43:35 +0800
commitb30a009e7e5f3d192a6986296740be5da249f78d (patch)
tree27728d18df7006e15c5df0f6dba8c3635d966e0d
parent9d6a1875d643b6d412be327f4a78231477c200de (diff)
MLK-16067 tty: serial: lpuart: enable wakeup source in .suspend_noirq()
When use lpuart with DMA mode as wake up source, it still switch to cpu mode in .suspend() that enable cpu interrupts RIE and ILIE as wakkup source. When the wakeup signal coming while rx dma chan is already teminated down, then driver should not call irq handler to submit the new dma descriptor. Enable the wakeup irq bits in .suspend_noirq() and disable the wakeup irq bits in .resume_noirq(). Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
-rw-r--r--drivers/tty/serial/fsl_lpuart.c85
1 files changed, 70 insertions, 15 deletions
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index ffee1392f395..0099b728e4de 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -2241,6 +2241,63 @@ static int lpuart_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM_SLEEP
+static void serial_lpuart_enable_wakeup(struct lpuart_port *sport, bool on)
+{
+ unsigned int val;
+
+ if (sport->lpuart32) {
+ val = lpuart32_read(sport->port.membase + UARTCTRL);
+ if (on)
+ val |= (UARTCTRL_RIE | UARTCTRL_ILIE);
+ else
+ val &= ~(UARTCTRL_RIE | UARTCTRL_ILIE);
+ lpuart32_write(val, sport->port.membase + UARTCTRL);
+ } else {
+ val = readb(sport->port.membase + UARTCR2);
+ if (on)
+ val |= UARTCR2_RIE;
+ else
+ val &= ~UARTCR2_RIE;
+ writeb(val, sport->port.membase + UARTCR2);
+ }
+}
+
+static int lpuart_suspend_noirq(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct lpuart_port *sport = platform_get_drvdata(pdev);
+
+ serial_lpuart_enable_wakeup(sport, true);
+
+ clk_disable(sport->ipg_clk);
+ pinctrl_pm_select_sleep_state(dev);
+
+ return 0;
+}
+
+static int lpuart_resume_noirq(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct lpuart_port *sport = platform_get_drvdata(pdev);
+ unsigned int val;
+ int ret;
+
+ pinctrl_pm_select_default_state(dev);
+ ret = clk_enable(sport->ipg_clk);
+ if (ret)
+ return ret;
+
+ serial_lpuart_enable_wakeup(sport, false);
+
+ /* clear the wakeup flags */
+ if (sport->lpuart32) {
+ val = lpuart32_read(sport->port.membase + UARTSTAT);
+ lpuart32_write(val, sport->port.membase + UARTSTAT);
+ }
+
+ return 0;
+}
+
static int lpuart_suspend(struct device *dev)
{
struct lpuart_port *sport = dev_get_drvdata(dev);
@@ -2258,17 +2315,11 @@ static int lpuart_suspend(struct device *dev)
/* disable Rx/Tx and interrupts */
temp = lpuart32_read(sport->port.membase + UARTCTRL);
temp &= ~(UARTCTRL_TE | UARTCTRL_TIE | UARTCTRL_TCIE);
- if (!console_suspend_enabled && uart_console(&sport->port) &&
- !sport->port.irq_wake)
- temp &= ~(UARTCTRL_RIE | UARTCTRL_ILIE);
lpuart32_write(temp, sport->port.membase + UARTCTRL);
} else {
/* disable Rx/Tx and interrupts */
temp = readb(sport->port.membase + UARTCR2);
temp &= ~(UARTCR2_TE | UARTCR2_TIE | UARTCR2_TCIE);
- if (!console_suspend_enabled && uart_console(&sport->port) &&
- !sport->port.irq_wake)
- temp &= ~UARTCR2_RIE;
writeb(temp, sport->port.membase + UARTCR2);
}
@@ -2296,9 +2347,6 @@ static int lpuart_suspend(struct device *dev)
dmaengine_terminate_all(sport->dma_tx_chan);
}
- clk_disable_unprepare(sport->ipg_clk);
- pinctrl_pm_select_sleep_state(dev);
-
return 0;
}
@@ -2408,9 +2456,6 @@ static int lpuart_resume(struct device *dev)
{
struct lpuart_port *sport = dev_get_drvdata(dev);
- pinctrl_pm_select_default_state(dev);
- clk_prepare_enable(sport->ipg_clk);
-
if (sport->lpuart32)
lpuart32_resume_init(sport);
else
@@ -2422,9 +2467,19 @@ static int lpuart_resume(struct device *dev)
return 0;
}
-#endif
-static SIMPLE_DEV_PM_OPS(lpuart_pm_ops, lpuart_suspend, lpuart_resume);
+static const struct dev_pm_ops lpuart_pm_ops = {
+ .suspend_noirq = lpuart_suspend_noirq,
+ .resume_noirq = lpuart_resume_noirq,
+ .suspend = lpuart_suspend,
+ .resume = lpuart_resume,
+};
+#define SERIAL_LPUART_PM_OPS (&lpuart_pm_ops)
+
+#else /* !CONFIG_PM_SLEEP */
+
+#define SERIAL_LPUART_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
static struct platform_driver lpuart_driver = {
.probe = lpuart_probe,
@@ -2432,7 +2487,7 @@ static struct platform_driver lpuart_driver = {
.driver = {
.name = "fsl-lpuart",
.of_match_table = lpuart_dt_ids,
- .pm = &lpuart_pm_ops,
+ .pm = SERIAL_LPUART_PM_OPS,
},
};