dt2801.c revision 8629efa4cbf6f89a54a85af4b8bc31762af01800
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 boardtype (*(const struct dt2801_board *)dev->board_ptr) 221 222struct dt2801_private { 223 224 const struct comedi_lrange *dac_range_types[2]; 225 unsigned int ao_readback[2]; 226}; 227 228#define devpriv ((struct dt2801_private *)dev->private) 229 230static int dt2801_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, 231 struct comedi_insn *insn, unsigned int *data); 232static int dt2801_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, 233 struct comedi_insn *insn, unsigned int *data); 234static int dt2801_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, 235 struct comedi_insn *insn, unsigned int *data); 236static int dt2801_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, 237 struct comedi_insn *insn, unsigned int *data); 238static int dt2801_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, 239 struct comedi_insn *insn, unsigned int *data); 240 241/* These are the low-level routines: 242 writecommand: write a command to the board 243 writedata: write data byte 244 readdata: read data byte 245 */ 246 247/* Only checks DataOutReady-flag, not the Ready-flag as it is done 248 in the examples of the manual. I don't see why this should be 249 necessary. */ 250static int dt2801_readdata(struct comedi_device *dev, int *data) 251{ 252 int stat = 0; 253 int timeout = DT2801_TIMEOUT; 254 255 do { 256 stat = inb_p(dev->iobase + DT2801_STATUS); 257 if (stat & (DT_S_COMPOSITE_ERROR | DT_S_READY)) { 258 return stat; 259 } 260 if (stat & DT_S_DATA_OUT_READY) { 261 *data = inb_p(dev->iobase + DT2801_DATA); 262 return 0; 263 } 264 } while (--timeout > 0); 265 266 return -ETIME; 267} 268 269static int dt2801_readdata2(struct comedi_device *dev, int *data) 270{ 271 int lb, hb; 272 int ret; 273 274 ret = dt2801_readdata(dev, &lb); 275 if (ret) 276 return ret; 277 ret = dt2801_readdata(dev, &hb); 278 if (ret) 279 return ret; 280 281 *data = (hb << 8) + lb; 282 return 0; 283} 284 285static int dt2801_writedata(struct comedi_device *dev, unsigned int data) 286{ 287 int stat = 0; 288 int timeout = DT2801_TIMEOUT; 289 290 do { 291 stat = inb_p(dev->iobase + DT2801_STATUS); 292 293 if (stat & DT_S_COMPOSITE_ERROR) { 294 return stat; 295 } 296 if (!(stat & DT_S_DATA_IN_FULL)) { 297 outb_p(data & 0xff, dev->iobase + DT2801_DATA); 298 return 0; 299 } 300#if 0 301 if (stat & DT_S_READY) { 302 printk("dt2801: ready flag set (bad!) in dt2801_writedata()\n"); 303 return -EIO; 304 } 305#endif 306 } while (--timeout > 0); 307 308 return -ETIME; 309} 310 311static int dt2801_writedata2(struct comedi_device *dev, unsigned int data) 312{ 313 int ret; 314 315 ret = dt2801_writedata(dev, data & 0xff); 316 if (ret < 0) 317 return ret; 318 ret = dt2801_writedata(dev, (data >> 8)); 319 if (ret < 0) 320 return ret; 321 322 return 0; 323} 324 325static int dt2801_wait_for_ready(struct comedi_device *dev) 326{ 327 int timeout = DT2801_TIMEOUT; 328 int stat; 329 330 stat = inb_p(dev->iobase + DT2801_STATUS); 331 if (stat & DT_S_READY) { 332 return 0; 333 } 334 do { 335 stat = inb_p(dev->iobase + DT2801_STATUS); 336 337 if (stat & DT_S_COMPOSITE_ERROR) { 338 return stat; 339 } 340 if (stat & DT_S_READY) { 341 return 0; 342 } 343 } while (--timeout > 0); 344 345 return -ETIME; 346} 347 348static int dt2801_writecmd(struct comedi_device *dev, int command) 349{ 350 int stat; 351 352 dt2801_wait_for_ready(dev); 353 354 stat = inb_p(dev->iobase + DT2801_STATUS); 355 if (stat & DT_S_COMPOSITE_ERROR) { 356 printk("dt2801: composite-error in dt2801_writecmd(), ignoring\n"); 357 } 358 if (!(stat & DT_S_READY)) { 359 printk("dt2801: !ready in dt2801_writecmd(), ignoring\n"); 360 } 361 outb_p(command, dev->iobase + DT2801_CMD); 362 363 return 0; 364} 365 366static int dt2801_reset(struct comedi_device *dev) 367{ 368 int board_code = 0; 369 unsigned int stat; 370 int timeout; 371 372 DPRINTK("dt2801: resetting board...\n"); 373 DPRINTK("fingerprint: 0x%02x 0x%02x\n", inb_p(dev->iobase), 374 inb_p(dev->iobase + 1)); 375 376 /* pull random data from data port */ 377 inb_p(dev->iobase + DT2801_DATA); 378 inb_p(dev->iobase + DT2801_DATA); 379 inb_p(dev->iobase + DT2801_DATA); 380 inb_p(dev->iobase + DT2801_DATA); 381 382 DPRINTK("dt2801: stop\n"); 383 /* dt2801_writecmd(dev,DT_C_STOP); */ 384 outb_p(DT_C_STOP, dev->iobase + DT2801_CMD); 385 386 /* dt2801_wait_for_ready(dev); */ 387 comedi_udelay(100); 388 timeout = 10000; 389 do { 390 stat = inb_p(dev->iobase + DT2801_STATUS); 391 if (stat & DT_S_READY) 392 break; 393 } while (timeout--); 394 if (!timeout) { 395 printk("dt2801: timeout 1 status=0x%02x\n", stat); 396 } 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 < ARRAY_SIZE(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 ret = alloc_subdevices(dev, 4); 524 if (ret < 0) 525 goto out; 526 527 ret = alloc_private(dev, sizeof(struct dt2801_private)); 528 if (ret < 0) 529 goto out; 530 531 dev->board_name = boardtype.name; 532 533 s = dev->subdevices + 0; 534 /* ai subdevice */ 535 s->type = COMEDI_SUBD_AI; 536 s->subdev_flags = SDF_READABLE | SDF_GROUND; 537#if 1 538 s->n_chan = n_ai_chans; 539#else 540 if (it->options[2]) 541 s->n_chan = boardtype.ad_chan; 542 else 543 s->n_chan = boardtype.ad_chan / 2; 544#endif 545 s->maxdata = (1 << boardtype.adbits) - 1; 546 s->range_table = ai_range_lkup(boardtype.adrangetype, it->options[3]); 547 s->insn_read = dt2801_ai_insn_read; 548 549 s++; 550 /* ao subdevice */ 551 s->type = COMEDI_SUBD_AO; 552 s->subdev_flags = SDF_WRITABLE; 553 s->n_chan = 2; 554 s->maxdata = (1 << boardtype.dabits) - 1; 555 s->range_table_list = devpriv->dac_range_types; 556 devpriv->dac_range_types[0] = dac_range_lkup(it->options[4]); 557 devpriv->dac_range_types[1] = dac_range_lkup(it->options[5]); 558 s->insn_read = dt2801_ao_insn_read; 559 s->insn_write = dt2801_ao_insn_write; 560 561 s++; 562 /* 1st digital subdevice */ 563 s->type = COMEDI_SUBD_DIO; 564 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 565 s->n_chan = 8; 566 s->maxdata = 1; 567 s->range_table = &range_digital; 568 s->insn_bits = dt2801_dio_insn_bits; 569 s->insn_config = dt2801_dio_insn_config; 570 571 s++; 572 /* 2nd digital subdevice */ 573 s->type = COMEDI_SUBD_DIO; 574 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 575 s->n_chan = 8; 576 s->maxdata = 1; 577 s->range_table = &range_digital; 578 s->insn_bits = dt2801_dio_insn_bits; 579 s->insn_config = dt2801_dio_insn_config; 580 581 ret = 0; 582 out: 583 printk("\n"); 584 585 return ret; 586} 587 588static int dt2801_detach(struct comedi_device *dev) 589{ 590 if (dev->iobase) 591 release_region(dev->iobase, DT2801_IOSIZE); 592 593 return 0; 594} 595 596static int dt2801_error(struct comedi_device *dev, int stat) 597{ 598 if (stat < 0) { 599 if (stat == -ETIME) { 600 printk("dt2801: timeout\n"); 601 } else { 602 printk("dt2801: error %d\n", stat); 603 } 604 return stat; 605 } 606 printk("dt2801: error status 0x%02x, resetting...\n", stat); 607 608 dt2801_reset(dev); 609 dt2801_reset(dev); 610 611 return -EIO; 612} 613 614static int dt2801_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, 615 struct comedi_insn *insn, unsigned int *data) 616{ 617 int d; 618 int stat; 619 int i; 620 621 for (i = 0; i < insn->n; i++) { 622 stat = dt2801_writecmd(dev, DT_C_READ_ADIM); 623 dt2801_writedata(dev, CR_RANGE(insn->chanspec)); 624 dt2801_writedata(dev, CR_CHAN(insn->chanspec)); 625 stat = dt2801_readdata2(dev, &d); 626 627 if (stat != 0) 628 return dt2801_error(dev, stat); 629 630 data[i] = d; 631 } 632 633 return i; 634} 635 636static int dt2801_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, 637 struct comedi_insn *insn, unsigned int *data) 638{ 639 data[0] = devpriv->ao_readback[CR_CHAN(insn->chanspec)]; 640 641 return 1; 642} 643 644static int dt2801_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, 645 struct comedi_insn *insn, unsigned int *data) 646{ 647 dt2801_writecmd(dev, DT_C_WRITE_DAIM); 648 dt2801_writedata(dev, CR_CHAN(insn->chanspec)); 649 dt2801_writedata2(dev, data[0]); 650 651 devpriv->ao_readback[CR_CHAN(insn->chanspec)] = data[0]; 652 653 return 1; 654} 655 656static int dt2801_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, 657 struct comedi_insn *insn, unsigned int *data) 658{ 659 int which = 0; 660 661 if (s == dev->subdevices + 4) 662 which = 1; 663 664 if (insn->n != 2) 665 return -EINVAL; 666 if (data[0]) { 667 s->state &= ~data[0]; 668 s->state |= (data[0] & data[1]); 669 dt2801_writecmd(dev, DT_C_WRITE_DIG); 670 dt2801_writedata(dev, which); 671 dt2801_writedata(dev, s->state); 672 } 673 dt2801_writecmd(dev, DT_C_READ_DIG); 674 dt2801_writedata(dev, which); 675 dt2801_readdata(dev, data + 1); 676 677 return 2; 678} 679 680static int dt2801_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, 681 struct comedi_insn *insn, unsigned int *data) 682{ 683 int which = 0; 684 685 if (s == dev->subdevices + 4) 686 which = 1; 687 688 /* configure */ 689 if (data[0]) { 690 s->io_bits = 0xff; 691 dt2801_writecmd(dev, DT_C_SET_DIGOUT); 692 } else { 693 s->io_bits = 0; 694 dt2801_writecmd(dev, DT_C_SET_DIGIN); 695 } 696 dt2801_writedata(dev, which); 697 698 return 1; 699} 700