dt282x.c revision f8b987b4d35c37cf973c30871fc42b16c6272041
1/* 2 comedi/drivers/dt282x.c 3 Hardware driver for Data Translation DT2821 series 4 5 COMEDI - Linux Control and Measurement Device Interface 6 Copyright (C) 1997-8 David A. Schleef <ds@schleef.org> 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 2 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 */ 18/* 19Driver: dt282x 20Description: Data Translation DT2821 series (including DT-EZ) 21Author: ds 22Devices: [Data Translation] DT2821 (dt2821), 23 DT2821-F-16SE (dt2821-f), DT2821-F-8DI (dt2821-f), 24 DT2821-G-16SE (dt2821-f), DT2821-G-8DI (dt2821-g), 25 DT2823 (dt2823), 26 DT2824-PGH (dt2824-pgh), DT2824-PGL (dt2824-pgl), DT2825 (dt2825), 27 DT2827 (dt2827), DT2828 (dt2828), DT21-EZ (dt21-ez), DT23-EZ (dt23-ez), 28 DT24-EZ (dt24-ez), DT24-EZ-PGL (dt24-ez-pgl) 29Status: complete 30Updated: Wed, 22 Aug 2001 17:11:34 -0700 31 32Configuration options: 33 [0] - I/O port base address 34 [1] - IRQ 35 [2] - DMA 1 36 [3] - DMA 2 37 [4] - AI jumpered for 0=single ended, 1=differential 38 [5] - AI jumpered for 0=straight binary, 1=2's complement 39 [6] - AO 0 jumpered for 0=straight binary, 1=2's complement 40 [7] - AO 1 jumpered for 0=straight binary, 1=2's complement 41 [8] - AI jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5] 42 [9] - AO 0 jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5], 43 4=[-2.5,2.5] 44 [10]- A0 1 jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5], 45 4=[-2.5,2.5] 46 47Notes: 48 - AO commands might be broken. 49 - If you try to run a command on both the AI and AO subdevices 50 simultaneously, bad things will happen. The driver needs to 51 be fixed to check for this situation and return an error. 52*/ 53 54#include <linux/module.h> 55#include "../comedidev.h" 56 57#include <linux/delay.h> 58#include <linux/gfp.h> 59#include <linux/interrupt.h> 60#include <linux/io.h> 61 62#include <asm/dma.h> 63 64#include "comedi_fc.h" 65 66/* 67 * Registers in the DT282x 68 */ 69 70#define DT2821_ADCSR 0x00 /* A/D Control/Status */ 71#define DT2821_CHANCSR 0x02 /* Channel Control/Status */ 72#define DT2821_ADDAT 0x04 /* A/D data */ 73#define DT2821_DACSR 0x06 /* D/A Control/Status */ 74#define DT2821_DADAT 0x08 /* D/A data */ 75#define DT2821_DIODAT 0x0a /* digital data */ 76#define DT2821_SUPCSR 0x0c /* Supervisor Control/Status */ 77#define DT2821_TMRCTR 0x0e /* Timer/Counter */ 78 79/* 80 * Bit fields of each register 81 */ 82 83/* ADCSR */ 84 85#define DT2821_ADERR 0x8000 /* (R) 1 for A/D error */ 86#define DT2821_ADCLK 0x0200 /* (R/W) A/D clock enable */ 87 /* 0x7c00 read as 1's */ 88#define DT2821_MUXBUSY 0x0100 /* (R) multiplexer busy */ 89#define DT2821_ADDONE 0x0080 /* (R) A/D done */ 90#define DT2821_IADDONE 0x0040 /* (R/W) interrupt on A/D done */ 91 /* 0x0030 gain select */ 92 /* 0x000f channel select */ 93 94/* CHANCSR */ 95 96#define DT2821_LLE 0x8000 /* (R/W) Load List Enable */ 97 /* 0x7000 read as 1's */ 98 /* 0x0f00 (R) present address */ 99 /* 0x00f0 read as 1's */ 100 /* 0x000f (R) number of entries - 1 */ 101 102/* DACSR */ 103 104#define DT2821_DAERR 0x8000 /* (R) D/A error */ 105#define DT2821_YSEL 0x0200 /* (R/W) DAC 1 select */ 106#define DT2821_SSEL 0x0100 /* (R/W) single channel select */ 107#define DT2821_DACRDY 0x0080 /* (R) DAC ready */ 108#define DT2821_IDARDY 0x0040 /* (R/W) interrupt on DAC ready */ 109#define DT2821_DACLK 0x0020 /* (R/W) D/A clock enable */ 110#define DT2821_HBOE 0x0002 /* (R/W) DIO high byte output enable */ 111#define DT2821_LBOE 0x0001 /* (R/W) DIO low byte output enable */ 112 113/* SUPCSR */ 114 115#define DT2821_DMAD 0x8000 /* (R) DMA done */ 116#define DT2821_ERRINTEN 0x4000 /* (R/W) interrupt on error */ 117#define DT2821_CLRDMADNE 0x2000 /* (W) clear DMA done */ 118#define DT2821_DDMA 0x1000 /* (R/W) dual DMA */ 119#define DT2821_DS1 0x0800 /* (R/W) DMA select 1 */ 120#define DT2821_DS0 0x0400 /* (R/W) DMA select 0 */ 121#define DT2821_BUFFB 0x0200 /* (R/W) buffer B selected */ 122#define DT2821_SCDN 0x0100 /* (R) scan done */ 123#define DT2821_DACON 0x0080 /* (W) DAC single conversion */ 124#define DT2821_ADCINIT 0x0040 /* (W) A/D initialize */ 125#define DT2821_DACINIT 0x0020 /* (W) D/A initialize */ 126#define DT2821_PRLD 0x0010 /* (W) preload multiplexer */ 127#define DT2821_STRIG 0x0008 /* (W) software trigger */ 128#define DT2821_XTRIG 0x0004 /* (R/W) external trigger enable */ 129#define DT2821_XCLK 0x0002 /* (R/W) external clock enable */ 130#define DT2821_BDINIT 0x0001 /* (W) initialize board */ 131 132static const struct comedi_lrange range_dt282x_ai_lo_bipolar = { 133 4, { 134 BIP_RANGE(10), 135 BIP_RANGE(5), 136 BIP_RANGE(2.5), 137 BIP_RANGE(1.25) 138 } 139}; 140 141static const struct comedi_lrange range_dt282x_ai_lo_unipolar = { 142 4, { 143 UNI_RANGE(10), 144 UNI_RANGE(5), 145 UNI_RANGE(2.5), 146 UNI_RANGE(1.25) 147 } 148}; 149 150static const struct comedi_lrange range_dt282x_ai_5_bipolar = { 151 4, { 152 BIP_RANGE(5), 153 BIP_RANGE(2.5), 154 BIP_RANGE(1.25), 155 BIP_RANGE(0.625) 156 } 157}; 158 159static const struct comedi_lrange range_dt282x_ai_5_unipolar = { 160 4, { 161 UNI_RANGE(5), 162 UNI_RANGE(2.5), 163 UNI_RANGE(1.25), 164 UNI_RANGE(0.625) 165 } 166}; 167 168static const struct comedi_lrange range_dt282x_ai_hi_bipolar = { 169 4, { 170 BIP_RANGE(10), 171 BIP_RANGE(1), 172 BIP_RANGE(0.1), 173 BIP_RANGE(0.02) 174 } 175}; 176 177static const struct comedi_lrange range_dt282x_ai_hi_unipolar = { 178 4, { 179 UNI_RANGE(10), 180 UNI_RANGE(1), 181 UNI_RANGE(0.1), 182 UNI_RANGE(0.02) 183 } 184}; 185 186struct dt282x_board { 187 const char *name; 188 unsigned int ai_maxdata; 189 int adchan_se; 190 int adchan_di; 191 int ai_speed; 192 int ispgl; 193 int dachan; 194 unsigned int ao_maxdata; 195}; 196 197static const struct dt282x_board boardtypes[] = { 198 { 199 .name = "dt2821", 200 .ai_maxdata = 0x0fff, 201 .adchan_se = 16, 202 .adchan_di = 8, 203 .ai_speed = 20000, 204 .dachan = 2, 205 .ao_maxdata = 0x0fff, 206 }, { 207 .name = "dt2821-f", 208 .ai_maxdata = 0x0fff, 209 .adchan_se = 16, 210 .adchan_di = 8, 211 .ai_speed = 6500, 212 .dachan = 2, 213 .ao_maxdata = 0x0fff, 214 }, { 215 .name = "dt2821-g", 216 .ai_maxdata = 0x0fff, 217 .adchan_se = 16, 218 .adchan_di = 8, 219 .ai_speed = 4000, 220 .dachan = 2, 221 .ao_maxdata = 0x0fff, 222 }, { 223 .name = "dt2823", 224 .ai_maxdata = 0xffff, 225 .adchan_di = 4, 226 .ai_speed = 10000, 227 .dachan = 2, 228 .ao_maxdata = 0xffff, 229 }, { 230 .name = "dt2824-pgh", 231 .ai_maxdata = 0x0fff, 232 .adchan_se = 16, 233 .adchan_di = 8, 234 .ai_speed = 20000, 235 }, { 236 .name = "dt2824-pgl", 237 .ai_maxdata = 0x0fff, 238 .adchan_se = 16, 239 .adchan_di = 8, 240 .ai_speed = 20000, 241 .ispgl = 1, 242 }, { 243 .name = "dt2825", 244 .ai_maxdata = 0x0fff, 245 .adchan_se = 16, 246 .adchan_di = 8, 247 .ai_speed = 20000, 248 .ispgl = 1, 249 .dachan = 2, 250 .ao_maxdata = 0x0fff, 251 }, { 252 .name = "dt2827", 253 .ai_maxdata = 0xffff, 254 .adchan_di = 4, 255 .ai_speed = 10000, 256 .dachan = 2, 257 .ao_maxdata = 0x0fff, 258 }, { 259 .name = "dt2828", 260 .ai_maxdata = 0x0fff, 261 .adchan_se = 4, 262 .ai_speed = 10000, 263 .dachan = 2, 264 .ao_maxdata = 0x0fff, 265 }, { 266 .name = "dt2829", 267 .ai_maxdata = 0xffff, 268 .adchan_se = 8, 269 .ai_speed = 33250, 270 .dachan = 2, 271 .ao_maxdata = 0xffff, 272 }, { 273 .name = "dt21-ez", 274 .ai_maxdata = 0x0fff, 275 .adchan_se = 16, 276 .adchan_di = 8, 277 .ai_speed = 10000, 278 .dachan = 2, 279 .ao_maxdata = 0x0fff, 280 }, { 281 .name = "dt23-ez", 282 .ai_maxdata = 0xffff, 283 .adchan_se = 16, 284 .adchan_di = 8, 285 .ai_speed = 10000, 286 }, { 287 .name = "dt24-ez", 288 .ai_maxdata = 0x0fff, 289 .adchan_se = 16, 290 .adchan_di = 8, 291 .ai_speed = 10000, 292 }, { 293 .name = "dt24-ez-pgl", 294 .ai_maxdata = 0x0fff, 295 .adchan_se = 16, 296 .adchan_di = 8, 297 .ai_speed = 10000, 298 .ispgl = 1, 299 }, 300}; 301 302struct dt282x_private { 303 unsigned int ad_2scomp:1; 304 unsigned int da0_2scomp:1; 305 unsigned int da1_2scomp:1; 306 307 const struct comedi_lrange *darangelist[2]; 308 309 unsigned short ao_readback[2]; 310 311 int dacsr; /* software copies of registers */ 312 int adcsr; 313 int supcsr; 314 315 int ntrig; 316 int nread; 317 318 struct { 319 int chan; 320 unsigned short *buf; /* DMA buffer */ 321 int size; /* size of current transfer */ 322 } dma[2]; 323 int dma_maxsize; /* max size of DMA transfer (in bytes) */ 324 int current_dma_index; 325 int dma_dir; 326}; 327 328static int dt282x_prep_ai_dma(struct comedi_device *dev, int dma_index, int n) 329{ 330 struct dt282x_private *devpriv = dev->private; 331 int dma_chan; 332 unsigned long dma_ptr; 333 unsigned long flags; 334 335 if (!devpriv->ntrig) 336 return 0; 337 338 if (n == 0) 339 n = devpriv->dma_maxsize; 340 if (n > devpriv->ntrig * 2) 341 n = devpriv->ntrig * 2; 342 devpriv->ntrig -= n / 2; 343 344 devpriv->dma[dma_index].size = n; 345 dma_chan = devpriv->dma[dma_index].chan; 346 dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf); 347 348 set_dma_mode(dma_chan, DMA_MODE_READ); 349 flags = claim_dma_lock(); 350 clear_dma_ff(dma_chan); 351 set_dma_addr(dma_chan, dma_ptr); 352 set_dma_count(dma_chan, n); 353 release_dma_lock(flags); 354 355 enable_dma(dma_chan); 356 357 return n; 358} 359 360static int dt282x_prep_ao_dma(struct comedi_device *dev, int dma_index, int n) 361{ 362 struct dt282x_private *devpriv = dev->private; 363 int dma_chan; 364 unsigned long dma_ptr; 365 unsigned long flags; 366 367 devpriv->dma[dma_index].size = n; 368 dma_chan = devpriv->dma[dma_index].chan; 369 dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf); 370 371 set_dma_mode(dma_chan, DMA_MODE_WRITE); 372 flags = claim_dma_lock(); 373 clear_dma_ff(dma_chan); 374 set_dma_addr(dma_chan, dma_ptr); 375 set_dma_count(dma_chan, n); 376 release_dma_lock(flags); 377 378 enable_dma(dma_chan); 379 380 return n; 381} 382 383static void dt282x_disable_dma(struct comedi_device *dev) 384{ 385 struct dt282x_private *devpriv = dev->private; 386 387 disable_dma(devpriv->dma[0].chan); 388 disable_dma(devpriv->dma[1].chan); 389} 390 391static int dt282x_ns_to_timer(int *nanosec, int round_mode) 392{ 393 int prescale, base, divider; 394 395 for (prescale = 0; prescale < 16; prescale++) { 396 if (prescale == 1) 397 continue; 398 base = 250 * (1 << prescale); 399 switch (round_mode) { 400 case TRIG_ROUND_NEAREST: 401 default: 402 divider = (*nanosec + base / 2) / base; 403 break; 404 case TRIG_ROUND_DOWN: 405 divider = (*nanosec) / base; 406 break; 407 case TRIG_ROUND_UP: 408 divider = (*nanosec + base - 1) / base; 409 break; 410 } 411 if (divider < 256) { 412 *nanosec = divider * base; 413 return (prescale << 8) | (255 - divider); 414 } 415 } 416 base = 250 * (1 << 15); 417 divider = 255; 418 *nanosec = divider * base; 419 return (15 << 8) | (255 - divider); 420} 421 422static void dt282x_munge(struct comedi_device *dev, 423 struct comedi_subdevice *s, 424 unsigned short *buf, 425 unsigned int nbytes) 426{ 427 struct dt282x_private *devpriv = dev->private; 428 unsigned int val; 429 int i; 430 431 if (nbytes % 2) 432 comedi_error(dev, "bug! odd number of bytes from dma xfer"); 433 434 for (i = 0; i < nbytes / 2; i++) { 435 val = buf[i]; 436 val &= s->maxdata; 437 if (devpriv->ad_2scomp) 438 val = comedi_offset_munge(s, val); 439 440 buf[i] = val; 441 } 442} 443 444static void dt282x_ao_dma_interrupt(struct comedi_device *dev, 445 struct comedi_subdevice *s) 446{ 447 struct dt282x_private *devpriv = dev->private; 448 int cur_dma = devpriv->current_dma_index; 449 void *ptr = devpriv->dma[cur_dma].buf; 450 int size; 451 452 outw(devpriv->supcsr | DT2821_CLRDMADNE, dev->iobase + DT2821_SUPCSR); 453 454 disable_dma(devpriv->dma[cur_dma].chan); 455 456 devpriv->current_dma_index = 1 - cur_dma; 457 458 size = cfc_read_array_from_buffer(s, ptr, devpriv->dma_maxsize); 459 if (size == 0) { 460 dev_err(dev->class_dev, "AO underrun\n"); 461 s->async->events |= COMEDI_CB_OVERFLOW; 462 } else { 463 dt282x_prep_ao_dma(dev, cur_dma, size); 464 } 465} 466 467static void dt282x_ai_dma_interrupt(struct comedi_device *dev, 468 struct comedi_subdevice *s) 469{ 470 struct dt282x_private *devpriv = dev->private; 471 int cur_dma = devpriv->current_dma_index; 472 void *ptr = devpriv->dma[cur_dma].buf; 473 int size = devpriv->dma[cur_dma].size; 474 int ret; 475 476 outw(devpriv->supcsr | DT2821_CLRDMADNE, dev->iobase + DT2821_SUPCSR); 477 478 disable_dma(devpriv->dma[cur_dma].chan); 479 480 devpriv->current_dma_index = 1 - cur_dma; 481 482 dt282x_munge(dev, s, ptr, size); 483 ret = cfc_write_array_to_buffer(s, ptr, size); 484 if (ret != size) { 485 s->async->events |= COMEDI_CB_OVERFLOW; 486 return; 487 } 488 489 devpriv->nread -= size / 2; 490 if (devpriv->nread < 0) { 491 dev_info(dev->class_dev, "nread off by one\n"); 492 devpriv->nread = 0; 493 } 494 if (!devpriv->nread) { 495 s->async->events |= COMEDI_CB_EOA; 496 return; 497 } 498#if 0 499 /* clear the dual dma flag, making this the last dma segment */ 500 /* XXX probably wrong */ 501 if (!devpriv->ntrig) { 502 devpriv->supcsr &= ~(DT2821_DDMA); 503 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR); 504 } 505#endif 506 /* restart the channel */ 507 dt282x_prep_ai_dma(dev, cur_dma, 0); 508} 509 510static irqreturn_t dt282x_interrupt(int irq, void *d) 511{ 512 struct comedi_device *dev = d; 513 struct dt282x_private *devpriv = dev->private; 514 struct comedi_subdevice *s = dev->read_subdev; 515 struct comedi_subdevice *s_ao = dev->write_subdev; 516 unsigned int supcsr, adcsr, dacsr; 517 int handled = 0; 518 519 if (!dev->attached) { 520 comedi_error(dev, "spurious interrupt"); 521 return IRQ_HANDLED; 522 } 523 524 adcsr = inw(dev->iobase + DT2821_ADCSR); 525 dacsr = inw(dev->iobase + DT2821_DACSR); 526 supcsr = inw(dev->iobase + DT2821_SUPCSR); 527 if (supcsr & DT2821_DMAD) { 528 if (devpriv->dma_dir == DMA_MODE_READ) 529 dt282x_ai_dma_interrupt(dev, s); 530 else 531 dt282x_ao_dma_interrupt(dev, s_ao); 532 handled = 1; 533 } 534 if (adcsr & DT2821_ADERR) { 535 if (devpriv->nread != 0) { 536 comedi_error(dev, "A/D error"); 537 s->async->events |= COMEDI_CB_ERROR; 538 } 539 handled = 1; 540 } 541 if (dacsr & DT2821_DAERR) { 542 comedi_error(dev, "D/A error"); 543 s_ao->async->events |= COMEDI_CB_ERROR; 544 handled = 1; 545 } 546#if 0 547 if (adcsr & DT2821_ADDONE) { 548 int ret; 549 unsigned short data; 550 551 data = inw(dev->iobase + DT2821_ADDAT); 552 data &= s->maxdata; 553 if (devpriv->ad_2scomp) 554 data = comedi_offset_munge(s, data); 555 556 ret = comedi_buf_put(s, data); 557 558 if (ret == 0) 559 s->async->events |= COMEDI_CB_OVERFLOW; 560 561 devpriv->nread--; 562 if (!devpriv->nread) { 563 s->async->events |= COMEDI_CB_EOA; 564 } else { 565 if (supcsr & DT2821_SCDN) 566 outw(devpriv->supcsr | DT2821_STRIG, 567 dev->iobase + DT2821_SUPCSR); 568 } 569 handled = 1; 570 } 571#endif 572 cfc_handle_events(dev, s); 573 cfc_handle_events(dev, s_ao); 574 575 return IRQ_RETVAL(handled); 576} 577 578static void dt282x_load_changain(struct comedi_device *dev, int n, 579 unsigned int *chanlist) 580{ 581 struct dt282x_private *devpriv = dev->private; 582 unsigned int i; 583 unsigned int chan, range; 584 585 outw(DT2821_LLE | (n - 1), dev->iobase + DT2821_CHANCSR); 586 for (i = 0; i < n; i++) { 587 chan = CR_CHAN(chanlist[i]); 588 range = CR_RANGE(chanlist[i]); 589 outw(devpriv->adcsr | (range << 4) | chan, 590 dev->iobase + DT2821_ADCSR); 591 } 592 outw(n - 1, dev->iobase + DT2821_CHANCSR); 593} 594 595static int dt282x_ai_timeout(struct comedi_device *dev, 596 struct comedi_subdevice *s, 597 struct comedi_insn *insn, 598 unsigned long context) 599{ 600 unsigned int status; 601 602 status = inw(dev->iobase + DT2821_ADCSR); 603 switch (context) { 604 case DT2821_MUXBUSY: 605 if ((status & DT2821_MUXBUSY) == 0) 606 return 0; 607 break; 608 case DT2821_ADDONE: 609 if (status & DT2821_ADDONE) 610 return 0; 611 break; 612 default: 613 return -EINVAL; 614 } 615 return -EBUSY; 616} 617 618/* 619 * Performs a single A/D conversion. 620 * - Put channel/gain into channel-gain list 621 * - preload multiplexer 622 * - trigger conversion and wait for it to finish 623 */ 624static int dt282x_ai_insn_read(struct comedi_device *dev, 625 struct comedi_subdevice *s, 626 struct comedi_insn *insn, 627 unsigned int *data) 628{ 629 struct dt282x_private *devpriv = dev->private; 630 unsigned int val; 631 int ret; 632 int i; 633 634 /* XXX should we really be enabling the ad clock here? */ 635 devpriv->adcsr = DT2821_ADCLK; 636 outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR); 637 638 dt282x_load_changain(dev, 1, &insn->chanspec); 639 640 outw(devpriv->supcsr | DT2821_PRLD, dev->iobase + DT2821_SUPCSR); 641 ret = comedi_timeout(dev, s, insn, dt282x_ai_timeout, DT2821_MUXBUSY); 642 if (ret) 643 return ret; 644 645 for (i = 0; i < insn->n; i++) { 646 outw(devpriv->supcsr | DT2821_STRIG, 647 dev->iobase + DT2821_SUPCSR); 648 649 ret = comedi_timeout(dev, s, insn, dt282x_ai_timeout, 650 DT2821_ADDONE); 651 if (ret) 652 return ret; 653 654 val = inw(dev->iobase + DT2821_ADDAT); 655 val &= s->maxdata; 656 if (devpriv->ad_2scomp) 657 val = comedi_offset_munge(s, val); 658 659 data[i] = val; 660 } 661 662 return i; 663} 664 665static int dt282x_ai_cmdtest(struct comedi_device *dev, 666 struct comedi_subdevice *s, struct comedi_cmd *cmd) 667{ 668 const struct dt282x_board *board = comedi_board(dev); 669 int err = 0; 670 unsigned int arg; 671 672 /* Step 1 : check if triggers are trivially valid */ 673 674 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); 675 err |= cfc_check_trigger_src(&cmd->scan_begin_src, 676 TRIG_FOLLOW | TRIG_EXT); 677 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER); 678 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); 679 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); 680 681 if (err) 682 return 1; 683 684 /* Step 2a : make sure trigger sources are unique */ 685 686 err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); 687 err |= cfc_check_trigger_is_unique(cmd->stop_src); 688 689 /* Step 2b : and mutually compatible */ 690 691 if (err) 692 return 2; 693 694 /* Step 3: check if arguments are trivially valid */ 695 696 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); 697 698 if (cmd->scan_begin_src == TRIG_FOLLOW) { 699 /* internal trigger */ 700 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); 701 } else { 702 /* external trigger */ 703 /* should be level/edge, hi/lo specification here */ 704 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); 705 } 706 707 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 4000); 708 709#define SLOWEST_TIMER (250*(1<<15)*255) 710 err |= cfc_check_trigger_arg_max(&cmd->convert_arg, SLOWEST_TIMER); 711 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, board->ai_speed); 712 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); 713 714 if (cmd->stop_src == TRIG_COUNT) { 715 /* any count is allowed */ 716 } else { /* TRIG_NONE */ 717 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); 718 } 719 720 if (err) 721 return 3; 722 723 /* step 4: fix up any arguments */ 724 725 arg = cmd->convert_arg; 726 dt282x_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK); 727 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); 728 729 if (err) 730 return 4; 731 732 return 0; 733} 734 735static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) 736{ 737 const struct dt282x_board *board = comedi_board(dev); 738 struct dt282x_private *devpriv = dev->private; 739 struct comedi_cmd *cmd = &s->async->cmd; 740 int timer; 741 int ret; 742 743 dt282x_disable_dma(dev); 744 745 if (cmd->convert_arg < board->ai_speed) 746 cmd->convert_arg = board->ai_speed; 747 timer = dt282x_ns_to_timer(&cmd->convert_arg, TRIG_ROUND_NEAREST); 748 outw(timer, dev->iobase + DT2821_TMRCTR); 749 750 if (cmd->scan_begin_src == TRIG_FOLLOW) { 751 /* internal trigger */ 752 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0; 753 } else { 754 /* external trigger */ 755 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0 | DT2821_DS1; 756 } 757 outw(devpriv->supcsr | DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_ADCINIT, 758 dev->iobase + DT2821_SUPCSR); 759 760 devpriv->ntrig = cmd->stop_arg * cmd->scan_end_arg; 761 devpriv->nread = devpriv->ntrig; 762 763 devpriv->dma_dir = DMA_MODE_READ; 764 devpriv->current_dma_index = 0; 765 dt282x_prep_ai_dma(dev, 0, 0); 766 if (devpriv->ntrig) { 767 dt282x_prep_ai_dma(dev, 1, 0); 768 devpriv->supcsr |= DT2821_DDMA; 769 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR); 770 } 771 772 devpriv->adcsr = 0; 773 774 dt282x_load_changain(dev, cmd->chanlist_len, cmd->chanlist); 775 776 devpriv->adcsr = DT2821_ADCLK | DT2821_IADDONE; 777 outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR); 778 779 outw(devpriv->supcsr | DT2821_PRLD, dev->iobase + DT2821_SUPCSR); 780 ret = comedi_timeout(dev, s, NULL, dt282x_ai_timeout, DT2821_MUXBUSY); 781 if (ret) 782 return ret; 783 784 if (cmd->scan_begin_src == TRIG_FOLLOW) { 785 outw(devpriv->supcsr | DT2821_STRIG, 786 dev->iobase + DT2821_SUPCSR); 787 } else { 788 devpriv->supcsr |= DT2821_XTRIG; 789 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR); 790 } 791 792 return 0; 793} 794 795static int dt282x_ai_cancel(struct comedi_device *dev, 796 struct comedi_subdevice *s) 797{ 798 struct dt282x_private *devpriv = dev->private; 799 800 dt282x_disable_dma(dev); 801 802 devpriv->adcsr = 0; 803 outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR); 804 805 devpriv->supcsr = 0; 806 outw(devpriv->supcsr | DT2821_ADCINIT, dev->iobase + DT2821_SUPCSR); 807 808 return 0; 809} 810 811static int dt282x_ao_insn_read(struct comedi_device *dev, 812 struct comedi_subdevice *s, 813 struct comedi_insn *insn, 814 unsigned int *data) 815{ 816 struct dt282x_private *devpriv = dev->private; 817 unsigned int chan = CR_CHAN(insn->chanspec); 818 int i; 819 820 for (i = 0; i < insn->n; i++) 821 data[i] = devpriv->ao_readback[chan]; 822 823 return insn->n; 824} 825 826static int dt282x_ao_insn_write(struct comedi_device *dev, 827 struct comedi_subdevice *s, 828 struct comedi_insn *insn, 829 unsigned int *data) 830{ 831 struct dt282x_private *devpriv = dev->private; 832 unsigned int chan = CR_CHAN(insn->chanspec); 833 bool munge = false; 834 unsigned int val; 835 int i; 836 837 devpriv->dacsr |= DT2821_SSEL; 838 if (chan) { 839 devpriv->dacsr |= DT2821_YSEL; 840 if (devpriv->da1_2scomp) 841 munge = true; 842 } else { 843 devpriv->dacsr &= ~DT2821_YSEL; 844 if (devpriv->da0_2scomp) 845 munge = true; 846 } 847 848 for (i = 0; i < insn->n; i++) { 849 val = data[i]; 850 devpriv->ao_readback[chan] = val; 851 852 if (munge) 853 val = comedi_offset_munge(s, val); 854 855 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR); 856 857 outw(val, dev->iobase + DT2821_DADAT); 858 859 outw(devpriv->supcsr | DT2821_DACON, 860 dev->iobase + DT2821_SUPCSR); 861 } 862 863 return insn->n; 864} 865 866static int dt282x_ao_cmdtest(struct comedi_device *dev, 867 struct comedi_subdevice *s, struct comedi_cmd *cmd) 868{ 869 int err = 0; 870 unsigned int arg; 871 872 /* Step 1 : check if triggers are trivially valid */ 873 874 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT); 875 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER); 876 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); 877 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); 878 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); 879 880 if (err) 881 return 1; 882 883 /* Step 2a : make sure trigger sources are unique */ 884 885 err |= cfc_check_trigger_is_unique(cmd->stop_src); 886 887 /* Step 2b : and mutually compatible */ 888 889 if (err) 890 return 2; 891 892 /* Step 3: check if arguments are trivially valid */ 893 894 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); 895 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 5000); 896 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); 897 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); 898 899 if (cmd->stop_src == TRIG_COUNT) { 900 /* any count is allowed */ 901 } else { /* TRIG_NONE */ 902 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); 903 } 904 905 if (err) 906 return 3; 907 908 /* step 4: fix up any arguments */ 909 910 arg = cmd->scan_begin_arg; 911 dt282x_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK); 912 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); 913 914 if (err) 915 return 4; 916 917 return 0; 918 919} 920 921static int dt282x_ao_inttrig(struct comedi_device *dev, 922 struct comedi_subdevice *s, 923 unsigned int trig_num) 924{ 925 struct dt282x_private *devpriv = dev->private; 926 struct comedi_cmd *cmd = &s->async->cmd; 927 int size; 928 929 if (trig_num != cmd->start_src) 930 return -EINVAL; 931 932 size = cfc_read_array_from_buffer(s, devpriv->dma[0].buf, 933 devpriv->dma_maxsize); 934 if (size == 0) { 935 dev_err(dev->class_dev, "AO underrun\n"); 936 return -EPIPE; 937 } 938 dt282x_prep_ao_dma(dev, 0, size); 939 940 size = cfc_read_array_from_buffer(s, devpriv->dma[1].buf, 941 devpriv->dma_maxsize); 942 if (size == 0) { 943 dev_err(dev->class_dev, "AO underrun\n"); 944 return -EPIPE; 945 } 946 dt282x_prep_ao_dma(dev, 1, size); 947 948 outw(devpriv->supcsr | DT2821_STRIG, dev->iobase + DT2821_SUPCSR); 949 s->async->inttrig = NULL; 950 951 return 1; 952} 953 954static int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) 955{ 956 struct dt282x_private *devpriv = dev->private; 957 int timer; 958 struct comedi_cmd *cmd = &s->async->cmd; 959 960 dt282x_disable_dma(dev); 961 962 devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS1 | DT2821_DDMA; 963 outw(devpriv->supcsr | DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_DACINIT, 964 dev->iobase + DT2821_SUPCSR); 965 966 devpriv->ntrig = cmd->stop_arg * cmd->chanlist_len; 967 devpriv->nread = devpriv->ntrig; 968 969 devpriv->dma_dir = DMA_MODE_WRITE; 970 devpriv->current_dma_index = 0; 971 972 timer = dt282x_ns_to_timer(&cmd->scan_begin_arg, TRIG_ROUND_NEAREST); 973 outw(timer, dev->iobase + DT2821_TMRCTR); 974 975 devpriv->dacsr = DT2821_SSEL | DT2821_DACLK | DT2821_IDARDY; 976 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR); 977 978 s->async->inttrig = dt282x_ao_inttrig; 979 980 return 0; 981} 982 983static int dt282x_ao_cancel(struct comedi_device *dev, 984 struct comedi_subdevice *s) 985{ 986 struct dt282x_private *devpriv = dev->private; 987 988 dt282x_disable_dma(dev); 989 990 devpriv->dacsr = 0; 991 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR); 992 993 devpriv->supcsr = 0; 994 outw(devpriv->supcsr | DT2821_DACINIT, dev->iobase + DT2821_SUPCSR); 995 996 return 0; 997} 998 999static int dt282x_dio_insn_bits(struct comedi_device *dev, 1000 struct comedi_subdevice *s, 1001 struct comedi_insn *insn, 1002 unsigned int *data) 1003{ 1004 if (comedi_dio_update_state(s, data)) 1005 outw(s->state, dev->iobase + DT2821_DIODAT); 1006 1007 data[1] = inw(dev->iobase + DT2821_DIODAT); 1008 1009 return insn->n; 1010} 1011 1012static int dt282x_dio_insn_config(struct comedi_device *dev, 1013 struct comedi_subdevice *s, 1014 struct comedi_insn *insn, 1015 unsigned int *data) 1016{ 1017 struct dt282x_private *devpriv = dev->private; 1018 unsigned int chan = CR_CHAN(insn->chanspec); 1019 unsigned int mask; 1020 int ret; 1021 1022 if (chan < 8) 1023 mask = 0x00ff; 1024 else 1025 mask = 0xff00; 1026 1027 ret = comedi_dio_insn_config(dev, s, insn, data, mask); 1028 if (ret) 1029 return ret; 1030 1031 devpriv->dacsr &= ~(DT2821_LBOE | DT2821_HBOE); 1032 if (s->io_bits & 0x00ff) 1033 devpriv->dacsr |= DT2821_LBOE; 1034 if (s->io_bits & 0xff00) 1035 devpriv->dacsr |= DT2821_HBOE; 1036 1037 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR); 1038 1039 return insn->n; 1040} 1041 1042static const struct comedi_lrange *const ai_range_table[] = { 1043 &range_dt282x_ai_lo_bipolar, 1044 &range_dt282x_ai_lo_unipolar, 1045 &range_dt282x_ai_5_bipolar, 1046 &range_dt282x_ai_5_unipolar 1047}; 1048 1049static const struct comedi_lrange *const ai_range_pgl_table[] = { 1050 &range_dt282x_ai_hi_bipolar, 1051 &range_dt282x_ai_hi_unipolar 1052}; 1053 1054static const struct comedi_lrange *opt_ai_range_lkup(int ispgl, int x) 1055{ 1056 if (ispgl) { 1057 if (x < 0 || x >= 2) 1058 x = 0; 1059 return ai_range_pgl_table[x]; 1060 } else { 1061 if (x < 0 || x >= 4) 1062 x = 0; 1063 return ai_range_table[x]; 1064 } 1065} 1066 1067static const struct comedi_lrange *const ao_range_table[] = { 1068 &range_bipolar10, 1069 &range_unipolar10, 1070 &range_bipolar5, 1071 &range_unipolar5, 1072 &range_bipolar2_5 1073}; 1074 1075static const struct comedi_lrange *opt_ao_range_lkup(int x) 1076{ 1077 if (x < 0 || x >= 5) 1078 x = 0; 1079 return ao_range_table[x]; 1080} 1081 1082static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2) 1083{ 1084 struct dt282x_private *devpriv = dev->private; 1085 int ret; 1086 1087 ret = request_dma(dma1, "dt282x A"); 1088 if (ret) 1089 return -EBUSY; 1090 devpriv->dma[0].chan = dma1; 1091 1092 ret = request_dma(dma2, "dt282x B"); 1093 if (ret) 1094 return -EBUSY; 1095 devpriv->dma[1].chan = dma2; 1096 1097 devpriv->dma_maxsize = PAGE_SIZE; 1098 devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA); 1099 devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA); 1100 if (!devpriv->dma[0].buf || !devpriv->dma[1].buf) 1101 return -ENOMEM; 1102 1103 return 0; 1104} 1105 1106static void dt282x_free_dma(struct comedi_device *dev) 1107{ 1108 struct dt282x_private *devpriv = dev->private; 1109 int i; 1110 1111 if (!devpriv) 1112 return; 1113 1114 for (i = 0; i < 2; i++) { 1115 if (devpriv->dma[i].chan) 1116 free_dma(devpriv->dma[i].chan); 1117 if (devpriv->dma[i].buf) 1118 free_page((unsigned long)devpriv->dma[i].buf); 1119 devpriv->dma[i].chan = 0; 1120 devpriv->dma[i].buf = NULL; 1121 } 1122} 1123 1124static int dt282x_initialize(struct comedi_device *dev) 1125{ 1126 /* Initialize board */ 1127 outw(DT2821_BDINIT, dev->iobase + DT2821_SUPCSR); 1128 inw(dev->iobase + DT2821_ADCSR); 1129 1130 /* 1131 * At power up, some registers are in a well-known state. 1132 * Check them to see if a DT2821 series board is present. 1133 */ 1134 if (((inw(dev->iobase + DT2821_ADCSR) & 0xfff0) != 0x7c00) || 1135 ((inw(dev->iobase + DT2821_CHANCSR) & 0xf0f0) != 0x70f0) || 1136 ((inw(dev->iobase + DT2821_DACSR) & 0x7c93) != 0x7c90) || 1137 ((inw(dev->iobase + DT2821_SUPCSR) & 0xf8ff) != 0x0000) || 1138 ((inw(dev->iobase + DT2821_TMRCTR) & 0xff00) != 0xf000)) { 1139 dev_err(dev->class_dev, "board not found\n"); 1140 return -EIO; 1141 } 1142 return 0; 1143} 1144 1145/* 1146 options: 1147 0 i/o base 1148 1 irq 1149 2 dma1 1150 3 dma2 1151 4 0=single ended, 1=differential 1152 5 ai 0=straight binary, 1=2's comp 1153 6 ao0 0=straight binary, 1=2's comp 1154 7 ao1 0=straight binary, 1=2's comp 1155 8 ai 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V 1156 9 ao0 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V 1157 10 ao1 0=±10 V, 1=0-10 V, 2=±5 V, 3=0-5 V, 4=±2.5 V 1158 */ 1159static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it) 1160{ 1161 const struct dt282x_board *board = comedi_board(dev); 1162 struct dt282x_private *devpriv; 1163 struct comedi_subdevice *s; 1164 int ret; 1165 1166 ret = comedi_request_region(dev, it->options[0], 0x10); 1167 if (ret) 1168 return ret; 1169 1170 ret = dt282x_initialize(dev); 1171 if (ret) 1172 return ret; 1173 1174 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); 1175 if (!devpriv) 1176 return -ENOMEM; 1177 1178 /* an IRQ and 2 DMA channels are required for async command support */ 1179 if (it->options[1] && it->options[2] && it->options[3]) { 1180 unsigned int irq = it->options[1]; 1181 unsigned int dma1 = it->options[2]; 1182 unsigned int dma2 = it->options[3]; 1183 1184 if (dma2 < dma1) { 1185 unsigned int swap; 1186 1187 swap = dma1; 1188 dma1 = dma2; 1189 dma2 = swap; 1190 } 1191 1192 if (dma1 != dma2 && 1193 dma1 >= 5 && dma1 <= 7 && 1194 dma2 >= 5 && dma2 <= 7) { 1195 ret = request_irq(irq, dt282x_interrupt, 0, 1196 dev->board_name, dev); 1197 if (ret == 0) { 1198 dev->irq = irq; 1199 1200 ret = dt282x_grab_dma(dev, dma1, dma2); 1201 if (ret < 0) { 1202 dt282x_free_dma(dev); 1203 free_irq(dev->irq, dev); 1204 dev->irq = 0; 1205 } 1206 } 1207 } 1208 } 1209 1210 ret = comedi_alloc_subdevices(dev, 3); 1211 if (ret) 1212 return ret; 1213 1214 s = &dev->subdevices[0]; 1215 1216 /* ai subdevice */ 1217 s->type = COMEDI_SUBD_AI; 1218 s->subdev_flags = SDF_READABLE; 1219 if (it->options[4]) { 1220 s->subdev_flags |= SDF_DIFF; 1221 s->n_chan = board->adchan_di; 1222 } else { 1223 s->subdev_flags |= SDF_COMMON; 1224 s->n_chan = board->adchan_se; 1225 } 1226 s->insn_read = dt282x_ai_insn_read; 1227 s->maxdata = board->ai_maxdata; 1228 s->range_table = opt_ai_range_lkup(board->ispgl, it->options[8]); 1229 devpriv->ad_2scomp = it->options[5] ? 1 : 0; 1230 if (dev->irq) { 1231 dev->read_subdev = s; 1232 s->subdev_flags |= SDF_CMD_READ; 1233 s->len_chanlist = 16; 1234 s->do_cmdtest = dt282x_ai_cmdtest; 1235 s->do_cmd = dt282x_ai_cmd; 1236 s->cancel = dt282x_ai_cancel; 1237 } 1238 1239 s = &dev->subdevices[1]; 1240 1241 s->n_chan = board->dachan; 1242 if (s->n_chan) { 1243 /* ao subsystem */ 1244 s->type = COMEDI_SUBD_AO; 1245 s->subdev_flags = SDF_WRITABLE; 1246 s->insn_read = dt282x_ao_insn_read; 1247 s->insn_write = dt282x_ao_insn_write; 1248 s->maxdata = board->ao_maxdata; 1249 s->range_table_list = devpriv->darangelist; 1250 devpriv->darangelist[0] = opt_ao_range_lkup(it->options[9]); 1251 devpriv->darangelist[1] = opt_ao_range_lkup(it->options[10]); 1252 devpriv->da0_2scomp = it->options[6] ? 1 : 0; 1253 devpriv->da1_2scomp = it->options[7] ? 1 : 0; 1254 if (dev->irq) { 1255 dev->write_subdev = s; 1256 s->subdev_flags |= SDF_CMD_WRITE; 1257 s->len_chanlist = 2; 1258 s->do_cmdtest = dt282x_ao_cmdtest; 1259 s->do_cmd = dt282x_ao_cmd; 1260 s->cancel = dt282x_ao_cancel; 1261 } 1262 } else { 1263 s->type = COMEDI_SUBD_UNUSED; 1264 } 1265 1266 /* Digital I/O subdevice */ 1267 s = &dev->subdevices[2]; 1268 s->type = COMEDI_SUBD_DIO; 1269 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 1270 s->n_chan = 16; 1271 s->maxdata = 1; 1272 s->range_table = &range_digital; 1273 s->insn_bits = dt282x_dio_insn_bits; 1274 s->insn_config = dt282x_dio_insn_config; 1275 1276 return 0; 1277} 1278 1279static void dt282x_detach(struct comedi_device *dev) 1280{ 1281 dt282x_free_dma(dev); 1282 comedi_legacy_detach(dev); 1283} 1284 1285static struct comedi_driver dt282x_driver = { 1286 .driver_name = "dt282x", 1287 .module = THIS_MODULE, 1288 .attach = dt282x_attach, 1289 .detach = dt282x_detach, 1290 .board_name = &boardtypes[0].name, 1291 .num_names = ARRAY_SIZE(boardtypes), 1292 .offset = sizeof(struct dt282x_board), 1293}; 1294module_comedi_driver(dt282x_driver); 1295 1296MODULE_AUTHOR("Comedi http://www.comedi.org"); 1297MODULE_DESCRIPTION("Comedi low-level driver"); 1298MODULE_LICENSE("GPL"); 1299