1*b1479ebbSBoris BREZILLON /* 2*b1479ebbSBoris BREZILLON * Atmel AT91 common AIC (Advanced Interrupt Controller) code shared by 3*b1479ebbSBoris BREZILLON * irq-atmel-aic and irq-atmel-aic5 drivers 4*b1479ebbSBoris BREZILLON * 5*b1479ebbSBoris BREZILLON * Copyright (C) 2004 SAN People 6*b1479ebbSBoris BREZILLON * Copyright (C) 2004 ATMEL 7*b1479ebbSBoris BREZILLON * Copyright (C) Rick Bronson 8*b1479ebbSBoris BREZILLON * Copyright (C) 2014 Free Electrons 9*b1479ebbSBoris BREZILLON * 10*b1479ebbSBoris BREZILLON * Author: Boris BREZILLON <boris.brezillon@free-electrons.com> 11*b1479ebbSBoris BREZILLON * 12*b1479ebbSBoris BREZILLON * This file is licensed under the terms of the GNU General Public 13*b1479ebbSBoris BREZILLON * License version 2. This program is licensed "as is" without any 14*b1479ebbSBoris BREZILLON * warranty of any kind, whether express or implied. 15*b1479ebbSBoris BREZILLON */ 16*b1479ebbSBoris BREZILLON 17*b1479ebbSBoris BREZILLON #include <linux/errno.h> 18*b1479ebbSBoris BREZILLON #include <linux/io.h> 19*b1479ebbSBoris BREZILLON #include <linux/irq.h> 20*b1479ebbSBoris BREZILLON #include <linux/irqdomain.h> 21*b1479ebbSBoris BREZILLON #include <linux/of.h> 22*b1479ebbSBoris BREZILLON #include <linux/of_address.h> 23*b1479ebbSBoris BREZILLON #include <linux/slab.h> 24*b1479ebbSBoris BREZILLON 25*b1479ebbSBoris BREZILLON #include "irq-atmel-aic-common.h" 26*b1479ebbSBoris BREZILLON 27*b1479ebbSBoris BREZILLON #define AT91_AIC_PRIOR GENMASK(2, 0) 28*b1479ebbSBoris BREZILLON #define AT91_AIC_IRQ_MIN_PRIORITY 0 29*b1479ebbSBoris BREZILLON #define AT91_AIC_IRQ_MAX_PRIORITY 7 30*b1479ebbSBoris BREZILLON 31*b1479ebbSBoris BREZILLON #define AT91_AIC_SRCTYPE GENMASK(7, 6) 32*b1479ebbSBoris BREZILLON #define AT91_AIC_SRCTYPE_LOW (0 << 5) 33*b1479ebbSBoris BREZILLON #define AT91_AIC_SRCTYPE_FALLING (1 << 5) 34*b1479ebbSBoris BREZILLON #define AT91_AIC_SRCTYPE_HIGH (2 << 5) 35*b1479ebbSBoris BREZILLON #define AT91_AIC_SRCTYPE_RISING (3 << 5) 36*b1479ebbSBoris BREZILLON 37*b1479ebbSBoris BREZILLON struct aic_chip_data { 38*b1479ebbSBoris BREZILLON u32 ext_irqs; 39*b1479ebbSBoris BREZILLON }; 40*b1479ebbSBoris BREZILLON 41*b1479ebbSBoris BREZILLON static void aic_common_shutdown(struct irq_data *d) 42*b1479ebbSBoris BREZILLON { 43*b1479ebbSBoris BREZILLON struct irq_chip_type *ct = irq_data_get_chip_type(d); 44*b1479ebbSBoris BREZILLON 45*b1479ebbSBoris BREZILLON ct->chip.irq_mask(d); 46*b1479ebbSBoris BREZILLON } 47*b1479ebbSBoris BREZILLON 48*b1479ebbSBoris BREZILLON int aic_common_set_type(struct irq_data *d, unsigned type, unsigned *val) 49*b1479ebbSBoris BREZILLON { 50*b1479ebbSBoris BREZILLON struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 51*b1479ebbSBoris BREZILLON struct aic_chip_data *aic = gc->private; 52*b1479ebbSBoris BREZILLON unsigned aic_type; 53*b1479ebbSBoris BREZILLON 54*b1479ebbSBoris BREZILLON switch (type) { 55*b1479ebbSBoris BREZILLON case IRQ_TYPE_LEVEL_HIGH: 56*b1479ebbSBoris BREZILLON aic_type = AT91_AIC_SRCTYPE_HIGH; 57*b1479ebbSBoris BREZILLON break; 58*b1479ebbSBoris BREZILLON case IRQ_TYPE_EDGE_RISING: 59*b1479ebbSBoris BREZILLON aic_type = AT91_AIC_SRCTYPE_RISING; 60*b1479ebbSBoris BREZILLON break; 61*b1479ebbSBoris BREZILLON case IRQ_TYPE_LEVEL_LOW: 62*b1479ebbSBoris BREZILLON if (!(d->mask & aic->ext_irqs)) 63*b1479ebbSBoris BREZILLON return -EINVAL; 64*b1479ebbSBoris BREZILLON 65*b1479ebbSBoris BREZILLON aic_type = AT91_AIC_SRCTYPE_LOW; 66*b1479ebbSBoris BREZILLON break; 67*b1479ebbSBoris BREZILLON case IRQ_TYPE_EDGE_FALLING: 68*b1479ebbSBoris BREZILLON if (!(d->mask & aic->ext_irqs)) 69*b1479ebbSBoris BREZILLON return -EINVAL; 70*b1479ebbSBoris BREZILLON 71*b1479ebbSBoris BREZILLON aic_type = AT91_AIC_SRCTYPE_FALLING; 72*b1479ebbSBoris BREZILLON break; 73*b1479ebbSBoris BREZILLON default: 74*b1479ebbSBoris BREZILLON return -EINVAL; 75*b1479ebbSBoris BREZILLON } 76*b1479ebbSBoris BREZILLON 77*b1479ebbSBoris BREZILLON *val &= AT91_AIC_SRCTYPE; 78*b1479ebbSBoris BREZILLON *val |= aic_type; 79*b1479ebbSBoris BREZILLON 80*b1479ebbSBoris BREZILLON return 0; 81*b1479ebbSBoris BREZILLON } 82*b1479ebbSBoris BREZILLON 83*b1479ebbSBoris BREZILLON int aic_common_set_priority(int priority, unsigned *val) 84*b1479ebbSBoris BREZILLON { 85*b1479ebbSBoris BREZILLON if (priority < AT91_AIC_IRQ_MIN_PRIORITY || 86*b1479ebbSBoris BREZILLON priority > AT91_AIC_IRQ_MAX_PRIORITY) 87*b1479ebbSBoris BREZILLON return -EINVAL; 88*b1479ebbSBoris BREZILLON 89*b1479ebbSBoris BREZILLON *val &= AT91_AIC_PRIOR; 90*b1479ebbSBoris BREZILLON *val |= priority; 91*b1479ebbSBoris BREZILLON 92*b1479ebbSBoris BREZILLON return 0; 93*b1479ebbSBoris BREZILLON } 94*b1479ebbSBoris BREZILLON 95*b1479ebbSBoris BREZILLON int aic_common_irq_domain_xlate(struct irq_domain *d, 96*b1479ebbSBoris BREZILLON struct device_node *ctrlr, 97*b1479ebbSBoris BREZILLON const u32 *intspec, 98*b1479ebbSBoris BREZILLON unsigned int intsize, 99*b1479ebbSBoris BREZILLON irq_hw_number_t *out_hwirq, 100*b1479ebbSBoris BREZILLON unsigned int *out_type) 101*b1479ebbSBoris BREZILLON { 102*b1479ebbSBoris BREZILLON if (WARN_ON(intsize < 3)) 103*b1479ebbSBoris BREZILLON return -EINVAL; 104*b1479ebbSBoris BREZILLON 105*b1479ebbSBoris BREZILLON if (WARN_ON((intspec[2] < AT91_AIC_IRQ_MIN_PRIORITY) || 106*b1479ebbSBoris BREZILLON (intspec[2] > AT91_AIC_IRQ_MAX_PRIORITY))) 107*b1479ebbSBoris BREZILLON return -EINVAL; 108*b1479ebbSBoris BREZILLON 109*b1479ebbSBoris BREZILLON *out_hwirq = intspec[0]; 110*b1479ebbSBoris BREZILLON *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK; 111*b1479ebbSBoris BREZILLON 112*b1479ebbSBoris BREZILLON return 0; 113*b1479ebbSBoris BREZILLON } 114*b1479ebbSBoris BREZILLON 115*b1479ebbSBoris BREZILLON static void __init aic_common_ext_irq_of_init(struct irq_domain *domain) 116*b1479ebbSBoris BREZILLON { 117*b1479ebbSBoris BREZILLON struct device_node *node = domain->of_node; 118*b1479ebbSBoris BREZILLON struct irq_chip_generic *gc; 119*b1479ebbSBoris BREZILLON struct aic_chip_data *aic; 120*b1479ebbSBoris BREZILLON struct property *prop; 121*b1479ebbSBoris BREZILLON const __be32 *p; 122*b1479ebbSBoris BREZILLON u32 hwirq; 123*b1479ebbSBoris BREZILLON 124*b1479ebbSBoris BREZILLON gc = irq_get_domain_generic_chip(domain, 0); 125*b1479ebbSBoris BREZILLON 126*b1479ebbSBoris BREZILLON aic = gc->private; 127*b1479ebbSBoris BREZILLON aic->ext_irqs |= 1; 128*b1479ebbSBoris BREZILLON 129*b1479ebbSBoris BREZILLON of_property_for_each_u32(node, "atmel,external-irqs", prop, p, hwirq) { 130*b1479ebbSBoris BREZILLON gc = irq_get_domain_generic_chip(domain, hwirq); 131*b1479ebbSBoris BREZILLON if (!gc) { 132*b1479ebbSBoris BREZILLON pr_warn("AIC: external irq %d >= %d skip it\n", 133*b1479ebbSBoris BREZILLON hwirq, domain->revmap_size); 134*b1479ebbSBoris BREZILLON continue; 135*b1479ebbSBoris BREZILLON } 136*b1479ebbSBoris BREZILLON 137*b1479ebbSBoris BREZILLON aic = gc->private; 138*b1479ebbSBoris BREZILLON aic->ext_irqs |= (1 << (hwirq % 32)); 139*b1479ebbSBoris BREZILLON } 140*b1479ebbSBoris BREZILLON } 141*b1479ebbSBoris BREZILLON 142*b1479ebbSBoris BREZILLON struct irq_domain *__init aic_common_of_init(struct device_node *node, 143*b1479ebbSBoris BREZILLON const struct irq_domain_ops *ops, 144*b1479ebbSBoris BREZILLON const char *name, int nirqs) 145*b1479ebbSBoris BREZILLON { 146*b1479ebbSBoris BREZILLON struct irq_chip_generic *gc; 147*b1479ebbSBoris BREZILLON struct irq_domain *domain; 148*b1479ebbSBoris BREZILLON struct aic_chip_data *aic; 149*b1479ebbSBoris BREZILLON void __iomem *reg_base; 150*b1479ebbSBoris BREZILLON int nchips; 151*b1479ebbSBoris BREZILLON int ret; 152*b1479ebbSBoris BREZILLON int i; 153*b1479ebbSBoris BREZILLON 154*b1479ebbSBoris BREZILLON nchips = DIV_ROUND_UP(nirqs, 32); 155*b1479ebbSBoris BREZILLON 156*b1479ebbSBoris BREZILLON reg_base = of_iomap(node, 0); 157*b1479ebbSBoris BREZILLON if (!reg_base) 158*b1479ebbSBoris BREZILLON return ERR_PTR(-ENOMEM); 159*b1479ebbSBoris BREZILLON 160*b1479ebbSBoris BREZILLON aic = kcalloc(nchips, sizeof(*aic), GFP_KERNEL); 161*b1479ebbSBoris BREZILLON if (!aic) { 162*b1479ebbSBoris BREZILLON ret = -ENOMEM; 163*b1479ebbSBoris BREZILLON goto err_iounmap; 164*b1479ebbSBoris BREZILLON } 165*b1479ebbSBoris BREZILLON 166*b1479ebbSBoris BREZILLON domain = irq_domain_add_linear(node, nchips * 32, ops, aic); 167*b1479ebbSBoris BREZILLON if (!domain) { 168*b1479ebbSBoris BREZILLON ret = -ENOMEM; 169*b1479ebbSBoris BREZILLON goto err_free_aic; 170*b1479ebbSBoris BREZILLON } 171*b1479ebbSBoris BREZILLON 172*b1479ebbSBoris BREZILLON ret = irq_alloc_domain_generic_chips(domain, 32, 1, name, 173*b1479ebbSBoris BREZILLON handle_level_irq, 0, 0, 174*b1479ebbSBoris BREZILLON IRQCHIP_SKIP_SET_WAKE); 175*b1479ebbSBoris BREZILLON if (ret) 176*b1479ebbSBoris BREZILLON goto err_domain_remove; 177*b1479ebbSBoris BREZILLON 178*b1479ebbSBoris BREZILLON for (i = 0; i < nchips; i++) { 179*b1479ebbSBoris BREZILLON gc = irq_get_domain_generic_chip(domain, i * 32); 180*b1479ebbSBoris BREZILLON 181*b1479ebbSBoris BREZILLON gc->reg_base = reg_base; 182*b1479ebbSBoris BREZILLON 183*b1479ebbSBoris BREZILLON gc->unused = 0; 184*b1479ebbSBoris BREZILLON gc->wake_enabled = ~0; 185*b1479ebbSBoris BREZILLON gc->chip_types[0].type = IRQ_TYPE_SENSE_MASK; 186*b1479ebbSBoris BREZILLON gc->chip_types[0].handler = handle_fasteoi_irq; 187*b1479ebbSBoris BREZILLON gc->chip_types[0].chip.irq_eoi = irq_gc_eoi; 188*b1479ebbSBoris BREZILLON gc->chip_types[0].chip.irq_set_wake = irq_gc_set_wake; 189*b1479ebbSBoris BREZILLON gc->chip_types[0].chip.irq_shutdown = aic_common_shutdown; 190*b1479ebbSBoris BREZILLON gc->private = &aic[i]; 191*b1479ebbSBoris BREZILLON } 192*b1479ebbSBoris BREZILLON 193*b1479ebbSBoris BREZILLON aic_common_ext_irq_of_init(domain); 194*b1479ebbSBoris BREZILLON 195*b1479ebbSBoris BREZILLON return domain; 196*b1479ebbSBoris BREZILLON 197*b1479ebbSBoris BREZILLON err_domain_remove: 198*b1479ebbSBoris BREZILLON irq_domain_remove(domain); 199*b1479ebbSBoris BREZILLON 200*b1479ebbSBoris BREZILLON err_free_aic: 201*b1479ebbSBoris BREZILLON kfree(aic); 202*b1479ebbSBoris BREZILLON 203*b1479ebbSBoris BREZILLON err_iounmap: 204*b1479ebbSBoris BREZILLON iounmap(reg_base); 205*b1479ebbSBoris BREZILLON 206*b1479ebbSBoris BREZILLON return ERR_PTR(ret); 207*b1479ebbSBoris BREZILLON } 208