dt2801.c revision 0a85b6f0ab0d2edb0d41b32697111ce0e4f43496
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 } 285 if (stat & DT_S_DATA_OUT_READY) { 286 *data = inb_p(dev->iobase + DT2801_DATA); 287 return 0; 288 } 289 } while (--timeout > 0); 290 291 return -ETIME; 292} 293 294static int dt2801_readdata2(struct comedi_device *dev, int *data) 295{ 296 int lb, hb; 297 int ret; 298 299 ret = dt2801_readdata(dev, &lb); 300 if (ret) 301 return ret; 302 ret = dt2801_readdata(dev, &hb); 303 if (ret) 304 return ret; 305 306 *data = (hb << 8) + lb; 307 return 0; 308} 309 310static int dt2801_writedata(struct comedi_device *dev, unsigned int data) 311{ 312 int stat = 0; 313 int timeout = DT2801_TIMEOUT; 314 315 do { 316 stat = inb_p(dev->iobase + DT2801_STATUS); 317 318 if (stat & DT_S_COMPOSITE_ERROR) { 319 return stat; 320 } 321 if (!(stat & DT_S_DATA_IN_FULL)) { 322 outb_p(data & 0xff, dev->iobase + DT2801_DATA); 323 return 0; 324 } 325#if 0 326 if (stat & DT_S_READY) { 327 printk 328 ("dt2801: ready flag set (bad!) in dt2801_writedata()\n"); 329 return -EIO; 330 } 331#endif 332 } while (--timeout > 0); 333 334 return -ETIME; 335} 336 337static int dt2801_writedata2(struct comedi_device *dev, unsigned int data) 338{ 339 int ret; 340 341 ret = dt2801_writedata(dev, data & 0xff); 342 if (ret < 0) 343 return ret; 344 ret = dt2801_writedata(dev, (data >> 8)); 345 if (ret < 0) 346 return ret; 347 348 return 0; 349} 350 351static int dt2801_wait_for_ready(struct comedi_device *dev) 352{ 353 int timeout = DT2801_TIMEOUT; 354 int stat; 355 356 stat = inb_p(dev->iobase + DT2801_STATUS); 357 if (stat & DT_S_READY) { 358 return 0; 359 } 360 do { 361 stat = inb_p(dev->iobase + DT2801_STATUS); 362 363 if (stat & DT_S_COMPOSITE_ERROR) { 364 return stat; 365 } 366 if (stat & DT_S_READY) { 367 return 0; 368 } 369 } while (--timeout > 0); 370 371 return -ETIME; 372} 373 374static int dt2801_writecmd(struct comedi_device *dev, int command) 375{ 376 int stat; 377 378 dt2801_wait_for_ready(dev); 379 380 stat = inb_p(dev->iobase + DT2801_STATUS); 381 if (stat & DT_S_COMPOSITE_ERROR) { 382 printk 383 ("dt2801: composite-error in dt2801_writecmd(), ignoring\n"); 384 } 385 if (!(stat & DT_S_READY)) { 386 printk("dt2801: !ready in dt2801_writecmd(), ignoring\n"); 387 } 388 outb_p(command, dev->iobase + DT2801_CMD); 389 390 return 0; 391} 392 393static int dt2801_reset(struct comedi_device *dev) 394{ 395 int board_code = 0; 396 unsigned int stat; 397 int timeout; 398 399 DPRINTK("dt2801: resetting board...\n"); 400 DPRINTK("fingerprint: 0x%02x 0x%02x\n", inb_p(dev->iobase), 401 inb_p(dev->iobase + 1)); 402 403 /* pull random data from data port */ 404 inb_p(dev->iobase + DT2801_DATA); 405 inb_p(dev->iobase + DT2801_DATA); 406 inb_p(dev->iobase + DT2801_DATA); 407 inb_p(dev->iobase + DT2801_DATA); 408 409 DPRINTK("dt2801: stop\n"); 410 /* dt2801_writecmd(dev,DT_C_STOP); */ 411 outb_p(DT_C_STOP, dev->iobase + DT2801_CMD); 412 413 /* dt2801_wait_for_ready(dev); */ 414 udelay(100); 415 timeout = 10000; 416 do { 417 stat = inb_p(dev->iobase + DT2801_STATUS); 418 if (stat & DT_S_READY) 419 break; 420 } while (timeout--); 421 if (!timeout) { 422 printk("dt2801: timeout 1 status=0x%02x\n", stat); 423 } 424 425 /* printk("dt2801: reading dummy\n"); */ 426 /* dt2801_readdata(dev,&board_code); */ 427 428 DPRINTK("dt2801: reset\n"); 429 outb_p(DT_C_RESET, dev->iobase + DT2801_CMD); 430 /* dt2801_writecmd(dev,DT_C_RESET); */ 431 432 udelay(100); 433 timeout = 10000; 434 do { 435 stat = inb_p(dev->iobase + DT2801_STATUS); 436 if (stat & DT_S_READY) 437 break; 438 } while (timeout--); 439 if (!timeout) { 440 printk("dt2801: timeout 2 status=0x%02x\n", stat); 441 } 442 443 DPRINTK("dt2801: reading code\n"); 444 dt2801_readdata(dev, &board_code); 445 446 DPRINTK("dt2801: ok. code=0x%02x\n", board_code); 447 448 return board_code; 449} 450 451static int probe_number_of_ai_chans(struct comedi_device *dev) 452{ 453 int n_chans; 454 int stat; 455 int data; 456 457 for (n_chans = 0; n_chans < 16; n_chans++) { 458 stat = dt2801_writecmd(dev, DT_C_READ_ADIM); 459 dt2801_writedata(dev, 0); 460 dt2801_writedata(dev, n_chans); 461 stat = dt2801_readdata2(dev, &data); 462 463 if (stat) 464 break; 465 } 466 467 dt2801_reset(dev); 468 dt2801_reset(dev); 469 470 return n_chans; 471} 472 473static const struct comedi_lrange *dac_range_table[] = { 474 &range_bipolar10, 475 &range_bipolar5, 476 &range_bipolar2_5, 477 &range_unipolar10, 478 &range_unipolar5 479}; 480 481static const struct comedi_lrange *dac_range_lkup(int opt) 482{ 483 if (opt < 0 || opt > 5) 484 return &range_unknown; 485 return dac_range_table[opt]; 486} 487 488static const struct comedi_lrange *ai_range_lkup(int type, int opt) 489{ 490 switch (type) { 491 case 0: 492 return (opt) ? 493 &range_dt2801_ai_pgl_unipolar : 494 &range_dt2801_ai_pgl_bipolar; 495 case 1: 496 return (opt) ? &range_unipolar10 : &range_bipolar10; 497 case 2: 498 return &range_unipolar5; 499 } 500 return &range_unknown; 501} 502 503/* 504 options: 505 [0] - i/o base 506 [1] - unused 507 [2] - a/d 0=differential, 1=single-ended 508 [3] - a/d range 0=[-10,10], 1=[0,10] 509 [4] - dac0 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5] 510 [5] - dac1 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5] 511*/ 512static int dt2801_attach(struct comedi_device *dev, struct comedi_devconfig *it) 513{ 514 struct comedi_subdevice *s; 515 unsigned long iobase; 516 int board_code, type; 517 int ret = 0; 518 int n_ai_chans; 519 520 iobase = it->options[0]; 521 if (!request_region(iobase, DT2801_IOSIZE, "dt2801")) { 522 comedi_error(dev, "I/O port conflict"); 523 return -EIO; 524 } 525 dev->iobase = iobase; 526 527 /* do some checking */ 528 529 board_code = dt2801_reset(dev); 530 531 /* heh. if it didn't work, try it again. */ 532 if (!board_code) 533 board_code = dt2801_reset(dev); 534 535 for (type = 0; type < ARRAY_SIZE(boardtypes); type++) { 536 if (boardtypes[type].boardcode == board_code) 537 goto havetype; 538 } 539 printk("dt2801: unrecognized board code=0x%02x, contact author\n", 540 board_code); 541 type = 0; 542 543havetype: 544 dev->board_ptr = boardtypes + type; 545 printk("dt2801: %s at port 0x%lx", boardtype.name, iobase); 546 547 n_ai_chans = probe_number_of_ai_chans(dev); 548 printk(" (ai channels = %d)", n_ai_chans); 549 550 ret = alloc_subdevices(dev, 4); 551 if (ret < 0) 552 goto out; 553 554 ret = alloc_private(dev, sizeof(struct dt2801_private)); 555 if (ret < 0) 556 goto out; 557 558 dev->board_name = boardtype.name; 559 560 s = dev->subdevices + 0; 561 /* ai subdevice */ 562 s->type = COMEDI_SUBD_AI; 563 s->subdev_flags = SDF_READABLE | SDF_GROUND; 564#if 1 565 s->n_chan = n_ai_chans; 566#else 567 if (it->options[2]) 568 s->n_chan = boardtype.ad_chan; 569 else 570 s->n_chan = boardtype.ad_chan / 2; 571#endif 572 s->maxdata = (1 << boardtype.adbits) - 1; 573 s->range_table = ai_range_lkup(boardtype.adrangetype, it->options[3]); 574 s->insn_read = dt2801_ai_insn_read; 575 576 s++; 577 /* ao subdevice */ 578 s->type = COMEDI_SUBD_AO; 579 s->subdev_flags = SDF_WRITABLE; 580 s->n_chan = 2; 581 s->maxdata = (1 << boardtype.dabits) - 1; 582 s->range_table_list = devpriv->dac_range_types; 583 devpriv->dac_range_types[0] = dac_range_lkup(it->options[4]); 584 devpriv->dac_range_types[1] = dac_range_lkup(it->options[5]); 585 s->insn_read = dt2801_ao_insn_read; 586 s->insn_write = dt2801_ao_insn_write; 587 588 s++; 589 /* 1st digital subdevice */ 590 s->type = COMEDI_SUBD_DIO; 591 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 592 s->n_chan = 8; 593 s->maxdata = 1; 594 s->range_table = &range_digital; 595 s->insn_bits = dt2801_dio_insn_bits; 596 s->insn_config = dt2801_dio_insn_config; 597 598 s++; 599 /* 2nd digital subdevice */ 600 s->type = COMEDI_SUBD_DIO; 601 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 602 s->n_chan = 8; 603 s->maxdata = 1; 604 s->range_table = &range_digital; 605 s->insn_bits = dt2801_dio_insn_bits; 606 s->insn_config = dt2801_dio_insn_config; 607 608 ret = 0; 609out: 610 printk("\n"); 611 612 return ret; 613} 614 615static int dt2801_detach(struct comedi_device *dev) 616{ 617 if (dev->iobase) 618 release_region(dev->iobase, DT2801_IOSIZE); 619 620 return 0; 621} 622 623static int dt2801_error(struct comedi_device *dev, int stat) 624{ 625 if (stat < 0) { 626 if (stat == -ETIME) { 627 printk("dt2801: timeout\n"); 628 } else { 629 printk("dt2801: error %d\n", stat); 630 } 631 return stat; 632 } 633 printk("dt2801: error status 0x%02x, resetting...\n", stat); 634 635 dt2801_reset(dev); 636 dt2801_reset(dev); 637 638 return -EIO; 639} 640 641static int dt2801_ai_insn_read(struct comedi_device *dev, 642 struct comedi_subdevice *s, 643 struct comedi_insn *insn, unsigned int *data) 644{ 645 int d; 646 int stat; 647 int i; 648 649 for (i = 0; i < insn->n; i++) { 650 stat = dt2801_writecmd(dev, DT_C_READ_ADIM); 651 dt2801_writedata(dev, CR_RANGE(insn->chanspec)); 652 dt2801_writedata(dev, CR_CHAN(insn->chanspec)); 653 stat = dt2801_readdata2(dev, &d); 654 655 if (stat != 0) 656 return dt2801_error(dev, stat); 657 658 data[i] = d; 659 } 660 661 return i; 662} 663 664static int dt2801_ao_insn_read(struct comedi_device *dev, 665 struct comedi_subdevice *s, 666 struct comedi_insn *insn, unsigned int *data) 667{ 668 data[0] = devpriv->ao_readback[CR_CHAN(insn->chanspec)]; 669 670 return 1; 671} 672 673static int dt2801_ao_insn_write(struct comedi_device *dev, 674 struct comedi_subdevice *s, 675 struct comedi_insn *insn, unsigned int *data) 676{ 677 dt2801_writecmd(dev, DT_C_WRITE_DAIM); 678 dt2801_writedata(dev, CR_CHAN(insn->chanspec)); 679 dt2801_writedata2(dev, data[0]); 680 681 devpriv->ao_readback[CR_CHAN(insn->chanspec)] = data[0]; 682 683 return 1; 684} 685 686static int dt2801_dio_insn_bits(struct comedi_device *dev, 687 struct comedi_subdevice *s, 688 struct comedi_insn *insn, unsigned int *data) 689{ 690 int which = 0; 691 692 if (s == dev->subdevices + 4) 693 which = 1; 694 695 if (insn->n != 2) 696 return -EINVAL; 697 if (data[0]) { 698 s->state &= ~data[0]; 699 s->state |= (data[0] & data[1]); 700 dt2801_writecmd(dev, DT_C_WRITE_DIG); 701 dt2801_writedata(dev, which); 702 dt2801_writedata(dev, s->state); 703 } 704 dt2801_writecmd(dev, DT_C_READ_DIG); 705 dt2801_writedata(dev, which); 706 dt2801_readdata(dev, data + 1); 707 708 return 2; 709} 710 711static int dt2801_dio_insn_config(struct comedi_device *dev, 712 struct comedi_subdevice *s, 713 struct comedi_insn *insn, unsigned int *data) 714{ 715 int which = 0; 716 717 if (s == dev->subdevices + 4) 718 which = 1; 719 720 /* configure */ 721 if (data[0]) { 722 s->io_bits = 0xff; 723 dt2801_writecmd(dev, DT_C_SET_DIGOUT); 724 } else { 725 s->io_bits = 0; 726 dt2801_writecmd(dev, DT_C_SET_DIGIN); 727 } 728 dt2801_writedata(dev, which); 729 730 return 1; 731} 732