dt2801.c revision 60efa611c788c4f5b9fdc206aeb9e7c91e0c3ffb
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 //printk("dt2801: reading dummy\n"); 399 //dt2801_readdata(dev,&board_code); 400 401 DPRINTK("dt2801: reset\n"); 402 outb_p(DT_C_RESET, dev->iobase + DT2801_CMD); 403 //dt2801_writecmd(dev,DT_C_RESET); 404 405 comedi_udelay(100); 406 timeout = 10000; 407 do { 408 stat = inb_p(dev->iobase + DT2801_STATUS); 409 if (stat & DT_S_READY) 410 break; 411 } while (timeout--); 412 if (!timeout) { 413 printk("dt2801: timeout 2 status=0x%02x\n", stat); 414 } 415 416 DPRINTK("dt2801: reading code\n"); 417 dt2801_readdata(dev, &board_code); 418 419 DPRINTK("dt2801: ok. code=0x%02x\n", board_code); 420 421 return board_code; 422} 423 424static int probe_number_of_ai_chans(struct comedi_device * dev) 425{ 426 int n_chans; 427 int stat; 428 int data; 429 430 for (n_chans = 0; n_chans < 16; n_chans++) { 431 stat = dt2801_writecmd(dev, DT_C_READ_ADIM); 432 dt2801_writedata(dev, 0); 433 dt2801_writedata(dev, n_chans); 434 stat = dt2801_readdata2(dev, &data); 435 436 if (stat) 437 break; 438 } 439 440 dt2801_reset(dev); 441 dt2801_reset(dev); 442 443 return n_chans; 444} 445 446static const struct comedi_lrange *dac_range_table[] = { 447 &range_bipolar10, 448 &range_bipolar5, 449 &range_bipolar2_5, 450 &range_unipolar10, 451 &range_unipolar5 452}; 453 454static const struct comedi_lrange *dac_range_lkup(int opt) 455{ 456 if (opt < 0 || opt > 5) 457 return &range_unknown; 458 return dac_range_table[opt]; 459} 460 461static const struct comedi_lrange *ai_range_lkup(int type, int opt) 462{ 463 switch (type) { 464 case 0: 465 return (opt) ? 466 &range_dt2801_ai_pgl_unipolar : 467 &range_dt2801_ai_pgl_bipolar; 468 case 1: 469 return (opt) ? &range_unipolar10 : &range_bipolar10; 470 case 2: 471 return &range_unipolar5; 472 } 473 return &range_unknown; 474} 475 476/* 477 options: 478 [0] - i/o base 479 [1] - unused 480 [2] - a/d 0=differential, 1=single-ended 481 [3] - a/d range 0=[-10,10], 1=[0,10] 482 [4] - dac0 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5] 483 [5] - dac1 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5] 484*/ 485static int dt2801_attach(struct comedi_device * dev, struct comedi_devconfig * it) 486{ 487 struct comedi_subdevice *s; 488 unsigned long iobase; 489 int board_code, type; 490 int ret = 0; 491 int n_ai_chans; 492 493 iobase = it->options[0]; 494 if (!request_region(iobase, DT2801_IOSIZE, "dt2801")) { 495 comedi_error(dev, "I/O port conflict"); 496 return -EIO; 497 } 498 dev->iobase = iobase; 499 500 /* do some checking */ 501 502 board_code = dt2801_reset(dev); 503 504 /* heh. if it didn't work, try it again. */ 505 if (!board_code) 506 board_code = dt2801_reset(dev); 507 508 for (type = 0; type < n_boardtypes; type++) { 509 if (boardtypes[type].boardcode == board_code) 510 goto havetype; 511 } 512 printk("dt2801: unrecognized board code=0x%02x, contact author\n", 513 board_code); 514 type = 0; 515 516 havetype: 517 dev->board_ptr = boardtypes + type; 518 printk("dt2801: %s at port 0x%lx", boardtype.name, iobase); 519 520 n_ai_chans = probe_number_of_ai_chans(dev); 521 printk(" (ai channels = %d)", n_ai_chans); 522 523 if ((ret = alloc_subdevices(dev, 4)) < 0) 524 goto out; 525 526 if ((ret = alloc_private(dev, sizeof(struct dt2801_private))) < 0) 527 goto out; 528 529 dev->board_name = boardtype.name; 530 531 s = dev->subdevices + 0; 532 /* ai subdevice */ 533 s->type = COMEDI_SUBD_AI; 534 s->subdev_flags = SDF_READABLE | SDF_GROUND; 535#if 1 536 s->n_chan = n_ai_chans; 537#else 538 if (it->options[2]) 539 s->n_chan = boardtype.ad_chan; 540 else 541 s->n_chan = boardtype.ad_chan / 2; 542#endif 543 s->maxdata = (1 << boardtype.adbits) - 1; 544 s->range_table = ai_range_lkup(boardtype.adrangetype, it->options[3]); 545 s->insn_read = dt2801_ai_insn_read; 546 547 s++; 548 /* ao subdevice */ 549 s->type = COMEDI_SUBD_AO; 550 s->subdev_flags = SDF_WRITABLE; 551 s->n_chan = 2; 552 s->maxdata = (1 << boardtype.dabits) - 1; 553 s->range_table_list = devpriv->dac_range_types; 554 devpriv->dac_range_types[0] = dac_range_lkup(it->options[4]); 555 devpriv->dac_range_types[1] = dac_range_lkup(it->options[5]); 556 s->insn_read = dt2801_ao_insn_read; 557 s->insn_write = dt2801_ao_insn_write; 558 559 s++; 560 /* 1st digital subdevice */ 561 s->type = COMEDI_SUBD_DIO; 562 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 563 s->n_chan = 8; 564 s->maxdata = 1; 565 s->range_table = &range_digital; 566 s->insn_bits = dt2801_dio_insn_bits; 567 s->insn_config = dt2801_dio_insn_config; 568 569 s++; 570 /* 2nd digital subdevice */ 571 s->type = COMEDI_SUBD_DIO; 572 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 573 s->n_chan = 8; 574 s->maxdata = 1; 575 s->range_table = &range_digital; 576 s->insn_bits = dt2801_dio_insn_bits; 577 s->insn_config = dt2801_dio_insn_config; 578 579 ret = 0; 580 out: 581 printk("\n"); 582 583 return ret; 584} 585 586static int dt2801_detach(struct comedi_device * dev) 587{ 588 if (dev->iobase) 589 release_region(dev->iobase, DT2801_IOSIZE); 590 591 return 0; 592} 593 594static int dt2801_error(struct comedi_device * dev, int stat) 595{ 596 if (stat < 0) { 597 if (stat == -ETIME) { 598 printk("dt2801: timeout\n"); 599 } else { 600 printk("dt2801: error %d\n", stat); 601 } 602 return stat; 603 } 604 printk("dt2801: error status 0x%02x, resetting...\n", stat); 605 606 dt2801_reset(dev); 607 dt2801_reset(dev); 608 609 return -EIO; 610} 611 612static int dt2801_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, 613 struct comedi_insn * insn, unsigned int * data) 614{ 615 int d; 616 int stat; 617 int i; 618 619 for (i = 0; i < insn->n; i++) { 620 stat = dt2801_writecmd(dev, DT_C_READ_ADIM); 621 dt2801_writedata(dev, CR_RANGE(insn->chanspec)); 622 dt2801_writedata(dev, CR_CHAN(insn->chanspec)); 623 stat = dt2801_readdata2(dev, &d); 624 625 if (stat != 0) 626 return dt2801_error(dev, stat); 627 628 data[i] = d; 629 } 630 631 return i; 632} 633 634static int dt2801_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, 635 struct comedi_insn * insn, unsigned int * data) 636{ 637 data[0] = devpriv->ao_readback[CR_CHAN(insn->chanspec)]; 638 639 return 1; 640} 641 642static int dt2801_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice * s, 643 struct comedi_insn * insn, unsigned int * data) 644{ 645 dt2801_writecmd(dev, DT_C_WRITE_DAIM); 646 dt2801_writedata(dev, CR_CHAN(insn->chanspec)); 647 dt2801_writedata2(dev, data[0]); 648 649 devpriv->ao_readback[CR_CHAN(insn->chanspec)] = data[0]; 650 651 return 1; 652} 653 654static int dt2801_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, 655 struct comedi_insn * insn, unsigned int * data) 656{ 657 int which = 0; 658 659 if (s == dev->subdevices + 4) 660 which = 1; 661 662 if (insn->n != 2) 663 return -EINVAL; 664 if (data[0]) { 665 s->state &= ~data[0]; 666 s->state |= (data[0] & data[1]); 667 dt2801_writecmd(dev, DT_C_WRITE_DIG); 668 dt2801_writedata(dev, which); 669 dt2801_writedata(dev, s->state); 670 } 671 dt2801_writecmd(dev, DT_C_READ_DIG); 672 dt2801_writedata(dev, which); 673 dt2801_readdata(dev, data + 1); 674 675 return 2; 676} 677 678static int dt2801_dio_insn_config(struct comedi_device * dev, 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 /* configure */ 687 if (data[0]) { 688 s->io_bits = 0xff; 689 dt2801_writecmd(dev, DT_C_SET_DIGOUT); 690 } else { 691 s->io_bits = 0; 692 dt2801_writecmd(dev, DT_C_SET_DIGIN); 693 } 694 dt2801_writedata(dev, which); 695 696 return 1; 697} 698