Staging: comedi: Remove COMEDI_MODULES_MACRO
[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
242COMEDI_INITCLEANUP(driver_dt2811);
243
da91b269 244static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0 245 struct comedi_insn *insn, unsigned int *data);
da91b269 246static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0
MT
247 struct comedi_insn *insn, unsigned int *data);
248static int dt2811_ao_insn_read(struct comedi_device *dev,
249 struct comedi_subdevice *s,
250 struct comedi_insn *insn, unsigned int *data);
251static int dt2811_di_insn_bits(struct comedi_device *dev,
252 struct comedi_subdevice *s,
253 struct comedi_insn *insn, unsigned int *data);
254static int dt2811_do_insn_bits(struct comedi_device *dev,
255 struct comedi_subdevice *s,
256 struct comedi_insn *insn, unsigned int *data);
3c443716
DS
257
258enum { card_2811_pgh, card_2811_pgl };
d89da617
BP
259
260struct dt2811_private {
3c443716
DS
261 int ntrig;
262 int curadchan;
263 enum {
264 adc_singleended, adc_diff, adc_pseudo_diff
265 } adc_mux;
266 enum {
267 dac_bipolar_5, dac_bipolar_2_5, dac_unipolar_5
268 } dac_range[2];
9ced1de6 269 const struct comedi_lrange *range_type_list[2];
790c5541 270 unsigned int ao_readback[2];
d89da617 271};
3c443716 272
d89da617 273#define devpriv ((struct dt2811_private *)dev->private)
3c443716 274
9ced1de6 275static const struct comedi_lrange *dac_range_types[] = {
3c443716
DS
276 &range_bipolar5,
277 &range_bipolar2_5,
278 &range_unipolar5
279};
280
281#define DT2811_TIMEOUT 5
282
283#if 0
70265d24 284static irqreturn_t dt2811_interrupt(int irq, void *d)
3c443716
DS
285{
286 int lo, hi;
287 int data;
71b5f4f1 288 struct comedi_device *dev = d;
3c443716
DS
289
290 if (!dev->attached) {
291 comedi_error(dev, "spurious interrupt");
292 return IRQ_HANDLED;
293 }
294
295 lo = inb(dev->iobase + DT2811_ADDATLO);
296 hi = inb(dev->iobase + DT2811_ADDATHI);
297
298 data = lo + (hi << 8);
299
300 if (!(--devpriv->ntrig)) {
301 /* how to turn off acquisition */
302 s->async->events |= COMEDI_SB_EOA;
303 }
304 comedi_event(dev, s);
305 return IRQ_HANDLED;
306}
307#endif
308
309/*
310 options[0] Board base address
311 options[1] IRQ
312 options[2] Input configuration
3b9fdcd5
IC
313 0 == single-ended
314 1 == differential
315 2 == pseudo-differential
3c443716 316 options[3] Analog input range configuration
3b9fdcd5
IC
317 0 == bipolar 5 (-5V -- +5V)
318 1 == bipolar 2.5V (-2.5V -- +2.5V)
319 2 == unipolar 5V (0V -- +5V)
3c443716 320 options[4] Analog output 0 range configuration
3b9fdcd5
IC
321 0 == bipolar 5 (-5V -- +5V)
322 1 == bipolar 2.5V (-2.5V -- +2.5V)
323 2 == unipolar 5V (0V -- +5V)
3c443716 324 options[5] Analog output 1 range configuration
3b9fdcd5
IC
325 0 == bipolar 5 (-5V -- +5V)
326 1 == bipolar 2.5V (-2.5V -- +2.5V)
327 2 == unipolar 5V (0V -- +5V)
3c443716
DS
328*/
329
da91b269 330static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it)
3c443716 331{
2696fb57
BP
332 /* int i, irq; */
333 /* unsigned long irqs; */
334 /* long flags; */
335
3c443716 336 int ret;
34c43922 337 struct comedi_subdevice *s;
3c443716
DS
338 unsigned long iobase;
339
340 iobase = it->options[0];
341
3b9fdcd5 342 printk(KERN_INFO "comedi%d: dt2811:base=0x%04lx\n", dev->minor, iobase);
3c443716
DS
343
344 if (!request_region(iobase, DT2811_SIZE, driver_name)) {
3b9fdcd5 345 printk(KERN_ERR "I/O port conflict\n");
3c443716
DS
346 return -EIO;
347 }
348
349 dev->iobase = iobase;
350 dev->board_name = this_board->name;
351
352#if 0
353 outb(0, dev->iobase + DT2811_ADCSR);
5f74ea14 354 udelay(100);
3c443716
DS
355 i = inb(dev->iobase + DT2811_ADDATLO);
356 i = inb(dev->iobase + DT2811_ADDATHI);
357#endif
358
359#if 0
360 irq = it->options[1];
361 if (irq < 0) {
362 save_flags(flags);
363 sti();
364 irqs = probe_irq_on();
365
366 outb(DT2811_CLRERROR | DT2811_INTENB,
0a85b6f0 367 dev->iobase + DT2811_ADCSR);
3c443716
DS
368 outb(0, dev->iobase + DT2811_ADGCR);
369
5f74ea14 370 udelay(100);
3c443716
DS
371
372 irq = probe_irq_off(irqs);
373 restore_flags(flags);
374
3b9fdcd5
IC
375 /*outb(DT2811_CLRERROR|DT2811_INTENB,
376 dev->iobase+DT2811_ADCSR);*/
3c443716 377
3b9fdcd5
IC
378 if (inb(dev->iobase + DT2811_ADCSR) & DT2811_ADERROR)
379 printk(KERN_ERR "error probing irq (bad)\n");
3c443716
DS
380 dev->irq = 0;
381 if (irq > 0) {
382 i = inb(dev->iobase + DT2811_ADDATLO);
383 i = inb(dev->iobase + DT2811_ADDATHI);
3b9fdcd5 384 printk(KERN_INFO "(irq = %d)\n", irq);
5f74ea14 385 ret = request_irq(irq, dt2811_interrupt, 0,
0a85b6f0 386 driver_name, dev);
3c443716
DS
387 if (ret < 0)
388 return -EIO;
389 dev->irq = irq;
390 } else if (irq == 0) {
3b9fdcd5 391 printk(KERN_INFO "(no irq)\n");
3c443716 392 } else {
3b9fdcd5 393 printk(KERN_ERR "( multiple irq's -- this is bad! )\n");
3c443716
DS
394 }
395 }
396#endif
397
c3744138
BP
398 ret = alloc_subdevices(dev, 4);
399 if (ret < 0)
3c443716 400 return ret;
c3744138
BP
401
402 ret = alloc_private(dev, sizeof(struct dt2811_private));
403 if (ret < 0)
3c443716 404 return ret;
c3744138 405
3c443716
DS
406 switch (it->options[2]) {
407 case 0:
408 devpriv->adc_mux = adc_singleended;
409 break;
410 case 1:
411 devpriv->adc_mux = adc_diff;
412 break;
413 case 2:
414 devpriv->adc_mux = adc_pseudo_diff;
415 break;
416 default:
417 devpriv->adc_mux = adc_singleended;
418 break;
419 }
420 switch (it->options[4]) {
421 case 0:
422 devpriv->dac_range[0] = dac_bipolar_5;
423 break;
424 case 1:
425 devpriv->dac_range[0] = dac_bipolar_2_5;
426 break;
427 case 2:
428 devpriv->dac_range[0] = dac_unipolar_5;
429 break;
430 default:
431 devpriv->dac_range[0] = dac_bipolar_5;
432 break;
433 }
434 switch (it->options[5]) {
435 case 0:
436 devpriv->dac_range[1] = dac_bipolar_5;
437 break;
438 case 1:
439 devpriv->dac_range[1] = dac_bipolar_2_5;
440 break;
441 case 2:
442 devpriv->dac_range[1] = dac_unipolar_5;
443 break;
444 default:
445 devpriv->dac_range[1] = dac_bipolar_5;
446 break;
447 }
448
449 s = dev->subdevices + 0;
450 /* initialize the ADC subdevice */
451 s->type = COMEDI_SUBD_AI;
452 s->subdev_flags = SDF_READABLE | SDF_GROUND;
453 s->n_chan = devpriv->adc_mux == adc_diff ? 8 : 16;
454 s->insn_read = dt2811_ai_insn;
455 s->maxdata = 0xfff;
456 switch (it->options[3]) {
457 case 0:
458 default:
459 s->range_table = this_board->bip_5;
460 break;
461 case 1:
462 s->range_table = this_board->bip_2_5;
463 break;
464 case 2:
465 s->range_table = this_board->unip_5;
466 break;
467 }
468
469 s = dev->subdevices + 1;
470 /* ao subdevice */
471 s->type = COMEDI_SUBD_AO;
472 s->subdev_flags = SDF_WRITABLE;
473 s->n_chan = 2;
474 s->insn_write = dt2811_ao_insn;
475 s->insn_read = dt2811_ao_insn_read;
476 s->maxdata = 0xfff;
477 s->range_table_list = devpriv->range_type_list;
478 devpriv->range_type_list[0] = dac_range_types[devpriv->dac_range[0]];
479 devpriv->range_type_list[1] = dac_range_types[devpriv->dac_range[1]];
480
481 s = dev->subdevices + 2;
482 /* di subdevice */
483 s->type = COMEDI_SUBD_DI;
484 s->subdev_flags = SDF_READABLE;
485 s->n_chan = 8;
486 s->insn_bits = dt2811_di_insn_bits;
487 s->maxdata = 1;
488 s->range_table = &range_digital;
489
490 s = dev->subdevices + 3;
491 /* do subdevice */
492 s->type = COMEDI_SUBD_DO;
493 s->subdev_flags = SDF_WRITABLE;
494 s->n_chan = 8;
495 s->insn_bits = dt2811_do_insn_bits;
496 s->maxdata = 1;
497 s->state = 0;
498 s->range_table = &range_digital;
499
500 return 0;
501}
502
da91b269 503static int dt2811_detach(struct comedi_device *dev)
3c443716 504{
3b9fdcd5 505 printk(KERN_INFO "comedi%d: dt2811: remove\n", dev->minor);
3c443716 506
3b9fdcd5 507 if (dev->irq)
5f74ea14 508 free_irq(dev->irq, dev);
3b9fdcd5 509 if (dev->iobase)
3c443716 510 release_region(dev->iobase, DT2811_SIZE);
3c443716
DS
511
512 return 0;
513}
514
da91b269 515static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0 516 struct comedi_insn *insn, unsigned int *data)
3c443716
DS
517{
518 int chan = CR_CHAN(insn->chanspec);
519 int timeout = DT2811_TIMEOUT;
520 int i;
521
522 for (i = 0; i < insn->n; i++) {
523 outb(chan, dev->iobase + DT2811_ADGCR);
524
525 while (timeout
0a85b6f0 526 && inb(dev->iobase + DT2811_ADCSR) & DT2811_ADBUSY)
3c443716
DS
527 timeout--;
528 if (!timeout)
529 return -ETIME;
530
531 data[i] = inb(dev->iobase + DT2811_ADDATLO);
532 data[i] |= inb(dev->iobase + DT2811_ADDATHI) << 8;
533 data[i] &= 0xfff;
534 }
535
536 return i;
537}
538
539#if 0
540/* Wow. This is code from the Comedi stone age. But it hasn't been
541 * replaced, so I'll let it stay. */
3b9fdcd5 542int dt2811_adtrig(kdev_t minor, comedi_adtrig *adtrig)
3c443716 543{
71b5f4f1 544 struct comedi_device *dev = comedi_devices + minor;
3c443716
DS
545
546 if (adtrig->n < 1)
547 return 0;
548 dev->curadchan = adtrig->chan;
549 switch (dev->i_admode) {
550 case COMEDI_MDEMAND:
551 dev->ntrig = adtrig->n - 1;
3b9fdcd5 552 /* not neccessary */
3c443716 553 /*printk("dt2811: AD soft trigger\n"); */
3b9fdcd5
IC
554 /*outb(DT2811_CLRERROR|DT2811_INTENB,
555 dev->iobase+DT2811_ADCSR); */
3c443716
DS
556 outb(dev->curadchan, dev->iobase + DT2811_ADGCR);
557 do_gettimeofday(&trigtime);
558 break;
559 case COMEDI_MCONTS:
560 dev->ntrig = adtrig->n;
561 break;
562 }
563
564 return 0;
565}
566#endif
567
da91b269 568static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0 569 struct comedi_insn *insn, unsigned int *data)
3c443716
DS
570{
571 int i;
572 int chan;
573
574 chan = CR_CHAN(insn->chanspec);
575
576 for (i = 0; i < insn->n; i++) {
577 outb(data[i] & 0xff, dev->iobase + DT2811_DADAT0LO + 2 * chan);
578 outb((data[i] >> 8) & 0xff,
0a85b6f0 579 dev->iobase + DT2811_DADAT0HI + 2 * chan);
3c443716
DS
580 devpriv->ao_readback[chan] = data[i];
581 }
582
583 return i;
584}
585
0a85b6f0
MT
586static int dt2811_ao_insn_read(struct comedi_device *dev,
587 struct comedi_subdevice *s,
588 struct comedi_insn *insn, unsigned int *data)
3c443716
DS
589{
590 int i;
591 int chan;
592
593 chan = CR_CHAN(insn->chanspec);
594
3b9fdcd5 595 for (i = 0; i < insn->n; i++)
3c443716 596 data[i] = devpriv->ao_readback[chan];
3c443716
DS
597
598 return i;
599}
600
0a85b6f0
MT
601static int dt2811_di_insn_bits(struct comedi_device *dev,
602 struct comedi_subdevice *s,
603 struct comedi_insn *insn, unsigned int *data)
3c443716
DS
604{
605 if (insn->n != 2)
606 return -EINVAL;
607
608 data[1] = inb(dev->iobase + DT2811_DIO);
609
610 return 2;
611}
612
0a85b6f0
MT
613static int dt2811_do_insn_bits(struct comedi_device *dev,
614 struct comedi_subdevice *s,
615 struct comedi_insn *insn, unsigned int *data)
3c443716
DS
616{
617 if (insn->n != 2)
618 return -EINVAL;
619
620 s->state &= ~data[0];
621 s->state |= data[0] & data[1];
622 outb(s->state, dev->iobase + DT2811_DIO);
623
624 data[1] = s->state;
625
626 return 2;
627}
90f703d3
AT
628
629MODULE_AUTHOR("Comedi http://www.comedi.org");
630MODULE_DESCRIPTION("Comedi low-level driver");
631MODULE_LICENSE("GPL");