irq-mb93493.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. /* irq-mb93493.c: MB93493 companion chip interrupt handler
  2. *
  3. * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
  4. * Written by David Howells (dhowells@redhat.com)
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version
  9. * 2 of the License, or (at your option) any later version.
  10. */
  11. #include <linux/ptrace.h>
  12. #include <linux/errno.h>
  13. #include <linux/signal.h>
  14. #include <linux/sched.h>
  15. #include <linux/ioport.h>
  16. #include <linux/interrupt.h>
  17. #include <linux/init.h>
  18. #include <linux/irq.h>
  19. #include <linux/bitops.h>
  20. #include <asm/io.h>
  21. #include <asm/system.h>
  22. #include <asm/delay.h>
  23. #include <asm/irq.h>
  24. #include <asm/irc-regs.h>
  25. #include <asm/mb93493-irqs.h>
  26. #include <asm/mb93493-regs.h>
  27. #define IRQ_ROUTE_ONE(X) (X##_ROUTE << (X - IRQ_BASE_MB93493))
  28. #define IRQ_ROUTING \
  29. (IRQ_ROUTE_ONE(IRQ_MB93493_VDC) | \
  30. IRQ_ROUTE_ONE(IRQ_MB93493_VCC) | \
  31. IRQ_ROUTE_ONE(IRQ_MB93493_AUDIO_OUT) | \
  32. IRQ_ROUTE_ONE(IRQ_MB93493_I2C_0) | \
  33. IRQ_ROUTE_ONE(IRQ_MB93493_I2C_1) | \
  34. IRQ_ROUTE_ONE(IRQ_MB93493_USB) | \
  35. IRQ_ROUTE_ONE(IRQ_MB93493_LOCAL_BUS) | \
  36. IRQ_ROUTE_ONE(IRQ_MB93493_PCMCIA) | \
  37. IRQ_ROUTE_ONE(IRQ_MB93493_GPIO) | \
  38. IRQ_ROUTE_ONE(IRQ_MB93493_AUDIO_IN))
  39. /*
  40. * daughter board PIC operations
  41. * - there is no way to ACK interrupts in the MB93493 chip
  42. */
  43. static void frv_mb93493_mask(struct irq_data *d)
  44. {
  45. uint32_t iqsr;
  46. volatile void *piqsr;
  47. if (IRQ_ROUTING & (1 << (d->irq - IRQ_BASE_MB93493)))
  48. piqsr = __addr_MB93493_IQSR(1);
  49. else
  50. piqsr = __addr_MB93493_IQSR(0);
  51. iqsr = readl(piqsr);
  52. iqsr &= ~(1 << (d->irq - IRQ_BASE_MB93493 + 16));
  53. writel(iqsr, piqsr);
  54. }
  55. static void frv_mb93493_ack(struct irq_data *d)
  56. {
  57. }
  58. static void frv_mb93493_unmask(struct irq_data *d)
  59. {
  60. uint32_t iqsr;
  61. volatile void *piqsr;
  62. if (IRQ_ROUTING & (1 << (d->irq - IRQ_BASE_MB93493)))
  63. piqsr = __addr_MB93493_IQSR(1);
  64. else
  65. piqsr = __addr_MB93493_IQSR(0);
  66. iqsr = readl(piqsr);
  67. iqsr |= 1 << (d->irq - IRQ_BASE_MB93493 + 16);
  68. writel(iqsr, piqsr);
  69. }
  70. static struct irq_chip frv_mb93493_pic = {
  71. .name = "mb93093",
  72. .irq_ack = frv_mb93493_ack,
  73. .irq_mask = frv_mb93493_mask,
  74. .irq_mask_ack = frv_mb93493_mask,
  75. .irq_unmask = frv_mb93493_unmask,
  76. };
  77. /*
  78. * MB93493 PIC interrupt handler
  79. */
  80. static irqreturn_t mb93493_interrupt(int irq, void *_piqsr)
  81. {
  82. volatile void *piqsr = _piqsr;
  83. uint32_t iqsr;
  84. iqsr = readl(piqsr);
  85. iqsr = iqsr & (iqsr >> 16) & 0xffff;
  86. /* poll all the triggered IRQs */
  87. while (iqsr) {
  88. int irq;
  89. asm("scan %1,gr0,%0" : "=r"(irq) : "r"(iqsr));
  90. irq = 31 - irq;
  91. iqsr &= ~(1 << irq);
  92. generic_handle_irq(IRQ_BASE_MB93493 + irq);
  93. }
  94. return IRQ_HANDLED;
  95. }
  96. /*
  97. * define an interrupt action for each MB93493 PIC output
  98. * - use dev_id to indicate the MB93493 PIC input to output mappings
  99. */
  100. static struct irqaction mb93493_irq[2] = {
  101. [0] = {
  102. .handler = mb93493_interrupt,
  103. .flags = IRQF_DISABLED | IRQF_SHARED,
  104. .name = "mb93493.0",
  105. .dev_id = (void *) __addr_MB93493_IQSR(0),
  106. },
  107. [1] = {
  108. .handler = mb93493_interrupt,
  109. .flags = IRQF_DISABLED | IRQF_SHARED,
  110. .name = "mb93493.1",
  111. .dev_id = (void *) __addr_MB93493_IQSR(1),
  112. }
  113. };
  114. /*
  115. * initialise the motherboard MB93493's PIC
  116. */
  117. void __init mb93493_init(void)
  118. {
  119. int irq;
  120. for (irq = IRQ_BASE_MB93493 + 0; irq <= IRQ_BASE_MB93493 + 10; irq++)
  121. irq_set_chip_and_handler(irq, &frv_mb93493_pic,
  122. handle_edge_irq);
  123. /* the MB93493 drives external IRQ inputs on the CPU PIC */
  124. setup_irq(IRQ_CPU_MB93493_0, &mb93493_irq[0]);
  125. setup_irq(IRQ_CPU_MB93493_1, &mb93493_irq[1]);
  126. }