pm.c 3.3 KB

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