cia.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  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. mach_irq = base->cia_irq;
  82. ints = cia_set_irq(base, CIA_ICR_ALL);
  83. amiga_custom.intreq = base->int_mask;
  84. for (; ints; mach_irq++, ints >>= 1) {
  85. if (ints & 1)
  86. generic_handle_irq(mach_irq);
  87. }
  88. return IRQ_HANDLED;
  89. }
  90. static void cia_irq_enable(struct irq_data *data)
  91. {
  92. unsigned int irq = data->irq;
  93. unsigned char mask;
  94. if (irq >= IRQ_AMIGA_CIAB) {
  95. mask = 1 << (irq - IRQ_AMIGA_CIAB);
  96. cia_set_irq(&ciab_base, mask);
  97. cia_able_irq(&ciab_base, CIA_ICR_SETCLR | mask);
  98. } else {
  99. mask = 1 << (irq - IRQ_AMIGA_CIAA);
  100. cia_set_irq(&ciaa_base, mask);
  101. cia_able_irq(&ciaa_base, CIA_ICR_SETCLR | mask);
  102. }
  103. }
  104. static void cia_irq_disable(struct irq_data *data)
  105. {
  106. unsigned int irq = data->irq;
  107. if (irq >= IRQ_AMIGA_CIAB)
  108. cia_able_irq(&ciab_base, 1 << (irq - IRQ_AMIGA_CIAB));
  109. else
  110. cia_able_irq(&ciaa_base, 1 << (irq - IRQ_AMIGA_CIAA));
  111. }
  112. static struct irq_chip cia_irq_chip = {
  113. .name = "cia",
  114. .irq_enable = cia_irq_enable,
  115. .irq_disable = cia_irq_disable,
  116. };
  117. /*
  118. * Override auto irq 2 & 6 and use them as general chain
  119. * for external interrupts, we link the CIA interrupt sources
  120. * into this chain.
  121. */
  122. static void auto_irq_enable(struct irq_data *data)
  123. {
  124. switch (data->irq) {
  125. case IRQ_AUTO_2:
  126. amiga_custom.intena = IF_SETCLR | IF_PORTS;
  127. break;
  128. case IRQ_AUTO_6:
  129. amiga_custom.intena = IF_SETCLR | IF_EXTER;
  130. break;
  131. }
  132. }
  133. static void auto_irq_disable(struct irq_data *data)
  134. {
  135. switch (data->irq) {
  136. case IRQ_AUTO_2:
  137. amiga_custom.intena = IF_PORTS;
  138. break;
  139. case IRQ_AUTO_6:
  140. amiga_custom.intena = IF_EXTER;
  141. break;
  142. }
  143. }
  144. static struct irq_chip auto_irq_chip = {
  145. .name = "auto",
  146. .irq_enable = auto_irq_enable,
  147. .irq_disable = auto_irq_disable,
  148. };
  149. void __init cia_init_IRQ(struct ciabase *base)
  150. {
  151. m68k_setup_irq_controller(&cia_irq_chip, handle_simple_irq,
  152. base->cia_irq, CIA_IRQS);
  153. /* clear any pending interrupt and turn off all interrupts */
  154. cia_set_irq(base, CIA_ICR_ALL);
  155. cia_able_irq(base, CIA_ICR_ALL);
  156. /* override auto int and install CIA handler */
  157. m68k_setup_irq_controller(&auto_irq_chip, handle_simple_irq,
  158. base->handler_irq, 1);
  159. m68k_irq_startup_irq(base->handler_irq);
  160. if (request_irq(base->handler_irq, cia_handler, IRQF_SHARED,
  161. base->name, base))
  162. pr_err("Couldn't register %s interrupt\n", base->name);
  163. }