]>
Commit | Line | Data |
---|---|---|
78818e47 VW |
1 | /* |
2 | * arch/arm/mach-pnx4008/irq.c | |
3 | * | |
4 | * PNX4008 IRQ controller driver | |
5 | * | |
6 | * Author: Dmitry Chigirev <source@mvista.com> | |
7 | * | |
8 | * Based on reference code received from Philips: | |
9 | * Copyright (C) 2003 Philips Semiconductors | |
10 | * | |
11 | * 2005 (c) MontaVista Software, Inc. This file is licensed under | |
12 | * the terms of the GNU General Public License version 2. This program | |
13 | * is licensed "as is" without any warranty of any kind, whether express | |
14 | * or implied. | |
15 | */ | |
16 | ||
17 | #include <linux/kernel.h> | |
18 | #include <linux/types.h> | |
19 | #include <linux/mm.h> | |
20 | #include <linux/interrupt.h> | |
21 | #include <linux/list.h> | |
22 | #include <linux/init.h> | |
23 | #include <linux/ioport.h> | |
24 | #include <linux/device.h> | |
5904a7f9 | 25 | #include <linux/irq.h> |
a09e64fb | 26 | #include <mach/hardware.h> |
78818e47 VW |
27 | #include <asm/io.h> |
28 | #include <asm/setup.h> | |
78818e47 VW |
29 | #include <asm/pgtable.h> |
30 | #include <asm/page.h> | |
31 | #include <asm/system.h> | |
32 | #include <asm/mach/arch.h> | |
33 | #include <asm/mach/irq.h> | |
34 | #include <asm/mach/map.h> | |
a09e64fb | 35 | #include <mach/irq.h> |
78818e47 VW |
36 | |
37 | static u8 pnx4008_irq_type[NR_IRQS] = PNX4008_IRQ_TYPES; | |
38 | ||
39 | static void pnx4008_mask_irq(unsigned int irq) | |
40 | { | |
41 | __raw_writel(__raw_readl(INTC_ER(irq)) & ~INTC_BIT(irq), INTC_ER(irq)); /* mask interrupt */ | |
42 | } | |
43 | ||
44 | static void pnx4008_unmask_irq(unsigned int irq) | |
45 | { | |
46 | __raw_writel(__raw_readl(INTC_ER(irq)) | INTC_BIT(irq), INTC_ER(irq)); /* unmask interrupt */ | |
47 | } | |
48 | ||
49 | static void pnx4008_mask_ack_irq(unsigned int irq) | |
50 | { | |
51 | __raw_writel(__raw_readl(INTC_ER(irq)) & ~INTC_BIT(irq), INTC_ER(irq)); /* mask interrupt */ | |
52 | __raw_writel(INTC_BIT(irq), INTC_SR(irq)); /* clear interrupt status */ | |
53 | } | |
54 | ||
55 | static int pnx4008_set_irq_type(unsigned int irq, unsigned int type) | |
56 | { | |
57 | switch (type) { | |
6cab4860 | 58 | case IRQ_TYPE_EDGE_RISING: |
78818e47 VW |
59 | __raw_writel(__raw_readl(INTC_ATR(irq)) | INTC_BIT(irq), INTC_ATR(irq)); /*edge sensitive */ |
60 | __raw_writel(__raw_readl(INTC_APR(irq)) | INTC_BIT(irq), INTC_APR(irq)); /*rising edge */ | |
10dd5ce2 | 61 | set_irq_handler(irq, handle_edge_irq); |
78818e47 | 62 | break; |
6cab4860 | 63 | case IRQ_TYPE_EDGE_FALLING: |
78818e47 VW |
64 | __raw_writel(__raw_readl(INTC_ATR(irq)) | INTC_BIT(irq), INTC_ATR(irq)); /*edge sensitive */ |
65 | __raw_writel(__raw_readl(INTC_APR(irq)) & ~INTC_BIT(irq), INTC_APR(irq)); /*falling edge */ | |
10dd5ce2 | 66 | set_irq_handler(irq, handle_edge_irq); |
78818e47 | 67 | break; |
6cab4860 | 68 | case IRQ_TYPE_LEVEL_LOW: |
78818e47 VW |
69 | __raw_writel(__raw_readl(INTC_ATR(irq)) & ~INTC_BIT(irq), INTC_ATR(irq)); /*level sensitive */ |
70 | __raw_writel(__raw_readl(INTC_APR(irq)) & ~INTC_BIT(irq), INTC_APR(irq)); /*low level */ | |
10dd5ce2 | 71 | set_irq_handler(irq, handle_level_irq); |
78818e47 | 72 | break; |
6cab4860 | 73 | case IRQ_TYPE_LEVEL_HIGH: |
78818e47 VW |
74 | __raw_writel(__raw_readl(INTC_ATR(irq)) & ~INTC_BIT(irq), INTC_ATR(irq)); /*level sensitive */ |
75 | __raw_writel(__raw_readl(INTC_APR(irq)) | INTC_BIT(irq), INTC_APR(irq)); /* high level */ | |
10dd5ce2 | 76 | set_irq_handler(irq, handle_level_irq); |
78818e47 VW |
77 | break; |
78 | ||
6cab4860 | 79 | /* IRQ_TYPE_EDGE_BOTH is not supported */ |
78818e47 VW |
80 | default: |
81 | printk(KERN_ERR "PNX4008 IRQ: Unsupported irq type %d\n", type); | |
82 | return -1; | |
83 | } | |
84 | return 0; | |
85 | } | |
86 | ||
10dd5ce2 | 87 | static struct irq_chip pnx4008_irq_chip = { |
78818e47 VW |
88 | .ack = pnx4008_mask_ack_irq, |
89 | .mask = pnx4008_mask_irq, | |
90 | .unmask = pnx4008_unmask_irq, | |
91 | .set_type = pnx4008_set_irq_type, | |
92 | }; | |
93 | ||
94 | void __init pnx4008_init_irq(void) | |
95 | { | |
96 | unsigned int i; | |
97 | ||
5904a7f9 VW |
98 | /* configure IRQ's */ |
99 | for (i = 0; i < NR_IRQS; i++) { | |
100 | set_irq_flags(i, IRQF_VALID); | |
101 | set_irq_chip(i, &pnx4008_irq_chip); | |
102 | pnx4008_set_irq_type(i, pnx4008_irq_type[i]); | |
103 | } | |
104 | ||
105 | /* configure and enable IRQ 0,1,30,31 (cascade interrupts) */ | |
78818e47 VW |
106 | pnx4008_set_irq_type(SUB1_IRQ_N, pnx4008_irq_type[SUB1_IRQ_N]); |
107 | pnx4008_set_irq_type(SUB2_IRQ_N, pnx4008_irq_type[SUB2_IRQ_N]); | |
108 | pnx4008_set_irq_type(SUB1_FIQ_N, pnx4008_irq_type[SUB1_FIQ_N]); | |
109 | pnx4008_set_irq_type(SUB2_FIQ_N, pnx4008_irq_type[SUB2_FIQ_N]); | |
110 | ||
5904a7f9 | 111 | /* mask all others */ |
78818e47 VW |
112 | __raw_writel((1 << SUB2_FIQ_N) | (1 << SUB1_FIQ_N) | |
113 | (1 << SUB2_IRQ_N) | (1 << SUB1_IRQ_N), | |
114 | INTC_ER(MAIN_BASE_INT)); | |
115 | __raw_writel(0, INTC_ER(SIC1_BASE_INT)); | |
116 | __raw_writel(0, INTC_ER(SIC2_BASE_INT)); | |
78818e47 VW |
117 | } |
118 |