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

Configure Feed

Select the types of activity you want to include in your feed.

at v6.12-rc6 273 lines 7.2 kB view raw
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/irqchip.h> 23#include <linux/of.h> 24#include <linux/of_address.h> 25#include <linux/of_irq.h> 26#include <linux/irqdomain.h> 27#include <linux/err.h> 28#include <linux/slab.h> 29#include <linux/io.h> 30 31#include <asm/exception.h> 32#include <asm/mach/irq.h> 33 34#include "irq-atmel-aic-common.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 58static struct irq_domain *aic_domain; 59 60static void __exception_irq_entry aic_handle(struct pt_regs *regs) 61{ 62 struct irq_domain_chip_generic *dgc = aic_domain->gc; 63 struct irq_chip_generic *gc = dgc->gc[0]; 64 u32 irqnr; 65 u32 irqstat; 66 67 irqnr = irq_reg_readl(gc, AT91_AIC_IVR); 68 irqstat = irq_reg_readl(gc, AT91_AIC_ISR); 69 70 if (!irqstat) 71 irq_reg_writel(gc, 0, AT91_AIC_EOICR); 72 else 73 generic_handle_domain_irq(aic_domain, irqnr); 74} 75 76static int aic_retrigger(struct irq_data *d) 77{ 78 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 79 80 /* Enable interrupt on AIC5 */ 81 irq_gc_lock(gc); 82 irq_reg_writel(gc, d->mask, AT91_AIC_ISCR); 83 irq_gc_unlock(gc); 84 85 return 1; 86} 87 88static int aic_set_type(struct irq_data *d, unsigned type) 89{ 90 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 91 unsigned int smr; 92 int ret; 93 94 smr = irq_reg_readl(gc, AT91_AIC_SMR(d->hwirq)); 95 ret = aic_common_set_type(d, type, &smr); 96 if (ret) 97 return ret; 98 99 irq_reg_writel(gc, smr, AT91_AIC_SMR(d->hwirq)); 100 101 return 0; 102} 103 104#ifdef CONFIG_PM 105static void aic_suspend(struct irq_data *d) 106{ 107 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 108 109 irq_gc_lock(gc); 110 irq_reg_writel(gc, gc->mask_cache, AT91_AIC_IDCR); 111 irq_reg_writel(gc, gc->wake_active, AT91_AIC_IECR); 112 irq_gc_unlock(gc); 113} 114 115static void aic_resume(struct irq_data *d) 116{ 117 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 118 119 irq_gc_lock(gc); 120 irq_reg_writel(gc, gc->wake_active, AT91_AIC_IDCR); 121 irq_reg_writel(gc, gc->mask_cache, AT91_AIC_IECR); 122 irq_gc_unlock(gc); 123} 124 125static void aic_pm_shutdown(struct irq_data *d) 126{ 127 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 128 129 irq_gc_lock(gc); 130 irq_reg_writel(gc, 0xffffffff, AT91_AIC_IDCR); 131 irq_reg_writel(gc, 0xffffffff, AT91_AIC_ICCR); 132 irq_gc_unlock(gc); 133} 134#else 135#define aic_suspend NULL 136#define aic_resume NULL 137#define aic_pm_shutdown NULL 138#endif /* CONFIG_PM */ 139 140static void __init aic_hw_init(struct irq_domain *domain) 141{ 142 struct irq_chip_generic *gc = irq_get_domain_generic_chip(domain, 0); 143 int i; 144 145 /* 146 * Perform 8 End Of Interrupt Command to make sure AIC 147 * will not Lock out nIRQ 148 */ 149 for (i = 0; i < 8; i++) 150 irq_reg_writel(gc, 0, AT91_AIC_EOICR); 151 152 /* 153 * Spurious Interrupt ID in Spurious Vector Register. 154 * When there is no current interrupt, the IRQ Vector Register 155 * reads the value stored in AIC_SPU 156 */ 157 irq_reg_writel(gc, 0xffffffff, AT91_AIC_SPU); 158 159 /* No debugging in AIC: Debug (Protect) Control Register */ 160 irq_reg_writel(gc, 0, AT91_AIC_DCR); 161 162 /* Disable and clear all interrupts initially */ 163 irq_reg_writel(gc, 0xffffffff, AT91_AIC_IDCR); 164 irq_reg_writel(gc, 0xffffffff, AT91_AIC_ICCR); 165 166 for (i = 0; i < 32; i++) 167 irq_reg_writel(gc, i, AT91_AIC_SVR(i)); 168} 169 170static int aic_irq_domain_xlate(struct irq_domain *d, 171 struct device_node *ctrlr, 172 const u32 *intspec, unsigned int intsize, 173 irq_hw_number_t *out_hwirq, 174 unsigned int *out_type) 175{ 176 struct irq_domain_chip_generic *dgc = d->gc; 177 struct irq_chip_generic *gc; 178 unsigned long flags; 179 unsigned smr; 180 int idx; 181 int ret; 182 183 if (!dgc) 184 return -EINVAL; 185 186 ret = aic_common_irq_domain_xlate(d, ctrlr, intspec, intsize, 187 out_hwirq, out_type); 188 if (ret) 189 return ret; 190 191 idx = intspec[0] / dgc->irqs_per_chip; 192 if (idx >= dgc->num_chips) 193 return -EINVAL; 194 195 gc = dgc->gc[idx]; 196 197 irq_gc_lock_irqsave(gc, flags); 198 smr = irq_reg_readl(gc, AT91_AIC_SMR(*out_hwirq)); 199 aic_common_set_priority(intspec[2], &smr); 200 irq_reg_writel(gc, smr, AT91_AIC_SMR(*out_hwirq)); 201 irq_gc_unlock_irqrestore(gc, flags); 202 203 return ret; 204} 205 206static const struct irq_domain_ops aic_irq_ops = { 207 .map = irq_map_generic_chip, 208 .xlate = aic_irq_domain_xlate, 209}; 210 211static void __init at91rm9200_aic_irq_fixup(void) 212{ 213 aic_common_rtc_irq_fixup(); 214} 215 216static void __init at91sam9260_aic_irq_fixup(void) 217{ 218 aic_common_rtt_irq_fixup(); 219} 220 221static void __init at91sam9g45_aic_irq_fixup(void) 222{ 223 aic_common_rtc_irq_fixup(); 224 aic_common_rtt_irq_fixup(); 225} 226 227static const struct of_device_id aic_irq_fixups[] __initconst = { 228 { .compatible = "atmel,at91rm9200", .data = at91rm9200_aic_irq_fixup }, 229 { .compatible = "atmel,at91sam9g45", .data = at91sam9g45_aic_irq_fixup }, 230 { .compatible = "atmel,at91sam9n12", .data = at91rm9200_aic_irq_fixup }, 231 { .compatible = "atmel,at91sam9rl", .data = at91sam9g45_aic_irq_fixup }, 232 { .compatible = "atmel,at91sam9x5", .data = at91rm9200_aic_irq_fixup }, 233 { .compatible = "atmel,at91sam9260", .data = at91sam9260_aic_irq_fixup }, 234 { .compatible = "atmel,at91sam9261", .data = at91sam9260_aic_irq_fixup }, 235 { .compatible = "atmel,at91sam9263", .data = at91sam9260_aic_irq_fixup }, 236 { .compatible = "atmel,at91sam9g20", .data = at91sam9260_aic_irq_fixup }, 237 { /* sentinel */ }, 238}; 239 240static int __init aic_of_init(struct device_node *node, 241 struct device_node *parent) 242{ 243 struct irq_chip_generic *gc; 244 struct irq_domain *domain; 245 246 if (aic_domain) 247 return -EEXIST; 248 249 domain = aic_common_of_init(node, &aic_irq_ops, "atmel-aic", 250 NR_AIC_IRQS, aic_irq_fixups); 251 if (IS_ERR(domain)) 252 return PTR_ERR(domain); 253 254 aic_domain = domain; 255 gc = irq_get_domain_generic_chip(domain, 0); 256 257 gc->chip_types[0].regs.eoi = AT91_AIC_EOICR; 258 gc->chip_types[0].regs.enable = AT91_AIC_IECR; 259 gc->chip_types[0].regs.disable = AT91_AIC_IDCR; 260 gc->chip_types[0].chip.irq_mask = irq_gc_mask_disable_reg; 261 gc->chip_types[0].chip.irq_unmask = irq_gc_unmask_enable_reg; 262 gc->chip_types[0].chip.irq_retrigger = aic_retrigger; 263 gc->chip_types[0].chip.irq_set_type = aic_set_type; 264 gc->chip_types[0].chip.irq_suspend = aic_suspend; 265 gc->chip_types[0].chip.irq_resume = aic_resume; 266 gc->chip_types[0].chip.irq_pm_shutdown = aic_pm_shutdown; 267 268 aic_hw_init(domain); 269 set_handle_irq(aic_handle); 270 271 return 0; 272} 273IRQCHIP_DECLARE(at91rm9200_aic, "atmel,at91rm9200-aic", aic_of_init);