2013-12-05 10:12:17 +04:00
/*
* linux / drivers / irqchip / irq - zevio . c
*
* Copyright ( C ) 2013 Daniel Tang < tangrs @ tangrs . id . au >
*
* 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/io.h>
# include <linux/irq.h>
2015-07-08 00:11:46 +03:00
# include <linux/irqchip.h>
2013-12-05 10:12:17 +04:00
# include <linux/of.h>
# include <linux/of_address.h>
# include <linux/of_irq.h>
# include <asm/mach/irq.h>
# include <asm/exception.h>
# define IO_STATUS 0x000
# define IO_RAW_STATUS 0x004
# define IO_ENABLE 0x008
# define IO_DISABLE 0x00C
# define IO_CURRENT 0x020
# define IO_RESET 0x028
# define IO_MAX_PRIOTY 0x02C
# define IO_IRQ_BASE 0x000
# define IO_FIQ_BASE 0x100
# define IO_INVERT_SEL 0x200
# define IO_STICKY_SEL 0x204
# define IO_PRIORITY_SEL 0x300
# define MAX_INTRS 32
# define FIQ_START MAX_INTRS
static struct irq_domain * zevio_irq_domain ;
static void __iomem * zevio_irq_io ;
static void zevio_irq_ack ( struct irq_data * irqd )
{
struct irq_chip_generic * gc = irq_data_get_irq_chip_data ( irqd ) ;
2015-12-30 17:16:37 +03:00
struct irq_chip_regs * regs = & irq_data_get_chip_type ( irqd ) - > regs ;
2013-12-05 10:12:17 +04:00
readl ( gc - > reg_base + regs - > ack ) ;
}
2014-03-05 04:40:30 +04:00
static void __exception_irq_entry zevio_handle_irq ( struct pt_regs * regs )
2013-12-05 10:12:17 +04:00
{
int irqnr ;
while ( readl ( zevio_irq_io + IO_STATUS ) ) {
irqnr = readl ( zevio_irq_io + IO_CURRENT ) ;
2014-08-26 14:03:32 +04:00
handle_domain_irq ( zevio_irq_domain , irqnr , regs ) ;
2013-12-05 10:12:17 +04:00
} ;
}
static void __init zevio_init_irq_base ( void __iomem * base )
{
/* Disable all interrupts */
writel ( ~ 0 , base + IO_DISABLE ) ;
/* Accept interrupts of all priorities */
writel ( 0xF , base + IO_MAX_PRIOTY ) ;
/* Reset existing interrupts */
readl ( base + IO_RESET ) ;
}
static int __init zevio_of_init ( struct device_node * node ,
struct device_node * parent )
{
unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN ;
struct irq_chip_generic * gc ;
int ret ;
if ( WARN_ON ( zevio_irq_io | | zevio_irq_domain ) )
return - EBUSY ;
zevio_irq_io = of_iomap ( node , 0 ) ;
BUG_ON ( ! zevio_irq_io ) ;
/* Do not invert interrupt status bits */
writel ( ~ 0 , zevio_irq_io + IO_INVERT_SEL ) ;
/* Disable sticky interrupts */
writel ( 0 , zevio_irq_io + IO_STICKY_SEL ) ;
/* We don't use IRQ priorities. Set each IRQ to highest priority. */
memset_io ( zevio_irq_io + IO_PRIORITY_SEL , 0 , MAX_INTRS * sizeof ( u32 ) ) ;
/* Init IRQ and FIQ */
zevio_init_irq_base ( zevio_irq_io + IO_IRQ_BASE ) ;
zevio_init_irq_base ( zevio_irq_io + IO_FIQ_BASE ) ;
zevio_irq_domain = irq_domain_add_linear ( node , MAX_INTRS ,
& irq_generic_chip_ops , NULL ) ;
BUG_ON ( ! zevio_irq_domain ) ;
ret = irq_alloc_domain_generic_chips ( zevio_irq_domain , MAX_INTRS , 1 ,
" zevio_intc " , handle_level_irq ,
clr , 0 , IRQ_GC_INIT_MASK_CACHE ) ;
BUG_ON ( ret ) ;
gc = irq_get_domain_generic_chip ( zevio_irq_domain , 0 ) ;
gc - > reg_base = zevio_irq_io ;
gc - > chip_types [ 0 ] . chip . irq_ack = zevio_irq_ack ;
gc - > chip_types [ 0 ] . chip . irq_mask = irq_gc_mask_disable_reg ;
gc - > chip_types [ 0 ] . chip . irq_unmask = irq_gc_unmask_enable_reg ;
gc - > chip_types [ 0 ] . regs . mask = IO_IRQ_BASE + IO_ENABLE ;
gc - > chip_types [ 0 ] . regs . enable = IO_IRQ_BASE + IO_ENABLE ;
gc - > chip_types [ 0 ] . regs . disable = IO_IRQ_BASE + IO_DISABLE ;
gc - > chip_types [ 0 ] . regs . ack = IO_IRQ_BASE + IO_RESET ;
set_handle_irq ( zevio_handle_irq ) ;
pr_info ( " TI-NSPIRE classic IRQ controller \n " ) ;
return 0 ;
}
IRQCHIP_DECLARE ( zevio_irq , " lsi,zevio-intc " , zevio_of_init ) ;