2 comedi/drivers/dt2811.c
3 Hardware driver for Data Translation DT2811
5 COMEDI - Linux Control and Measurement Device Interface
7 Base Version - David A. Schleef <ds@schleef.org>
8 December 1998 - Updated to work. David does not have a DT2811
9 board any longer so this was suffering from bitrot.
10 Updated performed by ...
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
24 Description: Data Translation DT2811
26 Devices: [Data Translation] DT2811-PGL (dt2811-pgl), DT2811-PGH (dt2811-pgh)
29 Configuration options:
30 [0] - I/O port base address
31 [1] - IRQ, although this is currently unused
35 2 = pseudo-differential (common reference)
40 [4] - D/A 0 range (same choices)
41 [4] - D/A 1 range (same choices)
44 #include <linux/module.h>
45 #include "../comedidev.h"
47 static const struct comedi_lrange range_dt2811_pgh_ai_5_unipolar = {
56 static const struct comedi_lrange range_dt2811_pgh_ai_2_5_bipolar = {
65 static const struct comedi_lrange range_dt2811_pgh_ai_5_bipolar = {
74 static const struct comedi_lrange range_dt2811_pgl_ai_5_unipolar = {
83 static const struct comedi_lrange range_dt2811_pgl_ai_2_5_bipolar = {
92 static const struct comedi_lrange range_dt2811_pgl_ai_5_bipolar = {
103 0x00 ADCSR R/W A/D Control/Status Register
104 bit 7 - (R) 1 indicates A/D conversion done
105 reading ADDAT clears bit
107 bit 6 - (R) 1 indicates A/D error
109 bit 5 - (R) 1 indicates A/D busy, cleared at end
115 bit 2 - (R/W) 1 indicates interrupts enabled
116 bits 1,0 - (R/W) mode bits
117 00 single conversion on ADGCR load
118 01 continuous conversion, internal clock,
119 (clock enabled on ADGCR load)
120 10 continuous conversion, internal clock,
122 11 continuous conversion, external clock,
125 0x01 ADGCR R/W A/D Gain/Channel Register
126 bit 6,7 - (R/W) gain select
127 00 gain=1, both PGH, PGL models
128 01 gain=2 PGH, 10 PGL
129 10 gain=4 PGH, 100 PGL
130 11 gain=8 PGH, 500 PGL
132 bit 3-0 - (R/W) channel select
133 channel number from 0-15
135 0x02,0x03 (R) ADDAT A/D Data Register
136 (W) DADAT0 D/A Data Register 0
140 0x04,0x05 (W) DADAT0 D/A Data Register 1
142 0x06 (R) DIO0 Digital Input Port 0
143 (W) DIO1 Digital Output Port 1
145 0x07 TMRCTR (R/W) Timer/Counter Register
147 bits 5-3 - Timer frequency control (mantissa)
148 543 divisor freqency (kHz)
157 bits 2-0 - Timer frequency control (exponent)
158 210 multiply divisor/divide frequency by
170 #define TIMEOUT 10000
172 #define DT2811_ADCSR 0
173 #define DT2811_ADGCR 1
174 #define DT2811_ADDATLO 2
175 #define DT2811_ADDATHI 3
176 #define DT2811_DADAT0LO 2
177 #define DT2811_DADAT0HI 3
178 #define DT2811_DADAT1LO 4
179 #define DT2811_DADAT1HI 5
181 #define DT2811_TMRCTR 7
189 #define DT2811_ADDONE 0x80
190 #define DT2811_ADERROR 0x40
191 #define DT2811_ADBUSY 0x20
192 #define DT2811_CLRERROR 0x10
193 #define DT2811_INTENB 0x04
194 #define DT2811_ADMODE 0x03
196 struct dt2811_board {
198 const struct comedi_lrange *bip_5;
199 const struct comedi_lrange *bip_2_5;
200 const struct comedi_lrange *unip_5;
203 enum { card_2811_pgh, card_2811_pgl };
205 struct dt2811_private {
209 adc_singleended, adc_diff, adc_pseudo_diff
212 dac_bipolar_5, dac_bipolar_2_5, dac_unipolar_5
214 const struct comedi_lrange *range_type_list[2];
217 static const struct comedi_lrange *dac_range_types[] = {
223 static int dt2811_ai_eoc(struct comedi_device *dev,
224 struct comedi_subdevice *s,
225 struct comedi_insn *insn,
226 unsigned long context)
230 status = inb(dev->iobase + DT2811_ADCSR);
231 if ((status & DT2811_ADBUSY) == 0)
236 static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
237 struct comedi_insn *insn, unsigned int *data)
239 int chan = CR_CHAN(insn->chanspec);
243 for (i = 0; i < insn->n; i++) {
244 outb(chan, dev->iobase + DT2811_ADGCR);
246 ret = comedi_timeout(dev, s, insn, dt2811_ai_eoc, 0);
250 data[i] = inb(dev->iobase + DT2811_ADDATLO);
251 data[i] |= inb(dev->iobase + DT2811_ADDATHI) << 8;
258 static int dt2811_ao_insn_write(struct comedi_device *dev,
259 struct comedi_subdevice *s,
260 struct comedi_insn *insn,
263 unsigned int chan = CR_CHAN(insn->chanspec);
264 unsigned int val = s->readback[chan];
267 for (i = 0; i < insn->n; i++) {
269 outb(val & 0xff, dev->iobase + DT2811_DADAT0LO + 2 * chan);
270 outb((val >> 8) & 0xff,
271 dev->iobase + DT2811_DADAT0HI + 2 * chan);
273 s->readback[chan] = val;
278 static int dt2811_di_insn_bits(struct comedi_device *dev,
279 struct comedi_subdevice *s,
280 struct comedi_insn *insn, unsigned int *data)
282 data[1] = inb(dev->iobase + DT2811_DIO);
287 static int dt2811_do_insn_bits(struct comedi_device *dev,
288 struct comedi_subdevice *s,
289 struct comedi_insn *insn,
292 if (comedi_dio_update_state(s, data))
293 outb(s->state, dev->iobase + DT2811_DIO);
301 options[0] Board base address
303 options[2] Input configuration
306 2 == pseudo-differential
307 options[3] Analog input range configuration
308 0 == bipolar 5 (-5V -- +5V)
309 1 == bipolar 2.5V (-2.5V -- +2.5V)
310 2 == unipolar 5V (0V -- +5V)
311 options[4] Analog output 0 range configuration
312 0 == bipolar 5 (-5V -- +5V)
313 1 == bipolar 2.5V (-2.5V -- +2.5V)
314 2 == unipolar 5V (0V -- +5V)
315 options[5] Analog output 1 range configuration
316 0 == bipolar 5 (-5V -- +5V)
317 1 == bipolar 2.5V (-2.5V -- +2.5V)
318 2 == unipolar 5V (0V -- +5V)
320 static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it)
323 const struct dt2811_board *board = dev->board_ptr;
324 struct dt2811_private *devpriv;
326 struct comedi_subdevice *s;
328 ret = comedi_request_region(dev, it->options[0], 0x8);
333 outb(0, dev->iobase + DT2811_ADCSR);
335 i = inb(dev->iobase + DT2811_ADDATLO);
336 i = inb(dev->iobase + DT2811_ADDATHI);
339 ret = comedi_alloc_subdevices(dev, 4);
343 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
347 switch (it->options[2]) {
349 devpriv->adc_mux = adc_singleended;
352 devpriv->adc_mux = adc_diff;
355 devpriv->adc_mux = adc_pseudo_diff;
358 devpriv->adc_mux = adc_singleended;
361 switch (it->options[4]) {
363 devpriv->dac_range[0] = dac_bipolar_5;
366 devpriv->dac_range[0] = dac_bipolar_2_5;
369 devpriv->dac_range[0] = dac_unipolar_5;
372 devpriv->dac_range[0] = dac_bipolar_5;
375 switch (it->options[5]) {
377 devpriv->dac_range[1] = dac_bipolar_5;
380 devpriv->dac_range[1] = dac_bipolar_2_5;
383 devpriv->dac_range[1] = dac_unipolar_5;
386 devpriv->dac_range[1] = dac_bipolar_5;
390 s = &dev->subdevices[0];
391 /* initialize the ADC subdevice */
392 s->type = COMEDI_SUBD_AI;
393 s->subdev_flags = SDF_READABLE | SDF_GROUND;
394 s->n_chan = devpriv->adc_mux == adc_diff ? 8 : 16;
395 s->insn_read = dt2811_ai_insn;
397 switch (it->options[3]) {
400 s->range_table = board->bip_5;
403 s->range_table = board->bip_2_5;
406 s->range_table = board->unip_5;
410 s = &dev->subdevices[1];
412 s->type = COMEDI_SUBD_AO;
413 s->subdev_flags = SDF_WRITABLE;
416 s->range_table_list = devpriv->range_type_list;
417 devpriv->range_type_list[0] = dac_range_types[devpriv->dac_range[0]];
418 devpriv->range_type_list[1] = dac_range_types[devpriv->dac_range[1]];
419 s->insn_write = dt2811_ao_insn_write;
421 ret = comedi_alloc_subdev_readback(s);
425 s = &dev->subdevices[2];
427 s->type = COMEDI_SUBD_DI;
428 s->subdev_flags = SDF_READABLE;
430 s->insn_bits = dt2811_di_insn_bits;
432 s->range_table = &range_digital;
434 s = &dev->subdevices[3];
436 s->type = COMEDI_SUBD_DO;
437 s->subdev_flags = SDF_WRITABLE;
439 s->insn_bits = dt2811_do_insn_bits;
442 s->range_table = &range_digital;
447 static const struct dt2811_board boardtypes[] = {
449 .name = "dt2811-pgh",
450 .bip_5 = &range_dt2811_pgh_ai_5_bipolar,
451 .bip_2_5 = &range_dt2811_pgh_ai_2_5_bipolar,
452 .unip_5 = &range_dt2811_pgh_ai_5_unipolar,
454 .name = "dt2811-pgl",
455 .bip_5 = &range_dt2811_pgl_ai_5_bipolar,
456 .bip_2_5 = &range_dt2811_pgl_ai_2_5_bipolar,
457 .unip_5 = &range_dt2811_pgl_ai_5_unipolar,
461 static struct comedi_driver dt2811_driver = {
462 .driver_name = "dt2811",
463 .module = THIS_MODULE,
464 .attach = dt2811_attach,
465 .detach = comedi_legacy_detach,
466 .board_name = &boardtypes[0].name,
467 .num_names = ARRAY_SIZE(boardtypes),
468 .offset = sizeof(struct dt2811_board),
470 module_comedi_driver(dt2811_driver);
472 MODULE_AUTHOR("Comedi http://www.comedi.org");
473 MODULE_DESCRIPTION("Comedi low-level driver");
474 MODULE_LICENSE("GPL");