]>
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> |
fced80c7 | 26 | #include <linux/io.h> |
a09e64fb | 27 | #include <mach/hardware.h> |
78818e47 | 28 | #include <asm/setup.h> |
78818e47 VW |
29 | #include <asm/pgtable.h> |
30 | #include <asm/page.h> | |
78818e47 VW |
31 | #include <asm/mach/arch.h> |
32 | #include <asm/mach/irq.h> | |
33 | #include <asm/mach/map.h> | |
a09e64fb | 34 | #include <mach/irq.h> |
78818e47 VW |
35 | |
36 | static u8 pnx4008_irq_type[NR_IRQS] = PNX4008_IRQ_TYPES; | |
37 | ||
406b0050 | 38 | static void pnx4008_mask_irq(struct irq_data *d) |
78818e47 | 39 | { |
406b0050 | 40 | __raw_writel(__raw_readl(INTC_ER(d->irq)) & ~INTC_BIT(d->irq), INTC_ER(d->irq)); /* mask interrupt */ |
78818e47 VW |
41 | } |
42 | ||
406b0050 | 43 | static void pnx4008_unmask_irq(struct irq_data *d) |
78818e47 | 44 | { |
406b0050 | 45 | __raw_writel(__raw_readl(INTC_ER(d->irq)) | INTC_BIT(d->irq), INTC_ER(d->irq)); /* unmask interrupt */ |
78818e47 VW |
46 | } |
47 | ||
406b0050 | 48 | static void pnx4008_mask_ack_irq(struct irq_data *d) |
78818e47 | 49 | { |
406b0050 LB |
50 | __raw_writel(__raw_readl(INTC_ER(d->irq)) & ~INTC_BIT(d->irq), INTC_ER(d->irq)); /* mask interrupt */ |
51 | __raw_writel(INTC_BIT(d->irq), INTC_SR(d->irq)); /* clear interrupt status */ | |
78818e47 VW |
52 | } |
53 | ||
406b0050 | 54 | static int pnx4008_set_irq_type(struct irq_data *d, unsigned int type) |
78818e47 VW |
55 | { |
56 | switch (type) { | |
6cab4860 | 57 | case IRQ_TYPE_EDGE_RISING: |
406b0050 LB |
58 | __raw_writel(__raw_readl(INTC_ATR(d->irq)) | INTC_BIT(d->irq), INTC_ATR(d->irq)); /*edge sensitive */ |
59 | __raw_writel(__raw_readl(INTC_APR(d->irq)) | INTC_BIT(d->irq), INTC_APR(d->irq)); /*rising edge */ | |
6845664a | 60 | irq_set_handler(d->irq, handle_edge_irq); |
78818e47 | 61 | break; |
6cab4860 | 62 | case IRQ_TYPE_EDGE_FALLING: |
406b0050 LB |
63 | __raw_writel(__raw_readl(INTC_ATR(d->irq)) | INTC_BIT(d->irq), INTC_ATR(d->irq)); /*edge sensitive */ |
64 | __raw_writel(__raw_readl(INTC_APR(d->irq)) & ~INTC_BIT(d->irq), INTC_APR(d->irq)); /*falling edge */ | |
6845664a | 65 | irq_set_handler(d->irq, handle_edge_irq); |
78818e47 | 66 | break; |
6cab4860 | 67 | case IRQ_TYPE_LEVEL_LOW: |
406b0050 LB |
68 | __raw_writel(__raw_readl(INTC_ATR(d->irq)) & ~INTC_BIT(d->irq), INTC_ATR(d->irq)); /*level sensitive */ |
69 | __raw_writel(__raw_readl(INTC_APR(d->irq)) & ~INTC_BIT(d->irq), INTC_APR(d->irq)); /*low level */ | |
6845664a | 70 | irq_set_handler(d->irq, handle_level_irq); |
78818e47 | 71 | break; |
6cab4860 | 72 | case IRQ_TYPE_LEVEL_HIGH: |
406b0050 LB |
73 | __raw_writel(__raw_readl(INTC_ATR(d->irq)) & ~INTC_BIT(d->irq), INTC_ATR(d->irq)); /*level sensitive */ |
74 | __raw_writel(__raw_readl(INTC_APR(d->irq)) | INTC_BIT(d->irq), INTC_APR(d->irq)); /* high level */ | |
6845664a | 75 | irq_set_handler(d->irq, handle_level_irq); |
78818e47 VW |
76 | break; |
77 | ||
6cab4860 | 78 | /* IRQ_TYPE_EDGE_BOTH is not supported */ |
78818e47 VW |
79 | default: |
80 | printk(KERN_ERR "PNX4008 IRQ: Unsupported irq type %d\n", type); | |
81 | return -1; | |
82 | } | |
83 | return 0; | |
84 | } | |
85 | ||
10dd5ce2 | 86 | static struct irq_chip pnx4008_irq_chip = { |
406b0050 LB |
87 | .irq_ack = pnx4008_mask_ack_irq, |
88 | .irq_mask = pnx4008_mask_irq, | |
89 | .irq_unmask = pnx4008_unmask_irq, | |
90 | .irq_set_type = pnx4008_set_irq_type, | |
78818e47 VW |
91 | }; |
92 | ||
93 | void __init pnx4008_init_irq(void) | |
94 | { | |
95 | unsigned int i; | |
96 | ||
5904a7f9 VW |
97 | /* configure IRQ's */ |
98 | for (i = 0; i < NR_IRQS; i++) { | |
99 | set_irq_flags(i, IRQF_VALID); | |
6845664a | 100 | irq_set_chip(i, &pnx4008_irq_chip); |
406b0050 | 101 | pnx4008_set_irq_type(irq_get_irq_data(i), pnx4008_irq_type[i]); |
5904a7f9 VW |
102 | } |
103 | ||
104 | /* configure and enable IRQ 0,1,30,31 (cascade interrupts) */ | |
406b0050 LB |
105 | pnx4008_set_irq_type(irq_get_irq_data(SUB1_IRQ_N), |
106 | pnx4008_irq_type[SUB1_IRQ_N]); | |
107 | pnx4008_set_irq_type(irq_get_irq_data(SUB2_IRQ_N), | |
108 | pnx4008_irq_type[SUB2_IRQ_N]); | |
109 | pnx4008_set_irq_type(irq_get_irq_data(SUB1_FIQ_N), | |
110 | pnx4008_irq_type[SUB1_FIQ_N]); | |
111 | pnx4008_set_irq_type(irq_get_irq_data(SUB2_FIQ_N), | |
112 | pnx4008_irq_type[SUB2_FIQ_N]); | |
78818e47 | 113 | |
5904a7f9 | 114 | /* mask all others */ |
78818e47 VW |
115 | __raw_writel((1 << SUB2_FIQ_N) | (1 << SUB1_FIQ_N) | |
116 | (1 << SUB2_IRQ_N) | (1 << SUB1_IRQ_N), | |
117 | INTC_ER(MAIN_BASE_INT)); | |
118 | __raw_writel(0, INTC_ER(SIC1_BASE_INT)); | |
119 | __raw_writel(0, INTC_ER(SIC2_BASE_INT)); | |
78818e47 VW |
120 | } |
121 |