diff options
author | Fugang Duan <fugang.duan@nxp.com> | 2017-07-25 16:42:11 +0800 |
---|---|---|
committer | Fugang Duan <fugang.duan@nxp.com> | 2017-07-25 19:43:35 +0800 |
commit | b30a009e7e5f3d192a6986296740be5da249f78d (patch) | |
tree | 27728d18df7006e15c5df0f6dba8c3635d966e0d | |
parent | 9d6a1875d643b6d412be327f4a78231477c200de (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.c | 85 |
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, }, }; |