From d4da77a73cb9cc9a1a349daa1a2723505b086e2d Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Wed, 19 May 2010 16:34:07 +0100 Subject: [PATCH] Staging: comedi: adv_pci_dio: Support Advantech PCI-1735U Add support for the Advantech PCI-1735U card, including support for a counter subdevice (based on an 82C54 counter timer chip). The counter subdevice needs more testing, as the only person I know who tried it couldn't get it to work! Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/adv_pci_dio.c | 180 +++++++++++++++++-- 1 file changed, 169 insertions(+), 11 deletions(-) diff --git a/drivers/staging/comedi/drivers/adv_pci_dio.c b/drivers/staging/comedi/drivers/adv_pci_dio.c index 40eeecf5347f..e424a0c7d34f 100644 --- a/drivers/staging/comedi/drivers/adv_pci_dio.c +++ b/drivers/staging/comedi/drivers/adv_pci_dio.c @@ -7,17 +7,17 @@ */ /* Driver: adv_pci_dio -Description: Advantech PCI-1730, PCI-1733, PCI-1734, PCI-1736UP, - PCI-1750, PCI-1751, PCI-1752, PCI-1753/E, PCI-1754, - PCI-1756, PCI-1762 +Description: Advantech PCI-1730, PCI-1733, PCI-1734, PCI-1735U, + PCI-1736UP, PCI-1750, PCI-1751, PCI-1752, PCI-1753/E, + PCI-1754, PCI-1756, PCI-1762 Author: Michal Dobes Devices: [Advantech] PCI-1730 (adv_pci_dio), PCI-1733, - PCI-1734, PCI-1736UP, PCI-1750, + PCI-1734, PCI-1735U, PCI-1736UP, PCI-1750, PCI-1751, PCI-1752, PCI-1753, PCI-1753+PCI-1753E, PCI-1754, PCI-1756, PCI-1760, PCI-1762 Status: untested -Updated: Mon, 14 Apr 2008 10:43:08 +0100 +Updated: Tue, 04 May 2010 13:00:00 +0000 This driver supports now only insn interface for DI/DO/DIO. @@ -35,6 +35,7 @@ Configuration options: #include "comedi_pci.h" #include "8255.h" +#include "8253.h" #undef PCI_DIO_EXTDEBUG /* if defined, enable extensive debug logging */ @@ -49,7 +50,7 @@ Configuration options: /* hardware types of the cards */ enum hw_cards_id { - TYPE_PCI1730, TYPE_PCI1733, TYPE_PCI1734, TYPE_PCI1736, + TYPE_PCI1730, TYPE_PCI1733, TYPE_PCI1734, TYPE_PCI1735, TYPE_PCI1736, TYPE_PCI1750, TYPE_PCI1751, TYPE_PCI1752, @@ -67,7 +68,10 @@ enum hw_io_access { #define MAX_DI_SUBDEVS 2 /* max number of DI subdevices per card */ #define MAX_DO_SUBDEVS 2 /* max number of DO subdevices per card */ #define MAX_DIO_SUBDEVG 2 /* max number of DIO subdevices group per card */ +#define MAX_8254_SUBDEVS 1 /* max number of 8254 counter subdevs per card */ + /* (could be more than one 8254 per subdevice) */ +#define SIZE_8254 4 /* 8254 IO space length */ #define SIZE_8255 4 /* 8255 IO space length */ #define PCIDIO_MAINREG 2 /* main I/O region for all Advantech cards? */ @@ -85,6 +89,12 @@ enum hw_io_access { #define PCI1734_IDO 0 /* W: Isolated digital output 0-31 */ #define PCI173x_BOARDID 4 /* R: Board I/D switch for 1730/3/4 */ +/* Advantech PCI-1735U */ +#define PCI1735_DI 0 /* R: Digital input 0-31 */ +#define PCI1735_DO 0 /* W: Digital output 0-31 */ +#define PCI1735_C8254 4 /* R/W: 8254 counter */ +#define PCI1735_BOARDID 8 /* R: Board I/D switch for 1735U */ + /* Advantech PCI-1736UP */ #define PCI1736_IDI 0 /* R: Isolated digital input 0-15 */ #define PCI1736_IDO 0 /* W: Isolated digital output 0-15 */ @@ -192,7 +202,8 @@ static int pci_dio_detach(struct comedi_device *dev); struct diosubd_data { int chans; /* num of chans */ int addr; /* PCI address ofset */ - int regs; /* number of registers to read or 8255 subdevices */ + int regs; /* number of registers to read or 8255 + subdevices or 8254 chips */ unsigned int specflags; /* addon subdevice flags */ }; @@ -206,6 +217,7 @@ struct dio_boardtype { struct diosubd_data sdo[MAX_DO_SUBDEVS]; /* DO chans */ struct diosubd_data sdio[MAX_DIO_SUBDEVG]; /* DIO 8255 chans */ struct diosubd_data boardid; /* card supports board ID switch */ + struct diosubd_data s8254[MAX_8254_SUBDEVS]; /* 8254 subdevices */ enum hw_io_access io_access; }; @@ -214,6 +226,7 @@ static DEFINE_PCI_DEVICE_TABLE(pci_dio_pci_table) = { PCI_VENDOR_ID_ADVANTECH, 0x1730, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_ADVANTECH, 0x1733, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_ADVANTECH, 0x1734, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { + PCI_VENDOR_ID_ADVANTECH, 0x1735, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_ADVANTECH, 0x1736, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_ADVANTECH, 0x1750, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_ADVANTECH, 0x1751, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { @@ -235,14 +248,15 @@ static const struct dio_boardtype boardtypes[] = { {{16, PCI1730_DO, 2, 0}, {16, PCI1730_IDO, 2, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}}, {4, PCI173x_BOARDID, 1, SDF_INTERNAL}, - IO_8b, - }, + {{0, 0, 0, 0}}, + IO_8b}, {"pci1733", PCI_VENDOR_ID_ADVANTECH, 0x1733, PCIDIO_MAINREG, TYPE_PCI1733, {{0, 0, 0, 0}, {32, PCI1733_IDI, 4, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}}, {4, PCI173x_BOARDID, 1, SDF_INTERNAL}, + {{0, 0, 0, 0}}, IO_8b}, {"pci1734", PCI_VENDOR_ID_ADVANTECH, 0x1734, PCIDIO_MAINREG, TYPE_PCI1734, @@ -250,6 +264,15 @@ static const struct dio_boardtype boardtypes[] = { {{0, 0, 0, 0}, {32, PCI1734_IDO, 4, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}}, {4, PCI173x_BOARDID, 1, SDF_INTERNAL}, + {{0, 0, 0, 0}}, + IO_8b}, + {"pci1735", PCI_VENDOR_ID_ADVANTECH, 0x1735, PCIDIO_MAINREG, + TYPE_PCI1735, + {{32, PCI1735_DI, 4, 0}, {0, 0, 0, 0}}, + {{32, PCI1735_DO, 4, 0}, {0, 0, 0, 0}}, + {{0, 0, 0, 0}, {0, 0, 0, 0}}, + { 4, PCI1735_BOARDID, 1, SDF_INTERNAL}, + {{3, PCI1735_C8254, 1, 0}}, IO_8b}, {"pci1736", PCI_VENDOR_ID_ADVANTECH, 0x1736, PCI1736_MAINREG, TYPE_PCI1736, @@ -257,14 +280,15 @@ static const struct dio_boardtype boardtypes[] = { {{0, 0, 0, 0}, {16, PCI1736_IDO, 2, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}}, {4, PCI1736_BOARDID, 1, SDF_INTERNAL}, - IO_8b, - }, + {{0, 0, 0, 0}}, + IO_8b}, {"pci1750", PCI_VENDOR_ID_ADVANTECH, 0x1750, PCIDIO_MAINREG, TYPE_PCI1750, {{0, 0, 0, 0}, {16, PCI1750_IDI, 2, 0}}, {{0, 0, 0, 0}, {16, PCI1750_IDO, 2, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}}, {0, 0, 0, 0}, + {{0, 0, 0, 0}}, IO_8b}, {"pci1751", PCI_VENDOR_ID_ADVANTECH, 0x1751, PCIDIO_MAINREG, TYPE_PCI1751, @@ -272,6 +296,7 @@ static const struct dio_boardtype boardtypes[] = { {{0, 0, 0, 0}, {0, 0, 0, 0}}, {{48, PCI1751_DIO, 2, 0}, {0, 0, 0, 0}}, {0, 0, 0, 0}, + {{0, 0, 0, 0}}, IO_8b}, {"pci1752", PCI_VENDOR_ID_ADVANTECH, 0x1752, PCIDIO_MAINREG, TYPE_PCI1752, @@ -279,6 +304,7 @@ static const struct dio_boardtype boardtypes[] = { {{32, PCI1752_IDO, 2, 0}, {32, PCI1752_IDO2, 2, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}}, {4, PCI175x_BOARDID, 1, SDF_INTERNAL}, + {{0, 0, 0, 0}}, IO_16b}, {"pci1753", PCI_VENDOR_ID_ADVANTECH, 0x1753, PCIDIO_MAINREG, TYPE_PCI1753, @@ -286,6 +312,7 @@ static const struct dio_boardtype boardtypes[] = { {{0, 0, 0, 0}, {0, 0, 0, 0}}, {{96, PCI1753_DIO, 4, 0}, {0, 0, 0, 0}}, {0, 0, 0, 0}, + {{0, 0, 0, 0}}, IO_8b}, {"pci1753e", PCI_VENDOR_ID_ADVANTECH, 0x1753, PCIDIO_MAINREG, TYPE_PCI1753E, @@ -293,6 +320,7 @@ static const struct dio_boardtype boardtypes[] = { {{0, 0, 0, 0}, {0, 0, 0, 0}}, {{96, PCI1753_DIO, 4, 0}, {96, PCI1753E_DIO, 4, 0}}, {0, 0, 0, 0}, + {{0, 0, 0, 0}}, IO_8b}, {"pci1754", PCI_VENDOR_ID_ADVANTECH, 0x1754, PCIDIO_MAINREG, TYPE_PCI1754, @@ -300,6 +328,7 @@ static const struct dio_boardtype boardtypes[] = { {{0, 0, 0, 0}, {0, 0, 0, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}}, {4, PCI175x_BOARDID, 1, SDF_INTERNAL}, + {{0, 0, 0, 0}}, IO_16b}, {"pci1756", PCI_VENDOR_ID_ADVANTECH, 0x1756, PCIDIO_MAINREG, TYPE_PCI1756, @@ -307,6 +336,7 @@ static const struct dio_boardtype boardtypes[] = { {{0, 0, 0, 0}, {32, PCI1756_IDO, 2, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}}, {4, PCI175x_BOARDID, 1, SDF_INTERNAL}, + {{0, 0, 0, 0}}, IO_16b}, {"pci1760", PCI_VENDOR_ID_ADVANTECH, 0x1760, 0, TYPE_PCI1760, @@ -314,6 +344,7 @@ static const struct dio_boardtype boardtypes[] = { {{0, 0, 0, 0}, {0, 0, 0, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}}, {0, 0, 0, 0}, + {{0, 0, 0, 0}}, IO_8b}, {"pci1762", PCI_VENDOR_ID_ADVANTECH, 0x1762, PCIDIO_MAINREG, TYPE_PCI1762, @@ -321,6 +352,7 @@ static const struct dio_boardtype boardtypes[] = { {{0, 0, 0, 0}, {16, PCI1762_RO, 1, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}}, {4, PCI1762_BOARDID, 1, SDF_INTERNAL}, + {{0, 0, 0, 0}}, IO_16b} }; @@ -437,6 +469,83 @@ static int pci_dio_insn_bits_do_w(struct comedi_device *dev, return 2; } +/* +============================================================================== +*/ +static int pci_8254_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + const struct diosubd_data *d = (const struct diosubd_data *)s->private; + unsigned int chan, chip, chipchan; + unsigned long flags; + + chan = CR_CHAN(insn->chanspec); /* channel on subdevice */ + chip = chan / 3; /* chip on subdevice */ + chipchan = chan - (3 * chip); /* channel on chip on subdevice */ + spin_lock_irqsave(&s->spin_lock, flags); + data[0] = i8254_read(dev->iobase + d->addr + (SIZE_8254 * chip), + 0, chipchan); + spin_unlock_irqrestore(&s->spin_lock, flags); + return 1; +} + +/* +============================================================================== +*/ +static int pci_8254_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + const struct diosubd_data *d = (const struct diosubd_data *)s->private; + unsigned int chan, chip, chipchan; + unsigned long flags; + + chan = CR_CHAN(insn->chanspec); /* channel on subdevice */ + chip = chan / 3; /* chip on subdevice */ + chipchan = chan - (3 * chip); /* channel on chip on subdevice */ + spin_lock_irqsave(&s->spin_lock, flags); + i8254_write(dev->iobase + d->addr + (SIZE_8254 * chip), + 0, chipchan, data[0]); + spin_unlock_irqrestore(&s->spin_lock, flags); + return 1; +} + +/* +============================================================================== +*/ +static int pci_8254_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + const struct diosubd_data *d = (const struct diosubd_data *)s->private; + unsigned int chan, chip, chipchan; + unsigned long iobase; + int ret = 0; + unsigned long flags; + + chan = CR_CHAN(insn->chanspec); /* channel on subdevice */ + chip = chan / 3; /* chip on subdevice */ + chipchan = chan - (3 * chip); /* channel on chip on subdevice */ + iobase = dev->iobase + d->addr + (SIZE_8254 * chip); + spin_lock_irqsave(&s->spin_lock, flags); + switch (data[0]) { + case INSN_CONFIG_SET_COUNTER_MODE: + ret = i8254_set_mode(iobase, 0, chipchan, data[1]); + if (ret < 0) + ret = -EINVAL; + break; + case INSN_CONFIG_8254_READ_STATUS: + data[1] = i8254_status(iobase, 0, chipchan); + break; + default: + ret = -EINVAL; + break; + } + spin_unlock_irqrestore(&s->spin_lock, flags); + return ret < 0 ? ret : insn->n; +} + /* ============================================================================== */ @@ -708,6 +817,15 @@ static int pci_dio_reset(struct comedi_device *dev) outb(0, dev->iobase + PCI1734_IDO + 2); outb(0, dev->iobase + PCI1734_IDO + 3); break; + case TYPE_PCI1735: + outb(0, dev->iobase + PCI1735_DO); /* clear outputs */ + outb(0, dev->iobase + PCI1735_DO + 1); + outb(0, dev->iobase + PCI1735_DO + 2); + outb(0, dev->iobase + PCI1735_DO + 3); + i8254_set_mode(dev->iobase + PCI1735_C8254, 0, 0, I8254_MODE0); + i8254_set_mode(dev->iobase + PCI1735_C8254, 0, 1, I8254_MODE0); + i8254_set_mode(dev->iobase + PCI1735_C8254, 0, 2, I8254_MODE0); + break; case TYPE_PCI1736: outb(0, dev->iobase + PCI1736_IDO); @@ -874,6 +992,26 @@ static int pci_dio_add_do(struct comedi_device *dev, struct comedi_subdevice *s, return 0; } +/* +============================================================================== +*/ +static int pci_dio_add_8254(struct comedi_device *dev, + struct comedi_subdevice * s, + const struct diosubd_data *d, int subdev) +{ + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_WRITABLE | SDF_READABLE; + s->n_chan = d->chans; + s->maxdata = 65535; + s->len_chanlist = d->chans; + s->insn_read = pci_8254_insn_read; + s->insn_write = pci_8254_insn_write; + s->insn_config = pci_8254_insn_config; + s->private = (void *)d; + + return 0; +} + /* ============================================================================== */ @@ -979,6 +1117,9 @@ static int pci_dio_attach(struct comedi_device *dev, n_subdevices += this_board->sdio[i].regs; if (this_board->boardid.chans) n_subdevices++; + for (i = 0; i < MAX_8254_SUBDEVS; i++) + if (this_board->s8254[i].chans) + n_subdevices++; } ret = alloc_subdevices(dev, n_subdevices); @@ -1022,6 +1163,13 @@ static int pci_dio_attach(struct comedi_device *dev, subdev++; } + for (i = 0; i < MAX_8254_SUBDEVS; i++) + if (this_board->s8254[i].chans) { + s = dev->subdevices + subdev; + pci_dio_add_8254(dev, s, &this_board->s8254[i], subdev); + subdev++; + } + if (this_board->cardtype == TYPE_PCI1760) pci1760_attach(dev, it); @@ -1067,6 +1215,16 @@ static int pci_dio_detach(struct comedi_device *dev) } } + if (this_board->boardid.chans) { + subdev++; + } + + for (i = 0; i < MAX_8254_SUBDEVS; i++) { + if (this_board->s8254[i].chans) { + subdev++; + } + } + for (i = 0; i < dev->n_subdevices; i++) { s = dev->subdevices + i; s->private = NULL; -- 2.30.2