dt2801.c revision 2696fb57e6af653dd8b4df41b16754579f42fc78
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 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 91static int dt2801_attach(struct comedi_device * dev, struct comedi_devconfig * it); 92static int dt2801_detach(struct comedi_device * dev); 93static struct comedi_driver driver_dt2801 = { 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 103/* ignore 'defined but not used' warning */ 104static 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 112static 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 */ 122static 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 130static 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 138struct dt2801_board { 139 140 const char *name; 141 int boardcode; 142 int ad_diff; 143 int ad_chan; 144 int adbits; 145 int adrangetype; 146 int dabits; 147}; 148 149 150/* Typeid's for the different boards of the DT2801-series 151 (taken from the test-software, that comes with the board) 152 */ 153static const struct dt2801_board boardtypes[] = { 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]))) 221#define boardtype (*(const struct dt2801_board *)dev->board_ptr) 222 223struct dt2801_private { 224 225 const struct comedi_lrange *dac_range_types[2]; 226 unsigned int ao_readback[2]; 227}; 228 229#define devpriv ((struct dt2801_private *)dev->private) 230 231static int dt2801_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, 232 struct comedi_insn * insn, unsigned int * data); 233static int dt2801_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, 234 struct comedi_insn * insn, unsigned int * data); 235static int dt2801_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice * s, 236 struct comedi_insn * insn, unsigned int * data); 237static int dt2801_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, 238 struct comedi_insn * insn, unsigned int * data); 239static int dt2801_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, 240 struct comedi_insn * insn, unsigned int * data); 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. */ 251static int dt2801_readdata(struct comedi_device * dev, int *data) 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 270static int dt2801_readdata2(struct comedi_device * dev, int *data) 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 286static int dt2801_writedata(struct comedi_device * dev, unsigned int data) 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 312static int dt2801_writedata2(struct comedi_device * dev, unsigned int data) 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 326static int dt2801_wait_for_ready(struct comedi_device * dev) 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 349static int dt2801_writecmd(struct comedi_device * dev, int command) 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 367static int dt2801_reset(struct comedi_device * dev) 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"); 384 /* dt2801_writecmd(dev,DT_C_STOP); */ 385 outb_p(DT_C_STOP, dev->iobase + DT2801_CMD); 386 387 /* dt2801_wait_for_ready(dev); */ 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 } 398 399 /* printk("dt2801: reading dummy\n"); */ 400 /* dt2801_readdata(dev,&board_code); */ 401 402 DPRINTK("dt2801: reset\n"); 403 outb_p(DT_C_RESET, dev->iobase + DT2801_CMD); 404 /* dt2801_writecmd(dev,DT_C_RESET); */ 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 425static int probe_number_of_ai_chans(struct comedi_device * dev) 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 447static const struct comedi_lrange *dac_range_table[] = { 448 &range_bipolar10, 449 &range_bipolar5, 450 &range_bipolar2_5, 451 &range_unipolar10, 452 &range_unipolar5 453}; 454 455static const struct comedi_lrange *dac_range_lkup(int opt) 456{ 457 if (opt < 0 || opt > 5) 458 return &range_unknown; 459 return dac_range_table[opt]; 460} 461 462static const struct comedi_lrange *ai_range_lkup(int type, int opt) 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*/ 486static int dt2801_attach(struct comedi_device * dev, struct comedi_devconfig * it) 487{ 488 struct comedi_subdevice *s; 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 527 if ((ret = alloc_private(dev, sizeof(struct dt2801_private))) < 0) 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 587static int dt2801_detach(struct comedi_device * dev) 588{ 589 if (dev->iobase) 590 release_region(dev->iobase, DT2801_IOSIZE); 591 592 return 0; 593} 594 595static int dt2801_error(struct comedi_device * dev, int stat) 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 613static int dt2801_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, 614 struct comedi_insn * insn, unsigned int * data) 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 635static int dt2801_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, 636 struct comedi_insn * insn, unsigned int * data) 637{ 638 data[0] = devpriv->ao_readback[CR_CHAN(insn->chanspec)]; 639 640 return 1; 641} 642 643static int dt2801_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice * s, 644 struct comedi_insn * insn, unsigned int * data) 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 655static int dt2801_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, 656 struct comedi_insn * insn, unsigned int * data) 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 679static int dt2801_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, 680 struct comedi_insn * insn, unsigned int * data) 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} 699