Merge branch 'kmemtrace-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[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         //printk("dt2801: reading dummy\n");
399         //dt2801_readdata(dev,&board_code);
400
401         DPRINTK("dt2801: reset\n");
402         outb_p(DT_C_RESET, dev->iobase + DT2801_CMD);
403         //dt2801_writecmd(dev,DT_C_RESET);
404
405         comedi_udelay(100);
406         timeout = 10000;
407         do {
408                 stat = inb_p(dev->iobase + DT2801_STATUS);
409                 if (stat & DT_S_READY)
410                         break;
411         } while (timeout--);
412         if (!timeout) {
413                 printk("dt2801: timeout 2 status=0x%02x\n", stat);
414         }
415
416         DPRINTK("dt2801: reading code\n");
417         dt2801_readdata(dev, &board_code);
418
419         DPRINTK("dt2801: ok.  code=0x%02x\n", board_code);
420
421         return board_code;
422 }
423
424 static int probe_number_of_ai_chans(struct comedi_device * dev)
425 {
426         int n_chans;
427         int stat;
428         int data;
429
430         for (n_chans = 0; n_chans < 16; n_chans++) {
431                 stat = dt2801_writecmd(dev, DT_C_READ_ADIM);
432                 dt2801_writedata(dev, 0);
433                 dt2801_writedata(dev, n_chans);
434                 stat = dt2801_readdata2(dev, &data);
435
436                 if (stat)
437                         break;
438         }
439
440         dt2801_reset(dev);
441         dt2801_reset(dev);
442
443         return n_chans;
444 }
445
446 static const struct comedi_lrange *dac_range_table[] = {
447         &range_bipolar10,
448         &range_bipolar5,
449         &range_bipolar2_5,
450         &range_unipolar10,
451         &range_unipolar5
452 };
453
454 static const struct comedi_lrange *dac_range_lkup(int opt)
455 {
456         if (opt < 0 || opt > 5)
457                 return &range_unknown;
458         return dac_range_table[opt];
459 }
460
461 static const struct comedi_lrange *ai_range_lkup(int type, int opt)
462 {
463         switch (type) {
464         case 0:
465                 return (opt) ?
466                         &range_dt2801_ai_pgl_unipolar :
467                         &range_dt2801_ai_pgl_bipolar;
468         case 1:
469                 return (opt) ? &range_unipolar10 : &range_bipolar10;
470         case 2:
471                 return &range_unipolar5;
472         }
473         return &range_unknown;
474 }
475
476 /*
477    options:
478         [0] - i/o base
479         [1] - unused
480         [2] - a/d 0=differential, 1=single-ended
481         [3] - a/d range 0=[-10,10], 1=[0,10]
482         [4] - dac0 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5]
483         [5] - dac1 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5]
484 */
485 static int dt2801_attach(struct comedi_device * dev, struct comedi_devconfig * it)
486 {
487         struct comedi_subdevice *s;
488         unsigned long iobase;
489         int board_code, type;
490         int ret = 0;
491         int n_ai_chans;
492
493         iobase = it->options[0];
494         if (!request_region(iobase, DT2801_IOSIZE, "dt2801")) {
495                 comedi_error(dev, "I/O port conflict");
496                 return -EIO;
497         }
498         dev->iobase = iobase;
499
500         /* do some checking */
501
502         board_code = dt2801_reset(dev);
503
504         /* heh.  if it didn't work, try it again. */
505         if (!board_code)
506                 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",
513                 board_code);
514         type = 0;
515
516       havetype:
517         dev->board_ptr = boardtypes + type;
518         printk("dt2801: %s at port 0x%lx", boardtype.name, iobase);
519
520         n_ai_chans = probe_number_of_ai_chans(dev);
521         printk(" (ai channels = %d)", n_ai_chans);
522
523         if ((ret = alloc_subdevices(dev, 4)) < 0)
524                 goto out;
525
526         if ((ret = alloc_private(dev, sizeof(struct dt2801_private))) < 0)
527                 goto out;
528
529         dev->board_name = boardtype.name;
530
531         s = dev->subdevices + 0;
532         /* ai subdevice */
533         s->type = COMEDI_SUBD_AI;
534         s->subdev_flags = SDF_READABLE | SDF_GROUND;
535 #if 1
536         s->n_chan = n_ai_chans;
537 #else
538         if (it->options[2])
539                 s->n_chan = boardtype.ad_chan;
540         else
541                 s->n_chan = boardtype.ad_chan / 2;
542 #endif
543         s->maxdata = (1 << boardtype.adbits) - 1;
544         s->range_table = ai_range_lkup(boardtype.adrangetype, it->options[3]);
545         s->insn_read = dt2801_ai_insn_read;
546
547         s++;
548         /* ao subdevice */
549         s->type = COMEDI_SUBD_AO;
550         s->subdev_flags = SDF_WRITABLE;
551         s->n_chan = 2;
552         s->maxdata = (1 << boardtype.dabits) - 1;
553         s->range_table_list = devpriv->dac_range_types;
554         devpriv->dac_range_types[0] = dac_range_lkup(it->options[4]);
555         devpriv->dac_range_types[1] = dac_range_lkup(it->options[5]);
556         s->insn_read = dt2801_ao_insn_read;
557         s->insn_write = dt2801_ao_insn_write;
558
559         s++;
560         /* 1st digital subdevice */
561         s->type = COMEDI_SUBD_DIO;
562         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
563         s->n_chan = 8;
564         s->maxdata = 1;
565         s->range_table = &range_digital;
566         s->insn_bits = dt2801_dio_insn_bits;
567         s->insn_config = dt2801_dio_insn_config;
568
569         s++;
570         /* 2nd digital subdevice */
571         s->type = COMEDI_SUBD_DIO;
572         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
573         s->n_chan = 8;
574         s->maxdata = 1;
575         s->range_table = &range_digital;
576         s->insn_bits = dt2801_dio_insn_bits;
577         s->insn_config = dt2801_dio_insn_config;
578
579         ret = 0;
580       out:
581         printk("\n");
582
583         return ret;
584 }
585
586 static int dt2801_detach(struct comedi_device * dev)
587 {
588         if (dev->iobase)
589                 release_region(dev->iobase, DT2801_IOSIZE);
590
591         return 0;
592 }
593
594 static int dt2801_error(struct comedi_device * dev, int stat)
595 {
596         if (stat < 0) {
597                 if (stat == -ETIME) {
598                         printk("dt2801: timeout\n");
599                 } else {
600                         printk("dt2801: error %d\n", stat);
601                 }
602                 return stat;
603         }
604         printk("dt2801: error status 0x%02x, resetting...\n", stat);
605
606         dt2801_reset(dev);
607         dt2801_reset(dev);
608
609         return -EIO;
610 }
611
612 static int dt2801_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
613         struct comedi_insn * insn, unsigned int * data)
614 {
615         int d;
616         int stat;
617         int i;
618
619         for (i = 0; i < insn->n; i++) {
620                 stat = dt2801_writecmd(dev, DT_C_READ_ADIM);
621                 dt2801_writedata(dev, CR_RANGE(insn->chanspec));
622                 dt2801_writedata(dev, CR_CHAN(insn->chanspec));
623                 stat = dt2801_readdata2(dev, &d);
624
625                 if (stat != 0)
626                         return dt2801_error(dev, stat);
627
628                 data[i] = d;
629         }
630
631         return i;
632 }
633
634 static int dt2801_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
635         struct comedi_insn * insn, unsigned int * data)
636 {
637         data[0] = devpriv->ao_readback[CR_CHAN(insn->chanspec)];
638
639         return 1;
640 }
641
642 static int dt2801_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice * s,
643         struct comedi_insn * insn, unsigned int * data)
644 {
645         dt2801_writecmd(dev, DT_C_WRITE_DAIM);
646         dt2801_writedata(dev, CR_CHAN(insn->chanspec));
647         dt2801_writedata2(dev, data[0]);
648
649         devpriv->ao_readback[CR_CHAN(insn->chanspec)] = data[0];
650
651         return 1;
652 }
653
654 static int dt2801_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
655         struct comedi_insn * insn, unsigned int * data)
656 {
657         int which = 0;
658
659         if (s == dev->subdevices + 4)
660                 which = 1;
661
662         if (insn->n != 2)
663                 return -EINVAL;
664         if (data[0]) {
665                 s->state &= ~data[0];
666                 s->state |= (data[0] & data[1]);
667                 dt2801_writecmd(dev, DT_C_WRITE_DIG);
668                 dt2801_writedata(dev, which);
669                 dt2801_writedata(dev, s->state);
670         }
671         dt2801_writecmd(dev, DT_C_READ_DIG);
672         dt2801_writedata(dev, which);
673         dt2801_readdata(dev, data + 1);
674
675         return 2;
676 }
677
678 static int dt2801_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s,
679         struct comedi_insn * insn, unsigned int * data)
680 {
681         int which = 0;
682
683         if (s == dev->subdevices + 4)
684                 which = 1;
685
686         /* configure */
687         if (data[0]) {
688                 s->io_bits = 0xff;
689                 dt2801_writecmd(dev, DT_C_SET_DIGOUT);
690         } else {
691                 s->io_bits = 0;
692                 dt2801_writecmd(dev, DT_C_SET_DIGIN);
693         }
694         dt2801_writedata(dev, which);
695
696         return 1;
697 }