Commit e1c4056f authored by Tony Lindgren's avatar Tony Lindgren

ARM: OMAP: Added support for serial wake-up events

By muxing serial RX lines into GPIO interrupts it's possible
to wake-up from deep sleep from serial port.

This is protected by Kconfig option CONFIG_OMAP_SERIAL_WAKE
until we have dev specific wake-up events that can be configured
via sysfs.
parent aafb87a4
...@@ -169,6 +169,14 @@ config OMAP_LL_DEBUG_UART3 ...@@ -169,6 +169,14 @@ config OMAP_LL_DEBUG_UART3
endchoice endchoice
config OMAP_SERIAL_WAKE
bool "Enable wake-up events for serial ports"
default y
help
Select this option if you want to have your system wake up
to data on the serial RX line. This allows you to wake the
system from serial console.
endmenu endmenu
endif endif
...@@ -24,7 +24,9 @@ ...@@ -24,7 +24,9 @@
#include <asm/arch/board.h> #include <asm/arch/board.h>
#include <asm/arch/mux.h> #include <asm/arch/mux.h>
#include <asm/arch/gpio.h>
#include <asm/arch/fpga.h> #include <asm/arch/fpga.h>
#include <asm/arch/pm.h>
static struct clk * uart1_ck = NULL; static struct clk * uart1_ck = NULL;
static struct clk * uart2_ck = NULL; static struct clk * uart2_ck = NULL;
...@@ -193,8 +195,86 @@ void __init omap_serial_init(int ports[OMAP_MAX_NR_PORTS]) ...@@ -193,8 +195,86 @@ void __init omap_serial_init(int ports[OMAP_MAX_NR_PORTS])
} }
} }
#ifdef CONFIG_OMAP_SERIAL_WAKE
static irqreturn_t omap_serial_wake_interrupt(int irq, void *dev_id,
struct pt_regs *regs)
{
/* Need to do something with serial port right after wake-up? */
return IRQ_HANDLED;
}
/*
* Reroutes serial RX lines to GPIO lines for the duration of
* sleep to allow waking up the device from serial port even
* in deep sleep.
*/
void omap_serial_wake_trigger(int enable)
{
if (!cpu_is_omap16xx())
return;
if (uart1_ck != NULL) {
if (enable)
omap_cfg_reg(V14_16XX_GPIO37);
else
omap_cfg_reg(V14_16XX_UART1_RX);
}
if (uart2_ck != NULL) {
if (enable)
omap_cfg_reg(R9_16XX_GPIO18);
else
omap_cfg_reg(R9_16XX_UART2_RX);
}
if (uart3_ck != NULL) {
if (enable)
omap_cfg_reg(L14_16XX_GPIO49);
else
omap_cfg_reg(L14_16XX_UART3_RX);
}
}
static void __init omap_serial_set_port_wakeup(int gpio_nr)
{
int ret;
ret = omap_request_gpio(gpio_nr);
if (ret < 0) {
printk(KERN_ERR "Could not request UART wake GPIO: %i\n",
gpio_nr);
return;
}
omap_set_gpio_direction(gpio_nr, 1);
set_irq_type(OMAP_GPIO_IRQ(gpio_nr), IRQT_RISING);
ret = request_irq(OMAP_GPIO_IRQ(gpio_nr), &omap_serial_wake_interrupt,
0, "serial wakeup", NULL);
if (ret) {
omap_free_gpio(gpio_nr);
printk(KERN_ERR "No interrupt for UART wake GPIO: %i\n",
gpio_nr);
return;
}
enable_irq_wake(OMAP_GPIO_IRQ(gpio_nr));
}
static void __init omap_serial_wakeup_init(void)
{
if (!cpu_is_omap16xx())
return;
if (uart1_ck != NULL)
omap_serial_set_port_wakeup(37);
if (uart2_ck != NULL)
omap_serial_set_port_wakeup(18);
if (uart3_ck != NULL)
omap_serial_set_port_wakeup(49);
}
#endif /* CONFIG_OMAP_SERIAL_WAKE */
static int __init omap_init(void) static int __init omap_init(void)
{ {
omap_serial_wakeup_init();
return platform_device_register(&serial_device); return platform_device_register(&serial_device);
} }
arch_initcall(omap_init); arch_initcall(omap_init);
...@@ -157,6 +157,8 @@ void omap_pm_suspend(void) ...@@ -157,6 +157,8 @@ void omap_pm_suspend(void)
printk("PM: OMAP%x is trying to enter deep sleep...\n", system_rev); printk("PM: OMAP%x is trying to enter deep sleep...\n", system_rev);
omap_serial_wake_trigger(1);
if (machine_is_omap_osk()) { if (machine_is_omap_osk()) {
/* Stop LED1 (D9) blink */ /* Stop LED1 (D9) blink */
tps65010_set_led(LED1, OFF); tps65010_set_led(LED1, OFF);
...@@ -312,6 +314,8 @@ void omap_pm_suspend(void) ...@@ -312,6 +314,8 @@ void omap_pm_suspend(void)
local_irq_enable(); local_irq_enable();
local_fiq_enable(); local_fiq_enable();
omap_serial_wake_trigger(0);
printk("PM: OMAP%x is re-starting from deep sleep...\n", system_rev); printk("PM: OMAP%x is re-starting from deep sleep...\n", system_rev);
if (machine_is_omap_osk()) { if (machine_is_omap_osk()) {
......
...@@ -111,6 +111,13 @@ extern void omap1610_cpu_suspend(unsigned short, unsigned short); ...@@ -111,6 +111,13 @@ extern void omap1610_cpu_suspend(unsigned short, unsigned short);
extern void omap1510_idle_loop_suspend(void); extern void omap1510_idle_loop_suspend(void);
extern void omap1610_idle_loop_suspend(void); extern void omap1610_idle_loop_suspend(void);
#ifdef CONFIG_OMAP_SERIAL_WAKE
extern void omap_serial_wake_trigger(int enable);
#else
#define omap_serial_wakeup_init() {}
#define omap_serial_wake_trigger(x) {}
#endif /* CONFIG_OMAP_SERIAL_WAKE */
extern unsigned int omap1510_cpu_suspend_sz; extern unsigned int omap1510_cpu_suspend_sz;
extern unsigned int omap1510_idle_loop_suspend_sz; extern unsigned int omap1510_idle_loop_suspend_sz;
extern unsigned int omap1610_cpu_suspend_sz; extern unsigned int omap1610_cpu_suspend_sz;
......
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