intc2.c 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. /*
  2. * Interrupt handling for INTC2-based IRQ.
  3. *
  4. * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
  5. * Copyright (C) 2005, 2006 Paul Mundt (lethal@linux-sh.org)
  6. *
  7. * May be copied or modified under the terms of the GNU General Public
  8. * License. See linux/COPYING for more information.
  9. *
  10. * These are the "new Hitachi style" interrupts, as present on the
  11. * Hitachi 7751, the STM ST40 STB1, SH7760, and SH7780.
  12. */
  13. #include <linux/kernel.h>
  14. #include <linux/interrupt.h>
  15. #include <linux/io.h>
  16. static inline struct intc2_desc *get_intc2_desc(unsigned int irq)
  17. {
  18. struct irq_chip *chip = get_irq_chip(irq);
  19. return (void *)((char *)chip - offsetof(struct intc2_desc, chip));
  20. }
  21. static void disable_intc2_irq(unsigned int irq)
  22. {
  23. struct intc2_data *p = get_irq_chip_data(irq);
  24. struct intc2_desc *d = get_intc2_desc(irq);
  25. ctrl_outl(1 << p->msk_shift, d->msk_base + p->msk_offset);
  26. }
  27. static void enable_intc2_irq(unsigned int irq)
  28. {
  29. struct intc2_data *p = get_irq_chip_data(irq);
  30. struct intc2_desc *d = get_intc2_desc(irq);
  31. ctrl_outl(1 << p->msk_shift, d->mskclr_base + p->msk_offset);
  32. }
  33. /*
  34. * Setup an INTC2 style interrupt.
  35. * NOTE: Unlike IPR interrupts, parameters are not shifted by this code,
  36. * allowing the use of the numbers straight out of the datasheet.
  37. * For example:
  38. * PIO1 which is INTPRI00[19,16] and INTMSK00[13]
  39. * would be: ^ ^ ^ ^
  40. * | | | |
  41. * { 84, 0, 16, 0, 13 },
  42. *
  43. * in the intc2_data table.
  44. */
  45. void register_intc2_controller(struct intc2_desc *desc)
  46. {
  47. int i;
  48. desc->chip.mask = disable_intc2_irq;
  49. desc->chip.unmask = enable_intc2_irq;
  50. desc->chip.mask_ack = disable_intc2_irq;
  51. for (i = 0; i < desc->nr_irqs; i++) {
  52. unsigned long ipr, flags;
  53. struct intc2_data *p = desc->intc2_data + i;
  54. disable_irq_nosync(p->irq);
  55. if (desc->prio_base) {
  56. /* Set the priority level */
  57. local_irq_save(flags);
  58. ipr = ctrl_inl(desc->prio_base + p->ipr_offset);
  59. ipr &= ~(0xf << p->ipr_shift);
  60. ipr |= p->priority << p->ipr_shift;
  61. ctrl_outl(ipr, desc->prio_base + p->ipr_offset);
  62. local_irq_restore(flags);
  63. }
  64. set_irq_chip_and_handler_name(p->irq, &desc->chip,
  65. handle_level_irq, "level");
  66. set_irq_chip_data(p->irq, p);
  67. disable_intc2_irq(p->irq);
  68. }
  69. }