summaryrefslogtreecommitdiff
path: root/arch/sh/boards/renesas/rts7751r2d/irq.c
blob: 154535440bbf7a626c76272e6b9c9ed36545c45b (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
/*
 * linux/arch/sh/boards/renesas/rts7751r2d/irq.c
 *
 * Copyright (C) 2000  Kazumoto Kojima
 *
 * Renesas Technology Sales RTS7751R2D Support.
 *
 * Modified for RTS7751R2D by
 * Atom Create Engineering Co., Ltd. 2002.
 */

#include <linux/init.h>
#include <linux/irq.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/rts7751r2d/rts7751r2d.h>

#if defined(CONFIG_RTS7751R2D_REV11)
static int mask_pos[] = {11, 9, 8, 12, 10, 6, 5, 4, 7, 14, 13, 0, 0, 0, 0};
#else
static int mask_pos[] = {6, 11, 9, 8, 12, 10, 5, 4, 7, 14, 13, 0, 0, 0, 0};
#endif

extern int voyagergx_irq_demux(int irq);
extern void setup_voyagergx_irq(void);

static void enable_rts7751r2d_irq(unsigned int irq);
static void disable_rts7751r2d_irq(unsigned int irq);

/* shutdown is same as "disable" */
#define shutdown_rts7751r2d_irq disable_rts7751r2d_irq

static void ack_rts7751r2d_irq(unsigned int irq);
static void end_rts7751r2d_irq(unsigned int irq);

static unsigned int startup_rts7751r2d_irq(unsigned int irq)
{
	enable_rts7751r2d_irq(irq);
	return 0; /* never anything pending */
}

static void disable_rts7751r2d_irq(unsigned int irq)
{
	unsigned long flags;
	unsigned short val;
	unsigned short mask = 0xffff ^ (0x0001 << mask_pos[irq]);

	/* Set the priority in IPR to 0 */
	local_irq_save(flags);
	val = ctrl_inw(IRLCNTR1);
	val &= mask;
	ctrl_outw(val, IRLCNTR1);
	local_irq_restore(flags);
}

static void enable_rts7751r2d_irq(unsigned int irq)
{
	unsigned long flags;
	unsigned short val;
	unsigned short value = (0x0001 << mask_pos[irq]);

	/* Set priority in IPR back to original value */
	local_irq_save(flags);
	val = ctrl_inw(IRLCNTR1);
	val |= value;
	ctrl_outw(val, IRLCNTR1);
	local_irq_restore(flags);
}

int rts7751r2d_irq_demux(int irq)
{
	int demux_irq;

	demux_irq = voyagergx_irq_demux(irq);
	return demux_irq;
}

static void ack_rts7751r2d_irq(unsigned int irq)
{
	disable_rts7751r2d_irq(irq);
}

static void end_rts7751r2d_irq(unsigned int irq)
{
	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
		enable_rts7751r2d_irq(irq);
}

static struct hw_interrupt_type rts7751r2d_irq_type = {
	.typename = "RTS7751R2D IRQ",
	.startup = startup_rts7751r2d_irq,
	.shutdown = shutdown_rts7751r2d_irq,
	.enable = enable_rts7751r2d_irq,
	.disable = disable_rts7751r2d_irq,
	.ack = ack_rts7751r2d_irq,
	.end = end_rts7751r2d_irq,
};

static void make_rts7751r2d_irq(unsigned int irq)
{
	disable_irq_nosync(irq);
	irq_desc[irq].chip = &rts7751r2d_irq_type;
	disable_rts7751r2d_irq(irq);
}

/*
 * Initialize IRQ setting
 */
void __init init_rts7751r2d_IRQ(void)
{
	int i;

	/* IRL0=KEY Input
	 * IRL1=Ethernet
	 * IRL2=CF Card
	 * IRL3=CF Card Insert
	 * IRL4=PCMCIA
	 * IRL5=VOYAGER
	 * IRL6=RTC Alarm
	 * IRL7=RTC Timer
	 * IRL8=SD Card
	 * IRL9=PCI Slot #1
	 * IRL10=PCI Slot #2
	 * IRL11=Extention #0
	 * IRL12=Extention #1
	 * IRL13=Extention #2
	 * IRL14=Extention #3
	 */

	for (i=0; i<15; i++)
		make_rts7751r2d_irq(i);

	setup_voyagergx_irq();
}