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