1edabd38eSSaeed Bishara /* 2edabd38eSSaeed Bishara * arch/arm/mach-dove/irq.c 3edabd38eSSaeed Bishara * 4edabd38eSSaeed Bishara * Dove IRQ handling. 5edabd38eSSaeed Bishara * 6edabd38eSSaeed Bishara * This file is licensed under the terms of the GNU General Public 7edabd38eSSaeed Bishara * License version 2. This program is licensed "as is" without any 8edabd38eSSaeed Bishara * warranty of any kind, whether express or implied. 9edabd38eSSaeed Bishara */ 10edabd38eSSaeed Bishara 11edabd38eSSaeed Bishara #include <linux/kernel.h> 12edabd38eSSaeed Bishara #include <linux/init.h> 13edabd38eSSaeed Bishara #include <linux/irq.h> 14edabd38eSSaeed Bishara #include <linux/gpio.h> 15edabd38eSSaeed Bishara #include <linux/io.h> 16edabd38eSSaeed Bishara #include <asm/mach/arch.h> 17edabd38eSSaeed Bishara #include <plat/irq.h> 18edabd38eSSaeed Bishara #include <asm/mach/irq.h> 19edabd38eSSaeed Bishara #include <mach/pm.h> 20edabd38eSSaeed Bishara #include <mach/bridge-regs.h> 21ce91574cSRob Herring #include <plat/orion-gpio.h> 22edabd38eSSaeed Bishara #include "common.h" 23edabd38eSSaeed Bishara 24aa456a6eSLennert Buytenhek static void pmu_irq_mask(struct irq_data *d) 25edabd38eSSaeed Bishara { 26aa456a6eSLennert Buytenhek int pin = irq_to_pmu(d->irq); 27edabd38eSSaeed Bishara u32 u; 28edabd38eSSaeed Bishara 29edabd38eSSaeed Bishara u = readl(PMU_INTERRUPT_MASK); 30edabd38eSSaeed Bishara u &= ~(1 << (pin & 31)); 31edabd38eSSaeed Bishara writel(u, PMU_INTERRUPT_MASK); 32edabd38eSSaeed Bishara } 33edabd38eSSaeed Bishara 34aa456a6eSLennert Buytenhek static void pmu_irq_unmask(struct irq_data *d) 35edabd38eSSaeed Bishara { 36aa456a6eSLennert Buytenhek int pin = irq_to_pmu(d->irq); 37edabd38eSSaeed Bishara u32 u; 38edabd38eSSaeed Bishara 39edabd38eSSaeed Bishara u = readl(PMU_INTERRUPT_MASK); 40edabd38eSSaeed Bishara u |= 1 << (pin & 31); 41edabd38eSSaeed Bishara writel(u, PMU_INTERRUPT_MASK); 42edabd38eSSaeed Bishara } 43edabd38eSSaeed Bishara 44aa456a6eSLennert Buytenhek static void pmu_irq_ack(struct irq_data *d) 45edabd38eSSaeed Bishara { 46aa456a6eSLennert Buytenhek int pin = irq_to_pmu(d->irq); 47edabd38eSSaeed Bishara u32 u; 48edabd38eSSaeed Bishara 495d3df935SRussell King - ARM Linux /* 505d3df935SRussell King - ARM Linux * The PMU mask register is not RW0C: it is RW. This means that 515d3df935SRussell King - ARM Linux * the bits take whatever value is written to them; if you write 525d3df935SRussell King - ARM Linux * a '1', you will set the interrupt. 535d3df935SRussell King - ARM Linux * 545d3df935SRussell King - ARM Linux * Unfortunately this means there is NO race free way to clear 555d3df935SRussell King - ARM Linux * these interrupts. 565d3df935SRussell King - ARM Linux * 575d3df935SRussell King - ARM Linux * So, let's structure the code so that the window is as small as 585d3df935SRussell King - ARM Linux * possible. 595d3df935SRussell King - ARM Linux */ 60edabd38eSSaeed Bishara u = ~(1 << (pin & 31)); 615d3df935SRussell King - ARM Linux u &= readl_relaxed(PMU_INTERRUPT_CAUSE); 625d3df935SRussell King - ARM Linux writel_relaxed(u, PMU_INTERRUPT_CAUSE); 63edabd38eSSaeed Bishara } 64edabd38eSSaeed Bishara 65edabd38eSSaeed Bishara static struct irq_chip pmu_irq_chip = { 66edabd38eSSaeed Bishara .name = "pmu_irq", 67aa456a6eSLennert Buytenhek .irq_mask = pmu_irq_mask, 68aa456a6eSLennert Buytenhek .irq_unmask = pmu_irq_unmask, 69aa456a6eSLennert Buytenhek .irq_ack = pmu_irq_ack, 70edabd38eSSaeed Bishara }; 71edabd38eSSaeed Bishara 72edabd38eSSaeed Bishara static void pmu_irq_handler(unsigned int irq, struct irq_desc *desc) 73edabd38eSSaeed Bishara { 74edabd38eSSaeed Bishara unsigned long cause = readl(PMU_INTERRUPT_CAUSE); 75edabd38eSSaeed Bishara 76edabd38eSSaeed Bishara cause &= readl(PMU_INTERRUPT_MASK); 77edabd38eSSaeed Bishara if (cause == 0) { 78edabd38eSSaeed Bishara do_bad_IRQ(irq, desc); 79edabd38eSSaeed Bishara return; 80edabd38eSSaeed Bishara } 81edabd38eSSaeed Bishara 82edabd38eSSaeed Bishara for (irq = 0; irq < NR_PMU_IRQS; irq++) { 83edabd38eSSaeed Bishara if (!(cause & (1 << irq))) 84edabd38eSSaeed Bishara continue; 85edabd38eSSaeed Bishara irq = pmu_to_irq(irq); 86cf0d6b76SThomas Gleixner generic_handle_irq(irq); 87edabd38eSSaeed Bishara } 88edabd38eSSaeed Bishara } 89edabd38eSSaeed Bishara 90278b45b0SAndrew Lunn static int __initdata gpio0_irqs[4] = { 91278b45b0SAndrew Lunn IRQ_DOVE_GPIO_0_7, 92278b45b0SAndrew Lunn IRQ_DOVE_GPIO_8_15, 93278b45b0SAndrew Lunn IRQ_DOVE_GPIO_16_23, 94278b45b0SAndrew Lunn IRQ_DOVE_GPIO_24_31, 95278b45b0SAndrew Lunn }; 96278b45b0SAndrew Lunn 97278b45b0SAndrew Lunn static int __initdata gpio1_irqs[4] = { 98278b45b0SAndrew Lunn IRQ_DOVE_HIGH_GPIO, 99278b45b0SAndrew Lunn 0, 100278b45b0SAndrew Lunn 0, 101278b45b0SAndrew Lunn 0, 102278b45b0SAndrew Lunn }; 103278b45b0SAndrew Lunn 104278b45b0SAndrew Lunn static int __initdata gpio2_irqs[4] = { 105278b45b0SAndrew Lunn 0, 106278b45b0SAndrew Lunn 0, 107278b45b0SAndrew Lunn 0, 108278b45b0SAndrew Lunn 0, 109278b45b0SAndrew Lunn }; 110278b45b0SAndrew Lunn 111edabd38eSSaeed Bishara void __init dove_init_irq(void) 112edabd38eSSaeed Bishara { 113edabd38eSSaeed Bishara int i; 114edabd38eSSaeed Bishara 115c3c5a281SThomas Petazzoni orion_irq_init(0, IRQ_VIRT_BASE + IRQ_MASK_LOW_OFF); 116c3c5a281SThomas Petazzoni orion_irq_init(32, IRQ_VIRT_BASE + IRQ_MASK_HIGH_OFF); 117edabd38eSSaeed Bishara 118edabd38eSSaeed Bishara /* 1199eac6d0aSLennert Buytenhek * Initialize gpiolib for GPIOs 0-71. 120edabd38eSSaeed Bishara */ 121c3c5a281SThomas Petazzoni orion_gpio_init(NULL, 0, 32, DOVE_GPIO_LO_VIRT_BASE, 0, 122278b45b0SAndrew Lunn IRQ_DOVE_GPIO_START, gpio0_irqs); 1239eac6d0aSLennert Buytenhek 124c3c5a281SThomas Petazzoni orion_gpio_init(NULL, 32, 32, DOVE_GPIO_HI_VIRT_BASE, 0, 125278b45b0SAndrew Lunn IRQ_DOVE_GPIO_START + 32, gpio1_irqs); 1269eac6d0aSLennert Buytenhek 127c3c5a281SThomas Petazzoni orion_gpio_init(NULL, 64, 8, DOVE_GPIO2_VIRT_BASE, 0, 128278b45b0SAndrew Lunn IRQ_DOVE_GPIO_START + 64, gpio2_irqs); 129edabd38eSSaeed Bishara 130edabd38eSSaeed Bishara /* 131edabd38eSSaeed Bishara * Mask and clear PMU interrupts 132edabd38eSSaeed Bishara */ 133edabd38eSSaeed Bishara writel(0, PMU_INTERRUPT_MASK); 134edabd38eSSaeed Bishara writel(0, PMU_INTERRUPT_CAUSE); 135edabd38eSSaeed Bishara 136edabd38eSSaeed Bishara for (i = IRQ_DOVE_PMU_START; i < NR_IRQS; i++) { 137f38c02f3SThomas Gleixner irq_set_chip_and_handler(i, &pmu_irq_chip, handle_level_irq); 138cf0d6b76SThomas Gleixner irq_set_status_flags(i, IRQ_LEVEL); 139edabd38eSSaeed Bishara set_irq_flags(i, IRQF_VALID); 140edabd38eSSaeed Bishara } 1416845664aSThomas Gleixner irq_set_chained_handler(IRQ_DOVE_PMU, pmu_irq_handler); 142edabd38eSSaeed Bishara } 143