dt2801.c revision 68c3dbff9fc9f25872408d0e95980d41733d48d0
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 ret = alloc_subdevices(dev, 4); 525 if (ret < 0) 526 goto out; 527 528 ret = alloc_private(dev, sizeof(struct dt2801_private)); 529 if (ret < 0) 530 goto out; 531 532 dev->board_name = boardtype.name; 533 534 s = dev->subdevices + 0; 535 /* ai subdevice */ 536 s->type = COMEDI_SUBD_AI; 537 s->subdev_flags = SDF_READABLE | SDF_GROUND; 538#if 1 539 s->n_chan = n_ai_chans; 540#else 541 if (it->options[2]) 542 s->n_chan = boardtype.ad_chan; 543 else 544 s->n_chan = boardtype.ad_chan / 2; 545#endif 546 s->maxdata = (1 << boardtype.adbits) - 1; 547 s->range_table = ai_range_lkup(boardtype.adrangetype, it->options[3]); 548 s->insn_read = dt2801_ai_insn_read; 549 550 s++; 551 /* ao subdevice */ 552 s->type = COMEDI_SUBD_AO; 553 s->subdev_flags = SDF_WRITABLE; 554 s->n_chan = 2; 555 s->maxdata = (1 << boardtype.dabits) - 1; 556 s->range_table_list = devpriv->dac_range_types; 557 devpriv->dac_range_types[0] = dac_range_lkup(it->options[4]); 558 devpriv->dac_range_types[1] = dac_range_lkup(it->options[5]); 559 s->insn_read = dt2801_ao_insn_read; 560 s->insn_write = dt2801_ao_insn_write; 561 562 s++; 563 /* 1st digital subdevice */ 564 s->type = COMEDI_SUBD_DIO; 565 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 566 s->n_chan = 8; 567 s->maxdata = 1; 568 s->range_table = &range_digital; 569 s->insn_bits = dt2801_dio_insn_bits; 570 s->insn_config = dt2801_dio_insn_config; 571 572 s++; 573 /* 2nd digital subdevice */ 574 s->type = COMEDI_SUBD_DIO; 575 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 576 s->n_chan = 8; 577 s->maxdata = 1; 578 s->range_table = &range_digital; 579 s->insn_bits = dt2801_dio_insn_bits; 580 s->insn_config = dt2801_dio_insn_config; 581 582 ret = 0; 583 out: 584 printk("\n"); 585 586 return ret; 587} 588 589static int dt2801_detach(struct comedi_device *dev) 590{ 591 if (dev->iobase) 592 release_region(dev->iobase, DT2801_IOSIZE); 593 594 return 0; 595} 596 597static int dt2801_error(struct comedi_device *dev, int stat) 598{ 599 if (stat < 0) { 600 if (stat == -ETIME) { 601 printk("dt2801: timeout\n"); 602 } else { 603 printk("dt2801: error %d\n", stat); 604 } 605 return stat; 606 } 607 printk("dt2801: error status 0x%02x, resetting...\n", stat); 608 609 dt2801_reset(dev); 610 dt2801_reset(dev); 611 612 return -EIO; 613} 614 615static int dt2801_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, 616 struct comedi_insn *insn, unsigned int *data) 617{ 618 int d; 619 int stat; 620 int i; 621 622 for (i = 0; i < insn->n; i++) { 623 stat = dt2801_writecmd(dev, DT_C_READ_ADIM); 624 dt2801_writedata(dev, CR_RANGE(insn->chanspec)); 625 dt2801_writedata(dev, CR_CHAN(insn->chanspec)); 626 stat = dt2801_readdata2(dev, &d); 627 628 if (stat != 0) 629 return dt2801_error(dev, stat); 630 631 data[i] = d; 632 } 633 634 return i; 635} 636 637static int dt2801_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, 638 struct comedi_insn *insn, unsigned int *data) 639{ 640 data[0] = devpriv->ao_readback[CR_CHAN(insn->chanspec)]; 641 642 return 1; 643} 644 645static int dt2801_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, 646 struct comedi_insn *insn, unsigned int *data) 647{ 648 dt2801_writecmd(dev, DT_C_WRITE_DAIM); 649 dt2801_writedata(dev, CR_CHAN(insn->chanspec)); 650 dt2801_writedata2(dev, data[0]); 651 652 devpriv->ao_readback[CR_CHAN(insn->chanspec)] = data[0]; 653 654 return 1; 655} 656 657static int dt2801_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, 658 struct comedi_insn *insn, unsigned int *data) 659{ 660 int which = 0; 661 662 if (s == dev->subdevices + 4) 663 which = 1; 664 665 if (insn->n != 2) 666 return -EINVAL; 667 if (data[0]) { 668 s->state &= ~data[0]; 669 s->state |= (data[0] & data[1]); 670 dt2801_writecmd(dev, DT_C_WRITE_DIG); 671 dt2801_writedata(dev, which); 672 dt2801_writedata(dev, s->state); 673 } 674 dt2801_writecmd(dev, DT_C_READ_DIG); 675 dt2801_writedata(dev, which); 676 dt2801_readdata(dev, data + 1); 677 678 return 2; 679} 680 681static int dt2801_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, 682 struct comedi_insn *insn, unsigned int *data) 683{ 684 int which = 0; 685 686 if (s == dev->subdevices + 4) 687 which = 1; 688 689 /* configure */ 690 if (data[0]) { 691 s->io_bits = 0xff; 692 dt2801_writecmd(dev, DT_C_SET_DIGOUT); 693 } else { 694 s->io_bits = 0; 695 dt2801_writecmd(dev, DT_C_SET_DIGIN); 696 } 697 dt2801_writedata(dev, which); 698 699 return 1; 700} 701