wm8994-irq.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. /*
  2. * wm8994-irq.c -- Interrupt controller support for Wolfson WM8994
  3. *
  4. * Copyright 2010 Wolfson Microelectronics PLC.
  5. *
  6. * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  7. *
  8. * This program is free software; you can redistribute it and/or modify it
  9. * under the terms of the GNU General Public License as published by the
  10. * Free Software Foundation; either version 2 of the License, or (at your
  11. * option) any later version.
  12. *
  13. */
  14. #include <linux/kernel.h>
  15. #include <linux/module.h>
  16. #include <linux/i2c.h>
  17. #include <linux/irq.h>
  18. #include <linux/mfd/core.h>
  19. #include <linux/interrupt.h>
  20. #include <linux/regmap.h>
  21. #include <linux/mfd/wm8994/core.h>
  22. #include <linux/mfd/wm8994/registers.h>
  23. #include <linux/delay.h>
  24. static struct regmap_irq wm8994_irqs[] = {
  25. [WM8994_IRQ_TEMP_SHUT] = {
  26. .reg_offset = 1,
  27. .mask = WM8994_TEMP_SHUT_EINT,
  28. },
  29. [WM8994_IRQ_MIC1_DET] = {
  30. .reg_offset = 1,
  31. .mask = WM8994_MIC1_DET_EINT,
  32. },
  33. [WM8994_IRQ_MIC1_SHRT] = {
  34. .reg_offset = 1,
  35. .mask = WM8994_MIC1_SHRT_EINT,
  36. },
  37. [WM8994_IRQ_MIC2_DET] = {
  38. .reg_offset = 1,
  39. .mask = WM8994_MIC2_DET_EINT,
  40. },
  41. [WM8994_IRQ_MIC2_SHRT] = {
  42. .reg_offset = 1,
  43. .mask = WM8994_MIC2_SHRT_EINT,
  44. },
  45. [WM8994_IRQ_FLL1_LOCK] = {
  46. .reg_offset = 1,
  47. .mask = WM8994_FLL1_LOCK_EINT,
  48. },
  49. [WM8994_IRQ_FLL2_LOCK] = {
  50. .reg_offset = 1,
  51. .mask = WM8994_FLL2_LOCK_EINT,
  52. },
  53. [WM8994_IRQ_SRC1_LOCK] = {
  54. .reg_offset = 1,
  55. .mask = WM8994_SRC1_LOCK_EINT,
  56. },
  57. [WM8994_IRQ_SRC2_LOCK] = {
  58. .reg_offset = 1,
  59. .mask = WM8994_SRC2_LOCK_EINT,
  60. },
  61. [WM8994_IRQ_AIF1DRC1_SIG_DET] = {
  62. .reg_offset = 1,
  63. .mask = WM8994_AIF1DRC1_SIG_DET,
  64. },
  65. [WM8994_IRQ_AIF1DRC2_SIG_DET] = {
  66. .reg_offset = 1,
  67. .mask = WM8994_AIF1DRC2_SIG_DET_EINT,
  68. },
  69. [WM8994_IRQ_AIF2DRC_SIG_DET] = {
  70. .reg_offset = 1,
  71. .mask = WM8994_AIF2DRC_SIG_DET_EINT,
  72. },
  73. [WM8994_IRQ_FIFOS_ERR] = {
  74. .reg_offset = 1,
  75. .mask = WM8994_FIFOS_ERR_EINT,
  76. },
  77. [WM8994_IRQ_WSEQ_DONE] = {
  78. .reg_offset = 1,
  79. .mask = WM8994_WSEQ_DONE_EINT,
  80. },
  81. [WM8994_IRQ_DCS_DONE] = {
  82. .reg_offset = 1,
  83. .mask = WM8994_DCS_DONE_EINT,
  84. },
  85. [WM8994_IRQ_TEMP_WARN] = {
  86. .reg_offset = 1,
  87. .mask = WM8994_TEMP_WARN_EINT,
  88. },
  89. [WM8994_IRQ_GPIO(1)] = {
  90. .mask = WM8994_GP1_EINT,
  91. },
  92. [WM8994_IRQ_GPIO(2)] = {
  93. .mask = WM8994_GP2_EINT,
  94. },
  95. [WM8994_IRQ_GPIO(3)] = {
  96. .mask = WM8994_GP3_EINT,
  97. },
  98. [WM8994_IRQ_GPIO(4)] = {
  99. .mask = WM8994_GP4_EINT,
  100. },
  101. [WM8994_IRQ_GPIO(5)] = {
  102. .mask = WM8994_GP5_EINT,
  103. },
  104. [WM8994_IRQ_GPIO(6)] = {
  105. .mask = WM8994_GP6_EINT,
  106. },
  107. [WM8994_IRQ_GPIO(7)] = {
  108. .mask = WM8994_GP7_EINT,
  109. },
  110. [WM8994_IRQ_GPIO(8)] = {
  111. .mask = WM8994_GP8_EINT,
  112. },
  113. [WM8994_IRQ_GPIO(9)] = {
  114. .mask = WM8994_GP8_EINT,
  115. },
  116. [WM8994_IRQ_GPIO(10)] = {
  117. .mask = WM8994_GP10_EINT,
  118. },
  119. [WM8994_IRQ_GPIO(11)] = {
  120. .mask = WM8994_GP11_EINT,
  121. },
  122. };
  123. static struct regmap_irq_chip wm8994_irq_chip = {
  124. .name = "wm8994",
  125. .irqs = wm8994_irqs,
  126. .num_irqs = ARRAY_SIZE(wm8994_irqs),
  127. .num_regs = 2,
  128. .status_base = WM8994_INTERRUPT_STATUS_1,
  129. .mask_base = WM8994_INTERRUPT_STATUS_1_MASK,
  130. .ack_base = WM8994_INTERRUPT_STATUS_1,
  131. };
  132. int wm8994_irq_init(struct wm8994 *wm8994)
  133. {
  134. int ret;
  135. if (!wm8994->irq) {
  136. dev_warn(wm8994->dev,
  137. "No interrupt specified, no interrupts\n");
  138. wm8994->irq_base = 0;
  139. return 0;
  140. }
  141. if (!wm8994->irq_base) {
  142. dev_err(wm8994->dev,
  143. "No interrupt base specified, no interrupts\n");
  144. return 0;
  145. }
  146. ret = regmap_add_irq_chip(wm8994->regmap, wm8994->irq,
  147. IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
  148. wm8994->irq_base, &wm8994_irq_chip,
  149. &wm8994->irq_data);
  150. if (ret != 0) {
  151. dev_err(wm8994->dev, "Failed to register IRQ chip: %d\n", ret);
  152. return ret;
  153. }
  154. /* Enable top level interrupt if it was masked */
  155. wm8994_reg_write(wm8994, WM8994_INTERRUPT_CONTROL, 0);
  156. return 0;
  157. }
  158. void wm8994_irq_exit(struct wm8994 *wm8994)
  159. {
  160. regmap_del_irq_chip(wm8994->irq, wm8994->irq_data);
  161. }