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

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

staging: comedi: pcl726: add support for the external interrupt signal



The ACL-6126 board supports an external interrupt signal on pin 17 of
its I/O connector (CN3). Add a new subdevice to this driver to support
asynchronous commands with this input.

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 fc93af58
Loading
Loading
Loading
Loading
+111 −4
Original line number Diff line number Diff line
@@ -67,6 +67,8 @@ Interrupts are not supported.

#include "../comedidev.h"

#include "comedi_fc.h"

#define PCL726_AO_MSB_REG(x)	(0x00 + ((x) * 2))
#define PCL726_AO_LSB_REG(x)	(0x01 + ((x) * 2))
#define PCL726_DO_MSB_REG	0x0c
@@ -157,10 +159,94 @@ static const struct pcl726_board boardtypes[] = {
struct pcl726_private {
	const struct comedi_lrange *rangelist[12];
	unsigned int ao_readback[12];
	unsigned int cmd_running:1;
};

static int pcl818_intr_insn_bits(struct comedi_device *dev,
				 struct comedi_subdevice *s,
				 struct comedi_insn *insn,
				 unsigned int *data)
{
	data[1] = 0;
	return insn->n;
}

static int pcl818_intr_cmdtest(struct comedi_device *dev,
			       struct comedi_subdevice *s,
			       struct comedi_cmd *cmd)
{
	int err = 0;

	/* Step 1 : check if triggers are trivially valid */

	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW);
	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE);

	if (err)
		return 1;

	/* Step 2a : make sure trigger sources are unique */
	/* Step 2b : and mutually compatible */

	if (err)
		return 2;

	/* Step 3: check if arguments are trivially valid */

	err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
	err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
	err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
	err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, 1);
	err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);

	if (err)
		return 3;

	/* step 4: ignored */

	if (err)
		return 4;

	return 0;
}

static int pcl818_intr_cmd(struct comedi_device *dev,
			   struct comedi_subdevice *s)
{
	struct pcl726_private *devpriv = dev->private;

	devpriv->cmd_running = 1;

	return 0;
}

static int pcl818_intr_cancel(struct comedi_device *dev,
			      struct comedi_subdevice *s)
{
	struct pcl726_private *devpriv = dev->private;

	devpriv->cmd_running = 0;

	return 0;
}

static irqreturn_t pcl818_interrupt(int irq, void *d)
{
	struct comedi_device *dev = d;
	struct comedi_subdevice *s = dev->read_subdev;
	struct pcl726_private *devpriv = dev->private;

	if (devpriv->cmd_running) {
		pcl818_intr_cancel(dev, s);

		comedi_buf_put(s->async, 0);
		s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
		comedi_event(dev, s);
	}

	return IRQ_HANDLED;
}

@@ -262,6 +348,7 @@ static int pcl726_attach(struct comedi_device *dev,
	const struct pcl726_board *board = comedi_board(dev);
	struct pcl726_private *devpriv;
	struct comedi_subdevice *s;
	int subdev;
	int ret;
	int i;

@@ -296,12 +383,17 @@ static int pcl726_attach(struct comedi_device *dev,
			devpriv->rangelist[i] = &range_unknown;
	}

	ret = comedi_alloc_subdevices(dev, board->have_dio ? 3 : 1);
	subdev = board->have_dio ? 3 : 1;
	if (dev->irq)
		subdev++;
	ret = comedi_alloc_subdevices(dev, subdev);
	if (ret)
		return ret;

	subdev = 0;

	/* Analog Output subdevice */
	s = &dev->subdevices[0];
	s = &dev->subdevices[subdev++];
	s->type		= COMEDI_SUBD_AO;
	s->subdev_flags	= SDF_WRITABLE | SDF_GROUND;
	s->n_chan	= board->ao_nchan;
@@ -312,7 +404,7 @@ static int pcl726_attach(struct comedi_device *dev,

	if (board->have_dio) {
		/* Digital Input subdevice */
		s = &dev->subdevices[1];
		s = &dev->subdevices[subdev++];
		s->type		= COMEDI_SUBD_DI;
		s->subdev_flags	= SDF_READABLE;
		s->n_chan	= 16;
@@ -321,7 +413,7 @@ static int pcl726_attach(struct comedi_device *dev,
		s->range_table	= &range_digital;

		/* Digital Output subdevice */
		s = &dev->subdevices[2];
		s = &dev->subdevices[subdev++];
		s->type		= COMEDI_SUBD_DO;
		s->subdev_flags	= SDF_WRITABLE;
		s->n_chan	= 16;
@@ -330,6 +422,21 @@ static int pcl726_attach(struct comedi_device *dev,
		s->range_table	= &range_digital;
	}

	if (dev->irq) {
		/* Digial Input subdevice - Interrupt support */
		s = &dev->subdevices[subdev++];
		dev->read_subdev = s;
		s->type		= COMEDI_SUBD_DI;
		s->subdev_flags	= SDF_READABLE | SDF_CMD_READ;
		s->n_chan	= 1;
		s->maxdata	= 1;
		s->range_table	= &range_digital;
		s->insn_bits	= pcl818_intr_insn_bits;
		s->do_cmdtest	= pcl818_intr_cmdtest;
		s->do_cmd	= pcl818_intr_cmd;
		s->cancel	= pcl818_intr_cancel;
	}

	return 0;
}