2010-01-06 10:14:51 +09:00
/* arch/arm/plat-samsung/irq-vic-timer.c
* originally part of arch / arm / plat - s3c64xx / irq . c
*
* Copyright 2008 Openmoko , Inc .
* Copyright 2008 Simtec Electronics
* Ben Dooks < ben @ simtec . co . uk >
* http : //armlinux.simtec.co.uk/
*
* S3C64XX - Interrupt handling
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/kernel.h>
# include <linux/interrupt.h>
# include <linux/irq.h>
# include <linux/io.h>
# include <mach/map.h>
2012-01-25 13:48:11 +09:00
# include <plat/cpu.h>
2010-01-06 10:14:51 +09:00
# include <plat/irq-vic-timer.h>
# include <plat/regs-timer.h>
2011-08-18 13:02:12 +09:00
# include <asm/mach/irq.h>
2010-01-06 10:14:51 +09:00
static void s3c_irq_demux_vic_timer ( unsigned int irq , struct irq_desc * desc )
{
2011-08-18 13:02:12 +09:00
struct irq_chip * chip = irq_get_chip ( irq ) ;
chained_irq_enter ( chip , desc ) ;
2010-12-14 22:55:57 +01:00
generic_handle_irq ( ( int ) desc - > irq_data . handler_data ) ;
2011-08-18 13:02:12 +09:00
chained_irq_exit ( chip , desc ) ;
2010-01-06 10:14:51 +09:00
}
/* We assume the IRQ_TIMER0..IRQ_TIMER4 range is continuous. */
2011-05-09 10:09:26 +02:00
static void s3c_irq_timer_ack ( struct irq_data * d )
2010-01-06 10:14:51 +09:00
{
2011-05-09 10:09:26 +02:00
struct irq_chip_generic * gc = irq_data_get_irq_chip_data ( d ) ;
u32 mask = ( 1 < < 5 ) < < ( d - > irq - gc - > irq_base ) ;
2010-01-06 10:14:51 +09:00
2011-05-09 10:09:26 +02:00
irq_reg_writel ( mask | gc - > mask_cache , gc - > reg_base ) ;
2010-01-06 10:14:51 +09:00
}
/**
* s3c_init_vic_timer_irq ( ) - initialise timer irq chanined off VIC . \
2011-05-09 10:09:26 +02:00
* @ num : Number of timers to initialize
* @ timer_irq : Base IRQ number to be used for the timers .
2010-01-06 10:14:51 +09:00
*
* Register the necessary IRQ chaining and support for the timer IRQs
* chained of the VIC .
*/
2011-05-09 10:09:26 +02:00
void __init s3c_init_vic_timer_irq ( unsigned int num , unsigned int timer_irq )
2010-01-06 10:14:51 +09:00
{
2011-05-09 10:09:26 +02:00
unsigned int pirq [ 5 ] = { IRQ_TIMER0_VIC , IRQ_TIMER1_VIC , IRQ_TIMER2_VIC ,
IRQ_TIMER3_VIC , IRQ_TIMER4_VIC } ;
struct irq_chip_generic * s3c_tgc ;
struct irq_chip_type * ct ;
unsigned int i ;
2010-01-06 10:14:51 +09:00
2012-01-25 13:48:11 +09:00
# ifdef CONFIG_ARCH_EXYNOS
if ( soc_is_exynos5250 ( ) ) {
pirq [ 0 ] = EXYNOS5_IRQ_TIMER0_VIC ;
pirq [ 1 ] = EXYNOS5_IRQ_TIMER1_VIC ;
pirq [ 2 ] = EXYNOS5_IRQ_TIMER2_VIC ;
pirq [ 3 ] = EXYNOS5_IRQ_TIMER3_VIC ;
pirq [ 4 ] = EXYNOS5_IRQ_TIMER4_VIC ;
} else {
pirq [ 0 ] = EXYNOS4_IRQ_TIMER0_VIC ;
pirq [ 1 ] = EXYNOS4_IRQ_TIMER1_VIC ;
pirq [ 2 ] = EXYNOS4_IRQ_TIMER2_VIC ;
pirq [ 3 ] = EXYNOS4_IRQ_TIMER3_VIC ;
pirq [ 4 ] = EXYNOS4_IRQ_TIMER4_VIC ;
}
# endif
2011-05-09 10:09:26 +02:00
s3c_tgc = irq_alloc_generic_chip ( " s3c-timer " , 1 , timer_irq ,
S3C64XX_TINT_CSTAT , handle_level_irq ) ;
2011-07-16 11:13:47 +09:00
if ( ! s3c_tgc ) {
pr_err ( " %s: irq_alloc_generic_chip for IRQ %d failed \n " ,
__func__ , timer_irq ) ;
return ;
}
2011-05-09 10:09:26 +02:00
ct = s3c_tgc - > chip_types ;
ct - > chip . irq_mask = irq_gc_mask_clr_bit ;
ct - > chip . irq_unmask = irq_gc_mask_set_bit ;
ct - > chip . irq_ack = s3c_irq_timer_ack ;
irq_setup_generic_chip ( s3c_tgc , IRQ_MSK ( num ) , IRQ_GC_INIT_MASK_CACHE ,
IRQ_NOREQUEST | IRQ_NOPROBE , 0 ) ;
/* Clear the upper bits of the mask_cache*/
s3c_tgc - > mask_cache & = 0x1f ;
2010-01-06 10:14:51 +09:00
2011-05-09 10:09:26 +02:00
for ( i = 0 ; i < num ; i + + , timer_irq + + ) {
irq_set_chained_handler ( pirq [ i ] , s3c_irq_demux_vic_timer ) ;
irq_set_handler_data ( pirq [ i ] , ( void * ) timer_irq ) ;
}
2010-01-06 10:14:51 +09:00
}