MIPS: Yeeloong 2F: Add LID open event as the wakeup event
authorWu Zhangjin <wuzhangjin@gmail.com>
Sat, 21 Nov 2009 11:05:24 +0000 (19:05 +0800)
committerRalf Baechle <ralf@linux-mips.org>
Thu, 17 Dec 2009 01:57:28 +0000 (01:57 +0000)
Yeeloong 2F netbook has an KB3310B embedded controller to manage the LID
action.  When the LID is closed or opened a SCI interrupt is sent out and
the corresponding event is saved to an EC register for later query.

Allow the LID open interrupt to wake the processor from wait mode if it is
in the suspend mode.

Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
Cc: linux-mips@linux-mips.org
Patchwork: http://patchwork.linux-mips.org/patch/685/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/include/asm/mach-loongson/loongson.h
arch/mips/loongson/lemote-2f/irq.c
arch/mips/loongson/lemote-2f/pm.c

index a7fa66e..06c28f3 100644 (file)
@@ -41,6 +41,7 @@ extern void __init bonito_irq_init(void);
 extern void __init set_irq_trigger_mode(void);
 extern void __init mach_init_irq(void);
 extern void mach_irq_dispatch(unsigned int pending);
+extern int mach_i8259_irq(void);
 
 /* We need this in some places... */
 #define delay()        ({              \
index 50e7bb6..77d32f9 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/interrupt.h>
+#include <linux/module.h>
 
 #include <asm/irq_cpu.h>
 #include <asm/i8259.h>
@@ -30,7 +31,7 @@
  * The generic i8259_irq() make the kernel hang on booting.  Since we cannot
  * get the irq via the IRR directly, we access the ISR instead.
  */
-static inline int mach_i8259_irq(void)
+int mach_i8259_irq(void)
 {
        int irq, isr;
 
@@ -60,6 +61,7 @@ static inline int mach_i8259_irq(void)
 
        return irq;
 }
+EXPORT_SYMBOL(mach_i8259_irq);
 
 static void i8259_irqdispatch(void)
 {
index 8090d05..81c0641 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/interrupt.h>
 #include <linux/pm.h>
 #include <linux/i8042.h>
+#include <linux/module.h>
 
 #include <asm/i8259.h>
 #include <asm/mipsregs.h>
@@ -21,6 +22,8 @@
 
 #include <loongson.h>
 
+#include "ec_kb3310b.h"
+
 #define I8042_KBD_IRQ          1
 #define I8042_CTR_KBDINT       0x01
 #define I8042_CTR_KBDDIS       0x10
@@ -49,9 +52,6 @@ static int i8042_enable_kbd_port(void)
        return 0;
 }
 
-/*
- * The i8042 is connnected to i8259A
- */
 void setup_wakeup_events(void)
 {
        int irq_mask;
@@ -65,9 +65,74 @@ void setup_wakeup_events(void)
 
                /* enable keyboard port */
                i8042_enable_kbd_port();
+
+               /* Wakeup CPU via SCI lid open event */
+               outb(irq_mask & ~(1 << PIC_CASCADE_IR), PIC_MASTER_IMR);
+               inb(PIC_MASTER_IMR);
+               outb(0xff & ~(1 << (SCI_IRQ_NUM - 8)), PIC_SLAVE_IMR);
+               inb(PIC_SLAVE_IMR);
+
                break;
 
        default:
                break;
        }
 }
+
+static struct delayed_work lid_task;
+static int initialized;
+/* yeeloong_report_lid_status will be implemented in yeeloong_laptop.c */
+sci_handler yeeloong_report_lid_status;
+EXPORT_SYMBOL(yeeloong_report_lid_status);
+static void yeeloong_lid_update_task(struct work_struct *work)
+{
+       if (yeeloong_report_lid_status)
+               yeeloong_report_lid_status(BIT_LID_DETECT_ON);
+}
+
+int wakeup_loongson(void)
+{
+       int irq;
+
+       /* query the interrupt number */
+       irq = mach_i8259_irq();
+       if (irq < 0)
+               return 0;
+
+       printk(KERN_INFO "%s: irq = %d\n", __func__, irq);
+
+       if (irq == I8042_KBD_IRQ)
+               return 1;
+       else if (irq == SCI_IRQ_NUM) {
+               int ret, sci_event;
+               /* query the event number */
+               ret = ec_query_seq(CMD_GET_EVENT_NUM);
+               if (ret < 0)
+                       return 0;
+               sci_event = ec_get_event_num();
+               if (sci_event < 0)
+                       return 0;
+               if (sci_event == EVENT_LID) {
+                       int lid_status;
+                       /* check the LID status */
+                       lid_status = ec_read(REG_LID_DETECT);
+                       /* wakeup cpu when people open the LID */
+                       if (lid_status == BIT_LID_DETECT_ON) {
+                               /* If we call it directly here, the WARNING
+                                * will be sent out by getnstimeofday
+                                * via "WARN_ON(timekeeping_suspended);"
+                                * because we can not schedule in suspend mode.
+                                */
+                               if (initialized == 0) {
+                                       INIT_DELAYED_WORK(&lid_task,
+                                               yeeloong_lid_update_task);
+                                       initialized = 1;
+                               }
+                               schedule_delayed_work(&lid_task, 1);
+                               return 1;
+                       }
+               }
+       }
+
+       return 0;
+}