Lines Matching +full:src +full:- +full:ref +full:- +full:clk +full:- +full:mhz
1 // SPDX-License-Identifier: GPL-2.0
4 * Comedi driver for Advantech PCI-1710 series boards
13 * Description: Comedi driver for Advantech PCI-1710 series boards
14 * Devices: [Advantech] PCI-1710 (adv_pci1710), PCI-1710HG, PCI-1711,
15 * PCI-1713, PCI-1731
17 * Updated: Fri, 29 Oct 2015 17:19:35 -0700
26 * The PCI-1710 and PCI-1710HG have the same PCI device ID, so the
40 * PCI BAR2 Register map (dev->iobase)
58 #define PCI171X_CTRL_CNT0 BIT(6) /* 1=ext. clk, 0=int. 100kHz clk */
118 UNI_RANGE(5), /* internal -5V ref */
119 UNI_RANGE(10), /* internal -10V ref */
120 RANGE_ext(0, 1) /* external -Vref (+/-10V max) */
176 unsigned char saved_seglen; /* len of the non-repeating chanlist */
185 struct pci1710_private *devpriv = dev->private; in pci1710_ai_check_chanlist()
186 unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); in pci1710_ai_check_chanlist()
187 unsigned int last_aref = CR_AREF(cmd->chanlist[0]); in pci1710_ai_check_chanlist()
188 unsigned int next_chan = (chan0 + 1) % s->n_chan; in pci1710_ai_check_chanlist()
193 if (cmd->chanlist_len == 1) { in pci1710_ai_check_chanlist()
194 devpriv->saved_seglen = cmd->chanlist_len; in pci1710_ai_check_chanlist()
199 chansegment[0] = cmd->chanlist[0]; in pci1710_ai_check_chanlist()
201 for (i = 1; i < cmd->chanlist_len; i++) { in pci1710_ai_check_chanlist()
202 unsigned int chan = CR_CHAN(cmd->chanlist[i]); in pci1710_ai_check_chanlist()
203 unsigned int aref = CR_AREF(cmd->chanlist[i]); in pci1710_ai_check_chanlist()
205 if (cmd->chanlist[0] == cmd->chanlist[i]) in pci1710_ai_check_chanlist()
209 dev_err(dev->class_dev, in pci1710_ai_check_chanlist()
211 return -EINVAL; in pci1710_ai_check_chanlist()
215 next_chan = (next_chan + 1) % s->n_chan; in pci1710_ai_check_chanlist()
217 dev_err(dev->class_dev, in pci1710_ai_check_chanlist()
220 return -EINVAL; in pci1710_ai_check_chanlist()
224 chansegment[i] = cmd->chanlist[i]; in pci1710_ai_check_chanlist()
229 for (i = 0; i < cmd->chanlist_len; i++) { in pci1710_ai_check_chanlist()
230 if (cmd->chanlist[i] != chansegment[i % seglen]) { in pci1710_ai_check_chanlist()
231 dev_err(dev->class_dev, in pci1710_ai_check_chanlist()
236 CR_CHAN(cmd->chanlist[i % seglen]), in pci1710_ai_check_chanlist()
237 CR_RANGE(cmd->chanlist[i % seglen]), in pci1710_ai_check_chanlist()
239 return -EINVAL; in pci1710_ai_check_chanlist()
242 devpriv->saved_seglen = seglen; in pci1710_ai_check_chanlist()
253 struct pci1710_private *devpriv = dev->private; in pci1710_ai_setup_chanlist()
255 unsigned int last_chan = CR_CHAN(chanlist[seglen - 1]); in pci1710_ai_setup_chanlist()
268 range -= devpriv->unipolar_gain; in pci1710_ai_setup_chanlist()
273 outw(PCI171X_MUX_CHAN(chan), dev->iobase + PCI171X_MUX_REG); in pci1710_ai_setup_chanlist()
274 outw(rangeval, dev->iobase + PCI171X_RANGE_REG); in pci1710_ai_setup_chanlist()
276 devpriv->act_chanlist[i] = chan; in pci1710_ai_setup_chanlist()
279 devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]); in pci1710_ai_setup_chanlist()
282 devpriv->mux_scan = PCI171X_MUX_CHANL(first_chan) | in pci1710_ai_setup_chanlist()
284 outw(devpriv->mux_scan, dev->iobase + PCI171X_MUX_REG); in pci1710_ai_setup_chanlist()
294 status = inw(dev->iobase + PCI171X_STATUS_REG); in pci1710_ai_eoc()
297 return -EBUSY; in pci1710_ai_eoc()
305 const struct boardtype *board = dev->board_ptr; in pci1710_ai_read_sample()
306 struct pci1710_private *devpriv = dev->private; in pci1710_ai_read_sample()
310 sample = inw(dev->iobase + PCI171X_AD_DATA_REG); in pci1710_ai_read_sample()
311 if (!board->is_pci1713) { in pci1710_ai_read_sample()
313 * The upper 4 bits of the 16-bit sample are the channel number in pci1710_ai_read_sample()
318 if (chan != devpriv->act_chanlist[cur_chan]) { in pci1710_ai_read_sample()
319 dev_err(dev->class_dev, in pci1710_ai_read_sample()
321 chan, devpriv->act_chanlist[cur_chan]); in pci1710_ai_read_sample()
322 return -ENODATA; in pci1710_ai_read_sample()
325 *val = sample & s->maxdata; in pci1710_ai_read_sample()
334 struct pci1710_private *devpriv = dev->private; in pci1710_ai_insn_read()
339 devpriv->ctrl |= PCI171X_CTRL_SW; in pci1710_ai_insn_read()
340 outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG); in pci1710_ai_insn_read()
342 outb(0, dev->iobase + PCI171X_CLRFIFO_REG); in pci1710_ai_insn_read()
343 outb(0, dev->iobase + PCI171X_CLRINT_REG); in pci1710_ai_insn_read()
345 pci1710_ai_setup_chanlist(dev, s, &insn->chanspec, 1, 1); in pci1710_ai_insn_read()
347 for (i = 0; i < insn->n; i++) { in pci1710_ai_insn_read()
351 outw(0, dev->iobase + PCI171X_SOFTTRG_REG); in pci1710_ai_insn_read()
365 devpriv->ctrl &= ~PCI171X_CTRL_SW; in pci1710_ai_insn_read()
366 outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG); in pci1710_ai_insn_read()
368 outb(0, dev->iobase + PCI171X_CLRFIFO_REG); in pci1710_ai_insn_read()
369 outb(0, dev->iobase + PCI171X_CLRINT_REG); in pci1710_ai_insn_read()
371 return ret ? ret : insn->n; in pci1710_ai_insn_read()
377 struct pci1710_private *devpriv = dev->private; in pci1710_ai_cancel()
380 devpriv->ctrl &= PCI171X_CTRL_CNT0; /* preserve counter 0 clk src */ in pci1710_ai_cancel()
381 outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG); in pci1710_ai_cancel()
384 comedi_8254_pacer_enable(dev->pacer, 1, 2, false); in pci1710_ai_cancel()
387 outb(0, dev->iobase + PCI171X_CLRFIFO_REG); in pci1710_ai_cancel()
388 outb(0, dev->iobase + PCI171X_CLRINT_REG); in pci1710_ai_cancel()
396 struct comedi_cmd *cmd = &s->async->cmd; in pci1710_handle_every_sample()
401 status = inw(dev->iobase + PCI171X_STATUS_REG); in pci1710_handle_every_sample()
403 dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", status); in pci1710_handle_every_sample()
404 s->async->events |= COMEDI_CB_ERROR; in pci1710_handle_every_sample()
408 dev_dbg(dev->class_dev, in pci1710_handle_every_sample()
410 s->async->events |= COMEDI_CB_ERROR; in pci1710_handle_every_sample()
414 outb(0, dev->iobase + PCI171X_CLRINT_REG); in pci1710_handle_every_sample()
416 for (; !(inw(dev->iobase + PCI171X_STATUS_REG) & PCI171X_STATUS_FE);) { in pci1710_handle_every_sample()
417 ret = pci1710_ai_read_sample(dev, s, s->async->cur_chan, &val); in pci1710_handle_every_sample()
419 s->async->events |= COMEDI_CB_ERROR; in pci1710_handle_every_sample()
425 if (cmd->stop_src == TRIG_COUNT && in pci1710_handle_every_sample()
426 s->async->scans_done >= cmd->stop_arg) { in pci1710_handle_every_sample()
427 s->async->events |= COMEDI_CB_EOA; in pci1710_handle_every_sample()
432 outb(0, dev->iobase + PCI171X_CLRINT_REG); in pci1710_handle_every_sample()
438 struct pci1710_private *devpriv = dev->private; in pci1710_handle_fifo()
439 struct comedi_async *async = s->async; in pci1710_handle_fifo()
440 struct comedi_cmd *cmd = &async->cmd; in pci1710_handle_fifo()
444 status = inw(dev->iobase + PCI171X_STATUS_REG); in pci1710_handle_fifo()
446 dev_dbg(dev->class_dev, "A/D FIFO not half full!\n"); in pci1710_handle_fifo()
447 async->events |= COMEDI_CB_ERROR; in pci1710_handle_fifo()
451 dev_dbg(dev->class_dev, in pci1710_handle_fifo()
453 async->events |= COMEDI_CB_ERROR; in pci1710_handle_fifo()
457 for (i = 0; i < devpriv->max_samples; i++) { in pci1710_handle_fifo()
461 ret = pci1710_ai_read_sample(dev, s, s->async->cur_chan, &val); in pci1710_handle_fifo()
463 s->async->events |= COMEDI_CB_ERROR; in pci1710_handle_fifo()
470 if (cmd->stop_src == TRIG_COUNT && in pci1710_handle_fifo()
471 async->scans_done >= cmd->stop_arg) { in pci1710_handle_fifo()
472 async->events |= COMEDI_CB_EOA; in pci1710_handle_fifo()
477 outb(0, dev->iobase + PCI171X_CLRINT_REG); in pci1710_handle_fifo()
483 struct pci1710_private *devpriv = dev->private; in pci1710_irq_handler()
487 if (!dev->attached) /* is device attached? */ in pci1710_irq_handler()
490 s = dev->read_subdev; in pci1710_irq_handler()
491 cmd = &s->async->cmd; in pci1710_irq_handler()
494 if (!(inw(dev->iobase + PCI171X_STATUS_REG) & PCI171X_STATUS_IRQ)) in pci1710_irq_handler()
497 if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */ in pci1710_irq_handler()
498 devpriv->ai_et = 0; in pci1710_irq_handler()
499 devpriv->ctrl &= PCI171X_CTRL_CNT0; in pci1710_irq_handler()
500 devpriv->ctrl |= PCI171X_CTRL_SW; /* set software trigger */ in pci1710_irq_handler()
501 outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG); in pci1710_irq_handler()
502 devpriv->ctrl = devpriv->ctrl_ext; in pci1710_irq_handler()
503 outb(0, dev->iobase + PCI171X_CLRFIFO_REG); in pci1710_irq_handler()
504 outb(0, dev->iobase + PCI171X_CLRINT_REG); in pci1710_irq_handler()
506 outw(devpriv->mux_scan, dev->iobase + PCI171X_MUX_REG); in pci1710_irq_handler()
507 outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG); in pci1710_irq_handler()
508 comedi_8254_pacer_enable(dev->pacer, 1, 2, true); in pci1710_irq_handler()
512 if (cmd->flags & CMDF_WAKE_EOS) in pci1710_irq_handler()
524 struct pci1710_private *devpriv = dev->private; in pci1710_ai_cmd()
525 struct comedi_cmd *cmd = &s->async->cmd; in pci1710_ai_cmd()
527 pci1710_ai_setup_chanlist(dev, s, cmd->chanlist, cmd->chanlist_len, in pci1710_ai_cmd()
528 devpriv->saved_seglen); in pci1710_ai_cmd()
530 outb(0, dev->iobase + PCI171X_CLRFIFO_REG); in pci1710_ai_cmd()
531 outb(0, dev->iobase + PCI171X_CLRINT_REG); in pci1710_ai_cmd()
533 devpriv->ctrl &= PCI171X_CTRL_CNT0; in pci1710_ai_cmd()
534 if ((cmd->flags & CMDF_WAKE_EOS) == 0) in pci1710_ai_cmd()
535 devpriv->ctrl |= PCI171X_CTRL_ONEFH; in pci1710_ai_cmd()
537 if (cmd->convert_src == TRIG_TIMER) { in pci1710_ai_cmd()
538 comedi_8254_update_divisors(dev->pacer); in pci1710_ai_cmd()
540 devpriv->ctrl |= PCI171X_CTRL_PACER | PCI171X_CTRL_IRQEN; in pci1710_ai_cmd()
541 if (cmd->start_src == TRIG_EXT) { in pci1710_ai_cmd()
542 devpriv->ctrl_ext = devpriv->ctrl; in pci1710_ai_cmd()
543 devpriv->ctrl &= ~(PCI171X_CTRL_PACER | in pci1710_ai_cmd()
546 devpriv->ctrl |= PCI171X_CTRL_EXT; in pci1710_ai_cmd()
547 devpriv->ai_et = 1; in pci1710_ai_cmd()
549 devpriv->ai_et = 0; in pci1710_ai_cmd()
551 outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG); in pci1710_ai_cmd()
553 if (cmd->start_src == TRIG_NOW) in pci1710_ai_cmd()
554 comedi_8254_pacer_enable(dev->pacer, 1, 2, true); in pci1710_ai_cmd()
556 devpriv->ctrl |= PCI171X_CTRL_EXT | PCI171X_CTRL_IRQEN; in pci1710_ai_cmd()
557 outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG); in pci1710_ai_cmd()
571 err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT); in pci1710_ai_cmdtest()
572 err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW); in pci1710_ai_cmdtest()
573 err |= comedi_check_trigger_src(&cmd->convert_src, in pci1710_ai_cmdtest()
575 err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); in pci1710_ai_cmdtest()
576 err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); in pci1710_ai_cmdtest()
583 err |= comedi_check_trigger_is_unique(cmd->start_src); in pci1710_ai_cmdtest()
584 err |= comedi_check_trigger_is_unique(cmd->convert_src); in pci1710_ai_cmdtest()
585 err |= comedi_check_trigger_is_unique(cmd->stop_src); in pci1710_ai_cmdtest()
594 err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0); in pci1710_ai_cmdtest()
595 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0); in pci1710_ai_cmdtest()
597 if (cmd->convert_src == TRIG_TIMER) in pci1710_ai_cmdtest()
598 err |= comedi_check_trigger_arg_min(&cmd->convert_arg, 10000); in pci1710_ai_cmdtest()
600 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0); in pci1710_ai_cmdtest()
602 err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg, in pci1710_ai_cmdtest()
603 cmd->chanlist_len); in pci1710_ai_cmdtest()
605 if (cmd->stop_src == TRIG_COUNT) in pci1710_ai_cmdtest()
606 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1); in pci1710_ai_cmdtest()
608 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0); in pci1710_ai_cmdtest()
615 if (cmd->convert_src == TRIG_TIMER) { in pci1710_ai_cmdtest()
616 unsigned int arg = cmd->convert_arg; in pci1710_ai_cmdtest()
618 comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags); in pci1710_ai_cmdtest()
619 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg); in pci1710_ai_cmdtest()
640 struct pci1710_private *devpriv = dev->private; in pci1710_ao_insn_write()
641 unsigned int chan = CR_CHAN(insn->chanspec); in pci1710_ao_insn_write()
642 unsigned int range = CR_RANGE(insn->chanspec); in pci1710_ao_insn_write()
643 unsigned int val = s->readback[chan]; in pci1710_ao_insn_write()
646 devpriv->da_ranges &= ~PCI171X_DAREF_MASK(chan); in pci1710_ao_insn_write()
647 devpriv->da_ranges |= PCI171X_DAREF(chan, range); in pci1710_ao_insn_write()
648 outw(devpriv->da_ranges, dev->iobase + PCI171X_DAREF_REG); in pci1710_ao_insn_write()
650 for (i = 0; i < insn->n; i++) { in pci1710_ao_insn_write()
652 outw(val, dev->iobase + PCI171X_DA_REG(chan)); in pci1710_ao_insn_write()
655 s->readback[chan] = val; in pci1710_ao_insn_write()
657 return insn->n; in pci1710_ao_insn_write()
665 data[1] = inw(dev->iobase + PCI171X_DI_REG); in pci1710_di_insn_bits()
667 return insn->n; in pci1710_di_insn_bits()
676 outw(s->state, dev->iobase + PCI171X_DO_REG); in pci1710_do_insn_bits()
678 data[1] = s->state; in pci1710_do_insn_bits()
680 return insn->n; in pci1710_do_insn_bits()
688 struct pci1710_private *devpriv = dev->private; in pci1710_counter_insn_config()
694 devpriv->ctrl_ext &= ~PCI171X_CTRL_CNT0; in pci1710_counter_insn_config()
697 devpriv->ctrl_ext |= PCI171X_CTRL_CNT0; in pci1710_counter_insn_config()
700 return -EINVAL; in pci1710_counter_insn_config()
702 outw(devpriv->ctrl_ext, dev->iobase + PCI171X_CTRL_REG); in pci1710_counter_insn_config()
705 if (devpriv->ctrl_ext & PCI171X_CTRL_CNT0) { in pci1710_counter_insn_config()
714 return -EINVAL; in pci1710_counter_insn_config()
717 return insn->n; in pci1710_counter_insn_config()
722 const struct boardtype *board = dev->board_ptr; in pci1710_reset()
726 * to use internal 1 MHz clock. in pci1710_reset()
728 outw(0, dev->iobase + PCI171X_CTRL_REG); in pci1710_reset()
731 outb(0, dev->iobase + PCI171X_CLRFIFO_REG); in pci1710_reset()
732 outb(0, dev->iobase + PCI171X_CLRINT_REG); in pci1710_reset()
734 if (board->has_ao) { in pci1710_reset()
736 outb(0, dev->iobase + PCI171X_DAREF_REG); in pci1710_reset()
737 outw(0, dev->iobase + PCI171X_DA_REG(0)); in pci1710_reset()
738 outw(0, dev->iobase + PCI171X_DA_REG(1)); in pci1710_reset()
742 outw(0, dev->iobase + PCI171X_DO_REG); in pci1710_reset()
758 return -ENODEV; in pci1710_auto_attach()
759 dev->board_ptr = board; in pci1710_auto_attach()
760 dev->board_name = board->name; in pci1710_auto_attach()
764 return -ENOMEM; in pci1710_auto_attach()
769 dev->iobase = pci_resource_start(pcidev, 2); in pci1710_auto_attach()
771 dev->pacer = comedi_8254_init(dev->iobase + PCI171X_TIMER_BASE, in pci1710_auto_attach()
773 if (!dev->pacer) in pci1710_auto_attach()
774 return -ENOMEM; in pci1710_auto_attach()
777 if (board->has_ao) in pci1710_auto_attach()
779 if (!board->is_pci1713) { in pci1710_auto_attach()
793 if (pcidev->irq) { in pci1710_auto_attach()
794 ret = request_irq(pcidev->irq, pci1710_irq_handler, in pci1710_auto_attach()
795 IRQF_SHARED, dev->board_name, dev); in pci1710_auto_attach()
797 dev->irq = pcidev->irq; in pci1710_auto_attach()
803 s = &dev->subdevices[subdev++]; in pci1710_auto_attach()
804 s->type = COMEDI_SUBD_AI; in pci1710_auto_attach()
805 s->subdev_flags = SDF_READABLE | SDF_GROUND; in pci1710_auto_attach()
806 if (!board->is_pci1711) in pci1710_auto_attach()
807 s->subdev_flags |= SDF_DIFF; in pci1710_auto_attach()
808 s->n_chan = board->is_pci1713 ? 32 : 16; in pci1710_auto_attach()
809 s->maxdata = 0x0fff; in pci1710_auto_attach()
810 s->range_table = board->ai_range; in pci1710_auto_attach()
811 s->insn_read = pci1710_ai_insn_read; in pci1710_auto_attach()
812 if (dev->irq) { in pci1710_auto_attach()
813 dev->read_subdev = s; in pci1710_auto_attach()
814 s->subdev_flags |= SDF_CMD_READ; in pci1710_auto_attach()
815 s->len_chanlist = s->n_chan; in pci1710_auto_attach()
816 s->do_cmdtest = pci1710_ai_cmdtest; in pci1710_auto_attach()
817 s->do_cmd = pci1710_ai_cmd; in pci1710_auto_attach()
818 s->cancel = pci1710_ai_cancel; in pci1710_auto_attach()
822 for (i = 0; i < s->range_table->length; i++) { in pci1710_auto_attach()
824 devpriv->unipolar_gain = i; in pci1710_auto_attach()
829 if (board->has_ao) { in pci1710_auto_attach()
831 s = &dev->subdevices[subdev++]; in pci1710_auto_attach()
832 s->type = COMEDI_SUBD_AO; in pci1710_auto_attach()
833 s->subdev_flags = SDF_WRITABLE | SDF_GROUND; in pci1710_auto_attach()
834 s->n_chan = 2; in pci1710_auto_attach()
835 s->maxdata = 0x0fff; in pci1710_auto_attach()
836 s->range_table = &pci171x_ao_range; in pci1710_auto_attach()
837 s->insn_write = pci1710_ao_insn_write; in pci1710_auto_attach()
844 if (!board->is_pci1713) { in pci1710_auto_attach()
846 s = &dev->subdevices[subdev++]; in pci1710_auto_attach()
847 s->type = COMEDI_SUBD_DI; in pci1710_auto_attach()
848 s->subdev_flags = SDF_READABLE; in pci1710_auto_attach()
849 s->n_chan = 16; in pci1710_auto_attach()
850 s->maxdata = 1; in pci1710_auto_attach()
851 s->range_table = &range_digital; in pci1710_auto_attach()
852 s->insn_bits = pci1710_di_insn_bits; in pci1710_auto_attach()
855 s = &dev->subdevices[subdev++]; in pci1710_auto_attach()
856 s->type = COMEDI_SUBD_DO; in pci1710_auto_attach()
857 s->subdev_flags = SDF_WRITABLE; in pci1710_auto_attach()
858 s->n_chan = 16; in pci1710_auto_attach()
859 s->maxdata = 1; in pci1710_auto_attach()
860 s->range_table = &range_digital; in pci1710_auto_attach()
861 s->insn_bits = pci1710_do_insn_bits; in pci1710_auto_attach()
864 s = &dev->subdevices[subdev++]; in pci1710_auto_attach()
865 comedi_8254_subdevice_init(s, dev->pacer); in pci1710_auto_attach()
867 dev->pacer->insn_config = pci1710_counter_insn_config; in pci1710_auto_attach()
870 comedi_8254_set_busy(dev->pacer, 1, true); in pci1710_auto_attach()
871 comedi_8254_set_busy(dev->pacer, 2, true); in pci1710_auto_attach()
875 devpriv->max_samples = (board->is_pci1711) ? 512 : 2048; in pci1710_auto_attach()
891 id->driver_data); in adv_pci1710_pci_probe()
962 MODULE_DESCRIPTION("Comedi: Advantech PCI-1710 Series Multifunction DAS Cards");