diff options
Diffstat (limited to 'drivers/staging/comedi/drivers/ii_pci20kc.c')
-rw-r--r-- | drivers/staging/comedi/drivers/ii_pci20kc.c | 524 |
1 files changed, 0 insertions, 524 deletions
diff --git a/drivers/staging/comedi/drivers/ii_pci20kc.c b/drivers/staging/comedi/drivers/ii_pci20kc.c deleted file mode 100644 index 399255dbe388..000000000000 --- a/drivers/staging/comedi/drivers/ii_pci20kc.c +++ /dev/null @@ -1,524 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * ii_pci20kc.c - * Driver for Intelligent Instruments PCI-20001C carrier board and modules. - * - * Copyright (C) 2000 Markus Kempf <kempf@matsci.uni-sb.de> - * with suggestions from David Schleef 16.06.2000 - */ - -/* - * Driver: ii_pci20kc - * Description: Intelligent Instruments PCI-20001C carrier board - * Devices: [Intelligent Instrumentation] PCI-20001C (ii_pci20kc) - * Author: Markus Kempf <kempf@matsci.uni-sb.de> - * Status: works - * - * Supports the PCI-20001C-1a and PCI-20001C-2a carrier boards. The - * -2a version has 32 on-board DIO channels. Three add-on modules - * can be added to the carrier board for additional functionality. - * - * Supported add-on modules: - * PCI-20006M-1 1 channel, 16-bit analog output module - * PCI-20006M-2 2 channel, 16-bit analog output module - * PCI-20341M-1A 4 channel, 16-bit analog input module - * - * Options: - * 0 Board base address - * 1 IRQ (not-used) - */ - -#include <linux/module.h> -#include <linux/io.h> -#include "../comedidev.h" - -/* - * Register I/O map - */ -#define II20K_SIZE 0x400 -#define II20K_MOD_OFFSET 0x100 -#define II20K_ID_REG 0x00 -#define II20K_ID_MOD1_EMPTY BIT(7) -#define II20K_ID_MOD2_EMPTY BIT(6) -#define II20K_ID_MOD3_EMPTY BIT(5) -#define II20K_ID_MASK 0x1f -#define II20K_ID_PCI20001C_1A 0x1b /* no on-board DIO */ -#define II20K_ID_PCI20001C_2A 0x1d /* on-board DIO */ -#define II20K_MOD_STATUS_REG 0x40 -#define II20K_MOD_STATUS_IRQ_MOD1 BIT(7) -#define II20K_MOD_STATUS_IRQ_MOD2 BIT(6) -#define II20K_MOD_STATUS_IRQ_MOD3 BIT(5) -#define II20K_DIO0_REG 0x80 -#define II20K_DIO1_REG 0x81 -#define II20K_DIR_ENA_REG 0x82 -#define II20K_DIR_DIO3_OUT BIT(7) -#define II20K_DIR_DIO2_OUT BIT(6) -#define II20K_BUF_DISAB_DIO3 BIT(5) -#define II20K_BUF_DISAB_DIO2 BIT(4) -#define II20K_DIR_DIO1_OUT BIT(3) -#define II20K_DIR_DIO0_OUT BIT(2) -#define II20K_BUF_DISAB_DIO1 BIT(1) -#define II20K_BUF_DISAB_DIO0 BIT(0) -#define II20K_CTRL01_REG 0x83 -#define II20K_CTRL01_SET BIT(7) -#define II20K_CTRL01_DIO0_IN BIT(4) -#define II20K_CTRL01_DIO1_IN BIT(1) -#define II20K_DIO2_REG 0xc0 -#define II20K_DIO3_REG 0xc1 -#define II20K_CTRL23_REG 0xc3 -#define II20K_CTRL23_SET BIT(7) -#define II20K_CTRL23_DIO2_IN BIT(4) -#define II20K_CTRL23_DIO3_IN BIT(1) - -#define II20K_ID_PCI20006M_1 0xe2 /* 1 AO channels */ -#define II20K_ID_PCI20006M_2 0xe3 /* 2 AO channels */ -#define II20K_AO_STRB_REG(x) (0x0b + ((x) * 0x08)) -#define II20K_AO_LSB_REG(x) (0x0d + ((x) * 0x08)) -#define II20K_AO_MSB_REG(x) (0x0e + ((x) * 0x08)) -#define II20K_AO_STRB_BOTH_REG 0x1b - -#define II20K_ID_PCI20341M_1 0x77 /* 4 AI channels */ -#define II20K_AI_STATUS_CMD_REG 0x01 -#define II20K_AI_STATUS_CMD_BUSY BIT(7) -#define II20K_AI_STATUS_CMD_HW_ENA BIT(1) -#define II20K_AI_STATUS_CMD_EXT_START BIT(0) -#define II20K_AI_LSB_REG 0x02 -#define II20K_AI_MSB_REG 0x03 -#define II20K_AI_PACER_RESET_REG 0x04 -#define II20K_AI_16BIT_DATA_REG 0x06 -#define II20K_AI_CONF_REG 0x10 -#define II20K_AI_CONF_ENA BIT(2) -#define II20K_AI_OPT_REG 0x11 -#define II20K_AI_OPT_TRIG_ENA BIT(5) -#define II20K_AI_OPT_TRIG_INV BIT(4) -#define II20K_AI_OPT_TIMEBASE(x) (((x) & 0x3) << 1) -#define II20K_AI_OPT_BURST_MODE BIT(0) -#define II20K_AI_STATUS_REG 0x12 -#define II20K_AI_STATUS_INT BIT(7) -#define II20K_AI_STATUS_TRIG BIT(6) -#define II20K_AI_STATUS_TRIG_ENA BIT(5) -#define II20K_AI_STATUS_PACER_ERR BIT(2) -#define II20K_AI_STATUS_DATA_ERR BIT(1) -#define II20K_AI_STATUS_SET_TIME_ERR BIT(0) -#define II20K_AI_LAST_CHAN_ADDR_REG 0x13 -#define II20K_AI_CUR_ADDR_REG 0x14 -#define II20K_AI_SET_TIME_REG 0x15 -#define II20K_AI_DELAY_LSB_REG 0x16 -#define II20K_AI_DELAY_MSB_REG 0x17 -#define II20K_AI_CHAN_ADV_REG 0x18 -#define II20K_AI_CHAN_RESET_REG 0x19 -#define II20K_AI_START_TRIG_REG 0x1a -#define II20K_AI_COUNT_RESET_REG 0x1b -#define II20K_AI_CHANLIST_REG 0x80 -#define II20K_AI_CHANLIST_ONBOARD_ONLY BIT(5) -#define II20K_AI_CHANLIST_GAIN(x) (((x) & 0x3) << 3) -#define II20K_AI_CHANLIST_MUX_ENA BIT(2) -#define II20K_AI_CHANLIST_CHAN(x) (((x) & 0x3) << 0) -#define II20K_AI_CHANLIST_LEN 0x80 - -/* the AO range is set by jumpers on the 20006M module */ -static const struct comedi_lrange ii20k_ao_ranges = { - 3, { - BIP_RANGE(5), /* Chan 0 - W1/W3 in Chan 1 - W2/W4 in */ - UNI_RANGE(10), /* Chan 0 - W1/W3 out Chan 1 - W2/W4 in */ - BIP_RANGE(10) /* Chan 0 - W1/W3 in Chan 1 - W2/W4 out */ - } -}; - -static const struct comedi_lrange ii20k_ai_ranges = { - 4, { - BIP_RANGE(5), /* gain 1 */ - BIP_RANGE(0.5), /* gain 10 */ - BIP_RANGE(0.05), /* gain 100 */ - BIP_RANGE(0.025) /* gain 200 */ - }, -}; - -static void __iomem *ii20k_module_iobase(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - return dev->mmio + (s->index + 1) * II20K_MOD_OFFSET; -} - -static int ii20k_ao_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - void __iomem *iobase = ii20k_module_iobase(dev, s); - unsigned int chan = CR_CHAN(insn->chanspec); - int i; - - for (i = 0; i < insn->n; i++) { - unsigned int val = data[i]; - - s->readback[chan] = val; - - /* munge the offset binary data to 2's complement */ - val = comedi_offset_munge(s, val); - - writeb(val & 0xff, iobase + II20K_AO_LSB_REG(chan)); - writeb((val >> 8) & 0xff, iobase + II20K_AO_MSB_REG(chan)); - writeb(0x00, iobase + II20K_AO_STRB_REG(chan)); - } - - return insn->n; -} - -static int ii20k_ai_eoc(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned long context) -{ - void __iomem *iobase = ii20k_module_iobase(dev, s); - unsigned char status; - - status = readb(iobase + II20K_AI_STATUS_REG); - if ((status & II20K_AI_STATUS_INT) == 0) - return 0; - return -EBUSY; -} - -static void ii20k_ai_setup(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int chanspec) -{ - void __iomem *iobase = ii20k_module_iobase(dev, s); - unsigned int chan = CR_CHAN(chanspec); - unsigned int range = CR_RANGE(chanspec); - unsigned char val; - - /* initialize module */ - writeb(II20K_AI_CONF_ENA, iobase + II20K_AI_CONF_REG); - - /* software conversion */ - writeb(0, iobase + II20K_AI_STATUS_CMD_REG); - - /* set the time base for the settling time counter based on the gain */ - val = (range < 3) ? II20K_AI_OPT_TIMEBASE(0) : II20K_AI_OPT_TIMEBASE(2); - writeb(val, iobase + II20K_AI_OPT_REG); - - /* set the settling time counter based on the gain */ - val = (range < 2) ? 0x58 : (range < 3) ? 0x93 : 0x99; - writeb(val, iobase + II20K_AI_SET_TIME_REG); - - /* set number of input channels */ - writeb(1, iobase + II20K_AI_LAST_CHAN_ADDR_REG); - - /* set the channel list byte */ - val = II20K_AI_CHANLIST_ONBOARD_ONLY | - II20K_AI_CHANLIST_MUX_ENA | - II20K_AI_CHANLIST_GAIN(range) | - II20K_AI_CHANLIST_CHAN(chan); - writeb(val, iobase + II20K_AI_CHANLIST_REG); - - /* reset settling time counter and trigger delay counter */ - writeb(0, iobase + II20K_AI_COUNT_RESET_REG); - - /* reset channel scanner */ - writeb(0, iobase + II20K_AI_CHAN_RESET_REG); -} - -static int ii20k_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - void __iomem *iobase = ii20k_module_iobase(dev, s); - int ret; - int i; - - ii20k_ai_setup(dev, s, insn->chanspec); - - for (i = 0; i < insn->n; i++) { - unsigned int val; - - /* generate a software start convert signal */ - readb(iobase + II20K_AI_PACER_RESET_REG); - - ret = comedi_timeout(dev, s, insn, ii20k_ai_eoc, 0); - if (ret) - return ret; - - val = readb(iobase + II20K_AI_LSB_REG); - val |= (readb(iobase + II20K_AI_MSB_REG) << 8); - - /* munge the 2's complement data to offset binary */ - data[i] = comedi_offset_munge(s, val); - } - - return insn->n; -} - -static void ii20k_dio_config(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - unsigned char ctrl01 = 0; - unsigned char ctrl23 = 0; - unsigned char dir_ena = 0; - - /* port 0 - channels 0-7 */ - if (s->io_bits & 0x000000ff) { - /* output port */ - ctrl01 &= ~II20K_CTRL01_DIO0_IN; - dir_ena &= ~II20K_BUF_DISAB_DIO0; - dir_ena |= II20K_DIR_DIO0_OUT; - } else { - /* input port */ - ctrl01 |= II20K_CTRL01_DIO0_IN; - dir_ena &= ~II20K_DIR_DIO0_OUT; - } - - /* port 1 - channels 8-15 */ - if (s->io_bits & 0x0000ff00) { - /* output port */ - ctrl01 &= ~II20K_CTRL01_DIO1_IN; - dir_ena &= ~II20K_BUF_DISAB_DIO1; - dir_ena |= II20K_DIR_DIO1_OUT; - } else { - /* input port */ - ctrl01 |= II20K_CTRL01_DIO1_IN; - dir_ena &= ~II20K_DIR_DIO1_OUT; - } - - /* port 2 - channels 16-23 */ - if (s->io_bits & 0x00ff0000) { - /* output port */ - ctrl23 &= ~II20K_CTRL23_DIO2_IN; - dir_ena &= ~II20K_BUF_DISAB_DIO2; - dir_ena |= II20K_DIR_DIO2_OUT; - } else { - /* input port */ - ctrl23 |= II20K_CTRL23_DIO2_IN; - dir_ena &= ~II20K_DIR_DIO2_OUT; - } - - /* port 3 - channels 24-31 */ - if (s->io_bits & 0xff000000) { - /* output port */ - ctrl23 &= ~II20K_CTRL23_DIO3_IN; - dir_ena &= ~II20K_BUF_DISAB_DIO3; - dir_ena |= II20K_DIR_DIO3_OUT; - } else { - /* input port */ - ctrl23 |= II20K_CTRL23_DIO3_IN; - dir_ena &= ~II20K_DIR_DIO3_OUT; - } - - ctrl23 |= II20K_CTRL01_SET; - ctrl23 |= II20K_CTRL23_SET; - - /* order is important */ - writeb(ctrl01, dev->mmio + II20K_CTRL01_REG); - writeb(ctrl23, dev->mmio + II20K_CTRL23_REG); - writeb(dir_ena, dev->mmio + II20K_DIR_ENA_REG); -} - -static int ii20k_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; - int ret; - - if (chan < 8) - mask = 0x000000ff; - else if (chan < 16) - mask = 0x0000ff00; - else if (chan < 24) - mask = 0x00ff0000; - else - mask = 0xff000000; - - ret = comedi_dio_insn_config(dev, s, insn, data, mask); - if (ret) - return ret; - - ii20k_dio_config(dev, s); - - return insn->n; -} - -static int ii20k_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - unsigned int mask; - - mask = comedi_dio_update_state(s, data); - if (mask) { - if (mask & 0x000000ff) - writeb((s->state >> 0) & 0xff, - dev->mmio + II20K_DIO0_REG); - if (mask & 0x0000ff00) - writeb((s->state >> 8) & 0xff, - dev->mmio + II20K_DIO1_REG); - if (mask & 0x00ff0000) - writeb((s->state >> 16) & 0xff, - dev->mmio + II20K_DIO2_REG); - if (mask & 0xff000000) - writeb((s->state >> 24) & 0xff, - dev->mmio + II20K_DIO3_REG); - } - - data[1] = readb(dev->mmio + II20K_DIO0_REG); - data[1] |= readb(dev->mmio + II20K_DIO1_REG) << 8; - data[1] |= readb(dev->mmio + II20K_DIO2_REG) << 16; - data[1] |= readb(dev->mmio + II20K_DIO3_REG) << 24; - - return insn->n; -} - -static int ii20k_init_module(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - void __iomem *iobase = ii20k_module_iobase(dev, s); - unsigned char id; - int ret; - - id = readb(iobase + II20K_ID_REG); - switch (id) { - case II20K_ID_PCI20006M_1: - case II20K_ID_PCI20006M_2: - /* Analog Output subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = (id == II20K_ID_PCI20006M_2) ? 2 : 1; - s->maxdata = 0xffff; - s->range_table = &ii20k_ao_ranges; - s->insn_write = ii20k_ao_insn_write; - - ret = comedi_alloc_subdev_readback(s); - if (ret) - return ret; - break; - case II20K_ID_PCI20341M_1: - /* Analog Input subdevice */ - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_DIFF; - s->n_chan = 4; - s->maxdata = 0xffff; - s->range_table = &ii20k_ai_ranges; - s->insn_read = ii20k_ai_insn_read; - break; - default: - s->type = COMEDI_SUBD_UNUSED; - break; - } - - return 0; -} - -static int ii20k_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - unsigned int membase; - unsigned char id; - bool has_dio; - int ret; - - membase = it->options[0]; - if (!membase || (membase & ~(0x100000 - II20K_SIZE))) { - dev_warn(dev->class_dev, - "%s: invalid memory address specified\n", - dev->board_name); - return -EINVAL; - } - - if (!request_mem_region(membase, II20K_SIZE, dev->board_name)) { - dev_warn(dev->class_dev, "%s: I/O mem conflict (%#x,%u)\n", - dev->board_name, membase, II20K_SIZE); - return -EIO; - } - dev->iobase = membase; /* actually, a memory address */ - - dev->mmio = ioremap(membase, II20K_SIZE); - if (!dev->mmio) - return -ENOMEM; - - id = readb(dev->mmio + II20K_ID_REG); - switch (id & II20K_ID_MASK) { - case II20K_ID_PCI20001C_1A: - has_dio = false; - break; - case II20K_ID_PCI20001C_2A: - has_dio = true; - break; - default: - return -ENODEV; - } - - ret = comedi_alloc_subdevices(dev, 4); - if (ret) - return ret; - - s = &dev->subdevices[0]; - if (id & II20K_ID_MOD1_EMPTY) { - s->type = COMEDI_SUBD_UNUSED; - } else { - ret = ii20k_init_module(dev, s); - if (ret) - return ret; - } - - s = &dev->subdevices[1]; - if (id & II20K_ID_MOD2_EMPTY) { - s->type = COMEDI_SUBD_UNUSED; - } else { - ret = ii20k_init_module(dev, s); - if (ret) - return ret; - } - - s = &dev->subdevices[2]; - if (id & II20K_ID_MOD3_EMPTY) { - s->type = COMEDI_SUBD_UNUSED; - } else { - ret = ii20k_init_module(dev, s); - if (ret) - return ret; - } - - /* Digital I/O subdevice */ - s = &dev->subdevices[3]; - if (has_dio) { - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 32; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = ii20k_dio_insn_bits; - s->insn_config = ii20k_dio_insn_config; - - /* default all channels to input */ - ii20k_dio_config(dev, s); - } else { - s->type = COMEDI_SUBD_UNUSED; - } - - return 0; -} - -static void ii20k_detach(struct comedi_device *dev) -{ - if (dev->mmio) - iounmap(dev->mmio); - if (dev->iobase) /* actually, a memory address */ - release_mem_region(dev->iobase, II20K_SIZE); -} - -static struct comedi_driver ii20k_driver = { - .driver_name = "ii_pci20kc", - .module = THIS_MODULE, - .attach = ii20k_attach, - .detach = ii20k_detach, -}; -module_comedi_driver(ii20k_driver); - -MODULE_AUTHOR("Comedi https://www.comedi.org"); -MODULE_DESCRIPTION("Comedi driver for Intelligent Instruments PCI-20001C"); -MODULE_LICENSE("GPL"); |