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