Commit 2ec19efb authored by H Hartley Sweeten's avatar H Hartley Sweeten Committed by Greg Kroah-Hartman

staging: comedi: addi_apci_1564: rewrite the counter subdevice support

Like the timer, the support functions for the counter subdevice are broken.

Rewrite the code to follow the comedi API.

The new implementation is based on the (minimal) datasheet I have from
ADDI-DATA.
Signed-off-by: default avatarH Hartley Sweeten <hsweeten@visionengravers.com>
Reviewed-by: default avatarIan Abbott <abbotti@mev.co.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 05704ffa
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 long iobase = devpriv->counters + APCI1564_COUNTER(chan);
unsigned int ctrl;
/* Stop The Timer */
ctrl = inl(iobase + ADDI_TCW_CTRL_REG);
ctrl &= ~(ADDI_TCW_CTRL_GATE | ADDI_TCW_CTRL_TRIG |
ADDI_TCW_CTRL_ENA);
outl(ctrl, iobase + ADDI_TCW_CTRL_REG);
/* Set the reload value */
outl(data[3], iobase + ADDI_TCW_RELOAD_REG);
/* Set the mode */
ctrl &= ~(ADDI_TCW_CTRL_EXT_CLK_MASK | ADDI_TCW_CTRL_MODE_MASK |
ADDI_TCW_CTRL_TIMER_ENA | ADDI_TCW_CTRL_RESET_ENA |
ADDI_TCW_CTRL_WARN_ENA);
ctrl |= ADDI_TCW_CTRL_CNTR_ENA | ADDI_TCW_CTRL_MODE(data[4]);
outl(ctrl, iobase + ADDI_TCW_CTRL_REG);
/* Enable or Disable Interrupt */
if (data[1])
ctrl |= ADDI_TCW_CTRL_IRQ_ENA;
else
ctrl &= ~ADDI_TCW_CTRL_IRQ_ENA;
outl(ctrl, iobase + ADDI_TCW_CTRL_REG);
/* Set the Up/Down selection */
if (data[6])
ctrl |= ADDI_TCW_CTRL_CNT_UP;
else
ctrl &= ~ADDI_TCW_CTRL_CNT_UP;
outl(ctrl, iobase + ADDI_TCW_CTRL_REG);
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 long iobase = devpriv->counters + APCI1564_COUNTER(chan);
unsigned int ctrl;
ctrl = inl(iobase + ADDI_TCW_CTRL_REG);
ctrl &= ~(ADDI_TCW_CTRL_GATE | ADDI_TCW_CTRL_TRIG);
switch (data[1]) {
case 0: /* Stops the Counter subdevice */
ctrl = 0;
break;
case 1: /* Start the Counter subdevice */
ctrl |= ADDI_TCW_CTRL_ENA;
break;
case 2: /* Clears the Counter subdevice */
ctrl |= ADDI_TCW_CTRL_GATE;
break;
}
outl(ctrl, iobase + ADDI_TCW_CTRL_REG);
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 long iobase = devpriv->counters + APCI1564_COUNTER(chan);
unsigned int status;
/* Read the Counter Actual Value. */
data[0] = inl(iobase + ADDI_TCW_VAL_REG);
status = inl(iobase + ADDI_TCW_STATUS_REG);
data[1] = (status & ADDI_TCW_STATUS_SOFT_TRIG) ? 1 : 0;
data[2] = (status & ADDI_TCW_STATUS_HARDWARE_TRIG) ? 1 : 0;
data[3] = (status & ADDI_TCW_STATUS_SOFT_CLR) ? 1 : 0;
data[4] = (status & ADDI_TCW_STATUS_OVERFLOW) ? 1 : 0;
return insn->n;
}
...@@ -67,6 +67,12 @@ ...@@ -67,6 +67,12 @@
* the raw data[1] to this register along with the raw data[2] value to the * the raw data[1] to this register along with the raw data[2] value to the
* ADDI_TCW_RELOAD_REG. If anyone tests this and can determine the actual * ADDI_TCW_RELOAD_REG. If anyone tests this and can determine the actual
* timebase/reload operation please let me know. * timebase/reload operation please let me know.
*
* The counter subdevice also does not use an async command. All control is
* handled by the (*insn_config).
*
* FIXME: The operation of the counters is not really described in the
* datasheet I have. The (*insn_config) needs more work.
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -177,8 +183,6 @@ struct apci1564_private { ...@@ -177,8 +183,6 @@ struct apci1564_private {
unsigned int ctrl; /* interrupt mode OR (edge) . AND (level) */ unsigned int ctrl; /* interrupt mode OR (edge) . AND (level) */
}; };
#include "addi-data/hwdrv_apci1564.c"
static int apci1564_reset(struct comedi_device *dev) static int apci1564_reset(struct comedi_device *dev)
{ {
struct apci1564_private *devpriv = dev->private; struct apci1564_private *devpriv = dev->private;
...@@ -573,6 +577,92 @@ static int apci1564_timer_insn_read(struct comedi_device *dev, ...@@ -573,6 +577,92 @@ static int apci1564_timer_insn_read(struct comedi_device *dev,
return insn->n; return insn->n;
} }
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 long iobase = devpriv->counters + APCI1564_COUNTER(chan);
unsigned int val;
switch (data[0]) {
case INSN_CONFIG_ARM:
val = inl(iobase + ADDI_TCW_CTRL_REG);
val |= ADDI_TCW_CTRL_IRQ_ENA | ADDI_TCW_CTRL_CNTR_ENA;
outl(data[1], iobase + ADDI_TCW_RELOAD_REG);
outl(val, iobase + ADDI_TCW_CTRL_REG);
break;
case INSN_CONFIG_DISARM:
val = inl(iobase + ADDI_TCW_CTRL_REG);
val &= ~(ADDI_TCW_CTRL_IRQ_ENA | ADDI_TCW_CTRL_CNTR_ENA);
outl(val, iobase + ADDI_TCW_CTRL_REG);
break;
case INSN_CONFIG_SET_COUNTER_MODE:
/*
* FIXME: The counter operation is not described in the
* datasheet. For now just write the raw data[1] value to
* the control register.
*/
outl(data[1], iobase + ADDI_TCW_CTRL_REG);
break;
case INSN_CONFIG_GET_COUNTER_STATUS:
data[1] = 0;
val = inl(iobase + ADDI_TCW_CTRL_REG);
if (val & ADDI_TCW_CTRL_IRQ_ENA)
data[1] |= COMEDI_COUNTER_ARMED;
if (val & ADDI_TCW_CTRL_CNTR_ENA)
data[1] |= COMEDI_COUNTER_COUNTING;
val = inl(iobase + ADDI_TCW_STATUS_REG);
if (val & ADDI_TCW_STATUS_OVERFLOW)
data[1] |= COMEDI_COUNTER_TERMINAL_COUNT;
data[2] = COMEDI_COUNTER_ARMED | COMEDI_COUNTER_COUNTING |
COMEDI_COUNTER_TERMINAL_COUNT;
break;
default:
return -EINVAL;
}
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 long iobase = devpriv->counters + APCI1564_COUNTER(chan);
/* just write the last last to the reload register */
if (insn->n) {
unsigned int val = data[insn->n - 1];
outl(val, iobase + ADDI_TCW_RELOAD_REG);
}
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 long iobase = devpriv->counters + APCI1564_COUNTER(chan);
int i;
/* return the actual value of the counter */
for (i = 0; i < insn->n; i++)
data[i] = inl(iobase + ADDI_TCW_VAL_REG);
return insn->n;
}
static int apci1564_auto_attach(struct comedi_device *dev, static int apci1564_auto_attach(struct comedi_device *dev,
unsigned long context_unused) unsigned long context_unused)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment