2 comedi/drivers/dt282x.c
3 Hardware 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.
20 Description: Data Translation DT2821 series (including DT-EZ)
22 Devices: [Data Translation] DT2821 (dt2821),
23 DT2821-F-16SE (dt2821-f), DT2821-F-8DI (dt2821-f),
24 DT2821-G-16SE (dt2821-f), DT2821-G-8DI (dt2821-g),
26 DT2824-PGH (dt2824-pgh), DT2824-PGL (dt2824-pgl), DT2825 (dt2825),
27 DT2827 (dt2827), DT2828 (dt2828), 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
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 jumpered for 0=straight binary, 1=2's complement
40 [7] - AO 1 jumpered for 0=straight binary, 1=2's complement
41 [8] - AI jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5]
42 [9] - AO 0 jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5],
44 [10]- A0 1 jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5],
48 - AO commands might be broken.
49 - If you try to run a command on both the AI and AO subdevices
50 simultaneously, bad things will happen. The driver needs to
51 be fixed to check for this situation and return an error.
54 #include <linux/module.h>
55 #include "../comedidev.h"
57 #include <linux/delay.h>
58 #include <linux/gfp.h>
59 #include <linux/interrupt.h>
64 #include "comedi_fc.h"
66 #define DT2821_SIZE 0x10
69 * Registers in the DT282x
72 #define DT2821_ADCSR 0x00 /* A/D Control/Status */
73 #define DT2821_CHANCSR 0x02 /* Channel Control/Status */
74 #define DT2821_ADDAT 0x04 /* A/D data */
75 #define DT2821_DACSR 0x06 /* D/A Control/Status */
76 #define DT2821_DADAT 0x08 /* D/A data */
77 #define DT2821_DIODAT 0x0a /* digital data */
78 #define DT2821_SUPCSR 0x0c /* Supervisor Control/Status */
79 #define DT2821_TMRCTR 0x0e /* Timer/Counter */
82 * At power up, some registers are in a well-known state. The
83 * masks and values are as follows:
86 #define DT2821_ADCSR_MASK 0xfff0
87 #define DT2821_ADCSR_VAL 0x7c00
89 #define DT2821_CHANCSR_MASK 0xf0f0
90 #define DT2821_CHANCSR_VAL 0x70f0
92 #define DT2821_DACSR_MASK 0x7c93
93 #define DT2821_DACSR_VAL 0x7c90
95 #define DT2821_SUPCSR_MASK 0xf8ff
96 #define DT2821_SUPCSR_VAL 0x0000
98 #define DT2821_TMRCTR_MASK 0xff00
99 #define DT2821_TMRCTR_VAL 0xf000
102 * Bit fields of each register
107 #define DT2821_ADERR 0x8000 /* (R) 1 for A/D error */
108 #define DT2821_ADCLK 0x0200 /* (R/W) A/D clock enable */
109 /* 0x7c00 read as 1's */
110 #define DT2821_MUXBUSY 0x0100 /* (R) multiplexer busy */
111 #define DT2821_ADDONE 0x0080 /* (R) A/D done */
112 #define DT2821_IADDONE 0x0040 /* (R/W) interrupt on A/D done */
113 /* 0x0030 gain select */
114 /* 0x000f channel select */
118 #define DT2821_LLE 0x8000 /* (R/W) Load List Enable */
119 /* 0x7000 read as 1's */
120 /* 0x0f00 (R) present address */
121 /* 0x00f0 read as 1's */
122 /* 0x000f (R) number of entries - 1 */
126 #define DT2821_DAERR 0x8000 /* (R) D/A error */
127 #define DT2821_YSEL 0x0200 /* (R/W) DAC 1 select */
128 #define DT2821_SSEL 0x0100 /* (R/W) single channel select */
129 #define DT2821_DACRDY 0x0080 /* (R) DAC ready */
130 #define DT2821_IDARDY 0x0040 /* (R/W) interrupt on DAC ready */
131 #define DT2821_DACLK 0x0020 /* (R/W) D/A clock enable */
132 #define DT2821_HBOE 0x0002 /* (R/W) DIO high byte output enable */
133 #define DT2821_LBOE 0x0001 /* (R/W) DIO low byte output enable */
137 #define DT2821_DMAD 0x8000 /* (R) DMA done */
138 #define DT2821_ERRINTEN 0x4000 /* (R/W) interrupt on error */
139 #define DT2821_CLRDMADNE 0x2000 /* (W) clear DMA done */
140 #define DT2821_DDMA 0x1000 /* (R/W) dual DMA */
141 #define DT2821_DS1 0x0800 /* (R/W) DMA select 1 */
142 #define DT2821_DS0 0x0400 /* (R/W) DMA select 0 */
143 #define DT2821_BUFFB 0x0200 /* (R/W) buffer B selected */
144 #define DT2821_SCDN 0x0100 /* (R) scan done */
145 #define DT2821_DACON 0x0080 /* (W) DAC single conversion */
146 #define DT2821_ADCINIT 0x0040 /* (W) A/D initialize */
147 #define DT2821_DACINIT 0x0020 /* (W) D/A initialize */
148 #define DT2821_PRLD 0x0010 /* (W) preload multiplexer */
149 #define DT2821_STRIG 0x0008 /* (W) software trigger */
150 #define DT2821_XTRIG 0x0004 /* (R/W) external trigger enable */
151 #define DT2821_XCLK 0x0002 /* (R/W) external clock enable */
152 #define DT2821_BDINIT 0x0001 /* (W) initialize board */
154 static const struct comedi_lrange range_dt282x_ai_lo_bipolar = {
163 static const struct comedi_lrange range_dt282x_ai_lo_unipolar = {
172 static const struct comedi_lrange range_dt282x_ai_5_bipolar = {
181 static const struct comedi_lrange range_dt282x_ai_5_unipolar = {
190 static const struct comedi_lrange range_dt282x_ai_hi_bipolar = {
199 static const struct comedi_lrange range_dt282x_ai_hi_unipolar = {
208 struct dt282x_board {
219 struct dt282x_private {
220 int ad_2scomp; /* we have 2's comp jumper set */
221 int da0_2scomp; /* same, for DAC0 */
222 int da1_2scomp; /* same, for DAC1 */
224 const struct comedi_lrange *darangelist[2];
226 unsigned short ao[2];
228 volatile int dacsr; /* software copies of registers */
237 unsigned short *buf; /* DMA buffer */
238 volatile int size; /* size of current transfer */
240 int dma_maxsize; /* max size of DMA transfer (in bytes) */
241 int usedma; /* driver uses DMA */
242 volatile int current_dma_index;
247 * Some useless abstractions
249 #define chan_to_DAC(a) ((a)&1)
251 static int prep_ai_dma(struct comedi_device *dev, int chan, int size);
252 static int prep_ao_dma(struct comedi_device *dev, int chan, int size);
253 static int dt282x_ai_cancel(struct comedi_device *dev,
254 struct comedi_subdevice *s);
255 static int dt282x_ao_cancel(struct comedi_device *dev,
256 struct comedi_subdevice *s);
257 static int dt282x_ns_to_timer(int *nanosec, int round_mode);
258 static void dt282x_disable_dma(struct comedi_device *dev);
260 static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2);
262 static void dt282x_munge(struct comedi_device *dev, unsigned short *buf,
265 const struct dt282x_board *board = comedi_board(dev);
266 struct dt282x_private *devpriv = dev->private;
268 unsigned short mask = (1 << board->adbits) - 1;
269 unsigned short sign = 1 << (board->adbits - 1);
272 if (devpriv->ad_2scomp)
273 sign = 1 << (board->adbits - 1);
278 comedi_error(dev, "bug! odd number of bytes from dma xfer");
280 for (i = 0; i < n; i++)
281 buf[i] = (buf[i] & mask) ^ sign;
284 static void dt282x_ao_dma_interrupt(struct comedi_device *dev)
286 struct dt282x_private *devpriv = dev->private;
287 struct comedi_subdevice *s = dev->write_subdev;
292 outw(devpriv->supcsr | DT2821_CLRDMADNE, dev->iobase + DT2821_SUPCSR);
294 if (!s->async->prealloc_buf) {
295 dev_err(dev->class_dev, "no buffer in %s\n", __func__);
299 i = devpriv->current_dma_index;
300 ptr = devpriv->dma[i].buf;
302 disable_dma(devpriv->dma[i].chan);
304 devpriv->current_dma_index = 1 - i;
306 size = cfc_read_array_from_buffer(s, ptr, devpriv->dma_maxsize);
308 dev_err(dev->class_dev, "AO underrun\n");
309 s->async->events |= COMEDI_CB_OVERFLOW;
312 prep_ao_dma(dev, i, size);
316 static void dt282x_ai_dma_interrupt(struct comedi_device *dev)
318 struct dt282x_private *devpriv = dev->private;
319 struct comedi_subdevice *s = dev->read_subdev;
325 outw(devpriv->supcsr | DT2821_CLRDMADNE, dev->iobase + DT2821_SUPCSR);
327 if (!s->async->prealloc_buf) {
328 dev_err(dev->class_dev, "no buffer in %s\n", __func__);
332 i = devpriv->current_dma_index;
333 ptr = devpriv->dma[i].buf;
334 size = devpriv->dma[i].size;
336 disable_dma(devpriv->dma[i].chan);
338 devpriv->current_dma_index = 1 - i;
340 dt282x_munge(dev, ptr, size);
341 ret = cfc_write_array_to_buffer(s, ptr, size);
343 s->async->events |= COMEDI_CB_OVERFLOW;
346 devpriv->nread -= size / 2;
348 if (devpriv->nread < 0) {
349 dev_info(dev->class_dev, "nread off by one\n");
352 if (!devpriv->nread) {
353 s->async->events |= COMEDI_CB_EOA;
357 /* clear the dual dma flag, making this the last dma segment */
358 /* XXX probably wrong */
359 if (!devpriv->ntrig) {
360 devpriv->supcsr &= ~(DT2821_DDMA);
361 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR);
364 /* restart the channel */
365 prep_ai_dma(dev, i, 0);
368 static int prep_ai_dma(struct comedi_device *dev, int dma_index, int n)
370 struct dt282x_private *devpriv = dev->private;
372 unsigned long dma_ptr;
379 n = devpriv->dma_maxsize;
380 if (n > devpriv->ntrig * 2)
381 n = devpriv->ntrig * 2;
382 devpriv->ntrig -= n / 2;
384 devpriv->dma[dma_index].size = n;
385 dma_chan = devpriv->dma[dma_index].chan;
386 dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
388 set_dma_mode(dma_chan, DMA_MODE_READ);
389 flags = claim_dma_lock();
390 clear_dma_ff(dma_chan);
391 set_dma_addr(dma_chan, dma_ptr);
392 set_dma_count(dma_chan, n);
393 release_dma_lock(flags);
395 enable_dma(dma_chan);
400 static int prep_ao_dma(struct comedi_device *dev, int dma_index, int n)
402 struct dt282x_private *devpriv = dev->private;
404 unsigned long dma_ptr;
407 devpriv->dma[dma_index].size = n;
408 dma_chan = devpriv->dma[dma_index].chan;
409 dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
411 set_dma_mode(dma_chan, DMA_MODE_WRITE);
412 flags = claim_dma_lock();
413 clear_dma_ff(dma_chan);
414 set_dma_addr(dma_chan, dma_ptr);
415 set_dma_count(dma_chan, n);
416 release_dma_lock(flags);
418 enable_dma(dma_chan);
423 static irqreturn_t dt282x_interrupt(int irq, void *d)
425 struct comedi_device *dev = d;
426 struct dt282x_private *devpriv = dev->private;
427 struct comedi_subdevice *s = dev->read_subdev;
428 struct comedi_subdevice *s_ao = dev->write_subdev;
429 unsigned int supcsr, adcsr, dacsr;
432 if (!dev->attached) {
433 comedi_error(dev, "spurious interrupt");
437 adcsr = inw(dev->iobase + DT2821_ADCSR);
438 dacsr = inw(dev->iobase + DT2821_DACSR);
439 supcsr = inw(dev->iobase + DT2821_SUPCSR);
440 if (supcsr & DT2821_DMAD) {
441 if (devpriv->dma_dir == DMA_MODE_READ)
442 dt282x_ai_dma_interrupt(dev);
444 dt282x_ao_dma_interrupt(dev);
447 if (adcsr & DT2821_ADERR) {
448 if (devpriv->nread != 0) {
449 comedi_error(dev, "A/D error");
450 s->async->events |= COMEDI_CB_ERROR;
454 if (dacsr & DT2821_DAERR) {
455 comedi_error(dev, "D/A error");
456 s_ao->async->events |= COMEDI_CB_ERROR;
460 if (adcsr & DT2821_ADDONE) {
464 data = inw(dev->iobase + DT2821_ADDAT);
465 data &= (1 << board->adbits) - 1;
467 if (devpriv->ad_2scomp)
468 data ^= 1 << (board->adbits - 1);
469 ret = comedi_buf_put(s, data);
472 s->async->events |= COMEDI_CB_OVERFLOW;
475 if (!devpriv->nread) {
476 s->async->events |= COMEDI_CB_EOA;
478 if (supcsr & DT2821_SCDN)
479 outw(devpriv->supcsr | DT2821_STRIG,
480 dev->iobase + DT2821_SUPCSR);
485 cfc_handle_events(dev, s);
486 cfc_handle_events(dev, s_ao);
488 return IRQ_RETVAL(handled);
491 static void dt282x_load_changain(struct comedi_device *dev, int n,
492 unsigned int *chanlist)
494 struct dt282x_private *devpriv = dev->private;
496 unsigned int chan, range;
498 outw(DT2821_LLE | (n - 1), dev->iobase + DT2821_CHANCSR);
499 for (i = 0; i < n; i++) {
500 chan = CR_CHAN(chanlist[i]);
501 range = CR_RANGE(chanlist[i]);
502 outw(devpriv->adcsr | (range << 4) | chan,
503 dev->iobase + DT2821_ADCSR);
505 outw(n - 1, dev->iobase + DT2821_CHANCSR);
508 static int dt282x_ai_timeout(struct comedi_device *dev,
509 struct comedi_subdevice *s,
510 struct comedi_insn *insn,
511 unsigned long context)
515 status = inw(dev->iobase + DT2821_ADCSR);
518 if ((status & DT2821_MUXBUSY) == 0)
522 if (status & DT2821_ADDONE)
532 * Performs a single A/D conversion.
533 * - Put channel/gain into channel-gain list
534 * - preload multiplexer
535 * - trigger conversion and wait for it to finish
537 static int dt282x_ai_insn_read(struct comedi_device *dev,
538 struct comedi_subdevice *s,
539 struct comedi_insn *insn, unsigned int *data)
541 const struct dt282x_board *board = comedi_board(dev);
542 struct dt282x_private *devpriv = dev->private;
546 /* XXX should we really be enabling the ad clock here? */
547 devpriv->adcsr = DT2821_ADCLK;
548 outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR);
550 dt282x_load_changain(dev, 1, &insn->chanspec);
552 outw(devpriv->supcsr | DT2821_PRLD, dev->iobase + DT2821_SUPCSR);
553 ret = comedi_timeout(dev, s, insn, dt282x_ai_timeout, DT2821_MUXBUSY);
557 for (i = 0; i < insn->n; i++) {
558 outw(devpriv->supcsr | DT2821_STRIG,
559 dev->iobase + DT2821_SUPCSR);
561 ret = comedi_timeout(dev, s, insn, dt282x_ai_timeout,
568 DT2821_ADDAT) & ((1 << board->adbits) - 1);
569 if (devpriv->ad_2scomp)
570 data[i] ^= (1 << (board->adbits - 1));
576 static int dt282x_ai_cmdtest(struct comedi_device *dev,
577 struct comedi_subdevice *s, struct comedi_cmd *cmd)
579 const struct dt282x_board *board = comedi_board(dev);
583 /* Step 1 : check if triggers are trivially valid */
585 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
586 err |= cfc_check_trigger_src(&cmd->scan_begin_src,
587 TRIG_FOLLOW | TRIG_EXT);
588 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
589 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
590 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
595 /* Step 2a : make sure trigger sources are unique */
597 err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
598 err |= cfc_check_trigger_is_unique(cmd->stop_src);
600 /* Step 2b : and mutually compatible */
605 /* Step 3: check if arguments are trivially valid */
607 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
609 if (cmd->scan_begin_src == TRIG_FOLLOW) {
610 /* internal trigger */
611 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
613 /* external trigger */
614 /* should be level/edge, hi/lo specification here */
615 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
618 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 4000);
620 #define SLOWEST_TIMER (250*(1<<15)*255)
621 err |= cfc_check_trigger_arg_max(&cmd->convert_arg, SLOWEST_TIMER);
622 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, board->ai_speed);
623 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
625 if (cmd->stop_src == TRIG_COUNT) {
626 /* any count is allowed */
627 } else { /* TRIG_NONE */
628 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
634 /* step 4: fix up any arguments */
636 arg = cmd->convert_arg;
637 dt282x_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK);
638 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
646 static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
648 const struct dt282x_board *board = comedi_board(dev);
649 struct dt282x_private *devpriv = dev->private;
650 struct comedi_cmd *cmd = &s->async->cmd;
654 if (devpriv->usedma == 0) {
656 "driver requires 2 dma channels"
657 " to execute command");
661 dt282x_disable_dma(dev);
663 if (cmd->convert_arg < board->ai_speed)
664 cmd->convert_arg = board->ai_speed;
665 timer = dt282x_ns_to_timer(&cmd->convert_arg, TRIG_ROUND_NEAREST);
666 outw(timer, dev->iobase + DT2821_TMRCTR);
668 if (cmd->scan_begin_src == TRIG_FOLLOW) {
669 /* internal trigger */
670 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0;
672 /* external trigger */
673 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0 | DT2821_DS1;
675 outw(devpriv->supcsr | DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_ADCINIT,
676 dev->iobase + DT2821_SUPCSR);
678 devpriv->ntrig = cmd->stop_arg * cmd->scan_end_arg;
679 devpriv->nread = devpriv->ntrig;
681 devpriv->dma_dir = DMA_MODE_READ;
682 devpriv->current_dma_index = 0;
683 prep_ai_dma(dev, 0, 0);
684 if (devpriv->ntrig) {
685 prep_ai_dma(dev, 1, 0);
686 devpriv->supcsr |= DT2821_DDMA;
687 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR);
692 dt282x_load_changain(dev, cmd->chanlist_len, cmd->chanlist);
694 devpriv->adcsr = DT2821_ADCLK | DT2821_IADDONE;
695 outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR);
697 outw(devpriv->supcsr | DT2821_PRLD, dev->iobase + DT2821_SUPCSR);
698 ret = comedi_timeout(dev, s, NULL, dt282x_ai_timeout, DT2821_MUXBUSY);
702 if (cmd->scan_begin_src == TRIG_FOLLOW) {
703 outw(devpriv->supcsr | DT2821_STRIG,
704 dev->iobase + DT2821_SUPCSR);
706 devpriv->supcsr |= DT2821_XTRIG;
707 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR);
713 static void dt282x_disable_dma(struct comedi_device *dev)
715 struct dt282x_private *devpriv = dev->private;
717 if (devpriv->usedma) {
718 disable_dma(devpriv->dma[0].chan);
719 disable_dma(devpriv->dma[1].chan);
723 static int dt282x_ai_cancel(struct comedi_device *dev,
724 struct comedi_subdevice *s)
726 struct dt282x_private *devpriv = dev->private;
728 dt282x_disable_dma(dev);
731 outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR);
734 outw(devpriv->supcsr | DT2821_ADCINIT, dev->iobase + DT2821_SUPCSR);
739 static int dt282x_ns_to_timer(int *nanosec, int round_mode)
741 int prescale, base, divider;
743 for (prescale = 0; prescale < 16; prescale++) {
746 base = 250 * (1 << prescale);
747 switch (round_mode) {
748 case TRIG_ROUND_NEAREST:
750 divider = (*nanosec + base / 2) / base;
752 case TRIG_ROUND_DOWN:
753 divider = (*nanosec) / base;
756 divider = (*nanosec + base - 1) / base;
760 *nanosec = divider * base;
761 return (prescale << 8) | (255 - divider);
764 base = 250 * (1 << 15);
766 *nanosec = divider * base;
767 return (15 << 8) | (255 - divider);
771 * Analog output routine. Selects single channel conversion,
772 * selects correct channel, converts from 2's compliment to
773 * offset binary if necessary, loads the data into the DAC
774 * data register, and performs the conversion.
776 static int dt282x_ao_insn_read(struct comedi_device *dev,
777 struct comedi_subdevice *s,
778 struct comedi_insn *insn, unsigned int *data)
780 struct dt282x_private *devpriv = dev->private;
782 data[0] = devpriv->ao[CR_CHAN(insn->chanspec)];
787 static int dt282x_ao_insn_write(struct comedi_device *dev,
788 struct comedi_subdevice *s,
789 struct comedi_insn *insn, unsigned int *data)
791 const struct dt282x_board *board = comedi_board(dev);
792 struct dt282x_private *devpriv = dev->private;
796 chan = CR_CHAN(insn->chanspec);
798 d &= (1 << board->dabits) - 1;
799 devpriv->ao[chan] = d;
801 devpriv->dacsr |= DT2821_SSEL;
805 devpriv->dacsr |= DT2821_YSEL;
806 if (devpriv->da0_2scomp)
807 d ^= (1 << (board->dabits - 1));
809 devpriv->dacsr &= ~DT2821_YSEL;
810 if (devpriv->da1_2scomp)
811 d ^= (1 << (board->dabits - 1));
814 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
816 outw(d, dev->iobase + DT2821_DADAT);
818 outw(devpriv->supcsr | DT2821_DACON, dev->iobase + DT2821_SUPCSR);
823 static int dt282x_ao_cmdtest(struct comedi_device *dev,
824 struct comedi_subdevice *s, struct comedi_cmd *cmd)
829 /* Step 1 : check if triggers are trivially valid */
831 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT);
832 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
833 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
834 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
835 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
840 /* Step 2a : make sure trigger sources are unique */
842 err |= cfc_check_trigger_is_unique(cmd->stop_src);
844 /* Step 2b : and mutually compatible */
849 /* Step 3: check if arguments are trivially valid */
851 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
852 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 5000);
853 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
854 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
856 if (cmd->stop_src == TRIG_COUNT) {
857 /* any count is allowed */
858 } else { /* TRIG_NONE */
859 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
865 /* step 4: fix up any arguments */
867 arg = cmd->scan_begin_arg;
868 dt282x_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK);
869 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
878 static int dt282x_ao_inttrig(struct comedi_device *dev,
879 struct comedi_subdevice *s,
880 unsigned int trig_num)
882 struct dt282x_private *devpriv = dev->private;
883 struct comedi_cmd *cmd = &s->async->cmd;
886 if (trig_num != cmd->start_src)
889 size = cfc_read_array_from_buffer(s, devpriv->dma[0].buf,
890 devpriv->dma_maxsize);
892 dev_err(dev->class_dev, "AO underrun\n");
895 prep_ao_dma(dev, 0, size);
897 size = cfc_read_array_from_buffer(s, devpriv->dma[1].buf,
898 devpriv->dma_maxsize);
900 dev_err(dev->class_dev, "AO underrun\n");
903 prep_ao_dma(dev, 1, size);
905 outw(devpriv->supcsr | DT2821_STRIG, dev->iobase + DT2821_SUPCSR);
906 s->async->inttrig = NULL;
911 static int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
913 struct dt282x_private *devpriv = dev->private;
915 struct comedi_cmd *cmd = &s->async->cmd;
917 if (devpriv->usedma == 0) {
919 "driver requires 2 dma channels"
920 " to execute command");
924 dt282x_disable_dma(dev);
926 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS1 | DT2821_DDMA;
927 outw(devpriv->supcsr | DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_DACINIT,
928 dev->iobase + DT2821_SUPCSR);
930 devpriv->ntrig = cmd->stop_arg * cmd->chanlist_len;
931 devpriv->nread = devpriv->ntrig;
933 devpriv->dma_dir = DMA_MODE_WRITE;
934 devpriv->current_dma_index = 0;
936 timer = dt282x_ns_to_timer(&cmd->scan_begin_arg, TRIG_ROUND_NEAREST);
937 outw(timer, dev->iobase + DT2821_TMRCTR);
939 devpriv->dacsr = DT2821_SSEL | DT2821_DACLK | DT2821_IDARDY;
940 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
942 s->async->inttrig = dt282x_ao_inttrig;
947 static int dt282x_ao_cancel(struct comedi_device *dev,
948 struct comedi_subdevice *s)
950 struct dt282x_private *devpriv = dev->private;
952 dt282x_disable_dma(dev);
955 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
958 outw(devpriv->supcsr | DT2821_DACINIT, dev->iobase + DT2821_SUPCSR);
963 static int dt282x_dio_insn_bits(struct comedi_device *dev,
964 struct comedi_subdevice *s,
965 struct comedi_insn *insn,
968 if (comedi_dio_update_state(s, data))
969 outw(s->state, dev->iobase + DT2821_DIODAT);
971 data[1] = inw(dev->iobase + DT2821_DIODAT);
976 static int dt282x_dio_insn_config(struct comedi_device *dev,
977 struct comedi_subdevice *s,
978 struct comedi_insn *insn,
981 struct dt282x_private *devpriv = dev->private;
982 unsigned int chan = CR_CHAN(insn->chanspec);
991 ret = comedi_dio_insn_config(dev, s, insn, data, mask);
995 devpriv->dacsr &= ~(DT2821_LBOE | DT2821_HBOE);
996 if (s->io_bits & 0x00ff)
997 devpriv->dacsr |= DT2821_LBOE;
998 if (s->io_bits & 0xff00)
999 devpriv->dacsr |= DT2821_HBOE;
1001 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
1006 static const struct comedi_lrange *const ai_range_table[] = {
1007 &range_dt282x_ai_lo_bipolar,
1008 &range_dt282x_ai_lo_unipolar,
1009 &range_dt282x_ai_5_bipolar,
1010 &range_dt282x_ai_5_unipolar
1013 static const struct comedi_lrange *const ai_range_pgl_table[] = {
1014 &range_dt282x_ai_hi_bipolar,
1015 &range_dt282x_ai_hi_unipolar
1018 static const struct comedi_lrange *opt_ai_range_lkup(int ispgl, int x)
1021 if (x < 0 || x >= 2)
1023 return ai_range_pgl_table[x];
1025 if (x < 0 || x >= 4)
1027 return ai_range_table[x];
1031 static const struct comedi_lrange *const ao_range_table[] = {
1039 static const struct comedi_lrange *opt_ao_range_lkup(int x)
1041 if (x < 0 || x >= 5)
1043 return ao_range_table[x];
1046 enum { /* i/o base, irq, dma channels */
1047 opt_iobase = 0, opt_irq, opt_dma1, opt_dma2,
1048 opt_diff, /* differential */
1049 opt_ai_twos, opt_ao0_twos, opt_ao1_twos, /* twos comp */
1050 opt_ai_range, opt_ao0_range, opt_ao1_range, /* range */
1053 static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2)
1055 struct dt282x_private *devpriv = dev->private;
1058 devpriv->usedma = 0;
1063 if (dma1 == dma2 || dma1 < 5 || dma2 < 5 || dma1 > 7 || dma2 > 7)
1073 ret = request_dma(dma1, "dt282x A");
1076 devpriv->dma[0].chan = dma1;
1078 ret = request_dma(dma2, "dt282x B");
1081 devpriv->dma[1].chan = dma2;
1083 devpriv->dma_maxsize = PAGE_SIZE;
1084 devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
1085 devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
1086 if (!devpriv->dma[0].buf || !devpriv->dma[1].buf)
1089 devpriv->usedma = 1;
1100 4 0=single ended, 1=differential
1101 5 ai 0=straight binary, 1=2's comp
1102 6 ao0 0=straight binary, 1=2's comp
1103 7 ao1 0=straight binary, 1=2's comp
1104 8 ai 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V
1105 9 ao0 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1106 10 ao1 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1108 static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1110 const struct dt282x_board *board = comedi_board(dev);
1111 struct dt282x_private *devpriv;
1112 struct comedi_subdevice *s;
1116 ret = comedi_request_region(dev, it->options[0], DT2821_SIZE);
1120 outw(DT2821_BDINIT, dev->iobase + DT2821_SUPCSR);
1121 i = inw(dev->iobase + DT2821_ADCSR);
1123 if (((inw(dev->iobase + DT2821_ADCSR) & DT2821_ADCSR_MASK)
1124 != DT2821_ADCSR_VAL) ||
1125 ((inw(dev->iobase + DT2821_CHANCSR) & DT2821_CHANCSR_MASK)
1126 != DT2821_CHANCSR_VAL) ||
1127 ((inw(dev->iobase + DT2821_DACSR) & DT2821_DACSR_MASK)
1128 != DT2821_DACSR_VAL) ||
1129 ((inw(dev->iobase + DT2821_SUPCSR) & DT2821_SUPCSR_MASK)
1130 != DT2821_SUPCSR_VAL) ||
1131 ((inw(dev->iobase + DT2821_TMRCTR) & DT2821_TMRCTR_MASK)
1132 != DT2821_TMRCTR_VAL)) {
1133 dev_err(dev->class_dev, "board not found\n");
1136 /* should do board test */
1138 if (it->options[opt_irq] > 0) {
1139 ret = request_irq(it->options[opt_irq], dt282x_interrupt, 0,
1140 dev->board_name, dev);
1142 dev->irq = it->options[opt_irq];
1145 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1150 ret = dt282x_grab_dma(dev, it->options[opt_dma1],
1151 it->options[opt_dma2]);
1156 ret = comedi_alloc_subdevices(dev, 3);
1160 s = &dev->subdevices[0];
1163 s->type = COMEDI_SUBD_AI;
1164 s->subdev_flags = SDF_READABLE |
1165 ((it->options[opt_diff]) ? SDF_DIFF : SDF_COMMON);
1167 (it->options[opt_diff]) ? board->adchan_di : board->adchan_se;
1168 s->insn_read = dt282x_ai_insn_read;
1169 s->maxdata = (1 << board->adbits) - 1;
1171 opt_ai_range_lkup(board->ispgl, it->options[opt_ai_range]);
1172 devpriv->ad_2scomp = it->options[opt_ai_twos];
1174 dev->read_subdev = s;
1175 s->subdev_flags |= SDF_CMD_READ;
1176 s->len_chanlist = 16;
1177 s->do_cmdtest = dt282x_ai_cmdtest;
1178 s->do_cmd = dt282x_ai_cmd;
1179 s->cancel = dt282x_ai_cancel;
1182 s = &dev->subdevices[1];
1184 s->n_chan = board->dachan;
1187 s->type = COMEDI_SUBD_AO;
1188 s->subdev_flags = SDF_WRITABLE;
1189 s->insn_read = dt282x_ao_insn_read;
1190 s->insn_write = dt282x_ao_insn_write;
1191 s->maxdata = (1 << board->dabits) - 1;
1192 s->range_table_list = devpriv->darangelist;
1193 devpriv->darangelist[0] =
1194 opt_ao_range_lkup(it->options[opt_ao0_range]);
1195 devpriv->darangelist[1] =
1196 opt_ao_range_lkup(it->options[opt_ao1_range]);
1197 devpriv->da0_2scomp = it->options[opt_ao0_twos];
1198 devpriv->da1_2scomp = it->options[opt_ao1_twos];
1200 dev->write_subdev = s;
1201 s->subdev_flags |= SDF_CMD_WRITE;
1202 s->len_chanlist = 2;
1203 s->do_cmdtest = dt282x_ao_cmdtest;
1204 s->do_cmd = dt282x_ao_cmd;
1205 s->cancel = dt282x_ao_cancel;
1208 s->type = COMEDI_SUBD_UNUSED;
1211 s = &dev->subdevices[2];
1213 s->type = COMEDI_SUBD_DIO;
1214 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1216 s->insn_bits = dt282x_dio_insn_bits;
1217 s->insn_config = dt282x_dio_insn_config;
1219 s->range_table = &range_digital;
1224 static void dt282x_detach(struct comedi_device *dev)
1226 struct dt282x_private *devpriv = dev->private;
1229 if (devpriv->dma[0].chan)
1230 free_dma(devpriv->dma[0].chan);
1231 if (devpriv->dma[1].chan)
1232 free_dma(devpriv->dma[1].chan);
1233 if (devpriv->dma[0].buf)
1234 free_page((unsigned long)devpriv->dma[0].buf);
1235 if (devpriv->dma[1].buf)
1236 free_page((unsigned long)devpriv->dma[1].buf);
1238 comedi_legacy_detach(dev);
1241 static const struct dt282x_board boardtypes[] = {
1279 .name = "dt2824-pgh",
1288 .name = "dt2824-pgl",
1360 .name = "dt24-ez-pgl",
1371 static struct comedi_driver dt282x_driver = {
1372 .driver_name = "dt282x",
1373 .module = THIS_MODULE,
1374 .attach = dt282x_attach,
1375 .detach = dt282x_detach,
1376 .board_name = &boardtypes[0].name,
1377 .num_names = ARRAY_SIZE(boardtypes),
1378 .offset = sizeof(struct dt282x_board),
1380 module_comedi_driver(dt282x_driver);
1382 MODULE_AUTHOR("Comedi http://www.comedi.org");
1383 MODULE_DESCRIPTION("Comedi low-level driver");
1384 MODULE_LICENSE("GPL");