[go: nahoru, domu]

1/*
2 * Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
3 *
4 *	ADDI-DATA GmbH
5 *	Dieselstrasse 3
6 *	D-77833 Ottersweier
7 *	Tel: +19(0)7223/9493-0
8 *	Fax: +49(0)7223/9493-92
9 *	http://www.addi-data.com
10 *	info@addi-data.com
11 *
12 * This program is free software; you can redistribute it and/or modify it under
13 * the terms of the GNU General Public License as published by the Free Software
14 * Foundation; either version 2 of the License, or (at your option) any later
15 * version.
16 *
17 * This program is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
20 * details.
21 */
22
23/* Card Specific information */
24#define APCI035_ADDRESS_RANGE		255
25
26/* Timer / Watchdog Related Defines */
27#define APCI035_TCW_SYNC_ENABLEDISABLE	0
28#define APCI035_TCW_RELOAD_VALUE	4
29#define APCI035_TCW_TIMEBASE		8
30#define APCI035_TCW_PROG		12
31#define APCI035_TCW_TRIG_STATUS		16
32#define APCI035_TCW_IRQ			20
33#define APCI035_TCW_WARN_TIMEVAL	24
34#define APCI035_TCW_WARN_TIMEBASE	28
35
36#define ADDIDATA_TIMER			0
37/* #define ADDIDATA_WATCHDOG		1 */
38
39#define APCI035_TW1			0
40#define APCI035_TW2			32
41#define APCI035_TW3			64
42#define APCI035_TW4			96
43
44#define APCI035_AI_OFFSET		0
45#define APCI035_TEMP			128
46#define APCI035_ALR_SEQ			4
47#define APCI035_START_STOP_INDEX	8
48#define APCI035_ALR_START_STOP		12
49#define APCI035_ALR_IRQ			16
50#define APCI035_EOS			20
51#define APCI035_CHAN_NO			24
52#define APCI035_CHAN_VAL		28
53#define APCI035_CONV_TIME_TIME_BASE	36
54#define APCI035_RELOAD_CONV_TIME_VAL	32
55#define APCI035_DELAY_TIME_TIME_BASE	44
56#define APCI035_RELOAD_DELAY_TIME_VAL	40
57#define ENABLE_EXT_TRIG			1
58#define ENABLE_EXT_GATE			2
59#define ENABLE_EXT_TRIG_GATE		3
60
61#define ANALOG_INPUT			0
62#define TEMPERATURE			1
63#define RESISTANCE			2
64
65#define ADDIDATA_GREATER_THAN_TEST	0
66#define ADDIDATA_LESS_THAN_TEST		1
67
68#define APCI035_MAXVOLT			2.5
69
70#define ADDIDATA_UNIPOLAR		1
71#define ADDIDATA_BIPOLAR		2
72
73/* ANALOG INPUT RANGE */
74static struct comedi_lrange range_apci035_ai = {
75	8, {
76		BIP_RANGE(10),
77		BIP_RANGE(5),
78		BIP_RANGE(2),
79		BIP_RANGE(1),
80		UNI_RANGE(10),
81		UNI_RANGE(5),
82		UNI_RANGE(2),
83		UNI_RANGE(1)
84	}
85};
86
87static int i_WatchdogNbr;
88static int i_Temp;
89static int i_Flag = 1;
90
91/*
92 * Configures The Timer , Counter or Watchdog
93 *
94 * data[0] 0 = Configure As Timer, 1 = Configure As Watchdog
95 * data[1] Watchdog number
96 * data[2] Time base Unit
97 * data[3] Reload Value
98 * data[4] External Trigger, 1 = Enable, 0 = Disable
99 * data[5] External Trigger Level
100 *	00 = Trigger Disabled
101 *	01 = Trigger Enabled (Low level)
102 *	10 = Trigger Enabled (High Level)
103 *	11 = Trigger Enabled (High/Low level)
104 * data[6] External Gate, 1 = Enable, 0 = Disable
105 * data[7] External Gate level
106 *	00 = Gate Disabled
107 *	01 = Gate Enabled (Low level)
108 *	10 = Gate Enabled (High Level)
109 * data[8] Warning Relay, 1 = Enable, 0 = Disable
110 * data[9] Warning Delay available
111 * data[10] Warning Relay Time unit
112 * data[11] Warning Relay Time Reload value
113 * data[12] Reset Relay, 1 = Enable, 0 = Disable
114 * data[13] Interrupt, 1 = Enable, 0 = Disable
115 */
116static int apci035_timer_config(struct comedi_device *dev,
117				struct comedi_subdevice *s,
118				struct comedi_insn *insn,
119				unsigned int *data)
120{
121	struct addi_private *devpriv = dev->private;
122	unsigned int ui_Status;
123	unsigned int ui_Command;
124	unsigned int ui_Mode;
125
126	i_Temp = 0;
127	devpriv->tsk_Current = current;
128	devpriv->b_TimerSelectMode = data[0];
129	i_WatchdogNbr = data[1];
130	if (data[0] == 0)
131		ui_Mode = 2;
132	else
133		ui_Mode = 0;
134
135	ui_Command = 0;
136	outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
137
138	ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
139
140	/* Set the reload value */
141	outl(data[3], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 4);
142
143	/* Set the time unit */
144	outl(data[2], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 8);
145	if (data[0] == ADDIDATA_TIMER) {
146
147		/* Set the mode :             */
148		/* - Disable the hardware     */
149		/* - Disable the counter mode */
150		/* - Disable the warning      */
151		/* - Disable the reset        */
152		/* - Enable the timer mode    */
153		/* - Set the timer mode       */
154
155		ui_Command =
156			(ui_Command & 0xFFF719E2UL) | ui_Mode << 13UL | 0x10UL;
157
158	} else if (data[0] == ADDIDATA_WATCHDOG) {
159
160		/* Set the mode :             */
161		/* - Disable the hardware     */
162		/* - Disable the counter mode */
163		/* - Disable the warning      */
164		/* - Disable the reset        */
165		/* - Disable the timer mode   */
166
167		ui_Command = ui_Command & 0xFFF819E2UL;
168
169	} else {
170		dev_err(dev->class_dev, "The parameter for Timer/watchdog selection is in error\n");
171		return -EINVAL;
172	}
173
174	outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
175
176	ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
177
178	/* Disable the hardware trigger */
179	ui_Command = ui_Command & 0xFFFFF89FUL;
180	if (data[4] == 1) {
181		/* Set the hardware trigger level */
182		ui_Command = ui_Command | (data[5] << 5);
183	}
184	outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
185
186	ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
187
188	/* Disable the hardware gate */
189	ui_Command = ui_Command & 0xFFFFF87FUL;
190	if (data[6] == 1) {
191		/* Set the hardware gate level */
192		ui_Command = ui_Command | (data[7] << 7);
193	}
194	outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
195
196	ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
197
198	/* Disable the hardware output */
199	ui_Command = ui_Command & 0xFFFFF9FBUL;
200
201	/* Set the hardware output level */
202	ui_Command = ui_Command | (data[8] << 2);
203	outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
204	if (data[9] == 1) {
205		/* Set the reload value */
206		outl(data[11],
207			devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 24);
208
209		/* Set the time unite */
210		outl(data[10],
211			devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 28);
212	}
213
214	ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
215
216	/* Disable the hardware output */
217	ui_Command = ui_Command & 0xFFFFF9F7UL;
218
219	/* Set the hardware output level */
220	ui_Command = ui_Command | (data[12] << 3);
221	outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
222
223	/* Enable the watchdog interrupt */
224	ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
225
226	/* Set the interrupt selection */
227	ui_Status = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 16);
228
229	ui_Command = (ui_Command & 0xFFFFF9FDUL) | (data[13] << 1);
230	outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
231
232	return insn->n;
233}
234
235/*
236 * Start / Stop The Selected Timer , or Watchdog
237 *
238 * data[0]
239 *	0 - Stop Selected Timer/Watchdog
240 *	1 - Start Selected Timer/Watch*dog
241 *	2 - Trigger Selected Timer/Watchdog
242 *	3 - Stop All Timer/Watchdog
243 *	4 - Start All Timer/Watchdog
244 *	5 - Trigger All Timer/Watchdog
245 */
246static int apci035_timer_write(struct comedi_device *dev,
247			       struct comedi_subdevice *s,
248			       struct comedi_insn *insn,
249			       unsigned int *data)
250{
251	struct addi_private *devpriv = dev->private;
252	unsigned int ui_Command;
253	int i_Count;
254
255	if (data[0] == 1) {
256		ui_Command =
257			inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
258
259		/* Start the hardware */
260		ui_Command = (ui_Command & 0xFFFFF9FFUL) | 0x1UL;
261		outl(ui_Command,
262			devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
263	}
264	if (data[0] == 2) {
265		ui_Command =
266			inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
267
268		/* Set the trigger command */
269		ui_Command = (ui_Command & 0xFFFFF9FFUL) | 0x200UL;
270		outl(ui_Command,
271			devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
272	}
273
274	if (data[0] == 0) {
275		/* Stop The Watchdog */
276		ui_Command = 0;
277		/*
278		* ui_Command = inl(devpriv->iobase+((i_WatchdogNbr-1)*32)+12);
279		* ui_Command = ui_Command & 0xFFFFF9FEUL;
280		*/
281		outl(ui_Command,
282			devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
283	}
284	if (data[0] == 3) {
285		/* stop all Watchdogs */
286		ui_Command = 0;
287		for (i_Count = 1; i_Count <= 4; i_Count++) {
288			if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG)
289				ui_Command = 0x2UL;
290			else
291				ui_Command = 0x10UL;
292
293			i_WatchdogNbr = i_Count;
294			outl(ui_Command,
295				devpriv->iobase + ((i_WatchdogNbr - 1) * 32) +
296				0);
297		}
298
299	}
300	if (data[0] == 4) {
301		/* start all Watchdogs */
302		ui_Command = 0;
303		for (i_Count = 1; i_Count <= 4; i_Count++) {
304			if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG)
305				ui_Command = 0x1UL;
306			else
307				ui_Command = 0x8UL;
308
309			i_WatchdogNbr = i_Count;
310			outl(ui_Command,
311				devpriv->iobase + ((i_WatchdogNbr - 1) * 32) +
312				0);
313		}
314	}
315	if (data[0] == 5) {
316		/* trigger all Watchdogs */
317		ui_Command = 0;
318		for (i_Count = 1; i_Count <= 4; i_Count++) {
319			if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG)
320				ui_Command = 0x4UL;
321			else
322				ui_Command = 0x20UL;
323
324			i_WatchdogNbr = i_Count;
325			outl(ui_Command,
326				devpriv->iobase + ((i_WatchdogNbr - 1) * 32) +
327				0);
328		}
329		i_Temp = 1;
330	}
331	return insn->n;
332}
333
334/*
335 * Read The Selected Timer , Counter or Watchdog
336 *
337 * data[0] software trigger status
338 * data[1] hardware trigger status
339 * data[2] Software clear status
340 * data[3] Overflow status
341 * data[4] Timer actual value
342 */
343static int apci035_timer_read(struct comedi_device *dev,
344			      struct comedi_subdevice *s,
345			      struct comedi_insn *insn,
346			      unsigned int *data)
347{
348	struct addi_private *devpriv = dev->private;
349	unsigned int ui_Status;	/*  Status register */
350
351	i_WatchdogNbr = insn->unused[0];
352
353	/* Get the status */
354	ui_Status = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 16);
355
356	/* Get the software trigger status */
357	data[0] = ((ui_Status >> 1) & 1);
358
359	/* Get the hardware trigger status */
360	data[1] = ((ui_Status >> 2) & 1);
361
362	/* Get the software clear status */
363	data[2] = ((ui_Status >> 3) & 1);
364
365	/* Get the overflow status */
366	data[3] = ((ui_Status >> 0) & 1);
367	if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER)
368		data[4] = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0);
369
370	return insn->n;
371}
372
373/*
374 * Configures The Analog Input Subdevice
375 *
376 * data[0] Warning delay value
377 */
378static int apci035_ai_config(struct comedi_device *dev,
379			     struct comedi_subdevice *s,
380			     struct comedi_insn *insn,
381			     unsigned int *data)
382{
383	struct addi_private *devpriv = dev->private;
384
385	devpriv->tsk_Current = current;
386	outl(0x200 | 0, devpriv->iobase + 128 + 0x4);
387	outl(0, devpriv->iobase + 128 + 0);
388
389	/* Initialise the warning value */
390	outl(0x300 | 0, devpriv->iobase + 128 + 0x4);
391	outl((data[0] << 8), devpriv->iobase + 128 + 0);
392	outl(0x200000UL, devpriv->iobase + 128 + 12);
393
394	return insn->n;
395}
396
397/*
398 * Read value of the selected channel
399 *
400 * data[0] Digital Value Of Input
401 */
402static int apci035_ai_read(struct comedi_device *dev,
403			   struct comedi_subdevice *s,
404			   struct comedi_insn *insn,
405			   unsigned int *data)
406{
407	struct addi_private *devpriv = dev->private;
408	unsigned int ui_CommandRegister;
409
410	/*  Set the start */
411	ui_CommandRegister = 0x80000;
412
413	/* Write the command register */
414	outl(ui_CommandRegister, devpriv->iobase + 128 + 8);
415
416	/* Read the digital value of the input */
417	data[0] = inl(devpriv->iobase + 128 + 28);
418	return insn->n;
419}
420
421static int apci035_reset(struct comedi_device *dev)
422{
423	struct addi_private *devpriv = dev->private;
424	int i_Count;
425
426	for (i_Count = 1; i_Count <= 4; i_Count++) {
427		i_WatchdogNbr = i_Count;
428
429		/* stop all timers */
430		outl(0x0, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0);
431	}
432	outl(0x0, devpriv->iobase + 128 + 12);	/* Disable the warning delay */
433
434	return 0;
435}
436
437static void apci035_interrupt(int irq, void *d)
438{
439	struct comedi_device *dev = d;
440	struct addi_private *devpriv = dev->private;
441	unsigned int ui_StatusRegister1;
442	unsigned int ui_StatusRegister2;
443	unsigned int ui_ReadCommand;
444	unsigned int ui_ChannelNumber;
445	unsigned int ui_DigitalTemperature;
446
447	if (i_Temp == 1) {
448		i_WatchdogNbr = i_Flag;
449		i_Flag = i_Flag + 1;
450	}
451
452	/* Read the interrupt status register of temperature Warning */
453	ui_StatusRegister1 = inl(devpriv->iobase + 128 + 16);
454
455	/* Read the interrupt status register for Watchdog/timer */
456	ui_StatusRegister2 =
457		inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 20);
458
459	/* Test if warning relay interrupt */
460	if ((((ui_StatusRegister1) & 0x8) == 0x8)) {
461
462		/* Disable the temperature warning */
463		ui_ReadCommand = inl(devpriv->iobase + 128 + 12);
464		ui_ReadCommand = ui_ReadCommand & 0xFFDF0000UL;
465		outl(ui_ReadCommand, devpriv->iobase + 128 + 12);
466
467		/* Read the channel number */
468		ui_ChannelNumber = inl(devpriv->iobase + 128 + 60);
469
470		/* Read the digital temperature value */
471		ui_DigitalTemperature = inl(devpriv->iobase + 128 + 60);
472
473		/*  send signal to the sample */
474		send_sig(SIGIO, devpriv->tsk_Current, 0);
475
476	} else if ((ui_StatusRegister2 & 0x1) == 0x1) {
477		/*  send signal to the sample */
478		send_sig(SIGIO, devpriv->tsk_Current, 0);
479	}
480}
481