1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * me4000.c
4 * Source code for the Meilhaus ME-4000 board family.
5 *
6 * COMEDI - Linux Control and Measurement Device Interface
7 * Copyright (C) 2000 David A. Schleef <ds@schleef.org>
8 */
9
10/*
11 * Driver: me4000
12 * Description: Meilhaus ME-4000 series boards
13 * Devices: [Meilhaus] ME-4650 (me4000), ME-4670i, ME-4680, ME-4680i,
14 * ME-4680is
15 * Author: gg (Guenter Gebhardt <g.gebhardt@meilhaus.com>)
16 * Updated: Mon, 18 Mar 2002 15:34:01 -0800
17 * Status: untested
18 *
19 * Supports:
20 * - Analog Input
21 * - Analog Output
22 * - Digital I/O
23 * - Counter
24 *
25 * Configuration Options: not applicable, uses PCI auto config
26 *
27 * The firmware required by these boards is available in the
28 * comedi_nonfree_firmware tarball available from
29 * https://www.comedi.org.
30 */
31
32#include <linux/module.h>
33#include <linux/delay.h>
34#include <linux/interrupt.h>
35#include <linux/comedi/comedi_pci.h>
36#include <linux/comedi/comedi_8254.h>
37
38#include "plx9052.h"
39
40#define ME4000_FIRMWARE "me4000_firmware.bin"
41
42/*
43 * ME4000 Register map and bit defines
44 */
45#define ME4000_AO_CHAN(x) ((x) * 0x18)
46
47#define ME4000_AO_CTRL_REG(x) (0x00 + ME4000_AO_CHAN(x))
48#define ME4000_AO_CTRL_MODE_0 BIT(0)
49#define ME4000_AO_CTRL_MODE_1 BIT(1)
50#define ME4000_AO_CTRL_STOP BIT(2)
51#define ME4000_AO_CTRL_ENABLE_FIFO BIT(3)
52#define ME4000_AO_CTRL_ENABLE_EX_TRIG BIT(4)
53#define ME4000_AO_CTRL_EX_TRIG_EDGE BIT(5)
54#define ME4000_AO_CTRL_IMMEDIATE_STOP BIT(7)
55#define ME4000_AO_CTRL_ENABLE_DO BIT(8)
56#define ME4000_AO_CTRL_ENABLE_IRQ BIT(9)
57#define ME4000_AO_CTRL_RESET_IRQ BIT(10)
58#define ME4000_AO_STATUS_REG(x) (0x04 + ME4000_AO_CHAN(x))
59#define ME4000_AO_STATUS_FSM BIT(0)
60#define ME4000_AO_STATUS_FF BIT(1)
61#define ME4000_AO_STATUS_HF BIT(2)
62#define ME4000_AO_STATUS_EF BIT(3)
63#define ME4000_AO_FIFO_REG(x) (0x08 + ME4000_AO_CHAN(x))
64#define ME4000_AO_SINGLE_REG(x) (0x0c + ME4000_AO_CHAN(x))
65#define ME4000_AO_TIMER_REG(x) (0x10 + ME4000_AO_CHAN(x))
66#define ME4000_AI_CTRL_REG 0x74
67#define ME4000_AI_STATUS_REG 0x74
68#define ME4000_AI_CTRL_MODE_0 BIT(0)
69#define ME4000_AI_CTRL_MODE_1 BIT(1)
70#define ME4000_AI_CTRL_MODE_2 BIT(2)
71#define ME4000_AI_CTRL_SAMPLE_HOLD BIT(3)
72#define ME4000_AI_CTRL_IMMEDIATE_STOP BIT(4)
73#define ME4000_AI_CTRL_STOP BIT(5)
74#define ME4000_AI_CTRL_CHANNEL_FIFO BIT(6)
75#define ME4000_AI_CTRL_DATA_FIFO BIT(7)
76#define ME4000_AI_CTRL_FULLSCALE BIT(8)
77#define ME4000_AI_CTRL_OFFSET BIT(9)
78#define ME4000_AI_CTRL_EX_TRIG_ANALOG BIT(10)
79#define ME4000_AI_CTRL_EX_TRIG BIT(11)
80#define ME4000_AI_CTRL_EX_TRIG_FALLING BIT(12)
81#define ME4000_AI_CTRL_EX_IRQ BIT(13)
82#define ME4000_AI_CTRL_EX_IRQ_RESET BIT(14)
83#define ME4000_AI_CTRL_LE_IRQ BIT(15)
84#define ME4000_AI_CTRL_LE_IRQ_RESET BIT(16)
85#define ME4000_AI_CTRL_HF_IRQ BIT(17)
86#define ME4000_AI_CTRL_HF_IRQ_RESET BIT(18)
87#define ME4000_AI_CTRL_SC_IRQ BIT(19)
88#define ME4000_AI_CTRL_SC_IRQ_RESET BIT(20)
89#define ME4000_AI_CTRL_SC_RELOAD BIT(21)
90#define ME4000_AI_STATUS_EF_CHANNEL BIT(22)
91#define ME4000_AI_STATUS_HF_CHANNEL BIT(23)
92#define ME4000_AI_STATUS_FF_CHANNEL BIT(24)
93#define ME4000_AI_STATUS_EF_DATA BIT(25)
94#define ME4000_AI_STATUS_HF_DATA BIT(26)
95#define ME4000_AI_STATUS_FF_DATA BIT(27)
96#define ME4000_AI_STATUS_LE BIT(28)
97#define ME4000_AI_STATUS_FSM BIT(29)
98#define ME4000_AI_CTRL_EX_TRIG_BOTH BIT(31)
99#define ME4000_AI_CHANNEL_LIST_REG 0x78
100#define ME4000_AI_LIST_INPUT_DIFFERENTIAL BIT(5)
101#define ME4000_AI_LIST_RANGE(x) ((3 - ((x) & 3)) << 6)
102#define ME4000_AI_LIST_LAST_ENTRY BIT(8)
103#define ME4000_AI_DATA_REG 0x7c
104#define ME4000_AI_CHAN_TIMER_REG 0x80
105#define ME4000_AI_CHAN_PRE_TIMER_REG 0x84
106#define ME4000_AI_SCAN_TIMER_LOW_REG 0x88
107#define ME4000_AI_SCAN_TIMER_HIGH_REG 0x8c
108#define ME4000_AI_SCAN_PRE_TIMER_LOW_REG 0x90
109#define ME4000_AI_SCAN_PRE_TIMER_HIGH_REG 0x94
110#define ME4000_AI_START_REG 0x98
111#define ME4000_IRQ_STATUS_REG 0x9c
112#define ME4000_IRQ_STATUS_EX BIT(0)
113#define ME4000_IRQ_STATUS_LE BIT(1)
114#define ME4000_IRQ_STATUS_AI_HF BIT(2)
115#define ME4000_IRQ_STATUS_AO_0_HF BIT(3)
116#define ME4000_IRQ_STATUS_AO_1_HF BIT(4)
117#define ME4000_IRQ_STATUS_AO_2_HF BIT(5)
118#define ME4000_IRQ_STATUS_AO_3_HF BIT(6)
119#define ME4000_IRQ_STATUS_SC BIT(7)
120#define ME4000_DIO_PORT_0_REG 0xa0
121#define ME4000_DIO_PORT_1_REG 0xa4
122#define ME4000_DIO_PORT_2_REG 0xa8
123#define ME4000_DIO_PORT_3_REG 0xac
124#define ME4000_DIO_DIR_REG 0xb0
125#define ME4000_AO_LOADSETREG_XX 0xb4
126#define ME4000_DIO_CTRL_REG 0xb8
127#define ME4000_DIO_CTRL_MODE_0 BIT(0)
128#define ME4000_DIO_CTRL_MODE_1 BIT(1)
129#define ME4000_DIO_CTRL_MODE_2 BIT(2)
130#define ME4000_DIO_CTRL_MODE_3 BIT(3)
131#define ME4000_DIO_CTRL_MODE_4 BIT(4)
132#define ME4000_DIO_CTRL_MODE_5 BIT(5)
133#define ME4000_DIO_CTRL_MODE_6 BIT(6)
134#define ME4000_DIO_CTRL_MODE_7 BIT(7)
135#define ME4000_DIO_CTRL_FUNCTION_0 BIT(8)
136#define ME4000_DIO_CTRL_FUNCTION_1 BIT(9)
137#define ME4000_DIO_CTRL_FIFO_HIGH_0 BIT(10)
138#define ME4000_DIO_CTRL_FIFO_HIGH_1 BIT(11)
139#define ME4000_DIO_CTRL_FIFO_HIGH_2 BIT(12)
140#define ME4000_DIO_CTRL_FIFO_HIGH_3 BIT(13)
141#define ME4000_AO_DEMUX_ADJUST_REG 0xbc
142#define ME4000_AO_DEMUX_ADJUST_VALUE 0x4c
143#define ME4000_AI_SAMPLE_COUNTER_REG 0xc0
144
145#define ME4000_AI_FIFO_COUNT 2048
146
147#define ME4000_AI_MIN_TICKS 66
148#define ME4000_AI_MIN_SAMPLE_TIME 2000
149
150#define ME4000_AI_CHANNEL_LIST_COUNT 1024
151
152struct me4000_private {
153 unsigned long plx_regbase;
154 unsigned int ai_ctrl_mode;
155 unsigned int ai_init_ticks;
156 unsigned int ai_scan_ticks;
157 unsigned int ai_chan_ticks;
158};
159
160enum me4000_boardid {
161 BOARD_ME4650,
162 BOARD_ME4660,
163 BOARD_ME4660I,
164 BOARD_ME4660S,
165 BOARD_ME4660IS,
166 BOARD_ME4670,
167 BOARD_ME4670I,
168 BOARD_ME4670S,
169 BOARD_ME4670IS,
170 BOARD_ME4680,
171 BOARD_ME4680I,
172 BOARD_ME4680S,
173 BOARD_ME4680IS,
174};
175
176struct me4000_board {
177 const char *name;
178 int ai_nchan;
179 unsigned int can_do_diff_ai:1;
180 unsigned int can_do_sh_ai:1; /* sample & hold (8 channels) */
181 unsigned int ex_trig_analog:1;
182 unsigned int has_ao:1;
183 unsigned int has_ao_fifo:1;
184 unsigned int has_counter:1;
185};
186
187static const struct me4000_board me4000_boards[] = {
188 [BOARD_ME4650] = {
189 .name = "ME-4650",
190 .ai_nchan = 16,
191 },
192 [BOARD_ME4660] = {
193 .name = "ME-4660",
194 .ai_nchan = 32,
195 .can_do_diff_ai = 1,
196 .has_counter = 1,
197 },
198 [BOARD_ME4660I] = {
199 .name = "ME-4660i",
200 .ai_nchan = 32,
201 .can_do_diff_ai = 1,
202 .has_counter = 1,
203 },
204 [BOARD_ME4660S] = {
205 .name = "ME-4660s",
206 .ai_nchan = 32,
207 .can_do_diff_ai = 1,
208 .can_do_sh_ai = 1,
209 .has_counter = 1,
210 },
211 [BOARD_ME4660IS] = {
212 .name = "ME-4660is",
213 .ai_nchan = 32,
214 .can_do_diff_ai = 1,
215 .can_do_sh_ai = 1,
216 .has_counter = 1,
217 },
218 [BOARD_ME4670] = {
219 .name = "ME-4670",
220 .ai_nchan = 32,
221 .can_do_diff_ai = 1,
222 .ex_trig_analog = 1,
223 .has_ao = 1,
224 .has_counter = 1,
225 },
226 [BOARD_ME4670I] = {
227 .name = "ME-4670i",
228 .ai_nchan = 32,
229 .can_do_diff_ai = 1,
230 .ex_trig_analog = 1,
231 .has_ao = 1,
232 .has_counter = 1,
233 },
234 [BOARD_ME4670S] = {
235 .name = "ME-4670s",
236 .ai_nchan = 32,
237 .can_do_diff_ai = 1,
238 .can_do_sh_ai = 1,
239 .ex_trig_analog = 1,
240 .has_ao = 1,
241 .has_counter = 1,
242 },
243 [BOARD_ME4670IS] = {
244 .name = "ME-4670is",
245 .ai_nchan = 32,
246 .can_do_diff_ai = 1,
247 .can_do_sh_ai = 1,
248 .ex_trig_analog = 1,
249 .has_ao = 1,
250 .has_counter = 1,
251 },
252 [BOARD_ME4680] = {
253 .name = "ME-4680",
254 .ai_nchan = 32,
255 .can_do_diff_ai = 1,
256 .ex_trig_analog = 1,
257 .has_ao = 1,
258 .has_ao_fifo = 1,
259 .has_counter = 1,
260 },
261 [BOARD_ME4680I] = {
262 .name = "ME-4680i",
263 .ai_nchan = 32,
264 .can_do_diff_ai = 1,
265 .ex_trig_analog = 1,
266 .has_ao = 1,
267 .has_ao_fifo = 1,
268 .has_counter = 1,
269 },
270 [BOARD_ME4680S] = {
271 .name = "ME-4680s",
272 .ai_nchan = 32,
273 .can_do_diff_ai = 1,
274 .can_do_sh_ai = 1,
275 .ex_trig_analog = 1,
276 .has_ao = 1,
277 .has_ao_fifo = 1,
278 .has_counter = 1,
279 },
280 [BOARD_ME4680IS] = {
281 .name = "ME-4680is",
282 .ai_nchan = 32,
283 .can_do_diff_ai = 1,
284 .can_do_sh_ai = 1,
285 .ex_trig_analog = 1,
286 .has_ao = 1,
287 .has_ao_fifo = 1,
288 .has_counter = 1,
289 },
290};
291
292/*
293 * NOTE: the ranges here are inverted compared to the values
294 * written to the ME4000_AI_CHANNEL_LIST_REG,
295 *
296 * The ME4000_AI_LIST_RANGE() macro handles the inversion.
297 */
298static const struct comedi_lrange me4000_ai_range = {
299 4, {
300 UNI_RANGE(2.5),
301 UNI_RANGE(10),
302 BIP_RANGE(2.5),
303 BIP_RANGE(10)
304 }
305};
306
307static int me4000_xilinx_download(struct comedi_device *dev,
308 const u8 *data, size_t size,
309 unsigned long context)
310{
311 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
312 struct me4000_private *devpriv = dev->private;
313 unsigned long xilinx_iobase = pci_resource_start(pcidev, 5);
314 unsigned int file_length;
315 unsigned int val;
316 unsigned int i;
317
318 if (!xilinx_iobase)
319 return -ENODEV;
320
321 /*
322 * Set PLX local interrupt 2 polarity to high.
323 * Interrupt is thrown by init pin of xilinx.
324 */
325 outl(PLX9052_INTCSR_LI2POL, port: devpriv->plx_regbase + PLX9052_INTCSR);
326
327 /* Set /CS and /WRITE of the Xilinx */
328 val = inl(port: devpriv->plx_regbase + PLX9052_CNTRL);
329 val |= PLX9052_CNTRL_UIO2_DATA;
330 outl(value: val, port: devpriv->plx_regbase + PLX9052_CNTRL);
331
332 /* Init Xilinx with CS1 */
333 inb(port: xilinx_iobase + 0xC8);
334
335 /* Wait until /INIT pin is set */
336 usleep_range(min: 20, max: 1000);
337 val = inl(port: devpriv->plx_regbase + PLX9052_INTCSR);
338 if (!(val & PLX9052_INTCSR_LI2STAT)) {
339 dev_err(dev->class_dev, "Can't init Xilinx\n");
340 return -EIO;
341 }
342
343 /* Reset /CS and /WRITE of the Xilinx */
344 val = inl(port: devpriv->plx_regbase + PLX9052_CNTRL);
345 val &= ~PLX9052_CNTRL_UIO2_DATA;
346 outl(value: val, port: devpriv->plx_regbase + PLX9052_CNTRL);
347
348 /* Download Xilinx firmware */
349 file_length = (((unsigned int)data[0] & 0xff) << 24) +
350 (((unsigned int)data[1] & 0xff) << 16) +
351 (((unsigned int)data[2] & 0xff) << 8) +
352 ((unsigned int)data[3] & 0xff);
353 usleep_range(min: 10, max: 1000);
354
355 for (i = 0; i < file_length; i++) {
356 outb(value: data[16 + i], port: xilinx_iobase);
357 usleep_range(min: 10, max: 1000);
358
359 /* Check if BUSY flag is low */
360 val = inl(port: devpriv->plx_regbase + PLX9052_CNTRL);
361 if (val & PLX9052_CNTRL_UIO1_DATA) {
362 dev_err(dev->class_dev,
363 "Xilinx is still busy (i = %d)\n", i);
364 return -EIO;
365 }
366 }
367
368 /* If done flag is high download was successful */
369 val = inl(port: devpriv->plx_regbase + PLX9052_CNTRL);
370 if (!(val & PLX9052_CNTRL_UIO0_DATA)) {
371 dev_err(dev->class_dev, "DONE flag is not set\n");
372 dev_err(dev->class_dev, "Download not successful\n");
373 return -EIO;
374 }
375
376 /* Set /CS and /WRITE */
377 val = inl(port: devpriv->plx_regbase + PLX9052_CNTRL);
378 val |= PLX9052_CNTRL_UIO2_DATA;
379 outl(value: val, port: devpriv->plx_regbase + PLX9052_CNTRL);
380
381 return 0;
382}
383
384static void me4000_ai_reset(struct comedi_device *dev)
385{
386 unsigned int ctrl;
387
388 /* Stop any running conversion */
389 ctrl = inl(port: dev->iobase + ME4000_AI_CTRL_REG);
390 ctrl |= ME4000_AI_CTRL_STOP | ME4000_AI_CTRL_IMMEDIATE_STOP;
391 outl(value: ctrl, port: dev->iobase + ME4000_AI_CTRL_REG);
392
393 /* Clear the control register */
394 outl(value: 0x0, port: dev->iobase + ME4000_AI_CTRL_REG);
395}
396
397static void me4000_reset(struct comedi_device *dev)
398{
399 struct me4000_private *devpriv = dev->private;
400 unsigned int val;
401 int chan;
402
403 /* Disable interrupts on the PLX */
404 outl(value: 0, port: devpriv->plx_regbase + PLX9052_INTCSR);
405
406 /* Software reset the PLX */
407 val = inl(port: devpriv->plx_regbase + PLX9052_CNTRL);
408 val |= PLX9052_CNTRL_PCI_RESET;
409 outl(value: val, port: devpriv->plx_regbase + PLX9052_CNTRL);
410 val &= ~PLX9052_CNTRL_PCI_RESET;
411 outl(value: val, port: devpriv->plx_regbase + PLX9052_CNTRL);
412
413 /* 0x8000 to the DACs means an output voltage of 0V */
414 for (chan = 0; chan < 4; chan++)
415 outl(value: 0x8000, port: dev->iobase + ME4000_AO_SINGLE_REG(chan));
416
417 me4000_ai_reset(dev);
418
419 /* Set both stop bits in the analog output control register */
420 val = ME4000_AO_CTRL_IMMEDIATE_STOP | ME4000_AO_CTRL_STOP;
421 for (chan = 0; chan < 4; chan++)
422 outl(value: val, port: dev->iobase + ME4000_AO_CTRL_REG(chan));
423
424 /* Set the adustment register for AO demux */
425 outl(ME4000_AO_DEMUX_ADJUST_VALUE,
426 port: dev->iobase + ME4000_AO_DEMUX_ADJUST_REG);
427
428 /*
429 * Set digital I/O direction for port 0
430 * to output on isolated versions
431 */
432 if (!(inl(port: dev->iobase + ME4000_DIO_DIR_REG) & 0x1))
433 outl(value: 0x1, port: dev->iobase + ME4000_DIO_CTRL_REG);
434}
435
436static unsigned int me4000_ai_get_sample(struct comedi_device *dev,
437 struct comedi_subdevice *s)
438{
439 unsigned int val;
440
441 /* read two's complement value and munge to offset binary */
442 val = inl(port: dev->iobase + ME4000_AI_DATA_REG);
443 return comedi_offset_munge(s, val);
444}
445
446static int me4000_ai_eoc(struct comedi_device *dev,
447 struct comedi_subdevice *s,
448 struct comedi_insn *insn,
449 unsigned long context)
450{
451 unsigned int status;
452
453 status = inl(port: dev->iobase + ME4000_AI_STATUS_REG);
454 if (status & ME4000_AI_STATUS_EF_DATA)
455 return 0;
456 return -EBUSY;
457}
458
459static int me4000_ai_insn_read(struct comedi_device *dev,
460 struct comedi_subdevice *s,
461 struct comedi_insn *insn,
462 unsigned int *data)
463{
464 unsigned int chan = CR_CHAN(insn->chanspec);
465 unsigned int range = CR_RANGE(insn->chanspec);
466 unsigned int aref = CR_AREF(insn->chanspec);
467 unsigned int entry;
468 int ret = 0;
469 int i;
470
471 entry = chan | ME4000_AI_LIST_RANGE(range);
472 if (aref == AREF_DIFF) {
473 if (!(s->subdev_flags & SDF_DIFF)) {
474 dev_err(dev->class_dev,
475 "Differential inputs are not available\n");
476 return -EINVAL;
477 }
478
479 if (!comedi_range_is_bipolar(s, range)) {
480 dev_err(dev->class_dev,
481 "Range must be bipolar when aref = diff\n");
482 return -EINVAL;
483 }
484
485 if (chan >= (s->n_chan / 2)) {
486 dev_err(dev->class_dev,
487 "Analog input is not available\n");
488 return -EINVAL;
489 }
490 entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL;
491 }
492
493 entry |= ME4000_AI_LIST_LAST_ENTRY;
494
495 /* Enable channel list and data fifo for single acquisition mode */
496 outl(ME4000_AI_CTRL_CHANNEL_FIFO | ME4000_AI_CTRL_DATA_FIFO,
497 port: dev->iobase + ME4000_AI_CTRL_REG);
498
499 /* Generate channel list entry */
500 outl(value: entry, port: dev->iobase + ME4000_AI_CHANNEL_LIST_REG);
501
502 /* Set the timer to maximum sample rate */
503 outl(ME4000_AI_MIN_TICKS, port: dev->iobase + ME4000_AI_CHAN_TIMER_REG);
504 outl(ME4000_AI_MIN_TICKS, port: dev->iobase + ME4000_AI_CHAN_PRE_TIMER_REG);
505
506 for (i = 0; i < insn->n; i++) {
507 unsigned int val;
508
509 /* start conversion by dummy read */
510 inl(port: dev->iobase + ME4000_AI_START_REG);
511
512 ret = comedi_timeout(dev, s, insn, cb: me4000_ai_eoc, context: 0);
513 if (ret)
514 break;
515
516 val = me4000_ai_get_sample(dev, s);
517 data[i] = comedi_offset_munge(s, val);
518 }
519
520 me4000_ai_reset(dev);
521
522 return ret ? ret : insn->n;
523}
524
525static int me4000_ai_cancel(struct comedi_device *dev,
526 struct comedi_subdevice *s)
527{
528 me4000_ai_reset(dev);
529
530 return 0;
531}
532
533static int me4000_ai_check_chanlist(struct comedi_device *dev,
534 struct comedi_subdevice *s,
535 struct comedi_cmd *cmd)
536{
537 unsigned int aref0 = CR_AREF(cmd->chanlist[0]);
538 int i;
539
540 for (i = 0; i < cmd->chanlist_len; i++) {
541 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
542 unsigned int range = CR_RANGE(cmd->chanlist[i]);
543 unsigned int aref = CR_AREF(cmd->chanlist[i]);
544
545 if (aref != aref0) {
546 dev_dbg(dev->class_dev,
547 "Mode is not equal for all entries\n");
548 return -EINVAL;
549 }
550
551 if (aref == AREF_DIFF) {
552 if (!(s->subdev_flags & SDF_DIFF)) {
553 dev_err(dev->class_dev,
554 "Differential inputs are not available\n");
555 return -EINVAL;
556 }
557
558 if (chan >= (s->n_chan / 2)) {
559 dev_dbg(dev->class_dev,
560 "Channel number to high\n");
561 return -EINVAL;
562 }
563
564 if (!comedi_range_is_bipolar(s, range)) {
565 dev_dbg(dev->class_dev,
566 "Bipolar is not selected in differential mode\n");
567 return -EINVAL;
568 }
569 }
570 }
571
572 return 0;
573}
574
575static void me4000_ai_round_cmd_args(struct comedi_device *dev,
576 struct comedi_subdevice *s,
577 struct comedi_cmd *cmd)
578{
579 struct me4000_private *devpriv = dev->private;
580 int rest;
581
582 devpriv->ai_init_ticks = 0;
583 devpriv->ai_scan_ticks = 0;
584 devpriv->ai_chan_ticks = 0;
585
586 if (cmd->start_arg) {
587 devpriv->ai_init_ticks = (cmd->start_arg * 33) / 1000;
588 rest = (cmd->start_arg * 33) % 1000;
589
590 if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_NEAREST) {
591 if (rest > 33)
592 devpriv->ai_init_ticks++;
593 } else if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_UP) {
594 if (rest)
595 devpriv->ai_init_ticks++;
596 }
597 }
598
599 if (cmd->scan_begin_arg) {
600 devpriv->ai_scan_ticks = (cmd->scan_begin_arg * 33) / 1000;
601 rest = (cmd->scan_begin_arg * 33) % 1000;
602
603 if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_NEAREST) {
604 if (rest > 33)
605 devpriv->ai_scan_ticks++;
606 } else if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_UP) {
607 if (rest)
608 devpriv->ai_scan_ticks++;
609 }
610 }
611
612 if (cmd->convert_arg) {
613 devpriv->ai_chan_ticks = (cmd->convert_arg * 33) / 1000;
614 rest = (cmd->convert_arg * 33) % 1000;
615
616 if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_NEAREST) {
617 if (rest > 33)
618 devpriv->ai_chan_ticks++;
619 } else if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_UP) {
620 if (rest)
621 devpriv->ai_chan_ticks++;
622 }
623 }
624}
625
626static void me4000_ai_write_chanlist(struct comedi_device *dev,
627 struct comedi_subdevice *s,
628 struct comedi_cmd *cmd)
629{
630 int i;
631
632 for (i = 0; i < cmd->chanlist_len; i++) {
633 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
634 unsigned int range = CR_RANGE(cmd->chanlist[i]);
635 unsigned int aref = CR_AREF(cmd->chanlist[i]);
636 unsigned int entry;
637
638 entry = chan | ME4000_AI_LIST_RANGE(range);
639
640 if (aref == AREF_DIFF)
641 entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL;
642
643 if (i == (cmd->chanlist_len - 1))
644 entry |= ME4000_AI_LIST_LAST_ENTRY;
645
646 outl(value: entry, port: dev->iobase + ME4000_AI_CHANNEL_LIST_REG);
647 }
648}
649
650static int me4000_ai_do_cmd(struct comedi_device *dev,
651 struct comedi_subdevice *s)
652{
653 struct me4000_private *devpriv = dev->private;
654 struct comedi_cmd *cmd = &s->async->cmd;
655 unsigned int ctrl;
656
657 /* Write timer arguments */
658 outl(value: devpriv->ai_init_ticks - 1,
659 port: dev->iobase + ME4000_AI_SCAN_PRE_TIMER_LOW_REG);
660 outl(value: 0x0, port: dev->iobase + ME4000_AI_SCAN_PRE_TIMER_HIGH_REG);
661
662 if (devpriv->ai_scan_ticks) {
663 outl(value: devpriv->ai_scan_ticks - 1,
664 port: dev->iobase + ME4000_AI_SCAN_TIMER_LOW_REG);
665 outl(value: 0x0, port: dev->iobase + ME4000_AI_SCAN_TIMER_HIGH_REG);
666 }
667
668 outl(value: devpriv->ai_chan_ticks - 1,
669 port: dev->iobase + ME4000_AI_CHAN_PRE_TIMER_REG);
670 outl(value: devpriv->ai_chan_ticks - 1,
671 port: dev->iobase + ME4000_AI_CHAN_TIMER_REG);
672
673 /* Start sources */
674 ctrl = devpriv->ai_ctrl_mode |
675 ME4000_AI_CTRL_CHANNEL_FIFO |
676 ME4000_AI_CTRL_DATA_FIFO;
677
678 /* Stop triggers */
679 if (cmd->stop_src == TRIG_COUNT) {
680 outl(value: cmd->chanlist_len * cmd->stop_arg,
681 port: dev->iobase + ME4000_AI_SAMPLE_COUNTER_REG);
682 ctrl |= ME4000_AI_CTRL_SC_IRQ;
683 } else if (cmd->stop_src == TRIG_NONE &&
684 cmd->scan_end_src == TRIG_COUNT) {
685 outl(value: cmd->scan_end_arg,
686 port: dev->iobase + ME4000_AI_SAMPLE_COUNTER_REG);
687 ctrl |= ME4000_AI_CTRL_SC_IRQ;
688 }
689 ctrl |= ME4000_AI_CTRL_HF_IRQ;
690
691 /* Write the setup to the control register */
692 outl(value: ctrl, port: dev->iobase + ME4000_AI_CTRL_REG);
693
694 /* Write the channel list */
695 me4000_ai_write_chanlist(dev, s, cmd);
696
697 /* Start acquistion by dummy read */
698 inl(port: dev->iobase + ME4000_AI_START_REG);
699
700 return 0;
701}
702
703static int me4000_ai_do_cmd_test(struct comedi_device *dev,
704 struct comedi_subdevice *s,
705 struct comedi_cmd *cmd)
706{
707 struct me4000_private *devpriv = dev->private;
708 int err = 0;
709
710 /* Step 1 : check if triggers are trivially valid */
711
712 err |= comedi_check_trigger_src(src: &cmd->start_src, TRIG_NOW | TRIG_EXT);
713 err |= comedi_check_trigger_src(src: &cmd->scan_begin_src,
714 TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT);
715 err |= comedi_check_trigger_src(src: &cmd->convert_src,
716 TRIG_TIMER | TRIG_EXT);
717 err |= comedi_check_trigger_src(src: &cmd->scan_end_src,
718 TRIG_NONE | TRIG_COUNT);
719 err |= comedi_check_trigger_src(src: &cmd->stop_src, TRIG_NONE | TRIG_COUNT);
720
721 if (err)
722 return 1;
723
724 /* Step 2a : make sure trigger sources are unique */
725
726 err |= comedi_check_trigger_is_unique(src: cmd->start_src);
727 err |= comedi_check_trigger_is_unique(src: cmd->scan_begin_src);
728 err |= comedi_check_trigger_is_unique(src: cmd->convert_src);
729 err |= comedi_check_trigger_is_unique(src: cmd->scan_end_src);
730 err |= comedi_check_trigger_is_unique(src: cmd->stop_src);
731
732 /* Step 2b : and mutually compatible */
733
734 if (cmd->start_src == TRIG_NOW &&
735 cmd->scan_begin_src == TRIG_TIMER &&
736 cmd->convert_src == TRIG_TIMER) {
737 devpriv->ai_ctrl_mode = ME4000_AI_CTRL_MODE_0;
738 } else if (cmd->start_src == TRIG_NOW &&
739 cmd->scan_begin_src == TRIG_FOLLOW &&
740 cmd->convert_src == TRIG_TIMER) {
741 devpriv->ai_ctrl_mode = ME4000_AI_CTRL_MODE_0;
742 } else if (cmd->start_src == TRIG_EXT &&
743 cmd->scan_begin_src == TRIG_TIMER &&
744 cmd->convert_src == TRIG_TIMER) {
745 devpriv->ai_ctrl_mode = ME4000_AI_CTRL_MODE_1;
746 } else if (cmd->start_src == TRIG_EXT &&
747 cmd->scan_begin_src == TRIG_FOLLOW &&
748 cmd->convert_src == TRIG_TIMER) {
749 devpriv->ai_ctrl_mode = ME4000_AI_CTRL_MODE_1;
750 } else if (cmd->start_src == TRIG_EXT &&
751 cmd->scan_begin_src == TRIG_EXT &&
752 cmd->convert_src == TRIG_TIMER) {
753 devpriv->ai_ctrl_mode = ME4000_AI_CTRL_MODE_2;
754 } else if (cmd->start_src == TRIG_EXT &&
755 cmd->scan_begin_src == TRIG_EXT &&
756 cmd->convert_src == TRIG_EXT) {
757 devpriv->ai_ctrl_mode = ME4000_AI_CTRL_MODE_0 |
758 ME4000_AI_CTRL_MODE_1;
759 } else {
760 err |= -EINVAL;
761 }
762
763 if (err)
764 return 2;
765
766 /* Step 3: check if arguments are trivially valid */
767
768 err |= comedi_check_trigger_arg_is(arg: &cmd->start_arg, val: 0);
769
770 if (cmd->chanlist_len < 1) {
771 cmd->chanlist_len = 1;
772 err |= -EINVAL;
773 }
774
775 /* Round the timer arguments */
776 me4000_ai_round_cmd_args(dev, s, cmd);
777
778 if (devpriv->ai_init_ticks < 66) {
779 cmd->start_arg = 2000;
780 err |= -EINVAL;
781 }
782 if (devpriv->ai_scan_ticks && devpriv->ai_scan_ticks < 67) {
783 cmd->scan_begin_arg = 2031;
784 err |= -EINVAL;
785 }
786 if (devpriv->ai_chan_ticks < 66) {
787 cmd->convert_arg = 2000;
788 err |= -EINVAL;
789 }
790
791 if (cmd->stop_src == TRIG_COUNT)
792 err |= comedi_check_trigger_arg_min(arg: &cmd->stop_arg, val: 1);
793 else /* TRIG_NONE */
794 err |= comedi_check_trigger_arg_is(arg: &cmd->stop_arg, val: 0);
795
796 if (err)
797 return 3;
798
799 /*
800 * Stage 4. Check for argument conflicts.
801 */
802 if (cmd->start_src == TRIG_NOW &&
803 cmd->scan_begin_src == TRIG_TIMER &&
804 cmd->convert_src == TRIG_TIMER) {
805 /* Check timer arguments */
806 if (devpriv->ai_init_ticks < ME4000_AI_MIN_TICKS) {
807 dev_err(dev->class_dev, "Invalid start arg\n");
808 cmd->start_arg = 2000; /* 66 ticks at least */
809 err++;
810 }
811 if (devpriv->ai_chan_ticks < ME4000_AI_MIN_TICKS) {
812 dev_err(dev->class_dev, "Invalid convert arg\n");
813 cmd->convert_arg = 2000; /* 66 ticks at least */
814 err++;
815 }
816 if (devpriv->ai_scan_ticks <=
817 cmd->chanlist_len * devpriv->ai_chan_ticks) {
818 dev_err(dev->class_dev, "Invalid scan end arg\n");
819
820 /* At least one tick more */
821 cmd->scan_end_arg = 2000 * cmd->chanlist_len + 31;
822 err++;
823 }
824 } else if (cmd->start_src == TRIG_NOW &&
825 cmd->scan_begin_src == TRIG_FOLLOW &&
826 cmd->convert_src == TRIG_TIMER) {
827 /* Check timer arguments */
828 if (devpriv->ai_init_ticks < ME4000_AI_MIN_TICKS) {
829 dev_err(dev->class_dev, "Invalid start arg\n");
830 cmd->start_arg = 2000; /* 66 ticks at least */
831 err++;
832 }
833 if (devpriv->ai_chan_ticks < ME4000_AI_MIN_TICKS) {
834 dev_err(dev->class_dev, "Invalid convert arg\n");
835 cmd->convert_arg = 2000; /* 66 ticks at least */
836 err++;
837 }
838 } else if (cmd->start_src == TRIG_EXT &&
839 cmd->scan_begin_src == TRIG_TIMER &&
840 cmd->convert_src == TRIG_TIMER) {
841 /* Check timer arguments */
842 if (devpriv->ai_init_ticks < ME4000_AI_MIN_TICKS) {
843 dev_err(dev->class_dev, "Invalid start arg\n");
844 cmd->start_arg = 2000; /* 66 ticks at least */
845 err++;
846 }
847 if (devpriv->ai_chan_ticks < ME4000_AI_MIN_TICKS) {
848 dev_err(dev->class_dev, "Invalid convert arg\n");
849 cmd->convert_arg = 2000; /* 66 ticks at least */
850 err++;
851 }
852 if (devpriv->ai_scan_ticks <=
853 cmd->chanlist_len * devpriv->ai_chan_ticks) {
854 dev_err(dev->class_dev, "Invalid scan end arg\n");
855
856 /* At least one tick more */
857 cmd->scan_end_arg = 2000 * cmd->chanlist_len + 31;
858 err++;
859 }
860 } else if (cmd->start_src == TRIG_EXT &&
861 cmd->scan_begin_src == TRIG_FOLLOW &&
862 cmd->convert_src == TRIG_TIMER) {
863 /* Check timer arguments */
864 if (devpriv->ai_init_ticks < ME4000_AI_MIN_TICKS) {
865 dev_err(dev->class_dev, "Invalid start arg\n");
866 cmd->start_arg = 2000; /* 66 ticks at least */
867 err++;
868 }
869 if (devpriv->ai_chan_ticks < ME4000_AI_MIN_TICKS) {
870 dev_err(dev->class_dev, "Invalid convert arg\n");
871 cmd->convert_arg = 2000; /* 66 ticks at least */
872 err++;
873 }
874 } else if (cmd->start_src == TRIG_EXT &&
875 cmd->scan_begin_src == TRIG_EXT &&
876 cmd->convert_src == TRIG_TIMER) {
877 /* Check timer arguments */
878 if (devpriv->ai_init_ticks < ME4000_AI_MIN_TICKS) {
879 dev_err(dev->class_dev, "Invalid start arg\n");
880 cmd->start_arg = 2000; /* 66 ticks at least */
881 err++;
882 }
883 if (devpriv->ai_chan_ticks < ME4000_AI_MIN_TICKS) {
884 dev_err(dev->class_dev, "Invalid convert arg\n");
885 cmd->convert_arg = 2000; /* 66 ticks at least */
886 err++;
887 }
888 } else if (cmd->start_src == TRIG_EXT &&
889 cmd->scan_begin_src == TRIG_EXT &&
890 cmd->convert_src == TRIG_EXT) {
891 /* Check timer arguments */
892 if (devpriv->ai_init_ticks < ME4000_AI_MIN_TICKS) {
893 dev_err(dev->class_dev, "Invalid start arg\n");
894 cmd->start_arg = 2000; /* 66 ticks at least */
895 err++;
896 }
897 }
898 if (cmd->scan_end_src == TRIG_COUNT) {
899 if (cmd->scan_end_arg == 0) {
900 dev_err(dev->class_dev, "Invalid scan end arg\n");
901 cmd->scan_end_arg = 1;
902 err++;
903 }
904 }
905
906 if (err)
907 return 4;
908
909 /* Step 5: check channel list if it exists */
910 if (cmd->chanlist && cmd->chanlist_len > 0)
911 err |= me4000_ai_check_chanlist(dev, s, cmd);
912
913 if (err)
914 return 5;
915
916 return 0;
917}
918
919static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
920{
921 unsigned int tmp;
922 struct comedi_device *dev = dev_id;
923 struct comedi_subdevice *s = dev->read_subdev;
924 int i;
925 int c = 0;
926 unsigned short lval;
927
928 if (!dev->attached)
929 return IRQ_NONE;
930
931 if (inl(port: dev->iobase + ME4000_IRQ_STATUS_REG) &
932 ME4000_IRQ_STATUS_AI_HF) {
933 /* Read status register to find out what happened */
934 tmp = inl(port: dev->iobase + ME4000_AI_STATUS_REG);
935
936 if (!(tmp & ME4000_AI_STATUS_FF_DATA) &&
937 !(tmp & ME4000_AI_STATUS_HF_DATA) &&
938 (tmp & ME4000_AI_STATUS_EF_DATA)) {
939 dev_err(dev->class_dev, "FIFO overflow\n");
940 s->async->events |= COMEDI_CB_ERROR;
941 c = ME4000_AI_FIFO_COUNT;
942 } else if ((tmp & ME4000_AI_STATUS_FF_DATA) &&
943 !(tmp & ME4000_AI_STATUS_HF_DATA) &&
944 (tmp & ME4000_AI_STATUS_EF_DATA)) {
945 c = ME4000_AI_FIFO_COUNT / 2;
946 } else {
947 dev_err(dev->class_dev, "Undefined FIFO state\n");
948 s->async->events |= COMEDI_CB_ERROR;
949 c = 0;
950 }
951
952 for (i = 0; i < c; i++) {
953 lval = me4000_ai_get_sample(dev, s);
954 if (!comedi_buf_write_samples(s, data: &lval, nsamples: 1))
955 break;
956 }
957
958 /* Work is done, so reset the interrupt */
959 tmp |= ME4000_AI_CTRL_HF_IRQ_RESET;
960 outl(value: tmp, port: dev->iobase + ME4000_AI_CTRL_REG);
961 tmp &= ~ME4000_AI_CTRL_HF_IRQ_RESET;
962 outl(value: tmp, port: dev->iobase + ME4000_AI_CTRL_REG);
963 }
964
965 if (inl(port: dev->iobase + ME4000_IRQ_STATUS_REG) &
966 ME4000_IRQ_STATUS_SC) {
967 /* Acquisition is complete */
968 s->async->events |= COMEDI_CB_EOA;
969
970 /* Poll data until fifo empty */
971 while (inl(port: dev->iobase + ME4000_AI_STATUS_REG) &
972 ME4000_AI_STATUS_EF_DATA) {
973 lval = me4000_ai_get_sample(dev, s);
974 if (!comedi_buf_write_samples(s, data: &lval, nsamples: 1))
975 break;
976 }
977
978 /* Work is done, so reset the interrupt */
979 tmp = inl(port: dev->iobase + ME4000_AI_CTRL_REG);
980 tmp |= ME4000_AI_CTRL_SC_IRQ_RESET;
981 outl(value: tmp, port: dev->iobase + ME4000_AI_CTRL_REG);
982 tmp &= ~ME4000_AI_CTRL_SC_IRQ_RESET;
983 outl(value: tmp, port: dev->iobase + ME4000_AI_CTRL_REG);
984 }
985
986 comedi_handle_events(dev, s);
987
988 return IRQ_HANDLED;
989}
990
991static int me4000_ao_insn_write(struct comedi_device *dev,
992 struct comedi_subdevice *s,
993 struct comedi_insn *insn,
994 unsigned int *data)
995{
996 unsigned int chan = CR_CHAN(insn->chanspec);
997 unsigned int tmp;
998
999 /* Stop any running conversion */
1000 tmp = inl(port: dev->iobase + ME4000_AO_CTRL_REG(chan));
1001 tmp |= ME4000_AO_CTRL_IMMEDIATE_STOP;
1002 outl(value: tmp, port: dev->iobase + ME4000_AO_CTRL_REG(chan));
1003
1004 /* Clear control register and set to single mode */
1005 outl(value: 0x0, port: dev->iobase + ME4000_AO_CTRL_REG(chan));
1006
1007 /* Write data value */
1008 outl(value: data[0], port: dev->iobase + ME4000_AO_SINGLE_REG(chan));
1009
1010 /* Store in the mirror */
1011 s->readback[chan] = data[0];
1012
1013 return 1;
1014}
1015
1016static int me4000_dio_insn_bits(struct comedi_device *dev,
1017 struct comedi_subdevice *s,
1018 struct comedi_insn *insn,
1019 unsigned int *data)
1020{
1021 if (comedi_dio_update_state(s, data)) {
1022 outl(value: (s->state >> 0) & 0xFF,
1023 port: dev->iobase + ME4000_DIO_PORT_0_REG);
1024 outl(value: (s->state >> 8) & 0xFF,
1025 port: dev->iobase + ME4000_DIO_PORT_1_REG);
1026 outl(value: (s->state >> 16) & 0xFF,
1027 port: dev->iobase + ME4000_DIO_PORT_2_REG);
1028 outl(value: (s->state >> 24) & 0xFF,
1029 port: dev->iobase + ME4000_DIO_PORT_3_REG);
1030 }
1031
1032 data[1] = ((inl(port: dev->iobase + ME4000_DIO_PORT_0_REG) & 0xFF) << 0) |
1033 ((inl(port: dev->iobase + ME4000_DIO_PORT_1_REG) & 0xFF) << 8) |
1034 ((inl(port: dev->iobase + ME4000_DIO_PORT_2_REG) & 0xFF) << 16) |
1035 ((inl(port: dev->iobase + ME4000_DIO_PORT_3_REG) & 0xFF) << 24);
1036
1037 return insn->n;
1038}
1039
1040static int me4000_dio_insn_config(struct comedi_device *dev,
1041 struct comedi_subdevice *s,
1042 struct comedi_insn *insn,
1043 unsigned int *data)
1044{
1045 unsigned int chan = CR_CHAN(insn->chanspec);
1046 unsigned int mask;
1047 unsigned int tmp;
1048 int ret;
1049
1050 if (chan < 8)
1051 mask = 0x000000ff;
1052 else if (chan < 16)
1053 mask = 0x0000ff00;
1054 else if (chan < 24)
1055 mask = 0x00ff0000;
1056 else
1057 mask = 0xff000000;
1058
1059 ret = comedi_dio_insn_config(dev, s, insn, data, mask);
1060 if (ret)
1061 return ret;
1062
1063 tmp = inl(port: dev->iobase + ME4000_DIO_CTRL_REG);
1064 tmp &= ~(ME4000_DIO_CTRL_MODE_0 | ME4000_DIO_CTRL_MODE_1 |
1065 ME4000_DIO_CTRL_MODE_2 | ME4000_DIO_CTRL_MODE_3 |
1066 ME4000_DIO_CTRL_MODE_4 | ME4000_DIO_CTRL_MODE_5 |
1067 ME4000_DIO_CTRL_MODE_6 | ME4000_DIO_CTRL_MODE_7);
1068 if (s->io_bits & 0x000000ff)
1069 tmp |= ME4000_DIO_CTRL_MODE_0;
1070 if (s->io_bits & 0x0000ff00)
1071 tmp |= ME4000_DIO_CTRL_MODE_2;
1072 if (s->io_bits & 0x00ff0000)
1073 tmp |= ME4000_DIO_CTRL_MODE_4;
1074 if (s->io_bits & 0xff000000)
1075 tmp |= ME4000_DIO_CTRL_MODE_6;
1076
1077 /*
1078 * Check for optoisolated ME-4000 version.
1079 * If one the first port is a fixed output
1080 * port and the second is a fixed input port.
1081 */
1082 if (inl(port: dev->iobase + ME4000_DIO_DIR_REG)) {
1083 s->io_bits |= 0x000000ff;
1084 s->io_bits &= ~0x0000ff00;
1085 tmp |= ME4000_DIO_CTRL_MODE_0;
1086 tmp &= ~(ME4000_DIO_CTRL_MODE_2 | ME4000_DIO_CTRL_MODE_3);
1087 }
1088
1089 outl(value: tmp, port: dev->iobase + ME4000_DIO_CTRL_REG);
1090
1091 return insn->n;
1092}
1093
1094static int me4000_auto_attach(struct comedi_device *dev,
1095 unsigned long context)
1096{
1097 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1098 const struct me4000_board *board = NULL;
1099 struct me4000_private *devpriv;
1100 struct comedi_subdevice *s;
1101 int result;
1102
1103 if (context < ARRAY_SIZE(me4000_boards))
1104 board = &me4000_boards[context];
1105 if (!board)
1106 return -ENODEV;
1107 dev->board_ptr = board;
1108 dev->board_name = board->name;
1109
1110 devpriv = comedi_alloc_devpriv(dev, size: sizeof(*devpriv));
1111 if (!devpriv)
1112 return -ENOMEM;
1113
1114 result = comedi_pci_enable(dev);
1115 if (result)
1116 return result;
1117
1118 devpriv->plx_regbase = pci_resource_start(pcidev, 1);
1119 dev->iobase = pci_resource_start(pcidev, 2);
1120 if (!devpriv->plx_regbase || !dev->iobase)
1121 return -ENODEV;
1122
1123 result = comedi_load_firmware(dev, hw_dev: &pcidev->dev, ME4000_FIRMWARE,
1124 cb: me4000_xilinx_download, context: 0);
1125 if (result < 0)
1126 return result;
1127
1128 me4000_reset(dev);
1129
1130 if (pcidev->irq > 0) {
1131 result = request_irq(irq: pcidev->irq, handler: me4000_ai_isr, IRQF_SHARED,
1132 name: dev->board_name, dev);
1133 if (result == 0) {
1134 dev->irq = pcidev->irq;
1135
1136 /* Enable interrupts on the PLX */
1137 outl(PLX9052_INTCSR_LI1ENAB | PLX9052_INTCSR_LI1POL |
1138 PLX9052_INTCSR_PCIENAB,
1139 port: devpriv->plx_regbase + PLX9052_INTCSR);
1140 }
1141 }
1142
1143 result = comedi_alloc_subdevices(dev, num_subdevices: 4);
1144 if (result)
1145 return result;
1146
1147 /* Analog Input subdevice */
1148 s = &dev->subdevices[0];
1149 s->type = COMEDI_SUBD_AI;
1150 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
1151 if (board->can_do_diff_ai)
1152 s->subdev_flags |= SDF_DIFF;
1153 s->n_chan = board->ai_nchan;
1154 s->maxdata = 0xffff;
1155 s->len_chanlist = ME4000_AI_CHANNEL_LIST_COUNT;
1156 s->range_table = &me4000_ai_range;
1157 s->insn_read = me4000_ai_insn_read;
1158
1159 if (dev->irq) {
1160 dev->read_subdev = s;
1161 s->subdev_flags |= SDF_CMD_READ;
1162 s->cancel = me4000_ai_cancel;
1163 s->do_cmdtest = me4000_ai_do_cmd_test;
1164 s->do_cmd = me4000_ai_do_cmd;
1165 }
1166
1167 /* Analog Output subdevice */
1168 s = &dev->subdevices[1];
1169 if (board->has_ao) {
1170 s->type = COMEDI_SUBD_AO;
1171 s->subdev_flags = SDF_WRITABLE | SDF_COMMON | SDF_GROUND;
1172 s->n_chan = 4;
1173 s->maxdata = 0xffff;
1174 s->range_table = &range_bipolar10;
1175 s->insn_write = me4000_ao_insn_write;
1176
1177 result = comedi_alloc_subdev_readback(s);
1178 if (result)
1179 return result;
1180 } else {
1181 s->type = COMEDI_SUBD_UNUSED;
1182 }
1183
1184 /* Digital I/O subdevice */
1185 s = &dev->subdevices[2];
1186 s->type = COMEDI_SUBD_DIO;
1187 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1188 s->n_chan = 32;
1189 s->maxdata = 1;
1190 s->range_table = &range_digital;
1191 s->insn_bits = me4000_dio_insn_bits;
1192 s->insn_config = me4000_dio_insn_config;
1193
1194 /*
1195 * Check for optoisolated ME-4000 version. If one the first
1196 * port is a fixed output port and the second is a fixed input port.
1197 */
1198 if (!inl(port: dev->iobase + ME4000_DIO_DIR_REG)) {
1199 s->io_bits |= 0xFF;
1200 outl(ME4000_DIO_CTRL_MODE_0,
1201 port: dev->iobase + ME4000_DIO_DIR_REG);
1202 }
1203
1204 /* Counter subdevice (8254) */
1205 s = &dev->subdevices[3];
1206 if (board->has_counter) {
1207 unsigned long timer_base = pci_resource_start(pcidev, 3);
1208
1209 if (!timer_base)
1210 return -ENODEV;
1211
1212 dev->pacer = comedi_8254_io_alloc(iobase: timer_base, osc_base: 0, I8254_IO8, regshift: 0);
1213 if (IS_ERR(ptr: dev->pacer))
1214 return PTR_ERR(ptr: dev->pacer);
1215
1216 comedi_8254_subdevice_init(s, i8254: dev->pacer);
1217 } else {
1218 s->type = COMEDI_SUBD_UNUSED;
1219 }
1220
1221 return 0;
1222}
1223
1224static void me4000_detach(struct comedi_device *dev)
1225{
1226 if (dev->irq) {
1227 struct me4000_private *devpriv = dev->private;
1228
1229 /* Disable interrupts on the PLX */
1230 outl(value: 0, port: devpriv->plx_regbase + PLX9052_INTCSR);
1231 }
1232 comedi_pci_detach(dev);
1233}
1234
1235static struct comedi_driver me4000_driver = {
1236 .driver_name = "me4000",
1237 .module = THIS_MODULE,
1238 .auto_attach = me4000_auto_attach,
1239 .detach = me4000_detach,
1240};
1241
1242static int me4000_pci_probe(struct pci_dev *dev,
1243 const struct pci_device_id *id)
1244{
1245 return comedi_pci_auto_config(pcidev: dev, driver: &me4000_driver, context: id->driver_data);
1246}
1247
1248static const struct pci_device_id me4000_pci_table[] = {
1249 { PCI_VDEVICE(MEILHAUS, 0x4650), BOARD_ME4650 },
1250 { PCI_VDEVICE(MEILHAUS, 0x4660), BOARD_ME4660 },
1251 { PCI_VDEVICE(MEILHAUS, 0x4661), BOARD_ME4660I },
1252 { PCI_VDEVICE(MEILHAUS, 0x4662), BOARD_ME4660S },
1253 { PCI_VDEVICE(MEILHAUS, 0x4663), BOARD_ME4660IS },
1254 { PCI_VDEVICE(MEILHAUS, 0x4670), BOARD_ME4670 },
1255 { PCI_VDEVICE(MEILHAUS, 0x4671), BOARD_ME4670I },
1256 { PCI_VDEVICE(MEILHAUS, 0x4672), BOARD_ME4670S },
1257 { PCI_VDEVICE(MEILHAUS, 0x4673), BOARD_ME4670IS },
1258 { PCI_VDEVICE(MEILHAUS, 0x4680), BOARD_ME4680 },
1259 { PCI_VDEVICE(MEILHAUS, 0x4681), BOARD_ME4680I },
1260 { PCI_VDEVICE(MEILHAUS, 0x4682), BOARD_ME4680S },
1261 { PCI_VDEVICE(MEILHAUS, 0x4683), BOARD_ME4680IS },
1262 { 0 }
1263};
1264MODULE_DEVICE_TABLE(pci, me4000_pci_table);
1265
1266static struct pci_driver me4000_pci_driver = {
1267 .name = "me4000",
1268 .id_table = me4000_pci_table,
1269 .probe = me4000_pci_probe,
1270 .remove = comedi_pci_auto_unconfig,
1271};
1272module_comedi_pci_driver(me4000_driver, me4000_pci_driver);
1273
1274MODULE_AUTHOR("Comedi https://www.comedi.org");
1275MODULE_DESCRIPTION("Comedi driver for Meilhaus ME-4000 series boards");
1276MODULE_LICENSE("GPL");
1277MODULE_FIRMWARE(ME4000_FIRMWARE);
1278

source code of linux/drivers/comedi/drivers/me4000.c