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