1 /* 2 * Atheros AR71xx/AR724x/AR913x MISC interrupt controller 3 * 4 * Copyright (C) 2015 Alban Bedel <albeu@free.fr> 5 * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com> 6 * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> 7 * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> 8 * 9 * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP 10 * 11 * This program is free software; you can redistribute it and/or modify it 12 * under the terms of the GNU General Public License version 2 as published 13 * by the Free Software Foundation. 14 */ 15 16 #include <linux/irqchip.h> 17 #include <linux/irqchip/chained_irq.h> 18 #include <linux/of_address.h> 19 #include <linux/of_irq.h> 20 21 #define AR71XX_RESET_REG_MISC_INT_STATUS 0 22 #define AR71XX_RESET_REG_MISC_INT_ENABLE 4 23 24 #define ATH79_MISC_IRQ_COUNT 32 25 26 static void ath79_misc_irq_handler(struct irq_desc *desc) 27 { 28 struct irq_domain *domain = irq_desc_get_handler_data(desc); 29 struct irq_chip *chip = irq_desc_get_chip(desc); 30 void __iomem *base = domain->host_data; 31 u32 pending; 32 33 chained_irq_enter(chip, desc); 34 35 pending = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS) & 36 __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); 37 38 if (!pending) { 39 spurious_interrupt(); 40 chained_irq_exit(chip, desc); 41 return; 42 } 43 44 while (pending) { 45 int bit = __ffs(pending); 46 47 generic_handle_irq(irq_linear_revmap(domain, bit)); 48 pending &= ~BIT(bit); 49 } 50 51 chained_irq_exit(chip, desc); 52 } 53 54 static void ar71xx_misc_irq_unmask(struct irq_data *d) 55 { 56 void __iomem *base = irq_data_get_irq_chip_data(d); 57 unsigned int irq = d->hwirq; 58 u32 t; 59 60 t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); 61 __raw_writel(t | BIT(irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE); 62 63 /* flush write */ 64 __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); 65 } 66 67 static void ar71xx_misc_irq_mask(struct irq_data *d) 68 { 69 void __iomem *base = irq_data_get_irq_chip_data(d); 70 unsigned int irq = d->hwirq; 71 u32 t; 72 73 t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); 74 __raw_writel(t & ~BIT(irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE); 75 76 /* flush write */ 77 __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); 78 } 79 80 static void ar724x_misc_irq_ack(struct irq_data *d) 81 { 82 void __iomem *base = irq_data_get_irq_chip_data(d); 83 unsigned int irq = d->hwirq; 84 u32 t; 85 86 t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS); 87 __raw_writel(t & ~BIT(irq), base + AR71XX_RESET_REG_MISC_INT_STATUS); 88 89 /* flush write */ 90 __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS); 91 } 92 93 static struct irq_chip ath79_misc_irq_chip = { 94 .name = "MISC", 95 .irq_unmask = ar71xx_misc_irq_unmask, 96 .irq_mask = ar71xx_misc_irq_mask, 97 }; 98 99 static int misc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) 100 { 101 irq_set_chip_and_handler(irq, &ath79_misc_irq_chip, handle_level_irq); 102 irq_set_chip_data(irq, d->host_data); 103 return 0; 104 } 105 106 static const struct irq_domain_ops misc_irq_domain_ops = { 107 .xlate = irq_domain_xlate_onecell, 108 .map = misc_map, 109 }; 110 111 static void __init ath79_misc_intc_domain_init( 112 struct irq_domain *domain, int irq) 113 { 114 void __iomem *base = domain->host_data; 115 116 /* Disable and clear all interrupts */ 117 __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_ENABLE); 118 __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_STATUS); 119 120 irq_set_chained_handler_and_data(irq, ath79_misc_irq_handler, domain); 121 } 122 123 static int __init ath79_misc_intc_of_init( 124 struct device_node *node, struct device_node *parent) 125 { 126 struct irq_domain *domain; 127 void __iomem *base; 128 int irq; 129 130 irq = irq_of_parse_and_map(node, 0); 131 if (!irq) { 132 pr_err("Failed to get MISC IRQ\n"); 133 return -EINVAL; 134 } 135 136 base = of_iomap(node, 0); 137 if (!base) { 138 pr_err("Failed to get MISC IRQ registers\n"); 139 return -ENOMEM; 140 } 141 142 domain = irq_domain_add_linear(node, ATH79_MISC_IRQ_COUNT, 143 &misc_irq_domain_ops, base); 144 if (!domain) { 145 pr_err("Failed to add MISC irqdomain\n"); 146 return -EINVAL; 147 } 148 149 ath79_misc_intc_domain_init(domain, irq); 150 return 0; 151 } 152 153 static int __init ar7100_misc_intc_of_init( 154 struct device_node *node, struct device_node *parent) 155 { 156 ath79_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask; 157 return ath79_misc_intc_of_init(node, parent); 158 } 159 160 IRQCHIP_DECLARE(ar7100_misc_intc, "qca,ar7100-misc-intc", 161 ar7100_misc_intc_of_init); 162 163 static int __init ar7240_misc_intc_of_init( 164 struct device_node *node, struct device_node *parent) 165 { 166 ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack; 167 return ath79_misc_intc_of_init(node, parent); 168 } 169 170 IRQCHIP_DECLARE(ar7240_misc_intc, "qca,ar7240-misc-intc", 171 ar7240_misc_intc_of_init); 172 173 void __init ath79_misc_irq_init(void __iomem *regs, int irq, 174 int irq_base, bool is_ar71xx) 175 { 176 struct irq_domain *domain; 177 178 if (is_ar71xx) 179 ath79_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask; 180 else 181 ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack; 182 183 domain = irq_domain_add_legacy(NULL, ATH79_MISC_IRQ_COUNT, 184 irq_base, 0, &misc_irq_domain_ops, regs); 185 if (!domain) 186 panic("Failed to create MISC irqdomain"); 187 188 ath79_misc_intc_domain_init(domain, irq); 189 } 190