• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/device.h>
27 #include <linux/io.h>
28 
29 #include <mach/hardware.h>
30 #include <asm/irq.h>
31 
32 #include <asm/mach/irq.h>
33 
34 #include <mach/regs-irq.h>
35 #include <mach/regs-gpio.h>
36 
ks8695_irq_mask(struct irq_data * d)37 static void ks8695_irq_mask(struct irq_data *d)
38 {
39 	unsigned long inten;
40 
41 	inten = __raw_readl(KS8695_IRQ_VA + KS8695_INTEN);
42 	inten &= ~(1 << d->irq);
43 
44 	__raw_writel(inten, KS8695_IRQ_VA + KS8695_INTEN);
45 }
46 
ks8695_irq_unmask(struct irq_data * d)47 static void ks8695_irq_unmask(struct irq_data *d)
48 {
49 	unsigned long inten;
50 
51 	inten = __raw_readl(KS8695_IRQ_VA + KS8695_INTEN);
52 	inten |= (1 << d->irq);
53 
54 	__raw_writel(inten, KS8695_IRQ_VA + KS8695_INTEN);
55 }
56 
ks8695_irq_ack(struct irq_data * d)57 static void ks8695_irq_ack(struct irq_data *d)
58 {
59 	__raw_writel((1 << d->irq), KS8695_IRQ_VA + KS8695_INTST);
60 }
61 
62 
63 static struct irq_chip ks8695_irq_level_chip;
64 static struct irq_chip ks8695_irq_edge_chip;
65 
66 
ks8695_irq_set_type(struct irq_data * d,unsigned int type)67 static int ks8695_irq_set_type(struct irq_data *d, unsigned int type)
68 {
69 	unsigned long ctrl, mode;
70 	unsigned short level_triggered = 0;
71 
72 	ctrl = __raw_readl(KS8695_GPIO_VA + KS8695_IOPC);
73 
74 	switch (type) {
75 		case IRQ_TYPE_LEVEL_HIGH:
76 			mode = IOPC_TM_HIGH;
77 			level_triggered = 1;
78 			break;
79 		case IRQ_TYPE_LEVEL_LOW:
80 			mode = IOPC_TM_LOW;
81 			level_triggered = 1;
82 			break;
83 		case IRQ_TYPE_EDGE_RISING:
84 			mode = IOPC_TM_RISING;
85 			break;
86 		case IRQ_TYPE_EDGE_FALLING:
87 			mode = IOPC_TM_FALLING;
88 			break;
89 		case IRQ_TYPE_EDGE_BOTH:
90 			mode = IOPC_TM_EDGE;
91 			break;
92 		default:
93 			return -EINVAL;
94 	}
95 
96 	switch (d->irq) {
97 		case KS8695_IRQ_EXTERN0:
98 			ctrl &= ~IOPC_IOEINT0TM;
99 			ctrl |= IOPC_IOEINT0_MODE(mode);
100 			break;
101 		case KS8695_IRQ_EXTERN1:
102 			ctrl &= ~IOPC_IOEINT1TM;
103 			ctrl |= IOPC_IOEINT1_MODE(mode);
104 			break;
105 		case KS8695_IRQ_EXTERN2:
106 			ctrl &= ~IOPC_IOEINT2TM;
107 			ctrl |= IOPC_IOEINT2_MODE(mode);
108 			break;
109 		case KS8695_IRQ_EXTERN3:
110 			ctrl &= ~IOPC_IOEINT3TM;
111 			ctrl |= IOPC_IOEINT3_MODE(mode);
112 			break;
113 		default:
114 			return -EINVAL;
115 	}
116 
117 	if (level_triggered) {
118 		irq_set_chip_and_handler(d->irq, &ks8695_irq_level_chip,
119 					 handle_level_irq);
120 	}
121 	else {
122 		irq_set_chip_and_handler(d->irq, &ks8695_irq_edge_chip,
123 					 handle_edge_irq);
124 	}
125 
126 	__raw_writel(ctrl, KS8695_GPIO_VA + KS8695_IOPC);
127 	return 0;
128 }
129 
130 static struct irq_chip ks8695_irq_level_chip = {
131 	.irq_ack	= ks8695_irq_mask,
132 	.irq_mask	= ks8695_irq_mask,
133 	.irq_unmask	= ks8695_irq_unmask,
134 	.irq_set_type	= ks8695_irq_set_type,
135 };
136 
137 static struct irq_chip ks8695_irq_edge_chip = {
138 	.irq_ack	= ks8695_irq_ack,
139 	.irq_mask	= ks8695_irq_mask,
140 	.irq_unmask	= ks8695_irq_unmask,
141 	.irq_set_type	= ks8695_irq_set_type,
142 };
143 
ks8695_init_irq(void)144 void __init ks8695_init_irq(void)
145 {
146 	unsigned int irq;
147 
148 	/* Disable all interrupts initially */
149 	__raw_writel(0, KS8695_IRQ_VA + KS8695_INTMC);
150 	__raw_writel(0, KS8695_IRQ_VA + KS8695_INTEN);
151 
152 	for (irq = 0; irq < NR_IRQS; irq++) {
153 		switch (irq) {
154 			/* Level-triggered interrupts */
155 			case KS8695_IRQ_BUS_ERROR:
156 			case KS8695_IRQ_UART_MODEM_STATUS:
157 			case KS8695_IRQ_UART_LINE_STATUS:
158 			case KS8695_IRQ_UART_RX:
159 			case KS8695_IRQ_COMM_TX:
160 			case KS8695_IRQ_COMM_RX:
161 				irq_set_chip_and_handler(irq,
162 							 &ks8695_irq_level_chip,
163 							 handle_level_irq);
164 				break;
165 
166 			/* Edge-triggered interrupts */
167 			default:
168 				/* clear pending bit */
169 				ks8695_irq_ack(irq_get_irq_data(irq));
170 				irq_set_chip_and_handler(irq,
171 							 &ks8695_irq_edge_chip,
172 							 handle_edge_irq);
173 		}
174 
175 		set_irq_flags(irq, IRQF_VALID);
176 	}
177 }
178