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.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 Description: Data Translation DT3000 series
27 Devices: [Data Translation] DT3001 (dt3000), DT3001-PGL, DT3002, DT3003,
28 DT3003-PGL, DT3004, DT3005, DT3004-200
29 Updated: Mon, 14 Apr 2008 15:41:24 +0100
32 Configuration Options: not applicable, uses PCI auto config
34 There is code to support AI commands, but it may not work.
36 AO commands are not supported.
40 The DT3000 series is Data Translation's attempt to make a PCI
41 data acquisition board. The design of this series is very nice,
42 since each board has an on-board DSP (Texas Instruments TMS320C52).
43 However, a few details are a little annoying. The boards lack
44 bus-mastering DMA, which eliminates them from serious work.
45 They also are not capable of autocalibration, which is a common
46 feature in modern hardware. The default firmware is pretty bad,
47 making it nearly impossible to write an RT compatible driver.
48 It would make an interesting project to write a decent firmware
51 Data Translation originally wanted an NDA for the documentation
52 for the 3k series. However, if you ask nicely, they might send
53 you the docs without one, also.
58 #include <linux/pci.h>
59 #include <linux/delay.h>
60 #include <linux/interrupt.h>
62 #include "../comedidev.h"
64 #include "comedi_fc.h"
66 static const struct comedi_lrange range_dt3000_ai = {
75 static const struct comedi_lrange range_dt3000_ai_pgl = {
94 struct dt3k_boardtype {
99 const struct comedi_lrange *adrange;
104 static const struct dt3k_boardtype dt3k_boardtypes[] = {
109 .adrange = &range_dt3000_ai,
114 [BOARD_DT3001_PGL] = {
115 .name = "dt3001-pgl",
118 .adrange = &range_dt3000_ai_pgl,
127 .adrange = &range_dt3000_ai,
134 .adrange = &range_dt3000_ai,
139 [BOARD_DT3003_PGL] = {
140 .name = "dt3003-pgl",
143 .adrange = &range_dt3000_ai_pgl,
152 .adrange = &range_dt3000_ai,
158 .name = "dt3005", /* a.k.a. 3004-200 */
161 .adrange = &range_dt3000_ai,
168 /* dual-ported RAM location definitions */
170 #define DPR_DAC_buffer (4*0x000)
171 #define DPR_ADC_buffer (4*0x800)
172 #define DPR_Command (4*0xfd3)
173 #define DPR_SubSys (4*0xfd3)
174 #define DPR_Encode (4*0xfd4)
175 #define DPR_Params(a) (4*(0xfd5+(a)))
176 #define DPR_Tick_Reg_Lo (4*0xff5)
177 #define DPR_Tick_Reg_Hi (4*0xff6)
178 #define DPR_DA_Buf_Front (4*0xff7)
179 #define DPR_DA_Buf_Rear (4*0xff8)
180 #define DPR_AD_Buf_Front (4*0xff9)
181 #define DPR_AD_Buf_Rear (4*0xffa)
182 #define DPR_Int_Mask (4*0xffb)
183 #define DPR_Intr_Flag (4*0xffc)
184 #define DPR_Response_Mbx (4*0xffe)
185 #define DPR_Command_Mbx (4*0xfff)
187 #define AI_FIFO_DEPTH 2003
188 #define AO_FIFO_DEPTH 2048
192 #define CMD_GETBRDINFO 0
194 #define CMD_GETCONFIG 2
197 #define CMD_READSINGLE 5
198 #define CMD_WRITESINGLE 6
199 #define CMD_CALCCLOCK 7
200 #define CMD_READEVENTS 8
201 #define CMD_WRITECTCTRL 16
202 #define CMD_READCTCTRL 17
203 #define CMD_WRITECT 18
204 #define CMD_READCT 19
205 #define CMD_WRITEDATA 32
206 #define CMD_READDATA 33
207 #define CMD_WRITEIO 34
208 #define CMD_READIO 35
209 #define CMD_WRITECODE 36
210 #define CMD_READCODE 37
211 #define CMD_EXECUTE 38
221 /* interrupt flags */
222 #define DT3000_CMDONE 0x80
223 #define DT3000_CTDONE 0x40
224 #define DT3000_DAHWERR 0x20
225 #define DT3000_DASWERR 0x10
226 #define DT3000_DAEMPTY 0x08
227 #define DT3000_ADHWERR 0x04
228 #define DT3000_ADSWERR 0x02
229 #define DT3000_ADFULL 0x01
231 #define DT3000_COMPLETION_MASK 0xff00
232 #define DT3000_COMMAND_MASK 0x00ff
233 #define DT3000_NOTPROCESSED 0x0000
234 #define DT3000_NOERROR 0x5500
235 #define DT3000_ERROR 0xaa00
236 #define DT3000_NOTSUPPORTED 0xff00
238 #define DT3000_EXTERNAL_CLOCK 1
239 #define DT3000_RISING_EDGE 2
241 #define TMODE_MASK 0x1c
243 #define DT3000_AD_TRIG_INTERNAL (0<<2)
244 #define DT3000_AD_TRIG_EXTERNAL (1<<2)
245 #define DT3000_AD_RETRIG_INTERNAL (2<<2)
246 #define DT3000_AD_RETRIG_EXTERNAL (3<<2)
247 #define DT3000_AD_EXTRETRIG (4<<2)
249 #define DT3000_CHANNEL_MODE_SE 0
250 #define DT3000_CHANNEL_MODE_DI 1
252 struct dt3k_private {
253 void __iomem *io_addr;
255 unsigned int ao_readback[2];
256 unsigned int ai_front;
257 unsigned int ai_rear;
261 static char *intr_flags[] = {
262 "AdFull", "AdSwError", "AdHwError", "DaEmpty",
263 "DaSwError", "DaHwError", "CtDone", "CmDone",
266 static void debug_intr_flags(unsigned int flags)
269 printk(KERN_DEBUG "dt3k: intr_flags:");
270 for (i = 0; i < 8; i++) {
271 if (flags & (1 << i))
272 printk(KERN_CONT " %s", intr_flags[i]);
274 printk(KERN_CONT "\n");
280 static void dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd)
282 struct dt3k_private *devpriv = dev->private;
284 unsigned int status = 0;
286 writew(cmd, devpriv->io_addr + DPR_Command_Mbx);
288 for (i = 0; i < TIMEOUT; i++) {
289 status = readw(devpriv->io_addr + DPR_Command_Mbx);
290 if ((status & DT3000_COMPLETION_MASK) != DT3000_NOTPROCESSED)
295 if ((status & DT3000_COMPLETION_MASK) != DT3000_NOERROR)
296 dev_dbg(dev->class_dev, "%s: timeout/error status=0x%04x\n",
300 static unsigned int dt3k_readsingle(struct comedi_device *dev,
301 unsigned int subsys, unsigned int chan,
304 struct dt3k_private *devpriv = dev->private;
306 writew(subsys, devpriv->io_addr + DPR_SubSys);
308 writew(chan, devpriv->io_addr + DPR_Params(0));
309 writew(gain, devpriv->io_addr + DPR_Params(1));
311 dt3k_send_cmd(dev, CMD_READSINGLE);
313 return readw(devpriv->io_addr + DPR_Params(2));
316 static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys,
317 unsigned int chan, unsigned int data)
319 struct dt3k_private *devpriv = dev->private;
321 writew(subsys, devpriv->io_addr + DPR_SubSys);
323 writew(chan, devpriv->io_addr + DPR_Params(0));
324 writew(0, devpriv->io_addr + DPR_Params(1));
325 writew(data, devpriv->io_addr + DPR_Params(2));
327 dt3k_send_cmd(dev, CMD_WRITESINGLE);
330 static void dt3k_ai_empty_fifo(struct comedi_device *dev,
331 struct comedi_subdevice *s)
333 struct dt3k_private *devpriv = dev->private;
340 front = readw(devpriv->io_addr + DPR_AD_Buf_Front);
341 count = front - devpriv->ai_front;
343 count += AI_FIFO_DEPTH;
345 rear = devpriv->ai_rear;
347 for (i = 0; i < count; i++) {
348 data = readw(devpriv->io_addr + DPR_ADC_buffer + rear);
349 comedi_buf_put(s->async, data);
351 if (rear >= AI_FIFO_DEPTH)
355 devpriv->ai_rear = rear;
356 writew(rear, devpriv->io_addr + DPR_AD_Buf_Rear);
359 static int dt3k_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
361 struct dt3k_private *devpriv = dev->private;
363 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
364 dt3k_send_cmd(dev, CMD_STOP);
366 writew(0, devpriv->io_addr + DPR_Int_Mask);
371 static int debug_n_ints;
373 /* FIXME! Assumes shared interrupt is for this card. */
374 /* What's this debug_n_ints stuff? Obviously needs some work... */
375 static irqreturn_t dt3k_interrupt(int irq, void *d)
377 struct comedi_device *dev = d;
378 struct dt3k_private *devpriv = dev->private;
379 struct comedi_subdevice *s;
385 s = &dev->subdevices[0];
386 status = readw(devpriv->io_addr + DPR_Intr_Flag);
388 debug_intr_flags(status);
391 if (status & DT3000_ADFULL) {
392 dt3k_ai_empty_fifo(dev, s);
393 s->async->events |= COMEDI_CB_BLOCK;
396 if (status & (DT3000_ADSWERR | DT3000_ADHWERR))
397 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
400 if (debug_n_ints >= 10) {
401 dt3k_ai_cancel(dev, s);
402 s->async->events |= COMEDI_CB_EOA;
405 comedi_event(dev, s);
409 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
410 unsigned int round_mode)
412 int divider, base, prescale;
414 /* This function needs improvment */
415 /* Don't know if divider==0 works. */
417 for (prescale = 0; prescale < 16; prescale++) {
418 base = timer_base * (prescale + 1);
419 switch (round_mode) {
420 case TRIG_ROUND_NEAREST:
422 divider = (*nanosec + base / 2) / base;
424 case TRIG_ROUND_DOWN:
425 divider = (*nanosec) / base;
428 divider = (*nanosec) / base;
431 if (divider < 65536) {
432 *nanosec = divider * base;
433 return (prescale << 16) | (divider);
438 base = timer_base * (1 << prescale);
440 *nanosec = divider * base;
441 return (prescale << 16) | (divider);
444 static int dt3k_ai_cmdtest(struct comedi_device *dev,
445 struct comedi_subdevice *s, struct comedi_cmd *cmd)
447 const struct dt3k_boardtype *this_board = comedi_board(dev);
451 /* Step 1 : check if triggers are trivially valid */
453 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
454 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
455 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
456 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
457 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT);
462 /* Step 2a : make sure trigger sources are unique */
463 /* Step 2b : and mutually compatible */
468 /* Step 3: check if arguments are trivially valid */
470 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
472 if (cmd->scan_begin_src == TRIG_TIMER) {
473 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
474 this_board->ai_speed);
475 err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg,
479 if (cmd->convert_src == TRIG_TIMER) {
480 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
481 this_board->ai_speed);
482 err |= cfc_check_trigger_arg_max(&cmd->convert_arg,
486 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
488 if (cmd->stop_src == TRIG_COUNT)
489 err |= cfc_check_trigger_arg_max(&cmd->stop_arg, 0x00ffffff);
491 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
496 /* step 4: fix up any arguments */
498 if (cmd->scan_begin_src == TRIG_TIMER) {
499 tmp = cmd->scan_begin_arg;
500 dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
501 cmd->flags & TRIG_ROUND_MASK);
502 if (tmp != cmd->scan_begin_arg)
506 if (cmd->convert_src == TRIG_TIMER) {
507 tmp = cmd->convert_arg;
508 dt3k_ns_to_timer(50, &cmd->convert_arg,
509 cmd->flags & TRIG_ROUND_MASK);
510 if (tmp != cmd->convert_arg)
512 if (cmd->scan_begin_src == TRIG_TIMER &&
513 cmd->scan_begin_arg <
514 cmd->convert_arg * cmd->scan_end_arg) {
515 cmd->scan_begin_arg =
516 cmd->convert_arg * cmd->scan_end_arg;
527 static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
529 struct dt3k_private *devpriv = dev->private;
530 struct comedi_cmd *cmd = &s->async->cmd;
532 unsigned int chan, range, aref;
533 unsigned int divider;
534 unsigned int tscandiv;
537 for (i = 0; i < cmd->chanlist_len; i++) {
538 chan = CR_CHAN(cmd->chanlist[i]);
539 range = CR_RANGE(cmd->chanlist[i]);
541 writew((range << 6) | chan,
542 devpriv->io_addr + DPR_ADC_buffer + i);
544 aref = CR_AREF(cmd->chanlist[0]);
546 writew(cmd->scan_end_arg, devpriv->io_addr + DPR_Params(0));
548 if (cmd->convert_src == TRIG_TIMER) {
549 divider = dt3k_ns_to_timer(50, &cmd->convert_arg,
550 cmd->flags & TRIG_ROUND_MASK);
551 writew((divider >> 16), devpriv->io_addr + DPR_Params(1));
552 writew((divider & 0xffff), devpriv->io_addr + DPR_Params(2));
555 if (cmd->scan_begin_src == TRIG_TIMER) {
556 tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
557 cmd->flags & TRIG_ROUND_MASK);
558 writew((tscandiv >> 16), devpriv->io_addr + DPR_Params(3));
559 writew((tscandiv & 0xffff), devpriv->io_addr + DPR_Params(4));
562 mode = DT3000_AD_RETRIG_INTERNAL | 0 | 0;
563 writew(mode, devpriv->io_addr + DPR_Params(5));
564 writew(aref == AREF_DIFF, devpriv->io_addr + DPR_Params(6));
566 writew(AI_FIFO_DEPTH / 2, devpriv->io_addr + DPR_Params(7));
568 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
569 dt3k_send_cmd(dev, CMD_CONFIG);
571 writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR,
572 devpriv->io_addr + DPR_Int_Mask);
576 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
577 dt3k_send_cmd(dev, CMD_START);
582 static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
583 struct comedi_insn *insn, unsigned int *data)
586 unsigned int chan, gain, aref;
588 chan = CR_CHAN(insn->chanspec);
589 gain = CR_RANGE(insn->chanspec);
590 /* XXX docs don't explain how to select aref */
591 aref = CR_AREF(insn->chanspec);
593 for (i = 0; i < insn->n; i++)
594 data[i] = dt3k_readsingle(dev, SUBS_AI, chan, gain);
599 static int dt3k_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
600 struct comedi_insn *insn, unsigned int *data)
602 struct dt3k_private *devpriv = dev->private;
606 chan = CR_CHAN(insn->chanspec);
607 for (i = 0; i < insn->n; i++) {
608 dt3k_writesingle(dev, SUBS_AO, chan, data[i]);
609 devpriv->ao_readback[chan] = data[i];
615 static int dt3k_ao_insn_read(struct comedi_device *dev,
616 struct comedi_subdevice *s,
617 struct comedi_insn *insn, unsigned int *data)
619 struct dt3k_private *devpriv = dev->private;
623 chan = CR_CHAN(insn->chanspec);
624 for (i = 0; i < insn->n; i++)
625 data[i] = devpriv->ao_readback[chan];
630 static void dt3k_dio_config(struct comedi_device *dev, int bits)
632 struct dt3k_private *devpriv = dev->private;
635 writew(SUBS_DOUT, devpriv->io_addr + DPR_SubSys);
637 writew(bits, devpriv->io_addr + DPR_Params(0));
640 writew(0, devpriv->io_addr + DPR_Params(1));
641 writew(0, devpriv->io_addr + DPR_Params(2));
644 dt3k_send_cmd(dev, CMD_CONFIG);
647 static int dt3k_dio_insn_config(struct comedi_device *dev,
648 struct comedi_subdevice *s,
649 struct comedi_insn *insn, unsigned int *data)
653 mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0;
656 case INSN_CONFIG_DIO_OUTPUT:
659 case INSN_CONFIG_DIO_INPUT:
662 case INSN_CONFIG_DIO_QUERY:
665 io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT :
673 mask = (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3);
674 dt3k_dio_config(dev, mask);
679 static int dt3k_dio_insn_bits(struct comedi_device *dev,
680 struct comedi_subdevice *s,
681 struct comedi_insn *insn, unsigned int *data)
684 s->state &= ~data[0];
685 s->state |= data[1] & data[0];
686 dt3k_writesingle(dev, SUBS_DOUT, 0, s->state);
688 data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0);
693 static int dt3k_mem_insn_read(struct comedi_device *dev,
694 struct comedi_subdevice *s,
695 struct comedi_insn *insn, unsigned int *data)
697 struct dt3k_private *devpriv = dev->private;
698 unsigned int addr = CR_CHAN(insn->chanspec);
701 for (i = 0; i < insn->n; i++) {
702 writew(SUBS_MEM, devpriv->io_addr + DPR_SubSys);
703 writew(addr, devpriv->io_addr + DPR_Params(0));
704 writew(1, devpriv->io_addr + DPR_Params(1));
706 dt3k_send_cmd(dev, CMD_READCODE);
708 data[i] = readw(devpriv->io_addr + DPR_Params(2));
714 static int dt3000_auto_attach(struct comedi_device *dev,
715 unsigned long context)
717 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
718 const struct dt3k_boardtype *this_board = NULL;
719 struct dt3k_private *devpriv;
720 struct comedi_subdevice *s;
723 if (context < ARRAY_SIZE(dt3k_boardtypes))
724 this_board = &dt3k_boardtypes[context];
727 dev->board_ptr = this_board;
728 dev->board_name = this_board->name;
730 devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
733 dev->private = devpriv;
735 ret = comedi_pci_enable(dev);
739 devpriv->io_addr = pci_ioremap_bar(pcidev, 0);
740 if (!devpriv->io_addr)
743 ret = request_irq(pcidev->irq, dt3k_interrupt, IRQF_SHARED,
744 dev->board_name, dev);
747 dev->irq = pcidev->irq;
749 ret = comedi_alloc_subdevices(dev, 4);
753 s = &dev->subdevices[0];
754 dev->read_subdev = s;
756 s->type = COMEDI_SUBD_AI;
757 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
758 s->n_chan = this_board->adchan;
759 s->insn_read = dt3k_ai_insn;
760 s->maxdata = (1 << this_board->adbits) - 1;
761 s->len_chanlist = 512;
762 s->range_table = &range_dt3000_ai; /* XXX */
763 s->do_cmd = dt3k_ai_cmd;
764 s->do_cmdtest = dt3k_ai_cmdtest;
765 s->cancel = dt3k_ai_cancel;
767 s = &dev->subdevices[1];
769 s->type = COMEDI_SUBD_AO;
770 s->subdev_flags = SDF_WRITABLE;
772 s->insn_read = dt3k_ao_insn_read;
773 s->insn_write = dt3k_ao_insn;
774 s->maxdata = (1 << this_board->dabits) - 1;
776 s->range_table = &range_bipolar10;
778 s = &dev->subdevices[2];
780 s->type = COMEDI_SUBD_DIO;
781 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
783 s->insn_config = dt3k_dio_insn_config;
784 s->insn_bits = dt3k_dio_insn_bits;
787 s->range_table = &range_digital;
789 s = &dev->subdevices[3];
791 s->type = COMEDI_SUBD_MEMORY;
792 s->subdev_flags = SDF_READABLE;
794 s->insn_read = dt3k_mem_insn_read;
797 s->range_table = &range_unknown;
800 s = &dev->subdevices[4];
802 s->type = COMEDI_SUBD_PROC;
805 dev_info(dev->class_dev, "%s attached\n", dev->board_name);
810 static void dt3000_detach(struct comedi_device *dev)
812 struct dt3k_private *devpriv = dev->private;
815 free_irq(dev->irq, dev);
817 if (devpriv->io_addr)
818 iounmap(devpriv->io_addr);
820 comedi_pci_disable(dev);
823 static struct comedi_driver dt3000_driver = {
824 .driver_name = "dt3000",
825 .module = THIS_MODULE,
826 .auto_attach = dt3000_auto_attach,
827 .detach = dt3000_detach,
830 static int dt3000_pci_probe(struct pci_dev *dev,
831 const struct pci_device_id *id)
833 return comedi_pci_auto_config(dev, &dt3000_driver, id->driver_data);
836 static DEFINE_PCI_DEVICE_TABLE(dt3000_pci_table) = {
837 { PCI_VDEVICE(DT, 0x0022), BOARD_DT3001 },
838 { PCI_VDEVICE(DT, 0x0023), BOARD_DT3002 },
839 { PCI_VDEVICE(DT, 0x0024), BOARD_DT3003 },
840 { PCI_VDEVICE(DT, 0x0025), BOARD_DT3004 },
841 { PCI_VDEVICE(DT, 0x0026), BOARD_DT3005 },
842 { PCI_VDEVICE(DT, 0x0027), BOARD_DT3001_PGL },
843 { PCI_VDEVICE(DT, 0x0028), BOARD_DT3003_PGL },
846 MODULE_DEVICE_TABLE(pci, dt3000_pci_table);
848 static struct pci_driver dt3000_pci_driver = {
850 .id_table = dt3000_pci_table,
851 .probe = dt3000_pci_probe,
852 .remove = comedi_pci_auto_unconfig,
854 module_comedi_pci_driver(dt3000_driver, dt3000_pci_driver);
856 MODULE_AUTHOR("Comedi http://www.comedi.org");
857 MODULE_DESCRIPTION("Comedi low-level driver");
858 MODULE_LICENSE("GPL");