Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dt2801.c
Go to the documentation of this file.
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 #if 0
92 /* ignore 'defined but not used' warning */
93 static const struct comedi_lrange range_dt2801_ai_pgh_bipolar = { 4, {
94  RANGE(-10,
95  10),
96  RANGE(-5,
97  5),
98  RANGE
99  (-2.5,
100  2.5),
101  RANGE
102  (-1.25,
103  1.25),
104  }
105 };
106 #endif
107 static const struct comedi_lrange range_dt2801_ai_pgl_bipolar = { 4, {
108  RANGE(-10,
109  10),
110  RANGE(-1,
111  1),
112  RANGE
113  (-0.1,
114  0.1),
115  RANGE
116  (-0.02,
117  0.02),
118  }
119 };
120 
121 #if 0
122 /* ignore 'defined but not used' warning */
123 static const struct comedi_lrange range_dt2801_ai_pgh_unipolar = { 4, {
124  RANGE(0,
125  10),
126  RANGE(0,
127  5),
128  RANGE(0,
129  2.5),
130  RANGE(0,
131  1.25),
132  }
133 };
134 #endif
135 static const struct comedi_lrange range_dt2801_ai_pgl_unipolar = { 4, {
136  RANGE(0,
137  10),
138  RANGE(0,
139  1),
140  RANGE(0,
141  0.1),
142  RANGE(0,
143  0.02),
144  }
145 };
146 
147 struct dt2801_board {
148 
149  const char *name;
151  int ad_diff;
152  int ad_chan;
153  int adbits;
155  int dabits;
156 };
157 
158 /* Typeid's for the different boards of the DT2801-series
159  (taken from the test-software, that comes with the board)
160  */
161 static const struct dt2801_board boardtypes[] = {
162  {
163  .name = "dt2801",
164  .boardcode = 0x09,
165  .ad_diff = 2,
166  .ad_chan = 16,
167  .adbits = 12,
168  .adrangetype = 0,
169  .dabits = 12},
170  {
171  .name = "dt2801-a",
172  .boardcode = 0x52,
173  .ad_diff = 2,
174  .ad_chan = 16,
175  .adbits = 12,
176  .adrangetype = 0,
177  .dabits = 12},
178  {
179  .name = "dt2801/5716a",
180  .boardcode = 0x82,
181  .ad_diff = 1,
182  .ad_chan = 16,
183  .adbits = 16,
184  .adrangetype = 1,
185  .dabits = 12},
186  {
187  .name = "dt2805",
188  .boardcode = 0x12,
189  .ad_diff = 1,
190  .ad_chan = 16,
191  .adbits = 12,
192  .adrangetype = 0,
193  .dabits = 12},
194  {
195  .name = "dt2805/5716a",
196  .boardcode = 0x92,
197  .ad_diff = 1,
198  .ad_chan = 16,
199  .adbits = 16,
200  .adrangetype = 1,
201  .dabits = 12},
202  {
203  .name = "dt2808",
204  .boardcode = 0x20,
205  .ad_diff = 0,
206  .ad_chan = 16,
207  .adbits = 12,
208  .adrangetype = 2,
209  .dabits = 8},
210  {
211  .name = "dt2818",
212  .boardcode = 0xa2,
213  .ad_diff = 0,
214  .ad_chan = 4,
215  .adbits = 12,
216  .adrangetype = 0,
217  .dabits = 12},
218  {
219  .name = "dt2809",
220  .boardcode = 0xb0,
221  .ad_diff = 0,
222  .ad_chan = 8,
223  .adbits = 12,
224  .adrangetype = 1,
225  .dabits = 12},
226 };
227 
228 #define boardtype (*(const struct dt2801_board *)dev->board_ptr)
229 
231 
232  const struct comedi_lrange *dac_range_types[2];
233  unsigned int ao_readback[2];
234 };
235 
236 #define devpriv ((struct dt2801_private *)dev->private)
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  if (stat & DT_S_DATA_OUT_READY) {
257  *data = inb_p(dev->iobase + DT2801_DATA);
258  return 0;
259  }
260  } while (--timeout > 0);
261 
262  return -ETIME;
263 }
264 
265 static int dt2801_readdata2(struct comedi_device *dev, int *data)
266 {
267  int lb, hb;
268  int ret;
269 
270  ret = dt2801_readdata(dev, &lb);
271  if (ret)
272  return ret;
273  ret = dt2801_readdata(dev, &hb);
274  if (ret)
275  return ret;
276 
277  *data = (hb << 8) + lb;
278  return 0;
279 }
280 
281 static int dt2801_writedata(struct comedi_device *dev, unsigned int data)
282 {
283  int stat = 0;
284  int timeout = DT2801_TIMEOUT;
285 
286  do {
287  stat = inb_p(dev->iobase + DT2801_STATUS);
288 
289  if (stat & DT_S_COMPOSITE_ERROR)
290  return stat;
291  if (!(stat & DT_S_DATA_IN_FULL)) {
292  outb_p(data & 0xff, dev->iobase + DT2801_DATA);
293  return 0;
294  }
295 #if 0
296  if (stat & DT_S_READY) {
297  printk
298  ("dt2801: ready flag set (bad!) in dt2801_writedata()\n");
299  return -EIO;
300  }
301 #endif
302  } while (--timeout > 0);
303 
304  return -ETIME;
305 }
306 
307 static int dt2801_writedata2(struct comedi_device *dev, unsigned int data)
308 {
309  int ret;
310 
311  ret = dt2801_writedata(dev, data & 0xff);
312  if (ret < 0)
313  return ret;
314  ret = dt2801_writedata(dev, (data >> 8));
315  if (ret < 0)
316  return ret;
317 
318  return 0;
319 }
320 
321 static int dt2801_wait_for_ready(struct comedi_device *dev)
322 {
323  int timeout = DT2801_TIMEOUT;
324  int stat;
325 
326  stat = inb_p(dev->iobase + DT2801_STATUS);
327  if (stat & DT_S_READY)
328  return 0;
329  do {
330  stat = inb_p(dev->iobase + DT2801_STATUS);
331 
332  if (stat & DT_S_COMPOSITE_ERROR)
333  return stat;
334  if (stat & DT_S_READY)
335  return 0;
336  } while (--timeout > 0);
337 
338  return -ETIME;
339 }
340 
341 static int dt2801_writecmd(struct comedi_device *dev, int command)
342 {
343  int stat;
344 
345  dt2801_wait_for_ready(dev);
346 
347  stat = inb_p(dev->iobase + DT2801_STATUS);
348  if (stat & DT_S_COMPOSITE_ERROR) {
349  printk
350  ("dt2801: composite-error in dt2801_writecmd(), ignoring\n");
351  }
352  if (!(stat & DT_S_READY))
353  printk("dt2801: !ready in dt2801_writecmd(), ignoring\n");
354  outb_p(command, dev->iobase + DT2801_CMD);
355 
356  return 0;
357 }
358 
359 static int dt2801_reset(struct comedi_device *dev)
360 {
361  int board_code = 0;
362  unsigned int stat;
363  int timeout;
364 
365  DPRINTK("dt2801: resetting board...\n");
366  DPRINTK("fingerprint: 0x%02x 0x%02x\n", inb_p(dev->iobase),
367  inb_p(dev->iobase + 1));
368 
369  /* pull random data from data port */
370  inb_p(dev->iobase + DT2801_DATA);
371  inb_p(dev->iobase + DT2801_DATA);
372  inb_p(dev->iobase + DT2801_DATA);
373  inb_p(dev->iobase + DT2801_DATA);
374 
375  DPRINTK("dt2801: stop\n");
376  /* dt2801_writecmd(dev,DT_C_STOP); */
378 
379  /* dt2801_wait_for_ready(dev); */
380  udelay(100);
381  timeout = 10000;
382  do {
383  stat = inb_p(dev->iobase + DT2801_STATUS);
384  if (stat & DT_S_READY)
385  break;
386  } while (timeout--);
387  if (!timeout)
388  printk("dt2801: timeout 1 status=0x%02x\n", stat);
389 
390  /* printk("dt2801: reading dummy\n"); */
391  /* dt2801_readdata(dev,&board_code); */
392 
393  DPRINTK("dt2801: reset\n");
395  /* dt2801_writecmd(dev,DT_C_RESET); */
396 
397  udelay(100);
398  timeout = 10000;
399  do {
400  stat = inb_p(dev->iobase + DT2801_STATUS);
401  if (stat & DT_S_READY)
402  break;
403  } while (timeout--);
404  if (!timeout)
405  printk("dt2801: timeout 2 status=0x%02x\n", stat);
406 
407  DPRINTK("dt2801: reading code\n");
408  dt2801_readdata(dev, &board_code);
409 
410  DPRINTK("dt2801: ok. code=0x%02x\n", board_code);
411 
412  return board_code;
413 }
414 
415 static int probe_number_of_ai_chans(struct comedi_device *dev)
416 {
417  int n_chans;
418  int stat;
419  int data;
420 
421  for (n_chans = 0; n_chans < 16; n_chans++) {
422  stat = dt2801_writecmd(dev, DT_C_READ_ADIM);
423  dt2801_writedata(dev, 0);
424  dt2801_writedata(dev, n_chans);
425  stat = dt2801_readdata2(dev, &data);
426 
427  if (stat)
428  break;
429  }
430 
431  dt2801_reset(dev);
432  dt2801_reset(dev);
433 
434  return n_chans;
435 }
436 
437 static const struct comedi_lrange *dac_range_table[] = {
443 };
444 
445 static const struct comedi_lrange *dac_range_lkup(int opt)
446 {
447  if (opt < 0 || opt >= 5)
448  return &range_unknown;
449  return dac_range_table[opt];
450 }
451 
452 static const struct comedi_lrange *ai_range_lkup(int type, int opt)
453 {
454  switch (type) {
455  case 0:
456  return (opt) ?
457  &range_dt2801_ai_pgl_unipolar :
458  &range_dt2801_ai_pgl_bipolar;
459  case 1:
460  return (opt) ? &range_unipolar10 : &range_bipolar10;
461  case 2:
462  return &range_unipolar5;
463  }
464  return &range_unknown;
465 }
466 
467 static int dt2801_error(struct comedi_device *dev, int stat)
468 {
469  if (stat < 0) {
470  if (stat == -ETIME)
471  printk("dt2801: timeout\n");
472  else
473  printk("dt2801: error %d\n", stat);
474  return stat;
475  }
476  printk("dt2801: error status 0x%02x, resetting...\n", stat);
477 
478  dt2801_reset(dev);
479  dt2801_reset(dev);
480 
481  return -EIO;
482 }
483 
484 static int dt2801_ai_insn_read(struct comedi_device *dev,
485  struct comedi_subdevice *s,
486  struct comedi_insn *insn, unsigned int *data)
487 {
488  int d;
489  int stat;
490  int i;
491 
492  for (i = 0; i < insn->n; i++) {
493  stat = dt2801_writecmd(dev, DT_C_READ_ADIM);
494  dt2801_writedata(dev, CR_RANGE(insn->chanspec));
495  dt2801_writedata(dev, CR_CHAN(insn->chanspec));
496  stat = dt2801_readdata2(dev, &d);
497 
498  if (stat != 0)
499  return dt2801_error(dev, stat);
500 
501  data[i] = d;
502  }
503 
504  return i;
505 }
506 
507 static int dt2801_ao_insn_read(struct comedi_device *dev,
508  struct comedi_subdevice *s,
509  struct comedi_insn *insn, unsigned int *data)
510 {
511  data[0] = devpriv->ao_readback[CR_CHAN(insn->chanspec)];
512 
513  return 1;
514 }
515 
516 static int dt2801_ao_insn_write(struct comedi_device *dev,
517  struct comedi_subdevice *s,
518  struct comedi_insn *insn, unsigned int *data)
519 {
520  dt2801_writecmd(dev, DT_C_WRITE_DAIM);
521  dt2801_writedata(dev, CR_CHAN(insn->chanspec));
522  dt2801_writedata2(dev, data[0]);
523 
524  devpriv->ao_readback[CR_CHAN(insn->chanspec)] = data[0];
525 
526  return 1;
527 }
528 
529 static int dt2801_dio_insn_bits(struct comedi_device *dev,
530  struct comedi_subdevice *s,
531  struct comedi_insn *insn, unsigned int *data)
532 {
533  int which = 0;
534 
535  if (s == &dev->subdevices[3])
536  which = 1;
537 
538  if (data[0]) {
539  s->state &= ~data[0];
540  s->state |= (data[0] & data[1]);
541  dt2801_writecmd(dev, DT_C_WRITE_DIG);
542  dt2801_writedata(dev, which);
543  dt2801_writedata(dev, s->state);
544  }
545  dt2801_writecmd(dev, DT_C_READ_DIG);
546  dt2801_writedata(dev, which);
547  dt2801_readdata(dev, data + 1);
548 
549  return insn->n;
550 }
551 
552 static int dt2801_dio_insn_config(struct comedi_device *dev,
553  struct comedi_subdevice *s,
554  struct comedi_insn *insn, unsigned int *data)
555 {
556  int which = 0;
557 
558  if (s == &dev->subdevices[3])
559  which = 1;
560 
561  /* configure */
562  switch (data[0]) {
564  s->io_bits = 0xff;
565  dt2801_writecmd(dev, DT_C_SET_DIGOUT);
566  break;
568  s->io_bits = 0;
569  dt2801_writecmd(dev, DT_C_SET_DIGIN);
570  break;
572  data[1] = s->io_bits ? COMEDI_OUTPUT : COMEDI_INPUT;
573  return insn->n;
574  default:
575  return -EINVAL;
576  }
577  dt2801_writedata(dev, which);
578 
579  return 1;
580 }
581 
582 /*
583  options:
584  [0] - i/o base
585  [1] - unused
586  [2] - a/d 0=differential, 1=single-ended
587  [3] - a/d range 0=[-10,10], 1=[0,10]
588  [4] - dac0 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5]
589  [5] - dac1 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5]
590 */
591 static int dt2801_attach(struct comedi_device *dev, struct comedi_devconfig *it)
592 {
593  struct comedi_subdevice *s;
594  unsigned long iobase;
595  int board_code, type;
596  int ret = 0;
597  int n_ai_chans;
598 
599  iobase = it->options[0];
600  if (!request_region(iobase, DT2801_IOSIZE, "dt2801")) {
601  comedi_error(dev, "I/O port conflict");
602  return -EIO;
603  }
604  dev->iobase = iobase;
605 
606  /* do some checking */
607 
608  board_code = dt2801_reset(dev);
609 
610  /* heh. if it didn't work, try it again. */
611  if (!board_code)
612  board_code = dt2801_reset(dev);
613 
614  for (type = 0; type < ARRAY_SIZE(boardtypes); type++) {
615  if (boardtypes[type].boardcode == board_code)
616  goto havetype;
617  }
618  printk("dt2801: unrecognized board code=0x%02x, contact author\n",
619  board_code);
620  type = 0;
621 
622 havetype:
623  dev->board_ptr = boardtypes + type;
624  printk("dt2801: %s at port 0x%lx", boardtype.name, iobase);
625 
626  n_ai_chans = probe_number_of_ai_chans(dev);
627  printk(" (ai channels = %d)\n", n_ai_chans);
628 
629  ret = comedi_alloc_subdevices(dev, 4);
630  if (ret)
631  goto out;
632 
633  ret = alloc_private(dev, sizeof(struct dt2801_private));
634  if (ret < 0)
635  return ret;
636 
637  dev->board_name = boardtype.name;
638 
639  s = &dev->subdevices[0];
640  /* ai subdevice */
641  s->type = COMEDI_SUBD_AI;
643 #if 1
644  s->n_chan = n_ai_chans;
645 #else
646  if (it->options[2])
647  s->n_chan = boardtype.ad_chan;
648  else
649  s->n_chan = boardtype.ad_chan / 2;
650 #endif
651  s->maxdata = (1 << boardtype.adbits) - 1;
652  s->range_table = ai_range_lkup(boardtype.adrangetype, it->options[3]);
653  s->insn_read = dt2801_ai_insn_read;
654 
655  s = &dev->subdevices[1];
656  /* ao subdevice */
657  s->type = COMEDI_SUBD_AO;
659  s->n_chan = 2;
660  s->maxdata = (1 << boardtype.dabits) - 1;
661  s->range_table_list = devpriv->dac_range_types;
662  devpriv->dac_range_types[0] = dac_range_lkup(it->options[4]);
663  devpriv->dac_range_types[1] = dac_range_lkup(it->options[5]);
664  s->insn_read = dt2801_ao_insn_read;
665  s->insn_write = dt2801_ao_insn_write;
666 
667  s = &dev->subdevices[2];
668  /* 1st digital subdevice */
669  s->type = COMEDI_SUBD_DIO;
671  s->n_chan = 8;
672  s->maxdata = 1;
674  s->insn_bits = dt2801_dio_insn_bits;
675  s->insn_config = dt2801_dio_insn_config;
676 
677  s = &dev->subdevices[3];
678  /* 2nd digital subdevice */
679  s->type = COMEDI_SUBD_DIO;
681  s->n_chan = 8;
682  s->maxdata = 1;
684  s->insn_bits = dt2801_dio_insn_bits;
685  s->insn_config = dt2801_dio_insn_config;
686 
687  ret = 0;
688 out:
689  return ret;
690 }
691 
692 static void dt2801_detach(struct comedi_device *dev)
693 {
694  if (dev->iobase)
696 }
697 
698 static struct comedi_driver dt2801_driver = {
699  .driver_name = "dt2801",
700  .module = THIS_MODULE,
701  .attach = dt2801_attach,
702  .detach = dt2801_detach,
703 };
704 module_comedi_driver(dt2801_driver);
705 
706 MODULE_AUTHOR("Comedi http://www.comedi.org");
707 MODULE_DESCRIPTION("Comedi low-level driver");
708 MODULE_LICENSE("GPL");