Staging: comedi: Remove comedi_insn typedef
[pandora-kernel.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 & typedef'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, 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 typedef struct {
139         const char *name;
140         int boardcode;
141         int ad_diff;
142         int ad_chan;
143         int adbits;
144         int adrangetype;
145         int dabits;
146 } boardtype_t;
147
148 /* Typeid's for the different boards of the DT2801-series
149    (taken from the test-software, that comes with the board)
150    */
151 static const boardtype_t boardtypes[] = {
152         {
153               name:     "dt2801",
154               boardcode:0x09,
155               ad_diff:  2,
156               ad_chan:  16,
157               adbits:   12,
158               adrangetype:0,
159       dabits:   12},
160         {
161               name:     "dt2801-a",
162               boardcode:0x52,
163               ad_diff:  2,
164               ad_chan:  16,
165               adbits:   12,
166               adrangetype:0,
167       dabits:   12},
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               name:     "dt2805",
178               boardcode:0x12,
179               ad_diff:  1,
180               ad_chan:  16,
181               adbits:   12,
182               adrangetype:0,
183       dabits:   12},
184         {
185               name:     "dt2805/5716a",
186               boardcode:0x92,
187               ad_diff:  1,
188               ad_chan:  16,
189               adbits:   16,
190               adrangetype:1,
191       dabits:   12},
192         {
193               name:     "dt2808",
194               boardcode:0x20,
195               ad_diff:  0,
196               ad_chan:  16,
197               adbits:   12,
198               adrangetype:2,
199       dabits:   8},
200         {
201               name:     "dt2818",
202               boardcode:0xa2,
203               ad_diff:  0,
204               ad_chan:  4,
205               adbits:   12,
206               adrangetype:0,
207       dabits:   12},
208         {
209               name:     "dt2809",
210               boardcode:0xb0,
211               ad_diff:  0,
212               ad_chan:  8,
213               adbits:   12,
214               adrangetype:1,
215       dabits:   12},
216 };
217
218 #define n_boardtypes ((sizeof(boardtypes))/(sizeof(boardtypes[0])))
219 #define boardtype (*(const boardtype_t *)dev->board_ptr)
220
221 typedef struct {
222         const struct comedi_lrange *dac_range_types[2];
223         unsigned int ao_readback[2];
224 } dt2801_private;
225 #define devpriv ((dt2801_private *)dev->private)
226
227 static int dt2801_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
228         struct comedi_insn * insn, unsigned int * data);
229 static int dt2801_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
230         struct comedi_insn * insn, unsigned int * data);
231 static int dt2801_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice * s,
232         struct comedi_insn * insn, unsigned int * data);
233 static int dt2801_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
234         struct comedi_insn * insn, unsigned int * data);
235 static int dt2801_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s,
236         struct comedi_insn * insn, unsigned int * data);
237
238 /* These are the low-level routines:
239    writecommand: write a command to the board
240    writedata: write data byte
241    readdata: read data byte
242  */
243
244 /* Only checks DataOutReady-flag, not the Ready-flag as it is done
245    in the examples of the manual. I don't see why this should be
246    necessary. */
247 static int dt2801_readdata(struct comedi_device * dev, int *data)
248 {
249         int stat = 0;
250         int timeout = DT2801_TIMEOUT;
251
252         do {
253                 stat = inb_p(dev->iobase + DT2801_STATUS);
254                 if (stat & (DT_S_COMPOSITE_ERROR | DT_S_READY)) {
255                         return stat;
256                 }
257                 if (stat & DT_S_DATA_OUT_READY) {
258                         *data = inb_p(dev->iobase + DT2801_DATA);
259                         return 0;
260                 }
261         } while (--timeout > 0);
262
263         return -ETIME;
264 }
265
266 static int dt2801_readdata2(struct comedi_device * dev, int *data)
267 {
268         int lb, hb;
269         int ret;
270
271         ret = dt2801_readdata(dev, &lb);
272         if (ret)
273                 return ret;
274         ret = dt2801_readdata(dev, &hb);
275         if (ret)
276                 return ret;
277
278         *data = (hb << 8) + lb;
279         return 0;
280 }
281
282 static int dt2801_writedata(struct comedi_device * dev, unsigned int data)
283 {
284         int stat = 0;
285         int timeout = DT2801_TIMEOUT;
286
287         do {
288                 stat = inb_p(dev->iobase + DT2801_STATUS);
289
290                 if (stat & DT_S_COMPOSITE_ERROR) {
291                         return stat;
292                 }
293                 if (!(stat & DT_S_DATA_IN_FULL)) {
294                         outb_p(data & 0xff, dev->iobase + DT2801_DATA);
295                         return 0;
296                 }
297 #if 0
298                 if (stat & DT_S_READY) {
299                         printk("dt2801: ready flag set (bad!) in dt2801_writedata()\n");
300                         return -EIO;
301                 }
302 #endif
303         } while (--timeout > 0);
304
305         return -ETIME;
306 }
307
308 static int dt2801_writedata2(struct comedi_device * dev, unsigned int data)
309 {
310         int ret;
311
312         ret = dt2801_writedata(dev, data & 0xff);
313         if (ret < 0)
314                 return ret;
315         ret = dt2801_writedata(dev, (data >> 8));
316         if (ret < 0)
317                 return ret;
318
319         return 0;
320 }
321
322 static int dt2801_wait_for_ready(struct comedi_device * dev)
323 {
324         int timeout = DT2801_TIMEOUT;
325         int stat;
326
327         stat = inb_p(dev->iobase + DT2801_STATUS);
328         if (stat & DT_S_READY) {
329                 return 0;
330         }
331         do {
332                 stat = inb_p(dev->iobase + DT2801_STATUS);
333
334                 if (stat & DT_S_COMPOSITE_ERROR) {
335                         return stat;
336                 }
337                 if (stat & DT_S_READY) {
338                         return 0;
339                 }
340         } while (--timeout > 0);
341
342         return -ETIME;
343 }
344
345 static int dt2801_writecmd(struct comedi_device * dev, int command)
346 {
347         int stat;
348
349         dt2801_wait_for_ready(dev);
350
351         stat = inb_p(dev->iobase + DT2801_STATUS);
352         if (stat & DT_S_COMPOSITE_ERROR) {
353                 printk("dt2801: composite-error in dt2801_writecmd(), ignoring\n");
354         }
355         if (!(stat & DT_S_READY)) {
356                 printk("dt2801: !ready in dt2801_writecmd(), ignoring\n");
357         }
358         outb_p(command, dev->iobase + DT2801_CMD);
359
360         return 0;
361 }
362
363 static int dt2801_reset(struct comedi_device * dev)
364 {
365         int board_code = 0;
366         unsigned int stat;
367         int timeout;
368
369         DPRINTK("dt2801: resetting board...\n");
370         DPRINTK("fingerprint: 0x%02x 0x%02x\n", inb_p(dev->iobase),
371                 inb_p(dev->iobase + 1));
372
373         /* pull random data from data port */
374         inb_p(dev->iobase + DT2801_DATA);
375         inb_p(dev->iobase + DT2801_DATA);
376         inb_p(dev->iobase + DT2801_DATA);
377         inb_p(dev->iobase + DT2801_DATA);
378
379         DPRINTK("dt2801: stop\n");
380         //dt2801_writecmd(dev,DT_C_STOP);
381         outb_p(DT_C_STOP, dev->iobase + DT2801_CMD);
382
383         //dt2801_wait_for_ready(dev);
384         comedi_udelay(100);
385         timeout = 10000;
386         do {
387                 stat = inb_p(dev->iobase + DT2801_STATUS);
388                 if (stat & DT_S_READY)
389                         break;
390         } while (timeout--);
391         if (!timeout) {
392                 printk("dt2801: timeout 1 status=0x%02x\n", stat);
393         }
394         //printk("dt2801: reading dummy\n");
395         //dt2801_readdata(dev,&board_code);
396
397         DPRINTK("dt2801: reset\n");
398         outb_p(DT_C_RESET, dev->iobase + DT2801_CMD);
399         //dt2801_writecmd(dev,DT_C_RESET);
400
401         comedi_udelay(100);
402         timeout = 10000;
403         do {
404                 stat = inb_p(dev->iobase + DT2801_STATUS);
405                 if (stat & DT_S_READY)
406                         break;
407         } while (timeout--);
408         if (!timeout) {
409                 printk("dt2801: timeout 2 status=0x%02x\n", stat);
410         }
411
412         DPRINTK("dt2801: reading code\n");
413         dt2801_readdata(dev, &board_code);
414
415         DPRINTK("dt2801: ok.  code=0x%02x\n", board_code);
416
417         return board_code;
418 }
419
420 static int probe_number_of_ai_chans(struct comedi_device * dev)
421 {
422         int n_chans;
423         int stat;
424         int data;
425
426         for (n_chans = 0; n_chans < 16; n_chans++) {
427                 stat = dt2801_writecmd(dev, DT_C_READ_ADIM);
428                 dt2801_writedata(dev, 0);
429                 dt2801_writedata(dev, n_chans);
430                 stat = dt2801_readdata2(dev, &data);
431
432                 if (stat)
433                         break;
434         }
435
436         dt2801_reset(dev);
437         dt2801_reset(dev);
438
439         return n_chans;
440 }
441
442 static const struct comedi_lrange *dac_range_table[] = {
443         &range_bipolar10,
444         &range_bipolar5,
445         &range_bipolar2_5,
446         &range_unipolar10,
447         &range_unipolar5
448 };
449
450 static const struct comedi_lrange *dac_range_lkup(int opt)
451 {
452         if (opt < 0 || opt > 5)
453                 return &range_unknown;
454         return dac_range_table[opt];
455 }
456
457 static const struct comedi_lrange *ai_range_lkup(int type, int opt)
458 {
459         switch (type) {
460         case 0:
461                 return (opt) ?
462                         &range_dt2801_ai_pgl_unipolar :
463                         &range_dt2801_ai_pgl_bipolar;
464         case 1:
465                 return (opt) ? &range_unipolar10 : &range_bipolar10;
466         case 2:
467                 return &range_unipolar5;
468         }
469         return &range_unknown;
470 }
471
472 /*
473    options:
474         [0] - i/o base
475         [1] - unused
476         [2] - a/d 0=differential, 1=single-ended
477         [3] - a/d range 0=[-10,10], 1=[0,10]
478         [4] - dac0 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5]
479         [5] - dac1 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5]
480 */
481 static int dt2801_attach(struct comedi_device * dev, comedi_devconfig * it)
482 {
483         struct comedi_subdevice *s;
484         unsigned long iobase;
485         int board_code, type;
486         int ret = 0;
487         int n_ai_chans;
488
489         iobase = it->options[0];
490         if (!request_region(iobase, DT2801_IOSIZE, "dt2801")) {
491                 comedi_error(dev, "I/O port conflict");
492                 return -EIO;
493         }
494         dev->iobase = iobase;
495
496         /* do some checking */
497
498         board_code = dt2801_reset(dev);
499
500         /* heh.  if it didn't work, try it again. */
501         if (!board_code)
502                 board_code = dt2801_reset(dev);
503
504         for (type = 0; type < n_boardtypes; type++) {
505                 if (boardtypes[type].boardcode == board_code)
506                         goto havetype;
507         }
508         printk("dt2801: unrecognized board code=0x%02x, contact author\n",
509                 board_code);
510         type = 0;
511
512       havetype:
513         dev->board_ptr = boardtypes + type;
514         printk("dt2801: %s at port 0x%lx", boardtype.name, iobase);
515
516         n_ai_chans = probe_number_of_ai_chans(dev);
517         printk(" (ai channels = %d)", n_ai_chans);
518
519         if ((ret = alloc_subdevices(dev, 4)) < 0)
520                 goto out;
521
522         if ((ret = alloc_private(dev, sizeof(dt2801_private))) < 0)
523                 goto out;
524
525         dev->board_name = boardtype.name;
526
527         s = dev->subdevices + 0;
528         /* ai subdevice */
529         s->type = COMEDI_SUBD_AI;
530         s->subdev_flags = SDF_READABLE | SDF_GROUND;
531 #if 1
532         s->n_chan = n_ai_chans;
533 #else
534         if (it->options[2])
535                 s->n_chan = boardtype.ad_chan;
536         else
537                 s->n_chan = boardtype.ad_chan / 2;
538 #endif
539         s->maxdata = (1 << boardtype.adbits) - 1;
540         s->range_table = ai_range_lkup(boardtype.adrangetype, it->options[3]);
541         s->insn_read = dt2801_ai_insn_read;
542
543         s++;
544         /* ao subdevice */
545         s->type = COMEDI_SUBD_AO;
546         s->subdev_flags = SDF_WRITABLE;
547         s->n_chan = 2;
548         s->maxdata = (1 << boardtype.dabits) - 1;
549         s->range_table_list = devpriv->dac_range_types;
550         devpriv->dac_range_types[0] = dac_range_lkup(it->options[4]);
551         devpriv->dac_range_types[1] = dac_range_lkup(it->options[5]);
552         s->insn_read = dt2801_ao_insn_read;
553         s->insn_write = dt2801_ao_insn_write;
554
555         s++;
556         /* 1st digital subdevice */
557         s->type = COMEDI_SUBD_DIO;
558         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
559         s->n_chan = 8;
560         s->maxdata = 1;
561         s->range_table = &range_digital;
562         s->insn_bits = dt2801_dio_insn_bits;
563         s->insn_config = dt2801_dio_insn_config;
564
565         s++;
566         /* 2nd digital subdevice */
567         s->type = COMEDI_SUBD_DIO;
568         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
569         s->n_chan = 8;
570         s->maxdata = 1;
571         s->range_table = &range_digital;
572         s->insn_bits = dt2801_dio_insn_bits;
573         s->insn_config = dt2801_dio_insn_config;
574
575         ret = 0;
576       out:
577         printk("\n");
578
579         return ret;
580 }
581
582 static int dt2801_detach(struct comedi_device * dev)
583 {
584         if (dev->iobase)
585                 release_region(dev->iobase, DT2801_IOSIZE);
586
587         return 0;
588 }
589
590 static int dt2801_error(struct comedi_device * dev, int stat)
591 {
592         if (stat < 0) {
593                 if (stat == -ETIME) {
594                         printk("dt2801: timeout\n");
595                 } else {
596                         printk("dt2801: error %d\n", stat);
597                 }
598                 return stat;
599         }
600         printk("dt2801: error status 0x%02x, resetting...\n", stat);
601
602         dt2801_reset(dev);
603         dt2801_reset(dev);
604
605         return -EIO;
606 }
607
608 static int dt2801_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
609         struct comedi_insn * insn, unsigned int * data)
610 {
611         int d;
612         int stat;
613         int i;
614
615         for (i = 0; i < insn->n; i++) {
616                 stat = dt2801_writecmd(dev, DT_C_READ_ADIM);
617                 dt2801_writedata(dev, CR_RANGE(insn->chanspec));
618                 dt2801_writedata(dev, CR_CHAN(insn->chanspec));
619                 stat = dt2801_readdata2(dev, &d);
620
621                 if (stat != 0)
622                         return dt2801_error(dev, stat);
623
624                 data[i] = d;
625         }
626
627         return i;
628 }
629
630 static int dt2801_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
631         struct comedi_insn * insn, unsigned int * 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(struct comedi_device * dev, struct comedi_subdevice * s,
639         struct comedi_insn * insn, unsigned int * 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(struct comedi_device * dev, struct comedi_subdevice * s,
651         struct comedi_insn * insn, unsigned int * data)
652 {
653         int which = 0;
654
655         if (s == dev->subdevices + 4)
656                 which = 1;
657
658         if (insn->n != 2)
659                 return -EINVAL;
660         if (data[0]) {
661                 s->state &= ~data[0];
662                 s->state |= (data[0] & data[1]);
663                 dt2801_writecmd(dev, DT_C_WRITE_DIG);
664                 dt2801_writedata(dev, which);
665                 dt2801_writedata(dev, s->state);
666         }
667         dt2801_writecmd(dev, DT_C_READ_DIG);
668         dt2801_writedata(dev, which);
669         dt2801_readdata(dev, data + 1);
670
671         return 2;
672 }
673
674 static int dt2801_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s,
675         struct comedi_insn * insn, unsigned int * data)
676 {
677         int which = 0;
678
679         if (s == dev->subdevices + 4)
680                 which = 1;
681
682         /* configure */
683         if (data[0]) {
684                 s->io_bits = 0xff;
685                 dt2801_writecmd(dev, DT_C_SET_DIGOUT);
686         } else {
687                 s->io_bits = 0;
688                 dt2801_writecmd(dev, DT_C_SET_DIGIN);
689         }
690         dt2801_writedata(dev, which);
691
692         return 1;
693 }