2010-05-03 09:24:30 +01:00
/*
* arch / arm / plat - spear / shirq . c
*
* SPEAr platform shared irq layer source file
*
* Copyright ( C ) 2009 ST Microelectronics
* Viresh Kumar < viresh . kumar @ st . com >
*
* 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/err.h>
# include <linux/io.h>
# include <linux/irq.h>
# include <linux/spinlock.h>
# include <plat/shirq.h>
struct spear_shirq * shirq ;
static DEFINE_SPINLOCK ( lock ) ;
2010-11-29 11:22:33 +01:00
static void shirq_irq_mask ( struct irq_data * d )
2010-05-03 09:24:30 +01:00
{
2010-11-29 11:22:33 +01:00
struct spear_shirq * shirq = irq_data_get_irq_chip_data ( d ) ;
u32 val , id = d - > irq - shirq - > dev_config [ 0 ] . virq ;
2010-05-03 09:24:30 +01:00
unsigned long flags ;
if ( ( shirq - > regs . enb_reg = = - 1 ) | | shirq - > dev_config [ id ] . enb_mask = = - 1 )
return ;
spin_lock_irqsave ( & lock , flags ) ;
val = readl ( shirq - > regs . base + shirq - > regs . enb_reg ) ;
if ( shirq - > regs . reset_to_enb )
val | = shirq - > dev_config [ id ] . enb_mask ;
else
val & = ~ ( shirq - > dev_config [ id ] . enb_mask ) ;
writel ( val , shirq - > regs . base + shirq - > regs . enb_reg ) ;
spin_unlock_irqrestore ( & lock , flags ) ;
}
2010-11-29 11:22:33 +01:00
static void shirq_irq_unmask ( struct irq_data * d )
2010-05-03 09:24:30 +01:00
{
2010-11-29 11:22:33 +01:00
struct spear_shirq * shirq = irq_data_get_irq_chip_data ( d ) ;
u32 val , id = d - > irq - shirq - > dev_config [ 0 ] . virq ;
2010-05-03 09:24:30 +01:00
unsigned long flags ;
if ( ( shirq - > regs . enb_reg = = - 1 ) | | shirq - > dev_config [ id ] . enb_mask = = - 1 )
return ;
spin_lock_irqsave ( & lock , flags ) ;
val = readl ( shirq - > regs . base + shirq - > regs . enb_reg ) ;
if ( shirq - > regs . reset_to_enb )
val & = ~ ( shirq - > dev_config [ id ] . enb_mask ) ;
else
val | = shirq - > dev_config [ id ] . enb_mask ;
writel ( val , shirq - > regs . base + shirq - > regs . enb_reg ) ;
spin_unlock_irqrestore ( & lock , flags ) ;
}
static struct irq_chip shirq_chip = {
. name = " spear_shirq " ,
2010-11-29 11:22:33 +01:00
. irq_ack = shirq_irq_mask ,
. irq_mask = shirq_irq_mask ,
. irq_unmask = shirq_irq_unmask ,
2010-05-03 09:24:30 +01:00
} ;
static void shirq_handler ( unsigned irq , struct irq_desc * desc )
{
u32 i , val , mask ;
2011-03-24 13:25:22 +01:00
struct spear_shirq * shirq = irq_get_handler_data ( irq ) ;
2010-05-03 09:24:30 +01:00
2010-11-29 11:22:33 +01:00
desc - > irq_data . chip - > irq_ack ( & desc - > irq_data ) ;
2010-05-03 09:24:30 +01:00
while ( ( val = readl ( shirq - > regs . base + shirq - > regs . status_reg ) &
shirq - > regs . status_reg_mask ) ) {
for ( i = 0 ; ( i < shirq - > dev_count ) & & val ; i + + ) {
if ( ! ( shirq - > dev_config [ i ] . status_mask & val ) )
continue ;
generic_handle_irq ( shirq - > dev_config [ i ] . virq ) ;
/* clear interrupt */
val & = ~ shirq - > dev_config [ i ] . status_mask ;
if ( ( shirq - > regs . clear_reg = = - 1 ) | |
shirq - > dev_config [ i ] . clear_mask = = - 1 )
continue ;
mask = readl ( shirq - > regs . base + shirq - > regs . clear_reg ) ;
if ( shirq - > regs . reset_to_clear )
mask & = ~ shirq - > dev_config [ i ] . clear_mask ;
else
mask | = shirq - > dev_config [ i ] . clear_mask ;
writel ( mask , shirq - > regs . base + shirq - > regs . clear_reg ) ;
}
}
2010-11-29 11:22:33 +01:00
desc - > irq_data . chip - > irq_unmask ( & desc - > irq_data ) ;
2010-05-03 09:24:30 +01:00
}
int spear_shirq_register ( struct spear_shirq * shirq )
{
int i ;
if ( ! shirq | | ! shirq - > dev_config | | ! shirq - > regs . base )
return - EFAULT ;
if ( ! shirq - > dev_count )
return - EINVAL ;
2011-03-24 13:25:22 +01:00
irq_set_chained_handler ( shirq - > irq , shirq_handler ) ;
2010-05-03 09:24:30 +01:00
for ( i = 0 ; i < shirq - > dev_count ; i + + ) {
2011-03-24 13:35:09 +01:00
irq_set_chip_and_handler ( shirq - > dev_config [ i ] . virq ,
& shirq_chip , handle_simple_irq ) ;
2010-05-03 09:24:30 +01:00
set_irq_flags ( shirq - > dev_config [ i ] . virq , IRQF_VALID ) ;
2011-03-24 13:25:22 +01:00
irq_set_chip_data ( shirq - > dev_config [ i ] . virq , shirq ) ;
2010-05-03 09:24:30 +01:00
}
2011-03-24 13:25:22 +01:00
irq_set_handler_data ( shirq - > irq , shirq ) ;
2010-05-03 09:24:30 +01:00
return 0 ;
}