irq-sunxi-nmi.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /*
  2. * Allwinner A20/A31 SoCs NMI IRQ chip driver.
  3. *
  4. * Carlo Caione <carlo.caione@gmail.com>
  5. *
  6. * This file is licensed under the terms of the GNU General Public
  7. * License version 2. This program is licensed "as is" without any
  8. * warranty of any kind, whether express or implied.
  9. */
  10. #include <linux/bitops.h>
  11. #include <linux/device.h>
  12. #include <linux/io.h>
  13. #include <linux/irq.h>
  14. #include <linux/interrupt.h>
  15. #include <linux/irqdomain.h>
  16. #include <linux/of_irq.h>
  17. #include <linux/of_address.h>
  18. #include <linux/of_platform.h>
  19. #include <linux/irqchip.h>
  20. #include <linux/irqchip/chained_irq.h>
  21. #define SUNXI_NMI_SRC_TYPE_MASK 0x00000003
  22. enum {
  23. SUNXI_SRC_TYPE_LEVEL_LOW = 0,
  24. SUNXI_SRC_TYPE_EDGE_FALLING,
  25. SUNXI_SRC_TYPE_LEVEL_HIGH,
  26. SUNXI_SRC_TYPE_EDGE_RISING,
  27. };
  28. struct sunxi_sc_nmi_reg_offs {
  29. u32 ctrl;
  30. u32 pend;
  31. u32 enable;
  32. };
  33. static struct sunxi_sc_nmi_reg_offs sun7i_reg_offs = {
  34. .ctrl = 0x00,
  35. .pend = 0x04,
  36. .enable = 0x08,
  37. };
  38. static struct sunxi_sc_nmi_reg_offs sun6i_reg_offs = {
  39. .ctrl = 0x00,
  40. .pend = 0x04,
  41. .enable = 0x34,
  42. };
  43. static inline void sunxi_sc_nmi_write(struct irq_chip_generic *gc, u32 off,
  44. u32 val)
  45. {
  46. irq_reg_writel(gc, val, off);
  47. }
  48. static inline u32 sunxi_sc_nmi_read(struct irq_chip_generic *gc, u32 off)
  49. {
  50. return irq_reg_readl(gc, off);
  51. }
  52. static void sunxi_sc_nmi_handle_irq(struct irq_desc *desc)
  53. {
  54. struct irq_domain *domain = irq_desc_get_handler_data(desc);
  55. struct irq_chip *chip = irq_desc_get_chip(desc);
  56. unsigned int virq = irq_find_mapping(domain, 0);
  57. chained_irq_enter(chip, desc);
  58. generic_handle_irq(virq);
  59. chained_irq_exit(chip, desc);
  60. }
  61. static int sunxi_sc_nmi_set_type(struct irq_data *data, unsigned int flow_type)
  62. {
  63. struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
  64. struct irq_chip_type *ct = gc->chip_types;
  65. u32 src_type_reg;
  66. u32 ctrl_off = ct->regs.type;
  67. unsigned int src_type;
  68. unsigned int i;
  69. irq_gc_lock(gc);
  70. switch (flow_type & IRQF_TRIGGER_MASK) {
  71. case IRQ_TYPE_EDGE_FALLING:
  72. src_type = SUNXI_SRC_TYPE_EDGE_FALLING;
  73. break;
  74. case IRQ_TYPE_EDGE_RISING:
  75. src_type = SUNXI_SRC_TYPE_EDGE_RISING;
  76. break;
  77. case IRQ_TYPE_LEVEL_HIGH:
  78. src_type = SUNXI_SRC_TYPE_LEVEL_HIGH;
  79. break;
  80. case IRQ_TYPE_NONE:
  81. case IRQ_TYPE_LEVEL_LOW:
  82. src_type = SUNXI_SRC_TYPE_LEVEL_LOW;
  83. break;
  84. default:
  85. irq_gc_unlock(gc);
  86. pr_err("%s: Cannot assign multiple trigger modes to IRQ %d.\n",
  87. __func__, data->irq);
  88. return -EBADR;
  89. }
  90. irqd_set_trigger_type(data, flow_type);
  91. irq_setup_alt_chip(data, flow_type);
  92. for (i = 0; i < gc->num_ct; i++, ct++)
  93. if (ct->type & flow_type)
  94. ctrl_off = ct->regs.type;
  95. src_type_reg = sunxi_sc_nmi_read(gc, ctrl_off);
  96. src_type_reg &= ~SUNXI_NMI_SRC_TYPE_MASK;
  97. src_type_reg |= src_type;
  98. sunxi_sc_nmi_write(gc, ctrl_off, src_type_reg);
  99. irq_gc_unlock(gc);
  100. return IRQ_SET_MASK_OK;
  101. }
  102. static int __init sunxi_sc_nmi_irq_init(struct device_node *node,
  103. struct sunxi_sc_nmi_reg_offs *reg_offs)
  104. {
  105. struct irq_domain *domain;
  106. struct irq_chip_generic *gc;
  107. unsigned int irq;
  108. unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
  109. int ret;
  110. domain = irq_domain_add_linear(node, 1, &irq_generic_chip_ops, NULL);
  111. if (!domain) {
  112. pr_err("%s: Could not register interrupt domain.\n", node->name);
  113. return -ENOMEM;
  114. }
  115. ret = irq_alloc_domain_generic_chips(domain, 1, 2, node->name,
  116. handle_fasteoi_irq, clr, 0,
  117. IRQ_GC_INIT_MASK_CACHE);
  118. if (ret) {
  119. pr_err("%s: Could not allocate generic interrupt chip.\n",
  120. node->name);
  121. goto fail_irqd_remove;
  122. }
  123. irq = irq_of_parse_and_map(node, 0);
  124. if (irq <= 0) {
  125. pr_err("%s: unable to parse irq\n", node->name);
  126. ret = -EINVAL;
  127. goto fail_irqd_remove;
  128. }
  129. gc = irq_get_domain_generic_chip(domain, 0);
  130. gc->reg_base = of_iomap(node, 0);
  131. if (!gc->reg_base) {
  132. pr_err("%s: unable to map resource\n", node->name);
  133. ret = -ENOMEM;
  134. goto fail_irqd_remove;
  135. }
  136. gc->chip_types[0].type = IRQ_TYPE_LEVEL_MASK;
  137. gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
  138. gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
  139. gc->chip_types[0].chip.irq_eoi = irq_gc_ack_set_bit;
  140. gc->chip_types[0].chip.irq_set_type = sunxi_sc_nmi_set_type;
  141. gc->chip_types[0].chip.flags = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED;
  142. gc->chip_types[0].regs.ack = reg_offs->pend;
  143. gc->chip_types[0].regs.mask = reg_offs->enable;
  144. gc->chip_types[0].regs.type = reg_offs->ctrl;
  145. gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH;
  146. gc->chip_types[1].chip.name = gc->chip_types[0].chip.name;
  147. gc->chip_types[1].chip.irq_ack = irq_gc_ack_set_bit;
  148. gc->chip_types[1].chip.irq_mask = irq_gc_mask_clr_bit;
  149. gc->chip_types[1].chip.irq_unmask = irq_gc_mask_set_bit;
  150. gc->chip_types[1].chip.irq_set_type = sunxi_sc_nmi_set_type;
  151. gc->chip_types[1].regs.ack = reg_offs->pend;
  152. gc->chip_types[1].regs.mask = reg_offs->enable;
  153. gc->chip_types[1].regs.type = reg_offs->ctrl;
  154. gc->chip_types[1].handler = handle_edge_irq;
  155. sunxi_sc_nmi_write(gc, reg_offs->enable, 0);
  156. sunxi_sc_nmi_write(gc, reg_offs->pend, 0x1);
  157. irq_set_chained_handler_and_data(irq, sunxi_sc_nmi_handle_irq, domain);
  158. return 0;
  159. fail_irqd_remove:
  160. irq_domain_remove(domain);
  161. return ret;
  162. }
  163. static int __init sun6i_sc_nmi_irq_init(struct device_node *node,
  164. struct device_node *parent)
  165. {
  166. return sunxi_sc_nmi_irq_init(node, &sun6i_reg_offs);
  167. }
  168. IRQCHIP_DECLARE(sun6i_sc_nmi, "allwinner,sun6i-a31-sc-nmi", sun6i_sc_nmi_irq_init);
  169. static int __init sun7i_sc_nmi_irq_init(struct device_node *node,
  170. struct device_node *parent)
  171. {
  172. return sunxi_sc_nmi_irq_init(node, &sun7i_reg_offs);
  173. }
  174. IRQCHIP_DECLARE(sun7i_sc_nmi, "allwinner,sun7i-a20-sc-nmi", sun7i_sc_nmi_irq_init);