1/* 2 * Interrupt handling for INTC2-based IRQ. 3 * 4 * Copyright (C) 2001 David J. Mckay (david.mckay@st.com) 5 * Copyright (C) 2005, 2006 Paul Mundt (lethal@linux-sh.org) 6 * 7 * May be copied or modified under the terms of the GNU General Public 8 * License. See linux/COPYING for more information. 9 * 10 * These are the "new Hitachi style" interrupts, as present on the 11 * Hitachi 7751, the STM ST40 STB1, SH7760, and SH7780. 12 */ 13#include <linux/kernel.h> 14#include <linux/interrupt.h> 15#include <linux/io.h> 16 17#if defined(CONFIG_CPU_SUBTYPE_SH7760) 18#define INTC2_BASE 0xfe080000 19#define INTC2_INTMSK (INTC2_BASE + 0x40) 20#define INTC2_INTMSKCLR (INTC2_BASE + 0x60) 21#elif defined(CONFIG_CPU_SUBTYPE_SH7780) || \ 22 defined(CONFIG_CPU_SUBTYPE_SH7785) 23#define INTC2_BASE 0xffd40000 24#define INTC2_INTMSK (INTC2_BASE + 0x38) 25#define INTC2_INTMSKCLR (INTC2_BASE + 0x3c) 26#endif 27 28static void disable_intc2_irq(unsigned int irq) 29{ 30 struct intc2_data *p = get_irq_chip_data(irq); 31 ctrl_outl(1 << p->msk_shift, INTC2_INTMSK + p->msk_offset); 32} 33 34static void enable_intc2_irq(unsigned int irq) 35{ 36 struct intc2_data *p = get_irq_chip_data(irq); 37 ctrl_outl(1 << p->msk_shift, INTC2_INTMSKCLR + p->msk_offset); 38} 39 40static struct irq_chip intc2_irq_chip = { 41 .name = "INTC2", 42 .mask = disable_intc2_irq, 43 .unmask = enable_intc2_irq, 44 .mask_ack = disable_intc2_irq, 45}; 46 47/* 48 * Setup an INTC2 style interrupt. 49 * NOTE: Unlike IPR interrupts, parameters are not shifted by this code, 50 * allowing the use of the numbers straight out of the datasheet. 51 * For example: 52 * PIO1 which is INTPRI00[19,16] and INTMSK00[13] 53 * would be: ^ ^ ^ ^ 54 * | | | | 55 * { 84, 0, 16, 0, 13 }, 56 * 57 * in the intc2_data table. 58 */ 59void make_intc2_irq(struct intc2_data *table, unsigned int nr_irqs) 60{ 61 int i; 62 63 for (i = 0; i < nr_irqs; i++) { 64 unsigned long ipr, flags; 65 struct intc2_data *p = table + i; 66 67 disable_irq_nosync(p->irq); 68 69 /* Set the priority level */ 70 local_irq_save(flags); 71 72 ipr = ctrl_inl(INTC2_BASE + p->ipr_offset); 73 ipr &= ~(0xf << p->ipr_shift); 74 ipr |= p->priority << p->ipr_shift; 75 ctrl_outl(ipr, INTC2_BASE + p->ipr_offset); 76 77 local_irq_restore(flags); 78 79 set_irq_chip_and_handler_name(p->irq, &intc2_irq_chip, 80 handle_level_irq, "level"); 81 set_irq_chip_data(p->irq, p); 82 83 enable_intc2_irq(p->irq); 84 } 85} 86