Merge branch 'core-rcu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[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 #undef DEBUG
102
103 #define ATMIO 1
104 #undef PCIMIO
105
106 /*
107  *  AT specific setup
108  */
109
110 #define NI_SIZE 0x20
111
112 #define MAX_N_CALDACS 32
113
114 static const struct ni_board_struct ni_boards[] = {
115         {.device_id = 44,
116          .isapnp_id = 0x0000,   /* XXX unknown */
117          .name = "at-mio-16e-1",
118          .n_adchan = 16,
119          .adbits = 12,
120          .ai_fifo_depth = 8192,
121          .alwaysdither = 0,
122          .gainlkup = ai_gain_16,
123          .ai_speed = 800,
124          .n_aochan = 2,
125          .aobits = 12,
126          .ao_fifo_depth = 2048,
127          .ao_range_table = &range_ni_E_ao_ext,
128          .ao_unipolar = 1,
129          .ao_speed = 1000,
130          .has_8255 = 0,
131          .num_p0_dio_channels = 8,
132          .caldac = {mb88341},
133          },
134         {.device_id = 25,
135          .isapnp_id = 0x1900,
136          .name = "at-mio-16e-2",
137          .n_adchan = 16,
138          .adbits = 12,
139          .ai_fifo_depth = 2048,
140          .alwaysdither = 0,
141          .gainlkup = ai_gain_16,
142          .ai_speed = 2000,
143          .n_aochan = 2,
144          .aobits = 12,
145          .ao_fifo_depth = 2048,
146          .ao_range_table = &range_ni_E_ao_ext,
147          .ao_unipolar = 1,
148          .ao_speed = 1000,
149          .has_8255 = 0,
150          .num_p0_dio_channels = 8,
151          .caldac = {mb88341},
152          },
153         {.device_id = 36,
154          .isapnp_id = 0x2400,
155          .name = "at-mio-16e-10",
156          .n_adchan = 16,
157          .adbits = 12,
158          .ai_fifo_depth = 512,
159          .alwaysdither = 0,
160          .gainlkup = ai_gain_16,
161          .ai_speed = 10000,
162          .n_aochan = 2,
163          .aobits = 12,
164          .ao_fifo_depth = 0,
165          .ao_range_table = &range_ni_E_ao_ext,
166          .ao_unipolar = 1,
167          .ao_speed = 10000,
168          .num_p0_dio_channels = 8,
169          .caldac = {ad8804_debug},
170          .has_8255 = 0,
171          },
172         {.device_id = 37,
173          .isapnp_id = 0x2500,
174          .name = "at-mio-16de-10",
175          .n_adchan = 16,
176          .adbits = 12,
177          .ai_fifo_depth = 512,
178          .alwaysdither = 0,
179          .gainlkup = ai_gain_16,
180          .ai_speed = 10000,
181          .n_aochan = 2,
182          .aobits = 12,
183          .ao_fifo_depth = 0,
184          .ao_range_table = &range_ni_E_ao_ext,
185          .ao_unipolar = 1,
186          .ao_speed = 10000,
187          .num_p0_dio_channels = 8,
188          .caldac = {ad8804_debug},
189          .has_8255 = 1,
190          },
191         {.device_id = 38,
192          .isapnp_id = 0x2600,
193          .name = "at-mio-64e-3",
194          .n_adchan = 64,
195          .adbits = 12,
196          .ai_fifo_depth = 2048,
197          .alwaysdither = 0,
198          .gainlkup = ai_gain_16,
199          .ai_speed = 2000,
200          .n_aochan = 2,
201          .aobits = 12,
202          .ao_fifo_depth = 2048,
203          .ao_range_table = &range_ni_E_ao_ext,
204          .ao_unipolar = 1,
205          .ao_speed = 1000,
206          .has_8255 = 0,
207          .num_p0_dio_channels = 8,
208          .caldac = {ad8804_debug},
209          },
210         {.device_id = 39,
211          .isapnp_id = 0x2700,
212          .name = "at-mio-16xe-50",
213          .n_adchan = 16,
214          .adbits = 16,
215          .ai_fifo_depth = 512,
216          .alwaysdither = 1,
217          .gainlkup = ai_gain_8,
218          .ai_speed = 50000,
219          .n_aochan = 2,
220          .aobits = 12,
221          .ao_fifo_depth = 0,
222          .ao_range_table = &range_bipolar10,
223          .ao_unipolar = 0,
224          .ao_speed = 50000,
225          .num_p0_dio_channels = 8,
226          .caldac = {dac8800, dac8043},
227          .has_8255 = 0,
228          },
229         {.device_id = 50,
230          .isapnp_id = 0x0000,   /* XXX unknown */
231          .name = "at-mio-16xe-10",
232          .n_adchan = 16,
233          .adbits = 16,
234          .ai_fifo_depth = 512,
235          .alwaysdither = 1,
236          .gainlkup = ai_gain_14,
237          .ai_speed = 10000,
238          .n_aochan = 2,
239          .aobits = 16,
240          .ao_fifo_depth = 2048,
241          .ao_range_table = &range_ni_E_ao_ext,
242          .ao_unipolar = 1,
243          .ao_speed = 1000,
244          .num_p0_dio_channels = 8,
245          .caldac = {dac8800, dac8043, ad8522},
246          .has_8255 = 0,
247          },
248         {.device_id = 51,
249          .isapnp_id = 0x0000,   /* XXX unknown */
250          .name = "at-ai-16xe-10",
251          .n_adchan = 16,
252          .adbits = 16,
253          .ai_fifo_depth = 512,
254          .alwaysdither = 1,     /* unknown */
255          .gainlkup = ai_gain_14,
256          .ai_speed = 10000,
257          .n_aochan = 0,
258          .aobits = 0,
259          .ao_fifo_depth = 0,
260          .ao_unipolar = 0,
261          .num_p0_dio_channels = 8,
262          .caldac = {dac8800, dac8043, ad8522},
263          .has_8255 = 0,
264          }
265 };
266
267 static const int ni_irqpin[] = {
268         -1, -1, -1, 0, 1, 2, -1, 3, -1, -1, 4, 5, 6, -1, -1, 7
269 };
270
271 #define interrupt_pin(a)        (ni_irqpin[(a)])
272
273 #define IRQ_POLARITY 0
274
275 #define NI_E_IRQ_FLAGS          0
276
277 struct ni_private {
278         struct pnp_dev *isapnp_dev;
279         NI_PRIVATE_COMMON
280
281 };
282
283 /* How we access registers */
284
285 #define ni_writel(a, b)         (outl((a), (b)+dev->iobase))
286 #define ni_readl(a)             (inl((a)+dev->iobase))
287 #define ni_writew(a, b)         (outw((a), (b)+dev->iobase))
288 #define ni_readw(a)             (inw((a)+dev->iobase))
289 #define ni_writeb(a, b)         (outb((a), (b)+dev->iobase))
290 #define ni_readb(a)             (inb((a)+dev->iobase))
291
292 /* How we access windowed registers */
293
294 /* We automatically take advantage of STC registers that can be
295  * read/written directly in the I/O space of the board.  The
296  * AT-MIO devices map the low 8 STC registers to iobase+addr*2. */
297
298 static void ni_atmio_win_out(struct comedi_device *dev, uint16_t data, int addr)
299 {
300         struct ni_private *devpriv = dev->private;
301         unsigned long flags;
302
303         spin_lock_irqsave(&devpriv->window_lock, flags);
304         if ((addr) < 8) {
305                 ni_writew(data, addr * 2);
306         } else {
307                 ni_writew(addr, Window_Address);
308                 ni_writew(data, Window_Data);
309         }
310         spin_unlock_irqrestore(&devpriv->window_lock, flags);
311 }
312
313 static uint16_t ni_atmio_win_in(struct comedi_device *dev, int addr)
314 {
315         struct ni_private *devpriv = dev->private;
316         unsigned long flags;
317         uint16_t ret;
318
319         spin_lock_irqsave(&devpriv->window_lock, flags);
320         if (addr < 8) {
321                 ret = ni_readw(addr * 2);
322         } else {
323                 ni_writew(addr, Window_Address);
324                 ret = ni_readw(Window_Data);
325         }
326         spin_unlock_irqrestore(&devpriv->window_lock, flags);
327
328         return ret;
329 }
330
331 static struct pnp_device_id device_ids[] = {
332         {.id = "NIC1900", .driver_data = 0},
333         {.id = "NIC2400", .driver_data = 0},
334         {.id = "NIC2500", .driver_data = 0},
335         {.id = "NIC2600", .driver_data = 0},
336         {.id = "NIC2700", .driver_data = 0},
337         {.id = ""}
338 };
339
340 MODULE_DEVICE_TABLE(pnp, device_ids);
341
342 #include "ni_mio_common.c"
343
344 static int ni_isapnp_find_board(struct pnp_dev **dev)
345 {
346         struct pnp_dev *isapnp_dev = NULL;
347         int i;
348
349         for (i = 0; i < ARRAY_SIZE(ni_boards); i++) {
350                 isapnp_dev = pnp_find_dev(NULL,
351                                           ISAPNP_VENDOR('N', 'I', 'C'),
352                                           ISAPNP_FUNCTION(ni_boards[i].
353                                                           isapnp_id), NULL);
354
355                 if (isapnp_dev == NULL || isapnp_dev->card == NULL)
356                         continue;
357
358                 if (pnp_device_attach(isapnp_dev) < 0) {
359                         printk
360                          ("ni_atmio: %s found but already active, skipping.\n",
361                           ni_boards[i].name);
362                         continue;
363                 }
364                 if (pnp_activate_dev(isapnp_dev) < 0) {
365                         pnp_device_detach(isapnp_dev);
366                         return -EAGAIN;
367                 }
368                 if (!pnp_port_valid(isapnp_dev, 0)
369                     || !pnp_irq_valid(isapnp_dev, 0)) {
370                         pnp_device_detach(isapnp_dev);
371                         printk("ni_atmio: pnp invalid port or irq, aborting\n");
372                         return -ENOMEM;
373                 }
374                 break;
375         }
376         if (i == ARRAY_SIZE(ni_boards))
377                 return -ENODEV;
378         *dev = isapnp_dev;
379         return 0;
380 }
381
382 static int ni_getboardtype(struct comedi_device *dev)
383 {
384         int device_id = ni_read_eeprom(dev, 511);
385         int i;
386
387         for (i = 0; i < ARRAY_SIZE(ni_boards); i++) {
388                 if (ni_boards[i].device_id == device_id)
389                         return i;
390
391         }
392         if (device_id == 255)
393                 printk(" can't find board\n");
394          else if (device_id == 0)
395                 printk(" EEPROM read error (?) or device not found\n");
396          else
397                 printk(" unknown device ID %d -- contact author\n", device_id);
398
399         return -1;
400 }
401
402 static int ni_atmio_attach(struct comedi_device *dev,
403                            struct comedi_devconfig *it)
404 {
405         const struct ni_board_struct *boardtype;
406         struct ni_private *devpriv;
407         struct pnp_dev *isapnp_dev;
408         int ret;
409         unsigned long iobase;
410         int board;
411         unsigned int irq;
412
413         ret = ni_alloc_private(dev);
414         if (ret)
415                 return ret;
416         devpriv = dev->private;
417
418         devpriv->stc_writew = &ni_atmio_win_out;
419         devpriv->stc_readw = &ni_atmio_win_in;
420         devpriv->stc_writel = &win_out2;
421         devpriv->stc_readl = &win_in2;
422
423         iobase = it->options[0];
424         irq = it->options[1];
425         isapnp_dev = NULL;
426         if (iobase == 0) {
427                 ret = ni_isapnp_find_board(&isapnp_dev);
428                 if (ret < 0)
429                         return ret;
430
431                 iobase = pnp_port_start(isapnp_dev, 0);
432                 irq = pnp_irq(isapnp_dev, 0);
433                 devpriv->isapnp_dev = isapnp_dev;
434         }
435
436         ret = comedi_request_region(dev, iobase, NI_SIZE);
437         if (ret)
438                 return ret;
439
440 #ifdef DEBUG
441         /* board existence sanity check */
442         {
443                 int i;
444
445                 printk(" board fingerprint:");
446                 for (i = 0; i < 16; i += 2) {
447                         printk(" %04x %02x", inw(dev->iobase + i),
448                                inb(dev->iobase + i + 1));
449                 }
450         }
451 #endif
452
453         /* get board type */
454
455         board = ni_getboardtype(dev);
456         if (board < 0)
457                 return -EIO;
458
459         dev->board_ptr = ni_boards + board;
460         boardtype = comedi_board(dev);
461
462         printk(" %s", boardtype->name);
463         dev->board_name = boardtype->name;
464
465         /* irq stuff */
466
467         if (irq != 0) {
468                 if (irq > 15 || ni_irqpin[irq] == -1) {
469                         printk(" invalid irq %u\n", irq);
470                         return -EINVAL;
471                 }
472                 printk(" ( irq = %u )", irq);
473                 ret = request_irq(irq, ni_E_interrupt, NI_E_IRQ_FLAGS,
474                                   "ni_atmio", dev);
475
476                 if (ret < 0) {
477                         printk(" irq not available\n");
478                         return -EINVAL;
479                 }
480                 dev->irq = irq;
481         }
482
483         /* generic E series stuff in ni_mio_common.c */
484
485         ret = ni_E_init(dev);
486         if (ret < 0)
487                 return ret;
488
489
490         return 0;
491 }
492
493 static void ni_atmio_detach(struct comedi_device *dev)
494 {
495         struct ni_private *devpriv = dev->private;
496
497         mio_common_detach(dev);
498         comedi_legacy_detach(dev);
499         if (devpriv->isapnp_dev)
500                 pnp_device_detach(devpriv->isapnp_dev);
501 }
502
503 static struct comedi_driver ni_atmio_driver = {
504         .driver_name    = "ni_atmio",
505         .module         = THIS_MODULE,
506         .attach         = ni_atmio_attach,
507         .detach         = ni_atmio_detach,
508 };
509 module_comedi_driver(ni_atmio_driver);