1*44e08e70SPaul Burton /* 2*44e08e70SPaul Burton * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de> 3*44e08e70SPaul Burton * JZ4740 platform IRQ support 4*44e08e70SPaul Burton * 5*44e08e70SPaul Burton * This program is free software; you can redistribute it and/or modify it 6*44e08e70SPaul Burton * under the terms of the GNU General Public License as published by the 7*44e08e70SPaul Burton * Free Software Foundation; either version 2 of the License, or (at your 8*44e08e70SPaul Burton * option) any later version. 9*44e08e70SPaul Burton * 10*44e08e70SPaul Burton * You should have received a copy of the GNU General Public License along 11*44e08e70SPaul Burton * with this program; if not, write to the Free Software Foundation, Inc., 12*44e08e70SPaul Burton * 675 Mass Ave, Cambridge, MA 02139, USA. 13*44e08e70SPaul Burton * 14*44e08e70SPaul Burton */ 15*44e08e70SPaul Burton 16*44e08e70SPaul Burton #include <linux/errno.h> 17*44e08e70SPaul Burton #include <linux/init.h> 18*44e08e70SPaul Burton #include <linux/types.h> 19*44e08e70SPaul Burton #include <linux/interrupt.h> 20*44e08e70SPaul Burton #include <linux/ioport.h> 21*44e08e70SPaul Burton #include <linux/irqchip/ingenic.h> 22*44e08e70SPaul Burton #include <linux/of_address.h> 23*44e08e70SPaul Burton #include <linux/of_irq.h> 24*44e08e70SPaul Burton #include <linux/timex.h> 25*44e08e70SPaul Burton #include <linux/slab.h> 26*44e08e70SPaul Burton #include <linux/delay.h> 27*44e08e70SPaul Burton 28*44e08e70SPaul Burton #include <asm/io.h> 29*44e08e70SPaul Burton #include <asm/mach-jz4740/irq.h> 30*44e08e70SPaul Burton 31*44e08e70SPaul Burton #include "irqchip.h" 32*44e08e70SPaul Burton 33*44e08e70SPaul Burton struct ingenic_intc_data { 34*44e08e70SPaul Burton void __iomem *base; 35*44e08e70SPaul Burton unsigned num_chips; 36*44e08e70SPaul Burton }; 37*44e08e70SPaul Burton 38*44e08e70SPaul Burton #define JZ_REG_INTC_STATUS 0x00 39*44e08e70SPaul Burton #define JZ_REG_INTC_MASK 0x04 40*44e08e70SPaul Burton #define JZ_REG_INTC_SET_MASK 0x08 41*44e08e70SPaul Burton #define JZ_REG_INTC_CLEAR_MASK 0x0c 42*44e08e70SPaul Burton #define JZ_REG_INTC_PENDING 0x10 43*44e08e70SPaul Burton #define CHIP_SIZE 0x20 44*44e08e70SPaul Burton 45*44e08e70SPaul Burton static irqreturn_t intc_cascade(int irq, void *data) 46*44e08e70SPaul Burton { 47*44e08e70SPaul Burton struct ingenic_intc_data *intc = irq_get_handler_data(irq); 48*44e08e70SPaul Burton uint32_t irq_reg; 49*44e08e70SPaul Burton unsigned i; 50*44e08e70SPaul Burton 51*44e08e70SPaul Burton for (i = 0; i < intc->num_chips; i++) { 52*44e08e70SPaul Burton irq_reg = readl(intc->base + (i * CHIP_SIZE) + 53*44e08e70SPaul Burton JZ_REG_INTC_PENDING); 54*44e08e70SPaul Burton if (!irq_reg) 55*44e08e70SPaul Burton continue; 56*44e08e70SPaul Burton 57*44e08e70SPaul Burton generic_handle_irq(__fls(irq_reg) + (i * 32) + JZ4740_IRQ_BASE); 58*44e08e70SPaul Burton } 59*44e08e70SPaul Burton 60*44e08e70SPaul Burton return IRQ_HANDLED; 61*44e08e70SPaul Burton } 62*44e08e70SPaul Burton 63*44e08e70SPaul Burton static void intc_irq_set_mask(struct irq_chip_generic *gc, uint32_t mask) 64*44e08e70SPaul Burton { 65*44e08e70SPaul Burton struct irq_chip_regs *regs = &gc->chip_types->regs; 66*44e08e70SPaul Burton 67*44e08e70SPaul Burton writel(mask, gc->reg_base + regs->enable); 68*44e08e70SPaul Burton writel(~mask, gc->reg_base + regs->disable); 69*44e08e70SPaul Burton } 70*44e08e70SPaul Burton 71*44e08e70SPaul Burton void ingenic_intc_irq_suspend(struct irq_data *data) 72*44e08e70SPaul Burton { 73*44e08e70SPaul Burton struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); 74*44e08e70SPaul Burton intc_irq_set_mask(gc, gc->wake_active); 75*44e08e70SPaul Burton } 76*44e08e70SPaul Burton 77*44e08e70SPaul Burton void ingenic_intc_irq_resume(struct irq_data *data) 78*44e08e70SPaul Burton { 79*44e08e70SPaul Burton struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); 80*44e08e70SPaul Burton intc_irq_set_mask(gc, gc->mask_cache); 81*44e08e70SPaul Burton } 82*44e08e70SPaul Burton 83*44e08e70SPaul Burton static struct irqaction intc_cascade_action = { 84*44e08e70SPaul Burton .handler = intc_cascade, 85*44e08e70SPaul Burton .name = "SoC intc cascade interrupt", 86*44e08e70SPaul Burton }; 87*44e08e70SPaul Burton 88*44e08e70SPaul Burton static int __init ingenic_intc_of_init(struct device_node *node, 89*44e08e70SPaul Burton unsigned num_chips) 90*44e08e70SPaul Burton { 91*44e08e70SPaul Burton struct ingenic_intc_data *intc; 92*44e08e70SPaul Burton struct irq_chip_generic *gc; 93*44e08e70SPaul Burton struct irq_chip_type *ct; 94*44e08e70SPaul Burton struct irq_domain *domain; 95*44e08e70SPaul Burton int parent_irq, err = 0; 96*44e08e70SPaul Burton unsigned i; 97*44e08e70SPaul Burton 98*44e08e70SPaul Burton intc = kzalloc(sizeof(*intc), GFP_KERNEL); 99*44e08e70SPaul Burton if (!intc) { 100*44e08e70SPaul Burton err = -ENOMEM; 101*44e08e70SPaul Burton goto out_err; 102*44e08e70SPaul Burton } 103*44e08e70SPaul Burton 104*44e08e70SPaul Burton parent_irq = irq_of_parse_and_map(node, 0); 105*44e08e70SPaul Burton if (!parent_irq) { 106*44e08e70SPaul Burton err = -EINVAL; 107*44e08e70SPaul Burton goto out_free; 108*44e08e70SPaul Burton } 109*44e08e70SPaul Burton 110*44e08e70SPaul Burton err = irq_set_handler_data(parent_irq, intc); 111*44e08e70SPaul Burton if (err) 112*44e08e70SPaul Burton goto out_unmap_irq; 113*44e08e70SPaul Burton 114*44e08e70SPaul Burton intc->num_chips = num_chips; 115*44e08e70SPaul Burton intc->base = of_iomap(node, 0); 116*44e08e70SPaul Burton if (!intc->base) { 117*44e08e70SPaul Burton err = -ENODEV; 118*44e08e70SPaul Burton goto out_unmap_irq; 119*44e08e70SPaul Burton } 120*44e08e70SPaul Burton 121*44e08e70SPaul Burton for (i = 0; i < num_chips; i++) { 122*44e08e70SPaul Burton /* Mask all irqs */ 123*44e08e70SPaul Burton writel(0xffffffff, intc->base + (i * CHIP_SIZE) + 124*44e08e70SPaul Burton JZ_REG_INTC_SET_MASK); 125*44e08e70SPaul Burton 126*44e08e70SPaul Burton gc = irq_alloc_generic_chip("INTC", 1, 127*44e08e70SPaul Burton JZ4740_IRQ_BASE + (i * 32), 128*44e08e70SPaul Burton intc->base + (i * CHIP_SIZE), 129*44e08e70SPaul Burton handle_level_irq); 130*44e08e70SPaul Burton 131*44e08e70SPaul Burton gc->wake_enabled = IRQ_MSK(32); 132*44e08e70SPaul Burton 133*44e08e70SPaul Burton ct = gc->chip_types; 134*44e08e70SPaul Burton ct->regs.enable = JZ_REG_INTC_CLEAR_MASK; 135*44e08e70SPaul Burton ct->regs.disable = JZ_REG_INTC_SET_MASK; 136*44e08e70SPaul Burton ct->chip.irq_unmask = irq_gc_unmask_enable_reg; 137*44e08e70SPaul Burton ct->chip.irq_mask = irq_gc_mask_disable_reg; 138*44e08e70SPaul Burton ct->chip.irq_mask_ack = irq_gc_mask_disable_reg; 139*44e08e70SPaul Burton ct->chip.irq_set_wake = irq_gc_set_wake; 140*44e08e70SPaul Burton ct->chip.irq_suspend = ingenic_intc_irq_suspend; 141*44e08e70SPaul Burton ct->chip.irq_resume = ingenic_intc_irq_resume; 142*44e08e70SPaul Burton 143*44e08e70SPaul Burton irq_setup_generic_chip(gc, IRQ_MSK(32), 0, 0, 144*44e08e70SPaul Burton IRQ_NOPROBE | IRQ_LEVEL); 145*44e08e70SPaul Burton } 146*44e08e70SPaul Burton 147*44e08e70SPaul Burton domain = irq_domain_add_legacy(node, num_chips * 32, JZ4740_IRQ_BASE, 0, 148*44e08e70SPaul Burton &irq_domain_simple_ops, NULL); 149*44e08e70SPaul Burton if (!domain) 150*44e08e70SPaul Burton pr_warn("unable to register IRQ domain\n"); 151*44e08e70SPaul Burton 152*44e08e70SPaul Burton setup_irq(parent_irq, &intc_cascade_action); 153*44e08e70SPaul Burton return 0; 154*44e08e70SPaul Burton 155*44e08e70SPaul Burton out_unmap_irq: 156*44e08e70SPaul Burton irq_dispose_mapping(parent_irq); 157*44e08e70SPaul Burton out_free: 158*44e08e70SPaul Burton kfree(intc); 159*44e08e70SPaul Burton out_err: 160*44e08e70SPaul Burton return err; 161*44e08e70SPaul Burton } 162*44e08e70SPaul Burton 163*44e08e70SPaul Burton static int __init intc_1chip_of_init(struct device_node *node, 164*44e08e70SPaul Burton struct device_node *parent) 165*44e08e70SPaul Burton { 166*44e08e70SPaul Burton return ingenic_intc_of_init(node, 1); 167*44e08e70SPaul Burton } 168*44e08e70SPaul Burton IRQCHIP_DECLARE(jz4740_intc, "ingenic,jz4740-intc", intc_1chip_of_init); 169*44e08e70SPaul Burton 170*44e08e70SPaul Burton static int __init intc_2chip_of_init(struct device_node *node, 171*44e08e70SPaul Burton struct device_node *parent) 172*44e08e70SPaul Burton { 173*44e08e70SPaul Burton return ingenic_intc_of_init(node, 2); 174*44e08e70SPaul Burton } 175*44e08e70SPaul Burton IRQCHIP_DECLARE(jz4770_intc, "ingenic,jz4770-intc", intc_2chip_of_init); 176*44e08e70SPaul Burton IRQCHIP_DECLARE(jz4775_intc, "ingenic,jz4775-intc", intc_2chip_of_init); 177*44e08e70SPaul Burton IRQCHIP_DECLARE(jz4780_intc, "ingenic,jz4780-intc", intc_2chip_of_init); 178