1/* 2 * linux/arch/arm/mach-at91/irq.c 3 * 4 * Copyright (C) 2004 SAN People 5 * Copyright (C) 2004 ATMEL 6 * Copyright (C) Rick Bronson 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 */ 22 23#include <linux/init.h> 24#include <linux/module.h> 25#include <linux/mm.h> 26#include <linux/types.h> 27 28#include <asm/hardware.h> 29#include <asm/irq.h> 30#include <asm/mach-types.h> 31#include <asm/setup.h> 32 33#include <asm/mach/arch.h> 34#include <asm/mach/irq.h> 35#include <asm/mach/map.h> 36 37 38static void at91_aic_mask_irq(unsigned int irq) 39{ 40 /* Disable interrupt on AIC */ 41 at91_sys_write(AT91_AIC_IDCR, 1 << irq); 42} 43 44static void at91_aic_unmask_irq(unsigned int irq) 45{ 46 /* Enable interrupt on AIC */ 47 at91_sys_write(AT91_AIC_IECR, 1 << irq); 48} 49 50unsigned int at91_extern_irq; 51 52#define is_extern_irq(irq) ((1 << (irq)) & at91_extern_irq) 53 54static int at91_aic_set_type(unsigned irq, unsigned type) 55{ 56 unsigned int smr, srctype; 57 58 switch (type) { 59 case IRQT_HIGH: 60 srctype = AT91_AIC_SRCTYPE_HIGH; 61 break; 62 case IRQT_RISING: 63 srctype = AT91_AIC_SRCTYPE_RISING; 64 break; 65 case IRQT_LOW: 66 if ((irq == AT91_ID_FIQ) || is_extern_irq(irq)) /* only supported on external interrupts */ 67 srctype = AT91_AIC_SRCTYPE_LOW; 68 else 69 return -EINVAL; 70 break; 71 case IRQT_FALLING: 72 if ((irq == AT91_ID_FIQ) || is_extern_irq(irq)) /* only supported on external interrupts */ 73 srctype = AT91_AIC_SRCTYPE_FALLING; 74 else 75 return -EINVAL; 76 break; 77 default: 78 return -EINVAL; 79 } 80 81 smr = at91_sys_read(AT91_AIC_SMR(irq)) & ~AT91_AIC_SRCTYPE; 82 at91_sys_write(AT91_AIC_SMR(irq), smr | srctype); 83 return 0; 84} 85 86#ifdef CONFIG_PM 87 88static u32 wakeups; 89static u32 backups; 90 91static int at91_aic_set_wake(unsigned irq, unsigned value) 92{ 93 if (unlikely(irq >= 32)) 94 return -EINVAL; 95 96 if (value) 97 wakeups |= (1 << irq); 98 else 99 wakeups &= ~(1 << irq); 100 101 return 0; 102} 103 104void at91_irq_suspend(void) 105{ 106 backups = at91_sys_read(AT91_AIC_IMR); 107 at91_sys_write(AT91_AIC_IDCR, backups); 108 at91_sys_write(AT91_AIC_IECR, wakeups); 109} 110 111void at91_irq_resume(void) 112{ 113 at91_sys_write(AT91_AIC_IDCR, wakeups); 114 at91_sys_write(AT91_AIC_IECR, backups); 115} 116 117#else 118#define at91_aic_set_wake NULL 119#endif 120 121static struct irq_chip at91_aic_chip = { 122 .name = "AIC", 123 .ack = at91_aic_mask_irq, 124 .mask = at91_aic_mask_irq, 125 .unmask = at91_aic_unmask_irq, 126 .set_type = at91_aic_set_type, 127 .set_wake = at91_aic_set_wake, 128}; 129 130/* 131 * Initialize the AIC interrupt controller. 132 */ 133void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS]) 134{ 135 unsigned int i; 136 137 /* 138 * The IVR is used by macro get_irqnr_and_base to read and verify. 139 * The irq number is NR_AIC_IRQS when a spurious interrupt has occurred. 140 */ 141 for (i = 0; i < NR_AIC_IRQS; i++) { 142 /* Put irq number in Source Vector Register: */ 143 at91_sys_write(AT91_AIC_SVR(i), i); 144 /* Active Low interrupt, with the specified priority */ 145 at91_sys_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]); 146 147 set_irq_chip(i, &at91_aic_chip); 148 set_irq_handler(i, handle_level_irq); 149 set_irq_flags(i, IRQF_VALID | IRQF_PROBE); 150 151 /* Perform 8 End Of Interrupt Command to make sure AIC will not Lock out nIRQ */ 152 if (i < 8) 153 at91_sys_write(AT91_AIC_EOICR, 0); 154 } 155 156 /* 157 * Spurious Interrupt ID in Spurious Vector Register is NR_AIC_IRQS 158 * When there is no current interrupt, the IRQ Vector Register reads the value stored in AIC_SPU 159 */ 160 at91_sys_write(AT91_AIC_SPU, NR_AIC_IRQS); 161 162 /* No debugging in AIC: Debug (Protect) Control Register */ 163 at91_sys_write(AT91_AIC_DCR, 0); 164 165 /* Disable and clear all interrupts initially */ 166 at91_sys_write(AT91_AIC_IDCR, 0xFFFFFFFF); 167 at91_sys_write(AT91_AIC_ICCR, 0xFFFFFFFF); 168} 169