wcd-irq.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
  3. */
  4. #include <linux/kernel.h>
  5. #include <linux/module.h>
  6. #include <linux/irq.h>
  7. #include <linux/of.h>
  8. #include <linux/of_irq.h>
  9. #include <linux/slab.h>
  10. #include <linux/irqdomain.h>
  11. #include <linux/regmap.h>
  12. #include <asoc/wcd-irq.h>
  13. static int wcd_map_irq(struct wcd_irq_info *irq_info, int irq)
  14. {
  15. if (!irq_info) {
  16. pr_err("%s: Null IRQ handle\n", __func__);
  17. return -EINVAL;
  18. }
  19. return regmap_irq_get_virq(irq_info->irq_chip, irq);
  20. }
  21. /**
  22. * wcd_request_irq: Request a thread handler for the given IRQ
  23. * @irq_info: pointer to IRQ info structure
  24. * @irq: irq number
  25. * @name: name for the IRQ thread
  26. * @handler: irq handler
  27. * @data: data pointer
  28. *
  29. * Returns 0 on success or error on failure
  30. */
  31. int wcd_request_irq(struct wcd_irq_info *irq_info, int irq, const char *name,
  32. irq_handler_t handler, void *data)
  33. {
  34. if (!irq_info) {
  35. pr_err("%s: Null IRQ handle\n", __func__);
  36. return -EINVAL;
  37. }
  38. irq = wcd_map_irq(irq_info, irq);
  39. if (irq < 0)
  40. return irq;
  41. return devm_request_threaded_irq(irq_info->dev, irq, NULL, handler,
  42. IRQF_ONESHOT | IRQF_TRIGGER_RISING,
  43. name, data);
  44. }
  45. EXPORT_SYMBOL(wcd_request_irq);
  46. /**
  47. * wcd_free_irq: Free the IRQ resources allocated during request_irq
  48. * @irq_info: pointer to IRQ info structure
  49. * @irq: irq number
  50. * @data: data pointer
  51. */
  52. void wcd_free_irq(struct wcd_irq_info *irq_info, int irq, void *data)
  53. {
  54. if (!irq_info) {
  55. pr_err("%s: Null IRQ handle\n", __func__);
  56. return;
  57. }
  58. irq = wcd_map_irq(irq_info, irq);
  59. if (irq < 0)
  60. return;
  61. devm_free_irq(irq_info->dev, irq, data);
  62. }
  63. EXPORT_SYMBOL(wcd_free_irq);
  64. /**
  65. * wcd_enable_irq: Enable the given IRQ
  66. * @irq_info: pointer to IRQ info structure
  67. * @irq: irq number
  68. */
  69. void wcd_enable_irq(struct wcd_irq_info *irq_info, int irq)
  70. {
  71. if (!irq_info)
  72. pr_err("%s: Null IRQ handle\n", __func__);
  73. else
  74. enable_irq(wcd_map_irq(irq_info, irq));
  75. }
  76. EXPORT_SYMBOL(wcd_enable_irq);
  77. /**
  78. * wcd_disable_irq: Disable the given IRQ
  79. * @irq_info: pointer to IRQ info structure
  80. * @irq: irq number
  81. */
  82. void wcd_disable_irq(struct wcd_irq_info *irq_info, int irq)
  83. {
  84. if (!irq_info)
  85. pr_err("%s: Null IRQ handle\n", __func__);
  86. else
  87. disable_irq_nosync(wcd_map_irq(irq_info, irq));
  88. }
  89. EXPORT_SYMBOL(wcd_disable_irq);
  90. static void wcd_irq_chip_disable(struct irq_data *data)
  91. {
  92. }
  93. static void wcd_irq_chip_enable(struct irq_data *data)
  94. {
  95. }
  96. static struct irq_chip wcd_irq_chip = {
  97. .name = NULL,
  98. .irq_disable = wcd_irq_chip_disable,
  99. .irq_enable = wcd_irq_chip_enable,
  100. };
  101. static struct lock_class_key wcd_irq_lock_class;
  102. static struct lock_class_key wcd_irq_lock_requested_class;
  103. static int wcd_irq_chip_map(struct irq_domain *irqd, unsigned int virq,
  104. irq_hw_number_t hw)
  105. {
  106. irq_set_chip_and_handler(virq, &wcd_irq_chip, handle_simple_irq);
  107. irq_set_lockdep_class(virq, &wcd_irq_lock_class,
  108. &wcd_irq_lock_requested_class);
  109. irq_set_nested_thread(virq, 1);
  110. irq_set_noprobe(virq);
  111. return 0;
  112. }
  113. static const struct irq_domain_ops wcd_domain_ops = {
  114. .map = wcd_irq_chip_map,
  115. };
  116. /**
  117. * wcd_irq_init: Initializes IRQ module
  118. * @irq_info: pointer to IRQ info structure
  119. *
  120. * Returns 0 on success or error on failure
  121. */
  122. int wcd_irq_init(struct wcd_irq_info *irq_info, struct irq_domain **virq)
  123. {
  124. int ret = 0;
  125. if (!irq_info) {
  126. pr_err("%s: Null IRQ handle\n", __func__);
  127. return -EINVAL;
  128. }
  129. wcd_irq_chip.name = irq_info->codec_name;
  130. *virq = irq_domain_add_linear(NULL, 1, &wcd_domain_ops, NULL);
  131. if (!(*virq)) {
  132. pr_err("%s: Failed to add IRQ domain\n", __func__);
  133. return -EINVAL;
  134. }
  135. ret = devm_regmap_add_irq_chip(irq_info->dev, irq_info->regmap,
  136. irq_create_mapping(*virq, 0),
  137. IRQF_ONESHOT, 0, irq_info->wcd_regmap_irq_chip,
  138. &irq_info->irq_chip);
  139. if (ret)
  140. pr_err("%s: Failed to add IRQs: %d\n",
  141. __func__, ret);
  142. return ret;
  143. }
  144. EXPORT_SYMBOL(wcd_irq_init);
  145. /**
  146. * wcd_irq_exit: Uninitialize regmap IRQ and free IRQ resources
  147. * @irq_info: pointer to IRQ info structure
  148. *
  149. * Returns 0 on success or error on failure
  150. */
  151. int wcd_irq_exit(struct wcd_irq_info *irq_info, struct irq_domain *virq)
  152. {
  153. if (!irq_info) {
  154. pr_err("%s: Null pointer handle\n", __func__);
  155. return -EINVAL;
  156. }
  157. devm_regmap_del_irq_chip(irq_info->dev, irq_find_mapping(virq, 0),
  158. irq_info->irq_chip);
  159. return 0;
  160. }
  161. EXPORT_SYMBOL(wcd_irq_exit);