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 RTI800_TIMEOUT 100
166 static irqreturn_t rti800_interrupt(int irq, void *dev)
171 /* settling delay times in usec for different gains */
172 static const int gaindelay[] = { 10, 20, 40, 80 };
174 static int rti800_ai_insn_read(struct comedi_device *dev,
175 struct comedi_subdevice *s,
176 struct comedi_insn *insn, unsigned int *data)
178 struct rti800_private *devpriv = dev->private;
181 int chan = CR_CHAN(insn->chanspec);
182 unsigned gain = CR_RANGE(insn->chanspec);
183 unsigned muxgain_bits;
185 inb(dev->iobase + RTI800_ADCHI);
186 outb(0, dev->iobase + RTI800_CLRFLAGS);
188 muxgain_bits = chan | (gain << 5);
189 if (muxgain_bits != devpriv->muxgain_bits) {
190 devpriv->muxgain_bits = muxgain_bits;
191 outb(devpriv->muxgain_bits, dev->iobase + RTI800_MUXGAIN);
192 /* without a delay here, the RTI_OVERRUN bit
193 * gets set, and you will have an error. */
195 BUG_ON(gain >= ARRAY_SIZE(gaindelay));
196 udelay(gaindelay[gain]);
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 printk(KERN_WARNING "rti800: a/d overrun\n");
206 outb(0, dev->iobase + RTI800_CLRFLAGS);
209 if (status & RTI800_DONE)
214 printk(KERN_WARNING "rti800: timeout\n");
217 data[i] = inb(dev->iobase + RTI800_ADCLO);
218 data[i] |= (0xf & inb(dev->iobase + RTI800_ADCHI)) << 8;
220 if (devpriv->adc_coding == adc_2comp)
227 static int rti800_ao_insn_read(struct comedi_device *dev,
228 struct comedi_subdevice *s,
229 struct comedi_insn *insn, unsigned int *data)
231 struct rti800_private *devpriv = dev->private;
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 struct rti800_private *devpriv = dev->private;
246 int chan = CR_CHAN(insn->chanspec);
250 for (i = 0; i < insn->n; i++) {
251 devpriv->ao_readback[chan] = d = data[i];
252 if (devpriv->dac0_coding == dac_2comp)
256 dev->iobase + (chan ? RTI800_DAC1LO : RTI800_DAC0LO));
258 dev->iobase + (chan ? RTI800_DAC1HI : RTI800_DAC0HI));
263 static int rti800_di_insn_bits(struct comedi_device *dev,
264 struct comedi_subdevice *s,
265 struct comedi_insn *insn, unsigned int *data)
267 data[1] = inb(dev->iobase + RTI800_DI);
271 static int rti800_do_insn_bits(struct comedi_device *dev,
272 struct comedi_subdevice *s,
273 struct comedi_insn *insn, unsigned int *data)
276 s->state &= ~data[0];
277 s->state |= data[0] & data[1];
278 /* Outputs are inverted... */
279 outb(s->state ^ 0xff, dev->iobase + RTI800_DO);
288 options[0] - I/O port
291 0=differential, 1=pseudodiff, 2=single
292 options[3] - a/d range
293 0=bipolar10, 1=bipolar5, 2=unipolar10
294 options[4] - a/d coding
295 0=2's comp, 1=straight binary
296 options[5] - dac0 range
297 0=bipolar10, 1=unipolar10
298 options[6] - dac0 coding
299 0=2's comp, 1=straight binary
300 options[7] - dac1 range
301 options[8] - dac1 coding
304 static int rti800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
306 const struct rti800_board *board = comedi_board(dev);
307 struct rti800_private *devpriv;
309 unsigned long iobase;
311 struct comedi_subdevice *s;
313 iobase = it->options[0];
314 printk(KERN_INFO "comedi%d: rti800: 0x%04lx\n", dev->minor, iobase);
315 if (!request_region(iobase, RTI800_SIZE, "rti800")) {
316 printk(KERN_WARNING "I/O port conflict\n");
319 dev->iobase = iobase;
322 printk(KERN_DEBUG "fingerprint=%x,%x,%x,%x,%x ",
323 inb(dev->iobase + 0),
324 inb(dev->iobase + 1),
325 inb(dev->iobase + 2),
326 inb(dev->iobase + 3), inb(dev->iobase + 4));
329 outb(0, dev->iobase + RTI800_CSR);
330 inb(dev->iobase + RTI800_ADCHI);
331 outb(0, dev->iobase + RTI800_CLRFLAGS);
333 irq = it->options[1];
335 printk(KERN_INFO "( irq = %u )\n", irq);
336 ret = request_irq(irq, rti800_interrupt, 0, "rti800", dev);
338 printk(KERN_WARNING " Failed to allocate IRQ\n");
343 printk(KERN_INFO "( no irq )\n");
346 dev->board_name = board->name;
348 ret = comedi_alloc_subdevices(dev, 4);
352 devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
355 dev->private = devpriv;
357 devpriv->adc_mux = it->options[2];
358 devpriv->adc_range = it->options[3];
359 devpriv->adc_coding = it->options[4];
360 devpriv->dac0_range = it->options[5];
361 devpriv->dac0_coding = it->options[6];
362 devpriv->dac1_range = it->options[7];
363 devpriv->dac1_coding = it->options[8];
364 devpriv->muxgain_bits = -1;
366 s = &dev->subdevices[0];
368 s->type = COMEDI_SUBD_AI;
369 s->subdev_flags = SDF_READABLE | SDF_GROUND;
370 s->n_chan = (devpriv->adc_mux ? 16 : 8);
371 s->insn_read = rti800_ai_insn_read;
373 switch (devpriv->adc_range) {
375 s->range_table = &range_rti800_ai_10_bipolar;
378 s->range_table = &range_rti800_ai_5_bipolar;
381 s->range_table = &range_rti800_ai_unipolar;
385 s = &dev->subdevices[1];
387 /* ao subdevice (only on rti815) */
388 s->type = COMEDI_SUBD_AO;
389 s->subdev_flags = SDF_WRITABLE;
391 s->insn_read = rti800_ao_insn_read;
392 s->insn_write = rti800_ao_insn_write;
394 s->range_table_list = devpriv->ao_range_type_list;
395 switch (devpriv->dac0_range) {
397 devpriv->ao_range_type_list[0] = &range_bipolar10;
400 devpriv->ao_range_type_list[0] = &range_unipolar10;
403 switch (devpriv->dac1_range) {
405 devpriv->ao_range_type_list[1] = &range_bipolar10;
408 devpriv->ao_range_type_list[1] = &range_unipolar10;
412 s->type = COMEDI_SUBD_UNUSED;
415 s = &dev->subdevices[2];
417 s->type = COMEDI_SUBD_DI;
418 s->subdev_flags = SDF_READABLE;
420 s->insn_bits = rti800_di_insn_bits;
422 s->range_table = &range_digital;
424 s = &dev->subdevices[3];
426 s->type = COMEDI_SUBD_DO;
427 s->subdev_flags = SDF_WRITABLE;
429 s->insn_bits = rti800_do_insn_bits;
431 s->range_table = &range_digital;
433 /* don't yet know how to deal with counter/timers */
435 s = &dev->subdevices[4];
437 s->type = COMEDI_SUBD_TIMER;
443 static void rti800_detach(struct comedi_device *dev)
446 release_region(dev->iobase, RTI800_SIZE);
448 free_irq(dev->irq, dev);
451 static const struct rti800_board boardtypes[] = {
456 static struct comedi_driver rti800_driver = {
457 .driver_name = "rti800",
458 .module = THIS_MODULE,
459 .attach = rti800_attach,
460 .detach = rti800_detach,
461 .num_names = ARRAY_SIZE(boardtypes),
462 .board_name = &boardtypes[0].name,
463 .offset = sizeof(struct rti800_board),
465 module_comedi_driver(rti800_driver);
467 MODULE_AUTHOR("Comedi http://www.comedi.org");
468 MODULE_DESCRIPTION("Comedi low-level driver");
469 MODULE_LICENSE("GPL");