Skip to content

Commit

Permalink
atmel_serial: update the powersave handler to match serial core
Browse files Browse the repository at this point in the history
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: Anti Sullin <anti.sullin@artecdesign.ee>
Signed-off-by: Haavard Skinnemoen <haavard.skinnemoen@atmel.com>
Cc: Michael Trimarchi <trimarchimichael@yahoo.it>
Cc: Andrew Victor <linux@maxim.org.za>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Anti Sullin authored and Linus Torvalds committed Sep 23, 2008
1 parent a10cebf commit f05596d
Showing 1 changed file with 19 additions and 13 deletions.
32 changes: 19 additions & 13 deletions drivers/serial/atmel_serial.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,8 @@ struct atmel_uart_char {
struct atmel_uart_port {
struct uart_port uart; /* uart */
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 */

short use_dma_rx; /* enable PDC receiver */
Expand Down Expand Up @@ -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.
*/
clk_enable(atmel_port->clk);

/* re-enable interrupts if we disabled some on suspend */
UART_PUT_IER(port, atmel_port->backup_imr);
break;
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.
* This is called on uart_close() or a suspend event.
Expand Down Expand Up @@ -1475,13 +1483,12 @@ static int atmel_serial_suspend(struct platform_device *pdev,
cpu_relax();
}

if (device_may_wakeup(&pdev->dev)
&& !atmel_serial_clk_will_stop())
enable_irq_wake(port->irq);
else {
uart_suspend_port(&atmel_uart, port);
atmel_port->suspended = 1;
}
/* we can not wake up if we're running on slow clock */
atmel_port->may_wakeup = device_may_wakeup(&pdev->dev);
if (atmel_serial_clk_will_stop())
device_set_wakeup_enable(&pdev->dev, 0);

uart_suspend_port(&atmel_uart, port);

return 0;
}
Expand All @@ -1491,11 +1498,8 @@ static int atmel_serial_resume(struct platform_device *pdev)
struct uart_port *port = platform_get_drvdata(pdev);
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);

if (atmel_port->suspended) {
uart_resume_port(&atmel_uart, port);
atmel_port->suspended = 0;
} else
disable_irq_wake(port->irq);
uart_resume_port(&atmel_uart, port);
device_set_wakeup_enable(&pdev->dev, atmel_port->may_wakeup);

return 0;
}
Expand All @@ -1513,6 +1517,8 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev)
BUILD_BUG_ON(!is_power_of_2(ATMEL_SERIAL_RINGSIZE));

port = &atmel_ports[pdev->id];
port->backup_imr = 0;

atmel_init_port(port, pdev);

if (!atmel_use_dma_rx(&port->uart)) {
Expand Down

0 comments on commit f05596d

Please sign in to comment.