1/* 2 * Support for Versatile FPGA-based IRQ controllers 3 */ 4#include <linux/irq.h> 5#include <linux/io.h> 6 7#include <asm/mach/irq.h> 8#include <plat/fpga-irq.h> 9 10#define IRQ_STATUS 0x00 11#define IRQ_RAW_STATUS 0x04 12#define IRQ_ENABLE_SET 0x08 13#define IRQ_ENABLE_CLEAR 0x0c 14 15static void fpga_irq_mask(struct irq_data *d) 16{ 17 struct fpga_irq_data *f = irq_data_get_irq_chip_data(d); 18 u32 mask = 1 << (d->irq - f->irq_start); 19 20 writel(mask, f->base + IRQ_ENABLE_CLEAR); 21} 22 23static void fpga_irq_unmask(struct irq_data *d) 24{ 25 struct fpga_irq_data *f = irq_data_get_irq_chip_data(d); 26 u32 mask = 1 << (d->irq - f->irq_start); 27 28 writel(mask, f->base + IRQ_ENABLE_SET); 29} 30 31static void fpga_irq_handle(unsigned int irq, struct irq_desc *desc) 32{ 33 struct fpga_irq_data *f = irq_desc_get_handler_data(desc); 34 u32 status = readl(f->base + IRQ_STATUS); 35 36 if (status == 0) { 37 do_bad_IRQ(irq, desc); 38 return; 39 } 40 41 do { 42 irq = ffs(status) - 1; 43 status &= ~(1 << irq); 44 45 generic_handle_irq(irq + f->irq_start); 46 } while (status); 47} 48 49void __init fpga_irq_init(int parent_irq, u32 valid, struct fpga_irq_data *f) 50{ 51 unsigned int i; 52 53 f->chip.irq_ack = fpga_irq_mask; 54 f->chip.irq_mask = fpga_irq_mask; 55 f->chip.irq_unmask = fpga_irq_unmask; 56 57 if (parent_irq != -1) { 58 irq_set_handler_data(parent_irq, f); 59 irq_set_chained_handler(parent_irq, fpga_irq_handle); 60 } 61 62 for (i = 0; i < 32; i++) { 63 if (valid & (1 << i)) { 64 unsigned int irq = f->irq_start + i; 65 66 irq_set_chip_data(irq, f); 67 irq_set_chip_and_handler(irq, &f->chip, 68 handle_level_irq); 69 set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); 70 } 71 } 72} 73