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"
68 #define DT2821_TIMEOUT 100 /* 500 us */
69 #define DT2821_SIZE 0x10
72 * Registers in the DT282x
75 #define DT2821_ADCSR 0x00 /* A/D Control/Status */
76 #define DT2821_CHANCSR 0x02 /* Channel Control/Status */
77 #define DT2821_ADDAT 0x04 /* A/D data */
78 #define DT2821_DACSR 0x06 /* D/A Control/Status */
79 #define DT2821_DADAT 0x08 /* D/A data */
80 #define DT2821_DIODAT 0x0a /* digital data */
81 #define DT2821_SUPCSR 0x0c /* Supervisor Control/Status */
82 #define DT2821_TMRCTR 0x0e /* Timer/Counter */
85 * At power up, some registers are in a well-known state. The
86 * masks and values are as follows:
89 #define DT2821_ADCSR_MASK 0xfff0
90 #define DT2821_ADCSR_VAL 0x7c00
92 #define DT2821_CHANCSR_MASK 0xf0f0
93 #define DT2821_CHANCSR_VAL 0x70f0
95 #define DT2821_DACSR_MASK 0x7c93
96 #define DT2821_DACSR_VAL 0x7c90
98 #define DT2821_SUPCSR_MASK 0xf8ff
99 #define DT2821_SUPCSR_VAL 0x0000
101 #define DT2821_TMRCTR_MASK 0xff00
102 #define DT2821_TMRCTR_VAL 0xf000
105 * Bit fields of each register
110 #define DT2821_ADERR 0x8000 /* (R) 1 for A/D error */
111 #define DT2821_ADCLK 0x0200 /* (R/W) A/D clock enable */
112 /* 0x7c00 read as 1's */
113 #define DT2821_MUXBUSY 0x0100 /* (R) multiplexer busy */
114 #define DT2821_ADDONE 0x0080 /* (R) A/D done */
115 #define DT2821_IADDONE 0x0040 /* (R/W) interrupt on A/D done */
116 /* 0x0030 gain select */
117 /* 0x000f channel select */
121 #define DT2821_LLE 0x8000 /* (R/W) Load List Enable */
122 /* 0x7000 read as 1's */
123 /* 0x0f00 (R) present address */
124 /* 0x00f0 read as 1's */
125 /* 0x000f (R) number of entries - 1 */
129 #define DT2821_DAERR 0x8000 /* (R) D/A error */
130 #define DT2821_YSEL 0x0200 /* (R/W) DAC 1 select */
131 #define DT2821_SSEL 0x0100 /* (R/W) single channel select */
132 #define DT2821_DACRDY 0x0080 /* (R) DAC ready */
133 #define DT2821_IDARDY 0x0040 /* (R/W) interrupt on DAC ready */
134 #define DT2821_DACLK 0x0020 /* (R/W) D/A clock enable */
135 #define DT2821_HBOE 0x0002 /* (R/W) DIO high byte output enable */
136 #define DT2821_LBOE 0x0001 /* (R/W) DIO low byte output enable */
140 #define DT2821_DMAD 0x8000 /* (R) DMA done */
141 #define DT2821_ERRINTEN 0x4000 /* (R/W) interrupt on error */
142 #define DT2821_CLRDMADNE 0x2000 /* (W) clear DMA done */
143 #define DT2821_DDMA 0x1000 /* (R/W) dual DMA */
144 #define DT2821_DS1 0x0800 /* (R/W) DMA select 1 */
145 #define DT2821_DS0 0x0400 /* (R/W) DMA select 0 */
146 #define DT2821_BUFFB 0x0200 /* (R/W) buffer B selected */
147 #define DT2821_SCDN 0x0100 /* (R) scan done */
148 #define DT2821_DACON 0x0080 /* (W) DAC single conversion */
149 #define DT2821_ADCINIT 0x0040 /* (W) A/D initialize */
150 #define DT2821_DACINIT 0x0020 /* (W) D/A initialize */
151 #define DT2821_PRLD 0x0010 /* (W) preload multiplexer */
152 #define DT2821_STRIG 0x0008 /* (W) software trigger */
153 #define DT2821_XTRIG 0x0004 /* (R/W) external trigger enable */
154 #define DT2821_XCLK 0x0002 /* (R/W) external clock enable */
155 #define DT2821_BDINIT 0x0001 /* (W) initialize board */
157 static const struct comedi_lrange range_dt282x_ai_lo_bipolar = {
166 static const struct comedi_lrange range_dt282x_ai_lo_unipolar = {
175 static const struct comedi_lrange range_dt282x_ai_5_bipolar = {
184 static const struct comedi_lrange range_dt282x_ai_5_unipolar = {
193 static const struct comedi_lrange range_dt282x_ai_hi_bipolar = {
202 static const struct comedi_lrange range_dt282x_ai_hi_unipolar = {
211 struct dt282x_board {
222 struct dt282x_private {
223 int ad_2scomp; /* we have 2's comp jumper set */
224 int da0_2scomp; /* same, for DAC0 */
225 int da1_2scomp; /* same, for DAC1 */
227 const struct comedi_lrange *darangelist[2];
231 volatile int dacsr; /* software copies of registers */
240 short *buf; /* DMA buffer */
241 volatile int size; /* size of current transfer */
243 int dma_maxsize; /* max size of DMA transfer (in bytes) */
244 int usedma; /* driver uses DMA */
245 volatile int current_dma_index;
250 * Some useless abstractions
252 #define chan_to_DAC(a) ((a)&1)
253 #define mux_busy() (inw(dev->iobase+DT2821_ADCSR)&DT2821_MUXBUSY)
254 #define ad_done() (inw(dev->iobase+DT2821_ADCSR)&DT2821_ADDONE)
257 * danger! macro abuse... a is the expression to wait on, and b is
258 * the statement(s) to execute if it doesn't happen.
260 #define wait_for(a, b) \
263 for (_i = 0; _i < DT2821_TIMEOUT; _i++) { \
274 static int prep_ai_dma(struct comedi_device *dev, int chan, int size);
275 static int prep_ao_dma(struct comedi_device *dev, int chan, int size);
276 static int dt282x_ai_cancel(struct comedi_device *dev,
277 struct comedi_subdevice *s);
278 static int dt282x_ao_cancel(struct comedi_device *dev,
279 struct comedi_subdevice *s);
280 static int dt282x_ns_to_timer(int *nanosec, int round_mode);
281 static void dt282x_disable_dma(struct comedi_device *dev);
283 static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2);
285 static void dt282x_munge(struct comedi_device *dev, short *buf,
288 const struct dt282x_board *board = comedi_board(dev);
289 struct dt282x_private *devpriv = dev->private;
291 unsigned short mask = (1 << board->adbits) - 1;
292 unsigned short sign = 1 << (board->adbits - 1);
295 if (devpriv->ad_2scomp)
296 sign = 1 << (board->adbits - 1);
301 comedi_error(dev, "bug! odd number of bytes from dma xfer");
303 for (i = 0; i < n; i++)
304 buf[i] = (buf[i] & mask) ^ sign;
307 static void dt282x_ao_dma_interrupt(struct comedi_device *dev)
309 struct dt282x_private *devpriv = dev->private;
313 struct comedi_subdevice *s = &dev->subdevices[1];
315 outw(devpriv->supcsr | DT2821_CLRDMADNE, dev->iobase + DT2821_SUPCSR);
317 if (!s->async->prealloc_buf) {
318 printk(KERN_ERR "async->data disappeared. dang!\n");
322 i = devpriv->current_dma_index;
323 ptr = devpriv->dma[i].buf;
325 disable_dma(devpriv->dma[i].chan);
327 devpriv->current_dma_index = 1 - i;
329 size = cfc_read_array_from_buffer(s, ptr, devpriv->dma_maxsize);
331 printk(KERN_ERR "dt282x: AO underrun\n");
332 dt282x_ao_cancel(dev, s);
333 s->async->events |= COMEDI_CB_OVERFLOW;
336 prep_ao_dma(dev, i, size);
340 static void dt282x_ai_dma_interrupt(struct comedi_device *dev)
342 struct dt282x_private *devpriv = dev->private;
347 struct comedi_subdevice *s = &dev->subdevices[0];
349 outw(devpriv->supcsr | DT2821_CLRDMADNE, dev->iobase + DT2821_SUPCSR);
351 if (!s->async->prealloc_buf) {
352 printk(KERN_ERR "async->data disappeared. dang!\n");
356 i = devpriv->current_dma_index;
357 ptr = devpriv->dma[i].buf;
358 size = devpriv->dma[i].size;
360 disable_dma(devpriv->dma[i].chan);
362 devpriv->current_dma_index = 1 - i;
364 dt282x_munge(dev, ptr, size);
365 ret = cfc_write_array_to_buffer(s, ptr, size);
367 dt282x_ai_cancel(dev, s);
370 devpriv->nread -= size / 2;
372 if (devpriv->nread < 0) {
373 printk(KERN_INFO "dt282x: off by one\n");
376 if (!devpriv->nread) {
377 dt282x_ai_cancel(dev, s);
378 s->async->events |= COMEDI_CB_EOA;
382 /* clear the dual dma flag, making this the last dma segment */
383 /* XXX probably wrong */
384 if (!devpriv->ntrig) {
385 devpriv->supcsr &= ~(DT2821_DDMA);
386 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR);
389 /* restart the channel */
390 prep_ai_dma(dev, i, 0);
393 static int prep_ai_dma(struct comedi_device *dev, int dma_index, int n)
395 struct dt282x_private *devpriv = dev->private;
397 unsigned long dma_ptr;
404 n = devpriv->dma_maxsize;
405 if (n > devpriv->ntrig * 2)
406 n = devpriv->ntrig * 2;
407 devpriv->ntrig -= n / 2;
409 devpriv->dma[dma_index].size = n;
410 dma_chan = devpriv->dma[dma_index].chan;
411 dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
413 set_dma_mode(dma_chan, DMA_MODE_READ);
414 flags = claim_dma_lock();
415 clear_dma_ff(dma_chan);
416 set_dma_addr(dma_chan, dma_ptr);
417 set_dma_count(dma_chan, n);
418 release_dma_lock(flags);
420 enable_dma(dma_chan);
425 static int prep_ao_dma(struct comedi_device *dev, int dma_index, int n)
427 struct dt282x_private *devpriv = dev->private;
429 unsigned long dma_ptr;
432 devpriv->dma[dma_index].size = n;
433 dma_chan = devpriv->dma[dma_index].chan;
434 dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
436 set_dma_mode(dma_chan, DMA_MODE_WRITE);
437 flags = claim_dma_lock();
438 clear_dma_ff(dma_chan);
439 set_dma_addr(dma_chan, dma_ptr);
440 set_dma_count(dma_chan, n);
441 release_dma_lock(flags);
443 enable_dma(dma_chan);
448 static irqreturn_t dt282x_interrupt(int irq, void *d)
450 struct comedi_device *dev = d;
451 struct dt282x_private *devpriv = dev->private;
452 struct comedi_subdevice *s;
453 struct comedi_subdevice *s_ao;
454 unsigned int supcsr, adcsr, dacsr;
457 if (!dev->attached) {
458 comedi_error(dev, "spurious interrupt");
462 s = &dev->subdevices[0];
463 s_ao = &dev->subdevices[1];
464 adcsr = inw(dev->iobase + DT2821_ADCSR);
465 dacsr = inw(dev->iobase + DT2821_DACSR);
466 supcsr = inw(dev->iobase + DT2821_SUPCSR);
467 if (supcsr & DT2821_DMAD) {
468 if (devpriv->dma_dir == DMA_MODE_READ)
469 dt282x_ai_dma_interrupt(dev);
471 dt282x_ao_dma_interrupt(dev);
474 if (adcsr & DT2821_ADERR) {
475 if (devpriv->nread != 0) {
476 comedi_error(dev, "A/D error");
477 dt282x_ai_cancel(dev, s);
478 s->async->events |= COMEDI_CB_ERROR;
482 if (dacsr & DT2821_DAERR) {
486 disable_irq(dev->irq);
487 printk(KERN_INFO "disabling irq\n");
490 comedi_error(dev, "D/A error");
491 dt282x_ao_cancel(dev, s_ao);
492 s->async->events |= COMEDI_CB_ERROR;
496 if (adcsr & DT2821_ADDONE) {
500 data = (short)inw(dev->iobase + DT2821_ADDAT);
501 data &= (1 << board->adbits) - 1;
503 if (devpriv->ad_2scomp)
504 data ^= 1 << (board->adbits - 1);
505 ret = comedi_buf_put(s->async, data);
508 s->async->events |= COMEDI_CB_OVERFLOW;
511 if (!devpriv->nread) {
512 s->async->events |= COMEDI_CB_EOA;
514 if (supcsr & DT2821_SCDN)
515 outw(devpriv->supcsr | DT2821_STRIG,
516 dev->iobase + DT2821_SUPCSR);
521 comedi_event(dev, s);
522 /* printk("adcsr=0x%02x dacsr-0x%02x supcsr=0x%02x\n",
523 adcsr, dacsr, supcsr); */
524 return IRQ_RETVAL(handled);
527 static void dt282x_load_changain(struct comedi_device *dev, int n,
528 unsigned int *chanlist)
530 struct dt282x_private *devpriv = dev->private;
532 unsigned int chan, range;
534 outw(DT2821_LLE | (n - 1), dev->iobase + DT2821_CHANCSR);
535 for (i = 0; i < n; i++) {
536 chan = CR_CHAN(chanlist[i]);
537 range = CR_RANGE(chanlist[i]);
538 outw(devpriv->adcsr | (range << 4) | chan,
539 dev->iobase + DT2821_ADCSR);
541 outw(n - 1, dev->iobase + DT2821_CHANCSR);
545 * Performs a single A/D conversion.
546 * - Put channel/gain into channel-gain list
547 * - preload multiplexer
548 * - trigger conversion and wait for it to finish
550 static int dt282x_ai_insn_read(struct comedi_device *dev,
551 struct comedi_subdevice *s,
552 struct comedi_insn *insn, unsigned int *data)
554 const struct dt282x_board *board = comedi_board(dev);
555 struct dt282x_private *devpriv = dev->private;
558 /* XXX should we really be enabling the ad clock here? */
559 devpriv->adcsr = DT2821_ADCLK;
560 outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR);
562 dt282x_load_changain(dev, 1, &insn->chanspec);
564 outw(devpriv->supcsr | DT2821_PRLD, dev->iobase + DT2821_SUPCSR);
565 wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;);
567 for (i = 0; i < insn->n; i++) {
568 outw(devpriv->supcsr | DT2821_STRIG,
569 dev->iobase + DT2821_SUPCSR);
570 wait_for(ad_done(), comedi_error(dev, "timeout\n");
575 DT2821_ADDAT) & ((1 << board->adbits) - 1);
576 if (devpriv->ad_2scomp)
577 data[i] ^= (1 << (board->adbits - 1));
583 static int dt282x_ai_cmdtest(struct comedi_device *dev,
584 struct comedi_subdevice *s, struct comedi_cmd *cmd)
586 const struct dt282x_board *board = comedi_board(dev);
590 /* Step 1 : check if triggers are trivially valid */
592 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
593 err |= cfc_check_trigger_src(&cmd->scan_begin_src,
594 TRIG_FOLLOW | TRIG_EXT);
595 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
596 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
597 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
602 /* Step 2a : make sure trigger sources are unique */
604 err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
605 err |= cfc_check_trigger_is_unique(cmd->stop_src);
607 /* Step 2b : and mutually compatible */
612 /* Step 3: check if arguments are trivially valid */
614 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
616 if (cmd->scan_begin_src == TRIG_FOLLOW) {
617 /* internal trigger */
618 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
620 /* external trigger */
621 /* should be level/edge, hi/lo specification here */
622 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
625 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 4000);
627 #define SLOWEST_TIMER (250*(1<<15)*255)
628 err |= cfc_check_trigger_arg_max(&cmd->convert_arg, SLOWEST_TIMER);
629 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, board->ai_speed);
630 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
632 if (cmd->stop_src == TRIG_COUNT) {
633 /* any count is allowed */
634 } else { /* TRIG_NONE */
635 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
641 /* step 4: fix up any arguments */
643 tmp = cmd->convert_arg;
644 dt282x_ns_to_timer(&cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK);
645 if (tmp != cmd->convert_arg)
654 static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
656 const struct dt282x_board *board = comedi_board(dev);
657 struct dt282x_private *devpriv = dev->private;
658 struct comedi_cmd *cmd = &s->async->cmd;
661 if (devpriv->usedma == 0) {
663 "driver requires 2 dma channels"
664 " to execute command");
668 dt282x_disable_dma(dev);
670 if (cmd->convert_arg < board->ai_speed)
671 cmd->convert_arg = board->ai_speed;
672 timer = dt282x_ns_to_timer(&cmd->convert_arg, TRIG_ROUND_NEAREST);
673 outw(timer, dev->iobase + DT2821_TMRCTR);
675 if (cmd->scan_begin_src == TRIG_FOLLOW) {
676 /* internal trigger */
677 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0;
679 /* external trigger */
680 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0 | DT2821_DS1;
682 outw(devpriv->supcsr | DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_ADCINIT,
683 dev->iobase + DT2821_SUPCSR);
685 devpriv->ntrig = cmd->stop_arg * cmd->scan_end_arg;
686 devpriv->nread = devpriv->ntrig;
688 devpriv->dma_dir = DMA_MODE_READ;
689 devpriv->current_dma_index = 0;
690 prep_ai_dma(dev, 0, 0);
691 if (devpriv->ntrig) {
692 prep_ai_dma(dev, 1, 0);
693 devpriv->supcsr |= DT2821_DDMA;
694 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR);
699 dt282x_load_changain(dev, cmd->chanlist_len, cmd->chanlist);
701 devpriv->adcsr = DT2821_ADCLK | DT2821_IADDONE;
702 outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR);
704 outw(devpriv->supcsr | DT2821_PRLD, dev->iobase + DT2821_SUPCSR);
705 wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;);
707 if (cmd->scan_begin_src == TRIG_FOLLOW) {
708 outw(devpriv->supcsr | DT2821_STRIG,
709 dev->iobase + DT2821_SUPCSR);
711 devpriv->supcsr |= DT2821_XTRIG;
712 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR);
718 static void dt282x_disable_dma(struct comedi_device *dev)
720 struct dt282x_private *devpriv = dev->private;
722 if (devpriv->usedma) {
723 disable_dma(devpriv->dma[0].chan);
724 disable_dma(devpriv->dma[1].chan);
728 static int dt282x_ai_cancel(struct comedi_device *dev,
729 struct comedi_subdevice *s)
731 struct dt282x_private *devpriv = dev->private;
733 dt282x_disable_dma(dev);
736 outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR);
739 outw(devpriv->supcsr | DT2821_ADCINIT, dev->iobase + DT2821_SUPCSR);
744 static int dt282x_ns_to_timer(int *nanosec, int round_mode)
746 int prescale, base, divider;
748 for (prescale = 0; prescale < 16; prescale++) {
751 base = 250 * (1 << prescale);
752 switch (round_mode) {
753 case TRIG_ROUND_NEAREST:
755 divider = (*nanosec + base / 2) / base;
757 case TRIG_ROUND_DOWN:
758 divider = (*nanosec) / base;
761 divider = (*nanosec + base - 1) / base;
765 *nanosec = divider * base;
766 return (prescale << 8) | (255 - divider);
769 base = 250 * (1 << 15);
771 *nanosec = divider * base;
772 return (15 << 8) | (255 - divider);
776 * Analog output routine. Selects single channel conversion,
777 * selects correct channel, converts from 2's compliment to
778 * offset binary if necessary, loads the data into the DAC
779 * data register, and performs the conversion.
781 static int dt282x_ao_insn_read(struct comedi_device *dev,
782 struct comedi_subdevice *s,
783 struct comedi_insn *insn, unsigned int *data)
785 struct dt282x_private *devpriv = dev->private;
787 data[0] = devpriv->ao[CR_CHAN(insn->chanspec)];
792 static int dt282x_ao_insn_write(struct comedi_device *dev,
793 struct comedi_subdevice *s,
794 struct comedi_insn *insn, unsigned int *data)
796 const struct dt282x_board *board = comedi_board(dev);
797 struct dt282x_private *devpriv = dev->private;
801 chan = CR_CHAN(insn->chanspec);
803 d &= (1 << board->dabits) - 1;
804 devpriv->ao[chan] = d;
806 devpriv->dacsr |= DT2821_SSEL;
810 devpriv->dacsr |= DT2821_YSEL;
811 if (devpriv->da0_2scomp)
812 d ^= (1 << (board->dabits - 1));
814 devpriv->dacsr &= ~DT2821_YSEL;
815 if (devpriv->da1_2scomp)
816 d ^= (1 << (board->dabits - 1));
819 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
821 outw(d, dev->iobase + DT2821_DADAT);
823 outw(devpriv->supcsr | DT2821_DACON, dev->iobase + DT2821_SUPCSR);
828 static int dt282x_ao_cmdtest(struct comedi_device *dev,
829 struct comedi_subdevice *s, struct comedi_cmd *cmd)
834 /* Step 1 : check if triggers are trivially valid */
836 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT);
837 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
838 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
839 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
840 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
845 /* Step 2a : make sure trigger sources are unique */
847 err |= cfc_check_trigger_is_unique(cmd->stop_src);
849 /* Step 2b : and mutually compatible */
854 /* Step 3: check if arguments are trivially valid */
856 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
857 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 5000);
858 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
859 err |= cfc_check_trigger_arg_max(&cmd->scan_end_arg, 2);
861 if (cmd->stop_src == TRIG_COUNT) {
862 /* any count is allowed */
863 } else { /* TRIG_NONE */
864 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
870 /* step 4: fix up any arguments */
872 tmp = cmd->scan_begin_arg;
873 dt282x_ns_to_timer(&cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK);
874 if (tmp != cmd->scan_begin_arg)
884 static int dt282x_ao_inttrig(struct comedi_device *dev,
885 struct comedi_subdevice *s, unsigned int x)
887 struct dt282x_private *devpriv = dev->private;
893 size = cfc_read_array_from_buffer(s, devpriv->dma[0].buf,
894 devpriv->dma_maxsize);
896 printk(KERN_ERR "dt282x: AO underrun\n");
899 prep_ao_dma(dev, 0, size);
901 size = cfc_read_array_from_buffer(s, devpriv->dma[1].buf,
902 devpriv->dma_maxsize);
904 printk(KERN_ERR "dt282x: AO underrun\n");
907 prep_ao_dma(dev, 1, size);
909 outw(devpriv->supcsr | DT2821_STRIG, dev->iobase + DT2821_SUPCSR);
910 s->async->inttrig = NULL;
915 static int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
917 struct dt282x_private *devpriv = dev->private;
919 struct comedi_cmd *cmd = &s->async->cmd;
921 if (devpriv->usedma == 0) {
923 "driver requires 2 dma channels"
924 " to execute command");
928 dt282x_disable_dma(dev);
930 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS1 | DT2821_DDMA;
931 outw(devpriv->supcsr | DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_DACINIT,
932 dev->iobase + DT2821_SUPCSR);
934 devpriv->ntrig = cmd->stop_arg * cmd->chanlist_len;
935 devpriv->nread = devpriv->ntrig;
937 devpriv->dma_dir = DMA_MODE_WRITE;
938 devpriv->current_dma_index = 0;
940 timer = dt282x_ns_to_timer(&cmd->scan_begin_arg, TRIG_ROUND_NEAREST);
941 outw(timer, dev->iobase + DT2821_TMRCTR);
943 devpriv->dacsr = DT2821_SSEL | DT2821_DACLK | DT2821_IDARDY;
944 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
946 s->async->inttrig = dt282x_ao_inttrig;
951 static int dt282x_ao_cancel(struct comedi_device *dev,
952 struct comedi_subdevice *s)
954 struct dt282x_private *devpriv = dev->private;
956 dt282x_disable_dma(dev);
959 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
962 outw(devpriv->supcsr | DT2821_DACINIT, dev->iobase + DT2821_SUPCSR);
967 static int dt282x_dio_insn_bits(struct comedi_device *dev,
968 struct comedi_subdevice *s,
969 struct comedi_insn *insn, unsigned int *data)
972 s->state &= ~data[0];
973 s->state |= (data[0] & data[1]);
975 outw(s->state, dev->iobase + DT2821_DIODAT);
977 data[1] = inw(dev->iobase + DT2821_DIODAT);
982 static int dt282x_dio_insn_config(struct comedi_device *dev,
983 struct comedi_subdevice *s,
984 struct comedi_insn *insn, unsigned int *data)
986 struct dt282x_private *devpriv = dev->private;
989 mask = (CR_CHAN(insn->chanspec) < 8) ? 0x00ff : 0xff00;
995 if (s->io_bits & 0x00ff)
996 devpriv->dacsr |= DT2821_LBOE;
998 devpriv->dacsr &= ~DT2821_LBOE;
999 if (s->io_bits & 0xff00)
1000 devpriv->dacsr |= DT2821_HBOE;
1002 devpriv->dacsr &= ~DT2821_HBOE;
1004 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
1009 static const struct comedi_lrange *const ai_range_table[] = {
1010 &range_dt282x_ai_lo_bipolar,
1011 &range_dt282x_ai_lo_unipolar,
1012 &range_dt282x_ai_5_bipolar,
1013 &range_dt282x_ai_5_unipolar
1016 static const struct comedi_lrange *const ai_range_pgl_table[] = {
1017 &range_dt282x_ai_hi_bipolar,
1018 &range_dt282x_ai_hi_unipolar
1021 static const struct comedi_lrange *opt_ai_range_lkup(int ispgl, int x)
1024 if (x < 0 || x >= 2)
1026 return ai_range_pgl_table[x];
1028 if (x < 0 || x >= 4)
1030 return ai_range_table[x];
1034 static const struct comedi_lrange *const ao_range_table[] = {
1042 static const struct comedi_lrange *opt_ao_range_lkup(int x)
1044 if (x < 0 || x >= 5)
1046 return ao_range_table[x];
1049 enum { /* i/o base, irq, dma channels */
1050 opt_iobase = 0, opt_irq, opt_dma1, opt_dma2,
1051 opt_diff, /* differential */
1052 opt_ai_twos, opt_ao0_twos, opt_ao1_twos, /* twos comp */
1053 opt_ai_range, opt_ao0_range, opt_ao1_range, /* range */
1056 static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2)
1058 struct dt282x_private *devpriv = dev->private;
1061 devpriv->usedma = 0;
1063 if (!dma1 && !dma2) {
1064 printk(KERN_ERR " (no dma)");
1068 if (dma1 == dma2 || dma1 < 5 || dma2 < 5 || dma1 > 7 || dma2 > 7)
1078 ret = request_dma(dma1, "dt282x A");
1081 devpriv->dma[0].chan = dma1;
1083 ret = request_dma(dma2, "dt282x B");
1086 devpriv->dma[1].chan = dma2;
1088 devpriv->dma_maxsize = PAGE_SIZE;
1089 devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
1090 devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
1091 if (!devpriv->dma[0].buf || !devpriv->dma[1].buf) {
1092 printk(KERN_ERR " can't get DMA memory");
1096 printk(KERN_INFO " (dma=%d,%d)", dma1, dma2);
1098 devpriv->usedma = 1;
1109 4 0=single ended, 1=differential
1110 5 ai 0=straight binary, 1=2's comp
1111 6 ao0 0=straight binary, 1=2's comp
1112 7 ao1 0=straight binary, 1=2's comp
1113 8 ai 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V
1114 9 ao0 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1115 10 ao1 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1117 static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1119 const struct dt282x_board *board = comedi_board(dev);
1120 struct dt282x_private *devpriv;
1123 struct comedi_subdevice *s;
1125 ret = comedi_request_region(dev, it->options[0], DT2821_SIZE);
1129 outw(DT2821_BDINIT, dev->iobase + DT2821_SUPCSR);
1130 i = inw(dev->iobase + DT2821_ADCSR);
1132 printk(KERN_DEBUG " fingerprint=%x,%x,%x,%x,%x",
1133 inw(dev->iobase + DT2821_ADCSR),
1134 inw(dev->iobase + DT2821_CHANCSR),
1135 inw(dev->iobase + DT2821_DACSR),
1136 inw(dev->iobase + DT2821_SUPCSR),
1137 inw(dev->iobase + DT2821_TMRCTR));
1140 if (((inw(dev->iobase + DT2821_ADCSR) & DT2821_ADCSR_MASK)
1141 != DT2821_ADCSR_VAL) ||
1142 ((inw(dev->iobase + DT2821_CHANCSR) & DT2821_CHANCSR_MASK)
1143 != DT2821_CHANCSR_VAL) ||
1144 ((inw(dev->iobase + DT2821_DACSR) & DT2821_DACSR_MASK)
1145 != DT2821_DACSR_VAL) ||
1146 ((inw(dev->iobase + DT2821_SUPCSR) & DT2821_SUPCSR_MASK)
1147 != DT2821_SUPCSR_VAL) ||
1148 ((inw(dev->iobase + DT2821_TMRCTR) & DT2821_TMRCTR_MASK)
1149 != DT2821_TMRCTR_VAL)) {
1150 printk(KERN_ERR " board not found");
1153 /* should do board test */
1155 irq = it->options[opt_irq];
1158 unsigned long flags;
1163 irqs = probe_irq_on();
1165 /* trigger interrupt */
1169 irq = probe_irq_off(irqs);
1170 restore_flags(flags);
1172 printk(KERN_ERR " error probing irq (bad)");
1176 printk(KERN_INFO " ( irq = %d )", irq);
1177 ret = request_irq(irq, dt282x_interrupt, 0,
1178 dev->board_name, dev);
1180 printk(KERN_ERR " failed to get irq\n");
1184 } else if (irq == 0) {
1185 printk(KERN_INFO " (no irq)");
1188 printk(KERN_INFO " (probe returned multiple irqs--bad)");
1190 printk(KERN_INFO " (irq probe not implemented)");
1194 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1198 ret = dt282x_grab_dma(dev, it->options[opt_dma1],
1199 it->options[opt_dma2]);
1203 ret = comedi_alloc_subdevices(dev, 3);
1207 s = &dev->subdevices[0];
1209 dev->read_subdev = s;
1211 s->type = COMEDI_SUBD_AI;
1212 s->subdev_flags = SDF_READABLE | SDF_CMD_READ |
1213 ((it->options[opt_diff]) ? SDF_DIFF : SDF_COMMON);
1215 (it->options[opt_diff]) ? board->adchan_di : board->adchan_se;
1216 s->insn_read = dt282x_ai_insn_read;
1217 s->do_cmdtest = dt282x_ai_cmdtest;
1218 s->do_cmd = dt282x_ai_cmd;
1219 s->cancel = dt282x_ai_cancel;
1220 s->maxdata = (1 << board->adbits) - 1;
1221 s->len_chanlist = 16;
1223 opt_ai_range_lkup(board->ispgl, it->options[opt_ai_range]);
1224 devpriv->ad_2scomp = it->options[opt_ai_twos];
1226 s = &dev->subdevices[1];
1228 s->n_chan = board->dachan;
1231 s->type = COMEDI_SUBD_AO;
1232 dev->write_subdev = s;
1233 s->subdev_flags = SDF_WRITABLE | SDF_CMD_WRITE;
1234 s->insn_read = dt282x_ao_insn_read;
1235 s->insn_write = dt282x_ao_insn_write;
1236 s->do_cmdtest = dt282x_ao_cmdtest;
1237 s->do_cmd = dt282x_ao_cmd;
1238 s->cancel = dt282x_ao_cancel;
1239 s->maxdata = (1 << board->dabits) - 1;
1240 s->len_chanlist = 2;
1241 s->range_table_list = devpriv->darangelist;
1242 devpriv->darangelist[0] =
1243 opt_ao_range_lkup(it->options[opt_ao0_range]);
1244 devpriv->darangelist[1] =
1245 opt_ao_range_lkup(it->options[opt_ao1_range]);
1246 devpriv->da0_2scomp = it->options[opt_ao0_twos];
1247 devpriv->da1_2scomp = it->options[opt_ao1_twos];
1249 s->type = COMEDI_SUBD_UNUSED;
1252 s = &dev->subdevices[2];
1254 s->type = COMEDI_SUBD_DIO;
1255 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1257 s->insn_bits = dt282x_dio_insn_bits;
1258 s->insn_config = dt282x_dio_insn_config;
1260 s->range_table = &range_digital;
1262 printk(KERN_INFO "\n");
1267 static void dt282x_detach(struct comedi_device *dev)
1269 struct dt282x_private *devpriv = dev->private;
1272 if (devpriv->dma[0].chan)
1273 free_dma(devpriv->dma[0].chan);
1274 if (devpriv->dma[1].chan)
1275 free_dma(devpriv->dma[1].chan);
1276 if (devpriv->dma[0].buf)
1277 free_page((unsigned long)devpriv->dma[0].buf);
1278 if (devpriv->dma[1].buf)
1279 free_page((unsigned long)devpriv->dma[1].buf);
1281 comedi_legacy_detach(dev);
1284 static const struct dt282x_board boardtypes[] = {
1322 .name = "dt2824-pgh",
1331 .name = "dt2824-pgl",
1403 .name = "dt24-ez-pgl",
1414 static struct comedi_driver dt282x_driver = {
1415 .driver_name = "dt282x",
1416 .module = THIS_MODULE,
1417 .attach = dt282x_attach,
1418 .detach = dt282x_detach,
1419 .board_name = &boardtypes[0].name,
1420 .num_names = ARRAY_SIZE(boardtypes),
1421 .offset = sizeof(struct dt282x_board),
1423 module_comedi_driver(dt282x_driver);
1425 MODULE_AUTHOR("Comedi http://www.comedi.org");
1426 MODULE_DESCRIPTION("Comedi low-level driver");
1427 MODULE_LICENSE("GPL");