Merge branch 'for-3.11' of git://linux-nfs.org/~bfields/linux
[linux-2.6.git] / drivers / staging / comedi / drivers / dt2811.c
blob5348cdae408a7e4045d8223a62d2ad7a0068a50d
1 /*
2 comedi/drivers/dt2811.c
3 Hardware driver for Data Translation DT2811
5 COMEDI - Linux Control and Measurement Device Interface
6 History:
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.
23 Driver: dt2811
24 Description: Data Translation DT2811
25 Author: ds
26 Devices: [Data Translation] DT2811-PGL (dt2811-pgl), DT2811-PGH (dt2811-pgh)
27 Status: works
29 Configuration options:
30 [0] - I/O port base address
31 [1] - IRQ, although this is currently unused
32 [2] - A/D reference
33 0 = signle-ended
34 1 = differential
35 2 = pseudo-differential (common reference)
36 [3] - A/D range
37 0 = [-5, 5]
38 1 = [-2.5, 2.5]
39 2 = [0, 5]
40 [4] - D/A 0 range (same choices)
41 [4] - D/A 1 range (same choices)
44 #include <linux/interrupt.h>
45 #include "../comedidev.h"
47 #include <linux/ioport.h>
49 static const struct comedi_lrange range_dt2811_pgh_ai_5_unipolar = {
50 4, {
51 RANGE(0, 5),
52 RANGE(0, 2.5),
53 RANGE(0, 1.25),
54 RANGE(0, 0.625)
58 static const struct comedi_lrange range_dt2811_pgh_ai_2_5_bipolar = {
59 4, {
60 RANGE(-2.5, 2.5),
61 RANGE(-1.25, 1.25),
62 RANGE(-0.625, 0.625),
63 RANGE(-0.3125, 0.3125)
67 static const struct comedi_lrange range_dt2811_pgh_ai_5_bipolar = {
68 4, {
69 RANGE(-5, 5),
70 RANGE(-2.5, 2.5),
71 RANGE(-1.25, 1.25),
72 RANGE(-0.625, 0.625)
76 static const struct comedi_lrange range_dt2811_pgl_ai_5_unipolar = {
77 4, {
78 RANGE(0, 5),
79 RANGE(0, 0.5),
80 RANGE(0, 0.05),
81 RANGE(0, 0.01)
85 static const struct comedi_lrange range_dt2811_pgl_ai_2_5_bipolar = {
86 4, {
87 RANGE(-2.5, 2.5),
88 RANGE(-0.25, 0.25),
89 RANGE(-0.025, 0.025),
90 RANGE(-0.005, 0.005)
94 static const struct comedi_lrange range_dt2811_pgl_ai_5_bipolar = {
95 4, {
96 RANGE(-5, 5),
97 RANGE(-0.5, 0.5),
98 RANGE(-0.05, 0.05),
99 RANGE(-0.01, 0.01)
105 0x00 ADCSR R/W A/D Control/Status Register
106 bit 7 - (R) 1 indicates A/D conversion done
107 reading ADDAT clears bit
108 (W) ignored
109 bit 6 - (R) 1 indicates A/D error
110 (W) ignored
111 bit 5 - (R) 1 indicates A/D busy, cleared at end
112 of conversion
113 (W) ignored
114 bit 4 - (R) 0
116 bit 3 - (R) 0
117 bit 2 - (R/W) 1 indicates interrupts enabled
118 bits 1,0 - (R/W) mode bits
119 00 single conversion on ADGCR load
120 01 continuous conversion, internal clock,
121 (clock enabled on ADGCR load)
122 10 continuous conversion, internal clock,
123 external trigger
124 11 continuous conversion, external clock,
125 external trigger
127 0x01 ADGCR R/W A/D Gain/Channel Register
128 bit 6,7 - (R/W) gain select
129 00 gain=1, both PGH, PGL models
130 01 gain=2 PGH, 10 PGL
131 10 gain=4 PGH, 100 PGL
132 11 gain=8 PGH, 500 PGL
133 bit 4,5 - reserved
134 bit 3-0 - (R/W) channel select
135 channel number from 0-15
137 0x02,0x03 (R) ADDAT A/D Data Register
138 (W) DADAT0 D/A Data Register 0
139 0x02 low byte
140 0x03 high byte
142 0x04,0x05 (W) DADAT0 D/A Data Register 1
144 0x06 (R) DIO0 Digital Input Port 0
145 (W) DIO1 Digital Output Port 1
147 0x07 TMRCTR (R/W) Timer/Counter Register
148 bits 6,7 - reserved
149 bits 5-3 - Timer frequency control (mantissa)
150 543 divisor freqency (kHz)
151 000 1 600
152 001 10 60
153 010 2 300
154 011 3 200
155 100 4 150
156 101 5 120
157 110 6 100
158 111 12 50
159 bits 2-0 - Timer frequency control (exponent)
160 210 multiply divisor/divide frequency by
161 000 1
162 001 10
163 010 100
164 011 1000
165 100 10000
166 101 100000
167 110 1000000
168 111 10000000
172 #define TIMEOUT 10000
174 #define DT2811_SIZE 8
176 #define DT2811_ADCSR 0
177 #define DT2811_ADGCR 1
178 #define DT2811_ADDATLO 2
179 #define DT2811_ADDATHI 3
180 #define DT2811_DADAT0LO 2
181 #define DT2811_DADAT0HI 3
182 #define DT2811_DADAT1LO 4
183 #define DT2811_DADAT1HI 5
184 #define DT2811_DIO 6
185 #define DT2811_TMRCTR 7
188 * flags
191 /* ADCSR */
193 #define DT2811_ADDONE 0x80
194 #define DT2811_ADERROR 0x40
195 #define DT2811_ADBUSY 0x20
196 #define DT2811_CLRERROR 0x10
197 #define DT2811_INTENB 0x04
198 #define DT2811_ADMODE 0x03
200 struct dt2811_board {
202 const char *name;
203 const struct comedi_lrange *bip_5;
204 const struct comedi_lrange *bip_2_5;
205 const struct comedi_lrange *unip_5;
208 enum { card_2811_pgh, card_2811_pgl };
210 struct dt2811_private {
211 int ntrig;
212 int curadchan;
213 enum {
214 adc_singleended, adc_diff, adc_pseudo_diff
215 } adc_mux;
216 enum {
217 dac_bipolar_5, dac_bipolar_2_5, dac_unipolar_5
218 } dac_range[2];
219 const struct comedi_lrange *range_type_list[2];
220 unsigned int ao_readback[2];
223 static const struct comedi_lrange *dac_range_types[] = {
224 &range_bipolar5,
225 &range_bipolar2_5,
226 &range_unipolar5
229 #define DT2811_TIMEOUT 5
231 #if 0
232 static irqreturn_t dt2811_interrupt(int irq, void *d)
234 int lo, hi;
235 int data;
236 struct comedi_device *dev = d;
237 struct dt2811_private *devpriv = dev->private;
239 if (!dev->attached) {
240 comedi_error(dev, "spurious interrupt");
241 return IRQ_HANDLED;
244 lo = inb(dev->iobase + DT2811_ADDATLO);
245 hi = inb(dev->iobase + DT2811_ADDATHI);
247 data = lo + (hi << 8);
249 if (!(--devpriv->ntrig)) {
250 /* how to turn off acquisition */
251 s->async->events |= COMEDI_SB_EOA;
253 comedi_event(dev, s);
254 return IRQ_HANDLED;
256 #endif
258 static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
259 struct comedi_insn *insn, unsigned int *data)
261 int chan = CR_CHAN(insn->chanspec);
262 int timeout = DT2811_TIMEOUT;
263 int i;
265 for (i = 0; i < insn->n; i++) {
266 outb(chan, dev->iobase + DT2811_ADGCR);
268 while (timeout
269 && inb(dev->iobase + DT2811_ADCSR) & DT2811_ADBUSY)
270 timeout--;
271 if (!timeout)
272 return -ETIME;
274 data[i] = inb(dev->iobase + DT2811_ADDATLO);
275 data[i] |= inb(dev->iobase + DT2811_ADDATHI) << 8;
276 data[i] &= 0xfff;
279 return i;
282 #if 0
283 /* Wow. This is code from the Comedi stone age. But it hasn't been
284 * replaced, so I'll let it stay. */
285 int dt2811_adtrig(kdev_t minor, comedi_adtrig *adtrig)
287 struct comedi_device *dev = comedi_devices + minor;
289 if (adtrig->n < 1)
290 return 0;
291 dev->curadchan = adtrig->chan;
292 switch (dev->i_admode) {
293 case COMEDI_MDEMAND:
294 dev->ntrig = adtrig->n - 1;
295 /* not necessary */
296 /*printk("dt2811: AD soft trigger\n"); */
297 /*outb(DT2811_CLRERROR|DT2811_INTENB,
298 dev->iobase+DT2811_ADCSR); */
299 outb(dev->curadchan, dev->iobase + DT2811_ADGCR);
300 do_gettimeofday(&trigtime);
301 break;
302 case COMEDI_MCONTS:
303 dev->ntrig = adtrig->n;
304 break;
307 return 0;
309 #endif
311 static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
312 struct comedi_insn *insn, unsigned int *data)
314 struct dt2811_private *devpriv = dev->private;
315 int i;
316 int chan;
318 chan = CR_CHAN(insn->chanspec);
320 for (i = 0; i < insn->n; i++) {
321 outb(data[i] & 0xff, dev->iobase + DT2811_DADAT0LO + 2 * chan);
322 outb((data[i] >> 8) & 0xff,
323 dev->iobase + DT2811_DADAT0HI + 2 * chan);
324 devpriv->ao_readback[chan] = data[i];
327 return i;
330 static int dt2811_ao_insn_read(struct comedi_device *dev,
331 struct comedi_subdevice *s,
332 struct comedi_insn *insn, unsigned int *data)
334 struct dt2811_private *devpriv = dev->private;
335 int i;
336 int chan;
338 chan = CR_CHAN(insn->chanspec);
340 for (i = 0; i < insn->n; i++)
341 data[i] = devpriv->ao_readback[chan];
343 return i;
346 static int dt2811_di_insn_bits(struct comedi_device *dev,
347 struct comedi_subdevice *s,
348 struct comedi_insn *insn, unsigned int *data)
350 data[1] = inb(dev->iobase + DT2811_DIO);
352 return insn->n;
355 static int dt2811_do_insn_bits(struct comedi_device *dev,
356 struct comedi_subdevice *s,
357 struct comedi_insn *insn, unsigned int *data)
359 s->state &= ~data[0];
360 s->state |= data[0] & data[1];
361 outb(s->state, dev->iobase + DT2811_DIO);
363 data[1] = s->state;
365 return insn->n;
369 options[0] Board base address
370 options[1] IRQ
371 options[2] Input configuration
372 0 == single-ended
373 1 == differential
374 2 == pseudo-differential
375 options[3] Analog input range configuration
376 0 == bipolar 5 (-5V -- +5V)
377 1 == bipolar 2.5V (-2.5V -- +2.5V)
378 2 == unipolar 5V (0V -- +5V)
379 options[4] Analog output 0 range configuration
380 0 == bipolar 5 (-5V -- +5V)
381 1 == bipolar 2.5V (-2.5V -- +2.5V)
382 2 == unipolar 5V (0V -- +5V)
383 options[5] Analog output 1 range configuration
384 0 == bipolar 5 (-5V -- +5V)
385 1 == bipolar 2.5V (-2.5V -- +2.5V)
386 2 == unipolar 5V (0V -- +5V)
388 static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it)
390 /* int i, irq; */
391 /* unsigned long irqs; */
392 /* long flags; */
394 const struct dt2811_board *board = comedi_board(dev);
395 struct dt2811_private *devpriv;
396 int ret;
397 struct comedi_subdevice *s;
399 ret = comedi_request_region(dev, it->options[0], DT2811_SIZE);
400 if (ret)
401 return ret;
403 #if 0
404 outb(0, dev->iobase + DT2811_ADCSR);
405 udelay(100);
406 i = inb(dev->iobase + DT2811_ADDATLO);
407 i = inb(dev->iobase + DT2811_ADDATHI);
408 #endif
410 #if 0
411 irq = it->options[1];
412 if (irq < 0) {
413 save_flags(flags);
414 sti();
415 irqs = probe_irq_on();
417 outb(DT2811_CLRERROR | DT2811_INTENB,
418 dev->iobase + DT2811_ADCSR);
419 outb(0, dev->iobase + DT2811_ADGCR);
421 udelay(100);
423 irq = probe_irq_off(irqs);
424 restore_flags(flags);
426 /*outb(DT2811_CLRERROR|DT2811_INTENB,
427 dev->iobase+DT2811_ADCSR);*/
429 if (inb(dev->iobase + DT2811_ADCSR) & DT2811_ADERROR)
430 printk(KERN_ERR "error probing irq (bad)\n");
431 dev->irq = 0;
432 if (irq > 0) {
433 i = inb(dev->iobase + DT2811_ADDATLO);
434 i = inb(dev->iobase + DT2811_ADDATHI);
435 printk(KERN_INFO "(irq = %d)\n", irq);
436 ret = request_irq(irq, dt2811_interrupt, 0,
437 dev->board_name, dev);
438 if (ret < 0)
439 return -EIO;
440 dev->irq = irq;
441 } else if (irq == 0) {
442 printk(KERN_INFO "(no irq)\n");
443 } else {
444 printk(KERN_ERR "( multiple irq's -- this is bad! )\n");
447 #endif
449 ret = comedi_alloc_subdevices(dev, 4);
450 if (ret)
451 return ret;
453 devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
454 if (!devpriv)
455 return -ENOMEM;
456 dev->private = devpriv;
458 switch (it->options[2]) {
459 case 0:
460 devpriv->adc_mux = adc_singleended;
461 break;
462 case 1:
463 devpriv->adc_mux = adc_diff;
464 break;
465 case 2:
466 devpriv->adc_mux = adc_pseudo_diff;
467 break;
468 default:
469 devpriv->adc_mux = adc_singleended;
470 break;
472 switch (it->options[4]) {
473 case 0:
474 devpriv->dac_range[0] = dac_bipolar_5;
475 break;
476 case 1:
477 devpriv->dac_range[0] = dac_bipolar_2_5;
478 break;
479 case 2:
480 devpriv->dac_range[0] = dac_unipolar_5;
481 break;
482 default:
483 devpriv->dac_range[0] = dac_bipolar_5;
484 break;
486 switch (it->options[5]) {
487 case 0:
488 devpriv->dac_range[1] = dac_bipolar_5;
489 break;
490 case 1:
491 devpriv->dac_range[1] = dac_bipolar_2_5;
492 break;
493 case 2:
494 devpriv->dac_range[1] = dac_unipolar_5;
495 break;
496 default:
497 devpriv->dac_range[1] = dac_bipolar_5;
498 break;
501 s = &dev->subdevices[0];
502 /* initialize the ADC subdevice */
503 s->type = COMEDI_SUBD_AI;
504 s->subdev_flags = SDF_READABLE | SDF_GROUND;
505 s->n_chan = devpriv->adc_mux == adc_diff ? 8 : 16;
506 s->insn_read = dt2811_ai_insn;
507 s->maxdata = 0xfff;
508 switch (it->options[3]) {
509 case 0:
510 default:
511 s->range_table = board->bip_5;
512 break;
513 case 1:
514 s->range_table = board->bip_2_5;
515 break;
516 case 2:
517 s->range_table = board->unip_5;
518 break;
521 s = &dev->subdevices[1];
522 /* ao subdevice */
523 s->type = COMEDI_SUBD_AO;
524 s->subdev_flags = SDF_WRITABLE;
525 s->n_chan = 2;
526 s->insn_write = dt2811_ao_insn;
527 s->insn_read = dt2811_ao_insn_read;
528 s->maxdata = 0xfff;
529 s->range_table_list = devpriv->range_type_list;
530 devpriv->range_type_list[0] = dac_range_types[devpriv->dac_range[0]];
531 devpriv->range_type_list[1] = dac_range_types[devpriv->dac_range[1]];
533 s = &dev->subdevices[2];
534 /* di subdevice */
535 s->type = COMEDI_SUBD_DI;
536 s->subdev_flags = SDF_READABLE;
537 s->n_chan = 8;
538 s->insn_bits = dt2811_di_insn_bits;
539 s->maxdata = 1;
540 s->range_table = &range_digital;
542 s = &dev->subdevices[3];
543 /* do subdevice */
544 s->type = COMEDI_SUBD_DO;
545 s->subdev_flags = SDF_WRITABLE;
546 s->n_chan = 8;
547 s->insn_bits = dt2811_do_insn_bits;
548 s->maxdata = 1;
549 s->state = 0;
550 s->range_table = &range_digital;
552 return 0;
555 static const struct dt2811_board boardtypes[] = {
557 .name = "dt2811-pgh",
558 .bip_5 = &range_dt2811_pgh_ai_5_bipolar,
559 .bip_2_5 = &range_dt2811_pgh_ai_2_5_bipolar,
560 .unip_5 = &range_dt2811_pgh_ai_5_unipolar,
561 }, {
562 .name = "dt2811-pgl",
563 .bip_5 = &range_dt2811_pgl_ai_5_bipolar,
564 .bip_2_5 = &range_dt2811_pgl_ai_2_5_bipolar,
565 .unip_5 = &range_dt2811_pgl_ai_5_unipolar,
569 static struct comedi_driver dt2811_driver = {
570 .driver_name = "dt2811",
571 .module = THIS_MODULE,
572 .attach = dt2811_attach,
573 .detach = comedi_legacy_detach,
574 .board_name = &boardtypes[0].name,
575 .num_names = ARRAY_SIZE(boardtypes),
576 .offset = sizeof(struct dt2811_board),
578 module_comedi_driver(dt2811_driver);
580 MODULE_AUTHOR("Comedi http://www.comedi.org");
581 MODULE_DESCRIPTION("Comedi low-level driver");
582 MODULE_LICENSE("GPL");