2011-01-19 15:32:15 +00:00
/*
* Support for Versatile FPGA - based IRQ controllers
*/
# include <linux/irq.h>
# include <linux/io.h>
# include <asm/mach/irq.h>
# include <plat/fpga-irq.h>
# define IRQ_STATUS 0x00
# define IRQ_RAW_STATUS 0x04
# define IRQ_ENABLE_SET 0x08
# define IRQ_ENABLE_CLEAR 0x0c
static void fpga_irq_mask ( struct irq_data * d )
{
struct fpga_irq_data * f = irq_data_get_irq_chip_data ( d ) ;
u32 mask = 1 < < ( d - > irq - f - > irq_start ) ;
writel ( mask , f - > base + IRQ_ENABLE_CLEAR ) ;
}
static void fpga_irq_unmask ( struct irq_data * d )
{
struct fpga_irq_data * f = irq_data_get_irq_chip_data ( d ) ;
u32 mask = 1 < < ( d - > irq - f - > irq_start ) ;
writel ( mask , f - > base + IRQ_ENABLE_SET ) ;
}
static void fpga_irq_handle ( unsigned int irq , struct irq_desc * desc )
{
2011-03-24 13:25:22 +01:00
struct fpga_irq_data * f = irq_desc_get_handler_data ( desc ) ;
2011-01-19 15:32:15 +00:00
u32 status = readl ( f - > base + IRQ_STATUS ) ;
if ( status = = 0 ) {
do_bad_IRQ ( irq , desc ) ;
return ;
}
do {
irq = ffs ( status ) - 1 ;
status & = ~ ( 1 < < irq ) ;
generic_handle_irq ( irq + f - > irq_start ) ;
} while ( status ) ;
}
void __init fpga_irq_init ( int parent_irq , u32 valid , struct fpga_irq_data * f )
{
unsigned int i ;
f - > chip . irq_ack = fpga_irq_mask ;
f - > chip . irq_mask = fpga_irq_mask ;
f - > chip . irq_unmask = fpga_irq_unmask ;
if ( parent_irq ! = - 1 ) {
2011-03-24 13:25:22 +01:00
irq_set_handler_data ( parent_irq , f ) ;
irq_set_chained_handler ( parent_irq , fpga_irq_handle ) ;
2011-01-19 15:32:15 +00:00
}
for ( i = 0 ; i < 32 ; i + + ) {
if ( valid & ( 1 < < i ) ) {
unsigned int irq = f - > irq_start + i ;
2011-03-24 13:25:22 +01:00
irq_set_chip_data ( irq , f ) ;
2011-03-24 13:35:09 +01:00
irq_set_chip_and_handler ( irq , & f - > chip ,
handle_level_irq ) ;
2011-01-19 15:32:15 +00:00
set_irq_flags ( irq , IRQF_VALID | IRQF_PROBE ) ;
}
}
}