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;
252 * Some useless abstractions
254 #define chan_to_DAC(a) ((a)&1)
255 #define mux_busy() (inw(dev->iobase+DT2821_ADCSR)&DT2821_MUXBUSY)
256 #define ad_done() (inw(dev->iobase+DT2821_ADCSR)&DT2821_ADDONE)
259 * danger! macro abuse... a is the expression to wait on, and b is
260 * the statement(s) to execute if it doesn't happen.
262 #define wait_for(a, b) \
265 for (_i = 0; _i < DT2821_TIMEOUT; _i++) { \
276 static int prep_ai_dma(struct comedi_device *dev, int chan, int size);
277 static int prep_ao_dma(struct comedi_device *dev, int chan, int size);
278 static int dt282x_ai_cancel(struct comedi_device *dev,
279 struct comedi_subdevice *s);
280 static int dt282x_ao_cancel(struct comedi_device *dev,
281 struct comedi_subdevice *s);
282 static int dt282x_ns_to_timer(int *nanosec, int round_mode);
283 static void dt282x_disable_dma(struct comedi_device *dev);
285 static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2);
287 static void dt282x_munge(struct comedi_device *dev, short *buf,
290 const struct dt282x_board *board = comedi_board(dev);
291 struct dt282x_private *devpriv = dev->private;
293 unsigned short mask = (1 << board->adbits) - 1;
294 unsigned short sign = 1 << (board->adbits - 1);
297 if (devpriv->ad_2scomp)
298 sign = 1 << (board->adbits - 1);
303 comedi_error(dev, "bug! odd number of bytes from dma xfer");
305 for (i = 0; i < n; i++)
306 buf[i] = (buf[i] & mask) ^ sign;
309 static void dt282x_ao_dma_interrupt(struct comedi_device *dev)
311 struct dt282x_private *devpriv = dev->private;
315 struct comedi_subdevice *s = &dev->subdevices[1];
317 outw(devpriv->supcsr | DT2821_CLRDMADNE, dev->iobase + DT2821_SUPCSR);
319 if (!s->async->prealloc_buf) {
320 printk(KERN_ERR "async->data disappeared. dang!\n");
324 i = devpriv->current_dma_index;
325 ptr = devpriv->dma[i].buf;
327 disable_dma(devpriv->dma[i].chan);
329 devpriv->current_dma_index = 1 - i;
331 size = cfc_read_array_from_buffer(s, ptr, devpriv->dma_maxsize);
333 printk(KERN_ERR "dt282x: AO underrun\n");
334 dt282x_ao_cancel(dev, s);
335 s->async->events |= COMEDI_CB_OVERFLOW;
338 prep_ao_dma(dev, i, size);
342 static void dt282x_ai_dma_interrupt(struct comedi_device *dev)
344 struct dt282x_private *devpriv = dev->private;
349 struct comedi_subdevice *s = &dev->subdevices[0];
351 outw(devpriv->supcsr | DT2821_CLRDMADNE, dev->iobase + DT2821_SUPCSR);
353 if (!s->async->prealloc_buf) {
354 printk(KERN_ERR "async->data disappeared. dang!\n");
358 i = devpriv->current_dma_index;
359 ptr = devpriv->dma[i].buf;
360 size = devpriv->dma[i].size;
362 disable_dma(devpriv->dma[i].chan);
364 devpriv->current_dma_index = 1 - i;
366 dt282x_munge(dev, ptr, size);
367 ret = cfc_write_array_to_buffer(s, ptr, size);
369 dt282x_ai_cancel(dev, s);
372 devpriv->nread -= size / 2;
374 if (devpriv->nread < 0) {
375 printk(KERN_INFO "dt282x: off by one\n");
378 if (!devpriv->nread) {
379 dt282x_ai_cancel(dev, s);
380 s->async->events |= COMEDI_CB_EOA;
384 /* clear the dual dma flag, making this the last dma segment */
385 /* XXX probably wrong */
386 if (!devpriv->ntrig) {
387 devpriv->supcsr &= ~(DT2821_DDMA);
388 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR);
391 /* restart the channel */
392 prep_ai_dma(dev, i, 0);
395 static int prep_ai_dma(struct comedi_device *dev, int dma_index, int n)
397 struct dt282x_private *devpriv = dev->private;
399 unsigned long dma_ptr;
406 n = devpriv->dma_maxsize;
407 if (n > devpriv->ntrig * 2)
408 n = devpriv->ntrig * 2;
409 devpriv->ntrig -= n / 2;
411 devpriv->dma[dma_index].size = n;
412 dma_chan = devpriv->dma[dma_index].chan;
413 dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
415 set_dma_mode(dma_chan, DMA_MODE_READ);
416 flags = claim_dma_lock();
417 clear_dma_ff(dma_chan);
418 set_dma_addr(dma_chan, dma_ptr);
419 set_dma_count(dma_chan, n);
420 release_dma_lock(flags);
422 enable_dma(dma_chan);
427 static int prep_ao_dma(struct comedi_device *dev, int dma_index, int n)
429 struct dt282x_private *devpriv = dev->private;
431 unsigned long dma_ptr;
434 devpriv->dma[dma_index].size = n;
435 dma_chan = devpriv->dma[dma_index].chan;
436 dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
438 set_dma_mode(dma_chan, DMA_MODE_WRITE);
439 flags = claim_dma_lock();
440 clear_dma_ff(dma_chan);
441 set_dma_addr(dma_chan, dma_ptr);
442 set_dma_count(dma_chan, n);
443 release_dma_lock(flags);
445 enable_dma(dma_chan);
450 static irqreturn_t dt282x_interrupt(int irq, void *d)
452 struct comedi_device *dev = d;
453 struct dt282x_private *devpriv = dev->private;
454 struct comedi_subdevice *s;
455 struct comedi_subdevice *s_ao;
456 unsigned int supcsr, adcsr, dacsr;
459 if (!dev->attached) {
460 comedi_error(dev, "spurious interrupt");
464 s = &dev->subdevices[0];
465 s_ao = &dev->subdevices[1];
466 adcsr = inw(dev->iobase + DT2821_ADCSR);
467 dacsr = inw(dev->iobase + DT2821_DACSR);
468 supcsr = inw(dev->iobase + DT2821_SUPCSR);
469 if (supcsr & DT2821_DMAD) {
470 if (devpriv->dma_dir == DMA_MODE_READ)
471 dt282x_ai_dma_interrupt(dev);
473 dt282x_ao_dma_interrupt(dev);
476 if (adcsr & DT2821_ADERR) {
477 if (devpriv->nread != 0) {
478 comedi_error(dev, "A/D error");
479 dt282x_ai_cancel(dev, s);
480 s->async->events |= COMEDI_CB_ERROR;
484 if (dacsr & DT2821_DAERR) {
488 disable_irq(dev->irq);
489 printk(KERN_INFO "disabling irq\n");
492 comedi_error(dev, "D/A error");
493 dt282x_ao_cancel(dev, s_ao);
494 s->async->events |= COMEDI_CB_ERROR;
498 if (adcsr & DT2821_ADDONE) {
502 data = (short)inw(dev->iobase + DT2821_ADDAT);
503 data &= (1 << board->adbits) - 1;
505 if (devpriv->ad_2scomp)
506 data ^= 1 << (board->adbits - 1);
507 ret = comedi_buf_put(s->async, data);
510 s->async->events |= COMEDI_CB_OVERFLOW;
513 if (!devpriv->nread) {
514 s->async->events |= COMEDI_CB_EOA;
516 if (supcsr & DT2821_SCDN)
517 outw(devpriv->supcsr | DT2821_STRIG,
518 dev->iobase + DT2821_SUPCSR);
523 comedi_event(dev, s);
524 /* printk("adcsr=0x%02x dacsr-0x%02x supcsr=0x%02x\n",
525 adcsr, dacsr, supcsr); */
526 return IRQ_RETVAL(handled);
529 static void dt282x_load_changain(struct comedi_device *dev, int n,
530 unsigned int *chanlist)
532 struct dt282x_private *devpriv = dev->private;
534 unsigned int chan, range;
536 outw(DT2821_LLE | (n - 1), dev->iobase + DT2821_CHANCSR);
537 for (i = 0; i < n; i++) {
538 chan = CR_CHAN(chanlist[i]);
539 range = CR_RANGE(chanlist[i]);
540 outw(devpriv->adcsr | (range << 4) | chan,
541 dev->iobase + DT2821_ADCSR);
543 outw(n - 1, dev->iobase + DT2821_CHANCSR);
547 * Performs a single A/D conversion.
548 * - Put channel/gain into channel-gain list
549 * - preload multiplexer
550 * - trigger conversion and wait for it to finish
552 static int dt282x_ai_insn_read(struct comedi_device *dev,
553 struct comedi_subdevice *s,
554 struct comedi_insn *insn, unsigned int *data)
556 const struct dt282x_board *board = comedi_board(dev);
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 << board->adbits) - 1);
578 if (devpriv->ad_2scomp)
579 data[i] ^= (1 << (board->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 const struct dt282x_board *board = comedi_board(dev);
799 struct dt282x_private *devpriv = dev->private;
803 chan = CR_CHAN(insn->chanspec);
805 d &= (1 << board->dabits) - 1;
806 devpriv->ao[chan] = d;
808 devpriv->dacsr |= DT2821_SSEL;
812 devpriv->dacsr |= DT2821_YSEL;
813 if (devpriv->da0_2scomp)
814 d ^= (1 << (board->dabits - 1));
816 devpriv->dacsr &= ~DT2821_YSEL;
817 if (devpriv->da1_2scomp)
818 d ^= (1 << (board->dabits - 1));
821 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
823 outw(d, dev->iobase + DT2821_DADAT);
825 outw(devpriv->supcsr | DT2821_DACON, dev->iobase + DT2821_SUPCSR);
830 static int dt282x_ao_cmdtest(struct comedi_device *dev,
831 struct comedi_subdevice *s, struct comedi_cmd *cmd)
836 /* Step 1 : check if triggers are trivially valid */
838 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT);
839 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
840 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
841 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
842 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
847 /* Step 2a : make sure trigger sources are unique */
849 err |= cfc_check_trigger_is_unique(cmd->stop_src);
851 /* Step 2b : and mutually compatible */
856 /* Step 3: check if arguments are trivially valid */
858 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
859 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 5000);
860 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
861 err |= cfc_check_trigger_arg_max(&cmd->scan_end_arg, 2);
863 if (cmd->stop_src == TRIG_COUNT) {
864 /* any count is allowed */
865 } else { /* TRIG_NONE */
866 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
872 /* step 4: fix up any arguments */
874 tmp = cmd->scan_begin_arg;
875 dt282x_ns_to_timer(&cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK);
876 if (tmp != cmd->scan_begin_arg)
886 static int dt282x_ao_inttrig(struct comedi_device *dev,
887 struct comedi_subdevice *s, unsigned int x)
889 struct dt282x_private *devpriv = dev->private;
895 size = cfc_read_array_from_buffer(s, devpriv->dma[0].buf,
896 devpriv->dma_maxsize);
898 printk(KERN_ERR "dt282x: AO underrun\n");
901 prep_ao_dma(dev, 0, size);
903 size = cfc_read_array_from_buffer(s, devpriv->dma[1].buf,
904 devpriv->dma_maxsize);
906 printk(KERN_ERR "dt282x: AO underrun\n");
909 prep_ao_dma(dev, 1, size);
911 outw(devpriv->supcsr | DT2821_STRIG, dev->iobase + DT2821_SUPCSR);
912 s->async->inttrig = NULL;
917 static int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
919 struct dt282x_private *devpriv = dev->private;
921 struct comedi_cmd *cmd = &s->async->cmd;
923 if (devpriv->usedma == 0) {
925 "driver requires 2 dma channels"
926 " to execute command");
930 dt282x_disable_dma(dev);
932 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS1 | DT2821_DDMA;
933 outw(devpriv->supcsr | DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_DACINIT,
934 dev->iobase + DT2821_SUPCSR);
936 devpriv->ntrig = cmd->stop_arg * cmd->chanlist_len;
937 devpriv->nread = devpriv->ntrig;
939 devpriv->dma_dir = DMA_MODE_WRITE;
940 devpriv->current_dma_index = 0;
942 timer = dt282x_ns_to_timer(&cmd->scan_begin_arg, TRIG_ROUND_NEAREST);
943 outw(timer, dev->iobase + DT2821_TMRCTR);
945 devpriv->dacsr = DT2821_SSEL | DT2821_DACLK | DT2821_IDARDY;
946 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
948 s->async->inttrig = dt282x_ao_inttrig;
953 static int dt282x_ao_cancel(struct comedi_device *dev,
954 struct comedi_subdevice *s)
956 struct dt282x_private *devpriv = dev->private;
958 dt282x_disable_dma(dev);
961 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
964 outw(devpriv->supcsr | DT2821_DACINIT, dev->iobase + DT2821_SUPCSR);
969 static int dt282x_dio_insn_bits(struct comedi_device *dev,
970 struct comedi_subdevice *s,
971 struct comedi_insn *insn, unsigned int *data)
974 s->state &= ~data[0];
975 s->state |= (data[0] & data[1]);
977 outw(s->state, dev->iobase + DT2821_DIODAT);
979 data[1] = inw(dev->iobase + DT2821_DIODAT);
984 static int dt282x_dio_insn_config(struct comedi_device *dev,
985 struct comedi_subdevice *s,
986 struct comedi_insn *insn, unsigned int *data)
988 struct dt282x_private *devpriv = dev->private;
991 mask = (CR_CHAN(insn->chanspec) < 8) ? 0x00ff : 0xff00;
997 if (s->io_bits & 0x00ff)
998 devpriv->dacsr |= DT2821_LBOE;
1000 devpriv->dacsr &= ~DT2821_LBOE;
1001 if (s->io_bits & 0xff00)
1002 devpriv->dacsr |= DT2821_HBOE;
1004 devpriv->dacsr &= ~DT2821_HBOE;
1006 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
1011 static const struct comedi_lrange *const ai_range_table[] = {
1012 &range_dt282x_ai_lo_bipolar,
1013 &range_dt282x_ai_lo_unipolar,
1014 &range_dt282x_ai_5_bipolar,
1015 &range_dt282x_ai_5_unipolar
1018 static const struct comedi_lrange *const ai_range_pgl_table[] = {
1019 &range_dt282x_ai_hi_bipolar,
1020 &range_dt282x_ai_hi_unipolar
1023 static const struct comedi_lrange *opt_ai_range_lkup(int ispgl, int x)
1026 if (x < 0 || x >= 2)
1028 return ai_range_pgl_table[x];
1030 if (x < 0 || x >= 4)
1032 return ai_range_table[x];
1036 static const struct comedi_lrange *const ao_range_table[] = {
1044 static const struct comedi_lrange *opt_ao_range_lkup(int x)
1046 if (x < 0 || x >= 5)
1048 return ao_range_table[x];
1051 enum { /* i/o base, irq, dma channels */
1052 opt_iobase = 0, opt_irq, opt_dma1, opt_dma2,
1053 opt_diff, /* differential */
1054 opt_ai_twos, opt_ao0_twos, opt_ao1_twos, /* twos comp */
1055 opt_ai_range, opt_ao0_range, opt_ao1_range, /* range */
1058 static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2)
1060 struct dt282x_private *devpriv = dev->private;
1063 devpriv->usedma = 0;
1065 if (!dma1 && !dma2) {
1066 printk(KERN_ERR " (no dma)");
1070 if (dma1 == dma2 || dma1 < 5 || dma2 < 5 || dma1 > 7 || dma2 > 7)
1080 ret = request_dma(dma1, "dt282x A");
1083 devpriv->dma[0].chan = dma1;
1085 ret = request_dma(dma2, "dt282x B");
1088 devpriv->dma[1].chan = dma2;
1090 devpriv->dma_maxsize = PAGE_SIZE;
1091 devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
1092 devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
1093 if (!devpriv->dma[0].buf || !devpriv->dma[1].buf) {
1094 printk(KERN_ERR " can't get DMA memory");
1098 printk(KERN_INFO " (dma=%d,%d)", dma1, dma2);
1100 devpriv->usedma = 1;
1111 4 0=single ended, 1=differential
1112 5 ai 0=straight binary, 1=2's comp
1113 6 ao0 0=straight binary, 1=2's comp
1114 7 ao1 0=straight binary, 1=2's comp
1115 8 ai 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V
1116 9 ao0 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1117 10 ao1 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1119 static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1121 const struct dt282x_board *board = comedi_board(dev);
1122 struct dt282x_private *devpriv;
1125 struct comedi_subdevice *s;
1127 ret = comedi_request_region(dev, it->options[0], DT2821_SIZE);
1131 outw(DT2821_BDINIT, dev->iobase + DT2821_SUPCSR);
1132 i = inw(dev->iobase + DT2821_ADCSR);
1134 printk(KERN_DEBUG " fingerprint=%x,%x,%x,%x,%x",
1135 inw(dev->iobase + DT2821_ADCSR),
1136 inw(dev->iobase + DT2821_CHANCSR),
1137 inw(dev->iobase + DT2821_DACSR),
1138 inw(dev->iobase + DT2821_SUPCSR),
1139 inw(dev->iobase + DT2821_TMRCTR));
1142 if (((inw(dev->iobase + DT2821_ADCSR) & DT2821_ADCSR_MASK)
1143 != DT2821_ADCSR_VAL) ||
1144 ((inw(dev->iobase + DT2821_CHANCSR) & DT2821_CHANCSR_MASK)
1145 != DT2821_CHANCSR_VAL) ||
1146 ((inw(dev->iobase + DT2821_DACSR) & DT2821_DACSR_MASK)
1147 != DT2821_DACSR_VAL) ||
1148 ((inw(dev->iobase + DT2821_SUPCSR) & DT2821_SUPCSR_MASK)
1149 != DT2821_SUPCSR_VAL) ||
1150 ((inw(dev->iobase + DT2821_TMRCTR) & DT2821_TMRCTR_MASK)
1151 != DT2821_TMRCTR_VAL)) {
1152 printk(KERN_ERR " board not found");
1155 /* should do board test */
1157 irq = it->options[opt_irq];
1160 unsigned long flags;
1165 irqs = probe_irq_on();
1167 /* trigger interrupt */
1171 irq = probe_irq_off(irqs);
1172 restore_flags(flags);
1174 printk(KERN_ERR " error probing irq (bad)");
1178 printk(KERN_INFO " ( irq = %d )", irq);
1179 ret = request_irq(irq, dt282x_interrupt, 0,
1180 dev->board_name, dev);
1182 printk(KERN_ERR " failed to get irq\n");
1186 } else if (irq == 0) {
1187 printk(KERN_INFO " (no irq)");
1190 printk(KERN_INFO " (probe returned multiple irqs--bad)");
1192 printk(KERN_INFO " (irq probe not implemented)");
1196 devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
1199 dev->private = devpriv;
1201 ret = dt282x_grab_dma(dev, it->options[opt_dma1],
1202 it->options[opt_dma2]);
1206 ret = comedi_alloc_subdevices(dev, 3);
1210 s = &dev->subdevices[0];
1212 dev->read_subdev = s;
1214 s->type = COMEDI_SUBD_AI;
1215 s->subdev_flags = SDF_READABLE | SDF_CMD_READ |
1216 ((it->options[opt_diff]) ? SDF_DIFF : SDF_COMMON);
1218 (it->options[opt_diff]) ? board->adchan_di : board->adchan_se;
1219 s->insn_read = dt282x_ai_insn_read;
1220 s->do_cmdtest = dt282x_ai_cmdtest;
1221 s->do_cmd = dt282x_ai_cmd;
1222 s->cancel = dt282x_ai_cancel;
1223 s->maxdata = (1 << board->adbits) - 1;
1224 s->len_chanlist = 16;
1226 opt_ai_range_lkup(board->ispgl, it->options[opt_ai_range]);
1227 devpriv->ad_2scomp = it->options[opt_ai_twos];
1229 s = &dev->subdevices[1];
1231 s->n_chan = board->dachan;
1234 s->type = COMEDI_SUBD_AO;
1235 dev->write_subdev = s;
1236 s->subdev_flags = SDF_WRITABLE | SDF_CMD_WRITE;
1237 s->insn_read = dt282x_ao_insn_read;
1238 s->insn_write = dt282x_ao_insn_write;
1239 s->do_cmdtest = dt282x_ao_cmdtest;
1240 s->do_cmd = dt282x_ao_cmd;
1241 s->cancel = dt282x_ao_cancel;
1242 s->maxdata = (1 << board->dabits) - 1;
1243 s->len_chanlist = 2;
1244 s->range_table_list = devpriv->darangelist;
1245 devpriv->darangelist[0] =
1246 opt_ao_range_lkup(it->options[opt_ao0_range]);
1247 devpriv->darangelist[1] =
1248 opt_ao_range_lkup(it->options[opt_ao1_range]);
1249 devpriv->da0_2scomp = it->options[opt_ao0_twos];
1250 devpriv->da1_2scomp = it->options[opt_ao1_twos];
1252 s->type = COMEDI_SUBD_UNUSED;
1255 s = &dev->subdevices[2];
1257 s->type = COMEDI_SUBD_DIO;
1258 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1260 s->insn_bits = dt282x_dio_insn_bits;
1261 s->insn_config = dt282x_dio_insn_config;
1263 s->range_table = &range_digital;
1265 printk(KERN_INFO "\n");
1270 static void dt282x_detach(struct comedi_device *dev)
1272 struct dt282x_private *devpriv = dev->private;
1275 if (devpriv->dma[0].chan)
1276 free_dma(devpriv->dma[0].chan);
1277 if (devpriv->dma[1].chan)
1278 free_dma(devpriv->dma[1].chan);
1279 if (devpriv->dma[0].buf)
1280 free_page((unsigned long)devpriv->dma[0].buf);
1281 if (devpriv->dma[1].buf)
1282 free_page((unsigned long)devpriv->dma[1].buf);
1284 comedi_legacy_detach(dev);
1287 static const struct dt282x_board boardtypes[] = {
1325 .name = "dt2824-pgh",
1334 .name = "dt2824-pgl",
1406 .name = "dt24-ez-pgl",
1417 static struct comedi_driver dt282x_driver = {
1418 .driver_name = "dt282x",
1419 .module = THIS_MODULE,
1420 .attach = dt282x_attach,
1421 .detach = dt282x_detach,
1422 .board_name = &boardtypes[0].name,
1423 .num_names = ARRAY_SIZE(boardtypes),
1424 .offset = sizeof(struct dt282x_board),
1426 module_comedi_driver(dt282x_driver);
1428 MODULE_AUTHOR("Comedi http://www.comedi.org");
1429 MODULE_DESCRIPTION("Comedi low-level driver");
1430 MODULE_LICENSE("GPL");