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.
53 #include <linux/module.h>
54 #include <linux/pci.h>
55 #include <linux/delay.h>
56 #include <linux/interrupt.h>
58 #include "../comedidev.h"
60 #include "comedi_fc.h"
62 static const struct comedi_lrange range_dt3000_ai = {
71 static const struct comedi_lrange range_dt3000_ai_pgl = {
90 struct dt3k_boardtype {
95 const struct comedi_lrange *adrange;
100 static const struct dt3k_boardtype dt3k_boardtypes[] = {
105 .adrange = &range_dt3000_ai,
110 [BOARD_DT3001_PGL] = {
111 .name = "dt3001-pgl",
114 .adrange = &range_dt3000_ai_pgl,
123 .adrange = &range_dt3000_ai,
130 .adrange = &range_dt3000_ai,
135 [BOARD_DT3003_PGL] = {
136 .name = "dt3003-pgl",
139 .adrange = &range_dt3000_ai_pgl,
148 .adrange = &range_dt3000_ai,
154 .name = "dt3005", /* a.k.a. 3004-200 */
157 .adrange = &range_dt3000_ai,
164 /* dual-ported RAM location definitions */
166 #define DPR_DAC_buffer (4*0x000)
167 #define DPR_ADC_buffer (4*0x800)
168 #define DPR_Command (4*0xfd3)
169 #define DPR_SubSys (4*0xfd3)
170 #define DPR_Encode (4*0xfd4)
171 #define DPR_Params(a) (4*(0xfd5+(a)))
172 #define DPR_Tick_Reg_Lo (4*0xff5)
173 #define DPR_Tick_Reg_Hi (4*0xff6)
174 #define DPR_DA_Buf_Front (4*0xff7)
175 #define DPR_DA_Buf_Rear (4*0xff8)
176 #define DPR_AD_Buf_Front (4*0xff9)
177 #define DPR_AD_Buf_Rear (4*0xffa)
178 #define DPR_Int_Mask (4*0xffb)
179 #define DPR_Intr_Flag (4*0xffc)
180 #define DPR_Response_Mbx (4*0xffe)
181 #define DPR_Command_Mbx (4*0xfff)
183 #define AI_FIFO_DEPTH 2003
184 #define AO_FIFO_DEPTH 2048
188 #define CMD_GETBRDINFO 0
190 #define CMD_GETCONFIG 2
193 #define CMD_READSINGLE 5
194 #define CMD_WRITESINGLE 6
195 #define CMD_CALCCLOCK 7
196 #define CMD_READEVENTS 8
197 #define CMD_WRITECTCTRL 16
198 #define CMD_READCTCTRL 17
199 #define CMD_WRITECT 18
200 #define CMD_READCT 19
201 #define CMD_WRITEDATA 32
202 #define CMD_READDATA 33
203 #define CMD_WRITEIO 34
204 #define CMD_READIO 35
205 #define CMD_WRITECODE 36
206 #define CMD_READCODE 37
207 #define CMD_EXECUTE 38
217 /* interrupt flags */
218 #define DT3000_CMDONE 0x80
219 #define DT3000_CTDONE 0x40
220 #define DT3000_DAHWERR 0x20
221 #define DT3000_DASWERR 0x10
222 #define DT3000_DAEMPTY 0x08
223 #define DT3000_ADHWERR 0x04
224 #define DT3000_ADSWERR 0x02
225 #define DT3000_ADFULL 0x01
227 #define DT3000_COMPLETION_MASK 0xff00
228 #define DT3000_COMMAND_MASK 0x00ff
229 #define DT3000_NOTPROCESSED 0x0000
230 #define DT3000_NOERROR 0x5500
231 #define DT3000_ERROR 0xaa00
232 #define DT3000_NOTSUPPORTED 0xff00
234 #define DT3000_EXTERNAL_CLOCK 1
235 #define DT3000_RISING_EDGE 2
237 #define TMODE_MASK 0x1c
239 #define DT3000_AD_TRIG_INTERNAL (0<<2)
240 #define DT3000_AD_TRIG_EXTERNAL (1<<2)
241 #define DT3000_AD_RETRIG_INTERNAL (2<<2)
242 #define DT3000_AD_RETRIG_EXTERNAL (3<<2)
243 #define DT3000_AD_EXTRETRIG (4<<2)
245 #define DT3000_CHANNEL_MODE_SE 0
246 #define DT3000_CHANNEL_MODE_DI 1
248 struct dt3k_private {
249 void __iomem *io_addr;
251 unsigned int ao_readback[2];
252 unsigned int ai_front;
253 unsigned int ai_rear;
257 static char *intr_flags[] = {
258 "AdFull", "AdSwError", "AdHwError", "DaEmpty",
259 "DaSwError", "DaHwError", "CtDone", "CmDone",
262 static void debug_intr_flags(unsigned int flags)
265 printk(KERN_DEBUG "dt3k: intr_flags:");
266 for (i = 0; i < 8; i++) {
267 if (flags & (1 << i))
268 printk(KERN_CONT " %s", intr_flags[i]);
270 printk(KERN_CONT "\n");
276 static void dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd)
278 struct dt3k_private *devpriv = dev->private;
280 unsigned int status = 0;
282 writew(cmd, devpriv->io_addr + DPR_Command_Mbx);
284 for (i = 0; i < TIMEOUT; i++) {
285 status = readw(devpriv->io_addr + DPR_Command_Mbx);
286 if ((status & DT3000_COMPLETION_MASK) != DT3000_NOTPROCESSED)
291 if ((status & DT3000_COMPLETION_MASK) != DT3000_NOERROR)
292 dev_dbg(dev->class_dev, "%s: timeout/error status=0x%04x\n",
296 static unsigned int dt3k_readsingle(struct comedi_device *dev,
297 unsigned int subsys, unsigned int chan,
300 struct dt3k_private *devpriv = dev->private;
302 writew(subsys, devpriv->io_addr + DPR_SubSys);
304 writew(chan, devpriv->io_addr + DPR_Params(0));
305 writew(gain, devpriv->io_addr + DPR_Params(1));
307 dt3k_send_cmd(dev, CMD_READSINGLE);
309 return readw(devpriv->io_addr + DPR_Params(2));
312 static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys,
313 unsigned int chan, unsigned int data)
315 struct dt3k_private *devpriv = dev->private;
317 writew(subsys, devpriv->io_addr + DPR_SubSys);
319 writew(chan, devpriv->io_addr + DPR_Params(0));
320 writew(0, devpriv->io_addr + DPR_Params(1));
321 writew(data, devpriv->io_addr + DPR_Params(2));
323 dt3k_send_cmd(dev, CMD_WRITESINGLE);
326 static void dt3k_ai_empty_fifo(struct comedi_device *dev,
327 struct comedi_subdevice *s)
329 struct dt3k_private *devpriv = dev->private;
336 front = readw(devpriv->io_addr + DPR_AD_Buf_Front);
337 count = front - devpriv->ai_front;
339 count += AI_FIFO_DEPTH;
341 rear = devpriv->ai_rear;
343 for (i = 0; i < count; i++) {
344 data = readw(devpriv->io_addr + DPR_ADC_buffer + rear);
345 comedi_buf_put(s->async, data);
347 if (rear >= AI_FIFO_DEPTH)
351 devpriv->ai_rear = rear;
352 writew(rear, devpriv->io_addr + DPR_AD_Buf_Rear);
355 static int dt3k_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
357 struct dt3k_private *devpriv = dev->private;
359 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
360 dt3k_send_cmd(dev, CMD_STOP);
362 writew(0, devpriv->io_addr + DPR_Int_Mask);
367 static int debug_n_ints;
369 /* FIXME! Assumes shared interrupt is for this card. */
370 /* What's this debug_n_ints stuff? Obviously needs some work... */
371 static irqreturn_t dt3k_interrupt(int irq, void *d)
373 struct comedi_device *dev = d;
374 struct dt3k_private *devpriv = dev->private;
375 struct comedi_subdevice *s;
381 s = &dev->subdevices[0];
382 status = readw(devpriv->io_addr + DPR_Intr_Flag);
384 debug_intr_flags(status);
387 if (status & DT3000_ADFULL) {
388 dt3k_ai_empty_fifo(dev, s);
389 s->async->events |= COMEDI_CB_BLOCK;
392 if (status & (DT3000_ADSWERR | DT3000_ADHWERR))
393 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
396 if (debug_n_ints >= 10) {
397 dt3k_ai_cancel(dev, s);
398 s->async->events |= COMEDI_CB_EOA;
401 comedi_event(dev, s);
405 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
406 unsigned int round_mode)
408 int divider, base, prescale;
410 /* This function needs improvment */
411 /* Don't know if divider==0 works. */
413 for (prescale = 0; prescale < 16; prescale++) {
414 base = timer_base * (prescale + 1);
415 switch (round_mode) {
416 case TRIG_ROUND_NEAREST:
418 divider = (*nanosec + base / 2) / base;
420 case TRIG_ROUND_DOWN:
421 divider = (*nanosec) / base;
424 divider = (*nanosec) / base;
427 if (divider < 65536) {
428 *nanosec = divider * base;
429 return (prescale << 16) | (divider);
434 base = timer_base * (1 << prescale);
436 *nanosec = divider * base;
437 return (prescale << 16) | (divider);
440 static int dt3k_ai_cmdtest(struct comedi_device *dev,
441 struct comedi_subdevice *s, struct comedi_cmd *cmd)
443 const struct dt3k_boardtype *this_board = comedi_board(dev);
447 /* Step 1 : check if triggers are trivially valid */
449 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
450 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
451 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
452 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
453 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT);
458 /* Step 2a : make sure trigger sources are unique */
459 /* Step 2b : and mutually compatible */
464 /* Step 3: check if arguments are trivially valid */
466 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
468 if (cmd->scan_begin_src == TRIG_TIMER) {
469 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
470 this_board->ai_speed);
471 err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg,
475 if (cmd->convert_src == TRIG_TIMER) {
476 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
477 this_board->ai_speed);
478 err |= cfc_check_trigger_arg_max(&cmd->convert_arg,
482 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
484 if (cmd->stop_src == TRIG_COUNT)
485 err |= cfc_check_trigger_arg_max(&cmd->stop_arg, 0x00ffffff);
487 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
492 /* step 4: fix up any arguments */
494 if (cmd->scan_begin_src == TRIG_TIMER) {
495 tmp = cmd->scan_begin_arg;
496 dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
497 cmd->flags & TRIG_ROUND_MASK);
498 if (tmp != cmd->scan_begin_arg)
502 if (cmd->convert_src == TRIG_TIMER) {
503 tmp = cmd->convert_arg;
504 dt3k_ns_to_timer(50, &cmd->convert_arg,
505 cmd->flags & TRIG_ROUND_MASK);
506 if (tmp != cmd->convert_arg)
508 if (cmd->scan_begin_src == TRIG_TIMER &&
509 cmd->scan_begin_arg <
510 cmd->convert_arg * cmd->scan_end_arg) {
511 cmd->scan_begin_arg =
512 cmd->convert_arg * cmd->scan_end_arg;
523 static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
525 struct dt3k_private *devpriv = dev->private;
526 struct comedi_cmd *cmd = &s->async->cmd;
528 unsigned int chan, range, aref;
529 unsigned int divider;
530 unsigned int tscandiv;
533 for (i = 0; i < cmd->chanlist_len; i++) {
534 chan = CR_CHAN(cmd->chanlist[i]);
535 range = CR_RANGE(cmd->chanlist[i]);
537 writew((range << 6) | chan,
538 devpriv->io_addr + DPR_ADC_buffer + i);
540 aref = CR_AREF(cmd->chanlist[0]);
542 writew(cmd->scan_end_arg, devpriv->io_addr + DPR_Params(0));
544 if (cmd->convert_src == TRIG_TIMER) {
545 divider = dt3k_ns_to_timer(50, &cmd->convert_arg,
546 cmd->flags & TRIG_ROUND_MASK);
547 writew((divider >> 16), devpriv->io_addr + DPR_Params(1));
548 writew((divider & 0xffff), devpriv->io_addr + DPR_Params(2));
551 if (cmd->scan_begin_src == TRIG_TIMER) {
552 tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
553 cmd->flags & TRIG_ROUND_MASK);
554 writew((tscandiv >> 16), devpriv->io_addr + DPR_Params(3));
555 writew((tscandiv & 0xffff), devpriv->io_addr + DPR_Params(4));
558 mode = DT3000_AD_RETRIG_INTERNAL | 0 | 0;
559 writew(mode, devpriv->io_addr + DPR_Params(5));
560 writew(aref == AREF_DIFF, devpriv->io_addr + DPR_Params(6));
562 writew(AI_FIFO_DEPTH / 2, devpriv->io_addr + DPR_Params(7));
564 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
565 dt3k_send_cmd(dev, CMD_CONFIG);
567 writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR,
568 devpriv->io_addr + DPR_Int_Mask);
572 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
573 dt3k_send_cmd(dev, CMD_START);
578 static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
579 struct comedi_insn *insn, unsigned int *data)
582 unsigned int chan, gain, aref;
584 chan = CR_CHAN(insn->chanspec);
585 gain = CR_RANGE(insn->chanspec);
586 /* XXX docs don't explain how to select aref */
587 aref = CR_AREF(insn->chanspec);
589 for (i = 0; i < insn->n; i++)
590 data[i] = dt3k_readsingle(dev, SUBS_AI, chan, gain);
595 static int dt3k_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
596 struct comedi_insn *insn, unsigned int *data)
598 struct dt3k_private *devpriv = dev->private;
602 chan = CR_CHAN(insn->chanspec);
603 for (i = 0; i < insn->n; i++) {
604 dt3k_writesingle(dev, SUBS_AO, chan, data[i]);
605 devpriv->ao_readback[chan] = data[i];
611 static int dt3k_ao_insn_read(struct comedi_device *dev,
612 struct comedi_subdevice *s,
613 struct comedi_insn *insn, unsigned int *data)
615 struct dt3k_private *devpriv = dev->private;
619 chan = CR_CHAN(insn->chanspec);
620 for (i = 0; i < insn->n; i++)
621 data[i] = devpriv->ao_readback[chan];
626 static void dt3k_dio_config(struct comedi_device *dev, int bits)
628 struct dt3k_private *devpriv = dev->private;
631 writew(SUBS_DOUT, devpriv->io_addr + DPR_SubSys);
633 writew(bits, devpriv->io_addr + DPR_Params(0));
636 writew(0, devpriv->io_addr + DPR_Params(1));
637 writew(0, devpriv->io_addr + DPR_Params(2));
640 dt3k_send_cmd(dev, CMD_CONFIG);
643 static int dt3k_dio_insn_config(struct comedi_device *dev,
644 struct comedi_subdevice *s,
645 struct comedi_insn *insn,
648 unsigned int chan = CR_CHAN(insn->chanspec);
657 ret = comedi_dio_insn_config(dev, s, insn, data, mask);
661 dt3k_dio_config(dev, (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3));
666 static int dt3k_dio_insn_bits(struct comedi_device *dev,
667 struct comedi_subdevice *s,
668 struct comedi_insn *insn,
671 if (comedi_dio_update_state(s, data))
672 dt3k_writesingle(dev, SUBS_DOUT, 0, s->state);
674 data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0);
679 static int dt3k_mem_insn_read(struct comedi_device *dev,
680 struct comedi_subdevice *s,
681 struct comedi_insn *insn, unsigned int *data)
683 struct dt3k_private *devpriv = dev->private;
684 unsigned int addr = CR_CHAN(insn->chanspec);
687 for (i = 0; i < insn->n; i++) {
688 writew(SUBS_MEM, devpriv->io_addr + DPR_SubSys);
689 writew(addr, devpriv->io_addr + DPR_Params(0));
690 writew(1, devpriv->io_addr + DPR_Params(1));
692 dt3k_send_cmd(dev, CMD_READCODE);
694 data[i] = readw(devpriv->io_addr + DPR_Params(2));
700 static int dt3000_auto_attach(struct comedi_device *dev,
701 unsigned long context)
703 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
704 const struct dt3k_boardtype *this_board = NULL;
705 struct dt3k_private *devpriv;
706 struct comedi_subdevice *s;
709 if (context < ARRAY_SIZE(dt3k_boardtypes))
710 this_board = &dt3k_boardtypes[context];
713 dev->board_ptr = this_board;
714 dev->board_name = this_board->name;
716 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
720 ret = comedi_pci_enable(dev);
724 devpriv->io_addr = pci_ioremap_bar(pcidev, 0);
725 if (!devpriv->io_addr)
728 ret = request_irq(pcidev->irq, dt3k_interrupt, IRQF_SHARED,
729 dev->board_name, dev);
732 dev->irq = pcidev->irq;
734 ret = comedi_alloc_subdevices(dev, 4);
738 s = &dev->subdevices[0];
739 dev->read_subdev = s;
741 s->type = COMEDI_SUBD_AI;
742 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
743 s->n_chan = this_board->adchan;
744 s->insn_read = dt3k_ai_insn;
745 s->maxdata = (1 << this_board->adbits) - 1;
746 s->len_chanlist = 512;
747 s->range_table = &range_dt3000_ai; /* XXX */
748 s->do_cmd = dt3k_ai_cmd;
749 s->do_cmdtest = dt3k_ai_cmdtest;
750 s->cancel = dt3k_ai_cancel;
752 s = &dev->subdevices[1];
754 s->type = COMEDI_SUBD_AO;
755 s->subdev_flags = SDF_WRITABLE;
757 s->insn_read = dt3k_ao_insn_read;
758 s->insn_write = dt3k_ao_insn;
759 s->maxdata = (1 << this_board->dabits) - 1;
761 s->range_table = &range_bipolar10;
763 s = &dev->subdevices[2];
765 s->type = COMEDI_SUBD_DIO;
766 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
768 s->insn_config = dt3k_dio_insn_config;
769 s->insn_bits = dt3k_dio_insn_bits;
772 s->range_table = &range_digital;
774 s = &dev->subdevices[3];
776 s->type = COMEDI_SUBD_MEMORY;
777 s->subdev_flags = SDF_READABLE;
779 s->insn_read = dt3k_mem_insn_read;
782 s->range_table = &range_unknown;
785 s = &dev->subdevices[4];
787 s->type = COMEDI_SUBD_PROC;
790 dev_info(dev->class_dev, "%s attached\n", dev->board_name);
795 static void dt3000_detach(struct comedi_device *dev)
797 struct dt3k_private *devpriv = dev->private;
800 free_irq(dev->irq, dev);
802 if (devpriv->io_addr)
803 iounmap(devpriv->io_addr);
805 comedi_pci_disable(dev);
808 static struct comedi_driver dt3000_driver = {
809 .driver_name = "dt3000",
810 .module = THIS_MODULE,
811 .auto_attach = dt3000_auto_attach,
812 .detach = dt3000_detach,
815 static int dt3000_pci_probe(struct pci_dev *dev,
816 const struct pci_device_id *id)
818 return comedi_pci_auto_config(dev, &dt3000_driver, id->driver_data);
821 static DEFINE_PCI_DEVICE_TABLE(dt3000_pci_table) = {
822 { PCI_VDEVICE(DT, 0x0022), BOARD_DT3001 },
823 { PCI_VDEVICE(DT, 0x0023), BOARD_DT3002 },
824 { PCI_VDEVICE(DT, 0x0024), BOARD_DT3003 },
825 { PCI_VDEVICE(DT, 0x0025), BOARD_DT3004 },
826 { PCI_VDEVICE(DT, 0x0026), BOARD_DT3005 },
827 { PCI_VDEVICE(DT, 0x0027), BOARD_DT3001_PGL },
828 { PCI_VDEVICE(DT, 0x0028), BOARD_DT3003_PGL },
831 MODULE_DEVICE_TABLE(pci, dt3000_pci_table);
833 static struct pci_driver dt3000_pci_driver = {
835 .id_table = dt3000_pci_table,
836 .probe = dt3000_pci_probe,
837 .remove = comedi_pci_auto_unconfig,
839 module_comedi_pci_driver(dt3000_driver, dt3000_pci_driver);
841 MODULE_AUTHOR("Comedi http://www.comedi.org");
842 MODULE_DESCRIPTION("Comedi low-level driver");
843 MODULE_LICENSE("GPL");