1 /* 2 * arch/arm/mach-orion5x/irq.c 3 * 4 * Core IRQ functions for Marvell Orion System On Chip 5 * 6 * Maintainer: Tzachi Perelstein <tzachi@marvell.com> 7 * 8 * This file is licensed under the terms of the GNU General Public 9 * License version 2. This program is licensed "as is" without any 10 * warranty of any kind, whether express or implied. 11 */ 12 13 #include <linux/kernel.h> 14 #include <linux/init.h> 15 #include <linux/irq.h> 16 #include <asm/gpio.h> 17 #include <asm/io.h> 18 #include <mach/orion5x.h> 19 #include <asm/plat-orion/irq.h> 20 #include "common.h" 21 22 /***************************************************************************** 23 * Orion GPIO IRQ 24 * 25 * GPIO_IN_POL register controlls whether GPIO_DATA_IN will hold the same 26 * value of the line or the opposite value. 27 * 28 * Level IRQ handlers: DATA_IN is used directly as cause register. 29 * Interrupt are masked by LEVEL_MASK registers. 30 * Edge IRQ handlers: Change in DATA_IN are latched in EDGE_CAUSE. 31 * Interrupt are masked by EDGE_MASK registers. 32 * Both-edge handlers: Similar to regular Edge handlers, but also swaps 33 * the polarity to catch the next line transaction. 34 * This is a race condition that might not perfectly 35 * work on some use cases. 36 * 37 * Every eight GPIO lines are grouped (OR'ed) before going up to main 38 * cause register. 39 * 40 * EDGE cause mask 41 * data-in /--------| |-----| |----\ 42 * -----| |----- ---- to main cause reg 43 * X \----------------| |----/ 44 * polarity LEVEL mask 45 * 46 ****************************************************************************/ 47 static void orion5x_gpio_irq_ack(u32 irq) 48 { 49 int pin = irq_to_gpio(irq); 50 if (irq_desc[irq].status & IRQ_LEVEL) 51 /* 52 * Mask bit for level interrupt 53 */ 54 orion5x_clrbits(GPIO_LEVEL_MASK, 1 << pin); 55 else 56 /* 57 * Clear casue bit for egde interrupt 58 */ 59 orion5x_clrbits(GPIO_EDGE_CAUSE, 1 << pin); 60 } 61 62 static void orion5x_gpio_irq_mask(u32 irq) 63 { 64 int pin = irq_to_gpio(irq); 65 if (irq_desc[irq].status & IRQ_LEVEL) 66 orion5x_clrbits(GPIO_LEVEL_MASK, 1 << pin); 67 else 68 orion5x_clrbits(GPIO_EDGE_MASK, 1 << pin); 69 } 70 71 static void orion5x_gpio_irq_unmask(u32 irq) 72 { 73 int pin = irq_to_gpio(irq); 74 if (irq_desc[irq].status & IRQ_LEVEL) 75 orion5x_setbits(GPIO_LEVEL_MASK, 1 << pin); 76 else 77 orion5x_setbits(GPIO_EDGE_MASK, 1 << pin); 78 } 79 80 static int orion5x_gpio_set_irq_type(u32 irq, u32 type) 81 { 82 int pin = irq_to_gpio(irq); 83 struct irq_desc *desc; 84 85 if ((readl(GPIO_IO_CONF) & (1 << pin)) == 0) { 86 printk(KERN_ERR "orion5x_gpio_set_irq_type failed " 87 "(irq %d, pin %d).\n", irq, pin); 88 return -EINVAL; 89 } 90 91 desc = irq_desc + irq; 92 93 switch (type) { 94 case IRQ_TYPE_LEVEL_HIGH: 95 desc->handle_irq = handle_level_irq; 96 desc->status |= IRQ_LEVEL; 97 orion5x_clrbits(GPIO_IN_POL, (1 << pin)); 98 break; 99 case IRQ_TYPE_LEVEL_LOW: 100 desc->handle_irq = handle_level_irq; 101 desc->status |= IRQ_LEVEL; 102 orion5x_setbits(GPIO_IN_POL, (1 << pin)); 103 break; 104 case IRQ_TYPE_EDGE_RISING: 105 desc->handle_irq = handle_edge_irq; 106 desc->status &= ~IRQ_LEVEL; 107 orion5x_clrbits(GPIO_IN_POL, (1 << pin)); 108 break; 109 case IRQ_TYPE_EDGE_FALLING: 110 desc->handle_irq = handle_edge_irq; 111 desc->status &= ~IRQ_LEVEL; 112 orion5x_setbits(GPIO_IN_POL, (1 << pin)); 113 break; 114 case IRQ_TYPE_EDGE_BOTH: 115 desc->handle_irq = handle_edge_irq; 116 desc->status &= ~IRQ_LEVEL; 117 /* 118 * set initial polarity based on current input level 119 */ 120 if ((readl(GPIO_IN_POL) ^ readl(GPIO_DATA_IN)) 121 & (1 << pin)) 122 orion5x_setbits(GPIO_IN_POL, (1 << pin)); /* falling */ 123 else 124 orion5x_clrbits(GPIO_IN_POL, (1 << pin)); /* rising */ 125 126 break; 127 default: 128 printk(KERN_ERR "failed to set irq=%d (type=%d)\n", irq, type); 129 return -EINVAL; 130 } 131 132 desc->status &= ~IRQ_TYPE_SENSE_MASK; 133 desc->status |= type & IRQ_TYPE_SENSE_MASK; 134 135 return 0; 136 } 137 138 static struct irq_chip orion5x_gpio_irq_chip = { 139 .name = "Orion-IRQ-GPIO", 140 .ack = orion5x_gpio_irq_ack, 141 .mask = orion5x_gpio_irq_mask, 142 .unmask = orion5x_gpio_irq_unmask, 143 .set_type = orion5x_gpio_set_irq_type, 144 }; 145 146 static void orion5x_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) 147 { 148 u32 cause, offs, pin; 149 150 BUG_ON(irq < IRQ_ORION5X_GPIO_0_7 || irq > IRQ_ORION5X_GPIO_24_31); 151 offs = (irq - IRQ_ORION5X_GPIO_0_7) * 8; 152 cause = (readl(GPIO_DATA_IN) & readl(GPIO_LEVEL_MASK)) | 153 (readl(GPIO_EDGE_CAUSE) & readl(GPIO_EDGE_MASK)); 154 155 for (pin = offs; pin < offs + 8; pin++) { 156 if (cause & (1 << pin)) { 157 irq = gpio_to_irq(pin); 158 desc = irq_desc + irq; 159 if ((desc->status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) { 160 /* Swap polarity (race with GPIO line) */ 161 u32 polarity = readl(GPIO_IN_POL); 162 polarity ^= 1 << pin; 163 writel(polarity, GPIO_IN_POL); 164 } 165 desc_handle_irq(irq, desc); 166 } 167 } 168 } 169 170 static void __init orion5x_init_gpio_irq(void) 171 { 172 int i; 173 struct irq_desc *desc; 174 175 /* 176 * Mask and clear GPIO IRQ interrupts 177 */ 178 writel(0x0, GPIO_LEVEL_MASK); 179 writel(0x0, GPIO_EDGE_MASK); 180 writel(0x0, GPIO_EDGE_CAUSE); 181 182 /* 183 * Register chained level handlers for GPIO IRQs by default. 184 * User can use set_type() if he wants to use edge types handlers. 185 */ 186 for (i = IRQ_ORION5X_GPIO_START; i < NR_IRQS; i++) { 187 set_irq_chip(i, &orion5x_gpio_irq_chip); 188 set_irq_handler(i, handle_level_irq); 189 desc = irq_desc + i; 190 desc->status |= IRQ_LEVEL; 191 set_irq_flags(i, IRQF_VALID); 192 } 193 set_irq_chained_handler(IRQ_ORION5X_GPIO_0_7, orion5x_gpio_irq_handler); 194 set_irq_chained_handler(IRQ_ORION5X_GPIO_8_15, orion5x_gpio_irq_handler); 195 set_irq_chained_handler(IRQ_ORION5X_GPIO_16_23, orion5x_gpio_irq_handler); 196 set_irq_chained_handler(IRQ_ORION5X_GPIO_24_31, orion5x_gpio_irq_handler); 197 } 198 199 /***************************************************************************** 200 * Orion Main IRQ 201 ****************************************************************************/ 202 static void __init orion5x_init_main_irq(void) 203 { 204 orion_irq_init(0, (void __iomem *)MAIN_IRQ_MASK); 205 } 206 207 void __init orion5x_init_irq(void) 208 { 209 orion5x_init_main_irq(); 210 orion5x_init_gpio_irq(); 211 } 212