* [PATCH v7 1/7] dt-bindings: iio: adc: Add binding for AD7380 ADCs
2024-05-28 14:20 [PATCH v7 0/7] iio: adc: add new ad7380 driver Julien Stephan
@ 2024-05-28 14:20 ` Julien Stephan
2024-05-28 14:20 ` [PATCH v7 2/7] iio: adc: ad7380: new driver " Julien Stephan
` (6 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Julien Stephan @ 2024-05-28 14:20 UTC (permalink / raw)
To: Lars-Peter Clausen, Michael Hennerich, Nuno Sá,
David Lechner, Jonathan Cameron, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Liam Girdwood, Mark Brown
Cc: kernel test robot, linux-iio, devicetree, linux-kernel,
Julien Stephan, Conor Dooley
From: David Lechner <dlechner@baylibre.com>
This adds a binding specification for the Analog Devices Inc. AD7380
family of ADCs.
Signed-off-by: David Lechner <dlechner@baylibre.com>
Signed-off-by: Julien Stephan <jstephan@baylibre.com>
Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
---
.../devicetree/bindings/iio/adc/adi,ad7380.yaml | 82 ++++++++++++++++++++++
MAINTAINERS | 9 +++
2 files changed, 91 insertions(+)
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml
new file mode 100644
index 000000000000..5e1ee0ebe0a2
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml
@@ -0,0 +1,82 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/adc/adi,ad7380.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices Simultaneous Sampling Analog to Digital Converters
+
+maintainers:
+ - Michael Hennerich <Michael.Hennerich@analog.com>
+ - Nuno Sá <nuno.sa@analog.com>
+
+description: |
+ * https://www.analog.com/en/products/ad7380.html
+ * https://www.analog.com/en/products/ad7381.html
+
+$ref: /schemas/spi/spi-peripheral-props.yaml#
+
+properties:
+ compatible:
+ enum:
+ - adi,ad7380
+ - adi,ad7381
+
+ reg:
+ maxItems: 1
+
+ spi-max-frequency:
+ maximum: 80000000
+ spi-cpol: true
+ spi-cpha: true
+
+ vcc-supply:
+ description: A 3V to 3.6V supply that powers the chip.
+
+ vlogic-supply:
+ description:
+ A 1.65V to 3.6V supply for the logic pins.
+
+ refio-supply:
+ description:
+ A 2.5V to 3.3V supply for the external reference voltage. When omitted,
+ the internal 2.5V reference is used.
+
+ interrupts:
+ description:
+ When the device is using 1-wire mode, this property is used to optionally
+ specify the ALERT interrupt.
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - vcc-supply
+ - vlogic-supply
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ adc@0 {
+ compatible = "adi,ad7380";
+ reg = <0>;
+
+ spi-cpol;
+ spi-cpha;
+ spi-max-frequency = <80000000>;
+
+ interrupts = <27 IRQ_TYPE_EDGE_FALLING>;
+ interrupt-parent = <&gpio0>;
+
+ vcc-supply = <&supply_3_3V>;
+ vlogic-supply = <&supply_3_3V>;
+ refio-supply = <&supply_2_5V>;
+ };
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index 758c202ec712..4f162600e982 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -427,6 +427,15 @@ W: http://wiki.analog.com/AD7142
W: https://ez.analog.com/linux-software-drivers
F: drivers/input/misc/ad714x.c
+AD738X ADC DRIVER (AD7380/1/2/4)
+M: Michael Hennerich <michael.hennerich@analog.com>
+M: Nuno Sá <nuno.sa@analog.com>
+R: David Lechner <dlechner@baylibre.com>
+S: Supported
+W: https://wiki.analog.com/resources/tools-software/linux-drivers/iio-adc/ad738x
+W: https://ez.analog.com/linux-software-drivers
+F: Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml
+
AD7877 TOUCHSCREEN DRIVER
M: Michael Hennerich <michael.hennerich@analog.com>
S: Supported
--
2.44.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v7 2/7] iio: adc: ad7380: new driver for AD7380 ADCs
2024-05-28 14:20 [PATCH v7 0/7] iio: adc: add new ad7380 driver Julien Stephan
2024-05-28 14:20 ` [PATCH v7 1/7] dt-bindings: iio: adc: Add binding for AD7380 ADCs Julien Stephan
@ 2024-05-28 14:20 ` Julien Stephan
2024-05-28 14:20 ` [PATCH v7 3/7] dt-bindings: iio: adc: ad7380: add pseudo-differential parts Julien Stephan
` (5 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Julien Stephan @ 2024-05-28 14:20 UTC (permalink / raw)
To: Lars-Peter Clausen, Michael Hennerich, Nuno Sá,
David Lechner, Jonathan Cameron, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Liam Girdwood, Mark Brown
Cc: kernel test robot, linux-iio, devicetree, linux-kernel,
Julien Stephan, Stefan Popa
From: David Lechner <dlechner@baylibre.com>
This adds a new driver for the AD7380 family ADCs.
The driver currently implements basic support for the AD7380, AD7381,
2-channel differential ADCs. Support for additional single-ended,
pseudo-differential and 4-channel chips that use the same register map
as well as additional features of the chip will be added in future patches.
Co-developed-by: Stefan Popa <stefan.popa@analog.com>
Signed-off-by: Stefan Popa <stefan.popa@analog.com>
Reviewed-by: Nuno Sa <nuno.sa@analog.com>
Signed-off-by: David Lechner <dlechner@baylibre.com>
[Julien Stephan: add datasheet links of supported parts]
[Julien Stephan: fix rx/tx buffer for regmap access]
[Julien Stephan: fix scale issue]
[Julien Stephan: use the new iio_device_claim_direct_scoped
instead of iio_device_claim_direct_mode]
Signed-off-by: Julien Stephan <jstephan@baylibre.com>
---
MAINTAINERS | 1 +
drivers/iio/adc/Kconfig | 16 ++
drivers/iio/adc/Makefile | 1 +
drivers/iio/adc/ad7380.c | 438 +++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 456 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 4f162600e982..315b3060946f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -435,6 +435,7 @@ S: Supported
W: https://wiki.analog.com/resources/tools-software/linux-drivers/iio-adc/ad738x
W: https://ez.analog.com/linux-software-drivers
F: Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml
+F: drivers/iio/adc/ad7380.c
AD7877 TOUCHSCREEN DRIVER
M: Michael Hennerich <michael.hennerich@analog.com>
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 8db68b80b391..631386b037ae 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -155,6 +155,22 @@ config AD7298
To compile this driver as a module, choose M here: the
module will be called ad7298.
+config AD7380
+ tristate "Analog Devices AD7380 ADC driver"
+ depends on SPI_MASTER
+ select IIO_BUFFER
+ select IIO_TRIGGER
+ select IIO_TRIGGERED_BUFFER
+ help
+ AD7380 is a family of simultaneous sampling ADCs that share the same
+ SPI register map and have similar pinouts.
+
+ Say yes here to build support for Analog Devices AD7380 ADC and
+ similar chips.
+
+ To compile this driver as a module, choose M here: the module will be
+ called ad7380.
+
config AD7476
tristate "Analog Devices AD7476 1-channel ADCs driver and other similar devices from AD and TI"
depends on SPI
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index edb32ce2af02..bd3cbbb178fa 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_AD7291) += ad7291.o
obj-$(CONFIG_AD7292) += ad7292.o
obj-$(CONFIG_AD7298) += ad7298.o
obj-$(CONFIG_AD7923) += ad7923.o
+obj-$(CONFIG_AD7380) += ad7380.o
obj-$(CONFIG_AD7476) += ad7476.o
obj-$(CONFIG_AD7606_IFACE_PARALLEL) += ad7606_par.o
obj-$(CONFIG_AD7606_IFACE_SPI) += ad7606_spi.o
diff --git a/drivers/iio/adc/ad7380.c b/drivers/iio/adc/ad7380.c
new file mode 100644
index 000000000000..dac7e11755ff
--- /dev/null
+++ b/drivers/iio/adc/ad7380.c
@@ -0,0 +1,438 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Analog Devices AD738x Simultaneous Sampling SAR ADCs
+ *
+ * Copyright 2017 Analog Devices Inc.
+ * Copyright 2024 BayLibre, SAS
+ *
+ * Datasheets of supported parts:
+ * ad7380/1 : https://www.analog.com/media/en/technical-documentation/data-sheets/AD7380-7381.pdf
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/cleanup.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+/* 2.5V internal reference voltage */
+#define AD7380_INTERNAL_REF_MV 2500
+
+/* reading and writing registers is more reliable at lower than max speed */
+#define AD7380_REG_WR_SPEED_HZ 10000000
+
+#define AD7380_REG_WR BIT(15)
+#define AD7380_REG_REGADDR GENMASK(14, 12)
+#define AD7380_REG_DATA GENMASK(11, 0)
+
+#define AD7380_REG_ADDR_NOP 0x0
+#define AD7380_REG_ADDR_CONFIG1 0x1
+#define AD7380_REG_ADDR_CONFIG2 0x2
+#define AD7380_REG_ADDR_ALERT 0x3
+#define AD7380_REG_ADDR_ALERT_LOW_TH 0x4
+#define AD7380_REG_ADDR_ALERT_HIGH_TH 0x5
+
+#define AD7380_CONFIG1_OS_MODE BIT(9)
+#define AD7380_CONFIG1_OSR GENMASK(8, 6)
+#define AD7380_CONFIG1_CRC_W BIT(5)
+#define AD7380_CONFIG1_CRC_R BIT(4)
+#define AD7380_CONFIG1_ALERTEN BIT(3)
+#define AD7380_CONFIG1_RES BIT(2)
+#define AD7380_CONFIG1_REFSEL BIT(1)
+#define AD7380_CONFIG1_PMODE BIT(0)
+
+#define AD7380_CONFIG2_SDO2 GENMASK(9, 8)
+#define AD7380_CONFIG2_SDO BIT(8)
+#define AD7380_CONFIG2_RESET GENMASK(7, 0)
+
+#define AD7380_CONFIG2_RESET_SOFT 0x3C
+#define AD7380_CONFIG2_RESET_HARD 0xFF
+
+#define AD7380_ALERT_LOW_TH GENMASK(11, 0)
+#define AD7380_ALERT_HIGH_TH GENMASK(11, 0)
+
+struct ad7380_chip_info {
+ const char *name;
+ const struct iio_chan_spec *channels;
+ unsigned int num_channels;
+};
+
+#define AD7380_CHANNEL(index, bits) { \
+ .type = IIO_VOLTAGE, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .indexed = 1, \
+ .differential = 1, \
+ .channel = 2 * (index), \
+ .channel2 = 2 * (index) + 1, \
+ .scan_index = (index), \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = (bits), \
+ .storagebits = 16, \
+ .endianness = IIO_CPU, \
+ }, \
+}
+
+#define DEFINE_AD7380_2_CHANNEL(name, bits) \
+static const struct iio_chan_spec name[] = { \
+ AD7380_CHANNEL(0, bits), \
+ AD7380_CHANNEL(1, bits), \
+ IIO_CHAN_SOFT_TIMESTAMP(2), \
+}
+
+DEFINE_AD7380_2_CHANNEL(ad7380_channels, 16);
+DEFINE_AD7380_2_CHANNEL(ad7381_channels, 14);
+
+/* Since this is simultaneous sampling, we don't allow individual channels. */
+static const unsigned long ad7380_2_channel_scan_masks[] = {
+ GENMASK(1, 0),
+ 0
+};
+
+static const struct ad7380_chip_info ad7380_chip_info = {
+ .name = "ad7380",
+ .channels = ad7380_channels,
+ .num_channels = ARRAY_SIZE(ad7380_channels),
+};
+
+static const struct ad7380_chip_info ad7381_chip_info = {
+ .name = "ad7381",
+ .channels = ad7381_channels,
+ .num_channels = ARRAY_SIZE(ad7381_channels),
+};
+
+struct ad7380_state {
+ const struct ad7380_chip_info *chip_info;
+ struct spi_device *spi;
+ struct regmap *regmap;
+ unsigned int vref_mv;
+ /*
+ * DMA (thus cache coherency maintenance) requires the
+ * transfer buffers to live in their own cache lines.
+ * Make the buffer large enough for 2 16-bit samples and one 64-bit
+ * aligned 64 bit timestamp.
+ */
+ struct {
+ u16 raw[2];
+
+ s64 ts __aligned(8);
+ } scan_data __aligned(IIO_DMA_MINALIGN);
+ u16 tx;
+ u16 rx;
+};
+
+static int ad7380_regmap_reg_write(void *context, unsigned int reg,
+ unsigned int val)
+{
+ struct ad7380_state *st = context;
+ struct spi_transfer xfer = {
+ .speed_hz = AD7380_REG_WR_SPEED_HZ,
+ .bits_per_word = 16,
+ .len = 2,
+ .tx_buf = &st->tx,
+ };
+
+ st->tx = FIELD_PREP(AD7380_REG_WR, 1) |
+ FIELD_PREP(AD7380_REG_REGADDR, reg) |
+ FIELD_PREP(AD7380_REG_DATA, val);
+
+ return spi_sync_transfer(st->spi, &xfer, 1);
+}
+
+static int ad7380_regmap_reg_read(void *context, unsigned int reg,
+ unsigned int *val)
+{
+ struct ad7380_state *st = context;
+ struct spi_transfer xfers[] = {
+ {
+ .speed_hz = AD7380_REG_WR_SPEED_HZ,
+ .bits_per_word = 16,
+ .len = 2,
+ .tx_buf = &st->tx,
+ .cs_change = 1,
+ .cs_change_delay = {
+ .value = 10, /* t[CSH] */
+ .unit = SPI_DELAY_UNIT_NSECS,
+ },
+ }, {
+ .speed_hz = AD7380_REG_WR_SPEED_HZ,
+ .bits_per_word = 16,
+ .len = 2,
+ .rx_buf = &st->rx,
+ },
+ };
+ int ret;
+
+ st->tx = FIELD_PREP(AD7380_REG_WR, 0) |
+ FIELD_PREP(AD7380_REG_REGADDR, reg) |
+ FIELD_PREP(AD7380_REG_DATA, 0);
+
+ ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
+ if (ret < 0)
+ return ret;
+
+ *val = FIELD_GET(AD7380_REG_DATA, st->rx);
+
+ return 0;
+}
+
+static const struct regmap_config ad7380_regmap_config = {
+ .reg_bits = 3,
+ .val_bits = 12,
+ .reg_read = ad7380_regmap_reg_read,
+ .reg_write = ad7380_regmap_reg_write,
+ .max_register = AD7380_REG_ADDR_ALERT_HIGH_TH,
+ .can_sleep = true,
+};
+
+static int ad7380_debugfs_reg_access(struct iio_dev *indio_dev, u32 reg,
+ u32 writeval, u32 *readval)
+{
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+ struct ad7380_state *st = iio_priv(indio_dev);
+
+ if (readval)
+ return regmap_read(st->regmap, reg, readval);
+ else
+ return regmap_write(st->regmap, reg, writeval);
+ }
+ unreachable();
+}
+
+static irqreturn_t ad7380_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct ad7380_state *st = iio_priv(indio_dev);
+ struct spi_transfer xfer = {
+ .bits_per_word = st->chip_info->channels[0].scan_type.realbits,
+ .len = 4,
+ .rx_buf = st->scan_data.raw,
+ };
+ int ret;
+
+ ret = spi_sync_transfer(st->spi, &xfer, 1);
+ if (ret)
+ goto out;
+
+ iio_push_to_buffers_with_timestamp(indio_dev, &st->scan_data,
+ pf->timestamp);
+
+out:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static int ad7380_read_direct(struct ad7380_state *st,
+ struct iio_chan_spec const *chan, int *val)
+{
+ struct spi_transfer xfers[] = {
+ /* toggle CS (no data xfer) to trigger a conversion */
+ {
+ .speed_hz = AD7380_REG_WR_SPEED_HZ,
+ .bits_per_word = chan->scan_type.realbits,
+ .delay = {
+ .value = 190, /* t[CONVERT] */
+ .unit = SPI_DELAY_UNIT_NSECS,
+ },
+ .cs_change = 1,
+ .cs_change_delay = {
+ .value = 10, /* t[CSH] */
+ .unit = SPI_DELAY_UNIT_NSECS,
+ },
+ },
+ /* then read both channels */
+ {
+ .speed_hz = AD7380_REG_WR_SPEED_HZ,
+ .bits_per_word = chan->scan_type.realbits,
+ .rx_buf = st->scan_data.raw,
+ .len = 4,
+ },
+ };
+ int ret;
+
+ ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
+ if (ret < 0)
+ return ret;
+
+ *val = sign_extend32(st->scan_data.raw[chan->scan_index],
+ chan->scan_type.realbits - 1);
+
+ return IIO_VAL_INT;
+}
+
+static int ad7380_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long info)
+{
+ struct ad7380_state *st = iio_priv(indio_dev);
+
+ switch (info) {
+ case IIO_CHAN_INFO_RAW:
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+ return ad7380_read_direct(st, chan, val);
+ }
+ unreachable();
+ case IIO_CHAN_INFO_SCALE:
+ /*
+ * According to the datasheet, the LSB size for fully differential ADC is
+ * (2 × VREF) / 2^N, where N is the ADC resolution (i.e realbits)
+ */
+ *val = st->vref_mv;
+ *val2 = chan->scan_type.realbits - 1;
+
+ return IIO_VAL_FRACTIONAL_LOG2;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info ad7380_info = {
+ .read_raw = &ad7380_read_raw,
+ .debugfs_reg_access = &ad7380_debugfs_reg_access,
+};
+
+static int ad7380_init(struct ad7380_state *st, struct regulator *vref)
+{
+ int ret;
+
+ /* perform hard reset */
+ ret = regmap_update_bits(st->regmap, AD7380_REG_ADDR_CONFIG2,
+ AD7380_CONFIG2_RESET,
+ FIELD_PREP(AD7380_CONFIG2_RESET,
+ AD7380_CONFIG2_RESET_HARD));
+ if (ret < 0)
+ return ret;
+
+ /* select internal or external reference voltage */
+ ret = regmap_update_bits(st->regmap, AD7380_REG_ADDR_CONFIG1,
+ AD7380_CONFIG1_REFSEL,
+ FIELD_PREP(AD7380_CONFIG1_REFSEL,
+ vref ? 1 : 0));
+ if (ret < 0)
+ return ret;
+
+ /* SPI 1-wire mode */
+ return regmap_update_bits(st->regmap, AD7380_REG_ADDR_CONFIG2,
+ AD7380_CONFIG2_SDO,
+ FIELD_PREP(AD7380_CONFIG2_SDO, 1));
+}
+
+static void ad7380_regulator_disable(void *p)
+{
+ regulator_disable(p);
+}
+
+static int ad7380_probe(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev;
+ struct ad7380_state *st;
+ struct regulator *vref;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+ st->spi = spi;
+ st->chip_info = spi_get_device_match_data(spi);
+ if (!st->chip_info)
+ return dev_err_probe(&spi->dev, -EINVAL, "missing match data\n");
+
+ vref = devm_regulator_get_optional(&spi->dev, "refio");
+ if (IS_ERR(vref)) {
+ if (PTR_ERR(vref) != -ENODEV)
+ return dev_err_probe(&spi->dev, PTR_ERR(vref),
+ "Failed to get refio regulator\n");
+
+ vref = NULL;
+ }
+
+ /*
+ * If there is no REFIO supply, then it means that we are using
+ * the internal 2.5V reference, otherwise REFIO is reference voltage.
+ */
+ if (vref) {
+ ret = regulator_enable(vref);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(&spi->dev,
+ ad7380_regulator_disable, vref);
+ if (ret)
+ return ret;
+
+ ret = regulator_get_voltage(vref);
+ if (ret < 0)
+ return ret;
+
+ st->vref_mv = ret / 1000;
+ } else {
+ st->vref_mv = AD7380_INTERNAL_REF_MV;
+ }
+
+ st->regmap = devm_regmap_init(&spi->dev, NULL, st, &ad7380_regmap_config);
+ if (IS_ERR(st->regmap))
+ return dev_err_probe(&spi->dev, PTR_ERR(st->regmap),
+ "failed to allocate register map\n");
+
+ indio_dev->channels = st->chip_info->channels;
+ indio_dev->num_channels = st->chip_info->num_channels;
+ indio_dev->name = st->chip_info->name;
+ indio_dev->info = &ad7380_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->available_scan_masks = ad7380_2_channel_scan_masks;
+
+ ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev,
+ iio_pollfunc_store_time,
+ ad7380_trigger_handler, NULL);
+ if (ret)
+ return ret;
+
+ ret = ad7380_init(st, vref);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(&spi->dev, indio_dev);
+}
+
+static const struct of_device_id ad7380_of_match_table[] = {
+ { .compatible = "adi,ad7380", .data = &ad7380_chip_info },
+ { .compatible = "adi,ad7381", .data = &ad7381_chip_info },
+ { }
+};
+
+static const struct spi_device_id ad7380_id_table[] = {
+ { "ad7380", (kernel_ulong_t)&ad7380_chip_info },
+ { "ad7381", (kernel_ulong_t)&ad7381_chip_info },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, ad7380_id_table);
+
+static struct spi_driver ad7380_driver = {
+ .driver = {
+ .name = "ad7380",
+ .of_match_table = ad7380_of_match_table,
+ },
+ .probe = ad7380_probe,
+ .id_table = ad7380_id_table,
+};
+module_spi_driver(ad7380_driver);
+
+MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD738x ADC driver");
+MODULE_LICENSE("GPL");
--
2.44.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v7 3/7] dt-bindings: iio: adc: ad7380: add pseudo-differential parts
2024-05-28 14:20 [PATCH v7 0/7] iio: adc: add new ad7380 driver Julien Stephan
2024-05-28 14:20 ` [PATCH v7 1/7] dt-bindings: iio: adc: Add binding for AD7380 ADCs Julien Stephan
2024-05-28 14:20 ` [PATCH v7 2/7] iio: adc: ad7380: new driver " Julien Stephan
@ 2024-05-28 14:20 ` Julien Stephan
2024-05-28 14:20 ` [PATCH v7 4/7] iio: adc: ad7380: add support for " Julien Stephan
` (4 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Julien Stephan @ 2024-05-28 14:20 UTC (permalink / raw)
To: Lars-Peter Clausen, Michael Hennerich, Nuno Sá,
David Lechner, Jonathan Cameron, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Liam Girdwood, Mark Brown
Cc: kernel test robot, linux-iio, devicetree, linux-kernel,
Julien Stephan, Conor Dooley
From: David Lechner <dlechner@baylibre.com>
Adding AD7383 and AD7384 compatible parts that are pseudo-differential.
Pseudo-differential require common mode voltage supplies, so add them
conditionally
Signed-off-by: David Lechner <dlechner@baylibre.com>
Signed-off-by: Julien Stephan <jstephan@baylibre.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
---
.../devicetree/bindings/iio/adc/adi,ad7380.yaml | 32 ++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml
index 5e1ee0ebe0a2..de3d28a021ae 100644
--- a/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml
@@ -13,6 +13,8 @@ maintainers:
description: |
* https://www.analog.com/en/products/ad7380.html
* https://www.analog.com/en/products/ad7381.html
+ * https://www.analog.com/en/products/ad7383.html
+ * https://www.analog.com/en/products/ad7384.html
$ref: /schemas/spi/spi-peripheral-props.yaml#
@@ -21,6 +23,8 @@ properties:
enum:
- adi,ad7380
- adi,ad7381
+ - adi,ad7383
+ - adi,ad7384
reg:
maxItems: 1
@@ -42,6 +46,16 @@ properties:
A 2.5V to 3.3V supply for the external reference voltage. When omitted,
the internal 2.5V reference is used.
+ aina-supply:
+ description:
+ The common mode voltage supply for the AINA- pin on pseudo-differential
+ chips.
+
+ ainb-supply:
+ description:
+ The common mode voltage supply for the AINB- pin on pseudo-differential
+ chips.
+
interrupts:
description:
When the device is using 1-wire mode, this property is used to optionally
@@ -56,6 +70,24 @@ required:
unevaluatedProperties: false
+allOf:
+ # pseudo-differential chips require common mode voltage supplies,
+ # true differential chips don't use them
+ - if:
+ properties:
+ compatible:
+ enum:
+ - adi,ad7383
+ - adi,ad7384
+ then:
+ required:
+ - aina-supply
+ - ainb-supply
+ else:
+ properties:
+ aina-supply: false
+ ainb-supply: false
+
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
--
2.44.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v7 4/7] iio: adc: ad7380: add support for pseudo-differential parts
2024-05-28 14:20 [PATCH v7 0/7] iio: adc: add new ad7380 driver Julien Stephan
` (2 preceding siblings ...)
2024-05-28 14:20 ` [PATCH v7 3/7] dt-bindings: iio: adc: ad7380: add pseudo-differential parts Julien Stephan
@ 2024-05-28 14:20 ` Julien Stephan
2024-05-28 14:20 ` [PATCH v7 5/7] iio: adc: ad7380: prepare for parts with more channels Julien Stephan
` (3 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Julien Stephan @ 2024-05-28 14:20 UTC (permalink / raw)
To: Lars-Peter Clausen, Michael Hennerich, Nuno Sá,
David Lechner, Jonathan Cameron, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Liam Girdwood, Mark Brown
Cc: kernel test robot, linux-iio, devicetree, linux-kernel,
Julien Stephan
From: David Lechner <dlechner@baylibre.com>
Add support for AD7383, AD7384 pseudo-differential compatible parts.
Pseudo differential parts require common mode voltage supplies so add
the support for them and add the support of IIO_CHAN_INFO_OFFSET to
retrieve the offset
Signed-off-by: David Lechner <dlechner@baylibre.com>
Signed-off-by: Julien Stephan <jstephan@baylibre.com>
---
drivers/iio/adc/ad7380.c | 110 ++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 94 insertions(+), 16 deletions(-)
diff --git a/drivers/iio/adc/ad7380.c b/drivers/iio/adc/ad7380.c
index dac7e11755ff..4ad283cf970d 100644
--- a/drivers/iio/adc/ad7380.c
+++ b/drivers/iio/adc/ad7380.c
@@ -7,6 +7,7 @@
*
* Datasheets of supported parts:
* ad7380/1 : https://www.analog.com/media/en/technical-documentation/data-sheets/AD7380-7381.pdf
+ * ad7383/4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7383-7384.pdf
*/
#include <linux/bitfield.h>
@@ -66,16 +67,19 @@ struct ad7380_chip_info {
const char *name;
const struct iio_chan_spec *channels;
unsigned int num_channels;
+ const char * const *vcm_supplies;
+ unsigned int num_vcm_supplies;
};
-#define AD7380_CHANNEL(index, bits) { \
+#define AD7380_CHANNEL(index, bits, diff) { \
.type = IIO_VOLTAGE, \
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ ((diff) ? 0 : BIT(IIO_CHAN_INFO_OFFSET)), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.indexed = 1, \
- .differential = 1, \
- .channel = 2 * (index), \
- .channel2 = 2 * (index) + 1, \
+ .differential = (diff), \
+ .channel = (diff) ? (2 * (index)) : (index), \
+ .channel2 = (diff) ? (2 * (index) + 1) : 0, \
.scan_index = (index), \
.scan_type = { \
.sign = 's', \
@@ -85,15 +89,23 @@ struct ad7380_chip_info {
}, \
}
-#define DEFINE_AD7380_2_CHANNEL(name, bits) \
-static const struct iio_chan_spec name[] = { \
- AD7380_CHANNEL(0, bits), \
- AD7380_CHANNEL(1, bits), \
- IIO_CHAN_SOFT_TIMESTAMP(2), \
+#define DEFINE_AD7380_2_CHANNEL(name, bits, diff) \
+static const struct iio_chan_spec name[] = { \
+ AD7380_CHANNEL(0, bits, diff), \
+ AD7380_CHANNEL(1, bits, diff), \
+ IIO_CHAN_SOFT_TIMESTAMP(2), \
}
-DEFINE_AD7380_2_CHANNEL(ad7380_channels, 16);
-DEFINE_AD7380_2_CHANNEL(ad7381_channels, 14);
+/* fully differential */
+DEFINE_AD7380_2_CHANNEL(ad7380_channels, 16, 1);
+DEFINE_AD7380_2_CHANNEL(ad7381_channels, 14, 1);
+/* pseudo differential */
+DEFINE_AD7380_2_CHANNEL(ad7383_channels, 16, 0);
+DEFINE_AD7380_2_CHANNEL(ad7384_channels, 14, 0);
+
+static const char * const ad7380_2_channel_vcm_supplies[] = {
+ "aina", "ainb",
+};
/* Since this is simultaneous sampling, we don't allow individual channels. */
static const unsigned long ad7380_2_channel_scan_masks[] = {
@@ -113,11 +125,28 @@ static const struct ad7380_chip_info ad7381_chip_info = {
.num_channels = ARRAY_SIZE(ad7381_channels),
};
+static const struct ad7380_chip_info ad7383_chip_info = {
+ .name = "ad7383",
+ .channels = ad7383_channels,
+ .num_channels = ARRAY_SIZE(ad7383_channels),
+ .vcm_supplies = ad7380_2_channel_vcm_supplies,
+ .num_vcm_supplies = ARRAY_SIZE(ad7380_2_channel_vcm_supplies),
+};
+
+static const struct ad7380_chip_info ad7384_chip_info = {
+ .name = "ad7384",
+ .channels = ad7384_channels,
+ .num_channels = ARRAY_SIZE(ad7384_channels),
+ .vcm_supplies = ad7380_2_channel_vcm_supplies,
+ .num_vcm_supplies = ARRAY_SIZE(ad7380_2_channel_vcm_supplies),
+};
+
struct ad7380_state {
const struct ad7380_chip_info *chip_info;
struct spi_device *spi;
struct regmap *regmap;
unsigned int vref_mv;
+ unsigned int vcm_mv[2];
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
@@ -288,13 +317,24 @@ static int ad7380_read_raw(struct iio_dev *indio_dev,
unreachable();
case IIO_CHAN_INFO_SCALE:
/*
- * According to the datasheet, the LSB size for fully differential ADC is
- * (2 × VREF) / 2^N, where N is the ADC resolution (i.e realbits)
+ * According to the datasheet, the LSB size is:
+ * * (2 × VREF) / 2^N, for differential chips
+ * * VREF / 2^N, for pseudo-differential chips
+ * where N is the ADC resolution (i.e realbits)
*/
*val = st->vref_mv;
- *val2 = chan->scan_type.realbits - 1;
+ *val2 = chan->scan_type.realbits - chan->differential;
return IIO_VAL_FRACTIONAL_LOG2;
+ case IIO_CHAN_INFO_OFFSET:
+ /*
+ * According to IIO ABI, offset is applied before scale,
+ * so offset is: vcm_mv / scale
+ */
+ *val = st->vcm_mv[chan->channel] * (1 << chan->scan_type.realbits)
+ / st->vref_mv;
+
+ return IIO_VAL_INT;
default:
return -EINVAL;
}
@@ -341,7 +381,7 @@ static int ad7380_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
struct ad7380_state *st;
struct regulator *vref;
- int ret;
+ int ret, i;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
@@ -385,6 +425,40 @@ static int ad7380_probe(struct spi_device *spi)
st->vref_mv = AD7380_INTERNAL_REF_MV;
}
+ if (st->chip_info->num_vcm_supplies > ARRAY_SIZE(st->vcm_mv))
+ return dev_err_probe(&spi->dev, -EINVAL,
+ "invalid number of VCM supplies\n");
+
+ /*
+ * pseudo-differential chips have common mode supplies for the negative
+ * input pin.
+ */
+ for (i = 0; i < st->chip_info->num_vcm_supplies; i++) {
+ struct regulator *vcm;
+
+ vcm = devm_regulator_get(&spi->dev,
+ st->chip_info->vcm_supplies[i]);
+ if (IS_ERR(vcm))
+ return dev_err_probe(&spi->dev, PTR_ERR(vcm),
+ "Failed to get %s regulator\n",
+ st->chip_info->vcm_supplies[i]);
+
+ ret = regulator_enable(vcm);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(&spi->dev,
+ ad7380_regulator_disable, vcm);
+ if (ret)
+ return ret;
+
+ ret = regulator_get_voltage(vcm);
+ if (ret < 0)
+ return ret;
+
+ st->vcm_mv[i] = ret / 1000;
+ }
+
st->regmap = devm_regmap_init(&spi->dev, NULL, st, &ad7380_regmap_config);
if (IS_ERR(st->regmap))
return dev_err_probe(&spi->dev, PTR_ERR(st->regmap),
@@ -413,12 +487,16 @@ static int ad7380_probe(struct spi_device *spi)
static const struct of_device_id ad7380_of_match_table[] = {
{ .compatible = "adi,ad7380", .data = &ad7380_chip_info },
{ .compatible = "adi,ad7381", .data = &ad7381_chip_info },
+ { .compatible = "adi,ad7383", .data = &ad7383_chip_info },
+ { .compatible = "adi,ad7384", .data = &ad7384_chip_info },
{ }
};
static const struct spi_device_id ad7380_id_table[] = {
{ "ad7380", (kernel_ulong_t)&ad7380_chip_info },
{ "ad7381", (kernel_ulong_t)&ad7381_chip_info },
+ { "ad7383", (kernel_ulong_t)&ad7383_chip_info },
+ { "ad7384", (kernel_ulong_t)&ad7384_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7380_id_table);
--
2.44.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v7 5/7] iio: adc: ad7380: prepare for parts with more channels
2024-05-28 14:20 [PATCH v7 0/7] iio: adc: add new ad7380 driver Julien Stephan
` (3 preceding siblings ...)
2024-05-28 14:20 ` [PATCH v7 4/7] iio: adc: ad7380: add support for " Julien Stephan
@ 2024-05-28 14:20 ` Julien Stephan
2024-05-28 14:20 ` [PATCH v7 6/7] dt-bindings: iio: adc: ad7380: add support for ad738x-4 4 channels variants Julien Stephan
` (2 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Julien Stephan @ 2024-05-28 14:20 UTC (permalink / raw)
To: Lars-Peter Clausen, Michael Hennerich, Nuno Sá,
David Lechner, Jonathan Cameron, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Liam Girdwood, Mark Brown
Cc: kernel test robot, linux-iio, devicetree, linux-kernel,
Julien Stephan
The current driver supports only parts with 2 channels.
In order to prepare the support of new compatible ADCs with more
channels, this commit:
- defines MAX_NUM_CHANNEL to specify the maximum number of
channels currently supported by the driver
- adds available_scan_mask member in ad7380_chip_info structure
- fixes spi xfer struct len depending on number of channels
- fixes scan_data.raw buffer size to handle more channels
- adds a timing specifications structure in ad7380_chip_info structure
Signed-off-by: Julien Stephan <jstephan@baylibre.com>
---
drivers/iio/adc/ad7380.c | 43 +++++++++++++++++++++++++++++++++----------
1 file changed, 33 insertions(+), 10 deletions(-)
diff --git a/drivers/iio/adc/ad7380.c b/drivers/iio/adc/ad7380.c
index 4ad283cf970d..790d08c90ad0 100644
--- a/drivers/iio/adc/ad7380.c
+++ b/drivers/iio/adc/ad7380.c
@@ -27,6 +27,7 @@
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
+#define MAX_NUM_CHANNELS 2
/* 2.5V internal reference voltage */
#define AD7380_INTERNAL_REF_MV 2500
@@ -63,12 +64,19 @@
#define AD7380_ALERT_LOW_TH GENMASK(11, 0)
#define AD7380_ALERT_HIGH_TH GENMASK(11, 0)
+#define T_CONVERT_NS 190 /* conversion time */
+struct ad7380_timing_specs {
+ const unsigned int t_csh_ns; /* CS minimum high time */
+};
+
struct ad7380_chip_info {
const char *name;
const struct iio_chan_spec *channels;
unsigned int num_channels;
const char * const *vcm_supplies;
unsigned int num_vcm_supplies;
+ const unsigned long *available_scan_masks;
+ const struct ad7380_timing_specs *timing_specs;
};
#define AD7380_CHANNEL(index, bits, diff) { \
@@ -113,16 +121,24 @@ static const unsigned long ad7380_2_channel_scan_masks[] = {
0
};
+static const struct ad7380_timing_specs ad7380_timing = {
+ .t_csh_ns = 10,
+};
+
static const struct ad7380_chip_info ad7380_chip_info = {
.name = "ad7380",
.channels = ad7380_channels,
.num_channels = ARRAY_SIZE(ad7380_channels),
+ .available_scan_masks = ad7380_2_channel_scan_masks,
+ .timing_specs = &ad7380_timing,
};
static const struct ad7380_chip_info ad7381_chip_info = {
.name = "ad7381",
.channels = ad7381_channels,
.num_channels = ARRAY_SIZE(ad7381_channels),
+ .available_scan_masks = ad7380_2_channel_scan_masks,
+ .timing_specs = &ad7380_timing,
};
static const struct ad7380_chip_info ad7383_chip_info = {
@@ -131,6 +147,8 @@ static const struct ad7380_chip_info ad7383_chip_info = {
.num_channels = ARRAY_SIZE(ad7383_channels),
.vcm_supplies = ad7380_2_channel_vcm_supplies,
.num_vcm_supplies = ARRAY_SIZE(ad7380_2_channel_vcm_supplies),
+ .available_scan_masks = ad7380_2_channel_scan_masks,
+ .timing_specs = &ad7380_timing,
};
static const struct ad7380_chip_info ad7384_chip_info = {
@@ -139,6 +157,8 @@ static const struct ad7380_chip_info ad7384_chip_info = {
.num_channels = ARRAY_SIZE(ad7384_channels),
.vcm_supplies = ad7380_2_channel_vcm_supplies,
.num_vcm_supplies = ARRAY_SIZE(ad7380_2_channel_vcm_supplies),
+ .available_scan_masks = ad7380_2_channel_scan_masks,
+ .timing_specs = &ad7380_timing,
};
struct ad7380_state {
@@ -146,15 +166,16 @@ struct ad7380_state {
struct spi_device *spi;
struct regmap *regmap;
unsigned int vref_mv;
- unsigned int vcm_mv[2];
+ unsigned int vcm_mv[MAX_NUM_CHANNELS];
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
- * Make the buffer large enough for 2 16-bit samples and one 64-bit
+ * Make the buffer large enough for MAX_NUM_CHANNELS 16-bit samples and one 64-bit
* aligned 64 bit timestamp.
+ * As MAX_NUM_CHANNELS is 2 the layout of the structure is the same for all parts
*/
struct {
- u16 raw[2];
+ u16 raw[MAX_NUM_CHANNELS];
s64 ts __aligned(8);
} scan_data __aligned(IIO_DMA_MINALIGN);
@@ -192,7 +213,7 @@ static int ad7380_regmap_reg_read(void *context, unsigned int reg,
.tx_buf = &st->tx,
.cs_change = 1,
.cs_change_delay = {
- .value = 10, /* t[CSH] */
+ .value = st->chip_info->timing_specs->t_csh_ns,
.unit = SPI_DELAY_UNIT_NSECS,
},
}, {
@@ -247,7 +268,8 @@ static irqreturn_t ad7380_trigger_handler(int irq, void *p)
struct ad7380_state *st = iio_priv(indio_dev);
struct spi_transfer xfer = {
.bits_per_word = st->chip_info->channels[0].scan_type.realbits,
- .len = 4,
+ .len = (st->chip_info->num_channels - 1) *
+ BITS_TO_BYTES(st->chip_info->channels->scan_type.storagebits),
.rx_buf = st->scan_data.raw,
};
int ret;
@@ -274,21 +296,22 @@ static int ad7380_read_direct(struct ad7380_state *st,
.speed_hz = AD7380_REG_WR_SPEED_HZ,
.bits_per_word = chan->scan_type.realbits,
.delay = {
- .value = 190, /* t[CONVERT] */
+ .value = T_CONVERT_NS,
.unit = SPI_DELAY_UNIT_NSECS,
},
.cs_change = 1,
.cs_change_delay = {
- .value = 10, /* t[CSH] */
+ .value = st->chip_info->timing_specs->t_csh_ns,
.unit = SPI_DELAY_UNIT_NSECS,
},
},
- /* then read both channels */
+ /* then read all channels */
{
.speed_hz = AD7380_REG_WR_SPEED_HZ,
.bits_per_word = chan->scan_type.realbits,
.rx_buf = st->scan_data.raw,
- .len = 4,
+ .len = (st->chip_info->num_channels - 1) *
+ ((chan->scan_type.storagebits > 16) ? 4 : 2),
},
};
int ret;
@@ -469,7 +492,7 @@ static int ad7380_probe(struct spi_device *spi)
indio_dev->name = st->chip_info->name;
indio_dev->info = &ad7380_info;
indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->available_scan_masks = ad7380_2_channel_scan_masks;
+ indio_dev->available_scan_masks = st->chip_info->available_scan_masks;
ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev,
iio_pollfunc_store_time,
--
2.44.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v7 6/7] dt-bindings: iio: adc: ad7380: add support for ad738x-4 4 channels variants
2024-05-28 14:20 [PATCH v7 0/7] iio: adc: add new ad7380 driver Julien Stephan
` (4 preceding siblings ...)
2024-05-28 14:20 ` [PATCH v7 5/7] iio: adc: ad7380: prepare for parts with more channels Julien Stephan
@ 2024-05-28 14:20 ` Julien Stephan
2024-05-28 14:20 ` [PATCH v7 7/7] " Julien Stephan
2024-06-02 9:34 ` [PATCH v7 0/7] iio: adc: add new ad7380 driver Jonathan Cameron
7 siblings, 0 replies; 9+ messages in thread
From: Julien Stephan @ 2024-05-28 14:20 UTC (permalink / raw)
To: Lars-Peter Clausen, Michael Hennerich, Nuno Sá,
David Lechner, Jonathan Cameron, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Liam Girdwood, Mark Brown
Cc: kernel test robot, linux-iio, devicetree, linux-kernel,
Julien Stephan, Conor Dooley
Add compatible support for ad7380/1/3/4-4 parts which are 4 channels
variants from ad7380/1/3/4
Signed-off-by: Julien Stephan <jstephan@baylibre.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
---
.../devicetree/bindings/iio/adc/adi,ad7380.yaml | 34 ++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml
index de3d28a021ae..899b777017ce 100644
--- a/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml
@@ -15,6 +15,10 @@ description: |
* https://www.analog.com/en/products/ad7381.html
* https://www.analog.com/en/products/ad7383.html
* https://www.analog.com/en/products/ad7384.html
+ * https://www.analog.com/en/products/ad7380-4.html
+ * https://www.analog.com/en/products/ad7381-4.html
+ * https://www.analog.com/en/products/ad7383-4.html
+ * https://www.analog.com/en/products/ad7384-4.html
$ref: /schemas/spi/spi-peripheral-props.yaml#
@@ -25,6 +29,10 @@ properties:
- adi,ad7381
- adi,ad7383
- adi,ad7384
+ - adi,ad7380-4
+ - adi,ad7381-4
+ - adi,ad7383-4
+ - adi,ad7384-4
reg:
maxItems: 1
@@ -56,6 +64,16 @@ properties:
The common mode voltage supply for the AINB- pin on pseudo-differential
chips.
+ ainc-supply:
+ description:
+ The common mode voltage supply for the AINC- pin on pseudo-differential
+ chips.
+
+ aind-supply:
+ description:
+ The common mode voltage supply for the AIND- pin on pseudo-differential
+ chips.
+
interrupts:
description:
When the device is using 1-wire mode, this property is used to optionally
@@ -79,6 +97,8 @@ allOf:
enum:
- adi,ad7383
- adi,ad7384
+ - adi,ad7383-4
+ - adi,ad7384-4
then:
required:
- aina-supply
@@ -87,6 +107,20 @@ allOf:
properties:
aina-supply: false
ainb-supply: false
+ - if:
+ properties:
+ compatible:
+ enum:
+ - adi,ad7383-4
+ - adi,ad7384-4
+ then:
+ required:
+ - ainc-supply
+ - aind-supply
+ else:
+ properties:
+ ainc-supply: false
+ aind-supply: false
examples:
- |
--
2.44.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v7 7/7] iio: adc: ad7380: add support for ad738x-4 4 channels variants
2024-05-28 14:20 [PATCH v7 0/7] iio: adc: add new ad7380 driver Julien Stephan
` (5 preceding siblings ...)
2024-05-28 14:20 ` [PATCH v7 6/7] dt-bindings: iio: adc: ad7380: add support for ad738x-4 4 channels variants Julien Stephan
@ 2024-05-28 14:20 ` Julien Stephan
2024-06-02 9:34 ` [PATCH v7 0/7] iio: adc: add new ad7380 driver Jonathan Cameron
7 siblings, 0 replies; 9+ messages in thread
From: Julien Stephan @ 2024-05-28 14:20 UTC (permalink / raw)
To: Lars-Peter Clausen, Michael Hennerich, Nuno Sá,
David Lechner, Jonathan Cameron, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Liam Girdwood, Mark Brown
Cc: kernel test robot, linux-iio, devicetree, linux-kernel,
Julien Stephan
Add support for ad7380/1/2/3-4 parts which are 4 channels
variants from ad7380/1/2/3
Signed-off-by: Julien Stephan <jstephan@baylibre.com>
---
drivers/iio/adc/ad7380.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 75 insertions(+), 2 deletions(-)
diff --git a/drivers/iio/adc/ad7380.c b/drivers/iio/adc/ad7380.c
index 790d08c90ad0..6b0b1b0be363 100644
--- a/drivers/iio/adc/ad7380.c
+++ b/drivers/iio/adc/ad7380.c
@@ -8,6 +8,9 @@
* Datasheets of supported parts:
* ad7380/1 : https://www.analog.com/media/en/technical-documentation/data-sheets/AD7380-7381.pdf
* ad7383/4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7383-7384.pdf
+ * ad7380-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7380-4.pdf
+ * ad7381-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7381-4.pdf
+ * ad7383/4-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7383-4-ad7384-4.pdf
*/
#include <linux/bitfield.h>
@@ -27,7 +30,7 @@
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
-#define MAX_NUM_CHANNELS 2
+#define MAX_NUM_CHANNELS 4
/* 2.5V internal reference voltage */
#define AD7380_INTERNAL_REF_MV 2500
@@ -104,27 +107,53 @@ static const struct iio_chan_spec name[] = { \
IIO_CHAN_SOFT_TIMESTAMP(2), \
}
+#define DEFINE_AD7380_4_CHANNEL(name, bits, diff) \
+static const struct iio_chan_spec name[] = { \
+ AD7380_CHANNEL(0, bits, diff), \
+ AD7380_CHANNEL(1, bits, diff), \
+ AD7380_CHANNEL(2, bits, diff), \
+ AD7380_CHANNEL(3, bits, diff), \
+ IIO_CHAN_SOFT_TIMESTAMP(4), \
+}
+
/* fully differential */
DEFINE_AD7380_2_CHANNEL(ad7380_channels, 16, 1);
DEFINE_AD7380_2_CHANNEL(ad7381_channels, 14, 1);
+DEFINE_AD7380_4_CHANNEL(ad7380_4_channels, 16, 1);
+DEFINE_AD7380_4_CHANNEL(ad7381_4_channels, 14, 1);
/* pseudo differential */
DEFINE_AD7380_2_CHANNEL(ad7383_channels, 16, 0);
DEFINE_AD7380_2_CHANNEL(ad7384_channels, 14, 0);
+DEFINE_AD7380_4_CHANNEL(ad7383_4_channels, 16, 0);
+DEFINE_AD7380_4_CHANNEL(ad7384_4_channels, 14, 0);
static const char * const ad7380_2_channel_vcm_supplies[] = {
"aina", "ainb",
};
+static const char * const ad7380_4_channel_vcm_supplies[] = {
+ "aina", "ainb", "ainc", "aind",
+};
+
/* Since this is simultaneous sampling, we don't allow individual channels. */
static const unsigned long ad7380_2_channel_scan_masks[] = {
GENMASK(1, 0),
0
};
+static const unsigned long ad7380_4_channel_scan_masks[] = {
+ GENMASK(3, 0),
+ 0
+};
+
static const struct ad7380_timing_specs ad7380_timing = {
.t_csh_ns = 10,
};
+static const struct ad7380_timing_specs ad7380_4_timing = {
+ .t_csh_ns = 20,
+};
+
static const struct ad7380_chip_info ad7380_chip_info = {
.name = "ad7380",
.channels = ad7380_channels,
@@ -161,6 +190,42 @@ static const struct ad7380_chip_info ad7384_chip_info = {
.timing_specs = &ad7380_timing,
};
+static const struct ad7380_chip_info ad7380_4_chip_info = {
+ .name = "ad7380-4",
+ .channels = ad7380_4_channels,
+ .num_channels = ARRAY_SIZE(ad7380_4_channels),
+ .available_scan_masks = ad7380_4_channel_scan_masks,
+ .timing_specs = &ad7380_4_timing,
+};
+
+static const struct ad7380_chip_info ad7381_4_chip_info = {
+ .name = "ad7381-4",
+ .channels = ad7381_4_channels,
+ .num_channels = ARRAY_SIZE(ad7381_4_channels),
+ .available_scan_masks = ad7380_4_channel_scan_masks,
+ .timing_specs = &ad7380_4_timing,
+};
+
+static const struct ad7380_chip_info ad7383_4_chip_info = {
+ .name = "ad7383-4",
+ .channels = ad7383_4_channels,
+ .num_channels = ARRAY_SIZE(ad7383_4_channels),
+ .vcm_supplies = ad7380_4_channel_vcm_supplies,
+ .num_vcm_supplies = ARRAY_SIZE(ad7380_4_channel_vcm_supplies),
+ .available_scan_masks = ad7380_4_channel_scan_masks,
+ .timing_specs = &ad7380_4_timing,
+};
+
+static const struct ad7380_chip_info ad7384_4_chip_info = {
+ .name = "ad7384-4",
+ .channels = ad7384_4_channels,
+ .num_channels = ARRAY_SIZE(ad7384_4_channels),
+ .vcm_supplies = ad7380_4_channel_vcm_supplies,
+ .num_vcm_supplies = ARRAY_SIZE(ad7380_4_channel_vcm_supplies),
+ .available_scan_masks = ad7380_4_channel_scan_masks,
+ .timing_specs = &ad7380_4_timing,
+};
+
struct ad7380_state {
const struct ad7380_chip_info *chip_info;
struct spi_device *spi;
@@ -172,7 +237,7 @@ struct ad7380_state {
* transfer buffers to live in their own cache lines.
* Make the buffer large enough for MAX_NUM_CHANNELS 16-bit samples and one 64-bit
* aligned 64 bit timestamp.
- * As MAX_NUM_CHANNELS is 2 the layout of the structure is the same for all parts
+ * As MAX_NUM_CHANNELS is 4 the layout of the structure is the same for all parts
*/
struct {
u16 raw[MAX_NUM_CHANNELS];
@@ -512,6 +577,10 @@ static const struct of_device_id ad7380_of_match_table[] = {
{ .compatible = "adi,ad7381", .data = &ad7381_chip_info },
{ .compatible = "adi,ad7383", .data = &ad7383_chip_info },
{ .compatible = "adi,ad7384", .data = &ad7384_chip_info },
+ { .compatible = "adi,ad7380-4", .data = &ad7380_4_chip_info },
+ { .compatible = "adi,ad7381-4", .data = &ad7381_4_chip_info },
+ { .compatible = "adi,ad7383-4", .data = &ad7383_4_chip_info },
+ { .compatible = "adi,ad7384-4", .data = &ad7384_4_chip_info },
{ }
};
@@ -520,6 +589,10 @@ static const struct spi_device_id ad7380_id_table[] = {
{ "ad7381", (kernel_ulong_t)&ad7381_chip_info },
{ "ad7383", (kernel_ulong_t)&ad7383_chip_info },
{ "ad7384", (kernel_ulong_t)&ad7384_chip_info },
+ { "ad7380-4", (kernel_ulong_t)&ad7380_4_chip_info },
+ { "ad7381-4", (kernel_ulong_t)&ad7381_4_chip_info },
+ { "ad7383-4", (kernel_ulong_t)&ad7383_4_chip_info },
+ { "ad7384-4", (kernel_ulong_t)&ad7384_4_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7380_id_table);
--
2.44.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH v7 0/7] iio: adc: add new ad7380 driver
2024-05-28 14:20 [PATCH v7 0/7] iio: adc: add new ad7380 driver Julien Stephan
` (6 preceding siblings ...)
2024-05-28 14:20 ` [PATCH v7 7/7] " Julien Stephan
@ 2024-06-02 9:34 ` Jonathan Cameron
7 siblings, 0 replies; 9+ messages in thread
From: Jonathan Cameron @ 2024-06-02 9:34 UTC (permalink / raw)
To: Julien Stephan
Cc: Lars-Peter Clausen, Michael Hennerich, Nuno Sá,
David Lechner, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Liam Girdwood, Mark Brown, kernel test robot, linux-iio,
devicetree, linux-kernel, Conor Dooley, Stefan Popa
On Tue, 28 May 2024 16:20:27 +0200
Julien Stephan <jstephan@baylibre.com> wrote:
> Taking over this series with David Lechner's approval, to add some
> fixes, proper handling of pseudo differential parts and
> some extra commits to add support for 4-channel compatible parts.
>
> Here is David's cover letter:
>
> This series is adding a new driver for the Analog Devices Inc. AD7380,
> AD7381, AD7383, and AD7384 ADCs. These chips are part of a family of
> simultaneous sampling SAR ADCs.
>
> To keep things simple, the initial driver implementation only supports
> the 2/4-channel differential chips listed above. There are also 4-channel
> single-ended chips in the family that can be added later.
>
> Furthermore, the driver is just implementing basic support for capturing
> data. Additional features like interrupts, CRC, etc. can be added later.
>
> This work is being done by BayLibre and on behalf of Analog Devices Inc.
> hence the maintainers are @analog.com.
>
Applied + I'll pick up the series David posted with oversampling support
now I have the precursor! A tiny bit of noise in this one because
of the reordering of the adc/Makefile
Thanks,
^ permalink raw reply [flat|nested] 9+ messages in thread