aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/comedi/drivers/addi_apci_3xxx.c
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2021-04-14 10:58:10 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2021-04-15 09:26:25 +0200
commit8ffdff6a8cfbdc174a3a390b6f825a277b5bb895 (patch)
tree10d8b8e9a98ca6dbcff017ef9ab0767ddcf30214 /drivers/staging/comedi/drivers/addi_apci_3xxx.c
parentstaging: rtl8723bs: remove sdio_drv_priv structure (diff)
downloadlinux-dev-8ffdff6a8cfbdc174a3a390b6f825a277b5bb895.tar.xz
linux-dev-8ffdff6a8cfbdc174a3a390b6f825a277b5bb895.zip
staging: comedi: move out of staging directory
The comedi code came into the kernel back in 2008, but traces its lifetime to much much earlier. It's been polished and buffed and there's really nothing preventing it from being part of the "real" portion of the kernel. So move it to drivers/comedi/ as it belongs there. Many thanks to the hundreds of developers who did the work to make this happen. Cc: Ian Abbott <abbotti@mev.co.uk> Cc: H Hartley Sweeten <hsweeten@visionengravers.com> Link: https://lore.kernel.org/r/YHauop4u3sP6lz8j@kroah.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging/comedi/drivers/addi_apci_3xxx.c')
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3xxx.c961
1 files changed, 0 insertions, 961 deletions
diff --git a/drivers/staging/comedi/drivers/addi_apci_3xxx.c b/drivers/staging/comedi/drivers/addi_apci_3xxx.c
deleted file mode 100644
index a90d59377e18..000000000000
--- a/drivers/staging/comedi/drivers/addi_apci_3xxx.c
+++ /dev/null
@@ -1,961 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * addi_apci_3xxx.c
- * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
- * Project manager: S. Weber
- *
- * ADDI-DATA GmbH
- * Dieselstrasse 3
- * D-77833 Ottersweier
- * Tel: +19(0)7223/9493-0
- * Fax: +49(0)7223/9493-92
- * http://www.addi-data.com
- * info@addi-data.com
- */
-
-#include <linux/module.h>
-#include <linux/interrupt.h>
-
-#include "../comedi_pci.h"
-
-#define CONV_UNIT_NS BIT(0)
-#define CONV_UNIT_US BIT(1)
-#define CONV_UNIT_MS BIT(2)
-
-static const struct comedi_lrange apci3xxx_ai_range = {
- 8, {
- BIP_RANGE(10),
- BIP_RANGE(5),
- BIP_RANGE(2),
- BIP_RANGE(1),
- UNI_RANGE(10),
- UNI_RANGE(5),
- UNI_RANGE(2),
- UNI_RANGE(1)
- }
-};
-
-static const struct comedi_lrange apci3xxx_ao_range = {
- 2, {
- BIP_RANGE(10),
- UNI_RANGE(10)
- }
-};
-
-enum apci3xxx_boardid {
- BOARD_APCI3000_16,
- BOARD_APCI3000_8,
- BOARD_APCI3000_4,
- BOARD_APCI3006_16,
- BOARD_APCI3006_8,
- BOARD_APCI3006_4,
- BOARD_APCI3010_16,
- BOARD_APCI3010_8,
- BOARD_APCI3010_4,
- BOARD_APCI3016_16,
- BOARD_APCI3016_8,
- BOARD_APCI3016_4,
- BOARD_APCI3100_16_4,
- BOARD_APCI3100_8_4,
- BOARD_APCI3106_16_4,
- BOARD_APCI3106_8_4,
- BOARD_APCI3110_16_4,
- BOARD_APCI3110_8_4,
- BOARD_APCI3116_16_4,
- BOARD_APCI3116_8_4,
- BOARD_APCI3003,
- BOARD_APCI3002_16,
- BOARD_APCI3002_8,
- BOARD_APCI3002_4,
- BOARD_APCI3500,
-};
-
-struct apci3xxx_boardinfo {
- const char *name;
- int ai_subdev_flags;
- int ai_n_chan;
- unsigned int ai_maxdata;
- unsigned char ai_conv_units;
- unsigned int ai_min_acq_ns;
- unsigned int has_ao:1;
- unsigned int has_dig_in:1;
- unsigned int has_dig_out:1;
- unsigned int has_ttl_io:1;
-};
-
-static const struct apci3xxx_boardinfo apci3xxx_boardtypes[] = {
- [BOARD_APCI3000_16] = {
- .name = "apci3000-16",
- .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF,
- .ai_n_chan = 16,
- .ai_maxdata = 0x0fff,
- .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US,
- .ai_min_acq_ns = 10000,
- .has_ttl_io = 1,
- },
- [BOARD_APCI3000_8] = {
- .name = "apci3000-8",
- .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF,
- .ai_n_chan = 8,
- .ai_maxdata = 0x0fff,
- .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US,
- .ai_min_acq_ns = 10000,
- .has_ttl_io = 1,
- },
- [BOARD_APCI3000_4] = {
- .name = "apci3000-4",
- .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF,
- .ai_n_chan = 4,
- .ai_maxdata = 0x0fff,
- .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US,
- .ai_min_acq_ns = 10000,
- .has_ttl_io = 1,
- },
- [BOARD_APCI3006_16] = {
- .name = "apci3006-16",
- .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF,
- .ai_n_chan = 16,
- .ai_maxdata = 0xffff,
- .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US,
- .ai_min_acq_ns = 10000,
- .has_ttl_io = 1,
- },
- [BOARD_APCI3006_8] = {
- .name = "apci3006-8",
- .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF,
- .ai_n_chan = 8,
- .ai_maxdata = 0xffff,
- .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US,
- .ai_min_acq_ns = 10000,
- .has_ttl_io = 1,
- },
- [BOARD_APCI3006_4] = {
- .name = "apci3006-4",
- .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF,
- .ai_n_chan = 4,
- .ai_maxdata = 0xffff,
- .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US,
- .ai_min_acq_ns = 10000,
- .has_ttl_io = 1,
- },
- [BOARD_APCI3010_16] = {
- .name = "apci3010-16",
- .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF,
- .ai_n_chan = 16,
- .ai_maxdata = 0x0fff,
- .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US,
- .ai_min_acq_ns = 5000,
- .has_dig_in = 1,
- .has_dig_out = 1,
- .has_ttl_io = 1,
- },
- [BOARD_APCI3010_8] = {
- .name = "apci3010-8",
- .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF,
- .ai_n_chan = 8,
- .ai_maxdata = 0x0fff,
- .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US,
- .ai_min_acq_ns = 5000,
- .has_dig_in = 1,
- .has_dig_out = 1,
- .has_ttl_io = 1,
- },
- [BOARD_APCI3010_4] = {
- .name = "apci3010-4",
- .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF,
- .ai_n_chan = 4,
- .ai_maxdata = 0x0fff,
- .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US,
- .ai_min_acq_ns = 5000,
- .has_dig_in = 1,
- .has_dig_out = 1,
- .has_ttl_io = 1,
- },
- [BOARD_APCI3016_16] = {
- .name = "apci3016-16",
- .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF,
- .ai_n_chan = 16,
- .ai_maxdata = 0xffff,
- .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US,
- .ai_min_acq_ns = 5000,
- .has_dig_in = 1,
- .has_dig_out = 1,
- .has_ttl_io = 1,
- },
- [BOARD_APCI3016_8] = {
- .name = "apci3016-8",
- .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF,
- .ai_n_chan = 8,
- .ai_maxdata = 0xffff,
- .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US,
- .ai_min_acq_ns = 5000,
- .has_dig_in = 1,
- .has_dig_out = 1,
- .has_ttl_io = 1,
- },
- [BOARD_APCI3016_4] = {
- .name = "apci3016-4",
- .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF,
- .ai_n_chan = 4,
- .ai_maxdata = 0xffff,
- .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US,
- .ai_min_acq_ns = 5000,
- .has_dig_in = 1,
- .has_dig_out = 1,
- .has_ttl_io = 1,
- },
- [BOARD_APCI3100_16_4] = {
- .name = "apci3100-16-4",
- .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF,
- .ai_n_chan = 16,
- .ai_maxdata = 0x0fff,
- .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US,
- .ai_min_acq_ns = 10000,
- .has_ao = 1,
- .has_ttl_io = 1,
- },
- [BOARD_APCI3100_8_4] = {
- .name = "apci3100-8-4",
- .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF,
- .ai_n_chan = 8,
- .ai_maxdata = 0x0fff,
- .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US,
- .ai_min_acq_ns = 10000,
- .has_ao = 1,
- .has_ttl_io = 1,
- },
- [BOARD_APCI3106_16_4] = {
- .name = "apci3106-16-4",
- .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF,
- .ai_n_chan = 16,
- .ai_maxdata = 0xffff,
- .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US,
- .ai_min_acq_ns = 10000,
- .has_ao = 1,
- .has_ttl_io = 1,
- },
- [BOARD_APCI3106_8_4] = {
- .name = "apci3106-8-4",
- .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF,
- .ai_n_chan = 8,
- .ai_maxdata = 0xffff,
- .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US,
- .ai_min_acq_ns = 10000,
- .has_ao = 1,
- .has_ttl_io = 1,
- },
- [BOARD_APCI3110_16_4] = {
- .name = "apci3110-16-4",
- .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF,
- .ai_n_chan = 16,
- .ai_maxdata = 0x0fff,
- .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US,
- .ai_min_acq_ns = 5000,
- .has_ao = 1,
- .has_dig_in = 1,
- .has_dig_out = 1,
- .has_ttl_io = 1,
- },
- [BOARD_APCI3110_8_4] = {
- .name = "apci3110-8-4",
- .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF,
- .ai_n_chan = 8,
- .ai_maxdata = 0x0fff,
- .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US,
- .ai_min_acq_ns = 5000,
- .has_ao = 1,
- .has_dig_in = 1,
- .has_dig_out = 1,
- .has_ttl_io = 1,
- },
- [BOARD_APCI3116_16_4] = {
- .name = "apci3116-16-4",
- .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF,
- .ai_n_chan = 16,
- .ai_maxdata = 0xffff,
- .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US,
- .ai_min_acq_ns = 5000,
- .has_ao = 1,
- .has_dig_in = 1,
- .has_dig_out = 1,
- .has_ttl_io = 1,
- },
- [BOARD_APCI3116_8_4] = {
- .name = "apci3116-8-4",
- .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF,
- .ai_n_chan = 8,
- .ai_maxdata = 0xffff,
- .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US,
- .ai_min_acq_ns = 5000,
- .has_ao = 1,
- .has_dig_in = 1,
- .has_dig_out = 1,
- .has_ttl_io = 1,
- },
- [BOARD_APCI3003] = {
- .name = "apci3003",
- .ai_subdev_flags = SDF_DIFF,
- .ai_n_chan = 4,
- .ai_maxdata = 0xffff,
- .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US |
- CONV_UNIT_NS,
- .ai_min_acq_ns = 2500,
- .has_dig_in = 1,
- .has_dig_out = 1,
- },
- [BOARD_APCI3002_16] = {
- .name = "apci3002-16",
- .ai_subdev_flags = SDF_DIFF,
- .ai_n_chan = 16,
- .ai_maxdata = 0xffff,
- .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US,
- .ai_min_acq_ns = 5000,
- .has_dig_in = 1,
- .has_dig_out = 1,
- },
- [BOARD_APCI3002_8] = {
- .name = "apci3002-8",
- .ai_subdev_flags = SDF_DIFF,
- .ai_n_chan = 8,
- .ai_maxdata = 0xffff,
- .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US,
- .ai_min_acq_ns = 5000,
- .has_dig_in = 1,
- .has_dig_out = 1,
- },
- [BOARD_APCI3002_4] = {
- .name = "apci3002-4",
- .ai_subdev_flags = SDF_DIFF,
- .ai_n_chan = 4,
- .ai_maxdata = 0xffff,
- .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US,
- .ai_min_acq_ns = 5000,
- .has_dig_in = 1,
- .has_dig_out = 1,
- },
- [BOARD_APCI3500] = {
- .name = "apci3500",
- .has_ao = 1,
- .has_ttl_io = 1,
- },
-};
-
-struct apci3xxx_private {
- unsigned int ai_timer;
- unsigned char ai_time_base;
-};
-
-static irqreturn_t apci3xxx_irq_handler(int irq, void *d)
-{
- struct comedi_device *dev = d;
- struct comedi_subdevice *s = dev->read_subdev;
- unsigned int status;
- unsigned int val;
-
- /* Test if interrupt occur */
- status = readl(dev->mmio + 16);
- if ((status & 0x2) == 0x2) {
- /* Reset the interrupt */
- writel(status, dev->mmio + 16);
-
- val = readl(dev->mmio + 28);
- comedi_buf_write_samples(s, &val, 1);
-
- s->async->events |= COMEDI_CB_EOA;
- comedi_handle_events(dev, s);
-
- return IRQ_HANDLED;
- }
- return IRQ_NONE;
-}
-
-static int apci3xxx_ai_started(struct comedi_device *dev)
-{
- if ((readl(dev->mmio + 8) & 0x80000) == 0x80000)
- return 1;
-
- return 0;
-}
-
-static int apci3xxx_ai_setup(struct comedi_device *dev, unsigned int chanspec)
-{
- unsigned int chan = CR_CHAN(chanspec);
- unsigned int range = CR_RANGE(chanspec);
- unsigned int aref = CR_AREF(chanspec);
- unsigned int delay_mode;
- unsigned int val;
-
- if (apci3xxx_ai_started(dev))
- return -EBUSY;
-
- /* Clear the FIFO */
- writel(0x10000, dev->mmio + 12);
-
- /* Get and save the delay mode */
- delay_mode = readl(dev->mmio + 4);
- delay_mode &= 0xfffffef0;
-
- /* Channel configuration selection */
- writel(delay_mode, dev->mmio + 4);
-
- /* Make the configuration */
- val = (range & 3) | ((range >> 2) << 6) |
- ((aref == AREF_DIFF) << 7);
- writel(val, dev->mmio + 0);
-
- /* Channel selection */
- writel(delay_mode | 0x100, dev->mmio + 4);
- writel(chan, dev->mmio + 0);
-
- /* Restore delay mode */
- writel(delay_mode, dev->mmio + 4);
-
- /* Set the number of sequence to 1 */
- writel(1, dev->mmio + 48);
-
- return 0;
-}
-
-static int apci3xxx_ai_eoc(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned long context)
-{
- unsigned int status;
-
- status = readl(dev->mmio + 20);
- if (status & 0x1)
- return 0;
- return -EBUSY;
-}
-
-static int apci3xxx_ai_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- int ret;
- int i;
-
- ret = apci3xxx_ai_setup(dev, insn->chanspec);
- if (ret)
- return ret;
-
- for (i = 0; i < insn->n; i++) {
- /* Start the conversion */
- writel(0x80000, dev->mmio + 8);
-
- /* Wait the EOS */
- ret = comedi_timeout(dev, s, insn, apci3xxx_ai_eoc, 0);
- if (ret)
- return ret;
-
- /* Read the analog value */
- data[i] = readl(dev->mmio + 28);
- }
-
- return insn->n;
-}
-
-static int apci3xxx_ai_ns_to_timer(struct comedi_device *dev,
- unsigned int *ns, unsigned int flags)
-{
- const struct apci3xxx_boardinfo *board = dev->board_ptr;
- struct apci3xxx_private *devpriv = dev->private;
- unsigned int base;
- unsigned int timer;
- int time_base;
-
- /* time_base: 0 = ns, 1 = us, 2 = ms */
- for (time_base = 0; time_base < 3; time_base++) {
- /* skip unsupported time bases */
- if (!(board->ai_conv_units & (1 << time_base)))
- continue;
-
- switch (time_base) {
- case 0:
- base = 1;
- break;
- case 1:
- base = 1000;
- break;
- case 2:
- base = 1000000;
- break;
- }
-
- switch (flags & CMDF_ROUND_MASK) {
- case CMDF_ROUND_NEAREST:
- default:
- timer = DIV_ROUND_CLOSEST(*ns, base);
- break;
- case CMDF_ROUND_DOWN:
- timer = *ns / base;
- break;
- case CMDF_ROUND_UP:
- timer = DIV_ROUND_UP(*ns, base);
- break;
- }
-
- if (timer < 0x10000) {
- devpriv->ai_time_base = time_base;
- devpriv->ai_timer = timer;
- *ns = timer * time_base;
- return 0;
- }
- }
- return -EINVAL;
-}
-
-static int apci3xxx_ai_cmdtest(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_cmd *cmd)
-{
- const struct apci3xxx_boardinfo *board = dev->board_ptr;
- int err = 0;
- unsigned int arg;
-
- /* 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_FOLLOW);
- err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
- err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
- err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
-
- if (err)
- return 1;
-
- /* Step 2a : make sure trigger sources are unique */
-
- err |= comedi_check_trigger_is_unique(cmd->stop_src);
-
- /* Step 2b : and mutually compatible */
-
- if (err)
- return 2;
-
- /* 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_min(&cmd->convert_arg,
- board->ai_min_acq_ns);
- err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
- cmd->chanlist_len);
-
- if (cmd->stop_src == TRIG_COUNT)
- err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
- else /* TRIG_NONE */
- err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
-
- if (err)
- return 3;
-
- /* step 4: fix up any arguments */
-
- arg = cmd->convert_arg;
- err |= apci3xxx_ai_ns_to_timer(dev, &arg, cmd->flags);
- err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
-
- if (err)
- return 4;
-
- return 0;
-}
-
-static int apci3xxx_ai_cmd(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- struct apci3xxx_private *devpriv = dev->private;
- struct comedi_cmd *cmd = &s->async->cmd;
- int ret;
-
- ret = apci3xxx_ai_setup(dev, cmd->chanlist[0]);
- if (ret)
- return ret;
-
- /* Set the convert timing unit */
- writel(devpriv->ai_time_base, dev->mmio + 36);
-
- /* Set the convert timing */
- writel(devpriv->ai_timer, dev->mmio + 32);
-
- /* Start the conversion */
- writel(0x180000, dev->mmio + 8);
-
- return 0;
-}
-
-static int apci3xxx_ai_cancel(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- return 0;
-}
-
-static int apci3xxx_ao_eoc(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned long context)
-{
- unsigned int status;
-
- status = readl(dev->mmio + 96);
- if (status & 0x100)
- return 0;
- return -EBUSY;
-}
-
-static int apci3xxx_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 ret;
- int i;
-
- for (i = 0; i < insn->n; i++) {
- unsigned int val = data[i];
-
- /* Set the range selection */
- writel(range, dev->mmio + 96);
-
- /* Write the analog value to the selected channel */
- writel((val << 8) | chan, dev->mmio + 100);
-
- /* Wait the end of transfer */
- ret = comedi_timeout(dev, s, insn, apci3xxx_ao_eoc, 0);
- if (ret)
- return ret;
-
- s->readback[chan] = val;
- }
-
- return insn->n;
-}
-
-static int apci3xxx_di_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- data[1] = inl(dev->iobase + 32) & 0xf;
-
- return insn->n;
-}
-
-static int apci3xxx_do_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- s->state = inl(dev->iobase + 48) & 0xf;
-
- if (comedi_dio_update_state(s, data))
- outl(s->state, dev->iobase + 48);
-
- data[1] = s->state;
-
- return insn->n;
-}
-
-static int apci3xxx_dio_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- unsigned int chan = CR_CHAN(insn->chanspec);
- unsigned int mask = 0;
- int ret;
-
- /*
- * Port 0 (channels 0-7) are always inputs
- * Port 1 (channels 8-15) are always outputs
- * Port 2 (channels 16-23) are programmable i/o
- */
- if (data[0] != INSN_CONFIG_DIO_QUERY) {
- /* ignore all other instructions for ports 0 and 1 */
- if (chan < 16)
- return -EINVAL;
-
- /* changing any channel in port 2 changes the entire port */
- mask = 0xff0000;
- }
-
- ret = comedi_dio_insn_config(dev, s, insn, data, mask);
- if (ret)
- return ret;
-
- /* update port 2 configuration */
- outl((s->io_bits >> 24) & 0xff, dev->iobase + 224);
-
- return insn->n;
-}
-
-static int apci3xxx_dio_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- unsigned int mask;
- unsigned int val;
-
- mask = comedi_dio_update_state(s, data);
- if (mask) {
- if (mask & 0xff)
- outl(s->state & 0xff, dev->iobase + 80);
- if (mask & 0xff0000)
- outl((s->state >> 16) & 0xff, dev->iobase + 112);
- }
-
- val = inl(dev->iobase + 80);
- val |= (inl(dev->iobase + 64) << 8);
- if (s->io_bits & 0xff0000)
- val |= (inl(dev->iobase + 112) << 16);
- else
- val |= (inl(dev->iobase + 96) << 16);
-
- data[1] = val;
-
- return insn->n;
-}
-
-static int apci3xxx_reset(struct comedi_device *dev)
-{
- unsigned int val;
- int i;
-
- /* Disable the interrupt */
- disable_irq(dev->irq);
-
- /* Clear the start command */
- writel(0, dev->mmio + 8);
-
- /* Reset the interrupt flags */
- val = readl(dev->mmio + 16);
- writel(val, dev->mmio + 16);
-
- /* clear the EOS */
- readl(dev->mmio + 20);
-
- /* Clear the FIFO */
- for (i = 0; i < 16; i++)
- val = readl(dev->mmio + 28);
-
- /* Enable the interrupt */
- enable_irq(dev->irq);
-
- return 0;
-}
-
-static int apci3xxx_auto_attach(struct comedi_device *dev,
- unsigned long context)
-{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- const struct apci3xxx_boardinfo *board = NULL;
- struct apci3xxx_private *devpriv;
- struct comedi_subdevice *s;
- int n_subdevices;
- int subdev;
- int ret;
-
- if (context < ARRAY_SIZE(apci3xxx_boardtypes))
- board = &apci3xxx_boardtypes[context];
- if (!board)
- return -ENODEV;
- dev->board_ptr = board;
- dev->board_name = board->name;
-
- devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
- if (!devpriv)
- return -ENOMEM;
-
- ret = comedi_pci_enable(dev);
- if (ret)
- return ret;
-
- dev->iobase = pci_resource_start(pcidev, 2);
- dev->mmio = pci_ioremap_bar(pcidev, 3);
- if (!dev->mmio)
- return -ENOMEM;
-
- if (pcidev->irq > 0) {
- ret = request_irq(pcidev->irq, apci3xxx_irq_handler,
- IRQF_SHARED, dev->board_name, dev);
- if (ret == 0)
- dev->irq = pcidev->irq;
- }
-
- n_subdevices = (board->ai_n_chan ? 0 : 1) + board->has_ao +
- board->has_dig_in + board->has_dig_out +
- board->has_ttl_io;
- ret = comedi_alloc_subdevices(dev, n_subdevices);
- if (ret)
- return ret;
-
- subdev = 0;
-
- /* Analog Input subdevice */
- if (board->ai_n_chan) {
- s = &dev->subdevices[subdev];
- s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE | board->ai_subdev_flags;
- s->n_chan = board->ai_n_chan;
- s->maxdata = board->ai_maxdata;
- s->range_table = &apci3xxx_ai_range;
- s->insn_read = apci3xxx_ai_insn_read;
- if (dev->irq) {
- /*
- * FIXME: The hardware supports multiple scan modes
- * but the original addi-data driver only supported
- * reading a single channel with interrupts. Need a
- * proper datasheet to fix this.
- *
- * The following scan modes are supported by the
- * hardware:
- * 1) Single software scan
- * 2) Single hardware triggered scan
- * 3) Continuous software scan
- * 4) Continuous software scan with timer delay
- * 5) Continuous hardware triggered scan
- * 6) Continuous hardware triggered scan with timer
- * delay
- *
- * For now, limit the chanlist to a single channel.
- */
- dev->read_subdev = s;
- s->subdev_flags |= SDF_CMD_READ;
- s->len_chanlist = 1;
- s->do_cmdtest = apci3xxx_ai_cmdtest;
- s->do_cmd = apci3xxx_ai_cmd;
- s->cancel = apci3xxx_ai_cancel;
- }
-
- subdev++;
- }
-
- /* Analog Output subdevice */
- if (board->has_ao) {
- s = &dev->subdevices[subdev];
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
- s->n_chan = 4;
- s->maxdata = 0x0fff;
- s->range_table = &apci3xxx_ao_range;
- s->insn_write = apci3xxx_ao_insn_write;
-
- ret = comedi_alloc_subdev_readback(s);
- if (ret)
- return ret;
-
- subdev++;
- }
-
- /* Digital Input subdevice */
- if (board->has_dig_in) {
- s = &dev->subdevices[subdev];
- s->type = COMEDI_SUBD_DI;
- s->subdev_flags = SDF_READABLE;
- s->n_chan = 4;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_bits = apci3xxx_di_insn_bits;
-
- subdev++;
- }
-
- /* Digital Output subdevice */
- if (board->has_dig_out) {
- s = &dev->subdevices[subdev];
- s->type = COMEDI_SUBD_DO;
- s->subdev_flags = SDF_WRITABLE;
- s->n_chan = 4;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_bits = apci3xxx_do_insn_bits;
-
- subdev++;
- }
-
- /* TTL Digital I/O subdevice */
- if (board->has_ttl_io) {
- s = &dev->subdevices[subdev];
- s->type = COMEDI_SUBD_DIO;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = 24;
- s->maxdata = 1;
- s->io_bits = 0xff; /* channels 0-7 are always outputs */
- s->range_table = &range_digital;
- s->insn_config = apci3xxx_dio_insn_config;
- s->insn_bits = apci3xxx_dio_insn_bits;
-
- subdev++;
- }
-
- apci3xxx_reset(dev);
- return 0;
-}
-
-static void apci3xxx_detach(struct comedi_device *dev)
-{
- if (dev->iobase)
- apci3xxx_reset(dev);
- comedi_pci_detach(dev);
-}
-
-static struct comedi_driver apci3xxx_driver = {
- .driver_name = "addi_apci_3xxx",
- .module = THIS_MODULE,
- .auto_attach = apci3xxx_auto_attach,
- .detach = apci3xxx_detach,
-};
-
-static int apci3xxx_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *id)
-{
- return comedi_pci_auto_config(dev, &apci3xxx_driver, id->driver_data);
-}
-
-static const struct pci_device_id apci3xxx_pci_table[] = {
- { PCI_VDEVICE(ADDIDATA, 0x3010), BOARD_APCI3000_16 },
- { PCI_VDEVICE(ADDIDATA, 0x300f), BOARD_APCI3000_8 },
- { PCI_VDEVICE(ADDIDATA, 0x300e), BOARD_APCI3000_4 },
- { PCI_VDEVICE(ADDIDATA, 0x3013), BOARD_APCI3006_16 },
- { PCI_VDEVICE(ADDIDATA, 0x3014), BOARD_APCI3006_8 },
- { PCI_VDEVICE(ADDIDATA, 0x3015), BOARD_APCI3006_4 },
- { PCI_VDEVICE(ADDIDATA, 0x3016), BOARD_APCI3010_16 },
- { PCI_VDEVICE(ADDIDATA, 0x3017), BOARD_APCI3010_8 },
- { PCI_VDEVICE(ADDIDATA, 0x3018), BOARD_APCI3010_4 },
- { PCI_VDEVICE(ADDIDATA, 0x3019), BOARD_APCI3016_16 },
- { PCI_VDEVICE(ADDIDATA, 0x301a), BOARD_APCI3016_8 },
- { PCI_VDEVICE(ADDIDATA, 0x301b), BOARD_APCI3016_4 },
- { PCI_VDEVICE(ADDIDATA, 0x301c), BOARD_APCI3100_16_4 },
- { PCI_VDEVICE(ADDIDATA, 0x301d), BOARD_APCI3100_8_4 },
- { PCI_VDEVICE(ADDIDATA, 0x301e), BOARD_APCI3106_16_4 },
- { PCI_VDEVICE(ADDIDATA, 0x301f), BOARD_APCI3106_8_4 },
- { PCI_VDEVICE(ADDIDATA, 0x3020), BOARD_APCI3110_16_4 },
- { PCI_VDEVICE(ADDIDATA, 0x3021), BOARD_APCI3110_8_4 },
- { PCI_VDEVICE(ADDIDATA, 0x3022), BOARD_APCI3116_16_4 },
- { PCI_VDEVICE(ADDIDATA, 0x3023), BOARD_APCI3116_8_4 },
- { PCI_VDEVICE(ADDIDATA, 0x300B), BOARD_APCI3003 },
- { PCI_VDEVICE(ADDIDATA, 0x3002), BOARD_APCI3002_16 },
- { PCI_VDEVICE(ADDIDATA, 0x3003), BOARD_APCI3002_8 },
- { PCI_VDEVICE(ADDIDATA, 0x3004), BOARD_APCI3002_4 },
- { PCI_VDEVICE(ADDIDATA, 0x3024), BOARD_APCI3500 },
- { 0 }
-};
-MODULE_DEVICE_TABLE(pci, apci3xxx_pci_table);
-
-static struct pci_driver apci3xxx_pci_driver = {
- .name = "addi_apci_3xxx",
- .id_table = apci3xxx_pci_table,
- .probe = apci3xxx_pci_probe,
- .remove = comedi_pci_auto_unconfig,
-};
-module_comedi_pci_driver(apci3xxx_driver, apci3xxx_pci_driver);
-
-MODULE_AUTHOR("Comedi https://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
-MODULE_LICENSE("GPL");