Lines Matching +full:acquisition +full:- +full:time +full:- +full:ns

1 // SPDX-License-Identifier: GPL-2.0
8 * COMEDI - Linux Control and Measurement Device Interface
13 * ftp://ftp.quatech.com/Manuals/daqp-208.pdf
15 * This manual is for both the DAQP-208 and the DAQP-308.
18 * - A/D conversion
19 * - 8 channels
20 * - 4 gain ranges
21 * - ground ref or differential
22 * - single-shot and timed both supported
23 * - D/A conversion, single-shot
24 * - digital I/O
27 * - any kind of triggering - external or D/A channel 1
28 * - the card's optional expansion board
29 * - the card's timer (for anything other than A/D conversion)
30 * - D/A update modes other than immediate (i.e, timed)
31 * - fancier timing modes
32 * - setting card's FIFO buffer thresholds to anything but default
38 * Devices: [Quatech] DAQP-208 (daqp), DAQP-308
49 * The D/A and timer registers can be accessed with 16-bit or 8-bit I/O
50 * instructions. All other registers can only use 8-bit instructions.
52 * The FIFO and scanlist registers require two 8-bit instructions to
53 * access the 16-bit data. Data is transferred LSB then MSB.
74 #define DAQP_CTRL_TRIG_MODE BIT(2) /* 0=one-shot; 1=continuous */
100 /* the monostable bits are self-clearing after the function is complete */
112 #define DAQP_AO_REG 0x08 /* and 0x09 (16-bit) */
114 #define DAQP_TIMER_REG 0x0a /* and 0x0b (16-bit) */
168 while (--loops) { in daqp_clear_events()
169 status = inb(dev->iobase + DAQP_STATUS_REG); in daqp_clear_events()
173 dev_err(dev->class_dev, "couldn't clear events in status register\n"); in daqp_clear_events()
174 return -EBUSY; in daqp_clear_events()
180 struct daqp_private *devpriv = dev->private; in daqp_ai_cancel()
182 if (devpriv->stop) in daqp_ai_cancel()
183 return -EIO; in daqp_ai_cancel()
189 outb(DAQP_CMD_STOP, dev->iobase + DAQP_CMD_REG); in daqp_ai_cancel()
190 outb(0, dev->iobase + DAQP_CTRL_REG); in daqp_ai_cancel()
191 inb(dev->iobase + DAQP_STATUS_REG); in daqp_ai_cancel()
205 val = inb(dev->iobase + DAQP_AI_FIFO_REG); in daqp_ai_get_sample()
206 val |= inb(dev->iobase + DAQP_AI_FIFO_REG) << 8; in daqp_ai_get_sample()
213 struct comedi_subdevice *s = dev->read_subdev; in daqp_interrupt()
214 struct comedi_cmd *cmd = &s->async->cmd; in daqp_interrupt()
218 if (!dev->attached) in daqp_interrupt()
221 status = inb(dev->iobase + DAQP_STATUS_REG); in daqp_interrupt()
229 s->async->events |= COMEDI_CB_OVERFLOW; in daqp_interrupt()
230 dev_warn(dev->class_dev, "data lost\n"); in daqp_interrupt()
237 if (cmd->stop_src == TRIG_COUNT && in daqp_interrupt()
238 s->async->scans_done >= cmd->stop_arg) { in daqp_interrupt()
239 s->async->events |= COMEDI_CB_EOA; in daqp_interrupt()
243 if ((loop_limit--) <= 0) in daqp_interrupt()
246 status = inb(dev->iobase + DAQP_STATUS_REG); in daqp_interrupt()
250 dev_warn(dev->class_dev, in daqp_interrupt()
252 s->async->events |= COMEDI_CB_ERROR; in daqp_interrupt()
277 outb(val & 0xff, dev->iobase + DAQP_SCANLIST_REG); in daqp_ai_set_one_scanlist_entry()
278 outb((val >> 8) & 0xff, dev->iobase + DAQP_SCANLIST_REG); in daqp_ai_set_one_scanlist_entry()
288 status = inb(dev->iobase + DAQP_AUX_REG); in daqp_ai_eos()
291 return -EBUSY; in daqp_ai_eos()
299 struct daqp_private *devpriv = dev->private; in daqp_ai_insn_read()
303 if (devpriv->stop) in daqp_ai_insn_read()
304 return -EIO; in daqp_ai_insn_read()
306 outb(0, dev->iobase + DAQP_AUX_REG); in daqp_ai_insn_read()
309 outb(DAQP_CMD_RSTQ, dev->iobase + DAQP_CMD_REG); in daqp_ai_insn_read()
312 daqp_ai_set_one_scanlist_entry(dev, insn->chanspec, 1); in daqp_ai_insn_read()
315 outb(DAQP_CMD_RSTF, dev->iobase + DAQP_CMD_REG); in daqp_ai_insn_read()
317 /* Set trigger - one-shot, internal, no interrupts */ in daqp_ai_insn_read()
318 outb(DAQP_CTRL_PACER_CLK_100KHZ, dev->iobase + DAQP_CTRL_REG); in daqp_ai_insn_read()
324 for (i = 0; i < insn->n; i++) { in daqp_ai_insn_read()
327 dev->iobase + DAQP_CMD_REG); in daqp_ai_insn_read()
334 inb(dev->iobase + DAQP_STATUS_REG); in daqp_ai_insn_read()
340 outb(DAQP_CMD_STOP, dev->iobase + DAQP_CMD_REG); in daqp_ai_insn_read()
341 inb(dev->iobase + DAQP_STATUS_REG); in daqp_ai_insn_read()
343 return ret ? ret : insn->n; in daqp_ai_insn_read()
346 /* This function converts ns nanoseconds to a counter value suitable
348 * which with its 24-bit counter, allows values up to 84 seconds.
349 * Also, the function adjusts ns so that it cooresponds to the actual
350 * time that the device will use.
353 static int daqp_ns_to_timer(unsigned int *ns, unsigned int flags) in daqp_ns_to_timer() argument
357 timer = *ns / 200; in daqp_ns_to_timer()
358 *ns = timer * 200; in daqp_ns_to_timer()
365 outb(val & 0xff, dev->iobase + DAQP_PACER_LOW_REG); in daqp_set_pacer()
366 outb((val >> 8) & 0xff, dev->iobase + DAQP_PACER_MID_REG); in daqp_set_pacer()
367 outb((val >> 16) & 0xff, dev->iobase + DAQP_PACER_HIGH_REG); in daqp_set_pacer()
374 struct daqp_private *devpriv = dev->private; in daqp_ai_cmdtest()
380 err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW); in daqp_ai_cmdtest()
381 err |= comedi_check_trigger_src(&cmd->scan_begin_src, in daqp_ai_cmdtest()
383 err |= comedi_check_trigger_src(&cmd->convert_src, in daqp_ai_cmdtest()
385 err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); in daqp_ai_cmdtest()
386 err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); in daqp_ai_cmdtest()
393 err |= comedi_check_trigger_is_unique(cmd->scan_begin_src); in daqp_ai_cmdtest()
394 err |= comedi_check_trigger_is_unique(cmd->convert_src); in daqp_ai_cmdtest()
395 err |= comedi_check_trigger_is_unique(cmd->stop_src); in daqp_ai_cmdtest()
400 if (cmd->scan_begin_src != TRIG_TIMER && cmd->convert_src != TRIG_TIMER) in daqp_ai_cmdtest()
401 err |= -EINVAL; in daqp_ai_cmdtest()
408 err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0); in daqp_ai_cmdtest()
410 err |= comedi_check_trigger_arg_min(&cmd->chanlist_len, 1); in daqp_ai_cmdtest()
411 err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg, in daqp_ai_cmdtest()
412 cmd->chanlist_len); in daqp_ai_cmdtest()
414 if (cmd->scan_begin_src == TRIG_TIMER) in daqp_ai_cmdtest()
415 err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg, in daqp_ai_cmdtest()
418 if (cmd->convert_src == TRIG_TIMER) { in daqp_ai_cmdtest()
419 err |= comedi_check_trigger_arg_min(&cmd->convert_arg, in daqp_ai_cmdtest()
422 if (cmd->scan_begin_src == TRIG_TIMER) { in daqp_ai_cmdtest()
426 * the scan time is the number of conversions times in daqp_ai_cmdtest()
427 * the convert time. in daqp_ai_cmdtest()
429 arg = cmd->convert_arg * cmd->scan_end_arg; in daqp_ai_cmdtest()
430 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, in daqp_ai_cmdtest()
435 if (cmd->stop_src == TRIG_COUNT) in daqp_ai_cmdtest()
436 err |= comedi_check_trigger_arg_max(&cmd->stop_arg, 0x00ffffff); in daqp_ai_cmdtest()
438 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0); in daqp_ai_cmdtest()
445 if (cmd->convert_src == TRIG_TIMER) { in daqp_ai_cmdtest()
446 arg = cmd->convert_arg; in daqp_ai_cmdtest()
447 devpriv->pacer_div = daqp_ns_to_timer(&arg, cmd->flags); in daqp_ai_cmdtest()
448 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg); in daqp_ai_cmdtest()
449 } else if (cmd->scan_begin_src == TRIG_TIMER) { in daqp_ai_cmdtest()
450 arg = cmd->scan_begin_arg; in daqp_ai_cmdtest()
451 devpriv->pacer_div = daqp_ns_to_timer(&arg, cmd->flags); in daqp_ai_cmdtest()
452 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg); in daqp_ai_cmdtest()
463 struct daqp_private *devpriv = dev->private; in daqp_ai_cmd()
464 struct comedi_cmd *cmd = &s->async->cmd; in daqp_ai_cmd()
470 if (devpriv->stop) in daqp_ai_cmd()
471 return -EIO; in daqp_ai_cmd()
473 outb(0, dev->iobase + DAQP_AUX_REG); in daqp_ai_cmd()
476 outb(DAQP_CMD_RSTQ, dev->iobase + DAQP_CMD_REG); in daqp_ai_cmd()
481 * TRIG_TIMER, then convert_arg specifies the time between in daqp_ai_cmd()
486 * is TRIG_TIMER, and scan_begin_arg specifies the time between in daqp_ai_cmd()
490 daqp_set_pacer(dev, devpriv->pacer_div); in daqp_ai_cmd()
492 if (cmd->convert_src == TRIG_TIMER) in daqp_ai_cmd()
498 for (i = 0; i < cmd->chanlist_len; i++) { in daqp_ai_cmd()
501 daqp_ai_set_one_scanlist_entry(dev, cmd->chanlist[i], start); in daqp_ai_cmd()
504 /* Now it's time to program the FIFO threshold, basically the in daqp_ai_cmd()
522 * three-quarters of the FIFO size - see below), we just use in daqp_ai_cmd()
525 * acquisition at that point and are done. If the stop count in daqp_ai_cmd()
545 * = 3^3 * 2). Hmmm... a one-line while loop or prime in daqp_ai_cmd()
548 * I'll also note a mini-race condition before ignoring it in in daqp_ai_cmd()
556 * samples (by halting the acquisition with four samples still in daqp_ai_cmd()
566 * compute the FIFO threshold (in bytes, not samples - that's in daqp_ai_cmd()
567 * why we multiple devpriv->count by 2 = sizeof(sample)) in daqp_ai_cmd()
570 if (cmd->stop_src == TRIG_COUNT) { in daqp_ai_cmd()
574 nsamples = (unsigned long long)cmd->stop_arg * in daqp_ai_cmd()
575 cmd->scan_end_arg; in daqp_ai_cmd()
586 outb(DAQP_CMD_RSTF, dev->iobase + DAQP_CMD_REG); in daqp_ai_cmd()
588 /* Set FIFO threshold. First two bytes are near-empty in daqp_ai_cmd()
589 * threshold, which is unused; next two bytes are near-full in daqp_ai_cmd()
596 outb(0x00, dev->iobase + DAQP_AI_FIFO_REG); in daqp_ai_cmd()
597 outb(0x00, dev->iobase + DAQP_AI_FIFO_REG); in daqp_ai_cmd()
599 outb((DAQP_FIFO_SIZE - threshold) & 0xff, in daqp_ai_cmd()
600 dev->iobase + DAQP_AI_FIFO_REG); in daqp_ai_cmd()
601 outb((DAQP_FIFO_SIZE - threshold) >> 8, dev->iobase + DAQP_AI_FIFO_REG); in daqp_ai_cmd()
603 /* Set trigger - continuous, internal */ in daqp_ai_cmd()
605 DAQP_CTRL_FIFO_INT_ENA, dev->iobase + DAQP_CTRL_REG); in daqp_ai_cmd()
612 outb(DAQP_CMD_ARM | DAQP_CMD_FIFO_DATA, dev->iobase + DAQP_CMD_REG); in daqp_ai_cmd()
624 status = inb(dev->iobase + DAQP_AUX_REG); in daqp_ao_empty()
627 return -EBUSY; in daqp_ao_empty()
635 struct daqp_private *devpriv = dev->private; in daqp_ao_insn_write()
636 unsigned int chan = CR_CHAN(insn->chanspec); in daqp_ao_insn_write()
639 if (devpriv->stop) in daqp_ao_insn_write()
640 return -EIO; in daqp_ao_insn_write()
643 outb(0, dev->iobase + DAQP_AUX_REG); in daqp_ao_insn_write()
645 for (i = 0; i < insn->n; i++) { in daqp_ao_insn_write()
656 dev->iobase + DAQP_AO_REG); in daqp_ao_insn_write()
658 s->readback[chan] = val; in daqp_ao_insn_write()
661 return insn->n; in daqp_ao_insn_write()
669 struct daqp_private *devpriv = dev->private; in daqp_di_insn_bits()
671 if (devpriv->stop) in daqp_di_insn_bits()
672 return -EIO; in daqp_di_insn_bits()
674 data[0] = inb(dev->iobase + DAQP_DI_REG); in daqp_di_insn_bits()
676 return insn->n; in daqp_di_insn_bits()
684 struct daqp_private *devpriv = dev->private; in daqp_do_insn_bits()
686 if (devpriv->stop) in daqp_do_insn_bits()
687 return -EIO; in daqp_do_insn_bits()
690 outb(s->state, dev->iobase + DAQP_DO_REG); in daqp_do_insn_bits()
692 data[1] = s->state; in daqp_do_insn_bits()
694 return insn->n; in daqp_do_insn_bits()
707 return -ENOMEM; in daqp_auto_attach()
709 link->config_flags |= CONF_AUTO_SET_IO | CONF_ENABLE_IRQ; in daqp_auto_attach()
713 dev->iobase = link->resource[0]->start; in daqp_auto_attach()
715 link->priv = dev; in daqp_auto_attach()
718 dev->irq = link->irq; in daqp_auto_attach()
724 s = &dev->subdevices[0]; in daqp_auto_attach()
725 s->type = COMEDI_SUBD_AI; in daqp_auto_attach()
726 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; in daqp_auto_attach()
727 s->n_chan = 8; in daqp_auto_attach()
728 s->maxdata = 0xffff; in daqp_auto_attach()
729 s->range_table = &range_daqp_ai; in daqp_auto_attach()
730 s->insn_read = daqp_ai_insn_read; in daqp_auto_attach()
731 if (dev->irq) { in daqp_auto_attach()
732 dev->read_subdev = s; in daqp_auto_attach()
733 s->subdev_flags |= SDF_CMD_READ; in daqp_auto_attach()
734 s->len_chanlist = 2048; in daqp_auto_attach()
735 s->do_cmdtest = daqp_ai_cmdtest; in daqp_auto_attach()
736 s->do_cmd = daqp_ai_cmd; in daqp_auto_attach()
737 s->cancel = daqp_ai_cancel; in daqp_auto_attach()
740 s = &dev->subdevices[1]; in daqp_auto_attach()
741 s->type = COMEDI_SUBD_AO; in daqp_auto_attach()
742 s->subdev_flags = SDF_WRITABLE; in daqp_auto_attach()
743 s->n_chan = 2; in daqp_auto_attach()
744 s->maxdata = 0x0fff; in daqp_auto_attach()
745 s->range_table = &range_bipolar5; in daqp_auto_attach()
746 s->insn_write = daqp_ao_insn_write; in daqp_auto_attach()
757 * ---- ----------------- ---------------------------- in daqp_auto_attach()
763 s = &dev->subdevices[2]; in daqp_auto_attach()
764 s->type = COMEDI_SUBD_DI; in daqp_auto_attach()
765 s->subdev_flags = SDF_READABLE; in daqp_auto_attach()
766 s->n_chan = 4; in daqp_auto_attach()
767 s->maxdata = 1; in daqp_auto_attach()
768 s->insn_bits = daqp_di_insn_bits; in daqp_auto_attach()
777 s = &dev->subdevices[3]; in daqp_auto_attach()
778 s->type = COMEDI_SUBD_DO; in daqp_auto_attach()
779 s->subdev_flags = SDF_WRITABLE; in daqp_auto_attach()
780 s->n_chan = 4; in daqp_auto_attach()
781 s->maxdata = 1; in daqp_auto_attach()
782 s->insn_bits = daqp_do_insn_bits; in daqp_auto_attach()
796 struct comedi_device *dev = link->priv; in daqp_cs_suspend()
797 struct daqp_private *devpriv = dev ? dev->private : NULL; in daqp_cs_suspend()
801 devpriv->stop = 1; in daqp_cs_suspend()
808 struct comedi_device *dev = link->priv; in daqp_cs_resume()
809 struct daqp_private *devpriv = dev ? dev->private : NULL; in daqp_cs_resume()
812 devpriv->stop = 0; in daqp_cs_resume()