Add support for the AD7405/ADUM770x, a high performance isolated ADC,
1-channel, 16-bit with a second-order Σ-Δ modulator that converts an
analog input signal into a high speed, single-bit data stream.
Signed-off-by: Pop Ioan Daniel <pop.ioan-daniel@analog.com>
---
changes in v2:
- sort the includes in alphabetical order
- delete headers that aren't used
- remove min_rate member
- remove ad7405_update_scan_mode because there is only one channel
- rename axi_clk_gen to clk
- remove unuseful members from ad7405 state struct
- return -EINVAL on ad7405_write_raw
- fix indentation
- remove blank lines
- remove chan, bits, sign parameters from AD7405_IIO_CHANNEL
- remove shift = 0
- add info_mask_shared_by_type with IIO_CHAN_INFO_SCALE and
IIO_CHAN_INFO_OFFSET flags
- add scan_index, differential, channel2 in AD7405_IIO_CHANNEL
- remove ad7405_channel_masks[]
- remove unuseful members from ad7405_chip_info struct
- remove platform_get_drvdata() from probe
- use device_get_match_data to be able to use different chip info
- use devm_clk_get_enabled() for efficiency
- add devm_add_action_or_reset to disable_unprepare the clock when the driver
is removed
- replace the devm_regulator_bulk_get_enable before applying any other signals
- check for return value of 0 for st->ref_frequency
- remove indio_dev->modes = INDIO_DIRECT_MODE
- remove iio_backend_disable/enable that is done implicitly
by devm_iio_backend_enable()
drivers/iio/adc/Kconfig | 10 ++
drivers/iio/adc/Makefile | 1 +
drivers/iio/adc/ad7405.c | 264 +++++++++++++++++++++++++++++++++++++++
3 files changed, 275 insertions(+)
create mode 100644 drivers/iio/adc/ad7405.c
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index ad06cf556785..6ed1042636d9 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -251,6 +251,16 @@ config AD7380
To compile this driver as a module, choose M here: the module will be
called ad7380.
+config AD7405
+ tristate "Analog Device AD7405 ADC Driver"
+ select IIO_BACKEND
+ help
+ Say yes here to build support for Analog Devices AD7405, ADUM7701,
+ ADUM7702, ADUM7703 analog to digital converters (ADC).
+
+ To compile this driver as a module, choose M here: the module will be
+ called ad7405.
+
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 07d4b832c42e..8115f30b7862 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_AD7291) += ad7291.o
obj-$(CONFIG_AD7292) += ad7292.o
obj-$(CONFIG_AD7298) += ad7298.o
obj-$(CONFIG_AD7380) += ad7380.o
+obj-$(CONFIG_AD7405) += ad7405.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/ad7405.c b/drivers/iio/adc/ad7405.c
new file mode 100644
index 000000000000..5fe36ce61819
--- /dev/null
+++ b/drivers/iio/adc/ad7405.c
@@ -0,0 +1,264 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Analog Devices AD7405 driver
+ *
+ * Copyright 2025 Analog Devices Inc.
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+#include <linux/util_macros.h>
+
+#include <linux/iio/backend.h>
+#include <linux/iio/iio.h>
+
+const unsigned int ad7405_dec_rates[] = {
+ 4096, 2048, 1024, 512, 256, 128, 64, 32,
+};
+
+struct ad7405_chip_info {
+ const char *name;
+ unsigned int max_rate;
+ struct iio_chan_spec channel[];
+};
+
+struct ad7405_state {
+ struct iio_backend *back;
+ /* lock to protect multiple accesses to the device registers */
+ struct mutex lock;
+ const struct ad7405_chip_info *info;
+ unsigned int sample_frequency_tbl[ARRAY_SIZE(ad7405_dec_rates)];
+ unsigned int sample_frequency;
+ unsigned int ref_frequency;
+};
+
+static void ad7405_fill_samp_freq_table(struct ad7405_state *st)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(ad7405_dec_rates); i++)
+ st->sample_frequency_tbl[i] =
+ DIV_ROUND_CLOSEST_ULL(st->ref_frequency, ad7405_dec_rates[i]);
+}
+
+static int ad7405_set_sampling_rate(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ unsigned int samp_rate)
+{
+ struct ad7405_state *st = iio_priv(indio_dev);
+ unsigned int dec_rate, idx;
+ int ret;
+
+ dec_rate = DIV_ROUND_CLOSEST_ULL(st->ref_frequency, samp_rate);
+
+ idx = find_closest_descending(dec_rate, ad7405_dec_rates,
+ ARRAY_SIZE(ad7405_dec_rates));
+
+ dec_rate = ad7405_dec_rates[idx];
+
+ ret = iio_backend_oversampling_ratio_set(st->back, 0, dec_rate);
+ if (ret)
+ return ret;
+
+ st->sample_frequency = DIV_ROUND_CLOSEST_ULL(st->ref_frequency, dec_rate);
+
+ return 0;
+}
+
+static int ad7405_read_raw(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, int *val,
+ int *val2, long info)
+{
+ struct ad7405_state *st = iio_priv(indio_dev);
+
+ switch (info) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *val = st->sample_frequency;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad7405_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val,
+ int val2, long info)
+{
+ switch (info) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ if (val < 1)
+ return -EINVAL;
+ return ad7405_set_sampling_rate(indio_dev, chan, val);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad7405_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long info)
+{
+ struct ad7405_state *st = iio_priv(indio_dev);
+
+ switch (info) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *vals = st->sample_frequency_tbl;
+ *length = ARRAY_SIZE(st->sample_frequency_tbl);
+ *type = IIO_VAL_INT;
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
+static void ad7405_clk_disable_unprepare(void *clk)
+{
+ clk_disable_unprepare(clk);
+}
+
+static const struct iio_info ad7405_iio_info = {
+ .read_raw = &ad7405_read_raw,
+ .write_raw = &ad7405_write_raw,
+ .read_avail = &ad7405_read_avail,
+};
+
+#define AD7405_IIO_CHANNEL { \
+ .type = IIO_VOLTAGE, \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_OFFSET), \
+ .indexed = 1, \
+ .channel = 0, \
+ .channel2 = 1, \
+ .differential = 1, \
+ .scan_index = 0, \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ }, \
+}
+
+static const struct ad7405_chip_info ad7405_chip_info = {
+ .name = "AD7405",
+ .channel = {
+ AD7405_IIO_CHANNEL,
+ },
+};
+
+static const struct ad7405_chip_info adum7701_chip_info = {
+ .name = "ADUM7701",
+ .channel = {
+ AD7405_IIO_CHANNEL,
+ },
+};
+
+static const char * const ad7405_power_supplies[] = {
+ "vdd1", "vdd2",
+};
+
+static int ad7405_probe(struct platform_device *pdev)
+{
+ const struct ad7405_chip_info *chip_info;
+ struct device *dev = &pdev->dev;
+ struct iio_dev *indio_dev;
+ struct ad7405_state *st;
+ struct clk *clk;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+
+ ret = devm_mutex_init(dev, &st->lock);
+ if (ret)
+ return ret;
+
+ chip_info = device_get_match_data(dev);
+ if (!chip_info)
+ return dev_err_probe(dev, -EINVAL, "no chip info\n");
+
+ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(ad7405_power_supplies),
+ ad7405_power_supplies);
+
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to get and enable supplies");
+
+ clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ ret = devm_add_action_or_reset(dev, ad7405_clk_disable_unprepare, clk);
+ if (ret)
+ return ret;
+
+ st->ref_frequency = clk_get_rate(clk);
+ if (!(st->ref_frequency))
+ return -EINVAL;
+
+ ad7405_fill_samp_freq_table(st);
+
+ indio_dev->dev.parent = dev;
+ indio_dev->name = chip_info->name;
+ indio_dev->channels = chip_info->channel;
+ indio_dev->num_channels = 1;
+ indio_dev->info = &ad7405_iio_info;
+
+ st->back = devm_iio_backend_get(dev, NULL);
+ if (IS_ERR(st->back))
+ return dev_err_probe(dev, PTR_ERR(st->back),
+ "failed to get IIO backend");
+
+ ret = iio_backend_chan_enable(st->back, 0);
+ if (ret)
+ return ret;
+
+ ret = devm_iio_backend_request_buffer(dev, st->back, indio_dev);
+ if (ret)
+ return ret;
+
+ ret = devm_iio_backend_enable(dev, st->back);
+ if (ret)
+ return ret;
+
+ ret = ad7405_set_sampling_rate(indio_dev, &indio_dev->channels[0],
+ chip_info->max_rate);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+/* Match table for of_platform binding */
+static const struct of_device_id ad7405_of_match[] = {
+ { .compatible = "adi,ad7405", .data = &ad7405_chip_info, },
+ { .compatible = "adi,adum7701", .data = &adum7701_chip_info, },
+ { .compatible = "adi,adum7702", .data = &adum7701_chip_info, },
+ { .compatible = "adi,adum7703", .data = &adum7701_chip_info, },
+ { /* end of list */ },
+};
+MODULE_DEVICE_TABLE(of, ad7405_of_match);
+
+static struct platform_driver ad7405_driver = {
+ .driver = {
+ .name = "ad7405",
+ .owner = THIS_MODULE,
+ .of_match_table = ad7405_of_match,
+ },
+ .probe = ad7405_probe,
+};
+module_platform_driver(ad7405_driver);
+
+MODULE_AUTHOR("Dragos Bogdan <dragos.bogdan@analog.com>");
+MODULE_AUTHOR("Pop Ioan Daniel <pop.ioan-daniel@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD7405 driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_BACKEND");
--
2.34.1
On Thu, 8 May 2025 15:30:57 +0300
Pop Ioan Daniel <pop.ioan-daniel@analog.com> wrote:
> Add support for the AD7405/ADUM770x, a high performance isolated ADC,
> 1-channel, 16-bit with a second-order Σ-Δ modulator that converts an
> analog input signal into a high speed, single-bit data stream.
>
> Signed-off-by: Pop Ioan Daniel <pop.ioan-daniel@analog.com>
Hi,
Just a few comments inline. In particular I'd avoid the gcc specific
behaviour unless we have it documented somewhere in the kernel that
static flexible array instantiation is allowed.
Doesn't make sense here anyway just make it 1 element.
Jonathan
> diff --git a/drivers/iio/adc/ad7405.c b/drivers/iio/adc/ad7405.c
> new file mode 100644
> index 000000000000..5fe36ce61819
> --- /dev/null
> +++ b/drivers/iio/adc/ad7405.c
> @@ -0,0 +1,264 @@
> +
> +struct ad7405_chip_info {
> + const char *name;
> + unsigned int max_rate;
> + struct iio_chan_spec channel[];
See below.
> +};
> +static int ad7405_read_avail(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan,
> + const int **vals, int *type, int *length,
> + long info)
> +{
> + struct ad7405_state *st = iio_priv(indio_dev);
> +
> + switch (info) {
> + case IIO_CHAN_INFO_SAMP_FREQ:
> + *vals = st->sample_frequency_tbl;
1 tab only.
> + *length = ARRAY_SIZE(st->sample_frequency_tbl);
> + *type = IIO_VAL_INT;
> + return IIO_AVAIL_LIST;
> + default:
> + return -EINVAL;
> + }
> +}
> +
> +static const struct ad7405_chip_info ad7405_chip_info = {
> + .name = "AD7405",
> + .channel = {
> + AD7405_IIO_CHANNEL,
> + },
> +};
> +
> +static const struct ad7405_chip_info adum7701_chip_info = {
> + .name = "ADUM7701",
Convention here is 1 tab indent only.
> + .channel = {
This will look nicer without the array of 1 thing going on.
Interesting corner of the c spec to use a flexible array member
for this. Definitely don't do that as I hate reading that spec to
check corners like this. On this occasion I looked and could
not find an answer. There is a gcc extension that makes this work
though.
> + AD7405_IIO_CHANNEL,
> + },
> +};
Hi Pop,
kernel test robot noticed the following build warnings:
[auto build test WARNING on jic23-iio/togreg]
[also build test WARNING on linus/master v6.15-rc5 next-20250508]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Pop-Ioan-Daniel/iio-backend-update-iio_backend_oversampling_ratio_set/20250508-203339
base: https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git togreg
patch link: https://lore.kernel.org/r/20250508123107.3797042-5-pop.ioan-daniel%40analog.com
patch subject: [PATCH v2 4/4] iio: adc: ad7405: add ad7405 driver
config: m68k-randconfig-r123-20250509 (https://download.01.org/0day-ci/archive/20250509/202505091958.k0P7xNyC-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 13.3.0
reproduce: (https://download.01.org/0day-ci/archive/20250509/202505091958.k0P7xNyC-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202505091958.k0P7xNyC-lkp@intel.com/
sparse warnings: (new ones prefixed by >>)
>> drivers/iio/adc/ad7405.c:19:20: sparse: sparse: symbol 'ad7405_dec_rates' was not declared. Should it be static?
vim +/ad7405_dec_rates +19 drivers/iio/adc/ad7405.c
18
> 19 const unsigned int ad7405_dec_rates[] = {
20 4096, 2048, 1024, 512, 256, 128, 64, 32,
21 };
22
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
On 5/8/25 7:30 AM, Pop Ioan Daniel wrote:
> Add support for the AD7405/ADUM770x, a high performance isolated ADC,
> 1-channel, 16-bit with a second-order Σ-Δ modulator that converts an
> analog input signal into a high speed, single-bit data stream.
>
> Signed-off-by: Pop Ioan Daniel <pop.ioan-daniel@analog.com>
> ---
...
> diff --git a/drivers/iio/adc/ad7405.c b/drivers/iio/adc/ad7405.c
> new file mode 100644
> index 000000000000..5fe36ce61819
> --- /dev/null
> +++ b/drivers/iio/adc/ad7405.c
> @@ -0,0 +1,264 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Analog Devices AD7405 driver
> + *
> + * Copyright 2025 Analog Devices Inc.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/module.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/platform_device.h>
> +#include <linux/property.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/util_macros.h>
> +
> +#include <linux/iio/backend.h>
> +#include <linux/iio/iio.h>
> +
> +const unsigned int ad7405_dec_rates[] = {
> + 4096, 2048, 1024, 512, 256, 128, 64, 32,
> +};
> +
> +struct ad7405_chip_info {
> + const char *name;
> + unsigned int max_rate;
> + struct iio_chan_spec channel[];
Since there is only one channel, we can drop the [] here.
> +};
> +
> +struct ad7405_state {
> + struct iio_backend *back;
> + /* lock to protect multiple accesses to the device registers */
> + struct mutex lock;
This lock isn't used and can be removed.
> + const struct ad7405_chip_info *info;
> + unsigned int sample_frequency_tbl[ARRAY_SIZE(ad7405_dec_rates)];
> + unsigned int sample_frequency;
> + unsigned int ref_frequency;
> +};
> +
> +static void ad7405_fill_samp_freq_table(struct ad7405_state *st)
> +{
> + unsigned int i;
> +
> + for (i = 0; i < ARRAY_SIZE(ad7405_dec_rates); i++)
> + st->sample_frequency_tbl[i] =
> + DIV_ROUND_CLOSEST_ULL(st->ref_frequency, ad7405_dec_rates[i]);
> +}
> +
> +static int ad7405_set_sampling_rate(struct iio_dev *indio_dev,
> + const struct iio_chan_spec *chan,
> + unsigned int samp_rate)
> +{
> + struct ad7405_state *st = iio_priv(indio_dev);
> + unsigned int dec_rate, idx;
> + int ret;
> +
> + dec_rate = DIV_ROUND_CLOSEST_ULL(st->ref_frequency, samp_rate);
> +
> + idx = find_closest_descending(dec_rate, ad7405_dec_rates,
> + ARRAY_SIZE(ad7405_dec_rates));
> +
> + dec_rate = ad7405_dec_rates[idx];
> +
> + ret = iio_backend_oversampling_ratio_set(st->back, 0, dec_rate);
> + if (ret)
> + return ret;
> +
> + st->sample_frequency = DIV_ROUND_CLOSEST_ULL(st->ref_frequency, dec_rate);
> +
> + return 0;
> +}
> +
> +static int ad7405_read_raw(struct iio_dev *indio_dev,
> + const struct iio_chan_spec *chan, int *val,
> + int *val2, long info)
> +{
> + struct ad7405_state *st = iio_priv(indio_dev);
> +
> + switch (info) {
This is missing an implementation for IIO_CHAN_INFO_SCALE and IIO_CHAN_INFO_OFFSET.
> + case IIO_CHAN_INFO_SAMP_FREQ:
> + *val = st->sample_frequency;
> + return IIO_VAL_INT;
> + default:
> + return -EINVAL;
> + }
> +}
> +
> +static int ad7405_write_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan, int val,
> + int val2, long info)
> +{
> + switch (info) {
> + case IIO_CHAN_INFO_SAMP_FREQ:
> + if (val < 1)
> + return -EINVAL;
> + return ad7405_set_sampling_rate(indio_dev, chan, val);
> + default:
> + return -EINVAL;
> + }
> +}
> +
> +static int ad7405_read_avail(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan,
> + const int **vals, int *type, int *length,
> + long info)
> +{
> + struct ad7405_state *st = iio_priv(indio_dev);
> +
> + switch (info) {
> + case IIO_CHAN_INFO_SAMP_FREQ:
> + *vals = st->sample_frequency_tbl;
> + *length = ARRAY_SIZE(st->sample_frequency_tbl);
> + *type = IIO_VAL_INT;
> + return IIO_AVAIL_LIST;
> + default:
> + return -EINVAL;
> + }
> +}
> +
> +static void ad7405_clk_disable_unprepare(void *clk)
> +{
> + clk_disable_unprepare(clk);
> +}
> +
> +static const struct iio_info ad7405_iio_info = {
> + .read_raw = &ad7405_read_raw,
> + .write_raw = &ad7405_write_raw,
> + .read_avail = &ad7405_read_avail,
> +};
> +
> +#define AD7405_IIO_CHANNEL { \
> + .type = IIO_VOLTAGE, \
> + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
> + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
Would it make more sense to use IIO_CHAN_INFO_OVERSAMPLING_RATIO for controlling
the decimation rate and have IIO_CHAN_INFO_SAMP_FREQ be read-only?
Maybe also useful to have a read-only filter_type attribute to say that the
backend is providing a sinc3 filter?
> + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
> + BIT(IIO_CHAN_INFO_OFFSET), \
> + .indexed = 1, \
> + .channel = 0, \
> + .channel2 = 1, \
> + .differential = 1, \
> + .scan_index = 0, \
> + .scan_type = { \
> + .sign = 'u', \
> + .realbits = 16, \
> + .storagebits = 16, \
> + }, \
> +}
> +
> +static const struct ad7405_chip_info ad7405_chip_info = {
> + .name = "AD7405",
> + .channel = {
> + AD7405_IIO_CHANNEL,
> + },
> +};
> +
> +static const struct ad7405_chip_info adum7701_chip_info = {
> + .name = "ADUM7701",
> + .channel = {
> + AD7405_IIO_CHANNEL,
> + },
> +};
> +
> +static const char * const ad7405_power_supplies[] = {
> + "vdd1", "vdd2",
> +};
> +
> +static int ad7405_probe(struct platform_device *pdev)
> +{
> + const struct ad7405_chip_info *chip_info;
> + struct device *dev = &pdev->dev;
> + struct iio_dev *indio_dev;
> + struct ad7405_state *st;
> + struct clk *clk;
> + int ret;
> +
> + indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
> + if (!indio_dev)
> + return -ENOMEM;
> +
> + st = iio_priv(indio_dev);
> +
> + ret = devm_mutex_init(dev, &st->lock);
> + if (ret)
> + return ret;
> +
> + chip_info = device_get_match_data(dev);
> + if (!chip_info)
> + return dev_err_probe(dev, -EINVAL, "no chip info\n");
> +
> + ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(ad7405_power_supplies),
> + ad7405_power_supplies);
> +
> + if (ret)
> + return dev_err_probe(dev, ret, "failed to get and enable supplies");
> +
> + clk = devm_clk_get_enabled(dev, NULL);
> + if (IS_ERR(clk))
> + return PTR_ERR(clk);
> +
> + ret = devm_add_action_or_reset(dev, ad7405_clk_disable_unprepare, clk);
devm_clk_get_enabled() already make sure the clock is disabled when the dirver
is removed, so this is not needed.
> + if (ret)
> + return ret;
> +
> + st->ref_frequency = clk_get_rate(clk);
> + if (!(st->ref_frequency))
Inner () not needed.
> + return -EINVAL;
> +
> + ad7405_fill_samp_freq_table(st);
> +
> + indio_dev->dev.parent = dev;
> + indio_dev->name = chip_info->name;
> + indio_dev->channels = chip_info->channel;
> + indio_dev->num_channels = 1;
> + indio_dev->info = &ad7405_iio_info;
> +
> + st->back = devm_iio_backend_get(dev, NULL);
> + if (IS_ERR(st->back))
> + return dev_err_probe(dev, PTR_ERR(st->back),
> + "failed to get IIO backend");
> +
> + ret = iio_backend_chan_enable(st->back, 0);
> + if (ret)
> + return ret;
> +
> + ret = devm_iio_backend_request_buffer(dev, st->back, indio_dev);
> + if (ret)
> + return ret;
> +
> + ret = devm_iio_backend_enable(dev, st->back);
> + if (ret)
> + return ret;
> +
> + ret = ad7405_set_sampling_rate(indio_dev, &indio_dev->channels[0],
> + chip_info->max_rate);
max_rate is never set, so will always be 0.
> + if (ret)
> + return ret;
> +
> + return devm_iio_device_register(dev, indio_dev);
> +}
> +
> +/* Match table for of_platform binding */
> +static const struct of_device_id ad7405_of_match[] = {
> + { .compatible = "adi,ad7405", .data = &ad7405_chip_info, },
> + { .compatible = "adi,adum7701", .data = &adum7701_chip_info, },
> + { .compatible = "adi,adum7702", .data = &adum7701_chip_info, },
> + { .compatible = "adi,adum7703", .data = &adum7701_chip_info, },
> + { /* end of list */ },
{ }
We standardized on this style in the IIO subsystem.
> +};
> +MODULE_DEVICE_TABLE(of, ad7405_of_match);
> +
> +static struct platform_driver ad7405_driver = {
> + .driver = {
> + .name = "ad7405",
> + .owner = THIS_MODULE,
> + .of_match_table = ad7405_of_match,
> + },
> + .probe = ad7405_probe,
> +};
> +module_platform_driver(ad7405_driver);
> +
> +MODULE_AUTHOR("Dragos Bogdan <dragos.bogdan@analog.com>");
> +MODULE_AUTHOR("Pop Ioan Daniel <pop.ioan-daniel@analog.com>");
> +MODULE_DESCRIPTION("Analog Devices AD7405 driver");
> +MODULE_LICENSE("GPL");
> +MODULE_IMPORT_NS("IIO_BACKEND");
> > +
> > +static const struct iio_info ad7405_iio_info = {
> > + .read_raw = &ad7405_read_raw,
> > + .write_raw = &ad7405_write_raw,
> > + .read_avail = &ad7405_read_avail,
> > +};
> > +
> > +#define AD7405_IIO_CHANNEL { \
> > + .type = IIO_VOLTAGE, \
> > + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
> > + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
>
> Would it make more sense to use IIO_CHAN_INFO_OVERSAMPLING_RATIO for controlling
> the decimation rate and have IIO_CHAN_INFO_SAMP_FREQ be read-only?
My initial reaction to this was that we'd be not providing one of the longest
standing and user friendly(ish) interfaces. However if it literally only affects
oversampling then indeed I think oversampling is the more informative interface.
Which is to say I started writing no then thought some more and ended up agreeing with
you ;)
As you say, a read only sampling frequency is fine. We use those when it's controlled
by some outside factor (like a clock frequency) so userspace should in theory at least
cope fine with that being RO.
> Maybe also useful to have a read-only filter_type attribute to say that the
> backend is providing a sinc3 filter?
Nice to have perhaps.
J
© 2016 - 2025 Red Hat, Inc.