Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/mips/loongson/lemote-2f/pm.c
10818 views
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
56
void setup_wakeup_events(void)
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);
72
inb(PIC_MASTER_IMR);
73
outb(0xff & ~(1 << (SCI_IRQ_NUM - 8)), PIC_SLAVE_IMR);
74
inb(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 */
86
sci_handler yeeloong_report_lid_status;
87
EXPORT_SYMBOL(yeeloong_report_lid_status);
88
static void yeeloong_lid_update_task(struct work_struct *work)
89
{
90
if (yeeloong_report_lid_status)
91
yeeloong_report_lid_status(BIT_LID_DETECT_ON);
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 */
110
ret = ec_query_seq(CMD_GET_EVENT_NUM);
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
141
void __weak mach_suspend(void)
142
{
143
disable_mfgpt0_counter();
144
}
145
146
void __weak mach_resume(void)
147
{
148
enable_mfgpt0_counter();
149
}
150
151