2 comedi/drivers/rti800.c
3 Hardware driver for Analog Devices RTI-800/815 board
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 1998 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: Analog Devices RTI-800/815
28 Updated: Fri, 05 Sep 2008 14:50:44 +0100
29 Devices: [Analog Devices] RTI-800 (rti800), RTI-815 (rti815)
31 Configuration options:
32 [0] - I/O port base address
36 1 = pseudodifferential (common)
51 [7] - DAC 1 range (same as DAC 0)
52 [8] - DAC 1 encoding (same as DAC 0)
55 #include <linux/interrupt.h>
56 #include "../comedidev.h"
58 #include <linux/ioport.h>
60 #define RTI800_SIZE 16
63 #define RTI800_MUXGAIN 1
64 #define RTI800_CONVERT 2
65 #define RTI800_ADCLO 3
66 #define RTI800_ADCHI 4
67 #define RTI800_DAC0LO 5
68 #define RTI800_DAC0HI 6
69 #define RTI800_DAC1LO 7
70 #define RTI800_DAC1HI 8
71 #define RTI800_CLRFLAGS 9
74 #define RTI800_9513A_DATA 12
75 #define RTI800_9513A_CNTRL 13
76 #define RTI800_9513A_STATUS 13
79 * flags for CSR register
82 #define RTI800_BUSY 0x80
83 #define RTI800_DONE 0x40
84 #define RTI800_OVERRUN 0x20
85 #define RTI800_TCR 0x10
86 #define RTI800_DMA_ENAB 0x08
87 #define RTI800_INTR_TC 0x04
88 #define RTI800_INTR_EC 0x02
89 #define RTI800_INTR_OVRN 0x01
91 #define Am9513_8BITBUS
93 #define Am9513_output_control(a) outb(a, dev->iobase+RTI800_9513A_CNTRL)
94 #define Am9513_output_data(a) outb(a, dev->iobase+RTI800_9513A_DATA)
95 #define Am9513_input_data() inb(dev->iobase+RTI800_9513A_DATA)
96 #define Am9513_input_status() inb(dev->iobase+RTI800_9513A_STATUS)
100 static const struct comedi_lrange range_rti800_ai_10_bipolar
= { 4, {
112 static const struct comedi_lrange range_rti800_ai_5_bipolar
= { 4, {
124 static const struct comedi_lrange range_rti800_ai_unipolar
= { 4, {
135 struct rti800_board
{
141 static irqreturn_t
rti800_interrupt(int irq
, void *dev
);
143 struct rti800_private
{
145 adc_diff
, adc_pseudodiff
, adc_singleended
148 adc_bipolar10
, adc_bipolar5
, adc_unipolar10
151 adc_2comp
, adc_straight
154 dac_bipolar10
, dac_unipolar10
155 } dac0_range
, dac1_range
;
157 dac_2comp
, dac_straight
158 } dac0_coding
, dac1_coding
;
159 const struct comedi_lrange
*ao_range_type_list
[2];
160 unsigned int ao_readback
[2];
164 #define devpriv ((struct rti800_private *)dev->private)
166 #define RTI800_TIMEOUT 100
168 static irqreturn_t
rti800_interrupt(int irq
, void *dev
)
173 /* settling delay times in usec for different gains */
174 static const int gaindelay
[] = { 10, 20, 40, 80 };
176 static int rti800_ai_insn_read(struct comedi_device
*dev
,
177 struct comedi_subdevice
*s
,
178 struct comedi_insn
*insn
, unsigned int *data
)
182 int chan
= CR_CHAN(insn
->chanspec
);
183 unsigned gain
= CR_RANGE(insn
->chanspec
);
184 unsigned muxgain_bits
;
186 inb(dev
->iobase
+ RTI800_ADCHI
);
187 outb(0, dev
->iobase
+ RTI800_CLRFLAGS
);
189 muxgain_bits
= chan
| (gain
<< 5);
190 if (muxgain_bits
!= devpriv
->muxgain_bits
) {
191 devpriv
->muxgain_bits
= muxgain_bits
;
192 outb(devpriv
->muxgain_bits
, dev
->iobase
+ RTI800_MUXGAIN
);
193 /* without a delay here, the RTI_OVERRUN bit
194 * gets set, and you will have an error. */
196 BUG_ON(gain
>= ARRAY_SIZE(gaindelay
));
197 udelay(gaindelay
[gain
]);
201 for (i
= 0; i
< insn
->n
; i
++) {
202 outb(0, dev
->iobase
+ RTI800_CONVERT
);
203 for (t
= RTI800_TIMEOUT
; t
; t
--) {
204 status
= inb(dev
->iobase
+ RTI800_CSR
);
205 if (status
& RTI800_OVERRUN
) {
206 printk(KERN_WARNING
"rti800: a/d overrun\n");
207 outb(0, dev
->iobase
+ RTI800_CLRFLAGS
);
210 if (status
& RTI800_DONE
)
215 printk(KERN_WARNING
"rti800: timeout\n");
218 data
[i
] = inb(dev
->iobase
+ RTI800_ADCLO
);
219 data
[i
] |= (0xf & inb(dev
->iobase
+ RTI800_ADCHI
)) << 8;
221 if (devpriv
->adc_coding
== adc_2comp
)
228 static int rti800_ao_insn_read(struct comedi_device
*dev
,
229 struct comedi_subdevice
*s
,
230 struct comedi_insn
*insn
, unsigned int *data
)
233 int chan
= CR_CHAN(insn
->chanspec
);
235 for (i
= 0; i
< insn
->n
; i
++)
236 data
[i
] = devpriv
->ao_readback
[chan
];
241 static int rti800_ao_insn_write(struct comedi_device
*dev
,
242 struct comedi_subdevice
*s
,
243 struct comedi_insn
*insn
, unsigned int *data
)
245 int chan
= CR_CHAN(insn
->chanspec
);
249 for (i
= 0; i
< insn
->n
; i
++) {
250 devpriv
->ao_readback
[chan
] = d
= data
[i
];
251 if (devpriv
->dac0_coding
== dac_2comp
)
255 dev
->iobase
+ (chan
? RTI800_DAC1LO
: RTI800_DAC0LO
));
257 dev
->iobase
+ (chan
? RTI800_DAC1HI
: RTI800_DAC0HI
));
262 static int rti800_di_insn_bits(struct comedi_device
*dev
,
263 struct comedi_subdevice
*s
,
264 struct comedi_insn
*insn
, unsigned int *data
)
268 data
[1] = inb(dev
->iobase
+ RTI800_DI
);
272 static int rti800_do_insn_bits(struct comedi_device
*dev
,
273 struct comedi_subdevice
*s
,
274 struct comedi_insn
*insn
, unsigned int *data
)
280 s
->state
&= ~data
[0];
281 s
->state
|= data
[0] & data
[1];
282 /* Outputs are inverted... */
283 outb(s
->state
^ 0xff, dev
->iobase
+ RTI800_DO
);
292 options[0] - I/O port
295 0=differential, 1=pseudodiff, 2=single
296 options[3] - a/d range
297 0=bipolar10, 1=bipolar5, 2=unipolar10
298 options[4] - a/d coding
299 0=2's comp, 1=straight binary
300 options[5] - dac0 range
301 0=bipolar10, 1=unipolar10
302 options[6] - dac0 coding
303 0=2's comp, 1=straight binary
304 options[7] - dac1 range
305 options[8] - dac1 coding
308 static int rti800_attach(struct comedi_device
*dev
, struct comedi_devconfig
*it
)
310 const struct rti800_board
*board
= comedi_board(dev
);
312 unsigned long iobase
;
314 struct comedi_subdevice
*s
;
316 iobase
= it
->options
[0];
317 printk(KERN_INFO
"comedi%d: rti800: 0x%04lx\n", dev
->minor
, iobase
);
318 if (!request_region(iobase
, RTI800_SIZE
, "rti800")) {
319 printk(KERN_WARNING
"I/O port conflict\n");
322 dev
->iobase
= iobase
;
325 printk(KERN_DEBUG
"fingerprint=%x,%x,%x,%x,%x ",
326 inb(dev
->iobase
+ 0),
327 inb(dev
->iobase
+ 1),
328 inb(dev
->iobase
+ 2),
329 inb(dev
->iobase
+ 3), inb(dev
->iobase
+ 4));
332 outb(0, dev
->iobase
+ RTI800_CSR
);
333 inb(dev
->iobase
+ RTI800_ADCHI
);
334 outb(0, dev
->iobase
+ RTI800_CLRFLAGS
);
336 irq
= it
->options
[1];
338 printk(KERN_INFO
"( irq = %u )\n", irq
);
339 ret
= request_irq(irq
, rti800_interrupt
, 0, "rti800", dev
);
341 printk(KERN_WARNING
" Failed to allocate IRQ\n");
346 printk(KERN_INFO
"( no irq )\n");
349 dev
->board_name
= board
->name
;
351 ret
= comedi_alloc_subdevices(dev
, 4);
355 ret
= alloc_private(dev
, sizeof(struct rti800_private
));
359 devpriv
->adc_mux
= it
->options
[2];
360 devpriv
->adc_range
= it
->options
[3];
361 devpriv
->adc_coding
= it
->options
[4];
362 devpriv
->dac0_range
= it
->options
[5];
363 devpriv
->dac0_coding
= it
->options
[6];
364 devpriv
->dac1_range
= it
->options
[7];
365 devpriv
->dac1_coding
= it
->options
[8];
366 devpriv
->muxgain_bits
= -1;
368 s
= dev
->subdevices
+ 0;
370 s
->type
= COMEDI_SUBD_AI
;
371 s
->subdev_flags
= SDF_READABLE
| SDF_GROUND
;
372 s
->n_chan
= (devpriv
->adc_mux
? 16 : 8);
373 s
->insn_read
= rti800_ai_insn_read
;
375 switch (devpriv
->adc_range
) {
377 s
->range_table
= &range_rti800_ai_10_bipolar
;
380 s
->range_table
= &range_rti800_ai_5_bipolar
;
383 s
->range_table
= &range_rti800_ai_unipolar
;
389 /* ao subdevice (only on rti815) */
390 s
->type
= COMEDI_SUBD_AO
;
391 s
->subdev_flags
= SDF_WRITABLE
;
393 s
->insn_read
= rti800_ao_insn_read
;
394 s
->insn_write
= rti800_ao_insn_write
;
396 s
->range_table_list
= devpriv
->ao_range_type_list
;
397 switch (devpriv
->dac0_range
) {
399 devpriv
->ao_range_type_list
[0] = &range_bipolar10
;
402 devpriv
->ao_range_type_list
[0] = &range_unipolar10
;
405 switch (devpriv
->dac1_range
) {
407 devpriv
->ao_range_type_list
[1] = &range_bipolar10
;
410 devpriv
->ao_range_type_list
[1] = &range_unipolar10
;
414 s
->type
= COMEDI_SUBD_UNUSED
;
419 s
->type
= COMEDI_SUBD_DI
;
420 s
->subdev_flags
= SDF_READABLE
;
422 s
->insn_bits
= rti800_di_insn_bits
;
424 s
->range_table
= &range_digital
;
428 s
->type
= COMEDI_SUBD_DO
;
429 s
->subdev_flags
= SDF_WRITABLE
;
431 s
->insn_bits
= rti800_do_insn_bits
;
433 s
->range_table
= &range_digital
;
435 /* don't yet know how to deal with counter/timers */
439 s
->type
= COMEDI_SUBD_TIMER
;
445 static void rti800_detach(struct comedi_device
*dev
)
448 release_region(dev
->iobase
, RTI800_SIZE
);
450 free_irq(dev
->irq
, dev
);
453 static const struct rti800_board boardtypes
[] = {
458 static struct comedi_driver rti800_driver
= {
459 .driver_name
= "rti800",
460 .module
= THIS_MODULE
,
461 .attach
= rti800_attach
,
462 .detach
= rti800_detach
,
463 .num_names
= ARRAY_SIZE(boardtypes
),
464 .board_name
= &boardtypes
[0].name
,
465 .offset
= sizeof(struct rti800_board
),
467 module_comedi_driver(rti800_driver
);
469 MODULE_AUTHOR("Comedi http://www.comedi.org");
470 MODULE_DESCRIPTION("Comedi low-level driver");
471 MODULE_LICENSE("GPL");