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