From: Rodrigo Alencar <[email protected]>

Implement trigger handler by leveraging the LDAC gpio to update all DAC
channels at once when it is available. Also, the multiple channel writes
can be flushed at once with the sync() operation.

Signed-off-by: Rodrigo Alencar <[email protected]>
---
 drivers/iio/dac/Kconfig  |  2 ++
 drivers/iio/dac/ad5686.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 61 insertions(+)

diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index 657c68e75542..5f14fcd780e2 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -240,6 +240,8 @@ config LTC2688
 
 config AD5686
        tristate
+       select IIO_BUFFER
+       select IIO_TRIGGERED_BUFFER
 
 config AD5686_SPI
        tristate "Analog Devices AD5686 and similar multi-channel DACs (SPI)"
diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c
index a4cc0f86ea54..5052df44ab1c 100644
--- a/drivers/iio/dac/ad5686.c
+++ b/drivers/iio/dac/ad5686.c
@@ -19,7 +19,11 @@
 #include <linux/sysfs.h>
 #include <linux/wordpart.h>
 
+#include <linux/iio/buffer.h>
 #include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
 
 #include "ad5686.h"
 
@@ -245,6 +249,7 @@ static const struct iio_chan_spec_ext_info 
ad5686_ext_info[] = {
                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),   \
                .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),\
                .address = addr,                                \
+               .scan_index = chan,                             \
                .scan_type = {                                  \
                        .sign = 'u',                            \
                        .realbits = (bits),                     \
@@ -469,6 +474,53 @@ const struct ad5686_chip_info ad5679r_chip_info = {
 };
 EXPORT_SYMBOL_NS_GPL(ad5679r_chip_info, "IIO_AD5686");
 
+static irqreturn_t ad5686_trigger_handler(int irq, void *p)
+{
+       struct iio_poll_func *pf = p;
+       struct iio_dev *indio_dev = pf->indio_dev;
+       struct iio_buffer *buffer = indio_dev->buffer;
+       struct ad5686_state *st = iio_priv(indio_dev);
+       u16 val[AD5686_MAX_CHANNELS] = { };
+       int ret, ch, i = 0;
+       bool async_update;
+       u8 cmd;
+
+       ret = iio_pop_from_buffer(buffer, val);
+       if (ret)
+               goto out;
+
+       mutex_lock(&st->lock);
+
+       async_update = st->ldac_gpio && 
bitmap_weight(indio_dev->active_scan_mask,
+                                                     
iio_get_masklength(indio_dev)) > 1;
+       if (async_update) {
+               /* use ldac to update all channels simultaneously */
+               cmd = AD5686_CMD_WRITE_INPUT_N;
+               gpiod_set_value_cansleep(st->ldac_gpio, 0);
+       } else {
+               cmd = AD5686_CMD_WRITE_INPUT_N_UPDATE_N;
+       }
+
+       iio_for_each_active_channel(indio_dev, ch) {
+               ret = st->ops->write(st, cmd, indio_dev->channels[ch].address, 
val[i++]);
+               if (ret)
+                       goto cleanup;
+       }
+
+       if (st->ops->sync)
+               ret = st->ops->sync(st); /* flush all pending transfers */
+
+cleanup:
+       if (async_update)
+               gpiod_set_value_cansleep(st->ldac_gpio, 1);
+
+       mutex_unlock(&st->lock);
+out:
+       iio_trigger_notify_done(indio_dev->trig);
+
+       return IRQ_HANDLED;
+}
+
 int ad5686_probe(struct device *dev,
                 const struct ad5686_chip_info *chip_info,
                 const char *name, const struct ad5686_bus_ops *ops,
@@ -569,6 +621,13 @@ int ad5686_probe(struct device *dev,
                return -EINVAL;
        }
 
+       ret = devm_iio_triggered_buffer_setup_ext(dev, indio_dev, NULL,
+                                                 &ad5686_trigger_handler,
+                                                 IIO_BUFFER_DIRECTION_OUT,
+                                                 NULL, NULL);
+       if (ret)
+               return ret;
+
        return devm_iio_device_register(dev, indio_dev);
 }
 EXPORT_SYMBOL_NS_GPL(ad5686_probe, "IIO_AD5686");

-- 
2.43.0



Reply via email to