Skip to content

Commit 4f5cb8c

Browse files
SherrySun5gregkh
authored andcommitted
tty: serial: fsl_lpuart: enable wakeup source for lpuart
LPUART supports both synchronous wakeup and asynchronous wakeup(wakeup the system when the UART clocks are shut-off), the synchronous wakeup is configured by UARTCTRL_RIE interrupt, and the asynchronous wakeup is configured by UARTBAUD_RXEDGIE interrupt. Add lpuart_uport_is_active() to determine if the uart port needs to get into the suspend states, also add lpuart_suspend_noirq() and lpuart_resume_noirq() to enable and disable the wakeup irq bits if the uart port needs to be set as wakeup source. When use lpuart with DMA mode, it still needs to switch to the cpu mode in .suspend() that enable cpu interrupts RIE and RXEDGIE as wakeup source, after system resume back, needs to setup DMA again, .resume() will share the HW setup code with .startup(), so abstract the same code to the api like lpuart32_hw_setup(). Signed-off-by: Sherry Sun <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 96e8298 commit 4f5cb8c

File tree

1 file changed

+200
-81
lines changed

1 file changed

+200
-81
lines changed

drivers/tty/serial/fsl_lpuart.c

Lines changed: 200 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <linux/of.h>
1919
#include <linux/of_device.h>
2020
#include <linux/of_dma.h>
21+
#include <linux/pinctrl/consumer.h>
2122
#include <linux/serial_core.h>
2223
#include <linux/slab.h>
2324
#include <linux/tty_flip.h>
@@ -1627,10 +1628,23 @@ static void lpuart_rx_dma_startup(struct lpuart_port *sport)
16271628
sport->lpuart_dma_rx_use = false;
16281629
}
16291630

1631+
static void lpuart_hw_setup(struct lpuart_port *sport)
1632+
{
1633+
unsigned long flags;
1634+
1635+
spin_lock_irqsave(&sport->port.lock, flags);
1636+
1637+
lpuart_setup_watermark_enable(sport);
1638+
1639+
lpuart_rx_dma_startup(sport);
1640+
lpuart_tx_dma_startup(sport);
1641+
1642+
spin_unlock_irqrestore(&sport->port.lock, flags);
1643+
}
1644+
16301645
static int lpuart_startup(struct uart_port *port)
16311646
{
16321647
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
1633-
unsigned long flags;
16341648
unsigned char temp;
16351649

16361650
/* determine FIFO size and enable FIFO mode */
@@ -1644,15 +1658,7 @@ static int lpuart_startup(struct uart_port *port)
16441658
UARTPFIFO_FIFOSIZE_MASK);
16451659

16461660
lpuart_request_dma(sport);
1647-
1648-
spin_lock_irqsave(&sport->port.lock, flags);
1649-
1650-
lpuart_setup_watermark_enable(sport);
1651-
1652-
lpuart_rx_dma_startup(sport);
1653-
lpuart_tx_dma_startup(sport);
1654-
1655-
spin_unlock_irqrestore(&sport->port.lock, flags);
1661+
lpuart_hw_setup(sport);
16561662

16571663
return 0;
16581664
}
@@ -1675,10 +1681,25 @@ static void lpuart32_configure(struct lpuart_port *sport)
16751681
lpuart32_write(&sport->port, temp, UARTCTRL);
16761682
}
16771683

1684+
static void lpuart32_hw_setup(struct lpuart_port *sport)
1685+
{
1686+
unsigned long flags;
1687+
1688+
spin_lock_irqsave(&sport->port.lock, flags);
1689+
1690+
lpuart32_setup_watermark_enable(sport);
1691+
1692+
lpuart_rx_dma_startup(sport);
1693+
lpuart_tx_dma_startup(sport);
1694+
1695+
lpuart32_configure(sport);
1696+
1697+
spin_unlock_irqrestore(&sport->port.lock, flags);
1698+
}
1699+
16781700
static int lpuart32_startup(struct uart_port *port)
16791701
{
16801702
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
1681-
unsigned long flags;
16821703
unsigned long temp;
16831704

16841705
/* determine FIFO size */
@@ -1703,17 +1724,8 @@ static int lpuart32_startup(struct uart_port *port)
17031724
}
17041725

17051726
lpuart_request_dma(sport);
1727+
lpuart32_hw_setup(sport);
17061728

1707-
spin_lock_irqsave(&sport->port.lock, flags);
1708-
1709-
lpuart32_setup_watermark_enable(sport);
1710-
1711-
lpuart_rx_dma_startup(sport);
1712-
lpuart_tx_dma_startup(sport);
1713-
1714-
lpuart32_configure(sport);
1715-
1716-
spin_unlock_irqrestore(&sport->port.lock, flags);
17171729
return 0;
17181730
}
17191731

@@ -2766,97 +2778,204 @@ static int lpuart_remove(struct platform_device *pdev)
27662778
return 0;
27672779
}
27682780

2769-
static int __maybe_unused lpuart_suspend(struct device *dev)
2781+
static void serial_lpuart_enable_wakeup(struct lpuart_port *sport, bool on)
27702782
{
2771-
struct lpuart_port *sport = dev_get_drvdata(dev);
2772-
unsigned long temp;
2773-
bool irq_wake;
2783+
unsigned int val, baud;
27742784

27752785
if (lpuart_is_32(sport)) {
2776-
/* disable Rx/Tx and interrupts */
2777-
temp = lpuart32_read(&sport->port, UARTCTRL);
2778-
temp &= ~(UARTCTRL_TE | UARTCTRL_TIE | UARTCTRL_TCIE);
2779-
lpuart32_write(&sport->port, temp, UARTCTRL);
2786+
val = lpuart32_read(&sport->port, UARTCTRL);
2787+
baud = lpuart32_read(&sport->port, UARTBAUD);
2788+
if (on) {
2789+
/* set rx_watermark to 0 in wakeup source mode */
2790+
lpuart32_write(&sport->port, 0, UARTWATER);
2791+
val |= UARTCTRL_RIE;
2792+
/* clear RXEDGIF flag before enable RXEDGIE interrupt */
2793+
lpuart32_write(&sport->port, UARTSTAT_RXEDGIF, UARTSTAT);
2794+
baud |= UARTBAUD_RXEDGIE;
2795+
} else {
2796+
val &= ~UARTCTRL_RIE;
2797+
baud &= ~UARTBAUD_RXEDGIE;
2798+
}
2799+
lpuart32_write(&sport->port, val, UARTCTRL);
2800+
lpuart32_write(&sport->port, baud, UARTBAUD);
27802801
} else {
2781-
/* disable Rx/Tx and interrupts */
2782-
temp = readb(sport->port.membase + UARTCR2);
2783-
temp &= ~(UARTCR2_TE | UARTCR2_TIE | UARTCR2_TCIE);
2784-
writeb(temp, sport->port.membase + UARTCR2);
2802+
val = readb(sport->port.membase + UARTCR2);
2803+
if (on)
2804+
val |= UARTCR2_RIE;
2805+
else
2806+
val &= ~UARTCR2_RIE;
2807+
writeb(val, sport->port.membase + UARTCR2);
27852808
}
2809+
}
27862810

2787-
uart_suspend_port(&lpuart_reg, &sport->port);
2811+
static bool lpuart_uport_is_active(struct lpuart_port *sport)
2812+
{
2813+
struct tty_port *port = &sport->port.state->port;
2814+
struct tty_struct *tty;
2815+
struct device *tty_dev;
2816+
int may_wake = 0;
27882817

2789-
/* uart_suspend_port() might set wakeup flag */
2790-
irq_wake = irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq));
2818+
tty = tty_port_tty_get(port);
2819+
if (tty) {
2820+
tty_dev = tty->dev;
2821+
may_wake = device_may_wakeup(tty_dev);
2822+
tty_kref_put(tty);
2823+
}
27912824

2792-
if (sport->lpuart_dma_rx_use) {
2793-
/*
2794-
* EDMA driver during suspend will forcefully release any
2795-
* non-idle DMA channels. If port wakeup is enabled or if port
2796-
* is console port or 'no_console_suspend' is set the Rx DMA
2797-
* cannot resume as expected, hence gracefully release the
2798-
* Rx DMA path before suspend and start Rx DMA path on resume.
2799-
*/
2800-
if (irq_wake) {
2801-
del_timer_sync(&sport->lpuart_timer);
2802-
lpuart_dma_rx_free(&sport->port);
2803-
}
2825+
if ((tty_port_initialized(port) && may_wake) ||
2826+
(!console_suspend_enabled && uart_console(&sport->port)))
2827+
return true;
2828+
2829+
return false;
2830+
}
2831+
2832+
static int __maybe_unused lpuart_suspend_noirq(struct device *dev)
2833+
{
2834+
struct lpuart_port *sport = dev_get_drvdata(dev);
2835+
bool irq_wake = irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq));
2836+
2837+
if (lpuart_uport_is_active(sport))
2838+
serial_lpuart_enable_wakeup(sport, !!irq_wake);
2839+
2840+
pinctrl_pm_select_sleep_state(dev);
2841+
2842+
return 0;
2843+
}
2844+
2845+
static int __maybe_unused lpuart_resume_noirq(struct device *dev)
2846+
{
2847+
struct lpuart_port *sport = dev_get_drvdata(dev);
2848+
unsigned int val;
2849+
2850+
pinctrl_pm_select_default_state(dev);
2851+
2852+
if (lpuart_uport_is_active(sport)) {
2853+
serial_lpuart_enable_wakeup(sport, false);
28042854

2805-
/* Disable Rx DMA to use UART port as wakeup source */
2855+
/* clear the wakeup flags */
28062856
if (lpuart_is_32(sport)) {
2807-
temp = lpuart32_read(&sport->port, UARTBAUD);
2808-
lpuart32_write(&sport->port, temp & ~UARTBAUD_RDMAE,
2809-
UARTBAUD);
2810-
} else {
2811-
writeb(readb(sport->port.membase + UARTCR5) &
2812-
~UARTCR5_RDMAS, sport->port.membase + UARTCR5);
2857+
val = lpuart32_read(&sport->port, UARTSTAT);
2858+
lpuart32_write(&sport->port, val, UARTSTAT);
28132859
}
28142860
}
28152861

2816-
if (sport->lpuart_dma_tx_use) {
2817-
sport->dma_tx_in_progress = false;
2818-
dmaengine_terminate_all(sport->dma_tx_chan);
2819-
}
2820-
2821-
if (sport->port.suspended && !irq_wake)
2822-
lpuart_disable_clks(sport);
2823-
28242862
return 0;
28252863
}
28262864

2827-
static int __maybe_unused lpuart_resume(struct device *dev)
2865+
static int __maybe_unused lpuart_suspend(struct device *dev)
28282866
{
28292867
struct lpuart_port *sport = dev_get_drvdata(dev);
2830-
bool irq_wake = irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq));
2868+
unsigned long temp, flags;
28312869

2832-
if (sport->port.suspended && !irq_wake)
2833-
lpuart_enable_clks(sport);
2870+
uart_suspend_port(&lpuart_reg, &sport->port);
28342871

2835-
if (lpuart_is_32(sport))
2836-
lpuart32_setup_watermark_enable(sport);
2837-
else
2838-
lpuart_setup_watermark_enable(sport);
2872+
if (lpuart_uport_is_active(sport)) {
2873+
spin_lock_irqsave(&sport->port.lock, flags);
2874+
if (lpuart_is_32(sport)) {
2875+
/* disable Rx/Tx and interrupts */
2876+
temp = lpuart32_read(&sport->port, UARTCTRL);
2877+
temp &= ~(UARTCTRL_TE | UARTCTRL_TIE | UARTCTRL_TCIE);
2878+
lpuart32_write(&sport->port, temp, UARTCTRL);
2879+
} else {
2880+
/* disable Rx/Tx and interrupts */
2881+
temp = readb(sport->port.membase + UARTCR2);
2882+
temp &= ~(UARTCR2_TE | UARTCR2_TIE | UARTCR2_TCIE);
2883+
writeb(temp, sport->port.membase + UARTCR2);
2884+
}
2885+
spin_unlock_irqrestore(&sport->port.lock, flags);
28392886

2840-
if (sport->lpuart_dma_rx_use) {
2841-
if (irq_wake) {
2842-
if (!lpuart_start_rx_dma(sport))
2843-
rx_dma_timer_init(sport);
2844-
else
2845-
sport->lpuart_dma_rx_use = false;
2887+
if (sport->lpuart_dma_rx_use) {
2888+
/*
2889+
* EDMA driver during suspend will forcefully release any
2890+
* non-idle DMA channels. If port wakeup is enabled or if port
2891+
* is console port or 'no_console_suspend' is set the Rx DMA
2892+
* cannot resume as expected, hence gracefully release the
2893+
* Rx DMA path before suspend and start Rx DMA path on resume.
2894+
*/
2895+
del_timer_sync(&sport->lpuart_timer);
2896+
lpuart_dma_rx_free(&sport->port);
2897+
2898+
/* Disable Rx DMA to use UART port as wakeup source */
2899+
spin_lock_irqsave(&sport->port.lock, flags);
2900+
if (lpuart_is_32(sport)) {
2901+
temp = lpuart32_read(&sport->port, UARTBAUD);
2902+
lpuart32_write(&sport->port, temp & ~UARTBAUD_RDMAE,
2903+
UARTBAUD);
2904+
} else {
2905+
writeb(readb(sport->port.membase + UARTCR5) &
2906+
~UARTCR5_RDMAS, sport->port.membase + UARTCR5);
2907+
}
2908+
spin_unlock_irqrestore(&sport->port.lock, flags);
2909+
}
2910+
2911+
if (sport->lpuart_dma_tx_use) {
2912+
spin_lock_irqsave(&sport->port.lock, flags);
2913+
if (lpuart_is_32(sport)) {
2914+
temp = lpuart32_read(&sport->port, UARTBAUD);
2915+
temp &= ~UARTBAUD_TDMAE;
2916+
lpuart32_write(&sport->port, temp, UARTBAUD);
2917+
} else {
2918+
temp = readb(sport->port.membase + UARTCR5);
2919+
temp &= ~UARTCR5_TDMAS;
2920+
writeb(temp, sport->port.membase + UARTCR5);
2921+
}
2922+
spin_unlock_irqrestore(&sport->port.lock, flags);
2923+
sport->dma_tx_in_progress = false;
2924+
dmaengine_terminate_all(sport->dma_tx_chan);
28462925
}
28472926
}
28482927

2849-
lpuart_tx_dma_startup(sport);
2928+
return 0;
2929+
}
28502930

2851-
if (lpuart_is_32(sport))
2852-
lpuart32_configure(sport);
2931+
static void lpuart_console_fixup(struct lpuart_port *sport)
2932+
{
2933+
struct tty_port *port = &sport->port.state->port;
2934+
struct uart_port *uport = &sport->port;
2935+
struct ktermios termios;
2936+
2937+
/* i.MX7ULP enter VLLS mode that lpuart module power off and registers
2938+
* all lost no matter the port is wakeup source.
2939+
* For console port, console baud rate setting lost and print messy
2940+
* log when enable the console port as wakeup source. To avoid the
2941+
* issue happen, user should not enable uart port as wakeup source
2942+
* in VLLS mode, or restore console setting here.
2943+
*/
2944+
if (is_imx7ulp_lpuart(sport) && lpuart_uport_is_active(sport) &&
2945+
console_suspend_enabled && uart_console(&sport->port)) {
2946+
2947+
mutex_lock(&port->mutex);
2948+
memset(&termios, 0, sizeof(struct ktermios));
2949+
termios.c_cflag = uport->cons->cflag;
2950+
if (port->tty && termios.c_cflag == 0)
2951+
termios = port->tty->termios;
2952+
uport->ops->set_termios(uport, &termios, NULL);
2953+
mutex_unlock(&port->mutex);
2954+
}
2955+
}
2956+
2957+
static int __maybe_unused lpuart_resume(struct device *dev)
2958+
{
2959+
struct lpuart_port *sport = dev_get_drvdata(dev);
2960+
2961+
if (lpuart_uport_is_active(sport)) {
2962+
if (lpuart_is_32(sport))
2963+
lpuart32_hw_setup(sport);
2964+
else
2965+
lpuart_hw_setup(sport);
2966+
}
28532967

2968+
lpuart_console_fixup(sport);
28542969
uart_resume_port(&lpuart_reg, &sport->port);
28552970

28562971
return 0;
28572972
}
28582973

2859-
static SIMPLE_DEV_PM_OPS(lpuart_pm_ops, lpuart_suspend, lpuart_resume);
2974+
static const struct dev_pm_ops lpuart_pm_ops = {
2975+
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(lpuart_suspend_noirq,
2976+
lpuart_resume_noirq)
2977+
SET_SYSTEM_SLEEP_PM_OPS(lpuart_suspend, lpuart_resume)
2978+
};
28602979

28612980
static struct platform_driver lpuart_driver = {
28622981
.probe = lpuart_probe,

0 commit comments

Comments
 (0)