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