Commit f05596db authored by Anti Sullin's avatar Anti Sullin Committed by Linus Torvalds

atmel_serial: update the powersave handler to match serial core

This problem seems to be unnoticed so far:

http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=b3b708fa2780cd2b5d8266a8f0c3a1cab364d4d2

has changed the serial core behavior to not to suspend the port if the
device is enabled as a wakeup source.  If the AT91 system goes to slow
clock mode, the port should be suspended always and the clocks should be
switched off.  The patch attached updates the atmel_serial driver to match
the changes in serial core.

Also, the interrupts are disabled when the clock is disabled.  If we
disable the clock with interrupts enabled, an interrupt may get stuck.  If
this is the DBGU interrupt, this blocks the OR logic at system controller
and thus all other sysc interrupts.
Signed-off-by: default avatarAnti Sullin <anti.sullin@artecdesign.ee>
Signed-off-by: default avatarHaavard Skinnemoen <haavard.skinnemoen@atmel.com>
Cc: Michael Trimarchi <trimarchimichael@yahoo.it>
Cc: Andrew Victor <linux@maxim.org.za>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent a10cebf5
...@@ -131,7 +131,8 @@ struct atmel_uart_char { ...@@ -131,7 +131,8 @@ struct atmel_uart_char {
struct atmel_uart_port { struct atmel_uart_port {
struct uart_port uart; /* uart */ struct uart_port uart; /* uart */
struct clk *clk; /* uart clock */ struct clk *clk; /* uart clock */
unsigned short suspended; /* is port suspended? */ int may_wakeup; /* cached value of device_may_wakeup for times we need to disable it */
u32 backup_imr; /* IMR saved during suspend */
int break_active; /* break being received */ int break_active; /* break being received */
short use_dma_rx; /* enable PDC receiver */ short use_dma_rx; /* enable PDC receiver */
...@@ -984,8 +985,15 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state, ...@@ -984,8 +985,15 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state,
* This is called on uart_open() or a resume event. * This is called on uart_open() or a resume event.
*/ */
clk_enable(atmel_port->clk); clk_enable(atmel_port->clk);
/* re-enable interrupts if we disabled some on suspend */
UART_PUT_IER(port, atmel_port->backup_imr);
break; break;
case 3: case 3:
/* Back up the interrupt mask and disable all interrupts */
atmel_port->backup_imr = UART_GET_IMR(port);
UART_PUT_IDR(port, -1);
/* /*
* Disable the peripheral clock for this serial port. * Disable the peripheral clock for this serial port.
* This is called on uart_close() or a suspend event. * This is called on uart_close() or a suspend event.
...@@ -1475,13 +1483,12 @@ static int atmel_serial_suspend(struct platform_device *pdev, ...@@ -1475,13 +1483,12 @@ static int atmel_serial_suspend(struct platform_device *pdev,
cpu_relax(); cpu_relax();
} }
if (device_may_wakeup(&pdev->dev) /* we can not wake up if we're running on slow clock */
&& !atmel_serial_clk_will_stop()) atmel_port->may_wakeup = device_may_wakeup(&pdev->dev);
enable_irq_wake(port->irq); if (atmel_serial_clk_will_stop())
else { device_set_wakeup_enable(&pdev->dev, 0);
uart_suspend_port(&atmel_uart, port); uart_suspend_port(&atmel_uart, port);
atmel_port->suspended = 1;
}
return 0; return 0;
} }
...@@ -1491,11 +1498,8 @@ static int atmel_serial_resume(struct platform_device *pdev) ...@@ -1491,11 +1498,8 @@ static int atmel_serial_resume(struct platform_device *pdev)
struct uart_port *port = platform_get_drvdata(pdev); struct uart_port *port = platform_get_drvdata(pdev);
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
if (atmel_port->suspended) {
uart_resume_port(&atmel_uart, port); uart_resume_port(&atmel_uart, port);
atmel_port->suspended = 0; device_set_wakeup_enable(&pdev->dev, atmel_port->may_wakeup);
} else
disable_irq_wake(port->irq);
return 0; return 0;
} }
...@@ -1513,6 +1517,8 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev) ...@@ -1513,6 +1517,8 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev)
BUILD_BUG_ON(!is_power_of_2(ATMEL_SERIAL_RINGSIZE)); BUILD_BUG_ON(!is_power_of_2(ATMEL_SERIAL_RINGSIZE));
port = &atmel_ports[pdev->id]; port = &atmel_ports[pdev->id];
port->backup_imr = 0;
atmel_init_port(port, pdev); atmel_init_port(port, pdev);
if (!atmel_use_dma_rx(&port->uart)) { if (!atmel_use_dma_rx(&port->uart)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment