diff options
Diffstat (limited to 'drivers/staging/comedi/drivers/pcl726.c')
-rw-r--r-- | drivers/staging/comedi/drivers/pcl726.c | 425 |
1 files changed, 0 insertions, 425 deletions
diff --git a/drivers/staging/comedi/drivers/pcl726.c b/drivers/staging/comedi/drivers/pcl726.c deleted file mode 100644 index 88f25d7e76f7..000000000000 --- a/drivers/staging/comedi/drivers/pcl726.c +++ /dev/null @@ -1,425 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * pcl726.c - * Comedi driver for 6/12-Channel D/A Output and DIO cards - * - * COMEDI - Linux Control and Measurement Device Interface - * Copyright (C) 1998 David A. Schleef <ds@schleef.org> - */ - -/* - * Driver: pcl726 - * Description: Advantech PCL-726 & compatibles - * Author: David A. Schleef <ds@schleef.org> - * Status: untested - * Devices: [Advantech] PCL-726 (pcl726), PCL-727 (pcl727), PCL-728 (pcl728), - * [ADLink] ACL-6126 (acl6126), ACL-6128 (acl6128) - * - * Configuration Options: - * [0] - IO Base - * [1] - IRQ (ACL-6126 only) - * [2] - D/A output range for channel 0 - * [3] - D/A output range for channel 1 - * - * Boards with > 2 analog output channels: - * [4] - D/A output range for channel 2 - * [5] - D/A output range for channel 3 - * [6] - D/A output range for channel 4 - * [7] - D/A output range for channel 5 - * - * Boards with > 6 analog output channels: - * [8] - D/A output range for channel 6 - * [9] - D/A output range for channel 7 - * [10] - D/A output range for channel 8 - * [11] - D/A output range for channel 9 - * [12] - D/A output range for channel 10 - * [13] - D/A output range for channel 11 - * - * For PCL-726 the D/A output ranges are: - * 0: 0-5V, 1: 0-10V, 2: +/-5V, 3: +/-10V, 4: 4-20mA, 5: unknown - * - * For PCL-727: - * 0: 0-5V, 1: 0-10V, 2: +/-5V, 3: 4-20mA - * - * For PCL-728 and ACL-6128: - * 0: 0-5V, 1: 0-10V, 2: +/-5V, 3: +/-10V, 4: 4-20mA, 5: 0-20mA - * - * For ACL-6126: - * 0: 0-5V, 1: 0-10V, 2: +/-5V, 3: +/-10V, 4: 4-20mA - */ - -#include <linux/module.h> -#include <linux/interrupt.h> - -#include "../comedidev.h" - -#define PCL726_AO_MSB_REG(x) (0x00 + ((x) * 2)) -#define PCL726_AO_LSB_REG(x) (0x01 + ((x) * 2)) -#define PCL726_DO_MSB_REG 0x0c -#define PCL726_DO_LSB_REG 0x0d -#define PCL726_DI_MSB_REG 0x0e -#define PCL726_DI_LSB_REG 0x0f - -#define PCL727_DI_MSB_REG 0x00 -#define PCL727_DI_LSB_REG 0x01 -#define PCL727_DO_MSB_REG 0x18 -#define PCL727_DO_LSB_REG 0x19 - -static const struct comedi_lrange *const rangelist_726[] = { - &range_unipolar5, - &range_unipolar10, - &range_bipolar5, - &range_bipolar10, - &range_4_20mA, - &range_unknown -}; - -static const struct comedi_lrange *const rangelist_727[] = { - &range_unipolar5, - &range_unipolar10, - &range_bipolar5, - &range_4_20mA -}; - -static const struct comedi_lrange *const rangelist_728[] = { - &range_unipolar5, - &range_unipolar10, - &range_bipolar5, - &range_bipolar10, - &range_4_20mA, - &range_0_20mA -}; - -struct pcl726_board { - const char *name; - unsigned long io_len; - unsigned int irq_mask; - const struct comedi_lrange *const *ao_ranges; - int ao_num_ranges; - int ao_nchan; - unsigned int have_dio:1; - unsigned int is_pcl727:1; -}; - -static const struct pcl726_board pcl726_boards[] = { - { - .name = "pcl726", - .io_len = 0x10, - .ao_ranges = &rangelist_726[0], - .ao_num_ranges = ARRAY_SIZE(rangelist_726), - .ao_nchan = 6, - .have_dio = 1, - }, { - .name = "pcl727", - .io_len = 0x20, - .ao_ranges = &rangelist_727[0], - .ao_num_ranges = ARRAY_SIZE(rangelist_727), - .ao_nchan = 12, - .have_dio = 1, - .is_pcl727 = 1, - }, { - .name = "pcl728", - .io_len = 0x08, - .ao_num_ranges = ARRAY_SIZE(rangelist_728), - .ao_ranges = &rangelist_728[0], - .ao_nchan = 2, - }, { - .name = "acl6126", - .io_len = 0x10, - .irq_mask = 0x96e8, - .ao_num_ranges = ARRAY_SIZE(rangelist_726), - .ao_ranges = &rangelist_726[0], - .ao_nchan = 6, - .have_dio = 1, - }, { - .name = "acl6128", - .io_len = 0x08, - .ao_num_ranges = ARRAY_SIZE(rangelist_728), - .ao_ranges = &rangelist_728[0], - .ao_nchan = 2, - }, -}; - -struct pcl726_private { - const struct comedi_lrange *rangelist[12]; - unsigned int cmd_running:1; -}; - -static int pcl726_intr_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - data[1] = 0; - return insn->n; -} - -static int pcl726_intr_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd) -{ - int err = 0; - - /* Step 1 : check if triggers are trivially valid */ - - err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW); - err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); - err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW); - err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); - err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_NONE); - - if (err) - return 1; - - /* Step 2a : make sure trigger sources are unique */ - /* Step 2b : and mutually compatible */ - - /* Step 3: check if arguments are trivially valid */ - - err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0); - err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0); - err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0); - err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg, - cmd->chanlist_len); - err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0); - - if (err) - return 3; - - /* Step 4: fix up any arguments */ - - /* Step 5: check channel list if it exists */ - - return 0; -} - -static int pcl726_intr_cmd(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - struct pcl726_private *devpriv = dev->private; - - devpriv->cmd_running = 1; - - return 0; -} - -static int pcl726_intr_cancel(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - struct pcl726_private *devpriv = dev->private; - - devpriv->cmd_running = 0; - - return 0; -} - -static irqreturn_t pcl726_interrupt(int irq, void *d) -{ - struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->read_subdev; - struct pcl726_private *devpriv = dev->private; - - if (devpriv->cmd_running) { - unsigned short val = 0; - - pcl726_intr_cancel(dev, s); - - comedi_buf_write_samples(s, &val, 1); - comedi_handle_events(dev, s); - } - - return IRQ_HANDLED; -} - -static int pcl726_ao_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - unsigned int chan = CR_CHAN(insn->chanspec); - unsigned int range = CR_RANGE(insn->chanspec); - int i; - - for (i = 0; i < insn->n; i++) { - unsigned int val = data[i]; - - s->readback[chan] = val; - - /* bipolar data to the DAC is two's complement */ - if (comedi_chan_range_is_bipolar(s, chan, range)) - val = comedi_offset_munge(s, val); - - /* order is important, MSB then LSB */ - outb((val >> 8) & 0xff, dev->iobase + PCL726_AO_MSB_REG(chan)); - outb(val & 0xff, dev->iobase + PCL726_AO_LSB_REG(chan)); - } - - return insn->n; -} - -static int pcl726_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - const struct pcl726_board *board = dev->board_ptr; - unsigned int val; - - if (board->is_pcl727) { - val = inb(dev->iobase + PCL727_DI_LSB_REG); - val |= (inb(dev->iobase + PCL727_DI_MSB_REG) << 8); - } else { - val = inb(dev->iobase + PCL726_DI_LSB_REG); - val |= (inb(dev->iobase + PCL726_DI_MSB_REG) << 8); - } - - data[1] = val; - - return insn->n; -} - -static int pcl726_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - const struct pcl726_board *board = dev->board_ptr; - unsigned long io = dev->iobase; - unsigned int mask; - - mask = comedi_dio_update_state(s, data); - if (mask) { - if (board->is_pcl727) { - if (mask & 0x00ff) - outb(s->state & 0xff, io + PCL727_DO_LSB_REG); - if (mask & 0xff00) - outb((s->state >> 8), io + PCL727_DO_MSB_REG); - } else { - if (mask & 0x00ff) - outb(s->state & 0xff, io + PCL726_DO_LSB_REG); - if (mask & 0xff00) - outb((s->state >> 8), io + PCL726_DO_MSB_REG); - } - } - - data[1] = s->state; - - return insn->n; -} - -static int pcl726_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - const struct pcl726_board *board = dev->board_ptr; - struct pcl726_private *devpriv; - struct comedi_subdevice *s; - int subdev; - int ret; - int i; - - ret = comedi_request_region(dev, it->options[0], board->io_len); - if (ret) - return ret; - - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) - return -ENOMEM; - - /* - * Hook up the external trigger source interrupt only if the - * user config option is valid and the board supports interrupts. - */ - if (it->options[1] && (board->irq_mask & (1 << it->options[1]))) { - ret = request_irq(it->options[1], pcl726_interrupt, 0, - dev->board_name, dev); - if (ret == 0) { - /* External trigger source is from Pin-17 of CN3 */ - dev->irq = it->options[1]; - } - } - - /* setup the per-channel analog output range_table_list */ - for (i = 0; i < 12; i++) { - unsigned int opt = it->options[2 + i]; - - if (opt < board->ao_num_ranges && i < board->ao_nchan) - devpriv->rangelist[i] = board->ao_ranges[opt]; - else - devpriv->rangelist[i] = &range_unknown; - } - - subdev = board->have_dio ? 3 : 1; - if (dev->irq) - subdev++; - ret = comedi_alloc_subdevices(dev, subdev); - if (ret) - return ret; - - subdev = 0; - - /* Analog Output subdevice */ - s = &dev->subdevices[subdev++]; - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND; - s->n_chan = board->ao_nchan; - s->maxdata = 0x0fff; - s->range_table_list = devpriv->rangelist; - s->insn_write = pcl726_ao_insn_write; - - ret = comedi_alloc_subdev_readback(s); - if (ret) - return ret; - - if (board->have_dio) { - /* Digital Input subdevice */ - s = &dev->subdevices[subdev++]; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = 16; - s->maxdata = 1; - s->insn_bits = pcl726_di_insn_bits; - s->range_table = &range_digital; - - /* Digital Output subdevice */ - s = &dev->subdevices[subdev++]; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 16; - s->maxdata = 1; - s->insn_bits = pcl726_do_insn_bits; - s->range_table = &range_digital; - } - - if (dev->irq) { - /* Digital Input subdevice - Interrupt support */ - s = &dev->subdevices[subdev++]; - dev->read_subdev = s; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE | SDF_CMD_READ; - s->n_chan = 1; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = pcl726_intr_insn_bits; - s->len_chanlist = 1; - s->do_cmdtest = pcl726_intr_cmdtest; - s->do_cmd = pcl726_intr_cmd; - s->cancel = pcl726_intr_cancel; - } - - return 0; -} - -static struct comedi_driver pcl726_driver = { - .driver_name = "pcl726", - .module = THIS_MODULE, - .attach = pcl726_attach, - .detach = comedi_legacy_detach, - .board_name = &pcl726_boards[0].name, - .num_names = ARRAY_SIZE(pcl726_boards), - .offset = sizeof(struct pcl726_board), -}; -module_comedi_driver(pcl726_driver); - -MODULE_AUTHOR("Comedi https://www.comedi.org"); -MODULE_DESCRIPTION("Comedi driver for Advantech PCL-726 & compatibles"); -MODULE_LICENSE("GPL"); |