Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Lemote loongson2f family machines' specific suspend support
0004  *
0005  *  Copyright (C) 2009 Lemote Inc.
0006  *  Author: Wu Zhangjin <wuzhangjin@gmail.com>
0007  */
0008 
0009 #include <linux/suspend.h>
0010 #include <linux/interrupt.h>
0011 #include <linux/pm.h>
0012 #include <linux/i8042.h>
0013 #include <linux/export.h>
0014 
0015 #include <asm/i8259.h>
0016 #include <asm/mipsregs.h>
0017 #include <asm/bootinfo.h>
0018 
0019 #include <loongson.h>
0020 
0021 #include <cs5536/cs5536_mfgpt.h>
0022 #include "ec_kb3310b.h"
0023 
0024 #define I8042_KBD_IRQ       1
0025 #define I8042_CTR_KBDINT    0x01
0026 #define I8042_CTR_KBDDIS    0x10
0027 
0028 static unsigned char i8042_ctr;
0029 
0030 static int i8042_enable_kbd_port(void)
0031 {
0032     if (i8042_command(&i8042_ctr, I8042_CMD_CTL_RCTR)) {
0033         pr_err("i8042.c: Can't read CTR while enabling i8042 kbd port."
0034                "\n");
0035         return -EIO;
0036     }
0037 
0038     i8042_ctr &= ~I8042_CTR_KBDDIS;
0039     i8042_ctr |= I8042_CTR_KBDINT;
0040 
0041     if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
0042         i8042_ctr &= ~I8042_CTR_KBDINT;
0043         i8042_ctr |= I8042_CTR_KBDDIS;
0044         pr_err("i8042.c: Failed to enable KBD port.\n");
0045 
0046         return -EIO;
0047     }
0048 
0049     return 0;
0050 }
0051 
0052 void setup_wakeup_events(void)
0053 {
0054     int irq_mask;
0055 
0056     switch (mips_machtype) {
0057     case MACH_LEMOTE_ML2F7:
0058     case MACH_LEMOTE_YL2F89:
0059         /* open the keyboard irq in i8259A */
0060         outb((0xff & ~(1 << I8042_KBD_IRQ)), PIC_MASTER_IMR);
0061         irq_mask = inb(PIC_MASTER_IMR);
0062 
0063         /* enable keyboard port */
0064         i8042_enable_kbd_port();
0065 
0066         /* Wakeup CPU via SCI lid open event */
0067         outb(irq_mask & ~(1 << PIC_CASCADE_IR), PIC_MASTER_IMR);
0068         inb(PIC_MASTER_IMR);
0069         outb(0xff & ~(1 << (SCI_IRQ_NUM - 8)), PIC_SLAVE_IMR);
0070         inb(PIC_SLAVE_IMR);
0071 
0072         break;
0073 
0074     default:
0075         break;
0076     }
0077 }
0078 
0079 static struct delayed_work lid_task;
0080 static int initialized;
0081 /* yeeloong_report_lid_status will be implemented in yeeloong_laptop.c */
0082 sci_handler yeeloong_report_lid_status;
0083 EXPORT_SYMBOL(yeeloong_report_lid_status);
0084 static void yeeloong_lid_update_task(struct work_struct *work)
0085 {
0086     if (yeeloong_report_lid_status)
0087         yeeloong_report_lid_status(BIT_LID_DETECT_ON);
0088 }
0089 
0090 int wakeup_loongson(void)
0091 {
0092     int irq;
0093 
0094     /* query the interrupt number */
0095     irq = mach_i8259_irq();
0096     if (irq < 0)
0097         return 0;
0098 
0099     printk(KERN_INFO "%s: irq = %d\n", __func__, irq);
0100 
0101     if (irq == I8042_KBD_IRQ)
0102         return 1;
0103     else if (irq == SCI_IRQ_NUM) {
0104         int ret, sci_event;
0105         /* query the event number */
0106         ret = ec_query_seq(CMD_GET_EVENT_NUM);
0107         if (ret < 0)
0108             return 0;
0109         sci_event = ec_get_event_num();
0110         if (sci_event < 0)
0111             return 0;
0112         if (sci_event == EVENT_LID) {
0113             int lid_status;
0114             /* check the LID status */
0115             lid_status = ec_read(REG_LID_DETECT);
0116             /* wakeup cpu when people open the LID */
0117             if (lid_status == BIT_LID_DETECT_ON) {
0118                 /* If we call it directly here, the WARNING
0119                  * will be sent out by getnstimeofday
0120                  * via "WARN_ON(timekeeping_suspended);"
0121                  * because we can not schedule in suspend mode.
0122                  */
0123                 if (initialized == 0) {
0124                     INIT_DELAYED_WORK(&lid_task,
0125                         yeeloong_lid_update_task);
0126                     initialized = 1;
0127                 }
0128                 schedule_delayed_work(&lid_task, 1);
0129                 return 1;
0130             }
0131         }
0132     }
0133 
0134     return 0;
0135 }
0136 
0137 void __weak mach_suspend(void)
0138 {
0139     disable_mfgpt0_counter();
0140 }
0141 
0142 void __weak mach_resume(void)
0143 {
0144     enable_mfgpt0_counter();
0145 }