@@ -29,6 +29,8 @@
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
+#include <dt-bindings/iio/adc/adi,ad7768-1.h>
+
/* AD7768 registers definition */
#define AD7768_REG_CHIP_TYPE 0x3
#define AD7768_REG_PROD_ID_L 0x4
@@ -101,6 +103,8 @@
#define AD7768_VCM_OFF 0x07
+#define AD7768_TRIGGER_SOURCE_SYNC_IDX 0
+
enum ad7768_conv_mode {
AD7768_CONTINUOUS,
AD7768_ONE_SHOT,
@@ -209,6 +213,7 @@ struct ad7768_state {
struct iio_trigger *trig;
struct gpio_desc *gpio_sync_in;
struct gpio_desc *gpio_reset;
+ bool en_spi_sync;
const char *labels[ARRAY_SIZE(ad7768_channels)];
struct gpio_chip gpiochip;
/*
@@ -296,6 +301,27 @@ static const struct regmap_config ad7768_regmap24_config = {
.max_register = AD7768_REG24_COEFF_DATA,
};
+static int ad7768_send_sync_pulse(struct ad7768_state *st)
+{
+ if (st->en_spi_sync)
+ return regmap_write(st->regmap, AD7768_REG_SYNC_RESET, 0x00);
+
+ /*
+ * The datasheet specifies a minimum SYNC_IN pulse width of 1.5 × Tmclk,
+ * where Tmclk is the MCLK period. The supported MCLK frequencies range
+ * from 0.6 MHz to 17 MHz, which corresponds to a minimum SYNC_IN pulse
+ * width of approximately 2.5 µs in the worst-case scenario (0.6 MHz).
+ *
+ * Add a delay to ensure the pulse width is always sufficient to
+ * trigger synchronization.
+ */
+ gpiod_set_value_cansleep(st->gpio_sync_in, 1);
+ fsleep(3);
+ gpiod_set_value_cansleep(st->gpio_sync_in, 0);
+
+ return 0;
+}
+
static int ad7768_set_mode(struct ad7768_state *st,
enum ad7768_conv_mode mode)
{
@@ -392,10 +418,7 @@ static int ad7768_set_dig_fil(struct ad7768_state *st,
return ret;
/* A sync-in pulse is required every time the filter dec rate changes */
- gpiod_set_value(st->gpio_sync_in, 1);
- gpiod_set_value(st->gpio_sync_in, 0);
-
- return 0;
+ return ad7768_send_sync_pulse(st);
}
static int ad7768_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
@@ -672,6 +695,62 @@ static const struct iio_info ad7768_info = {
.debugfs_reg_access = &ad7768_reg_access,
};
+static int ad7768_trigger_sources_sync_setup(struct device *dev,
+ struct fwnode_handle *dev_fwnode,
+ struct ad7768_state *st)
+{
+ struct fwnode_reference_args args;
+
+ struct fwnode_handle *fwnode __free(fwnode_handle) =
+ fwnode_find_reference_args(dev_fwnode, "trigger-sources",
+ "#trigger-source-cells", 0,
+ AD7768_TRIGGER_SOURCE_SYNC_IDX, &args);
+ if (IS_ERR(fwnode))
+ return PTR_ERR(fwnode);
+
+ /* First, try getting the GPIO trigger source */
+ if (fwnode_device_is_compatible(fwnode, "gpio-trigger")) {
+ st->gpio_sync_in = devm_fwnode_gpiod_get_index(dev, fwnode,
+ NULL,
+ 0,
+ GPIOD_OUT_LOW,
+ "sync-in");
+ return PTR_ERR_OR_ZERO(st->gpio_sync_in);
+ }
+
+ /*
+ * TODO: Support the other cases when we have a trigger subsystem
+ * to reliably handle other types of devices as trigger sources.
+ *
+ * For now, return an error message. For self triggering, omit the
+ * trigger-sources property.
+ */
+ return dev_err_probe(dev, -EOPNOTSUPP, "Invalid synchronization trigger source\n");
+}
+
+static int ad7768_trigger_sources_get_sync(struct device *dev,
+ struct ad7768_state *st)
+{
+ struct fwnode_handle *dev_fwnode = dev_fwnode(dev);
+
+ /*
+ * The AD7768-1 allows two primary methods for driving the SYNC_IN pin
+ * to synchronize one or more devices:
+ * 1. Using an external GPIO.
+ * 2. Using a SPI command, where the SYNC_OUT pin generates a
+ * synchronization pulse that drives the SYNC_IN pin.
+ */
+ if (fwnode_property_present(dev_fwnode, "trigger-sources"))
+ return ad7768_trigger_sources_sync_setup(dev, dev_fwnode, st);
+
+ /*
+ * In the absence of trigger-sources property, enable self
+ * synchronization over SPI (SYNC_OUT).
+ */
+ st->en_spi_sync = true;
+ return 0;
+}
+
static int ad7768_setup(struct iio_dev *indio_dev)
{
struct ad7768_state *st = iio_priv(indio_dev);
@@ -702,11 +781,22 @@ static int ad7768_setup(struct iio_dev *indio_dev)
return ret;
}
- st->gpio_sync_in = devm_gpiod_get(&st->spi->dev, "adi,sync-in",
- GPIOD_OUT_LOW);
+ /* For backwards compatibility, try the adi,sync-in-gpios property */
+ st->gpio_sync_in = devm_gpiod_get_optional(&st->spi->dev, "adi,sync-in",
+ GPIOD_OUT_LOW);
if (IS_ERR(st->gpio_sync_in))
return PTR_ERR(st->gpio_sync_in);
+ /*
+ * If the synchronization is not defined by adi,sync-in-gpios, try the
+ * trigger-sources.
+ */
+ if (!st->gpio_sync_in) {
+ ret = ad7768_trigger_sources_get_sync(&st->spi->dev, st);
+ if (ret)
+ return ret;
+ }
+
/* Only create a Chip GPIO if flagged for it */
if (device_property_read_bool(&st->spi->dev, "gpio-controller")) {
ret = ad7768_gpio_init(indio_dev);