Staging: comedi: vmk80xx.c: get the driver to build properly
[linux-2.6] / 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 }