shirq.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. /*
  2. * arch/arm/plat-spear/shirq.c
  3. *
  4. * SPEAr platform shared irq layer source file
  5. *
  6. * Copyright (C) 2009 ST Microelectronics
  7. * Viresh Kumar<viresh.kumar@st.com>
  8. *
  9. * This file is licensed under the terms of the GNU General Public
  10. * License version 2. This program is licensed "as is" without any
  11. * warranty of any kind, whether express or implied.
  12. */
  13. #include <linux/err.h>
  14. #include <linux/io.h>
  15. #include <linux/irq.h>
  16. #include <linux/spinlock.h>
  17. #include <plat/shirq.h>
  18. struct spear_shirq *shirq;
  19. static DEFINE_SPINLOCK(lock);
  20. static void shirq_irq_mask(struct irq_data *d)
  21. {
  22. struct spear_shirq *shirq = irq_data_get_irq_chip_data(d);
  23. u32 val, id = d->irq - shirq->dev_config[0].virq;
  24. unsigned long flags;
  25. if ((shirq->regs.enb_reg == -1) || shirq->dev_config[id].enb_mask == -1)
  26. return;
  27. spin_lock_irqsave(&lock, flags);
  28. val = readl(shirq->regs.base + shirq->regs.enb_reg);
  29. if (shirq->regs.reset_to_enb)
  30. val |= shirq->dev_config[id].enb_mask;
  31. else
  32. val &= ~(shirq->dev_config[id].enb_mask);
  33. writel(val, shirq->regs.base + shirq->regs.enb_reg);
  34. spin_unlock_irqrestore(&lock, flags);
  35. }
  36. static void shirq_irq_unmask(struct irq_data *d)
  37. {
  38. struct spear_shirq *shirq = irq_data_get_irq_chip_data(d);
  39. u32 val, id = d->irq - shirq->dev_config[0].virq;
  40. unsigned long flags;
  41. if ((shirq->regs.enb_reg == -1) || shirq->dev_config[id].enb_mask == -1)
  42. return;
  43. spin_lock_irqsave(&lock, flags);
  44. val = readl(shirq->regs.base + shirq->regs.enb_reg);
  45. if (shirq->regs.reset_to_enb)
  46. val &= ~(shirq->dev_config[id].enb_mask);
  47. else
  48. val |= shirq->dev_config[id].enb_mask;
  49. writel(val, shirq->regs.base + shirq->regs.enb_reg);
  50. spin_unlock_irqrestore(&lock, flags);
  51. }
  52. static struct irq_chip shirq_chip = {
  53. .name = "spear_shirq",
  54. .irq_ack = shirq_irq_mask,
  55. .irq_mask = shirq_irq_mask,
  56. .irq_unmask = shirq_irq_unmask,
  57. };
  58. static void shirq_handler(unsigned irq, struct irq_desc *desc)
  59. {
  60. u32 i, val, mask;
  61. struct spear_shirq *shirq = irq_get_handler_data(irq);
  62. desc->irq_data.chip->irq_ack(&desc->irq_data);
  63. while ((val = readl(shirq->regs.base + shirq->regs.status_reg) &
  64. shirq->regs.status_reg_mask)) {
  65. for (i = 0; (i < shirq->dev_count) && val; i++) {
  66. if (!(shirq->dev_config[i].status_mask & val))
  67. continue;
  68. generic_handle_irq(shirq->dev_config[i].virq);
  69. /* clear interrupt */
  70. val &= ~shirq->dev_config[i].status_mask;
  71. if ((shirq->regs.clear_reg == -1) ||
  72. shirq->dev_config[i].clear_mask == -1)
  73. continue;
  74. mask = readl(shirq->regs.base + shirq->regs.clear_reg);
  75. if (shirq->regs.reset_to_clear)
  76. mask &= ~shirq->dev_config[i].clear_mask;
  77. else
  78. mask |= shirq->dev_config[i].clear_mask;
  79. writel(mask, shirq->regs.base + shirq->regs.clear_reg);
  80. }
  81. }
  82. desc->irq_data.chip->irq_unmask(&desc->irq_data);
  83. }
  84. int spear_shirq_register(struct spear_shirq *shirq)
  85. {
  86. int i;
  87. if (!shirq || !shirq->dev_config || !shirq->regs.base)
  88. return -EFAULT;
  89. if (!shirq->dev_count)
  90. return -EINVAL;
  91. irq_set_chained_handler(shirq->irq, shirq_handler);
  92. for (i = 0; i < shirq->dev_count; i++) {
  93. irq_set_chip_and_handler(shirq->dev_config[i].virq,
  94. &shirq_chip, handle_simple_irq);
  95. set_irq_flags(shirq->dev_config[i].virq, IRQF_VALID);
  96. irq_set_chip_data(shirq->dev_config[i].virq, shirq);
  97. }
  98. irq_set_handler_data(shirq->irq, shirq);
  99. return 0;
  100. }