Fix common misspellings
[linux-2.6-block.git] / drivers / staging / comedi / drivers / dt2811.c
CommitLineData
3c443716
DS
1/*
2 comedi/drivers/dt2811.c
3 Hardware driver for Data Translation DT2811
4
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 ...
11
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.
16
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.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 */
26/*
27Driver: dt2811
28Description: Data Translation DT2811
29Author: ds
30Devices: [Data Translation] DT2811-PGL (dt2811-pgl), DT2811-PGH (dt2811-pgh)
31Status: works
32
33Configuration options:
34 [0] - I/O port base address
35 [1] - IRQ, although this is currently unused
36 [2] - A/D reference
3b9fdcd5
IC
37 0 = signle-ended
38 1 = differential
3c443716
DS
39 2 = pseudo-differential (common reference)
40 [3] - A/D range
3b9fdcd5
IC
41 0 = [-5, 5]
42 1 = [-2.5, 2.5]
43 2 = [0, 5]
3c443716
DS
44 [4] - D/A 0 range (same choices)
45 [4] - D/A 1 range (same choices)
46*/
47
25436dc9 48#include <linux/interrupt.h>
3c443716
DS
49#include "../comedidev.h"
50
51#include <linux/ioport.h>
52
53static const char *driver_name = "dt2811";
54
3b9fdcd5
IC
55static const struct comedi_lrange range_dt2811_pgh_ai_5_unipolar = {
56 4, {
57 RANGE(0, 5),
58 RANGE(0, 2.5),
59 RANGE(0, 1.25),
60 RANGE(0, 0.625)
61 }
3c443716 62};
0a85b6f0 63
3b9fdcd5
IC
64static const struct comedi_lrange range_dt2811_pgh_ai_2_5_bipolar = {
65 4, {
66 RANGE(-2.5, 2.5),
67 RANGE(-1.25, 1.25),
68 RANGE(-0.625, 0.625),
69 RANGE(-0.3125, 0.3125)
70 }
3c443716 71};
0a85b6f0 72
3b9fdcd5
IC
73static const struct comedi_lrange range_dt2811_pgh_ai_5_bipolar = {
74 4, {
75 RANGE(-5, 5),
76 RANGE(-2.5, 2.5),
77 RANGE(-1.25, 1.25),
78 RANGE(-0.625, 0.625)
79 }
3c443716 80};
0a85b6f0 81
3b9fdcd5
IC
82static const struct comedi_lrange range_dt2811_pgl_ai_5_unipolar = {
83 4, {
84 RANGE(0, 5),
85 RANGE(0, 0.5),
86 RANGE(0, 0.05),
87 RANGE(0, 0.01)
88 }
3c443716 89};
0a85b6f0 90
3b9fdcd5
IC
91static const struct comedi_lrange range_dt2811_pgl_ai_2_5_bipolar = {
92 4, {
93 RANGE(-2.5, 2.5),
94 RANGE(-0.25, 0.25),
95 RANGE(-0.025, 0.025),
96 RANGE(-0.005, 0.005)
97 }
3c443716 98};
0a85b6f0 99
3b9fdcd5
IC
100static const struct comedi_lrange range_dt2811_pgl_ai_5_bipolar = {
101 4, {
102 RANGE(-5, 5),
103 RANGE(-0.5, 0.5),
104 RANGE(-0.05, 0.05),
105 RANGE(-0.01, 0.01)
106 }
3c443716
DS
107};
108
109/*
110
111 0x00 ADCSR R/W A/D Control/Status Register
112 bit 7 - (R) 1 indicates A/D conversion done
113 reading ADDAT clears bit
114 (W) ignored
115 bit 6 - (R) 1 indicates A/D error
116 (W) ignored
117 bit 5 - (R) 1 indicates A/D busy, cleared at end
118 of conversion
119 (W) ignored
120 bit 4 - (R) 0
121 (W)
122 bit 3 - (R) 0
123 bit 2 - (R/W) 1 indicates interrupts enabled
124 bits 1,0 - (R/W) mode bits
125 00 single conversion on ADGCR load
126 01 continuous conversion, internal clock,
127 (clock enabled on ADGCR load)
128 10 continuous conversion, internal clock,
129 external trigger
130 11 continuous conversion, external clock,
131 external trigger
132
133 0x01 ADGCR R/W A/D Gain/Channel Register
134 bit 6,7 - (R/W) gain select
135 00 gain=1, both PGH, PGL models
136 01 gain=2 PGH, 10 PGL
137 10 gain=4 PGH, 100 PGL
138 11 gain=8 PGH, 500 PGL
139 bit 4,5 - reserved
140 bit 3-0 - (R/W) channel select
141 channel number from 0-15
142
143 0x02,0x03 (R) ADDAT A/D Data Register
144 (W) DADAT0 D/A Data Register 0
145 0x02 low byte
146 0x03 high byte
147
148 0x04,0x05 (W) DADAT0 D/A Data Register 1
149
150 0x06 (R) DIO0 Digital Input Port 0
151 (W) DIO1 Digital Output Port 1
152
153 0x07 TMRCTR (R/W) Timer/Counter Register
154 bits 6,7 - reserved
155 bits 5-3 - Timer frequency control (mantissa)
156 543 divisor freqency (kHz)
157 000 1 600
158 001 10 60
159 010 2 300
160 011 3 200
161 100 4 150
162 101 5 120
163 110 6 100
164 111 12 50
165 bits 2-0 - Timer frequency control (exponent)
166 210 multiply divisor/divide frequency by
167 000 1
168 001 10
169 010 100
170 011 1000
171 100 10000
172 101 100000
173 110 1000000
174 111 10000000
175
176 */
177
178#define TIMEOUT 10000
179
180#define DT2811_SIZE 8
181
182#define DT2811_ADCSR 0
183#define DT2811_ADGCR 1
184#define DT2811_ADDATLO 2
185#define DT2811_ADDATHI 3
186#define DT2811_DADAT0LO 2
187#define DT2811_DADAT0HI 3
188#define DT2811_DADAT1LO 4
189#define DT2811_DADAT1HI 5
190#define DT2811_DIO 6
191#define DT2811_TMRCTR 7
192
193/*
194 * flags
195 */
196
197/* ADCSR */
198
199#define DT2811_ADDONE 0x80
200#define DT2811_ADERROR 0x40
201#define DT2811_ADBUSY 0x20
202#define DT2811_CLRERROR 0x10
203#define DT2811_INTENB 0x04
204#define DT2811_ADMODE 0x03
205
42f1884d
BP
206struct dt2811_board {
207
3c443716 208 const char *name;
9ced1de6
BP
209 const struct comedi_lrange *bip_5;
210 const struct comedi_lrange *bip_2_5;
211 const struct comedi_lrange *unip_5;
42f1884d
BP
212};
213
214static const struct dt2811_board boardtypes[] = {
3c443716 215 {"dt2811-pgh",
0a85b6f0
MT
216 &range_dt2811_pgh_ai_5_bipolar,
217 &range_dt2811_pgh_ai_2_5_bipolar,
218 &range_dt2811_pgh_ai_5_unipolar,
219 },
3c443716 220 {"dt2811-pgl",
0a85b6f0
MT
221 &range_dt2811_pgl_ai_5_bipolar,
222 &range_dt2811_pgl_ai_2_5_bipolar,
223 &range_dt2811_pgl_ai_5_unipolar,
224 },
3c443716
DS
225};
226
42f1884d 227#define this_board ((const struct dt2811_board *)dev->board_ptr)
3c443716 228
0a85b6f0
MT
229static int dt2811_attach(struct comedi_device *dev,
230 struct comedi_devconfig *it);
da91b269 231static int dt2811_detach(struct comedi_device *dev);
139dfbdf 232static struct comedi_driver driver_dt2811 = {
68c3dbff
BP
233 .driver_name = "dt2811",
234 .module = THIS_MODULE,
235 .attach = dt2811_attach,
236 .detach = dt2811_detach,
237 .board_name = &boardtypes[0].name,
8629efa4 238 .num_names = ARRAY_SIZE(boardtypes),
68c3dbff 239 .offset = sizeof(struct dt2811_board),
3c443716
DS
240};
241
7114a280
AT
242static int __init driver_dt2811_init_module(void)
243{
244 return comedi_driver_register(&driver_dt2811);
245}
246
247static void __exit driver_dt2811_cleanup_module(void)
248{
249 comedi_driver_unregister(&driver_dt2811);
250}
251
252module_init(driver_dt2811_init_module);
253module_exit(driver_dt2811_cleanup_module);
3c443716 254
da91b269 255static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0 256 struct comedi_insn *insn, unsigned int *data);
da91b269 257static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0
MT
258 struct comedi_insn *insn, unsigned int *data);
259static int dt2811_ao_insn_read(struct comedi_device *dev,
260 struct comedi_subdevice *s,
261 struct comedi_insn *insn, unsigned int *data);
262static int dt2811_di_insn_bits(struct comedi_device *dev,
263 struct comedi_subdevice *s,
264 struct comedi_insn *insn, unsigned int *data);
265static int dt2811_do_insn_bits(struct comedi_device *dev,
266 struct comedi_subdevice *s,
267 struct comedi_insn *insn, unsigned int *data);
3c443716
DS
268
269enum { card_2811_pgh, card_2811_pgl };
d89da617
BP
270
271struct dt2811_private {
3c443716
DS
272 int ntrig;
273 int curadchan;
274 enum {
275 adc_singleended, adc_diff, adc_pseudo_diff
276 } adc_mux;
277 enum {
278 dac_bipolar_5, dac_bipolar_2_5, dac_unipolar_5
279 } dac_range[2];
9ced1de6 280 const struct comedi_lrange *range_type_list[2];
790c5541 281 unsigned int ao_readback[2];
d89da617 282};
3c443716 283
d89da617 284#define devpriv ((struct dt2811_private *)dev->private)
3c443716 285
9ced1de6 286static const struct comedi_lrange *dac_range_types[] = {
3c443716
DS
287 &range_bipolar5,
288 &range_bipolar2_5,
289 &range_unipolar5
290};
291
292#define DT2811_TIMEOUT 5
293
294#if 0
70265d24 295static irqreturn_t dt2811_interrupt(int irq, void *d)
3c443716
DS
296{
297 int lo, hi;
298 int data;
71b5f4f1 299 struct comedi_device *dev = d;
3c443716
DS
300
301 if (!dev->attached) {
302 comedi_error(dev, "spurious interrupt");
303 return IRQ_HANDLED;
304 }
305
306 lo = inb(dev->iobase + DT2811_ADDATLO);
307 hi = inb(dev->iobase + DT2811_ADDATHI);
308
309 data = lo + (hi << 8);
310
311 if (!(--devpriv->ntrig)) {
312 /* how to turn off acquisition */
313 s->async->events |= COMEDI_SB_EOA;
314 }
315 comedi_event(dev, s);
316 return IRQ_HANDLED;
317}
318#endif
319
320/*
321 options[0] Board base address
322 options[1] IRQ
323 options[2] Input configuration
3b9fdcd5
IC
324 0 == single-ended
325 1 == differential
326 2 == pseudo-differential
3c443716 327 options[3] Analog input range configuration
3b9fdcd5
IC
328 0 == bipolar 5 (-5V -- +5V)
329 1 == bipolar 2.5V (-2.5V -- +2.5V)
330 2 == unipolar 5V (0V -- +5V)
3c443716 331 options[4] Analog output 0 range configuration
3b9fdcd5
IC
332 0 == bipolar 5 (-5V -- +5V)
333 1 == bipolar 2.5V (-2.5V -- +2.5V)
334 2 == unipolar 5V (0V -- +5V)
3c443716 335 options[5] Analog output 1 range configuration
3b9fdcd5
IC
336 0 == bipolar 5 (-5V -- +5V)
337 1 == bipolar 2.5V (-2.5V -- +2.5V)
338 2 == unipolar 5V (0V -- +5V)
3c443716
DS
339*/
340
da91b269 341static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it)
3c443716 342{
2696fb57
BP
343 /* int i, irq; */
344 /* unsigned long irqs; */
345 /* long flags; */
346
3c443716 347 int ret;
34c43922 348 struct comedi_subdevice *s;
3c443716
DS
349 unsigned long iobase;
350
351 iobase = it->options[0];
352
3b9fdcd5 353 printk(KERN_INFO "comedi%d: dt2811:base=0x%04lx\n", dev->minor, iobase);
3c443716
DS
354
355 if (!request_region(iobase, DT2811_SIZE, driver_name)) {
3b9fdcd5 356 printk(KERN_ERR "I/O port conflict\n");
3c443716
DS
357 return -EIO;
358 }
359
360 dev->iobase = iobase;
361 dev->board_name = this_board->name;
362
363#if 0
364 outb(0, dev->iobase + DT2811_ADCSR);
5f74ea14 365 udelay(100);
3c443716
DS
366 i = inb(dev->iobase + DT2811_ADDATLO);
367 i = inb(dev->iobase + DT2811_ADDATHI);
368#endif
369
370#if 0
371 irq = it->options[1];
372 if (irq < 0) {
373 save_flags(flags);
374 sti();
375 irqs = probe_irq_on();
376
377 outb(DT2811_CLRERROR | DT2811_INTENB,
0a85b6f0 378 dev->iobase + DT2811_ADCSR);
3c443716
DS
379 outb(0, dev->iobase + DT2811_ADGCR);
380
5f74ea14 381 udelay(100);
3c443716
DS
382
383 irq = probe_irq_off(irqs);
384 restore_flags(flags);
385
3b9fdcd5
IC
386 /*outb(DT2811_CLRERROR|DT2811_INTENB,
387 dev->iobase+DT2811_ADCSR);*/
3c443716 388
3b9fdcd5
IC
389 if (inb(dev->iobase + DT2811_ADCSR) & DT2811_ADERROR)
390 printk(KERN_ERR "error probing irq (bad)\n");
3c443716
DS
391 dev->irq = 0;
392 if (irq > 0) {
393 i = inb(dev->iobase + DT2811_ADDATLO);
394 i = inb(dev->iobase + DT2811_ADDATHI);
3b9fdcd5 395 printk(KERN_INFO "(irq = %d)\n", irq);
5f74ea14 396 ret = request_irq(irq, dt2811_interrupt, 0,
0a85b6f0 397 driver_name, dev);
3c443716
DS
398 if (ret < 0)
399 return -EIO;
400 dev->irq = irq;
401 } else if (irq == 0) {
3b9fdcd5 402 printk(KERN_INFO "(no irq)\n");
3c443716 403 } else {
3b9fdcd5 404 printk(KERN_ERR "( multiple irq's -- this is bad! )\n");
3c443716
DS
405 }
406 }
407#endif
408
c3744138
BP
409 ret = alloc_subdevices(dev, 4);
410 if (ret < 0)
3c443716 411 return ret;
c3744138
BP
412
413 ret = alloc_private(dev, sizeof(struct dt2811_private));
414 if (ret < 0)
3c443716 415 return ret;
c3744138 416
3c443716
DS
417 switch (it->options[2]) {
418 case 0:
419 devpriv->adc_mux = adc_singleended;
420 break;
421 case 1:
422 devpriv->adc_mux = adc_diff;
423 break;
424 case 2:
425 devpriv->adc_mux = adc_pseudo_diff;
426 break;
427 default:
428 devpriv->adc_mux = adc_singleended;
429 break;
430 }
431 switch (it->options[4]) {
432 case 0:
433 devpriv->dac_range[0] = dac_bipolar_5;
434 break;
435 case 1:
436 devpriv->dac_range[0] = dac_bipolar_2_5;
437 break;
438 case 2:
439 devpriv->dac_range[0] = dac_unipolar_5;
440 break;
441 default:
442 devpriv->dac_range[0] = dac_bipolar_5;
443 break;
444 }
445 switch (it->options[5]) {
446 case 0:
447 devpriv->dac_range[1] = dac_bipolar_5;
448 break;
449 case 1:
450 devpriv->dac_range[1] = dac_bipolar_2_5;
451 break;
452 case 2:
453 devpriv->dac_range[1] = dac_unipolar_5;
454 break;
455 default:
456 devpriv->dac_range[1] = dac_bipolar_5;
457 break;
458 }
459
460 s = dev->subdevices + 0;
461 /* initialize the ADC subdevice */
462 s->type = COMEDI_SUBD_AI;
463 s->subdev_flags = SDF_READABLE | SDF_GROUND;
464 s->n_chan = devpriv->adc_mux == adc_diff ? 8 : 16;
465 s->insn_read = dt2811_ai_insn;
466 s->maxdata = 0xfff;
467 switch (it->options[3]) {
468 case 0:
469 default:
470 s->range_table = this_board->bip_5;
471 break;
472 case 1:
473 s->range_table = this_board->bip_2_5;
474 break;
475 case 2:
476 s->range_table = this_board->unip_5;
477 break;
478 }
479
480 s = dev->subdevices + 1;
481 /* ao subdevice */
482 s->type = COMEDI_SUBD_AO;
483 s->subdev_flags = SDF_WRITABLE;
484 s->n_chan = 2;
485 s->insn_write = dt2811_ao_insn;
486 s->insn_read = dt2811_ao_insn_read;
487 s->maxdata = 0xfff;
488 s->range_table_list = devpriv->range_type_list;
489 devpriv->range_type_list[0] = dac_range_types[devpriv->dac_range[0]];
490 devpriv->range_type_list[1] = dac_range_types[devpriv->dac_range[1]];
491
492 s = dev->subdevices + 2;
493 /* di subdevice */
494 s->type = COMEDI_SUBD_DI;
495 s->subdev_flags = SDF_READABLE;
496 s->n_chan = 8;
497 s->insn_bits = dt2811_di_insn_bits;
498 s->maxdata = 1;
499 s->range_table = &range_digital;
500
501 s = dev->subdevices + 3;
502 /* do subdevice */
503 s->type = COMEDI_SUBD_DO;
504 s->subdev_flags = SDF_WRITABLE;
505 s->n_chan = 8;
506 s->insn_bits = dt2811_do_insn_bits;
507 s->maxdata = 1;
508 s->state = 0;
509 s->range_table = &range_digital;
510
511 return 0;
512}
513
da91b269 514static int dt2811_detach(struct comedi_device *dev)
3c443716 515{
3b9fdcd5 516 printk(KERN_INFO "comedi%d: dt2811: remove\n", dev->minor);
3c443716 517
3b9fdcd5 518 if (dev->irq)
5f74ea14 519 free_irq(dev->irq, dev);
3b9fdcd5 520 if (dev->iobase)
3c443716 521 release_region(dev->iobase, DT2811_SIZE);
3c443716
DS
522
523 return 0;
524}
525
da91b269 526static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0 527 struct comedi_insn *insn, unsigned int *data)
3c443716
DS
528{
529 int chan = CR_CHAN(insn->chanspec);
530 int timeout = DT2811_TIMEOUT;
531 int i;
532
533 for (i = 0; i < insn->n; i++) {
534 outb(chan, dev->iobase + DT2811_ADGCR);
535
536 while (timeout
0a85b6f0 537 && inb(dev->iobase + DT2811_ADCSR) & DT2811_ADBUSY)
3c443716
DS
538 timeout--;
539 if (!timeout)
540 return -ETIME;
541
542 data[i] = inb(dev->iobase + DT2811_ADDATLO);
543 data[i] |= inb(dev->iobase + DT2811_ADDATHI) << 8;
544 data[i] &= 0xfff;
545 }
546
547 return i;
548}
549
550#if 0
551/* Wow. This is code from the Comedi stone age. But it hasn't been
552 * replaced, so I'll let it stay. */
3b9fdcd5 553int dt2811_adtrig(kdev_t minor, comedi_adtrig *adtrig)
3c443716 554{
71b5f4f1 555 struct comedi_device *dev = comedi_devices + minor;
3c443716
DS
556
557 if (adtrig->n < 1)
558 return 0;
559 dev->curadchan = adtrig->chan;
560 switch (dev->i_admode) {
561 case COMEDI_MDEMAND:
562 dev->ntrig = adtrig->n - 1;
25985edc 563 /* not necessary */
3c443716 564 /*printk("dt2811: AD soft trigger\n"); */
3b9fdcd5
IC
565 /*outb(DT2811_CLRERROR|DT2811_INTENB,
566 dev->iobase+DT2811_ADCSR); */
3c443716
DS
567 outb(dev->curadchan, dev->iobase + DT2811_ADGCR);
568 do_gettimeofday(&trigtime);
569 break;
570 case COMEDI_MCONTS:
571 dev->ntrig = adtrig->n;
572 break;
573 }
574
575 return 0;
576}
577#endif
578
da91b269 579static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0 580 struct comedi_insn *insn, unsigned int *data)
3c443716
DS
581{
582 int i;
583 int chan;
584
585 chan = CR_CHAN(insn->chanspec);
586
587 for (i = 0; i < insn->n; i++) {
588 outb(data[i] & 0xff, dev->iobase + DT2811_DADAT0LO + 2 * chan);
589 outb((data[i] >> 8) & 0xff,
0a85b6f0 590 dev->iobase + DT2811_DADAT0HI + 2 * chan);
3c443716
DS
591 devpriv->ao_readback[chan] = data[i];
592 }
593
594 return i;
595}
596
0a85b6f0
MT
597static int dt2811_ao_insn_read(struct comedi_device *dev,
598 struct comedi_subdevice *s,
599 struct comedi_insn *insn, unsigned int *data)
3c443716
DS
600{
601 int i;
602 int chan;
603
604 chan = CR_CHAN(insn->chanspec);
605
3b9fdcd5 606 for (i = 0; i < insn->n; i++)
3c443716 607 data[i] = devpriv->ao_readback[chan];
3c443716
DS
608
609 return i;
610}
611
0a85b6f0
MT
612static int dt2811_di_insn_bits(struct comedi_device *dev,
613 struct comedi_subdevice *s,
614 struct comedi_insn *insn, unsigned int *data)
3c443716
DS
615{
616 if (insn->n != 2)
617 return -EINVAL;
618
619 data[1] = inb(dev->iobase + DT2811_DIO);
620
621 return 2;
622}
623
0a85b6f0
MT
624static int dt2811_do_insn_bits(struct comedi_device *dev,
625 struct comedi_subdevice *s,
626 struct comedi_insn *insn, unsigned int *data)
3c443716
DS
627{
628 if (insn->n != 2)
629 return -EINVAL;
630
631 s->state &= ~data[0];
632 s->state |= data[0] & data[1];
633 outb(s->state, dev->iobase + DT2811_DIO);
634
635 data[1] = s->state;
636
637 return 2;
638}
90f703d3
AT
639
640MODULE_AUTHOR("Comedi http://www.comedi.org");
641MODULE_DESCRIPTION("Comedi low-level driver");
642MODULE_LICENSE("GPL");