cia.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. /*
  2. * linux/arch/m68k/amiga/cia.c - CIA support
  3. *
  4. * Copyright (C) 1996 Roman Zippel
  5. *
  6. * The concept of some functions bases on the original Amiga OS function
  7. *
  8. * This file is subject to the terms and conditions of the GNU General Public
  9. * License. See the file COPYING in the main directory of this archive
  10. * for more details.
  11. */
  12. #include <linux/types.h>
  13. #include <linux/kernel.h>
  14. #include <linux/sched.h>
  15. #include <linux/errno.h>
  16. #include <linux/kernel_stat.h>
  17. #include <linux/init.h>
  18. #include <linux/seq_file.h>
  19. #include <linux/interrupt.h>
  20. #include <linux/irq.h>
  21. #include <asm/irq.h>
  22. #include <asm/amigahw.h>
  23. #include <asm/amigaints.h>
  24. struct ciabase {
  25. volatile struct CIA *cia;
  26. unsigned char icr_mask, icr_data;
  27. unsigned short int_mask;
  28. int handler_irq, cia_irq, server_irq;
  29. char *name;
  30. } ciaa_base = {
  31. .cia = &ciaa,
  32. .int_mask = IF_PORTS,
  33. .handler_irq = IRQ_AMIGA_PORTS,
  34. .cia_irq = IRQ_AMIGA_CIAA,
  35. .name = "CIAA"
  36. }, ciab_base = {
  37. .cia = &ciab,
  38. .int_mask = IF_EXTER,
  39. .handler_irq = IRQ_AMIGA_EXTER,
  40. .cia_irq = IRQ_AMIGA_CIAB,
  41. .name = "CIAB"
  42. };
  43. /*
  44. * Cause or clear CIA interrupts, return old interrupt status.
  45. */
  46. unsigned char cia_set_irq(struct ciabase *base, unsigned char mask)
  47. {
  48. unsigned char old;
  49. old = (base->icr_data |= base->cia->icr);
  50. if (mask & CIA_ICR_SETCLR)
  51. base->icr_data |= mask;
  52. else
  53. base->icr_data &= ~mask;
  54. if (base->icr_data & base->icr_mask)
  55. amiga_custom.intreq = IF_SETCLR | base->int_mask;
  56. return old & base->icr_mask;
  57. }
  58. /*
  59. * Enable or disable CIA interrupts, return old interrupt mask,
  60. */
  61. unsigned char cia_able_irq(struct ciabase *base, unsigned char mask)
  62. {
  63. unsigned char old;
  64. old = base->icr_mask;
  65. base->icr_data |= base->cia->icr;
  66. base->cia->icr = mask;
  67. if (mask & CIA_ICR_SETCLR)
  68. base->icr_mask |= mask;
  69. else
  70. base->icr_mask &= ~mask;
  71. base->icr_mask &= CIA_ICR_ALL;
  72. if (base->icr_data & base->icr_mask)
  73. amiga_custom.intreq = IF_SETCLR | base->int_mask;
  74. return old;
  75. }
  76. static irqreturn_t cia_handler(int irq, void *dev_id)
  77. {
  78. struct ciabase *base = dev_id;
  79. int mach_irq;
  80. unsigned char ints;
  81. unsigned long flags;
  82. /* Interrupts get disabled while the timer irq flag is cleared and
  83. * the timer interrupt serviced.
  84. */
  85. mach_irq = base->cia_irq;
  86. local_irq_save(flags);
  87. ints = cia_set_irq(base, CIA_ICR_ALL);
  88. amiga_custom.intreq = base->int_mask;
  89. if (ints & 1)
  90. generic_handle_irq(mach_irq);
  91. local_irq_restore(flags);
  92. mach_irq++, ints >>= 1;
  93. for (; ints; mach_irq++, ints >>= 1) {
  94. if (ints & 1)
  95. generic_handle_irq(mach_irq);
  96. }
  97. return IRQ_HANDLED;
  98. }
  99. static void cia_irq_enable(struct irq_data *data)
  100. {
  101. unsigned int irq = data->irq;
  102. unsigned char mask;
  103. if (irq >= IRQ_AMIGA_CIAB) {
  104. mask = 1 << (irq - IRQ_AMIGA_CIAB);
  105. cia_set_irq(&ciab_base, mask);
  106. cia_able_irq(&ciab_base, CIA_ICR_SETCLR | mask);
  107. } else {
  108. mask = 1 << (irq - IRQ_AMIGA_CIAA);
  109. cia_set_irq(&ciaa_base, mask);
  110. cia_able_irq(&ciaa_base, CIA_ICR_SETCLR | mask);
  111. }
  112. }
  113. static void cia_irq_disable(struct irq_data *data)
  114. {
  115. unsigned int irq = data->irq;
  116. if (irq >= IRQ_AMIGA_CIAB)
  117. cia_able_irq(&ciab_base, 1 << (irq - IRQ_AMIGA_CIAB));
  118. else
  119. cia_able_irq(&ciaa_base, 1 << (irq - IRQ_AMIGA_CIAA));
  120. }
  121. static struct irq_chip cia_irq_chip = {
  122. .name = "cia",
  123. .irq_enable = cia_irq_enable,
  124. .irq_disable = cia_irq_disable,
  125. };
  126. /*
  127. * Override auto irq 2 & 6 and use them as general chain
  128. * for external interrupts, we link the CIA interrupt sources
  129. * into this chain.
  130. */
  131. static void auto_irq_enable(struct irq_data *data)
  132. {
  133. switch (data->irq) {
  134. case IRQ_AUTO_2:
  135. amiga_custom.intena = IF_SETCLR | IF_PORTS;
  136. break;
  137. case IRQ_AUTO_6:
  138. amiga_custom.intena = IF_SETCLR | IF_EXTER;
  139. break;
  140. }
  141. }
  142. static void auto_irq_disable(struct irq_data *data)
  143. {
  144. switch (data->irq) {
  145. case IRQ_AUTO_2:
  146. amiga_custom.intena = IF_PORTS;
  147. break;
  148. case IRQ_AUTO_6:
  149. amiga_custom.intena = IF_EXTER;
  150. break;
  151. }
  152. }
  153. static struct irq_chip auto_irq_chip = {
  154. .name = "auto",
  155. .irq_enable = auto_irq_enable,
  156. .irq_disable = auto_irq_disable,
  157. };
  158. void __init cia_init_IRQ(struct ciabase *base)
  159. {
  160. m68k_setup_irq_controller(&cia_irq_chip, handle_simple_irq,
  161. base->cia_irq, CIA_IRQS);
  162. /* clear any pending interrupt and turn off all interrupts */
  163. cia_set_irq(base, CIA_ICR_ALL);
  164. cia_able_irq(base, CIA_ICR_ALL);
  165. /* override auto int and install CIA handler */
  166. m68k_setup_irq_controller(&auto_irq_chip, handle_simple_irq,
  167. base->handler_irq, 1);
  168. m68k_irq_startup_irq(base->handler_irq);
  169. if (request_irq(base->handler_irq, cia_handler, IRQF_SHARED,
  170. base->name, base))
  171. pr_err("Couldn't register %s interrupt\n", base->name);
  172. }