summaryrefslogtreecommitdiffstats
path: root/kernel/arch/sh/boards/mach-r2d/irq.c
blob: 574f009c3c31099437d581250449f60d7264119d (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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/*
 * linux/arch/sh/boards/renesas/rts7751r2d/irq.c
 *
 * Copyright (C) 2007  Magnus Damm
 * Copyright (C) 2000  Kazumoto Kojima
 *
 * Renesas Technology Sales RTS7751R2D Support, R2D-PLUS and R2D-1.
 *
 * Modified for RTS7751R2D by
 * Atom Create Engineering Co., Ltd. 2002.
 */
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <mach/r2d.h>

#define R2D_NR_IRL 13

enum {
	UNUSED = 0,

	/* board specific interrupt sources (R2D-1 and R2D-PLUS) */
	EXT,              /* EXT_INT0-3 */
	RTC_T, RTC_A,     /* Real Time Clock */
	AX88796,          /* Ethernet controller (R2D-1 board) */
	KEY,              /* Key input (R2D-PLUS board) */
	SDCARD,           /* SD Card */
	CF_CD, CF_IDE,    /* CF Card Detect + CF IDE */
	SM501,            /* SM501 aka Voyager */
	PCI_INTD_RTL8139, /* Ethernet controller */
	PCI_INTC_PCI1520, /* Cardbus/PCMCIA bridge */
	PCI_INTB_RTL8139, /* Ethernet controller with HUB (R2D-PLUS board) */
	PCI_INTB_SLOT,    /* PCI Slot 3.3v (R2D-1 board) */
	PCI_INTA_SLOT,    /* PCI Slot 3.3v */
	TP,               /* Touch Panel */
};

#ifdef CONFIG_RTS7751R2D_1

/* Vectors for R2D-1 */
static struct intc_vect vectors_r2d_1[] __initdata = {
	INTC_IRQ(EXT, IRQ_EXT),
	INTC_IRQ(RTC_T, IRQ_RTC_T), INTC_IRQ(RTC_A, IRQ_RTC_A),
	INTC_IRQ(AX88796, IRQ_AX88796), INTC_IRQ(SDCARD, IRQ_SDCARD),
	INTC_IRQ(CF_CD, IRQ_CF_CD), INTC_IRQ(CF_IDE, IRQ_CF_IDE), /* ng */
	INTC_IRQ(SM501, IRQ_VOYAGER),
	INTC_IRQ(PCI_INTD_RTL8139, IRQ_PCI_INTD),
	INTC_IRQ(PCI_INTC_PCI1520, IRQ_PCI_INTC),
	INTC_IRQ(PCI_INTB_SLOT, IRQ_PCI_INTB),
	INTC_IRQ(PCI_INTA_SLOT, IRQ_PCI_INTA),
	INTC_IRQ(TP, IRQ_TP),
};

/* IRLMSK mask register layout for R2D-1 */
static struct intc_mask_reg mask_registers_r2d_1[] __initdata = {
	{ 0xa4000000, 0, 16, /* IRLMSK */
	  { TP, PCI_INTA_SLOT, PCI_INTB_SLOT,
	    PCI_INTC_PCI1520, PCI_INTD_RTL8139,
	    SM501, CF_IDE, CF_CD, SDCARD, AX88796,
	    RTC_A, RTC_T, 0, 0, 0, EXT } },
};

/* IRLn to IRQ table for R2D-1 */
static unsigned char irl2irq_r2d_1[R2D_NR_IRL] __initdata = {
	IRQ_PCI_INTD, IRQ_CF_IDE, IRQ_CF_CD, IRQ_PCI_INTC,
	IRQ_VOYAGER, IRQ_AX88796, IRQ_RTC_A, IRQ_RTC_T,
	IRQ_SDCARD, IRQ_PCI_INTA, IRQ_PCI_INTB, IRQ_EXT,
	IRQ_TP,
};

static DECLARE_INTC_DESC(intc_desc_r2d_1, "r2d-1", vectors_r2d_1,
			 NULL, mask_registers_r2d_1, NULL, NULL);

#endif /* CONFIG_RTS7751R2D_1 */

#ifdef CONFIG_RTS7751R2D_PLUS

/* Vectors for R2D-PLUS */
static struct intc_vect vectors_r2d_plus[] __initdata = {
	INTC_IRQ(EXT, IRQ_EXT),
	INTC_IRQ(RTC_T, IRQ_RTC_T), INTC_IRQ(RTC_A, IRQ_RTC_A),
	INTC_IRQ(KEY, IRQ_KEY), INTC_IRQ(SDCARD, IRQ_SDCARD),
	INTC_IRQ(CF_CD, IRQ_CF_CD), INTC_IRQ(CF_IDE, IRQ_CF_IDE),
	INTC_IRQ(SM501, IRQ_VOYAGER),
	INTC_IRQ(PCI_INTD_RTL8139, IRQ_PCI_INTD),
	INTC_IRQ(PCI_INTC_PCI1520, IRQ_PCI_INTC),
	INTC_IRQ(PCI_INTB_RTL8139, IRQ_PCI_INTB),
	INTC_IRQ(PCI_INTA_SLOT, IRQ_PCI_INTA),
	INTC_IRQ(TP, IRQ_TP),
};

/* IRLMSK mask register layout for R2D-PLUS */
static struct intc_mask_reg mask_registers_r2d_plus[] __initdata = {
	{ 0xa4000000, 0, 16, /* IRLMSK */
	  { TP, PCI_INTA_SLOT, PCI_INTB_RTL8139,
	    PCI_INTC_PCI1520, PCI_INTD_RTL8139,
	    SM501, CF_IDE, CF_CD, SDCARD, KEY,
	    RTC_A, RTC_T, 0, 0, 0, EXT } },
};

/* IRLn to IRQ table for R2D-PLUS */
static unsigned char irl2irq_r2d_plus[R2D_NR_IRL] __initdata = {
	IRQ_PCI_INTD, IRQ_CF_IDE, IRQ_CF_CD, IRQ_PCI_INTC,
	IRQ_VOYAGER, IRQ_KEY, IRQ_RTC_A, IRQ_RTC_T,
	IRQ_SDCARD, IRQ_PCI_INTA, IRQ_PCI_INTB, IRQ_EXT,
	IRQ_TP,
};

static DECLARE_INTC_DESC(intc_desc_r2d_plus, "r2d-plus", vectors_r2d_plus,
			 NULL, mask_registers_r2d_plus, NULL, NULL);

#endif /* CONFIG_RTS7751R2D_PLUS */

static unsigned char irl2irq[R2D_NR_IRL];

int rts7751r2d_irq_demux(int irq)
{
	if (irq >= R2D_NR_IRL || irq < 0 || !irl2irq[irq])
		return irq;

	return irl2irq[irq];
}

/*
 * Initialize IRQ setting
 */
void __init init_rts7751r2d_IRQ(void)
{
	struct intc_desc *d;

	switch (__raw_readw(PA_VERREG) & 0xf0) {
#ifdef CONFIG_RTS7751R2D_PLUS
	case 0x10:
		printk(KERN_INFO "Using R2D-PLUS interrupt controller.\n");
		d = &intc_desc_r2d_plus;
		memcpy(irl2irq, irl2irq_r2d_plus, R2D_NR_IRL);
		break;
#endif
#ifdef CONFIG_RTS7751R2D_1
	case 0x00: /* according to manual */
	case 0x30: /* in reality */
		printk(KERN_INFO "Using R2D-1 interrupt controller.\n");
		d = &intc_desc_r2d_1;
		memcpy(irl2irq, irl2irq_r2d_1, R2D_NR_IRL);
		break;
#endif
	default:
		printk(KERN_INFO "Unknown R2D interrupt controller 0x%04x\n",
		       __raw_readw(PA_VERREG));
		return;
	}

	register_intc_controller(d);
}