1/*
2 * arch/arm/mach-ks8695/irq.c
3 *
4 * Copyright (C) 2006 Ben Dooks <ben@simtec.co.uk>
5 * Copyright (C) 2006 Simtec Electronics
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20 */
21
22#include <linux/init.h>
23#include <linux/module.h>
24#include <linux/interrupt.h>
25#include <linux/ioport.h>
26#include <linux/ptrace.h>
27#include <linux/sysdev.h>
28
29#include <asm/hardware.h>
30#include <asm/irq.h>
31#include <asm/io.h>
32
33#include <asm/mach/irq.h>
34
35#include <asm/arch/regs-irq.h>
36#include <asm/arch/regs-gpio.h>
37
38static void ks8695_irq_mask(unsigned int irqno)
39{
40	unsigned long inten;
41
42	inten = __raw_readl(KS8695_IRQ_VA + KS8695_INTEN);
43	inten &= ~(1 << irqno);
44
45	__raw_writel(inten, KS8695_IRQ_VA + KS8695_INTEN);
46}
47
48static void ks8695_irq_unmask(unsigned int irqno)
49{
50	unsigned long inten;
51
52	inten = __raw_readl(KS8695_IRQ_VA + KS8695_INTEN);
53	inten |= (1 << irqno);
54
55	__raw_writel(inten, KS8695_IRQ_VA + KS8695_INTEN);
56}
57
58static void ks8695_irq_ack(unsigned int irqno)
59{
60	__raw_writel((1 << irqno), KS8695_IRQ_VA + KS8695_INTST);
61}
62
63
64static struct irq_chip ks8695_irq_level_chip;
65static struct irq_chip ks8695_irq_edge_chip;
66
67
68static int ks8695_irq_set_type(unsigned int irqno, unsigned int type)
69{
70	unsigned long ctrl, mode;
71	unsigned short level_triggered = 0;
72
73	ctrl = __raw_readl(KS8695_GPIO_VA + KS8695_IOPC);
74
75	switch (type) {
76		case IRQT_HIGH:
77			mode = IOPC_TM_HIGH;
78			level_triggered = 1;
79			break;
80		case IRQT_LOW:
81			mode = IOPC_TM_LOW;
82			level_triggered = 1;
83			break;
84		case IRQT_RISING:
85			mode = IOPC_TM_RISING;
86			break;
87		case IRQT_FALLING:
88			mode = IOPC_TM_FALLING;
89			break;
90		case IRQT_BOTHEDGE:
91			mode = IOPC_TM_EDGE;
92			break;
93		default:
94			return -EINVAL;
95	}
96
97	switch (irqno) {
98		case KS8695_IRQ_EXTERN0:
99			ctrl &= ~IOPC_IOEINT0TM;
100			ctrl |= IOPC_IOEINT0_MODE(mode);
101			break;
102		case KS8695_IRQ_EXTERN1:
103			ctrl &= ~IOPC_IOEINT1TM;
104			ctrl |= IOPC_IOEINT1_MODE(mode);
105			break;
106		case KS8695_IRQ_EXTERN2:
107			ctrl &= ~IOPC_IOEINT2TM;
108			ctrl |= IOPC_IOEINT2_MODE(mode);
109			break;
110		case KS8695_IRQ_EXTERN3:
111			ctrl &= ~IOPC_IOEINT3TM;
112			ctrl |= IOPC_IOEINT3_MODE(mode);
113			break;
114		default:
115			return -EINVAL;
116	}
117
118	if (level_triggered) {
119		set_irq_chip(irqno, &ks8695_irq_level_chip);
120		set_irq_handler(irqno, handle_level_irq);
121	}
122	else {
123		set_irq_chip(irqno, &ks8695_irq_edge_chip);
124		set_irq_handler(irqno, handle_edge_irq);
125	}
126
127	__raw_writel(ctrl, KS8695_GPIO_VA + KS8695_IOPC);
128	return 0;
129}
130
131static struct irq_chip ks8695_irq_level_chip = {
132	.ack		= ks8695_irq_mask,
133	.mask		= ks8695_irq_mask,
134	.unmask		= ks8695_irq_unmask,
135	.set_type	= ks8695_irq_set_type,
136};
137
138static struct irq_chip ks8695_irq_edge_chip = {
139	.ack		= ks8695_irq_ack,
140	.mask		= ks8695_irq_mask,
141	.unmask		= ks8695_irq_unmask,
142	.set_type	= ks8695_irq_set_type,
143};
144
145void __init ks8695_init_irq(void)
146{
147	unsigned int irq;
148
149	/* Disable all interrupts initially */
150	__raw_writel(0, KS8695_IRQ_VA + KS8695_INTMC);
151	__raw_writel(0, KS8695_IRQ_VA + KS8695_INTEN);
152
153	for (irq = 0; irq < NR_IRQS; irq++) {
154		switch (irq) {
155			/* Level-triggered interrupts */
156			case KS8695_IRQ_BUS_ERROR:
157			case KS8695_IRQ_UART_MODEM_STATUS:
158			case KS8695_IRQ_UART_LINE_STATUS:
159			case KS8695_IRQ_UART_RX:
160			case KS8695_IRQ_COMM_TX:
161			case KS8695_IRQ_COMM_RX:
162				set_irq_chip(irq, &ks8695_irq_level_chip);
163				set_irq_handler(irq, handle_level_irq);
164				break;
165
166			/* Edge-triggered interrupts */
167			default:
168				ks8695_irq_ack(irq);	/* clear pending bit */
169				set_irq_chip(irq, &ks8695_irq_edge_chip);
170				set_irq_handler(irq, handle_edge_irq);
171		}
172
173		set_irq_flags(irq, IRQF_VALID);
174	}
175}
176