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