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