summaryrefslogtreecommitdiffstats
path: root/target/linux/adm8668/files/arch/mips/adm8668/irq.c
blob: aac2ff4e0b98bebcbc2c10707f518d95a966deb8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/*
 * Copyright (C) 2010 Scott Nicholas <neutronscott@scottn.us>
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 */

#include <linux/init.h>
#include <linux/kernel_stat.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/random.h>
#include <linux/pm.h>
#include <linux/irq.h>
#include <asm/mipsregs.h>
#include <asm/irq_cpu.h>
#include <asm/irq.h>
#include <adm8668.h>


void enable_adm8668_irq(unsigned int irq);
void disable_adm8668_irq(unsigned int irq);
void adm8668_irq_cascade(void);

void plat_irq_dispatch(void)
{
	unsigned int pending;

	pending = read_c0_cause() & read_c0_status() & ST0_IM;

	/* timer interrupt, that we renumbered */
	if (pending & STATUSF_IP7)
		do_IRQ(MIPS_CPU_IRQ_BASE + 7);
	if (pending & STATUSF_IP2)
		adm8668_irq_cascade();
}

/*
 * System irq dispatch
 */
void adm8668_irq_cascade()
{
	int i;
	unsigned long intsrc;

	intsrc = ADM8668_INTC_REG(IRQ_STATUS_REG) & IRQ_MASK;
	for (i = 0; intsrc; intsrc >>= 1, i++)
		if (intsrc & 0x1)
			do_IRQ(i);
}

/*
 * irq enable
 */
static __inline void _irq_enable(int irql)
{
	ADM8668_INTC_REG(IRQ_ENABLE_REG) = (1 << irql);
}


/*
 * irq disable
 */
static __inline void _irq_disable(int irql)
{
	ADM8668_INTC_REG(IRQ_DISABLE_REG) = (1 << irql);
}


/*
 * enable 8668 irq
 */
void enable_adm8668_irq(unsigned int irq)
{
	if ((irq < 0) || (irq > NR_IRQS))
		return;

	_irq_enable(irq);
}


/*
 * disable 8668 irq
 */
void disable_adm8668_irq(unsigned int irq)
{
	if ((irq < 0) || (irq > NR_IRQS))
		return;

	_irq_disable(irq);
}

static inline void ack_adm8668_irq(unsigned int irq_nr)
{
	ADM8668_INTC_REG(IRQ_DISABLE_REG) = (1 << irq_nr);
}

/*
 * system irq type
 */

static struct irq_chip adm8668_irq_type = {
	.name = "adm8668",
	.ack = ack_adm8668_irq,
	.mask = disable_adm8668_irq,
	.unmask = enable_adm8668_irq
};

/*
 * irq init
 */
void __init init_adm8668_irqs(void)
{
	int i;

	for (i = 0; i <= INT_LVL_MAX; i++)
		set_irq_chip_and_handler(i, &adm8668_irq_type,
			handle_level_irq);

	/* hw0 is where our interrupts are uh.. interrupted at. */
	set_c0_status(IE_IRQ0);
}

/*
 * system init
 */
void __init arch_init_irq(void)
{
	mips_cpu_irq_init();
	init_adm8668_irqs();
}