From: H Hartley Sweeten Date: Mon, 10 Nov 2014 23:20:16 +0000 (-0700) Subject: staging: comedi: addi_apci_1564: split timer and counter subdevices X-Git-Tag: firefly_0821_release~176^2~2665^2~162 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=0658d6de9c9750201a5728f25dd3037a73941077;p=firefly-linux-kernel-4.4.55.git staging: comedi: addi_apci_1564: split timer and counter subdevices The timer subdevice is currently broken in this driver. The Rev 1.0 and 2.x versions of the board both have a 12-bit timer. But only the Rev 2.x boards have the 3 32-bit counters. Split the current timer subdevice into two separate subdevices: 1) A single channel 12-bit timer subdevice 2) A three channel 32-bit counter subdevice This represents the hardware correctly and the counters can be disabled on the Rev 1.0 boards. Split up the current (*insn_config), (*insn_write), and (*insn_read) so they only deal with the hardware associated with the subdevice. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c index af37df713a37..23bc8de3a80a 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c @@ -17,199 +17,185 @@ #define ADDIDATA_COUNTER 1 #define ADDIDATA_WATCHDOG 2 -/* - * Configures The Timer or Counter - * - * data[0] Configure as: 0 = Timer, 1 = Counter - * data[1] 1 = Enable Interrupt, 0 = Disable Interrupt - * data[2] Time Unit - * data[3] Reload Value - * data[4] Timer Mode - * data[5] Timer Counter Watchdog Number - * data[6] Counter Direction - */ -static int apci1564_timer_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci1564_timer_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct apci1564_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - unsigned int ul_Command1 = 0; + unsigned int ctrl; devpriv->tsk_current = current; - if (data[0] == ADDIDATA_TIMER) { - /* First Stop The Timer */ - ul_Command1 = inl(devpriv->timer + APCI1564_TIMER_CTRL_REG); - ul_Command1 = ul_Command1 & 0xFFFFF9FEUL; - /* Stop The Timer */ - outl(ul_Command1, devpriv->timer + APCI1564_TIMER_CTRL_REG); - - devpriv->timer_select_mode = ADDIDATA_TIMER; - if (data[1] == 1) { - /* Enable TIMER int & DISABLE ALL THE OTHER int SOURCES */ - outl(0x02, devpriv->timer + APCI1564_TIMER_CTRL_REG); - outl(0x0, dev->iobase + APCI1564_DI_IRQ_REG); - outl(0x0, dev->iobase + APCI1564_DO_IRQ_REG); - outl(0x0, dev->iobase + APCI1564_WDOG_IRQ_REG); + + /* First Stop The Timer */ + ctrl = inl(devpriv->timer + APCI1564_TIMER_CTRL_REG); + ctrl &= 0xfffff9fe; + /* Stop The Timer */ + outl(ctrl, devpriv->timer + APCI1564_TIMER_CTRL_REG); + + if (data[1] == 1) { + /* Enable timer int & disable all the other int sources */ + outl(0x02, devpriv->timer + APCI1564_TIMER_CTRL_REG); + outl(0x0, dev->iobase + APCI1564_DI_IRQ_REG); + outl(0x0, dev->iobase + APCI1564_DO_IRQ_REG); + outl(0x0, dev->iobase + APCI1564_WDOG_IRQ_REG); + if (devpriv->counters) { outl(0x0, devpriv->counters + APCI1564_COUNTER_IRQ_REG(0)); outl(0x0, devpriv->counters + APCI1564_COUNTER_IRQ_REG(1)); outl(0x0, devpriv->counters + APCI1564_COUNTER_IRQ_REG(2)); - } else { - /* disable Timer interrupt */ - outl(0x0, devpriv->timer + APCI1564_TIMER_CTRL_REG); } - - /* Loading Timebase */ - outl(data[2], devpriv->timer + APCI1564_TIMER_TIMEBASE_REG); - - /* Loading the Reload value */ - outl(data[3], devpriv->timer + APCI1564_TIMER_RELOAD_REG); - - ul_Command1 = inl(devpriv->timer + APCI1564_TIMER_CTRL_REG); - ul_Command1 = (ul_Command1 & 0xFFF719E2UL) | 2UL << 13UL | 0x10UL; - /* mode 2 */ - outl(ul_Command1, devpriv->timer + APCI1564_TIMER_CTRL_REG); - } else if (data[0] == ADDIDATA_COUNTER) { - devpriv->timer_select_mode = ADDIDATA_COUNTER; - - /* First Stop The Counter */ - ul_Command1 = inl(devpriv->counters + - APCI1564_COUNTER_CTRL_REG(chan)); - ul_Command1 = ul_Command1 & 0xFFFFF9FEUL; - /* Stop The Timer */ - outl(ul_Command1, - devpriv->counters + APCI1564_COUNTER_CTRL_REG(chan)); - - /* Set the reload value */ - outl(data[3], - devpriv->counters + APCI1564_COUNTER_RELOAD_REG(chan)); - - /* Set the mode : */ - /* - Disable the hardware */ - /* - Disable the counter mode */ - /* - Disable the warning */ - /* - Disable the reset */ - /* - Disable the timer mode */ - /* - Enable the counter mode */ - - ul_Command1 = - (ul_Command1 & 0xFFFC19E2UL) | 0x80000UL | - (unsigned int) ((unsigned int) data[4] << 16UL); - outl(ul_Command1, - devpriv->counters + APCI1564_COUNTER_CTRL_REG(chan)); - - /* Enable or Disable Interrupt */ - ul_Command1 = (ul_Command1 & 0xFFFFF9FD) | (data[1] << 1); - outl(ul_Command1, - devpriv->counters + APCI1564_COUNTER_CTRL_REG(chan)); - - /* Set the Up/Down selection */ - ul_Command1 = (ul_Command1 & 0xFFFBF9FFUL) | (data[6] << 18); - outl(ul_Command1, - devpriv->counters + APCI1564_COUNTER_CTRL_REG(chan)); } else { - dev_err(dev->class_dev, "Invalid subdevice.\n"); + /* disable Timer interrupt */ + outl(0x0, devpriv->timer + APCI1564_TIMER_CTRL_REG); } + + /* Loading Timebase */ + outl(data[2], devpriv->timer + APCI1564_TIMER_TIMEBASE_REG); + + /* Loading the Reload value */ + outl(data[3], devpriv->timer + APCI1564_TIMER_RELOAD_REG); + + ctrl = inl(devpriv->timer + APCI1564_TIMER_CTRL_REG); + ctrl &= 0xfff719e2; + ctrl |= (2 << 13) | 0x10; + /* mode 2 */ + outl(ctrl, devpriv->timer + APCI1564_TIMER_CTRL_REG); + return insn->n; } -/* - * Start / Stop The Selected Timer or Counter - * - * data[0] Configure as: 0 = Timer, 1 = Counter - * data[1] 0 = Stop, 1 = Start, 2 = Trigger Clear (Only Counter) - */ -static int apci1564_timer_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci1564_timer_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct apci1564_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - unsigned int ul_Command1 = 0; - - if (devpriv->timer_select_mode == ADDIDATA_TIMER) { - if (data[1] == 1) { - ul_Command1 = inl(devpriv->timer + - APCI1564_TIMER_CTRL_REG); - ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL; - - /* Enable the Timer */ - outl(ul_Command1, - devpriv->timer + APCI1564_TIMER_CTRL_REG); - } else if (data[1] == 0) { - /* Stop The Timer */ - - ul_Command1 = inl(devpriv->timer + - APCI1564_TIMER_CTRL_REG); - ul_Command1 = ul_Command1 & 0xFFFFF9FEUL; - outl(ul_Command1, - devpriv->timer + APCI1564_TIMER_CTRL_REG); - } - } else if (devpriv->timer_select_mode == ADDIDATA_COUNTER) { - ul_Command1 = inl(devpriv->counters + - APCI1564_COUNTER_CTRL_REG(chan)); - if (data[1] == 1) { - /* Start the Counter subdevice */ - ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL; - } else if (data[1] == 0) { - /* Stops the Counter subdevice */ - ul_Command1 = 0; - - } else if (data[1] == 2) { - /* Clears the Counter subdevice */ - ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x400; - } - outl(ul_Command1, - devpriv->counters + APCI1564_COUNTER_CTRL_REG(chan)); - } else { - dev_err(dev->class_dev, "Invalid subdevice.\n"); + unsigned int ctrl; + + ctrl = inl(devpriv->timer + APCI1564_TIMER_CTRL_REG); + switch (data[1]) { + case 0: /* Stop The Timer */ + ctrl &= 0xfffff9fe; + break; + case 1: /* Enable the Timer */ + ctrl &= 0xfffff9ff; + ctrl |= 0x1; + break; } + outl(ctrl, devpriv->timer + APCI1564_TIMER_CTRL_REG); + return insn->n; } -/* - * Read The Selected Timer or Counter - */ -static int apci1564_timer_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci1564_timer_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct apci1564_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - unsigned int ul_Command1 = 0; - if (devpriv->timer_select_mode == ADDIDATA_TIMER) { - /* Stores the status of the Timer */ - data[0] = inl(devpriv->timer + APCI1564_TIMER_STATUS_REG) & 0x1; + /* Stores the status of the Timer */ + data[0] = inl(devpriv->timer + APCI1564_TIMER_STATUS_REG) & 0x1; - /* Stores the Actual value of the Timer */ - data[1] = inl(devpriv->timer + APCI1564_TIMER_REG); - } else if (devpriv->timer_select_mode == ADDIDATA_COUNTER) { - /* Read the Counter Actual Value. */ - data[0] = inl(devpriv->counters + - APCI1564_COUNTER_REG(chan)); - ul_Command1 = inl(devpriv->counters + - APCI1564_COUNTER_STATUS_REG(chan)); + /* Stores the Actual value of the Timer */ + data[1] = inl(devpriv->timer + APCI1564_TIMER_REG); - /* Get the software trigger status */ - data[1] = (unsigned char) ((ul_Command1 >> 1) & 1); + return insn->n; +} - /* Get the hardware trigger status */ - data[2] = (unsigned char) ((ul_Command1 >> 2) & 1); +static int apci1564_counter_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct apci1564_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int ctrl; - /* Get the software clear status */ - data[3] = (unsigned char) ((ul_Command1 >> 3) & 1); + devpriv->tsk_current = current; - /* Get the overflow status */ - data[4] = (unsigned char) ((ul_Command1 >> 0) & 1); - } else { - dev_err(dev->class_dev, "Invalid subdevice.\n"); + /* First Stop The Counter */ + ctrl = inl(devpriv->counters + APCI1564_COUNTER_CTRL_REG(chan)); + ctrl &= 0xfffff9fe; + /* Stop The Timer */ + outl(ctrl, devpriv->counters + APCI1564_COUNTER_CTRL_REG(chan)); + + /* Set the reload value */ + outl(data[3], devpriv->counters + APCI1564_COUNTER_RELOAD_REG(chan)); + + /* Set the mode : */ + /* - Disable the hardware */ + /* - Disable the counter mode */ + /* - Disable the warning */ + /* - Disable the reset */ + /* - Disable the timer mode */ + /* - Enable the counter mode */ + + ctrl &= 0xfffc19e2; + ctrl |= 0x80000 | (data[4] << 16); + outl(ctrl, devpriv->counters + APCI1564_COUNTER_CTRL_REG(chan)); + + /* Enable or Disable Interrupt */ + ctrl &= 0xfffff9fd; + ctrl |= (data[1] << 1); + outl(ctrl, devpriv->counters + APCI1564_COUNTER_CTRL_REG(chan)); + + /* Set the Up/Down selection */ + ctrl &= 0xfffbf9ff; + ctrl |= (data[6] << 18); + outl(ctrl, devpriv->counters + APCI1564_COUNTER_CTRL_REG(chan)); + + return insn->n; +} + +static int apci1564_counter_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct apci1564_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int ctrl; + + ctrl = inl(devpriv->counters + APCI1564_COUNTER_CTRL_REG(chan)); + switch (data[1]) { + case 0: /* Stops the Counter subdevice */ + ctrl = 0; + break; + case 1: /* Start the Counter subdevice */ + ctrl &= 0xfffff9ff; + ctrl |= 0x1; + break; + case 2: /* Clears the Counter subdevice */ + ctrl &= 0xfffff9ff; + ctrl |= 0x400; + break; } + outl(ctrl, devpriv->counters + APCI1564_COUNTER_CTRL_REG(chan)); + + return insn->n; +} + +static int apci1564_counter_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct apci1564_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int status; + + /* Read the Counter Actual Value. */ + data[0] = inl(devpriv->counters + APCI1564_COUNTER_REG(chan)); + + status = inl(devpriv->counters + APCI1564_COUNTER_STATUS_REG(chan)); + data[1] = (status >> 1) & 1; /* software trigger status */ + data[2] = (status >> 2) & 1; /* hardware trigger status */ + data[3] = (status >> 3) & 1; /* software clear status */ + data[4] = (status >> 0) & 1; /* overflow status */ + return insn->n; } diff --git a/drivers/staging/comedi/drivers/addi_apci_1564.c b/drivers/staging/comedi/drivers/addi_apci_1564.c index 958eb7d29be2..359880d422f2 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1564.c +++ b/drivers/staging/comedi/drivers/addi_apci_1564.c @@ -127,7 +127,6 @@ struct apci1564_private { 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; struct task_struct *tsk_current; }; @@ -486,7 +485,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; @@ -527,25 +526,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_WRITABLE; - s->n_chan = 3; - s->maxdata = 0; + s->subdev_flags = SDF_WRITABLE | SDF_READABLE; + s->n_chan = 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]; + 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;