extint.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /*
  2. * External interrupt handling for AT32AP CPUs
  3. *
  4. * Copyright (C) 2006 Atmel Corporation
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation.
  9. */
  10. #include <linux/errno.h>
  11. #include <linux/init.h>
  12. #include <linux/interrupt.h>
  13. #include <linux/irq.h>
  14. #include <linux/platform_device.h>
  15. #include <linux/random.h>
  16. #include <asm/io.h>
  17. #include <asm/arch/sm.h>
  18. #include "sm.h"
  19. static void eim_ack_irq(unsigned int irq)
  20. {
  21. struct at32_sm *sm = get_irq_chip_data(irq);
  22. sm_writel(sm, EIM_ICR, 1 << (irq - sm->eim_first_irq));
  23. }
  24. static void eim_mask_irq(unsigned int irq)
  25. {
  26. struct at32_sm *sm = get_irq_chip_data(irq);
  27. sm_writel(sm, EIM_IDR, 1 << (irq - sm->eim_first_irq));
  28. }
  29. static void eim_mask_ack_irq(unsigned int irq)
  30. {
  31. struct at32_sm *sm = get_irq_chip_data(irq);
  32. sm_writel(sm, EIM_ICR, 1 << (irq - sm->eim_first_irq));
  33. sm_writel(sm, EIM_IDR, 1 << (irq - sm->eim_first_irq));
  34. }
  35. static void eim_unmask_irq(unsigned int irq)
  36. {
  37. struct at32_sm *sm = get_irq_chip_data(irq);
  38. sm_writel(sm, EIM_IER, 1 << (irq - sm->eim_first_irq));
  39. }
  40. static int eim_set_irq_type(unsigned int irq, unsigned int flow_type)
  41. {
  42. struct at32_sm *sm = get_irq_chip_data(irq);
  43. struct irq_desc *desc;
  44. unsigned int i = irq - sm->eim_first_irq;
  45. u32 mode, edge, level;
  46. unsigned long flags;
  47. int ret = 0;
  48. flow_type &= IRQ_TYPE_SENSE_MASK;
  49. if (flow_type == IRQ_TYPE_NONE)
  50. flow_type = IRQ_TYPE_LEVEL_LOW;
  51. desc = &irq_desc[irq];
  52. spin_lock_irqsave(&sm->lock, flags);
  53. mode = sm_readl(sm, EIM_MODE);
  54. edge = sm_readl(sm, EIM_EDGE);
  55. level = sm_readl(sm, EIM_LEVEL);
  56. switch (flow_type) {
  57. case IRQ_TYPE_LEVEL_LOW:
  58. mode |= 1 << i;
  59. level &= ~(1 << i);
  60. break;
  61. case IRQ_TYPE_LEVEL_HIGH:
  62. mode |= 1 << i;
  63. level |= 1 << i;
  64. break;
  65. case IRQ_TYPE_EDGE_RISING:
  66. mode &= ~(1 << i);
  67. edge |= 1 << i;
  68. break;
  69. case IRQ_TYPE_EDGE_FALLING:
  70. mode &= ~(1 << i);
  71. edge &= ~(1 << i);
  72. break;
  73. default:
  74. ret = -EINVAL;
  75. break;
  76. }
  77. if (ret == 0) {
  78. sm_writel(sm, EIM_MODE, mode);
  79. sm_writel(sm, EIM_EDGE, edge);
  80. sm_writel(sm, EIM_LEVEL, level);
  81. if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
  82. flow_type |= IRQ_LEVEL;
  83. desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
  84. desc->status |= flow_type;
  85. }
  86. spin_unlock_irqrestore(&sm->lock, flags);
  87. return ret;
  88. }
  89. struct irq_chip eim_chip = {
  90. .name = "eim",
  91. .ack = eim_ack_irq,
  92. .mask = eim_mask_irq,
  93. .mask_ack = eim_mask_ack_irq,
  94. .unmask = eim_unmask_irq,
  95. .set_type = eim_set_irq_type,
  96. };
  97. static void demux_eim_irq(unsigned int irq, struct irq_desc *desc)
  98. {
  99. struct at32_sm *sm = desc->handler_data;
  100. struct irq_desc *ext_desc;
  101. unsigned long status, pending;
  102. unsigned int i, ext_irq;
  103. status = sm_readl(sm, EIM_ISR);
  104. pending = status & sm_readl(sm, EIM_IMR);
  105. while (pending) {
  106. i = fls(pending) - 1;
  107. pending &= ~(1 << i);
  108. ext_irq = i + sm->eim_first_irq;
  109. ext_desc = irq_desc + ext_irq;
  110. if (ext_desc->status & IRQ_LEVEL)
  111. handle_level_irq(ext_irq, ext_desc);
  112. else
  113. handle_edge_irq(ext_irq, ext_desc);
  114. }
  115. }
  116. static int __init eim_init(void)
  117. {
  118. struct at32_sm *sm = &system_manager;
  119. unsigned int i;
  120. unsigned int nr_irqs;
  121. unsigned int int_irq;
  122. u32 pattern;
  123. /*
  124. * The EIM is really the same module as SM, so register
  125. * mapping, etc. has been taken care of already.
  126. */
  127. /*
  128. * Find out how many interrupt lines that are actually
  129. * implemented in hardware.
  130. */
  131. sm_writel(sm, EIM_IDR, ~0UL);
  132. sm_writel(sm, EIM_MODE, ~0UL);
  133. pattern = sm_readl(sm, EIM_MODE);
  134. nr_irqs = fls(pattern);
  135. /* Trigger on falling edge unless overridden by driver */
  136. sm_writel(sm, EIM_MODE, 0UL);
  137. sm_writel(sm, EIM_EDGE, 0UL);
  138. sm->eim_chip = &eim_chip;
  139. for (i = 0; i < nr_irqs; i++) {
  140. /* NOTE the handler we set here is ignored by the demux */
  141. set_irq_chip_and_handler(sm->eim_first_irq + i, &eim_chip,
  142. handle_level_irq);
  143. set_irq_chip_data(sm->eim_first_irq + i, sm);
  144. }
  145. int_irq = platform_get_irq_byname(sm->pdev, "eim");
  146. set_irq_chained_handler(int_irq, demux_eim_irq);
  147. set_irq_data(int_irq, sm);
  148. printk("EIM: External Interrupt Module at 0x%p, IRQ %u\n",
  149. sm->regs, int_irq);
  150. printk("EIM: Handling %u external IRQs, starting with IRQ %u\n",
  151. nr_irqs, sm->eim_first_irq);
  152. return 0;
  153. }
  154. arch_initcall(eim_init);