xref: /OK3568_Linux_fs/kernel/arch/mips/loongson2ef/lemote-2f/pm.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *  Lemote loongson2f family machines' specific suspend support
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *  Copyright (C) 2009 Lemote Inc.
6*4882a593Smuzhiyun  *  Author: Wu Zhangjin <wuzhangjin@gmail.com>
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/suspend.h>
10*4882a593Smuzhiyun #include <linux/interrupt.h>
11*4882a593Smuzhiyun #include <linux/pm.h>
12*4882a593Smuzhiyun #include <linux/i8042.h>
13*4882a593Smuzhiyun #include <linux/export.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include <asm/i8259.h>
16*4882a593Smuzhiyun #include <asm/mipsregs.h>
17*4882a593Smuzhiyun #include <asm/bootinfo.h>
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #include <loongson.h>
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun #include <cs5536/cs5536_mfgpt.h>
22*4882a593Smuzhiyun #include "ec_kb3310b.h"
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #define I8042_KBD_IRQ		1
25*4882a593Smuzhiyun #define I8042_CTR_KBDINT	0x01
26*4882a593Smuzhiyun #define I8042_CTR_KBDDIS	0x10
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun static unsigned char i8042_ctr;
29*4882a593Smuzhiyun 
i8042_enable_kbd_port(void)30*4882a593Smuzhiyun static int i8042_enable_kbd_port(void)
31*4882a593Smuzhiyun {
32*4882a593Smuzhiyun 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_RCTR)) {
33*4882a593Smuzhiyun 		pr_err("i8042.c: Can't read CTR while enabling i8042 kbd port."
34*4882a593Smuzhiyun 		       "\n");
35*4882a593Smuzhiyun 		return -EIO;
36*4882a593Smuzhiyun 	}
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun 	i8042_ctr &= ~I8042_CTR_KBDDIS;
39*4882a593Smuzhiyun 	i8042_ctr |= I8042_CTR_KBDINT;
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
42*4882a593Smuzhiyun 		i8042_ctr &= ~I8042_CTR_KBDINT;
43*4882a593Smuzhiyun 		i8042_ctr |= I8042_CTR_KBDDIS;
44*4882a593Smuzhiyun 		pr_err("i8042.c: Failed to enable KBD port.\n");
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 		return -EIO;
47*4882a593Smuzhiyun 	}
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	return 0;
50*4882a593Smuzhiyun }
51*4882a593Smuzhiyun 
setup_wakeup_events(void)52*4882a593Smuzhiyun void setup_wakeup_events(void)
53*4882a593Smuzhiyun {
54*4882a593Smuzhiyun 	int irq_mask;
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun 	switch (mips_machtype) {
57*4882a593Smuzhiyun 	case MACH_LEMOTE_ML2F7:
58*4882a593Smuzhiyun 	case MACH_LEMOTE_YL2F89:
59*4882a593Smuzhiyun 		/* open the keyboard irq in i8259A */
60*4882a593Smuzhiyun 		outb((0xff & ~(1 << I8042_KBD_IRQ)), PIC_MASTER_IMR);
61*4882a593Smuzhiyun 		irq_mask = inb(PIC_MASTER_IMR);
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 		/* enable keyboard port */
64*4882a593Smuzhiyun 		i8042_enable_kbd_port();
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 		/* Wakeup CPU via SCI lid open event */
67*4882a593Smuzhiyun 		outb(irq_mask & ~(1 << PIC_CASCADE_IR), PIC_MASTER_IMR);
68*4882a593Smuzhiyun 		inb(PIC_MASTER_IMR);
69*4882a593Smuzhiyun 		outb(0xff & ~(1 << (SCI_IRQ_NUM - 8)), PIC_SLAVE_IMR);
70*4882a593Smuzhiyun 		inb(PIC_SLAVE_IMR);
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 		break;
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	default:
75*4882a593Smuzhiyun 		break;
76*4882a593Smuzhiyun 	}
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun static struct delayed_work lid_task;
80*4882a593Smuzhiyun static int initialized;
81*4882a593Smuzhiyun /* yeeloong_report_lid_status will be implemented in yeeloong_laptop.c */
82*4882a593Smuzhiyun sci_handler yeeloong_report_lid_status;
83*4882a593Smuzhiyun EXPORT_SYMBOL(yeeloong_report_lid_status);
yeeloong_lid_update_task(struct work_struct * work)84*4882a593Smuzhiyun static void yeeloong_lid_update_task(struct work_struct *work)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun 	if (yeeloong_report_lid_status)
87*4882a593Smuzhiyun 		yeeloong_report_lid_status(BIT_LID_DETECT_ON);
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun 
wakeup_loongson(void)90*4882a593Smuzhiyun int wakeup_loongson(void)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun 	int irq;
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	/* query the interrupt number */
95*4882a593Smuzhiyun 	irq = mach_i8259_irq();
96*4882a593Smuzhiyun 	if (irq < 0)
97*4882a593Smuzhiyun 		return 0;
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	printk(KERN_INFO "%s: irq = %d\n", __func__, irq);
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	if (irq == I8042_KBD_IRQ)
102*4882a593Smuzhiyun 		return 1;
103*4882a593Smuzhiyun 	else if (irq == SCI_IRQ_NUM) {
104*4882a593Smuzhiyun 		int ret, sci_event;
105*4882a593Smuzhiyun 		/* query the event number */
106*4882a593Smuzhiyun 		ret = ec_query_seq(CMD_GET_EVENT_NUM);
107*4882a593Smuzhiyun 		if (ret < 0)
108*4882a593Smuzhiyun 			return 0;
109*4882a593Smuzhiyun 		sci_event = ec_get_event_num();
110*4882a593Smuzhiyun 		if (sci_event < 0)
111*4882a593Smuzhiyun 			return 0;
112*4882a593Smuzhiyun 		if (sci_event == EVENT_LID) {
113*4882a593Smuzhiyun 			int lid_status;
114*4882a593Smuzhiyun 			/* check the LID status */
115*4882a593Smuzhiyun 			lid_status = ec_read(REG_LID_DETECT);
116*4882a593Smuzhiyun 			/* wakeup cpu when people open the LID */
117*4882a593Smuzhiyun 			if (lid_status == BIT_LID_DETECT_ON) {
118*4882a593Smuzhiyun 				/* If we call it directly here, the WARNING
119*4882a593Smuzhiyun 				 * will be sent out by getnstimeofday
120*4882a593Smuzhiyun 				 * via "WARN_ON(timekeeping_suspended);"
121*4882a593Smuzhiyun 				 * because we can not schedule in suspend mode.
122*4882a593Smuzhiyun 				 */
123*4882a593Smuzhiyun 				if (initialized == 0) {
124*4882a593Smuzhiyun 					INIT_DELAYED_WORK(&lid_task,
125*4882a593Smuzhiyun 						yeeloong_lid_update_task);
126*4882a593Smuzhiyun 					initialized = 1;
127*4882a593Smuzhiyun 				}
128*4882a593Smuzhiyun 				schedule_delayed_work(&lid_task, 1);
129*4882a593Smuzhiyun 				return 1;
130*4882a593Smuzhiyun 			}
131*4882a593Smuzhiyun 		}
132*4882a593Smuzhiyun 	}
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	return 0;
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun 
mach_suspend(void)137*4882a593Smuzhiyun void __weak mach_suspend(void)
138*4882a593Smuzhiyun {
139*4882a593Smuzhiyun 	disable_mfgpt0_counter();
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun 
mach_resume(void)142*4882a593Smuzhiyun void __weak mach_resume(void)
143*4882a593Smuzhiyun {
144*4882a593Smuzhiyun 	enable_mfgpt0_counter();
145*4882a593Smuzhiyun }
146