Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / 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 <linux/module.h>
33 #include "../comedidev.h"
34 #include <linux/delay.h>
35
36 #define DT2801_TIMEOUT 1000
37
38 /* Hardware Configuration */
39 /* ====================== */
40
41 #define DT2801_MAX_DMA_SIZE (64 * 1024)
42
43 /* define's */
44 /* ====================== */
45
46 /* Commands */
47 #define DT_C_RESET       0x0
48 #define DT_C_CLEAR_ERR   0x1
49 #define DT_C_READ_ERRREG 0x2
50 #define DT_C_SET_CLOCK   0x3
51
52 #define DT_C_TEST        0xb
53 #define DT_C_STOP        0xf
54
55 #define DT_C_SET_DIGIN   0x4
56 #define DT_C_SET_DIGOUT  0x5
57 #define DT_C_READ_DIG    0x6
58 #define DT_C_WRITE_DIG   0x7
59
60 #define DT_C_WRITE_DAIM  0x8
61 #define DT_C_SET_DA      0x9
62 #define DT_C_WRITE_DA    0xa
63
64 #define DT_C_READ_ADIM   0xc
65 #define DT_C_SET_AD      0xd
66 #define DT_C_READ_AD     0xe
67
68 /* Command modifiers (only used with read/write), EXTTRIG can be
69    used with some other commands.
70 */
71 #define DT_MOD_DMA     (1<<4)
72 #define DT_MOD_CONT    (1<<5)
73 #define DT_MOD_EXTCLK  (1<<6)
74 #define DT_MOD_EXTTRIG (1<<7)
75
76 /* Bits in status register */
77 #define DT_S_DATA_OUT_READY   (1<<0)
78 #define DT_S_DATA_IN_FULL     (1<<1)
79 #define DT_S_READY            (1<<2)
80 #define DT_S_COMMAND          (1<<3)
81 #define DT_S_COMPOSITE_ERROR  (1<<7)
82
83 /* registers */
84 #define DT2801_DATA             0
85 #define DT2801_STATUS           1
86 #define DT2801_CMD              1
87
88 #if 0
89 /* ignore 'defined but not used' warning */
90 static const struct comedi_lrange range_dt2801_ai_pgh_bipolar = {
91         4, {
92                 BIP_RANGE(10),
93                 BIP_RANGE(5),
94                 BIP_RANGE(2.5),
95                 BIP_RANGE(1.25)
96         }
97 };
98 #endif
99 static const struct comedi_lrange range_dt2801_ai_pgl_bipolar = {
100         4, {
101                 BIP_RANGE(10),
102                 BIP_RANGE(1),
103                 BIP_RANGE(0.1),
104                 BIP_RANGE(0.02)
105         }
106 };
107
108 #if 0
109 /* ignore 'defined but not used' warning */
110 static const struct comedi_lrange range_dt2801_ai_pgh_unipolar = {
111         4, {
112                 UNI_RANGE(10),
113                 UNI_RANGE(5),
114                 UNI_RANGE(2.5),
115                 UNI_RANGE(1.25)
116         }
117 };
118 #endif
119 static const struct comedi_lrange range_dt2801_ai_pgl_unipolar = {
120         4, {
121                 UNI_RANGE(10),
122                 UNI_RANGE(1),
123                 UNI_RANGE(0.1),
124                 UNI_RANGE(0.02)
125         }
126 };
127
128 struct dt2801_board {
129         const char *name;
130         int boardcode;
131         int ad_diff;
132         int ad_chan;
133         int adbits;
134         int adrangetype;
135         int dabits;
136 };
137
138 /* Typeid's for the different boards of the DT2801-series
139    (taken from the test-software, that comes with the board)
140    */
141 static const struct dt2801_board boardtypes[] = {
142         {
143          .name = "dt2801",
144          .boardcode = 0x09,
145          .ad_diff = 2,
146          .ad_chan = 16,
147          .adbits = 12,
148          .adrangetype = 0,
149          .dabits = 12},
150         {
151          .name = "dt2801-a",
152          .boardcode = 0x52,
153          .ad_diff = 2,
154          .ad_chan = 16,
155          .adbits = 12,
156          .adrangetype = 0,
157          .dabits = 12},
158         {
159          .name = "dt2801/5716a",
160          .boardcode = 0x82,
161          .ad_diff = 1,
162          .ad_chan = 16,
163          .adbits = 16,
164          .adrangetype = 1,
165          .dabits = 12},
166         {
167          .name = "dt2805",
168          .boardcode = 0x12,
169          .ad_diff = 1,
170          .ad_chan = 16,
171          .adbits = 12,
172          .adrangetype = 0,
173          .dabits = 12},
174         {
175          .name = "dt2805/5716a",
176          .boardcode = 0x92,
177          .ad_diff = 1,
178          .ad_chan = 16,
179          .adbits = 16,
180          .adrangetype = 1,
181          .dabits = 12},
182         {
183          .name = "dt2808",
184          .boardcode = 0x20,
185          .ad_diff = 0,
186          .ad_chan = 16,
187          .adbits = 12,
188          .adrangetype = 2,
189          .dabits = 8},
190         {
191          .name = "dt2818",
192          .boardcode = 0xa2,
193          .ad_diff = 0,
194          .ad_chan = 4,
195          .adbits = 12,
196          .adrangetype = 0,
197          .dabits = 12},
198         {
199          .name = "dt2809",
200          .boardcode = 0xb0,
201          .ad_diff = 0,
202          .ad_chan = 8,
203          .adbits = 12,
204          .adrangetype = 1,
205          .dabits = 12},
206 };
207
208 struct dt2801_private {
209         const struct comedi_lrange *dac_range_types[2];
210 };
211
212 /* These are the low-level routines:
213    writecommand: write a command to the board
214    writedata: write data byte
215    readdata: read data byte
216  */
217
218 /* Only checks DataOutReady-flag, not the Ready-flag as it is done
219    in the examples of the manual. I don't see why this should be
220    necessary. */
221 static int dt2801_readdata(struct comedi_device *dev, int *data)
222 {
223         int stat = 0;
224         int timeout = DT2801_TIMEOUT;
225
226         do {
227                 stat = inb_p(dev->iobase + DT2801_STATUS);
228                 if (stat & (DT_S_COMPOSITE_ERROR | DT_S_READY))
229                         return stat;
230                 if (stat & DT_S_DATA_OUT_READY) {
231                         *data = inb_p(dev->iobase + DT2801_DATA);
232                         return 0;
233                 }
234         } while (--timeout > 0);
235
236         return -ETIME;
237 }
238
239 static int dt2801_readdata2(struct comedi_device *dev, int *data)
240 {
241         int lb = 0;
242         int hb = 0;
243         int ret;
244
245         ret = dt2801_readdata(dev, &lb);
246         if (ret)
247                 return ret;
248         ret = dt2801_readdata(dev, &hb);
249         if (ret)
250                 return ret;
251
252         *data = (hb << 8) + lb;
253         return 0;
254 }
255
256 static int dt2801_writedata(struct comedi_device *dev, unsigned int data)
257 {
258         int stat = 0;
259         int timeout = DT2801_TIMEOUT;
260
261         do {
262                 stat = inb_p(dev->iobase + DT2801_STATUS);
263
264                 if (stat & DT_S_COMPOSITE_ERROR)
265                         return stat;
266                 if (!(stat & DT_S_DATA_IN_FULL)) {
267                         outb_p(data & 0xff, dev->iobase + DT2801_DATA);
268                         return 0;
269                 }
270         } while (--timeout > 0);
271
272         return -ETIME;
273 }
274
275 static int dt2801_writedata2(struct comedi_device *dev, unsigned int data)
276 {
277         int ret;
278
279         ret = dt2801_writedata(dev, data & 0xff);
280         if (ret < 0)
281                 return ret;
282         ret = dt2801_writedata(dev, data >> 8);
283         if (ret < 0)
284                 return ret;
285
286         return 0;
287 }
288
289 static int dt2801_wait_for_ready(struct comedi_device *dev)
290 {
291         int timeout = DT2801_TIMEOUT;
292         int stat;
293
294         stat = inb_p(dev->iobase + DT2801_STATUS);
295         if (stat & DT_S_READY)
296                 return 0;
297         do {
298                 stat = inb_p(dev->iobase + DT2801_STATUS);
299
300                 if (stat & DT_S_COMPOSITE_ERROR)
301                         return stat;
302                 if (stat & DT_S_READY)
303                         return 0;
304         } while (--timeout > 0);
305
306         return -ETIME;
307 }
308
309 static void dt2801_writecmd(struct comedi_device *dev, int command)
310 {
311         int stat;
312
313         dt2801_wait_for_ready(dev);
314
315         stat = inb_p(dev->iobase + DT2801_STATUS);
316         if (stat & DT_S_COMPOSITE_ERROR) {
317                 dev_dbg(dev->class_dev,
318                         "composite-error in %s, ignoring\n", __func__);
319         }
320         if (!(stat & DT_S_READY))
321                 dev_dbg(dev->class_dev, "!ready in %s, ignoring\n", __func__);
322         outb_p(command, dev->iobase + DT2801_CMD);
323 }
324
325 static int dt2801_reset(struct comedi_device *dev)
326 {
327         int board_code = 0;
328         unsigned int stat;
329         int timeout;
330
331         /* pull random data from data port */
332         inb_p(dev->iobase + DT2801_DATA);
333         inb_p(dev->iobase + DT2801_DATA);
334         inb_p(dev->iobase + DT2801_DATA);
335         inb_p(dev->iobase + DT2801_DATA);
336
337         /* dt2801_writecmd(dev,DT_C_STOP); */
338         outb_p(DT_C_STOP, dev->iobase + DT2801_CMD);
339
340         /* dt2801_wait_for_ready(dev); */
341         udelay(100);
342         timeout = 10000;
343         do {
344                 stat = inb_p(dev->iobase + DT2801_STATUS);
345                 if (stat & DT_S_READY)
346                         break;
347         } while (timeout--);
348         if (!timeout)
349                 dev_dbg(dev->class_dev, "timeout 1 status=0x%02x\n", stat);
350
351         /* dt2801_readdata(dev,&board_code); */
352
353         outb_p(DT_C_RESET, dev->iobase + DT2801_CMD);
354         /* dt2801_writecmd(dev,DT_C_RESET); */
355
356         udelay(100);
357         timeout = 10000;
358         do {
359                 stat = inb_p(dev->iobase + DT2801_STATUS);
360                 if (stat & DT_S_READY)
361                         break;
362         } while (timeout--);
363         if (!timeout)
364                 dev_dbg(dev->class_dev, "timeout 2 status=0x%02x\n", stat);
365
366         dt2801_readdata(dev, &board_code);
367
368         return board_code;
369 }
370
371 static int probe_number_of_ai_chans(struct comedi_device *dev)
372 {
373         int n_chans;
374         int stat;
375         int data;
376
377         for (n_chans = 0; n_chans < 16; n_chans++) {
378                 dt2801_writecmd(dev, DT_C_READ_ADIM);
379                 dt2801_writedata(dev, 0);
380                 dt2801_writedata(dev, n_chans);
381                 stat = dt2801_readdata2(dev, &data);
382
383                 if (stat)
384                         break;
385         }
386
387         dt2801_reset(dev);
388         dt2801_reset(dev);
389
390         return n_chans;
391 }
392
393 static const struct comedi_lrange *dac_range_table[] = {
394         &range_bipolar10,
395         &range_bipolar5,
396         &range_bipolar2_5,
397         &range_unipolar10,
398         &range_unipolar5
399 };
400
401 static const struct comedi_lrange *dac_range_lkup(int opt)
402 {
403         if (opt < 0 || opt >= 5)
404                 return &range_unknown;
405         return dac_range_table[opt];
406 }
407
408 static const struct comedi_lrange *ai_range_lkup(int type, int opt)
409 {
410         switch (type) {
411         case 0:
412                 return (opt) ?
413                     &range_dt2801_ai_pgl_unipolar :
414                     &range_dt2801_ai_pgl_bipolar;
415         case 1:
416                 return (opt) ? &range_unipolar10 : &range_bipolar10;
417         case 2:
418                 return &range_unipolar5;
419         }
420         return &range_unknown;
421 }
422
423 static int dt2801_error(struct comedi_device *dev, int stat)
424 {
425         if (stat < 0) {
426                 if (stat == -ETIME)
427                         dev_dbg(dev->class_dev, "timeout\n");
428                 else
429                         dev_dbg(dev->class_dev, "error %d\n", stat);
430                 return stat;
431         }
432         dev_dbg(dev->class_dev, "error status 0x%02x, resetting...\n", stat);
433
434         dt2801_reset(dev);
435         dt2801_reset(dev);
436
437         return -EIO;
438 }
439
440 static int dt2801_ai_insn_read(struct comedi_device *dev,
441                                struct comedi_subdevice *s,
442                                struct comedi_insn *insn, unsigned int *data)
443 {
444         int d;
445         int stat;
446         int i;
447
448         for (i = 0; i < insn->n; i++) {
449                 dt2801_writecmd(dev, DT_C_READ_ADIM);
450                 dt2801_writedata(dev, CR_RANGE(insn->chanspec));
451                 dt2801_writedata(dev, CR_CHAN(insn->chanspec));
452                 stat = dt2801_readdata2(dev, &d);
453
454                 if (stat != 0)
455                         return dt2801_error(dev, stat);
456
457                 data[i] = d;
458         }
459
460         return i;
461 }
462
463 static int dt2801_ao_insn_write(struct comedi_device *dev,
464                                 struct comedi_subdevice *s,
465                                 struct comedi_insn *insn,
466                                 unsigned int *data)
467 {
468         unsigned int chan = CR_CHAN(insn->chanspec);
469
470         dt2801_writecmd(dev, DT_C_WRITE_DAIM);
471         dt2801_writedata(dev, chan);
472         dt2801_writedata2(dev, data[0]);
473
474         s->readback[chan] = data[0];
475
476         return 1;
477 }
478
479 static int dt2801_dio_insn_bits(struct comedi_device *dev,
480                                 struct comedi_subdevice *s,
481                                 struct comedi_insn *insn,
482                                 unsigned int *data)
483 {
484         int which = (s == &dev->subdevices[3]) ? 1 : 0;
485         unsigned int val = 0;
486
487         if (comedi_dio_update_state(s, data)) {
488                 dt2801_writecmd(dev, DT_C_WRITE_DIG);
489                 dt2801_writedata(dev, which);
490                 dt2801_writedata(dev, s->state);
491         }
492
493         dt2801_writecmd(dev, DT_C_READ_DIG);
494         dt2801_writedata(dev, which);
495         dt2801_readdata(dev, &val);
496
497         data[1] = val;
498
499         return insn->n;
500 }
501
502 static int dt2801_dio_insn_config(struct comedi_device *dev,
503                                   struct comedi_subdevice *s,
504                                   struct comedi_insn *insn,
505                                   unsigned int *data)
506 {
507         int ret;
508
509         ret = comedi_dio_insn_config(dev, s, insn, data, 0xff);
510         if (ret)
511                 return ret;
512
513         dt2801_writecmd(dev, s->io_bits ? DT_C_SET_DIGOUT : DT_C_SET_DIGIN);
514         dt2801_writedata(dev, (s == &dev->subdevices[3]) ? 1 : 0);
515
516         return insn->n;
517 }
518
519 /*
520    options:
521         [0] - i/o base
522         [1] - unused
523         [2] - a/d 0=differential, 1=single-ended
524         [3] - a/d range 0=[-10,10], 1=[0,10]
525         [4] - dac0 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5]
526         [5] - dac1 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5]
527 */
528 static int dt2801_attach(struct comedi_device *dev, struct comedi_devconfig *it)
529 {
530         const struct dt2801_board *board;
531         struct dt2801_private *devpriv;
532         struct comedi_subdevice *s;
533         int board_code, type;
534         int ret = 0;
535         int n_ai_chans;
536
537         ret = comedi_request_region(dev, it->options[0], 0x2);
538         if (ret)
539                 return ret;
540
541         /* do some checking */
542
543         board_code = dt2801_reset(dev);
544
545         /* heh.  if it didn't work, try it again. */
546         if (!board_code)
547                 board_code = dt2801_reset(dev);
548
549         for (type = 0; type < ARRAY_SIZE(boardtypes); type++) {
550                 if (boardtypes[type].boardcode == board_code)
551                         goto havetype;
552         }
553         dev_dbg(dev->class_dev,
554                 "unrecognized board code=0x%02x, contact author\n", board_code);
555         type = 0;
556
557 havetype:
558         dev->board_ptr = boardtypes + type;
559         board = dev->board_ptr;
560
561         n_ai_chans = probe_number_of_ai_chans(dev);
562
563         ret = comedi_alloc_subdevices(dev, 4);
564         if (ret)
565                 goto out;
566
567         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
568         if (!devpriv)
569                 return -ENOMEM;
570
571         dev->board_name = board->name;
572
573         s = &dev->subdevices[0];
574         /* ai subdevice */
575         s->type = COMEDI_SUBD_AI;
576         s->subdev_flags = SDF_READABLE | SDF_GROUND;
577 #if 1
578         s->n_chan = n_ai_chans;
579 #else
580         if (it->options[2])
581                 s->n_chan = board->ad_chan;
582         else
583                 s->n_chan = board->ad_chan / 2;
584 #endif
585         s->maxdata = (1 << board->adbits) - 1;
586         s->range_table = ai_range_lkup(board->adrangetype, it->options[3]);
587         s->insn_read = dt2801_ai_insn_read;
588
589         s = &dev->subdevices[1];
590         /* ao subdevice */
591         s->type = COMEDI_SUBD_AO;
592         s->subdev_flags = SDF_WRITABLE;
593         s->n_chan = 2;
594         s->maxdata = (1 << board->dabits) - 1;
595         s->range_table_list = devpriv->dac_range_types;
596         devpriv->dac_range_types[0] = dac_range_lkup(it->options[4]);
597         devpriv->dac_range_types[1] = dac_range_lkup(it->options[5]);
598         s->insn_write = dt2801_ao_insn_write;
599
600         ret = comedi_alloc_subdev_readback(s);
601         if (ret)
602                 return ret;
603
604         s = &dev->subdevices[2];
605         /* 1st digital subdevice */
606         s->type = COMEDI_SUBD_DIO;
607         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
608         s->n_chan = 8;
609         s->maxdata = 1;
610         s->range_table = &range_digital;
611         s->insn_bits = dt2801_dio_insn_bits;
612         s->insn_config = dt2801_dio_insn_config;
613
614         s = &dev->subdevices[3];
615         /* 2nd digital subdevice */
616         s->type = COMEDI_SUBD_DIO;
617         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
618         s->n_chan = 8;
619         s->maxdata = 1;
620         s->range_table = &range_digital;
621         s->insn_bits = dt2801_dio_insn_bits;
622         s->insn_config = dt2801_dio_insn_config;
623
624         ret = 0;
625 out:
626         return ret;
627 }
628
629 static struct comedi_driver dt2801_driver = {
630         .driver_name    = "dt2801",
631         .module         = THIS_MODULE,
632         .attach         = dt2801_attach,
633         .detach         = comedi_legacy_detach,
634 };
635 module_comedi_driver(dt2801_driver);
636
637 MODULE_AUTHOR("Comedi http://www.comedi.org");
638 MODULE_DESCRIPTION("Comedi low-level driver");
639 MODULE_LICENSE("GPL");