From e1c4056ffd01d2feef369097667d7072bb6c5957 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 9 Jun 2005 17:02:50 -0700 Subject: [PATCH] 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. --- arch/arm/mach-omap/Kconfig | 8 ++++ arch/arm/mach-omap/omap1/serial.c | 80 +++++++++++++++++++++++++++++++ arch/arm/mach-omap/pm.c | 4 ++ include/asm-arm/arch-omap/pm.h | 7 +++ 4 files changed, 99 insertions(+) diff --git a/arch/arm/mach-omap/Kconfig b/arch/arm/mach-omap/Kconfig index c5e7776b660..6d3de71f664 100644 --- a/arch/arm/mach-omap/Kconfig +++ b/arch/arm/mach-omap/Kconfig @@ -169,6 +169,14 @@ config OMAP_LL_DEBUG_UART3 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 endif diff --git a/arch/arm/mach-omap/omap1/serial.c b/arch/arm/mach-omap/omap1/serial.c index b5b9844552f..73f5d2a5772 100644 --- a/arch/arm/mach-omap/omap1/serial.c +++ b/arch/arm/mach-omap/omap1/serial.c @@ -24,7 +24,9 @@ #include #include +#include #include +#include static struct clk * uart1_ck = NULL; static struct clk * uart2_ck = NULL; @@ -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) { + omap_serial_wakeup_init(); return platform_device_register(&serial_device); } arch_initcall(omap_init); diff --git a/arch/arm/mach-omap/pm.c b/arch/arm/mach-omap/pm.c index 6f9b28d693e..8c5e4626462 100644 --- a/arch/arm/mach-omap/pm.c +++ b/arch/arm/mach-omap/pm.c @@ -157,6 +157,8 @@ void omap_pm_suspend(void) printk("PM: OMAP%x is trying to enter deep sleep...\n", system_rev); + omap_serial_wake_trigger(1); + if (machine_is_omap_osk()) { /* Stop LED1 (D9) blink */ tps65010_set_led(LED1, OFF); @@ -312,6 +314,8 @@ void omap_pm_suspend(void) local_irq_enable(); local_fiq_enable(); + omap_serial_wake_trigger(0); + printk("PM: OMAP%x is re-starting from deep sleep...\n", system_rev); if (machine_is_omap_osk()) { diff --git a/include/asm-arm/arch-omap/pm.h b/include/asm-arm/arch-omap/pm.h index e728cc7a7eb..b2cfdaf9a59 100644 --- a/include/asm-arm/arch-omap/pm.h +++ b/include/asm-arm/arch-omap/pm.h @@ -111,6 +111,13 @@ extern void omap1610_cpu_suspend(unsigned short, unsigned short); extern void omap1510_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_idle_loop_suspend_sz; extern unsigned int omap1610_cpu_suspend_sz; -- 2.41.1