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