iio: dac: ad5686: add triggered buffer support

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.

Reviewed-by: David Lechner <dlechner@baylibre.com>
Signed-off-by: Rodrigo Alencar <rodrigo.alencar@analog.com>
Signed-off-by: Jonathan Cameron <jonathan.cameron@oss.qualcomm.com>
This commit is contained in:
Rodrigo Alencar 2026-07-16 13:14:23 +01:00 committed by Jonathan Cameron
parent 32052904ae
commit a3c37fa97b
2 changed files with 67 additions and 0 deletions

View File

@ -243,6 +243,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)"

View File

@ -21,7 +21,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"
@ -243,6 +247,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), \
@ -467,6 +472,59 @@ const struct ad5686_chip_info ad5679r_chip_info = {
};
EXPORT_SYMBOL_NS_GPL(ad5679r_chip_info, "IIO_AD5686");
static void do_ad5686_trigger_handler(struct iio_dev *indio_dev)
{
struct ad5686_state *st = iio_priv(indio_dev);
u16 val[AD5686_MAX_CHANNELS] = { };
unsigned int scan_count, ch, i;
bool async_update;
u8 cmd;
if (iio_pop_from_buffer(indio_dev->buffer, val))
return;
guard(mutex)(&st->lock);
scan_count = bitmap_weight(indio_dev->active_scan_mask,
iio_get_masklength(indio_dev));
async_update = st->ldac_gpio && scan_count > 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;
}
i = 0;
iio_for_each_active_channel(indio_dev, ch) {
if (st->ops->write(st, cmd, indio_dev->channels[ch].address, val[i++]))
break;
}
/*
* If sync() is available, it is called here regardless of write
* failure to allow bus implementation to reset. In that case, partial
* writes are unlikely as the write operations would just queue up
* the transfers.
*/
if (st->ops->sync)
st->ops->sync(st);
if (async_update)
gpiod_set_value_cansleep(st->ldac_gpio, 1);
}
static irqreturn_t ad5686_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
do_ad5686_trigger_handler(indio_dev);
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 +627,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");