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 {
247 void __iomem *io_addr;
249 unsigned int ao_readback[2];
250 unsigned int ai_front;
251 unsigned int ai_rear;
256 static void dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd)
258 struct dt3k_private *devpriv = dev->private;
260 unsigned int status = 0;
262 writew(cmd, devpriv->io_addr + DPR_Command_Mbx);
264 for (i = 0; i < TIMEOUT; i++) {
265 status = readw(devpriv->io_addr + DPR_Command_Mbx);
266 if ((status & DT3000_COMPLETION_MASK) != DT3000_NOTPROCESSED)
271 if ((status & DT3000_COMPLETION_MASK) != DT3000_NOERROR)
272 dev_dbg(dev->class_dev, "%s: timeout/error status=0x%04x\n",
276 static unsigned int dt3k_readsingle(struct comedi_device *dev,
277 unsigned int subsys, unsigned int chan,
280 struct dt3k_private *devpriv = dev->private;
282 writew(subsys, devpriv->io_addr + DPR_SubSys);
284 writew(chan, devpriv->io_addr + DPR_Params(0));
285 writew(gain, devpriv->io_addr + DPR_Params(1));
287 dt3k_send_cmd(dev, CMD_READSINGLE);
289 return readw(devpriv->io_addr + DPR_Params(2));
292 static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys,
293 unsigned int chan, unsigned int data)
295 struct dt3k_private *devpriv = dev->private;
297 writew(subsys, devpriv->io_addr + DPR_SubSys);
299 writew(chan, devpriv->io_addr + DPR_Params(0));
300 writew(0, devpriv->io_addr + DPR_Params(1));
301 writew(data, devpriv->io_addr + DPR_Params(2));
303 dt3k_send_cmd(dev, CMD_WRITESINGLE);
306 static void dt3k_ai_empty_fifo(struct comedi_device *dev,
307 struct comedi_subdevice *s)
309 struct dt3k_private *devpriv = dev->private;
316 front = readw(devpriv->io_addr + DPR_AD_Buf_Front);
317 count = front - devpriv->ai_front;
319 count += AI_FIFO_DEPTH;
321 rear = devpriv->ai_rear;
323 for (i = 0; i < count; i++) {
324 data = readw(devpriv->io_addr + DPR_ADC_buffer + rear);
325 comedi_buf_put(s->async, data);
327 if (rear >= AI_FIFO_DEPTH)
331 devpriv->ai_rear = rear;
332 writew(rear, devpriv->io_addr + DPR_AD_Buf_Rear);
335 static int dt3k_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
337 struct dt3k_private *devpriv = dev->private;
339 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
340 dt3k_send_cmd(dev, CMD_STOP);
342 writew(0, devpriv->io_addr + DPR_Int_Mask);
347 static int debug_n_ints;
349 /* FIXME! Assumes shared interrupt is for this card. */
350 /* What's this debug_n_ints stuff? Obviously needs some work... */
351 static irqreturn_t dt3k_interrupt(int irq, void *d)
353 struct comedi_device *dev = d;
354 struct dt3k_private *devpriv = dev->private;
355 struct comedi_subdevice *s;
361 s = &dev->subdevices[0];
362 status = readw(devpriv->io_addr + DPR_Intr_Flag);
364 if (status & DT3000_ADFULL) {
365 dt3k_ai_empty_fifo(dev, s);
366 s->async->events |= COMEDI_CB_BLOCK;
369 if (status & (DT3000_ADSWERR | DT3000_ADHWERR))
370 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
373 if (debug_n_ints >= 10) {
374 dt3k_ai_cancel(dev, s);
375 s->async->events |= COMEDI_CB_EOA;
378 comedi_event(dev, s);
382 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
383 unsigned int round_mode)
385 int divider, base, prescale;
387 /* This function needs improvment */
388 /* Don't know if divider==0 works. */
390 for (prescale = 0; prescale < 16; prescale++) {
391 base = timer_base * (prescale + 1);
392 switch (round_mode) {
393 case TRIG_ROUND_NEAREST:
395 divider = (*nanosec + base / 2) / base;
397 case TRIG_ROUND_DOWN:
398 divider = (*nanosec) / base;
401 divider = (*nanosec) / base;
404 if (divider < 65536) {
405 *nanosec = divider * base;
406 return (prescale << 16) | (divider);
411 base = timer_base * (1 << prescale);
413 *nanosec = divider * base;
414 return (prescale << 16) | (divider);
417 static int dt3k_ai_cmdtest(struct comedi_device *dev,
418 struct comedi_subdevice *s, struct comedi_cmd *cmd)
420 const struct dt3k_boardtype *this_board = comedi_board(dev);
424 /* Step 1 : check if triggers are trivially valid */
426 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
427 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
428 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
429 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
430 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT);
435 /* Step 2a : make sure trigger sources are unique */
436 /* Step 2b : and mutually compatible */
441 /* Step 3: check if arguments are trivially valid */
443 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
445 if (cmd->scan_begin_src == TRIG_TIMER) {
446 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
447 this_board->ai_speed);
448 err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg,
452 if (cmd->convert_src == TRIG_TIMER) {
453 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
454 this_board->ai_speed);
455 err |= cfc_check_trigger_arg_max(&cmd->convert_arg,
459 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
461 if (cmd->stop_src == TRIG_COUNT)
462 err |= cfc_check_trigger_arg_max(&cmd->stop_arg, 0x00ffffff);
464 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
469 /* step 4: fix up any arguments */
471 if (cmd->scan_begin_src == TRIG_TIMER) {
472 tmp = cmd->scan_begin_arg;
473 dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
474 cmd->flags & TRIG_ROUND_MASK);
475 if (tmp != cmd->scan_begin_arg)
479 if (cmd->convert_src == TRIG_TIMER) {
480 tmp = cmd->convert_arg;
481 dt3k_ns_to_timer(50, &cmd->convert_arg,
482 cmd->flags & TRIG_ROUND_MASK);
483 if (tmp != cmd->convert_arg)
485 if (cmd->scan_begin_src == TRIG_TIMER &&
486 cmd->scan_begin_arg <
487 cmd->convert_arg * cmd->scan_end_arg) {
488 cmd->scan_begin_arg =
489 cmd->convert_arg * cmd->scan_end_arg;
500 static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
502 struct dt3k_private *devpriv = dev->private;
503 struct comedi_cmd *cmd = &s->async->cmd;
505 unsigned int chan, range, aref;
506 unsigned int divider;
507 unsigned int tscandiv;
510 for (i = 0; i < cmd->chanlist_len; i++) {
511 chan = CR_CHAN(cmd->chanlist[i]);
512 range = CR_RANGE(cmd->chanlist[i]);
514 writew((range << 6) | chan,
515 devpriv->io_addr + DPR_ADC_buffer + i);
517 aref = CR_AREF(cmd->chanlist[0]);
519 writew(cmd->scan_end_arg, devpriv->io_addr + DPR_Params(0));
521 if (cmd->convert_src == TRIG_TIMER) {
522 divider = dt3k_ns_to_timer(50, &cmd->convert_arg,
523 cmd->flags & TRIG_ROUND_MASK);
524 writew((divider >> 16), devpriv->io_addr + DPR_Params(1));
525 writew((divider & 0xffff), devpriv->io_addr + DPR_Params(2));
528 if (cmd->scan_begin_src == TRIG_TIMER) {
529 tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
530 cmd->flags & TRIG_ROUND_MASK);
531 writew((tscandiv >> 16), devpriv->io_addr + DPR_Params(3));
532 writew((tscandiv & 0xffff), devpriv->io_addr + DPR_Params(4));
535 mode = DT3000_AD_RETRIG_INTERNAL | 0 | 0;
536 writew(mode, devpriv->io_addr + DPR_Params(5));
537 writew(aref == AREF_DIFF, devpriv->io_addr + DPR_Params(6));
539 writew(AI_FIFO_DEPTH / 2, devpriv->io_addr + DPR_Params(7));
541 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
542 dt3k_send_cmd(dev, CMD_CONFIG);
544 writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR,
545 devpriv->io_addr + DPR_Int_Mask);
549 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
550 dt3k_send_cmd(dev, CMD_START);
555 static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
556 struct comedi_insn *insn, unsigned int *data)
559 unsigned int chan, gain, aref;
561 chan = CR_CHAN(insn->chanspec);
562 gain = CR_RANGE(insn->chanspec);
563 /* XXX docs don't explain how to select aref */
564 aref = CR_AREF(insn->chanspec);
566 for (i = 0; i < insn->n; i++)
567 data[i] = dt3k_readsingle(dev, SUBS_AI, chan, gain);
572 static int dt3k_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
573 struct comedi_insn *insn, unsigned int *data)
575 struct dt3k_private *devpriv = dev->private;
579 chan = CR_CHAN(insn->chanspec);
580 for (i = 0; i < insn->n; i++) {
581 dt3k_writesingle(dev, SUBS_AO, chan, data[i]);
582 devpriv->ao_readback[chan] = data[i];
588 static int dt3k_ao_insn_read(struct comedi_device *dev,
589 struct comedi_subdevice *s,
590 struct comedi_insn *insn, unsigned int *data)
592 struct dt3k_private *devpriv = dev->private;
596 chan = CR_CHAN(insn->chanspec);
597 for (i = 0; i < insn->n; i++)
598 data[i] = devpriv->ao_readback[chan];
603 static void dt3k_dio_config(struct comedi_device *dev, int bits)
605 struct dt3k_private *devpriv = dev->private;
608 writew(SUBS_DOUT, devpriv->io_addr + DPR_SubSys);
610 writew(bits, devpriv->io_addr + DPR_Params(0));
613 writew(0, devpriv->io_addr + DPR_Params(1));
614 writew(0, devpriv->io_addr + DPR_Params(2));
617 dt3k_send_cmd(dev, CMD_CONFIG);
620 static int dt3k_dio_insn_config(struct comedi_device *dev,
621 struct comedi_subdevice *s,
622 struct comedi_insn *insn,
625 unsigned int chan = CR_CHAN(insn->chanspec);
634 ret = comedi_dio_insn_config(dev, s, insn, data, mask);
638 dt3k_dio_config(dev, (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3));
643 static int dt3k_dio_insn_bits(struct comedi_device *dev,
644 struct comedi_subdevice *s,
645 struct comedi_insn *insn,
648 if (comedi_dio_update_state(s, data))
649 dt3k_writesingle(dev, SUBS_DOUT, 0, s->state);
651 data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0);
656 static int dt3k_mem_insn_read(struct comedi_device *dev,
657 struct comedi_subdevice *s,
658 struct comedi_insn *insn, unsigned int *data)
660 struct dt3k_private *devpriv = dev->private;
661 unsigned int addr = CR_CHAN(insn->chanspec);
664 for (i = 0; i < insn->n; i++) {
665 writew(SUBS_MEM, devpriv->io_addr + DPR_SubSys);
666 writew(addr, devpriv->io_addr + DPR_Params(0));
667 writew(1, devpriv->io_addr + DPR_Params(1));
669 dt3k_send_cmd(dev, CMD_READCODE);
671 data[i] = readw(devpriv->io_addr + DPR_Params(2));
677 static int dt3000_auto_attach(struct comedi_device *dev,
678 unsigned long context)
680 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
681 const struct dt3k_boardtype *this_board = NULL;
682 struct dt3k_private *devpriv;
683 struct comedi_subdevice *s;
686 if (context < ARRAY_SIZE(dt3k_boardtypes))
687 this_board = &dt3k_boardtypes[context];
690 dev->board_ptr = this_board;
691 dev->board_name = this_board->name;
693 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
697 ret = comedi_pci_enable(dev);
701 devpriv->io_addr = pci_ioremap_bar(pcidev, 0);
702 if (!devpriv->io_addr)
705 ret = request_irq(pcidev->irq, dt3k_interrupt, IRQF_SHARED,
706 dev->board_name, dev);
709 dev->irq = pcidev->irq;
711 ret = comedi_alloc_subdevices(dev, 4);
715 s = &dev->subdevices[0];
716 dev->read_subdev = s;
718 s->type = COMEDI_SUBD_AI;
719 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
720 s->n_chan = this_board->adchan;
721 s->insn_read = dt3k_ai_insn;
722 s->maxdata = (1 << this_board->adbits) - 1;
723 s->len_chanlist = 512;
724 s->range_table = &range_dt3000_ai; /* XXX */
725 s->do_cmd = dt3k_ai_cmd;
726 s->do_cmdtest = dt3k_ai_cmdtest;
727 s->cancel = dt3k_ai_cancel;
729 s = &dev->subdevices[1];
731 s->type = COMEDI_SUBD_AO;
732 s->subdev_flags = SDF_WRITABLE;
734 s->insn_read = dt3k_ao_insn_read;
735 s->insn_write = dt3k_ao_insn;
736 s->maxdata = (1 << this_board->dabits) - 1;
738 s->range_table = &range_bipolar10;
740 s = &dev->subdevices[2];
742 s->type = COMEDI_SUBD_DIO;
743 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
745 s->insn_config = dt3k_dio_insn_config;
746 s->insn_bits = dt3k_dio_insn_bits;
749 s->range_table = &range_digital;
751 s = &dev->subdevices[3];
753 s->type = COMEDI_SUBD_MEMORY;
754 s->subdev_flags = SDF_READABLE;
756 s->insn_read = dt3k_mem_insn_read;
759 s->range_table = &range_unknown;
762 s = &dev->subdevices[4];
764 s->type = COMEDI_SUBD_PROC;
767 dev_info(dev->class_dev, "%s attached\n", dev->board_name);
772 static void dt3000_detach(struct comedi_device *dev)
774 struct dt3k_private *devpriv = dev->private;
777 free_irq(dev->irq, dev);
779 if (devpriv->io_addr)
780 iounmap(devpriv->io_addr);
782 comedi_pci_disable(dev);
785 static struct comedi_driver dt3000_driver = {
786 .driver_name = "dt3000",
787 .module = THIS_MODULE,
788 .auto_attach = dt3000_auto_attach,
789 .detach = dt3000_detach,
792 static int dt3000_pci_probe(struct pci_dev *dev,
793 const struct pci_device_id *id)
795 return comedi_pci_auto_config(dev, &dt3000_driver, id->driver_data);
798 static const struct pci_device_id dt3000_pci_table[] = {
799 { PCI_VDEVICE(DT, 0x0022), BOARD_DT3001 },
800 { PCI_VDEVICE(DT, 0x0023), BOARD_DT3002 },
801 { PCI_VDEVICE(DT, 0x0024), BOARD_DT3003 },
802 { PCI_VDEVICE(DT, 0x0025), BOARD_DT3004 },
803 { PCI_VDEVICE(DT, 0x0026), BOARD_DT3005 },
804 { PCI_VDEVICE(DT, 0x0027), BOARD_DT3001_PGL },
805 { PCI_VDEVICE(DT, 0x0028), BOARD_DT3003_PGL },
808 MODULE_DEVICE_TABLE(pci, dt3000_pci_table);
810 static struct pci_driver dt3000_pci_driver = {
812 .id_table = dt3000_pci_table,
813 .probe = dt3000_pci_probe,
814 .remove = comedi_pci_auto_unconfig,
816 module_comedi_pci_driver(dt3000_driver, dt3000_pci_driver);
818 MODULE_AUTHOR("Comedi http://www.comedi.org");
819 MODULE_DESCRIPTION("Comedi low-level driver");
820 MODULE_LICENSE("GPL");