msp_hwbutton.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /*
  2. * Sets up interrupt handlers for various hardware switches which are
  3. * connected to interrupt lines.
  4. *
  5. * Copyright 2005-2207 PMC-Sierra, Inc.
  6. *
  7. * This program is free software; you can redistribute it and/or modify it
  8. * under the terms of the GNU General Public License as published by the
  9. * Free Software Foundation; either version 2 of the License, or (at your
  10. * option) any later version.
  11. *
  12. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  13. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  14. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
  15. * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  16. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  17. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  18. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  19. * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  20. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  21. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  22. *
  23. * You should have received a copy of the GNU General Public License along
  24. * with this program; if not, write to the Free Software Foundation, Inc.,
  25. * 675 Mass Ave, Cambridge, MA 02139, USA.
  26. */
  27. #include <linux/kernel.h>
  28. #include <linux/init.h>
  29. #include <linux/interrupt.h>
  30. #include <msp_int.h>
  31. #include <msp_regs.h>
  32. #include <msp_regops.h>
  33. #ifdef CONFIG_PMCTWILED
  34. #include <msp_led_macros.h>
  35. #endif
  36. /* For hwbutton_interrupt->initial_state */
  37. #define HWBUTTON_HI 0x1
  38. #define HWBUTTON_LO 0x2
  39. /*
  40. * This struct describes a hardware button
  41. */
  42. struct hwbutton_interrupt {
  43. char *name; /* Name of button */
  44. int irq; /* Actual LINUX IRQ */
  45. int eirq; /* Extended IRQ number (0-7) */
  46. int initial_state; /* The "normal" state of the switch */
  47. void (*handle_hi)(void *); /* Handler: switch input has gone HI */
  48. void (*handle_lo)(void *); /* Handler: switch input has gone LO */
  49. void *data; /* Optional data to pass to handler */
  50. };
  51. #ifdef CONFIG_PMC_MSP7120_GW
  52. extern void msp_restart(char *);
  53. static void softreset_push(void *data)
  54. {
  55. printk(KERN_WARNING "SOFTRESET switch was pushed\n");
  56. /*
  57. * In the future you could move this to the release handler,
  58. * timing the difference between the 'push' and 'release', and only
  59. * doing this ungraceful restart if the button has been down for
  60. * a certain amount of time; otherwise doing a graceful restart.
  61. */
  62. msp_restart(NULL);
  63. }
  64. static void softreset_release(void *data)
  65. {
  66. printk(KERN_WARNING "SOFTRESET switch was released\n");
  67. /* Do nothing */
  68. }
  69. static void standby_on(void *data)
  70. {
  71. printk(KERN_WARNING "STANDBY switch was set to ON (not implemented)\n");
  72. /* TODO: Put board in standby mode */
  73. #ifdef CONFIG_PMCTWILED
  74. msp_led_turn_off(MSP_LED_PWRSTANDBY_GREEN);
  75. msp_led_turn_on(MSP_LED_PWRSTANDBY_RED);
  76. #endif
  77. }
  78. static void standby_off(void *data)
  79. {
  80. printk(KERN_WARNING
  81. "STANDBY switch was set to OFF (not implemented)\n");
  82. /* TODO: Take out of standby mode */
  83. #ifdef CONFIG_PMCTWILED
  84. msp_led_turn_on(MSP_LED_PWRSTANDBY_GREEN);
  85. msp_led_turn_off(MSP_LED_PWRSTANDBY_RED);
  86. #endif
  87. }
  88. static struct hwbutton_interrupt softreset_sw = {
  89. .name = "Softreset button",
  90. .irq = MSP_INT_EXT0,
  91. .eirq = 0,
  92. .initial_state = HWBUTTON_HI,
  93. .handle_hi = softreset_release,
  94. .handle_lo = softreset_push,
  95. .data = NULL,
  96. };
  97. static struct hwbutton_interrupt standby_sw = {
  98. .name = "Standby switch",
  99. .irq = MSP_INT_EXT1,
  100. .eirq = 1,
  101. .initial_state = HWBUTTON_HI,
  102. .handle_hi = standby_off,
  103. .handle_lo = standby_on,
  104. .data = NULL,
  105. };
  106. #endif /* CONFIG_PMC_MSP7120_GW */
  107. static irqreturn_t hwbutton_handler(int irq, void *data)
  108. {
  109. struct hwbutton_interrupt *hirq = data;
  110. unsigned long cic_ext = *CIC_EXT_CFG_REG;
  111. if (CIC_EXT_IS_ACTIVE_HI(cic_ext, hirq->eirq)) {
  112. /* Interrupt: pin is now HI */
  113. CIC_EXT_SET_ACTIVE_LO(cic_ext, hirq->eirq);
  114. hirq->handle_hi(hirq->data);
  115. } else {
  116. /* Interrupt: pin is now LO */
  117. CIC_EXT_SET_ACTIVE_HI(cic_ext, hirq->eirq);
  118. hirq->handle_lo(hirq->data);
  119. }
  120. /*
  121. * Invert the POLARITY of this level interrupt to ack the interrupt
  122. * Thus next state change will invoke the opposite message
  123. */
  124. *CIC_EXT_CFG_REG = cic_ext;
  125. return IRQ_HANDLED;
  126. }
  127. static int msp_hwbutton_register(struct hwbutton_interrupt *hirq)
  128. {
  129. unsigned long cic_ext;
  130. if (hirq->handle_hi == NULL || hirq->handle_lo == NULL)
  131. return -EINVAL;
  132. cic_ext = *CIC_EXT_CFG_REG;
  133. CIC_EXT_SET_TRIGGER_LEVEL(cic_ext, hirq->eirq);
  134. if (hirq->initial_state == HWBUTTON_HI)
  135. CIC_EXT_SET_ACTIVE_LO(cic_ext, hirq->eirq);
  136. else
  137. CIC_EXT_SET_ACTIVE_HI(cic_ext, hirq->eirq);
  138. *CIC_EXT_CFG_REG = cic_ext;
  139. return request_irq(hirq->irq, hwbutton_handler, IRQF_DISABLED,
  140. hirq->name, hirq);
  141. }
  142. static int __init msp_hwbutton_setup(void)
  143. {
  144. #ifdef CONFIG_PMC_MSP7120_GW
  145. msp_hwbutton_register(&softreset_sw);
  146. msp_hwbutton_register(&standby_sw);
  147. #endif
  148. return 0;
  149. }
  150. subsys_initcall(msp_hwbutton_setup);