2 comedi/drivers/dt3000.c
3 Data Translation DT3000 series driver
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 1999 David A. Schleef <ds@schleef.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
20 Description: Data Translation DT3000 series
22 Devices: [Data Translation] DT3001 (dt3000), DT3001-PGL, DT3002, DT3003,
23 DT3003-PGL, DT3004, DT3005, DT3004-200
24 Updated: Mon, 14 Apr 2008 15:41:24 +0100
27 Configuration Options: not applicable, uses PCI auto config
29 There is code to support AI commands, but it may not work.
31 AO commands are not supported.
35 The DT3000 series is Data Translation's attempt to make a PCI
36 data acquisition board. The design of this series is very nice,
37 since each board has an on-board DSP (Texas Instruments TMS320C52).
38 However, a few details are a little annoying. The boards lack
39 bus-mastering DMA, which eliminates them from serious work.
40 They also are not capable of autocalibration, which is a common
41 feature in modern hardware. The default firmware is pretty bad,
42 making it nearly impossible to write an RT compatible driver.
43 It would make an interesting project to write a decent firmware
46 Data Translation originally wanted an NDA for the documentation
47 for the 3k series. However, if you ask nicely, they might send
48 you the docs without one, also.
51 #include <linux/module.h>
52 #include <linux/pci.h>
53 #include <linux/delay.h>
54 #include <linux/interrupt.h>
56 #include "../comedidev.h"
58 #include "comedi_fc.h"
60 static const struct comedi_lrange range_dt3000_ai = {
69 static const struct comedi_lrange range_dt3000_ai_pgl = {
88 struct dt3k_boardtype {
93 const struct comedi_lrange *adrange;
98 static const struct dt3k_boardtype dt3k_boardtypes[] = {
103 .adrange = &range_dt3000_ai,
108 [BOARD_DT3001_PGL] = {
109 .name = "dt3001-pgl",
112 .adrange = &range_dt3000_ai_pgl,
121 .adrange = &range_dt3000_ai,
128 .adrange = &range_dt3000_ai,
133 [BOARD_DT3003_PGL] = {
134 .name = "dt3003-pgl",
137 .adrange = &range_dt3000_ai_pgl,
146 .adrange = &range_dt3000_ai,
152 .name = "dt3005", /* a.k.a. 3004-200 */
155 .adrange = &range_dt3000_ai,
162 /* dual-ported RAM location definitions */
164 #define DPR_DAC_buffer (4*0x000)
165 #define DPR_ADC_buffer (4*0x800)
166 #define DPR_Command (4*0xfd3)
167 #define DPR_SubSys (4*0xfd3)
168 #define DPR_Encode (4*0xfd4)
169 #define DPR_Params(a) (4*(0xfd5+(a)))
170 #define DPR_Tick_Reg_Lo (4*0xff5)
171 #define DPR_Tick_Reg_Hi (4*0xff6)
172 #define DPR_DA_Buf_Front (4*0xff7)
173 #define DPR_DA_Buf_Rear (4*0xff8)
174 #define DPR_AD_Buf_Front (4*0xff9)
175 #define DPR_AD_Buf_Rear (4*0xffa)
176 #define DPR_Int_Mask (4*0xffb)
177 #define DPR_Intr_Flag (4*0xffc)
178 #define DPR_Response_Mbx (4*0xffe)
179 #define DPR_Command_Mbx (4*0xfff)
181 #define AI_FIFO_DEPTH 2003
182 #define AO_FIFO_DEPTH 2048
186 #define CMD_GETBRDINFO 0
188 #define CMD_GETCONFIG 2
191 #define CMD_READSINGLE 5
192 #define CMD_WRITESINGLE 6
193 #define CMD_CALCCLOCK 7
194 #define CMD_READEVENTS 8
195 #define CMD_WRITECTCTRL 16
196 #define CMD_READCTCTRL 17
197 #define CMD_WRITECT 18
198 #define CMD_READCT 19
199 #define CMD_WRITEDATA 32
200 #define CMD_READDATA 33
201 #define CMD_WRITEIO 34
202 #define CMD_READIO 35
203 #define CMD_WRITECODE 36
204 #define CMD_READCODE 37
205 #define CMD_EXECUTE 38
215 /* interrupt flags */
216 #define DT3000_CMDONE 0x80
217 #define DT3000_CTDONE 0x40
218 #define DT3000_DAHWERR 0x20
219 #define DT3000_DASWERR 0x10
220 #define DT3000_DAEMPTY 0x08
221 #define DT3000_ADHWERR 0x04
222 #define DT3000_ADSWERR 0x02
223 #define DT3000_ADFULL 0x01
225 #define DT3000_COMPLETION_MASK 0xff00
226 #define DT3000_COMMAND_MASK 0x00ff
227 #define DT3000_NOTPROCESSED 0x0000
228 #define DT3000_NOERROR 0x5500
229 #define DT3000_ERROR 0xaa00
230 #define DT3000_NOTSUPPORTED 0xff00
232 #define DT3000_EXTERNAL_CLOCK 1
233 #define DT3000_RISING_EDGE 2
235 #define TMODE_MASK 0x1c
237 #define DT3000_AD_TRIG_INTERNAL (0<<2)
238 #define DT3000_AD_TRIG_EXTERNAL (1<<2)
239 #define DT3000_AD_RETRIG_INTERNAL (2<<2)
240 #define DT3000_AD_RETRIG_EXTERNAL (3<<2)
241 #define DT3000_AD_EXTRETRIG (4<<2)
243 #define DT3000_CHANNEL_MODE_SE 0
244 #define DT3000_CHANNEL_MODE_DI 1
246 struct dt3k_private {
248 unsigned int ai_front;
249 unsigned int ai_rear;
254 static void dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd)
257 unsigned int status = 0;
259 writew(cmd, dev->mmio + DPR_Command_Mbx);
261 for (i = 0; i < TIMEOUT; i++) {
262 status = readw(dev->mmio + DPR_Command_Mbx);
263 if ((status & DT3000_COMPLETION_MASK) != DT3000_NOTPROCESSED)
268 if ((status & DT3000_COMPLETION_MASK) != DT3000_NOERROR)
269 dev_dbg(dev->class_dev, "%s: timeout/error status=0x%04x\n",
273 static unsigned int dt3k_readsingle(struct comedi_device *dev,
274 unsigned int subsys, unsigned int chan,
277 writew(subsys, dev->mmio + DPR_SubSys);
279 writew(chan, dev->mmio + DPR_Params(0));
280 writew(gain, dev->mmio + DPR_Params(1));
282 dt3k_send_cmd(dev, CMD_READSINGLE);
284 return readw(dev->mmio + DPR_Params(2));
287 static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys,
288 unsigned int chan, unsigned int data)
290 writew(subsys, dev->mmio + DPR_SubSys);
292 writew(chan, dev->mmio + DPR_Params(0));
293 writew(0, dev->mmio + DPR_Params(1));
294 writew(data, dev->mmio + DPR_Params(2));
296 dt3k_send_cmd(dev, CMD_WRITESINGLE);
299 static void dt3k_ai_empty_fifo(struct comedi_device *dev,
300 struct comedi_subdevice *s)
302 struct dt3k_private *devpriv = dev->private;
309 front = readw(dev->mmio + DPR_AD_Buf_Front);
310 count = front - devpriv->ai_front;
312 count += AI_FIFO_DEPTH;
314 rear = devpriv->ai_rear;
316 for (i = 0; i < count; i++) {
317 data = readw(dev->mmio + DPR_ADC_buffer + rear);
318 comedi_buf_write_samples(s, &data, 1);
320 if (rear >= AI_FIFO_DEPTH)
324 devpriv->ai_rear = rear;
325 writew(rear, dev->mmio + DPR_AD_Buf_Rear);
328 static int dt3k_ai_cancel(struct comedi_device *dev,
329 struct comedi_subdevice *s)
331 writew(SUBS_AI, dev->mmio + DPR_SubSys);
332 dt3k_send_cmd(dev, CMD_STOP);
334 writew(0, dev->mmio + DPR_Int_Mask);
339 static int debug_n_ints;
341 /* FIXME! Assumes shared interrupt is for this card. */
342 /* What's this debug_n_ints stuff? Obviously needs some work... */
343 static irqreturn_t dt3k_interrupt(int irq, void *d)
345 struct comedi_device *dev = d;
346 struct comedi_subdevice *s = dev->read_subdev;
352 status = readw(dev->mmio + DPR_Intr_Flag);
354 if (status & DT3000_ADFULL)
355 dt3k_ai_empty_fifo(dev, s);
357 if (status & (DT3000_ADSWERR | DT3000_ADHWERR))
358 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
361 if (debug_n_ints >= 10)
362 s->async->events |= COMEDI_CB_EOA;
364 comedi_handle_events(dev, s);
368 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
371 int divider, base, prescale;
373 /* This function needs improvment */
374 /* Don't know if divider==0 works. */
376 for (prescale = 0; prescale < 16; prescale++) {
377 base = timer_base * (prescale + 1);
378 switch (flags & CMDF_ROUND_MASK) {
379 case CMDF_ROUND_NEAREST:
381 divider = (*nanosec + base / 2) / base;
383 case CMDF_ROUND_DOWN:
384 divider = (*nanosec) / base;
387 divider = (*nanosec) / base;
390 if (divider < 65536) {
391 *nanosec = divider * base;
392 return (prescale << 16) | (divider);
397 base = timer_base * (1 << prescale);
399 *nanosec = divider * base;
400 return (prescale << 16) | (divider);
403 static int dt3k_ai_cmdtest(struct comedi_device *dev,
404 struct comedi_subdevice *s, struct comedi_cmd *cmd)
406 const struct dt3k_boardtype *this_board = dev->board_ptr;
410 /* Step 1 : check if triggers are trivially valid */
412 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
413 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
414 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
415 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
416 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT);
421 /* Step 2a : make sure trigger sources are unique */
422 /* Step 2b : and mutually compatible */
424 /* Step 3: check if arguments are trivially valid */
426 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
428 if (cmd->scan_begin_src == TRIG_TIMER) {
429 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
430 this_board->ai_speed);
431 err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg,
435 if (cmd->convert_src == TRIG_TIMER) {
436 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
437 this_board->ai_speed);
438 err |= cfc_check_trigger_arg_max(&cmd->convert_arg,
442 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
444 if (cmd->stop_src == TRIG_COUNT)
445 err |= cfc_check_trigger_arg_max(&cmd->stop_arg, 0x00ffffff);
447 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
452 /* step 4: fix up any arguments */
454 if (cmd->scan_begin_src == TRIG_TIMER) {
455 arg = cmd->scan_begin_arg;
456 dt3k_ns_to_timer(100, &arg, cmd->flags);
457 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
460 if (cmd->convert_src == TRIG_TIMER) {
461 arg = cmd->convert_arg;
462 dt3k_ns_to_timer(50, &arg, cmd->flags);
463 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
465 if (cmd->scan_begin_src == TRIG_TIMER) {
466 arg = cmd->convert_arg * cmd->scan_end_arg;
467 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
478 static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
480 struct comedi_cmd *cmd = &s->async->cmd;
482 unsigned int chan, range, aref;
483 unsigned int divider;
484 unsigned int tscandiv;
486 for (i = 0; i < cmd->chanlist_len; i++) {
487 chan = CR_CHAN(cmd->chanlist[i]);
488 range = CR_RANGE(cmd->chanlist[i]);
490 writew((range << 6) | chan, dev->mmio + DPR_ADC_buffer + i);
492 aref = CR_AREF(cmd->chanlist[0]);
494 writew(cmd->scan_end_arg, dev->mmio + DPR_Params(0));
496 if (cmd->convert_src == TRIG_TIMER) {
497 divider = dt3k_ns_to_timer(50, &cmd->convert_arg, cmd->flags);
498 writew((divider >> 16), dev->mmio + DPR_Params(1));
499 writew((divider & 0xffff), dev->mmio + DPR_Params(2));
502 if (cmd->scan_begin_src == TRIG_TIMER) {
503 tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
505 writew((tscandiv >> 16), dev->mmio + DPR_Params(3));
506 writew((tscandiv & 0xffff), dev->mmio + DPR_Params(4));
509 writew(DT3000_AD_RETRIG_INTERNAL, dev->mmio + DPR_Params(5));
510 writew(aref == AREF_DIFF, dev->mmio + DPR_Params(6));
512 writew(AI_FIFO_DEPTH / 2, dev->mmio + DPR_Params(7));
514 writew(SUBS_AI, dev->mmio + DPR_SubSys);
515 dt3k_send_cmd(dev, CMD_CONFIG);
517 writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR,
518 dev->mmio + DPR_Int_Mask);
522 writew(SUBS_AI, dev->mmio + DPR_SubSys);
523 dt3k_send_cmd(dev, CMD_START);
528 static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
529 struct comedi_insn *insn, unsigned int *data)
532 unsigned int chan, gain, aref;
534 chan = CR_CHAN(insn->chanspec);
535 gain = CR_RANGE(insn->chanspec);
536 /* XXX docs don't explain how to select aref */
537 aref = CR_AREF(insn->chanspec);
539 for (i = 0; i < insn->n; i++)
540 data[i] = dt3k_readsingle(dev, SUBS_AI, chan, gain);
545 static int dt3k_ao_insn_write(struct comedi_device *dev,
546 struct comedi_subdevice *s,
547 struct comedi_insn *insn,
550 unsigned int chan = CR_CHAN(insn->chanspec);
551 unsigned int val = s->readback[chan];
554 for (i = 0; i < insn->n; i++) {
556 dt3k_writesingle(dev, SUBS_AO, chan, val);
558 s->readback[chan] = val;
563 static void dt3k_dio_config(struct comedi_device *dev, int bits)
566 writew(SUBS_DOUT, dev->mmio + DPR_SubSys);
568 writew(bits, dev->mmio + DPR_Params(0));
571 writew(0, dev->mmio + DPR_Params(1));
572 writew(0, dev->mmio + DPR_Params(2));
575 dt3k_send_cmd(dev, CMD_CONFIG);
578 static int dt3k_dio_insn_config(struct comedi_device *dev,
579 struct comedi_subdevice *s,
580 struct comedi_insn *insn,
583 unsigned int chan = CR_CHAN(insn->chanspec);
592 ret = comedi_dio_insn_config(dev, s, insn, data, mask);
596 dt3k_dio_config(dev, (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3));
601 static int dt3k_dio_insn_bits(struct comedi_device *dev,
602 struct comedi_subdevice *s,
603 struct comedi_insn *insn,
606 if (comedi_dio_update_state(s, data))
607 dt3k_writesingle(dev, SUBS_DOUT, 0, s->state);
609 data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0);
614 static int dt3k_mem_insn_read(struct comedi_device *dev,
615 struct comedi_subdevice *s,
616 struct comedi_insn *insn,
619 unsigned int addr = CR_CHAN(insn->chanspec);
622 for (i = 0; i < insn->n; i++) {
623 writew(SUBS_MEM, dev->mmio + DPR_SubSys);
624 writew(addr, dev->mmio + DPR_Params(0));
625 writew(1, dev->mmio + DPR_Params(1));
627 dt3k_send_cmd(dev, CMD_READCODE);
629 data[i] = readw(dev->mmio + DPR_Params(2));
635 static int dt3000_auto_attach(struct comedi_device *dev,
636 unsigned long context)
638 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
639 const struct dt3k_boardtype *this_board = NULL;
640 struct dt3k_private *devpriv;
641 struct comedi_subdevice *s;
644 if (context < ARRAY_SIZE(dt3k_boardtypes))
645 this_board = &dt3k_boardtypes[context];
648 dev->board_ptr = this_board;
649 dev->board_name = this_board->name;
651 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
655 ret = comedi_pci_enable(dev);
659 dev->mmio = pci_ioremap_bar(pcidev, 0);
664 ret = request_irq(pcidev->irq, dt3k_interrupt, IRQF_SHARED,
665 dev->board_name, dev);
667 dev->irq = pcidev->irq;
670 ret = comedi_alloc_subdevices(dev, 4);
674 s = &dev->subdevices[0];
676 s->type = COMEDI_SUBD_AI;
677 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
678 s->n_chan = this_board->adchan;
679 s->insn_read = dt3k_ai_insn;
680 s->maxdata = (1 << this_board->adbits) - 1;
681 s->range_table = &range_dt3000_ai; /* XXX */
683 dev->read_subdev = s;
684 s->subdev_flags |= SDF_CMD_READ;
685 s->len_chanlist = 512;
686 s->do_cmd = dt3k_ai_cmd;
687 s->do_cmdtest = dt3k_ai_cmdtest;
688 s->cancel = dt3k_ai_cancel;
691 s = &dev->subdevices[1];
693 s->type = COMEDI_SUBD_AO;
694 s->subdev_flags = SDF_WRITABLE;
696 s->maxdata = (1 << this_board->dabits) - 1;
698 s->range_table = &range_bipolar10;
699 s->insn_write = dt3k_ao_insn_write;
701 ret = comedi_alloc_subdev_readback(s);
705 s = &dev->subdevices[2];
707 s->type = COMEDI_SUBD_DIO;
708 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
710 s->insn_config = dt3k_dio_insn_config;
711 s->insn_bits = dt3k_dio_insn_bits;
714 s->range_table = &range_digital;
716 s = &dev->subdevices[3];
718 s->type = COMEDI_SUBD_MEMORY;
719 s->subdev_flags = SDF_READABLE;
721 s->insn_read = dt3k_mem_insn_read;
724 s->range_table = &range_unknown;
727 s = &dev->subdevices[4];
729 s->type = COMEDI_SUBD_PROC;
735 static struct comedi_driver dt3000_driver = {
736 .driver_name = "dt3000",
737 .module = THIS_MODULE,
738 .auto_attach = dt3000_auto_attach,
739 .detach = comedi_pci_detach,
742 static int dt3000_pci_probe(struct pci_dev *dev,
743 const struct pci_device_id *id)
745 return comedi_pci_auto_config(dev, &dt3000_driver, id->driver_data);
748 static const struct pci_device_id dt3000_pci_table[] = {
749 { PCI_VDEVICE(DT, 0x0022), BOARD_DT3001 },
750 { PCI_VDEVICE(DT, 0x0023), BOARD_DT3002 },
751 { PCI_VDEVICE(DT, 0x0024), BOARD_DT3003 },
752 { PCI_VDEVICE(DT, 0x0025), BOARD_DT3004 },
753 { PCI_VDEVICE(DT, 0x0026), BOARD_DT3005 },
754 { PCI_VDEVICE(DT, 0x0027), BOARD_DT3001_PGL },
755 { PCI_VDEVICE(DT, 0x0028), BOARD_DT3003_PGL },
758 MODULE_DEVICE_TABLE(pci, dt3000_pci_table);
760 static struct pci_driver dt3000_pci_driver = {
762 .id_table = dt3000_pci_table,
763 .probe = dt3000_pci_probe,
764 .remove = comedi_pci_auto_unconfig,
766 module_comedi_pci_driver(dt3000_driver, dt3000_pci_driver);
768 MODULE_AUTHOR("Comedi http://www.comedi.org");
769 MODULE_DESCRIPTION("Comedi low-level driver");
770 MODULE_LICENSE("GPL");