diff options
Diffstat (limited to 'drivers/staging/comedi/drivers/addi_apci_1564.c')
-rw-r--r-- | drivers/staging/comedi/drivers/addi_apci_1564.c | 268 |
1 files changed, 181 insertions, 87 deletions
diff --git a/drivers/staging/comedi/drivers/addi_apci_1564.c b/drivers/staging/comedi/drivers/addi_apci_1564.c index 688b015a834e..6872b69da5db 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1564.c +++ b/drivers/staging/comedi/drivers/addi_apci_1564.c @@ -28,16 +28,91 @@ #include "../comedidev.h" #include "comedi_fc.h" -#include "amcc_s5933.h" +#include "addi_tcw.h" #include "addi_watchdog.h" +/* + * PCI BAR 0 + * + * PLD Revision 1.0 I/O Mapping + * 0x00 93C76 EEPROM + * 0x04 - 0x18 Timer 12-Bit + * + * PLD Revision 2.x I/O Mapping + * 0x00 93C76 EEPROM + * 0x04 - 0x14 Digital Input + * 0x18 - 0x25 Digital Output + * 0x28 - 0x44 Watchdog 8-Bit + * 0x48 - 0x64 Timer 12-Bit + */ +#define APCI1564_EEPROM_REG 0x00 +#define APCI1564_EEPROM_VCC_STATUS (1 << 8) +#define APCI1564_EEPROM_TO_REV(x) (((x) >> 4) & 0xf) +#define APCI1564_EEPROM_DI (1 << 3) +#define APCI1564_EEPROM_DO (1 << 2) +#define APCI1564_EEPROM_CS (1 << 1) +#define APCI1564_EEPROM_CLK (1 << 0) +#define APCI1564_REV1_TIMER_IOBASE 0x04 +#define APCI1564_REV2_MAIN_IOBASE 0x04 +#define APCI1564_REV2_TIMER_IOBASE 0x48 + +/* + * PCI BAR 1 + * + * PLD Revision 1.0 I/O Mapping + * 0x00 - 0x10 Digital Input + * 0x14 - 0x20 Digital Output + * 0x24 - 0x3c Watchdog 8-Bit + * + * PLD Revision 2.x I/O Mapping + * 0x00 Counter_0 + * 0x20 Counter_1 + * 0x30 Counter_3 + */ +#define APCI1564_REV1_MAIN_IOBASE 0x00 + +/* + * dev->iobase Register Map + * PLD Revision 1.0 - PCI BAR 1 + 0x00 + * PLD Revision 2.x - PCI BAR 0 + 0x04 + */ +#define APCI1564_DI_REG 0x00 +#define APCI1564_DI_INT_MODE1_REG 0x04 +#define APCI1564_DI_INT_MODE2_REG 0x08 +#define APCI1564_DI_INT_STATUS_REG 0x0c +#define APCI1564_DI_IRQ_REG 0x10 +#define APCI1564_DO_REG 0x14 +#define APCI1564_DO_INT_CTRL_REG 0x18 +#define APCI1564_DO_INT_STATUS_REG 0x1c +#define APCI1564_DO_IRQ_REG 0x20 +#define APCI1564_WDOG_REG 0x24 +#define APCI1564_WDOG_RELOAD_REG 0x28 +#define APCI1564_WDOG_TIMEBASE_REG 0x2c +#define APCI1564_WDOG_CTRL_REG 0x30 +#define APCI1564_WDOG_STATUS_REG 0x34 +#define APCI1564_WDOG_IRQ_REG 0x38 +#define APCI1564_WDOG_WARN_TIMEVAL_REG 0x3c +#define APCI1564_WDOG_WARN_TIMEBASE_REG 0x40 + +/* + * devpriv->timer Register Map (see addi_tcw.h for register/bit defines) + * PLD Revision 1.0 - PCI BAR 0 + 0x04 + * PLD Revision 2.x - PCI BAR 0 + 0x48 + */ + +/* + * devpriv->counters Register Map (see addi_tcw.h for register/bit defines) + * PLD Revision 2.x - PCI BAR 1 + 0x00 + */ +#define APCI1564_COUNTER(x) ((x) * 0x20) + struct apci1564_private { - unsigned int amcc_iobase; /* base of AMCC I/O registers */ + unsigned long eeprom; /* base address of EEPROM register */ + unsigned long timer; /* base address of 12-bit timer */ + unsigned long counters; /* base address of 32-bit counters */ unsigned int mode1; /* riding-edge/high level channels */ unsigned int mode2; /* falling-edge/low level channels */ unsigned int ctrl; /* interrupt mode OR (edge) . AND (level) */ - unsigned char timer_select_mode; - unsigned char mode_select_register; struct task_struct *tsk_current; }; @@ -48,27 +123,30 @@ static int apci1564_reset(struct comedi_device *dev) struct apci1564_private *devpriv = dev->private; /* Disable the input interrupts and reset status register */ - outl(0x0, devpriv->amcc_iobase + APCI1564_DI_IRQ_REG); - inl(devpriv->amcc_iobase + APCI1564_DI_INT_STATUS_REG); - outl(0x0, devpriv->amcc_iobase + APCI1564_DI_INT_MODE1_REG); - outl(0x0, devpriv->amcc_iobase + APCI1564_DI_INT_MODE2_REG); + outl(0x0, dev->iobase + APCI1564_DI_IRQ_REG); + inl(dev->iobase + APCI1564_DI_INT_STATUS_REG); + outl(0x0, dev->iobase + APCI1564_DI_INT_MODE1_REG); + outl(0x0, dev->iobase + APCI1564_DI_INT_MODE2_REG); /* Reset the output channels and disable interrupts */ - outl(0x0, devpriv->amcc_iobase + APCI1564_DO_REG); - outl(0x0, devpriv->amcc_iobase + APCI1564_DO_INT_CTRL_REG); + outl(0x0, dev->iobase + APCI1564_DO_REG); + outl(0x0, dev->iobase + APCI1564_DO_INT_CTRL_REG); /* Reset the watchdog registers */ - addi_watchdog_reset(devpriv->amcc_iobase + APCI1564_WDOG_REG); + addi_watchdog_reset(dev->iobase + APCI1564_WDOG_REG); /* Reset the timer registers */ - outl(0x0, devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG); - outl(0x0, devpriv->amcc_iobase + APCI1564_TIMER_RELOAD_REG); + outl(0x0, devpriv->timer + ADDI_TCW_CTRL_REG); + outl(0x0, devpriv->timer + ADDI_TCW_RELOAD_REG); + + if (devpriv->counters) { + unsigned long iobase = devpriv->counters + ADDI_TCW_CTRL_REG; - /* Reset the counter registers */ - outl(0x0, dev->iobase + APCI1564_COUNTER_CTRL_REG(APCI1564_COUNTER1)); - outl(0x0, dev->iobase + APCI1564_COUNTER_CTRL_REG(APCI1564_COUNTER2)); - outl(0x0, dev->iobase + APCI1564_COUNTER_CTRL_REG(APCI1564_COUNTER3)); - outl(0x0, dev->iobase + APCI1564_COUNTER_CTRL_REG(APCI1564_COUNTER4)); + /* Reset the counter registers */ + outl(0x0, iobase + APCI1564_COUNTER(0)); + outl(0x0, iobase + APCI1564_COUNTER(1)); + outl(0x0, iobase + APCI1564_COUNTER(2)); + } return 0; } @@ -82,55 +160,52 @@ static irqreturn_t apci1564_interrupt(int irq, void *d) unsigned int ctrl; unsigned int chan; - /* check interrupt is from this device */ - if ((inl(devpriv->amcc_iobase + AMCC_OP_REG_INTCSR) & - INTCSR_INTR_ASSERTED) == 0) - return IRQ_NONE; - - status = inl(devpriv->amcc_iobase + APCI1564_DI_IRQ_REG); + status = inl(dev->iobase + APCI1564_DI_IRQ_REG); if (status & APCI1564_DI_INT_ENABLE) { /* disable the interrupt */ outl(status & APCI1564_DI_INT_DISABLE, - devpriv->amcc_iobase + APCI1564_DI_IRQ_REG); + dev->iobase + APCI1564_DI_IRQ_REG); - s->state = inl(dev->iobase + APCI1564_DI_INT_STATUS_REG) - & 0xffff; - comedi_buf_put(s, s->state); - s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; - comedi_event(dev, s); + s->state = inl(dev->iobase + APCI1564_DI_INT_STATUS_REG) & + 0xffff; + comedi_buf_write_samples(s, &s->state, 1); + comedi_handle_events(dev, s); /* enable the interrupt */ - outl(status, devpriv->amcc_iobase + APCI1564_DI_IRQ_REG); + outl(status, dev->iobase + APCI1564_DI_IRQ_REG); } - status = inl(devpriv->amcc_iobase + APCI1564_TIMER_IRQ_REG); + status = inl(devpriv->timer + ADDI_TCW_IRQ_REG); if (status & 0x01) { /* Disable Timer Interrupt */ - ctrl = inl(devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG); - outl(0x0, devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG); + ctrl = inl(devpriv->timer + ADDI_TCW_CTRL_REG); + outl(0x0, devpriv->timer + ADDI_TCW_CTRL_REG); /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_current, 0); /* Enable Timer Interrupt */ - outl(ctrl, devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG); + outl(ctrl, devpriv->timer + ADDI_TCW_CTRL_REG); } - for (chan = 0; chan < 4; chan++) { - status = inl(dev->iobase + APCI1564_COUNTER_IRQ_REG(chan)); - if (status & 0x01) { - /* Disable Counter Interrupt */ - ctrl = inl(dev->iobase + - APCI1564_COUNTER_CTRL_REG(chan)); - outl(0x0, dev->iobase + - APCI1564_COUNTER_CTRL_REG(chan)); - - /* Send a signal to from kernel to user space */ - send_sig(SIGIO, devpriv->tsk_current, 0); - - /* Enable Counter Interrupt */ - outl(ctrl, dev->iobase + - APCI1564_COUNTER_CTRL_REG(chan)); + if (devpriv->counters) { + for (chan = 0; chan < 4; chan++) { + unsigned long iobase; + + iobase = devpriv->counters + APCI1564_COUNTER(chan); + + status = inl(iobase + ADDI_TCW_IRQ_REG); + if (status & 0x01) { + /* Disable Counter Interrupt */ + ctrl = inl(iobase + ADDI_TCW_CTRL_REG); + outl(0x0, iobase + ADDI_TCW_CTRL_REG); + + /* Send a signal to from kernel to user space */ + send_sig(SIGIO, devpriv->tsk_current, 0); + + /* Enable Counter Interrupt */ + outl(ctrl, iobase + ADDI_TCW_CTRL_REG); + } } } @@ -142,9 +217,7 @@ static int apci1564_di_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct apci1564_private *devpriv = dev->private; - - data[1] = inl(devpriv->amcc_iobase + APCI1564_DI_REG); + data[1] = inl(dev->iobase + APCI1564_DI_REG); return insn->n; } @@ -154,12 +227,10 @@ static int apci1564_do_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct apci1564_private *devpriv = dev->private; - - s->state = inl(devpriv->amcc_iobase + APCI1564_DO_REG); + s->state = inl(dev->iobase + APCI1564_DO_REG); if (comedi_dio_update_state(s, data)) - outl(s->state, devpriv->amcc_iobase + APCI1564_DO_REG); + outl(s->state, dev->iobase + APCI1564_DO_REG); data[1] = s->state; @@ -171,9 +242,7 @@ static int apci1564_diag_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct apci1564_private *devpriv = dev->private; - - data[1] = inl(devpriv->amcc_iobase + APCI1564_DO_INT_STATUS_REG) & 3; + data[1] = inl(dev->iobase + APCI1564_DO_INT_STATUS_REG) & 3; return insn->n; } @@ -227,10 +296,10 @@ static int apci1564_cos_insn_config(struct comedi_device *dev, devpriv->ctrl = 0; devpriv->mode1 = 0; devpriv->mode2 = 0; - outl(0x0, devpriv->amcc_iobase + APCI1564_DI_IRQ_REG); - inl(devpriv->amcc_iobase + APCI1564_DI_INT_STATUS_REG); - outl(0x0, devpriv->amcc_iobase + APCI1564_DI_INT_MODE1_REG); - outl(0x0, devpriv->amcc_iobase + APCI1564_DI_INT_MODE2_REG); + outl(0x0, dev->iobase + APCI1564_DI_IRQ_REG); + inl(dev->iobase + APCI1564_DI_INT_STATUS_REG); + outl(0x0, dev->iobase + APCI1564_DI_INT_MODE1_REG); + outl(0x0, dev->iobase + APCI1564_DI_INT_MODE2_REG); break; case COMEDI_DIGITAL_TRIG_ENABLE_EDGES: if (devpriv->ctrl != (APCI1564_DI_INT_ENABLE | @@ -342,9 +411,9 @@ static int apci1564_cos_cmd(struct comedi_device *dev, return -EINVAL; } - outl(devpriv->mode1, devpriv->amcc_iobase + APCI1564_DI_INT_MODE1_REG); - outl(devpriv->mode2, devpriv->amcc_iobase + APCI1564_DI_INT_MODE2_REG); - outl(devpriv->ctrl, devpriv->amcc_iobase + APCI1564_DI_IRQ_REG); + outl(devpriv->mode1, dev->iobase + APCI1564_DI_INT_MODE1_REG); + outl(devpriv->mode2, dev->iobase + APCI1564_DI_INT_MODE2_REG); + outl(devpriv->ctrl, dev->iobase + APCI1564_DI_IRQ_REG); return 0; } @@ -352,12 +421,10 @@ static int apci1564_cos_cmd(struct comedi_device *dev, static int apci1564_cos_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - struct apci1564_private *devpriv = dev->private; - - outl(0x0, devpriv->amcc_iobase + APCI1564_DI_IRQ_REG); - inl(devpriv->amcc_iobase + APCI1564_DI_INT_STATUS_REG); - outl(0x0, devpriv->amcc_iobase + APCI1564_DI_INT_MODE1_REG); - outl(0x0, devpriv->amcc_iobase + APCI1564_DI_INT_MODE2_REG); + outl(0x0, dev->iobase + APCI1564_DI_IRQ_REG); + inl(dev->iobase + APCI1564_DI_INT_STATUS_REG); + outl(0x0, dev->iobase + APCI1564_DI_INT_MODE1_REG); + outl(0x0, dev->iobase + APCI1564_DI_INT_MODE2_REG); return 0; } @@ -368,6 +435,7 @@ static int apci1564_auto_attach(struct comedi_device *dev, struct pci_dev *pcidev = comedi_to_pci_dev(dev); struct apci1564_private *devpriv; struct comedi_subdevice *s; + unsigned int val; int ret; devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); @@ -378,8 +446,20 @@ static int apci1564_auto_attach(struct comedi_device *dev, if (ret) return ret; - dev->iobase = pci_resource_start(pcidev, 1); - devpriv->amcc_iobase = pci_resource_start(pcidev, 0); + /* read the EEPROM register and check the I/O map revision */ + devpriv->eeprom = pci_resource_start(pcidev, 0); + val = inl(devpriv->eeprom + APCI1564_EEPROM_REG); + if (APCI1564_EEPROM_TO_REV(val) == 0) { + /* PLD Revision 1.0 I/O Mapping */ + dev->iobase = pci_resource_start(pcidev, 1) + + APCI1564_REV1_MAIN_IOBASE; + devpriv->timer = devpriv->eeprom + APCI1564_REV1_TIMER_IOBASE; + } else { + /* PLD Revision 2.x I/O Mapping */ + dev->iobase = devpriv->eeprom + APCI1564_REV2_MAIN_IOBASE; + devpriv->timer = devpriv->eeprom + APCI1564_REV2_TIMER_IOBASE; + devpriv->counters = pci_resource_start(pcidev, 1); + } apci1564_reset(dev); @@ -390,7 +470,7 @@ static int apci1564_auto_attach(struct comedi_device *dev, dev->irq = pcidev->irq; } - ret = comedi_alloc_subdevices(dev, 6); + ret = comedi_alloc_subdevices(dev, 7); if (ret) return ret; @@ -406,7 +486,7 @@ static int apci1564_auto_attach(struct comedi_device *dev, /* Allocate and Initialise DO Subdevice Structures */ s = &dev->subdevices[1]; s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITEABLE; + s->subdev_flags = SDF_WRITABLE; s->n_chan = 32; s->maxdata = 1; s->range_table = &range_digital; @@ -431,26 +511,40 @@ static int apci1564_auto_attach(struct comedi_device *dev, s->type = COMEDI_SUBD_UNUSED; } - /* Allocate and Initialise Timer Subdevice Structures */ + /* Timer subdevice */ s = &dev->subdevices[3]; s->type = COMEDI_SUBD_TIMER; - s->subdev_flags = SDF_WRITEABLE; + s->subdev_flags = SDF_WRITABLE | SDF_READABLE; s->n_chan = 1; - s->maxdata = 0; - s->len_chanlist = 1; + s->maxdata = 0x0fff; s->range_table = &range_digital; - s->insn_write = apci1564_timer_write; - s->insn_read = apci1564_timer_read; - s->insn_config = apci1564_timer_config; + s->insn_config = apci1564_timer_insn_config; + s->insn_write = apci1564_timer_insn_write; + s->insn_read = apci1564_timer_insn_read; - /* Initialize the watchdog subdevice */ + /* Counter subdevice */ s = &dev->subdevices[4]; - ret = addi_watchdog_init(s, devpriv->amcc_iobase + APCI1564_WDOG_REG); + if (devpriv->counters) { + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_WRITABLE | SDF_READABLE | SDF_LSAMPL; + s->n_chan = 3; + s->maxdata = 0xffffffff; + s->range_table = &range_digital; + s->insn_config = apci1564_counter_insn_config; + s->insn_write = apci1564_counter_insn_write; + s->insn_read = apci1564_counter_insn_read; + } else { + s->type = COMEDI_SUBD_UNUSED; + } + + /* Initialize the watchdog subdevice */ + s = &dev->subdevices[5]; + ret = addi_watchdog_init(s, dev->iobase + APCI1564_WDOG_REG); if (ret) return ret; /* Initialize the diagnostic status subdevice */ - s = &dev->subdevices[5]; + s = &dev->subdevices[6]; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; s->n_chan = 2; |