2007-06-15 01:54:47 +04:00
/*
* This file define the irq handler for MSP SLM subsystem interrupts .
*
* Copyright 2005 - 2006 PMC - Sierra , Inc , derived from irq_cpu . c
* Author : Andrew Hughes , Andrew_Hughes @ pmc - sierra . com
*
2013-01-22 15:59:30 +04:00
* 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
2007-06-15 01:54:47 +04:00
* Free Software Foundation ; either version 2 of the License , or ( at your
* option ) any later version .
*/
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/kernel.h>
# include <linux/bitops.h>
# include <asm/mipsregs.h>
# include <msp_slp_int.h>
# include <msp_regs.h>
2011-03-24 00:09:06 +03:00
static inline void unmask_msp_slp_irq ( struct irq_data * d )
2007-06-15 01:54:47 +04:00
{
2011-03-24 00:09:06 +03:00
unsigned int irq = d - > irq ;
2007-06-15 01:54:47 +04:00
/* check for PER interrupt range */
if ( irq < MSP_PER_INTBASE )
* SLP_INT_MSK_REG | = ( 1 < < ( irq - MSP_SLP_INTBASE ) ) ;
else
* PER_INT_MSK_REG | = ( 1 < < ( irq - MSP_PER_INTBASE ) ) ;
}
2011-03-24 00:09:06 +03:00
static inline void mask_msp_slp_irq ( struct irq_data * d )
2007-06-15 01:54:47 +04:00
{
2011-03-24 00:09:06 +03:00
unsigned int irq = d - > irq ;
2007-06-15 01:54:47 +04:00
/* check for PER interrupt range */
if ( irq < MSP_PER_INTBASE )
* SLP_INT_MSK_REG & = ~ ( 1 < < ( irq - MSP_SLP_INTBASE ) ) ;
else
* PER_INT_MSK_REG & = ~ ( 1 < < ( irq - MSP_PER_INTBASE ) ) ;
}
/*
* While we ack the interrupt interrupts are disabled and thus we don ' t need
* to deal with concurrency issues . Same for msp_slp_irq_end .
*/
2011-03-24 00:09:06 +03:00
static inline void ack_msp_slp_irq ( struct irq_data * d )
2007-06-15 01:54:47 +04:00
{
2011-03-24 00:09:06 +03:00
unsigned int irq = d - > irq ;
2007-06-15 01:54:47 +04:00
/* check for PER interrupt range */
if ( irq < MSP_PER_INTBASE )
* SLP_INT_STS_REG = ( 1 < < ( irq - MSP_SLP_INTBASE ) ) ;
else
* PER_INT_STS_REG = ( 1 < < ( irq - MSP_PER_INTBASE ) ) ;
}
static struct irq_chip msp_slp_irq_controller = {
. name = " MSP_SLP " ,
2011-03-24 00:09:06 +03:00
. irq_ack = ack_msp_slp_irq ,
. irq_mask = mask_msp_slp_irq ,
. irq_unmask = unmask_msp_slp_irq ,
2007-06-15 01:54:47 +04:00
} ;
void __init msp_slp_irq_init ( void )
{
int i ;
/* Mask/clear interrupts. */
* SLP_INT_MSK_REG = 0x00000000 ;
* PER_INT_MSK_REG = 0x00000000 ;
* SLP_INT_STS_REG = 0xFFFFFFFF ;
* PER_INT_STS_REG = 0xFFFFFFFF ;
/* initialize all the IRQ descriptors */
for ( i = MSP_SLP_INTBASE ; i < MSP_PER_INTBASE + 32 ; i + + )
2011-03-27 17:19:28 +04:00
irq_set_chip_and_handler ( i , & msp_slp_irq_controller ,
2007-06-15 01:54:47 +04:00
handle_level_irq ) ;
}
void msp_slp_irq_dispatch ( void )
{
u32 pending ;
int intbase ;
intbase = MSP_SLP_INTBASE ;
pending = * SLP_INT_STS_REG & * SLP_INT_MSK_REG ;
/* check for PER interrupt */
if ( pending = = ( 1 < < ( MSP_INT_PER - MSP_SLP_INTBASE ) ) ) {
intbase = MSP_PER_INTBASE ;
pending = * PER_INT_STS_REG & * PER_INT_MSK_REG ;
}
/* check for spurious interrupt */
if ( pending = = 0x00000000 ) {
printk ( KERN_ERR " Spurious %s interrupt? \n " ,
( intbase = = MSP_SLP_INTBASE ) ? " SLP " : " PER " ) ;
return ;
}
/* dispatch the irq */
do_IRQ ( ffs ( pending ) + intbase - 1 ) ;
}