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