Lines Matching +full:mux +full:- +full:ctrl +full:- +full:list

1 // SPDX-License-Identifier: GPL-2.0
4 * Comedi driver for Advantech PCL-816 cards
12 * Description: Advantech PCL-816 cards, PCL-814
13 * Devices: [Advantech] PCL-816 (pcl816), PCL-814B (pcl814b)
16 * Updated: Tue, 2 Apr 2002 23:15:21 -0800
26 * [0] - IO Base
27 * [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
28 * [2] - DMA (0=disable, 1, 3)
29 * [3] - 0, 10=10MHz clock for 8254
114 struct pcl816_private *devpriv = dev->private; in pcl816_ai_setup_dma()
115 struct comedi_isadma *dma = devpriv->dma; in pcl816_ai_setup_dma()
116 struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma]; in pcl816_ai_setup_dma()
117 unsigned int max_samples = comedi_bytes_to_samples(s, desc->maxsize); in pcl816_ai_setup_dma()
120 comedi_isadma_disable(dma->chan); in pcl816_ai_setup_dma()
128 nsamples -= unread_samples; in pcl816_ai_setup_dma()
129 desc->size = comedi_samples_to_bytes(s, nsamples); in pcl816_ai_setup_dma()
138 outb(chan, dev->iobase + PCL816_MUX_REG); in pcl816_ai_set_chan_range()
139 outb(range, dev->iobase + PCL816_RANGE_REG); in pcl816_ai_set_chan_range()
147 dev->iobase + PCL816_MUX_REG); in pcl816_ai_set_chan_scan()
159 /* store range list to card */ in pcl816_ai_setup_chanlist()
175 outb(0, dev->iobase + PCL816_CLRINT_REG); in pcl816_ai_clear_eoc()
181 outb(0, dev->iobase + PCL816_AI_LSB_REG); in pcl816_ai_soft_trig()
189 val = inb(dev->iobase + PCL816_AI_MSB_REG) << 8; in pcl816_ai_get_sample()
190 val |= inb(dev->iobase + PCL816_AI_LSB_REG); in pcl816_ai_get_sample()
192 return val & s->maxdata; in pcl816_ai_get_sample()
202 status = inb(dev->iobase + PCL816_STATUS_REG); in pcl816_ai_eoc()
205 return -EBUSY; in pcl816_ai_eoc()
211 struct comedi_cmd *cmd = &s->async->cmd; in pcl816_ai_next_chan()
213 if (cmd->stop_src == TRIG_COUNT && in pcl816_ai_next_chan()
214 s->async->scans_done >= cmd->stop_arg) { in pcl816_ai_next_chan()
215 s->async->events |= COMEDI_CB_EOA; in pcl816_ai_next_chan()
242 struct comedi_subdevice *s = dev->read_subdev; in pcl816_interrupt()
243 struct pcl816_private *devpriv = dev->private; in pcl816_interrupt()
244 struct comedi_isadma *dma = devpriv->dma; in pcl816_interrupt()
245 struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma]; in pcl816_interrupt()
249 if (!dev->attached || !devpriv->ai_cmd_running) { in pcl816_interrupt()
254 if (devpriv->ai_cmd_canceled) { in pcl816_interrupt()
255 devpriv->ai_cmd_canceled = 0; in pcl816_interrupt()
260 nsamples = comedi_bytes_to_samples(s, desc->size) - in pcl816_interrupt()
261 devpriv->ai_poll_ptr; in pcl816_interrupt()
262 bufptr = devpriv->ai_poll_ptr; in pcl816_interrupt()
263 devpriv->ai_poll_ptr = 0; in pcl816_interrupt()
266 dma->cur_dma = 1 - dma->cur_dma; in pcl816_interrupt()
269 transfer_from_dma_buf(dev, s, desc->virt_addr, bufptr, nsamples); in pcl816_interrupt()
287 dev_err(dev->class_dev, "range/channel list is empty!\n"); in check_channel_list()
299 (CR_CHAN(chansegment[i - 1]) + 1) % chanlen; in check_channel_list()
301 /* channel list isn't continuous :-( */ in check_channel_list()
302 dev_dbg(dev->class_dev, in check_channel_list()
303 "channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n", in check_channel_list()
308 /* well, this is next correct channel in list */ in check_channel_list()
315 dev_dbg(dev->class_dev, in check_channel_list()
323 return 0; /* chan/gain list is strange */ in check_channel_list()
330 return seglen; /* we can serve this with MUX logic */ in check_channel_list()
340 err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW); in pcl816_ai_cmdtest()
341 err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW); in pcl816_ai_cmdtest()
342 err |= comedi_check_trigger_src(&cmd->convert_src, in pcl816_ai_cmdtest()
344 err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); in pcl816_ai_cmdtest()
345 err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); in pcl816_ai_cmdtest()
352 err |= comedi_check_trigger_is_unique(cmd->convert_src); in pcl816_ai_cmdtest()
353 err |= comedi_check_trigger_is_unique(cmd->stop_src); in pcl816_ai_cmdtest()
362 err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0); in pcl816_ai_cmdtest()
363 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0); in pcl816_ai_cmdtest()
365 if (cmd->convert_src == TRIG_TIMER) in pcl816_ai_cmdtest()
366 err |= comedi_check_trigger_arg_min(&cmd->convert_arg, 10000); in pcl816_ai_cmdtest()
368 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0); in pcl816_ai_cmdtest()
370 err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg, in pcl816_ai_cmdtest()
371 cmd->chanlist_len); in pcl816_ai_cmdtest()
373 if (cmd->stop_src == TRIG_COUNT) in pcl816_ai_cmdtest()
374 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1); in pcl816_ai_cmdtest()
376 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0); in pcl816_ai_cmdtest()
382 if (cmd->convert_src == TRIG_TIMER) { in pcl816_ai_cmdtest()
383 unsigned int arg = cmd->convert_arg; in pcl816_ai_cmdtest()
385 comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags); in pcl816_ai_cmdtest()
386 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg); in pcl816_ai_cmdtest()
394 if (cmd->chanlist) { in pcl816_ai_cmdtest()
395 if (!check_channel_list(dev, s, cmd->chanlist, in pcl816_ai_cmdtest()
396 cmd->chanlist_len)) in pcl816_ai_cmdtest()
397 return 5; /* incorrect channels list */ in pcl816_ai_cmdtest()
405 struct pcl816_private *devpriv = dev->private; in pcl816_ai_cmd()
406 struct comedi_isadma *dma = devpriv->dma; in pcl816_ai_cmd()
407 struct comedi_cmd *cmd = &s->async->cmd; in pcl816_ai_cmd()
408 unsigned int ctrl; in pcl816_ai_cmd() local
411 if (devpriv->ai_cmd_running) in pcl816_ai_cmd()
412 return -EBUSY; in pcl816_ai_cmd()
414 seglen = check_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len); in pcl816_ai_cmd()
416 return -EINVAL; in pcl816_ai_cmd()
417 pcl816_ai_setup_chanlist(dev, cmd->chanlist, seglen); in pcl816_ai_cmd()
420 devpriv->ai_cmd_running = 1; in pcl816_ai_cmd()
421 devpriv->ai_poll_ptr = 0; in pcl816_ai_cmd()
422 devpriv->ai_cmd_canceled = 0; in pcl816_ai_cmd()
425 dma->cur_dma = 0; in pcl816_ai_cmd()
428 comedi_8254_set_mode(dev->pacer, 0, I8254_MODE1 | I8254_BINARY); in pcl816_ai_cmd()
429 comedi_8254_write(dev->pacer, 0, 0x0ff); in pcl816_ai_cmd()
431 comedi_8254_update_divisors(dev->pacer); in pcl816_ai_cmd()
432 comedi_8254_pacer_enable(dev->pacer, 1, 2, true); in pcl816_ai_cmd()
434 ctrl = PCL816_CTRL_INTEN | PCL816_CTRL_DMAEN | in pcl816_ai_cmd()
436 if (cmd->convert_src == TRIG_TIMER) in pcl816_ai_cmd()
437 ctrl |= PCL816_CTRL_PACER_TRIG; in pcl816_ai_cmd()
439 ctrl |= PCL816_CTRL_EXT_TRIG; in pcl816_ai_cmd()
441 outb(ctrl, dev->iobase + PCL816_CTRL_REG); in pcl816_ai_cmd()
442 outb((dma->chan << 4) | dev->irq, in pcl816_ai_cmd()
443 dev->iobase + PCL816_STATUS_REG); in pcl816_ai_cmd()
450 struct pcl816_private *devpriv = dev->private; in pcl816_ai_poll()
451 struct comedi_isadma *dma = devpriv->dma; in pcl816_ai_poll()
457 spin_lock_irqsave(&dev->spinlock, flags); in pcl816_ai_poll()
461 if (poll > devpriv->ai_poll_ptr) { in pcl816_ai_poll()
462 desc = &dma->desc[dma->cur_dma]; in pcl816_ai_poll()
463 transfer_from_dma_buf(dev, s, desc->virt_addr, in pcl816_ai_poll()
464 devpriv->ai_poll_ptr, in pcl816_ai_poll()
465 poll - devpriv->ai_poll_ptr); in pcl816_ai_poll()
467 devpriv->ai_poll_ptr = poll; in pcl816_ai_poll()
476 spin_unlock_irqrestore(&dev->spinlock, flags); in pcl816_ai_poll()
484 struct pcl816_private *devpriv = dev->private; in pcl816_ai_cancel()
486 if (!devpriv->ai_cmd_running) in pcl816_ai_cancel()
489 outb(0, dev->iobase + PCL816_CTRL_REG); in pcl816_ai_cancel()
492 comedi_8254_pacer_enable(dev->pacer, 1, 2, false); in pcl816_ai_cancel()
494 devpriv->ai_cmd_running = 0; in pcl816_ai_cancel()
495 devpriv->ai_cmd_canceled = 1; in pcl816_ai_cancel()
505 unsigned int chan = CR_CHAN(insn->chanspec); in pcl816_ai_insn_read()
506 unsigned int range = CR_RANGE(insn->chanspec); in pcl816_ai_insn_read()
510 outb(PCL816_CTRL_SOFT_TRIG, dev->iobase + PCL816_CTRL_REG); in pcl816_ai_insn_read()
515 for (i = 0; i < insn->n; i++) { in pcl816_ai_insn_read()
525 outb(0, dev->iobase + PCL816_CTRL_REG); in pcl816_ai_insn_read()
528 return ret ? ret : insn->n; in pcl816_ai_insn_read()
536 data[1] = inb(dev->iobase + PCL816_DO_DI_LSB_REG) | in pcl816_di_insn_bits()
537 (inb(dev->iobase + PCL816_DO_DI_MSB_REG) << 8); in pcl816_di_insn_bits()
539 return insn->n; in pcl816_di_insn_bits()
548 outb(s->state & 0xff, dev->iobase + PCL816_DO_DI_LSB_REG); in pcl816_do_insn_bits()
549 outb((s->state >> 8), dev->iobase + PCL816_DO_DI_MSB_REG); in pcl816_do_insn_bits()
552 data[1] = s->state; in pcl816_do_insn_bits()
554 return insn->n; in pcl816_do_insn_bits()
559 outb(0, dev->iobase + PCL816_CTRL_REG); in pcl816_reset()
564 outb(0, dev->iobase + PCL816_DO_DI_LSB_REG); in pcl816_reset()
565 outb(0, dev->iobase + PCL816_DO_DI_MSB_REG); in pcl816_reset()
571 struct pcl816_private *devpriv = dev->private; in pcl816_alloc_irq_and_dma()
572 unsigned int irq_num = it->options[1]; in pcl816_alloc_irq_and_dma()
573 unsigned int dma_chan = it->options[2]; in pcl816_alloc_irq_and_dma()
575 /* only IRQs 2-7 and DMA channels 3 and 1 are valid */ in pcl816_alloc_irq_and_dma()
580 if (request_irq(irq_num, pcl816_interrupt, 0, dev->board_name, dev)) in pcl816_alloc_irq_and_dma()
584 devpriv->dma = comedi_isadma_alloc(dev, 2, dma_chan, dma_chan, in pcl816_alloc_irq_and_dma()
586 if (!devpriv->dma) in pcl816_alloc_irq_and_dma()
589 dev->irq = irq_num; in pcl816_alloc_irq_and_dma()
594 struct pcl816_private *devpriv = dev->private; in pcl816_free_dma()
597 comedi_isadma_free(devpriv->dma); in pcl816_free_dma()
602 const struct pcl816_board *board = dev->board_ptr; in pcl816_attach()
609 return -ENOMEM; in pcl816_attach()
611 ret = comedi_request_region(dev, it->options[0], 0x10); in pcl816_attach()
618 dev->pacer = comedi_8254_io_alloc(dev->iobase + PCL816_TIMER_BASE, in pcl816_attach()
620 if (IS_ERR(dev->pacer)) in pcl816_attach()
621 return PTR_ERR(dev->pacer); in pcl816_attach()
627 s = &dev->subdevices[0]; in pcl816_attach()
628 s->type = COMEDI_SUBD_AI; in pcl816_attach()
629 s->subdev_flags = SDF_CMD_READ | SDF_DIFF; in pcl816_attach()
630 s->n_chan = 16; in pcl816_attach()
631 s->maxdata = board->ai_maxdata; in pcl816_attach()
632 s->range_table = &range_pcl816; in pcl816_attach()
633 s->insn_read = pcl816_ai_insn_read; in pcl816_attach()
634 if (dev->irq) { in pcl816_attach()
635 dev->read_subdev = s; in pcl816_attach()
636 s->subdev_flags |= SDF_CMD_READ; in pcl816_attach()
637 s->len_chanlist = board->ai_chanlist; in pcl816_attach()
638 s->do_cmdtest = pcl816_ai_cmdtest; in pcl816_attach()
639 s->do_cmd = pcl816_ai_cmd; in pcl816_attach()
640 s->poll = pcl816_ai_poll; in pcl816_attach()
641 s->cancel = pcl816_ai_cancel; in pcl816_attach()
645 s = &dev->subdevices[1]; in pcl816_attach()
646 s->type = COMEDI_SUBD_UNUSED; in pcl816_attach()
649 s = &dev->subdevices[2]; in pcl816_attach()
650 s->type = COMEDI_SUBD_DI; in pcl816_attach()
651 s->subdev_flags = SDF_READABLE; in pcl816_attach()
652 s->n_chan = 16; in pcl816_attach()
653 s->maxdata = 1; in pcl816_attach()
654 s->range_table = &range_digital; in pcl816_attach()
655 s->insn_bits = pcl816_di_insn_bits; in pcl816_attach()
658 s = &dev->subdevices[3]; in pcl816_attach()
659 s->type = COMEDI_SUBD_DO; in pcl816_attach()
660 s->subdev_flags = SDF_WRITABLE; in pcl816_attach()
661 s->n_chan = 16; in pcl816_attach()
662 s->maxdata = 1; in pcl816_attach()
663 s->range_table = &range_digital; in pcl816_attach()
664 s->insn_bits = pcl816_do_insn_bits; in pcl816_attach()
673 if (dev->private) { in pcl816_detach()
674 pcl816_ai_cancel(dev, dev->read_subdev); in pcl816_detach()
693 MODULE_DESCRIPTION("Comedi low-level driver");