2019-05-27 09:55:00 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2010-07-17 15:08:43 +04:00
/*
* Copyright ( C ) 2009 - 2010 , Lars - Peter Clausen < lars @ metafoo . de >
2019-10-02 14:25:25 +03:00
* Ingenic XBurst platform IRQ support
2010-07-17 15:08:43 +04:00
*/
# include <linux/errno.h>
# include <linux/init.h>
# include <linux/types.h>
# include <linux/interrupt.h>
# include <linux/ioport.h>
2015-07-08 00:11:46 +03:00
# include <linux/irqchip.h>
2015-05-24 18:11:28 +03:00
# include <linux/of_address.h>
2015-05-24 18:11:21 +03:00
# include <linux/of_irq.h>
2010-07-17 15:08:43 +04:00
# include <linux/timex.h>
# include <linux/slab.h>
# include <linux/delay.h>
# include <asm/io.h>
2014-12-18 05:39:01 +03:00
2015-05-24 18:11:25 +03:00
struct ingenic_intc_data {
void __iomem * base ;
2019-10-02 14:25:23 +03:00
struct irq_domain * domain ;
2015-05-24 18:11:26 +03:00
unsigned num_chips ;
2015-05-24 18:11:25 +03:00
} ;
2010-07-17 15:08:43 +04:00
# define JZ_REG_INTC_STATUS 0x00
# define JZ_REG_INTC_MASK 0x04
# define JZ_REG_INTC_SET_MASK 0x08
# define JZ_REG_INTC_CLEAR_MASK 0x0c
# define JZ_REG_INTC_PENDING 0x10
2015-05-24 18:11:26 +03:00
# define CHIP_SIZE 0x20
2010-07-17 15:08:43 +04:00
2015-05-24 18:11:29 +03:00
static irqreturn_t intc_cascade ( int irq , void * data )
2010-07-17 15:08:43 +04:00
{
2015-05-24 18:11:25 +03:00
struct ingenic_intc_data * intc = irq_get_handler_data ( irq ) ;
2019-10-02 14:25:23 +03:00
struct irq_domain * domain = intc - > domain ;
2019-10-02 14:25:24 +03:00
struct irq_chip_generic * gc ;
2019-10-02 14:25:25 +03:00
uint32_t pending ;
2015-05-24 18:11:26 +03:00
unsigned i ;
2010-07-17 15:08:43 +04:00
2015-05-24 18:11:26 +03:00
for ( i = 0 ; i < intc - > num_chips ; i + + ) {
2019-10-02 14:25:24 +03:00
gc = irq_get_domain_generic_chip ( domain , i * 32 ) ;
2019-10-02 14:25:25 +03:00
pending = irq_reg_readl ( gc , JZ_REG_INTC_PENDING ) ;
if ( ! pending )
2015-05-24 18:11:26 +03:00
continue ;
2010-07-17 15:08:43 +04:00
2019-10-02 14:25:25 +03:00
while ( pending ) {
int bit = __fls ( pending ) ;
2020-01-13 19:33:29 +03:00
irq = irq_linear_revmap ( domain , bit + ( i * 32 ) ) ;
2019-10-02 14:25:25 +03:00
generic_handle_irq ( irq ) ;
pending & = ~ BIT ( bit ) ;
}
2015-05-24 18:11:26 +03:00
}
2011-09-24 04:29:46 +04:00
return IRQ_HANDLED ;
2011-03-24 00:08:53 +03:00
}
2015-05-24 18:11:26 +03:00
static int __init ingenic_intc_of_init ( struct device_node * node ,
unsigned num_chips )
2010-07-17 15:08:43 +04:00
{
2015-05-24 18:11:25 +03:00
struct ingenic_intc_data * intc ;
2011-09-24 04:29:46 +04:00
struct irq_chip_generic * gc ;
struct irq_chip_type * ct ;
2015-05-24 18:11:23 +03:00
struct irq_domain * domain ;
2015-05-24 18:11:25 +03:00
int parent_irq , err = 0 ;
2015-05-24 18:11:26 +03:00
unsigned i ;
2015-05-24 18:11:25 +03:00
intc = kzalloc ( sizeof ( * intc ) , GFP_KERNEL ) ;
if ( ! intc ) {
err = - ENOMEM ;
goto out_err ;
}
2015-05-24 18:11:22 +03:00
parent_irq = irq_of_parse_and_map ( node , 0 ) ;
2015-05-24 18:11:25 +03:00
if ( ! parent_irq ) {
err = - EINVAL ;
goto out_free ;
}
2011-09-24 04:29:46 +04:00
2015-05-24 18:11:25 +03:00
err = irq_set_handler_data ( parent_irq , intc ) ;
if ( err )
goto out_unmap_irq ;
2015-05-24 18:11:26 +03:00
intc - > num_chips = num_chips ;
2015-05-24 18:11:28 +03:00
intc - > base = of_iomap ( node , 0 ) ;
if ( ! intc - > base ) {
err = - ENODEV ;
goto out_unmap_irq ;
}
2010-07-17 15:08:43 +04:00
2020-01-13 19:33:29 +03:00
domain = irq_domain_add_linear ( node , num_chips * 32 ,
2019-10-02 14:25:24 +03:00
& irq_generic_chip_ops , NULL ) ;
2019-10-02 14:25:22 +03:00
if ( ! domain ) {
err = - ENOMEM ;
goto out_unmap_base ;
}
2019-10-02 14:25:23 +03:00
intc - > domain = domain ;
2019-10-02 14:25:24 +03:00
err = irq_alloc_domain_generic_chips ( domain , 32 , 1 , " INTC " ,
handle_level_irq , 0 ,
IRQ_NOPROBE | IRQ_LEVEL , 0 ) ;
if ( err )
goto out_domain_remove ;
2015-05-24 18:11:26 +03:00
2019-10-02 14:25:24 +03:00
for ( i = 0 ; i < num_chips ; i + + ) {
gc = irq_get_domain_generic_chip ( domain , i * 32 ) ;
2015-05-24 18:11:26 +03:00
gc - > wake_enabled = IRQ_MSK ( 32 ) ;
2019-10-02 14:25:24 +03:00
gc - > reg_base = intc - > base + ( i * CHIP_SIZE ) ;
2015-05-24 18:11:26 +03:00
ct = gc - > chip_types ;
ct - > regs . enable = JZ_REG_INTC_CLEAR_MASK ;
ct - > regs . disable = JZ_REG_INTC_SET_MASK ;
ct - > chip . irq_unmask = irq_gc_unmask_enable_reg ;
ct - > chip . irq_mask = irq_gc_mask_disable_reg ;
ct - > chip . irq_mask_ack = irq_gc_mask_disable_reg ;
ct - > chip . irq_set_wake = irq_gc_set_wake ;
2019-10-02 14:25:21 +03:00
ct - > chip . flags = IRQCHIP_MASK_ON_SUSPEND ;
2015-05-24 18:11:26 +03:00
2019-10-02 14:25:24 +03:00
/* Mask all irqs */
irq_reg_writel ( gc , IRQ_MSK ( 32 ) , JZ_REG_INTC_SET_MASK ) ;
2015-05-24 18:11:26 +03:00
}
2010-07-17 15:08:43 +04:00
2020-08-19 21:06:02 +03:00
if ( request_irq ( parent_irq , intc_cascade , IRQF_NO_SUSPEND ,
2020-03-04 03:48:38 +03:00
" SoC intc cascade interrupt " , NULL ) )
pr_err ( " Failed to register SoC intc cascade interrupt \n " ) ;
2015-05-24 18:11:21 +03:00
return 0 ;
2015-05-24 18:11:25 +03:00
2019-10-02 14:25:24 +03:00
out_domain_remove :
irq_domain_remove ( domain ) ;
2019-10-02 14:25:22 +03:00
out_unmap_base :
iounmap ( intc - > base ) ;
2015-05-24 18:11:25 +03:00
out_unmap_irq :
irq_dispose_mapping ( parent_irq ) ;
out_free :
kfree ( intc ) ;
out_err :
return err ;
2010-07-17 15:08:43 +04:00
}
2015-05-24 18:11:26 +03:00
static int __init intc_1chip_of_init ( struct device_node * node ,
struct device_node * parent )
{
return ingenic_intc_of_init ( node , 1 ) ;
}
IRQCHIP_DECLARE ( jz4740_intc , " ingenic,jz4740-intc " , intc_1chip_of_init ) ;
2018-07-13 17:49:09 +03:00
IRQCHIP_DECLARE ( jz4725b_intc , " ingenic,jz4725b-intc " , intc_1chip_of_init ) ;
2015-05-24 18:11:30 +03:00
static int __init intc_2chip_of_init ( struct device_node * node ,
struct device_node * parent )
{
return ingenic_intc_of_init ( node , 2 ) ;
}
2021-03-07 20:20:14 +03:00
IRQCHIP_DECLARE ( jz4760_intc , " ingenic,jz4760-intc " , intc_2chip_of_init ) ;
2015-05-24 18:11:30 +03:00
IRQCHIP_DECLARE ( jz4770_intc , " ingenic,jz4770-intc " , intc_2chip_of_init ) ;
IRQCHIP_DECLARE ( jz4775_intc , " ingenic,jz4775-intc " , intc_2chip_of_init ) ;
IRQCHIP_DECLARE ( jz4780_intc , " ingenic,jz4780-intc " , intc_2chip_of_init ) ;