1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * dt3000.c
4 * Data Translation DT3000 series driver
5 *
6 * COMEDI - Linux Control and Measurement Device Interface
7 * Copyright (C) 1999 David A. Schleef <ds@schleef.org>
8 */
9
10/*
11 * Driver: dt3000
12 * Description: Data Translation DT3000 series
13 * Devices: [Data Translation] DT3001 (dt3000), DT3001-PGL, DT3002, DT3003,
14 *   DT3003-PGL, DT3004, DT3005, DT3004-200
15 * Author: ds
16 * Updated: Mon, 14 Apr 2008 15:41:24 +0100
17 * Status: works
18 *
19 * Configuration Options: not applicable, uses PCI auto config
20 *
21 * There is code to support AI commands, but it may not work.
22 *
23 * AO commands are not supported.
24 */
25
26/*
27 * The DT3000 series is Data Translation's attempt to make a PCI
28 * data acquisition board.  The design of this series is very nice,
29 * since each board has an on-board DSP (Texas Instruments TMS320C52).
30 * However, a few details are a little annoying.  The boards lack
31 * bus-mastering DMA, which eliminates them from serious work.
32 * They also are not capable of autocalibration, which is a common
33 * feature in modern hardware.  The default firmware is pretty bad,
34 * making it nearly impossible to write an RT compatible driver.
35 * It would make an interesting project to write a decent firmware
36 * for these boards.
37 *
38 * Data Translation originally wanted an NDA for the documentation
39 * for the 3k series.  However, if you ask nicely, they might send
40 * you the docs without one, also.
41 */
42
43#include <linux/module.h>
44#include <linux/delay.h>
45#include <linux/interrupt.h>
46#include <linux/comedi/comedi_pci.h>
47
48/*
49 * PCI BAR0 - dual-ported RAM location definitions (dev->mmio)
50 */
51#define DPR_DAC_BUFFER		(4 * 0x000)
52#define DPR_ADC_BUFFER		(4 * 0x800)
53#define DPR_COMMAND		(4 * 0xfd3)
54#define DPR_SUBSYS		(4 * 0xfd3)
55#define DPR_SUBSYS_AI		0
56#define DPR_SUBSYS_AO		1
57#define DPR_SUBSYS_DIN		2
58#define DPR_SUBSYS_DOUT		3
59#define DPR_SUBSYS_MEM		4
60#define DPR_SUBSYS_CT		5
61#define DPR_ENCODE		(4 * 0xfd4)
62#define DPR_PARAMS(x)		(4 * (0xfd5 + (x)))
63#define DPR_TICK_REG_LO		(4 * 0xff5)
64#define DPR_TICK_REG_HI		(4 * 0xff6)
65#define DPR_DA_BUF_FRONT	(4 * 0xff7)
66#define DPR_DA_BUF_REAR		(4 * 0xff8)
67#define DPR_AD_BUF_FRONT	(4 * 0xff9)
68#define DPR_AD_BUF_REAR		(4 * 0xffa)
69#define DPR_INT_MASK		(4 * 0xffb)
70#define DPR_INTR_FLAG		(4 * 0xffc)
71#define DPR_INTR_CMDONE		BIT(7)
72#define DPR_INTR_CTDONE		BIT(6)
73#define DPR_INTR_DAHWERR	BIT(5)
74#define DPR_INTR_DASWERR	BIT(4)
75#define DPR_INTR_DAEMPTY	BIT(3)
76#define DPR_INTR_ADHWERR	BIT(2)
77#define DPR_INTR_ADSWERR	BIT(1)
78#define DPR_INTR_ADFULL		BIT(0)
79#define DPR_RESPONSE_MBX	(4 * 0xffe)
80#define DPR_CMD_MBX		(4 * 0xfff)
81#define DPR_CMD_COMPLETION(x)	((x) << 8)
82#define DPR_CMD_NOTPROCESSED	DPR_CMD_COMPLETION(0x00)
83#define DPR_CMD_NOERROR		DPR_CMD_COMPLETION(0x55)
84#define DPR_CMD_ERROR		DPR_CMD_COMPLETION(0xaa)
85#define DPR_CMD_NOTSUPPORTED	DPR_CMD_COMPLETION(0xff)
86#define DPR_CMD_COMPLETION_MASK	DPR_CMD_COMPLETION(0xff)
87#define DPR_CMD(x)		((x) << 0)
88#define DPR_CMD_GETBRDINFO	DPR_CMD(0)
89#define DPR_CMD_CONFIG		DPR_CMD(1)
90#define DPR_CMD_GETCONFIG	DPR_CMD(2)
91#define DPR_CMD_START		DPR_CMD(3)
92#define DPR_CMD_STOP		DPR_CMD(4)
93#define DPR_CMD_READSINGLE	DPR_CMD(5)
94#define DPR_CMD_WRITESINGLE	DPR_CMD(6)
95#define DPR_CMD_CALCCLOCK	DPR_CMD(7)
96#define DPR_CMD_READEVENTS	DPR_CMD(8)
97#define DPR_CMD_WRITECTCTRL	DPR_CMD(16)
98#define DPR_CMD_READCTCTRL	DPR_CMD(17)
99#define DPR_CMD_WRITECT		DPR_CMD(18)
100#define DPR_CMD_READCT		DPR_CMD(19)
101#define DPR_CMD_WRITEDATA	DPR_CMD(32)
102#define DPR_CMD_READDATA	DPR_CMD(33)
103#define DPR_CMD_WRITEIO		DPR_CMD(34)
104#define DPR_CMD_READIO		DPR_CMD(35)
105#define DPR_CMD_WRITECODE	DPR_CMD(36)
106#define DPR_CMD_READCODE	DPR_CMD(37)
107#define DPR_CMD_EXECUTE		DPR_CMD(38)
108#define DPR_CMD_HALT		DPR_CMD(48)
109#define DPR_CMD_MASK		DPR_CMD(0xff)
110
111#define DPR_PARAM5_AD_TRIG(x)		(((x) & 0x7) << 2)
112#define DPR_PARAM5_AD_TRIG_INT		DPR_PARAM5_AD_TRIG(0)
113#define DPR_PARAM5_AD_TRIG_EXT		DPR_PARAM5_AD_TRIG(1)
114#define DPR_PARAM5_AD_TRIG_INT_RETRIG	DPR_PARAM5_AD_TRIG(2)
115#define DPR_PARAM5_AD_TRIG_EXT_RETRIG	DPR_PARAM5_AD_TRIG(3)
116#define DPR_PARAM5_AD_TRIG_INT_RETRIG2	DPR_PARAM5_AD_TRIG(4)
117
118#define DPR_PARAM6_AD_DIFF		BIT(0)
119
120#define DPR_AI_FIFO_DEPTH		2003
121#define DPR_AO_FIFO_DEPTH		2048
122
123#define DPR_EXTERNAL_CLOCK		1
124#define DPR_RISING_EDGE			2
125
126#define DPR_TMODE_MASK			0x1c
127
128#define DPR_CMD_TIMEOUT			100
129
130static const struct comedi_lrange range_dt3000_ai = {
131	4, {
132		BIP_RANGE(10),
133		BIP_RANGE(5),
134		BIP_RANGE(2.5),
135		BIP_RANGE(1.25)
136	}
137};
138
139static const struct comedi_lrange range_dt3000_ai_pgl = {
140	4, {
141		BIP_RANGE(10),
142		BIP_RANGE(1),
143		BIP_RANGE(0.1),
144		BIP_RANGE(0.02)
145	}
146};
147
148enum dt3k_boardid {
149	BOARD_DT3001,
150	BOARD_DT3001_PGL,
151	BOARD_DT3002,
152	BOARD_DT3003,
153	BOARD_DT3003_PGL,
154	BOARD_DT3004,
155	BOARD_DT3005,
156};
157
158struct dt3k_boardtype {
159	const char *name;
160	int adchan;
161	int ai_speed;
162	const struct comedi_lrange *adrange;
163	unsigned int ai_is_16bit:1;
164	unsigned int has_ao:1;
165};
166
167static const struct dt3k_boardtype dt3k_boardtypes[] = {
168	[BOARD_DT3001] = {
169		.name		= "dt3001",
170		.adchan		= 16,
171		.adrange	= &range_dt3000_ai,
172		.ai_speed	= 3000,
173		.has_ao		= 1,
174	},
175	[BOARD_DT3001_PGL] = {
176		.name		= "dt3001-pgl",
177		.adchan		= 16,
178		.adrange	= &range_dt3000_ai_pgl,
179		.ai_speed	= 3000,
180		.has_ao		= 1,
181	},
182	[BOARD_DT3002] = {
183		.name		= "dt3002",
184		.adchan		= 32,
185		.adrange	= &range_dt3000_ai,
186		.ai_speed	= 3000,
187	},
188	[BOARD_DT3003] = {
189		.name		= "dt3003",
190		.adchan		= 64,
191		.adrange	= &range_dt3000_ai,
192		.ai_speed	= 3000,
193		.has_ao		= 1,
194	},
195	[BOARD_DT3003_PGL] = {
196		.name		= "dt3003-pgl",
197		.adchan		= 64,
198		.adrange	= &range_dt3000_ai_pgl,
199		.ai_speed	= 3000,
200		.has_ao		= 1,
201	},
202	[BOARD_DT3004] = {
203		.name		= "dt3004",
204		.adchan		= 16,
205		.adrange	= &range_dt3000_ai,
206		.ai_speed	= 10000,
207		.ai_is_16bit	= 1,
208		.has_ao		= 1,
209	},
210	[BOARD_DT3005] = {
211		.name		= "dt3005",	/* a.k.a. 3004-200 */
212		.adchan		= 16,
213		.adrange	= &range_dt3000_ai,
214		.ai_speed	= 5000,
215		.ai_is_16bit	= 1,
216		.has_ao		= 1,
217	},
218};
219
220struct dt3k_private {
221	unsigned int lock;
222	unsigned int ai_front;
223	unsigned int ai_rear;
224};
225
226static void dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd)
227{
228	int i;
229	unsigned int status = 0;
230
231	writew(cmd, dev->mmio + DPR_CMD_MBX);
232
233	for (i = 0; i < DPR_CMD_TIMEOUT; i++) {
234		status = readw(dev->mmio + DPR_CMD_MBX);
235		status &= DPR_CMD_COMPLETION_MASK;
236		if (status != DPR_CMD_NOTPROCESSED)
237			break;
238		udelay(1);
239	}
240
241	if (status != DPR_CMD_NOERROR)
242		dev_dbg(dev->class_dev, "%s: timeout/error status=0x%04x\n",
243			__func__, status);
244}
245
246static unsigned int dt3k_readsingle(struct comedi_device *dev,
247				    unsigned int subsys, unsigned int chan,
248				    unsigned int gain)
249{
250	writew(subsys, dev->mmio + DPR_SUBSYS);
251
252	writew(chan, dev->mmio + DPR_PARAMS(0));
253	writew(gain, dev->mmio + DPR_PARAMS(1));
254
255	dt3k_send_cmd(dev, DPR_CMD_READSINGLE);
256
257	return readw(dev->mmio + DPR_PARAMS(2));
258}
259
260static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys,
261			     unsigned int chan, unsigned int data)
262{
263	writew(subsys, dev->mmio + DPR_SUBSYS);
264
265	writew(chan, dev->mmio + DPR_PARAMS(0));
266	writew(0, dev->mmio + DPR_PARAMS(1));
267	writew(data, dev->mmio + DPR_PARAMS(2));
268
269	dt3k_send_cmd(dev, DPR_CMD_WRITESINGLE);
270}
271
272static void dt3k_ai_empty_fifo(struct comedi_device *dev,
273			       struct comedi_subdevice *s)
274{
275	struct dt3k_private *devpriv = dev->private;
276	int front;
277	int rear;
278	int count;
279	int i;
280	unsigned short data;
281
282	front = readw(dev->mmio + DPR_AD_BUF_FRONT);
283	count = front - devpriv->ai_front;
284	if (count < 0)
285		count += DPR_AI_FIFO_DEPTH;
286
287	rear = devpriv->ai_rear;
288
289	for (i = 0; i < count; i++) {
290		data = readw(dev->mmio + DPR_ADC_BUFFER + rear);
291		comedi_buf_write_samples(s, &data, 1);
292		rear++;
293		if (rear >= DPR_AI_FIFO_DEPTH)
294			rear = 0;
295	}
296
297	devpriv->ai_rear = rear;
298	writew(rear, dev->mmio + DPR_AD_BUF_REAR);
299}
300
301static int dt3k_ai_cancel(struct comedi_device *dev,
302			  struct comedi_subdevice *s)
303{
304	writew(DPR_SUBSYS_AI, dev->mmio + DPR_SUBSYS);
305	dt3k_send_cmd(dev, DPR_CMD_STOP);
306
307	writew(0, dev->mmio + DPR_INT_MASK);
308
309	return 0;
310}
311
312static int debug_n_ints;
313
314/* FIXME! Assumes shared interrupt is for this card. */
315/* What's this debug_n_ints stuff? Obviously needs some work... */
316static irqreturn_t dt3k_interrupt(int irq, void *d)
317{
318	struct comedi_device *dev = d;
319	struct comedi_subdevice *s = dev->read_subdev;
320	unsigned int status;
321
322	if (!dev->attached)
323		return IRQ_NONE;
324
325	status = readw(dev->mmio + DPR_INTR_FLAG);
326
327	if (status & DPR_INTR_ADFULL)
328		dt3k_ai_empty_fifo(dev, s);
329
330	if (status & (DPR_INTR_ADSWERR | DPR_INTR_ADHWERR))
331		s->async->events |= COMEDI_CB_ERROR;
332
333	debug_n_ints++;
334	if (debug_n_ints >= 10)
335		s->async->events |= COMEDI_CB_EOA;
336
337	comedi_handle_events(dev, s);
338	return IRQ_HANDLED;
339}
340
341static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
342			    unsigned int flags)
343{
344	unsigned int divider, base, prescale;
345
346	/* This function needs improvement */
347	/* Don't know if divider==0 works. */
348
349	for (prescale = 0; prescale < 16; prescale++) {
350		base = timer_base * (prescale + 1);
351		switch (flags & CMDF_ROUND_MASK) {
352		case CMDF_ROUND_NEAREST:
353		default:
354			divider = DIV_ROUND_CLOSEST(*nanosec, base);
355			break;
356		case CMDF_ROUND_DOWN:
357			divider = (*nanosec) / base;
358			break;
359		case CMDF_ROUND_UP:
360			divider = DIV_ROUND_UP(*nanosec, base);
361			break;
362		}
363		if (divider < 65536) {
364			*nanosec = divider * base;
365			return (prescale << 16) | (divider);
366		}
367	}
368
369	prescale = 15;
370	base = timer_base * (prescale + 1);
371	divider = 65535;
372	*nanosec = divider * base;
373	return (prescale << 16) | (divider);
374}
375
376static int dt3k_ai_cmdtest(struct comedi_device *dev,
377			   struct comedi_subdevice *s, struct comedi_cmd *cmd)
378{
379	const struct dt3k_boardtype *board = dev->board_ptr;
380	int err = 0;
381	unsigned int arg;
382
383	/* Step 1 : check if triggers are trivially valid */
384
385	err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW);
386	err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
387	err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
388	err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
389	err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT);
390
391	if (err)
392		return 1;
393
394	/* Step 2a : make sure trigger sources are unique */
395	/* Step 2b : and mutually compatible */
396
397	/* Step 3: check if arguments are trivially valid */
398
399	err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
400
401	if (cmd->scan_begin_src == TRIG_TIMER) {
402		err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg,
403						    board->ai_speed);
404		err |= comedi_check_trigger_arg_max(&cmd->scan_begin_arg,
405						    100 * 16 * 65535);
406	}
407
408	if (cmd->convert_src == TRIG_TIMER) {
409		err |= comedi_check_trigger_arg_min(&cmd->convert_arg,
410						    board->ai_speed);
411		err |= comedi_check_trigger_arg_max(&cmd->convert_arg,
412						    50 * 16 * 65535);
413	}
414
415	err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
416					   cmd->chanlist_len);
417
418	if (cmd->stop_src == TRIG_COUNT)
419		err |= comedi_check_trigger_arg_max(&cmd->stop_arg, 0x00ffffff);
420	else	/* TRIG_NONE */
421		err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
422
423	if (err)
424		return 3;
425
426	/* step 4: fix up any arguments */
427
428	if (cmd->scan_begin_src == TRIG_TIMER) {
429		arg = cmd->scan_begin_arg;
430		dt3k_ns_to_timer(100, &arg, cmd->flags);
431		err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
432	}
433
434	if (cmd->convert_src == TRIG_TIMER) {
435		arg = cmd->convert_arg;
436		dt3k_ns_to_timer(50, &arg, cmd->flags);
437		err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
438
439		if (cmd->scan_begin_src == TRIG_TIMER) {
440			arg = cmd->convert_arg * cmd->scan_end_arg;
441			err |= comedi_check_trigger_arg_min(
442				&cmd->scan_begin_arg, arg);
443		}
444	}
445
446	if (err)
447		return 4;
448
449	return 0;
450}
451
452static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
453{
454	struct comedi_cmd *cmd = &s->async->cmd;
455	int i;
456	unsigned int chan, range, aref;
457	unsigned int divider;
458	unsigned int tscandiv;
459
460	for (i = 0; i < cmd->chanlist_len; i++) {
461		chan = CR_CHAN(cmd->chanlist[i]);
462		range = CR_RANGE(cmd->chanlist[i]);
463
464		writew((range << 6) | chan, dev->mmio + DPR_ADC_BUFFER + i);
465	}
466	aref = CR_AREF(cmd->chanlist[0]);
467
468	writew(cmd->scan_end_arg, dev->mmio + DPR_PARAMS(0));
469
470	if (cmd->convert_src == TRIG_TIMER) {
471		divider = dt3k_ns_to_timer(50, &cmd->convert_arg, cmd->flags);
472		writew((divider >> 16), dev->mmio + DPR_PARAMS(1));
473		writew((divider & 0xffff), dev->mmio + DPR_PARAMS(2));
474	}
475
476	if (cmd->scan_begin_src == TRIG_TIMER) {
477		tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
478					    cmd->flags);
479		writew((tscandiv >> 16), dev->mmio + DPR_PARAMS(3));
480		writew((tscandiv & 0xffff), dev->mmio + DPR_PARAMS(4));
481	}
482
483	writew(DPR_PARAM5_AD_TRIG_INT_RETRIG, dev->mmio + DPR_PARAMS(5));
484	writew((aref == AREF_DIFF) ? DPR_PARAM6_AD_DIFF : 0,
485	       dev->mmio + DPR_PARAMS(6));
486
487	writew(DPR_AI_FIFO_DEPTH / 2, dev->mmio + DPR_PARAMS(7));
488
489	writew(DPR_SUBSYS_AI, dev->mmio + DPR_SUBSYS);
490	dt3k_send_cmd(dev, DPR_CMD_CONFIG);
491
492	writew(DPR_INTR_ADFULL | DPR_INTR_ADSWERR | DPR_INTR_ADHWERR,
493	       dev->mmio + DPR_INT_MASK);
494
495	debug_n_ints = 0;
496
497	writew(DPR_SUBSYS_AI, dev->mmio + DPR_SUBSYS);
498	dt3k_send_cmd(dev, DPR_CMD_START);
499
500	return 0;
501}
502
503static int dt3k_ai_insn_read(struct comedi_device *dev,
504			     struct comedi_subdevice *s,
505			     struct comedi_insn *insn,
506			     unsigned int *data)
507{
508	int i;
509	unsigned int chan, gain;
510
511	chan = CR_CHAN(insn->chanspec);
512	gain = CR_RANGE(insn->chanspec);
513	/* XXX docs don't explain how to select aref */
514
515	for (i = 0; i < insn->n; i++)
516		data[i] = dt3k_readsingle(dev, DPR_SUBSYS_AI, chan, gain);
517
518	return i;
519}
520
521static int dt3k_ao_insn_write(struct comedi_device *dev,
522			      struct comedi_subdevice *s,
523			      struct comedi_insn *insn,
524			      unsigned int *data)
525{
526	unsigned int chan = CR_CHAN(insn->chanspec);
527	unsigned int val = s->readback[chan];
528	int i;
529
530	for (i = 0; i < insn->n; i++) {
531		val = data[i];
532		dt3k_writesingle(dev, DPR_SUBSYS_AO, chan, val);
533	}
534	s->readback[chan] = val;
535
536	return insn->n;
537}
538
539static void dt3k_dio_config(struct comedi_device *dev, int bits)
540{
541	/* XXX */
542	writew(DPR_SUBSYS_DOUT, dev->mmio + DPR_SUBSYS);
543
544	writew(bits, dev->mmio + DPR_PARAMS(0));
545
546	/* XXX write 0 to DPR_PARAMS(1) and DPR_PARAMS(2) ? */
547
548	dt3k_send_cmd(dev, DPR_CMD_CONFIG);
549}
550
551static int dt3k_dio_insn_config(struct comedi_device *dev,
552				struct comedi_subdevice *s,
553				struct comedi_insn *insn,
554				unsigned int *data)
555{
556	unsigned int chan = CR_CHAN(insn->chanspec);
557	unsigned int mask;
558	int ret;
559
560	if (chan < 4)
561		mask = 0x0f;
562	else
563		mask = 0xf0;
564
565	ret = comedi_dio_insn_config(dev, s, insn, data, mask);
566	if (ret)
567		return ret;
568
569	dt3k_dio_config(dev, (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3));
570
571	return insn->n;
572}
573
574static int dt3k_dio_insn_bits(struct comedi_device *dev,
575			      struct comedi_subdevice *s,
576			      struct comedi_insn *insn,
577			      unsigned int *data)
578{
579	if (comedi_dio_update_state(s, data))
580		dt3k_writesingle(dev, DPR_SUBSYS_DOUT, 0, s->state);
581
582	data[1] = dt3k_readsingle(dev, DPR_SUBSYS_DIN, 0, 0);
583
584	return insn->n;
585}
586
587static int dt3k_mem_insn_read(struct comedi_device *dev,
588			      struct comedi_subdevice *s,
589			      struct comedi_insn *insn,
590			      unsigned int *data)
591{
592	unsigned int addr = CR_CHAN(insn->chanspec);
593	int i;
594
595	for (i = 0; i < insn->n; i++) {
596		writew(DPR_SUBSYS_MEM, dev->mmio + DPR_SUBSYS);
597		writew(addr, dev->mmio + DPR_PARAMS(0));
598		writew(1, dev->mmio + DPR_PARAMS(1));
599
600		dt3k_send_cmd(dev, DPR_CMD_READCODE);
601
602		data[i] = readw(dev->mmio + DPR_PARAMS(2));
603	}
604
605	return i;
606}
607
608static int dt3000_auto_attach(struct comedi_device *dev,
609			      unsigned long context)
610{
611	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
612	const struct dt3k_boardtype *board = NULL;
613	struct dt3k_private *devpriv;
614	struct comedi_subdevice *s;
615	int ret = 0;
616
617	if (context < ARRAY_SIZE(dt3k_boardtypes))
618		board = &dt3k_boardtypes[context];
619	if (!board)
620		return -ENODEV;
621	dev->board_ptr = board;
622	dev->board_name = board->name;
623
624	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
625	if (!devpriv)
626		return -ENOMEM;
627
628	ret = comedi_pci_enable(dev);
629	if (ret < 0)
630		return ret;
631
632	dev->mmio = pci_ioremap_bar(pcidev, 0);
633	if (!dev->mmio)
634		return -ENOMEM;
635
636	if (pcidev->irq) {
637		ret = request_irq(pcidev->irq, dt3k_interrupt, IRQF_SHARED,
638				  dev->board_name, dev);
639		if (ret == 0)
640			dev->irq = pcidev->irq;
641	}
642
643	ret = comedi_alloc_subdevices(dev, 4);
644	if (ret)
645		return ret;
646
647	/* Analog Input subdevice */
648	s = &dev->subdevices[0];
649	s->type		= COMEDI_SUBD_AI;
650	s->subdev_flags	= SDF_READABLE | SDF_GROUND | SDF_DIFF;
651	s->n_chan	= board->adchan;
652	s->maxdata	= board->ai_is_16bit ? 0xffff : 0x0fff;
653	s->range_table	= &range_dt3000_ai;	/* XXX */
654	s->insn_read	= dt3k_ai_insn_read;
655	if (dev->irq) {
656		dev->read_subdev = s;
657		s->subdev_flags	|= SDF_CMD_READ;
658		s->len_chanlist	= 512;
659		s->do_cmd	= dt3k_ai_cmd;
660		s->do_cmdtest	= dt3k_ai_cmdtest;
661		s->cancel	= dt3k_ai_cancel;
662	}
663
664	/* Analog Output subdevice */
665	s = &dev->subdevices[1];
666	if (board->has_ao) {
667		s->type		= COMEDI_SUBD_AO;
668		s->subdev_flags	= SDF_WRITABLE;
669		s->n_chan	= 2;
670		s->maxdata	= 0x0fff;
671		s->range_table	= &range_bipolar10;
672		s->insn_write	= dt3k_ao_insn_write;
673
674		ret = comedi_alloc_subdev_readback(s);
675		if (ret)
676			return ret;
677
678	} else {
679		s->type		= COMEDI_SUBD_UNUSED;
680	}
681
682	/* Digital I/O subdevice */
683	s = &dev->subdevices[2];
684	s->type		= COMEDI_SUBD_DIO;
685	s->subdev_flags	= SDF_READABLE | SDF_WRITABLE;
686	s->n_chan	= 8;
687	s->maxdata	= 1;
688	s->range_table	= &range_digital;
689	s->insn_config	= dt3k_dio_insn_config;
690	s->insn_bits	= dt3k_dio_insn_bits;
691
692	/* Memory subdevice */
693	s = &dev->subdevices[3];
694	s->type		= COMEDI_SUBD_MEMORY;
695	s->subdev_flags	= SDF_READABLE;
696	s->n_chan	= 0x1000;
697	s->maxdata	= 0xff;
698	s->range_table	= &range_unknown;
699	s->insn_read	= dt3k_mem_insn_read;
700
701	return 0;
702}
703
704static struct comedi_driver dt3000_driver = {
705	.driver_name	= "dt3000",
706	.module		= THIS_MODULE,
707	.auto_attach	= dt3000_auto_attach,
708	.detach		= comedi_pci_detach,
709};
710
711static int dt3000_pci_probe(struct pci_dev *dev,
712			    const struct pci_device_id *id)
713{
714	return comedi_pci_auto_config(dev, &dt3000_driver, id->driver_data);
715}
716
717static const struct pci_device_id dt3000_pci_table[] = {
718	{ PCI_VDEVICE(DT, 0x0022), BOARD_DT3001 },
719	{ PCI_VDEVICE(DT, 0x0023), BOARD_DT3002 },
720	{ PCI_VDEVICE(DT, 0x0024), BOARD_DT3003 },
721	{ PCI_VDEVICE(DT, 0x0025), BOARD_DT3004 },
722	{ PCI_VDEVICE(DT, 0x0026), BOARD_DT3005 },
723	{ PCI_VDEVICE(DT, 0x0027), BOARD_DT3001_PGL },
724	{ PCI_VDEVICE(DT, 0x0028), BOARD_DT3003_PGL },
725	{ 0 }
726};
727MODULE_DEVICE_TABLE(pci, dt3000_pci_table);
728
729static struct pci_driver dt3000_pci_driver = {
730	.name		= "dt3000",
731	.id_table	= dt3000_pci_table,
732	.probe		= dt3000_pci_probe,
733	.remove		= comedi_pci_auto_unconfig,
734};
735module_comedi_pci_driver(dt3000_driver, dt3000_pci_driver);
736
737MODULE_AUTHOR("Comedi https://www.comedi.org");
738MODULE_DESCRIPTION("Comedi driver for Data Translation DT3000 series boards");
739MODULE_LICENSE("GPL");
740