Path: blob/master/arch/mips/loongson/lemote-2f/pm.c
10818 views
/*1* Lemote loongson2f family machines' specific suspend support2*3* Copyright (C) 2009 Lemote Inc.4* Author: Wu Zhangjin <[email protected]>5*6* This program is free software; you can redistribute it and/or modify7* it under the terms of the GNU General Public License as published by8* the Free Software Foundation; either version 2 of the License, or9* (at your option) any later version.10*/1112#include <linux/suspend.h>13#include <linux/interrupt.h>14#include <linux/pm.h>15#include <linux/i8042.h>16#include <linux/module.h>1718#include <asm/i8259.h>19#include <asm/mipsregs.h>20#include <asm/bootinfo.h>2122#include <loongson.h>2324#include <cs5536/cs5536_mfgpt.h>25#include "ec_kb3310b.h"2627#define I8042_KBD_IRQ 128#define I8042_CTR_KBDINT 0x0129#define I8042_CTR_KBDDIS 0x103031static unsigned char i8042_ctr;3233static int i8042_enable_kbd_port(void)34{35if (i8042_command(&i8042_ctr, I8042_CMD_CTL_RCTR)) {36pr_err("i8042.c: Can't read CTR while enabling i8042 kbd port."37"\n");38return -EIO;39}4041i8042_ctr &= ~I8042_CTR_KBDDIS;42i8042_ctr |= I8042_CTR_KBDINT;4344if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {45i8042_ctr &= ~I8042_CTR_KBDINT;46i8042_ctr |= I8042_CTR_KBDDIS;47pr_err("i8042.c: Failed to enable KBD port.\n");4849return -EIO;50}5152return 0;53}5455void setup_wakeup_events(void)56{57int irq_mask;5859switch (mips_machtype) {60case MACH_LEMOTE_ML2F7:61case MACH_LEMOTE_YL2F89:62/* open the keyboard irq in i8259A */63outb((0xff & ~(1 << I8042_KBD_IRQ)), PIC_MASTER_IMR);64irq_mask = inb(PIC_MASTER_IMR);6566/* enable keyboard port */67i8042_enable_kbd_port();6869/* Wakeup CPU via SCI lid open event */70outb(irq_mask & ~(1 << PIC_CASCADE_IR), PIC_MASTER_IMR);71inb(PIC_MASTER_IMR);72outb(0xff & ~(1 << (SCI_IRQ_NUM - 8)), PIC_SLAVE_IMR);73inb(PIC_SLAVE_IMR);7475break;7677default:78break;79}80}8182static struct delayed_work lid_task;83static int initialized;84/* yeeloong_report_lid_status will be implemented in yeeloong_laptop.c */85sci_handler yeeloong_report_lid_status;86EXPORT_SYMBOL(yeeloong_report_lid_status);87static void yeeloong_lid_update_task(struct work_struct *work)88{89if (yeeloong_report_lid_status)90yeeloong_report_lid_status(BIT_LID_DETECT_ON);91}9293int wakeup_loongson(void)94{95int irq;9697/* query the interrupt number */98irq = mach_i8259_irq();99if (irq < 0)100return 0;101102printk(KERN_INFO "%s: irq = %d\n", __func__, irq);103104if (irq == I8042_KBD_IRQ)105return 1;106else if (irq == SCI_IRQ_NUM) {107int ret, sci_event;108/* query the event number */109ret = ec_query_seq(CMD_GET_EVENT_NUM);110if (ret < 0)111return 0;112sci_event = ec_get_event_num();113if (sci_event < 0)114return 0;115if (sci_event == EVENT_LID) {116int lid_status;117/* check the LID status */118lid_status = ec_read(REG_LID_DETECT);119/* wakeup cpu when people open the LID */120if (lid_status == BIT_LID_DETECT_ON) {121/* If we call it directly here, the WARNING122* will be sent out by getnstimeofday123* via "WARN_ON(timekeeping_suspended);"124* because we can not schedule in suspend mode.125*/126if (initialized == 0) {127INIT_DELAYED_WORK(&lid_task,128yeeloong_lid_update_task);129initialized = 1;130}131schedule_delayed_work(&lid_task, 1);132return 1;133}134}135}136137return 0;138}139140void __weak mach_suspend(void)141{142disable_mfgpt0_counter();143}144145void __weak mach_resume(void)146{147enable_mfgpt0_counter();148}149150151