Thursday, November 10, 2011

Wake-up enable for UART

Requirement
=========
Suspend the device to RAM. It should wake up on any key press from UART.

First Method
=============
This can be done by just adding  "no_console_suspend" to bootargs.
By doing this during suspends to RAM, Uart clk src will be kept alive.

Second Method
==============
For this method, hardware should have the capability to wake-up from UART interrupt.

All devices in the device model has two flags to control the wake-up events. They are "can_wakeup" and "wakeup" flags in

struct device {
....
struct dev_pm_info power;
....
}

struct dev_pm_info {
.......
unsigned int can_wakeup:1;
struct wakeup_source *wakeup;
........
}

Flag can_wakeup is initialized by the device driver code by using device_set_wakeup_capable().
And, device_set_wakeup_enable(&dev, 1) will initiallize the struct wakeup_source and add in the list of wake-able sources.

can_wakeup is used to mark whether the hardware can support the wake-up. For most of the devices wake-up will be NULL by default. But used by drivers like power buttons, keyboards and Ethernet.

I want to configure UART as my wake-up source, this patch does it on kernel-3.0.1

diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index ab2e6e7..2bae1aa 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -2401,7 +2401,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
tty_dev = tty_register_device(drv->tty_driver, uport->line, uport->dev);
if (likely(!IS_ERR(tty_dev))) {
device_init_wakeup(tty_dev, 1);
- device_set_wakeup_enable(tty_dev, 0);
+ device_set_wakeup_enable(tty_dev, 1);
} else
printk(KERN_ERR "Cannot register tty device on line %d\n",
uport->line);

Then I tested it with echo mem > /sys/power/state

The device is able to wake-up from my UART1 interrupt which is also my console.

Now my board has many UART. I want to configure the UART2 as wake-able source, but my console is on UART1.

From the command prompt,
cat /dev/ttyS1 &

this done to initialize the UART2 port

And opened UART2 serial port on second instance of minicom. Then entering any character on second minicom wake-up my device.