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.
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 DT2821 series (including DT-EZ)
27 Devices: [Data Translation] DT2821 (dt2821),
28 DT2821-F-16SE (dt2821-f), DT2821-F-8DI (dt2821-f),
29 DT2821-G-16SE (dt2821-f), DT2821-G-8DI (dt2821-g),
31 DT2824-PGH (dt2824-pgh), DT2824-PGL (dt2824-pgl), DT2825 (dt2825),
32 DT2827 (dt2827), DT2828 (dt2828), DT21-EZ (dt21-ez), DT23-EZ (dt23-ez),
33 DT24-EZ (dt24-ez), DT24-EZ-PGL (dt24-ez-pgl)
35 Updated: Wed, 22 Aug 2001 17:11:34 -0700
37 Configuration options:
38 [0] - I/O port base address
42 [4] - AI jumpered for 0=single ended, 1=differential
43 [5] - AI jumpered for 0=straight binary, 1=2's complement
44 [6] - AO 0 jumpered for 0=straight binary, 1=2's complement
45 [7] - AO 1 jumpered for 0=straight binary, 1=2's complement
46 [8] - AI jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5]
47 [9] - AO 0 jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5],
49 [10]- A0 1 jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5],
53 - AO commands might be broken.
54 - If you try to run a command on both the AI and AO subdevices
55 simultaneously, bad things will happen. The driver needs to
56 be fixed to check for this situation and return an error.
59 #include "../comedidev.h"
61 #include <linux/gfp.h>
62 #include <linux/ioport.h>
63 #include <linux/interrupt.h>
66 #include "comedi_fc.h"
70 #define DT2821_TIMEOUT 100 /* 500 us */
71 #define DT2821_SIZE 0x10
74 * Registers in the DT282x
77 #define DT2821_ADCSR 0x00 /* A/D Control/Status */
78 #define DT2821_CHANCSR 0x02 /* Channel Control/Status */
79 #define DT2821_ADDAT 0x04 /* A/D data */
80 #define DT2821_DACSR 0x06 /* D/A Control/Status */
81 #define DT2821_DADAT 0x08 /* D/A data */
82 #define DT2821_DIODAT 0x0a /* digital data */
83 #define DT2821_SUPCSR 0x0c /* Supervisor Control/Status */
84 #define DT2821_TMRCTR 0x0e /* Timer/Counter */
87 * At power up, some registers are in a well-known state. The
88 * masks and values are as follows:
91 #define DT2821_ADCSR_MASK 0xfff0
92 #define DT2821_ADCSR_VAL 0x7c00
94 #define DT2821_CHANCSR_MASK 0xf0f0
95 #define DT2821_CHANCSR_VAL 0x70f0
97 #define DT2821_DACSR_MASK 0x7c93
98 #define DT2821_DACSR_VAL 0x7c90
100 #define DT2821_SUPCSR_MASK 0xf8ff
101 #define DT2821_SUPCSR_VAL 0x0000
103 #define DT2821_TMRCTR_MASK 0xff00
104 #define DT2821_TMRCTR_VAL 0xf000
107 * Bit fields of each register
112 #define DT2821_ADERR 0x8000 /* (R) 1 for A/D error */
113 #define DT2821_ADCLK 0x0200 /* (R/W) A/D clock enable */
114 /* 0x7c00 read as 1's */
115 #define DT2821_MUXBUSY 0x0100 /* (R) multiplexer busy */
116 #define DT2821_ADDONE 0x0080 /* (R) A/D done */
117 #define DT2821_IADDONE 0x0040 /* (R/W) interrupt on A/D done */
118 /* 0x0030 gain select */
119 /* 0x000f channel select */
123 #define DT2821_LLE 0x8000 /* (R/W) Load List Enable */
124 /* 0x7000 read as 1's */
125 /* 0x0f00 (R) present address */
126 /* 0x00f0 read as 1's */
127 /* 0x000f (R) number of entries - 1 */
131 #define DT2821_DAERR 0x8000 /* (R) D/A error */
132 #define DT2821_YSEL 0x0200 /* (R/W) DAC 1 select */
133 #define DT2821_SSEL 0x0100 /* (R/W) single channel select */
134 #define DT2821_DACRDY 0x0080 /* (R) DAC ready */
135 #define DT2821_IDARDY 0x0040 /* (R/W) interrupt on DAC ready */
136 #define DT2821_DACLK 0x0020 /* (R/W) D/A clock enable */
137 #define DT2821_HBOE 0x0002 /* (R/W) DIO high byte output enable */
138 #define DT2821_LBOE 0x0001 /* (R/W) DIO low byte output enable */
142 #define DT2821_DMAD 0x8000 /* (R) DMA done */
143 #define DT2821_ERRINTEN 0x4000 /* (R/W) interrupt on error */
144 #define DT2821_CLRDMADNE 0x2000 /* (W) clear DMA done */
145 #define DT2821_DDMA 0x1000 /* (R/W) dual DMA */
146 #define DT2821_DS1 0x0800 /* (R/W) DMA select 1 */
147 #define DT2821_DS0 0x0400 /* (R/W) DMA select 0 */
148 #define DT2821_BUFFB 0x0200 /* (R/W) buffer B selected */
149 #define DT2821_SCDN 0x0100 /* (R) scan done */
150 #define DT2821_DACON 0x0080 /* (W) DAC single conversion */
151 #define DT2821_ADCINIT 0x0040 /* (W) A/D initialize */
152 #define DT2821_DACINIT 0x0020 /* (W) D/A initialize */
153 #define DT2821_PRLD 0x0010 /* (W) preload multiplexer */
154 #define DT2821_STRIG 0x0008 /* (W) software trigger */
155 #define DT2821_XTRIG 0x0004 /* (R/W) external trigger enable */
156 #define DT2821_XCLK 0x0002 /* (R/W) external clock enable */
157 #define DT2821_BDINIT 0x0001 /* (W) initialize board */
159 static const struct comedi_lrange range_dt282x_ai_lo_bipolar = {
168 static const struct comedi_lrange range_dt282x_ai_lo_unipolar = {
177 static const struct comedi_lrange range_dt282x_ai_5_bipolar = {
186 static const struct comedi_lrange range_dt282x_ai_5_unipolar = {
195 static const struct comedi_lrange range_dt282x_ai_hi_bipolar = {
204 static const struct comedi_lrange range_dt282x_ai_hi_unipolar = {
213 struct dt282x_board {
224 struct dt282x_private {
225 int ad_2scomp; /* we have 2's comp jumper set */
226 int da0_2scomp; /* same, for DAC0 */
227 int da1_2scomp; /* same, for DAC1 */
229 const struct comedi_lrange *darangelist[2];
233 volatile int dacsr; /* software copies of registers */
242 short *buf; /* DMA buffer */
243 volatile int size; /* size of current transfer */
245 int dma_maxsize; /* max size of DMA transfer (in bytes) */
246 int usedma; /* driver uses DMA */
247 volatile int current_dma_index;
251 #define boardtype (*(const struct dt282x_board *)dev->board_ptr)
254 * Some useless abstractions
256 #define chan_to_DAC(a) ((a)&1)
257 #define mux_busy() (inw(dev->iobase+DT2821_ADCSR)&DT2821_MUXBUSY)
258 #define ad_done() (inw(dev->iobase+DT2821_ADCSR)&DT2821_ADDONE)
261 * danger! macro abuse... a is the expression to wait on, and b is
262 * the statement(s) to execute if it doesn't happen.
264 #define wait_for(a, b) \
267 for (_i = 0; _i < DT2821_TIMEOUT; _i++) { \
278 static int prep_ai_dma(struct comedi_device *dev, int chan, int size);
279 static int prep_ao_dma(struct comedi_device *dev, int chan, int size);
280 static int dt282x_ai_cancel(struct comedi_device *dev,
281 struct comedi_subdevice *s);
282 static int dt282x_ao_cancel(struct comedi_device *dev,
283 struct comedi_subdevice *s);
284 static int dt282x_ns_to_timer(int *nanosec, int round_mode);
285 static void dt282x_disable_dma(struct comedi_device *dev);
287 static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2);
289 static void dt282x_munge(struct comedi_device *dev, short *buf,
292 struct dt282x_private *devpriv = dev->private;
294 unsigned short mask = (1 << boardtype.adbits) - 1;
295 unsigned short sign = 1 << (boardtype.adbits - 1);
298 if (devpriv->ad_2scomp)
299 sign = 1 << (boardtype.adbits - 1);
304 comedi_error(dev, "bug! odd number of bytes from dma xfer");
306 for (i = 0; i < n; i++)
307 buf[i] = (buf[i] & mask) ^ sign;
310 static void dt282x_ao_dma_interrupt(struct comedi_device *dev)
312 struct dt282x_private *devpriv = dev->private;
316 struct comedi_subdevice *s = &dev->subdevices[1];
318 outw(devpriv->supcsr | DT2821_CLRDMADNE, dev->iobase + DT2821_SUPCSR);
320 if (!s->async->prealloc_buf) {
321 printk(KERN_ERR "async->data disappeared. dang!\n");
325 i = devpriv->current_dma_index;
326 ptr = devpriv->dma[i].buf;
328 disable_dma(devpriv->dma[i].chan);
330 devpriv->current_dma_index = 1 - i;
332 size = cfc_read_array_from_buffer(s, ptr, devpriv->dma_maxsize);
334 printk(KERN_ERR "dt282x: AO underrun\n");
335 dt282x_ao_cancel(dev, s);
336 s->async->events |= COMEDI_CB_OVERFLOW;
339 prep_ao_dma(dev, i, size);
343 static void dt282x_ai_dma_interrupt(struct comedi_device *dev)
345 struct dt282x_private *devpriv = dev->private;
350 struct comedi_subdevice *s = &dev->subdevices[0];
352 outw(devpriv->supcsr | DT2821_CLRDMADNE, dev->iobase + DT2821_SUPCSR);
354 if (!s->async->prealloc_buf) {
355 printk(KERN_ERR "async->data disappeared. dang!\n");
359 i = devpriv->current_dma_index;
360 ptr = devpriv->dma[i].buf;
361 size = devpriv->dma[i].size;
363 disable_dma(devpriv->dma[i].chan);
365 devpriv->current_dma_index = 1 - i;
367 dt282x_munge(dev, ptr, size);
368 ret = cfc_write_array_to_buffer(s, ptr, size);
370 dt282x_ai_cancel(dev, s);
373 devpriv->nread -= size / 2;
375 if (devpriv->nread < 0) {
376 printk(KERN_INFO "dt282x: off by one\n");
379 if (!devpriv->nread) {
380 dt282x_ai_cancel(dev, s);
381 s->async->events |= COMEDI_CB_EOA;
385 /* clear the dual dma flag, making this the last dma segment */
386 /* XXX probably wrong */
387 if (!devpriv->ntrig) {
388 devpriv->supcsr &= ~(DT2821_DDMA);
389 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR);
392 /* restart the channel */
393 prep_ai_dma(dev, i, 0);
396 static int prep_ai_dma(struct comedi_device *dev, int dma_index, int n)
398 struct dt282x_private *devpriv = dev->private;
400 unsigned long dma_ptr;
407 n = devpriv->dma_maxsize;
408 if (n > devpriv->ntrig * 2)
409 n = devpriv->ntrig * 2;
410 devpriv->ntrig -= n / 2;
412 devpriv->dma[dma_index].size = n;
413 dma_chan = devpriv->dma[dma_index].chan;
414 dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
416 set_dma_mode(dma_chan, DMA_MODE_READ);
417 flags = claim_dma_lock();
418 clear_dma_ff(dma_chan);
419 set_dma_addr(dma_chan, dma_ptr);
420 set_dma_count(dma_chan, n);
421 release_dma_lock(flags);
423 enable_dma(dma_chan);
428 static int prep_ao_dma(struct comedi_device *dev, int dma_index, int n)
430 struct dt282x_private *devpriv = dev->private;
432 unsigned long dma_ptr;
435 devpriv->dma[dma_index].size = n;
436 dma_chan = devpriv->dma[dma_index].chan;
437 dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
439 set_dma_mode(dma_chan, DMA_MODE_WRITE);
440 flags = claim_dma_lock();
441 clear_dma_ff(dma_chan);
442 set_dma_addr(dma_chan, dma_ptr);
443 set_dma_count(dma_chan, n);
444 release_dma_lock(flags);
446 enable_dma(dma_chan);
451 static irqreturn_t dt282x_interrupt(int irq, void *d)
453 struct comedi_device *dev = d;
454 struct dt282x_private *devpriv = dev->private;
455 struct comedi_subdevice *s;
456 struct comedi_subdevice *s_ao;
457 unsigned int supcsr, adcsr, dacsr;
460 if (!dev->attached) {
461 comedi_error(dev, "spurious interrupt");
465 s = &dev->subdevices[0];
466 s_ao = &dev->subdevices[1];
467 adcsr = inw(dev->iobase + DT2821_ADCSR);
468 dacsr = inw(dev->iobase + DT2821_DACSR);
469 supcsr = inw(dev->iobase + DT2821_SUPCSR);
470 if (supcsr & DT2821_DMAD) {
471 if (devpriv->dma_dir == DMA_MODE_READ)
472 dt282x_ai_dma_interrupt(dev);
474 dt282x_ao_dma_interrupt(dev);
477 if (adcsr & DT2821_ADERR) {
478 if (devpriv->nread != 0) {
479 comedi_error(dev, "A/D error");
480 dt282x_ai_cancel(dev, s);
481 s->async->events |= COMEDI_CB_ERROR;
485 if (dacsr & DT2821_DAERR) {
489 disable_irq(dev->irq);
490 printk(KERN_INFO "disabling irq\n");
493 comedi_error(dev, "D/A error");
494 dt282x_ao_cancel(dev, s_ao);
495 s->async->events |= COMEDI_CB_ERROR;
499 if (adcsr & DT2821_ADDONE) {
503 data = (short)inw(dev->iobase + DT2821_ADDAT);
504 data &= (1 << boardtype.adbits) - 1;
506 if (devpriv->ad_2scomp)
507 data ^= 1 << (boardtype.adbits - 1);
508 ret = comedi_buf_put(s->async, data);
511 s->async->events |= COMEDI_CB_OVERFLOW;
514 if (!devpriv->nread) {
515 s->async->events |= COMEDI_CB_EOA;
517 if (supcsr & DT2821_SCDN)
518 outw(devpriv->supcsr | DT2821_STRIG,
519 dev->iobase + DT2821_SUPCSR);
524 comedi_event(dev, s);
525 /* printk("adcsr=0x%02x dacsr-0x%02x supcsr=0x%02x\n",
526 adcsr, dacsr, supcsr); */
527 return IRQ_RETVAL(handled);
530 static void dt282x_load_changain(struct comedi_device *dev, int n,
531 unsigned int *chanlist)
533 struct dt282x_private *devpriv = dev->private;
535 unsigned int chan, range;
537 outw(DT2821_LLE | (n - 1), dev->iobase + DT2821_CHANCSR);
538 for (i = 0; i < n; i++) {
539 chan = CR_CHAN(chanlist[i]);
540 range = CR_RANGE(chanlist[i]);
541 outw(devpriv->adcsr | (range << 4) | chan,
542 dev->iobase + DT2821_ADCSR);
544 outw(n - 1, dev->iobase + DT2821_CHANCSR);
548 * Performs a single A/D conversion.
549 * - Put channel/gain into channel-gain list
550 * - preload multiplexer
551 * - trigger conversion and wait for it to finish
553 static int dt282x_ai_insn_read(struct comedi_device *dev,
554 struct comedi_subdevice *s,
555 struct comedi_insn *insn, unsigned int *data)
557 struct dt282x_private *devpriv = dev->private;
560 /* XXX should we really be enabling the ad clock here? */
561 devpriv->adcsr = DT2821_ADCLK;
562 outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR);
564 dt282x_load_changain(dev, 1, &insn->chanspec);
566 outw(devpriv->supcsr | DT2821_PRLD, dev->iobase + DT2821_SUPCSR);
567 wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;);
569 for (i = 0; i < insn->n; i++) {
570 outw(devpriv->supcsr | DT2821_STRIG,
571 dev->iobase + DT2821_SUPCSR);
572 wait_for(ad_done(), comedi_error(dev, "timeout\n");
577 DT2821_ADDAT) & ((1 << boardtype.adbits) - 1);
578 if (devpriv->ad_2scomp)
579 data[i] ^= (1 << (boardtype.adbits - 1));
585 static int dt282x_ai_cmdtest(struct comedi_device *dev,
586 struct comedi_subdevice *s, struct comedi_cmd *cmd)
588 const struct dt282x_board *board = comedi_board(dev);
592 /* Step 1 : check if triggers are trivially valid */
594 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
595 err |= cfc_check_trigger_src(&cmd->scan_begin_src,
596 TRIG_FOLLOW | TRIG_EXT);
597 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
598 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
599 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
604 /* Step 2a : make sure trigger sources are unique */
606 err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
607 err |= cfc_check_trigger_is_unique(cmd->stop_src);
609 /* Step 2b : and mutually compatible */
614 /* Step 3: check if arguments are trivially valid */
616 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
618 if (cmd->scan_begin_src == TRIG_FOLLOW) {
619 /* internal trigger */
620 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
622 /* external trigger */
623 /* should be level/edge, hi/lo specification here */
624 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
627 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 4000);
629 #define SLOWEST_TIMER (250*(1<<15)*255)
630 err |= cfc_check_trigger_arg_max(&cmd->convert_arg, SLOWEST_TIMER);
631 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, board->ai_speed);
632 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
634 if (cmd->stop_src == TRIG_COUNT) {
635 /* any count is allowed */
636 } else { /* TRIG_NONE */
637 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
643 /* step 4: fix up any arguments */
645 tmp = cmd->convert_arg;
646 dt282x_ns_to_timer(&cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK);
647 if (tmp != cmd->convert_arg)
656 static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
658 const struct dt282x_board *board = comedi_board(dev);
659 struct dt282x_private *devpriv = dev->private;
660 struct comedi_cmd *cmd = &s->async->cmd;
663 if (devpriv->usedma == 0) {
665 "driver requires 2 dma channels"
666 " to execute command");
670 dt282x_disable_dma(dev);
672 if (cmd->convert_arg < board->ai_speed)
673 cmd->convert_arg = board->ai_speed;
674 timer = dt282x_ns_to_timer(&cmd->convert_arg, TRIG_ROUND_NEAREST);
675 outw(timer, dev->iobase + DT2821_TMRCTR);
677 if (cmd->scan_begin_src == TRIG_FOLLOW) {
678 /* internal trigger */
679 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0;
681 /* external trigger */
682 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0 | DT2821_DS1;
684 outw(devpriv->supcsr | DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_ADCINIT,
685 dev->iobase + DT2821_SUPCSR);
687 devpriv->ntrig = cmd->stop_arg * cmd->scan_end_arg;
688 devpriv->nread = devpriv->ntrig;
690 devpriv->dma_dir = DMA_MODE_READ;
691 devpriv->current_dma_index = 0;
692 prep_ai_dma(dev, 0, 0);
693 if (devpriv->ntrig) {
694 prep_ai_dma(dev, 1, 0);
695 devpriv->supcsr |= DT2821_DDMA;
696 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR);
701 dt282x_load_changain(dev, cmd->chanlist_len, cmd->chanlist);
703 devpriv->adcsr = DT2821_ADCLK | DT2821_IADDONE;
704 outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR);
706 outw(devpriv->supcsr | DT2821_PRLD, dev->iobase + DT2821_SUPCSR);
707 wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;);
709 if (cmd->scan_begin_src == TRIG_FOLLOW) {
710 outw(devpriv->supcsr | DT2821_STRIG,
711 dev->iobase + DT2821_SUPCSR);
713 devpriv->supcsr |= DT2821_XTRIG;
714 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR);
720 static void dt282x_disable_dma(struct comedi_device *dev)
722 struct dt282x_private *devpriv = dev->private;
724 if (devpriv->usedma) {
725 disable_dma(devpriv->dma[0].chan);
726 disable_dma(devpriv->dma[1].chan);
730 static int dt282x_ai_cancel(struct comedi_device *dev,
731 struct comedi_subdevice *s)
733 struct dt282x_private *devpriv = dev->private;
735 dt282x_disable_dma(dev);
738 outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR);
741 outw(devpriv->supcsr | DT2821_ADCINIT, dev->iobase + DT2821_SUPCSR);
746 static int dt282x_ns_to_timer(int *nanosec, int round_mode)
748 int prescale, base, divider;
750 for (prescale = 0; prescale < 16; prescale++) {
753 base = 250 * (1 << prescale);
754 switch (round_mode) {
755 case TRIG_ROUND_NEAREST:
757 divider = (*nanosec + base / 2) / base;
759 case TRIG_ROUND_DOWN:
760 divider = (*nanosec) / base;
763 divider = (*nanosec + base - 1) / base;
767 *nanosec = divider * base;
768 return (prescale << 8) | (255 - divider);
771 base = 250 * (1 << 15);
773 *nanosec = divider * base;
774 return (15 << 8) | (255 - divider);
778 * Analog output routine. Selects single channel conversion,
779 * selects correct channel, converts from 2's compliment to
780 * offset binary if necessary, loads the data into the DAC
781 * data register, and performs the conversion.
783 static int dt282x_ao_insn_read(struct comedi_device *dev,
784 struct comedi_subdevice *s,
785 struct comedi_insn *insn, unsigned int *data)
787 struct dt282x_private *devpriv = dev->private;
789 data[0] = devpriv->ao[CR_CHAN(insn->chanspec)];
794 static int dt282x_ao_insn_write(struct comedi_device *dev,
795 struct comedi_subdevice *s,
796 struct comedi_insn *insn, unsigned int *data)
798 struct dt282x_private *devpriv = dev->private;
802 chan = CR_CHAN(insn->chanspec);
804 d &= (1 << boardtype.dabits) - 1;
805 devpriv->ao[chan] = d;
807 devpriv->dacsr |= DT2821_SSEL;
811 devpriv->dacsr |= DT2821_YSEL;
812 if (devpriv->da0_2scomp)
813 d ^= (1 << (boardtype.dabits - 1));
815 devpriv->dacsr &= ~DT2821_YSEL;
816 if (devpriv->da1_2scomp)
817 d ^= (1 << (boardtype.dabits - 1));
820 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
822 outw(d, dev->iobase + DT2821_DADAT);
824 outw(devpriv->supcsr | DT2821_DACON, dev->iobase + DT2821_SUPCSR);
829 static int dt282x_ao_cmdtest(struct comedi_device *dev,
830 struct comedi_subdevice *s, struct comedi_cmd *cmd)
835 /* Step 1 : check if triggers are trivially valid */
837 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT);
838 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
839 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
840 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
841 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
846 /* Step 2a : make sure trigger sources are unique */
848 err |= cfc_check_trigger_is_unique(cmd->stop_src);
850 /* Step 2b : and mutually compatible */
855 /* Step 3: check if arguments are trivially valid */
857 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
858 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 5000);
859 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
860 err |= cfc_check_trigger_arg_max(&cmd->scan_end_arg, 2);
862 if (cmd->stop_src == TRIG_COUNT) {
863 /* any count is allowed */
864 } else { /* TRIG_NONE */
865 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
871 /* step 4: fix up any arguments */
873 tmp = cmd->scan_begin_arg;
874 dt282x_ns_to_timer(&cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK);
875 if (tmp != cmd->scan_begin_arg)
885 static int dt282x_ao_inttrig(struct comedi_device *dev,
886 struct comedi_subdevice *s, unsigned int x)
888 struct dt282x_private *devpriv = dev->private;
894 size = cfc_read_array_from_buffer(s, devpriv->dma[0].buf,
895 devpriv->dma_maxsize);
897 printk(KERN_ERR "dt282x: AO underrun\n");
900 prep_ao_dma(dev, 0, size);
902 size = cfc_read_array_from_buffer(s, devpriv->dma[1].buf,
903 devpriv->dma_maxsize);
905 printk(KERN_ERR "dt282x: AO underrun\n");
908 prep_ao_dma(dev, 1, size);
910 outw(devpriv->supcsr | DT2821_STRIG, dev->iobase + DT2821_SUPCSR);
911 s->async->inttrig = NULL;
916 static int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
918 struct dt282x_private *devpriv = dev->private;
920 struct comedi_cmd *cmd = &s->async->cmd;
922 if (devpriv->usedma == 0) {
924 "driver requires 2 dma channels"
925 " to execute command");
929 dt282x_disable_dma(dev);
931 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS1 | DT2821_DDMA;
932 outw(devpriv->supcsr | DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_DACINIT,
933 dev->iobase + DT2821_SUPCSR);
935 devpriv->ntrig = cmd->stop_arg * cmd->chanlist_len;
936 devpriv->nread = devpriv->ntrig;
938 devpriv->dma_dir = DMA_MODE_WRITE;
939 devpriv->current_dma_index = 0;
941 timer = dt282x_ns_to_timer(&cmd->scan_begin_arg, TRIG_ROUND_NEAREST);
942 outw(timer, dev->iobase + DT2821_TMRCTR);
944 devpriv->dacsr = DT2821_SSEL | DT2821_DACLK | DT2821_IDARDY;
945 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
947 s->async->inttrig = dt282x_ao_inttrig;
952 static int dt282x_ao_cancel(struct comedi_device *dev,
953 struct comedi_subdevice *s)
955 struct dt282x_private *devpriv = dev->private;
957 dt282x_disable_dma(dev);
960 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
963 outw(devpriv->supcsr | DT2821_DACINIT, dev->iobase + DT2821_SUPCSR);
968 static int dt282x_dio_insn_bits(struct comedi_device *dev,
969 struct comedi_subdevice *s,
970 struct comedi_insn *insn, unsigned int *data)
973 s->state &= ~data[0];
974 s->state |= (data[0] & data[1]);
976 outw(s->state, dev->iobase + DT2821_DIODAT);
978 data[1] = inw(dev->iobase + DT2821_DIODAT);
983 static int dt282x_dio_insn_config(struct comedi_device *dev,
984 struct comedi_subdevice *s,
985 struct comedi_insn *insn, unsigned int *data)
987 struct dt282x_private *devpriv = dev->private;
990 mask = (CR_CHAN(insn->chanspec) < 8) ? 0x00ff : 0xff00;
996 if (s->io_bits & 0x00ff)
997 devpriv->dacsr |= DT2821_LBOE;
999 devpriv->dacsr &= ~DT2821_LBOE;
1000 if (s->io_bits & 0xff00)
1001 devpriv->dacsr |= DT2821_HBOE;
1003 devpriv->dacsr &= ~DT2821_HBOE;
1005 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
1010 static const struct comedi_lrange *const ai_range_table[] = {
1011 &range_dt282x_ai_lo_bipolar,
1012 &range_dt282x_ai_lo_unipolar,
1013 &range_dt282x_ai_5_bipolar,
1014 &range_dt282x_ai_5_unipolar
1017 static const struct comedi_lrange *const ai_range_pgl_table[] = {
1018 &range_dt282x_ai_hi_bipolar,
1019 &range_dt282x_ai_hi_unipolar
1022 static const struct comedi_lrange *opt_ai_range_lkup(int ispgl, int x)
1025 if (x < 0 || x >= 2)
1027 return ai_range_pgl_table[x];
1029 if (x < 0 || x >= 4)
1031 return ai_range_table[x];
1035 static const struct comedi_lrange *const ao_range_table[] = {
1043 static const struct comedi_lrange *opt_ao_range_lkup(int x)
1045 if (x < 0 || x >= 5)
1047 return ao_range_table[x];
1050 enum { /* i/o base, irq, dma channels */
1051 opt_iobase = 0, opt_irq, opt_dma1, opt_dma2,
1052 opt_diff, /* differential */
1053 opt_ai_twos, opt_ao0_twos, opt_ao1_twos, /* twos comp */
1054 opt_ai_range, opt_ao0_range, opt_ao1_range, /* range */
1057 static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2)
1059 struct dt282x_private *devpriv = dev->private;
1062 devpriv->usedma = 0;
1064 if (!dma1 && !dma2) {
1065 printk(KERN_ERR " (no dma)");
1069 if (dma1 == dma2 || dma1 < 5 || dma2 < 5 || dma1 > 7 || dma2 > 7)
1079 ret = request_dma(dma1, "dt282x A");
1082 devpriv->dma[0].chan = dma1;
1084 ret = request_dma(dma2, "dt282x B");
1087 devpriv->dma[1].chan = dma2;
1089 devpriv->dma_maxsize = PAGE_SIZE;
1090 devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
1091 devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
1092 if (!devpriv->dma[0].buf || !devpriv->dma[1].buf) {
1093 printk(KERN_ERR " can't get DMA memory");
1097 printk(KERN_INFO " (dma=%d,%d)", dma1, dma2);
1099 devpriv->usedma = 1;
1110 4 0=single ended, 1=differential
1111 5 ai 0=straight binary, 1=2's comp
1112 6 ao0 0=straight binary, 1=2's comp
1113 7 ao1 0=straight binary, 1=2's comp
1114 8 ai 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V
1115 9 ao0 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1116 10 ao1 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1118 static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1120 const struct dt282x_board *board = comedi_board(dev);
1121 struct dt282x_private *devpriv;
1124 struct comedi_subdevice *s;
1125 unsigned long iobase;
1127 dev->board_name = board->name;
1129 iobase = it->options[opt_iobase];
1133 printk(KERN_INFO "comedi%d: dt282x: 0x%04lx", dev->minor, iobase);
1134 if (!request_region(iobase, DT2821_SIZE, "dt282x")) {
1135 printk(KERN_INFO " I/O port conflict\n");
1138 dev->iobase = iobase;
1140 outw(DT2821_BDINIT, dev->iobase + DT2821_SUPCSR);
1141 i = inw(dev->iobase + DT2821_ADCSR);
1143 printk(KERN_DEBUG " fingerprint=%x,%x,%x,%x,%x",
1144 inw(dev->iobase + DT2821_ADCSR),
1145 inw(dev->iobase + DT2821_CHANCSR),
1146 inw(dev->iobase + DT2821_DACSR),
1147 inw(dev->iobase + DT2821_SUPCSR),
1148 inw(dev->iobase + DT2821_TMRCTR));
1151 if (((inw(dev->iobase + DT2821_ADCSR) & DT2821_ADCSR_MASK)
1152 != DT2821_ADCSR_VAL) ||
1153 ((inw(dev->iobase + DT2821_CHANCSR) & DT2821_CHANCSR_MASK)
1154 != DT2821_CHANCSR_VAL) ||
1155 ((inw(dev->iobase + DT2821_DACSR) & DT2821_DACSR_MASK)
1156 != DT2821_DACSR_VAL) ||
1157 ((inw(dev->iobase + DT2821_SUPCSR) & DT2821_SUPCSR_MASK)
1158 != DT2821_SUPCSR_VAL) ||
1159 ((inw(dev->iobase + DT2821_TMRCTR) & DT2821_TMRCTR_MASK)
1160 != DT2821_TMRCTR_VAL)) {
1161 printk(KERN_ERR " board not found");
1164 /* should do board test */
1166 irq = it->options[opt_irq];
1169 unsigned long flags;
1174 irqs = probe_irq_on();
1176 /* trigger interrupt */
1180 irq = probe_irq_off(irqs);
1181 restore_flags(flags);
1183 printk(KERN_ERR " error probing irq (bad)");
1187 printk(KERN_INFO " ( irq = %d )", irq);
1188 ret = request_irq(irq, dt282x_interrupt, 0, "dt282x", dev);
1190 printk(KERN_ERR " failed to get irq\n");
1194 } else if (irq == 0) {
1195 printk(KERN_INFO " (no irq)");
1198 printk(KERN_INFO " (probe returned multiple irqs--bad)");
1200 printk(KERN_INFO " (irq probe not implemented)");
1204 devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
1207 dev->private = devpriv;
1209 ret = dt282x_grab_dma(dev, it->options[opt_dma1],
1210 it->options[opt_dma2]);
1214 ret = comedi_alloc_subdevices(dev, 3);
1218 s = &dev->subdevices[0];
1220 dev->read_subdev = s;
1222 s->type = COMEDI_SUBD_AI;
1223 s->subdev_flags = SDF_READABLE | SDF_CMD_READ |
1224 ((it->options[opt_diff]) ? SDF_DIFF : SDF_COMMON);
1226 (it->options[opt_diff]) ? boardtype.adchan_di : boardtype.adchan_se;
1227 s->insn_read = dt282x_ai_insn_read;
1228 s->do_cmdtest = dt282x_ai_cmdtest;
1229 s->do_cmd = dt282x_ai_cmd;
1230 s->cancel = dt282x_ai_cancel;
1231 s->maxdata = (1 << boardtype.adbits) - 1;
1232 s->len_chanlist = 16;
1234 opt_ai_range_lkup(boardtype.ispgl, it->options[opt_ai_range]);
1235 devpriv->ad_2scomp = it->options[opt_ai_twos];
1237 s = &dev->subdevices[1];
1239 s->n_chan = boardtype.dachan;
1242 s->type = COMEDI_SUBD_AO;
1243 dev->write_subdev = s;
1244 s->subdev_flags = SDF_WRITABLE | SDF_CMD_WRITE;
1245 s->insn_read = dt282x_ao_insn_read;
1246 s->insn_write = dt282x_ao_insn_write;
1247 s->do_cmdtest = dt282x_ao_cmdtest;
1248 s->do_cmd = dt282x_ao_cmd;
1249 s->cancel = dt282x_ao_cancel;
1250 s->maxdata = (1 << boardtype.dabits) - 1;
1251 s->len_chanlist = 2;
1252 s->range_table_list = devpriv->darangelist;
1253 devpriv->darangelist[0] =
1254 opt_ao_range_lkup(it->options[opt_ao0_range]);
1255 devpriv->darangelist[1] =
1256 opt_ao_range_lkup(it->options[opt_ao1_range]);
1257 devpriv->da0_2scomp = it->options[opt_ao0_twos];
1258 devpriv->da1_2scomp = it->options[opt_ao1_twos];
1260 s->type = COMEDI_SUBD_UNUSED;
1263 s = &dev->subdevices[2];
1265 s->type = COMEDI_SUBD_DIO;
1266 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1268 s->insn_bits = dt282x_dio_insn_bits;
1269 s->insn_config = dt282x_dio_insn_config;
1271 s->range_table = &range_digital;
1273 printk(KERN_INFO "\n");
1278 static void dt282x_detach(struct comedi_device *dev)
1280 struct dt282x_private *devpriv = dev->private;
1283 free_irq(dev->irq, dev);
1285 release_region(dev->iobase, DT2821_SIZE);
1287 if (devpriv->dma[0].chan)
1288 free_dma(devpriv->dma[0].chan);
1289 if (devpriv->dma[1].chan)
1290 free_dma(devpriv->dma[1].chan);
1291 if (devpriv->dma[0].buf)
1292 free_page((unsigned long)devpriv->dma[0].buf);
1293 if (devpriv->dma[1].buf)
1294 free_page((unsigned long)devpriv->dma[1].buf);
1298 static const struct dt282x_board boardtypes[] = {
1336 .name = "dt2824-pgh",
1345 .name = "dt2824-pgl",
1417 .name = "dt24-ez-pgl",
1428 static struct comedi_driver dt282x_driver = {
1429 .driver_name = "dt282x",
1430 .module = THIS_MODULE,
1431 .attach = dt282x_attach,
1432 .detach = dt282x_detach,
1433 .board_name = &boardtypes[0].name,
1434 .num_names = ARRAY_SIZE(boardtypes),
1435 .offset = sizeof(struct dt282x_board),
1437 module_comedi_driver(dt282x_driver);
1439 MODULE_AUTHOR("Comedi http://www.comedi.org");
1440 MODULE_DESCRIPTION("Comedi low-level driver");
1441 MODULE_LICENSE("GPL");