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 Devices: [Analog Devices] RTI-800 (rti800), RTI-815 (rti815)
30 Configuration options:
31 [0] - I/O port base address
35 1 = pseudodifferential (common)
50 [6] - DAC 1 range (same as DAC 0)
51 [7] - DAC 1 encoding (same as DAC 0)
54 #include <linux/kernel.h>
55 #include <linux/module.h>
56 #include <linux/sched.h>
58 #include <linux/slab.h>
59 #include <linux/errno.h>
60 #include <linux/ioport.h>
61 #include <linux/delay.h>
62 #include <linux/interrupt.h>
63 #include <linux/timex.h>
64 #include <linux/timer.h>
66 #include <linux/comedidev.h>
69 #define RTI800_SIZE 16
72 #define RTI800_MUXGAIN 1
73 #define RTI800_CONVERT 2
74 #define RTI800_ADCLO 3
75 #define RTI800_ADCHI 4
76 #define RTI800_DAC0LO 5
77 #define RTI800_DAC0HI 6
78 #define RTI800_DAC1LO 7
79 #define RTI800_DAC1HI 8
80 #define RTI800_CLRFLAGS 9
83 #define RTI800_9513A_DATA 12
84 #define RTI800_9513A_CNTRL 13
85 #define RTI800_9513A_STATUS 13
89 * flags for CSR register
92 #define RTI800_BUSY 0x80
93 #define RTI800_DONE 0x40
94 #define RTI800_OVERRUN 0x20
95 #define RTI800_TCR 0x10
96 #define RTI800_DMA_ENAB 0x08
97 #define RTI800_INTR_TC 0x04
98 #define RTI800_INTR_EC 0x02
99 #define RTI800_INTR_OVRN 0x01
101 #define Am9513_8BITBUS
103 #define Am9513_output_control(a) outb(a,dev->iobase+RTI800_9513A_CNTRL)
104 #define Am9513_output_data(a) outb(a,dev->iobase+RTI800_9513A_DATA)
105 #define Am9513_input_data() inb(dev->iobase+RTI800_9513A_DATA)
106 #define Am9513_input_status() inb(dev->iobase+RTI800_9513A_STATUS)
110 static comedi_lrange range_rti800_ai_10_bipolar = { 4, {
116 static comedi_lrange range_rti800_ai_5_bipolar = { 4, {
122 static comedi_lrange range_rti800_ai_unipolar = { 4, {
133 static boardtype boardtypes[]={
137 #define this_board ((boardtype *)dev->board_ptr)
139 static int rti800_attach(comedi_device *dev,comedi_devconfig *it);
140 static int rti800_detach(comedi_device *dev);
141 static comedi_driver driver_rti800={
142 driver_name: "rti800",
144 attach: rti800_attach,
145 detach: rti800_detach,
146 num_names: sizeof(boardtypes)/sizeof(boardtype),
147 board_name: boardtypes,
148 offset: sizeof(boardtype),
150 COMEDI_INITCLEANUP(driver_rti800);
152 static void rti800_interrupt(int irq, void *dev, struct pt_regs *regs);
156 adc_diff, adc_pseudodiff, adc_singleended
159 adc_bipolar10, adc_bipolar5, adc_unipolar10
162 adc_2comp, adc_straight
165 dac_bipolar10, dac_unipolar10
166 } dac0_range, dac1_range;
168 dac_2comp, dac_straight
169 } dac0_coding, dac1_coding;
170 comedi_lrange * ao_range_type_list[2];
171 lsampl_t ao_readback[2];
174 #define devpriv ((rti800_private *)dev->private)
176 #define RTI800_TIMEOUT 10
178 static void rti800_interrupt(int irq, void *dev, struct pt_regs *regs)
184 // settling delay times in usec for different gains
185 //static int gaindelay[]={10,20,40,80};
187 static int rti800_ai_insn_read(comedi_device *dev,comedi_subdevice *s,
188 comedi_insn *insn,lsampl_t *data)
192 int chan = CR_CHAN(insn->chanspec);
193 int gain = CR_RANGE(insn->chanspec);
195 inb(dev->iobase + RTI800_ADCHI);
196 outb(0,dev->iobase+RTI800_CLRFLAGS);
198 outb(chan | (gain << 5), dev->iobase + RTI800_MUXGAIN);
200 for(i=0;i<insn->n;i++){
201 outb(0, dev->iobase + RTI800_CONVERT);
202 for (t = RTI800_TIMEOUT; t; t--) {
203 status=inb(dev->iobase+RTI800_CSR);
204 if(status & RTI800_OVERRUN){
205 rt_printk("rti800: a/d overrun\n");
206 outb(0,dev->iobase+RTI800_CLRFLAGS);
209 if (status & RTI800_DONE)break;
213 rt_printk("rti800: timeout\n");
216 data[i] = inb(dev->iobase + RTI800_ADCLO);
217 data[i] |= (0xf & inb(dev->iobase + RTI800_ADCHI))<<8;
219 if (devpriv->adc_coding == adc_2comp) {
227 static int rti800_ao_insn_read(comedi_device *dev,comedi_subdevice *s,
228 comedi_insn *insn,lsampl_t *data)
231 int chan=CR_CHAN(insn->chanspec);
233 for(i=0;i<insn->n;i++)
234 data[i] = devpriv->ao_readback[chan];
239 static int rti800_ao_insn_write(comedi_device *dev,comedi_subdevice *s,
240 comedi_insn *insn,lsampl_t *data)
242 int chan=CR_CHAN(insn->chanspec);
246 for(i=0;i<insn->n;i++){
247 devpriv->ao_readback[chan] = d = data[i];
248 if (devpriv->dac0_coding == dac_2comp) {
251 outb(d & 0xff, dev->iobase + (chan?RTI800_DAC1LO:RTI800_DAC0LO));
252 outb(d >> 8, dev->iobase + (chan?RTI800_DAC1HI:RTI800_DAC0HI));
257 static int rti800_di_insn_bits(comedi_device *dev,comedi_subdevice *s,
258 comedi_insn *insn,lsampl_t *data)
260 if(insn->n!=2)return -EINVAL;
261 data[1] = inb(dev->iobase + RTI800_DI);
265 static int rti800_do_insn_bits(comedi_device *dev,comedi_subdevice *s,
266 comedi_insn *insn,lsampl_t *data)
268 if(insn->n!=2)return -EINVAL;
271 s->state &= ~data[0];
272 s->state |= data[0]&data[1];
273 /* Outputs are inverted... */
274 outb(s->state ^ 0xff, dev->iobase + RTI800_DO);
284 options[0] - I/O port
287 0=differential, 1=pseudodiff, 2=single
288 options[3] - a/d range
289 0=bipolar10, 1=bipolar5, 2=unipolar10
290 options[4] - a/d coding
291 0=2's comp, 1=straight binary
292 options[5] - dac0 range
293 0=bipolar10, 1=unipolar10
294 options[6] - dac0 coding
295 0=2's comp, 1=straight binary
296 options[7] - dac1 range
297 options[8] - dac1 coding
300 static int rti800_attach(comedi_device * dev, comedi_devconfig * it)
307 iobase = it->options[0];
308 printk("comedi%d: rti800: 0x%04x ", dev->minor, iobase);
309 if (check_region(iobase, RTI800_SIZE) < 0) {
310 printk("I/O port conflict\n");
313 request_region(iobase, RTI800_SIZE, "rti800");
314 dev->iobase = iobase;
317 printk("fingerprint=%x,%x,%x,%x,%x ",
318 inb(dev->iobase + 0),
319 inb(dev->iobase + 1),
320 inb(dev->iobase + 2),
321 inb(dev->iobase + 3),
322 inb(dev->iobase + 4));
325 outb(0,dev->iobase+RTI800_CSR);
326 inb(dev->iobase+RTI800_ADCHI);
327 outb(0,dev->iobase+RTI800_CLRFLAGS);
331 printk("( irq = %d )\n",irq);
332 if((ret=comedi_request_irq(irq,rti800_interrupt, 0, "rti800", dev))<0)
336 printk("( no irq )");
339 dev->board_name = this_board->name;
342 if((ret=alloc_subdevices(dev))<0)
344 if((ret=alloc_private(dev,sizeof(rti800_private)))<0)
347 devpriv->adc_mux = it->options[2];
348 devpriv->adc_range = it->options[3];
349 devpriv->adc_coding = it->options[4];
350 devpriv->dac0_range = it->options[5];
351 devpriv->dac0_coding = it->options[6];
352 devpriv->dac1_range = it->options[7];
353 devpriv->dac1_coding = it->options[8];
357 s->type=COMEDI_SUBD_AI;
358 s->subdev_flags=SDF_READABLE;
359 s->n_chan=(devpriv->adc_mux? 16 : 8);
360 s->insn_read=rti800_ai_insn_read;
362 switch (devpriv->adc_range) {
364 s->range_table = &range_rti800_ai_10_bipolar;
367 s->range_table = &range_rti800_ai_5_bipolar;
370 s->range_table = &range_rti800_ai_unipolar;
375 if (this_board->has_ao){
376 /* ao subdevice (only on rti815) */
377 s->type=COMEDI_SUBD_AO;
378 s->subdev_flags=SDF_WRITABLE;
380 s->insn_read=rti800_ao_insn_read;
381 s->insn_write=rti800_ao_insn_write;
383 s->range_table_list=devpriv->ao_range_type_list;
384 switch (devpriv->dac0_range) {
386 devpriv->ao_range_type_list[0] = &range_bipolar10;
389 devpriv->ao_range_type_list[0] = &range_unipolar10;
392 switch (devpriv->dac1_range) {
394 devpriv->ao_range_type_list[1] = &range_bipolar10;
397 devpriv->ao_range_type_list[1] = &range_unipolar10;
401 s->type=COMEDI_SUBD_UNUSED;
406 s->type=COMEDI_SUBD_DI;
407 s->subdev_flags=SDF_READABLE;
409 s->insn_bits=rti800_di_insn_bits;
411 s->range_table=&range_digital;
415 s->type=COMEDI_SUBD_DO;
416 s->subdev_flags=SDF_WRITABLE;
418 s->insn_bits=rti800_do_insn_bits;
420 s->range_table=&range_digital;
423 /* don't yet know how to deal with counter/timers */
427 s->type=COMEDI_SUBD_TIMER;
436 static int rti800_detach(comedi_device * dev)
438 printk("comedi%d: rti800: remove\n", dev->minor);
441 release_region(dev->iobase, RTI800_SIZE);
444 comedi_free_irq(dev->irq,dev);