Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'irqchip/atmel-aic' into irqchip/core

Topic branch set up to facilitate merging the rest of the series which
removes the driver from arch code.

+929 -2
Documentation/devicetree/bindings/arm/atmel-aic.txt Documentation/devicetree/bindings/interrupt-controller/atmel,aic.txt
+14
drivers/irqchip/Kconfig
··· 35 35 The maximum number of VICs available in the system, for 36 36 power management. 37 37 38 + config ATMEL_AIC_IRQ 39 + bool 40 + select GENERIC_IRQ_CHIP 41 + select IRQ_DOMAIN 42 + select MULTI_IRQ_HANDLER 43 + select SPARSE_IRQ 44 + 45 + config ATMEL_AIC5_IRQ 46 + bool 47 + select GENERIC_IRQ_CHIP 48 + select IRQ_DOMAIN 49 + select MULTI_IRQ_HANDLER 50 + select SPARSE_IRQ 51 + 38 52 config BRCMSTB_L2_IRQ 39 53 bool 40 54 depends on ARM
+2
drivers/irqchip/Makefile
··· 20 20 obj-$(CONFIG_ARM_GIC_V3) += irq-gic-v3.o irq-gic-common.o 21 21 obj-$(CONFIG_ARM_NVIC) += irq-nvic.o 22 22 obj-$(CONFIG_ARM_VIC) += irq-vic.o 23 + obj-$(CONFIG_ATMEL_AIC_IRQ) += irq-atmel-aic-common.o irq-atmel-aic.o 24 + obj-$(CONFIG_ATMEL_AIC5_IRQ) += irq-atmel-aic-common.o irq-atmel-aic5.o 23 25 obj-$(CONFIG_IMGPDC_IRQ) += irq-imgpdc.o 24 26 obj-$(CONFIG_SIRF_IRQ) += irq-sirfsoc.o 25 27 obj-$(CONFIG_RENESAS_INTC_IRQPIN) += irq-renesas-intc-irqpin.o
+254
drivers/irqchip/irq-atmel-aic-common.c
··· 1 + /* 2 + * Atmel AT91 common AIC (Advanced Interrupt Controller) code shared by 3 + * irq-atmel-aic and irq-atmel-aic5 drivers 4 + * 5 + * Copyright (C) 2004 SAN People 6 + * Copyright (C) 2004 ATMEL 7 + * Copyright (C) Rick Bronson 8 + * Copyright (C) 2014 Free Electrons 9 + * 10 + * Author: Boris BREZILLON <boris.brezillon@free-electrons.com> 11 + * 12 + * This file is licensed under the terms of the GNU General Public 13 + * License version 2. This program is licensed "as is" without any 14 + * warranty of any kind, whether express or implied. 15 + */ 16 + 17 + #include <linux/errno.h> 18 + #include <linux/io.h> 19 + #include <linux/irq.h> 20 + #include <linux/irqdomain.h> 21 + #include <linux/of.h> 22 + #include <linux/of_address.h> 23 + #include <linux/slab.h> 24 + 25 + #include "irq-atmel-aic-common.h" 26 + 27 + #define AT91_AIC_PRIOR GENMASK(2, 0) 28 + #define AT91_AIC_IRQ_MIN_PRIORITY 0 29 + #define AT91_AIC_IRQ_MAX_PRIORITY 7 30 + 31 + #define AT91_AIC_SRCTYPE GENMASK(7, 6) 32 + #define AT91_AIC_SRCTYPE_LOW (0 << 5) 33 + #define AT91_AIC_SRCTYPE_FALLING (1 << 5) 34 + #define AT91_AIC_SRCTYPE_HIGH (2 << 5) 35 + #define AT91_AIC_SRCTYPE_RISING (3 << 5) 36 + 37 + struct aic_chip_data { 38 + u32 ext_irqs; 39 + }; 40 + 41 + static void aic_common_shutdown(struct irq_data *d) 42 + { 43 + struct irq_chip_type *ct = irq_data_get_chip_type(d); 44 + 45 + ct->chip.irq_mask(d); 46 + } 47 + 48 + int aic_common_set_type(struct irq_data *d, unsigned type, unsigned *val) 49 + { 50 + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 51 + struct aic_chip_data *aic = gc->private; 52 + unsigned aic_type; 53 + 54 + switch (type) { 55 + case IRQ_TYPE_LEVEL_HIGH: 56 + aic_type = AT91_AIC_SRCTYPE_HIGH; 57 + break; 58 + case IRQ_TYPE_EDGE_RISING: 59 + aic_type = AT91_AIC_SRCTYPE_RISING; 60 + break; 61 + case IRQ_TYPE_LEVEL_LOW: 62 + if (!(d->mask & aic->ext_irqs)) 63 + return -EINVAL; 64 + 65 + aic_type = AT91_AIC_SRCTYPE_LOW; 66 + break; 67 + case IRQ_TYPE_EDGE_FALLING: 68 + if (!(d->mask & aic->ext_irqs)) 69 + return -EINVAL; 70 + 71 + aic_type = AT91_AIC_SRCTYPE_FALLING; 72 + break; 73 + default: 74 + return -EINVAL; 75 + } 76 + 77 + *val &= AT91_AIC_SRCTYPE; 78 + *val |= aic_type; 79 + 80 + return 0; 81 + } 82 + 83 + int aic_common_set_priority(int priority, unsigned *val) 84 + { 85 + if (priority < AT91_AIC_IRQ_MIN_PRIORITY || 86 + priority > AT91_AIC_IRQ_MAX_PRIORITY) 87 + return -EINVAL; 88 + 89 + *val &= AT91_AIC_PRIOR; 90 + *val |= priority; 91 + 92 + return 0; 93 + } 94 + 95 + int aic_common_irq_domain_xlate(struct irq_domain *d, 96 + struct device_node *ctrlr, 97 + const u32 *intspec, 98 + unsigned int intsize, 99 + irq_hw_number_t *out_hwirq, 100 + unsigned int *out_type) 101 + { 102 + if (WARN_ON(intsize < 3)) 103 + return -EINVAL; 104 + 105 + if (WARN_ON((intspec[2] < AT91_AIC_IRQ_MIN_PRIORITY) || 106 + (intspec[2] > AT91_AIC_IRQ_MAX_PRIORITY))) 107 + return -EINVAL; 108 + 109 + *out_hwirq = intspec[0]; 110 + *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK; 111 + 112 + return 0; 113 + } 114 + 115 + static void __init aic_common_ext_irq_of_init(struct irq_domain *domain) 116 + { 117 + struct device_node *node = domain->of_node; 118 + struct irq_chip_generic *gc; 119 + struct aic_chip_data *aic; 120 + struct property *prop; 121 + const __be32 *p; 122 + u32 hwirq; 123 + 124 + gc = irq_get_domain_generic_chip(domain, 0); 125 + 126 + aic = gc->private; 127 + aic->ext_irqs |= 1; 128 + 129 + of_property_for_each_u32(node, "atmel,external-irqs", prop, p, hwirq) { 130 + gc = irq_get_domain_generic_chip(domain, hwirq); 131 + if (!gc) { 132 + pr_warn("AIC: external irq %d >= %d skip it\n", 133 + hwirq, domain->revmap_size); 134 + continue; 135 + } 136 + 137 + aic = gc->private; 138 + aic->ext_irqs |= (1 << (hwirq % 32)); 139 + } 140 + } 141 + 142 + #define AT91_RTC_IDR 0x24 143 + #define AT91_RTC_IMR 0x28 144 + #define AT91_RTC_IRQ_MASK 0x1f 145 + 146 + void __init aic_common_rtc_irq_fixup(struct device_node *root) 147 + { 148 + struct device_node *np; 149 + void __iomem *regs; 150 + 151 + np = of_find_compatible_node(root, NULL, "atmel,at91rm9200-rtc"); 152 + if (!np) 153 + np = of_find_compatible_node(root, NULL, 154 + "atmel,at91sam9x5-rtc"); 155 + 156 + if (!np) 157 + return; 158 + 159 + regs = of_iomap(np, 0); 160 + of_node_put(np); 161 + 162 + if (!regs) 163 + return; 164 + 165 + writel(AT91_RTC_IRQ_MASK, regs + AT91_RTC_IDR); 166 + 167 + iounmap(regs); 168 + } 169 + 170 + void __init aic_common_irq_fixup(const struct of_device_id *matches) 171 + { 172 + struct device_node *root = of_find_node_by_path("/"); 173 + const struct of_device_id *match; 174 + 175 + if (!root) 176 + return; 177 + 178 + match = of_match_node(matches, root); 179 + of_node_put(root); 180 + 181 + if (match) { 182 + void (*fixup)(struct device_node *) = match->data; 183 + fixup(root); 184 + } 185 + 186 + of_node_put(root); 187 + } 188 + 189 + struct irq_domain *__init aic_common_of_init(struct device_node *node, 190 + const struct irq_domain_ops *ops, 191 + const char *name, int nirqs) 192 + { 193 + struct irq_chip_generic *gc; 194 + struct irq_domain *domain; 195 + struct aic_chip_data *aic; 196 + void __iomem *reg_base; 197 + int nchips; 198 + int ret; 199 + int i; 200 + 201 + nchips = DIV_ROUND_UP(nirqs, 32); 202 + 203 + reg_base = of_iomap(node, 0); 204 + if (!reg_base) 205 + return ERR_PTR(-ENOMEM); 206 + 207 + aic = kcalloc(nchips, sizeof(*aic), GFP_KERNEL); 208 + if (!aic) { 209 + ret = -ENOMEM; 210 + goto err_iounmap; 211 + } 212 + 213 + domain = irq_domain_add_linear(node, nchips * 32, ops, aic); 214 + if (!domain) { 215 + ret = -ENOMEM; 216 + goto err_free_aic; 217 + } 218 + 219 + ret = irq_alloc_domain_generic_chips(domain, 32, 1, name, 220 + handle_level_irq, 0, 0, 221 + IRQCHIP_SKIP_SET_WAKE); 222 + if (ret) 223 + goto err_domain_remove; 224 + 225 + for (i = 0; i < nchips; i++) { 226 + gc = irq_get_domain_generic_chip(domain, i * 32); 227 + 228 + gc->reg_base = reg_base; 229 + 230 + gc->unused = 0; 231 + gc->wake_enabled = ~0; 232 + gc->chip_types[0].type = IRQ_TYPE_SENSE_MASK; 233 + gc->chip_types[0].handler = handle_fasteoi_irq; 234 + gc->chip_types[0].chip.irq_eoi = irq_gc_eoi; 235 + gc->chip_types[0].chip.irq_set_wake = irq_gc_set_wake; 236 + gc->chip_types[0].chip.irq_shutdown = aic_common_shutdown; 237 + gc->private = &aic[i]; 238 + } 239 + 240 + aic_common_ext_irq_of_init(domain); 241 + 242 + return domain; 243 + 244 + err_domain_remove: 245 + irq_domain_remove(domain); 246 + 247 + err_free_aic: 248 + kfree(aic); 249 + 250 + err_iounmap: 251 + iounmap(reg_base); 252 + 253 + return ERR_PTR(ret); 254 + }
+39
drivers/irqchip/irq-atmel-aic-common.h
··· 1 + /* 2 + * Atmel AT91 common AIC (Advanced Interrupt Controller) header file 3 + * 4 + * Copyright (C) 2004 SAN People 5 + * Copyright (C) 2004 ATMEL 6 + * Copyright (C) Rick Bronson 7 + * Copyright (C) 2014 Free Electrons 8 + * 9 + * Author: Boris BREZILLON <boris.brezillon@free-electrons.com> 10 + * 11 + * This file is licensed under the terms of the GNU General Public 12 + * License version 2. This program is licensed "as is" without any 13 + * warranty of any kind, whether express or implied. 14 + */ 15 + 16 + #ifndef __IRQ_ATMEL_AIC_COMMON_H 17 + #define __IRQ_ATMEL_AIC_COMMON_H 18 + 19 + 20 + int aic_common_set_type(struct irq_data *d, unsigned type, unsigned *val); 21 + 22 + int aic_common_set_priority(int priority, unsigned *val); 23 + 24 + int aic_common_irq_domain_xlate(struct irq_domain *d, 25 + struct device_node *ctrlr, 26 + const u32 *intspec, 27 + unsigned int intsize, 28 + irq_hw_number_t *out_hwirq, 29 + unsigned int *out_type); 30 + 31 + struct irq_domain *__init aic_common_of_init(struct device_node *node, 32 + const struct irq_domain_ops *ops, 33 + const char *name, int nirqs); 34 + 35 + void __init aic_common_rtc_irq_fixup(struct device_node *root); 36 + 37 + void __init aic_common_irq_fixup(const struct of_device_id *matches); 38 + 39 + #endif /* __IRQ_ATMEL_AIC_COMMON_H */
+262
drivers/irqchip/irq-atmel-aic.c
··· 1 + /* 2 + * Atmel AT91 AIC (Advanced Interrupt Controller) driver 3 + * 4 + * Copyright (C) 2004 SAN People 5 + * Copyright (C) 2004 ATMEL 6 + * Copyright (C) Rick Bronson 7 + * Copyright (C) 2014 Free Electrons 8 + * 9 + * Author: Boris BREZILLON <boris.brezillon@free-electrons.com> 10 + * 11 + * This file is licensed under the terms of the GNU General Public 12 + * License version 2. This program is licensed "as is" without any 13 + * warranty of any kind, whether express or implied. 14 + */ 15 + 16 + #include <linux/init.h> 17 + #include <linux/module.h> 18 + #include <linux/mm.h> 19 + #include <linux/bitmap.h> 20 + #include <linux/types.h> 21 + #include <linux/irq.h> 22 + #include <linux/of.h> 23 + #include <linux/of_address.h> 24 + #include <linux/of_irq.h> 25 + #include <linux/irqdomain.h> 26 + #include <linux/err.h> 27 + #include <linux/slab.h> 28 + #include <linux/io.h> 29 + 30 + #include <asm/exception.h> 31 + #include <asm/mach/irq.h> 32 + 33 + #include "irq-atmel-aic-common.h" 34 + #include "irqchip.h" 35 + 36 + /* Number of irq lines managed by AIC */ 37 + #define NR_AIC_IRQS 32 38 + 39 + #define AT91_AIC_SMR(n) ((n) * 4) 40 + 41 + #define AT91_AIC_SVR(n) (0x80 + ((n) * 4)) 42 + #define AT91_AIC_IVR 0x100 43 + #define AT91_AIC_FVR 0x104 44 + #define AT91_AIC_ISR 0x108 45 + 46 + #define AT91_AIC_IPR 0x10c 47 + #define AT91_AIC_IMR 0x110 48 + #define AT91_AIC_CISR 0x114 49 + 50 + #define AT91_AIC_IECR 0x120 51 + #define AT91_AIC_IDCR 0x124 52 + #define AT91_AIC_ICCR 0x128 53 + #define AT91_AIC_ISCR 0x12c 54 + #define AT91_AIC_EOICR 0x130 55 + #define AT91_AIC_SPU 0x134 56 + #define AT91_AIC_DCR 0x138 57 + 58 + static struct irq_domain *aic_domain; 59 + 60 + static asmlinkage void __exception_irq_entry 61 + aic_handle(struct pt_regs *regs) 62 + { 63 + struct irq_domain_chip_generic *dgc = aic_domain->gc; 64 + struct irq_chip_generic *gc = dgc->gc[0]; 65 + u32 irqnr; 66 + u32 irqstat; 67 + 68 + irqnr = irq_reg_readl(gc->reg_base + AT91_AIC_IVR); 69 + irqstat = irq_reg_readl(gc->reg_base + AT91_AIC_ISR); 70 + 71 + irqnr = irq_find_mapping(aic_domain, irqnr); 72 + 73 + if (!irqstat) 74 + irq_reg_writel(0, gc->reg_base + AT91_AIC_EOICR); 75 + else 76 + handle_IRQ(irqnr, regs); 77 + } 78 + 79 + static int aic_retrigger(struct irq_data *d) 80 + { 81 + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 82 + 83 + /* Enable interrupt on AIC5 */ 84 + irq_gc_lock(gc); 85 + irq_reg_writel(d->mask, gc->reg_base + AT91_AIC_ISCR); 86 + irq_gc_unlock(gc); 87 + 88 + return 0; 89 + } 90 + 91 + static int aic_set_type(struct irq_data *d, unsigned type) 92 + { 93 + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 94 + unsigned int smr; 95 + int ret; 96 + 97 + smr = irq_reg_readl(gc->reg_base + AT91_AIC_SMR(d->hwirq)); 98 + ret = aic_common_set_type(d, type, &smr); 99 + if (ret) 100 + return ret; 101 + 102 + irq_reg_writel(smr, gc->reg_base + AT91_AIC_SMR(d->hwirq)); 103 + 104 + return 0; 105 + } 106 + 107 + #ifdef CONFIG_PM 108 + static void aic_suspend(struct irq_data *d) 109 + { 110 + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 111 + 112 + irq_gc_lock(gc); 113 + irq_reg_writel(gc->mask_cache, gc->reg_base + AT91_AIC_IDCR); 114 + irq_reg_writel(gc->wake_active, gc->reg_base + AT91_AIC_IECR); 115 + irq_gc_unlock(gc); 116 + } 117 + 118 + static void aic_resume(struct irq_data *d) 119 + { 120 + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 121 + 122 + irq_gc_lock(gc); 123 + irq_reg_writel(gc->wake_active, gc->reg_base + AT91_AIC_IDCR); 124 + irq_reg_writel(gc->mask_cache, gc->reg_base + AT91_AIC_IECR); 125 + irq_gc_unlock(gc); 126 + } 127 + 128 + static void aic_pm_shutdown(struct irq_data *d) 129 + { 130 + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 131 + 132 + irq_gc_lock(gc); 133 + irq_reg_writel(0xffffffff, gc->reg_base + AT91_AIC_IDCR); 134 + irq_reg_writel(0xffffffff, gc->reg_base + AT91_AIC_ICCR); 135 + irq_gc_unlock(gc); 136 + } 137 + #else 138 + #define aic_suspend NULL 139 + #define aic_resume NULL 140 + #define aic_pm_shutdown NULL 141 + #endif /* CONFIG_PM */ 142 + 143 + static void __init aic_hw_init(struct irq_domain *domain) 144 + { 145 + struct irq_chip_generic *gc = irq_get_domain_generic_chip(domain, 0); 146 + int i; 147 + 148 + /* 149 + * Perform 8 End Of Interrupt Command to make sure AIC 150 + * will not Lock out nIRQ 151 + */ 152 + for (i = 0; i < 8; i++) 153 + irq_reg_writel(0, gc->reg_base + AT91_AIC_EOICR); 154 + 155 + /* 156 + * Spurious Interrupt ID in Spurious Vector Register. 157 + * When there is no current interrupt, the IRQ Vector Register 158 + * reads the value stored in AIC_SPU 159 + */ 160 + irq_reg_writel(0xffffffff, gc->reg_base + AT91_AIC_SPU); 161 + 162 + /* No debugging in AIC: Debug (Protect) Control Register */ 163 + irq_reg_writel(0, gc->reg_base + AT91_AIC_DCR); 164 + 165 + /* Disable and clear all interrupts initially */ 166 + irq_reg_writel(0xffffffff, gc->reg_base + AT91_AIC_IDCR); 167 + irq_reg_writel(0xffffffff, gc->reg_base + AT91_AIC_ICCR); 168 + 169 + for (i = 0; i < 32; i++) 170 + irq_reg_writel(i, gc->reg_base + AT91_AIC_SVR(i)); 171 + } 172 + 173 + static int aic_irq_domain_xlate(struct irq_domain *d, 174 + struct device_node *ctrlr, 175 + const u32 *intspec, unsigned int intsize, 176 + irq_hw_number_t *out_hwirq, 177 + unsigned int *out_type) 178 + { 179 + struct irq_domain_chip_generic *dgc = d->gc; 180 + struct irq_chip_generic *gc; 181 + unsigned smr; 182 + int idx; 183 + int ret; 184 + 185 + if (!dgc) 186 + return -EINVAL; 187 + 188 + ret = aic_common_irq_domain_xlate(d, ctrlr, intspec, intsize, 189 + out_hwirq, out_type); 190 + if (ret) 191 + return ret; 192 + 193 + idx = intspec[0] / dgc->irqs_per_chip; 194 + if (idx >= dgc->num_chips) 195 + return -EINVAL; 196 + 197 + gc = dgc->gc[idx]; 198 + 199 + irq_gc_lock(gc); 200 + smr = irq_reg_readl(gc->reg_base + AT91_AIC_SMR(*out_hwirq)); 201 + ret = aic_common_set_priority(intspec[2], &smr); 202 + if (!ret) 203 + irq_reg_writel(smr, gc->reg_base + AT91_AIC_SMR(*out_hwirq)); 204 + irq_gc_unlock(gc); 205 + 206 + return ret; 207 + } 208 + 209 + static const struct irq_domain_ops aic_irq_ops = { 210 + .map = irq_map_generic_chip, 211 + .xlate = aic_irq_domain_xlate, 212 + }; 213 + 214 + static void __init at91sam9_aic_irq_fixup(struct device_node *root) 215 + { 216 + aic_common_rtc_irq_fixup(root); 217 + } 218 + 219 + static const struct of_device_id __initdata aic_irq_fixups[] = { 220 + { .compatible = "atmel,at91sam9g45", .data = at91sam9_aic_irq_fixup }, 221 + { .compatible = "atmel,at91sam9n12", .data = at91sam9_aic_irq_fixup }, 222 + { .compatible = "atmel,at91sam9rl", .data = at91sam9_aic_irq_fixup }, 223 + { .compatible = "atmel,at91sam9x5", .data = at91sam9_aic_irq_fixup }, 224 + { /* sentinel */ }, 225 + }; 226 + 227 + static int __init aic_of_init(struct device_node *node, 228 + struct device_node *parent) 229 + { 230 + struct irq_chip_generic *gc; 231 + struct irq_domain *domain; 232 + 233 + if (aic_domain) 234 + return -EEXIST; 235 + 236 + domain = aic_common_of_init(node, &aic_irq_ops, "atmel-aic", 237 + NR_AIC_IRQS); 238 + if (IS_ERR(domain)) 239 + return PTR_ERR(domain); 240 + 241 + aic_common_irq_fixup(aic_irq_fixups); 242 + 243 + aic_domain = domain; 244 + gc = irq_get_domain_generic_chip(domain, 0); 245 + 246 + gc->chip_types[0].regs.eoi = AT91_AIC_EOICR; 247 + gc->chip_types[0].regs.enable = AT91_AIC_IECR; 248 + gc->chip_types[0].regs.disable = AT91_AIC_IDCR; 249 + gc->chip_types[0].chip.irq_mask = irq_gc_mask_disable_reg; 250 + gc->chip_types[0].chip.irq_unmask = irq_gc_unmask_enable_reg; 251 + gc->chip_types[0].chip.irq_retrigger = aic_retrigger; 252 + gc->chip_types[0].chip.irq_set_type = aic_set_type; 253 + gc->chip_types[0].chip.irq_suspend = aic_suspend; 254 + gc->chip_types[0].chip.irq_resume = aic_resume; 255 + gc->chip_types[0].chip.irq_pm_shutdown = aic_pm_shutdown; 256 + 257 + aic_hw_init(domain); 258 + set_handle_irq(aic_handle); 259 + 260 + return 0; 261 + } 262 + IRQCHIP_DECLARE(at91rm9200_aic, "atmel,at91rm9200-aic", aic_of_init);
+353
drivers/irqchip/irq-atmel-aic5.c
··· 1 + /* 2 + * Atmel AT91 AIC5 (Advanced Interrupt Controller) driver 3 + * 4 + * Copyright (C) 2004 SAN People 5 + * Copyright (C) 2004 ATMEL 6 + * Copyright (C) Rick Bronson 7 + * Copyright (C) 2014 Free Electrons 8 + * 9 + * Author: Boris BREZILLON <boris.brezillon@free-electrons.com> 10 + * 11 + * This file is licensed under the terms of the GNU General Public 12 + * License version 2. This program is licensed "as is" without any 13 + * warranty of any kind, whether express or implied. 14 + */ 15 + 16 + #include <linux/init.h> 17 + #include <linux/module.h> 18 + #include <linux/mm.h> 19 + #include <linux/bitmap.h> 20 + #include <linux/types.h> 21 + #include <linux/irq.h> 22 + #include <linux/of.h> 23 + #include <linux/of_address.h> 24 + #include <linux/of_irq.h> 25 + #include <linux/irqdomain.h> 26 + #include <linux/err.h> 27 + #include <linux/slab.h> 28 + #include <linux/io.h> 29 + 30 + #include <asm/exception.h> 31 + #include <asm/mach/irq.h> 32 + 33 + #include "irq-atmel-aic-common.h" 34 + #include "irqchip.h" 35 + 36 + /* Number of irq lines managed by AIC */ 37 + #define NR_AIC5_IRQS 128 38 + 39 + #define AT91_AIC5_SSR 0x0 40 + #define AT91_AIC5_INTSEL_MSK (0x7f << 0) 41 + 42 + #define AT91_AIC5_SMR 0x4 43 + 44 + #define AT91_AIC5_SVR 0x8 45 + #define AT91_AIC5_IVR 0x10 46 + #define AT91_AIC5_FVR 0x14 47 + #define AT91_AIC5_ISR 0x18 48 + 49 + #define AT91_AIC5_IPR0 0x20 50 + #define AT91_AIC5_IPR1 0x24 51 + #define AT91_AIC5_IPR2 0x28 52 + #define AT91_AIC5_IPR3 0x2c 53 + #define AT91_AIC5_IMR 0x30 54 + #define AT91_AIC5_CISR 0x34 55 + 56 + #define AT91_AIC5_IECR 0x40 57 + #define AT91_AIC5_IDCR 0x44 58 + #define AT91_AIC5_ICCR 0x48 59 + #define AT91_AIC5_ISCR 0x4c 60 + #define AT91_AIC5_EOICR 0x38 61 + #define AT91_AIC5_SPU 0x3c 62 + #define AT91_AIC5_DCR 0x6c 63 + 64 + #define AT91_AIC5_FFER 0x50 65 + #define AT91_AIC5_FFDR 0x54 66 + #define AT91_AIC5_FFSR 0x58 67 + 68 + static struct irq_domain *aic5_domain; 69 + 70 + static asmlinkage void __exception_irq_entry 71 + aic5_handle(struct pt_regs *regs) 72 + { 73 + struct irq_domain_chip_generic *dgc = aic5_domain->gc; 74 + struct irq_chip_generic *gc = dgc->gc[0]; 75 + u32 irqnr; 76 + u32 irqstat; 77 + 78 + irqnr = irq_reg_readl(gc->reg_base + AT91_AIC5_IVR); 79 + irqstat = irq_reg_readl(gc->reg_base + AT91_AIC5_ISR); 80 + 81 + irqnr = irq_find_mapping(aic5_domain, irqnr); 82 + 83 + if (!irqstat) 84 + irq_reg_writel(0, gc->reg_base + AT91_AIC5_EOICR); 85 + else 86 + handle_IRQ(irqnr, regs); 87 + } 88 + 89 + static void aic5_mask(struct irq_data *d) 90 + { 91 + struct irq_domain *domain = d->domain; 92 + struct irq_domain_chip_generic *dgc = domain->gc; 93 + struct irq_chip_generic *gc = dgc->gc[0]; 94 + 95 + /* Disable interrupt on AIC5 */ 96 + irq_gc_lock(gc); 97 + irq_reg_writel(d->hwirq, gc->reg_base + AT91_AIC5_SSR); 98 + irq_reg_writel(1, gc->reg_base + AT91_AIC5_IDCR); 99 + gc->mask_cache &= ~d->mask; 100 + irq_gc_unlock(gc); 101 + } 102 + 103 + static void aic5_unmask(struct irq_data *d) 104 + { 105 + struct irq_domain *domain = d->domain; 106 + struct irq_domain_chip_generic *dgc = domain->gc; 107 + struct irq_chip_generic *gc = dgc->gc[0]; 108 + 109 + /* Enable interrupt on AIC5 */ 110 + irq_gc_lock(gc); 111 + irq_reg_writel(d->hwirq, gc->reg_base + AT91_AIC5_SSR); 112 + irq_reg_writel(1, gc->reg_base + AT91_AIC5_IECR); 113 + gc->mask_cache |= d->mask; 114 + irq_gc_unlock(gc); 115 + } 116 + 117 + static int aic5_retrigger(struct irq_data *d) 118 + { 119 + struct irq_domain *domain = d->domain; 120 + struct irq_domain_chip_generic *dgc = domain->gc; 121 + struct irq_chip_generic *gc = dgc->gc[0]; 122 + 123 + /* Enable interrupt on AIC5 */ 124 + irq_gc_lock(gc); 125 + irq_reg_writel(d->hwirq, gc->reg_base + AT91_AIC5_SSR); 126 + irq_reg_writel(1, gc->reg_base + AT91_AIC5_ISCR); 127 + irq_gc_unlock(gc); 128 + 129 + return 0; 130 + } 131 + 132 + static int aic5_set_type(struct irq_data *d, unsigned type) 133 + { 134 + struct irq_domain *domain = d->domain; 135 + struct irq_domain_chip_generic *dgc = domain->gc; 136 + struct irq_chip_generic *gc = dgc->gc[0]; 137 + unsigned int smr; 138 + int ret; 139 + 140 + irq_gc_lock(gc); 141 + irq_reg_writel(d->hwirq, gc->reg_base + AT91_AIC5_SSR); 142 + smr = irq_reg_readl(gc->reg_base + AT91_AIC5_SMR); 143 + ret = aic_common_set_type(d, type, &smr); 144 + if (!ret) 145 + irq_reg_writel(smr, gc->reg_base + AT91_AIC5_SMR); 146 + irq_gc_unlock(gc); 147 + 148 + return ret; 149 + } 150 + 151 + #ifdef CONFIG_PM 152 + static void aic5_suspend(struct irq_data *d) 153 + { 154 + struct irq_domain *domain = d->domain; 155 + struct irq_domain_chip_generic *dgc = domain->gc; 156 + struct irq_chip_generic *bgc = dgc->gc[0]; 157 + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 158 + int i; 159 + u32 mask; 160 + 161 + irq_gc_lock(bgc); 162 + for (i = 0; i < dgc->irqs_per_chip; i++) { 163 + mask = 1 << i; 164 + if ((mask & gc->mask_cache) == (mask & gc->wake_active)) 165 + continue; 166 + 167 + irq_reg_writel(i + gc->irq_base, 168 + bgc->reg_base + AT91_AIC5_SSR); 169 + if (mask & gc->wake_active) 170 + irq_reg_writel(1, bgc->reg_base + AT91_AIC5_IECR); 171 + else 172 + irq_reg_writel(1, bgc->reg_base + AT91_AIC5_IDCR); 173 + } 174 + irq_gc_unlock(bgc); 175 + } 176 + 177 + static void aic5_resume(struct irq_data *d) 178 + { 179 + struct irq_domain *domain = d->domain; 180 + struct irq_domain_chip_generic *dgc = domain->gc; 181 + struct irq_chip_generic *bgc = dgc->gc[0]; 182 + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 183 + int i; 184 + u32 mask; 185 + 186 + irq_gc_lock(bgc); 187 + for (i = 0; i < dgc->irqs_per_chip; i++) { 188 + mask = 1 << i; 189 + if ((mask & gc->mask_cache) == (mask & gc->wake_active)) 190 + continue; 191 + 192 + irq_reg_writel(i + gc->irq_base, 193 + bgc->reg_base + AT91_AIC5_SSR); 194 + if (mask & gc->mask_cache) 195 + irq_reg_writel(1, bgc->reg_base + AT91_AIC5_IECR); 196 + else 197 + irq_reg_writel(1, bgc->reg_base + AT91_AIC5_IDCR); 198 + } 199 + irq_gc_unlock(bgc); 200 + } 201 + 202 + static void aic5_pm_shutdown(struct irq_data *d) 203 + { 204 + struct irq_domain *domain = d->domain; 205 + struct irq_domain_chip_generic *dgc = domain->gc; 206 + struct irq_chip_generic *bgc = dgc->gc[0]; 207 + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 208 + int i; 209 + 210 + irq_gc_lock(bgc); 211 + for (i = 0; i < dgc->irqs_per_chip; i++) { 212 + irq_reg_writel(i + gc->irq_base, 213 + bgc->reg_base + AT91_AIC5_SSR); 214 + irq_reg_writel(1, bgc->reg_base + AT91_AIC5_IDCR); 215 + irq_reg_writel(1, bgc->reg_base + AT91_AIC5_ICCR); 216 + } 217 + irq_gc_unlock(bgc); 218 + } 219 + #else 220 + #define aic5_suspend NULL 221 + #define aic5_resume NULL 222 + #define aic5_pm_shutdown NULL 223 + #endif /* CONFIG_PM */ 224 + 225 + static void __init aic5_hw_init(struct irq_domain *domain) 226 + { 227 + struct irq_chip_generic *gc = irq_get_domain_generic_chip(domain, 0); 228 + int i; 229 + 230 + /* 231 + * Perform 8 End Of Interrupt Command to make sure AIC 232 + * will not Lock out nIRQ 233 + */ 234 + for (i = 0; i < 8; i++) 235 + irq_reg_writel(0, gc->reg_base + AT91_AIC5_EOICR); 236 + 237 + /* 238 + * Spurious Interrupt ID in Spurious Vector Register. 239 + * When there is no current interrupt, the IRQ Vector Register 240 + * reads the value stored in AIC_SPU 241 + */ 242 + irq_reg_writel(0xffffffff, gc->reg_base + AT91_AIC5_SPU); 243 + 244 + /* No debugging in AIC: Debug (Protect) Control Register */ 245 + irq_reg_writel(0, gc->reg_base + AT91_AIC5_DCR); 246 + 247 + /* Disable and clear all interrupts initially */ 248 + for (i = 0; i < domain->revmap_size; i++) { 249 + irq_reg_writel(i, gc->reg_base + AT91_AIC5_SSR); 250 + irq_reg_writel(i, gc->reg_base + AT91_AIC5_SVR); 251 + irq_reg_writel(1, gc->reg_base + AT91_AIC5_IDCR); 252 + irq_reg_writel(1, gc->reg_base + AT91_AIC5_ICCR); 253 + } 254 + } 255 + 256 + static int aic5_irq_domain_xlate(struct irq_domain *d, 257 + struct device_node *ctrlr, 258 + const u32 *intspec, unsigned int intsize, 259 + irq_hw_number_t *out_hwirq, 260 + unsigned int *out_type) 261 + { 262 + struct irq_domain_chip_generic *dgc = d->gc; 263 + struct irq_chip_generic *gc; 264 + unsigned smr; 265 + int ret; 266 + 267 + if (!dgc) 268 + return -EINVAL; 269 + 270 + ret = aic_common_irq_domain_xlate(d, ctrlr, intspec, intsize, 271 + out_hwirq, out_type); 272 + if (ret) 273 + return ret; 274 + 275 + gc = dgc->gc[0]; 276 + 277 + irq_gc_lock(gc); 278 + irq_reg_writel(*out_hwirq, gc->reg_base + AT91_AIC5_SSR); 279 + smr = irq_reg_readl(gc->reg_base + AT91_AIC5_SMR); 280 + ret = aic_common_set_priority(intspec[2], &smr); 281 + if (!ret) 282 + irq_reg_writel(intspec[2] | smr, gc->reg_base + AT91_AIC5_SMR); 283 + irq_gc_unlock(gc); 284 + 285 + return ret; 286 + } 287 + 288 + static const struct irq_domain_ops aic5_irq_ops = { 289 + .map = irq_map_generic_chip, 290 + .xlate = aic5_irq_domain_xlate, 291 + }; 292 + 293 + static void __init sama5d3_aic_irq_fixup(struct device_node *root) 294 + { 295 + aic_common_rtc_irq_fixup(root); 296 + } 297 + 298 + static const struct of_device_id __initdata aic5_irq_fixups[] = { 299 + { .compatible = "atmel,sama5d3", .data = sama5d3_aic_irq_fixup }, 300 + { /* sentinel */ }, 301 + }; 302 + 303 + static int __init aic5_of_init(struct device_node *node, 304 + struct device_node *parent, 305 + int nirqs) 306 + { 307 + struct irq_chip_generic *gc; 308 + struct irq_domain *domain; 309 + int nchips; 310 + int i; 311 + 312 + if (nirqs > NR_AIC5_IRQS) 313 + return -EINVAL; 314 + 315 + if (aic5_domain) 316 + return -EEXIST; 317 + 318 + domain = aic_common_of_init(node, &aic5_irq_ops, "atmel-aic5", 319 + nirqs); 320 + if (IS_ERR(domain)) 321 + return PTR_ERR(domain); 322 + 323 + aic_common_irq_fixup(aic5_irq_fixups); 324 + 325 + aic5_domain = domain; 326 + nchips = aic5_domain->revmap_size / 32; 327 + for (i = 0; i < nchips; i++) { 328 + gc = irq_get_domain_generic_chip(domain, i * 32); 329 + 330 + gc->chip_types[0].regs.eoi = AT91_AIC5_EOICR; 331 + gc->chip_types[0].chip.irq_mask = aic5_mask; 332 + gc->chip_types[0].chip.irq_unmask = aic5_unmask; 333 + gc->chip_types[0].chip.irq_retrigger = aic5_retrigger; 334 + gc->chip_types[0].chip.irq_set_type = aic5_set_type; 335 + gc->chip_types[0].chip.irq_suspend = aic5_suspend; 336 + gc->chip_types[0].chip.irq_resume = aic5_resume; 337 + gc->chip_types[0].chip.irq_pm_shutdown = aic5_pm_shutdown; 338 + } 339 + 340 + aic5_hw_init(domain); 341 + set_handle_irq(aic5_handle); 342 + 343 + return 0; 344 + } 345 + 346 + #define NR_SAMA5D3_IRQS 50 347 + 348 + static int __init sama5d3_aic5_of_init(struct device_node *node, 349 + struct device_node *parent) 350 + { 351 + return aic5_of_init(node, parent, NR_SAMA5D3_IRQS); 352 + } 353 + IRQCHIP_DECLARE(sama5d3_aic5, "atmel,sama5d3-aic", sama5d3_aic5_of_init);
+2
include/linux/irq.h
··· 771 771 int irq_gc_set_wake(struct irq_data *d, unsigned int on); 772 772 773 773 /* Setup functions for irq_chip_generic */ 774 + int irq_map_generic_chip(struct irq_domain *d, unsigned int virq, 775 + irq_hw_number_t hw_irq); 774 776 struct irq_chip_generic * 775 777 irq_alloc_generic_chip(const char *name, int nr_ct, unsigned int irq_base, 776 778 void __iomem *reg_base, irq_flow_handler_t handler);
+3 -2
kernel/irq/generic-chip.c
··· 341 341 /* 342 342 * irq_map_generic_chip - Map a generic chip for an irq domain 343 343 */ 344 - static int irq_map_generic_chip(struct irq_domain *d, unsigned int virq, 345 - irq_hw_number_t hw_irq) 344 + int irq_map_generic_chip(struct irq_domain *d, unsigned int virq, 345 + irq_hw_number_t hw_irq) 346 346 { 347 347 struct irq_data *data = irq_get_irq_data(virq); 348 348 struct irq_domain_chip_generic *dgc = d->gc; ··· 394 394 irq_modify_status(virq, dgc->irq_flags_to_clear, dgc->irq_flags_to_set); 395 395 return 0; 396 396 } 397 + EXPORT_SYMBOL_GPL(irq_map_generic_chip); 397 398 398 399 struct irq_domain_ops irq_generic_chip_ops = { 399 400 .map = irq_map_generic_chip,