2006-05-16 14:54:37 +04:00
/*
* arch / arm / mach - pnx4008 / irq . c
*
* PNX4008 IRQ controller driver
*
* Author : Dmitry Chigirev < source @ mvista . com >
*
* Based on reference code received from Philips :
* Copyright ( C ) 2003 Philips Semiconductors
*
* 2005 ( c ) MontaVista Software , Inc . This file is licensed under
* the terms of the GNU General Public License version 2. This program
* is licensed " as is " without any warranty of any kind , whether express
* or implied .
*/
# include <linux/kernel.h>
# include <linux/types.h>
# include <linux/mm.h>
# include <linux/interrupt.h>
# include <linux/list.h>
# include <linux/init.h>
# include <linux/ioport.h>
# include <linux/device.h>
2006-07-05 17:47:20 +04:00
# include <linux/irq.h>
2008-09-06 15:10:45 +04:00
# include <linux/io.h>
2008-08-05 19:14:15 +04:00
# include <mach/hardware.h>
2006-05-16 14:54:37 +04:00
# include <asm/setup.h>
# include <asm/pgtable.h>
# include <asm/page.h>
# include <asm/system.h>
# include <asm/mach/arch.h>
# include <asm/mach/irq.h>
# include <asm/mach/map.h>
2008-08-05 19:14:15 +04:00
# include <mach/irq.h>
2006-05-16 14:54:37 +04:00
static u8 pnx4008_irq_type [ NR_IRQS ] = PNX4008_IRQ_TYPES ;
static void pnx4008_mask_irq ( unsigned int irq )
{
__raw_writel ( __raw_readl ( INTC_ER ( irq ) ) & ~ INTC_BIT ( irq ) , INTC_ER ( irq ) ) ; /* mask interrupt */
}
static void pnx4008_unmask_irq ( unsigned int irq )
{
__raw_writel ( __raw_readl ( INTC_ER ( irq ) ) | INTC_BIT ( irq ) , INTC_ER ( irq ) ) ; /* unmask interrupt */
}
static void pnx4008_mask_ack_irq ( unsigned int irq )
{
__raw_writel ( __raw_readl ( INTC_ER ( irq ) ) & ~ INTC_BIT ( irq ) , INTC_ER ( irq ) ) ; /* mask interrupt */
__raw_writel ( INTC_BIT ( irq ) , INTC_SR ( irq ) ) ; /* clear interrupt status */
}
static int pnx4008_set_irq_type ( unsigned int irq , unsigned int type )
{
switch ( type ) {
2008-07-27 07:23:31 +04:00
case IRQ_TYPE_EDGE_RISING :
2006-05-16 14:54:37 +04:00
__raw_writel ( __raw_readl ( INTC_ATR ( irq ) ) | INTC_BIT ( irq ) , INTC_ATR ( irq ) ) ; /*edge sensitive */
__raw_writel ( __raw_readl ( INTC_APR ( irq ) ) | INTC_BIT ( irq ) , INTC_APR ( irq ) ) ; /*rising edge */
2006-11-23 14:41:32 +03:00
set_irq_handler ( irq , handle_edge_irq ) ;
2006-05-16 14:54:37 +04:00
break ;
2008-07-27 07:23:31 +04:00
case IRQ_TYPE_EDGE_FALLING :
2006-05-16 14:54:37 +04:00
__raw_writel ( __raw_readl ( INTC_ATR ( irq ) ) | INTC_BIT ( irq ) , INTC_ATR ( irq ) ) ; /*edge sensitive */
__raw_writel ( __raw_readl ( INTC_APR ( irq ) ) & ~ INTC_BIT ( irq ) , INTC_APR ( irq ) ) ; /*falling edge */
2006-11-23 14:41:32 +03:00
set_irq_handler ( irq , handle_edge_irq ) ;
2006-05-16 14:54:37 +04:00
break ;
2008-07-27 07:23:31 +04:00
case IRQ_TYPE_LEVEL_LOW :
2006-05-16 14:54:37 +04:00
__raw_writel ( __raw_readl ( INTC_ATR ( irq ) ) & ~ INTC_BIT ( irq ) , INTC_ATR ( irq ) ) ; /*level sensitive */
__raw_writel ( __raw_readl ( INTC_APR ( irq ) ) & ~ INTC_BIT ( irq ) , INTC_APR ( irq ) ) ; /*low level */
2006-11-23 14:41:32 +03:00
set_irq_handler ( irq , handle_level_irq ) ;
2006-05-16 14:54:37 +04:00
break ;
2008-07-27 07:23:31 +04:00
case IRQ_TYPE_LEVEL_HIGH :
2006-05-16 14:54:37 +04:00
__raw_writel ( __raw_readl ( INTC_ATR ( irq ) ) & ~ INTC_BIT ( irq ) , INTC_ATR ( irq ) ) ; /*level sensitive */
__raw_writel ( __raw_readl ( INTC_APR ( irq ) ) | INTC_BIT ( irq ) , INTC_APR ( irq ) ) ; /* high level */
2006-11-23 14:41:32 +03:00
set_irq_handler ( irq , handle_level_irq ) ;
2006-05-16 14:54:37 +04:00
break ;
2008-07-27 07:23:31 +04:00
/* IRQ_TYPE_EDGE_BOTH is not supported */
2006-05-16 14:54:37 +04:00
default :
printk ( KERN_ERR " PNX4008 IRQ: Unsupported irq type %d \n " , type ) ;
return - 1 ;
}
return 0 ;
}
2006-11-23 14:41:32 +03:00
static struct irq_chip pnx4008_irq_chip = {
2006-05-16 14:54:37 +04:00
. ack = pnx4008_mask_ack_irq ,
. mask = pnx4008_mask_irq ,
. unmask = pnx4008_unmask_irq ,
. set_type = pnx4008_set_irq_type ,
} ;
void __init pnx4008_init_irq ( void )
{
unsigned int i ;
2006-07-05 17:47:20 +04:00
/* configure IRQ's */
for ( i = 0 ; i < NR_IRQS ; i + + ) {
set_irq_flags ( i , IRQF_VALID ) ;
set_irq_chip ( i , & pnx4008_irq_chip ) ;
pnx4008_set_irq_type ( i , pnx4008_irq_type [ i ] ) ;
}
/* configure and enable IRQ 0,1,30,31 (cascade interrupts) */
2006-05-16 14:54:37 +04:00
pnx4008_set_irq_type ( SUB1_IRQ_N , pnx4008_irq_type [ SUB1_IRQ_N ] ) ;
pnx4008_set_irq_type ( SUB2_IRQ_N , pnx4008_irq_type [ SUB2_IRQ_N ] ) ;
pnx4008_set_irq_type ( SUB1_FIQ_N , pnx4008_irq_type [ SUB1_FIQ_N ] ) ;
pnx4008_set_irq_type ( SUB2_FIQ_N , pnx4008_irq_type [ SUB2_FIQ_N ] ) ;
2006-07-05 17:47:20 +04:00
/* mask all others */
2006-05-16 14:54:37 +04:00
__raw_writel ( ( 1 < < SUB2_FIQ_N ) | ( 1 < < SUB1_FIQ_N ) |
( 1 < < SUB2_IRQ_N ) | ( 1 < < SUB1_IRQ_N ) ,
INTC_ER ( MAIN_BASE_INT ) ) ;
__raw_writel ( 0 , INTC_ER ( SIC1_BASE_INT ) ) ;
__raw_writel ( 0 , INTC_ER ( SIC2_BASE_INT ) ) ;
}