Merge branch 'vhost-net-next' of git://git.kernel.org/pub/scm/linux/kernel/git/mst...
[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(struct irq_data *data)
72 {
73         unsigned int irq = data->irq;
74         struct fpga_irq set = get_fpga_irq(fpga2irq(irq));
75         unsigned int bit = irq - set.base;
76         __raw_writew(__raw_readw(set.mraddr) | 0x0001 << bit, set.mraddr);
77 }
78
79 static void enable_se7724_irq(struct irq_data *data)
80 {
81         unsigned int irq = data->irq;
82         struct fpga_irq set = get_fpga_irq(fpga2irq(irq));
83         unsigned int bit = irq - set.base;
84         __raw_writew(__raw_readw(set.mraddr) & ~(0x0001 << bit), set.mraddr);
85 }
86
87 static struct irq_chip se7724_irq_chip __read_mostly = {
88         .name           = "SE7724-FPGA",
89         .irq_mask       = disable_se7724_irq,
90         .irq_unmask     = enable_se7724_irq,
91 };
92
93 static void se7724_irq_demux(unsigned int irq, struct irq_desc *desc)
94 {
95         struct fpga_irq set = get_fpga_irq(irq);
96         unsigned short intv = __raw_readw(set.sraddr);
97         unsigned int ext_irq = set.base;
98
99         intv &= set.mask;
100
101         for (; intv; intv >>= 1, ext_irq++) {
102                 if (!(intv & 1))
103                         continue;
104
105                 generic_handle_irq(ext_irq);
106         }
107 }
108
109 /*
110  * Initialize IRQ setting
111  */
112 void __init init_se7724_IRQ(void)
113 {
114         int i, nid = cpu_to_node(boot_cpu_data);
115
116         __raw_writew(0xffff, IRQ0_MR);  /* mask all */
117         __raw_writew(0xffff, IRQ1_MR);  /* mask all */
118         __raw_writew(0xffff, IRQ2_MR);  /* mask all */
119         __raw_writew(0x0000, IRQ0_SR);  /* clear irq */
120         __raw_writew(0x0000, IRQ1_SR);  /* clear irq */
121         __raw_writew(0x0000, IRQ2_SR);  /* clear irq */
122         __raw_writew(0x002a, IRQ_MODE); /* set irq type */
123
124         for (i = 0; i < SE7724_FPGA_IRQ_NR; i++) {
125                 int irq, wanted;
126
127                 wanted = SE7724_FPGA_IRQ_BASE + i;
128
129                 irq = create_irq_nr(wanted, nid);
130                 if (unlikely(irq == 0)) {
131                         pr_err("%s: failed hooking irq %d for FPGA\n",
132                                __func__, wanted);
133                         return;
134                 }
135
136                 if (unlikely(irq != wanted)) {
137                         pr_err("%s: got irq %d but wanted %d, bailing.\n",
138                                __func__, irq, wanted);
139                         destroy_irq(irq);
140                         return;
141                 }
142
143                 set_irq_chip_and_handler_name(irq,
144                                               &se7724_irq_chip,
145                                               handle_level_irq, "level");
146         }
147
148         set_irq_chained_handler(IRQ0_IRQ, se7724_irq_demux);
149         set_irq_type(IRQ0_IRQ, IRQ_TYPE_LEVEL_LOW);
150
151         set_irq_chained_handler(IRQ1_IRQ, se7724_irq_demux);
152         set_irq_type(IRQ1_IRQ, IRQ_TYPE_LEVEL_LOW);
153
154         set_irq_chained_handler(IRQ2_IRQ, se7724_irq_demux);
155         set_irq_type(IRQ2_IRQ, IRQ_TYPE_LEVEL_LOW);
156 }