Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+0 −92
Original line number Diff line number Diff line
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;
}
+92 −2
Original line number Diff line number Diff line
@@ -67,6 +67,12 @@
 * 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
 * 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>
@@ -177,8 +183,6 @@ struct apci1564_private {
	unsigned int ctrl;	/* interrupt mode OR (edge) . AND (level) */
};

#include "addi-data/hwdrv_apci1564.c"

static int apci1564_reset(struct comedi_device *dev)
{
	struct apci1564_private *devpriv = dev->private;
@@ -573,6 +577,92 @@ static int apci1564_timer_insn_read(struct comedi_device *dev,
	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,
				unsigned long context_unused)
{