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 "../comedidev.h"
61 #include <linux/delay.h>
62 #include <linux/gfp.h>
63 #include <linux/interrupt.h>
68 #include "comedi_fc.h"
73 #define DT2821_ADCSR_REG 0x00
74 #define DT2821_ADCSR_ADERR (1 << 15)
75 #define DT2821_ADCSR_ADCLK (1 << 9)
76 #define DT2821_ADCSR_MUXBUSY (1 << 8)
77 #define DT2821_ADCSR_ADDONE (1 << 7)
78 #define DT2821_ADCSR_IADDONE (1 << 6)
79 #define DT2821_ADCSR_GS(x) (((x) & 0x3) << 4)
80 #define DT2821_ADCSR_CHAN(x) (((x) & 0xf) << 0)
81 #define DT2821_CHANCSR_REG 0x02
82 #define DT2821_CHANCSR_LLE (1 << 15)
83 #define DT2821_CHANCSR_PRESLA(x) (((x) & 0xf) >> 8)
84 #define DT2821_CHANCSR_NUMB(x) ((((x) - 1) & 0xf) << 0)
85 #define DT2821_ADDAT_REG 0x04
86 #define DT2821_DACSR_REG 0x06
87 #define DT2821_DACSR_DAERR (1 << 15)
88 #define DT2821_DACSR_YSEL(x) ((x) << 9)
89 #define DT2821_DACSR_SSEL (1 << 8)
90 #define DT2821_DACSR_DACRDY (1 << 7)
91 #define DT2821_DACSR_IDARDY (1 << 6)
92 #define DT2821_DACSR_DACLK (1 << 5)
93 #define DT2821_DACSR_HBOE (1 << 1)
94 #define DT2821_DACSR_LBOE (1 << 0)
95 #define DT2821_DADAT_REG 0x08
96 #define DT2821_DIODAT_REG 0x0a
97 #define DT2821_SUPCSR_REG 0x0c
98 #define DT2821_SUPCSR_DMAD (1 << 15)
99 #define DT2821_SUPCSR_ERRINTEN (1 << 14)
100 #define DT2821_SUPCSR_CLRDMADNE (1 << 13)
101 #define DT2821_SUPCSR_DDMA (1 << 12)
102 #define DT2821_SUPCSR_DS_PIO (0 << 10)
103 #define DT2821_SUPCSR_DS_AD_CLK (1 << 10)
104 #define DT2821_SUPCSR_DS_DA_CLK (2 << 10)
105 #define DT2821_SUPCSR_DS_AD_TRIG (3 << 10)
106 #define DT2821_SUPCSR_BUFFB (1 << 9)
107 #define DT2821_SUPCSR_SCDN (1 << 8)
108 #define DT2821_SUPCSR_DACON (1 << 7)
109 #define DT2821_SUPCSR_ADCINIT (1 << 6)
110 #define DT2821_SUPCSR_DACINIT (1 << 5)
111 #define DT2821_SUPCSR_PRLD (1 << 4)
112 #define DT2821_SUPCSR_STRIG (1 << 3)
113 #define DT2821_SUPCSR_XTRIG (1 << 2)
114 #define DT2821_SUPCSR_XCLK (1 << 1)
115 #define DT2821_SUPCSR_BDINIT (1 << 0)
116 #define DT2821_TMRCTR_REG 0x0e
118 static const struct comedi_lrange range_dt282x_ai_lo_bipolar = {
127 static const struct comedi_lrange range_dt282x_ai_lo_unipolar = {
136 static const struct comedi_lrange range_dt282x_ai_5_bipolar = {
145 static const struct comedi_lrange range_dt282x_ai_5_unipolar = {
154 static const struct comedi_lrange range_dt282x_ai_hi_bipolar = {
163 static const struct comedi_lrange range_dt282x_ai_hi_unipolar = {
173 * The Analog Output range is set per-channel using jumpers on the board.
174 * All of these ranges may not be available on some DT2821 series boards.
175 * The default jumper setting has both channels set for +/-10V output.
177 static const struct comedi_lrange dt282x_ao_range = {
187 struct dt282x_board {
189 unsigned int ai_maxdata;
195 unsigned int ao_maxdata;
198 static const struct dt282x_board boardtypes[] = {
201 .ai_maxdata = 0x0fff,
206 .ao_maxdata = 0x0fff,
209 .ai_maxdata = 0x0fff,
214 .ao_maxdata = 0x0fff,
217 .ai_maxdata = 0x0fff,
222 .ao_maxdata = 0x0fff,
225 .ai_maxdata = 0xffff,
229 .ao_maxdata = 0xffff,
231 .name = "dt2824-pgh",
232 .ai_maxdata = 0x0fff,
237 .name = "dt2824-pgl",
238 .ai_maxdata = 0x0fff,
245 .ai_maxdata = 0x0fff,
251 .ao_maxdata = 0x0fff,
254 .ai_maxdata = 0xffff,
258 .ao_maxdata = 0x0fff,
261 .ai_maxdata = 0x0fff,
265 .ao_maxdata = 0x0fff,
268 .ai_maxdata = 0xffff,
272 .ao_maxdata = 0xffff,
275 .ai_maxdata = 0x0fff,
280 .ao_maxdata = 0x0fff,
283 .ai_maxdata = 0xffff,
289 .ai_maxdata = 0x0fff,
294 .name = "dt24-ez-pgl",
295 .ai_maxdata = 0x0fff,
303 struct dt282x_private {
304 unsigned int ad_2scomp:1;
306 unsigned int divisor;
308 int dacsr; /* software copies of registers */
317 unsigned short *buf; /* DMA buffer */
318 int size; /* size of current transfer */
320 int dma_maxsize; /* max size of DMA transfer (in bytes) */
321 int current_dma_index;
325 static int dt282x_prep_ai_dma(struct comedi_device *dev, int dma_index, int n)
327 struct dt282x_private *devpriv = dev->private;
329 unsigned long dma_ptr;
336 n = devpriv->dma_maxsize;
337 if (n > devpriv->ntrig * 2)
338 n = devpriv->ntrig * 2;
339 devpriv->ntrig -= n / 2;
341 devpriv->dma[dma_index].size = n;
342 dma_chan = devpriv->dma[dma_index].chan;
343 dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
345 set_dma_mode(dma_chan, DMA_MODE_READ);
346 flags = claim_dma_lock();
347 clear_dma_ff(dma_chan);
348 set_dma_addr(dma_chan, dma_ptr);
349 set_dma_count(dma_chan, n);
350 release_dma_lock(flags);
352 enable_dma(dma_chan);
357 static int dt282x_prep_ao_dma(struct comedi_device *dev, int dma_index, int n)
359 struct dt282x_private *devpriv = dev->private;
361 unsigned long dma_ptr;
364 devpriv->dma[dma_index].size = n;
365 dma_chan = devpriv->dma[dma_index].chan;
366 dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
368 set_dma_mode(dma_chan, DMA_MODE_WRITE);
369 flags = claim_dma_lock();
370 clear_dma_ff(dma_chan);
371 set_dma_addr(dma_chan, dma_ptr);
372 set_dma_count(dma_chan, n);
373 release_dma_lock(flags);
375 enable_dma(dma_chan);
380 static void dt282x_disable_dma(struct comedi_device *dev)
382 struct dt282x_private *devpriv = dev->private;
384 disable_dma(devpriv->dma[0].chan);
385 disable_dma(devpriv->dma[1].chan);
388 static unsigned int dt282x_ns_to_timer(unsigned int *ns, unsigned int flags)
390 unsigned int prescale, base, divider;
392 for (prescale = 0; prescale < 16; prescale++) {
395 base = 250 * (1 << prescale);
396 switch (flags & CMDF_ROUND_MASK) {
397 case CMDF_ROUND_NEAREST:
399 divider = (*ns + base / 2) / base;
401 case CMDF_ROUND_DOWN:
402 divider = (*ns) / base;
405 divider = (*ns + base - 1) / base;
409 *ns = divider * base;
410 return (prescale << 8) | (255 - divider);
413 base = 250 * (1 << 15);
415 *ns = divider * base;
416 return (15 << 8) | (255 - divider);
419 static void dt282x_munge(struct comedi_device *dev,
420 struct comedi_subdevice *s,
424 struct dt282x_private *devpriv = dev->private;
429 dev_err(dev->class_dev,
430 "bug! odd number of bytes from dma xfer\n");
432 for (i = 0; i < nbytes / 2; i++) {
435 if (devpriv->ad_2scomp)
436 val = comedi_offset_munge(s, val);
442 static unsigned int dt282x_ao_setup_dma(struct comedi_device *dev,
443 struct comedi_subdevice *s,
446 struct dt282x_private *devpriv = dev->private;
447 void *ptr = devpriv->dma[cur_dma].buf;
448 unsigned int nsamples = comedi_bytes_to_samples(s, devpriv->dma_maxsize);
451 nbytes = comedi_buf_read_samples(s, ptr, nsamples);
453 dt282x_prep_ao_dma(dev, cur_dma, nbytes);
455 dev_err(dev->class_dev, "AO underrun\n");
460 static void dt282x_ao_dma_interrupt(struct comedi_device *dev,
461 struct comedi_subdevice *s)
463 struct dt282x_private *devpriv = dev->private;
464 int cur_dma = devpriv->current_dma_index;
466 outw(devpriv->supcsr | DT2821_SUPCSR_CLRDMADNE,
467 dev->iobase + DT2821_SUPCSR_REG);
469 disable_dma(devpriv->dma[cur_dma].chan);
471 devpriv->current_dma_index = 1 - cur_dma;
473 if (!dt282x_ao_setup_dma(dev, s, cur_dma))
474 s->async->events |= COMEDI_CB_OVERFLOW;
477 static void dt282x_ai_dma_interrupt(struct comedi_device *dev,
478 struct comedi_subdevice *s)
480 struct dt282x_private *devpriv = dev->private;
481 int cur_dma = devpriv->current_dma_index;
482 void *ptr = devpriv->dma[cur_dma].buf;
483 int size = devpriv->dma[cur_dma].size;
484 unsigned int nsamples = comedi_bytes_to_samples(s, size);
487 outw(devpriv->supcsr | DT2821_SUPCSR_CLRDMADNE,
488 dev->iobase + DT2821_SUPCSR_REG);
490 disable_dma(devpriv->dma[cur_dma].chan);
492 devpriv->current_dma_index = 1 - cur_dma;
494 dt282x_munge(dev, s, ptr, size);
495 ret = comedi_buf_write_samples(s, ptr, nsamples);
499 devpriv->nread -= nsamples;
500 if (devpriv->nread < 0) {
501 dev_info(dev->class_dev, "nread off by one\n");
504 if (!devpriv->nread) {
505 s->async->events |= COMEDI_CB_EOA;
509 /* clear the dual dma flag, making this the last dma segment */
510 /* XXX probably wrong */
511 if (!devpriv->ntrig) {
512 devpriv->supcsr &= ~DT2821_SUPCSR_DDMA;
513 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR_REG);
516 /* restart the channel */
517 dt282x_prep_ai_dma(dev, cur_dma, 0);
520 static irqreturn_t dt282x_interrupt(int irq, void *d)
522 struct comedi_device *dev = d;
523 struct dt282x_private *devpriv = dev->private;
524 struct comedi_subdevice *s = dev->read_subdev;
525 struct comedi_subdevice *s_ao = dev->write_subdev;
526 unsigned int supcsr, adcsr, dacsr;
529 if (!dev->attached) {
530 dev_err(dev->class_dev, "spurious interrupt\n");
534 adcsr = inw(dev->iobase + DT2821_ADCSR_REG);
535 dacsr = inw(dev->iobase + DT2821_DACSR_REG);
536 supcsr = inw(dev->iobase + DT2821_SUPCSR_REG);
537 if (supcsr & DT2821_SUPCSR_DMAD) {
538 if (devpriv->dma_dir == DMA_MODE_READ)
539 dt282x_ai_dma_interrupt(dev, s);
541 dt282x_ao_dma_interrupt(dev, s_ao);
544 if (adcsr & DT2821_ADCSR_ADERR) {
545 if (devpriv->nread != 0) {
546 dev_err(dev->class_dev, "A/D error\n");
547 s->async->events |= COMEDI_CB_ERROR;
551 if (dacsr & DT2821_DACSR_DAERR) {
552 dev_err(dev->class_dev, "D/A error\n");
553 s_ao->async->events |= COMEDI_CB_ERROR;
557 if (adcsr & DT2821_ADCSR_ADDONE) {
560 data = inw(dev->iobase + DT2821_ADDAT_REG);
562 if (devpriv->ad_2scomp)
563 data = comedi_offset_munge(s, data);
565 comedi_buf_write_samples(s, &data, 1);
568 if (!devpriv->nread) {
569 s->async->events |= COMEDI_CB_EOA;
571 if (supcsr & DT2821_SUPCSR_SCDN)
572 outw(devpriv->supcsr | DT2821_SUPCSR_STRIG,
573 dev->iobase + DT2821_SUPCSR_REG);
578 comedi_handle_events(dev, s);
579 comedi_handle_events(dev, s_ao);
581 return IRQ_RETVAL(handled);
584 static void dt282x_load_changain(struct comedi_device *dev, int n,
585 unsigned int *chanlist)
587 struct dt282x_private *devpriv = dev->private;
590 outw(DT2821_CHANCSR_LLE | DT2821_CHANCSR_NUMB(n),
591 dev->iobase + DT2821_CHANCSR_REG);
592 for (i = 0; i < n; i++) {
593 unsigned int chan = CR_CHAN(chanlist[i]);
594 unsigned int range = CR_RANGE(chanlist[i]);
596 outw(devpriv->adcsr |
597 DT2821_ADCSR_GS(range) |
598 DT2821_ADCSR_CHAN(chan),
599 dev->iobase + DT2821_ADCSR_REG);
601 outw(DT2821_CHANCSR_NUMB(n), dev->iobase + DT2821_CHANCSR_REG);
604 static int dt282x_ai_timeout(struct comedi_device *dev,
605 struct comedi_subdevice *s,
606 struct comedi_insn *insn,
607 unsigned long context)
611 status = inw(dev->iobase + DT2821_ADCSR_REG);
613 case DT2821_ADCSR_MUXBUSY:
614 if ((status & DT2821_ADCSR_MUXBUSY) == 0)
617 case DT2821_ADCSR_ADDONE:
618 if (status & DT2821_ADCSR_ADDONE)
628 * Performs a single A/D conversion.
629 * - Put channel/gain into channel-gain list
630 * - preload multiplexer
631 * - trigger conversion and wait for it to finish
633 static int dt282x_ai_insn_read(struct comedi_device *dev,
634 struct comedi_subdevice *s,
635 struct comedi_insn *insn,
638 struct dt282x_private *devpriv = dev->private;
643 /* XXX should we really be enabling the ad clock here? */
644 devpriv->adcsr = DT2821_ADCSR_ADCLK;
645 outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR_REG);
647 dt282x_load_changain(dev, 1, &insn->chanspec);
649 outw(devpriv->supcsr | DT2821_SUPCSR_PRLD,
650 dev->iobase + DT2821_SUPCSR_REG);
651 ret = comedi_timeout(dev, s, insn,
652 dt282x_ai_timeout, DT2821_ADCSR_MUXBUSY);
656 for (i = 0; i < insn->n; i++) {
657 outw(devpriv->supcsr | DT2821_SUPCSR_STRIG,
658 dev->iobase + DT2821_SUPCSR_REG);
660 ret = comedi_timeout(dev, s, insn,
661 dt282x_ai_timeout, DT2821_ADCSR_ADDONE);
665 val = inw(dev->iobase + DT2821_ADDAT_REG);
667 if (devpriv->ad_2scomp)
668 val = comedi_offset_munge(s, val);
676 static int dt282x_ai_cmdtest(struct comedi_device *dev,
677 struct comedi_subdevice *s,
678 struct comedi_cmd *cmd)
680 const struct dt282x_board *board = dev->board_ptr;
681 struct dt282x_private *devpriv = dev->private;
685 /* Step 1 : check if triggers are trivially valid */
687 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
688 err |= cfc_check_trigger_src(&cmd->scan_begin_src,
689 TRIG_FOLLOW | TRIG_EXT);
690 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
691 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
692 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
697 /* Step 2a : make sure trigger sources are unique */
699 err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
700 err |= cfc_check_trigger_is_unique(cmd->stop_src);
702 /* Step 2b : and mutually compatible */
707 /* Step 3: check if arguments are trivially valid */
709 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
711 if (cmd->scan_begin_src == TRIG_FOLLOW) {
712 /* internal trigger */
713 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
715 /* external trigger */
716 /* should be level/edge, hi/lo specification here */
717 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
720 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 4000);
722 #define SLOWEST_TIMER (250*(1<<15)*255)
723 err |= cfc_check_trigger_arg_max(&cmd->convert_arg, SLOWEST_TIMER);
724 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, board->ai_speed);
725 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
727 if (cmd->stop_src == TRIG_COUNT)
728 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
729 else /* TRIG_EXT | TRIG_NONE */
730 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
735 /* step 4: fix up any arguments */
737 arg = cmd->convert_arg;
738 devpriv->divisor = dt282x_ns_to_timer(&arg, cmd->flags);
739 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
747 static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
749 struct dt282x_private *devpriv = dev->private;
750 struct comedi_cmd *cmd = &s->async->cmd;
753 dt282x_disable_dma(dev);
755 outw(devpriv->divisor, dev->iobase + DT2821_TMRCTR_REG);
757 devpriv->supcsr = DT2821_SUPCSR_ERRINTEN;
758 if (cmd->scan_begin_src == TRIG_FOLLOW)
759 devpriv->supcsr = DT2821_SUPCSR_DS_AD_CLK;
761 devpriv->supcsr = DT2821_SUPCSR_DS_AD_TRIG;
762 outw(devpriv->supcsr |
763 DT2821_SUPCSR_CLRDMADNE |
764 DT2821_SUPCSR_BUFFB |
765 DT2821_SUPCSR_ADCINIT,
766 dev->iobase + DT2821_SUPCSR_REG);
768 devpriv->ntrig = cmd->stop_arg * cmd->scan_end_arg;
769 devpriv->nread = devpriv->ntrig;
771 devpriv->dma_dir = DMA_MODE_READ;
772 devpriv->current_dma_index = 0;
773 dt282x_prep_ai_dma(dev, 0, 0);
774 if (devpriv->ntrig) {
775 dt282x_prep_ai_dma(dev, 1, 0);
776 devpriv->supcsr |= DT2821_SUPCSR_DDMA;
777 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR_REG);
782 dt282x_load_changain(dev, cmd->chanlist_len, cmd->chanlist);
784 devpriv->adcsr = DT2821_ADCSR_ADCLK | DT2821_ADCSR_IADDONE;
785 outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR_REG);
787 outw(devpriv->supcsr | DT2821_SUPCSR_PRLD,
788 dev->iobase + DT2821_SUPCSR_REG);
789 ret = comedi_timeout(dev, s, NULL,
790 dt282x_ai_timeout, DT2821_ADCSR_MUXBUSY);
794 if (cmd->scan_begin_src == TRIG_FOLLOW) {
795 outw(devpriv->supcsr | DT2821_SUPCSR_STRIG,
796 dev->iobase + DT2821_SUPCSR_REG);
798 devpriv->supcsr |= DT2821_SUPCSR_XTRIG;
799 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR_REG);
805 static int dt282x_ai_cancel(struct comedi_device *dev,
806 struct comedi_subdevice *s)
808 struct dt282x_private *devpriv = dev->private;
810 dt282x_disable_dma(dev);
813 outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR_REG);
816 outw(devpriv->supcsr | DT2821_SUPCSR_ADCINIT,
817 dev->iobase + DT2821_SUPCSR_REG);
822 static int dt282x_ao_insn_write(struct comedi_device *dev,
823 struct comedi_subdevice *s,
824 struct comedi_insn *insn,
827 struct dt282x_private *devpriv = dev->private;
828 unsigned int chan = CR_CHAN(insn->chanspec);
829 unsigned int range = CR_RANGE(insn->chanspec);
832 devpriv->dacsr |= DT2821_DACSR_SSEL | DT2821_DACSR_YSEL(chan);
834 for (i = 0; i < insn->n; i++) {
835 unsigned int val = data[i];
837 s->readback[chan] = val;
839 if (comedi_range_is_bipolar(s, range))
840 val = comedi_offset_munge(s, val);
842 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR_REG);
844 outw(val, dev->iobase + DT2821_DADAT_REG);
846 outw(devpriv->supcsr | DT2821_SUPCSR_DACON,
847 dev->iobase + DT2821_SUPCSR_REG);
853 static int dt282x_ao_cmdtest(struct comedi_device *dev,
854 struct comedi_subdevice *s,
855 struct comedi_cmd *cmd)
857 struct dt282x_private *devpriv = dev->private;
861 /* Step 1 : check if triggers are trivially valid */
863 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT);
864 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
865 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
866 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
867 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
872 /* Step 2a : make sure trigger sources are unique */
874 err |= cfc_check_trigger_is_unique(cmd->stop_src);
876 /* Step 2b : and mutually compatible */
881 /* Step 3: check if arguments are trivially valid */
883 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
884 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 5000);
885 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
886 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
888 if (cmd->stop_src == TRIG_COUNT)
889 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
890 else /* TRIG_EXT | TRIG_NONE */
891 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
896 /* step 4: fix up any arguments */
898 arg = cmd->scan_begin_arg;
899 devpriv->divisor = dt282x_ns_to_timer(&arg, cmd->flags);
900 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
909 static int dt282x_ao_inttrig(struct comedi_device *dev,
910 struct comedi_subdevice *s,
911 unsigned int trig_num)
913 struct dt282x_private *devpriv = dev->private;
914 struct comedi_cmd *cmd = &s->async->cmd;
916 if (trig_num != cmd->start_src)
919 if (!dt282x_ao_setup_dma(dev, s, 0))
922 if (!dt282x_ao_setup_dma(dev, s, 1))
925 outw(devpriv->supcsr | DT2821_SUPCSR_STRIG,
926 dev->iobase + DT2821_SUPCSR_REG);
927 s->async->inttrig = NULL;
932 static int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
934 struct dt282x_private *devpriv = dev->private;
935 struct comedi_cmd *cmd = &s->async->cmd;
937 dt282x_disable_dma(dev);
939 devpriv->supcsr = DT2821_SUPCSR_ERRINTEN |
940 DT2821_SUPCSR_DS_DA_CLK |
942 outw(devpriv->supcsr |
943 DT2821_SUPCSR_CLRDMADNE |
944 DT2821_SUPCSR_BUFFB |
945 DT2821_SUPCSR_DACINIT,
946 dev->iobase + DT2821_SUPCSR_REG);
948 devpriv->ntrig = cmd->stop_arg * cmd->chanlist_len;
949 devpriv->nread = devpriv->ntrig;
951 devpriv->dma_dir = DMA_MODE_WRITE;
952 devpriv->current_dma_index = 0;
954 outw(devpriv->divisor, dev->iobase + DT2821_TMRCTR_REG);
956 /* clear all bits but the DIO direction bits */
957 devpriv->dacsr &= (DT2821_DACSR_LBOE | DT2821_DACSR_HBOE);
959 devpriv->dacsr |= (DT2821_DACSR_SSEL |
961 DT2821_DACSR_IDARDY);
962 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR_REG);
964 s->async->inttrig = dt282x_ao_inttrig;
969 static int dt282x_ao_cancel(struct comedi_device *dev,
970 struct comedi_subdevice *s)
972 struct dt282x_private *devpriv = dev->private;
974 dt282x_disable_dma(dev);
976 /* clear all bits but the DIO direction bits */
977 devpriv->dacsr &= (DT2821_DACSR_LBOE | DT2821_DACSR_HBOE);
979 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR_REG);
982 outw(devpriv->supcsr | DT2821_SUPCSR_DACINIT,
983 dev->iobase + DT2821_SUPCSR_REG);
988 static int dt282x_dio_insn_bits(struct comedi_device *dev,
989 struct comedi_subdevice *s,
990 struct comedi_insn *insn,
993 if (comedi_dio_update_state(s, data))
994 outw(s->state, dev->iobase + DT2821_DIODAT_REG);
996 data[1] = inw(dev->iobase + DT2821_DIODAT_REG);
1001 static int dt282x_dio_insn_config(struct comedi_device *dev,
1002 struct comedi_subdevice *s,
1003 struct comedi_insn *insn,
1006 struct dt282x_private *devpriv = dev->private;
1007 unsigned int chan = CR_CHAN(insn->chanspec);
1016 ret = comedi_dio_insn_config(dev, s, insn, data, mask);
1020 devpriv->dacsr &= ~(DT2821_DACSR_LBOE | DT2821_DACSR_HBOE);
1021 if (s->io_bits & 0x00ff)
1022 devpriv->dacsr |= DT2821_DACSR_LBOE;
1023 if (s->io_bits & 0xff00)
1024 devpriv->dacsr |= DT2821_DACSR_HBOE;
1026 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR_REG);
1031 static const struct comedi_lrange *const ai_range_table[] = {
1032 &range_dt282x_ai_lo_bipolar,
1033 &range_dt282x_ai_lo_unipolar,
1034 &range_dt282x_ai_5_bipolar,
1035 &range_dt282x_ai_5_unipolar
1038 static const struct comedi_lrange *const ai_range_pgl_table[] = {
1039 &range_dt282x_ai_hi_bipolar,
1040 &range_dt282x_ai_hi_unipolar
1043 static const struct comedi_lrange *opt_ai_range_lkup(int ispgl, int x)
1046 if (x < 0 || x >= 2)
1048 return ai_range_pgl_table[x];
1051 if (x < 0 || x >= 4)
1053 return ai_range_table[x];
1056 static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2)
1058 struct dt282x_private *devpriv = dev->private;
1061 ret = request_dma(dma1, "dt282x A");
1064 devpriv->dma[0].chan = dma1;
1066 ret = request_dma(dma2, "dt282x B");
1069 devpriv->dma[1].chan = dma2;
1071 devpriv->dma_maxsize = PAGE_SIZE;
1072 devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
1073 devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
1074 if (!devpriv->dma[0].buf || !devpriv->dma[1].buf)
1080 static void dt282x_free_dma(struct comedi_device *dev)
1082 struct dt282x_private *devpriv = dev->private;
1088 for (i = 0; i < 2; i++) {
1089 if (devpriv->dma[i].chan)
1090 free_dma(devpriv->dma[i].chan);
1091 if (devpriv->dma[i].buf)
1092 free_page((unsigned long)devpriv->dma[i].buf);
1093 devpriv->dma[i].chan = 0;
1094 devpriv->dma[i].buf = NULL;
1098 static int dt282x_initialize(struct comedi_device *dev)
1100 /* Initialize board */
1101 outw(DT2821_SUPCSR_BDINIT, dev->iobase + DT2821_SUPCSR_REG);
1102 inw(dev->iobase + DT2821_ADCSR_REG);
1105 * At power up, some registers are in a well-known state.
1106 * Check them to see if a DT2821 series board is present.
1108 if (((inw(dev->iobase + DT2821_ADCSR_REG) & 0xfff0) != 0x7c00) ||
1109 ((inw(dev->iobase + DT2821_CHANCSR_REG) & 0xf0f0) != 0x70f0) ||
1110 ((inw(dev->iobase + DT2821_DACSR_REG) & 0x7c93) != 0x7c90) ||
1111 ((inw(dev->iobase + DT2821_SUPCSR_REG) & 0xf8ff) != 0x0000) ||
1112 ((inw(dev->iobase + DT2821_TMRCTR_REG) & 0xff00) != 0xf000)) {
1113 dev_err(dev->class_dev, "board not found\n");
1125 4 0=single ended, 1=differential
1126 5 ai 0=straight binary, 1=2's comp
1127 6 ao0 0=straight binary, 1=2's comp
1128 7 ao1 0=straight binary, 1=2's comp
1129 8 ai 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V
1130 9 ao0 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1131 10 ao1 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1133 static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1135 const struct dt282x_board *board = dev->board_ptr;
1136 struct dt282x_private *devpriv;
1137 struct comedi_subdevice *s;
1140 ret = comedi_request_region(dev, it->options[0], 0x10);
1144 ret = dt282x_initialize(dev);
1148 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1152 /* an IRQ and 2 DMA channels are required for async command support */
1153 if (it->options[1] && it->options[2] && it->options[3]) {
1154 unsigned int irq = it->options[1];
1155 unsigned int dma1 = it->options[2];
1156 unsigned int dma2 = it->options[3];
1167 dma1 >= 5 && dma1 <= 7 &&
1168 dma2 >= 5 && dma2 <= 7) {
1169 ret = request_irq(irq, dt282x_interrupt, 0,
1170 dev->board_name, dev);
1174 ret = dt282x_grab_dma(dev, dma1, dma2);
1176 dt282x_free_dma(dev);
1177 free_irq(dev->irq, dev);
1184 ret = comedi_alloc_subdevices(dev, 3);
1188 /* Analog Input subdevice */
1189 s = &dev->subdevices[0];
1190 s->type = COMEDI_SUBD_AI;
1191 s->subdev_flags = SDF_READABLE;
1192 if ((it->options[4] && board->adchan_di) || board->adchan_se == 0) {
1193 s->subdev_flags |= SDF_DIFF;
1194 s->n_chan = board->adchan_di;
1196 s->subdev_flags |= SDF_COMMON;
1197 s->n_chan = board->adchan_se;
1199 s->maxdata = board->ai_maxdata;
1201 s->range_table = opt_ai_range_lkup(board->ispgl, it->options[8]);
1202 devpriv->ad_2scomp = it->options[5] ? 1 : 0;
1204 s->insn_read = dt282x_ai_insn_read;
1206 dev->read_subdev = s;
1207 s->subdev_flags |= SDF_CMD_READ;
1208 s->len_chanlist = s->n_chan;
1209 s->do_cmdtest = dt282x_ai_cmdtest;
1210 s->do_cmd = dt282x_ai_cmd;
1211 s->cancel = dt282x_ai_cancel;
1214 /* Analog Output subdevice */
1215 s = &dev->subdevices[1];
1216 if (board->dachan) {
1217 s->type = COMEDI_SUBD_AO;
1218 s->subdev_flags = SDF_WRITABLE;
1219 s->n_chan = board->dachan;
1220 s->maxdata = board->ao_maxdata;
1221 /* ranges are per-channel, set by jumpers on the board */
1222 s->range_table = &dt282x_ao_range;
1223 s->insn_write = dt282x_ao_insn_write;
1225 dev->write_subdev = s;
1226 s->subdev_flags |= SDF_CMD_WRITE;
1227 s->len_chanlist = s->n_chan;
1228 s->do_cmdtest = dt282x_ao_cmdtest;
1229 s->do_cmd = dt282x_ao_cmd;
1230 s->cancel = dt282x_ao_cancel;
1233 ret = comedi_alloc_subdev_readback(s);
1237 s->type = COMEDI_SUBD_UNUSED;
1240 /* Digital I/O subdevice */
1241 s = &dev->subdevices[2];
1242 s->type = COMEDI_SUBD_DIO;
1243 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1246 s->range_table = &range_digital;
1247 s->insn_bits = dt282x_dio_insn_bits;
1248 s->insn_config = dt282x_dio_insn_config;
1253 static void dt282x_detach(struct comedi_device *dev)
1255 dt282x_free_dma(dev);
1256 comedi_legacy_detach(dev);
1259 static struct comedi_driver dt282x_driver = {
1260 .driver_name = "dt282x",
1261 .module = THIS_MODULE,
1262 .attach = dt282x_attach,
1263 .detach = dt282x_detach,
1264 .board_name = &boardtypes[0].name,
1265 .num_names = ARRAY_SIZE(boardtypes),
1266 .offset = sizeof(struct dt282x_board),
1268 module_comedi_driver(dt282x_driver);
1270 MODULE_AUTHOR("Comedi http://www.comedi.org");
1271 MODULE_DESCRIPTION("Comedi driver for Data Translation DT2821 series");
1272 MODULE_LICENSE("GPL");