PageRenderTime 39ms CodeModel.GetById 18ms app.highlight 16ms RepoModel.GetById 2ms app.codeStats 0ms

/arch/sh/kernel/cpu/sh4/irq_intc2.c

https://bitbucket.org/evzijst/gittest
C | 222 lines | 153 code | 40 blank | 29 comment | 10 complexity | 3ec8be0308403b611dc36849a959f082 MD5 | raw file
  1/*
  2 * linux/arch/sh/kernel/irq_intc2.c
  3 *
  4 * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
  5 *
  6 * May be copied or modified under the terms of the GNU General Public
  7 * License.  See linux/COPYING for more information.                            
  8 *
  9 * Interrupt handling for INTC2-based IRQ.
 10 *
 11 * These are the "new Hitachi style" interrupts, as present on the 
 12 * Hitachi 7751 and the STM ST40 STB1.
 13 */
 14
 15#include <linux/kernel.h>
 16#include <linux/init.h>
 17#include <linux/irq.h>
 18
 19#include <asm/system.h>
 20#include <asm/io.h>
 21#include <asm/machvec.h>
 22
 23
 24struct intc2_data {
 25	unsigned char msk_offset;
 26	unsigned char msk_shift;
 27#ifdef CONFIG_CPU_SUBTYPE_ST40
 28	int (*clear_irq) (int);
 29#endif
 30};
 31
 32
 33static struct intc2_data intc2_data[NR_INTC2_IRQS];
 34
 35static void enable_intc2_irq(unsigned int irq);
 36static void disable_intc2_irq(unsigned int irq);
 37
 38/* shutdown is same as "disable" */
 39#define shutdown_intc2_irq disable_intc2_irq
 40
 41static void mask_and_ack_intc2(unsigned int);
 42static void end_intc2_irq(unsigned int irq);
 43
 44static unsigned int startup_intc2_irq(unsigned int irq)
 45{ 
 46	enable_intc2_irq(irq);
 47	return 0; /* never anything pending */
 48}
 49
 50static struct hw_interrupt_type intc2_irq_type = {
 51	"INTC2-IRQ",
 52	startup_intc2_irq,
 53	shutdown_intc2_irq,
 54	enable_intc2_irq,
 55	disable_intc2_irq,
 56	mask_and_ack_intc2,
 57	end_intc2_irq
 58};
 59
 60static void disable_intc2_irq(unsigned int irq)
 61{
 62	int irq_offset = irq - INTC2_FIRST_IRQ;
 63	int msk_shift, msk_offset;
 64
 65	// Sanity check
 66	if((irq_offset<0) || (irq_offset>=NR_INTC2_IRQS))
 67		return;
 68
 69	msk_shift = intc2_data[irq_offset].msk_shift;
 70	msk_offset = intc2_data[irq_offset].msk_offset;
 71
 72	ctrl_outl(1<<msk_shift,
 73		  INTC2_BASE+INTC2_INTMSK_OFFSET+msk_offset);
 74}
 75
 76static void enable_intc2_irq(unsigned int irq)
 77{
 78	int irq_offset = irq - INTC2_FIRST_IRQ;
 79	int msk_shift, msk_offset;
 80
 81	/* Sanity check */
 82	if((irq_offset<0) || (irq_offset>=NR_INTC2_IRQS))
 83		return;
 84
 85	msk_shift = intc2_data[irq_offset].msk_shift;
 86	msk_offset = intc2_data[irq_offset].msk_offset;
 87
 88	ctrl_outl(1<<msk_shift,
 89		  INTC2_BASE+INTC2_INTMSKCLR_OFFSET+msk_offset);
 90}
 91
 92static void mask_and_ack_intc2(unsigned int irq)
 93{
 94	disable_intc2_irq(irq);
 95}
 96
 97static void end_intc2_irq(unsigned int irq)
 98{
 99	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
100		enable_intc2_irq(irq);
101
102#ifdef CONFIG_CPU_SUBTYPE_ST40
103	if (intc2_data[irq - INTC2_FIRST_IRQ].clear_irq)
104		intc2_data[irq - INTC2_FIRST_IRQ].clear_irq (irq);
105#endif
106}
107
108/*
109 * Setup an INTC2 style interrupt.
110 * NOTE: Unlike IPR interrupts, parameters are not shifted by this code,
111 * allowing the use of the numbers straight out of the datasheet.
112 * For example:
113 *    PIO1 which is INTPRI00[19,16] and INTMSK00[13]
114 * would be:               ^     ^             ^  ^
115 *                         |     |             |  |
116 *    make_intc2_irq(84,   0,   16,            0, 13);
117 */
118void make_intc2_irq(unsigned int irq,
119		    unsigned int ipr_offset, unsigned int ipr_shift,
120		    unsigned int msk_offset, unsigned int msk_shift,
121		    unsigned int priority)
122{
123	int irq_offset = irq - INTC2_FIRST_IRQ;
124	unsigned int flags;
125	unsigned long ipr;
126
127	if((irq_offset<0) || (irq_offset>=NR_INTC2_IRQS))
128		return;
129
130	disable_irq_nosync(irq);
131
132	/* Fill the data we need */
133	intc2_data[irq_offset].msk_offset = msk_offset;
134	intc2_data[irq_offset].msk_shift  = msk_shift;
135#ifdef CONFIG_CPU_SUBTYPE_ST40
136	intc2_data[irq_offset].clear_irq = NULL;
137#endif
138		
139	/* Set the priority level */
140	local_irq_save(flags);
141
142	ipr=ctrl_inl(INTC2_BASE+INTC2_INTPRI_OFFSET+ipr_offset);
143	ipr&=~(0xf<<ipr_shift);
144	ipr|=(priority)<<ipr_shift;
145	ctrl_outl(ipr, INTC2_BASE+INTC2_INTPRI_OFFSET+ipr_offset);
146
147	local_irq_restore(flags);
148
149	irq_desc[irq].handler=&intc2_irq_type;
150
151	disable_intc2_irq(irq);
152}
153
154#ifdef CONFIG_CPU_SUBTYPE_ST40
155
156struct intc2_init {
157	unsigned short irq;
158	unsigned char ipr_offset, ipr_shift;
159	unsigned char msk_offset, msk_shift;
160};
161
162static struct intc2_init intc2_init_data[]  __initdata = {
163	{64,  0,  0, 0,  0},	/* PCI serr */
164	{65,  0,  4, 0,  1},	/* PCI err */
165	{66,  0,  4, 0,  2},	/* PCI ad */
166	{67,  0,  4, 0,  3},	/* PCI pwd down */
167	{72,  0,  8, 0,  5},	/* DMAC INT0 */
168	{73,  0,  8, 0,  6},	/* DMAC INT1 */
169	{74,  0,  8, 0,  7},	/* DMAC INT2 */
170	{75,  0,  8, 0,  8},	/* DMAC INT3 */
171	{76,  0,  8, 0,  9},	/* DMAC INT4 */
172	{78,  0,  8, 0, 11},	/* DMAC ERR */
173	{80,  0, 12, 0, 12},	/* PIO0 */
174	{84,  0, 16, 0, 13},	/* PIO1 */
175	{88,  0, 20, 0, 14},	/* PIO2 */
176	{112, 4,  0, 4,  0},	/* Mailbox */
177#ifdef CONFIG_CPU_SUBTYPE_ST40GX1
178	{116, 4,  4, 4,  4},	/* SSC0 */
179	{120, 4,  8, 4,  8},	/* IR Blaster */
180	{124, 4, 12, 4, 12},	/* USB host */
181	{128, 4, 16, 4, 16},	/* Video processor BLITTER */
182	{132, 4, 20, 4, 20},	/* UART0 */
183	{134, 4, 20, 4, 22},	/* UART2 */
184	{136, 4, 24, 4, 24},	/* IO_PIO0 */
185	{140, 4, 28, 4, 28},	/* EMPI */
186	{144, 8,  0, 8,  0},	/* MAFE */
187	{148, 8,  4, 8,  4},	/* PWM */
188	{152, 8,  8, 8,  8},	/* SSC1 */
189	{156, 8, 12, 8, 12},	/* IO_PIO1 */
190	{160, 8, 16, 8, 16},	/* USB target */
191	{164, 8, 20, 8, 20},	/* UART1 */
192	{168, 8, 24, 8, 24},	/* Teletext */
193	{172, 8, 28, 8, 28},	/* VideoSync VTG */
194	{173, 8, 28, 8, 29},	/* VideoSync DVP0 */
195	{174, 8, 28, 8, 30},	/* VideoSync DVP1 */
196#endif
197};
198
199void __init init_IRQ_intc2(void)
200{
201	struct intc2_init *p;
202
203	printk(KERN_ALERT "init_IRQ_intc2\n");
204
205	for (p = intc2_init_data;
206	     p<intc2_init_data+ARRAY_SIZE(intc2_init_data);
207	     p++) {
208		make_intc2_irq(p->irq, p->ipr_offset, p->ipr_shift,
209			       p-> msk_offset, p->msk_shift, 13);
210	}
211}
212
213/* Adds a termination callback to the interrupt */
214void intc2_add_clear_irq(int irq, int (*fn)(int))
215{
216	if (irq < INTC2_FIRST_IRQ)
217		return;
218
219	intc2_data[irq - INTC2_FIRST_IRQ].clear_irq = fn;
220}
221
222#endif /* CONFIG_CPU_SUBTYPE_ST40 */