3 * Comedi driver for Data Translation DT2821 series
5 * COMEDI - Linux Control and Measurement Device Interface
6 * Copyright (C) 1997-8 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.
21 * Description: Data Translation DT2821 series (including DT-EZ)
23 * Devices: [Data Translation] DT2821 (dt2821), DT2821-F-16SE (dt2821-f),
24 * DT2821-F-8DI (dt2821-f), DT2821-G-16SE (dt2821-g),
25 * DT2821-G-8DI (dt2821-g), DT2823 (dt2823), DT2824-PGH (dt2824-pgh),
26 * DT2824-PGL (dt2824-pgl), DT2825 (dt2825), DT2827 (dt2827),
27 * DT2828 (dt2828), DT2928 (dt2829), DT21-EZ (dt21-ez), DT23-EZ (dt23-ez),
28 * DT24-EZ (dt24-ez), DT24-EZ-PGL (dt24-ez-pgl)
30 * Updated: Wed, 22 Aug 2001 17:11:34 -0700
32 * Configuration options:
33 * [0] - I/O port base address
34 * [1] - IRQ (optional, required for async command support)
35 * [2] - DMA 1 (optional, required for async command support)
36 * [3] - DMA 2 (optional, required for async command support)
37 * [4] - AI jumpered for 0=single ended, 1=differential
38 * [5] - AI jumpered for 0=straight binary, 1=2's complement
39 * [6] - AO 0 data format (deprecated, see below)
40 * [7] - AO 1 data format (deprecated, see below)
41 * [8] - AI jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5]
42 * [9] - AO channel 0 range (deprecated, see below)
43 * [10]- AO channel 1 range (deprecated, see below)
46 * - AO commands might be broken.
47 * - If you try to run a command on both the AI and AO subdevices
48 * simultaneously, bad things will happen. The driver needs to
49 * be fixed to check for this situation and return an error.
50 * - AO range is not programmable. The AO subdevice has a range_table
51 * containing all the possible analog output ranges. Use the range
52 * that matches your board configuration to convert between data
53 * values and physical units. The format of the data written to the
54 * board is handled automatically based on the unipolar/bipolar
55 * range that is selected.
58 #include <linux/module.h>
59 #include <linux/delay.h>
60 #include <linux/gfp.h>
61 #include <linux/interrupt.h>
64 #include "../comedidev.h"
66 #include "comedi_isadma.h"
71 #define DT2821_ADCSR_REG 0x00
72 #define DT2821_ADCSR_ADERR (1 << 15)
73 #define DT2821_ADCSR_ADCLK (1 << 9)
74 #define DT2821_ADCSR_MUXBUSY (1 << 8)
75 #define DT2821_ADCSR_ADDONE (1 << 7)
76 #define DT2821_ADCSR_IADDONE (1 << 6)
77 #define DT2821_ADCSR_GS(x) (((x) & 0x3) << 4)
78 #define DT2821_ADCSR_CHAN(x) (((x) & 0xf) << 0)
79 #define DT2821_CHANCSR_REG 0x02
80 #define DT2821_CHANCSR_LLE (1 << 15)
81 #define DT2821_CHANCSR_PRESLA(x) (((x) & 0xf) >> 8)
82 #define DT2821_CHANCSR_NUMB(x) ((((x) - 1) & 0xf) << 0)
83 #define DT2821_ADDAT_REG 0x04
84 #define DT2821_DACSR_REG 0x06
85 #define DT2821_DACSR_DAERR (1 << 15)
86 #define DT2821_DACSR_YSEL(x) ((x) << 9)
87 #define DT2821_DACSR_SSEL (1 << 8)
88 #define DT2821_DACSR_DACRDY (1 << 7)
89 #define DT2821_DACSR_IDARDY (1 << 6)
90 #define DT2821_DACSR_DACLK (1 << 5)
91 #define DT2821_DACSR_HBOE (1 << 1)
92 #define DT2821_DACSR_LBOE (1 << 0)
93 #define DT2821_DADAT_REG 0x08
94 #define DT2821_DIODAT_REG 0x0a
95 #define DT2821_SUPCSR_REG 0x0c
96 #define DT2821_SUPCSR_DMAD (1 << 15)
97 #define DT2821_SUPCSR_ERRINTEN (1 << 14)
98 #define DT2821_SUPCSR_CLRDMADNE (1 << 13)
99 #define DT2821_SUPCSR_DDMA (1 << 12)
100 #define DT2821_SUPCSR_DS_PIO (0 << 10)
101 #define DT2821_SUPCSR_DS_AD_CLK (1 << 10)
102 #define DT2821_SUPCSR_DS_DA_CLK (2 << 10)
103 #define DT2821_SUPCSR_DS_AD_TRIG (3 << 10)
104 #define DT2821_SUPCSR_BUFFB (1 << 9)
105 #define DT2821_SUPCSR_SCDN (1 << 8)
106 #define DT2821_SUPCSR_DACON (1 << 7)
107 #define DT2821_SUPCSR_ADCINIT (1 << 6)
108 #define DT2821_SUPCSR_DACINIT (1 << 5)
109 #define DT2821_SUPCSR_PRLD (1 << 4)
110 #define DT2821_SUPCSR_STRIG (1 << 3)
111 #define DT2821_SUPCSR_XTRIG (1 << 2)
112 #define DT2821_SUPCSR_XCLK (1 << 1)
113 #define DT2821_SUPCSR_BDINIT (1 << 0)
114 #define DT2821_TMRCTR_REG 0x0e
116 static const struct comedi_lrange range_dt282x_ai_lo_bipolar = {
125 static const struct comedi_lrange range_dt282x_ai_lo_unipolar = {
134 static const struct comedi_lrange range_dt282x_ai_5_bipolar = {
143 static const struct comedi_lrange range_dt282x_ai_5_unipolar = {
152 static const struct comedi_lrange range_dt282x_ai_hi_bipolar = {
161 static const struct comedi_lrange range_dt282x_ai_hi_unipolar = {
171 * The Analog Output range is set per-channel using jumpers on the board.
172 * All of these ranges may not be available on some DT2821 series boards.
173 * The default jumper setting has both channels set for +/-10V output.
175 static const struct comedi_lrange dt282x_ao_range = {
185 struct dt282x_board {
187 unsigned int ai_maxdata;
193 unsigned int ao_maxdata;
196 static const struct dt282x_board boardtypes[] = {
199 .ai_maxdata = 0x0fff,
204 .ao_maxdata = 0x0fff,
207 .ai_maxdata = 0x0fff,
212 .ao_maxdata = 0x0fff,
215 .ai_maxdata = 0x0fff,
220 .ao_maxdata = 0x0fff,
223 .ai_maxdata = 0xffff,
227 .ao_maxdata = 0xffff,
229 .name = "dt2824-pgh",
230 .ai_maxdata = 0x0fff,
235 .name = "dt2824-pgl",
236 .ai_maxdata = 0x0fff,
243 .ai_maxdata = 0x0fff,
249 .ao_maxdata = 0x0fff,
252 .ai_maxdata = 0xffff,
256 .ao_maxdata = 0x0fff,
259 .ai_maxdata = 0x0fff,
263 .ao_maxdata = 0x0fff,
266 .ai_maxdata = 0xffff,
270 .ao_maxdata = 0xffff,
273 .ai_maxdata = 0x0fff,
278 .ao_maxdata = 0x0fff,
281 .ai_maxdata = 0xffff,
287 .ai_maxdata = 0x0fff,
292 .name = "dt24-ez-pgl",
293 .ai_maxdata = 0x0fff,
301 struct dt282x_private {
302 struct comedi_isadma *dma;
303 unsigned int ad_2scomp:1;
304 unsigned int divisor;
305 int dacsr; /* software copies of registers */
313 static int dt282x_prep_ai_dma(struct comedi_device *dev, int dma_index, int n)
315 struct dt282x_private *devpriv = dev->private;
316 struct comedi_isadma *dma = devpriv->dma;
317 struct comedi_isadma_desc *desc = &dma->desc[dma_index];
324 if (n > devpriv->ntrig * 2)
325 n = devpriv->ntrig * 2;
326 devpriv->ntrig -= n / 2;
329 comedi_isadma_set_mode(desc, devpriv->dma_dir);
331 comedi_isadma_program(desc);
336 static int dt282x_prep_ao_dma(struct comedi_device *dev, int dma_index, int n)
338 struct dt282x_private *devpriv = dev->private;
339 struct comedi_isadma *dma = devpriv->dma;
340 struct comedi_isadma_desc *desc = &dma->desc[dma_index];
343 comedi_isadma_set_mode(desc, devpriv->dma_dir);
345 comedi_isadma_program(desc);
350 static void dt282x_disable_dma(struct comedi_device *dev)
352 struct dt282x_private *devpriv = dev->private;
353 struct comedi_isadma *dma = devpriv->dma;
354 struct comedi_isadma_desc *desc;
357 for (i = 0; i < 2; i++) {
358 desc = &dma->desc[i];
359 comedi_isadma_disable(desc->chan);
363 static unsigned int dt282x_ns_to_timer(unsigned int *ns, unsigned int flags)
365 unsigned int prescale, base, divider;
367 for (prescale = 0; prescale < 16; prescale++) {
370 base = 250 * (1 << prescale);
371 switch (flags & CMDF_ROUND_MASK) {
372 case CMDF_ROUND_NEAREST:
374 divider = (*ns + base / 2) / base;
376 case CMDF_ROUND_DOWN:
377 divider = (*ns) / base;
380 divider = (*ns + base - 1) / base;
384 *ns = divider * base;
385 return (prescale << 8) | (255 - divider);
388 base = 250 * (1 << 15);
390 *ns = divider * base;
391 return (15 << 8) | (255 - divider);
394 static void dt282x_munge(struct comedi_device *dev,
395 struct comedi_subdevice *s,
399 struct dt282x_private *devpriv = dev->private;
404 dev_err(dev->class_dev,
405 "bug! odd number of bytes from dma xfer\n");
407 for (i = 0; i < nbytes / 2; i++) {
410 if (devpriv->ad_2scomp)
411 val = comedi_offset_munge(s, val);
417 static unsigned int dt282x_ao_setup_dma(struct comedi_device *dev,
418 struct comedi_subdevice *s,
421 struct dt282x_private *devpriv = dev->private;
422 struct comedi_isadma *dma = devpriv->dma;
423 struct comedi_isadma_desc *desc = &dma->desc[cur_dma];
424 unsigned int nsamples = comedi_bytes_to_samples(s, desc->maxsize);
427 nbytes = comedi_buf_read_samples(s, desc->virt_addr, nsamples);
429 dt282x_prep_ao_dma(dev, cur_dma, nbytes);
431 dev_err(dev->class_dev, "AO underrun\n");
436 static void dt282x_ao_dma_interrupt(struct comedi_device *dev,
437 struct comedi_subdevice *s)
439 struct dt282x_private *devpriv = dev->private;
440 struct comedi_isadma *dma = devpriv->dma;
441 struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
443 outw(devpriv->supcsr | DT2821_SUPCSR_CLRDMADNE,
444 dev->iobase + DT2821_SUPCSR_REG);
446 comedi_isadma_disable(desc->chan);
448 if (!dt282x_ao_setup_dma(dev, s, dma->cur_dma))
449 s->async->events |= COMEDI_CB_OVERFLOW;
451 dma->cur_dma = 1 - dma->cur_dma;
454 static void dt282x_ai_dma_interrupt(struct comedi_device *dev,
455 struct comedi_subdevice *s)
457 struct dt282x_private *devpriv = dev->private;
458 struct comedi_isadma *dma = devpriv->dma;
459 struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
460 unsigned int nsamples = comedi_bytes_to_samples(s, desc->size);
463 outw(devpriv->supcsr | DT2821_SUPCSR_CLRDMADNE,
464 dev->iobase + DT2821_SUPCSR_REG);
466 comedi_isadma_disable(desc->chan);
468 dt282x_munge(dev, s, desc->virt_addr, desc->size);
469 ret = comedi_buf_write_samples(s, desc->virt_addr, nsamples);
470 if (ret != desc->size)
473 devpriv->nread -= nsamples;
474 if (devpriv->nread < 0) {
475 dev_info(dev->class_dev, "nread off by one\n");
478 if (!devpriv->nread) {
479 s->async->events |= COMEDI_CB_EOA;
483 /* clear the dual dma flag, making this the last dma segment */
484 /* XXX probably wrong */
485 if (!devpriv->ntrig) {
486 devpriv->supcsr &= ~DT2821_SUPCSR_DDMA;
487 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR_REG);
490 /* restart the channel */
491 dt282x_prep_ai_dma(dev, dma->cur_dma, 0);
493 dma->cur_dma = 1 - dma->cur_dma;
496 static irqreturn_t dt282x_interrupt(int irq, void *d)
498 struct comedi_device *dev = d;
499 struct dt282x_private *devpriv = dev->private;
500 struct comedi_subdevice *s = dev->read_subdev;
501 struct comedi_subdevice *s_ao = dev->write_subdev;
502 unsigned int supcsr, adcsr, dacsr;
505 if (!dev->attached) {
506 dev_err(dev->class_dev, "spurious interrupt\n");
510 adcsr = inw(dev->iobase + DT2821_ADCSR_REG);
511 dacsr = inw(dev->iobase + DT2821_DACSR_REG);
512 supcsr = inw(dev->iobase + DT2821_SUPCSR_REG);
513 if (supcsr & DT2821_SUPCSR_DMAD) {
514 if (devpriv->dma_dir == COMEDI_ISADMA_READ)
515 dt282x_ai_dma_interrupt(dev, s);
517 dt282x_ao_dma_interrupt(dev, s_ao);
520 if (adcsr & DT2821_ADCSR_ADERR) {
521 if (devpriv->nread != 0) {
522 dev_err(dev->class_dev, "A/D error\n");
523 s->async->events |= COMEDI_CB_ERROR;
527 if (dacsr & DT2821_DACSR_DAERR) {
528 dev_err(dev->class_dev, "D/A error\n");
529 s_ao->async->events |= COMEDI_CB_ERROR;
533 if (adcsr & DT2821_ADCSR_ADDONE) {
536 data = inw(dev->iobase + DT2821_ADDAT_REG);
538 if (devpriv->ad_2scomp)
539 data = comedi_offset_munge(s, data);
541 comedi_buf_write_samples(s, &data, 1);
544 if (!devpriv->nread) {
545 s->async->events |= COMEDI_CB_EOA;
547 if (supcsr & DT2821_SUPCSR_SCDN)
548 outw(devpriv->supcsr | DT2821_SUPCSR_STRIG,
549 dev->iobase + DT2821_SUPCSR_REG);
554 comedi_handle_events(dev, s);
555 comedi_handle_events(dev, s_ao);
557 return IRQ_RETVAL(handled);
560 static void dt282x_load_changain(struct comedi_device *dev, int n,
561 unsigned int *chanlist)
563 struct dt282x_private *devpriv = dev->private;
566 outw(DT2821_CHANCSR_LLE | DT2821_CHANCSR_NUMB(n),
567 dev->iobase + DT2821_CHANCSR_REG);
568 for (i = 0; i < n; i++) {
569 unsigned int chan = CR_CHAN(chanlist[i]);
570 unsigned int range = CR_RANGE(chanlist[i]);
572 outw(devpriv->adcsr |
573 DT2821_ADCSR_GS(range) |
574 DT2821_ADCSR_CHAN(chan),
575 dev->iobase + DT2821_ADCSR_REG);
577 outw(DT2821_CHANCSR_NUMB(n), dev->iobase + DT2821_CHANCSR_REG);
580 static int dt282x_ai_timeout(struct comedi_device *dev,
581 struct comedi_subdevice *s,
582 struct comedi_insn *insn,
583 unsigned long context)
587 status = inw(dev->iobase + DT2821_ADCSR_REG);
589 case DT2821_ADCSR_MUXBUSY:
590 if ((status & DT2821_ADCSR_MUXBUSY) == 0)
593 case DT2821_ADCSR_ADDONE:
594 if (status & DT2821_ADCSR_ADDONE)
604 * Performs a single A/D conversion.
605 * - Put channel/gain into channel-gain list
606 * - preload multiplexer
607 * - trigger conversion and wait for it to finish
609 static int dt282x_ai_insn_read(struct comedi_device *dev,
610 struct comedi_subdevice *s,
611 struct comedi_insn *insn,
614 struct dt282x_private *devpriv = dev->private;
619 /* XXX should we really be enabling the ad clock here? */
620 devpriv->adcsr = DT2821_ADCSR_ADCLK;
621 outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR_REG);
623 dt282x_load_changain(dev, 1, &insn->chanspec);
625 outw(devpriv->supcsr | DT2821_SUPCSR_PRLD,
626 dev->iobase + DT2821_SUPCSR_REG);
627 ret = comedi_timeout(dev, s, insn,
628 dt282x_ai_timeout, DT2821_ADCSR_MUXBUSY);
632 for (i = 0; i < insn->n; i++) {
633 outw(devpriv->supcsr | DT2821_SUPCSR_STRIG,
634 dev->iobase + DT2821_SUPCSR_REG);
636 ret = comedi_timeout(dev, s, insn,
637 dt282x_ai_timeout, DT2821_ADCSR_ADDONE);
641 val = inw(dev->iobase + DT2821_ADDAT_REG);
643 if (devpriv->ad_2scomp)
644 val = comedi_offset_munge(s, val);
652 static int dt282x_ai_cmdtest(struct comedi_device *dev,
653 struct comedi_subdevice *s,
654 struct comedi_cmd *cmd)
656 const struct dt282x_board *board = dev->board_ptr;
657 struct dt282x_private *devpriv = dev->private;
661 /* Step 1 : check if triggers are trivially valid */
663 err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW);
664 err |= comedi_check_trigger_src(&cmd->scan_begin_src,
665 TRIG_FOLLOW | TRIG_EXT);
666 err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
667 err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
668 err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
673 /* Step 2a : make sure trigger sources are unique */
675 err |= comedi_check_trigger_is_unique(cmd->scan_begin_src);
676 err |= comedi_check_trigger_is_unique(cmd->stop_src);
678 /* Step 2b : and mutually compatible */
683 /* Step 3: check if arguments are trivially valid */
685 err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
687 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
689 err |= comedi_check_trigger_arg_min(&cmd->convert_arg, 4000);
691 #define SLOWEST_TIMER (250*(1<<15)*255)
692 err |= comedi_check_trigger_arg_max(&cmd->convert_arg, SLOWEST_TIMER);
693 err |= comedi_check_trigger_arg_min(&cmd->convert_arg, board->ai_speed);
694 err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
697 if (cmd->stop_src == TRIG_COUNT)
698 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
699 else /* TRIG_EXT | TRIG_NONE */
700 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
705 /* step 4: fix up any arguments */
707 arg = cmd->convert_arg;
708 devpriv->divisor = dt282x_ns_to_timer(&arg, cmd->flags);
709 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
717 static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
719 struct dt282x_private *devpriv = dev->private;
720 struct comedi_isadma *dma = devpriv->dma;
721 struct comedi_cmd *cmd = &s->async->cmd;
724 dt282x_disable_dma(dev);
726 outw(devpriv->divisor, dev->iobase + DT2821_TMRCTR_REG);
728 devpriv->supcsr = DT2821_SUPCSR_ERRINTEN;
729 if (cmd->scan_begin_src == TRIG_FOLLOW)
730 devpriv->supcsr = DT2821_SUPCSR_DS_AD_CLK;
732 devpriv->supcsr = DT2821_SUPCSR_DS_AD_TRIG;
733 outw(devpriv->supcsr |
734 DT2821_SUPCSR_CLRDMADNE |
735 DT2821_SUPCSR_BUFFB |
736 DT2821_SUPCSR_ADCINIT,
737 dev->iobase + DT2821_SUPCSR_REG);
739 devpriv->ntrig = cmd->stop_arg * cmd->scan_end_arg;
740 devpriv->nread = devpriv->ntrig;
742 devpriv->dma_dir = COMEDI_ISADMA_READ;
744 dt282x_prep_ai_dma(dev, 0, 0);
745 if (devpriv->ntrig) {
746 dt282x_prep_ai_dma(dev, 1, 0);
747 devpriv->supcsr |= DT2821_SUPCSR_DDMA;
748 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR_REG);
753 dt282x_load_changain(dev, cmd->chanlist_len, cmd->chanlist);
755 devpriv->adcsr = DT2821_ADCSR_ADCLK | DT2821_ADCSR_IADDONE;
756 outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR_REG);
758 outw(devpriv->supcsr | DT2821_SUPCSR_PRLD,
759 dev->iobase + DT2821_SUPCSR_REG);
760 ret = comedi_timeout(dev, s, NULL,
761 dt282x_ai_timeout, DT2821_ADCSR_MUXBUSY);
765 if (cmd->scan_begin_src == TRIG_FOLLOW) {
766 outw(devpriv->supcsr | DT2821_SUPCSR_STRIG,
767 dev->iobase + DT2821_SUPCSR_REG);
769 devpriv->supcsr |= DT2821_SUPCSR_XTRIG;
770 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR_REG);
776 static int dt282x_ai_cancel(struct comedi_device *dev,
777 struct comedi_subdevice *s)
779 struct dt282x_private *devpriv = dev->private;
781 dt282x_disable_dma(dev);
784 outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR_REG);
787 outw(devpriv->supcsr | DT2821_SUPCSR_ADCINIT,
788 dev->iobase + DT2821_SUPCSR_REG);
793 static int dt282x_ao_insn_write(struct comedi_device *dev,
794 struct comedi_subdevice *s,
795 struct comedi_insn *insn,
798 struct dt282x_private *devpriv = dev->private;
799 unsigned int chan = CR_CHAN(insn->chanspec);
800 unsigned int range = CR_RANGE(insn->chanspec);
803 devpriv->dacsr |= DT2821_DACSR_SSEL | DT2821_DACSR_YSEL(chan);
805 for (i = 0; i < insn->n; i++) {
806 unsigned int val = data[i];
808 s->readback[chan] = val;
810 if (comedi_range_is_bipolar(s, range))
811 val = comedi_offset_munge(s, val);
813 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR_REG);
815 outw(val, dev->iobase + DT2821_DADAT_REG);
817 outw(devpriv->supcsr | DT2821_SUPCSR_DACON,
818 dev->iobase + DT2821_SUPCSR_REG);
824 static int dt282x_ao_cmdtest(struct comedi_device *dev,
825 struct comedi_subdevice *s,
826 struct comedi_cmd *cmd)
828 struct dt282x_private *devpriv = dev->private;
832 /* Step 1 : check if triggers are trivially valid */
834 err |= comedi_check_trigger_src(&cmd->start_src, TRIG_INT);
835 err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
836 err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_NOW);
837 err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
838 err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
843 /* Step 2a : make sure trigger sources are unique */
845 err |= comedi_check_trigger_is_unique(cmd->stop_src);
847 /* Step 2b : and mutually compatible */
852 /* Step 3: check if arguments are trivially valid */
854 err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
855 err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg, 5000);
856 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
857 err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
860 if (cmd->stop_src == TRIG_COUNT)
861 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
862 else /* TRIG_EXT | TRIG_NONE */
863 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
868 /* step 4: fix up any arguments */
870 arg = cmd->scan_begin_arg;
871 devpriv->divisor = dt282x_ns_to_timer(&arg, cmd->flags);
872 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
880 static int dt282x_ao_inttrig(struct comedi_device *dev,
881 struct comedi_subdevice *s,
882 unsigned int trig_num)
884 struct dt282x_private *devpriv = dev->private;
885 struct comedi_cmd *cmd = &s->async->cmd;
887 if (trig_num != cmd->start_src)
890 if (!dt282x_ao_setup_dma(dev, s, 0))
893 if (!dt282x_ao_setup_dma(dev, s, 1))
896 outw(devpriv->supcsr | DT2821_SUPCSR_STRIG,
897 dev->iobase + DT2821_SUPCSR_REG);
898 s->async->inttrig = NULL;
903 static int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
905 struct dt282x_private *devpriv = dev->private;
906 struct comedi_isadma *dma = devpriv->dma;
907 struct comedi_cmd *cmd = &s->async->cmd;
909 dt282x_disable_dma(dev);
911 devpriv->supcsr = DT2821_SUPCSR_ERRINTEN |
912 DT2821_SUPCSR_DS_DA_CLK |
914 outw(devpriv->supcsr |
915 DT2821_SUPCSR_CLRDMADNE |
916 DT2821_SUPCSR_BUFFB |
917 DT2821_SUPCSR_DACINIT,
918 dev->iobase + DT2821_SUPCSR_REG);
920 devpriv->ntrig = cmd->stop_arg * cmd->chanlist_len;
921 devpriv->nread = devpriv->ntrig;
923 devpriv->dma_dir = COMEDI_ISADMA_WRITE;
926 outw(devpriv->divisor, dev->iobase + DT2821_TMRCTR_REG);
928 /* clear all bits but the DIO direction bits */
929 devpriv->dacsr &= (DT2821_DACSR_LBOE | DT2821_DACSR_HBOE);
931 devpriv->dacsr |= (DT2821_DACSR_SSEL |
933 DT2821_DACSR_IDARDY);
934 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR_REG);
936 s->async->inttrig = dt282x_ao_inttrig;
941 static int dt282x_ao_cancel(struct comedi_device *dev,
942 struct comedi_subdevice *s)
944 struct dt282x_private *devpriv = dev->private;
946 dt282x_disable_dma(dev);
948 /* clear all bits but the DIO direction bits */
949 devpriv->dacsr &= (DT2821_DACSR_LBOE | DT2821_DACSR_HBOE);
951 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR_REG);
954 outw(devpriv->supcsr | DT2821_SUPCSR_DACINIT,
955 dev->iobase + DT2821_SUPCSR_REG);
960 static int dt282x_dio_insn_bits(struct comedi_device *dev,
961 struct comedi_subdevice *s,
962 struct comedi_insn *insn,
965 if (comedi_dio_update_state(s, data))
966 outw(s->state, dev->iobase + DT2821_DIODAT_REG);
968 data[1] = inw(dev->iobase + DT2821_DIODAT_REG);
973 static int dt282x_dio_insn_config(struct comedi_device *dev,
974 struct comedi_subdevice *s,
975 struct comedi_insn *insn,
978 struct dt282x_private *devpriv = dev->private;
979 unsigned int chan = CR_CHAN(insn->chanspec);
988 ret = comedi_dio_insn_config(dev, s, insn, data, mask);
992 devpriv->dacsr &= ~(DT2821_DACSR_LBOE | DT2821_DACSR_HBOE);
993 if (s->io_bits & 0x00ff)
994 devpriv->dacsr |= DT2821_DACSR_LBOE;
995 if (s->io_bits & 0xff00)
996 devpriv->dacsr |= DT2821_DACSR_HBOE;
998 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR_REG);
1003 static const struct comedi_lrange *const ai_range_table[] = {
1004 &range_dt282x_ai_lo_bipolar,
1005 &range_dt282x_ai_lo_unipolar,
1006 &range_dt282x_ai_5_bipolar,
1007 &range_dt282x_ai_5_unipolar
1010 static const struct comedi_lrange *const ai_range_pgl_table[] = {
1011 &range_dt282x_ai_hi_bipolar,
1012 &range_dt282x_ai_hi_unipolar
1015 static const struct comedi_lrange *opt_ai_range_lkup(int ispgl, int x)
1018 if (x < 0 || x >= 2)
1020 return ai_range_pgl_table[x];
1023 if (x < 0 || x >= 4)
1025 return ai_range_table[x];
1028 static void dt282x_alloc_dma(struct comedi_device *dev,
1029 struct comedi_devconfig *it)
1031 struct dt282x_private *devpriv = dev->private;
1032 unsigned int irq_num = it->options[1];
1033 unsigned int dma_chan[2];
1035 if (it->options[2] < it->options[3]) {
1036 dma_chan[0] = it->options[2];
1037 dma_chan[1] = it->options[3];
1039 dma_chan[0] = it->options[3];
1040 dma_chan[1] = it->options[2];
1043 if (!irq_num || dma_chan[0] == dma_chan[1] ||
1044 dma_chan[0] < 5 || dma_chan[0] > 7 ||
1045 dma_chan[1] < 5 || dma_chan[1] > 7)
1048 if (request_irq(irq_num, dt282x_interrupt, 0, dev->board_name, dev))
1051 /* DMA uses two 4K buffers with separate DMA channels */
1052 devpriv->dma = comedi_isadma_alloc(dev, 2, dma_chan[0], dma_chan[1],
1055 free_irq(irq_num, dev);
1058 static void dt282x_free_dma(struct comedi_device *dev)
1060 struct dt282x_private *devpriv = dev->private;
1063 comedi_isadma_free(devpriv->dma);
1066 static int dt282x_initialize(struct comedi_device *dev)
1068 /* Initialize board */
1069 outw(DT2821_SUPCSR_BDINIT, dev->iobase + DT2821_SUPCSR_REG);
1070 inw(dev->iobase + DT2821_ADCSR_REG);
1073 * At power up, some registers are in a well-known state.
1074 * Check them to see if a DT2821 series board is present.
1076 if (((inw(dev->iobase + DT2821_ADCSR_REG) & 0xfff0) != 0x7c00) ||
1077 ((inw(dev->iobase + DT2821_CHANCSR_REG) & 0xf0f0) != 0x70f0) ||
1078 ((inw(dev->iobase + DT2821_DACSR_REG) & 0x7c93) != 0x7c90) ||
1079 ((inw(dev->iobase + DT2821_SUPCSR_REG) & 0xf8ff) != 0x0000) ||
1080 ((inw(dev->iobase + DT2821_TMRCTR_REG) & 0xff00) != 0xf000)) {
1081 dev_err(dev->class_dev, "board not found\n");
1093 4 0=single ended, 1=differential
1094 5 ai 0=straight binary, 1=2's comp
1095 6 ao0 0=straight binary, 1=2's comp
1096 7 ao1 0=straight binary, 1=2's comp
1097 8 ai 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V
1098 9 ao0 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1099 10 ao1 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1101 static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1103 const struct dt282x_board *board = dev->board_ptr;
1104 struct dt282x_private *devpriv;
1105 struct comedi_subdevice *s;
1108 ret = comedi_request_region(dev, it->options[0], 0x10);
1112 ret = dt282x_initialize(dev);
1116 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1120 /* an IRQ and 2 DMA channels are required for async command support */
1121 dt282x_alloc_dma(dev, it);
1123 ret = comedi_alloc_subdevices(dev, 3);
1127 /* Analog Input subdevice */
1128 s = &dev->subdevices[0];
1129 s->type = COMEDI_SUBD_AI;
1130 s->subdev_flags = SDF_READABLE;
1131 if ((it->options[4] && board->adchan_di) || board->adchan_se == 0) {
1132 s->subdev_flags |= SDF_DIFF;
1133 s->n_chan = board->adchan_di;
1135 s->subdev_flags |= SDF_COMMON;
1136 s->n_chan = board->adchan_se;
1138 s->maxdata = board->ai_maxdata;
1140 s->range_table = opt_ai_range_lkup(board->ispgl, it->options[8]);
1141 devpriv->ad_2scomp = it->options[5] ? 1 : 0;
1143 s->insn_read = dt282x_ai_insn_read;
1145 dev->read_subdev = s;
1146 s->subdev_flags |= SDF_CMD_READ;
1147 s->len_chanlist = s->n_chan;
1148 s->do_cmdtest = dt282x_ai_cmdtest;
1149 s->do_cmd = dt282x_ai_cmd;
1150 s->cancel = dt282x_ai_cancel;
1153 /* Analog Output subdevice */
1154 s = &dev->subdevices[1];
1155 if (board->dachan) {
1156 s->type = COMEDI_SUBD_AO;
1157 s->subdev_flags = SDF_WRITABLE;
1158 s->n_chan = board->dachan;
1159 s->maxdata = board->ao_maxdata;
1160 /* ranges are per-channel, set by jumpers on the board */
1161 s->range_table = &dt282x_ao_range;
1162 s->insn_write = dt282x_ao_insn_write;
1164 dev->write_subdev = s;
1165 s->subdev_flags |= SDF_CMD_WRITE;
1166 s->len_chanlist = s->n_chan;
1167 s->do_cmdtest = dt282x_ao_cmdtest;
1168 s->do_cmd = dt282x_ao_cmd;
1169 s->cancel = dt282x_ao_cancel;
1172 ret = comedi_alloc_subdev_readback(s);
1176 s->type = COMEDI_SUBD_UNUSED;
1179 /* Digital I/O subdevice */
1180 s = &dev->subdevices[2];
1181 s->type = COMEDI_SUBD_DIO;
1182 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1185 s->range_table = &range_digital;
1186 s->insn_bits = dt282x_dio_insn_bits;
1187 s->insn_config = dt282x_dio_insn_config;
1192 static void dt282x_detach(struct comedi_device *dev)
1194 dt282x_free_dma(dev);
1195 comedi_legacy_detach(dev);
1198 static struct comedi_driver dt282x_driver = {
1199 .driver_name = "dt282x",
1200 .module = THIS_MODULE,
1201 .attach = dt282x_attach,
1202 .detach = dt282x_detach,
1203 .board_name = &boardtypes[0].name,
1204 .num_names = ARRAY_SIZE(boardtypes),
1205 .offset = sizeof(struct dt282x_board),
1207 module_comedi_driver(dt282x_driver);
1209 MODULE_AUTHOR("Comedi http://www.comedi.org");
1210 MODULE_DESCRIPTION("Comedi driver for Data Translation DT2821 series");
1211 MODULE_LICENSE("GPL");