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)
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.
35 #include <linux/version.h>
36 #include <linux/module.h>
38 #include <linux/slab.h>
39 #include <linux/spinlock.h>
41 #include <linux/types.h>
42 #include <linux/interrupt.h>
44 #include "medefines.h"
45 #include "meinternal.h"
50 #include "meplx_reg.h"
51 #include "me0600_ext_irq_reg.h"
52 #include "me0600_ext_irq.h"
58 static int me0600_ext_irq_io_irq_start(struct me_subdevice
*subdevice
,
62 int irq_edge
, int irq_arg
, int flags
)
64 me0600_ext_irq_subdevice_t
*instance
;
66 unsigned long cpu_flags
;
68 PDEBUG("executed.\n");
70 instance
= (me0600_ext_irq_subdevice_t
*) subdevice
;
72 if (flags
& ~ME_IO_IRQ_START_DIO_BIT
) {
73 PERROR("Invalid flag specified.\n");
74 return ME_ERRNO_INVALID_FLAGS
;
77 if (instance
->lintno
> 1) {
78 PERROR("Wrong idx=%d.\n", instance
->lintno
);
79 return ME_ERRNO_INVALID_SUBDEVICE
;
83 PERROR("Invalid channel specified.\n");
84 return ME_ERRNO_INVALID_CHANNEL
;
87 if (irq_source
!= ME_IRQ_SOURCE_DIO_LINE
) {
88 PERROR("Invalid irq source specified.\n");
89 return ME_ERRNO_INVALID_IRQ_SOURCE
;
92 if (irq_edge
!= ME_IRQ_EDGE_RISING
) {
93 PERROR("Invalid irq edge specified.\n");
94 return ME_ERRNO_INVALID_IRQ_EDGE
;
99 spin_lock_irqsave(&instance
->subdevice_lock
, cpu_flags
);
100 spin_lock(instance
->intcsr_lock
);
101 tmp
= inl(instance
->intcsr
);
102 switch (instance
->lintno
) {
105 PLX_INTCSR_LOCAL_INT1_EN
| PLX_INTCSR_LOCAL_INT1_POL
|
106 PLX_INTCSR_PCI_INT_EN
;
110 PLX_INTCSR_LOCAL_INT2_EN
| PLX_INTCSR_LOCAL_INT2_POL
|
111 PLX_INTCSR_PCI_INT_EN
;
114 outl(tmp
, instance
->intcsr
);
115 PDEBUG_REG("intcsr outl(plx:0x%X)=0x%x\n", instance
->intcsr
, tmp
);
116 spin_unlock(instance
->intcsr_lock
);
118 spin_unlock_irqrestore(&instance
->subdevice_lock
, cpu_flags
);
122 return ME_ERRNO_SUCCESS
;
125 static int me0600_ext_irq_io_irq_wait(struct me_subdevice
*subdevice
,
129 int *value
, int time_out
, int flags
)
131 me0600_ext_irq_subdevice_t
*instance
;
132 int err
= ME_ERRNO_SUCCESS
;
134 unsigned long cpu_flags
;
136 PDEBUG("executed.\n");
138 instance
= (me0600_ext_irq_subdevice_t
*) subdevice
;
141 PERROR("Invalid flag specified.\n");
142 return ME_ERRNO_INVALID_FLAGS
;
146 PERROR("Invalid channel specified.\n");
147 return ME_ERRNO_INVALID_CHANNEL
;
151 PERROR("Invalid time_out specified.\n");
152 return ME_ERRNO_INVALID_TIMEOUT
;
156 t
= (time_out
* HZ
) / 1000;
164 if (instance
->rised
<= 0) {
168 t
= wait_event_interruptible_timeout(instance
->
174 PERROR("Wait on interrupt timed out.\n");
175 err
= ME_ERRNO_TIMEOUT
;
178 wait_event_interruptible(instance
->wait_queue
,
179 (instance
->rised
!= 0));
182 if (instance
->rised
< 0) {
183 PERROR("Wait on interrupt aborted by user.\n");
184 err
= ME_ERRNO_CANCELLED
;
188 if (signal_pending(current
)) {
189 PERROR("Wait on interrupt aborted by signal.\n");
190 err
= ME_ERRNO_SIGNAL
;
193 spin_lock_irqsave(&instance
->subdevice_lock
, cpu_flags
);
195 *irq_count
= instance
->n
;
197 spin_unlock_irqrestore(&instance
->subdevice_lock
, cpu_flags
);
204 static int me0600_ext_irq_io_irq_stop(struct me_subdevice
*subdevice
,
206 int channel
, int flags
)
208 me0600_ext_irq_subdevice_t
*instance
;
209 int err
= ME_ERRNO_SUCCESS
;
211 unsigned long cpu_flags
;
213 PDEBUG("executed.\n");
215 instance
= (me0600_ext_irq_subdevice_t
*) subdevice
;
218 PERROR("Invalid flag specified.\n");
219 return ME_ERRNO_INVALID_FLAGS
;
222 if (instance
->lintno
> 1) {
223 PERROR("Wrong idx=%d.\n", instance
->lintno
);
224 return ME_ERRNO_INVALID_SUBDEVICE
;
228 PERROR("Invalid channel specified.\n");
229 return ME_ERRNO_INVALID_CHANNEL
;
234 spin_lock_irqsave(&instance
->subdevice_lock
, cpu_flags
);
235 spin_lock(instance
->intcsr_lock
);
236 tmp
= inl(instance
->intcsr
);
237 switch (instance
->lintno
) {
239 tmp
&= ~PLX_INTCSR_LOCAL_INT1_EN
;
242 tmp
&= ~PLX_INTCSR_LOCAL_INT2_EN
;
245 outl(tmp
, instance
->intcsr
);
246 PDEBUG_REG("intcsr outl(plx:0x%X)=0x%x\n", instance
->intcsr
, tmp
);
247 spin_unlock(instance
->intcsr_lock
);
248 instance
->rised
= -1;
249 spin_unlock_irqrestore(&instance
->subdevice_lock
, cpu_flags
);
250 wake_up_interruptible_all(&instance
->wait_queue
);
257 static int me0600_ext_irq_io_reset_subdevice(struct me_subdevice
*subdevice
,
258 struct file
*filep
, int flags
)
260 me0600_ext_irq_subdevice_t
*instance
;
262 unsigned long cpu_flags
;
264 PDEBUG("executed.\n");
266 instance
= (me0600_ext_irq_subdevice_t
*) subdevice
;
269 PERROR("Invalid flag specified.\n");
270 return ME_ERRNO_INVALID_FLAGS
;
275 spin_lock_irqsave(&instance
->subdevice_lock
, cpu_flags
);
276 spin_lock(instance
->intcsr_lock
);
277 tmp
= inl(instance
->intcsr
);
278 switch (instance
->lintno
) {
280 tmp
|= PLX_INTCSR_LOCAL_INT1_POL
| PLX_INTCSR_PCI_INT_EN
;
281 tmp
&= ~PLX_INTCSR_LOCAL_INT1_EN
;
284 tmp
|= PLX_INTCSR_LOCAL_INT2_POL
| PLX_INTCSR_PCI_INT_EN
;
285 tmp
&= ~PLX_INTCSR_LOCAL_INT2_EN
;
288 outl(tmp
, instance
->intcsr
);
289 PDEBUG_REG("intcsr outl(plx:0x%X)=0x%x\n", instance
->intcsr
, tmp
);
290 spin_unlock(instance
->intcsr_lock
);
292 instance
->rised
= -1;
294 spin_unlock_irqrestore(&instance
->subdevice_lock
, cpu_flags
);
295 wake_up_interruptible_all(&instance
->wait_queue
);
299 return ME_ERRNO_SUCCESS
;
302 static int me0600_ext_irq_query_number_channels(struct me_subdevice
*subdevice
,
305 PDEBUG("executed.\n");
307 return ME_ERRNO_SUCCESS
;
310 static int me0600_ext_irq_query_subdevice_type(struct me_subdevice
*subdevice
,
311 int *type
, int *subtype
)
313 PDEBUG("executed.\n");
314 *type
= ME_TYPE_EXT_IRQ
;
315 *subtype
= ME_SUBTYPE_SINGLE
;
316 return ME_ERRNO_SUCCESS
;
319 static int me0600_ext_irq_query_subdevice_caps(struct me_subdevice
*subdevice
,
322 PDEBUG("executed.\n");
323 *caps
= ME_CAPS_EXT_IRQ_EDGE_RISING
;
324 return ME_ERRNO_SUCCESS
;
327 static void me0600_ext_irq_destructor(struct me_subdevice
*subdevice
)
329 me0600_ext_irq_subdevice_t
*instance
;
331 PDEBUG("executed.\n");
333 instance
= (me0600_ext_irq_subdevice_t
*) subdevice
;
335 free_irq(instance
->irq
, (void *)instance
);
336 me_subdevice_deinit(&instance
->base
);
340 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
341 static irqreturn_t
me0600_isr(int irq
, void *dev_id
)
343 static irqreturn_t
me0600_isr(int irq
, void *dev_id
, struct pt_regs
*regs
)
346 me0600_ext_irq_subdevice_t
*instance
;
348 uint32_t mask
= PLX_INTCSR_PCI_INT_EN
;
349 irqreturn_t ret
= IRQ_HANDLED
;
351 instance
= (me0600_ext_irq_subdevice_t
*) dev_id
;
353 if (irq
!= instance
->irq
) {
354 PERROR("Incorrect interrupt num: %d.\n", irq
);
358 PDEBUG("executed.\n");
360 if (instance
->lintno
> 1) {
362 ("%s():Wrong subdevice index=%d plx:irq_status_reg=0x%04X.\n",
363 __func__
, instance
->lintno
, inl(instance
->intcsr
));
367 spin_lock(&instance
->subdevice_lock
);
368 spin_lock(instance
->intcsr_lock
);
369 status
= inl(instance
->intcsr
);
370 switch (instance
->lintno
) {
372 mask
|= PLX_INTCSR_LOCAL_INT1_STATE
| PLX_INTCSR_LOCAL_INT1_EN
;
375 mask
|= PLX_INTCSR_LOCAL_INT2_STATE
| PLX_INTCSR_LOCAL_INT2_EN
;
379 if ((status
& mask
) == mask
) {
382 inb(instance
->reset_reg
);
383 PDEBUG("Interrupt detected.\n");
386 ("%ld Shared interrupt. %s(): idx=0 plx:irq_status_reg=0x%04X\n",
387 jiffies
, __func__
, status
);
390 spin_unlock(instance
->intcsr_lock
);
391 spin_unlock(&instance
->subdevice_lock
);
393 wake_up_interruptible_all(&instance
->wait_queue
);
398 me0600_ext_irq_subdevice_t
*me0600_ext_irq_constructor(uint32_t plx_reg_base
,
399 uint32_t me0600_reg_base
,
400 spinlock_t
* intcsr_lock
,
401 unsigned ext_irq_idx
,
404 me0600_ext_irq_subdevice_t
*subdevice
;
407 PDEBUG("executed.\n");
409 /* Allocate memory for subdevice instance */
410 subdevice
= kmalloc(sizeof(me0600_ext_irq_subdevice_t
), GFP_KERNEL
);
413 PERROR("Cannot get memory for 630_ext_irq instance.\n");
417 memset(subdevice
, 0, sizeof(me0600_ext_irq_subdevice_t
));
419 /* Initialize subdevice base class */
420 err
= me_subdevice_init(&subdevice
->base
);
423 PERROR("Cannot initialize subdevice base class instance.\n");
427 // Initialize spin locks.
428 spin_lock_init(&subdevice
->subdevice_lock
);
430 subdevice
->intcsr_lock
= intcsr_lock
;
432 /* Initialize wait queue */
433 init_waitqueue_head(&subdevice
->wait_queue
);
435 subdevice
->lintno
= ext_irq_idx
;
437 /* Request interrupt line */
438 subdevice
->irq
= irq
;
440 err
= request_irq(subdevice
->irq
, me0600_isr
,
442 IRQF_DISABLED
| IRQF_SHARED
,
444 SA_INTERRUPT
| SA_SHIRQ
,
446 ME0600_NAME
, (void *)subdevice
);
449 PERROR("Cannot get interrupt line.\n");
453 PINFO("Registered irq=%d.\n", subdevice
->irq
);
455 /* Initialize registers */
456 subdevice
->intcsr
= plx_reg_base
+ PLX_INTCSR
;
457 subdevice
->reset_reg
=
458 me0600_reg_base
+ ME0600_INT_0_RESET_REG
+ ext_irq_idx
;
460 /* Initialize the subdevice methods */
461 subdevice
->base
.me_subdevice_io_irq_start
= me0600_ext_irq_io_irq_start
;
462 subdevice
->base
.me_subdevice_io_irq_wait
= me0600_ext_irq_io_irq_wait
;
463 subdevice
->base
.me_subdevice_io_irq_stop
= me0600_ext_irq_io_irq_stop
;
464 subdevice
->base
.me_subdevice_io_reset_subdevice
=
465 me0600_ext_irq_io_reset_subdevice
;
466 subdevice
->base
.me_subdevice_query_number_channels
=
467 me0600_ext_irq_query_number_channels
;
468 subdevice
->base
.me_subdevice_query_subdevice_type
=
469 me0600_ext_irq_query_subdevice_type
;
470 subdevice
->base
.me_subdevice_query_subdevice_caps
=
471 me0600_ext_irq_query_subdevice_caps
;
472 subdevice
->base
.me_subdevice_destructor
= me0600_ext_irq_destructor
;
474 subdevice
->rised
= 0;