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 "../comedidev.h"
57 #include <linux/ioport.h>
59 #define RTI800_SIZE 16
62 #define RTI800_MUXGAIN 1
63 #define RTI800_CONVERT 2
64 #define RTI800_ADCLO 3
65 #define RTI800_ADCHI 4
66 #define RTI800_DAC0LO 5
67 #define RTI800_DAC0HI 6
68 #define RTI800_DAC1LO 7
69 #define RTI800_DAC1HI 8
70 #define RTI800_CLRFLAGS 9
73 #define RTI800_9513A_DATA 12
74 #define RTI800_9513A_CNTRL 13
75 #define RTI800_9513A_STATUS 13
78 * flags for CSR register
81 #define RTI800_BUSY 0x80
82 #define RTI800_DONE 0x40
83 #define RTI800_OVERRUN 0x20
84 #define RTI800_TCR 0x10
85 #define RTI800_DMA_ENAB 0x08
86 #define RTI800_INTR_TC 0x04
87 #define RTI800_INTR_EC 0x02
88 #define RTI800_INTR_OVRN 0x01
90 #define Am9513_8BITBUS
92 #define Am9513_output_control(a) outb(a,dev->iobase+RTI800_9513A_CNTRL)
93 #define Am9513_output_data(a) outb(a,dev->iobase+RTI800_9513A_DATA)
94 #define Am9513_input_data() inb(dev->iobase+RTI800_9513A_DATA)
95 #define Am9513_input_status() inb(dev->iobase+RTI800_9513A_STATUS)
99 static const struct comedi_lrange range_rti800_ai_10_bipolar = { 4, {
106 static const struct comedi_lrange range_rti800_ai_5_bipolar = { 4, {
113 static const struct comedi_lrange range_rti800_ai_unipolar = { 4, {
121 struct rti800_board {
127 static const struct rti800_board boardtypes[] = {
132 #define this_board ((const struct rti800_board *)dev->board_ptr)
134 static int rti800_attach(struct comedi_device * dev, struct comedi_devconfig * it);
135 static int rti800_detach(struct comedi_device * dev);
136 static struct comedi_driver driver_rti800 = {
137 driver_name:"rti800",
139 attach:rti800_attach,
140 detach:rti800_detach,
141 num_names:sizeof(boardtypes) / sizeof(struct rti800_board),
142 board_name:&boardtypes[0].name,
143 offset:sizeof(struct rti800_board),
146 COMEDI_INITCLEANUP(driver_rti800);
148 static irqreturn_t rti800_interrupt(int irq, void *dev PT_REGS_ARG);
150 struct rti800_private {
152 adc_diff, adc_pseudodiff, adc_singleended
155 adc_bipolar10, adc_bipolar5, adc_unipolar10
158 adc_2comp, adc_straight
161 dac_bipolar10, dac_unipolar10
162 } dac0_range, dac1_range;
164 dac_2comp, dac_straight
165 } dac0_coding, dac1_coding;
166 const struct comedi_lrange *ao_range_type_list[2];
167 unsigned int ao_readback[2];
171 #define devpriv ((struct rti800_private *)dev->private)
173 #define RTI800_TIMEOUT 100
175 static irqreturn_t rti800_interrupt(int irq, void *dev PT_REGS_ARG)
180 // settling delay times in usec for different gains
181 static const int gaindelay[] = { 10, 20, 40, 80 };
183 static int rti800_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
184 struct comedi_insn * insn, unsigned int * data)
188 int chan = CR_CHAN(insn->chanspec);
189 unsigned gain = CR_RANGE(insn->chanspec);
190 unsigned muxgain_bits;
192 inb(dev->iobase + RTI800_ADCHI);
193 outb(0, dev->iobase + RTI800_CLRFLAGS);
195 muxgain_bits = chan | (gain << 5);
196 if (muxgain_bits != devpriv->muxgain_bits) {
197 devpriv->muxgain_bits = muxgain_bits;
198 outb(devpriv->muxgain_bits, dev->iobase + RTI800_MUXGAIN);
199 /* without a delay here, the RTI_OVERRUN bit
200 * gets set, and you will have an error. */
203 sizeof(gaindelay) / sizeof(gaindelay[0]));
204 comedi_udelay(gaindelay[gain]);
208 for (i = 0; i < insn->n; i++) {
209 outb(0, dev->iobase + RTI800_CONVERT);
210 for (t = RTI800_TIMEOUT; t; t--) {
211 status = inb(dev->iobase + RTI800_CSR);
212 if (status & RTI800_OVERRUN) {
213 rt_printk("rti800: a/d overrun\n");
214 outb(0, dev->iobase + RTI800_CLRFLAGS);
217 if (status & RTI800_DONE)
222 rt_printk("rti800: timeout\n");
225 data[i] = inb(dev->iobase + RTI800_ADCLO);
226 data[i] |= (0xf & inb(dev->iobase + RTI800_ADCHI)) << 8;
228 if (devpriv->adc_coding == adc_2comp) {
236 static int rti800_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
237 struct comedi_insn * insn, unsigned int * data)
240 int chan = CR_CHAN(insn->chanspec);
242 for (i = 0; i < insn->n; i++)
243 data[i] = devpriv->ao_readback[chan];
248 static int rti800_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice * s,
249 struct comedi_insn * insn, unsigned int * data)
251 int chan = CR_CHAN(insn->chanspec);
255 for (i = 0; i < insn->n; i++) {
256 devpriv->ao_readback[chan] = d = data[i];
257 if (devpriv->dac0_coding == dac_2comp) {
261 dev->iobase + (chan ? RTI800_DAC1LO : RTI800_DAC0LO));
263 dev->iobase + (chan ? RTI800_DAC1HI : RTI800_DAC0HI));
268 static int rti800_di_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
269 struct comedi_insn * insn, unsigned int * data)
273 data[1] = inb(dev->iobase + RTI800_DI);
277 static int rti800_do_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
278 struct comedi_insn * insn, unsigned int * data)
284 s->state &= ~data[0];
285 s->state |= data[0] & data[1];
286 /* Outputs are inverted... */
287 outb(s->state ^ 0xff, dev->iobase + RTI800_DO);
296 options[0] - I/O port
299 0=differential, 1=pseudodiff, 2=single
300 options[3] - a/d range
301 0=bipolar10, 1=bipolar5, 2=unipolar10
302 options[4] - a/d coding
303 0=2's comp, 1=straight binary
304 options[5] - dac0 range
305 0=bipolar10, 1=unipolar10
306 options[6] - dac0 coding
307 0=2's comp, 1=straight binary
308 options[7] - dac1 range
309 options[8] - dac1 coding
312 static int rti800_attach(struct comedi_device * dev, struct comedi_devconfig * it)
315 unsigned long iobase;
317 struct comedi_subdevice *s;
319 iobase = it->options[0];
320 printk("comedi%d: rti800: 0x%04lx ", dev->minor, iobase);
321 if (!request_region(iobase, RTI800_SIZE, "rti800")) {
322 printk("I/O port conflict\n");
325 dev->iobase = iobase;
328 printk("fingerprint=%x,%x,%x,%x,%x ",
329 inb(dev->iobase + 0),
330 inb(dev->iobase + 1),
331 inb(dev->iobase + 2),
332 inb(dev->iobase + 3), inb(dev->iobase + 4));
335 outb(0, dev->iobase + RTI800_CSR);
336 inb(dev->iobase + RTI800_ADCHI);
337 outb(0, dev->iobase + RTI800_CLRFLAGS);
339 irq = it->options[1];
341 printk("( irq = %u )", irq);
342 if ((ret = comedi_request_irq(irq, rti800_interrupt, 0,
343 "rti800", dev)) < 0) {
344 printk(" Failed to allocate IRQ\n");
349 printk("( no irq )");
352 dev->board_name = this_board->name;
354 if ((ret = alloc_subdevices(dev, 4)) < 0)
356 if ((ret = alloc_private(dev, sizeof(struct rti800_private))) < 0)
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;
388 if (this_board->has_ao) {
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;
447 static int rti800_detach(struct comedi_device * dev)
449 printk("comedi%d: rti800: remove\n", dev->minor);
452 release_region(dev->iobase, RTI800_SIZE);
455 comedi_free_irq(dev->irq, dev);