diff options
Diffstat (limited to 'arch/mips/jz4740/irq.c')
-rw-r--r-- | arch/mips/jz4740/irq.c | 71 |
1 files changed, 46 insertions, 25 deletions
diff --git a/arch/mips/jz4740/irq.c b/arch/mips/jz4740/irq.c index 854cd14bea94..7ad6688f371b 100644 --- a/arch/mips/jz4740/irq.c +++ b/arch/mips/jz4740/irq.c @@ -34,6 +34,7 @@ struct ingenic_intc_data { void __iomem *base; + unsigned num_chips; }; #define JZ_REG_INTC_STATUS 0x00 @@ -41,16 +42,22 @@ struct ingenic_intc_data { #define JZ_REG_INTC_SET_MASK 0x08 #define JZ_REG_INTC_CLEAR_MASK 0x0c #define JZ_REG_INTC_PENDING 0x10 +#define CHIP_SIZE 0x20 static irqreturn_t jz4740_cascade(int irq, void *data) { struct ingenic_intc_data *intc = irq_get_handler_data(irq); uint32_t irq_reg; + unsigned i; - irq_reg = readl(intc->base + JZ_REG_INTC_PENDING); + for (i = 0; i < intc->num_chips; i++) { + irq_reg = readl(intc->base + (i * CHIP_SIZE) + + JZ_REG_INTC_PENDING); + if (!irq_reg) + continue; - if (irq_reg) - generic_handle_irq(__fls(irq_reg) + JZ4740_IRQ_BASE); + generic_handle_irq(__fls(irq_reg) + (i * 32) + JZ4740_IRQ_BASE); + } return IRQ_HANDLED; } @@ -80,14 +87,15 @@ static struct irqaction jz4740_cascade_action = { .name = "JZ4740 cascade interrupt", }; -static int __init jz4740_intc_of_init(struct device_node *node, - struct device_node *parent) +static int __init ingenic_intc_of_init(struct device_node *node, + unsigned num_chips) { struct ingenic_intc_data *intc; struct irq_chip_generic *gc; struct irq_chip_type *ct; struct irq_domain *domain; int parent_irq, err = 0; + unsigned i; intc = kzalloc(sizeof(*intc), GFP_KERNEL); if (!intc) { @@ -105,27 +113,34 @@ static int __init jz4740_intc_of_init(struct device_node *node, if (err) goto out_unmap_irq; + intc->num_chips = num_chips; intc->base = ioremap(JZ4740_INTC_BASE_ADDR, 0x14); - /* Mask all irqs */ - writel(0xffffffff, intc->base + JZ_REG_INTC_SET_MASK); - - gc = irq_alloc_generic_chip("INTC", 1, JZ4740_IRQ_BASE, intc->base, - handle_level_irq); - - gc->wake_enabled = IRQ_MSK(32); - - 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; - ct->chip.irq_suspend = jz4740_irq_suspend; - ct->chip.irq_resume = jz4740_irq_resume; - - irq_setup_generic_chip(gc, IRQ_MSK(32), 0, 0, IRQ_NOPROBE | IRQ_LEVEL); + for (i = 0; i < num_chips; i++) { + /* Mask all irqs */ + writel(0xffffffff, intc->base + (i * CHIP_SIZE) + + JZ_REG_INTC_SET_MASK); + + gc = irq_alloc_generic_chip("INTC", 1, + JZ4740_IRQ_BASE + (i * 32), + intc->base + (i * CHIP_SIZE), + handle_level_irq); + + gc->wake_enabled = IRQ_MSK(32); + + 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; + ct->chip.irq_suspend = jz4740_irq_suspend; + ct->chip.irq_resume = jz4740_irq_resume; + + irq_setup_generic_chip(gc, IRQ_MSK(32), 0, 0, + IRQ_NOPROBE | IRQ_LEVEL); + } domain = irq_domain_add_legacy(node, num_chips * 32, JZ4740_IRQ_BASE, 0, &irq_domain_simple_ops, NULL); @@ -142,4 +157,10 @@ out_free: out_err: return err; } -IRQCHIP_DECLARE(jz4740_intc, "ingenic,jz4740-intc", jz4740_intc_of_init); + +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); |