2006-01-09 20:05:41 +03:00
/*
2007-02-05 13:42:07 +03:00
* linux / arch / arm / mach - at91 / irq . c
2006-01-09 20:05:41 +03:00
*
* Copyright ( C ) 2004 SAN People
* Copyright ( C ) 2004 ATMEL
* Copyright ( C ) Rick Bronson
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include <linux/init.h>
# include <linux/module.h>
# include <linux/mm.h>
2012-05-30 12:01:09 +04:00
# include <linux/bitmap.h>
2006-01-09 20:05:41 +03:00
# include <linux/types.h>
2011-11-23 01:26:09 +04:00
# include <linux/irq.h>
# include <linux/of.h>
# include <linux/of_address.h>
# include <linux/of_irq.h>
# include <linux/irqdomain.h>
# include <linux/err.h>
2012-06-20 18:13:30 +04:00
# include <linux/slab.h>
2006-01-09 20:05:41 +03:00
2008-08-05 19:14:15 +04:00
# include <mach/hardware.h>
2006-01-09 20:05:41 +03:00
# include <asm/irq.h>
# include <asm/setup.h>
2012-06-11 17:38:03 +04:00
# include <asm/exception.h>
2006-01-09 20:05:41 +03:00
# include <asm/mach/arch.h>
# include <asm/mach/irq.h>
# include <asm/mach/map.h>
2012-10-30 02:41:28 +04:00
# include "at91_aic.h"
2012-06-21 16:47:27 +04:00
2011-11-02 21:12:50 +04:00
void __iomem * at91_aic_base ;
2011-11-23 01:26:09 +04:00
static struct irq_domain * at91_aic_domain ;
static struct device_node * at91_aic_np ;
2012-05-30 12:01:09 +04:00
static unsigned int n_irqs = NR_AIC_IRQS ;
static unsigned long at91_aic_caps = 0 ;
2006-01-09 20:05:41 +03:00
2012-05-30 12:01:09 +04:00
/* AIC5 introduces a Source Select Register */
# define AT91_AIC_CAP_AIC5 (1 << 0)
# define has_aic5() (at91_aic_caps & AT91_AIC_CAP_AIC5)
# ifdef CONFIG_PM
static unsigned long * wakeups ;
static unsigned long * backups ;
# define set_backup(bit) set_bit(bit, backups)
# define clear_backup(bit) clear_bit(bit, backups)
static int at91_aic_pm_init ( void )
{
backups = kzalloc ( BITS_TO_LONGS ( n_irqs ) * sizeof ( * backups ) , GFP_KERNEL ) ;
if ( ! backups )
return - ENOMEM ;
wakeups = kzalloc ( BITS_TO_LONGS ( n_irqs ) * sizeof ( * backups ) , GFP_KERNEL ) ;
if ( ! wakeups ) {
kfree ( backups ) ;
return - ENOMEM ;
}
return 0 ;
}
static int at91_aic_set_wake ( struct irq_data * d , unsigned value )
{
if ( unlikely ( d - > hwirq > = n_irqs ) )
return - EINVAL ;
if ( value )
set_bit ( d - > hwirq , wakeups ) ;
else
clear_bit ( d - > hwirq , wakeups ) ;
return 0 ;
}
void at91_irq_suspend ( void )
{
2013-03-08 19:13:57 +04:00
int bit = - 1 ;
2012-05-30 12:01:09 +04:00
if ( has_aic5 ( ) ) {
/* disable enabled irqs */
2013-03-08 19:13:57 +04:00
while ( ( bit = find_next_bit ( backups , n_irqs , bit + 1 ) ) < n_irqs ) {
2012-05-30 12:01:09 +04:00
at91_aic_write ( AT91_AIC5_SSR ,
bit & AT91_AIC5_INTSEL_MSK ) ;
at91_aic_write ( AT91_AIC5_IDCR , 1 ) ;
}
/* enable wakeup irqs */
2013-03-08 19:13:57 +04:00
bit = - 1 ;
while ( ( bit = find_next_bit ( wakeups , n_irqs , bit + 1 ) ) < n_irqs ) {
2012-05-30 12:01:09 +04:00
at91_aic_write ( AT91_AIC5_SSR ,
bit & AT91_AIC5_INTSEL_MSK ) ;
at91_aic_write ( AT91_AIC5_IECR , 1 ) ;
}
} else {
at91_aic_write ( AT91_AIC_IDCR , * backups ) ;
at91_aic_write ( AT91_AIC_IECR , * wakeups ) ;
}
}
void at91_irq_resume ( void )
{
2013-03-08 19:13:57 +04:00
int bit = - 1 ;
2012-05-30 12:01:09 +04:00
if ( has_aic5 ( ) ) {
/* disable wakeup irqs */
2013-03-08 19:13:57 +04:00
while ( ( bit = find_next_bit ( wakeups , n_irqs , bit + 1 ) ) < n_irqs ) {
2012-05-30 12:01:09 +04:00
at91_aic_write ( AT91_AIC5_SSR ,
bit & AT91_AIC5_INTSEL_MSK ) ;
at91_aic_write ( AT91_AIC5_IDCR , 1 ) ;
}
/* enable irqs disabled for suspend */
2013-03-08 19:13:57 +04:00
bit = - 1 ;
while ( ( bit = find_next_bit ( backups , n_irqs , bit + 1 ) ) < n_irqs ) {
2012-05-30 12:01:09 +04:00
at91_aic_write ( AT91_AIC5_SSR ,
bit & AT91_AIC5_INTSEL_MSK ) ;
at91_aic_write ( AT91_AIC5_IECR , 1 ) ;
}
} else {
at91_aic_write ( AT91_AIC_IDCR , * wakeups ) ;
at91_aic_write ( AT91_AIC_IECR , * backups ) ;
}
}
# else
static inline int at91_aic_pm_init ( void )
{
return 0 ;
}
# define set_backup(bit)
# define clear_backup(bit)
# define at91_aic_set_wake NULL
# endif /* CONFIG_PM */
asmlinkage void __exception_irq_entry
at91_aic_handle_irq ( struct pt_regs * regs )
2012-06-11 17:38:03 +04:00
{
u32 irqnr ;
u32 irqstat ;
irqnr = at91_aic_read ( AT91_AIC_IVR ) ;
irqstat = at91_aic_read ( AT91_AIC_ISR ) ;
/*
* ISR value is 0 when there is no current interrupt or when there is
* a spurious interrupt
*/
if ( ! irqstat )
at91_aic_write ( AT91_AIC_EOICR , 0 ) ;
else
handle_IRQ ( irqnr , regs ) ;
}
2012-05-30 12:01:09 +04:00
asmlinkage void __exception_irq_entry
at91_aic5_handle_irq ( struct pt_regs * regs )
{
u32 irqnr ;
u32 irqstat ;
irqnr = at91_aic_read ( AT91_AIC5_IVR ) ;
irqstat = at91_aic_read ( AT91_AIC5_ISR ) ;
if ( ! irqstat )
at91_aic_write ( AT91_AIC5_EOICR , 0 ) ;
else
handle_IRQ ( irqnr , regs ) ;
}
2010-11-29 12:26:19 +03:00
static void at91_aic_mask_irq ( struct irq_data * d )
2006-01-09 20:05:41 +03:00
{
/* Disable interrupt on AIC */
2011-11-23 01:26:09 +04:00
at91_aic_write ( AT91_AIC_IDCR , 1 < < d - > hwirq ) ;
2012-05-30 12:01:09 +04:00
/* Update ISR cache */
clear_backup ( d - > hwirq ) ;
}
static void __maybe_unused at91_aic5_mask_irq ( struct irq_data * d )
{
/* Disable interrupt on AIC5 */
at91_aic_write ( AT91_AIC5_SSR , d - > hwirq & AT91_AIC5_INTSEL_MSK ) ;
at91_aic_write ( AT91_AIC5_IDCR , 1 ) ;
/* Update ISR cache */
clear_backup ( d - > hwirq ) ;
2006-01-09 20:05:41 +03:00
}
2010-11-29 12:26:19 +03:00
static void at91_aic_unmask_irq ( struct irq_data * d )
2006-01-09 20:05:41 +03:00
{
/* Enable interrupt on AIC */
2011-11-23 01:26:09 +04:00
at91_aic_write ( AT91_AIC_IECR , 1 < < d - > hwirq ) ;
2012-05-30 12:01:09 +04:00
/* Update ISR cache */
set_backup ( d - > hwirq ) ;
}
static void __maybe_unused at91_aic5_unmask_irq ( struct irq_data * d )
{
/* Enable interrupt on AIC5 */
at91_aic_write ( AT91_AIC5_SSR , d - > hwirq & AT91_AIC5_INTSEL_MSK ) ;
at91_aic_write ( AT91_AIC5_IECR , 1 ) ;
/* Update ISR cache */
set_backup ( d - > hwirq ) ;
2006-01-09 20:05:41 +03:00
}
2012-05-25 16:11:51 +04:00
static void at91_aic_eoi ( struct irq_data * d )
{
/*
* Mark end - of - interrupt on AIC , the controller doesn ' t care about
* the value written . Moreover it ' s a write - only register .
*/
at91_aic_write ( AT91_AIC_EOICR , 0 ) ;
}
2012-05-30 12:01:09 +04:00
static void __maybe_unused at91_aic5_eoi ( struct irq_data * d )
{
at91_aic_write ( AT91_AIC5_EOICR , 0 ) ;
}
2006-11-30 12:01:47 +03:00
2012-05-30 12:01:09 +04:00
unsigned long * at91_extern_irq ;
2006-11-30 12:01:47 +03:00
2012-05-30 12:01:09 +04:00
# define is_extern_irq(hwirq) test_bit(hwirq, at91_extern_irq)
static int at91_aic_compute_srctype ( struct irq_data * d , unsigned type )
2006-01-09 20:05:41 +03:00
{
2012-05-30 12:01:09 +04:00
int srctype ;
2006-01-09 20:05:41 +03:00
switch ( type ) {
2008-07-27 07:23:31 +04:00
case IRQ_TYPE_LEVEL_HIGH :
2006-01-09 20:05:41 +03:00
srctype = AT91_AIC_SRCTYPE_HIGH ;
break ;
2008-07-27 07:23:31 +04:00
case IRQ_TYPE_EDGE_RISING :
2006-01-09 20:05:41 +03:00
srctype = AT91_AIC_SRCTYPE_RISING ;
break ;
2008-07-27 07:23:31 +04:00
case IRQ_TYPE_LEVEL_LOW :
2011-11-23 01:26:09 +04:00
if ( ( d - > hwirq = = AT91_ID_FIQ ) | | is_extern_irq ( d - > hwirq ) ) /* only supported on external interrupts */
2006-11-30 12:01:47 +03:00
srctype = AT91_AIC_SRCTYPE_LOW ;
else
2012-05-30 12:01:09 +04:00
srctype = - EINVAL ;
2006-01-09 20:05:41 +03:00
break ;
2008-07-27 07:23:31 +04:00
case IRQ_TYPE_EDGE_FALLING :
2011-11-23 01:26:09 +04:00
if ( ( d - > hwirq = = AT91_ID_FIQ ) | | is_extern_irq ( d - > hwirq ) ) /* only supported on external interrupts */
2006-11-30 12:01:47 +03:00
srctype = AT91_AIC_SRCTYPE_FALLING ;
else
2012-05-30 12:01:09 +04:00
srctype = - EINVAL ;
2006-01-09 20:05:41 +03:00
break ;
default :
2012-05-30 12:01:09 +04:00
srctype = - EINVAL ;
2006-01-09 20:05:41 +03:00
}
2012-05-30 12:01:09 +04:00
return srctype ;
2006-01-09 20:05:41 +03:00
}
2012-05-30 12:01:09 +04:00
static int at91_aic_set_type ( struct irq_data * d , unsigned type )
2006-06-19 18:26:53 +04:00
{
2012-05-30 12:01:09 +04:00
unsigned int smr ;
int srctype ;
srctype = at91_aic_compute_srctype ( d , type ) ;
if ( srctype < 0 )
return srctype ;
if ( has_aic5 ( ) ) {
at91_aic_write ( AT91_AIC5_SSR ,
d - > hwirq & AT91_AIC5_INTSEL_MSK ) ;
smr = at91_aic_read ( AT91_AIC5_SMR ) & ~ AT91_AIC_SRCTYPE ;
at91_aic_write ( AT91_AIC5_SMR , smr | srctype ) ;
} else {
smr = at91_aic_read ( AT91_AIC_SMR ( d - > hwirq ) )
& ~ AT91_AIC_SRCTYPE ;
at91_aic_write ( AT91_AIC_SMR ( d - > hwirq ) , smr | srctype ) ;
}
2006-06-19 18:26:53 +04:00
return 0 ;
}
2006-08-02 01:26:25 +04:00
static struct irq_chip at91_aic_chip = {
. name = " AIC " ,
2010-11-29 12:26:19 +03:00
. irq_mask = at91_aic_mask_irq ,
. irq_unmask = at91_aic_unmask_irq ,
. irq_set_type = at91_aic_set_type ,
. irq_set_wake = at91_aic_set_wake ,
2012-05-25 16:11:51 +04:00
. irq_eoi = at91_aic_eoi ,
2006-01-09 20:05:41 +03:00
} ;
2012-02-14 21:08:14 +04:00
static void __init at91_aic_hw_init ( unsigned int spu_vector )
{
int i ;
/*
* Perform 8 End Of Interrupt Command to make sure AIC
* will not Lock out nIRQ
*/
for ( i = 0 ; i < 8 ; i + + )
at91_aic_write ( AT91_AIC_EOICR , 0 ) ;
/*
* Spurious Interrupt ID in Spurious Vector Register .
* When there is no current interrupt , the IRQ Vector Register
* reads the value stored in AIC_SPU
*/
at91_aic_write ( AT91_AIC_SPU , spu_vector ) ;
/* No debugging in AIC: Debug (Protect) Control Register */
at91_aic_write ( AT91_AIC_DCR , 0 ) ;
/* Disable and clear all interrupts initially */
at91_aic_write ( AT91_AIC_IDCR , 0xFFFFFFFF ) ;
at91_aic_write ( AT91_AIC_ICCR , 0xFFFFFFFF ) ;
}
2012-05-30 12:01:09 +04:00
static void __init __maybe_unused at91_aic5_hw_init ( unsigned int spu_vector )
{
int i ;
/*
* Perform 8 End Of Interrupt Command to make sure AIC
* will not Lock out nIRQ
*/
for ( i = 0 ; i < 8 ; i + + )
at91_aic_write ( AT91_AIC5_EOICR , 0 ) ;
/*
* Spurious Interrupt ID in Spurious Vector Register .
* When there is no current interrupt , the IRQ Vector Register
* reads the value stored in AIC_SPU
*/
at91_aic_write ( AT91_AIC5_SPU , spu_vector ) ;
/* No debugging in AIC: Debug (Protect) Control Register */
at91_aic_write ( AT91_AIC5_DCR , 0 ) ;
/* Disable and clear all interrupts initially */
for ( i = 0 ; i < n_irqs ; i + + ) {
at91_aic_write ( AT91_AIC5_SSR , i & AT91_AIC5_INTSEL_MSK ) ;
at91_aic_write ( AT91_AIC5_IDCR , 1 ) ;
at91_aic_write ( AT91_AIC5_ICCR , 1 ) ;
}
}
2011-11-23 01:26:09 +04:00
# if defined(CONFIG_OF)
2012-07-04 11:45:16 +04:00
static unsigned int * at91_aic_irq_priorities ;
2012-02-14 21:08:14 +04:00
static int at91_aic_irq_map ( struct irq_domain * h , unsigned int virq ,
irq_hw_number_t hw )
2011-11-23 01:26:09 +04:00
{
2012-02-14 21:08:14 +04:00
/* Put virq number in Source Vector Register */
at91_aic_write ( AT91_AIC_SVR ( hw ) , virq ) ;
2012-06-20 18:13:30 +04:00
/* Active Low interrupt, with priority */
at91_aic_write ( AT91_AIC_SMR ( hw ) ,
AT91_AIC_SRCTYPE_LOW | at91_aic_irq_priorities [ hw ] ) ;
2012-02-14 21:08:14 +04:00
2012-05-25 16:11:51 +04:00
irq_set_chip_and_handler ( virq , & at91_aic_chip , handle_fasteoi_irq ) ;
2012-02-14 21:08:14 +04:00
set_irq_flags ( virq , IRQF_VALID | IRQF_PROBE ) ;
2011-11-23 01:26:09 +04:00
return 0 ;
}
2012-05-30 12:01:09 +04:00
static int at91_aic5_irq_map ( struct irq_domain * h , unsigned int virq ,
irq_hw_number_t hw )
{
at91_aic_write ( AT91_AIC5_SSR , hw & AT91_AIC5_INTSEL_MSK ) ;
/* Put virq number in Source Vector Register */
at91_aic_write ( AT91_AIC5_SVR , virq ) ;
/* Active Low interrupt, with priority */
at91_aic_write ( AT91_AIC5_SMR ,
AT91_AIC_SRCTYPE_LOW | at91_aic_irq_priorities [ hw ] ) ;
irq_set_chip_and_handler ( virq , & at91_aic_chip , handle_fasteoi_irq ) ;
set_irq_flags ( virq , IRQF_VALID | IRQF_PROBE ) ;
return 0 ;
}
2012-06-20 18:13:30 +04:00
static int at91_aic_irq_domain_xlate ( struct irq_domain * d , struct device_node * ctrlr ,
const u32 * intspec , unsigned int intsize ,
irq_hw_number_t * out_hwirq , unsigned int * out_type )
{
if ( WARN_ON ( intsize < 3 ) )
return - EINVAL ;
2012-05-30 12:01:09 +04:00
if ( WARN_ON ( intspec [ 0 ] > = n_irqs ) )
2012-06-20 18:13:30 +04:00
return - EINVAL ;
if ( WARN_ON ( ( intspec [ 2 ] < AT91_AIC_IRQ_MIN_PRIORITY )
| | ( intspec [ 2 ] > AT91_AIC_IRQ_MAX_PRIORITY ) ) )
return - EINVAL ;
* out_hwirq = intspec [ 0 ] ;
* out_type = intspec [ 1 ] & IRQ_TYPE_SENSE_MASK ;
at91_aic_irq_priorities [ * out_hwirq ] = intspec [ 2 ] ;
return 0 ;
}
2012-02-14 21:08:14 +04:00
static struct irq_domain_ops at91_aic_irq_ops = {
. map = at91_aic_irq_map ,
2012-06-20 18:13:30 +04:00
. xlate = at91_aic_irq_domain_xlate ,
2011-11-23 01:26:09 +04:00
} ;
2012-05-30 12:01:09 +04:00
int __init at91_aic_of_common_init ( struct device_node * node ,
struct device_node * parent )
2011-11-23 01:26:09 +04:00
{
2012-04-09 15:36:36 +04:00
struct property * prop ;
const __be32 * p ;
u32 val ;
2012-05-30 12:01:09 +04:00
at91_extern_irq = kzalloc ( BITS_TO_LONGS ( n_irqs )
* sizeof ( * at91_extern_irq ) , GFP_KERNEL ) ;
if ( ! at91_extern_irq )
return - ENOMEM ;
if ( at91_aic_pm_init ( ) ) {
kfree ( at91_extern_irq ) ;
return - ENOMEM ;
}
at91_aic_irq_priorities = kzalloc ( n_irqs
2012-06-20 18:13:30 +04:00
* sizeof ( * at91_aic_irq_priorities ) ,
GFP_KERNEL ) ;
if ( ! at91_aic_irq_priorities )
return - ENOMEM ;
2012-02-14 21:08:14 +04:00
at91_aic_base = of_iomap ( node , 0 ) ;
at91_aic_np = node ;
2012-05-30 12:01:09 +04:00
at91_aic_domain = irq_domain_add_linear ( at91_aic_np , n_irqs ,
2012-02-14 21:08:14 +04:00
& at91_aic_irq_ops , NULL ) ;
if ( ! at91_aic_domain )
panic ( " Unable to add AIC irq domain (DT) \n " ) ;
2012-04-09 15:36:36 +04:00
of_property_for_each_u32 ( node , " atmel,external-irqs " , prop , p , val ) {
2012-05-30 12:01:09 +04:00
if ( val > = n_irqs )
pr_warn ( " AIC: external irq %d >= %d skip it \n " ,
val , n_irqs ) ;
2012-04-09 15:36:36 +04:00
else
2012-05-30 12:01:09 +04:00
set_bit ( val , at91_extern_irq ) ;
2012-04-09 15:36:36 +04:00
}
2012-02-14 21:08:14 +04:00
irq_set_default_host ( at91_aic_domain ) ;
2012-05-30 12:01:09 +04:00
return 0 ;
}
int __init at91_aic_of_init ( struct device_node * node ,
struct device_node * parent )
{
int err ;
err = at91_aic_of_common_init ( node , parent ) ;
if ( err )
return err ;
at91_aic_hw_init ( n_irqs ) ;
return 0 ;
}
int __init at91_aic5_of_init ( struct device_node * node ,
struct device_node * parent )
{
int err ;
at91_aic_caps | = AT91_AIC_CAP_AIC5 ;
n_irqs = NR_AIC5_IRQS ;
at91_aic_chip . irq_ack = at91_aic5_mask_irq ;
at91_aic_chip . irq_mask = at91_aic5_mask_irq ;
at91_aic_chip . irq_unmask = at91_aic5_unmask_irq ;
at91_aic_chip . irq_eoi = at91_aic5_eoi ;
at91_aic_irq_ops . map = at91_aic5_irq_map ;
err = at91_aic_of_common_init ( node , parent ) ;
if ( err )
return err ;
at91_aic5_hw_init ( n_irqs ) ;
2012-02-14 21:08:14 +04:00
return 0 ;
2011-11-23 01:26:09 +04:00
}
# endif
2006-01-09 20:05:41 +03:00
/*
* Initialize the AIC interrupt controller .
*/
2012-10-24 18:09:57 +04:00
void __init at91_aic_init ( unsigned int * priority , unsigned int ext_irq_mask )
2006-01-09 20:05:41 +03:00
{
unsigned int i ;
2011-11-23 01:26:09 +04:00
int irq_base ;
2006-01-09 20:05:41 +03:00
2012-10-24 18:09:57 +04:00
at91_extern_irq = kzalloc ( BITS_TO_LONGS ( n_irqs )
* sizeof ( * at91_extern_irq ) , GFP_KERNEL ) ;
if ( at91_aic_pm_init ( ) | | at91_extern_irq = = NULL )
2012-05-30 12:01:09 +04:00
panic ( " Unable to allocate bit maps \n " ) ;
2012-10-24 18:09:57 +04:00
* at91_extern_irq = ext_irq_mask ;
2012-02-14 21:08:14 +04:00
at91_aic_base = ioremap ( AT91_AIC , 512 ) ;
2011-11-02 21:12:50 +04:00
if ( ! at91_aic_base )
2011-11-23 01:26:09 +04:00
panic ( " Unable to ioremap AIC registers \n " ) ;
/* Add irq domain for AIC */
2012-05-30 12:01:09 +04:00
irq_base = irq_alloc_descs ( - 1 , 0 , n_irqs , 0 ) ;
2011-11-23 01:26:09 +04:00
if ( irq_base < 0 ) {
WARN ( 1 , " Cannot allocate irq_descs, assuming pre-allocated \n " ) ;
irq_base = 0 ;
}
2012-05-30 12:01:09 +04:00
at91_aic_domain = irq_domain_add_legacy ( at91_aic_np , n_irqs ,
2011-11-23 01:26:09 +04:00
irq_base , 0 ,
& irq_domain_simple_ops , NULL ) ;
if ( ! at91_aic_domain )
panic ( " Unable to add AIC irq domain \n " ) ;
2011-11-02 21:12:50 +04:00
2012-02-14 21:08:14 +04:00
irq_set_default_host ( at91_aic_domain ) ;
2006-01-09 20:05:41 +03:00
/*
* The IVR is used by macro get_irqnr_and_base to read and verify .
* The irq number is NR_AIC_IRQS when a spurious interrupt has occurred .
*/
2012-05-30 12:01:09 +04:00
for ( i = 0 ; i < n_irqs ; i + + ) {
2011-11-23 01:26:09 +04:00
/* Put hardware irq number in Source Vector Register: */
2012-06-21 16:47:27 +04:00
at91_aic_write ( AT91_AIC_SVR ( i ) , NR_IRQS_LEGACY + i ) ;
2006-07-05 20:22:52 +04:00
/* Active Low interrupt, with the specified priority */
2011-11-02 21:12:50 +04:00
at91_aic_write ( AT91_AIC_SMR ( i ) , AT91_AIC_SRCTYPE_LOW | priority [ i ] ) ;
2012-06-21 16:47:27 +04:00
irq_set_chip_and_handler ( NR_IRQS_LEGACY + i , & at91_aic_chip , handle_fasteoi_irq ) ;
2006-01-09 20:05:41 +03:00
set_irq_flags ( i , IRQF_VALID | IRQF_PROBE ) ;
}
2012-05-30 12:01:09 +04:00
at91_aic_hw_init ( n_irqs ) ;
2006-01-09 20:05:41 +03:00
}