irq-rda-intc.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * RDA8810PL SoC irqchip driver
  4. *
  5. * Copyright RDA Microelectronics Company Limited
  6. * Copyright (c) 2017 Andreas Färber
  7. * Copyright (c) 2018 Manivannan Sadhasivam
  8. */
  9. #include <linux/init.h>
  10. #include <linux/interrupt.h>
  11. #include <linux/irq.h>
  12. #include <linux/irqchip.h>
  13. #include <linux/irqdomain.h>
  14. #include <linux/of_address.h>
  15. #include <asm/exception.h>
  16. #define RDA_INTC_FINALSTATUS 0x00
  17. #define RDA_INTC_MASK_SET 0x08
  18. #define RDA_INTC_MASK_CLR 0x0c
  19. #define RDA_IRQ_MASK_ALL 0xFFFFFFFF
  20. #define RDA_NR_IRQS 32
  21. static void __iomem *rda_intc_base;
  22. static struct irq_domain *rda_irq_domain;
  23. static void rda_intc_mask_irq(struct irq_data *d)
  24. {
  25. writel_relaxed(BIT(d->hwirq), rda_intc_base + RDA_INTC_MASK_CLR);
  26. }
  27. static void rda_intc_unmask_irq(struct irq_data *d)
  28. {
  29. writel_relaxed(BIT(d->hwirq), rda_intc_base + RDA_INTC_MASK_SET);
  30. }
  31. static int rda_intc_set_type(struct irq_data *data, unsigned int flow_type)
  32. {
  33. /* Hardware supports only level triggered interrupts */
  34. if ((flow_type & (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW)) == flow_type)
  35. return 0;
  36. return -EINVAL;
  37. }
  38. static void __exception_irq_entry rda_handle_irq(struct pt_regs *regs)
  39. {
  40. u32 stat = readl_relaxed(rda_intc_base + RDA_INTC_FINALSTATUS);
  41. u32 hwirq;
  42. while (stat) {
  43. hwirq = __fls(stat);
  44. handle_domain_irq(rda_irq_domain, hwirq, regs);
  45. stat &= ~BIT(hwirq);
  46. }
  47. }
  48. static struct irq_chip rda_irq_chip = {
  49. .name = "rda-intc",
  50. .irq_mask = rda_intc_mask_irq,
  51. .irq_unmask = rda_intc_unmask_irq,
  52. .irq_set_type = rda_intc_set_type,
  53. };
  54. static int rda_irq_map(struct irq_domain *d,
  55. unsigned int virq, irq_hw_number_t hw)
  56. {
  57. irq_set_status_flags(virq, IRQ_LEVEL);
  58. irq_set_chip_and_handler(virq, &rda_irq_chip, handle_level_irq);
  59. irq_set_chip_data(virq, d->host_data);
  60. irq_set_probe(virq);
  61. return 0;
  62. }
  63. static const struct irq_domain_ops rda_irq_domain_ops = {
  64. .map = rda_irq_map,
  65. .xlate = irq_domain_xlate_onecell,
  66. };
  67. static int __init rda8810_intc_init(struct device_node *node,
  68. struct device_node *parent)
  69. {
  70. rda_intc_base = of_io_request_and_map(node, 0, "rda-intc");
  71. if (IS_ERR(rda_intc_base))
  72. return PTR_ERR(rda_intc_base);
  73. /* Mask all interrupt sources */
  74. writel_relaxed(RDA_IRQ_MASK_ALL, rda_intc_base + RDA_INTC_MASK_CLR);
  75. rda_irq_domain = irq_domain_create_linear(&node->fwnode, RDA_NR_IRQS,
  76. &rda_irq_domain_ops,
  77. rda_intc_base);
  78. if (!rda_irq_domain) {
  79. iounmap(rda_intc_base);
  80. return -ENOMEM;
  81. }
  82. set_handle_irq(rda_handle_irq);
  83. return 0;
  84. }
  85. IRQCHIP_DECLARE(rda_intc, "rda,8810pl-intc", rda8810_intc_init);