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 static irqreturn_t
me0600_isr(int irq
, void *dev_id
)
342 me0600_ext_irq_subdevice_t
*instance
;
344 uint32_t mask
= PLX_INTCSR_PCI_INT_EN
;
345 irqreturn_t ret
= IRQ_HANDLED
;
347 instance
= (me0600_ext_irq_subdevice_t
*) dev_id
;
349 if (irq
!= instance
->irq
) {
350 PERROR("Incorrect interrupt num: %d.\n", irq
);
354 PDEBUG("executed.\n");
356 if (instance
->lintno
> 1) {
358 ("%s():Wrong subdevice index=%d plx:irq_status_reg=0x%04X.\n",
359 __func__
, instance
->lintno
, inl(instance
->intcsr
));
363 spin_lock(&instance
->subdevice_lock
);
364 spin_lock(instance
->intcsr_lock
);
365 status
= inl(instance
->intcsr
);
366 switch (instance
->lintno
) {
368 mask
|= PLX_INTCSR_LOCAL_INT1_STATE
| PLX_INTCSR_LOCAL_INT1_EN
;
371 mask
|= PLX_INTCSR_LOCAL_INT2_STATE
| PLX_INTCSR_LOCAL_INT2_EN
;
375 if ((status
& mask
) == mask
) {
378 inb(instance
->reset_reg
);
379 PDEBUG("Interrupt detected.\n");
382 ("%ld Shared interrupt. %s(): idx=0 plx:irq_status_reg=0x%04X\n",
383 jiffies
, __func__
, status
);
386 spin_unlock(instance
->intcsr_lock
);
387 spin_unlock(&instance
->subdevice_lock
);
389 wake_up_interruptible_all(&instance
->wait_queue
);
394 me0600_ext_irq_subdevice_t
*me0600_ext_irq_constructor(uint32_t plx_reg_base
,
395 uint32_t me0600_reg_base
,
396 spinlock_t
*intcsr_lock
,
397 unsigned ext_irq_idx
,
400 me0600_ext_irq_subdevice_t
*subdevice
;
403 PDEBUG("executed.\n");
405 /* Allocate memory for subdevice instance */
406 subdevice
= kmalloc(sizeof(me0600_ext_irq_subdevice_t
), GFP_KERNEL
);
409 PERROR("Cannot get memory for 630_ext_irq instance.\n");
413 memset(subdevice
, 0, sizeof(me0600_ext_irq_subdevice_t
));
415 /* Initialize subdevice base class */
416 err
= me_subdevice_init(&subdevice
->base
);
419 PERROR("Cannot initialize subdevice base class instance.\n");
423 // Initialize spin locks.
424 spin_lock_init(&subdevice
->subdevice_lock
);
426 subdevice
->intcsr_lock
= intcsr_lock
;
428 /* Initialize wait queue */
429 init_waitqueue_head(&subdevice
->wait_queue
);
431 subdevice
->lintno
= ext_irq_idx
;
433 /* Request interrupt line */
434 subdevice
->irq
= irq
;
436 err
= request_irq(subdevice
->irq
, me0600_isr
,
438 IRQF_DISABLED
| IRQF_SHARED
,
440 SA_INTERRUPT
| SA_SHIRQ
,
442 ME0600_NAME
, (void *)subdevice
);
445 PERROR("Cannot get interrupt line.\n");
449 PINFO("Registered irq=%d.\n", subdevice
->irq
);
451 /* Initialize registers */
452 subdevice
->intcsr
= plx_reg_base
+ PLX_INTCSR
;
453 subdevice
->reset_reg
=
454 me0600_reg_base
+ ME0600_INT_0_RESET_REG
+ ext_irq_idx
;
456 /* Initialize the subdevice methods */
457 subdevice
->base
.me_subdevice_io_irq_start
= me0600_ext_irq_io_irq_start
;
458 subdevice
->base
.me_subdevice_io_irq_wait
= me0600_ext_irq_io_irq_wait
;
459 subdevice
->base
.me_subdevice_io_irq_stop
= me0600_ext_irq_io_irq_stop
;
460 subdevice
->base
.me_subdevice_io_reset_subdevice
=
461 me0600_ext_irq_io_reset_subdevice
;
462 subdevice
->base
.me_subdevice_query_number_channels
=
463 me0600_ext_irq_query_number_channels
;
464 subdevice
->base
.me_subdevice_query_subdevice_type
=
465 me0600_ext_irq_query_subdevice_type
;
466 subdevice
->base
.me_subdevice_query_subdevice_caps
=
467 me0600_ext_irq_query_subdevice_caps
;
468 subdevice
->base
.me_subdevice_destructor
= me0600_ext_irq_destructor
;
470 subdevice
->rised
= 0;