diff options
author | Ian Abbott <abbotti@mev.co.uk> | 2014-07-21 17:29:05 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-07-22 16:07:05 -0700 |
commit | 110f9e687c1a8490383612817ac03f4b29861da1 (patch) | |
tree | 4d5dea9d237aee72c7af1ba80c6b35cce419b9a6 /drivers | |
parent | d484e33728f13ce1f0a0014d6b4068d053ed69b3 (diff) |
staging: comedi: ni_6527: support INSN_CONFIG_DIGITAL_TRIG
The "edge detection interrupt" subdevice supports the
`INSN_CONFIG_CHANGE_NOTIFY` comedi instruction which is only supported
by one other driver. The `INSN_CONFIG_DIGITAL_TRIG` comedi instruction
is more flexible as it supports both edge and level detection, but is
not currently supported by this driver.
Add partial support for `INSN_CONFIG_DIGITAL_TRIG`, but only for edge
detection. Make use of the `ni6527_set_edge_detection()` used for
`INSN_CONFIG_CHANGE_NOTIFY`, but add a parameter holding a mask of the
rising and falling edges to be updated and preserve the unmasked edges
when updating.
Signed-off-by: Ian Abbott <abbotti@mev.co.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/staging/comedi/drivers/ni_6527.c | 72 |
1 files changed, 61 insertions, 11 deletions
diff --git a/drivers/staging/comedi/drivers/ni_6527.c b/drivers/staging/comedi/drivers/ni_6527.c index c8b1fa793a37..57d8d4c30459 100644 --- a/drivers/staging/comedi/drivers/ni_6527.c +++ b/drivers/staging/comedi/drivers/ni_6527.c @@ -299,21 +299,38 @@ static int ni6527_intr_insn_bits(struct comedi_device *dev, } static void ni6527_set_edge_detection(struct comedi_device *dev, + unsigned int mask, unsigned int rising, unsigned int falling) { struct ni6527_private *devpriv = dev->private; void __iomem *mmio = devpriv->mmio_base; - - /* enable rising-edge detection channels */ - writeb(rising & 0xff, mmio + NI6527_RISING_EDGE_REG(0)); - writeb((rising >> 8) & 0xff, mmio + NI6527_RISING_EDGE_REG(1)); - writeb((rising >> 16) & 0xff, mmio + NI6527_RISING_EDGE_REG(2)); - - /* enable falling-edge detection channels */ - writeb(falling & 0xff, mmio + NI6527_FALLING_EDGE_REG(0)); - writeb((falling >> 8) & 0xff, mmio + NI6527_FALLING_EDGE_REG(1)); - writeb((falling >> 16) & 0xff, mmio + NI6527_FALLING_EDGE_REG(2)); + unsigned int i; + + rising &= mask; + falling &= mask; + for (i = 0; i < 2; i++) { + if (mask & 0xff) { + if (~mask & 0xff) { + /* preserve rising-edge detection channels */ + rising |= readb(mmio + + NI6527_RISING_EDGE_REG(i)) & + (~mask & 0xff); + /* preserve falling-edge detection channels */ + falling |= readb(mmio + + NI6527_FALLING_EDGE_REG(i)) & + (~mask & 0xff); + } + /* update rising-edge detection channels */ + writeb(rising & 0xff, mmio + NI6527_RISING_EDGE_REG(i)); + /* update falling-edge detection channels */ + writeb(falling & 0xff, + mmio + NI6527_FALLING_EDGE_REG(i)); + } + rising >>= 8; + falling >>= 8; + mask >>= 8; + } } static int ni6527_intr_insn_config(struct comedi_device *dev, @@ -321,12 +338,45 @@ static int ni6527_intr_insn_config(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { + unsigned int mask = 0xffffffff; + unsigned int rising, falling, shift; + switch (data[0]) { case INSN_CONFIG_CHANGE_NOTIFY: /* check_insn_config_length() does not check this instruction */ if (insn->n != 3) return -EINVAL; - ni6527_set_edge_detection(dev, data[1], data[2]); + rising = data[1]; + falling = data[2]; + ni6527_set_edge_detection(dev, mask, rising, falling); + break; + case INSN_CONFIG_DIGITAL_TRIG: + /* check trigger number */ + if (data[1] != 0) + return -EINVAL; + /* check digital trigger operation */ + switch (data[2]) { + case COMEDI_DIGITAL_TRIG_DISABLE: + rising = 0; + falling = 0; + break; + case COMEDI_DIGITAL_TRIG_ENABLE_EDGES: + /* check shift amount */ + shift = data[3]; + if (shift >= s->n_chan) { + mask = 0; + rising = 0; + falling = 0; + } else { + mask <<= shift; + rising = data[4] << shift; + falling = data[5] << shift; + } + break; + default: + return -EINVAL; + } + ni6527_set_edge_detection(dev, mask, rising, falling); break; default: return -EINVAL; |