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 <linux/module.h> 33#include "../comedidev.h" 34#include <linux/delay.h> 35 36#define DT2801_TIMEOUT 1000 37 38/* Hardware Configuration */ 39/* ====================== */ 40 41#define DT2801_MAX_DMA_SIZE (64 * 1024) 42 43/* define's */ 44/* ====================== */ 45 46/* Commands */ 47#define DT_C_RESET 0x0 48#define DT_C_CLEAR_ERR 0x1 49#define DT_C_READ_ERRREG 0x2 50#define DT_C_SET_CLOCK 0x3 51 52#define DT_C_TEST 0xb 53#define DT_C_STOP 0xf 54 55#define DT_C_SET_DIGIN 0x4 56#define DT_C_SET_DIGOUT 0x5 57#define DT_C_READ_DIG 0x6 58#define DT_C_WRITE_DIG 0x7 59 60#define DT_C_WRITE_DAIM 0x8 61#define DT_C_SET_DA 0x9 62#define DT_C_WRITE_DA 0xa 63 64#define DT_C_READ_ADIM 0xc 65#define DT_C_SET_AD 0xd 66#define DT_C_READ_AD 0xe 67 68/* Command modifiers (only used with read/write), EXTTRIG can be 69 used with some other commands. 70*/ 71#define DT_MOD_DMA (1<<4) 72#define DT_MOD_CONT (1<<5) 73#define DT_MOD_EXTCLK (1<<6) 74#define DT_MOD_EXTTRIG (1<<7) 75 76/* Bits in status register */ 77#define DT_S_DATA_OUT_READY (1<<0) 78#define DT_S_DATA_IN_FULL (1<<1) 79#define DT_S_READY (1<<2) 80#define DT_S_COMMAND (1<<3) 81#define DT_S_COMPOSITE_ERROR (1<<7) 82 83/* registers */ 84#define DT2801_DATA 0 85#define DT2801_STATUS 1 86#define DT2801_CMD 1 87 88#if 0 89/* ignore 'defined but not used' warning */ 90static const struct comedi_lrange range_dt2801_ai_pgh_bipolar = { 91 4, { 92 BIP_RANGE(10), 93 BIP_RANGE(5), 94 BIP_RANGE(2.5), 95 BIP_RANGE(1.25) 96 } 97}; 98#endif 99static const struct comedi_lrange range_dt2801_ai_pgl_bipolar = { 100 4, { 101 BIP_RANGE(10), 102 BIP_RANGE(1), 103 BIP_RANGE(0.1), 104 BIP_RANGE(0.02) 105 } 106}; 107 108#if 0 109/* ignore 'defined but not used' warning */ 110static const struct comedi_lrange range_dt2801_ai_pgh_unipolar = { 111 4, { 112 UNI_RANGE(10), 113 UNI_RANGE(5), 114 UNI_RANGE(2.5), 115 UNI_RANGE(1.25) 116 } 117}; 118#endif 119static const struct comedi_lrange range_dt2801_ai_pgl_unipolar = { 120 4, { 121 UNI_RANGE(10), 122 UNI_RANGE(1), 123 UNI_RANGE(0.1), 124 UNI_RANGE(0.02) 125 } 126}; 127 128struct dt2801_board { 129 130 const char *name; 131 int boardcode; 132 int ad_diff; 133 int ad_chan; 134 int adbits; 135 int adrangetype; 136 int dabits; 137}; 138 139/* Typeid's for the different boards of the DT2801-series 140 (taken from the test-software, that comes with the board) 141 */ 142static const struct dt2801_board boardtypes[] = { 143 { 144 .name = "dt2801", 145 .boardcode = 0x09, 146 .ad_diff = 2, 147 .ad_chan = 16, 148 .adbits = 12, 149 .adrangetype = 0, 150 .dabits = 12}, 151 { 152 .name = "dt2801-a", 153 .boardcode = 0x52, 154 .ad_diff = 2, 155 .ad_chan = 16, 156 .adbits = 12, 157 .adrangetype = 0, 158 .dabits = 12}, 159 { 160 .name = "dt2801/5716a", 161 .boardcode = 0x82, 162 .ad_diff = 1, 163 .ad_chan = 16, 164 .adbits = 16, 165 .adrangetype = 1, 166 .dabits = 12}, 167 { 168 .name = "dt2805", 169 .boardcode = 0x12, 170 .ad_diff = 1, 171 .ad_chan = 16, 172 .adbits = 12, 173 .adrangetype = 0, 174 .dabits = 12}, 175 { 176 .name = "dt2805/5716a", 177 .boardcode = 0x92, 178 .ad_diff = 1, 179 .ad_chan = 16, 180 .adbits = 16, 181 .adrangetype = 1, 182 .dabits = 12}, 183 { 184 .name = "dt2808", 185 .boardcode = 0x20, 186 .ad_diff = 0, 187 .ad_chan = 16, 188 .adbits = 12, 189 .adrangetype = 2, 190 .dabits = 8}, 191 { 192 .name = "dt2818", 193 .boardcode = 0xa2, 194 .ad_diff = 0, 195 .ad_chan = 4, 196 .adbits = 12, 197 .adrangetype = 0, 198 .dabits = 12}, 199 { 200 .name = "dt2809", 201 .boardcode = 0xb0, 202 .ad_diff = 0, 203 .ad_chan = 8, 204 .adbits = 12, 205 .adrangetype = 1, 206 .dabits = 12}, 207}; 208 209struct dt2801_private { 210 const struct comedi_lrange *dac_range_types[2]; 211}; 212 213/* These are the low-level routines: 214 writecommand: write a command to the board 215 writedata: write data byte 216 readdata: read data byte 217 */ 218 219/* Only checks DataOutReady-flag, not the Ready-flag as it is done 220 in the examples of the manual. I don't see why this should be 221 necessary. */ 222static int dt2801_readdata(struct comedi_device *dev, int *data) 223{ 224 int stat = 0; 225 int timeout = DT2801_TIMEOUT; 226 227 do { 228 stat = inb_p(dev->iobase + DT2801_STATUS); 229 if (stat & (DT_S_COMPOSITE_ERROR | DT_S_READY)) 230 return stat; 231 if (stat & DT_S_DATA_OUT_READY) { 232 *data = inb_p(dev->iobase + DT2801_DATA); 233 return 0; 234 } 235 } while (--timeout > 0); 236 237 return -ETIME; 238} 239 240static int dt2801_readdata2(struct comedi_device *dev, int *data) 241{ 242 int lb = 0; 243 int hb = 0; 244 int ret; 245 246 ret = dt2801_readdata(dev, &lb); 247 if (ret) 248 return ret; 249 ret = dt2801_readdata(dev, &hb); 250 if (ret) 251 return ret; 252 253 *data = (hb << 8) + lb; 254 return 0; 255} 256 257static int dt2801_writedata(struct comedi_device *dev, unsigned int data) 258{ 259 int stat = 0; 260 int timeout = DT2801_TIMEOUT; 261 262 do { 263 stat = inb_p(dev->iobase + DT2801_STATUS); 264 265 if (stat & DT_S_COMPOSITE_ERROR) 266 return stat; 267 if (!(stat & DT_S_DATA_IN_FULL)) { 268 outb_p(data & 0xff, dev->iobase + DT2801_DATA); 269 return 0; 270 } 271 } while (--timeout > 0); 272 273 return -ETIME; 274} 275 276static int dt2801_writedata2(struct comedi_device *dev, unsigned int data) 277{ 278 int ret; 279 280 ret = dt2801_writedata(dev, data & 0xff); 281 if (ret < 0) 282 return ret; 283 ret = dt2801_writedata(dev, (data >> 8)); 284 if (ret < 0) 285 return ret; 286 287 return 0; 288} 289 290static int dt2801_wait_for_ready(struct comedi_device *dev) 291{ 292 int timeout = DT2801_TIMEOUT; 293 int stat; 294 295 stat = inb_p(dev->iobase + DT2801_STATUS); 296 if (stat & DT_S_READY) 297 return 0; 298 do { 299 stat = inb_p(dev->iobase + DT2801_STATUS); 300 301 if (stat & DT_S_COMPOSITE_ERROR) 302 return stat; 303 if (stat & DT_S_READY) 304 return 0; 305 } while (--timeout > 0); 306 307 return -ETIME; 308} 309 310static void dt2801_writecmd(struct comedi_device *dev, int command) 311{ 312 int stat; 313 314 dt2801_wait_for_ready(dev); 315 316 stat = inb_p(dev->iobase + DT2801_STATUS); 317 if (stat & DT_S_COMPOSITE_ERROR) { 318 dev_dbg(dev->class_dev, 319 "composite-error in %s, ignoring\n", __func__); 320 } 321 if (!(stat & DT_S_READY)) 322 dev_dbg(dev->class_dev, "!ready in %s, ignoring\n", __func__); 323 outb_p(command, dev->iobase + DT2801_CMD); 324} 325 326static int dt2801_reset(struct comedi_device *dev) 327{ 328 int board_code = 0; 329 unsigned int stat; 330 int timeout; 331 332 /* pull random data from data port */ 333 inb_p(dev->iobase + DT2801_DATA); 334 inb_p(dev->iobase + DT2801_DATA); 335 inb_p(dev->iobase + DT2801_DATA); 336 inb_p(dev->iobase + DT2801_DATA); 337 338 /* dt2801_writecmd(dev,DT_C_STOP); */ 339 outb_p(DT_C_STOP, dev->iobase + DT2801_CMD); 340 341 /* dt2801_wait_for_ready(dev); */ 342 udelay(100); 343 timeout = 10000; 344 do { 345 stat = inb_p(dev->iobase + DT2801_STATUS); 346 if (stat & DT_S_READY) 347 break; 348 } while (timeout--); 349 if (!timeout) 350 dev_dbg(dev->class_dev, "timeout 1 status=0x%02x\n", stat); 351 352 /* dt2801_readdata(dev,&board_code); */ 353 354 outb_p(DT_C_RESET, dev->iobase + DT2801_CMD); 355 /* dt2801_writecmd(dev,DT_C_RESET); */ 356 357 udelay(100); 358 timeout = 10000; 359 do { 360 stat = inb_p(dev->iobase + DT2801_STATUS); 361 if (stat & DT_S_READY) 362 break; 363 } while (timeout--); 364 if (!timeout) 365 dev_dbg(dev->class_dev, "timeout 2 status=0x%02x\n", stat); 366 367 dt2801_readdata(dev, &board_code); 368 369 return board_code; 370} 371 372static int probe_number_of_ai_chans(struct comedi_device *dev) 373{ 374 int n_chans; 375 int stat; 376 int data; 377 378 for (n_chans = 0; n_chans < 16; n_chans++) { 379 dt2801_writecmd(dev, DT_C_READ_ADIM); 380 dt2801_writedata(dev, 0); 381 dt2801_writedata(dev, n_chans); 382 stat = dt2801_readdata2(dev, &data); 383 384 if (stat) 385 break; 386 } 387 388 dt2801_reset(dev); 389 dt2801_reset(dev); 390 391 return n_chans; 392} 393 394static const struct comedi_lrange *dac_range_table[] = { 395 &range_bipolar10, 396 &range_bipolar5, 397 &range_bipolar2_5, 398 &range_unipolar10, 399 &range_unipolar5 400}; 401 402static const struct comedi_lrange *dac_range_lkup(int opt) 403{ 404 if (opt < 0 || opt >= 5) 405 return &range_unknown; 406 return dac_range_table[opt]; 407} 408 409static const struct comedi_lrange *ai_range_lkup(int type, int opt) 410{ 411 switch (type) { 412 case 0: 413 return (opt) ? 414 &range_dt2801_ai_pgl_unipolar : 415 &range_dt2801_ai_pgl_bipolar; 416 case 1: 417 return (opt) ? &range_unipolar10 : &range_bipolar10; 418 case 2: 419 return &range_unipolar5; 420 } 421 return &range_unknown; 422} 423 424static int dt2801_error(struct comedi_device *dev, int stat) 425{ 426 if (stat < 0) { 427 if (stat == -ETIME) 428 dev_dbg(dev->class_dev, "timeout\n"); 429 else 430 dev_dbg(dev->class_dev, "error %d\n", stat); 431 return stat; 432 } 433 dev_dbg(dev->class_dev, "error status 0x%02x, resetting...\n", stat); 434 435 dt2801_reset(dev); 436 dt2801_reset(dev); 437 438 return -EIO; 439} 440 441static int dt2801_ai_insn_read(struct comedi_device *dev, 442 struct comedi_subdevice *s, 443 struct comedi_insn *insn, unsigned int *data) 444{ 445 int d; 446 int stat; 447 int i; 448 449 for (i = 0; i < insn->n; i++) { 450 dt2801_writecmd(dev, DT_C_READ_ADIM); 451 dt2801_writedata(dev, CR_RANGE(insn->chanspec)); 452 dt2801_writedata(dev, CR_CHAN(insn->chanspec)); 453 stat = dt2801_readdata2(dev, &d); 454 455 if (stat != 0) 456 return dt2801_error(dev, stat); 457 458 data[i] = d; 459 } 460 461 return i; 462} 463 464static int dt2801_ao_insn_write(struct comedi_device *dev, 465 struct comedi_subdevice *s, 466 struct comedi_insn *insn, 467 unsigned int *data) 468{ 469 unsigned int chan = CR_CHAN(insn->chanspec); 470 471 dt2801_writecmd(dev, DT_C_WRITE_DAIM); 472 dt2801_writedata(dev, chan); 473 dt2801_writedata2(dev, data[0]); 474 475 s->readback[chan] = data[0]; 476 477 return 1; 478} 479 480static int dt2801_dio_insn_bits(struct comedi_device *dev, 481 struct comedi_subdevice *s, 482 struct comedi_insn *insn, 483 unsigned int *data) 484{ 485 int which = (s == &dev->subdevices[3]) ? 1 : 0; 486 unsigned int val = 0; 487 488 if (comedi_dio_update_state(s, data)) { 489 dt2801_writecmd(dev, DT_C_WRITE_DIG); 490 dt2801_writedata(dev, which); 491 dt2801_writedata(dev, s->state); 492 } 493 494 dt2801_writecmd(dev, DT_C_READ_DIG); 495 dt2801_writedata(dev, which); 496 dt2801_readdata(dev, &val); 497 498 data[1] = val; 499 500 return insn->n; 501} 502 503static int dt2801_dio_insn_config(struct comedi_device *dev, 504 struct comedi_subdevice *s, 505 struct comedi_insn *insn, 506 unsigned int *data) 507{ 508 int ret; 509 510 ret = comedi_dio_insn_config(dev, s, insn, data, 0xff); 511 if (ret) 512 return ret; 513 514 dt2801_writecmd(dev, s->io_bits ? DT_C_SET_DIGOUT : DT_C_SET_DIGIN); 515 dt2801_writedata(dev, (s == &dev->subdevices[3]) ? 1 : 0); 516 517 return insn->n; 518} 519 520/* 521 options: 522 [0] - i/o base 523 [1] - unused 524 [2] - a/d 0=differential, 1=single-ended 525 [3] - a/d range 0=[-10,10], 1=[0,10] 526 [4] - dac0 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5] 527 [5] - dac1 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5] 528*/ 529static int dt2801_attach(struct comedi_device *dev, struct comedi_devconfig *it) 530{ 531 const struct dt2801_board *board; 532 struct dt2801_private *devpriv; 533 struct comedi_subdevice *s; 534 int board_code, type; 535 int ret = 0; 536 int n_ai_chans; 537 538 ret = comedi_request_region(dev, it->options[0], 0x2); 539 if (ret) 540 return ret; 541 542 /* do some checking */ 543 544 board_code = dt2801_reset(dev); 545 546 /* heh. if it didn't work, try it again. */ 547 if (!board_code) 548 board_code = dt2801_reset(dev); 549 550 for (type = 0; type < ARRAY_SIZE(boardtypes); type++) { 551 if (boardtypes[type].boardcode == board_code) 552 goto havetype; 553 } 554 dev_dbg(dev->class_dev, 555 "unrecognized board code=0x%02x, contact author\n", board_code); 556 type = 0; 557 558havetype: 559 dev->board_ptr = boardtypes + type; 560 board = dev->board_ptr; 561 562 n_ai_chans = probe_number_of_ai_chans(dev); 563 564 ret = comedi_alloc_subdevices(dev, 4); 565 if (ret) 566 goto out; 567 568 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); 569 if (!devpriv) 570 return -ENOMEM; 571 572 dev->board_name = board->name; 573 574 s = &dev->subdevices[0]; 575 /* ai subdevice */ 576 s->type = COMEDI_SUBD_AI; 577 s->subdev_flags = SDF_READABLE | SDF_GROUND; 578#if 1 579 s->n_chan = n_ai_chans; 580#else 581 if (it->options[2]) 582 s->n_chan = board->ad_chan; 583 else 584 s->n_chan = board->ad_chan / 2; 585#endif 586 s->maxdata = (1 << board->adbits) - 1; 587 s->range_table = ai_range_lkup(board->adrangetype, it->options[3]); 588 s->insn_read = dt2801_ai_insn_read; 589 590 s = &dev->subdevices[1]; 591 /* ao subdevice */ 592 s->type = COMEDI_SUBD_AO; 593 s->subdev_flags = SDF_WRITABLE; 594 s->n_chan = 2; 595 s->maxdata = (1 << board->dabits) - 1; 596 s->range_table_list = devpriv->dac_range_types; 597 devpriv->dac_range_types[0] = dac_range_lkup(it->options[4]); 598 devpriv->dac_range_types[1] = dac_range_lkup(it->options[5]); 599 s->insn_write = dt2801_ao_insn_write; 600 s->insn_read = comedi_readback_insn_read; 601 602 ret = comedi_alloc_subdev_readback(s); 603 if (ret) 604 return ret; 605 606 s = &dev->subdevices[2]; 607 /* 1st digital subdevice */ 608 s->type = COMEDI_SUBD_DIO; 609 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 610 s->n_chan = 8; 611 s->maxdata = 1; 612 s->range_table = &range_digital; 613 s->insn_bits = dt2801_dio_insn_bits; 614 s->insn_config = dt2801_dio_insn_config; 615 616 s = &dev->subdevices[3]; 617 /* 2nd digital subdevice */ 618 s->type = COMEDI_SUBD_DIO; 619 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 620 s->n_chan = 8; 621 s->maxdata = 1; 622 s->range_table = &range_digital; 623 s->insn_bits = dt2801_dio_insn_bits; 624 s->insn_config = dt2801_dio_insn_config; 625 626 ret = 0; 627out: 628 return ret; 629} 630 631static struct comedi_driver dt2801_driver = { 632 .driver_name = "dt2801", 633 .module = THIS_MODULE, 634 .attach = dt2801_attach, 635 .detach = comedi_legacy_detach, 636}; 637module_comedi_driver(dt2801_driver); 638 639MODULE_AUTHOR("Comedi http://www.comedi.org"); 640MODULE_DESCRIPTION("Comedi low-level driver"); 641MODULE_LICENSE("GPL"); 642