Merge branch 'x86/asm' into x86/atomic
[pandora-kernel.git] / arch / sh / boards / mach-se / 7724 / irq.c
1 /*
2  * linux/arch/sh/boards/se/7724/irq.c
3  *
4  * Copyright (C) 2009 Renesas Solutions Corp.
5  *
6  * Kuninori Morimoto <morimoto.kuninori@renesas.com>
7  *
8  * Based on  linux/arch/sh/boards/se/7722/irq.c
9  * Copyright (C) 2007  Nobuhiro Iwamatsu
10  *
11  * Hitachi UL SolutionEngine 7724 Support.
12  *
13  * This file is subject to the terms and conditions of the GNU General Public
14  * License.  See the file "COPYING" in the main directory of this archive
15  * for more details.
16  */
17 #include <linux/init.h>
18 #include <linux/irq.h>
19 #include <linux/interrupt.h>
20 #include <asm/irq.h>
21 #include <asm/io.h>
22 #include <mach-se/mach/se7724.h>
23
24 struct fpga_irq {
25         unsigned long  sraddr;
26         unsigned long  mraddr;
27         unsigned short mask;
28         unsigned int   base;
29 };
30
31 static unsigned int fpga2irq(unsigned int irq)
32 {
33         if (irq >= IRQ0_BASE &&
34             irq <= IRQ0_END)
35                 return IRQ0_IRQ;
36         else if (irq >= IRQ1_BASE &&
37                  irq <= IRQ1_END)
38                 return IRQ1_IRQ;
39         else
40                 return IRQ2_IRQ;
41 }
42
43 static struct fpga_irq get_fpga_irq(unsigned int irq)
44 {
45         struct fpga_irq set;
46
47         switch (irq) {
48         case IRQ0_IRQ:
49                 set.sraddr = IRQ0_SR;
50                 set.mraddr = IRQ0_MR;
51                 set.mask   = IRQ0_MASK;
52                 set.base   = IRQ0_BASE;
53                 break;
54         case IRQ1_IRQ:
55                 set.sraddr = IRQ1_SR;
56                 set.mraddr = IRQ1_MR;
57                 set.mask   = IRQ1_MASK;
58                 set.base   = IRQ1_BASE;
59                 break;
60         default:
61                 set.sraddr = IRQ2_SR;
62                 set.mraddr = IRQ2_MR;
63                 set.mask   = IRQ2_MASK;
64                 set.base   = IRQ2_BASE;
65                 break;
66         }
67
68         return set;
69 }
70
71 static void disable_se7724_irq(unsigned int irq)
72 {
73         struct fpga_irq set = get_fpga_irq(fpga2irq(irq));
74         unsigned int bit = irq - set.base;
75         __raw_writew(__raw_readw(set.mraddr) | 0x0001 << bit, set.mraddr);
76 }
77
78 static void enable_se7724_irq(unsigned int irq)
79 {
80         struct fpga_irq set = get_fpga_irq(fpga2irq(irq));
81         unsigned int bit = irq - set.base;
82         __raw_writew(__raw_readw(set.mraddr) & ~(0x0001 << bit), set.mraddr);
83 }
84
85 static struct irq_chip se7724_irq_chip __read_mostly = {
86         .name           = "SE7724-FPGA",
87         .mask           = disable_se7724_irq,
88         .unmask         = enable_se7724_irq,
89         .mask_ack       = disable_se7724_irq,
90 };
91
92 static void se7724_irq_demux(unsigned int irq, struct irq_desc *desc)
93 {
94         struct fpga_irq set = get_fpga_irq(irq);
95         unsigned short intv = __raw_readw(set.sraddr);
96         unsigned int ext_irq = set.base;
97
98         intv &= set.mask;
99
100         for (; intv; intv >>= 1, ext_irq++) {
101                 if (!(intv & 1))
102                         continue;
103
104                 generic_handle_irq(ext_irq);
105         }
106 }
107
108 /*
109  * Initialize IRQ setting
110  */
111 void __init init_se7724_IRQ(void)
112 {
113         int i, nid = cpu_to_node(boot_cpu_data);
114
115         __raw_writew(0xffff, IRQ0_MR);  /* mask all */
116         __raw_writew(0xffff, IRQ1_MR);  /* mask all */
117         __raw_writew(0xffff, IRQ2_MR);  /* mask all */
118         __raw_writew(0x0000, IRQ0_SR);  /* clear irq */
119         __raw_writew(0x0000, IRQ1_SR);  /* clear irq */
120         __raw_writew(0x0000, IRQ2_SR);  /* clear irq */
121         __raw_writew(0x002a, IRQ_MODE); /* set irq type */
122
123         for (i = 0; i < SE7724_FPGA_IRQ_NR; i++) {
124                 int irq, wanted;
125
126                 wanted = SE7724_FPGA_IRQ_BASE + i;
127
128                 irq = create_irq_nr(wanted, nid);
129                 if (unlikely(irq == 0)) {
130                         pr_err("%s: failed hooking irq %d for FPGA\n",
131                                __func__, wanted);
132                         return;
133                 }
134
135                 if (unlikely(irq != wanted)) {
136                         pr_err("%s: got irq %d but wanted %d, bailing.\n",
137                                __func__, irq, wanted);
138                         destroy_irq(irq);
139                         return;
140                 }
141
142                 set_irq_chip_and_handler_name(irq,
143                                               &se7724_irq_chip,
144                                               handle_level_irq, "level");
145         }
146
147         set_irq_chained_handler(IRQ0_IRQ, se7724_irq_demux);
148         set_irq_type(IRQ0_IRQ, IRQ_TYPE_LEVEL_LOW);
149
150         set_irq_chained_handler(IRQ1_IRQ, se7724_irq_demux);
151         set_irq_type(IRQ1_IRQ, IRQ_TYPE_LEVEL_LOW);
152
153         set_irq_chained_handler(IRQ2_IRQ, se7724_irq_demux);
154         set_irq_type(IRQ2_IRQ, IRQ_TYPE_LEVEL_LOW);
155 }