irq-sunxi-nmi.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  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. #define DRV_NAME "sunxi-nmi"
  11. #define pr_fmt(fmt) DRV_NAME ": " fmt
  12. #include <linux/bitops.h>
  13. #include <linux/device.h>
  14. #include <linux/io.h>
  15. #include <linux/irq.h>
  16. #include <linux/interrupt.h>
  17. #include <linux/irqdomain.h>
  18. #include <linux/of_irq.h>
  19. #include <linux/of_address.h>
  20. #include <linux/of_platform.h>
  21. #include <linux/irqchip.h>
  22. #include <linux/irqchip/chained_irq.h>
  23. #define SUNXI_NMI_SRC_TYPE_MASK 0x00000003
  24. #define SUNXI_NMI_IRQ_BIT BIT(0)
  25. #define SUN6I_R_INTC_CTRL 0x0c
  26. #define SUN6I_R_INTC_PENDING 0x10
  27. #define SUN6I_R_INTC_ENABLE 0x40
  28. /*
  29. * For deprecated sun6i-a31-sc-nmi compatible.
  30. * Registers are offset by 0x0c.
  31. */
  32. #define SUN6I_R_INTC_NMI_OFFSET 0x0c
  33. #define SUN6I_NMI_CTRL (SUN6I_R_INTC_CTRL - SUN6I_R_INTC_NMI_OFFSET)
  34. #define SUN6I_NMI_PENDING (SUN6I_R_INTC_PENDING - SUN6I_R_INTC_NMI_OFFSET)
  35. #define SUN6I_NMI_ENABLE (SUN6I_R_INTC_ENABLE - SUN6I_R_INTC_NMI_OFFSET)
  36. #define SUN7I_NMI_CTRL 0x00
  37. #define SUN7I_NMI_PENDING 0x04
  38. #define SUN7I_NMI_ENABLE 0x08
  39. #define SUN9I_NMI_CTRL 0x00
  40. #define SUN9I_NMI_ENABLE 0x04
  41. #define SUN9I_NMI_PENDING 0x08
  42. enum {
  43. SUNXI_SRC_TYPE_LEVEL_LOW = 0,
  44. SUNXI_SRC_TYPE_EDGE_FALLING,
  45. SUNXI_SRC_TYPE_LEVEL_HIGH,
  46. SUNXI_SRC_TYPE_EDGE_RISING,
  47. };
  48. struct sunxi_sc_nmi_reg_offs {
  49. u32 ctrl;
  50. u32 pend;
  51. u32 enable;
  52. };
  53. static const struct sunxi_sc_nmi_reg_offs sun6i_r_intc_reg_offs __initconst = {
  54. .ctrl = SUN6I_R_INTC_CTRL,
  55. .pend = SUN6I_R_INTC_PENDING,
  56. .enable = SUN6I_R_INTC_ENABLE,
  57. };
  58. static const struct sunxi_sc_nmi_reg_offs sun6i_reg_offs __initconst = {
  59. .ctrl = SUN6I_NMI_CTRL,
  60. .pend = SUN6I_NMI_PENDING,
  61. .enable = SUN6I_NMI_ENABLE,
  62. };
  63. static const struct sunxi_sc_nmi_reg_offs sun7i_reg_offs __initconst = {
  64. .ctrl = SUN7I_NMI_CTRL,
  65. .pend = SUN7I_NMI_PENDING,
  66. .enable = SUN7I_NMI_ENABLE,
  67. };
  68. static const struct sunxi_sc_nmi_reg_offs sun9i_reg_offs __initconst = {
  69. .ctrl = SUN9I_NMI_CTRL,
  70. .pend = SUN9I_NMI_PENDING,
  71. .enable = SUN9I_NMI_ENABLE,
  72. };
  73. static inline void sunxi_sc_nmi_write(struct irq_chip_generic *gc, u32 off,
  74. u32 val)
  75. {
  76. irq_reg_writel(gc, val, off);
  77. }
  78. static inline u32 sunxi_sc_nmi_read(struct irq_chip_generic *gc, u32 off)
  79. {
  80. return irq_reg_readl(gc, off);
  81. }
  82. static void sunxi_sc_nmi_handle_irq(struct irq_desc *desc)
  83. {
  84. struct irq_domain *domain = irq_desc_get_handler_data(desc);
  85. struct irq_chip *chip = irq_desc_get_chip(desc);
  86. unsigned int virq = irq_find_mapping(domain, 0);
  87. chained_irq_enter(chip, desc);
  88. generic_handle_irq(virq);
  89. chained_irq_exit(chip, desc);
  90. }
  91. static int sunxi_sc_nmi_set_type(struct irq_data *data, unsigned int flow_type)
  92. {
  93. struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
  94. struct irq_chip_type *ct = gc->chip_types;
  95. u32 src_type_reg;
  96. u32 ctrl_off = ct->regs.type;
  97. unsigned int src_type;
  98. unsigned int i;
  99. irq_gc_lock(gc);
  100. switch (flow_type & IRQF_TRIGGER_MASK) {
  101. case IRQ_TYPE_EDGE_FALLING:
  102. src_type = SUNXI_SRC_TYPE_EDGE_FALLING;
  103. break;
  104. case IRQ_TYPE_EDGE_RISING:
  105. src_type = SUNXI_SRC_TYPE_EDGE_RISING;
  106. break;
  107. case IRQ_TYPE_LEVEL_HIGH:
  108. src_type = SUNXI_SRC_TYPE_LEVEL_HIGH;
  109. break;
  110. case IRQ_TYPE_NONE:
  111. case IRQ_TYPE_LEVEL_LOW:
  112. src_type = SUNXI_SRC_TYPE_LEVEL_LOW;
  113. break;
  114. default:
  115. irq_gc_unlock(gc);
  116. pr_err("Cannot assign multiple trigger modes to IRQ %d.\n",
  117. data->irq);
  118. return -EBADR;
  119. }
  120. irqd_set_trigger_type(data, flow_type);
  121. irq_setup_alt_chip(data, flow_type);
  122. for (i = 0; i < gc->num_ct; i++, ct++)
  123. if (ct->type & flow_type)
  124. ctrl_off = ct->regs.type;
  125. src_type_reg = sunxi_sc_nmi_read(gc, ctrl_off);
  126. src_type_reg &= ~SUNXI_NMI_SRC_TYPE_MASK;
  127. src_type_reg |= src_type;
  128. sunxi_sc_nmi_write(gc, ctrl_off, src_type_reg);
  129. irq_gc_unlock(gc);
  130. return IRQ_SET_MASK_OK;
  131. }
  132. static int __init sunxi_sc_nmi_irq_init(struct device_node *node,
  133. const struct sunxi_sc_nmi_reg_offs *reg_offs)
  134. {
  135. struct irq_domain *domain;
  136. struct irq_chip_generic *gc;
  137. unsigned int irq;
  138. unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
  139. int ret;
  140. domain = irq_domain_add_linear(node, 1, &irq_generic_chip_ops, NULL);
  141. if (!domain) {
  142. pr_err("Could not register interrupt domain.\n");
  143. return -ENOMEM;
  144. }
  145. ret = irq_alloc_domain_generic_chips(domain, 1, 2, DRV_NAME,
  146. handle_fasteoi_irq, clr, 0,
  147. IRQ_GC_INIT_MASK_CACHE);
  148. if (ret) {
  149. pr_err("Could not allocate generic interrupt chip.\n");
  150. goto fail_irqd_remove;
  151. }
  152. irq = irq_of_parse_and_map(node, 0);
  153. if (irq <= 0) {
  154. pr_err("unable to parse irq\n");
  155. ret = -EINVAL;
  156. goto fail_irqd_remove;
  157. }
  158. gc = irq_get_domain_generic_chip(domain, 0);
  159. gc->reg_base = of_io_request_and_map(node, 0, of_node_full_name(node));
  160. if (IS_ERR(gc->reg_base)) {
  161. pr_err("unable to map resource\n");
  162. ret = PTR_ERR(gc->reg_base);
  163. goto fail_irqd_remove;
  164. }
  165. gc->chip_types[0].type = IRQ_TYPE_LEVEL_MASK;
  166. gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
  167. gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
  168. gc->chip_types[0].chip.irq_eoi = irq_gc_ack_set_bit;
  169. gc->chip_types[0].chip.irq_set_type = sunxi_sc_nmi_set_type;
  170. gc->chip_types[0].chip.flags = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED;
  171. gc->chip_types[0].regs.ack = reg_offs->pend;
  172. gc->chip_types[0].regs.mask = reg_offs->enable;
  173. gc->chip_types[0].regs.type = reg_offs->ctrl;
  174. gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH;
  175. gc->chip_types[1].chip.name = gc->chip_types[0].chip.name;
  176. gc->chip_types[1].chip.irq_ack = irq_gc_ack_set_bit;
  177. gc->chip_types[1].chip.irq_mask = irq_gc_mask_clr_bit;
  178. gc->chip_types[1].chip.irq_unmask = irq_gc_mask_set_bit;
  179. gc->chip_types[1].chip.irq_set_type = sunxi_sc_nmi_set_type;
  180. gc->chip_types[1].regs.ack = reg_offs->pend;
  181. gc->chip_types[1].regs.mask = reg_offs->enable;
  182. gc->chip_types[1].regs.type = reg_offs->ctrl;
  183. gc->chip_types[1].handler = handle_edge_irq;
  184. /* Disable any active interrupts */
  185. sunxi_sc_nmi_write(gc, reg_offs->enable, 0);
  186. /* Clear any pending NMI interrupts */
  187. sunxi_sc_nmi_write(gc, reg_offs->pend, SUNXI_NMI_IRQ_BIT);
  188. irq_set_chained_handler_and_data(irq, sunxi_sc_nmi_handle_irq, domain);
  189. return 0;
  190. fail_irqd_remove:
  191. irq_domain_remove(domain);
  192. return ret;
  193. }
  194. static int __init sun6i_r_intc_irq_init(struct device_node *node,
  195. struct device_node *parent)
  196. {
  197. return sunxi_sc_nmi_irq_init(node, &sun6i_r_intc_reg_offs);
  198. }
  199. IRQCHIP_DECLARE(sun6i_r_intc, "allwinner,sun6i-a31-r-intc",
  200. sun6i_r_intc_irq_init);
  201. static int __init sun6i_sc_nmi_irq_init(struct device_node *node,
  202. struct device_node *parent)
  203. {
  204. return sunxi_sc_nmi_irq_init(node, &sun6i_reg_offs);
  205. }
  206. IRQCHIP_DECLARE(sun6i_sc_nmi, "allwinner,sun6i-a31-sc-nmi", sun6i_sc_nmi_irq_init);
  207. static int __init sun7i_sc_nmi_irq_init(struct device_node *node,
  208. struct device_node *parent)
  209. {
  210. return sunxi_sc_nmi_irq_init(node, &sun7i_reg_offs);
  211. }
  212. IRQCHIP_DECLARE(sun7i_sc_nmi, "allwinner,sun7i-a20-sc-nmi", sun7i_sc_nmi_irq_init);
  213. static int __init sun9i_nmi_irq_init(struct device_node *node,
  214. struct device_node *parent)
  215. {
  216. return sunxi_sc_nmi_irq_init(node, &sun9i_reg_offs);
  217. }
  218. IRQCHIP_DECLARE(sun9i_nmi, "allwinner,sun9i-a80-nmi", sun9i_nmi_irq_init);