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 10 #include <linux/init.h> 11 #include <linux/interrupt.h> 12 #include <linux/irq.h> 13 #include <linux/irqchip.h> 14 #include <linux/irqdomain.h> 15 #include <linux/of_address.h> 16 17 #include <asm/exception.h> 18 19 #define RDA_INTC_FINALSTATUS 0x00 20 #define RDA_INTC_MASK_SET 0x08 21 #define RDA_INTC_MASK_CLR 0x0c 22 23 #define RDA_IRQ_MASK_ALL 0xFFFFFFFF 24 25 #define RDA_NR_IRQS 32 26 27 static void __iomem *rda_intc_base; 28 static struct irq_domain *rda_irq_domain; 29 30 static void rda_intc_mask_irq(struct irq_data *d) 31 { 32 writel_relaxed(BIT(d->hwirq), rda_intc_base + RDA_INTC_MASK_CLR); 33 } 34 35 static void rda_intc_unmask_irq(struct irq_data *d) 36 { 37 writel_relaxed(BIT(d->hwirq), rda_intc_base + RDA_INTC_MASK_SET); 38 } 39 40 static int rda_intc_set_type(struct irq_data *data, unsigned int flow_type) 41 { 42 /* Hardware supports only level triggered interrupts */ 43 if ((flow_type & (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW)) == flow_type) 44 return 0; 45 46 return -EINVAL; 47 } 48 49 static void __exception_irq_entry rda_handle_irq(struct pt_regs *regs) 50 { 51 u32 stat = readl_relaxed(rda_intc_base + RDA_INTC_FINALSTATUS); 52 u32 hwirq; 53 54 while (stat) { 55 hwirq = __fls(stat); 56 generic_handle_domain_irq(rda_irq_domain, hwirq); 57 stat &= ~BIT(hwirq); 58 } 59 } 60 61 static struct irq_chip rda_irq_chip = { 62 .name = "rda-intc", 63 .irq_mask = rda_intc_mask_irq, 64 .irq_unmask = rda_intc_unmask_irq, 65 .irq_set_type = rda_intc_set_type, 66 }; 67 68 static int rda_irq_map(struct irq_domain *d, 69 unsigned int virq, irq_hw_number_t hw) 70 { 71 irq_set_status_flags(virq, IRQ_LEVEL); 72 irq_set_chip_and_handler(virq, &rda_irq_chip, handle_level_irq); 73 irq_set_chip_data(virq, d->host_data); 74 irq_set_probe(virq); 75 76 return 0; 77 } 78 79 static const struct irq_domain_ops rda_irq_domain_ops = { 80 .map = rda_irq_map, 81 .xlate = irq_domain_xlate_onecell, 82 }; 83 84 static int __init rda8810_intc_init(struct device_node *node, 85 struct device_node *parent) 86 { 87 rda_intc_base = of_io_request_and_map(node, 0, "rda-intc"); 88 if (IS_ERR(rda_intc_base)) 89 return PTR_ERR(rda_intc_base); 90 91 /* Mask all interrupt sources */ 92 writel_relaxed(RDA_IRQ_MASK_ALL, rda_intc_base + RDA_INTC_MASK_CLR); 93 94 rda_irq_domain = irq_domain_create_linear(&node->fwnode, RDA_NR_IRQS, 95 &rda_irq_domain_ops, 96 rda_intc_base); 97 if (!rda_irq_domain) { 98 iounmap(rda_intc_base); 99 return -ENOMEM; 100 } 101 102 set_handle_irq(rda_handle_irq); 103 104 return 0; 105 } 106 107 IRQCHIP_DECLARE(rda_intc, "rda,8810pl-intc", rda8810_intc_init); 108