]> pilppa.com Git - linux-2.6-omap-h63xx.git/commitdiff
ARM: OMAP: Added support for serial wake-up events
authorTony Lindgren <tony@atomide.com>
Fri, 10 Jun 2005 00:02:50 +0000 (17:02 -0700)
committerTony Lindgren <tony@atomide.com>
Fri, 10 Jun 2005 00:02:50 +0000 (17:02 -0700)
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
arch/arm/mach-omap/omap1/serial.c
arch/arm/mach-omap/pm.c
include/asm-arm/arch-omap/pm.h

index c5e7776b660f1ec8160d7fb03592d15d47713fca..6d3de71f664f60bd418469b8c45d971eef17563e 100644 (file)
@@ -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
index b5b9844552fc54b130834ec9698180fdb5977b34..73f5d2a5772a426cab86eefe07b908532d79662c 100644 (file)
@@ -24,7 +24,9 @@
 
 #include <asm/arch/board.h>
 #include <asm/arch/mux.h>
+#include <asm/arch/gpio.h>
 #include <asm/arch/fpga.h>
+#include <asm/arch/pm.h>
 
 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);
index 6f9b28d693e76f93c58eb32325848f4eb6ec44fb..8c5e4626462162f8657d9c539845d33011739207 100644 (file)
@@ -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()) {
index e728cc7a7eb081f51e827957f5ecedf051710636..b2cfdaf9a597e059a54c12c55fd91e232889adf9 100644 (file)
@@ -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;