Commit 9869848d12601cdddf097a36aebe0b10dc5d177b
Committed by
Ralf Baechle
1 parent
570a0bb82f
Exists in
master
and in
7 other branches
MIPS: JZ4740: Add IRQ handler code
Add support for IRQ handling on a JZ4740 SoC. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/1465/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Showing 3 changed files with 245 additions and 0 deletions Side-by-side Diff
arch/mips/include/asm/mach-jz4740/irq.h
1 | +/* | |
2 | + * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de> | |
3 | + * JZ4740 IRQ definitions | |
4 | + * | |
5 | + * This program is free software; you can redistribute it and/or modify it | |
6 | + * under the terms of the GNU General Public License as published by the | |
7 | + * Free Software Foundation; either version 2 of the License, or (at your | |
8 | + * option) any later version. | |
9 | + * | |
10 | + * You should have received a copy of the GNU General Public License along | |
11 | + * with this program; if not, write to the Free Software Foundation, Inc., | |
12 | + * 675 Mass Ave, Cambridge, MA 02139, USA. | |
13 | + * | |
14 | + */ | |
15 | + | |
16 | +#ifndef __ASM_MACH_JZ4740_IRQ_H__ | |
17 | +#define __ASM_MACH_JZ4740_IRQ_H__ | |
18 | + | |
19 | +#define MIPS_CPU_IRQ_BASE 0 | |
20 | +#define JZ4740_IRQ_BASE 8 | |
21 | + | |
22 | +/* 1st-level interrupts */ | |
23 | +#define JZ4740_IRQ(x) (JZ4740_IRQ_BASE + (x)) | |
24 | +#define JZ4740_IRQ_I2C JZ4740_IRQ(1) | |
25 | +#define JZ4740_IRQ_UHC JZ4740_IRQ(3) | |
26 | +#define JZ4740_IRQ_UART1 JZ4740_IRQ(8) | |
27 | +#define JZ4740_IRQ_UART0 JZ4740_IRQ(9) | |
28 | +#define JZ4740_IRQ_SADC JZ4740_IRQ(12) | |
29 | +#define JZ4740_IRQ_MSC JZ4740_IRQ(14) | |
30 | +#define JZ4740_IRQ_RTC JZ4740_IRQ(15) | |
31 | +#define JZ4740_IRQ_SSI JZ4740_IRQ(16) | |
32 | +#define JZ4740_IRQ_CIM JZ4740_IRQ(17) | |
33 | +#define JZ4740_IRQ_AIC JZ4740_IRQ(18) | |
34 | +#define JZ4740_IRQ_ETH JZ4740_IRQ(19) | |
35 | +#define JZ4740_IRQ_DMAC JZ4740_IRQ(20) | |
36 | +#define JZ4740_IRQ_TCU2 JZ4740_IRQ(21) | |
37 | +#define JZ4740_IRQ_TCU1 JZ4740_IRQ(22) | |
38 | +#define JZ4740_IRQ_TCU0 JZ4740_IRQ(23) | |
39 | +#define JZ4740_IRQ_UDC JZ4740_IRQ(24) | |
40 | +#define JZ4740_IRQ_GPIO3 JZ4740_IRQ(25) | |
41 | +#define JZ4740_IRQ_GPIO2 JZ4740_IRQ(26) | |
42 | +#define JZ4740_IRQ_GPIO1 JZ4740_IRQ(27) | |
43 | +#define JZ4740_IRQ_GPIO0 JZ4740_IRQ(28) | |
44 | +#define JZ4740_IRQ_IPU JZ4740_IRQ(29) | |
45 | +#define JZ4740_IRQ_LCD JZ4740_IRQ(30) | |
46 | + | |
47 | +/* 2nd-level interrupts */ | |
48 | +#define JZ4740_IRQ_DMA(x) (JZ4740_IRQ(32) + (X)) | |
49 | + | |
50 | +#define JZ4740_IRQ_INTC_GPIO(x) (JZ4740_IRQ_GPIO0 - (x)) | |
51 | +#define JZ4740_IRQ_GPIO(x) (JZ4740_IRQ(48) + (x)) | |
52 | + | |
53 | +#define JZ4740_IRQ_ADC_BASE JZ4740_IRQ(176) | |
54 | + | |
55 | +#define NR_IRQS (JZ4740_IRQ_ADC_BASE + 6) | |
56 | + | |
57 | +#endif |
arch/mips/jz4740/irq.c
1 | +/* | |
2 | + * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de> | |
3 | + * JZ4740 platform IRQ support | |
4 | + * | |
5 | + * This program is free software; you can redistribute it and/or modify it | |
6 | + * under the terms of the GNU General Public License as published by the | |
7 | + * Free Software Foundation; either version 2 of the License, or (at your | |
8 | + * option) any later version. | |
9 | + * | |
10 | + * You should have received a copy of the GNU General Public License along | |
11 | + * with this program; if not, write to the Free Software Foundation, Inc., | |
12 | + * 675 Mass Ave, Cambridge, MA 02139, USA. | |
13 | + * | |
14 | + */ | |
15 | + | |
16 | +#include <linux/errno.h> | |
17 | +#include <linux/init.h> | |
18 | +#include <linux/types.h> | |
19 | +#include <linux/interrupt.h> | |
20 | +#include <linux/ioport.h> | |
21 | +#include <linux/timex.h> | |
22 | +#include <linux/slab.h> | |
23 | +#include <linux/delay.h> | |
24 | + | |
25 | +#include <linux/debugfs.h> | |
26 | +#include <linux/seq_file.h> | |
27 | + | |
28 | +#include <asm/io.h> | |
29 | +#include <asm/mipsregs.h> | |
30 | +#include <asm/irq_cpu.h> | |
31 | + | |
32 | +#include <asm/mach-jz4740/base.h> | |
33 | + | |
34 | +static void __iomem *jz_intc_base; | |
35 | +static uint32_t jz_intc_wakeup; | |
36 | +static uint32_t jz_intc_saved; | |
37 | + | |
38 | +#define JZ_REG_INTC_STATUS 0x00 | |
39 | +#define JZ_REG_INTC_MASK 0x04 | |
40 | +#define JZ_REG_INTC_SET_MASK 0x08 | |
41 | +#define JZ_REG_INTC_CLEAR_MASK 0x0c | |
42 | +#define JZ_REG_INTC_PENDING 0x10 | |
43 | + | |
44 | +#define IRQ_BIT(x) BIT((x) - JZ4740_IRQ_BASE) | |
45 | + | |
46 | +static void intc_irq_unmask(unsigned int irq) | |
47 | +{ | |
48 | + writel(IRQ_BIT(irq), jz_intc_base + JZ_REG_INTC_CLEAR_MASK); | |
49 | +} | |
50 | + | |
51 | +static void intc_irq_mask(unsigned int irq) | |
52 | +{ | |
53 | + writel(IRQ_BIT(irq), jz_intc_base + JZ_REG_INTC_SET_MASK); | |
54 | +} | |
55 | + | |
56 | +static int intc_irq_set_wake(unsigned int irq, unsigned int on) | |
57 | +{ | |
58 | + if (on) | |
59 | + jz_intc_wakeup |= IRQ_BIT(irq); | |
60 | + else | |
61 | + jz_intc_wakeup &= ~IRQ_BIT(irq); | |
62 | + | |
63 | + return 0; | |
64 | +} | |
65 | + | |
66 | +static struct irq_chip intc_irq_type = { | |
67 | + .name = "INTC", | |
68 | + .mask = intc_irq_mask, | |
69 | + .mask_ack = intc_irq_mask, | |
70 | + .unmask = intc_irq_unmask, | |
71 | + .set_wake = intc_irq_set_wake, | |
72 | +}; | |
73 | + | |
74 | +static irqreturn_t jz4740_cascade(int irq, void *data) | |
75 | +{ | |
76 | + uint32_t irq_reg; | |
77 | + | |
78 | + irq_reg = readl(jz_intc_base + JZ_REG_INTC_PENDING); | |
79 | + | |
80 | + if (irq_reg) | |
81 | + generic_handle_irq(__fls(irq_reg) + JZ4740_IRQ_BASE); | |
82 | + | |
83 | + return IRQ_HANDLED; | |
84 | +} | |
85 | + | |
86 | +static struct irqaction jz4740_cascade_action = { | |
87 | + .handler = jz4740_cascade, | |
88 | + .name = "JZ4740 cascade interrupt", | |
89 | +}; | |
90 | + | |
91 | +void __init arch_init_irq(void) | |
92 | +{ | |
93 | + int i; | |
94 | + mips_cpu_irq_init(); | |
95 | + | |
96 | + jz_intc_base = ioremap(JZ4740_INTC_BASE_ADDR, 0x14); | |
97 | + | |
98 | + for (i = JZ4740_IRQ_BASE; i < JZ4740_IRQ_BASE + 32; i++) { | |
99 | + intc_irq_mask(i); | |
100 | + set_irq_chip_and_handler(i, &intc_irq_type, handle_level_irq); | |
101 | + } | |
102 | + | |
103 | + setup_irq(2, &jz4740_cascade_action); | |
104 | +} | |
105 | + | |
106 | +asmlinkage void plat_irq_dispatch(void) | |
107 | +{ | |
108 | + unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM; | |
109 | + if (pending & STATUSF_IP2) | |
110 | + do_IRQ(2); | |
111 | + else if (pending & STATUSF_IP3) | |
112 | + do_IRQ(3); | |
113 | + else | |
114 | + spurious_interrupt(); | |
115 | +} | |
116 | + | |
117 | +void jz4740_intc_suspend(void) | |
118 | +{ | |
119 | + jz_intc_saved = readl(jz_intc_base + JZ_REG_INTC_MASK); | |
120 | + writel(~jz_intc_wakeup, jz_intc_base + JZ_REG_INTC_SET_MASK); | |
121 | + writel(jz_intc_wakeup, jz_intc_base + JZ_REG_INTC_CLEAR_MASK); | |
122 | +} | |
123 | + | |
124 | +void jz4740_intc_resume(void) | |
125 | +{ | |
126 | + writel(~jz_intc_saved, jz_intc_base + JZ_REG_INTC_CLEAR_MASK); | |
127 | + writel(jz_intc_saved, jz_intc_base + JZ_REG_INTC_SET_MASK); | |
128 | +} | |
129 | + | |
130 | +#ifdef CONFIG_DEBUG_FS | |
131 | + | |
132 | +static inline void intc_seq_reg(struct seq_file *s, const char *name, | |
133 | + unsigned int reg) | |
134 | +{ | |
135 | + seq_printf(s, "%s:\t\t%08x\n", name, readl(jz_intc_base + reg)); | |
136 | +} | |
137 | + | |
138 | +static int intc_regs_show(struct seq_file *s, void *unused) | |
139 | +{ | |
140 | + intc_seq_reg(s, "Status", JZ_REG_INTC_STATUS); | |
141 | + intc_seq_reg(s, "Mask", JZ_REG_INTC_MASK); | |
142 | + intc_seq_reg(s, "Pending", JZ_REG_INTC_PENDING); | |
143 | + | |
144 | + return 0; | |
145 | +} | |
146 | + | |
147 | +static int intc_regs_open(struct inode *inode, struct file *file) | |
148 | +{ | |
149 | + return single_open(file, intc_regs_show, NULL); | |
150 | +} | |
151 | + | |
152 | +static const struct file_operations intc_regs_operations = { | |
153 | + .open = intc_regs_open, | |
154 | + .read = seq_read, | |
155 | + .llseek = seq_lseek, | |
156 | + .release = single_release, | |
157 | +}; | |
158 | + | |
159 | +static int __init intc_debugfs_init(void) | |
160 | +{ | |
161 | + (void) debugfs_create_file("jz_regs_intc", S_IFREG | S_IRUGO, | |
162 | + NULL, NULL, &intc_regs_operations); | |
163 | + return 0; | |
164 | +} | |
165 | +subsys_initcall(intc_debugfs_init); | |
166 | + | |
167 | +#endif |
arch/mips/jz4740/irq.h
1 | +/* | |
2 | + * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de> | |
3 | + * | |
4 | + * This program is free software; you can redistribute it and/or modify it | |
5 | + * under the terms of the GNU General Public License as published by the | |
6 | + * Free Software Foundation; either version 2 of the License, or (at your | |
7 | + * option) any later version. | |
8 | + * | |
9 | + * You should have received a copy of the GNU General Public License along | |
10 | + * with this program; if not, write to the Free Software Foundation, Inc., | |
11 | + * 675 Mass Ave, Cambridge, MA 02139, USA. | |
12 | + * | |
13 | + */ | |
14 | + | |
15 | +#ifndef __MIPS_JZ4740_IRQ_H__ | |
16 | +#define __MIPS_JZ4740_IRQ_H__ | |
17 | + | |
18 | +extern void jz4740_intc_suspend(void); | |
19 | +extern void jz4740_intc_resume(void); | |
20 | + | |
21 | +#endif |