1397e7b51SDaniel Tang /* 2397e7b51SDaniel Tang * linux/drivers/irqchip/irq-zevio.c 3397e7b51SDaniel Tang * 4397e7b51SDaniel Tang * Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au> 5397e7b51SDaniel Tang * 6397e7b51SDaniel Tang * This program is free software; you can redistribute it and/or modify 7397e7b51SDaniel Tang * it under the terms of the GNU General Public License version 2, as 8397e7b51SDaniel Tang * published by the Free Software Foundation. 9397e7b51SDaniel Tang * 10397e7b51SDaniel Tang */ 11397e7b51SDaniel Tang 12397e7b51SDaniel Tang #include <linux/io.h> 13397e7b51SDaniel Tang #include <linux/irq.h> 14397e7b51SDaniel Tang #include <linux/of.h> 15397e7b51SDaniel Tang #include <linux/of_address.h> 16397e7b51SDaniel Tang #include <linux/of_irq.h> 17397e7b51SDaniel Tang 18397e7b51SDaniel Tang #include <asm/mach/irq.h> 19397e7b51SDaniel Tang #include <asm/exception.h> 20397e7b51SDaniel Tang 21397e7b51SDaniel Tang #include "irqchip.h" 22397e7b51SDaniel Tang 23397e7b51SDaniel Tang #define IO_STATUS 0x000 24397e7b51SDaniel Tang #define IO_RAW_STATUS 0x004 25397e7b51SDaniel Tang #define IO_ENABLE 0x008 26397e7b51SDaniel Tang #define IO_DISABLE 0x00C 27397e7b51SDaniel Tang #define IO_CURRENT 0x020 28397e7b51SDaniel Tang #define IO_RESET 0x028 29397e7b51SDaniel Tang #define IO_MAX_PRIOTY 0x02C 30397e7b51SDaniel Tang 31397e7b51SDaniel Tang #define IO_IRQ_BASE 0x000 32397e7b51SDaniel Tang #define IO_FIQ_BASE 0x100 33397e7b51SDaniel Tang 34397e7b51SDaniel Tang #define IO_INVERT_SEL 0x200 35397e7b51SDaniel Tang #define IO_STICKY_SEL 0x204 36397e7b51SDaniel Tang #define IO_PRIORITY_SEL 0x300 37397e7b51SDaniel Tang 38397e7b51SDaniel Tang #define MAX_INTRS 32 39397e7b51SDaniel Tang #define FIQ_START MAX_INTRS 40397e7b51SDaniel Tang 41397e7b51SDaniel Tang static struct irq_domain *zevio_irq_domain; 42397e7b51SDaniel Tang static void __iomem *zevio_irq_io; 43397e7b51SDaniel Tang 44397e7b51SDaniel Tang static void zevio_irq_ack(struct irq_data *irqd) 45397e7b51SDaniel Tang { 46397e7b51SDaniel Tang struct irq_chip_generic *gc = irq_data_get_irq_chip_data(irqd); 47397e7b51SDaniel Tang struct irq_chip_regs *regs = 48397e7b51SDaniel Tang &container_of(irqd->chip, struct irq_chip_type, chip)->regs; 49397e7b51SDaniel Tang 50397e7b51SDaniel Tang readl(gc->reg_base + regs->ack); 51397e7b51SDaniel Tang } 52397e7b51SDaniel Tang 538783dd3aSStephen Boyd static void __exception_irq_entry zevio_handle_irq(struct pt_regs *regs) 54397e7b51SDaniel Tang { 55397e7b51SDaniel Tang int irqnr; 56397e7b51SDaniel Tang 57397e7b51SDaniel Tang while (readl(zevio_irq_io + IO_STATUS)) { 58397e7b51SDaniel Tang irqnr = readl(zevio_irq_io + IO_CURRENT); 59d8c0ffa5SMarc Zyngier handle_domain_irq(zevio_irq_domain, irqnr, regs); 60397e7b51SDaniel Tang }; 61397e7b51SDaniel Tang } 62397e7b51SDaniel Tang 63397e7b51SDaniel Tang static void __init zevio_init_irq_base(void __iomem *base) 64397e7b51SDaniel Tang { 65397e7b51SDaniel Tang /* Disable all interrupts */ 66397e7b51SDaniel Tang writel(~0, base + IO_DISABLE); 67397e7b51SDaniel Tang 68397e7b51SDaniel Tang /* Accept interrupts of all priorities */ 69397e7b51SDaniel Tang writel(0xF, base + IO_MAX_PRIOTY); 70397e7b51SDaniel Tang 71397e7b51SDaniel Tang /* Reset existing interrupts */ 72397e7b51SDaniel Tang readl(base + IO_RESET); 73397e7b51SDaniel Tang } 74397e7b51SDaniel Tang 75397e7b51SDaniel Tang static int __init zevio_of_init(struct device_node *node, 76397e7b51SDaniel Tang struct device_node *parent) 77397e7b51SDaniel Tang { 78397e7b51SDaniel Tang unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; 79397e7b51SDaniel Tang struct irq_chip_generic *gc; 80397e7b51SDaniel Tang int ret; 81397e7b51SDaniel Tang 82397e7b51SDaniel Tang if (WARN_ON(zevio_irq_io || zevio_irq_domain)) 83397e7b51SDaniel Tang return -EBUSY; 84397e7b51SDaniel Tang 85397e7b51SDaniel Tang zevio_irq_io = of_iomap(node, 0); 86397e7b51SDaniel Tang BUG_ON(!zevio_irq_io); 87397e7b51SDaniel Tang 88397e7b51SDaniel Tang /* Do not invert interrupt status bits */ 89397e7b51SDaniel Tang writel(~0, zevio_irq_io + IO_INVERT_SEL); 90397e7b51SDaniel Tang 91397e7b51SDaniel Tang /* Disable sticky interrupts */ 92397e7b51SDaniel Tang writel(0, zevio_irq_io + IO_STICKY_SEL); 93397e7b51SDaniel Tang 94397e7b51SDaniel Tang /* We don't use IRQ priorities. Set each IRQ to highest priority. */ 95397e7b51SDaniel Tang memset_io(zevio_irq_io + IO_PRIORITY_SEL, 0, MAX_INTRS * sizeof(u32)); 96397e7b51SDaniel Tang 97397e7b51SDaniel Tang /* Init IRQ and FIQ */ 98397e7b51SDaniel Tang zevio_init_irq_base(zevio_irq_io + IO_IRQ_BASE); 99397e7b51SDaniel Tang zevio_init_irq_base(zevio_irq_io + IO_FIQ_BASE); 100397e7b51SDaniel Tang 101397e7b51SDaniel Tang zevio_irq_domain = irq_domain_add_linear(node, MAX_INTRS, 102397e7b51SDaniel Tang &irq_generic_chip_ops, NULL); 103397e7b51SDaniel Tang BUG_ON(!zevio_irq_domain); 104397e7b51SDaniel Tang 105397e7b51SDaniel Tang ret = irq_alloc_domain_generic_chips(zevio_irq_domain, MAX_INTRS, 1, 106397e7b51SDaniel Tang "zevio_intc", handle_level_irq, 107397e7b51SDaniel Tang clr, 0, IRQ_GC_INIT_MASK_CACHE); 108397e7b51SDaniel Tang BUG_ON(ret); 109397e7b51SDaniel Tang 110397e7b51SDaniel Tang gc = irq_get_domain_generic_chip(zevio_irq_domain, 0); 111397e7b51SDaniel Tang gc->reg_base = zevio_irq_io; 112397e7b51SDaniel Tang gc->chip_types[0].chip.irq_ack = zevio_irq_ack; 113397e7b51SDaniel Tang gc->chip_types[0].chip.irq_mask = irq_gc_mask_disable_reg; 114397e7b51SDaniel Tang gc->chip_types[0].chip.irq_unmask = irq_gc_unmask_enable_reg; 115397e7b51SDaniel Tang gc->chip_types[0].regs.mask = IO_IRQ_BASE + IO_ENABLE; 116397e7b51SDaniel Tang gc->chip_types[0].regs.enable = IO_IRQ_BASE + IO_ENABLE; 117397e7b51SDaniel Tang gc->chip_types[0].regs.disable = IO_IRQ_BASE + IO_DISABLE; 118397e7b51SDaniel Tang gc->chip_types[0].regs.ack = IO_IRQ_BASE + IO_RESET; 119397e7b51SDaniel Tang 120397e7b51SDaniel Tang set_handle_irq(zevio_handle_irq); 121397e7b51SDaniel Tang 122397e7b51SDaniel Tang pr_info("TI-NSPIRE classic IRQ controller\n"); 123397e7b51SDaniel Tang return 0; 124397e7b51SDaniel Tang } 125397e7b51SDaniel Tang 126397e7b51SDaniel Tang IRQCHIP_DECLARE(zevio_irq, "lsi,zevio-intc", zevio_of_init); 127