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