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