irq-ath79-misc.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /*
  2. * Atheros AR71xx/AR724x/AR913x MISC interrupt controller
  3. *
  4. * Copyright (C) 2015 Alban Bedel <albeu@free.fr>
  5. * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com>
  6. * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
  7. * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
  8. *
  9. * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP
  10. *
  11. * This program is free software; you can redistribute it and/or modify it
  12. * under the terms of the GNU General Public License version 2 as published
  13. * by the Free Software Foundation.
  14. */
  15. #include <linux/irqchip.h>
  16. #include <linux/irqchip/chained_irq.h>
  17. #include <linux/of_address.h>
  18. #include <linux/of_irq.h>
  19. #define AR71XX_RESET_REG_MISC_INT_STATUS 0
  20. #define AR71XX_RESET_REG_MISC_INT_ENABLE 4
  21. #define ATH79_MISC_IRQ_COUNT 32
  22. static void ath79_misc_irq_handler(struct irq_desc *desc)
  23. {
  24. struct irq_domain *domain = irq_desc_get_handler_data(desc);
  25. struct irq_chip *chip = irq_desc_get_chip(desc);
  26. void __iomem *base = domain->host_data;
  27. u32 pending;
  28. chained_irq_enter(chip, desc);
  29. pending = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS) &
  30. __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
  31. if (!pending) {
  32. spurious_interrupt();
  33. chained_irq_exit(chip, desc);
  34. return;
  35. }
  36. while (pending) {
  37. int bit = __ffs(pending);
  38. generic_handle_irq(irq_linear_revmap(domain, bit));
  39. pending &= ~BIT(bit);
  40. }
  41. chained_irq_exit(chip, desc);
  42. }
  43. static void ar71xx_misc_irq_unmask(struct irq_data *d)
  44. {
  45. void __iomem *base = irq_data_get_irq_chip_data(d);
  46. unsigned int irq = d->hwirq;
  47. u32 t;
  48. t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
  49. __raw_writel(t | BIT(irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE);
  50. /* flush write */
  51. __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
  52. }
  53. static void ar71xx_misc_irq_mask(struct irq_data *d)
  54. {
  55. void __iomem *base = irq_data_get_irq_chip_data(d);
  56. unsigned int irq = d->hwirq;
  57. u32 t;
  58. t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
  59. __raw_writel(t & ~BIT(irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE);
  60. /* flush write */
  61. __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
  62. }
  63. static void ar724x_misc_irq_ack(struct irq_data *d)
  64. {
  65. void __iomem *base = irq_data_get_irq_chip_data(d);
  66. unsigned int irq = d->hwirq;
  67. u32 t;
  68. t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS);
  69. __raw_writel(t & ~BIT(irq), base + AR71XX_RESET_REG_MISC_INT_STATUS);
  70. /* flush write */
  71. __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS);
  72. }
  73. static struct irq_chip ath79_misc_irq_chip = {
  74. .name = "MISC",
  75. .irq_unmask = ar71xx_misc_irq_unmask,
  76. .irq_mask = ar71xx_misc_irq_mask,
  77. };
  78. static int misc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
  79. {
  80. irq_set_chip_and_handler(irq, &ath79_misc_irq_chip, handle_level_irq);
  81. irq_set_chip_data(irq, d->host_data);
  82. return 0;
  83. }
  84. static const struct irq_domain_ops misc_irq_domain_ops = {
  85. .xlate = irq_domain_xlate_onecell,
  86. .map = misc_map,
  87. };
  88. static void __init ath79_misc_intc_domain_init(
  89. struct irq_domain *domain, int irq)
  90. {
  91. void __iomem *base = domain->host_data;
  92. /* Disable and clear all interrupts */
  93. __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_ENABLE);
  94. __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_STATUS);
  95. irq_set_chained_handler_and_data(irq, ath79_misc_irq_handler, domain);
  96. }
  97. static int __init ath79_misc_intc_of_init(
  98. struct device_node *node, struct device_node *parent)
  99. {
  100. struct irq_domain *domain;
  101. void __iomem *base;
  102. int irq;
  103. irq = irq_of_parse_and_map(node, 0);
  104. if (!irq) {
  105. pr_err("Failed to get MISC IRQ\n");
  106. return -EINVAL;
  107. }
  108. base = of_iomap(node, 0);
  109. if (!base) {
  110. pr_err("Failed to get MISC IRQ registers\n");
  111. return -ENOMEM;
  112. }
  113. domain = irq_domain_add_linear(node, ATH79_MISC_IRQ_COUNT,
  114. &misc_irq_domain_ops, base);
  115. if (!domain) {
  116. pr_err("Failed to add MISC irqdomain\n");
  117. return -EINVAL;
  118. }
  119. ath79_misc_intc_domain_init(domain, irq);
  120. return 0;
  121. }
  122. static int __init ar7100_misc_intc_of_init(
  123. struct device_node *node, struct device_node *parent)
  124. {
  125. ath79_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask;
  126. return ath79_misc_intc_of_init(node, parent);
  127. }
  128. IRQCHIP_DECLARE(ar7100_misc_intc, "qca,ar7100-misc-intc",
  129. ar7100_misc_intc_of_init);
  130. static int __init ar7240_misc_intc_of_init(
  131. struct device_node *node, struct device_node *parent)
  132. {
  133. ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack;
  134. return ath79_misc_intc_of_init(node, parent);
  135. }
  136. IRQCHIP_DECLARE(ar7240_misc_intc, "qca,ar7240-misc-intc",
  137. ar7240_misc_intc_of_init);
  138. void __init ath79_misc_irq_init(void __iomem *regs, int irq,
  139. int irq_base, bool is_ar71xx)
  140. {
  141. struct irq_domain *domain;
  142. if (is_ar71xx)
  143. ath79_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask;
  144. else
  145. ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack;
  146. domain = irq_domain_add_legacy(NULL, ATH79_MISC_IRQ_COUNT,
  147. irq_base, 0, &misc_irq_domain_ops, regs);
  148. if (!domain)
  149. panic("Failed to create MISC irqdomain");
  150. ath79_misc_intc_domain_init(domain, irq);
  151. }