staging: comedi: ni_stc.h: remove 'ao_unipolar' flag from ni_board_struct
[cascardo/linux.git] / drivers / staging / comedi / drivers / ni_atmio.c
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 /*
19 Driver: ni_atmio
20 Description: National Instruments AT-MIO-E series
21 Author: ds
22 Devices: [National Instruments] AT-MIO-16E-1 (ni_atmio),
23   AT-MIO-16E-2, AT-MIO-16E-10, AT-MIO-16DE-10, AT-MIO-64E-3,
24   AT-MIO-16XE-50, AT-MIO-16XE-10, AT-AI-16XE-10
25 Status: works
26 Updated: Thu May  1 20:03:02 CDT 2003
27
28 The driver has 2.6 kernel isapnp support, and
29 will automatically probe for a supported board if the
30 I/O base is left unspecified with comedi_config.
31 However, many of
32 the isapnp id numbers are unknown.  If your board is not
33 recognized, please send the output of 'cat /proc/isapnp'
34 (you may need to modprobe the isa-pnp module for
35 /proc/isapnp to exist) so the
36 id numbers for your board can be added to the driver.
37
38 Otherwise, you can use the isapnptools package to configure
39 your board.  Use isapnp to
40 configure the I/O base and IRQ for the board, and then pass
41 the same values as
42 parameters in comedi_config.  A sample isapnp.conf file is included
43 in the etc/ directory of Comedilib.
44
45 Comedilib includes a utility to autocalibrate these boards.  The
46 boards seem to boot into a state where the all calibration DACs
47 are at one extreme of their range, thus the default calibration
48 is terrible.  Calibration at boot is strongly encouraged.
49
50 To use the extended digital I/O on some of the boards, enable the
51 8255 driver when configuring the Comedi source tree.
52
53 External triggering is supported for some events.  The channel index
54 (scan_begin_arg, etc.) maps to PFI0 - PFI9.
55
56 Some of the more esoteric triggering possibilities of these boards
57 are not supported.
58 */
59 /*
60         The real guts of the driver is in ni_mio_common.c, which is included
61         both here and in ni_pcimio.c
62
63         Interrupt support added by Truxton Fulton <trux@truxton.com>
64
65         References for specifications:
66
67            340747b.pdf  Register Level Programmer Manual (obsolete)
68            340747c.pdf  Register Level Programmer Manual (new)
69            DAQ-STC reference manual
70
71         Other possibly relevant info:
72
73            320517c.pdf  User manual (obsolete)
74            320517f.pdf  User manual (new)
75            320889a.pdf  delete
76            320906c.pdf  maximum signal ratings
77            321066a.pdf  about 16x
78            321791a.pdf  discontinuation of at-mio-16e-10 rev. c
79            321808a.pdf  about at-mio-16e-10 rev P
80            321837a.pdf  discontinuation of at-mio-16de-10 rev d
81            321838a.pdf  about at-mio-16de-10 rev N
82
83         ISSUES:
84
85         need to deal with external reference for DAC, and other DAC
86         properties in board properties
87
88         deal with at-mio-16de-10 revision D to N changes, etc.
89
90 */
91
92 #include <linux/module.h>
93 #include <linux/interrupt.h>
94 #include "../comedidev.h"
95
96 #include <linux/isapnp.h>
97
98 #include "ni_stc.h"
99 #include "8255.h"
100
101 /*
102  *  AT specific setup
103  */
104
105 static const struct ni_board_struct ni_boards[] = {
106         {
107                 .name           = "at-mio-16e-1",
108                 .device_id      = 44,
109                 .isapnp_id      = 0x0000,       /* XXX unknown */
110                 .n_adchan       = 16,
111                 .adbits         = 12,
112                 .ai_fifo_depth  = 8192,
113                 .gainlkup       = ai_gain_16,
114                 .ai_speed       = 800,
115                 .n_aochan       = 2,
116                 .aobits         = 12,
117                 .ao_fifo_depth  = 2048,
118                 .ao_range_table = &range_ni_E_ao_ext,
119                 .ao_speed       = 1000,
120                 .num_p0_dio_channels = 8,
121                 .caldac         = { mb88341 },
122         }, {
123                 .name           = "at-mio-16e-2",
124                 .device_id      = 25,
125                 .isapnp_id      = 0x1900,
126                 .n_adchan       = 16,
127                 .adbits         = 12,
128                 .ai_fifo_depth  = 2048,
129                 .gainlkup       = ai_gain_16,
130                 .ai_speed       = 2000,
131                 .n_aochan       = 2,
132                 .aobits         = 12,
133                 .ao_fifo_depth  = 2048,
134                 .ao_range_table = &range_ni_E_ao_ext,
135                 .ao_speed       = 1000,
136                 .num_p0_dio_channels = 8,
137                 .caldac         = { mb88341 },
138         }, {
139                 .name           = "at-mio-16e-10",
140                 .device_id      = 36,
141                 .isapnp_id      = 0x2400,
142                 .n_adchan       = 16,
143                 .adbits         = 12,
144                 .ai_fifo_depth  = 512,
145                 .gainlkup       = ai_gain_16,
146                 .ai_speed       = 10000,
147                 .n_aochan       = 2,
148                 .aobits         = 12,
149                 .ao_range_table = &range_ni_E_ao_ext,
150                 .ao_speed       = 10000,
151                 .num_p0_dio_channels = 8,
152                 .caldac         = { ad8804_debug },
153         }, {
154                 .name           = "at-mio-16de-10",
155                 .device_id      = 37,
156                 .isapnp_id      = 0x2500,
157                 .n_adchan       = 16,
158                 .adbits         = 12,
159                 .ai_fifo_depth  = 512,
160                 .gainlkup       = ai_gain_16,
161                 .ai_speed       = 10000,
162                 .n_aochan       = 2,
163                 .aobits         = 12,
164                 .ao_range_table = &range_ni_E_ao_ext,
165                 .ao_speed       = 10000,
166                 .num_p0_dio_channels = 8,
167                 .caldac         = { ad8804_debug },
168                 .has_8255       = 1,
169         }, {
170                 .name           = "at-mio-64e-3",
171                 .device_id      = 38,
172                 .isapnp_id      = 0x2600,
173                 .n_adchan       = 64,
174                 .adbits         = 12,
175                 .ai_fifo_depth  = 2048,
176                 .gainlkup       = ai_gain_16,
177                 .ai_speed       = 2000,
178                 .n_aochan       = 2,
179                 .aobits         = 12,
180                 .ao_fifo_depth  = 2048,
181                 .ao_range_table = &range_ni_E_ao_ext,
182                 .ao_speed       = 1000,
183                 .num_p0_dio_channels = 8,
184                 .caldac         = { ad8804_debug },
185         }, {
186                 .name           = "at-mio-16xe-50",
187                 .device_id      = 39,
188                 .isapnp_id      = 0x2700,
189                 .n_adchan       = 16,
190                 .adbits         = 16,
191                 .ai_fifo_depth  = 512,
192                 .alwaysdither   = 1,
193                 .gainlkup       = ai_gain_8,
194                 .ai_speed       = 50000,
195                 .n_aochan       = 2,
196                 .aobits         = 12,
197                 .ao_range_table = &range_bipolar10,
198                 .ao_speed       = 50000,
199                 .num_p0_dio_channels = 8,
200                 .caldac         = { dac8800, dac8043 },
201         }, {
202                 .name           = "at-mio-16xe-10",
203                 .device_id      = 50,
204                 .isapnp_id      = 0x0000,       /* XXX unknown */
205                 .n_adchan       = 16,
206                 .adbits         = 16,
207                 .ai_fifo_depth  = 512,
208                 .alwaysdither   = 1,
209                 .gainlkup       = ai_gain_14,
210                 .ai_speed       = 10000,
211                 .n_aochan       = 2,
212                 .aobits         = 16,
213                 .ao_fifo_depth  = 2048,
214                 .ao_range_table = &range_ni_E_ao_ext,
215                 .ao_speed       = 1000,
216                 .num_p0_dio_channels = 8,
217                 .caldac         = { dac8800, dac8043, ad8522 },
218         }, {
219                 .name           = "at-ai-16xe-10",
220                 .device_id      = 51,
221                 .isapnp_id      = 0x0000,       /* XXX unknown */
222                 .n_adchan       = 16,
223                 .adbits         = 16,
224                 .ai_fifo_depth  = 512,
225                 .alwaysdither   = 1,    /* unknown */
226                 .gainlkup       = ai_gain_14,
227                 .ai_speed       = 10000,
228                 .num_p0_dio_channels = 8,
229                 .caldac         = { dac8800, dac8043, ad8522 },
230         },
231 };
232
233 static const int ni_irqpin[] = {
234         -1, -1, -1, 0, 1, 2, -1, 3, -1, -1, 4, 5, 6, -1, -1, 7
235 };
236
237 #include "ni_mio_common.c"
238
239 static struct pnp_device_id device_ids[] = {
240         {.id = "NIC1900", .driver_data = 0},
241         {.id = "NIC2400", .driver_data = 0},
242         {.id = "NIC2500", .driver_data = 0},
243         {.id = "NIC2600", .driver_data = 0},
244         {.id = "NIC2700", .driver_data = 0},
245         {.id = ""}
246 };
247
248 MODULE_DEVICE_TABLE(pnp, device_ids);
249
250 static int ni_isapnp_find_board(struct pnp_dev **dev)
251 {
252         struct pnp_dev *isapnp_dev = NULL;
253         int i;
254
255         for (i = 0; i < ARRAY_SIZE(ni_boards); i++) {
256                 isapnp_dev = pnp_find_dev(NULL,
257                                           ISAPNP_VENDOR('N', 'I', 'C'),
258                                           ISAPNP_FUNCTION(ni_boards[i].
259                                                           isapnp_id), NULL);
260
261                 if (isapnp_dev == NULL || isapnp_dev->card == NULL)
262                         continue;
263
264                 if (pnp_device_attach(isapnp_dev) < 0) {
265                         printk
266                          ("ni_atmio: %s found but already active, skipping.\n",
267                           ni_boards[i].name);
268                         continue;
269                 }
270                 if (pnp_activate_dev(isapnp_dev) < 0) {
271                         pnp_device_detach(isapnp_dev);
272                         return -EAGAIN;
273                 }
274                 if (!pnp_port_valid(isapnp_dev, 0)
275                     || !pnp_irq_valid(isapnp_dev, 0)) {
276                         pnp_device_detach(isapnp_dev);
277                         printk("ni_atmio: pnp invalid port or irq, aborting\n");
278                         return -ENOMEM;
279                 }
280                 break;
281         }
282         if (i == ARRAY_SIZE(ni_boards))
283                 return -ENODEV;
284         *dev = isapnp_dev;
285         return 0;
286 }
287
288 static int ni_getboardtype(struct comedi_device *dev)
289 {
290         int device_id = ni_read_eeprom(dev, 511);
291         int i;
292
293         for (i = 0; i < ARRAY_SIZE(ni_boards); i++) {
294                 if (ni_boards[i].device_id == device_id)
295                         return i;
296
297         }
298         if (device_id == 255)
299                 printk(" can't find board\n");
300          else if (device_id == 0)
301                 printk(" EEPROM read error (?) or device not found\n");
302          else
303                 printk(" unknown device ID %d -- contact author\n", device_id);
304
305         return -1;
306 }
307
308 static int ni_atmio_attach(struct comedi_device *dev,
309                            struct comedi_devconfig *it)
310 {
311         const struct ni_board_struct *boardtype;
312         struct ni_private *devpriv;
313         struct pnp_dev *isapnp_dev;
314         int ret;
315         unsigned long iobase;
316         int board;
317         unsigned int irq;
318
319         ret = ni_alloc_private(dev);
320         if (ret)
321                 return ret;
322         devpriv = dev->private;
323
324         iobase = it->options[0];
325         irq = it->options[1];
326         isapnp_dev = NULL;
327         if (iobase == 0) {
328                 ret = ni_isapnp_find_board(&isapnp_dev);
329                 if (ret < 0)
330                         return ret;
331
332                 iobase = pnp_port_start(isapnp_dev, 0);
333                 irq = pnp_irq(isapnp_dev, 0);
334                 comedi_set_hw_dev(dev, &isapnp_dev->dev);
335         }
336
337         ret = comedi_request_region(dev, iobase, 0x20);
338         if (ret)
339                 return ret;
340
341         /* get board type */
342
343         board = ni_getboardtype(dev);
344         if (board < 0)
345                 return -EIO;
346
347         dev->board_ptr = ni_boards + board;
348         boardtype = comedi_board(dev);
349
350         printk(" %s", boardtype->name);
351         dev->board_name = boardtype->name;
352
353         /* irq stuff */
354
355         if (irq != 0) {
356                 if (irq > 15 || ni_irqpin[irq] == -1) {
357                         printk(" invalid irq %u\n", irq);
358                         return -EINVAL;
359                 }
360                 printk(" ( irq = %u )", irq);
361                 ret = request_irq(irq, ni_E_interrupt, 0,
362                                   "ni_atmio", dev);
363
364                 if (ret < 0) {
365                         printk(" irq not available\n");
366                         return -EINVAL;
367                 }
368                 dev->irq = irq;
369         }
370
371         /* generic E series stuff in ni_mio_common.c */
372
373         ret = ni_E_init(dev, ni_irqpin[dev->irq], 0);
374         if (ret < 0)
375                 return ret;
376
377
378         return 0;
379 }
380
381 static void ni_atmio_detach(struct comedi_device *dev)
382 {
383         struct pnp_dev *isapnp_dev;
384
385         mio_common_detach(dev);
386         comedi_legacy_detach(dev);
387
388         isapnp_dev = dev->hw_dev ? to_pnp_dev(dev->hw_dev) : NULL;
389         if (isapnp_dev)
390                 pnp_device_detach(isapnp_dev);
391 }
392
393 static struct comedi_driver ni_atmio_driver = {
394         .driver_name    = "ni_atmio",
395         .module         = THIS_MODULE,
396         .attach         = ni_atmio_attach,
397         .detach         = ni_atmio_detach,
398 };
399 module_comedi_driver(ni_atmio_driver);