Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pm.c
Go to the documentation of this file.
1 /*
2  * Lemote loongson2f family machines' specific suspend support
3  *
4  * Copyright (C) 2009 Lemote Inc.
5  * Author: Wu Zhangjin <[email protected]>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  */
12 
13 #include <linux/suspend.h>
14 #include <linux/interrupt.h>
15 #include <linux/pm.h>
16 #include <linux/i8042.h>
17 #include <linux/module.h>
18 
19 #include <asm/i8259.h>
20 #include <asm/mipsregs.h>
21 #include <asm/bootinfo.h>
22 
23 #include <loongson.h>
24 
25 #include <cs5536/cs5536_mfgpt.h>
26 #include "ec_kb3310b.h"
27 
28 #define I8042_KBD_IRQ 1
29 #define I8042_CTR_KBDINT 0x01
30 #define I8042_CTR_KBDDIS 0x10
31 
32 static unsigned char i8042_ctr;
33 
34 static int i8042_enable_kbd_port(void)
35 {
36  if (i8042_command(&i8042_ctr, I8042_CMD_CTL_RCTR)) {
37  pr_err("i8042.c: Can't read CTR while enabling i8042 kbd port."
38  "\n");
39  return -EIO;
40  }
41 
42  i8042_ctr &= ~I8042_CTR_KBDDIS;
43  i8042_ctr |= I8042_CTR_KBDINT;
44 
45  if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
46  i8042_ctr &= ~I8042_CTR_KBDINT;
47  i8042_ctr |= I8042_CTR_KBDDIS;
48  pr_err("i8042.c: Failed to enable KBD port.\n");
49 
50  return -EIO;
51  }
52 
53  return 0;
54 }
55 
57 {
58  int irq_mask;
59 
60  switch (mips_machtype) {
61  case MACH_LEMOTE_ML2F7:
62  case MACH_LEMOTE_YL2F89:
63  /* open the keyboard irq in i8259A */
64  outb((0xff & ~(1 << I8042_KBD_IRQ)), PIC_MASTER_IMR);
65  irq_mask = inb(PIC_MASTER_IMR);
66 
67  /* enable keyboard port */
68  i8042_enable_kbd_port();
69 
70  /* Wakeup CPU via SCI lid open event */
71  outb(irq_mask & ~(1 << PIC_CASCADE_IR), PIC_MASTER_IMR);
73  outb(0xff & ~(1 << (SCI_IRQ_NUM - 8)), PIC_SLAVE_IMR);
75 
76  break;
77 
78  default:
79  break;
80  }
81 }
82 
83 static struct delayed_work lid_task;
84 static int initialized;
85 /* yeeloong_report_lid_status will be implemented in yeeloong_laptop.c */
88 static void yeeloong_lid_update_task(struct work_struct *work)
89 {
92 }
93 
94 int wakeup_loongson(void)
95 {
96  int irq;
97 
98  /* query the interrupt number */
99  irq = mach_i8259_irq();
100  if (irq < 0)
101  return 0;
102 
103  printk(KERN_INFO "%s: irq = %d\n", __func__, irq);
104 
105  if (irq == I8042_KBD_IRQ)
106  return 1;
107  else if (irq == SCI_IRQ_NUM) {
108  int ret, sci_event;
109  /* query the event number */
111  if (ret < 0)
112  return 0;
113  sci_event = ec_get_event_num();
114  if (sci_event < 0)
115  return 0;
116  if (sci_event == EVENT_LID) {
117  int lid_status;
118  /* check the LID status */
119  lid_status = ec_read(REG_LID_DETECT);
120  /* wakeup cpu when people open the LID */
121  if (lid_status == BIT_LID_DETECT_ON) {
122  /* If we call it directly here, the WARNING
123  * will be sent out by getnstimeofday
124  * via "WARN_ON(timekeeping_suspended);"
125  * because we can not schedule in suspend mode.
126  */
127  if (initialized == 0) {
128  INIT_DELAYED_WORK(&lid_task,
129  yeeloong_lid_update_task);
130  initialized = 1;
131  }
132  schedule_delayed_work(&lid_task, 1);
133  return 1;
134  }
135  }
136  }
137 
138  return 0;
139 }
140 
142 {
144 }
145 
146 void __weak mach_resume(void)
147 {
149 }