• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * @file me4600_ext_irq.c
3  *
4  * @brief ME-4000 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/module.h>
36 
37 #include <linux/slab.h>
38 #include <linux/spinlock.h>
39 #include <linux/interrupt.h>
40 #include <asm/io.h>
41 #include <linux/types.h>
42 #include <linux/version.h>
43 
44 #include "medefines.h"
45 #include "meinternal.h"
46 #include "meerror.h"
47 
48 #include "medebug.h"
49 #include "meids.h"
50 #include "me4600_reg.h"
51 #include "me4600_ai_reg.h"
52 #include "me4600_ext_irq_reg.h"
53 #include "me4600_ext_irq.h"
54 
55 /*
56  * Defines
57  */
58 
59 /*
60  * Functions
61  */
62 
me4600_ext_irq_io_irq_start(me_subdevice_t * subdevice,struct file * filep,int channel,int irq_source,int irq_edge,int irq_arg,int flags)63 static int me4600_ext_irq_io_irq_start(me_subdevice_t * subdevice,
64 				       struct file *filep,
65 				       int channel,
66 				       int irq_source,
67 				       int irq_edge, int irq_arg, int flags)
68 {
69 	me4600_ext_irq_subdevice_t *instance;
70 	int err = ME_ERRNO_SUCCESS;
71 	unsigned long cpu_flags;
72 	uint32_t tmp;
73 
74 	PDEBUG("executed.\n");
75 
76 	instance = (me4600_ext_irq_subdevice_t *) subdevice;
77 
78 	if (flags & ~ME_IO_IRQ_START_DIO_BIT) {
79 		PERROR("Invalid flag specified.\n");
80 		return ME_ERRNO_INVALID_FLAGS;
81 	}
82 
83 	if ((irq_edge != ME_IRQ_EDGE_RISING)
84 	    && (irq_edge != ME_IRQ_EDGE_FALLING)
85 	    && (irq_edge != ME_IRQ_EDGE_ANY)
86 	    ) {
87 		PERROR("Invalid irq edge specified.\n");
88 		return ME_ERRNO_INVALID_IRQ_EDGE;
89 	}
90 
91 	if (irq_source != ME_IRQ_SOURCE_DIO_LINE) {
92 		PERROR("Invalid irq source specified.\n");
93 		return ME_ERRNO_INVALID_IRQ_SOURCE;
94 	}
95 
96 	if (channel) {
97 		PERROR("Invalid channel specified.\n");
98 		return ME_ERRNO_INVALID_CHANNEL;
99 	}
100 
101 	ME_SUBDEVICE_ENTER;
102 
103 	spin_lock(&instance->subdevice_lock);
104 	tmp = 0x0;		//inl(instance->ext_irq_config_reg);
105 
106 	if (irq_edge == ME_IRQ_EDGE_RISING) {
107 		//tmp &= ~ME4600_EXT_IRQ_CONFIG_MASK;
108 		//tmp |= ME4600_EXT_IRQ_CONFIG_MASK_RISING;
109 	} else if (irq_edge == ME_IRQ_EDGE_FALLING) {
110 		//tmp &= ~ME4600_EXT_IRQ_CONFIG_MASK;
111 		//tmp |= ME4600_EXT_IRQ_CONFIG_MASK_FALLING;
112 		tmp = ME4600_EXT_IRQ_CONFIG_MASK_FALLING;
113 	} else if (irq_edge == ME_IRQ_EDGE_ANY) {
114 		//tmp &= ~ME4600_EXT_IRQ_CONFIG_MASK;
115 		//tmp |= ME4600_EXT_IRQ_CONFIG_MASK_ANY;
116 		tmp = ME4600_EXT_IRQ_CONFIG_MASK_ANY;
117 	}
118 
119 	outl(tmp, instance->ext_irq_config_reg);
120 	PDEBUG_REG("ext_irq_config_reg outl(0x%lX+0x%lX)=0x%x\n",
121 		   instance->reg_base,
122 		   instance->ext_irq_config_reg - instance->reg_base, tmp);
123 
124 	spin_lock_irqsave(instance->ctrl_reg_lock, cpu_flags);
125 	tmp = inl(instance->ctrl_reg);
126 	tmp &= ~(ME4600_AI_CTRL_BIT_EX_IRQ | ME4600_AI_CTRL_BIT_EX_IRQ_RESET);
127 	tmp |= ME4600_AI_CTRL_BIT_EX_IRQ;
128 	outl(tmp, instance->ctrl_reg);
129 	spin_unlock_irqrestore(instance->ctrl_reg_lock, cpu_flags);
130 	instance->rised = 0;
131 	spin_unlock(&instance->subdevice_lock);
132 
133 	ME_SUBDEVICE_EXIT;
134 
135 	return err;
136 }
137 
me4600_ext_irq_io_irq_wait(me_subdevice_t * subdevice,struct file * filep,int channel,int * irq_count,int * value,int time_out,int flags)138 static int me4600_ext_irq_io_irq_wait(me_subdevice_t * subdevice,
139 				      struct file *filep,
140 				      int channel,
141 				      int *irq_count,
142 				      int *value, int time_out, int flags)
143 {
144 	me4600_ext_irq_subdevice_t *instance;
145 	int err = ME_ERRNO_SUCCESS;
146 	long t = 0;
147 	unsigned long cpu_flags;
148 
149 	PDEBUG("executed.\n");
150 
151 	instance = (me4600_ext_irq_subdevice_t *) subdevice;
152 
153 	if (flags) {
154 		PERROR("Invalid flag specified.\n");
155 		return ME_ERRNO_INVALID_FLAGS;
156 	}
157 
158 	if (channel) {
159 		PERROR("Invalid channel specified.\n");
160 		return ME_ERRNO_INVALID_CHANNEL;
161 	}
162 
163 	if (time_out < 0) {
164 		PERROR("Invalid time_out specified.\n");
165 		return ME_ERRNO_INVALID_TIMEOUT;
166 	}
167 
168 	if (time_out) {
169 		t = (time_out * HZ) / 1000;
170 
171 		if (t == 0)
172 			t = 1;
173 	}
174 
175 	ME_SUBDEVICE_ENTER;
176 
177 	if (instance->rised <= 0) {
178 		instance->rised = 0;
179 		if (time_out) {
180 			t = wait_event_interruptible_timeout(instance->
181 							     wait_queue,
182 							     (instance->rised !=
183 							      0), t);
184 
185 			if (t == 0) {
186 				PERROR
187 				    ("Wait on external interrupt timed out.\n");
188 				err = ME_ERRNO_TIMEOUT;
189 			}
190 		} else {
191 			wait_event_interruptible(instance->wait_queue,
192 						 (instance->rised != 0));
193 		}
194 
195 		if (instance->rised < 0) {
196 			PERROR("Wait on interrupt aborted by user.\n");
197 			err = ME_ERRNO_CANCELLED;
198 		}
199 	}
200 
201 	if (signal_pending(current)) {
202 		PERROR("Wait on external interrupt aborted by signal.\n");
203 		err = ME_ERRNO_SIGNAL;
204 	}
205 
206 	spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
207 	instance->rised = 0;
208 	*irq_count = instance->count;
209 	*value = instance->value;
210 	spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
211 
212 	ME_SUBDEVICE_EXIT;
213 
214 	return err;
215 }
216 
me4600_ext_irq_io_irq_stop(me_subdevice_t * subdevice,struct file * filep,int channel,int flags)217 static int me4600_ext_irq_io_irq_stop(me_subdevice_t * subdevice,
218 				      struct file *filep,
219 				      int channel, int flags)
220 {
221 	me4600_ext_irq_subdevice_t *instance;
222 	int err = ME_ERRNO_SUCCESS;
223 	unsigned long cpu_flags;
224 	uint32_t tmp;
225 
226 	PDEBUG("executed.\n");
227 
228 	instance = (me4600_ext_irq_subdevice_t *) subdevice;
229 
230 	if (flags) {
231 		PERROR("Invalid flag specified.\n");
232 		return ME_ERRNO_INVALID_FLAGS;
233 	}
234 
235 	if (channel) {
236 		PERROR("Invalid channel specified.\n");
237 		return ME_ERRNO_INVALID_CHANNEL;
238 	}
239 
240 	ME_SUBDEVICE_ENTER;
241 
242 	spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
243 	spin_lock(instance->ctrl_reg_lock);
244 	tmp = inl(instance->ctrl_reg);
245 	tmp &= ~(ME4600_AI_CTRL_BIT_EX_IRQ | ME4600_AI_CTRL_BIT_EX_IRQ_RESET);
246 	outl(tmp, instance->ctrl_reg);
247 	PDEBUG_REG("ctrl_regv outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
248 		   instance->ctrl_reg - instance->reg_base, tmp);
249 	spin_unlock(instance->ctrl_reg_lock);
250 	instance->rised = -1;
251 	spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
252 	wake_up_interruptible_all(&instance->wait_queue);
253 
254 	ME_SUBDEVICE_EXIT;
255 
256 	return err;
257 }
258 
me4600_ext_irq_io_reset_subdevice(me_subdevice_t * subdevice,struct file * filep,int flags)259 static int me4600_ext_irq_io_reset_subdevice(me_subdevice_t * subdevice,
260 					     struct file *filep, int flags)
261 {
262 	me4600_ext_irq_subdevice_t *instance;
263 	unsigned long cpu_flags;
264 	uint32_t tmp;
265 
266 	PDEBUG("executed.\n");
267 
268 	instance = (me4600_ext_irq_subdevice_t *) subdevice;
269 
270 	if (flags) {
271 		PERROR("Invalid flag specified.\n");
272 		return ME_ERRNO_INVALID_FLAGS;
273 	}
274 
275 	ME_SUBDEVICE_ENTER;
276 
277 	spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
278 	spin_lock(instance->ctrl_reg_lock);
279 	tmp = inl(instance->ctrl_reg);
280 	tmp &= ~(ME4600_AI_CTRL_BIT_EX_IRQ | ME4600_AI_CTRL_BIT_EX_IRQ_RESET);
281 	outl(tmp, instance->ctrl_reg);
282 	PDEBUG_REG("ctrl_regv outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
283 		   instance->ctrl_reg - instance->reg_base, tmp);
284 	spin_unlock(instance->ctrl_reg_lock);
285 	instance->rised = -1;
286 	instance->count = 0;
287 	outl(ME4600_EXT_IRQ_CONFIG_MASK_ANY, instance->ext_irq_config_reg);
288 	PDEBUG_REG("ext_irq_config_reg outl(0x%lX+0x%lX)=0x%x\n",
289 		   instance->reg_base,
290 		   instance->ext_irq_config_reg - instance->reg_base,
291 		   ME4600_EXT_IRQ_CONFIG_MASK_ANY);
292 	spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
293 	wake_up_interruptible_all(&instance->wait_queue);
294 
295 	ME_SUBDEVICE_EXIT;
296 
297 	return ME_ERRNO_SUCCESS;
298 }
299 
me4600_ext_irq_destructor(struct me_subdevice * subdevice)300 static void me4600_ext_irq_destructor(struct me_subdevice *subdevice)
301 {
302 	me4600_ext_irq_subdevice_t *instance;
303 
304 	PDEBUG("executed.\n");
305 	instance = (me4600_ext_irq_subdevice_t *) subdevice;
306 	me_subdevice_deinit(&instance->base);
307 	free_irq(instance->irq, instance);
308 	kfree(instance);
309 }
310 
me4600_ext_irq_query_number_channels(me_subdevice_t * subdevice,int * number)311 static int me4600_ext_irq_query_number_channels(me_subdevice_t * subdevice,
312 						int *number)
313 {
314 	PDEBUG("executed.\n");
315 	*number = 1;
316 	return ME_ERRNO_SUCCESS;
317 }
318 
me4600_ext_irq_query_subdevice_type(me_subdevice_t * subdevice,int * type,int * subtype)319 static int me4600_ext_irq_query_subdevice_type(me_subdevice_t * subdevice,
320 					       int *type, int *subtype)
321 {
322 	PDEBUG("executed.\n");
323 	*type = ME_TYPE_EXT_IRQ;
324 	*subtype = ME_SUBTYPE_SINGLE;
325 	return ME_ERRNO_SUCCESS;
326 }
327 
me4600_ext_irq_query_subdevice_caps(me_subdevice_t * subdevice,int * caps)328 static int me4600_ext_irq_query_subdevice_caps(me_subdevice_t * subdevice,
329 					       int *caps)
330 {
331 	PDEBUG("executed.\n");
332 	*caps =
333 	    ME_CAPS_EXT_IRQ_EDGE_RISING | ME_CAPS_EXT_IRQ_EDGE_FALLING |
334 	    ME_CAPS_EXT_IRQ_EDGE_ANY;
335 	return ME_ERRNO_SUCCESS;
336 }
337 
338 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
me4600_ext_irq_isr(int irq,void * dev_id)339 static irqreturn_t me4600_ext_irq_isr(int irq, void *dev_id)
340 #else
341 static irqreturn_t me4600_ext_irq_isr(int irq, void *dev_id,
342 				      struct pt_regs *regs)
343 #endif
344 {
345 	me4600_ext_irq_subdevice_t *instance;
346 	uint32_t ctrl;
347 	uint32_t irq_status;
348 
349 	instance = (me4600_ext_irq_subdevice_t *) dev_id;
350 
351 	if (irq != instance->irq) {
352 		PERROR("Incorrect interrupt num: %d.\n", irq);
353 		return IRQ_NONE;
354 	}
355 
356 	irq_status = inl(instance->irq_status_reg);
357 	if (!(irq_status & ME4600_IRQ_STATUS_BIT_EX)) {
358 		PINFO("%ld Shared interrupt. %s(): irq_status_reg=0x%04X\n",
359 		      jiffies, __func__, irq_status);
360 		return IRQ_NONE;
361 	}
362 
363 	PDEBUG("executed.\n");
364 
365 	spin_lock(&instance->subdevice_lock);
366 	instance->rised = 1;
367 	instance->value = inl(instance->ext_irq_value_reg);
368 	instance->count++;
369 
370 	spin_lock(instance->ctrl_reg_lock);
371 	ctrl = inl(instance->ctrl_reg);
372 	ctrl |= ME4600_AI_CTRL_BIT_EX_IRQ_RESET;
373 	outl(ctrl, instance->ctrl_reg);
374 	PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
375 		   instance->ctrl_reg - instance->reg_base, ctrl);
376 	ctrl &= ~ME4600_AI_CTRL_BIT_EX_IRQ_RESET;
377 	outl(ctrl, instance->ctrl_reg);
378 	PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
379 		   instance->ctrl_reg - instance->reg_base, ctrl);
380 	spin_unlock(instance->ctrl_reg_lock);
381 
382 	spin_unlock(&instance->subdevice_lock);
383 	wake_up_interruptible_all(&instance->wait_queue);
384 
385 	return IRQ_HANDLED;
386 }
387 
me4600_ext_irq_constructor(uint32_t reg_base,int irq,spinlock_t * ctrl_reg_lock)388 me4600_ext_irq_subdevice_t *me4600_ext_irq_constructor(uint32_t reg_base,
389 						       int irq,
390 						       spinlock_t *
391 						       ctrl_reg_lock)
392 {
393 	me4600_ext_irq_subdevice_t *subdevice;
394 	int err;
395 
396 	PDEBUG("executed.\n");
397 
398 	/* Allocate memory for subdevice instance */
399 	subdevice = kmalloc(sizeof(me4600_ext_irq_subdevice_t), GFP_KERNEL);
400 
401 	if (!subdevice) {
402 		PERROR("Cannot get memory for subdevice instance.\n");
403 		return NULL;
404 	}
405 
406 	memset(subdevice, 0, sizeof(me4600_ext_irq_subdevice_t));
407 
408 	/* Initialize subdevice base class */
409 	err = me_subdevice_init(&subdevice->base);
410 
411 	if (err) {
412 		PERROR("Cannot initialize subdevice base class instance.\n");
413 		kfree(subdevice);
414 		return NULL;
415 	}
416 	// Initialize spin locks.
417 	spin_lock_init(&subdevice->subdevice_lock);
418 
419 	subdevice->ctrl_reg_lock = ctrl_reg_lock;
420 
421 	/* Initialize wait queue */
422 	init_waitqueue_head(&subdevice->wait_queue);
423 
424 	/* Register interrupt */
425 	subdevice->irq = irq;
426 
427 	if (request_irq(subdevice->irq, me4600_ext_irq_isr,
428 #ifdef IRQF_DISABLED
429 			IRQF_DISABLED | IRQF_SHARED,
430 #else
431 			SA_INTERRUPT | SA_SHIRQ,
432 #endif
433 			ME4600_NAME, subdevice)) {
434 		PERROR("Cannot register interrupt.\n");
435 		kfree(subdevice);
436 		return NULL;
437 	}
438 	PINFO("Registered irq=%d.\n", subdevice->irq);
439 
440 	/* Initialize registers */
441 	subdevice->irq_status_reg = reg_base + ME4600_IRQ_STATUS_REG;
442 	subdevice->ctrl_reg = reg_base + ME4600_AI_CTRL_REG;
443 	subdevice->ext_irq_config_reg = reg_base + ME4600_EXT_IRQ_CONFIG_REG;
444 	subdevice->ext_irq_value_reg = reg_base + ME4600_EXT_IRQ_VALUE_REG;
445 #ifdef MEDEBUG_DEBUG_REG
446 	subdevice->reg_base = reg_base;
447 #endif
448 
449 	/* Override base class methods. */
450 	subdevice->base.me_subdevice_destructor = me4600_ext_irq_destructor;
451 	subdevice->base.me_subdevice_io_reset_subdevice =
452 	    me4600_ext_irq_io_reset_subdevice;
453 	subdevice->base.me_subdevice_io_irq_start = me4600_ext_irq_io_irq_start;
454 	subdevice->base.me_subdevice_io_irq_wait = me4600_ext_irq_io_irq_wait;
455 	subdevice->base.me_subdevice_io_irq_stop = me4600_ext_irq_io_irq_stop;
456 	subdevice->base.me_subdevice_query_number_channels =
457 	    me4600_ext_irq_query_number_channels;
458 	subdevice->base.me_subdevice_query_subdevice_type =
459 	    me4600_ext_irq_query_subdevice_type;
460 	subdevice->base.me_subdevice_query_subdevice_caps =
461 	    me4600_ext_irq_query_subdevice_caps;
462 
463 	subdevice->rised = 0;
464 	subdevice->count = 0;
465 
466 	return subdevice;
467 }
468