]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - arch/sh/boards/mach-se/7724/irq.c
Merge remote-tracking branch 'qcom/qcom/for-next'
[karo-tx-linux.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 <linux/export.h>
21 #include <linux/topology.h>
22 #include <linux/io.h>
23 #include <linux/err.h>
24 #include <mach-se/mach/se7724.h>
25
26 struct fpga_irq {
27         unsigned long  sraddr;
28         unsigned long  mraddr;
29         unsigned short mask;
30         unsigned int   base;
31 };
32
33 static unsigned int fpga2irq(unsigned int irq)
34 {
35         if (irq >= IRQ0_BASE &&
36             irq <= IRQ0_END)
37                 return IRQ0_IRQ;
38         else if (irq >= IRQ1_BASE &&
39                  irq <= IRQ1_END)
40                 return IRQ1_IRQ;
41         else
42                 return IRQ2_IRQ;
43 }
44
45 static struct fpga_irq get_fpga_irq(unsigned int irq)
46 {
47         struct fpga_irq set;
48
49         switch (irq) {
50         case IRQ0_IRQ:
51                 set.sraddr = IRQ0_SR;
52                 set.mraddr = IRQ0_MR;
53                 set.mask   = IRQ0_MASK;
54                 set.base   = IRQ0_BASE;
55                 break;
56         case IRQ1_IRQ:
57                 set.sraddr = IRQ1_SR;
58                 set.mraddr = IRQ1_MR;
59                 set.mask   = IRQ1_MASK;
60                 set.base   = IRQ1_BASE;
61                 break;
62         default:
63                 set.sraddr = IRQ2_SR;
64                 set.mraddr = IRQ2_MR;
65                 set.mask   = IRQ2_MASK;
66                 set.base   = IRQ2_BASE;
67                 break;
68         }
69
70         return set;
71 }
72
73 static void disable_se7724_irq(struct irq_data *data)
74 {
75         unsigned int irq = data->irq;
76         struct fpga_irq set = get_fpga_irq(fpga2irq(irq));
77         unsigned int bit = irq - set.base;
78         __raw_writew(__raw_readw(set.mraddr) | 0x0001 << bit, set.mraddr);
79 }
80
81 static void enable_se7724_irq(struct irq_data *data)
82 {
83         unsigned int irq = data->irq;
84         struct fpga_irq set = get_fpga_irq(fpga2irq(irq));
85         unsigned int bit = irq - set.base;
86         __raw_writew(__raw_readw(set.mraddr) & ~(0x0001 << bit), set.mraddr);
87 }
88
89 static struct irq_chip se7724_irq_chip __read_mostly = {
90         .name           = "SE7724-FPGA",
91         .irq_mask       = disable_se7724_irq,
92         .irq_unmask     = enable_se7724_irq,
93 };
94
95 static void se7724_irq_demux(struct irq_desc *desc)
96 {
97         unsigned int irq = irq_desc_get_irq(desc);
98         struct fpga_irq set = get_fpga_irq(irq);
99         unsigned short intv = __raw_readw(set.sraddr);
100         unsigned int ext_irq = set.base;
101
102         intv &= set.mask;
103
104         for (; intv; intv >>= 1, ext_irq++) {
105                 if (!(intv & 1))
106                         continue;
107
108                 generic_handle_irq(ext_irq);
109         }
110 }
111
112 /*
113  * Initialize IRQ setting
114  */
115 void __init init_se7724_IRQ(void)
116 {
117         int irq_base, i;
118
119         __raw_writew(0xffff, IRQ0_MR);  /* mask all */
120         __raw_writew(0xffff, IRQ1_MR);  /* mask all */
121         __raw_writew(0xffff, IRQ2_MR);  /* mask all */
122         __raw_writew(0x0000, IRQ0_SR);  /* clear irq */
123         __raw_writew(0x0000, IRQ1_SR);  /* clear irq */
124         __raw_writew(0x0000, IRQ2_SR);  /* clear irq */
125         __raw_writew(0x002a, IRQ_MODE); /* set irq type */
126
127         irq_base = irq_alloc_descs(SE7724_FPGA_IRQ_BASE, SE7724_FPGA_IRQ_BASE,
128                                    SE7724_FPGA_IRQ_NR, numa_node_id());
129         if (IS_ERR_VALUE(irq_base)) {
130                 pr_err("%s: failed hooking irqs for FPGA\n", __func__);
131                 return;
132         }
133
134         for (i = 0; i < SE7724_FPGA_IRQ_NR; i++)
135                 irq_set_chip_and_handler_name(irq_base + i, &se7724_irq_chip,
136                                               handle_level_irq, "level");
137
138         irq_set_chained_handler(IRQ0_IRQ, se7724_irq_demux);
139         irq_set_irq_type(IRQ0_IRQ, IRQ_TYPE_LEVEL_LOW);
140
141         irq_set_chained_handler(IRQ1_IRQ, se7724_irq_demux);
142         irq_set_irq_type(IRQ1_IRQ, IRQ_TYPE_LEVEL_LOW);
143
144         irq_set_chained_handler(IRQ2_IRQ, se7724_irq_demux);
145         irq_set_irq_type(IRQ2_IRQ, IRQ_TYPE_LEVEL_LOW);
146 }