Skip to content

Commit 09df0b3

Browse files
martin-kaisergregkh
authored andcommitted
serial: imx: fix endless loop during suspend
Before we go into suspend mode, we enable the imx uart's interrupt for the awake bit in the UART Status Register 1. If, for some reason, the awake bit is already set before we enter suspend mode, we get an interrupt immediately when we enable interrupts for awake. The uart's clk_ipg is disabled at this point (unless there's an ongoing transfer). We end up in the interrupt handler, which usually tries to clear the awake bit. This doesn't work with the clock disabled. Therefore, we keep getting interrupts forever, resulting in an endless loop. Clear the awake bit before setting the awaken bit to signal that we want an imx interrupt when the awake bit will be set. This ensures that we're not woken up by events that happened before we started going into suspend mode. Change the clock handling so that suspend prepares and enables the clock and suspend_noirq disables it. Revert these operations in resume_noirq and resume. With these preparations in place, we can now modify awake and awaken in the suspend function when the actual imx interrupt is disabled and the required clk_ipg is active. Update the thaw and freeze functions to use the new clock handling since we share the suspend_noirq function between suspend and hibernate. Signed-off-by: Martin Kaiser <martin@kaiser.cx> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 44117a1 commit 09df0b3

File tree

1 file changed

+15
-17
lines changed

1 file changed

+15
-17
lines changed

drivers/tty/serial/imx.c

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2219,8 +2219,10 @@ static void serial_imx_enable_wakeup(struct imx_port *sport, bool on)
22192219
unsigned int val;
22202220

22212221
val = readl(sport->port.membase + UCR3);
2222-
if (on)
2222+
if (on) {
2223+
writel(USR1_AWAKE, sport->port.membase + USR1);
22232224
val |= UCR3_AWAKEN;
2225+
}
22242226
else
22252227
val &= ~UCR3_AWAKEN;
22262228
writel(val, sport->port.membase + UCR3);
@@ -2239,11 +2241,6 @@ static int imx_serial_port_suspend_noirq(struct device *dev)
22392241
{
22402242
struct platform_device *pdev = to_platform_device(dev);
22412243
struct imx_port *sport = platform_get_drvdata(pdev);
2242-
int ret;
2243-
2244-
ret = clk_enable(sport->clk_ipg);
2245-
if (ret)
2246-
return ret;
22472244

22482245
serial_imx_save_context(sport);
22492246

@@ -2264,24 +2261,26 @@ static int imx_serial_port_resume_noirq(struct device *dev)
22642261

22652262
serial_imx_restore_context(sport);
22662263

2267-
clk_disable(sport->clk_ipg);
2268-
22692264
return 0;
22702265
}
22712266

22722267
static int imx_serial_port_suspend(struct device *dev)
22732268
{
22742269
struct platform_device *pdev = to_platform_device(dev);
22752270
struct imx_port *sport = platform_get_drvdata(pdev);
2276-
2277-
/* enable wakeup from i.MX UART */
2278-
serial_imx_enable_wakeup(sport, true);
2271+
int ret;
22792272

22802273
uart_suspend_port(&imx_reg, &sport->port);
22812274
disable_irq(sport->port.irq);
22822275

2283-
/* Needed to enable clock in suspend_noirq */
2284-
return clk_prepare(sport->clk_ipg);
2276+
ret = clk_prepare_enable(sport->clk_ipg);
2277+
if (ret)
2278+
return ret;
2279+
2280+
/* enable wakeup from i.MX UART */
2281+
serial_imx_enable_wakeup(sport, true);
2282+
2283+
return 0;
22852284
}
22862285

22872286
static int imx_serial_port_resume(struct device *dev)
@@ -2295,7 +2294,7 @@ static int imx_serial_port_resume(struct device *dev)
22952294
uart_resume_port(&imx_reg, &sport->port);
22962295
enable_irq(sport->port.irq);
22972296

2298-
clk_unprepare(sport->clk_ipg);
2297+
clk_disable_unprepare(sport->clk_ipg);
22992298

23002299
return 0;
23012300
}
@@ -2307,8 +2306,7 @@ static int imx_serial_port_freeze(struct device *dev)
23072306

23082307
uart_suspend_port(&imx_reg, &sport->port);
23092308

2310-
/* Needed to enable clock in suspend_noirq */
2311-
return clk_prepare(sport->clk_ipg);
2309+
return clk_prepare_enable(sport->clk_ipg);
23122310
}
23132311

23142312
static int imx_serial_port_thaw(struct device *dev)
@@ -2318,7 +2316,7 @@ static int imx_serial_port_thaw(struct device *dev)
23182316

23192317
uart_resume_port(&imx_reg, &sport->port);
23202318

2321-
clk_unprepare(sport->clk_ipg);
2319+
clk_disable_unprepare(sport->clk_ipg);
23222320

23232321
return 0;
23242322
}

0 commit comments

Comments
 (0)