Staging: remove me4000 driver.
[linux-2.6.git] / drivers / staging / meilhaus / me0600_ext_irq.c
blob1d098420a548681535327bbff0d8506a4fce5d38
1 /**
2 * @file me0600_ext_irq.c
4 * @brief ME-630 external interrupt subdevice instance.
5 * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
6 * @author Guenter Gebhardt
7 * @author Krzysztof Gantzke (k.gantzke@meilhaus.de)
8 */
11 * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
13 * This file is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 #ifndef __KERNEL__
29 # define __KERNEL__
30 #endif
33 * Includes
35 #include <linux/module.h>
37 #include <linux/slab.h>
38 #include <linux/spinlock.h>
39 #include <linux/io.h>
40 #include <linux/types.h>
41 #include <linux/interrupt.h>
43 #include "medefines.h"
44 #include "meinternal.h"
45 #include "meerror.h"
46 #include "meids.h"
47 #include "medebug.h"
49 #include "meplx_reg.h"
50 #include "me0600_ext_irq_reg.h"
51 #include "me0600_ext_irq.h"
54 * Functions
57 static int me0600_ext_irq_io_irq_start(struct me_subdevice *subdevice,
58 struct file *filep,
59 int channel,
60 int irq_source,
61 int irq_edge, int irq_arg, int flags)
63 me0600_ext_irq_subdevice_t *instance;
64 uint32_t tmp;
65 unsigned long cpu_flags;
67 PDEBUG("executed.\n");
69 instance = (me0600_ext_irq_subdevice_t *) subdevice;
71 if (flags & ~ME_IO_IRQ_START_DIO_BIT) {
72 PERROR("Invalid flag specified.\n");
73 return ME_ERRNO_INVALID_FLAGS;
76 if (instance->lintno > 1) {
77 PERROR("Wrong idx=%d.\n", instance->lintno);
78 return ME_ERRNO_INVALID_SUBDEVICE;
81 if (channel) {
82 PERROR("Invalid channel specified.\n");
83 return ME_ERRNO_INVALID_CHANNEL;
86 if (irq_source != ME_IRQ_SOURCE_DIO_LINE) {
87 PERROR("Invalid irq source specified.\n");
88 return ME_ERRNO_INVALID_IRQ_SOURCE;
91 if (irq_edge != ME_IRQ_EDGE_RISING) {
92 PERROR("Invalid irq edge specified.\n");
93 return ME_ERRNO_INVALID_IRQ_EDGE;
96 ME_SUBDEVICE_ENTER;
98 spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
99 spin_lock(instance->intcsr_lock);
100 tmp = inl(instance->intcsr);
101 switch (instance->lintno) {
102 case 0:
103 tmp |=
104 PLX_INTCSR_LOCAL_INT1_EN | PLX_INTCSR_LOCAL_INT1_POL |
105 PLX_INTCSR_PCI_INT_EN;
106 break;
107 case 1:
108 tmp |=
109 PLX_INTCSR_LOCAL_INT2_EN | PLX_INTCSR_LOCAL_INT2_POL |
110 PLX_INTCSR_PCI_INT_EN;
111 break;
113 outl(tmp, instance->intcsr);
114 PDEBUG_REG("intcsr outl(plx:0x%X)=0x%x\n", instance->intcsr, tmp);
115 spin_unlock(instance->intcsr_lock);
116 instance->rised = 0;
117 spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
119 ME_SUBDEVICE_EXIT;
121 return ME_ERRNO_SUCCESS;
124 static int me0600_ext_irq_io_irq_wait(struct me_subdevice *subdevice,
125 struct file *filep,
126 int channel,
127 int *irq_count,
128 int *value, int time_out, int flags)
130 me0600_ext_irq_subdevice_t *instance;
131 int err = ME_ERRNO_SUCCESS;
132 long t = 0;
133 unsigned long cpu_flags;
135 PDEBUG("executed.\n");
137 instance = (me0600_ext_irq_subdevice_t *) subdevice;
139 if (flags) {
140 PERROR("Invalid flag specified.\n");
141 return ME_ERRNO_INVALID_FLAGS;
144 if (channel) {
145 PERROR("Invalid channel specified.\n");
146 return ME_ERRNO_INVALID_CHANNEL;
149 if (time_out < 0) {
150 PERROR("Invalid time_out specified.\n");
151 return ME_ERRNO_INVALID_TIMEOUT;
154 if (time_out) {
155 t = (time_out * HZ) / 1000;
157 if (t == 0)
158 t = 1;
161 ME_SUBDEVICE_ENTER;
163 if (instance->rised <= 0) {
164 instance->rised = 0;
166 if (time_out) {
167 t = wait_event_interruptible_timeout(instance->
168 wait_queue,
169 (instance->rised !=
170 0), t);
172 if (t == 0) {
173 PERROR("Wait on interrupt timed out.\n");
174 err = ME_ERRNO_TIMEOUT;
176 } else {
177 wait_event_interruptible(instance->wait_queue,
178 (instance->rised != 0));
181 if (instance->rised < 0) {
182 PERROR("Wait on interrupt aborted by user.\n");
183 err = ME_ERRNO_CANCELLED;
187 if (signal_pending(current)) {
188 PERROR("Wait on interrupt aborted by signal.\n");
189 err = ME_ERRNO_SIGNAL;
192 spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
193 instance->rised = 0;
194 *irq_count = instance->n;
195 *value = 1;
196 spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
198 ME_SUBDEVICE_EXIT;
200 return err;
203 static int me0600_ext_irq_io_irq_stop(struct me_subdevice *subdevice,
204 struct file *filep,
205 int channel, int flags)
207 me0600_ext_irq_subdevice_t *instance;
208 int err = ME_ERRNO_SUCCESS;
209 uint32_t tmp;
210 unsigned long cpu_flags;
212 PDEBUG("executed.\n");
214 instance = (me0600_ext_irq_subdevice_t *) subdevice;
216 if (flags) {
217 PERROR("Invalid flag specified.\n");
218 return ME_ERRNO_INVALID_FLAGS;
221 if (instance->lintno > 1) {
222 PERROR("Wrong idx=%d.\n", instance->lintno);
223 return ME_ERRNO_INVALID_SUBDEVICE;
226 if (channel) {
227 PERROR("Invalid channel specified.\n");
228 return ME_ERRNO_INVALID_CHANNEL;
231 ME_SUBDEVICE_ENTER;
233 spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
234 spin_lock(instance->intcsr_lock);
235 tmp = inl(instance->intcsr);
236 switch (instance->lintno) {
237 case 0:
238 tmp &= ~PLX_INTCSR_LOCAL_INT1_EN;
239 break;
240 case 1:
241 tmp &= ~PLX_INTCSR_LOCAL_INT2_EN;
242 break;
244 outl(tmp, instance->intcsr);
245 PDEBUG_REG("intcsr outl(plx:0x%X)=0x%x\n", instance->intcsr, tmp);
246 spin_unlock(instance->intcsr_lock);
247 instance->rised = -1;
248 spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
249 wake_up_interruptible_all(&instance->wait_queue);
251 ME_SUBDEVICE_EXIT;
253 return err;
256 static int me0600_ext_irq_io_reset_subdevice(struct me_subdevice *subdevice,
257 struct file *filep, int flags)
259 me0600_ext_irq_subdevice_t *instance;
260 uint32_t tmp;
261 unsigned long cpu_flags;
263 PDEBUG("executed.\n");
265 instance = (me0600_ext_irq_subdevice_t *) subdevice;
267 if (flags) {
268 PERROR("Invalid flag specified.\n");
269 return ME_ERRNO_INVALID_FLAGS;
272 ME_SUBDEVICE_ENTER;
274 spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
275 spin_lock(instance->intcsr_lock);
276 tmp = inl(instance->intcsr);
277 switch (instance->lintno) {
278 case 0:
279 tmp |= PLX_INTCSR_LOCAL_INT1_POL | PLX_INTCSR_PCI_INT_EN;
280 tmp &= ~PLX_INTCSR_LOCAL_INT1_EN;
281 break;
282 case 1:
283 tmp |= PLX_INTCSR_LOCAL_INT2_POL | PLX_INTCSR_PCI_INT_EN;
284 tmp &= ~PLX_INTCSR_LOCAL_INT2_EN;
285 break;
287 outl(tmp, instance->intcsr);
288 PDEBUG_REG("intcsr outl(plx:0x%X)=0x%x\n", instance->intcsr, tmp);
289 spin_unlock(instance->intcsr_lock);
291 instance->rised = -1;
292 instance->n = 0;
293 spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
294 wake_up_interruptible_all(&instance->wait_queue);
296 ME_SUBDEVICE_EXIT;
298 return ME_ERRNO_SUCCESS;
301 static int me0600_ext_irq_query_number_channels(struct me_subdevice *subdevice,
302 int *number)
304 PDEBUG("executed.\n");
305 *number = 1;
306 return ME_ERRNO_SUCCESS;
309 static int me0600_ext_irq_query_subdevice_type(struct me_subdevice *subdevice,
310 int *type, int *subtype)
312 PDEBUG("executed.\n");
313 *type = ME_TYPE_EXT_IRQ;
314 *subtype = ME_SUBTYPE_SINGLE;
315 return ME_ERRNO_SUCCESS;
318 static int me0600_ext_irq_query_subdevice_caps(struct me_subdevice *subdevice,
319 int *caps)
321 PDEBUG("executed.\n");
322 *caps = ME_CAPS_EXT_IRQ_EDGE_RISING;
323 return ME_ERRNO_SUCCESS;
326 static void me0600_ext_irq_destructor(struct me_subdevice *subdevice)
328 me0600_ext_irq_subdevice_t *instance;
330 PDEBUG("executed.\n");
332 instance = (me0600_ext_irq_subdevice_t *) subdevice;
334 free_irq(instance->irq, (void *)instance);
335 me_subdevice_deinit(&instance->base);
336 kfree(instance);
339 static irqreturn_t me0600_isr(int irq, void *dev_id)
341 me0600_ext_irq_subdevice_t *instance;
342 uint32_t status;
343 uint32_t mask = PLX_INTCSR_PCI_INT_EN;
344 irqreturn_t ret = IRQ_HANDLED;
346 instance = (me0600_ext_irq_subdevice_t *) dev_id;
348 if (irq != instance->irq) {
349 PERROR("Incorrect interrupt num: %d.\n", irq);
350 return IRQ_NONE;
353 PDEBUG("executed.\n");
355 if (instance->lintno > 1) {
356 PERROR_CRITICAL
357 ("%s():Wrong subdevice index=%d plx:irq_status_reg=0x%04X.\n",
358 __func__, instance->lintno, inl(instance->intcsr));
359 return IRQ_NONE;
362 spin_lock(&instance->subdevice_lock);
363 spin_lock(instance->intcsr_lock);
364 status = inl(instance->intcsr);
365 switch (instance->lintno) {
366 case 0:
367 mask |= PLX_INTCSR_LOCAL_INT1_STATE | PLX_INTCSR_LOCAL_INT1_EN;
368 break;
369 case 1:
370 mask |= PLX_INTCSR_LOCAL_INT2_STATE | PLX_INTCSR_LOCAL_INT2_EN;
371 break;
374 if ((status & mask) == mask) {
375 instance->rised = 1;
376 instance->n++;
377 inb(instance->reset_reg);
378 PDEBUG("Interrupt detected.\n");
379 } else {
380 PINFO
381 ("%ld Shared interrupt. %s(): idx=0 plx:irq_status_reg=0x%04X\n",
382 jiffies, __func__, status);
383 ret = IRQ_NONE;
385 spin_unlock(instance->intcsr_lock);
386 spin_unlock(&instance->subdevice_lock);
388 wake_up_interruptible_all(&instance->wait_queue);
390 return ret;
393 me0600_ext_irq_subdevice_t *me0600_ext_irq_constructor(uint32_t plx_reg_base,
394 uint32_t me0600_reg_base,
395 spinlock_t *intcsr_lock,
396 unsigned ext_irq_idx,
397 int irq)
399 me0600_ext_irq_subdevice_t *subdevice;
400 int err;
402 PDEBUG("executed.\n");
404 /* Allocate memory for subdevice instance */
405 subdevice = kmalloc(sizeof(me0600_ext_irq_subdevice_t), GFP_KERNEL);
407 if (!subdevice) {
408 PERROR("Cannot get memory for 630_ext_irq instance.\n");
409 return NULL;
412 memset(subdevice, 0, sizeof(me0600_ext_irq_subdevice_t));
414 /* Initialize subdevice base class */
415 err = me_subdevice_init(&subdevice->base);
417 if (err) {
418 PERROR("Cannot initialize subdevice base class instance.\n");
419 kfree(subdevice);
420 return NULL;
422 // Initialize spin locks.
423 spin_lock_init(&subdevice->subdevice_lock);
425 subdevice->intcsr_lock = intcsr_lock;
427 /* Initialize wait queue */
428 init_waitqueue_head(&subdevice->wait_queue);
430 subdevice->lintno = ext_irq_idx;
432 /* Request interrupt line */
433 subdevice->irq = irq;
435 err = request_irq(subdevice->irq, me0600_isr,
436 IRQF_DISABLED | IRQF_SHARED,
437 ME0600_NAME, (void *)subdevice);
439 if (err) {
440 PERROR("Cannot get interrupt line.\n");
441 kfree(subdevice);
442 return NULL;
444 PINFO("Registered irq=%d.\n", subdevice->irq);
446 /* Initialize registers */
447 subdevice->intcsr = plx_reg_base + PLX_INTCSR;
448 subdevice->reset_reg =
449 me0600_reg_base + ME0600_INT_0_RESET_REG + ext_irq_idx;
451 /* Initialize the subdevice methods */
452 subdevice->base.me_subdevice_io_irq_start = me0600_ext_irq_io_irq_start;
453 subdevice->base.me_subdevice_io_irq_wait = me0600_ext_irq_io_irq_wait;
454 subdevice->base.me_subdevice_io_irq_stop = me0600_ext_irq_io_irq_stop;
455 subdevice->base.me_subdevice_io_reset_subdevice =
456 me0600_ext_irq_io_reset_subdevice;
457 subdevice->base.me_subdevice_query_number_channels =
458 me0600_ext_irq_query_number_channels;
459 subdevice->base.me_subdevice_query_subdevice_type =
460 me0600_ext_irq_query_subdevice_type;
461 subdevice->base.me_subdevice_query_subdevice_caps =
462 me0600_ext_irq_query_subdevice_caps;
463 subdevice->base.me_subdevice_destructor = me0600_ext_irq_destructor;
465 subdevice->rised = 0;
466 subdevice->n = 0;
468 return subdevice;