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

source code of linux/arch/mips/loongson2ef/lemote-2f/pm.c