Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * RDA8810PL SoC irqchip driver
0004  *
0005  * Copyright RDA Microelectronics Company Limited
0006  * Copyright (c) 2017 Andreas Färber
0007  * Copyright (c) 2018 Manivannan Sadhasivam
0008  */
0009 
0010 #include <linux/init.h>
0011 #include <linux/interrupt.h>
0012 #include <linux/irq.h>
0013 #include <linux/irqchip.h>
0014 #include <linux/irqdomain.h>
0015 #include <linux/of_address.h>
0016 
0017 #include <asm/exception.h>
0018 
0019 #define RDA_INTC_FINALSTATUS    0x00
0020 #define RDA_INTC_MASK_SET   0x08
0021 #define RDA_INTC_MASK_CLR   0x0c
0022 
0023 #define RDA_IRQ_MASK_ALL    0xFFFFFFFF
0024 
0025 #define RDA_NR_IRQS 32
0026 
0027 static void __iomem *rda_intc_base;
0028 static struct irq_domain *rda_irq_domain;
0029 
0030 static void rda_intc_mask_irq(struct irq_data *d)
0031 {
0032     writel_relaxed(BIT(d->hwirq), rda_intc_base + RDA_INTC_MASK_CLR);
0033 }
0034 
0035 static void rda_intc_unmask_irq(struct irq_data *d)
0036 {
0037     writel_relaxed(BIT(d->hwirq), rda_intc_base + RDA_INTC_MASK_SET);
0038 }
0039 
0040 static int rda_intc_set_type(struct irq_data *data, unsigned int flow_type)
0041 {
0042     /* Hardware supports only level triggered interrupts */
0043     if ((flow_type & (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW)) == flow_type)
0044         return 0;
0045 
0046     return -EINVAL;
0047 }
0048 
0049 static void __exception_irq_entry rda_handle_irq(struct pt_regs *regs)
0050 {
0051     u32 stat = readl_relaxed(rda_intc_base + RDA_INTC_FINALSTATUS);
0052     u32 hwirq;
0053 
0054     while (stat) {
0055         hwirq = __fls(stat);
0056         generic_handle_domain_irq(rda_irq_domain, hwirq);
0057         stat &= ~BIT(hwirq);
0058     }
0059 }
0060 
0061 static struct irq_chip rda_irq_chip = {
0062     .name       = "rda-intc",
0063     .irq_mask   = rda_intc_mask_irq,
0064     .irq_unmask = rda_intc_unmask_irq,
0065     .irq_set_type   = rda_intc_set_type,
0066 };
0067 
0068 static int rda_irq_map(struct irq_domain *d,
0069                unsigned int virq, irq_hw_number_t hw)
0070 {
0071     irq_set_status_flags(virq, IRQ_LEVEL);
0072     irq_set_chip_and_handler(virq, &rda_irq_chip, handle_level_irq);
0073     irq_set_chip_data(virq, d->host_data);
0074     irq_set_probe(virq);
0075 
0076     return 0;
0077 }
0078 
0079 static const struct irq_domain_ops rda_irq_domain_ops = {
0080     .map = rda_irq_map,
0081     .xlate = irq_domain_xlate_onecell,
0082 };
0083 
0084 static int __init rda8810_intc_init(struct device_node *node,
0085                     struct device_node *parent)
0086 {
0087     rda_intc_base = of_io_request_and_map(node, 0, "rda-intc");
0088     if (IS_ERR(rda_intc_base))
0089         return PTR_ERR(rda_intc_base);
0090 
0091     /* Mask all interrupt sources */
0092     writel_relaxed(RDA_IRQ_MASK_ALL, rda_intc_base + RDA_INTC_MASK_CLR);
0093 
0094     rda_irq_domain = irq_domain_create_linear(&node->fwnode, RDA_NR_IRQS,
0095                           &rda_irq_domain_ops,
0096                           rda_intc_base);
0097     if (!rda_irq_domain) {
0098         iounmap(rda_intc_base);
0099         return -ENOMEM;
0100     }
0101 
0102     set_handle_irq(rda_handle_irq);
0103 
0104     return 0;
0105 }
0106 
0107 IRQCHIP_DECLARE(rda_intc, "rda,8810pl-intc", rda8810_intc_init);