Commit cb1ed9e1 authored by Wu Zhangjin's avatar Wu Zhangjin Committed by Ralf Baechle

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: default avatarWu Zhangjin <wuzhangjin@gmail.com>
Cc: linux-mips@linux-mips.org
Patchwork: http://patchwork.linux-mips.org/patch/685/Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent ec614d80
...@@ -41,6 +41,7 @@ extern void __init bonito_irq_init(void); ...@@ -41,6 +41,7 @@ extern void __init bonito_irq_init(void);
extern void __init set_irq_trigger_mode(void); extern void __init set_irq_trigger_mode(void);
extern void __init mach_init_irq(void); extern void __init mach_init_irq(void);
extern void mach_irq_dispatch(unsigned int pending); extern void mach_irq_dispatch(unsigned int pending);
extern int mach_i8259_irq(void);
/* We need this in some places... */ /* We need this in some places... */
#define delay() ({ \ #define delay() ({ \
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
*/ */
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/module.h>
#include <asm/irq_cpu.h> #include <asm/irq_cpu.h>
#include <asm/i8259.h> #include <asm/i8259.h>
...@@ -30,7 +31,7 @@ ...@@ -30,7 +31,7 @@
* The generic i8259_irq() make the kernel hang on booting. Since we cannot * 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. * 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; int irq, isr;
...@@ -60,6 +61,7 @@ static inline int mach_i8259_irq(void) ...@@ -60,6 +61,7 @@ static inline int mach_i8259_irq(void)
return irq; return irq;
} }
EXPORT_SYMBOL(mach_i8259_irq);
static void i8259_irqdispatch(void) static void i8259_irqdispatch(void)
{ {
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/i8042.h> #include <linux/i8042.h>
#include <linux/module.h>
#include <asm/i8259.h> #include <asm/i8259.h>
#include <asm/mipsregs.h> #include <asm/mipsregs.h>
...@@ -21,6 +22,8 @@ ...@@ -21,6 +22,8 @@
#include <loongson.h> #include <loongson.h>
#include "ec_kb3310b.h"
#define I8042_KBD_IRQ 1 #define I8042_KBD_IRQ 1
#define I8042_CTR_KBDINT 0x01 #define I8042_CTR_KBDINT 0x01
#define I8042_CTR_KBDDIS 0x10 #define I8042_CTR_KBDDIS 0x10
...@@ -49,9 +52,6 @@ static int i8042_enable_kbd_port(void) ...@@ -49,9 +52,6 @@ static int i8042_enable_kbd_port(void)
return 0; return 0;
} }
/*
* The i8042 is connnected to i8259A
*/
void setup_wakeup_events(void) void setup_wakeup_events(void)
{ {
int irq_mask; int irq_mask;
...@@ -65,9 +65,74 @@ void setup_wakeup_events(void) ...@@ -65,9 +65,74 @@ void setup_wakeup_events(void)
/* enable keyboard port */ /* enable keyboard port */
i8042_enable_kbd_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; break;
default: default:
break; 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;
}
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