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

staging: comedi: addi_apci_3501: remove timer/counter subdevice support



This driver is for a simple 4/8 channel analog output board with 2 isolated
digital inputs and 2 isolated digital outputs. Support for these subdevices
is provided by the driver.

The boards also has a watchdog timer that can be used to reset the analog
outputs. It can also be used as a general purpose 12-bit timer when the
watchdog function is not necessary. The current support code for this
subdevice is broken. It does not follow the comedi API and requires some
out-of-tree patches in order to even work.

Remove the subdevice support. If a proper register map can be located for
this board we can add support back later.

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 686869b4
Loading
Loading
Loading
Loading
+0 −141
Original line number Diff line number Diff line
/* Watchdog Related Defines */

#define ADDIDATA_TIMER			0
#define ADDIDATA_WATCHDOG		2

/*
 * (*insn_config) for the timer subdevice
 *
 * Configures The Timer, Counter or Watchdog
 * Data Pointer contains configuration parameters as below
 *	data[0] : 0 Configure As Timer
 *		  1 Configure As Counter
 *		  2 Configure As Watchdog
 *	data[1] : 1 Enable  Interrupt
 *		  0 Disable Interrupt
 *	data[2] : Time Unit
 *	data[3] : Reload Value
 */
static int apci3501_config_insn_timer(struct comedi_device *dev,
				      struct comedi_subdevice *s,
				      struct comedi_insn *insn,
				      unsigned int *data)
{
	struct apci3501_private *devpriv = dev->private;
	unsigned int ctrl;

	if (data[0] != ADDIDATA_WATCHDOG &&
	    data[0] != ADDIDATA_TIMER)
		return -EINVAL;

	devpriv->tsk_Current = current;

	devpriv->timer_mode = data[0];

	/* first, disable the watchdog or stop the timer */
	if (devpriv->timer_mode == ADDIDATA_WATCHDOG) {
		ctrl = 0;
	} else {
		ctrl = inl(devpriv->tcw + ADDI_TCW_CTRL_REG);
		ctrl &= ~(ADDI_TCW_CTRL_GATE | ADDI_TCW_CTRL_TRIG |
			  ADDI_TCW_CTRL_ENA);
	}
	outl(ctrl, devpriv->tcw + ADDI_TCW_CTRL_REG);

	/* enable/disable the timer interrupt */
	ctrl = (data[1] == 1) ? ADDI_TCW_CTRL_IRQ_ENA : 0;
	outl(ctrl, devpriv->tcw + ADDI_TCW_CTRL_REG);

	outl(data[2], devpriv->tcw + ADDI_TCW_TIMEBASE_REG);
	outl(data[3], devpriv->tcw + ADDI_TCW_RELOAD_REG);

	ctrl = inl(devpriv->tcw + ADDI_TCW_CTRL_REG);
	if (devpriv->timer_mode == ADDIDATA_WATCHDOG) {
		/* Set the mode (e2->e0) NOTE: this doesn't look correct */
		ctrl |= ~(ADDI_TCW_CTRL_CNT_UP | ADDI_TCW_CTRL_EXT_CLK_MASK |
			  ADDI_TCW_CTRL_MODE_MASK | ADDI_TCW_CTRL_GATE |
			  ADDI_TCW_CTRL_TRIG | ADDI_TCW_CTRL_TIMER_ENA |
			  ADDI_TCW_CTRL_RESET_ENA | ADDI_TCW_CTRL_WARN_ENA |
			  ADDI_TCW_CTRL_IRQ_ENA | ADDI_TCW_CTRL_ENA);
	} else {
		/* mode 2 */
		ctrl &= ~(ADDI_TCW_CTRL_CNTR_ENA | ADDI_TCW_CTRL_MODE_MASK |
			  ADDI_TCW_CTRL_GATE | ADDI_TCW_CTRL_TRIG |
			  ADDI_TCW_CTRL_TIMER_ENA | ADDI_TCW_CTRL_RESET_ENA |
			  ADDI_TCW_CTRL_WARN_ENA | ADDI_TCW_CTRL_ENA);
		ctrl |= ADDI_TCW_CTRL_MODE(2) | ADDI_TCW_CTRL_TIMER_ENA;
	}
	outl(ctrl, devpriv->tcw + ADDI_TCW_CTRL_REG);

	return insn->n;
}

/*
 * (*insn_write) for the timer subdevice
 *
 * Start / Stop The Selected Timer , Counter or Watchdog
 * Data Pointer contains configuration parameters as below
 *	data[0] : 0 Timer
 *		  1 Counter
 *		  2 Watchdog
 *	data[1] : 1 Start
 *		  0 Stop
 *		  2 Trigger
 */
static int apci3501_write_insn_timer(struct comedi_device *dev,
				     struct comedi_subdevice *s,
				     struct comedi_insn *insn,
				     unsigned int *data)
{
	struct apci3501_private *devpriv = dev->private;
	unsigned int ctrl;

	if (devpriv->timer_mode == ADDIDATA_WATCHDOG ||
	    devpriv->timer_mode == ADDIDATA_TIMER) {
		ctrl = inl(devpriv->tcw + ADDI_TCW_CTRL_REG);
		ctrl &= ~(ADDI_TCW_CTRL_GATE | ADDI_TCW_CTRL_TRIG);

		if (data[1] == 1) {		/* enable */
			ctrl |= ADDI_TCW_CTRL_ENA;
		} else if (data[1] == 0) {	/* stop */
			if (devpriv->timer_mode == ADDIDATA_WATCHDOG)
				ctrl = 0;
			else
				ctrl &= ~ADDI_TCW_CTRL_ENA;
		} else if (data[1] == 2) {	/* trigger */
			ctrl |= ADDI_TCW_CTRL_TRIG;
		}
		outl(ctrl, devpriv->tcw + ADDI_TCW_CTRL_REG);
	}

	inl(devpriv->tcw + ADDI_TCW_STATUS_REG);
	return insn->n;
}

/*
 * (*insn_read) for the timer subdevice
 *
 * Read The Selected Timer, Counter or Watchdog
 * Data Pointer contains configuration parameters as below
 *	data[0] : 0 Timer
 *		  1 Counter
 *		  2 Watchdog
 *	data[1] : Timer Counter Watchdog Number
 */
static int apci3501_read_insn_timer(struct comedi_device *dev,
				    struct comedi_subdevice *s,
				    struct comedi_insn *insn,
				    unsigned int *data)
{
	struct apci3501_private *devpriv = dev->private;

	if (devpriv->timer_mode != ADDIDATA_TIMER &&
	    devpriv->timer_mode != ADDIDATA_WATCHDOG)
		return -EINVAL;

	data[0] = inl(devpriv->tcw + ADDI_TCW_STATUS_REG) &
		  ADDI_TCW_STATUS_OVERFLOW;
	data[1] = inl(devpriv->tcw + ADDI_TCW_VAL_REG);

	return insn->n;
}
+2 −56
Original line number Diff line number Diff line
@@ -23,11 +23,8 @@
 */

#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/sched.h>

#include "../comedi_pci.h"
#include "addi_tcw.h"
#include "amcc_s5933.h"

/*
@@ -67,8 +64,6 @@

struct apci3501_private {
	unsigned long amcc;
	unsigned long tcw;
	struct task_struct *tsk_Current;
	unsigned char timer_mode;
};

@@ -139,8 +134,6 @@ static int apci3501_ao_insn_write(struct comedi_device *dev,
	return insn->n;
}

#include "addi-data/hwdrv_apci3501.c"

static int apci3501_di_insn_bits(struct comedi_device *dev,
				 struct comedi_subdevice *s,
				 struct comedi_insn *insn,
@@ -253,37 +246,6 @@ static int apci3501_eeprom_insn_read(struct comedi_device *dev,
	return insn->n;
}

static irqreturn_t apci3501_interrupt(int irq, void *d)
{
	struct comedi_device *dev = d;
	struct apci3501_private *devpriv = dev->private;
	unsigned int status;
	unsigned int ctrl;

	/*  Disable Interrupt */
	ctrl = inl(devpriv->tcw + ADDI_TCW_CTRL_REG);
	ctrl &= ~(ADDI_TCW_CTRL_GATE | ADDI_TCW_CTRL_TRIG |
		  ADDI_TCW_CTRL_IRQ_ENA);
	outl(ctrl, devpriv->tcw + ADDI_TCW_CTRL_REG);

	status = inl(devpriv->tcw + ADDI_TCW_IRQ_REG);
	if (!(status & ADDI_TCW_IRQ)) {
		dev_err(dev->class_dev, "IRQ from unknown source\n");
		return IRQ_NONE;
	}

	/* Enable Interrupt Send a signal to from kernel to user space */
	send_sig(SIGIO, devpriv->tsk_Current, 0);
	ctrl = inl(devpriv->tcw + ADDI_TCW_CTRL_REG);
	ctrl &= ~(ADDI_TCW_CTRL_GATE | ADDI_TCW_CTRL_TRIG |
		  ADDI_TCW_CTRL_IRQ_ENA);
	ctrl |= ADDI_TCW_CTRL_IRQ_ENA;
	outl(ctrl, devpriv->tcw + ADDI_TCW_CTRL_REG);
	inl(devpriv->tcw + ADDI_TCW_STATUS_REG);

	return IRQ_HANDLED;
}

static int apci3501_reset(struct comedi_device *dev)
{
	unsigned int val;
@@ -333,17 +295,9 @@ static int apci3501_auto_attach(struct comedi_device *dev,

	devpriv->amcc = pci_resource_start(pcidev, 0);
	dev->iobase = pci_resource_start(pcidev, 1);
	devpriv->tcw = dev->iobase + APCI3501_TIMER_BASE;

	ao_n_chan = apci3501_eeprom_get_ao_n_chan(dev);

	if (pcidev->irq > 0) {
		ret = request_irq(pcidev->irq, apci3501_interrupt, IRQF_SHARED,
				  dev->board_name, dev);
		if (ret == 0)
			dev->irq = pcidev->irq;
	}

	ret = comedi_alloc_subdevices(dev, 5);
	if (ret)
		return ret;
@@ -383,17 +337,9 @@ static int apci3501_auto_attach(struct comedi_device *dev,
	s->range_table	= &range_digital;
	s->insn_bits	= apci3501_do_insn_bits;

	/* Initialize the timer/watchdog subdevice */
	/* Timer/Watchdog subdevice */
	s = &dev->subdevices[3];
	s->type = COMEDI_SUBD_TIMER;
	s->subdev_flags = SDF_WRITABLE;
	s->n_chan = 1;
	s->maxdata = 0;
	s->len_chanlist = 1;
	s->range_table = &range_digital;
	s->insn_write = apci3501_write_insn_timer;
	s->insn_read = apci3501_read_insn_timer;
	s->insn_config = apci3501_config_insn_timer;
	s->type		= COMEDI_SUBD_UNUSED;

	/* Initialize the eeprom subdevice */
	s = &dev->subdevices[4];