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/ioport.h>
60 #include <linux/interrupt.h>
65 #include "comedi_fc.h"
69 #define DT2821_TIMEOUT 100 /* 500 us */
70 #define DT2821_SIZE 0x10
73 * Registers in the DT282x
76 #define DT2821_ADCSR 0x00 /* A/D Control/Status */
77 #define DT2821_CHANCSR 0x02 /* Channel Control/Status */
78 #define DT2821_ADDAT 0x04 /* A/D data */
79 #define DT2821_DACSR 0x06 /* D/A Control/Status */
80 #define DT2821_DADAT 0x08 /* D/A data */
81 #define DT2821_DIODAT 0x0a /* digital data */
82 #define DT2821_SUPCSR 0x0c /* Supervisor Control/Status */
83 #define DT2821_TMRCTR 0x0e /* Timer/Counter */
86 * At power up, some registers are in a well-known state. The
87 * masks and values are as follows:
90 #define DT2821_ADCSR_MASK 0xfff0
91 #define DT2821_ADCSR_VAL 0x7c00
93 #define DT2821_CHANCSR_MASK 0xf0f0
94 #define DT2821_CHANCSR_VAL 0x70f0
96 #define DT2821_DACSR_MASK 0x7c93
97 #define DT2821_DACSR_VAL 0x7c90
99 #define DT2821_SUPCSR_MASK 0xf8ff
100 #define DT2821_SUPCSR_VAL 0x0000
102 #define DT2821_TMRCTR_MASK 0xff00
103 #define DT2821_TMRCTR_VAL 0xf000
106 * Bit fields of each register
111 #define DT2821_ADERR 0x8000 /* (R) 1 for A/D error */
112 #define DT2821_ADCLK 0x0200 /* (R/W) A/D clock enable */
113 /* 0x7c00 read as 1's */
114 #define DT2821_MUXBUSY 0x0100 /* (R) multiplexer busy */
115 #define DT2821_ADDONE 0x0080 /* (R) A/D done */
116 #define DT2821_IADDONE 0x0040 /* (R/W) interrupt on A/D done */
117 /* 0x0030 gain select */
118 /* 0x000f channel select */
122 #define DT2821_LLE 0x8000 /* (R/W) Load List Enable */
123 /* 0x7000 read as 1's */
124 /* 0x0f00 (R) present address */
125 /* 0x00f0 read as 1's */
126 /* 0x000f (R) number of entries - 1 */
130 #define DT2821_DAERR 0x8000 /* (R) D/A error */
131 #define DT2821_YSEL 0x0200 /* (R/W) DAC 1 select */
132 #define DT2821_SSEL 0x0100 /* (R/W) single channel select */
133 #define DT2821_DACRDY 0x0080 /* (R) DAC ready */
134 #define DT2821_IDARDY 0x0040 /* (R/W) interrupt on DAC ready */
135 #define DT2821_DACLK 0x0020 /* (R/W) D/A clock enable */
136 #define DT2821_HBOE 0x0002 /* (R/W) DIO high byte output enable */
137 #define DT2821_LBOE 0x0001 /* (R/W) DIO low byte output enable */
141 #define DT2821_DMAD 0x8000 /* (R) DMA done */
142 #define DT2821_ERRINTEN 0x4000 /* (R/W) interrupt on error */
143 #define DT2821_CLRDMADNE 0x2000 /* (W) clear DMA done */
144 #define DT2821_DDMA 0x1000 /* (R/W) dual DMA */
145 #define DT2821_DS1 0x0800 /* (R/W) DMA select 1 */
146 #define DT2821_DS0 0x0400 /* (R/W) DMA select 0 */
147 #define DT2821_BUFFB 0x0200 /* (R/W) buffer B selected */
148 #define DT2821_SCDN 0x0100 /* (R) scan done */
149 #define DT2821_DACON 0x0080 /* (W) DAC single conversion */
150 #define DT2821_ADCINIT 0x0040 /* (W) A/D initialize */
151 #define DT2821_DACINIT 0x0020 /* (W) D/A initialize */
152 #define DT2821_PRLD 0x0010 /* (W) preload multiplexer */
153 #define DT2821_STRIG 0x0008 /* (W) software trigger */
154 #define DT2821_XTRIG 0x0004 /* (R/W) external trigger enable */
155 #define DT2821_XCLK 0x0002 /* (R/W) external clock enable */
156 #define DT2821_BDINIT 0x0001 /* (W) initialize board */
158 static const struct comedi_lrange range_dt282x_ai_lo_bipolar = {
167 static const struct comedi_lrange range_dt282x_ai_lo_unipolar = {
176 static const struct comedi_lrange range_dt282x_ai_5_bipolar = {
185 static const struct comedi_lrange range_dt282x_ai_5_unipolar = {
194 static const struct comedi_lrange range_dt282x_ai_hi_bipolar = {
203 static const struct comedi_lrange range_dt282x_ai_hi_unipolar = {
212 struct dt282x_board {
223 struct dt282x_private {
224 int ad_2scomp; /* we have 2's comp jumper set */
225 int da0_2scomp; /* same, for DAC0 */
226 int da1_2scomp; /* same, for DAC1 */
228 const struct comedi_lrange *darangelist[2];
232 volatile int dacsr; /* software copies of registers */
241 short *buf; /* DMA buffer */
242 volatile int size; /* size of current transfer */
244 int dma_maxsize; /* max size of DMA transfer (in bytes) */
245 int usedma; /* driver uses DMA */
246 volatile int current_dma_index;
251 * Some useless abstractions
253 #define chan_to_DAC(a) ((a)&1)
254 #define mux_busy() (inw(dev->iobase+DT2821_ADCSR)&DT2821_MUXBUSY)
255 #define ad_done() (inw(dev->iobase+DT2821_ADCSR)&DT2821_ADDONE)
258 * danger! macro abuse... a is the expression to wait on, and b is
259 * the statement(s) to execute if it doesn't happen.
261 #define wait_for(a, b) \
264 for (_i = 0; _i < DT2821_TIMEOUT; _i++) { \
275 static int prep_ai_dma(struct comedi_device *dev, int chan, int size);
276 static int prep_ao_dma(struct comedi_device *dev, int chan, int size);
277 static int dt282x_ai_cancel(struct comedi_device *dev,
278 struct comedi_subdevice *s);
279 static int dt282x_ao_cancel(struct comedi_device *dev,
280 struct comedi_subdevice *s);
281 static int dt282x_ns_to_timer(int *nanosec, int round_mode);
282 static void dt282x_disable_dma(struct comedi_device *dev);
284 static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2);
286 static void dt282x_munge(struct comedi_device *dev, short *buf,
289 const struct dt282x_board *board = comedi_board(dev);
290 struct dt282x_private *devpriv = dev->private;
292 unsigned short mask = (1 << board->adbits) - 1;
293 unsigned short sign = 1 << (board->adbits - 1);
296 if (devpriv->ad_2scomp)
297 sign = 1 << (board->adbits - 1);
302 comedi_error(dev, "bug! odd number of bytes from dma xfer");
304 for (i = 0; i < n; i++)
305 buf[i] = (buf[i] & mask) ^ sign;
308 static void dt282x_ao_dma_interrupt(struct comedi_device *dev)
310 struct dt282x_private *devpriv = dev->private;
314 struct comedi_subdevice *s = &dev->subdevices[1];
316 outw(devpriv->supcsr | DT2821_CLRDMADNE, dev->iobase + DT2821_SUPCSR);
318 if (!s->async->prealloc_buf) {
319 printk(KERN_ERR "async->data disappeared. dang!\n");
323 i = devpriv->current_dma_index;
324 ptr = devpriv->dma[i].buf;
326 disable_dma(devpriv->dma[i].chan);
328 devpriv->current_dma_index = 1 - i;
330 size = cfc_read_array_from_buffer(s, ptr, devpriv->dma_maxsize);
332 printk(KERN_ERR "dt282x: AO underrun\n");
333 dt282x_ao_cancel(dev, s);
334 s->async->events |= COMEDI_CB_OVERFLOW;
337 prep_ao_dma(dev, i, size);
341 static void dt282x_ai_dma_interrupt(struct comedi_device *dev)
343 struct dt282x_private *devpriv = dev->private;
348 struct comedi_subdevice *s = &dev->subdevices[0];
350 outw(devpriv->supcsr | DT2821_CLRDMADNE, dev->iobase + DT2821_SUPCSR);
352 if (!s->async->prealloc_buf) {
353 printk(KERN_ERR "async->data disappeared. dang!\n");
357 i = devpriv->current_dma_index;
358 ptr = devpriv->dma[i].buf;
359 size = devpriv->dma[i].size;
361 disable_dma(devpriv->dma[i].chan);
363 devpriv->current_dma_index = 1 - i;
365 dt282x_munge(dev, ptr, size);
366 ret = cfc_write_array_to_buffer(s, ptr, size);
368 dt282x_ai_cancel(dev, s);
371 devpriv->nread -= size / 2;
373 if (devpriv->nread < 0) {
374 printk(KERN_INFO "dt282x: off by one\n");
377 if (!devpriv->nread) {
378 dt282x_ai_cancel(dev, s);
379 s->async->events |= COMEDI_CB_EOA;
383 /* clear the dual dma flag, making this the last dma segment */
384 /* XXX probably wrong */
385 if (!devpriv->ntrig) {
386 devpriv->supcsr &= ~(DT2821_DDMA);
387 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR);
390 /* restart the channel */
391 prep_ai_dma(dev, i, 0);
394 static int prep_ai_dma(struct comedi_device *dev, int dma_index, int n)
396 struct dt282x_private *devpriv = dev->private;
398 unsigned long dma_ptr;
405 n = devpriv->dma_maxsize;
406 if (n > devpriv->ntrig * 2)
407 n = devpriv->ntrig * 2;
408 devpriv->ntrig -= n / 2;
410 devpriv->dma[dma_index].size = n;
411 dma_chan = devpriv->dma[dma_index].chan;
412 dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
414 set_dma_mode(dma_chan, DMA_MODE_READ);
415 flags = claim_dma_lock();
416 clear_dma_ff(dma_chan);
417 set_dma_addr(dma_chan, dma_ptr);
418 set_dma_count(dma_chan, n);
419 release_dma_lock(flags);
421 enable_dma(dma_chan);
426 static int prep_ao_dma(struct comedi_device *dev, int dma_index, int n)
428 struct dt282x_private *devpriv = dev->private;
430 unsigned long dma_ptr;
433 devpriv->dma[dma_index].size = n;
434 dma_chan = devpriv->dma[dma_index].chan;
435 dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
437 set_dma_mode(dma_chan, DMA_MODE_WRITE);
438 flags = claim_dma_lock();
439 clear_dma_ff(dma_chan);
440 set_dma_addr(dma_chan, dma_ptr);
441 set_dma_count(dma_chan, n);
442 release_dma_lock(flags);
444 enable_dma(dma_chan);
449 static irqreturn_t dt282x_interrupt(int irq, void *d)
451 struct comedi_device *dev = d;
452 struct dt282x_private *devpriv = dev->private;
453 struct comedi_subdevice *s;
454 struct comedi_subdevice *s_ao;
455 unsigned int supcsr, adcsr, dacsr;
458 if (!dev->attached) {
459 comedi_error(dev, "spurious interrupt");
463 s = &dev->subdevices[0];
464 s_ao = &dev->subdevices[1];
465 adcsr = inw(dev->iobase + DT2821_ADCSR);
466 dacsr = inw(dev->iobase + DT2821_DACSR);
467 supcsr = inw(dev->iobase + DT2821_SUPCSR);
468 if (supcsr & DT2821_DMAD) {
469 if (devpriv->dma_dir == DMA_MODE_READ)
470 dt282x_ai_dma_interrupt(dev);
472 dt282x_ao_dma_interrupt(dev);
475 if (adcsr & DT2821_ADERR) {
476 if (devpriv->nread != 0) {
477 comedi_error(dev, "A/D error");
478 dt282x_ai_cancel(dev, s);
479 s->async->events |= COMEDI_CB_ERROR;
483 if (dacsr & DT2821_DAERR) {
487 disable_irq(dev->irq);
488 printk(KERN_INFO "disabling irq\n");
491 comedi_error(dev, "D/A error");
492 dt282x_ao_cancel(dev, s_ao);
493 s->async->events |= COMEDI_CB_ERROR;
497 if (adcsr & DT2821_ADDONE) {
501 data = (short)inw(dev->iobase + DT2821_ADDAT);
502 data &= (1 << board->adbits) - 1;
504 if (devpriv->ad_2scomp)
505 data ^= 1 << (board->adbits - 1);
506 ret = comedi_buf_put(s->async, data);
509 s->async->events |= COMEDI_CB_OVERFLOW;
512 if (!devpriv->nread) {
513 s->async->events |= COMEDI_CB_EOA;
515 if (supcsr & DT2821_SCDN)
516 outw(devpriv->supcsr | DT2821_STRIG,
517 dev->iobase + DT2821_SUPCSR);
522 comedi_event(dev, s);
523 /* printk("adcsr=0x%02x dacsr-0x%02x supcsr=0x%02x\n",
524 adcsr, dacsr, supcsr); */
525 return IRQ_RETVAL(handled);
528 static void dt282x_load_changain(struct comedi_device *dev, int n,
529 unsigned int *chanlist)
531 struct dt282x_private *devpriv = dev->private;
533 unsigned int chan, range;
535 outw(DT2821_LLE | (n - 1), dev->iobase + DT2821_CHANCSR);
536 for (i = 0; i < n; i++) {
537 chan = CR_CHAN(chanlist[i]);
538 range = CR_RANGE(chanlist[i]);
539 outw(devpriv->adcsr | (range << 4) | chan,
540 dev->iobase + DT2821_ADCSR);
542 outw(n - 1, dev->iobase + DT2821_CHANCSR);
546 * Performs a single A/D conversion.
547 * - Put channel/gain into channel-gain list
548 * - preload multiplexer
549 * - trigger conversion and wait for it to finish
551 static int dt282x_ai_insn_read(struct comedi_device *dev,
552 struct comedi_subdevice *s,
553 struct comedi_insn *insn, unsigned int *data)
555 const struct dt282x_board *board = comedi_board(dev);
556 struct dt282x_private *devpriv = dev->private;
559 /* XXX should we really be enabling the ad clock here? */
560 devpriv->adcsr = DT2821_ADCLK;
561 outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR);
563 dt282x_load_changain(dev, 1, &insn->chanspec);
565 outw(devpriv->supcsr | DT2821_PRLD, dev->iobase + DT2821_SUPCSR);
566 wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;);
568 for (i = 0; i < insn->n; i++) {
569 outw(devpriv->supcsr | DT2821_STRIG,
570 dev->iobase + DT2821_SUPCSR);
571 wait_for(ad_done(), comedi_error(dev, "timeout\n");
576 DT2821_ADDAT) & ((1 << board->adbits) - 1);
577 if (devpriv->ad_2scomp)
578 data[i] ^= (1 << (board->adbits - 1));
584 static int dt282x_ai_cmdtest(struct comedi_device *dev,
585 struct comedi_subdevice *s, struct comedi_cmd *cmd)
587 const struct dt282x_board *board = comedi_board(dev);
591 /* Step 1 : check if triggers are trivially valid */
593 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
594 err |= cfc_check_trigger_src(&cmd->scan_begin_src,
595 TRIG_FOLLOW | TRIG_EXT);
596 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
597 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
598 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
603 /* Step 2a : make sure trigger sources are unique */
605 err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
606 err |= cfc_check_trigger_is_unique(cmd->stop_src);
608 /* Step 2b : and mutually compatible */
613 /* Step 3: check if arguments are trivially valid */
615 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
617 if (cmd->scan_begin_src == TRIG_FOLLOW) {
618 /* internal trigger */
619 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
621 /* external trigger */
622 /* should be level/edge, hi/lo specification here */
623 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
626 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 4000);
628 #define SLOWEST_TIMER (250*(1<<15)*255)
629 err |= cfc_check_trigger_arg_max(&cmd->convert_arg, SLOWEST_TIMER);
630 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, board->ai_speed);
631 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
633 if (cmd->stop_src == TRIG_COUNT) {
634 /* any count is allowed */
635 } else { /* TRIG_NONE */
636 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
642 /* step 4: fix up any arguments */
644 tmp = cmd->convert_arg;
645 dt282x_ns_to_timer(&cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK);
646 if (tmp != cmd->convert_arg)
655 static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
657 const struct dt282x_board *board = comedi_board(dev);
658 struct dt282x_private *devpriv = dev->private;
659 struct comedi_cmd *cmd = &s->async->cmd;
662 if (devpriv->usedma == 0) {
664 "driver requires 2 dma channels"
665 " to execute command");
669 dt282x_disable_dma(dev);
671 if (cmd->convert_arg < board->ai_speed)
672 cmd->convert_arg = board->ai_speed;
673 timer = dt282x_ns_to_timer(&cmd->convert_arg, TRIG_ROUND_NEAREST);
674 outw(timer, dev->iobase + DT2821_TMRCTR);
676 if (cmd->scan_begin_src == TRIG_FOLLOW) {
677 /* internal trigger */
678 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0;
680 /* external trigger */
681 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0 | DT2821_DS1;
683 outw(devpriv->supcsr | DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_ADCINIT,
684 dev->iobase + DT2821_SUPCSR);
686 devpriv->ntrig = cmd->stop_arg * cmd->scan_end_arg;
687 devpriv->nread = devpriv->ntrig;
689 devpriv->dma_dir = DMA_MODE_READ;
690 devpriv->current_dma_index = 0;
691 prep_ai_dma(dev, 0, 0);
692 if (devpriv->ntrig) {
693 prep_ai_dma(dev, 1, 0);
694 devpriv->supcsr |= DT2821_DDMA;
695 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR);
700 dt282x_load_changain(dev, cmd->chanlist_len, cmd->chanlist);
702 devpriv->adcsr = DT2821_ADCLK | DT2821_IADDONE;
703 outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR);
705 outw(devpriv->supcsr | DT2821_PRLD, dev->iobase + DT2821_SUPCSR);
706 wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;);
708 if (cmd->scan_begin_src == TRIG_FOLLOW) {
709 outw(devpriv->supcsr | DT2821_STRIG,
710 dev->iobase + DT2821_SUPCSR);
712 devpriv->supcsr |= DT2821_XTRIG;
713 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR);
719 static void dt282x_disable_dma(struct comedi_device *dev)
721 struct dt282x_private *devpriv = dev->private;
723 if (devpriv->usedma) {
724 disable_dma(devpriv->dma[0].chan);
725 disable_dma(devpriv->dma[1].chan);
729 static int dt282x_ai_cancel(struct comedi_device *dev,
730 struct comedi_subdevice *s)
732 struct dt282x_private *devpriv = dev->private;
734 dt282x_disable_dma(dev);
737 outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR);
740 outw(devpriv->supcsr | DT2821_ADCINIT, dev->iobase + DT2821_SUPCSR);
745 static int dt282x_ns_to_timer(int *nanosec, int round_mode)
747 int prescale, base, divider;
749 for (prescale = 0; prescale < 16; prescale++) {
752 base = 250 * (1 << prescale);
753 switch (round_mode) {
754 case TRIG_ROUND_NEAREST:
756 divider = (*nanosec + base / 2) / base;
758 case TRIG_ROUND_DOWN:
759 divider = (*nanosec) / base;
762 divider = (*nanosec + base - 1) / base;
766 *nanosec = divider * base;
767 return (prescale << 8) | (255 - divider);
770 base = 250 * (1 << 15);
772 *nanosec = divider * base;
773 return (15 << 8) | (255 - divider);
777 * Analog output routine. Selects single channel conversion,
778 * selects correct channel, converts from 2's compliment to
779 * offset binary if necessary, loads the data into the DAC
780 * data register, and performs the conversion.
782 static int dt282x_ao_insn_read(struct comedi_device *dev,
783 struct comedi_subdevice *s,
784 struct comedi_insn *insn, unsigned int *data)
786 struct dt282x_private *devpriv = dev->private;
788 data[0] = devpriv->ao[CR_CHAN(insn->chanspec)];
793 static int dt282x_ao_insn_write(struct comedi_device *dev,
794 struct comedi_subdevice *s,
795 struct comedi_insn *insn, unsigned int *data)
797 const struct dt282x_board *board = comedi_board(dev);
798 struct dt282x_private *devpriv = dev->private;
802 chan = CR_CHAN(insn->chanspec);
804 d &= (1 << board->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 << (board->dabits - 1));
815 devpriv->dacsr &= ~DT2821_YSEL;
816 if (devpriv->da1_2scomp)
817 d ^= (1 << (board->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;
1126 ret = comedi_request_region(dev, it->options[0], DT2821_SIZE);
1130 outw(DT2821_BDINIT, dev->iobase + DT2821_SUPCSR);
1131 i = inw(dev->iobase + DT2821_ADCSR);
1133 printk(KERN_DEBUG " fingerprint=%x,%x,%x,%x,%x",
1134 inw(dev->iobase + DT2821_ADCSR),
1135 inw(dev->iobase + DT2821_CHANCSR),
1136 inw(dev->iobase + DT2821_DACSR),
1137 inw(dev->iobase + DT2821_SUPCSR),
1138 inw(dev->iobase + DT2821_TMRCTR));
1141 if (((inw(dev->iobase + DT2821_ADCSR) & DT2821_ADCSR_MASK)
1142 != DT2821_ADCSR_VAL) ||
1143 ((inw(dev->iobase + DT2821_CHANCSR) & DT2821_CHANCSR_MASK)
1144 != DT2821_CHANCSR_VAL) ||
1145 ((inw(dev->iobase + DT2821_DACSR) & DT2821_DACSR_MASK)
1146 != DT2821_DACSR_VAL) ||
1147 ((inw(dev->iobase + DT2821_SUPCSR) & DT2821_SUPCSR_MASK)
1148 != DT2821_SUPCSR_VAL) ||
1149 ((inw(dev->iobase + DT2821_TMRCTR) & DT2821_TMRCTR_MASK)
1150 != DT2821_TMRCTR_VAL)) {
1151 printk(KERN_ERR " board not found");
1154 /* should do board test */
1156 irq = it->options[opt_irq];
1159 unsigned long flags;
1164 irqs = probe_irq_on();
1166 /* trigger interrupt */
1170 irq = probe_irq_off(irqs);
1171 restore_flags(flags);
1173 printk(KERN_ERR " error probing irq (bad)");
1177 printk(KERN_INFO " ( irq = %d )", irq);
1178 ret = request_irq(irq, dt282x_interrupt, 0,
1179 dev->board_name, dev);
1181 printk(KERN_ERR " failed to get irq\n");
1185 } else if (irq == 0) {
1186 printk(KERN_INFO " (no irq)");
1189 printk(KERN_INFO " (probe returned multiple irqs--bad)");
1191 printk(KERN_INFO " (irq probe not implemented)");
1195 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1199 ret = dt282x_grab_dma(dev, it->options[opt_dma1],
1200 it->options[opt_dma2]);
1204 ret = comedi_alloc_subdevices(dev, 3);
1208 s = &dev->subdevices[0];
1210 dev->read_subdev = s;
1212 s->type = COMEDI_SUBD_AI;
1213 s->subdev_flags = SDF_READABLE | SDF_CMD_READ |
1214 ((it->options[opt_diff]) ? SDF_DIFF : SDF_COMMON);
1216 (it->options[opt_diff]) ? board->adchan_di : board->adchan_se;
1217 s->insn_read = dt282x_ai_insn_read;
1218 s->do_cmdtest = dt282x_ai_cmdtest;
1219 s->do_cmd = dt282x_ai_cmd;
1220 s->cancel = dt282x_ai_cancel;
1221 s->maxdata = (1 << board->adbits) - 1;
1222 s->len_chanlist = 16;
1224 opt_ai_range_lkup(board->ispgl, it->options[opt_ai_range]);
1225 devpriv->ad_2scomp = it->options[opt_ai_twos];
1227 s = &dev->subdevices[1];
1229 s->n_chan = board->dachan;
1232 s->type = COMEDI_SUBD_AO;
1233 dev->write_subdev = s;
1234 s->subdev_flags = SDF_WRITABLE | SDF_CMD_WRITE;
1235 s->insn_read = dt282x_ao_insn_read;
1236 s->insn_write = dt282x_ao_insn_write;
1237 s->do_cmdtest = dt282x_ao_cmdtest;
1238 s->do_cmd = dt282x_ao_cmd;
1239 s->cancel = dt282x_ao_cancel;
1240 s->maxdata = (1 << board->dabits) - 1;
1241 s->len_chanlist = 2;
1242 s->range_table_list = devpriv->darangelist;
1243 devpriv->darangelist[0] =
1244 opt_ao_range_lkup(it->options[opt_ao0_range]);
1245 devpriv->darangelist[1] =
1246 opt_ao_range_lkup(it->options[opt_ao1_range]);
1247 devpriv->da0_2scomp = it->options[opt_ao0_twos];
1248 devpriv->da1_2scomp = it->options[opt_ao1_twos];
1250 s->type = COMEDI_SUBD_UNUSED;
1253 s = &dev->subdevices[2];
1255 s->type = COMEDI_SUBD_DIO;
1256 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1258 s->insn_bits = dt282x_dio_insn_bits;
1259 s->insn_config = dt282x_dio_insn_config;
1261 s->range_table = &range_digital;
1263 printk(KERN_INFO "\n");
1268 static void dt282x_detach(struct comedi_device *dev)
1270 struct dt282x_private *devpriv = dev->private;
1273 if (devpriv->dma[0].chan)
1274 free_dma(devpriv->dma[0].chan);
1275 if (devpriv->dma[1].chan)
1276 free_dma(devpriv->dma[1].chan);
1277 if (devpriv->dma[0].buf)
1278 free_page((unsigned long)devpriv->dma[0].buf);
1279 if (devpriv->dma[1].buf)
1280 free_page((unsigned long)devpriv->dma[1].buf);
1282 comedi_legacy_detach(dev);
1285 static const struct dt282x_board boardtypes[] = {
1323 .name = "dt2824-pgh",
1332 .name = "dt2824-pgl",
1404 .name = "dt24-ez-pgl",
1415 static struct comedi_driver dt282x_driver = {
1416 .driver_name = "dt282x",
1417 .module = THIS_MODULE,
1418 .attach = dt282x_attach,
1419 .detach = dt282x_detach,
1420 .board_name = &boardtypes[0].name,
1421 .num_names = ARRAY_SIZE(boardtypes),
1422 .offset = sizeof(struct dt282x_board),
1424 module_comedi_driver(dt282x_driver);
1426 MODULE_AUTHOR("Comedi http://www.comedi.org");
1427 MODULE_DESCRIPTION("Comedi low-level driver");
1428 MODULE_LICENSE("GPL");