2 comedi/drivers/dt282x.c
3 Hardware driver for Data Translation DT2821 series
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 1997-8 David A. Schleef <ds@schleef.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 Description: Data Translation DT2821 series (including DT-EZ)
27 Devices: [Data Translation] DT2821 (dt2821),
28 DT2821-F-16SE (dt2821-f), DT2821-F-8DI (dt2821-f),
29 DT2821-G-16SE (dt2821-f), DT2821-G-8DI (dt2821-g),
31 DT2824-PGH (dt2824-pgh), DT2824-PGL (dt2824-pgl), DT2825 (dt2825),
32 DT2827 (dt2827), DT2828 (dt2828), DT21-EZ (dt21-ez), DT23-EZ (dt23-ez),
33 DT24-EZ (dt24-ez), DT24-EZ-PGL (dt24-ez-pgl)
35 Updated: Wed, 22 Aug 2001 17:11:34 -0700
37 Configuration options:
38 [0] - I/O port base address
42 [4] - AI jumpered for 0=single ended, 1=differential
43 [5] - AI jumpered for 0=straight binary, 1=2's complement
44 [6] - AO 0 jumpered for 0=straight binary, 1=2's complement
45 [7] - AO 1 jumpered for 0=straight binary, 1=2's complement
46 [8] - AI jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5]
47 [9] - AO 0 jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5],
49 [10]- A0 1 jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5],
53 - AO commands might be broken.
54 - If you try to run a command on both the AI and AO subdevices
55 simultaneously, bad things will happen. The driver needs to
56 be fixed to check for this situation and return an error.
59 #include "../comedidev.h"
61 #include <linux/gfp.h>
62 #include <linux/ioport.h>
63 #include <linux/interrupt.h>
66 #include "comedi_fc.h"
70 #define DT2821_TIMEOUT 100 /* 500 us */
71 #define DT2821_SIZE 0x10
74 * Registers in the DT282x
77 #define DT2821_ADCSR 0x00 /* A/D Control/Status */
78 #define DT2821_CHANCSR 0x02 /* Channel Control/Status */
79 #define DT2821_ADDAT 0x04 /* A/D data */
80 #define DT2821_DACSR 0x06 /* D/A Control/Status */
81 #define DT2821_DADAT 0x08 /* D/A data */
82 #define DT2821_DIODAT 0x0a /* digital data */
83 #define DT2821_SUPCSR 0x0c /* Supervisor Control/Status */
84 #define DT2821_TMRCTR 0x0e /* Timer/Counter */
87 * At power up, some registers are in a well-known state. The
88 * masks and values are as follows:
91 #define DT2821_ADCSR_MASK 0xfff0
92 #define DT2821_ADCSR_VAL 0x7c00
94 #define DT2821_CHANCSR_MASK 0xf0f0
95 #define DT2821_CHANCSR_VAL 0x70f0
97 #define DT2821_DACSR_MASK 0x7c93
98 #define DT2821_DACSR_VAL 0x7c90
100 #define DT2821_SUPCSR_MASK 0xf8ff
101 #define DT2821_SUPCSR_VAL 0x0000
103 #define DT2821_TMRCTR_MASK 0xff00
104 #define DT2821_TMRCTR_VAL 0xf000
107 * Bit fields of each register
112 #define DT2821_ADERR 0x8000 /* (R) 1 for A/D error */
113 #define DT2821_ADCLK 0x0200 /* (R/W) A/D clock enable */
114 /* 0x7c00 read as 1's */
115 #define DT2821_MUXBUSY 0x0100 /* (R) multiplexer busy */
116 #define DT2821_ADDONE 0x0080 /* (R) A/D done */
117 #define DT2821_IADDONE 0x0040 /* (R/W) interrupt on A/D done */
118 /* 0x0030 gain select */
119 /* 0x000f channel select */
123 #define DT2821_LLE 0x8000 /* (R/W) Load List Enable */
124 /* 0x7000 read as 1's */
125 /* 0x0f00 (R) present address */
126 /* 0x00f0 read as 1's */
127 /* 0x000f (R) number of entries - 1 */
131 #define DT2821_DAERR 0x8000 /* (R) D/A error */
132 #define DT2821_YSEL 0x0200 /* (R/W) DAC 1 select */
133 #define DT2821_SSEL 0x0100 /* (R/W) single channel select */
134 #define DT2821_DACRDY 0x0080 /* (R) DAC ready */
135 #define DT2821_IDARDY 0x0040 /* (R/W) interrupt on DAC ready */
136 #define DT2821_DACLK 0x0020 /* (R/W) D/A clock enable */
137 #define DT2821_HBOE 0x0002 /* (R/W) DIO high byte output enable */
138 #define DT2821_LBOE 0x0001 /* (R/W) DIO low byte output enable */
142 #define DT2821_DMAD 0x8000 /* (R) DMA done */
143 #define DT2821_ERRINTEN 0x4000 /* (R/W) interrupt on error */
144 #define DT2821_CLRDMADNE 0x2000 /* (W) clear DMA done */
145 #define DT2821_DDMA 0x1000 /* (R/W) dual DMA */
146 #define DT2821_DS1 0x0800 /* (R/W) DMA select 1 */
147 #define DT2821_DS0 0x0400 /* (R/W) DMA select 0 */
148 #define DT2821_BUFFB 0x0200 /* (R/W) buffer B selected */
149 #define DT2821_SCDN 0x0100 /* (R) scan done */
150 #define DT2821_DACON 0x0080 /* (W) DAC single conversion */
151 #define DT2821_ADCINIT 0x0040 /* (W) A/D initialize */
152 #define DT2821_DACINIT 0x0020 /* (W) D/A initialize */
153 #define DT2821_PRLD 0x0010 /* (W) preload multiplexer */
154 #define DT2821_STRIG 0x0008 /* (W) software trigger */
155 #define DT2821_XTRIG 0x0004 /* (R/W) external trigger enable */
156 #define DT2821_XCLK 0x0002 /* (R/W) external clock enable */
157 #define DT2821_BDINIT 0x0001 /* (W) initialize board */
159 static const struct comedi_lrange range_dt282x_ai_lo_bipolar
= {
168 static const struct comedi_lrange range_dt282x_ai_lo_unipolar
= {
177 static const struct comedi_lrange range_dt282x_ai_5_bipolar
= {
186 static const struct comedi_lrange range_dt282x_ai_5_unipolar
= {
195 static const struct comedi_lrange range_dt282x_ai_hi_bipolar
= {
204 static const struct comedi_lrange range_dt282x_ai_hi_unipolar
= {
213 struct dt282x_board
{
224 struct dt282x_private
{
225 int ad_2scomp
; /* we have 2's comp jumper set */
226 int da0_2scomp
; /* same, for DAC0 */
227 int da1_2scomp
; /* same, for DAC1 */
229 const struct comedi_lrange
*darangelist
[2];
233 volatile int dacsr
; /* software copies of registers */
242 short *buf
; /* DMA buffer */
243 volatile int size
; /* size of current transfer */
245 int dma_maxsize
; /* max size of DMA transfer (in bytes) */
246 int usedma
; /* driver uses DMA */
247 volatile int current_dma_index
;
251 #define devpriv ((struct dt282x_private *)dev->private)
252 #define boardtype (*(const struct dt282x_board *)dev->board_ptr)
255 * Some useless abstractions
257 #define chan_to_DAC(a) ((a)&1)
258 #define mux_busy() (inw(dev->iobase+DT2821_ADCSR)&DT2821_MUXBUSY)
259 #define ad_done() (inw(dev->iobase+DT2821_ADCSR)&DT2821_ADDONE)
262 * danger! macro abuse... a is the expression to wait on, and b is
263 * the statement(s) to execute if it doesn't happen.
265 #define wait_for(a, b) \
268 for (_i = 0; _i < DT2821_TIMEOUT; _i++) { \
279 static int prep_ai_dma(struct comedi_device
*dev
, int chan
, int size
);
280 static int prep_ao_dma(struct comedi_device
*dev
, int chan
, int size
);
281 static int dt282x_ai_cancel(struct comedi_device
*dev
,
282 struct comedi_subdevice
*s
);
283 static int dt282x_ao_cancel(struct comedi_device
*dev
,
284 struct comedi_subdevice
*s
);
285 static int dt282x_ns_to_timer(int *nanosec
, int round_mode
);
286 static void dt282x_disable_dma(struct comedi_device
*dev
);
288 static int dt282x_grab_dma(struct comedi_device
*dev
, int dma1
, int dma2
);
290 static void dt282x_munge(struct comedi_device
*dev
, short *buf
,
294 unsigned short mask
= (1 << boardtype
.adbits
) - 1;
295 unsigned short sign
= 1 << (boardtype
.adbits
- 1);
298 if (devpriv
->ad_2scomp
)
299 sign
= 1 << (boardtype
.adbits
- 1);
304 comedi_error(dev
, "bug! odd number of bytes from dma xfer");
306 for (i
= 0; i
< n
; i
++)
307 buf
[i
] = (buf
[i
] & mask
) ^ sign
;
310 static void dt282x_ao_dma_interrupt(struct comedi_device
*dev
)
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
)
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
)
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
)
428 unsigned long dma_ptr
;
431 devpriv
->dma
[dma_index
].size
= n
;
432 dma_chan
= devpriv
->dma
[dma_index
].chan
;
433 dma_ptr
= virt_to_bus(devpriv
->dma
[dma_index
].buf
);
435 set_dma_mode(dma_chan
, DMA_MODE_WRITE
);
436 flags
= claim_dma_lock();
437 clear_dma_ff(dma_chan
);
438 set_dma_addr(dma_chan
, dma_ptr
);
439 set_dma_count(dma_chan
, n
);
440 release_dma_lock(flags
);
442 enable_dma(dma_chan
);
447 static irqreturn_t
dt282x_interrupt(int irq
, void *d
)
449 struct comedi_device
*dev
= d
;
450 struct comedi_subdevice
*s
;
451 struct comedi_subdevice
*s_ao
;
452 unsigned int supcsr
, adcsr
, dacsr
;
455 if (!dev
->attached
) {
456 comedi_error(dev
, "spurious interrupt");
460 s
= &dev
->subdevices
[0];
461 s_ao
= &dev
->subdevices
[1];
462 adcsr
= inw(dev
->iobase
+ DT2821_ADCSR
);
463 dacsr
= inw(dev
->iobase
+ DT2821_DACSR
);
464 supcsr
= inw(dev
->iobase
+ DT2821_SUPCSR
);
465 if (supcsr
& DT2821_DMAD
) {
466 if (devpriv
->dma_dir
== DMA_MODE_READ
)
467 dt282x_ai_dma_interrupt(dev
);
469 dt282x_ao_dma_interrupt(dev
);
472 if (adcsr
& DT2821_ADERR
) {
473 if (devpriv
->nread
!= 0) {
474 comedi_error(dev
, "A/D error");
475 dt282x_ai_cancel(dev
, s
);
476 s
->async
->events
|= COMEDI_CB_ERROR
;
480 if (dacsr
& DT2821_DAERR
) {
484 disable_irq(dev
->irq
);
485 printk(KERN_INFO
"disabling irq\n");
488 comedi_error(dev
, "D/A error");
489 dt282x_ao_cancel(dev
, s_ao
);
490 s
->async
->events
|= COMEDI_CB_ERROR
;
494 if (adcsr
& DT2821_ADDONE
) {
498 data
= (short)inw(dev
->iobase
+ DT2821_ADDAT
);
499 data
&= (1 << boardtype
.adbits
) - 1;
501 if (devpriv
->ad_2scomp
)
502 data
^= 1 << (boardtype
.adbits
- 1);
503 ret
= comedi_buf_put(s
->async
, data
);
506 s
->async
->events
|= COMEDI_CB_OVERFLOW
;
509 if (!devpriv
->nread
) {
510 s
->async
->events
|= COMEDI_CB_EOA
;
512 if (supcsr
& DT2821_SCDN
)
513 outw(devpriv
->supcsr
| DT2821_STRIG
,
514 dev
->iobase
+ DT2821_SUPCSR
);
519 comedi_event(dev
, s
);
520 /* printk("adcsr=0x%02x dacsr-0x%02x supcsr=0x%02x\n",
521 adcsr, dacsr, supcsr); */
522 return IRQ_RETVAL(handled
);
525 static void dt282x_load_changain(struct comedi_device
*dev
, int n
,
526 unsigned int *chanlist
)
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
)
553 /* XXX should we really be enabling the ad clock here? */
554 devpriv
->adcsr
= DT2821_ADCLK
;
555 outw(devpriv
->adcsr
, dev
->iobase
+ DT2821_ADCSR
);
557 dt282x_load_changain(dev
, 1, &insn
->chanspec
);
559 outw(devpriv
->supcsr
| DT2821_PRLD
, dev
->iobase
+ DT2821_SUPCSR
);
560 wait_for(!mux_busy(), comedi_error(dev
, "timeout\n"); return -ETIME
;);
562 for (i
= 0; i
< insn
->n
; i
++) {
563 outw(devpriv
->supcsr
| DT2821_STRIG
,
564 dev
->iobase
+ DT2821_SUPCSR
);
565 wait_for(ad_done(), comedi_error(dev
, "timeout\n");
570 DT2821_ADDAT
) & ((1 << boardtype
.adbits
) - 1);
571 if (devpriv
->ad_2scomp
)
572 data
[i
] ^= (1 << (boardtype
.adbits
- 1));
578 static int dt282x_ai_cmdtest(struct comedi_device
*dev
,
579 struct comedi_subdevice
*s
, struct comedi_cmd
*cmd
)
581 const struct dt282x_board
*board
= comedi_board(dev
);
585 /* Step 1 : check if triggers are trivially valid */
587 err
|= cfc_check_trigger_src(&cmd
->start_src
, TRIG_NOW
);
588 err
|= cfc_check_trigger_src(&cmd
->scan_begin_src
,
589 TRIG_FOLLOW
| TRIG_EXT
);
590 err
|= cfc_check_trigger_src(&cmd
->convert_src
, TRIG_TIMER
);
591 err
|= cfc_check_trigger_src(&cmd
->scan_end_src
, TRIG_COUNT
);
592 err
|= cfc_check_trigger_src(&cmd
->stop_src
, TRIG_COUNT
| TRIG_NONE
);
597 /* Step 2a : make sure trigger sources are unique */
599 err
|= cfc_check_trigger_is_unique(cmd
->scan_begin_src
);
600 err
|= cfc_check_trigger_is_unique(cmd
->stop_src
);
602 /* Step 2b : and mutually compatible */
607 /* step 3: make sure arguments are trivially compatible */
609 if (cmd
->start_arg
!= 0) {
613 if (cmd
->scan_begin_src
== TRIG_FOLLOW
) {
614 /* internal trigger */
615 if (cmd
->scan_begin_arg
!= 0) {
616 cmd
->scan_begin_arg
= 0;
620 /* external trigger */
621 /* should be level/edge, hi/lo specification here */
622 if (cmd
->scan_begin_arg
!= 0) {
623 cmd
->scan_begin_arg
= 0;
627 if (cmd
->convert_arg
< 4000) {
628 /* XXX board dependent */
629 cmd
->convert_arg
= 4000;
632 #define SLOWEST_TIMER (250*(1<<15)*255)
633 if (cmd
->convert_arg
> SLOWEST_TIMER
) {
634 cmd
->convert_arg
= SLOWEST_TIMER
;
637 if (cmd
->convert_arg
< board
->ai_speed
) {
638 cmd
->convert_arg
= board
->ai_speed
;
641 if (cmd
->scan_end_arg
!= cmd
->chanlist_len
) {
642 cmd
->scan_end_arg
= cmd
->chanlist_len
;
645 if (cmd
->stop_src
== TRIG_COUNT
) {
646 /* any count is allowed */
649 if (cmd
->stop_arg
!= 0) {
658 /* step 4: fix up any arguments */
660 tmp
= cmd
->convert_arg
;
661 dt282x_ns_to_timer(&cmd
->convert_arg
, cmd
->flags
& TRIG_ROUND_MASK
);
662 if (tmp
!= cmd
->convert_arg
)
671 static int dt282x_ai_cmd(struct comedi_device
*dev
, struct comedi_subdevice
*s
)
673 const struct dt282x_board
*board
= comedi_board(dev
);
674 struct comedi_cmd
*cmd
= &s
->async
->cmd
;
677 if (devpriv
->usedma
== 0) {
679 "driver requires 2 dma channels"
680 " to execute command");
684 dt282x_disable_dma(dev
);
686 if (cmd
->convert_arg
< board
->ai_speed
)
687 cmd
->convert_arg
= board
->ai_speed
;
688 timer
= dt282x_ns_to_timer(&cmd
->convert_arg
, TRIG_ROUND_NEAREST
);
689 outw(timer
, dev
->iobase
+ DT2821_TMRCTR
);
691 if (cmd
->scan_begin_src
== TRIG_FOLLOW
) {
692 /* internal trigger */
693 devpriv
->supcsr
= DT2821_ERRINTEN
| DT2821_DS0
;
695 /* external trigger */
696 devpriv
->supcsr
= DT2821_ERRINTEN
| DT2821_DS0
| DT2821_DS1
;
698 outw(devpriv
->supcsr
| DT2821_CLRDMADNE
| DT2821_BUFFB
| DT2821_ADCINIT
,
699 dev
->iobase
+ DT2821_SUPCSR
);
701 devpriv
->ntrig
= cmd
->stop_arg
* cmd
->scan_end_arg
;
702 devpriv
->nread
= devpriv
->ntrig
;
704 devpriv
->dma_dir
= DMA_MODE_READ
;
705 devpriv
->current_dma_index
= 0;
706 prep_ai_dma(dev
, 0, 0);
707 if (devpriv
->ntrig
) {
708 prep_ai_dma(dev
, 1, 0);
709 devpriv
->supcsr
|= DT2821_DDMA
;
710 outw(devpriv
->supcsr
, dev
->iobase
+ DT2821_SUPCSR
);
715 dt282x_load_changain(dev
, cmd
->chanlist_len
, cmd
->chanlist
);
717 devpriv
->adcsr
= DT2821_ADCLK
| DT2821_IADDONE
;
718 outw(devpriv
->adcsr
, dev
->iobase
+ DT2821_ADCSR
);
720 outw(devpriv
->supcsr
| DT2821_PRLD
, dev
->iobase
+ DT2821_SUPCSR
);
721 wait_for(!mux_busy(), comedi_error(dev
, "timeout\n"); return -ETIME
;);
723 if (cmd
->scan_begin_src
== TRIG_FOLLOW
) {
724 outw(devpriv
->supcsr
| DT2821_STRIG
,
725 dev
->iobase
+ DT2821_SUPCSR
);
727 devpriv
->supcsr
|= DT2821_XTRIG
;
728 outw(devpriv
->supcsr
, dev
->iobase
+ DT2821_SUPCSR
);
734 static void dt282x_disable_dma(struct comedi_device
*dev
)
736 if (devpriv
->usedma
) {
737 disable_dma(devpriv
->dma
[0].chan
);
738 disable_dma(devpriv
->dma
[1].chan
);
742 static int dt282x_ai_cancel(struct comedi_device
*dev
,
743 struct comedi_subdevice
*s
)
745 dt282x_disable_dma(dev
);
748 outw(devpriv
->adcsr
, dev
->iobase
+ DT2821_ADCSR
);
751 outw(devpriv
->supcsr
| DT2821_ADCINIT
, dev
->iobase
+ DT2821_SUPCSR
);
756 static int dt282x_ns_to_timer(int *nanosec
, int round_mode
)
758 int prescale
, base
, divider
;
760 for (prescale
= 0; prescale
< 16; prescale
++) {
763 base
= 250 * (1 << prescale
);
764 switch (round_mode
) {
765 case TRIG_ROUND_NEAREST
:
767 divider
= (*nanosec
+ base
/ 2) / base
;
769 case TRIG_ROUND_DOWN
:
770 divider
= (*nanosec
) / base
;
773 divider
= (*nanosec
+ base
- 1) / base
;
777 *nanosec
= divider
* base
;
778 return (prescale
<< 8) | (255 - divider
);
781 base
= 250 * (1 << 15);
783 *nanosec
= divider
* base
;
784 return (15 << 8) | (255 - divider
);
788 * Analog output routine. Selects single channel conversion,
789 * selects correct channel, converts from 2's compliment to
790 * offset binary if necessary, loads the data into the DAC
791 * data register, and performs the conversion.
793 static int dt282x_ao_insn_read(struct comedi_device
*dev
,
794 struct comedi_subdevice
*s
,
795 struct comedi_insn
*insn
, unsigned int *data
)
797 data
[0] = devpriv
->ao
[CR_CHAN(insn
->chanspec
)];
802 static int dt282x_ao_insn_write(struct comedi_device
*dev
,
803 struct comedi_subdevice
*s
,
804 struct comedi_insn
*insn
, unsigned int *data
)
809 chan
= CR_CHAN(insn
->chanspec
);
811 d
&= (1 << boardtype
.dabits
) - 1;
812 devpriv
->ao
[chan
] = d
;
814 devpriv
->dacsr
|= DT2821_SSEL
;
818 devpriv
->dacsr
|= DT2821_YSEL
;
819 if (devpriv
->da0_2scomp
)
820 d
^= (1 << (boardtype
.dabits
- 1));
822 devpriv
->dacsr
&= ~DT2821_YSEL
;
823 if (devpriv
->da1_2scomp
)
824 d
^= (1 << (boardtype
.dabits
- 1));
827 outw(devpriv
->dacsr
, dev
->iobase
+ DT2821_DACSR
);
829 outw(d
, dev
->iobase
+ DT2821_DADAT
);
831 outw(devpriv
->supcsr
| DT2821_DACON
, dev
->iobase
+ DT2821_SUPCSR
);
836 static int dt282x_ao_cmdtest(struct comedi_device
*dev
,
837 struct comedi_subdevice
*s
, struct comedi_cmd
*cmd
)
842 /* Step 1 : check if triggers are trivially valid */
844 err
|= cfc_check_trigger_src(&cmd
->start_src
, TRIG_INT
);
845 err
|= cfc_check_trigger_src(&cmd
->scan_begin_src
, TRIG_TIMER
);
846 err
|= cfc_check_trigger_src(&cmd
->convert_src
, TRIG_NOW
);
847 err
|= cfc_check_trigger_src(&cmd
->scan_end_src
, TRIG_COUNT
);
848 err
|= cfc_check_trigger_src(&cmd
->stop_src
, TRIG_COUNT
| TRIG_NONE
);
853 /* Step 2a : make sure trigger sources are unique */
855 err
|= cfc_check_trigger_is_unique(cmd
->stop_src
);
857 /* Step 2b : and mutually compatible */
862 /* step 3: make sure arguments are trivially compatible */
864 if (cmd
->start_arg
!= 0) {
868 if (cmd
->scan_begin_arg
< 5000 /* XXX unknown */) {
869 cmd
->scan_begin_arg
= 5000;
872 if (cmd
->convert_arg
!= 0) {
873 cmd
->convert_arg
= 0;
876 if (cmd
->scan_end_arg
> 2) {
877 /* XXX chanlist stuff? */
878 cmd
->scan_end_arg
= 2;
881 if (cmd
->stop_src
== TRIG_COUNT
) {
882 /* any count is allowed */
885 if (cmd
->stop_arg
!= 0) {
894 /* step 4: fix up any arguments */
896 tmp
= cmd
->scan_begin_arg
;
897 dt282x_ns_to_timer(&cmd
->scan_begin_arg
, cmd
->flags
& TRIG_ROUND_MASK
);
898 if (tmp
!= cmd
->scan_begin_arg
)
908 static int dt282x_ao_inttrig(struct comedi_device
*dev
,
909 struct comedi_subdevice
*s
, unsigned int x
)
916 size
= cfc_read_array_from_buffer(s
, devpriv
->dma
[0].buf
,
917 devpriv
->dma_maxsize
);
919 printk(KERN_ERR
"dt282x: AO underrun\n");
922 prep_ao_dma(dev
, 0, size
);
924 size
= cfc_read_array_from_buffer(s
, devpriv
->dma
[1].buf
,
925 devpriv
->dma_maxsize
);
927 printk(KERN_ERR
"dt282x: AO underrun\n");
930 prep_ao_dma(dev
, 1, size
);
932 outw(devpriv
->supcsr
| DT2821_STRIG
, dev
->iobase
+ DT2821_SUPCSR
);
933 s
->async
->inttrig
= NULL
;
938 static int dt282x_ao_cmd(struct comedi_device
*dev
, struct comedi_subdevice
*s
)
941 struct comedi_cmd
*cmd
= &s
->async
->cmd
;
943 if (devpriv
->usedma
== 0) {
945 "driver requires 2 dma channels"
946 " to execute command");
950 dt282x_disable_dma(dev
);
952 devpriv
->supcsr
= DT2821_ERRINTEN
| DT2821_DS1
| DT2821_DDMA
;
953 outw(devpriv
->supcsr
| DT2821_CLRDMADNE
| DT2821_BUFFB
| DT2821_DACINIT
,
954 dev
->iobase
+ DT2821_SUPCSR
);
956 devpriv
->ntrig
= cmd
->stop_arg
* cmd
->chanlist_len
;
957 devpriv
->nread
= devpriv
->ntrig
;
959 devpriv
->dma_dir
= DMA_MODE_WRITE
;
960 devpriv
->current_dma_index
= 0;
962 timer
= dt282x_ns_to_timer(&cmd
->scan_begin_arg
, TRIG_ROUND_NEAREST
);
963 outw(timer
, dev
->iobase
+ DT2821_TMRCTR
);
965 devpriv
->dacsr
= DT2821_SSEL
| DT2821_DACLK
| DT2821_IDARDY
;
966 outw(devpriv
->dacsr
, dev
->iobase
+ DT2821_DACSR
);
968 s
->async
->inttrig
= dt282x_ao_inttrig
;
973 static int dt282x_ao_cancel(struct comedi_device
*dev
,
974 struct comedi_subdevice
*s
)
976 dt282x_disable_dma(dev
);
979 outw(devpriv
->dacsr
, dev
->iobase
+ DT2821_DACSR
);
982 outw(devpriv
->supcsr
| DT2821_DACINIT
, dev
->iobase
+ DT2821_SUPCSR
);
987 static int dt282x_dio_insn_bits(struct comedi_device
*dev
,
988 struct comedi_subdevice
*s
,
989 struct comedi_insn
*insn
, unsigned int *data
)
992 s
->state
&= ~data
[0];
993 s
->state
|= (data
[0] & data
[1]);
995 outw(s
->state
, dev
->iobase
+ DT2821_DIODAT
);
997 data
[1] = inw(dev
->iobase
+ DT2821_DIODAT
);
1002 static int dt282x_dio_insn_config(struct comedi_device
*dev
,
1003 struct comedi_subdevice
*s
,
1004 struct comedi_insn
*insn
, unsigned int *data
)
1008 mask
= (CR_CHAN(insn
->chanspec
) < 8) ? 0x00ff : 0xff00;
1012 s
->io_bits
&= ~mask
;
1014 if (s
->io_bits
& 0x00ff)
1015 devpriv
->dacsr
|= DT2821_LBOE
;
1017 devpriv
->dacsr
&= ~DT2821_LBOE
;
1018 if (s
->io_bits
& 0xff00)
1019 devpriv
->dacsr
|= DT2821_HBOE
;
1021 devpriv
->dacsr
&= ~DT2821_HBOE
;
1023 outw(devpriv
->dacsr
, dev
->iobase
+ DT2821_DACSR
);
1028 static const struct comedi_lrange
*const ai_range_table
[] = {
1029 &range_dt282x_ai_lo_bipolar
,
1030 &range_dt282x_ai_lo_unipolar
,
1031 &range_dt282x_ai_5_bipolar
,
1032 &range_dt282x_ai_5_unipolar
1035 static const struct comedi_lrange
*const ai_range_pgl_table
[] = {
1036 &range_dt282x_ai_hi_bipolar
,
1037 &range_dt282x_ai_hi_unipolar
1040 static const struct comedi_lrange
*opt_ai_range_lkup(int ispgl
, int x
)
1043 if (x
< 0 || x
>= 2)
1045 return ai_range_pgl_table
[x
];
1047 if (x
< 0 || x
>= 4)
1049 return ai_range_table
[x
];
1053 static const struct comedi_lrange
*const ao_range_table
[] = {
1061 static const struct comedi_lrange
*opt_ao_range_lkup(int x
)
1063 if (x
< 0 || x
>= 5)
1065 return ao_range_table
[x
];
1068 enum { /* i/o base, irq, dma channels */
1069 opt_iobase
= 0, opt_irq
, opt_dma1
, opt_dma2
,
1070 opt_diff
, /* differential */
1071 opt_ai_twos
, opt_ao0_twos
, opt_ao1_twos
, /* twos comp */
1072 opt_ai_range
, opt_ao0_range
, opt_ao1_range
, /* range */
1075 static int dt282x_grab_dma(struct comedi_device
*dev
, int dma1
, int dma2
)
1079 devpriv
->usedma
= 0;
1081 if (!dma1
&& !dma2
) {
1082 printk(KERN_ERR
" (no dma)");
1086 if (dma1
== dma2
|| dma1
< 5 || dma2
< 5 || dma1
> 7 || dma2
> 7)
1096 ret
= request_dma(dma1
, "dt282x A");
1099 devpriv
->dma
[0].chan
= dma1
;
1101 ret
= request_dma(dma2
, "dt282x B");
1104 devpriv
->dma
[1].chan
= dma2
;
1106 devpriv
->dma_maxsize
= PAGE_SIZE
;
1107 devpriv
->dma
[0].buf
= (void *)__get_free_page(GFP_KERNEL
| GFP_DMA
);
1108 devpriv
->dma
[1].buf
= (void *)__get_free_page(GFP_KERNEL
| GFP_DMA
);
1109 if (!devpriv
->dma
[0].buf
|| !devpriv
->dma
[1].buf
) {
1110 printk(KERN_ERR
" can't get DMA memory");
1114 printk(KERN_INFO
" (dma=%d,%d)", dma1
, dma2
);
1116 devpriv
->usedma
= 1;
1127 4 0=single ended, 1=differential
1128 5 ai 0=straight binary, 1=2's comp
1129 6 ao0 0=straight binary, 1=2's comp
1130 7 ao1 0=straight binary, 1=2's comp
1131 8 ai 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V
1132 9 ao0 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1133 10 ao1 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V
1135 static int dt282x_attach(struct comedi_device
*dev
, struct comedi_devconfig
*it
)
1137 const struct dt282x_board
*board
= comedi_board(dev
);
1140 struct comedi_subdevice
*s
;
1141 unsigned long iobase
;
1143 dev
->board_name
= board
->name
;
1145 iobase
= it
->options
[opt_iobase
];
1149 printk(KERN_INFO
"comedi%d: dt282x: 0x%04lx", dev
->minor
, iobase
);
1150 if (!request_region(iobase
, DT2821_SIZE
, "dt282x")) {
1151 printk(KERN_INFO
" I/O port conflict\n");
1154 dev
->iobase
= iobase
;
1156 outw(DT2821_BDINIT
, dev
->iobase
+ DT2821_SUPCSR
);
1157 i
= inw(dev
->iobase
+ DT2821_ADCSR
);
1159 printk(KERN_DEBUG
" fingerprint=%x,%x,%x,%x,%x",
1160 inw(dev
->iobase
+ DT2821_ADCSR
),
1161 inw(dev
->iobase
+ DT2821_CHANCSR
),
1162 inw(dev
->iobase
+ DT2821_DACSR
),
1163 inw(dev
->iobase
+ DT2821_SUPCSR
),
1164 inw(dev
->iobase
+ DT2821_TMRCTR
));
1167 if (((inw(dev
->iobase
+ DT2821_ADCSR
) & DT2821_ADCSR_MASK
)
1168 != DT2821_ADCSR_VAL
) ||
1169 ((inw(dev
->iobase
+ DT2821_CHANCSR
) & DT2821_CHANCSR_MASK
)
1170 != DT2821_CHANCSR_VAL
) ||
1171 ((inw(dev
->iobase
+ DT2821_DACSR
) & DT2821_DACSR_MASK
)
1172 != DT2821_DACSR_VAL
) ||
1173 ((inw(dev
->iobase
+ DT2821_SUPCSR
) & DT2821_SUPCSR_MASK
)
1174 != DT2821_SUPCSR_VAL
) ||
1175 ((inw(dev
->iobase
+ DT2821_TMRCTR
) & DT2821_TMRCTR_MASK
)
1176 != DT2821_TMRCTR_VAL
)) {
1177 printk(KERN_ERR
" board not found");
1180 /* should do board test */
1182 irq
= it
->options
[opt_irq
];
1185 unsigned long flags
;
1190 irqs
= probe_irq_on();
1192 /* trigger interrupt */
1196 irq
= probe_irq_off(irqs
);
1197 restore_flags(flags
);
1199 printk(KERN_ERR
" error probing irq (bad)");
1203 printk(KERN_INFO
" ( irq = %d )", irq
);
1204 ret
= request_irq(irq
, dt282x_interrupt
, 0, "dt282x", dev
);
1206 printk(KERN_ERR
" failed to get irq\n");
1210 } else if (irq
== 0) {
1211 printk(KERN_INFO
" (no irq)");
1214 printk(KERN_INFO
" (probe returned multiple irqs--bad)");
1216 printk(KERN_INFO
" (irq probe not implemented)");
1220 ret
= alloc_private(dev
, sizeof(struct dt282x_private
));
1224 ret
= dt282x_grab_dma(dev
, it
->options
[opt_dma1
],
1225 it
->options
[opt_dma2
]);
1229 ret
= comedi_alloc_subdevices(dev
, 3);
1233 s
= &dev
->subdevices
[0];
1235 dev
->read_subdev
= s
;
1237 s
->type
= COMEDI_SUBD_AI
;
1238 s
->subdev_flags
= SDF_READABLE
| SDF_CMD_READ
|
1239 ((it
->options
[opt_diff
]) ? SDF_DIFF
: SDF_COMMON
);
1241 (it
->options
[opt_diff
]) ? boardtype
.adchan_di
: boardtype
.adchan_se
;
1242 s
->insn_read
= dt282x_ai_insn_read
;
1243 s
->do_cmdtest
= dt282x_ai_cmdtest
;
1244 s
->do_cmd
= dt282x_ai_cmd
;
1245 s
->cancel
= dt282x_ai_cancel
;
1246 s
->maxdata
= (1 << boardtype
.adbits
) - 1;
1247 s
->len_chanlist
= 16;
1249 opt_ai_range_lkup(boardtype
.ispgl
, it
->options
[opt_ai_range
]);
1250 devpriv
->ad_2scomp
= it
->options
[opt_ai_twos
];
1252 s
= &dev
->subdevices
[1];
1254 s
->n_chan
= boardtype
.dachan
;
1257 s
->type
= COMEDI_SUBD_AO
;
1258 dev
->write_subdev
= s
;
1259 s
->subdev_flags
= SDF_WRITABLE
| SDF_CMD_WRITE
;
1260 s
->insn_read
= dt282x_ao_insn_read
;
1261 s
->insn_write
= dt282x_ao_insn_write
;
1262 s
->do_cmdtest
= dt282x_ao_cmdtest
;
1263 s
->do_cmd
= dt282x_ao_cmd
;
1264 s
->cancel
= dt282x_ao_cancel
;
1265 s
->maxdata
= (1 << boardtype
.dabits
) - 1;
1266 s
->len_chanlist
= 2;
1267 s
->range_table_list
= devpriv
->darangelist
;
1268 devpriv
->darangelist
[0] =
1269 opt_ao_range_lkup(it
->options
[opt_ao0_range
]);
1270 devpriv
->darangelist
[1] =
1271 opt_ao_range_lkup(it
->options
[opt_ao1_range
]);
1272 devpriv
->da0_2scomp
= it
->options
[opt_ao0_twos
];
1273 devpriv
->da1_2scomp
= it
->options
[opt_ao1_twos
];
1275 s
->type
= COMEDI_SUBD_UNUSED
;
1278 s
= &dev
->subdevices
[2];
1280 s
->type
= COMEDI_SUBD_DIO
;
1281 s
->subdev_flags
= SDF_READABLE
| SDF_WRITABLE
;
1283 s
->insn_bits
= dt282x_dio_insn_bits
;
1284 s
->insn_config
= dt282x_dio_insn_config
;
1286 s
->range_table
= &range_digital
;
1288 printk(KERN_INFO
"\n");
1293 static void dt282x_detach(struct comedi_device
*dev
)
1296 free_irq(dev
->irq
, dev
);
1298 release_region(dev
->iobase
, DT2821_SIZE
);
1300 if (devpriv
->dma
[0].chan
)
1301 free_dma(devpriv
->dma
[0].chan
);
1302 if (devpriv
->dma
[1].chan
)
1303 free_dma(devpriv
->dma
[1].chan
);
1304 if (devpriv
->dma
[0].buf
)
1305 free_page((unsigned long)devpriv
->dma
[0].buf
);
1306 if (devpriv
->dma
[1].buf
)
1307 free_page((unsigned long)devpriv
->dma
[1].buf
);
1311 static const struct dt282x_board boardtypes
[] = {
1349 .name
= "dt2824-pgh",
1358 .name
= "dt2824-pgl",
1430 .name
= "dt24-ez-pgl",
1441 static struct comedi_driver dt282x_driver
= {
1442 .driver_name
= "dt282x",
1443 .module
= THIS_MODULE
,
1444 .attach
= dt282x_attach
,
1445 .detach
= dt282x_detach
,
1446 .board_name
= &boardtypes
[0].name
,
1447 .num_names
= ARRAY_SIZE(boardtypes
),
1448 .offset
= sizeof(struct dt282x_board
),
1450 module_comedi_driver(dt282x_driver
);
1452 MODULE_AUTHOR("Comedi http://www.comedi.org");
1453 MODULE_DESCRIPTION("Comedi low-level driver");
1454 MODULE_LICENSE("GPL");