Lines Matching +full:adc +full:- +full:use +full:- +full:external +full:- +full:triggers
1 // SPDX-License-Identifier: GPL-2.0+
4 * Driver for Winsystems PC-104 based multifunction IO board.
6 * COMEDI - Linux Control and Measurement Device Interface
12 * Description: A driver for the PCM-MIO multifunction board
13 * Devices: [Winsystems] PCM-MIO (pcmmio)
15 * Updated: Wed, May 16 2007 16:21:10 -0500
18 * A driver for the PCM-MIO multifunction board from Winsystems. This
19 * is a PC-104 based I/O board. It contains four subdevices:
21 * subdevice 0 - 16 channels of 16-bit AI
22 * subdevice 1 - 8 channels of 16-bit AO
23 * subdevice 2 - first 24 channels of the 48 channel of DIO
24 * (with edge-triggered interrupt support)
25 * subdevice 3 - last 24 channels of the 48 channel DIO
34 * are basically edge-triggered interrupts for any configuration of the
39 * A few words about edge-detection IRQ support (commands on DIO):
41 * To use edge-detection IRQ support for the DIO subdevice, pass the IRQ
43 * but rather configured through software, so any IRQ from 1-15 is OK.
46 * comedi_command in order to use edge-triggered interrupts for DIO.
48 * Use comedi_commands with TRIG_NOW. Your callback will be called each
51 * one 32-bit unsigned int. This value is the mask of channels that had
56 * To set the polarity of the edge-detection interrupts pass a nonzero value
57 * for either CR_RANGE or CR_AREF for edge-up polarity, or a zero
58 * value for both CR_RANGE and CR_AREF if you want edge-down polarity.
61 * [0] - I/O port base address
62 * [1] - IRQ (optional -- for edge-detect interrupt support only,
133 * ------ ----------- ----------- ----------- -----------
173 RANGE(-2.5, 7.5)
187 struct pcmmio_private *devpriv = dev->private; in pcmmio_dio_write()
188 unsigned long iobase = dev->iobase; in pcmmio_dio_write()
191 spin_lock_irqsave(&devpriv->pagelock, flags); in pcmmio_dio_write()
203 spin_unlock_irqrestore(&devpriv->pagelock, flags); in pcmmio_dio_write()
209 struct pcmmio_private *devpriv = dev->private; in pcmmio_dio_read()
210 unsigned long iobase = dev->iobase; in pcmmio_dio_read()
214 spin_lock_irqsave(&devpriv->pagelock, flags); in pcmmio_dio_read()
226 spin_unlock_irqrestore(&devpriv->pagelock, flags); in pcmmio_dio_read()
234 * to go to a high-z state (pulled high by an external 10K resistor).
246 /* subdevice 2 uses ports 0-2, subdevice 3 uses ports 3-5 */ in pcmmio_dio_insn_bits()
247 int port = s->index == 2 ? 0 : 3; in pcmmio_dio_insn_bits()
248 unsigned int chanmask = (1 << s->n_chan) - 1; in pcmmio_dio_insn_bits()
258 * The s->io_bits mask makes sure the input channels in pcmmio_dio_insn_bits()
260 * z-state. in pcmmio_dio_insn_bits()
262 val = ~s->state & chanmask; in pcmmio_dio_insn_bits()
263 val &= s->io_bits; in pcmmio_dio_insn_bits()
273 return insn->n; in pcmmio_dio_insn_bits()
281 /* subdevice 2 uses ports 0-2, subdevice 3 uses ports 3-5 */ in pcmmio_dio_insn_config()
282 int port = s->index == 2 ? 0 : 3; in pcmmio_dio_insn_config()
290 pcmmio_dio_write(dev, s->io_bits, 0, port); in pcmmio_dio_insn_config()
292 return insn->n; in pcmmio_dio_insn_config()
307 /* devpriv->spinlock is already locked */
311 struct pcmmio_private *devpriv = dev->private; in pcmmio_stop_intr()
313 devpriv->enabled_mask = 0; in pcmmio_stop_intr()
314 devpriv->active = 0; in pcmmio_stop_intr()
315 s->async->inttrig = NULL; in pcmmio_stop_intr()
325 struct pcmmio_private *devpriv = dev->private; in pcmmio_handle_dio_intr()
326 struct comedi_cmd *cmd = &s->async->cmd; in pcmmio_handle_dio_intr()
331 spin_lock_irqsave(&devpriv->spinlock, flags); in pcmmio_handle_dio_intr()
333 if (!devpriv->active) in pcmmio_handle_dio_intr()
336 if (!(triggered & devpriv->enabled_mask)) in pcmmio_handle_dio_intr()
339 for (i = 0; i < cmd->chanlist_len; i++) { in pcmmio_handle_dio_intr()
340 unsigned int chan = CR_CHAN(cmd->chanlist[i]); in pcmmio_handle_dio_intr()
348 if (cmd->stop_src == TRIG_COUNT && in pcmmio_handle_dio_intr()
349 s->async->scans_done >= cmd->stop_arg) in pcmmio_handle_dio_intr()
350 s->async->events |= COMEDI_CB_EOA; in pcmmio_handle_dio_intr()
353 spin_unlock_irqrestore(&devpriv->spinlock, flags); in pcmmio_handle_dio_intr()
361 struct comedi_subdevice *s = dev->read_subdev; in interrupt_pcmmio()
366 int_pend = inb(dev->iobase + PCMMIO_INT_PENDING_REG) & 0x07; in interrupt_pcmmio()
379 /* devpriv->spinlock is already locked */
383 struct pcmmio_private *devpriv = dev->private; in pcmmio_start_intr()
384 struct comedi_cmd *cmd = &s->async->cmd; in pcmmio_start_intr()
389 devpriv->enabled_mask = 0; in pcmmio_start_intr()
390 devpriv->active = 1; in pcmmio_start_intr()
391 if (cmd->chanlist) { in pcmmio_start_intr()
392 for (i = 0; i < cmd->chanlist_len; i++) { in pcmmio_start_intr()
393 unsigned int chanspec = cmd->chanlist[i]; in pcmmio_start_intr()
402 bits &= ((1 << s->n_chan) - 1); in pcmmio_start_intr()
403 devpriv->enabled_mask = bits; in pcmmio_start_intr()
412 struct pcmmio_private *devpriv = dev->private; in pcmmio_cancel()
415 spin_lock_irqsave(&devpriv->spinlock, flags); in pcmmio_cancel()
416 if (devpriv->active) in pcmmio_cancel()
418 spin_unlock_irqrestore(&devpriv->spinlock, flags); in pcmmio_cancel()
427 struct pcmmio_private *devpriv = dev->private; in pcmmio_inttrig_start_intr()
428 struct comedi_cmd *cmd = &s->async->cmd; in pcmmio_inttrig_start_intr()
431 if (trig_num != cmd->start_arg) in pcmmio_inttrig_start_intr()
432 return -EINVAL; in pcmmio_inttrig_start_intr()
434 spin_lock_irqsave(&devpriv->spinlock, flags); in pcmmio_inttrig_start_intr()
435 s->async->inttrig = NULL; in pcmmio_inttrig_start_intr()
436 if (devpriv->active) in pcmmio_inttrig_start_intr()
438 spin_unlock_irqrestore(&devpriv->spinlock, flags); in pcmmio_inttrig_start_intr()
448 struct pcmmio_private *devpriv = dev->private; in pcmmio_cmd()
449 struct comedi_cmd *cmd = &s->async->cmd; in pcmmio_cmd()
452 spin_lock_irqsave(&devpriv->spinlock, flags); in pcmmio_cmd()
453 devpriv->active = 1; in pcmmio_cmd()
456 if (cmd->start_src == TRIG_INT) in pcmmio_cmd()
457 s->async->inttrig = pcmmio_inttrig_start_intr; in pcmmio_cmd()
461 spin_unlock_irqrestore(&devpriv->spinlock, flags); in pcmmio_cmd()
472 /* Step 1 : check if triggers are trivially valid */ in pcmmio_cmdtest()
474 err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT); in pcmmio_cmdtest()
475 err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); in pcmmio_cmdtest()
476 err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_NOW); in pcmmio_cmdtest()
477 err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); in pcmmio_cmdtest()
478 err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); in pcmmio_cmdtest()
485 err |= comedi_check_trigger_is_unique(cmd->start_src); in pcmmio_cmdtest()
486 err |= comedi_check_trigger_is_unique(cmd->stop_src); in pcmmio_cmdtest()
495 err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0); in pcmmio_cmdtest()
496 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0); in pcmmio_cmdtest()
497 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0); in pcmmio_cmdtest()
498 err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg, in pcmmio_cmdtest()
499 cmd->chanlist_len); in pcmmio_cmdtest()
501 if (cmd->stop_src == TRIG_COUNT) in pcmmio_cmdtest()
502 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1); in pcmmio_cmdtest()
504 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0); in pcmmio_cmdtest()
523 status = inb(dev->iobase + PCMMIO_AI_STATUS_REG); in pcmmio_ai_eoc()
526 return -EBUSY; in pcmmio_ai_eoc()
534 unsigned long iobase = dev->iobase; in pcmmio_ai_insn_read()
535 unsigned int chan = CR_CHAN(insn->chanspec); in pcmmio_ai_insn_read()
536 unsigned int range = CR_RANGE(insn->chanspec); in pcmmio_ai_insn_read()
537 unsigned int aref = CR_AREF(insn->chanspec); in pcmmio_ai_insn_read()
544 * The PCM-MIO uses two Linear Tech LTC1859CG 8-channel A/D converters. in pcmmio_ai_insn_read()
545 * The devices use a full duplex serial interface which transmits and in pcmmio_ai_insn_read()
546 * receives data simultaneously. An 8-bit command is shifted into the in pcmmio_ai_insn_read()
547 * ADC interface to configure it for the next conversion. At the same in pcmmio_ai_insn_read()
555 * in ADC which will get flushed on the next comedi_insn. in pcmmio_ai_insn_read()
559 chan -= 8; in pcmmio_ai_insn_read()
579 for (i = 0; i < insn->n; i++) { in pcmmio_ai_insn_read()
596 return insn->n; in pcmmio_ai_insn_read()
606 status = inb(dev->iobase + PCMMIO_AO_STATUS_REG); in pcmmio_ao_eoc()
609 return -EBUSY; in pcmmio_ao_eoc()
617 unsigned long iobase = dev->iobase; in pcmmio_ao_insn_write()
618 unsigned int chan = CR_CHAN(insn->chanspec); in pcmmio_ao_insn_write()
619 unsigned int range = CR_RANGE(insn->chanspec); in pcmmio_ao_insn_write()
625 * The PCM-MIO has two Linear Tech LTC2704 DAC devices. Each device in pcmmio_ao_insn_write()
626 * is a 4-channel converter with software-selectable output range. in pcmmio_ao_insn_write()
630 cmd |= PCMMIO_AO_CMD_CHAN_SEL(chan - 4); in pcmmio_ao_insn_write()
645 for (i = 0; i < insn->n; i++) { in pcmmio_ao_insn_write()
658 s->readback[chan] = val; in pcmmio_ao_insn_write()
661 return insn->n; in pcmmio_ao_insn_write()
670 ret = comedi_request_region(dev, it->options[0], 32); in pcmmio_attach()
676 return -ENOMEM; in pcmmio_attach()
678 spin_lock_init(&devpriv->pagelock); in pcmmio_attach()
679 spin_lock_init(&devpriv->spinlock); in pcmmio_attach()
683 if (it->options[1]) { in pcmmio_attach()
684 ret = request_irq(it->options[1], interrupt_pcmmio, 0, in pcmmio_attach()
685 dev->board_name, dev); in pcmmio_attach()
687 dev->irq = it->options[1]; in pcmmio_attach()
691 dev->iobase + PCMMIO_AI_RES_ENA_REG); in pcmmio_attach()
692 outb(PCMMIO_RESOURCE_IRQ(dev->irq), in pcmmio_attach()
693 dev->iobase + PCMMIO_RESOURCE_REG); in pcmmio_attach()
702 s = &dev->subdevices[0]; in pcmmio_attach()
703 s->type = COMEDI_SUBD_AI; in pcmmio_attach()
704 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; in pcmmio_attach()
705 s->n_chan = 16; in pcmmio_attach()
706 s->maxdata = 0xffff; in pcmmio_attach()
707 s->range_table = &pcmmio_ai_ranges; in pcmmio_attach()
708 s->insn_read = pcmmio_ai_insn_read; in pcmmio_attach()
712 dev->iobase + PCMMIO_AI_RES_ENA_REG); in pcmmio_attach()
714 dev->iobase + PCMMIO_AI_RES_ENA_REG + PCMMIO_AI_2ND_ADC_OFFSET); in pcmmio_attach()
717 s = &dev->subdevices[1]; in pcmmio_attach()
718 s->type = COMEDI_SUBD_AO; in pcmmio_attach()
719 s->subdev_flags = SDF_READABLE; in pcmmio_attach()
720 s->n_chan = 8; in pcmmio_attach()
721 s->maxdata = 0xffff; in pcmmio_attach()
722 s->range_table = &pcmmio_ao_ranges; in pcmmio_attach()
723 s->insn_write = pcmmio_ao_insn_write; in pcmmio_attach()
730 outb(0, dev->iobase + PCMMIO_AO_RESOURCE_ENA_REG); in pcmmio_attach()
731 outb(0, dev->iobase + PCMMIO_AO_2ND_DAC_OFFSET + in pcmmio_attach()
735 s = &dev->subdevices[2]; in pcmmio_attach()
736 s->type = COMEDI_SUBD_DIO; in pcmmio_attach()
737 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; in pcmmio_attach()
738 s->n_chan = 24; in pcmmio_attach()
739 s->maxdata = 1; in pcmmio_attach()
740 s->len_chanlist = 1; in pcmmio_attach()
741 s->range_table = &range_digital; in pcmmio_attach()
742 s->insn_bits = pcmmio_dio_insn_bits; in pcmmio_attach()
743 s->insn_config = pcmmio_dio_insn_config; in pcmmio_attach()
744 if (dev->irq) { in pcmmio_attach()
745 dev->read_subdev = s; in pcmmio_attach()
746 s->subdev_flags |= SDF_CMD_READ | SDF_LSAMPL | SDF_PACKED; in pcmmio_attach()
747 s->len_chanlist = s->n_chan; in pcmmio_attach()
748 s->cancel = pcmmio_cancel; in pcmmio_attach()
749 s->do_cmd = pcmmio_cmd; in pcmmio_attach()
750 s->do_cmdtest = pcmmio_cmdtest; in pcmmio_attach()
754 s = &dev->subdevices[3]; in pcmmio_attach()
755 s->type = COMEDI_SUBD_DIO; in pcmmio_attach()
756 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; in pcmmio_attach()
757 s->n_chan = 24; in pcmmio_attach()
758 s->maxdata = 1; in pcmmio_attach()
759 s->range_table = &range_digital; in pcmmio_attach()
760 s->insn_bits = pcmmio_dio_insn_bits; in pcmmio_attach()
761 s->insn_config = pcmmio_dio_insn_config; in pcmmio_attach()
775 MODULE_DESCRIPTION("Comedi driver for Winsystems PCM-MIO PC/104 board");