diff options
author | Wu Zhangjin <wuzhangjin@gmail.com> | 2009-11-21 12:05:24 +0100 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2009-12-17 02:57:28 +0100 |
commit | cb1ed9e117098269de3c0dfff816dff453dd4b59 (patch) | |
tree | 918d2eec2f59ca418e395d44b95881951a4dddab /arch/mips/loongson | |
parent | MIPS: Yeeloong 2F: Add basic EC operations (diff) | |
download | linux-cb1ed9e117098269de3c0dfff816dff453dd4b59.tar.xz linux-cb1ed9e117098269de3c0dfff816dff453dd4b59.zip |
MIPS: Yeeloong 2F: Add LID open event as the wakeup event
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>
Diffstat (limited to 'arch/mips/loongson')
-rw-r--r-- | arch/mips/loongson/lemote-2f/irq.c | 4 | ||||
-rw-r--r-- | arch/mips/loongson/lemote-2f/pm.c | 71 |
2 files changed, 71 insertions, 4 deletions
diff --git a/arch/mips/loongson/lemote-2f/irq.c b/arch/mips/loongson/lemote-2f/irq.c index 50e7bb6012b7..77d32f9cf31e 100644 --- a/arch/mips/loongson/lemote-2f/irq.c +++ b/arch/mips/loongson/lemote-2f/irq.c @@ -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) { diff --git a/arch/mips/loongson/lemote-2f/pm.c b/arch/mips/loongson/lemote-2f/pm.c index 8090d0514221..81c06410aa76 100644 --- a/arch/mips/loongson/lemote-2f/pm.c +++ b/arch/mips/loongson/lemote-2f/pm.c @@ -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; +} |