msp_hwbutton.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  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. /* For hwbutton_interrupt->initial_state */
  34. #define HWBUTTON_HI 0x1
  35. #define HWBUTTON_LO 0x2
  36. /*
  37. * This struct describes a hardware button
  38. */
  39. struct hwbutton_interrupt {
  40. char *name; /* Name of button */
  41. int irq; /* Actual LINUX IRQ */
  42. int eirq; /* Extended IRQ number (0-7) */
  43. int initial_state; /* The "normal" state of the switch */
  44. void (*handle_hi)(void *); /* Handler: switch input has gone HI */
  45. void (*handle_lo)(void *); /* Handler: switch input has gone LO */
  46. void *data; /* Optional data to pass to handler */
  47. };
  48. #ifdef CONFIG_PMC_MSP7120_GW
  49. extern void msp_restart(char *);
  50. static void softreset_push(void *data)
  51. {
  52. printk(KERN_WARNING "SOFTRESET switch was pushed\n");
  53. /*
  54. * In the future you could move this to the release handler,
  55. * timing the difference between the 'push' and 'release', and only
  56. * doing this ungraceful restart if the button has been down for
  57. * a certain amount of time; otherwise doing a graceful restart.
  58. */
  59. msp_restart(NULL);
  60. }
  61. static void softreset_release(void *data)
  62. {
  63. printk(KERN_WARNING "SOFTRESET switch was released\n");
  64. /* Do nothing */
  65. }
  66. static void standby_on(void *data)
  67. {
  68. printk(KERN_WARNING "STANDBY switch was set to ON (not implemented)\n");
  69. /* TODO: Put board in standby mode */
  70. }
  71. static void standby_off(void *data)
  72. {
  73. printk(KERN_WARNING
  74. "STANDBY switch was set to OFF (not implemented)\n");
  75. /* TODO: Take out of standby mode */
  76. }
  77. static struct hwbutton_interrupt softreset_sw = {
  78. .name = "Softreset button",
  79. .irq = MSP_INT_EXT0,
  80. .eirq = 0,
  81. .initial_state = HWBUTTON_HI,
  82. .handle_hi = softreset_release,
  83. .handle_lo = softreset_push,
  84. .data = NULL,
  85. };
  86. static struct hwbutton_interrupt standby_sw = {
  87. .name = "Standby switch",
  88. .irq = MSP_INT_EXT1,
  89. .eirq = 1,
  90. .initial_state = HWBUTTON_HI,
  91. .handle_hi = standby_off,
  92. .handle_lo = standby_on,
  93. .data = NULL,
  94. };
  95. #endif /* CONFIG_PMC_MSP7120_GW */
  96. static irqreturn_t hwbutton_handler(int irq, void *data)
  97. {
  98. struct hwbutton_interrupt *hirq = data;
  99. unsigned long cic_ext = *CIC_EXT_CFG_REG;
  100. if (CIC_EXT_IS_ACTIVE_HI(cic_ext, hirq->eirq)) {
  101. /* Interrupt: pin is now HI */
  102. CIC_EXT_SET_ACTIVE_LO(cic_ext, hirq->eirq);
  103. hirq->handle_hi(hirq->data);
  104. } else {
  105. /* Interrupt: pin is now LO */
  106. CIC_EXT_SET_ACTIVE_HI(cic_ext, hirq->eirq);
  107. hirq->handle_lo(hirq->data);
  108. }
  109. /*
  110. * Invert the POLARITY of this level interrupt to ack the interrupt
  111. * Thus next state change will invoke the opposite message
  112. */
  113. *CIC_EXT_CFG_REG = cic_ext;
  114. return IRQ_HANDLED;
  115. }
  116. static int msp_hwbutton_register(struct hwbutton_interrupt *hirq)
  117. {
  118. unsigned long cic_ext;
  119. if (hirq->handle_hi == NULL || hirq->handle_lo == NULL)
  120. return -EINVAL;
  121. cic_ext = *CIC_EXT_CFG_REG;
  122. CIC_EXT_SET_TRIGGER_LEVEL(cic_ext, hirq->eirq);
  123. if (hirq->initial_state == HWBUTTON_HI)
  124. CIC_EXT_SET_ACTIVE_LO(cic_ext, hirq->eirq);
  125. else
  126. CIC_EXT_SET_ACTIVE_HI(cic_ext, hirq->eirq);
  127. *CIC_EXT_CFG_REG = cic_ext;
  128. return request_irq(hirq->irq, hwbutton_handler, 0,
  129. hirq->name, hirq);
  130. }
  131. static int __init msp_hwbutton_setup(void)
  132. {
  133. #ifdef CONFIG_PMC_MSP7120_GW
  134. msp_hwbutton_register(&softreset_sw);
  135. msp_hwbutton_register(&standby_sw);
  136. #endif
  137. return 0;
  138. }
  139. subsys_initcall(msp_hwbutton_setup);