]> git.proxmox.com Git - mirror_ubuntu-kernels.git/blob - drivers/staging/comedi/drivers/dt2801.c
Staging: comedi: Remove C99 comments
[mirror_ubuntu-kernels.git] / drivers / staging / comedi / drivers / dt2801.c
1 /*
2 * comedi/drivers/dt2801.c
3 * Device Driver for DataTranslation DT2801
4 *
5 */
6 /*
7 Driver: dt2801
8 Description: Data Translation DT2801 series and DT01-EZ
9 Author: ds
10 Status: works
11 Devices: [Data Translation] DT2801 (dt2801), DT2801-A, DT2801/5716A,
12 DT2805, DT2805/5716A, DT2808, DT2818, DT2809, DT01-EZ
13
14 This driver can autoprobe the type of board.
15
16 Configuration options:
17 [0] - I/O port base address
18 [1] - unused
19 [2] - A/D reference 0=differential, 1=single-ended
20 [3] - A/D range
21 0 = [-10,10]
22 1 = [0,10]
23 [4] - D/A 0 range
24 0 = [-10,10]
25 1 = [-5,5]
26 2 = [-2.5,2.5]
27 3 = [0,10]
28 4 = [0,5]
29 [5] - D/A 1 range (same choices)
30 */
31
32 #include "../comedidev.h"
33 #include <linux/delay.h>
34 #include <linux/ioport.h>
35
36 #define DT2801_TIMEOUT 1000
37
38 /* Hardware Configuration */
39 /* ====================== */
40
41 #define DT2801_MAX_DMA_SIZE (64 * 1024)
42
43 /* Ports */
44 #define DT2801_IOSIZE 2
45
46 /* define's */
47 /* ====================== */
48
49 /* Commands */
50 #define DT_C_RESET 0x0
51 #define DT_C_CLEAR_ERR 0x1
52 #define DT_C_READ_ERRREG 0x2
53 #define DT_C_SET_CLOCK 0x3
54
55 #define DT_C_TEST 0xb
56 #define DT_C_STOP 0xf
57
58 #define DT_C_SET_DIGIN 0x4
59 #define DT_C_SET_DIGOUT 0x5
60 #define DT_C_READ_DIG 0x6
61 #define DT_C_WRITE_DIG 0x7
62
63 #define DT_C_WRITE_DAIM 0x8
64 #define DT_C_SET_DA 0x9
65 #define DT_C_WRITE_DA 0xa
66
67 #define DT_C_READ_ADIM 0xc
68 #define DT_C_SET_AD 0xd
69 #define DT_C_READ_AD 0xe
70
71 /* Command modifiers (only used with read/write), EXTTRIG can be
72 used with some other commands.
73 */
74 #define DT_MOD_DMA (1<<4)
75 #define DT_MOD_CONT (1<<5)
76 #define DT_MOD_EXTCLK (1<<6)
77 #define DT_MOD_EXTTRIG (1<<7)
78
79 /* Bits in status register */
80 #define DT_S_DATA_OUT_READY (1<<0)
81 #define DT_S_DATA_IN_FULL (1<<1)
82 #define DT_S_READY (1<<2)
83 #define DT_S_COMMAND (1<<3)
84 #define DT_S_COMPOSITE_ERROR (1<<7)
85
86 /* registers */
87 #define DT2801_DATA 0
88 #define DT2801_STATUS 1
89 #define DT2801_CMD 1
90
91 static int dt2801_attach(struct comedi_device * dev, struct comedi_devconfig * it);
92 static int dt2801_detach(struct comedi_device * dev);
93 static struct comedi_driver driver_dt2801 = {
94 driver_name:"dt2801",
95 module:THIS_MODULE,
96 attach:dt2801_attach,
97 detach:dt2801_detach,
98 };
99
100 COMEDI_INITCLEANUP(driver_dt2801);
101
102 #if 0
103 /* ignore 'defined but not used' warning */
104 static const struct comedi_lrange range_dt2801_ai_pgh_bipolar = { 4, {
105 RANGE(-10, 10),
106 RANGE(-5, 5),
107 RANGE(-2.5, 2.5),
108 RANGE(-1.25, 1.25),
109 }
110 };
111 #endif
112 static const struct comedi_lrange range_dt2801_ai_pgl_bipolar = { 4, {
113 RANGE(-10, 10),
114 RANGE(-1, 1),
115 RANGE(-0.1, 0.1),
116 RANGE(-0.02, 0.02),
117 }
118 };
119
120 #if 0
121 /* ignore 'defined but not used' warning */
122 static const struct comedi_lrange range_dt2801_ai_pgh_unipolar = { 4, {
123 RANGE(0, 10),
124 RANGE(0, 5),
125 RANGE(0, 2.5),
126 RANGE(0, 1.25),
127 }
128 };
129 #endif
130 static const struct comedi_lrange range_dt2801_ai_pgl_unipolar = { 4, {
131 RANGE(0, 10),
132 RANGE(0, 1),
133 RANGE(0, 0.1),
134 RANGE(0, 0.02),
135 }
136 };
137
138 struct dt2801_board {
139
140 const char *name;
141 int boardcode;
142 int ad_diff;
143 int ad_chan;
144 int adbits;
145 int adrangetype;
146 int dabits;
147 };
148
149
150 /* Typeid's for the different boards of the DT2801-series
151 (taken from the test-software, that comes with the board)
152 */
153 static const struct dt2801_board boardtypes[] = {
154 {
155 name: "dt2801",
156 boardcode:0x09,
157 ad_diff: 2,
158 ad_chan: 16,
159 adbits: 12,
160 adrangetype:0,
161 dabits: 12},
162 {
163 name: "dt2801-a",
164 boardcode:0x52,
165 ad_diff: 2,
166 ad_chan: 16,
167 adbits: 12,
168 adrangetype:0,
169 dabits: 12},
170 {
171 name: "dt2801/5716a",
172 boardcode:0x82,
173 ad_diff: 1,
174 ad_chan: 16,
175 adbits: 16,
176 adrangetype:1,
177 dabits: 12},
178 {
179 name: "dt2805",
180 boardcode:0x12,
181 ad_diff: 1,
182 ad_chan: 16,
183 adbits: 12,
184 adrangetype:0,
185 dabits: 12},
186 {
187 name: "dt2805/5716a",
188 boardcode:0x92,
189 ad_diff: 1,
190 ad_chan: 16,
191 adbits: 16,
192 adrangetype:1,
193 dabits: 12},
194 {
195 name: "dt2808",
196 boardcode:0x20,
197 ad_diff: 0,
198 ad_chan: 16,
199 adbits: 12,
200 adrangetype:2,
201 dabits: 8},
202 {
203 name: "dt2818",
204 boardcode:0xa2,
205 ad_diff: 0,
206 ad_chan: 4,
207 adbits: 12,
208 adrangetype:0,
209 dabits: 12},
210 {
211 name: "dt2809",
212 boardcode:0xb0,
213 ad_diff: 0,
214 ad_chan: 8,
215 adbits: 12,
216 adrangetype:1,
217 dabits: 12},
218 };
219
220 #define n_boardtypes ((sizeof(boardtypes))/(sizeof(boardtypes[0])))
221 #define boardtype (*(const struct dt2801_board *)dev->board_ptr)
222
223 struct dt2801_private {
224
225 const struct comedi_lrange *dac_range_types[2];
226 unsigned int ao_readback[2];
227 };
228
229 #define devpriv ((struct dt2801_private *)dev->private)
230
231 static int dt2801_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
232 struct comedi_insn * insn, unsigned int * data);
233 static int dt2801_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
234 struct comedi_insn * insn, unsigned int * data);
235 static int dt2801_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice * s,
236 struct comedi_insn * insn, unsigned int * data);
237 static int dt2801_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
238 struct comedi_insn * insn, unsigned int * data);
239 static int dt2801_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s,
240 struct comedi_insn * insn, unsigned int * data);
241
242 /* These are the low-level routines:
243 writecommand: write a command to the board
244 writedata: write data byte
245 readdata: read data byte
246 */
247
248 /* Only checks DataOutReady-flag, not the Ready-flag as it is done
249 in the examples of the manual. I don't see why this should be
250 necessary. */
251 static int dt2801_readdata(struct comedi_device * dev, int *data)
252 {
253 int stat = 0;
254 int timeout = DT2801_TIMEOUT;
255
256 do {
257 stat = inb_p(dev->iobase + DT2801_STATUS);
258 if (stat & (DT_S_COMPOSITE_ERROR | DT_S_READY)) {
259 return stat;
260 }
261 if (stat & DT_S_DATA_OUT_READY) {
262 *data = inb_p(dev->iobase + DT2801_DATA);
263 return 0;
264 }
265 } while (--timeout > 0);
266
267 return -ETIME;
268 }
269
270 static int dt2801_readdata2(struct comedi_device * dev, int *data)
271 {
272 int lb, hb;
273 int ret;
274
275 ret = dt2801_readdata(dev, &lb);
276 if (ret)
277 return ret;
278 ret = dt2801_readdata(dev, &hb);
279 if (ret)
280 return ret;
281
282 *data = (hb << 8) + lb;
283 return 0;
284 }
285
286 static int dt2801_writedata(struct comedi_device * dev, unsigned int data)
287 {
288 int stat = 0;
289 int timeout = DT2801_TIMEOUT;
290
291 do {
292 stat = inb_p(dev->iobase + DT2801_STATUS);
293
294 if (stat & DT_S_COMPOSITE_ERROR) {
295 return stat;
296 }
297 if (!(stat & DT_S_DATA_IN_FULL)) {
298 outb_p(data & 0xff, dev->iobase + DT2801_DATA);
299 return 0;
300 }
301 #if 0
302 if (stat & DT_S_READY) {
303 printk("dt2801: ready flag set (bad!) in dt2801_writedata()\n");
304 return -EIO;
305 }
306 #endif
307 } while (--timeout > 0);
308
309 return -ETIME;
310 }
311
312 static int dt2801_writedata2(struct comedi_device * dev, unsigned int data)
313 {
314 int ret;
315
316 ret = dt2801_writedata(dev, data & 0xff);
317 if (ret < 0)
318 return ret;
319 ret = dt2801_writedata(dev, (data >> 8));
320 if (ret < 0)
321 return ret;
322
323 return 0;
324 }
325
326 static int dt2801_wait_for_ready(struct comedi_device * dev)
327 {
328 int timeout = DT2801_TIMEOUT;
329 int stat;
330
331 stat = inb_p(dev->iobase + DT2801_STATUS);
332 if (stat & DT_S_READY) {
333 return 0;
334 }
335 do {
336 stat = inb_p(dev->iobase + DT2801_STATUS);
337
338 if (stat & DT_S_COMPOSITE_ERROR) {
339 return stat;
340 }
341 if (stat & DT_S_READY) {
342 return 0;
343 }
344 } while (--timeout > 0);
345
346 return -ETIME;
347 }
348
349 static int dt2801_writecmd(struct comedi_device * dev, int command)
350 {
351 int stat;
352
353 dt2801_wait_for_ready(dev);
354
355 stat = inb_p(dev->iobase + DT2801_STATUS);
356 if (stat & DT_S_COMPOSITE_ERROR) {
357 printk("dt2801: composite-error in dt2801_writecmd(), ignoring\n");
358 }
359 if (!(stat & DT_S_READY)) {
360 printk("dt2801: !ready in dt2801_writecmd(), ignoring\n");
361 }
362 outb_p(command, dev->iobase + DT2801_CMD);
363
364 return 0;
365 }
366
367 static int dt2801_reset(struct comedi_device * dev)
368 {
369 int board_code = 0;
370 unsigned int stat;
371 int timeout;
372
373 DPRINTK("dt2801: resetting board...\n");
374 DPRINTK("fingerprint: 0x%02x 0x%02x\n", inb_p(dev->iobase),
375 inb_p(dev->iobase + 1));
376
377 /* pull random data from data port */
378 inb_p(dev->iobase + DT2801_DATA);
379 inb_p(dev->iobase + DT2801_DATA);
380 inb_p(dev->iobase + DT2801_DATA);
381 inb_p(dev->iobase + DT2801_DATA);
382
383 DPRINTK("dt2801: stop\n");
384 /* dt2801_writecmd(dev,DT_C_STOP); */
385 outb_p(DT_C_STOP, dev->iobase + DT2801_CMD);
386
387 /* dt2801_wait_for_ready(dev); */
388 comedi_udelay(100);
389 timeout = 10000;
390 do {
391 stat = inb_p(dev->iobase + DT2801_STATUS);
392 if (stat & DT_S_READY)
393 break;
394 } while (timeout--);
395 if (!timeout) {
396 printk("dt2801: timeout 1 status=0x%02x\n", stat);
397 }
398
399 /* printk("dt2801: reading dummy\n"); */
400 /* dt2801_readdata(dev,&board_code); */
401
402 DPRINTK("dt2801: reset\n");
403 outb_p(DT_C_RESET, dev->iobase + DT2801_CMD);
404 /* dt2801_writecmd(dev,DT_C_RESET); */
405
406 comedi_udelay(100);
407 timeout = 10000;
408 do {
409 stat = inb_p(dev->iobase + DT2801_STATUS);
410 if (stat & DT_S_READY)
411 break;
412 } while (timeout--);
413 if (!timeout) {
414 printk("dt2801: timeout 2 status=0x%02x\n", stat);
415 }
416
417 DPRINTK("dt2801: reading code\n");
418 dt2801_readdata(dev, &board_code);
419
420 DPRINTK("dt2801: ok. code=0x%02x\n", board_code);
421
422 return board_code;
423 }
424
425 static int probe_number_of_ai_chans(struct comedi_device * dev)
426 {
427 int n_chans;
428 int stat;
429 int data;
430
431 for (n_chans = 0; n_chans < 16; n_chans++) {
432 stat = dt2801_writecmd(dev, DT_C_READ_ADIM);
433 dt2801_writedata(dev, 0);
434 dt2801_writedata(dev, n_chans);
435 stat = dt2801_readdata2(dev, &data);
436
437 if (stat)
438 break;
439 }
440
441 dt2801_reset(dev);
442 dt2801_reset(dev);
443
444 return n_chans;
445 }
446
447 static const struct comedi_lrange *dac_range_table[] = {
448 &range_bipolar10,
449 &range_bipolar5,
450 &range_bipolar2_5,
451 &range_unipolar10,
452 &range_unipolar5
453 };
454
455 static const struct comedi_lrange *dac_range_lkup(int opt)
456 {
457 if (opt < 0 || opt > 5)
458 return &range_unknown;
459 return dac_range_table[opt];
460 }
461
462 static const struct comedi_lrange *ai_range_lkup(int type, int opt)
463 {
464 switch (type) {
465 case 0:
466 return (opt) ?
467 &range_dt2801_ai_pgl_unipolar :
468 &range_dt2801_ai_pgl_bipolar;
469 case 1:
470 return (opt) ? &range_unipolar10 : &range_bipolar10;
471 case 2:
472 return &range_unipolar5;
473 }
474 return &range_unknown;
475 }
476
477 /*
478 options:
479 [0] - i/o base
480 [1] - unused
481 [2] - a/d 0=differential, 1=single-ended
482 [3] - a/d range 0=[-10,10], 1=[0,10]
483 [4] - dac0 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5]
484 [5] - dac1 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5]
485 */
486 static int dt2801_attach(struct comedi_device * dev, struct comedi_devconfig * it)
487 {
488 struct comedi_subdevice *s;
489 unsigned long iobase;
490 int board_code, type;
491 int ret = 0;
492 int n_ai_chans;
493
494 iobase = it->options[0];
495 if (!request_region(iobase, DT2801_IOSIZE, "dt2801")) {
496 comedi_error(dev, "I/O port conflict");
497 return -EIO;
498 }
499 dev->iobase = iobase;
500
501 /* do some checking */
502
503 board_code = dt2801_reset(dev);
504
505 /* heh. if it didn't work, try it again. */
506 if (!board_code)
507 board_code = dt2801_reset(dev);
508
509 for (type = 0; type < n_boardtypes; type++) {
510 if (boardtypes[type].boardcode == board_code)
511 goto havetype;
512 }
513 printk("dt2801: unrecognized board code=0x%02x, contact author\n",
514 board_code);
515 type = 0;
516
517 havetype:
518 dev->board_ptr = boardtypes + type;
519 printk("dt2801: %s at port 0x%lx", boardtype.name, iobase);
520
521 n_ai_chans = probe_number_of_ai_chans(dev);
522 printk(" (ai channels = %d)", n_ai_chans);
523
524 if ((ret = alloc_subdevices(dev, 4)) < 0)
525 goto out;
526
527 if ((ret = alloc_private(dev, sizeof(struct dt2801_private))) < 0)
528 goto out;
529
530 dev->board_name = boardtype.name;
531
532 s = dev->subdevices + 0;
533 /* ai subdevice */
534 s->type = COMEDI_SUBD_AI;
535 s->subdev_flags = SDF_READABLE | SDF_GROUND;
536 #if 1
537 s->n_chan = n_ai_chans;
538 #else
539 if (it->options[2])
540 s->n_chan = boardtype.ad_chan;
541 else
542 s->n_chan = boardtype.ad_chan / 2;
543 #endif
544 s->maxdata = (1 << boardtype.adbits) - 1;
545 s->range_table = ai_range_lkup(boardtype.adrangetype, it->options[3]);
546 s->insn_read = dt2801_ai_insn_read;
547
548 s++;
549 /* ao subdevice */
550 s->type = COMEDI_SUBD_AO;
551 s->subdev_flags = SDF_WRITABLE;
552 s->n_chan = 2;
553 s->maxdata = (1 << boardtype.dabits) - 1;
554 s->range_table_list = devpriv->dac_range_types;
555 devpriv->dac_range_types[0] = dac_range_lkup(it->options[4]);
556 devpriv->dac_range_types[1] = dac_range_lkup(it->options[5]);
557 s->insn_read = dt2801_ao_insn_read;
558 s->insn_write = dt2801_ao_insn_write;
559
560 s++;
561 /* 1st digital subdevice */
562 s->type = COMEDI_SUBD_DIO;
563 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
564 s->n_chan = 8;
565 s->maxdata = 1;
566 s->range_table = &range_digital;
567 s->insn_bits = dt2801_dio_insn_bits;
568 s->insn_config = dt2801_dio_insn_config;
569
570 s++;
571 /* 2nd digital subdevice */
572 s->type = COMEDI_SUBD_DIO;
573 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
574 s->n_chan = 8;
575 s->maxdata = 1;
576 s->range_table = &range_digital;
577 s->insn_bits = dt2801_dio_insn_bits;
578 s->insn_config = dt2801_dio_insn_config;
579
580 ret = 0;
581 out:
582 printk("\n");
583
584 return ret;
585 }
586
587 static int dt2801_detach(struct comedi_device * dev)
588 {
589 if (dev->iobase)
590 release_region(dev->iobase, DT2801_IOSIZE);
591
592 return 0;
593 }
594
595 static int dt2801_error(struct comedi_device * dev, int stat)
596 {
597 if (stat < 0) {
598 if (stat == -ETIME) {
599 printk("dt2801: timeout\n");
600 } else {
601 printk("dt2801: error %d\n", stat);
602 }
603 return stat;
604 }
605 printk("dt2801: error status 0x%02x, resetting...\n", stat);
606
607 dt2801_reset(dev);
608 dt2801_reset(dev);
609
610 return -EIO;
611 }
612
613 static int dt2801_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
614 struct comedi_insn * insn, unsigned int * data)
615 {
616 int d;
617 int stat;
618 int i;
619
620 for (i = 0; i < insn->n; i++) {
621 stat = dt2801_writecmd(dev, DT_C_READ_ADIM);
622 dt2801_writedata(dev, CR_RANGE(insn->chanspec));
623 dt2801_writedata(dev, CR_CHAN(insn->chanspec));
624 stat = dt2801_readdata2(dev, &d);
625
626 if (stat != 0)
627 return dt2801_error(dev, stat);
628
629 data[i] = d;
630 }
631
632 return i;
633 }
634
635 static int dt2801_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
636 struct comedi_insn * insn, unsigned int * data)
637 {
638 data[0] = devpriv->ao_readback[CR_CHAN(insn->chanspec)];
639
640 return 1;
641 }
642
643 static int dt2801_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice * s,
644 struct comedi_insn * insn, unsigned int * data)
645 {
646 dt2801_writecmd(dev, DT_C_WRITE_DAIM);
647 dt2801_writedata(dev, CR_CHAN(insn->chanspec));
648 dt2801_writedata2(dev, data[0]);
649
650 devpriv->ao_readback[CR_CHAN(insn->chanspec)] = data[0];
651
652 return 1;
653 }
654
655 static int dt2801_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
656 struct comedi_insn * insn, unsigned int * data)
657 {
658 int which = 0;
659
660 if (s == dev->subdevices + 4)
661 which = 1;
662
663 if (insn->n != 2)
664 return -EINVAL;
665 if (data[0]) {
666 s->state &= ~data[0];
667 s->state |= (data[0] & data[1]);
668 dt2801_writecmd(dev, DT_C_WRITE_DIG);
669 dt2801_writedata(dev, which);
670 dt2801_writedata(dev, s->state);
671 }
672 dt2801_writecmd(dev, DT_C_READ_DIG);
673 dt2801_writedata(dev, which);
674 dt2801_readdata(dev, data + 1);
675
676 return 2;
677 }
678
679 static int dt2801_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s,
680 struct comedi_insn * insn, unsigned int * data)
681 {
682 int which = 0;
683
684 if (s == dev->subdevices + 4)
685 which = 1;
686
687 /* configure */
688 if (data[0]) {
689 s->io_bits = 0xff;
690 dt2801_writecmd(dev, DT_C_SET_DIGOUT);
691 } else {
692 s->io_bits = 0;
693 dt2801_writecmd(dev, DT_C_SET_DIGIN);
694 }
695 dt2801_writedata(dev, which);
696
697 return 1;
698 }