Staging: comedi: Remove C99 comments
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / staging / comedi / drivers / dt2801.c
CommitLineData
a4c87948
DS
1/*
2 * comedi/drivers/dt2801.c
3 * Device Driver for DataTranslation DT2801
4 *
5 */
6/*
7Driver: dt2801
8Description: Data Translation DT2801 series and DT01-EZ
9Author: ds
10Status: works
11Devices: [Data Translation] DT2801 (dt2801), DT2801-A, DT2801/5716A,
12 DT2805, DT2805/5716A, DT2808, DT2818, DT2809, DT01-EZ
13
14This driver can autoprobe the type of board.
15
16Configuration 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
60efa611 46/* define's */
a4c87948
DS
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
0707bb04 91static int dt2801_attach(struct comedi_device * dev, struct comedi_devconfig * it);
71b5f4f1 92static int dt2801_detach(struct comedi_device * dev);
139dfbdf 93static struct comedi_driver driver_dt2801 = {
a4c87948
DS
94 driver_name:"dt2801",
95 module:THIS_MODULE,
96 attach:dt2801_attach,
97 detach:dt2801_detach,
98};
99
100COMEDI_INITCLEANUP(driver_dt2801);
101
102#if 0
2696fb57 103/* ignore 'defined but not used' warning */
9ced1de6 104static const struct comedi_lrange range_dt2801_ai_pgh_bipolar = { 4, {
a4c87948
DS
105 RANGE(-10, 10),
106 RANGE(-5, 5),
107 RANGE(-2.5, 2.5),
108 RANGE(-1.25, 1.25),
109 }
110};
111#endif
9ced1de6 112static const struct comedi_lrange range_dt2801_ai_pgl_bipolar = { 4, {
a4c87948
DS
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
2696fb57 121/* ignore 'defined but not used' warning */
9ced1de6 122static const struct comedi_lrange range_dt2801_ai_pgh_unipolar = { 4, {
a4c87948
DS
123 RANGE(0, 10),
124 RANGE(0, 5),
125 RANGE(0, 2.5),
126 RANGE(0, 1.25),
127 }
128};
129#endif
9ced1de6 130static const struct comedi_lrange range_dt2801_ai_pgl_unipolar = { 4, {
a4c87948
DS
131 RANGE(0, 10),
132 RANGE(0, 1),
133 RANGE(0, 0.1),
134 RANGE(0, 0.02),
135 }
136};
137
d438a179
BP
138struct dt2801_board {
139
a4c87948
DS
140 const char *name;
141 int boardcode;
142 int ad_diff;
143 int ad_chan;
144 int adbits;
145 int adrangetype;
146 int dabits;
d438a179
BP
147};
148
a4c87948
DS
149
150/* Typeid's for the different boards of the DT2801-series
151 (taken from the test-software, that comes with the board)
152 */
d438a179 153static const struct dt2801_board boardtypes[] = {
a4c87948
DS
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])))
d438a179 221#define boardtype (*(const struct dt2801_board *)dev->board_ptr)
a4c87948 222
7f435c06
BP
223struct dt2801_private {
224
9ced1de6 225 const struct comedi_lrange *dac_range_types[2];
790c5541 226 unsigned int ao_readback[2];
7f435c06
BP
227};
228
229#define devpriv ((struct dt2801_private *)dev->private)
a4c87948 230
34c43922 231static int dt2801_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
90035c08 232 struct comedi_insn * insn, unsigned int * data);
34c43922 233static int dt2801_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
90035c08 234 struct comedi_insn * insn, unsigned int * data);
34c43922 235static int dt2801_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice * s,
90035c08 236 struct comedi_insn * insn, unsigned int * data);
34c43922 237static int dt2801_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
90035c08 238 struct comedi_insn * insn, unsigned int * data);
34c43922 239static int dt2801_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s,
90035c08 240 struct comedi_insn * insn, unsigned int * data);
a4c87948
DS
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. */
71b5f4f1 251static int dt2801_readdata(struct comedi_device * dev, int *data)
a4c87948
DS
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
71b5f4f1 270static int dt2801_readdata2(struct comedi_device * dev, int *data)
a4c87948
DS
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
71b5f4f1 286static int dt2801_writedata(struct comedi_device * dev, unsigned int data)
a4c87948
DS
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
71b5f4f1 312static int dt2801_writedata2(struct comedi_device * dev, unsigned int data)
a4c87948
DS
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
71b5f4f1 326static int dt2801_wait_for_ready(struct comedi_device * dev)
a4c87948
DS
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
71b5f4f1 349static int dt2801_writecmd(struct comedi_device * dev, int command)
a4c87948
DS
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
71b5f4f1 367static int dt2801_reset(struct comedi_device * dev)
a4c87948
DS
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");
2696fb57 384 /* dt2801_writecmd(dev,DT_C_STOP); */
a4c87948
DS
385 outb_p(DT_C_STOP, dev->iobase + DT2801_CMD);
386
2696fb57 387 /* dt2801_wait_for_ready(dev); */
a4c87948
DS
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 }
2696fb57
BP
398
399 /* printk("dt2801: reading dummy\n"); */
400 /* dt2801_readdata(dev,&board_code); */
a4c87948
DS
401
402 DPRINTK("dt2801: reset\n");
403 outb_p(DT_C_RESET, dev->iobase + DT2801_CMD);
2696fb57 404 /* dt2801_writecmd(dev,DT_C_RESET); */
a4c87948
DS
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
71b5f4f1 425static int probe_number_of_ai_chans(struct comedi_device * dev)
a4c87948
DS
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
9ced1de6 447static const struct comedi_lrange *dac_range_table[] = {
a4c87948
DS
448 &range_bipolar10,
449 &range_bipolar5,
450 &range_bipolar2_5,
451 &range_unipolar10,
452 &range_unipolar5
453};
454
9ced1de6 455static const struct comedi_lrange *dac_range_lkup(int opt)
a4c87948
DS
456{
457 if (opt < 0 || opt > 5)
458 return &range_unknown;
459 return dac_range_table[opt];
460}
461
9ced1de6 462static const struct comedi_lrange *ai_range_lkup(int type, int opt)
a4c87948
DS
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*/
0707bb04 486static int dt2801_attach(struct comedi_device * dev, struct comedi_devconfig * it)
a4c87948 487{
34c43922 488 struct comedi_subdevice *s;
a4c87948
DS
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
7f435c06 527 if ((ret = alloc_private(dev, sizeof(struct dt2801_private))) < 0)
a4c87948
DS
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
71b5f4f1 587static int dt2801_detach(struct comedi_device * dev)
a4c87948
DS
588{
589 if (dev->iobase)
590 release_region(dev->iobase, DT2801_IOSIZE);
591
592 return 0;
593}
594
71b5f4f1 595static int dt2801_error(struct comedi_device * dev, int stat)
a4c87948
DS
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
34c43922 613static int dt2801_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
90035c08 614 struct comedi_insn * insn, unsigned int * data)
a4c87948
DS
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
34c43922 635static int dt2801_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
90035c08 636 struct comedi_insn * insn, unsigned int * data)
a4c87948
DS
637{
638 data[0] = devpriv->ao_readback[CR_CHAN(insn->chanspec)];
639
640 return 1;
641}
642
34c43922 643static int dt2801_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice * s,
90035c08 644 struct comedi_insn * insn, unsigned int * data)
a4c87948
DS
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
34c43922 655static int dt2801_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
90035c08 656 struct comedi_insn * insn, unsigned int * data)
a4c87948
DS
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
34c43922 679static int dt2801_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s,
90035c08 680 struct comedi_insn * insn, unsigned int * data)
a4c87948
DS
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}