Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'irqchip/tango' into irqchip/core

+287
+49
Documentation/devicetree/bindings/interrupt-controller/sigma,smp8642-intc.txt
··· 1 + Sigma Designs SMP86xx/SMP87xx secondary interrupt controller 2 + 3 + Required properties: 4 + - compatible: should be "sigma,smp8642-intc" 5 + - reg: physical address of MMIO region 6 + - ranges: address space mapping of child nodes 7 + - interrupt-parent: phandle of parent interrupt controller 8 + - interrupt-controller: boolean 9 + - #address-cells: should be <1> 10 + - #size-cells: should be <1> 11 + 12 + One child node per control block with properties: 13 + - reg: address of registers for this control block 14 + - interrupt-controller: boolean 15 + - #interrupt-cells: should be <2>, interrupt index and flags per interrupts.txt 16 + - interrupts: interrupt spec of primary interrupt controller 17 + 18 + Example: 19 + 20 + interrupt-controller@6e000 { 21 + compatible = "sigma,smp8642-intc"; 22 + reg = <0x6e000 0x400>; 23 + ranges = <0x0 0x6e000 0x400>; 24 + interrupt-parent = <&gic>; 25 + interrupt-controller; 26 + #address-cells = <1>; 27 + #size-cells = <1>; 28 + 29 + irq0: interrupt-controller@0 { 30 + reg = <0x000 0x100>; 31 + interrupt-controller; 32 + #interrupt-cells = <2>; 33 + interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>; 34 + }; 35 + 36 + irq1: interrupt-controller@100 { 37 + reg = <0x100 0x100>; 38 + interrupt-controller; 39 + #interrupt-cells = <2>; 40 + interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>; 41 + }; 42 + 43 + irq2: interrupt-controller@300 { 44 + reg = <0x300 0x100>; 45 + interrupt-controller; 46 + #interrupt-cells = <2>; 47 + interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>; 48 + }; 49 + };
+5
drivers/irqchip/Kconfig
··· 156 156 help 157 157 Enables SysCfg Controlled IRQs on STi based platforms. 158 158 159 + config TANGO_IRQ 160 + bool 161 + select IRQ_DOMAIN 162 + select GENERIC_IRQ_CHIP 163 + 159 164 config TB10X_IRQC 160 165 bool 161 166 select IRQ_DOMAIN
+1
drivers/irqchip/Makefile
··· 40 40 obj-$(CONFIG_ARCH_NSPIRE) += irq-zevio.o 41 41 obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o 42 42 obj-$(CONFIG_ST_IRQCHIP) += irq-st.o 43 + obj-$(CONFIG_TANGO_IRQ) += irq-tango.o 43 44 obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o 44 45 obj-$(CONFIG_TS4800_IRQ) += irq-ts4800.o 45 46 obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o
+232
drivers/irqchip/irq-tango.c
··· 1 + /* 2 + * Copyright (C) 2014 Mans Rullgard <mans@mansr.com> 3 + * 4 + * This program is free software; you can redistribute it and/or modify it 5 + * under the terms of the GNU General Public License as published by the 6 + * Free Software Foundation; either version 2 of the License, or (at your 7 + * option) any later version. 8 + */ 9 + 10 + #include <linux/init.h> 11 + #include <linux/irq.h> 12 + #include <linux/irqchip.h> 13 + #include <linux/irqchip/chained_irq.h> 14 + #include <linux/ioport.h> 15 + #include <linux/io.h> 16 + #include <linux/of_address.h> 17 + #include <linux/of_irq.h> 18 + #include <linux/slab.h> 19 + 20 + #define IRQ0_CTL_BASE 0x0000 21 + #define IRQ1_CTL_BASE 0x0100 22 + #define EDGE_CTL_BASE 0x0200 23 + #define IRQ2_CTL_BASE 0x0300 24 + 25 + #define IRQ_CTL_HI 0x18 26 + #define EDGE_CTL_HI 0x20 27 + 28 + #define IRQ_STATUS 0x00 29 + #define IRQ_RAWSTAT 0x04 30 + #define IRQ_EN_SET 0x08 31 + #define IRQ_EN_CLR 0x0c 32 + #define IRQ_SOFT_SET 0x10 33 + #define IRQ_SOFT_CLR 0x14 34 + 35 + #define EDGE_STATUS 0x00 36 + #define EDGE_RAWSTAT 0x04 37 + #define EDGE_CFG_RISE 0x08 38 + #define EDGE_CFG_FALL 0x0c 39 + #define EDGE_CFG_RISE_SET 0x10 40 + #define EDGE_CFG_RISE_CLR 0x14 41 + #define EDGE_CFG_FALL_SET 0x18 42 + #define EDGE_CFG_FALL_CLR 0x1c 43 + 44 + struct tangox_irq_chip { 45 + void __iomem *base; 46 + unsigned long ctl; 47 + }; 48 + 49 + static inline u32 intc_readl(struct tangox_irq_chip *chip, int reg) 50 + { 51 + return readl_relaxed(chip->base + reg); 52 + } 53 + 54 + static inline void intc_writel(struct tangox_irq_chip *chip, int reg, u32 val) 55 + { 56 + writel_relaxed(val, chip->base + reg); 57 + } 58 + 59 + static void tangox_dispatch_irqs(struct irq_domain *dom, unsigned int status, 60 + int base) 61 + { 62 + unsigned int hwirq; 63 + unsigned int virq; 64 + 65 + while (status) { 66 + hwirq = __ffs(status); 67 + virq = irq_find_mapping(dom, base + hwirq); 68 + if (virq) 69 + generic_handle_irq(virq); 70 + status &= ~BIT(hwirq); 71 + } 72 + } 73 + 74 + static void tangox_irq_handler(struct irq_desc *desc) 75 + { 76 + struct irq_domain *dom = irq_desc_get_handler_data(desc); 77 + struct irq_chip *host_chip = irq_desc_get_chip(desc); 78 + struct tangox_irq_chip *chip = dom->host_data; 79 + unsigned int status_lo, status_hi; 80 + 81 + chained_irq_enter(host_chip, desc); 82 + 83 + status_lo = intc_readl(chip, chip->ctl + IRQ_STATUS); 84 + status_hi = intc_readl(chip, chip->ctl + IRQ_CTL_HI + IRQ_STATUS); 85 + 86 + tangox_dispatch_irqs(dom, status_lo, 0); 87 + tangox_dispatch_irqs(dom, status_hi, 32); 88 + 89 + chained_irq_exit(host_chip, desc); 90 + } 91 + 92 + static int tangox_irq_set_type(struct irq_data *d, unsigned int flow_type) 93 + { 94 + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 95 + struct tangox_irq_chip *chip = gc->domain->host_data; 96 + struct irq_chip_regs *regs = &gc->chip_types[0].regs; 97 + 98 + switch (flow_type & IRQ_TYPE_SENSE_MASK) { 99 + case IRQ_TYPE_EDGE_RISING: 100 + intc_writel(chip, regs->type + EDGE_CFG_RISE_SET, d->mask); 101 + intc_writel(chip, regs->type + EDGE_CFG_FALL_CLR, d->mask); 102 + break; 103 + 104 + case IRQ_TYPE_EDGE_FALLING: 105 + intc_writel(chip, regs->type + EDGE_CFG_RISE_CLR, d->mask); 106 + intc_writel(chip, regs->type + EDGE_CFG_FALL_SET, d->mask); 107 + break; 108 + 109 + case IRQ_TYPE_LEVEL_HIGH: 110 + intc_writel(chip, regs->type + EDGE_CFG_RISE_CLR, d->mask); 111 + intc_writel(chip, regs->type + EDGE_CFG_FALL_CLR, d->mask); 112 + break; 113 + 114 + case IRQ_TYPE_LEVEL_LOW: 115 + intc_writel(chip, regs->type + EDGE_CFG_RISE_SET, d->mask); 116 + intc_writel(chip, regs->type + EDGE_CFG_FALL_SET, d->mask); 117 + break; 118 + 119 + default: 120 + pr_err("Invalid trigger mode %x for IRQ %d\n", 121 + flow_type, d->irq); 122 + return -EINVAL; 123 + } 124 + 125 + return irq_setup_alt_chip(d, flow_type); 126 + } 127 + 128 + static void __init tangox_irq_init_chip(struct irq_chip_generic *gc, 129 + unsigned long ctl_offs, 130 + unsigned long edge_offs) 131 + { 132 + struct tangox_irq_chip *chip = gc->domain->host_data; 133 + struct irq_chip_type *ct = gc->chip_types; 134 + unsigned long ctl_base = chip->ctl + ctl_offs; 135 + unsigned long edge_base = EDGE_CTL_BASE + edge_offs; 136 + int i; 137 + 138 + gc->reg_base = chip->base; 139 + gc->unused = 0; 140 + 141 + for (i = 0; i < 2; i++) { 142 + ct[i].chip.irq_ack = irq_gc_ack_set_bit; 143 + ct[i].chip.irq_mask = irq_gc_mask_disable_reg; 144 + ct[i].chip.irq_mask_ack = irq_gc_mask_disable_reg_and_ack; 145 + ct[i].chip.irq_unmask = irq_gc_unmask_enable_reg; 146 + ct[i].chip.irq_set_type = tangox_irq_set_type; 147 + ct[i].chip.name = gc->domain->name; 148 + 149 + ct[i].regs.enable = ctl_base + IRQ_EN_SET; 150 + ct[i].regs.disable = ctl_base + IRQ_EN_CLR; 151 + ct[i].regs.ack = edge_base + EDGE_RAWSTAT; 152 + ct[i].regs.type = edge_base; 153 + } 154 + 155 + ct[0].type = IRQ_TYPE_LEVEL_MASK; 156 + ct[0].handler = handle_level_irq; 157 + 158 + ct[1].type = IRQ_TYPE_EDGE_BOTH; 159 + ct[1].handler = handle_edge_irq; 160 + 161 + intc_writel(chip, ct->regs.disable, 0xffffffff); 162 + intc_writel(chip, ct->regs.ack, 0xffffffff); 163 + } 164 + 165 + static void __init tangox_irq_domain_init(struct irq_domain *dom) 166 + { 167 + struct irq_chip_generic *gc; 168 + int i; 169 + 170 + for (i = 0; i < 2; i++) { 171 + gc = irq_get_domain_generic_chip(dom, i * 32); 172 + tangox_irq_init_chip(gc, i * IRQ_CTL_HI, i * EDGE_CTL_HI); 173 + } 174 + } 175 + 176 + static int __init tangox_irq_init(void __iomem *base, struct resource *baseres, 177 + struct device_node *node) 178 + { 179 + struct tangox_irq_chip *chip; 180 + struct irq_domain *dom; 181 + struct resource res; 182 + int irq; 183 + int err; 184 + 185 + irq = irq_of_parse_and_map(node, 0); 186 + if (!irq) 187 + panic("%s: failed to get IRQ", node->name); 188 + 189 + err = of_address_to_resource(node, 0, &res); 190 + if (err) 191 + panic("%s: failed to get address", node->name); 192 + 193 + chip = kzalloc(sizeof(*chip), GFP_KERNEL); 194 + chip->ctl = res.start - baseres->start; 195 + chip->base = base; 196 + 197 + dom = irq_domain_add_linear(node, 64, &irq_generic_chip_ops, chip); 198 + if (!dom) 199 + panic("%s: failed to create irqdomain", node->name); 200 + 201 + err = irq_alloc_domain_generic_chips(dom, 32, 2, node->name, 202 + handle_level_irq, 0, 0, 0); 203 + if (err) 204 + panic("%s: failed to allocate irqchip", node->name); 205 + 206 + tangox_irq_domain_init(dom); 207 + 208 + irq_set_chained_handler(irq, tangox_irq_handler); 209 + irq_set_handler_data(irq, dom); 210 + 211 + return 0; 212 + } 213 + 214 + static int __init tangox_of_irq_init(struct device_node *node, 215 + struct device_node *parent) 216 + { 217 + struct device_node *c; 218 + struct resource res; 219 + void __iomem *base; 220 + 221 + base = of_iomap(node, 0); 222 + if (!base) 223 + panic("%s: of_iomap failed", node->name); 224 + 225 + of_address_to_resource(node, 0, &res); 226 + 227 + for_each_child_of_node(node, c) 228 + tangox_irq_init(base, &res, c); 229 + 230 + return 0; 231 + } 232 + IRQCHIP_DECLARE(tangox_intc, "sigma,smp8642-intc", tangox_of_irq_init);