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