]> pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/staging/meilhaus/me0600_ext_irq.c
ALSA: hda - Revert the codec probe at control-creation errors
[linux-2.6-omap-h63xx.git] / drivers / staging / meilhaus / me0600_ext_irq.c
1 /**
2  * @file me0600_ext_irq.c
3  *
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  */
9
10 /*
11  * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
12  *
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.
17  *
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.
22  *
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.
26  */
27
28 #ifndef __KERNEL__
29 #  define __KERNEL__
30 #endif
31
32 /*
33  * Includes
34  */
35 #include <linux/version.h>
36 #include <linux/module.h>
37
38 #include <linux/slab.h>
39 #include <linux/spinlock.h>
40 #include <asm/io.h>
41 #include <linux/types.h>
42 #include <linux/interrupt.h>
43
44 #include "medefines.h"
45 #include "meinternal.h"
46 #include "meerror.h"
47 #include "meids.h"
48 #include "medebug.h"
49
50 #include "meplx_reg.h"
51 #include "me0600_ext_irq_reg.h"
52 #include "me0600_ext_irq.h"
53
54 /*
55  * Functions
56  */
57
58 static int me0600_ext_irq_io_irq_start(struct me_subdevice *subdevice,
59                                        struct file *filep,
60                                        int channel,
61                                        int irq_source,
62                                        int irq_edge, int irq_arg, int flags)
63 {
64         me0600_ext_irq_subdevice_t *instance;
65         uint32_t tmp;
66         unsigned long cpu_flags;
67
68         PDEBUG("executed.\n");
69
70         instance = (me0600_ext_irq_subdevice_t *) subdevice;
71
72         if (flags & ~ME_IO_IRQ_START_DIO_BIT) {
73                 PERROR("Invalid flag specified.\n");
74                 return ME_ERRNO_INVALID_FLAGS;
75         }
76
77         if (instance->lintno > 1) {
78                 PERROR("Wrong idx=%d.\n", instance->lintno);
79                 return ME_ERRNO_INVALID_SUBDEVICE;
80         }
81
82         if (channel) {
83                 PERROR("Invalid channel specified.\n");
84                 return ME_ERRNO_INVALID_CHANNEL;
85         }
86
87         if (irq_source != ME_IRQ_SOURCE_DIO_LINE) {
88                 PERROR("Invalid irq source specified.\n");
89                 return ME_ERRNO_INVALID_IRQ_SOURCE;
90         }
91
92         if (irq_edge != ME_IRQ_EDGE_RISING) {
93                 PERROR("Invalid irq edge specified.\n");
94                 return ME_ERRNO_INVALID_IRQ_EDGE;
95         }
96
97         ME_SUBDEVICE_ENTER;
98
99         spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
100         spin_lock(instance->intcsr_lock);
101         tmp = inl(instance->intcsr);
102         switch (instance->lintno) {
103         case 0:
104                 tmp |=
105                     PLX_INTCSR_LOCAL_INT1_EN | PLX_INTCSR_LOCAL_INT1_POL |
106                     PLX_INTCSR_PCI_INT_EN;
107                 break;
108         case 1:
109                 tmp |=
110                     PLX_INTCSR_LOCAL_INT2_EN | PLX_INTCSR_LOCAL_INT2_POL |
111                     PLX_INTCSR_PCI_INT_EN;
112                 break;
113         }
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);
117         instance->rised = 0;
118         spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
119
120         ME_SUBDEVICE_EXIT;
121
122         return ME_ERRNO_SUCCESS;
123 }
124
125 static int me0600_ext_irq_io_irq_wait(struct me_subdevice *subdevice,
126                                       struct file *filep,
127                                       int channel,
128                                       int *irq_count,
129                                       int *value, int time_out, int flags)
130 {
131         me0600_ext_irq_subdevice_t *instance;
132         int err = ME_ERRNO_SUCCESS;
133         long t = 0;
134         unsigned long cpu_flags;
135
136         PDEBUG("executed.\n");
137
138         instance = (me0600_ext_irq_subdevice_t *) subdevice;
139
140         if (flags) {
141                 PERROR("Invalid flag specified.\n");
142                 return ME_ERRNO_INVALID_FLAGS;
143         }
144
145         if (channel) {
146                 PERROR("Invalid channel specified.\n");
147                 return ME_ERRNO_INVALID_CHANNEL;
148         }
149
150         if (time_out < 0) {
151                 PERROR("Invalid time_out specified.\n");
152                 return ME_ERRNO_INVALID_TIMEOUT;
153         }
154
155         if (time_out) {
156                 t = (time_out * HZ) / 1000;
157
158                 if (t == 0)
159                         t = 1;
160         }
161
162         ME_SUBDEVICE_ENTER;
163
164         if (instance->rised <= 0) {
165                 instance->rised = 0;
166
167                 if (time_out) {
168                         t = wait_event_interruptible_timeout(instance->
169                                                              wait_queue,
170                                                              (instance->rised !=
171                                                               0), t);
172
173                         if (t == 0) {
174                                 PERROR("Wait on interrupt timed out.\n");
175                                 err = ME_ERRNO_TIMEOUT;
176                         }
177                 } else {
178                         wait_event_interruptible(instance->wait_queue,
179                                                  (instance->rised != 0));
180                 }
181
182                 if (instance->rised < 0) {
183                         PERROR("Wait on interrupt aborted by user.\n");
184                         err = ME_ERRNO_CANCELLED;
185                 }
186         }
187
188         if (signal_pending(current)) {
189                 PERROR("Wait on interrupt aborted by signal.\n");
190                 err = ME_ERRNO_SIGNAL;
191         }
192
193         spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
194         instance->rised = 0;
195         *irq_count = instance->n;
196         *value = 1;
197         spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
198
199         ME_SUBDEVICE_EXIT;
200
201         return err;
202 }
203
204 static int me0600_ext_irq_io_irq_stop(struct me_subdevice *subdevice,
205                                       struct file *filep,
206                                       int channel, int flags)
207 {
208         me0600_ext_irq_subdevice_t *instance;
209         int err = ME_ERRNO_SUCCESS;
210         uint32_t tmp;
211         unsigned long cpu_flags;
212
213         PDEBUG("executed.\n");
214
215         instance = (me0600_ext_irq_subdevice_t *) subdevice;
216
217         if (flags) {
218                 PERROR("Invalid flag specified.\n");
219                 return ME_ERRNO_INVALID_FLAGS;
220         }
221
222         if (instance->lintno > 1) {
223                 PERROR("Wrong idx=%d.\n", instance->lintno);
224                 return ME_ERRNO_INVALID_SUBDEVICE;
225         }
226
227         if (channel) {
228                 PERROR("Invalid channel specified.\n");
229                 return ME_ERRNO_INVALID_CHANNEL;
230         }
231
232         ME_SUBDEVICE_ENTER;
233
234         spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
235         spin_lock(instance->intcsr_lock);
236         tmp = inl(instance->intcsr);
237         switch (instance->lintno) {
238         case 0:
239                 tmp &= ~PLX_INTCSR_LOCAL_INT1_EN;
240                 break;
241         case 1:
242                 tmp &= ~PLX_INTCSR_LOCAL_INT2_EN;
243                 break;
244         }
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);
251
252         ME_SUBDEVICE_EXIT;
253
254         return err;
255 }
256
257 static int me0600_ext_irq_io_reset_subdevice(struct me_subdevice *subdevice,
258                                              struct file *filep, int flags)
259 {
260         me0600_ext_irq_subdevice_t *instance;
261         uint32_t tmp;
262         unsigned long cpu_flags;
263
264         PDEBUG("executed.\n");
265
266         instance = (me0600_ext_irq_subdevice_t *) subdevice;
267
268         if (flags) {
269                 PERROR("Invalid flag specified.\n");
270                 return ME_ERRNO_INVALID_FLAGS;
271         }
272
273         ME_SUBDEVICE_ENTER;
274
275         spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
276         spin_lock(instance->intcsr_lock);
277         tmp = inl(instance->intcsr);
278         switch (instance->lintno) {
279         case 0:
280                 tmp |= PLX_INTCSR_LOCAL_INT1_POL | PLX_INTCSR_PCI_INT_EN;
281                 tmp &= ~PLX_INTCSR_LOCAL_INT1_EN;
282                 break;
283         case 1:
284                 tmp |= PLX_INTCSR_LOCAL_INT2_POL | PLX_INTCSR_PCI_INT_EN;
285                 tmp &= ~PLX_INTCSR_LOCAL_INT2_EN;
286                 break;
287         }
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);
291
292         instance->rised = -1;
293         instance->n = 0;
294         spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
295         wake_up_interruptible_all(&instance->wait_queue);
296
297         ME_SUBDEVICE_EXIT;
298
299         return ME_ERRNO_SUCCESS;
300 }
301
302 static int me0600_ext_irq_query_number_channels(struct me_subdevice *subdevice,
303                                                 int *number)
304 {
305         PDEBUG("executed.\n");
306         *number = 1;
307         return ME_ERRNO_SUCCESS;
308 }
309
310 static int me0600_ext_irq_query_subdevice_type(struct me_subdevice *subdevice,
311                                                int *type, int *subtype)
312 {
313         PDEBUG("executed.\n");
314         *type = ME_TYPE_EXT_IRQ;
315         *subtype = ME_SUBTYPE_SINGLE;
316         return ME_ERRNO_SUCCESS;
317 }
318
319 static int me0600_ext_irq_query_subdevice_caps(struct me_subdevice *subdevice,
320                                                int *caps)
321 {
322         PDEBUG("executed.\n");
323         *caps = ME_CAPS_EXT_IRQ_EDGE_RISING;
324         return ME_ERRNO_SUCCESS;
325 }
326
327 static void me0600_ext_irq_destructor(struct me_subdevice *subdevice)
328 {
329         me0600_ext_irq_subdevice_t *instance;
330
331         PDEBUG("executed.\n");
332
333         instance = (me0600_ext_irq_subdevice_t *) subdevice;
334
335         free_irq(instance->irq, (void *)instance);
336         me_subdevice_deinit(&instance->base);
337         kfree(instance);
338 }
339
340 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
341 static irqreturn_t me0600_isr(int irq, void *dev_id)
342 #else
343 static irqreturn_t me0600_isr(int irq, void *dev_id, struct pt_regs *regs)
344 #endif
345 {
346         me0600_ext_irq_subdevice_t *instance;
347         uint32_t status;
348         uint32_t mask = PLX_INTCSR_PCI_INT_EN;
349         irqreturn_t ret = IRQ_HANDLED;
350
351         instance = (me0600_ext_irq_subdevice_t *) dev_id;
352
353         if (irq != instance->irq) {
354                 PERROR("Incorrect interrupt num: %d.\n", irq);
355                 return IRQ_NONE;
356         }
357
358         PDEBUG("executed.\n");
359
360         if (instance->lintno > 1) {
361                 PERROR_CRITICAL
362                     ("%s():Wrong subdevice index=%d plx:irq_status_reg=0x%04X.\n",
363                      __func__, instance->lintno, inl(instance->intcsr));
364                 return IRQ_NONE;
365         }
366
367         spin_lock(&instance->subdevice_lock);
368         spin_lock(instance->intcsr_lock);
369         status = inl(instance->intcsr);
370         switch (instance->lintno) {
371         case 0:
372                 mask |= PLX_INTCSR_LOCAL_INT1_STATE | PLX_INTCSR_LOCAL_INT1_EN;
373                 break;
374         case 1:
375                 mask |= PLX_INTCSR_LOCAL_INT2_STATE | PLX_INTCSR_LOCAL_INT2_EN;
376                 break;
377         }
378
379         if ((status & mask) == mask) {
380                 instance->rised = 1;
381                 instance->n++;
382                 inb(instance->reset_reg);
383                 PDEBUG("Interrupt detected.\n");
384         } else {
385                 PINFO
386                     ("%ld Shared interrupt. %s(): idx=0 plx:irq_status_reg=0x%04X\n",
387                      jiffies, __func__, status);
388                 ret = IRQ_NONE;
389         }
390         spin_unlock(instance->intcsr_lock);
391         spin_unlock(&instance->subdevice_lock);
392
393         wake_up_interruptible_all(&instance->wait_queue);
394
395         return ret;
396 }
397
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,
402                                                        int irq)
403 {
404         me0600_ext_irq_subdevice_t *subdevice;
405         int err;
406
407         PDEBUG("executed.\n");
408
409         /* Allocate memory for subdevice instance */
410         subdevice = kmalloc(sizeof(me0600_ext_irq_subdevice_t), GFP_KERNEL);
411
412         if (!subdevice) {
413                 PERROR("Cannot get memory for 630_ext_irq instance.\n");
414                 return NULL;
415         }
416
417         memset(subdevice, 0, sizeof(me0600_ext_irq_subdevice_t));
418
419         /* Initialize subdevice base class */
420         err = me_subdevice_init(&subdevice->base);
421
422         if (err) {
423                 PERROR("Cannot initialize subdevice base class instance.\n");
424                 kfree(subdevice);
425                 return NULL;
426         }
427         // Initialize spin locks.
428         spin_lock_init(&subdevice->subdevice_lock);
429
430         subdevice->intcsr_lock = intcsr_lock;
431
432         /* Initialize wait queue */
433         init_waitqueue_head(&subdevice->wait_queue);
434
435         subdevice->lintno = ext_irq_idx;
436
437         /* Request interrupt line */
438         subdevice->irq = irq;
439
440         err = request_irq(subdevice->irq, me0600_isr,
441 #ifdef IRQF_DISABLED
442                           IRQF_DISABLED | IRQF_SHARED,
443 #else
444                           SA_INTERRUPT | SA_SHIRQ,
445 #endif
446                           ME0600_NAME, (void *)subdevice);
447
448         if (err) {
449                 PERROR("Cannot get interrupt line.\n");
450                 kfree(subdevice);
451                 return NULL;
452         }
453         PINFO("Registered irq=%d.\n", subdevice->irq);
454
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;
459
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;
473
474         subdevice->rised = 0;
475         subdevice->n = 0;
476
477         return subdevice;
478 }