1 /*
2     comedi/drivers/ni_atmio.c
3     Hardware driver for NI AT-MIO E series cards
4 
5     COMEDI - Linux Control and Measurement Device Interface
6     Copyright (C) 1997-2001 David A. Schleef <ds@schleef.org>
7 
8     This program is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 2 of the License, or
11     (at your option) any later version.
12 
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17 
18     You should have received a copy of the GNU General Public License
19     along with this program; if not, write to the Free Software
20     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22 /*
23 Driver: ni_atmio
24 Description: National Instruments AT-MIO-E series
25 Author: ds
26 Devices: [National Instruments] AT-MIO-16E-1 (ni_atmio),
27   AT-MIO-16E-2, AT-MIO-16E-10, AT-MIO-16DE-10, AT-MIO-64E-3,
28   AT-MIO-16XE-50, AT-MIO-16XE-10, AT-AI-16XE-10
29 Status: works
30 Updated: Thu May  1 20:03:02 CDT 2003
31 
32 The driver has 2.6 kernel isapnp support, and
33 will automatically probe for a supported board if the
34 I/O base is left unspecified with comedi_config.
35 However, many of
36 the isapnp id numbers are unknown.  If your board is not
37 recognized, please send the output of 'cat /proc/isapnp'
38 (you may need to modprobe the isa-pnp module for
39 /proc/isapnp to exist) so the
40 id numbers for your board can be added to the driver.
41 
42 Otherwise, you can use the isapnptools package to configure
43 your board.  Use isapnp to
44 configure the I/O base and IRQ for the board, and then pass
45 the same values as
46 parameters in comedi_config.  A sample isapnp.conf file is included
47 in the etc/ directory of Comedilib.
48 
49 Comedilib includes a utility to autocalibrate these boards.  The
50 boards seem to boot into a state where the all calibration DACs
51 are at one extreme of their range, thus the default calibration
52 is terrible.  Calibration at boot is strongly encouraged.
53 
54 To use the extended digital I/O on some of the boards, enable the
55 8255 driver when configuring the Comedi source tree.
56 
57 External triggering is supported for some events.  The channel index
58 (scan_begin_arg, etc.) maps to PFI0 - PFI9.
59 
60 Some of the more esoteric triggering possibilities of these boards
61 are not supported.
62 */
63 /*
64 	The real guts of the driver is in ni_mio_common.c, which is included
65 	both here and in ni_pcimio.c
66 
67 	Interrupt support added by Truxton Fulton <trux@truxton.com>
68 
69 	References for specifications:
70 
71 	   340747b.pdf  Register Level Programmer Manual (obsolete)
72 	   340747c.pdf  Register Level Programmer Manual (new)
73 	   DAQ-STC reference manual
74 
75 	Other possibly relevant info:
76 
77 	   320517c.pdf  User manual (obsolete)
78 	   320517f.pdf  User manual (new)
79 	   320889a.pdf  delete
80 	   320906c.pdf  maximum signal ratings
81 	   321066a.pdf  about 16x
82 	   321791a.pdf  discontinuation of at-mio-16e-10 rev. c
83 	   321808a.pdf  about at-mio-16e-10 rev P
84 	   321837a.pdf  discontinuation of at-mio-16de-10 rev d
85 	   321838a.pdf  about at-mio-16de-10 rev N
86 
87 	ISSUES:
88 
89 	need to deal with external reference for DAC, and other DAC
90 	properties in board properties
91 
92 	deal with at-mio-16de-10 revision D to N changes, etc.
93 
94 */
95 
96 #include <linux/interrupt.h>
97 #include "../comedidev.h"
98 
99 #include <linux/delay.h>
100 #include <linux/isapnp.h>
101 
102 #include "ni_stc.h"
103 #include "8255.h"
104 
105 #undef DEBUG
106 
107 #define ATMIO 1
108 #undef PCIMIO
109 
110 /*
111  *  AT specific setup
112  */
113 
114 #define NI_SIZE 0x20
115 
116 #define MAX_N_CALDACS 32
117 
118 static const struct ni_board_struct ni_boards[] = {
119 	{.device_id = 44,
120 	 .isapnp_id = 0x0000,	/* XXX unknown */
121 	 .name = "at-mio-16e-1",
122 	 .n_adchan = 16,
123 	 .adbits = 12,
124 	 .ai_fifo_depth = 8192,
125 	 .alwaysdither = 0,
126 	 .gainlkup = ai_gain_16,
127 	 .ai_speed = 800,
128 	 .n_aochan = 2,
129 	 .aobits = 12,
130 	 .ao_fifo_depth = 2048,
131 	 .ao_range_table = &range_ni_E_ao_ext,
132 	 .ao_unipolar = 1,
133 	 .ao_speed = 1000,
134 	 .has_8255 = 0,
135 	 .num_p0_dio_channels = 8,
136 	 .caldac = {mb88341},
137 	 },
138 	{.device_id = 25,
139 	 .isapnp_id = 0x1900,
140 	 .name = "at-mio-16e-2",
141 	 .n_adchan = 16,
142 	 .adbits = 12,
143 	 .ai_fifo_depth = 2048,
144 	 .alwaysdither = 0,
145 	 .gainlkup = ai_gain_16,
146 	 .ai_speed = 2000,
147 	 .n_aochan = 2,
148 	 .aobits = 12,
149 	 .ao_fifo_depth = 2048,
150 	 .ao_range_table = &range_ni_E_ao_ext,
151 	 .ao_unipolar = 1,
152 	 .ao_speed = 1000,
153 	 .has_8255 = 0,
154 	 .num_p0_dio_channels = 8,
155 	 .caldac = {mb88341},
156 	 },
157 	{.device_id = 36,
158 	 .isapnp_id = 0x2400,
159 	 .name = "at-mio-16e-10",
160 	 .n_adchan = 16,
161 	 .adbits = 12,
162 	 .ai_fifo_depth = 512,
163 	 .alwaysdither = 0,
164 	 .gainlkup = ai_gain_16,
165 	 .ai_speed = 10000,
166 	 .n_aochan = 2,
167 	 .aobits = 12,
168 	 .ao_fifo_depth = 0,
169 	 .ao_range_table = &range_ni_E_ao_ext,
170 	 .ao_unipolar = 1,
171 	 .ao_speed = 10000,
172 	 .num_p0_dio_channels = 8,
173 	 .caldac = {ad8804_debug},
174 	 .has_8255 = 0,
175 	 },
176 	{.device_id = 37,
177 	 .isapnp_id = 0x2500,
178 	 .name = "at-mio-16de-10",
179 	 .n_adchan = 16,
180 	 .adbits = 12,
181 	 .ai_fifo_depth = 512,
182 	 .alwaysdither = 0,
183 	 .gainlkup = ai_gain_16,
184 	 .ai_speed = 10000,
185 	 .n_aochan = 2,
186 	 .aobits = 12,
187 	 .ao_fifo_depth = 0,
188 	 .ao_range_table = &range_ni_E_ao_ext,
189 	 .ao_unipolar = 1,
190 	 .ao_speed = 10000,
191 	 .num_p0_dio_channels = 8,
192 	 .caldac = {ad8804_debug},
193 	 .has_8255 = 1,
194 	 },
195 	{.device_id = 38,
196 	 .isapnp_id = 0x2600,
197 	 .name = "at-mio-64e-3",
198 	 .n_adchan = 64,
199 	 .adbits = 12,
200 	 .ai_fifo_depth = 2048,
201 	 .alwaysdither = 0,
202 	 .gainlkup = ai_gain_16,
203 	 .ai_speed = 2000,
204 	 .n_aochan = 2,
205 	 .aobits = 12,
206 	 .ao_fifo_depth = 2048,
207 	 .ao_range_table = &range_ni_E_ao_ext,
208 	 .ao_unipolar = 1,
209 	 .ao_speed = 1000,
210 	 .has_8255 = 0,
211 	 .num_p0_dio_channels = 8,
212 	 .caldac = {ad8804_debug},
213 	 },
214 	{.device_id = 39,
215 	 .isapnp_id = 0x2700,
216 	 .name = "at-mio-16xe-50",
217 	 .n_adchan = 16,
218 	 .adbits = 16,
219 	 .ai_fifo_depth = 512,
220 	 .alwaysdither = 1,
221 	 .gainlkup = ai_gain_8,
222 	 .ai_speed = 50000,
223 	 .n_aochan = 2,
224 	 .aobits = 12,
225 	 .ao_fifo_depth = 0,
226 	 .ao_range_table = &range_bipolar10,
227 	 .ao_unipolar = 0,
228 	 .ao_speed = 50000,
229 	 .num_p0_dio_channels = 8,
230 	 .caldac = {dac8800, dac8043},
231 	 .has_8255 = 0,
232 	 },
233 	{.device_id = 50,
234 	 .isapnp_id = 0x0000,	/* XXX unknown */
235 	 .name = "at-mio-16xe-10",
236 	 .n_adchan = 16,
237 	 .adbits = 16,
238 	 .ai_fifo_depth = 512,
239 	 .alwaysdither = 1,
240 	 .gainlkup = ai_gain_14,
241 	 .ai_speed = 10000,
242 	 .n_aochan = 2,
243 	 .aobits = 16,
244 	 .ao_fifo_depth = 2048,
245 	 .ao_range_table = &range_ni_E_ao_ext,
246 	 .ao_unipolar = 1,
247 	 .ao_speed = 1000,
248 	 .num_p0_dio_channels = 8,
249 	 .caldac = {dac8800, dac8043, ad8522},
250 	 .has_8255 = 0,
251 	 },
252 	{.device_id = 51,
253 	 .isapnp_id = 0x0000,	/* XXX unknown */
254 	 .name = "at-ai-16xe-10",
255 	 .n_adchan = 16,
256 	 .adbits = 16,
257 	 .ai_fifo_depth = 512,
258 	 .alwaysdither = 1,	/* unknown */
259 	 .gainlkup = ai_gain_14,
260 	 .ai_speed = 10000,
261 	 .n_aochan = 0,
262 	 .aobits = 0,
263 	 .ao_fifo_depth = 0,
264 	 .ao_unipolar = 0,
265 	 .num_p0_dio_channels = 8,
266 	 .caldac = {dac8800, dac8043, ad8522},
267 	 .has_8255 = 0,
268 	 }
269 };
270 
271 static const int ni_irqpin[] = {
272 	-1, -1, -1, 0, 1, 2, -1, 3, -1, -1, 4, 5, 6, -1, -1, 7
273 };
274 
275 #define interrupt_pin(a)	(ni_irqpin[(a)])
276 
277 #define IRQ_POLARITY 0
278 
279 #define NI_E_IRQ_FLAGS		0
280 
281 struct ni_private {
282 	struct pnp_dev *isapnp_dev;
283 	NI_PRIVATE_COMMON
284 
285 };
286 
287 #define devpriv ((struct ni_private *)dev->private)
288 
289 /* How we access registers */
290 
291 #define ni_writel(a, b)		(outl((a), (b)+dev->iobase))
292 #define ni_readl(a)		(inl((a)+dev->iobase))
293 #define ni_writew(a, b)		(outw((a), (b)+dev->iobase))
294 #define ni_readw(a)		(inw((a)+dev->iobase))
295 #define ni_writeb(a, b)		(outb((a), (b)+dev->iobase))
296 #define ni_readb(a)		(inb((a)+dev->iobase))
297 
298 /* How we access windowed registers */
299 
300 /* We automatically take advantage of STC registers that can be
301  * read/written directly in the I/O space of the board.  The
302  * AT-MIO devices map the low 8 STC registers to iobase+addr*2. */
303 
ni_atmio_win_out(struct comedi_device * dev,uint16_t data,int addr)304 static void ni_atmio_win_out(struct comedi_device *dev, uint16_t data, int addr)
305 {
306 	unsigned long flags;
307 
308 	spin_lock_irqsave(&devpriv->window_lock, flags);
309 	if ((addr) < 8) {
310 		ni_writew(data, addr * 2);
311 	} else {
312 		ni_writew(addr, Window_Address);
313 		ni_writew(data, Window_Data);
314 	}
315 	spin_unlock_irqrestore(&devpriv->window_lock, flags);
316 }
317 
ni_atmio_win_in(struct comedi_device * dev,int addr)318 static uint16_t ni_atmio_win_in(struct comedi_device *dev, int addr)
319 {
320 	unsigned long flags;
321 	uint16_t ret;
322 
323 	spin_lock_irqsave(&devpriv->window_lock, flags);
324 	if (addr < 8) {
325 		ret = ni_readw(addr * 2);
326 	} else {
327 		ni_writew(addr, Window_Address);
328 		ret = ni_readw(Window_Data);
329 	}
330 	spin_unlock_irqrestore(&devpriv->window_lock, flags);
331 
332 	return ret;
333 }
334 
335 static struct pnp_device_id device_ids[] = {
336 	{.id = "NIC1900", .driver_data = 0},
337 	{.id = "NIC2400", .driver_data = 0},
338 	{.id = "NIC2500", .driver_data = 0},
339 	{.id = "NIC2600", .driver_data = 0},
340 	{.id = "NIC2700", .driver_data = 0},
341 	{.id = ""}
342 };
343 
344 MODULE_DEVICE_TABLE(pnp, device_ids);
345 
346 static int ni_atmio_attach(struct comedi_device *dev,
347 			   struct comedi_devconfig *it);
348 static int ni_atmio_detach(struct comedi_device *dev);
349 static struct comedi_driver driver_atmio = {
350 	.driver_name = "ni_atmio",
351 	.module = THIS_MODULE,
352 	.attach = ni_atmio_attach,
353 	.detach = ni_atmio_detach,
354 };
355 
driver_atmio_init_module(void)356 static int __init driver_atmio_init_module(void)
357 {
358 	return comedi_driver_register(&driver_atmio);
359 }
360 
driver_atmio_cleanup_module(void)361 static void __exit driver_atmio_cleanup_module(void)
362 {
363 	comedi_driver_unregister(&driver_atmio);
364 }
365 
366 module_init(driver_atmio_init_module);
367 module_exit(driver_atmio_cleanup_module);
368 
369 #include "ni_mio_common.c"
370 
371 static int ni_getboardtype(struct comedi_device *dev);
372 
373 /* clean up allocated resources */
ni_atmio_detach(struct comedi_device * dev)374 static int ni_atmio_detach(struct comedi_device *dev)
375 {
376 	mio_common_detach(dev);
377 
378 	if (dev->iobase)
379 		release_region(dev->iobase, NI_SIZE);
380 	if (dev->irq)
381 		free_irq(dev->irq, dev);
382 
383 	if (devpriv->isapnp_dev)
384 		pnp_device_detach(devpriv->isapnp_dev);
385 
386 	return 0;
387 }
388 
ni_isapnp_find_board(struct pnp_dev ** dev)389 static int ni_isapnp_find_board(struct pnp_dev **dev)
390 {
391 	struct pnp_dev *isapnp_dev = NULL;
392 	int i;
393 
394 	for (i = 0; i < n_ni_boards; i++) {
395 		isapnp_dev = pnp_find_dev(NULL,
396 					  ISAPNP_VENDOR('N', 'I', 'C'),
397 					  ISAPNP_FUNCTION(ni_boards[i].
398 							  isapnp_id), NULL);
399 
400 		if (isapnp_dev == NULL || isapnp_dev->card == NULL)
401 			continue;
402 
403 		if (pnp_device_attach(isapnp_dev) < 0) {
404 			printk
405 			 ("ni_atmio: %s found but already active, skipping.\n",
406 			  ni_boards[i].name);
407 			continue;
408 		}
409 		if (pnp_activate_dev(isapnp_dev) < 0) {
410 			pnp_device_detach(isapnp_dev);
411 			return -EAGAIN;
412 		}
413 		if (!pnp_port_valid(isapnp_dev, 0)
414 		    || !pnp_irq_valid(isapnp_dev, 0)) {
415 			pnp_device_detach(isapnp_dev);
416 			printk("ni_atmio: pnp invalid port or irq, aborting\n");
417 			return -ENOMEM;
418 		}
419 		break;
420 	}
421 	if (i == n_ni_boards)
422 		return -ENODEV;
423 	*dev = isapnp_dev;
424 	return 0;
425 }
426 
ni_atmio_attach(struct comedi_device * dev,struct comedi_devconfig * it)427 static int ni_atmio_attach(struct comedi_device *dev,
428 			   struct comedi_devconfig *it)
429 {
430 	struct pnp_dev *isapnp_dev;
431 	int ret;
432 	unsigned long iobase;
433 	int board;
434 	unsigned int irq;
435 
436 	/* allocate private area */
437 	ret = ni_alloc_private(dev);
438 	if (ret < 0)
439 		return ret;
440 
441 	devpriv->stc_writew = &ni_atmio_win_out;
442 	devpriv->stc_readw = &ni_atmio_win_in;
443 	devpriv->stc_writel = &win_out2;
444 	devpriv->stc_readl = &win_in2;
445 
446 	iobase = it->options[0];
447 	irq = it->options[1];
448 	isapnp_dev = NULL;
449 	if (iobase == 0) {
450 		ret = ni_isapnp_find_board(&isapnp_dev);
451 		if (ret < 0)
452 			return ret;
453 
454 		iobase = pnp_port_start(isapnp_dev, 0);
455 		irq = pnp_irq(isapnp_dev, 0);
456 		devpriv->isapnp_dev = isapnp_dev;
457 	}
458 
459 	/* reserve our I/O region */
460 
461 	printk("comedi%d: ni_atmio: 0x%04lx", dev->minor, iobase);
462 	if (!request_region(iobase, NI_SIZE, "ni_atmio")) {
463 		printk(" I/O port conflict\n");
464 		return -EIO;
465 	}
466 
467 	dev->iobase = iobase;
468 
469 #ifdef DEBUG
470 	/* board existence sanity check */
471 	{
472 		int i;
473 
474 		printk(" board fingerprint:");
475 		for (i = 0; i < 16; i += 2) {
476 			printk(" %04x %02x", inw(dev->iobase + i),
477 			       inb(dev->iobase + i + 1));
478 		}
479 	}
480 #endif
481 
482 	/* get board type */
483 
484 	board = ni_getboardtype(dev);
485 	if (board < 0)
486 		return -EIO;
487 
488 	dev->board_ptr = ni_boards + board;
489 
490 	printk(" %s", boardtype.name);
491 	dev->board_name = boardtype.name;
492 
493 	/* irq stuff */
494 
495 	if (irq != 0) {
496 		if (irq > 15 || ni_irqpin[irq] == -1) {
497 			printk(" invalid irq %u\n", irq);
498 			return -EINVAL;
499 		}
500 		printk(" ( irq = %u )", irq);
501 		ret = request_irq(irq, ni_E_interrupt, NI_E_IRQ_FLAGS,
502 				  "ni_atmio", dev);
503 
504 		if (ret < 0) {
505 			printk(" irq not available\n");
506 			return -EINVAL;
507 		}
508 		dev->irq = irq;
509 	}
510 
511 	/* generic E series stuff in ni_mio_common.c */
512 
513 	ret = ni_E_init(dev, it);
514 	if (ret < 0)
515 		return ret;
516 
517 
518 	return 0;
519 }
520 
ni_getboardtype(struct comedi_device * dev)521 static int ni_getboardtype(struct comedi_device *dev)
522 {
523 	int device_id = ni_read_eeprom(dev, 511);
524 	int i;
525 
526 	for (i = 0; i < n_ni_boards; i++) {
527 		if (ni_boards[i].device_id == device_id)
528 			return i;
529 
530 	}
531 	if (device_id == 255)
532 		printk(" can't find board\n");
533 	 else if (device_id == 0)
534 		printk(" EEPROM read error (?) or device not found\n");
535 	 else
536 		printk(" unknown device ID %d -- contact author\n", device_id);
537 
538 	return -1;
539 }
540