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 "../comedidev.h"
56 #include <linux/gfp.h>
57 #include <linux/ioport.h>
58 #include <linux/interrupt.h>
61 #include "comedi_fc.h"
65 #define DT2821_TIMEOUT 100 /* 500 us */
66 #define DT2821_SIZE 0x10
69 * Registers in the DT282x
72 #define DT2821_ADCSR 0x00 /* A/D Control/Status */
73 #define DT2821_CHANCSR 0x02 /* Channel Control/Status */
74 #define DT2821_ADDAT 0x04 /* A/D data */
75 #define DT2821_DACSR 0x06 /* D/A Control/Status */
76 #define DT2821_DADAT 0x08 /* D/A data */
77 #define DT2821_DIODAT 0x0a /* digital data */
78 #define DT2821_SUPCSR 0x0c /* Supervisor Control/Status */
79 #define DT2821_TMRCTR 0x0e /* Timer/Counter */
82 * At power up, some registers are in a well-known state. The
83 * masks and values are as follows:
86 #define DT2821_ADCSR_MASK 0xfff0
87 #define DT2821_ADCSR_VAL 0x7c00
89 #define DT2821_CHANCSR_MASK 0xf0f0
90 #define DT2821_CHANCSR_VAL 0x70f0
92 #define DT2821_DACSR_MASK 0x7c93
93 #define DT2821_DACSR_VAL 0x7c90
95 #define DT2821_SUPCSR_MASK 0xf8ff
96 #define DT2821_SUPCSR_VAL 0x0000
98 #define DT2821_TMRCTR_MASK 0xff00
99 #define DT2821_TMRCTR_VAL 0xf000
102 * Bit fields of each register
107 #define DT2821_ADERR 0x8000 /* (R) 1 for A/D error */
108 #define DT2821_ADCLK 0x0200 /* (R/W) A/D clock enable */
109 /* 0x7c00 read as 1's */
110 #define DT2821_MUXBUSY 0x0100 /* (R) multiplexer busy */
111 #define DT2821_ADDONE 0x0080 /* (R) A/D done */
112 #define DT2821_IADDONE 0x0040 /* (R/W) interrupt on A/D done */
113 /* 0x0030 gain select */
114 /* 0x000f channel select */
118 #define DT2821_LLE 0x8000 /* (R/W) Load List Enable */
119 /* 0x7000 read as 1's */
120 /* 0x0f00 (R) present address */
121 /* 0x00f0 read as 1's */
122 /* 0x000f (R) number of entries - 1 */
126 #define DT2821_DAERR 0x8000 /* (R) D/A error */
127 #define DT2821_YSEL 0x0200 /* (R/W) DAC 1 select */
128 #define DT2821_SSEL 0x0100 /* (R/W) single channel select */
129 #define DT2821_DACRDY 0x0080 /* (R) DAC ready */
130 #define DT2821_IDARDY 0x0040 /* (R/W) interrupt on DAC ready */
131 #define DT2821_DACLK 0x0020 /* (R/W) D/A clock enable */
132 #define DT2821_HBOE 0x0002 /* (R/W) DIO high byte output enable */
133 #define DT2821_LBOE 0x0001 /* (R/W) DIO low byte output enable */
137 #define DT2821_DMAD 0x8000 /* (R) DMA done */
138 #define DT2821_ERRINTEN 0x4000 /* (R/W) interrupt on error */
139 #define DT2821_CLRDMADNE 0x2000 /* (W) clear DMA done */
140 #define DT2821_DDMA 0x1000 /* (R/W) dual DMA */
141 #define DT2821_DS1 0x0800 /* (R/W) DMA select 1 */
142 #define DT2821_DS0 0x0400 /* (R/W) DMA select 0 */
143 #define DT2821_BUFFB 0x0200 /* (R/W) buffer B selected */
144 #define DT2821_SCDN 0x0100 /* (R) scan done */
145 #define DT2821_DACON 0x0080 /* (W) DAC single conversion */
146 #define DT2821_ADCINIT 0x0040 /* (W) A/D initialize */
147 #define DT2821_DACINIT 0x0020 /* (W) D/A initialize */
148 #define DT2821_PRLD 0x0010 /* (W) preload multiplexer */
149 #define DT2821_STRIG 0x0008 /* (W) software trigger */
150 #define DT2821_XTRIG 0x0004 /* (R/W) external trigger enable */
151 #define DT2821_XCLK 0x0002 /* (R/W) external clock enable */
152 #define DT2821_BDINIT 0x0001 /* (W) initialize board */
154 static const struct comedi_lrange range_dt282x_ai_lo_bipolar = {
163 static const struct comedi_lrange range_dt282x_ai_lo_unipolar = {
172 static const struct comedi_lrange range_dt282x_ai_5_bipolar = {
181 static const struct comedi_lrange range_dt282x_ai_5_unipolar = {
190 static const struct comedi_lrange range_dt282x_ai_hi_bipolar = {
199 static const struct comedi_lrange range_dt282x_ai_hi_unipolar = {
208 struct dt282x_board {
219 struct dt282x_private {
220 int ad_2scomp; /* we have 2's comp jumper set */
221 int da0_2scomp; /* same, for DAC0 */
222 int da1_2scomp; /* same, for DAC1 */
224 const struct comedi_lrange *darangelist[2];
228 volatile int dacsr; /* software copies of registers */
237 short *buf; /* DMA buffer */
238 volatile int size; /* size of current transfer */
240 int dma_maxsize; /* max size of DMA transfer (in bytes) */
241 int usedma; /* driver uses DMA */
242 volatile int current_dma_index;
247 * Some useless abstractions
249 #define chan_to_DAC(a) ((a)&1)
250 #define mux_busy() (inw(dev->iobase+DT2821_ADCSR)&DT2821_MUXBUSY)
251 #define ad_done() (inw(dev->iobase+DT2821_ADCSR)&DT2821_ADDONE)
254 * danger! macro abuse... a is the expression to wait on, and b is
255 * the statement(s) to execute if it doesn't happen.
257 #define wait_for(a, b) \
260 for (_i = 0; _i < DT2821_TIMEOUT; _i++) { \
271 static int prep_ai_dma(struct comedi_device *dev, int chan, int size);
272 static int prep_ao_dma(struct comedi_device *dev, int chan, int size);
273 static int dt282x_ai_cancel(struct comedi_device *dev,
274 struct comedi_subdevice *s);
275 static int dt282x_ao_cancel(struct comedi_device *dev,
276 struct comedi_subdevice *s);
277 static int dt282x_ns_to_timer(int *nanosec, int round_mode);
278 static void dt282x_disable_dma(struct comedi_device *dev);
280 static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2);
282 static void dt282x_munge(struct comedi_device *dev, short *buf,
285 const struct dt282x_board *board = comedi_board(dev);
286 struct dt282x_private *devpriv = dev->private;
288 unsigned short mask = (1 << board->adbits) - 1;
289 unsigned short sign = 1 << (board->adbits - 1);
292 if (devpriv->ad_2scomp)
293 sign = 1 << (board->adbits - 1);
298 comedi_error(dev, "bug! odd number of bytes from dma xfer");
300 for (i = 0; i < n; i++)
301 buf[i] = (buf[i] & mask) ^ sign;
304 static void dt282x_ao_dma_interrupt(struct comedi_device *dev)
306 struct dt282x_private *devpriv = dev->private;
310 struct comedi_subdevice *s = &dev->subdevices[1];
312 outw(devpriv->supcsr | DT2821_CLRDMADNE, dev->iobase + DT2821_SUPCSR);
314 if (!s->async->prealloc_buf) {
315 printk(KERN_ERR "async->data disappeared. dang!\n");
319 i = devpriv->current_dma_index;
320 ptr = devpriv->dma[i].buf;
322 disable_dma(devpriv->dma[i].chan);
324 devpriv->current_dma_index = 1 - i;
326 size = cfc_read_array_from_buffer(s, ptr, devpriv->dma_maxsize);
328 printk(KERN_ERR "dt282x: AO underrun\n");
329 dt282x_ao_cancel(dev, s);
330 s->async->events |= COMEDI_CB_OVERFLOW;
333 prep_ao_dma(dev, i, size);
337 static void dt282x_ai_dma_interrupt(struct comedi_device *dev)
339 struct dt282x_private *devpriv = dev->private;
344 struct comedi_subdevice *s = &dev->subdevices[0];
346 outw(devpriv->supcsr | DT2821_CLRDMADNE, dev->iobase + DT2821_SUPCSR);
348 if (!s->async->prealloc_buf) {
349 printk(KERN_ERR "async->data disappeared. dang!\n");
353 i = devpriv->current_dma_index;
354 ptr = devpriv->dma[i].buf;
355 size = devpriv->dma[i].size;
357 disable_dma(devpriv->dma[i].chan);
359 devpriv->current_dma_index = 1 - i;
361 dt282x_munge(dev, ptr, size);
362 ret = cfc_write_array_to_buffer(s, ptr, size);
364 dt282x_ai_cancel(dev, s);
367 devpriv->nread -= size / 2;
369 if (devpriv->nread < 0) {
370 printk(KERN_INFO "dt282x: off by one\n");
373 if (!devpriv->nread) {
374 dt282x_ai_cancel(dev, s);
375 s->async->events |= COMEDI_CB_EOA;
379 /* clear the dual dma flag, making this the last dma segment */
380 /* XXX probably wrong */
381 if (!devpriv->ntrig) {
382 devpriv->supcsr &= ~(DT2821_DDMA);
383 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR);
386 /* restart the channel */
387 prep_ai_dma(dev, i, 0);
390 static int prep_ai_dma(struct comedi_device *dev, int dma_index, int n)
392 struct dt282x_private *devpriv = dev->private;
394 unsigned long dma_ptr;
401 n = devpriv->dma_maxsize;
402 if (n > devpriv->ntrig * 2)
403 n = devpriv->ntrig * 2;
404 devpriv->ntrig -= n / 2;
406 devpriv->dma[dma_index].size = n;
407 dma_chan = devpriv->dma[dma_index].chan;
408 dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
410 set_dma_mode(dma_chan, DMA_MODE_READ);
411 flags = claim_dma_lock();
412 clear_dma_ff(dma_chan);
413 set_dma_addr(dma_chan, dma_ptr);
414 set_dma_count(dma_chan, n);
415 release_dma_lock(flags);
417 enable_dma(dma_chan);
422 static int prep_ao_dma(struct comedi_device *dev, int dma_index, int n)
424 struct dt282x_private *devpriv = dev->private;
426 unsigned long dma_ptr;
429 devpriv->dma[dma_index].size = n;
430 dma_chan = devpriv->dma[dma_index].chan;
431 dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
433 set_dma_mode(dma_chan, DMA_MODE_WRITE);
434 flags = claim_dma_lock();
435 clear_dma_ff(dma_chan);
436 set_dma_addr(dma_chan, dma_ptr);
437 set_dma_count(dma_chan, n);
438 release_dma_lock(flags);
440 enable_dma(dma_chan);
445 static irqreturn_t dt282x_interrupt(int irq, void *d)
447 struct comedi_device *dev = d;
448 struct dt282x_private *devpriv = dev->private;
449 struct comedi_subdevice *s;
450 struct comedi_subdevice *s_ao;
451 unsigned int supcsr, adcsr, dacsr;
454 if (!dev->attached) {
455 comedi_error(dev, "spurious interrupt");
459 s = &dev->subdevices[0];
460 s_ao = &dev->subdevices[1];
461 adcsr = inw(dev->iobase + DT2821_ADCSR);
462 dacsr = inw(dev->iobase + DT2821_DACSR);
463 supcsr = inw(dev->iobase + DT2821_SUPCSR);
464 if (supcsr & DT2821_DMAD) {
465 if (devpriv->dma_dir == DMA_MODE_READ)
466 dt282x_ai_dma_interrupt(dev);
468 dt282x_ao_dma_interrupt(dev);
471 if (adcsr & DT2821_ADERR) {
472 if (devpriv->nread != 0) {
473 comedi_error(dev, "A/D error");
474 dt282x_ai_cancel(dev, s);
475 s->async->events |= COMEDI_CB_ERROR;
479 if (dacsr & DT2821_DAERR) {
483 disable_irq(dev->irq);
484 printk(KERN_INFO "disabling irq\n");
487 comedi_error(dev, "D/A error");
488 dt282x_ao_cancel(dev, s_ao);
489 s->async->events |= COMEDI_CB_ERROR;
493 if (adcsr & DT2821_ADDONE) {
497 data = (short)inw(dev->iobase + DT2821_ADDAT);
498 data &= (1 << board->adbits) - 1;
500 if (devpriv->ad_2scomp)
501 data ^= 1 << (board->adbits - 1);
502 ret = comedi_buf_put(s->async, data);
505 s->async->events |= COMEDI_CB_OVERFLOW;
508 if (!devpriv->nread) {
509 s->async->events |= COMEDI_CB_EOA;
511 if (supcsr & DT2821_SCDN)
512 outw(devpriv->supcsr | DT2821_STRIG,
513 dev->iobase + DT2821_SUPCSR);
518 comedi_event(dev, s);
519 /* printk("adcsr=0x%02x dacsr-0x%02x supcsr=0x%02x\n",
520 adcsr, dacsr, supcsr); */
521 return IRQ_RETVAL(handled);
524 static void dt282x_load_changain(struct comedi_device *dev, int n,
525 unsigned int *chanlist)
527 struct dt282x_private *devpriv = dev->private;
529 unsigned int chan, range;
531 outw(DT2821_LLE | (n - 1), dev->iobase + DT2821_CHANCSR);
532 for (i = 0; i < n; i++) {
533 chan = CR_CHAN(chanlist[i]);
534 range = CR_RANGE(chanlist[i]);
535 outw(devpriv->adcsr | (range << 4) | chan,
536 dev->iobase + DT2821_ADCSR);
538 outw(n - 1, dev->iobase + DT2821_CHANCSR);
542 * Performs a single A/D conversion.
543 * - Put channel/gain into channel-gain list
544 * - preload multiplexer
545 * - trigger conversion and wait for it to finish
547 static int dt282x_ai_insn_read(struct comedi_device *dev,
548 struct comedi_subdevice *s,
549 struct comedi_insn *insn, unsigned int *data)
551 const struct dt282x_board *board = comedi_board(dev);
552 struct dt282x_private *devpriv = dev->private;
555 /* XXX should we really be enabling the ad clock here? */
556 devpriv->adcsr = DT2821_ADCLK;
557 outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR);
559 dt282x_load_changain(dev, 1, &insn->chanspec);
561 outw(devpriv->supcsr | DT2821_PRLD, dev->iobase + DT2821_SUPCSR);
562 wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;);
564 for (i = 0; i < insn->n; i++) {
565 outw(devpriv->supcsr | DT2821_STRIG,
566 dev->iobase + DT2821_SUPCSR);
567 wait_for(ad_done(), comedi_error(dev, "timeout\n");
572 DT2821_ADDAT) & ((1 << board->adbits) - 1);
573 if (devpriv->ad_2scomp)
574 data[i] ^= (1 << (board->adbits - 1));
580 static int dt282x_ai_cmdtest(struct comedi_device *dev,
581 struct comedi_subdevice *s, struct comedi_cmd *cmd)
583 const struct dt282x_board *board = comedi_board(dev);
587 /* Step 1 : check if triggers are trivially valid */
589 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
590 err |= cfc_check_trigger_src(&cmd->scan_begin_src,
591 TRIG_FOLLOW | TRIG_EXT);
592 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
593 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
594 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
599 /* Step 2a : make sure trigger sources are unique */
601 err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
602 err |= cfc_check_trigger_is_unique(cmd->stop_src);
604 /* Step 2b : and mutually compatible */
609 /* Step 3: check if arguments are trivially valid */
611 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
613 if (cmd->scan_begin_src == TRIG_FOLLOW) {
614 /* internal trigger */
615 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
617 /* external trigger */
618 /* should be level/edge, hi/lo specification here */
619 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
622 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 4000);
624 #define SLOWEST_TIMER (250*(1<<15)*255)
625 err |= cfc_check_trigger_arg_max(&cmd->convert_arg, SLOWEST_TIMER);
626 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, board->ai_speed);
627 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
629 if (cmd->stop_src == TRIG_COUNT) {
630 /* any count is allowed */
631 } else { /* TRIG_NONE */
632 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
638 /* step 4: fix up any arguments */
640 tmp = cmd->convert_arg;
641 dt282x_ns_to_timer(&cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK);
642 if (tmp != cmd->convert_arg)
651 static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
653 const struct dt282x_board *board = comedi_board(dev);
654 struct dt282x_private *devpriv = dev->private;
655 struct comedi_cmd *cmd = &s->async->cmd;
658 if (devpriv->usedma == 0) {
660 "driver requires 2 dma channels"
661 " to execute command");
665 dt282x_disable_dma(dev);
667 if (cmd->convert_arg < board->ai_speed)
668 cmd->convert_arg = board->ai_speed;
669 timer = dt282x_ns_to_timer(&cmd->convert_arg, TRIG_ROUND_NEAREST);
670 outw(timer, dev->iobase + DT2821_TMRCTR);
672 if (cmd->scan_begin_src == TRIG_FOLLOW) {
673 /* internal trigger */
674 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0;
676 /* external trigger */
677 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0 | DT2821_DS1;
679 outw(devpriv->supcsr | DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_ADCINIT,
680 dev->iobase + DT2821_SUPCSR);
682 devpriv->ntrig = cmd->stop_arg * cmd->scan_end_arg;
683 devpriv->nread = devpriv->ntrig;
685 devpriv->dma_dir = DMA_MODE_READ;
686 devpriv->current_dma_index = 0;
687 prep_ai_dma(dev, 0, 0);
688 if (devpriv->ntrig) {
689 prep_ai_dma(dev, 1, 0);
690 devpriv->supcsr |= DT2821_DDMA;
691 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR);
696 dt282x_load_changain(dev, cmd->chanlist_len, cmd->chanlist);
698 devpriv->adcsr = DT2821_ADCLK | DT2821_IADDONE;
699 outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR);
701 outw(devpriv->supcsr | DT2821_PRLD, dev->iobase + DT2821_SUPCSR);
702 wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;);
704 if (cmd->scan_begin_src == TRIG_FOLLOW) {
705 outw(devpriv->supcsr | DT2821_STRIG,
706 dev->iobase + DT2821_SUPCSR);
708 devpriv->supcsr |= DT2821_XTRIG;
709 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR);
715 static void dt282x_disable_dma(struct comedi_device *dev)
717 struct dt282x_private *devpriv = dev->private;
719 if (devpriv->usedma) {
720 disable_dma(devpriv->dma[0].chan);
721 disable_dma(devpriv->dma[1].chan);
725 static int dt282x_ai_cancel(struct comedi_device *dev,
726 struct comedi_subdevice *s)
728 struct dt282x_private *devpriv = dev->private;
730 dt282x_disable_dma(dev);
733 outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR);
736 outw(devpriv->supcsr | DT2821_ADCINIT, dev->iobase + DT2821_SUPCSR);
741 static int dt282x_ns_to_timer(int *nanosec, int round_mode)
743 int prescale, base, divider;
745 for (prescale = 0; prescale < 16; prescale++) {
748 base = 250 * (1 << prescale);
749 switch (round_mode) {
750 case TRIG_ROUND_NEAREST:
752 divider = (*nanosec + base / 2) / base;
754 case TRIG_ROUND_DOWN:
755 divider = (*nanosec) / base;
758 divider = (*nanosec + base - 1) / base;
762 *nanosec = divider * base;
763 return (prescale << 8) | (255 - divider);
766 base = 250 * (1 << 15);
768 *nanosec = divider * base;
769 return (15 << 8) | (255 - divider);
773 * Analog output routine. Selects single channel conversion,
774 * selects correct channel, converts from 2's compliment to
775 * offset binary if necessary, loads the data into the DAC
776 * data register, and performs the conversion.
778 static int dt282x_ao_insn_read(struct comedi_device *dev,
779 struct comedi_subdevice *s,
780 struct comedi_insn *insn, unsigned int *data)
782 struct dt282x_private *devpriv = dev->private;
784 data[0] = devpriv->ao[CR_CHAN(insn->chanspec)];
789 static int dt282x_ao_insn_write(struct comedi_device *dev,
790 struct comedi_subdevice *s,
791 struct comedi_insn *insn, unsigned int *data)
793 const struct dt282x_board *board = comedi_board(dev);
794 struct dt282x_private *devpriv = dev->private;
798 chan = CR_CHAN(insn->chanspec);
800 d &= (1 << board->dabits) - 1;
801 devpriv->ao[chan] = d;
803 devpriv->dacsr |= DT2821_SSEL;
807 devpriv->dacsr |= DT2821_YSEL;
808 if (devpriv->da0_2scomp)
809 d ^= (1 << (board->dabits - 1));
811 devpriv->dacsr &= ~DT2821_YSEL;
812 if (devpriv->da1_2scomp)
813 d ^= (1 << (board->dabits - 1));
816 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
818 outw(d, dev->iobase + DT2821_DADAT);
820 outw(devpriv->supcsr | DT2821_DACON, dev->iobase + DT2821_SUPCSR);
825 static int dt282x_ao_cmdtest(struct comedi_device *dev,
826 struct comedi_subdevice *s, struct comedi_cmd *cmd)
831 /* Step 1 : check if triggers are trivially valid */
833 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT);
834 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
835 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
836 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
837 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
842 /* Step 2a : make sure trigger sources are unique */
844 err |= cfc_check_trigger_is_unique(cmd->stop_src);
846 /* Step 2b : and mutually compatible */
851 /* Step 3: check if arguments are trivially valid */
853 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
854 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 5000);
855 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
856 err |= cfc_check_trigger_arg_max(&cmd->scan_end_arg, 2);
858 if (cmd->stop_src == TRIG_COUNT) {
859 /* any count is allowed */
860 } else { /* TRIG_NONE */
861 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
867 /* step 4: fix up any arguments */
869 tmp = cmd->scan_begin_arg;
870 dt282x_ns_to_timer(&cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK);
871 if (tmp != cmd->scan_begin_arg)
881 static int dt282x_ao_inttrig(struct comedi_device *dev,
882 struct comedi_subdevice *s, unsigned int x)
884 struct dt282x_private *devpriv = dev->private;
890 size = cfc_read_array_from_buffer(s, devpriv->dma[0].buf,
891 devpriv->dma_maxsize);
893 printk(KERN_ERR "dt282x: AO underrun\n");
896 prep_ao_dma(dev, 0, size);
898 size = cfc_read_array_from_buffer(s, devpriv->dma[1].buf,
899 devpriv->dma_maxsize);
901 printk(KERN_ERR "dt282x: AO underrun\n");
904 prep_ao_dma(dev, 1, size);
906 outw(devpriv->supcsr | DT2821_STRIG, dev->iobase + DT2821_SUPCSR);
907 s->async->inttrig = NULL;
912 static int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
914 struct dt282x_private *devpriv = dev->private;
916 struct comedi_cmd *cmd = &s->async->cmd;
918 if (devpriv->usedma == 0) {
920 "driver requires 2 dma channels"
921 " to execute command");
925 dt282x_disable_dma(dev);
927 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS1 | DT2821_DDMA;
928 outw(devpriv->supcsr | DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_DACINIT,
929 dev->iobase + DT2821_SUPCSR);
931 devpriv->ntrig = cmd->stop_arg * cmd->chanlist_len;
932 devpriv->nread = devpriv->ntrig;
934 devpriv->dma_dir = DMA_MODE_WRITE;
935 devpriv->current_dma_index = 0;
937 timer = dt282x_ns_to_timer(&cmd->scan_begin_arg, TRIG_ROUND_NEAREST);
938 outw(timer, dev->iobase + DT2821_TMRCTR);
940 devpriv->dacsr = DT2821_SSEL | DT2821_DACLK | DT2821_IDARDY;
941 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
943 s->async->inttrig = dt282x_ao_inttrig;
948 static int dt282x_ao_cancel(struct comedi_device *dev,
949 struct comedi_subdevice *s)
951 struct dt282x_private *devpriv = dev->private;
953 dt282x_disable_dma(dev);
956 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
959 outw(devpriv->supcsr | DT2821_DACINIT, dev->iobase + DT2821_SUPCSR);
964 static int dt282x_dio_insn_bits(struct comedi_device *dev,
965 struct comedi_subdevice *s,
966 struct comedi_insn *insn, unsigned int *data)
969 s->state &= ~data[0];
970 s->state |= (data[0] & data[1]);
972 outw(s->state, dev->iobase + DT2821_DIODAT);
974 data[1] = inw(dev->iobase + DT2821_DIODAT);
979 static int dt282x_dio_insn_config(struct comedi_device *dev,
980 struct comedi_subdevice *s,
981 struct comedi_insn *insn, unsigned int *data)
983 struct dt282x_private *devpriv = dev->private;
986 mask = (CR_CHAN(insn->chanspec) < 8) ? 0x00ff : 0xff00;
992 if (s->io_bits & 0x00ff)
993 devpriv->dacsr |= DT2821_LBOE;
995 devpriv->dacsr &= ~DT2821_LBOE;
996 if (s->io_bits & 0xff00)
997 devpriv->dacsr |= DT2821_HBOE;
999 devpriv->dacsr &= ~DT2821_HBOE;
1001 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
1006 static const struct comedi_lrange *const ai_range_table[] = {
1007 &range_dt282x_ai_lo_bipolar,
1008 &range_dt282x_ai_lo_unipolar,
1009 &range_dt282x_ai_5_bipolar,
1010 &range_dt282x_ai_5_unipolar
1013 static const struct comedi_lrange *const ai_range_pgl_table[] = {
1014 &range_dt282x_ai_hi_bipolar,
1015 &range_dt282x_ai_hi_unipolar
1018 static const struct comedi_lrange *opt_ai_range_lkup(int ispgl, int x)
1021 if (x < 0 || x >= 2)
1023 return ai_range_pgl_table[x];
1025 if (x < 0 || x >= 4)
1027 return ai_range_table[x];
1031 static const struct comedi_lrange *const ao_range_table[] = {
1039 static const struct comedi_lrange *opt_ao_range_lkup(int x)
1041 if (x < 0 || x >= 5)
1043 return ao_range_table[x];
1046 enum { /* i/o base, irq, dma channels */
1047 opt_iobase = 0, opt_irq, opt_dma1, opt_dma2,
1048 opt_diff, /* differential */
1049 opt_ai_twos, opt_ao0_twos, opt_ao1_twos, /* twos comp */
1050 opt_ai_range, opt_ao0_range, opt_ao1_range, /* range */
1053 static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2)
1055 struct dt282x_private *devpriv = dev->private;
1058 devpriv->usedma = 0;
1060 if (!dma1 && !dma2) {
1061 printk(KERN_ERR " (no dma)");
1065 if (dma1 == dma2 || dma1 < 5 || dma2 < 5 || dma1 > 7 || dma2 > 7)
1075 ret = request_dma(dma1, "dt282x A");
1078 devpriv->dma[0].chan = dma1;
1080 ret = request_dma(dma2, "dt282x B");
1083 devpriv->dma[1].chan = dma2;
1085 devpriv->dma_maxsize = PAGE_SIZE;
1086 devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
1087 devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
1088 if (!devpriv->dma[0].buf || !devpriv->dma[1].buf) {
1089 printk(KERN_ERR " can't get DMA memory");
1093 printk(KERN_INFO " (dma=%d,%d)", dma1, dma2);
1095 devpriv->usedma = 1;
1106 4 0=single ended, 1=differential
1107 5 ai 0=straight binary, 1=2's comp
1108 6 ao0 0=straight binary, 1=2's comp
1109 7 ao1 0=straight binary, 1=2's comp
1110 8 ai 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V
1111 9 ao0 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1112 10 ao1 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1114 static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1116 const struct dt282x_board *board = comedi_board(dev);
1117 struct dt282x_private *devpriv;
1120 struct comedi_subdevice *s;
1122 ret = comedi_request_region(dev, it->options[0], DT2821_SIZE);
1126 outw(DT2821_BDINIT, dev->iobase + DT2821_SUPCSR);
1127 i = inw(dev->iobase + DT2821_ADCSR);
1129 printk(KERN_DEBUG " fingerprint=%x,%x,%x,%x,%x",
1130 inw(dev->iobase + DT2821_ADCSR),
1131 inw(dev->iobase + DT2821_CHANCSR),
1132 inw(dev->iobase + DT2821_DACSR),
1133 inw(dev->iobase + DT2821_SUPCSR),
1134 inw(dev->iobase + DT2821_TMRCTR));
1137 if (((inw(dev->iobase + DT2821_ADCSR) & DT2821_ADCSR_MASK)
1138 != DT2821_ADCSR_VAL) ||
1139 ((inw(dev->iobase + DT2821_CHANCSR) & DT2821_CHANCSR_MASK)
1140 != DT2821_CHANCSR_VAL) ||
1141 ((inw(dev->iobase + DT2821_DACSR) & DT2821_DACSR_MASK)
1142 != DT2821_DACSR_VAL) ||
1143 ((inw(dev->iobase + DT2821_SUPCSR) & DT2821_SUPCSR_MASK)
1144 != DT2821_SUPCSR_VAL) ||
1145 ((inw(dev->iobase + DT2821_TMRCTR) & DT2821_TMRCTR_MASK)
1146 != DT2821_TMRCTR_VAL)) {
1147 printk(KERN_ERR " board not found");
1150 /* should do board test */
1152 irq = it->options[opt_irq];
1155 unsigned long flags;
1160 irqs = probe_irq_on();
1162 /* trigger interrupt */
1166 irq = probe_irq_off(irqs);
1167 restore_flags(flags);
1169 printk(KERN_ERR " error probing irq (bad)");
1173 printk(KERN_INFO " ( irq = %d )", irq);
1174 ret = request_irq(irq, dt282x_interrupt, 0,
1175 dev->board_name, dev);
1177 printk(KERN_ERR " failed to get irq\n");
1181 } else if (irq == 0) {
1182 printk(KERN_INFO " (no irq)");
1185 printk(KERN_INFO " (probe returned multiple irqs--bad)");
1187 printk(KERN_INFO " (irq probe not implemented)");
1191 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1195 ret = dt282x_grab_dma(dev, it->options[opt_dma1],
1196 it->options[opt_dma2]);
1200 ret = comedi_alloc_subdevices(dev, 3);
1204 s = &dev->subdevices[0];
1206 dev->read_subdev = s;
1208 s->type = COMEDI_SUBD_AI;
1209 s->subdev_flags = SDF_READABLE | SDF_CMD_READ |
1210 ((it->options[opt_diff]) ? SDF_DIFF : SDF_COMMON);
1212 (it->options[opt_diff]) ? board->adchan_di : board->adchan_se;
1213 s->insn_read = dt282x_ai_insn_read;
1214 s->do_cmdtest = dt282x_ai_cmdtest;
1215 s->do_cmd = dt282x_ai_cmd;
1216 s->cancel = dt282x_ai_cancel;
1217 s->maxdata = (1 << board->adbits) - 1;
1218 s->len_chanlist = 16;
1220 opt_ai_range_lkup(board->ispgl, it->options[opt_ai_range]);
1221 devpriv->ad_2scomp = it->options[opt_ai_twos];
1223 s = &dev->subdevices[1];
1225 s->n_chan = board->dachan;
1228 s->type = COMEDI_SUBD_AO;
1229 dev->write_subdev = s;
1230 s->subdev_flags = SDF_WRITABLE | SDF_CMD_WRITE;
1231 s->insn_read = dt282x_ao_insn_read;
1232 s->insn_write = dt282x_ao_insn_write;
1233 s->do_cmdtest = dt282x_ao_cmdtest;
1234 s->do_cmd = dt282x_ao_cmd;
1235 s->cancel = dt282x_ao_cancel;
1236 s->maxdata = (1 << board->dabits) - 1;
1237 s->len_chanlist = 2;
1238 s->range_table_list = devpriv->darangelist;
1239 devpriv->darangelist[0] =
1240 opt_ao_range_lkup(it->options[opt_ao0_range]);
1241 devpriv->darangelist[1] =
1242 opt_ao_range_lkup(it->options[opt_ao1_range]);
1243 devpriv->da0_2scomp = it->options[opt_ao0_twos];
1244 devpriv->da1_2scomp = it->options[opt_ao1_twos];
1246 s->type = COMEDI_SUBD_UNUSED;
1249 s = &dev->subdevices[2];
1251 s->type = COMEDI_SUBD_DIO;
1252 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1254 s->insn_bits = dt282x_dio_insn_bits;
1255 s->insn_config = dt282x_dio_insn_config;
1257 s->range_table = &range_digital;
1259 printk(KERN_INFO "\n");
1264 static void dt282x_detach(struct comedi_device *dev)
1266 struct dt282x_private *devpriv = dev->private;
1269 if (devpriv->dma[0].chan)
1270 free_dma(devpriv->dma[0].chan);
1271 if (devpriv->dma[1].chan)
1272 free_dma(devpriv->dma[1].chan);
1273 if (devpriv->dma[0].buf)
1274 free_page((unsigned long)devpriv->dma[0].buf);
1275 if (devpriv->dma[1].buf)
1276 free_page((unsigned long)devpriv->dma[1].buf);
1278 comedi_legacy_detach(dev);
1281 static const struct dt282x_board boardtypes[] = {
1319 .name = "dt2824-pgh",
1328 .name = "dt2824-pgl",
1400 .name = "dt24-ez-pgl",
1411 static struct comedi_driver dt282x_driver = {
1412 .driver_name = "dt282x",
1413 .module = THIS_MODULE,
1414 .attach = dt282x_attach,
1415 .detach = dt282x_detach,
1416 .board_name = &boardtypes[0].name,
1417 .num_names = ARRAY_SIZE(boardtypes),
1418 .offset = sizeof(struct dt282x_board),
1420 module_comedi_driver(dt282x_driver);
1422 MODULE_AUTHOR("Comedi http://www.comedi.org");
1423 MODULE_DESCRIPTION("Comedi low-level driver");
1424 MODULE_LICENSE("GPL");