Staging: meilhaus: Remove long-deprecated SA_* interrupt macros.
[pandora-kernel.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 <linux/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 static irqreturn_t me0600_isr(int irq, void *dev_id)
341 {
342         me0600_ext_irq_subdevice_t *instance;
343         uint32_t status;
344         uint32_t mask = PLX_INTCSR_PCI_INT_EN;
345         irqreturn_t ret = IRQ_HANDLED;
346
347         instance = (me0600_ext_irq_subdevice_t *) dev_id;
348
349         if (irq != instance->irq) {
350                 PERROR("Incorrect interrupt num: %d.\n", irq);
351                 return IRQ_NONE;
352         }
353
354         PDEBUG("executed.\n");
355
356         if (instance->lintno > 1) {
357                 PERROR_CRITICAL
358                     ("%s():Wrong subdevice index=%d plx:irq_status_reg=0x%04X.\n",
359                      __func__, instance->lintno, inl(instance->intcsr));
360                 return IRQ_NONE;
361         }
362
363         spin_lock(&instance->subdevice_lock);
364         spin_lock(instance->intcsr_lock);
365         status = inl(instance->intcsr);
366         switch (instance->lintno) {
367         case 0:
368                 mask |= PLX_INTCSR_LOCAL_INT1_STATE | PLX_INTCSR_LOCAL_INT1_EN;
369                 break;
370         case 1:
371                 mask |= PLX_INTCSR_LOCAL_INT2_STATE | PLX_INTCSR_LOCAL_INT2_EN;
372                 break;
373         }
374
375         if ((status & mask) == mask) {
376                 instance->rised = 1;
377                 instance->n++;
378                 inb(instance->reset_reg);
379                 PDEBUG("Interrupt detected.\n");
380         } else {
381                 PINFO
382                     ("%ld Shared interrupt. %s(): idx=0 plx:irq_status_reg=0x%04X\n",
383                      jiffies, __func__, status);
384                 ret = IRQ_NONE;
385         }
386         spin_unlock(instance->intcsr_lock);
387         spin_unlock(&instance->subdevice_lock);
388
389         wake_up_interruptible_all(&instance->wait_queue);
390
391         return ret;
392 }
393
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,
398                                                        int irq)
399 {
400         me0600_ext_irq_subdevice_t *subdevice;
401         int err;
402
403         PDEBUG("executed.\n");
404
405         /* Allocate memory for subdevice instance */
406         subdevice = kmalloc(sizeof(me0600_ext_irq_subdevice_t), GFP_KERNEL);
407
408         if (!subdevice) {
409                 PERROR("Cannot get memory for 630_ext_irq instance.\n");
410                 return NULL;
411         }
412
413         memset(subdevice, 0, sizeof(me0600_ext_irq_subdevice_t));
414
415         /* Initialize subdevice base class */
416         err = me_subdevice_init(&subdevice->base);
417
418         if (err) {
419                 PERROR("Cannot initialize subdevice base class instance.\n");
420                 kfree(subdevice);
421                 return NULL;
422         }
423         // Initialize spin locks.
424         spin_lock_init(&subdevice->subdevice_lock);
425
426         subdevice->intcsr_lock = intcsr_lock;
427
428         /* Initialize wait queue */
429         init_waitqueue_head(&subdevice->wait_queue);
430
431         subdevice->lintno = ext_irq_idx;
432
433         /* Request interrupt line */
434         subdevice->irq = irq;
435
436         err = request_irq(subdevice->irq, me0600_isr,
437                           IRQF_DISABLED | IRQF_SHARED,
438                           ME0600_NAME, (void *)subdevice);
439
440         if (err) {
441                 PERROR("Cannot get interrupt line.\n");
442                 kfree(subdevice);
443                 return NULL;
444         }
445         PINFO("Registered irq=%d.\n", subdevice->irq);
446
447         /* Initialize registers */
448         subdevice->intcsr = plx_reg_base + PLX_INTCSR;
449         subdevice->reset_reg =
450             me0600_reg_base + ME0600_INT_0_RESET_REG + ext_irq_idx;
451
452         /* Initialize the subdevice methods */
453         subdevice->base.me_subdevice_io_irq_start = me0600_ext_irq_io_irq_start;
454         subdevice->base.me_subdevice_io_irq_wait = me0600_ext_irq_io_irq_wait;
455         subdevice->base.me_subdevice_io_irq_stop = me0600_ext_irq_io_irq_stop;
456         subdevice->base.me_subdevice_io_reset_subdevice =
457             me0600_ext_irq_io_reset_subdevice;
458         subdevice->base.me_subdevice_query_number_channels =
459             me0600_ext_irq_query_number_channels;
460         subdevice->base.me_subdevice_query_subdevice_type =
461             me0600_ext_irq_query_subdevice_type;
462         subdevice->base.me_subdevice_query_subdevice_caps =
463             me0600_ext_irq_query_subdevice_caps;
464         subdevice->base.me_subdevice_destructor = me0600_ext_irq_destructor;
465
466         subdevice->rised = 0;
467         subdevice->n = 0;
468
469         return subdevice;
470 }