Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * irqchip for the Faraday Technology FTINTC010 Copyright (C) 2017 Linus
0004  * Walleij <linus.walleij@linaro.org>
0005  *
0006  * Based on arch/arm/mach-gemini/irq.c
0007  * Copyright (C) 2001-2006 Storlink, Corp.
0008  * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@gmail.com>
0009  */
0010 #include <linux/bitops.h>
0011 #include <linux/irq.h>
0012 #include <linux/io.h>
0013 #include <linux/irqchip.h>
0014 #include <linux/irqdomain.h>
0015 #include <linux/module.h>
0016 #include <linux/of.h>
0017 #include <linux/of_address.h>
0018 #include <linux/of_irq.h>
0019 #include <linux/cpu.h>
0020 
0021 #include <asm/exception.h>
0022 #include <asm/mach/irq.h>
0023 
0024 #define FT010_NUM_IRQS 32
0025 
0026 #define FT010_IRQ_SOURCE(base_addr) (base_addr + 0x00)
0027 #define FT010_IRQ_MASK(base_addr)   (base_addr + 0x04)
0028 #define FT010_IRQ_CLEAR(base_addr)  (base_addr + 0x08)
0029 /* Selects level- or edge-triggered */
0030 #define FT010_IRQ_MODE(base_addr)   (base_addr + 0x0C)
0031 /* Selects active low/high or falling/rising edge */
0032 #define FT010_IRQ_POLARITY(base_addr)   (base_addr + 0x10)
0033 #define FT010_IRQ_STATUS(base_addr) (base_addr + 0x14)
0034 #define FT010_FIQ_SOURCE(base_addr) (base_addr + 0x20)
0035 #define FT010_FIQ_MASK(base_addr)   (base_addr + 0x24)
0036 #define FT010_FIQ_CLEAR(base_addr)  (base_addr + 0x28)
0037 #define FT010_FIQ_MODE(base_addr)   (base_addr + 0x2C)
0038 #define FT010_FIQ_POLARITY(base_addr)   (base_addr + 0x30)
0039 #define FT010_FIQ_STATUS(base_addr) (base_addr + 0x34)
0040 
0041 /**
0042  * struct ft010_irq_data - irq data container for the Faraday IRQ controller
0043  * @base: memory offset in virtual memory
0044  * @chip: chip container for this instance
0045  * @domain: IRQ domain for this instance
0046  */
0047 struct ft010_irq_data {
0048     void __iomem *base;
0049     struct irq_chip chip;
0050     struct irq_domain *domain;
0051 };
0052 
0053 static void ft010_irq_mask(struct irq_data *d)
0054 {
0055     struct ft010_irq_data *f = irq_data_get_irq_chip_data(d);
0056     unsigned int mask;
0057 
0058     mask = readl(FT010_IRQ_MASK(f->base));
0059     mask &= ~BIT(irqd_to_hwirq(d));
0060     writel(mask, FT010_IRQ_MASK(f->base));
0061 }
0062 
0063 static void ft010_irq_unmask(struct irq_data *d)
0064 {
0065     struct ft010_irq_data *f = irq_data_get_irq_chip_data(d);
0066     unsigned int mask;
0067 
0068     mask = readl(FT010_IRQ_MASK(f->base));
0069     mask |= BIT(irqd_to_hwirq(d));
0070     writel(mask, FT010_IRQ_MASK(f->base));
0071 }
0072 
0073 static void ft010_irq_ack(struct irq_data *d)
0074 {
0075     struct ft010_irq_data *f = irq_data_get_irq_chip_data(d);
0076 
0077     writel(BIT(irqd_to_hwirq(d)), FT010_IRQ_CLEAR(f->base));
0078 }
0079 
0080 static int ft010_irq_set_type(struct irq_data *d, unsigned int trigger)
0081 {
0082     struct ft010_irq_data *f = irq_data_get_irq_chip_data(d);
0083     int offset = irqd_to_hwirq(d);
0084     u32 mode, polarity;
0085 
0086     mode = readl(FT010_IRQ_MODE(f->base));
0087     polarity = readl(FT010_IRQ_POLARITY(f->base));
0088 
0089     if (trigger & (IRQ_TYPE_LEVEL_LOW)) {
0090         irq_set_handler_locked(d, handle_level_irq);
0091         mode &= ~BIT(offset);
0092         polarity |= BIT(offset);
0093     } else if (trigger & (IRQ_TYPE_LEVEL_HIGH)) {
0094         irq_set_handler_locked(d, handle_level_irq);
0095         mode &= ~BIT(offset);
0096         polarity &= ~BIT(offset);
0097     } else if (trigger & IRQ_TYPE_EDGE_FALLING) {
0098         irq_set_handler_locked(d, handle_edge_irq);
0099         mode |= BIT(offset);
0100         polarity |= BIT(offset);
0101     } else if (trigger & IRQ_TYPE_EDGE_RISING) {
0102         irq_set_handler_locked(d, handle_edge_irq);
0103         mode |= BIT(offset);
0104         polarity &= ~BIT(offset);
0105     } else {
0106         irq_set_handler_locked(d, handle_bad_irq);
0107         pr_warn("Faraday IRQ: no supported trigger selected for line %d\n",
0108             offset);
0109     }
0110 
0111     writel(mode, FT010_IRQ_MODE(f->base));
0112     writel(polarity, FT010_IRQ_POLARITY(f->base));
0113 
0114     return 0;
0115 }
0116 
0117 static struct irq_chip ft010_irq_chip = {
0118     .name       = "FTINTC010",
0119     .irq_ack    = ft010_irq_ack,
0120     .irq_mask   = ft010_irq_mask,
0121     .irq_unmask = ft010_irq_unmask,
0122     .irq_set_type   = ft010_irq_set_type,
0123 };
0124 
0125 /* Local static for the IRQ entry call */
0126 static struct ft010_irq_data firq;
0127 
0128 asmlinkage void __exception_irq_entry ft010_irqchip_handle_irq(struct pt_regs *regs)
0129 {
0130     struct ft010_irq_data *f = &firq;
0131     int irq;
0132     u32 status;
0133 
0134     while ((status = readl(FT010_IRQ_STATUS(f->base)))) {
0135         irq = ffs(status) - 1;
0136         generic_handle_domain_irq(f->domain, irq);
0137     }
0138 }
0139 
0140 static int ft010_irqdomain_map(struct irq_domain *d, unsigned int irq,
0141                 irq_hw_number_t hwirq)
0142 {
0143     struct ft010_irq_data *f = d->host_data;
0144 
0145     irq_set_chip_data(irq, f);
0146     /* All IRQs should set up their type, flags as bad by default */
0147     irq_set_chip_and_handler(irq, &ft010_irq_chip, handle_bad_irq);
0148     irq_set_probe(irq);
0149 
0150     return 0;
0151 }
0152 
0153 static void ft010_irqdomain_unmap(struct irq_domain *d, unsigned int irq)
0154 {
0155     irq_set_chip_and_handler(irq, NULL, NULL);
0156     irq_set_chip_data(irq, NULL);
0157 }
0158 
0159 static const struct irq_domain_ops ft010_irqdomain_ops = {
0160     .map = ft010_irqdomain_map,
0161     .unmap = ft010_irqdomain_unmap,
0162     .xlate = irq_domain_xlate_onetwocell,
0163 };
0164 
0165 int __init ft010_of_init_irq(struct device_node *node,
0166                   struct device_node *parent)
0167 {
0168     struct ft010_irq_data *f = &firq;
0169 
0170     /*
0171      * Disable the idle handler by default since it is buggy
0172      * For more info see arch/arm/mach-gemini/idle.c
0173      */
0174     cpu_idle_poll_ctrl(true);
0175 
0176     f->base = of_iomap(node, 0);
0177     WARN(!f->base, "unable to map gemini irq registers\n");
0178 
0179     /* Disable all interrupts */
0180     writel(0, FT010_IRQ_MASK(f->base));
0181     writel(0, FT010_FIQ_MASK(f->base));
0182 
0183     f->domain = irq_domain_add_simple(node, FT010_NUM_IRQS, 0,
0184                       &ft010_irqdomain_ops, f);
0185     set_handle_irq(ft010_irqchip_handle_irq);
0186 
0187     return 0;
0188 }
0189 IRQCHIP_DECLARE(faraday, "faraday,ftintc010",
0190         ft010_of_init_irq);
0191 IRQCHIP_DECLARE(gemini, "cortina,gemini-interrupt-controller",
0192         ft010_of_init_irq);
0193 IRQCHIP_DECLARE(moxa, "moxa,moxart-ic",
0194         ft010_of_init_irq);