staging: comedi: remove FSF address from boilerplate text
[deliverable/linux.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.
3c443716
DS
21 */
22/*
23Driver: dt2811
24Description: Data Translation DT2811
25Author: ds
26Devices: [Data Translation] DT2811-PGL (dt2811-pgl), DT2811-PGH (dt2811-pgh)
27Status: works
28
29Configuration options:
30 [0] - I/O port base address
31 [1] - IRQ, although this is currently unused
32 [2] - A/D reference
3b9fdcd5
IC
33 0 = signle-ended
34 1 = differential
3c443716
DS
35 2 = pseudo-differential (common reference)
36 [3] - A/D range
3b9fdcd5
IC
37 0 = [-5, 5]
38 1 = [-2.5, 2.5]
39 2 = [0, 5]
3c443716
DS
40 [4] - D/A 0 range (same choices)
41 [4] - D/A 1 range (same choices)
42*/
43
25436dc9 44#include <linux/interrupt.h>
3c443716
DS
45#include "../comedidev.h"
46
47#include <linux/ioport.h>
48
3b9fdcd5
IC
49static 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)
55 }
3c443716 56};
0a85b6f0 57
3b9fdcd5
IC
58static 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)
64 }
3c443716 65};
0a85b6f0 66
3b9fdcd5
IC
67static 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)
73 }
3c443716 74};
0a85b6f0 75
3b9fdcd5
IC
76static 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)
82 }
3c443716 83};
0a85b6f0 84
3b9fdcd5
IC
85static 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)
91 }
3c443716 92};
0a85b6f0 93
3b9fdcd5
IC
94static 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)
100 }
3c443716
DS
101};
102
103/*
104
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
115 (W)
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
126
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
136
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
141
142 0x04,0x05 (W) DADAT0 D/A Data Register 1
143
144 0x06 (R) DIO0 Digital Input Port 0
145 (W) DIO1 Digital Output Port 1
146
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
169
170 */
171
172#define TIMEOUT 10000
173
174#define DT2811_SIZE 8
175
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
186
187/*
188 * flags
189 */
190
191/* ADCSR */
192
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
199
42f1884d
BP
200struct dt2811_board {
201
3c443716 202 const char *name;
9ced1de6
BP
203 const struct comedi_lrange *bip_5;
204 const struct comedi_lrange *bip_2_5;
205 const struct comedi_lrange *unip_5;
42f1884d
BP
206};
207
3c443716 208enum { card_2811_pgh, card_2811_pgl };
d89da617
BP
209
210struct dt2811_private {
3c443716
DS
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];
9ced1de6 219 const struct comedi_lrange *range_type_list[2];
790c5541 220 unsigned int ao_readback[2];
d89da617 221};
3c443716 222
9ced1de6 223static const struct comedi_lrange *dac_range_types[] = {
3c443716
DS
224 &range_bipolar5,
225 &range_bipolar2_5,
226 &range_unipolar5
227};
228
229#define DT2811_TIMEOUT 5
230
231#if 0
70265d24 232static irqreturn_t dt2811_interrupt(int irq, void *d)
3c443716
DS
233{
234 int lo, hi;
235 int data;
71b5f4f1 236 struct comedi_device *dev = d;
9a1a6cf8 237 struct dt2811_private *devpriv = dev->private;
3c443716
DS
238
239 if (!dev->attached) {
240 comedi_error(dev, "spurious interrupt");
241 return IRQ_HANDLED;
242 }
243
244 lo = inb(dev->iobase + DT2811_ADDATLO);
245 hi = inb(dev->iobase + DT2811_ADDATHI);
246
247 data = lo + (hi << 8);
248
249 if (!(--devpriv->ntrig)) {
250 /* how to turn off acquisition */
251 s->async->events |= COMEDI_SB_EOA;
252 }
253 comedi_event(dev, s);
254 return IRQ_HANDLED;
255}
256#endif
257
5675d899
HS
258static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
259 struct comedi_insn *insn, unsigned int *data)
260{
261 int chan = CR_CHAN(insn->chanspec);
262 int timeout = DT2811_TIMEOUT;
263 int i;
264
265 for (i = 0; i < insn->n; i++) {
266 outb(chan, dev->iobase + DT2811_ADGCR);
267
268 while (timeout
269 && inb(dev->iobase + DT2811_ADCSR) & DT2811_ADBUSY)
270 timeout--;
271 if (!timeout)
272 return -ETIME;
273
274 data[i] = inb(dev->iobase + DT2811_ADDATLO);
275 data[i] |= inb(dev->iobase + DT2811_ADDATHI) << 8;
276 data[i] &= 0xfff;
277 }
278
279 return i;
280}
281
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. */
285int dt2811_adtrig(kdev_t minor, comedi_adtrig *adtrig)
286{
287 struct comedi_device *dev = comedi_devices + minor;
288
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;
305 }
306
307 return 0;
308}
309#endif
310
311static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
312 struct comedi_insn *insn, unsigned int *data)
313{
9a1a6cf8 314 struct dt2811_private *devpriv = dev->private;
5675d899
HS
315 int i;
316 int chan;
317
318 chan = CR_CHAN(insn->chanspec);
319
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];
325 }
326
327 return i;
328}
329
330static int dt2811_ao_insn_read(struct comedi_device *dev,
331 struct comedi_subdevice *s,
332 struct comedi_insn *insn, unsigned int *data)
333{
9a1a6cf8 334 struct dt2811_private *devpriv = dev->private;
5675d899
HS
335 int i;
336 int chan;
337
338 chan = CR_CHAN(insn->chanspec);
339
340 for (i = 0; i < insn->n; i++)
341 data[i] = devpriv->ao_readback[chan];
342
343 return i;
344}
345
346static int dt2811_di_insn_bits(struct comedi_device *dev,
347 struct comedi_subdevice *s,
348 struct comedi_insn *insn, unsigned int *data)
349{
5675d899
HS
350 data[1] = inb(dev->iobase + DT2811_DIO);
351
a2714e3e 352 return insn->n;
5675d899
HS
353}
354
355static int dt2811_do_insn_bits(struct comedi_device *dev,
356 struct comedi_subdevice *s,
357 struct comedi_insn *insn, unsigned int *data)
358{
5675d899
HS
359 s->state &= ~data[0];
360 s->state |= data[0] & data[1];
361 outb(s->state, dev->iobase + DT2811_DIO);
362
363 data[1] = s->state;
364
a2714e3e 365 return insn->n;
5675d899
HS
366}
367
3c443716
DS
368/*
369 options[0] Board base address
370 options[1] IRQ
371 options[2] Input configuration
3b9fdcd5
IC
372 0 == single-ended
373 1 == differential
374 2 == pseudo-differential
3c443716 375 options[3] Analog input range configuration
3b9fdcd5
IC
376 0 == bipolar 5 (-5V -- +5V)
377 1 == bipolar 2.5V (-2.5V -- +2.5V)
378 2 == unipolar 5V (0V -- +5V)
3c443716 379 options[4] Analog output 0 range configuration
3b9fdcd5
IC
380 0 == bipolar 5 (-5V -- +5V)
381 1 == bipolar 2.5V (-2.5V -- +2.5V)
382 2 == unipolar 5V (0V -- +5V)
3c443716 383 options[5] Analog output 1 range configuration
3b9fdcd5
IC
384 0 == bipolar 5 (-5V -- +5V)
385 1 == bipolar 2.5V (-2.5V -- +2.5V)
386 2 == unipolar 5V (0V -- +5V)
3c443716 387*/
da91b269 388static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it)
3c443716 389{
2696fb57
BP
390 /* int i, irq; */
391 /* unsigned long irqs; */
392 /* long flags; */
393
5a011d61 394 const struct dt2811_board *board = comedi_board(dev);
9a1a6cf8 395 struct dt2811_private *devpriv;
3c443716 396 int ret;
34c43922 397 struct comedi_subdevice *s;
3c443716 398
6ca3f28b
HS
399 ret = comedi_request_region(dev, it->options[0], DT2811_SIZE);
400 if (ret)
401 return ret;
3c443716
DS
402
403#if 0
404 outb(0, dev->iobase + DT2811_ADCSR);
5f74ea14 405 udelay(100);
3c443716
DS
406 i = inb(dev->iobase + DT2811_ADDATLO);
407 i = inb(dev->iobase + DT2811_ADDATHI);
408#endif
409
410#if 0
411 irq = it->options[1];
412 if (irq < 0) {
413 save_flags(flags);
414 sti();
415 irqs = probe_irq_on();
416
417 outb(DT2811_CLRERROR | DT2811_INTENB,
0a85b6f0 418 dev->iobase + DT2811_ADCSR);
3c443716
DS
419 outb(0, dev->iobase + DT2811_ADGCR);
420
5f74ea14 421 udelay(100);
3c443716
DS
422
423 irq = probe_irq_off(irqs);
424 restore_flags(flags);
425
3b9fdcd5
IC
426 /*outb(DT2811_CLRERROR|DT2811_INTENB,
427 dev->iobase+DT2811_ADCSR);*/
3c443716 428
3b9fdcd5
IC
429 if (inb(dev->iobase + DT2811_ADCSR) & DT2811_ADERROR)
430 printk(KERN_ERR "error probing irq (bad)\n");
3c443716
DS
431 dev->irq = 0;
432 if (irq > 0) {
433 i = inb(dev->iobase + DT2811_ADDATLO);
434 i = inb(dev->iobase + DT2811_ADDATHI);
3b9fdcd5 435 printk(KERN_INFO "(irq = %d)\n", irq);
5f74ea14 436 ret = request_irq(irq, dt2811_interrupt, 0,
3871a752 437 dev->board_name, dev);
3c443716
DS
438 if (ret < 0)
439 return -EIO;
440 dev->irq = irq;
441 } else if (irq == 0) {
3b9fdcd5 442 printk(KERN_INFO "(no irq)\n");
3c443716 443 } else {
3b9fdcd5 444 printk(KERN_ERR "( multiple irq's -- this is bad! )\n");
3c443716
DS
445 }
446 }
447#endif
448
2f0b9d08 449 ret = comedi_alloc_subdevices(dev, 4);
8b6c5694 450 if (ret)
3c443716 451 return ret;
c3744138 452
c34fa261
HS
453 devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
454 if (!devpriv)
455 return -ENOMEM;
456 dev->private = devpriv;
c3744138 457
3c443716
DS
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;
471 }
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;
485 }
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;
499 }
500
4ea49896 501 s = &dev->subdevices[0];
3c443716
DS
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:
5a011d61 511 s->range_table = board->bip_5;
3c443716
DS
512 break;
513 case 1:
5a011d61 514 s->range_table = board->bip_2_5;
3c443716
DS
515 break;
516 case 2:
5a011d61 517 s->range_table = board->unip_5;
3c443716
DS
518 break;
519 }
520
4ea49896 521 s = &dev->subdevices[1];
3c443716
DS
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]];
532
4ea49896 533 s = &dev->subdevices[2];
3c443716
DS
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;
541
4ea49896 542 s = &dev->subdevices[3];
3c443716
DS
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;
551
552 return 0;
553}
554
5675d899
HS
555static const struct dt2811_board boardtypes[] = {
556 {
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,
566 },
567};
3c443716 568
5675d899
HS
569static struct comedi_driver dt2811_driver = {
570 .driver_name = "dt2811",
571 .module = THIS_MODULE,
572 .attach = dt2811_attach,
3d1fe3f7 573 .detach = comedi_legacy_detach,
5675d899
HS
574 .board_name = &boardtypes[0].name,
575 .num_names = ARRAY_SIZE(boardtypes),
576 .offset = sizeof(struct dt2811_board),
577};
578module_comedi_driver(dt2811_driver);
90f703d3
AT
579
580MODULE_AUTHOR("Comedi http://www.comedi.org");
581MODULE_DESCRIPTION("Comedi low-level driver");
582MODULE_LICENSE("GPL");
This page took 0.487712 seconds and 5 git commands to generate.