123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- /*
- * Lemote loongson2f family machines' specific suspend support
- *
- * Copyright (C) 2009 Lemote Inc.
- * Author: Wu Zhangjin <wuzhangjin@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
- #include <linux/suspend.h>
- #include <linux/interrupt.h>
- #include <linux/pm.h>
- #include <linux/i8042.h>
- #include <linux/module.h>
- #include <asm/i8259.h>
- #include <asm/mipsregs.h>
- #include <asm/bootinfo.h>
- #include <loongson.h>
- #include <cs5536/cs5536_mfgpt.h>
- #include "ec_kb3310b.h"
- #define I8042_KBD_IRQ 1
- #define I8042_CTR_KBDINT 0x01
- #define I8042_CTR_KBDDIS 0x10
- static unsigned char i8042_ctr;
- static int i8042_enable_kbd_port(void)
- {
- if (i8042_command(&i8042_ctr, I8042_CMD_CTL_RCTR)) {
- pr_err("i8042.c: Can't read CTR while enabling i8042 kbd port."
- "\n");
- return -EIO;
- }
- i8042_ctr &= ~I8042_CTR_KBDDIS;
- i8042_ctr |= I8042_CTR_KBDINT;
- if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
- i8042_ctr &= ~I8042_CTR_KBDINT;
- i8042_ctr |= I8042_CTR_KBDDIS;
- pr_err("i8042.c: Failed to enable KBD port.\n");
- return -EIO;
- }
- return 0;
- }
- void setup_wakeup_events(void)
- {
- int irq_mask;
- switch (mips_machtype) {
- case MACH_LEMOTE_ML2F7:
- case MACH_LEMOTE_YL2F89:
- /* open the keyboard irq in i8259A */
- outb((0xff & ~(1 << I8042_KBD_IRQ)), PIC_MASTER_IMR);
- irq_mask = inb(PIC_MASTER_IMR);
- /* enable keyboard port */
- i8042_enable_kbd_port();
- /* Wakeup CPU via SCI lid open event */
- outb(irq_mask & ~(1 << PIC_CASCADE_IR), PIC_MASTER_IMR);
- inb(PIC_MASTER_IMR);
- outb(0xff & ~(1 << (SCI_IRQ_NUM - 8)), PIC_SLAVE_IMR);
- inb(PIC_SLAVE_IMR);
- break;
- default:
- break;
- }
- }
- static struct delayed_work lid_task;
- static int initialized;
- /* yeeloong_report_lid_status will be implemented in yeeloong_laptop.c */
- sci_handler yeeloong_report_lid_status;
- EXPORT_SYMBOL(yeeloong_report_lid_status);
- static void yeeloong_lid_update_task(struct work_struct *work)
- {
- if (yeeloong_report_lid_status)
- yeeloong_report_lid_status(BIT_LID_DETECT_ON);
- }
- int wakeup_loongson(void)
- {
- int irq;
- /* query the interrupt number */
- irq = mach_i8259_irq();
- if (irq < 0)
- return 0;
- printk(KERN_INFO "%s: irq = %d\n", __func__, irq);
- if (irq == I8042_KBD_IRQ)
- return 1;
- else if (irq == SCI_IRQ_NUM) {
- int ret, sci_event;
- /* query the event number */
- ret = ec_query_seq(CMD_GET_EVENT_NUM);
- if (ret < 0)
- return 0;
- sci_event = ec_get_event_num();
- if (sci_event < 0)
- return 0;
- if (sci_event == EVENT_LID) {
- int lid_status;
- /* check the LID status */
- lid_status = ec_read(REG_LID_DETECT);
- /* wakeup cpu when people open the LID */
- if (lid_status == BIT_LID_DETECT_ON) {
- /* If we call it directly here, the WARNING
- * will be sent out by getnstimeofday
- * via "WARN_ON(timekeeping_suspended);"
- * because we can not schedule in suspend mode.
- */
- if (initialized == 0) {
- INIT_DELAYED_WORK(&lid_task,
- yeeloong_lid_update_task);
- initialized = 1;
- }
- schedule_delayed_work(&lid_task, 1);
- return 1;
- }
- }
- }
- return 0;
- }
- void __weak mach_suspend(void)
- {
- disable_mfgpt0_counter();
- }
- void __weak mach_resume(void)
- {
- enable_mfgpt0_counter();
- }
|