Lines Matching +full:link +full:- +full:trigger +full:- +full:order
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()
348 * which with its 24-bit counter, allows values up to 84 seconds.
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()
391 /* Step 2a : make sure trigger sources are unique */ 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()
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()
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()
514 * service for a full 10 milliseconds in order to lose data in daqp_ai_cmd()
522 * three-quarters of the FIFO size - see below), we just use 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()
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()
700 struct pcmcia_device *link = comedi_to_pcmcia_dev(dev); in daqp_auto_attach() local
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()
716 ret = pcmcia_request_irq(link, daqp_interrupt); 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()
758 * 0 DI0, ext. trigger Same as normal mode 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()
794 static int daqp_cs_suspend(struct pcmcia_device *link) in daqp_cs_suspend() argument
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()
806 static int daqp_cs_resume(struct pcmcia_device *link) in daqp_cs_resume() argument
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()
817 static int daqp_cs_attach(struct pcmcia_device *link) in daqp_cs_attach() argument
819 return comedi_pcmcia_auto_config(link, &driver_daqp); in daqp_cs_attach()