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