summaryrefslogtreecommitdiff
path: root/drivers/iio/adc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio/adc')
-rw-r--r--drivers/iio/adc/Kconfig31
-rw-r--r--drivers/iio/adc/Makefile3
-rw-r--r--drivers/iio/adc/ad4030.c4
-rw-r--r--drivers/iio/adc/ad4080.c126
-rw-r--r--drivers/iio/adc/ad7124.c295
-rw-r--r--drivers/iio/adc/ad7768-1.c2
-rw-r--r--drivers/iio/adc/ade9000.c2
-rw-r--r--drivers/iio/adc/aspeed_adc.c34
-rw-r--r--drivers/iio/adc/max14001.c391
-rw-r--r--drivers/iio/adc/mcp3564.c2
-rw-r--r--drivers/iio/adc/meson_saradc.c6
-rw-r--r--drivers/iio/adc/mt6360-adc.c2
-rw-r--r--drivers/iio/adc/pac1921.c8
-rw-r--r--drivers/iio/adc/pac1934.c2
-rw-r--r--drivers/iio/adc/qcom-spmi-rradc.c2
-rw-r--r--drivers/iio/adc/rohm-bd79112.c13
-rw-r--r--drivers/iio/adc/rohm-bd79124.c39
-rw-r--r--drivers/iio/adc/rzn1-adc.c490
-rw-r--r--drivers/iio/adc/rzt2h_adc.c304
-rw-r--r--drivers/iio/adc/ti-ads131e08.c2
-rw-r--r--drivers/iio/adc/ti_am335x_adc.c2
21 files changed, 1526 insertions, 234 deletions
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 58a14e6833f6..58da8255525e 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -1020,6 +1020,16 @@ config MAX1363
To compile this driver as a module, choose M here: the module will be
called max1363.
+config MAX14001
+ tristate "Analog Devices MAX14001/MAX14002 ADC driver"
+ depends on SPI
+ help
+ Say yes here to build support for Analog Devices MAX14001/MAX14002
+ Configurable, Isolated 10-bit ADCs for Multi-Range Binary Inputs.
+
+ To compile this driver as a module, choose M here: the module will be
+ called max14001.
+
config MAX34408
tristate "Maxim max34408/max344089 ADC driver"
depends on I2C
@@ -1403,6 +1413,27 @@ config RZG2L_ADC
To compile this driver as a module, choose M here: the
module will be called rzg2l_adc.
+config RZN1_ADC
+ tristate "Renesas RZ/N1 ADC driver"
+ depends on ARCH_RZN1 || COMPILE_TEST
+ help
+ Say yes here to build support for the ADC found in Renesas
+ RZ/N1 family.
+
+ To compile this driver as a module, choose M here: the
+ module will be called rzn1-adc.
+
+config RZT2H_ADC
+ tristate "Renesas RZ/T2H / RZ/N2H ADC driver"
+ depends on ARCH_RENESAS || COMPILE_TEST
+ select IIO_ADC_HELPER
+ help
+ Say yes here to build support for the ADC found in Renesas
+ RZ/T2H / RZ/N2H SoCs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called rzt2h_adc.
+
config SC27XX_ADC
tristate "Spreadtrum SC27xx series PMICs ADC"
depends on MFD_SC27XX_PMIC || COMPILE_TEST
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index d008f78dc010..7cc8f9a12f76 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -89,6 +89,7 @@ obj-$(CONFIG_MAX11205) += max11205.o
obj-$(CONFIG_MAX11410) += max11410.o
obj-$(CONFIG_MAX1241) += max1241.o
obj-$(CONFIG_MAX1363) += max1363.o
+obj-$(CONFIG_MAX14001) += max14001.o
obj-$(CONFIG_MAX34408) += max34408.o
obj-$(CONFIG_MAX77541_ADC) += max77541-adc.o
obj-$(CONFIG_MAX9611) += max9611.o
@@ -123,6 +124,8 @@ obj-$(CONFIG_ROHM_BD79112) += rohm-bd79112.o
obj-$(CONFIG_ROHM_BD79124) += rohm-bd79124.o
obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
obj-$(CONFIG_RZG2L_ADC) += rzg2l_adc.o
+obj-$(CONFIG_RZN1_ADC) += rzn1-adc.o
+obj-$(CONFIG_RZT2H_ADC) += rzt2h_adc.o
obj-$(CONFIG_SC27XX_ADC) += sc27xx_adc.o
obj-$(CONFIG_SD_ADC_MODULATOR) += sd_adc_modulator.o
obj-$(CONFIG_SOPHGO_CV1800B_ADC) += sophgo-cv1800b-adc.o
diff --git a/drivers/iio/adc/ad4030.c b/drivers/iio/adc/ad4030.c
index d8bee6a4215a..68446db9bef1 100644
--- a/drivers/iio/adc/ad4030.c
+++ b/drivers/iio/adc/ad4030.c
@@ -852,8 +852,8 @@ static int ad4030_read_label(struct iio_dev *indio_dev,
char *label)
{
if (chan->differential)
- return sprintf(label, "differential%lu\n", chan->address);
- return sprintf(label, "common-mode%lu\n", chan->address);
+ return sysfs_emit(label, "differential%lu\n", chan->address);
+ return sysfs_emit(label, "common-mode%lu\n", chan->address);
}
static int ad4030_get_current_scan_type(const struct iio_dev *indio_dev,
diff --git a/drivers/iio/adc/ad4080.c b/drivers/iio/adc/ad4080.c
index 6e61787ed321..7cf3b6ed7940 100644
--- a/drivers/iio/adc/ad4080.c
+++ b/drivers/iio/adc/ad4080.c
@@ -125,7 +125,12 @@
/* Miscellaneous Definitions */
#define AD4080_SPI_READ BIT(7)
-#define AD4080_CHIP_ID GENMASK(2, 0)
+#define AD4080_CHIP_ID 0x0050
+#define AD4081_CHIP_ID 0x0051
+#define AD4083_CHIP_ID 0x0053
+#define AD4084_CHIP_ID 0x0054
+#define AD4086_CHIP_ID 0x0056
+#define AD4087_CHIP_ID 0x0057
#define AD4080_LVDS_CNV_CLK_CNT_MAX 7
@@ -167,6 +172,7 @@ struct ad4080_chip_info {
const unsigned int (*scale_table)[2];
const struct iio_chan_spec *channels;
unsigned int num_channels;
+ unsigned int lvds_cnv_clk_cnt_max;
};
struct ad4080_state {
@@ -414,23 +420,35 @@ static struct iio_chan_spec_ext_info ad4080_ext_info[] = {
{ }
};
-static const struct iio_chan_spec ad4080_channel = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 0,
- .info_mask_separate = BIT(IIO_CHAN_INFO_SCALE),
- .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) |
- BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
- .info_mask_shared_by_all_available =
- BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
- .ext_info = ad4080_ext_info,
- .scan_index = 0,
- .scan_type = {
- .sign = 's',
- .realbits = 20,
- .storagebits = 32,
- },
-};
+#define AD4080_CHANNEL_DEFINE(bits, storage) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = 0, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ .info_mask_shared_by_all_available = \
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ .ext_info = ad4080_ext_info, \
+ .scan_index = 0, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = (bits), \
+ .storagebits = (storage), \
+ }, \
+}
+
+static const struct iio_chan_spec ad4080_channel = AD4080_CHANNEL_DEFINE(20, 32);
+
+static const struct iio_chan_spec ad4081_channel = AD4080_CHANNEL_DEFINE(20, 32);
+
+static const struct iio_chan_spec ad4083_channel = AD4080_CHANNEL_DEFINE(16, 16);
+
+static const struct iio_chan_spec ad4084_channel = AD4080_CHANNEL_DEFINE(16, 16);
+
+static const struct iio_chan_spec ad4086_channel = AD4080_CHANNEL_DEFINE(14, 16);
+
+static const struct iio_chan_spec ad4087_channel = AD4080_CHANNEL_DEFINE(14, 16);
static const struct ad4080_chip_info ad4080_chip_info = {
.name = "ad4080",
@@ -439,13 +457,65 @@ static const struct ad4080_chip_info ad4080_chip_info = {
.num_scales = ARRAY_SIZE(ad4080_scale_table),
.num_channels = 1,
.channels = &ad4080_channel,
+ .lvds_cnv_clk_cnt_max = AD4080_LVDS_CNV_CLK_CNT_MAX,
+};
+
+static const struct ad4080_chip_info ad4081_chip_info = {
+ .name = "ad4081",
+ .product_id = AD4081_CHIP_ID,
+ .scale_table = ad4080_scale_table,
+ .num_scales = ARRAY_SIZE(ad4080_scale_table),
+ .num_channels = 1,
+ .channels = &ad4081_channel,
+ .lvds_cnv_clk_cnt_max = 2,
+};
+
+static const struct ad4080_chip_info ad4083_chip_info = {
+ .name = "ad4083",
+ .product_id = AD4083_CHIP_ID,
+ .scale_table = ad4080_scale_table,
+ .num_scales = ARRAY_SIZE(ad4080_scale_table),
+ .num_channels = 1,
+ .channels = &ad4083_channel,
+ .lvds_cnv_clk_cnt_max = 5,
+};
+
+static const struct ad4080_chip_info ad4084_chip_info = {
+ .name = "ad4084",
+ .product_id = AD4084_CHIP_ID,
+ .scale_table = ad4080_scale_table,
+ .num_scales = ARRAY_SIZE(ad4080_scale_table),
+ .num_channels = 1,
+ .channels = &ad4084_channel,
+ .lvds_cnv_clk_cnt_max = 2,
+};
+
+static const struct ad4080_chip_info ad4086_chip_info = {
+ .name = "ad4086",
+ .product_id = AD4086_CHIP_ID,
+ .scale_table = ad4080_scale_table,
+ .num_scales = ARRAY_SIZE(ad4080_scale_table),
+ .num_channels = 1,
+ .channels = &ad4086_channel,
+ .lvds_cnv_clk_cnt_max = 4,
+};
+
+static const struct ad4080_chip_info ad4087_chip_info = {
+ .name = "ad4087",
+ .product_id = AD4087_CHIP_ID,
+ .scale_table = ad4080_scale_table,
+ .num_scales = ARRAY_SIZE(ad4080_scale_table),
+ .num_channels = 1,
+ .channels = &ad4087_channel,
+ .lvds_cnv_clk_cnt_max = 1,
};
static int ad4080_setup(struct iio_dev *indio_dev)
{
struct ad4080_state *st = iio_priv(indio_dev);
struct device *dev = regmap_get_device(st->regmap);
- unsigned int id;
+ __le16 id_le;
+ u16 id;
int ret;
ret = regmap_write(st->regmap, AD4080_REG_INTERFACE_CONFIG_A,
@@ -458,11 +528,13 @@ static int ad4080_setup(struct iio_dev *indio_dev)
if (ret)
return ret;
- ret = regmap_read(st->regmap, AD4080_REG_CHIP_TYPE, &id);
+ ret = regmap_bulk_read(st->regmap, AD4080_REG_PRODUCT_ID_L, &id_le,
+ sizeof(id_le));
if (ret)
return ret;
- if (id != AD4080_CHIP_ID)
+ id = le16_to_cpu(id_le);
+ if (id != st->info->product_id)
dev_info(dev, "Unrecognized CHIP_ID 0x%X\n", id);
ret = regmap_set_bits(st->regmap, AD4080_REG_GPIO_CONFIG_A,
@@ -488,7 +560,7 @@ static int ad4080_setup(struct iio_dev *indio_dev)
AD4080_REG_ADC_DATA_INTF_CONFIG_B,
AD4080_ADC_DATA_INTF_CONFIG_B_LVDS_CNV_CLK_CNT_MSK,
FIELD_PREP(AD4080_ADC_DATA_INTF_CONFIG_B_LVDS_CNV_CLK_CNT_MSK,
- AD4080_LVDS_CNV_CLK_CNT_MAX));
+ st->info->lvds_cnv_clk_cnt_max));
if (ret)
return ret;
@@ -593,12 +665,22 @@ static int ad4080_probe(struct spi_device *spi)
static const struct spi_device_id ad4080_id[] = {
{ "ad4080", (kernel_ulong_t)&ad4080_chip_info },
+ { "ad4081", (kernel_ulong_t)&ad4081_chip_info },
+ { "ad4083", (kernel_ulong_t)&ad4083_chip_info },
+ { "ad4084", (kernel_ulong_t)&ad4084_chip_info },
+ { "ad4086", (kernel_ulong_t)&ad4086_chip_info },
+ { "ad4087", (kernel_ulong_t)&ad4087_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ad4080_id);
static const struct of_device_id ad4080_of_match[] = {
{ .compatible = "adi,ad4080", &ad4080_chip_info },
+ { .compatible = "adi,ad4081", &ad4081_chip_info },
+ { .compatible = "adi,ad4083", &ad4083_chip_info },
+ { .compatible = "adi,ad4084", &ad4084_chip_info },
+ { .compatible = "adi,ad4086", &ad4086_chip_info },
+ { .compatible = "adi,ad4087", &ad4087_chip_info },
{ }
};
MODULE_DEVICE_TABLE(of, ad4080_of_match);
diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c
index 61623cc6cb25..5c1a8f886bcc 100644
--- a/drivers/iio/adc/ad7124.c
+++ b/drivers/iio/adc/ad7124.c
@@ -10,6 +10,7 @@
#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
+#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
@@ -110,6 +111,8 @@
#define AD7124_FILTER_SINGLE_CYCLE BIT(16)
#define AD7124_FILTER_FS GENMASK(10, 0)
+#define AD7124_CFG_SLOT_UNASSIGNED ~0U
+
#define AD7124_MAX_CONFIGS 8
#define AD7124_MAX_CHANNELS 16
@@ -175,14 +178,13 @@ enum ad7124_filter_type {
};
struct ad7124_channel_config {
- bool live;
unsigned int cfg_slot;
unsigned int requested_odr;
unsigned int requested_odr_micro;
/*
* Following fields are used to compare for equality. If you
* make adaptations in it, you most likely also have to adapt
- * ad7124_find_similar_live_cfg(), too.
+ * ad7124_config_equal(), too.
*/
struct_group(config_props,
enum ad7124_ref_sel refsel;
@@ -199,7 +201,6 @@ struct ad7124_channel_config {
};
struct ad7124_channel {
- unsigned int nr;
struct ad7124_channel_config cfg;
unsigned int ain;
unsigned int slot;
@@ -215,14 +216,14 @@ struct ad7124_state {
unsigned int adc_control;
unsigned int num_channels;
struct mutex cfgs_lock; /* lock for configs access */
- unsigned long cfg_slots_status; /* bitmap with slot status (1 means it is used) */
+ u8 cfg_slot_use_count[AD7124_MAX_CONFIGS];
/*
* Stores the power-on reset value for the GAIN(x) registers which are
* needed for measurements at gain 1 (i.e. CONFIG(x).PGA == 0)
*/
unsigned int gain_default;
- DECLARE_KFIFO(live_cfgs_fifo, struct ad7124_channel_config *, AD7124_MAX_CONFIGS);
+ bool enable_single_cycle;
};
static const struct ad7124_chip_info ad7124_4_chip_info = {
@@ -366,9 +367,6 @@ static void ad7124_set_channel_odr(struct ad7124_state *st, unsigned int channel
cfg->requested_odr_micro * factor / MICRO;
odr_sel_bits = clamp(DIV_ROUND_CLOSEST(fclk, divisor), 1, 2047);
- if (odr_sel_bits != st->channels[channel].cfg.odr_sel_bits)
- st->channels[channel].cfg.live = false;
-
st->channels[channel].cfg.odr_sel_bits = odr_sel_bits;
}
@@ -403,61 +401,6 @@ static int ad7124_get_3db_filter_factor(struct ad7124_state *st,
}
}
-static struct ad7124_channel_config *ad7124_find_similar_live_cfg(struct ad7124_state *st,
- struct ad7124_channel_config *cfg)
-{
- struct ad7124_channel_config *cfg_aux;
- int i;
-
- /*
- * This is just to make sure that the comparison is adapted after
- * struct ad7124_channel_config was changed.
- */
- static_assert(sizeof_field(struct ad7124_channel_config, config_props) ==
- sizeof(struct {
- enum ad7124_ref_sel refsel;
- bool bipolar;
- bool buf_positive;
- bool buf_negative;
- unsigned int vref_mv;
- unsigned int pga_bits;
- unsigned int odr_sel_bits;
- enum ad7124_filter_type filter_type;
- unsigned int calibration_offset;
- unsigned int calibration_gain;
- }));
-
- for (i = 0; i < st->num_channels; i++) {
- cfg_aux = &st->channels[i].cfg;
-
- if (cfg_aux->live &&
- cfg->refsel == cfg_aux->refsel &&
- cfg->bipolar == cfg_aux->bipolar &&
- cfg->buf_positive == cfg_aux->buf_positive &&
- cfg->buf_negative == cfg_aux->buf_negative &&
- cfg->vref_mv == cfg_aux->vref_mv &&
- cfg->pga_bits == cfg_aux->pga_bits &&
- cfg->odr_sel_bits == cfg_aux->odr_sel_bits &&
- cfg->filter_type == cfg_aux->filter_type &&
- cfg->calibration_offset == cfg_aux->calibration_offset &&
- cfg->calibration_gain == cfg_aux->calibration_gain)
- return cfg_aux;
- }
-
- return NULL;
-}
-
-static int ad7124_find_free_config_slot(struct ad7124_state *st)
-{
- unsigned int free_cfg_slot;
-
- free_cfg_slot = find_first_zero_bit(&st->cfg_slots_status, AD7124_MAX_CONFIGS);
- if (free_cfg_slot == AD7124_MAX_CONFIGS)
- return -1;
-
- return free_cfg_slot;
-}
-
/* Only called during probe, so dev_err_probe() can be used */
static int ad7124_init_config_vref(struct ad7124_state *st, struct ad7124_channel_config *cfg)
{
@@ -486,6 +429,21 @@ static int ad7124_init_config_vref(struct ad7124_state *st, struct ad7124_channe
}
}
+static bool ad7124_config_equal(struct ad7124_channel_config *a,
+ struct ad7124_channel_config *b)
+{
+ return a->refsel == b->refsel &&
+ a->bipolar == b->bipolar &&
+ a->buf_positive == b->buf_positive &&
+ a->buf_negative == b->buf_negative &&
+ a->vref_mv == b->vref_mv &&
+ a->pga_bits == b->pga_bits &&
+ a->odr_sel_bits == b->odr_sel_bits &&
+ a->filter_type == b->filter_type &&
+ a->calibration_offset == b->calibration_offset &&
+ a->calibration_gain == b->calibration_gain;
+}
+
static int ad7124_write_config(struct ad7124_state *st, struct ad7124_channel_config *cfg,
unsigned int cfg_slot)
{
@@ -494,13 +452,13 @@ static int ad7124_write_config(struct ad7124_state *st, struct ad7124_channel_co
unsigned int post = 0;
int ret;
- cfg->cfg_slot = cfg_slot;
-
- ret = ad_sd_write_reg(&st->sd, AD7124_OFFSET(cfg->cfg_slot), 3, cfg->calibration_offset);
+ ret = ad_sd_write_reg(&st->sd, AD7124_OFFSET(cfg_slot), 3,
+ cfg->calibration_offset);
if (ret)
return ret;
- ret = ad_sd_write_reg(&st->sd, AD7124_GAIN(cfg->cfg_slot), 3, cfg->calibration_gain);
+ ret = ad_sd_write_reg(&st->sd, AD7124_GAIN(cfg_slot), 3,
+ cfg->calibration_gain);
if (ret)
return ret;
@@ -510,7 +468,7 @@ static int ad7124_write_config(struct ad7124_state *st, struct ad7124_channel_co
(cfg->buf_negative ? AD7124_CONFIG_AIN_BUFM : 0) |
FIELD_PREP(AD7124_CONFIG_PGA, cfg->pga_bits);
- ret = ad_sd_write_reg(&st->sd, AD7124_CONFIG(cfg->cfg_slot), 2, val);
+ ret = ad_sd_write_reg(&st->sd, AD7124_CONFIG(cfg_slot), 2, val);
if (ret < 0)
return ret;
@@ -560,108 +518,107 @@ static int ad7124_write_config(struct ad7124_state *st, struct ad7124_channel_co
* sampling frequency even when only one channel is enabled in a
* buffered read. If it was not set, the N in ad7124_set_channel_odr()
* would be 1 and we would get a faster sampling frequency than what
- * was requested.
+ * was requested. It may only be disabled through debugfs for testing
+ * purposes.
*/
- return ad_sd_write_reg(&st->sd, AD7124_FILTER(cfg->cfg_slot), 3,
+ return ad_sd_write_reg(&st->sd, AD7124_FILTER(cfg_slot), 3,
FIELD_PREP(AD7124_FILTER_FILTER, filter) |
FIELD_PREP(AD7124_FILTER_REJ60, rej60) |
FIELD_PREP(AD7124_FILTER_POST_FILTER, post) |
- AD7124_FILTER_SINGLE_CYCLE |
+ FIELD_PREP(AD7124_FILTER_SINGLE_CYCLE,
+ st->enable_single_cycle) |
FIELD_PREP(AD7124_FILTER_FS, cfg->odr_sel_bits));
}
-static struct ad7124_channel_config *ad7124_pop_config(struct ad7124_state *st)
+/**
+ * ad7124_request_config_slot() - Request a config slot for a given config
+ * @st: Driver instance
+ * @channel: Channel to request a slot for
+ *
+ * Tries to find a matching config already in use, otherwise finds a free
+ * slot. If this function returns successfully, the use count for the slot is
+ * increased and the slot number is stored in cfg->cfg_slot.
+ *
+ * The slot must be released again with ad7124_release_config_slot() when no
+ * longer needed.
+ *
+ * Returns: 0 if a slot was successfully assigned, -EUSERS if no slot is
+ * available or other error if SPI communication fails.
+ */
+static int ad7124_request_config_slot(struct ad7124_state *st, u8 channel)
{
- struct ad7124_channel_config *lru_cfg;
- struct ad7124_channel_config *cfg;
- int ret;
- int i;
+ unsigned int other, slot;
+ int last_used_slot = -1;
- /*
- * Pop least recently used config from the fifo
- * in order to make room for the new one
- */
- ret = kfifo_get(&st->live_cfgs_fifo, &lru_cfg);
- if (ret <= 0)
- return NULL;
+ /* Find another channel with a matching config, if any. */
+ for (other = 0; other < st->num_channels; other++) {
+ if (other == channel)
+ continue;
- lru_cfg->live = false;
+ if (st->channels[other].cfg.cfg_slot == AD7124_CFG_SLOT_UNASSIGNED)
+ continue;
- /* mark slot as free */
- assign_bit(lru_cfg->cfg_slot, &st->cfg_slots_status, 0);
+ last_used_slot = max_t(int, last_used_slot,
+ st->channels[other].cfg.cfg_slot);
- /* invalidate all other configs that pointed to this one */
- for (i = 0; i < st->num_channels; i++) {
- cfg = &st->channels[i].cfg;
+ if (!ad7124_config_equal(&st->channels[other].cfg,
+ &st->channels[channel].cfg))
+ continue;
- if (cfg->cfg_slot == lru_cfg->cfg_slot)
- cfg->live = false;
+ /* Found a match, re-use that slot. */
+ slot = st->channels[other].cfg.cfg_slot;
+ st->cfg_slot_use_count[slot]++;
+ st->channels[channel].cfg.cfg_slot = slot;
+
+ return 0;
}
- return lru_cfg;
+ /* No match, use next free slot. */
+ slot = last_used_slot + 1;
+ if (slot >= AD7124_MAX_CONFIGS)
+ return -EUSERS;
+
+ st->cfg_slot_use_count[slot]++;
+ st->channels[channel].cfg.cfg_slot = slot;
+
+ return ad7124_write_config(st, &st->channels[channel].cfg, slot);
}
-static int ad7124_push_config(struct ad7124_state *st, struct ad7124_channel_config *cfg)
+static void ad7124_release_config_slot(struct ad7124_state *st, u8 channel)
{
- struct ad7124_channel_config *lru_cfg;
- int free_cfg_slot;
-
- free_cfg_slot = ad7124_find_free_config_slot(st);
- if (free_cfg_slot >= 0) {
- /* push the new config in configs queue */
- kfifo_put(&st->live_cfgs_fifo, cfg);
- } else {
- /* pop one config to make room for the new one */
- lru_cfg = ad7124_pop_config(st);
- if (!lru_cfg)
- return -EINVAL;
+ unsigned int slot;
- /* push the new config in configs queue */
- free_cfg_slot = lru_cfg->cfg_slot;
- kfifo_put(&st->live_cfgs_fifo, cfg);
- }
+ /*
+ * All of these early return conditions can happen at probe when all
+ * channels are disabled. Otherwise, they should not happen normally.
+ */
+ if (channel >= st->num_channels)
+ return;
- /* mark slot as used */
- assign_bit(free_cfg_slot, &st->cfg_slots_status, 1);
+ slot = st->channels[channel].cfg.cfg_slot;
- return ad7124_write_config(st, cfg, free_cfg_slot);
-}
+ if (slot == AD7124_CFG_SLOT_UNASSIGNED ||
+ st->cfg_slot_use_count[slot] == 0)
+ return;
-static int ad7124_enable_channel(struct ad7124_state *st, struct ad7124_channel *ch)
-{
- ch->cfg.live = true;
- return ad_sd_write_reg(&st->sd, AD7124_CHANNEL(ch->nr), 2, ch->ain |
- FIELD_PREP(AD7124_CHANNEL_SETUP, ch->cfg.cfg_slot) |
- AD7124_CHANNEL_ENABLE);
+ st->cfg_slot_use_count[slot]--;
+ st->channels[channel].cfg.cfg_slot = AD7124_CFG_SLOT_UNASSIGNED;
}
static int ad7124_prepare_read(struct ad7124_state *st, int address)
{
struct ad7124_channel_config *cfg = &st->channels[address].cfg;
- struct ad7124_channel_config *live_cfg;
+ int ret;
- /*
- * Before doing any reads assign the channel a configuration.
- * Check if channel's config is on the device
- */
- if (!cfg->live) {
- /* check if config matches another one */
- live_cfg = ad7124_find_similar_live_cfg(st, cfg);
- if (!live_cfg)
- ad7124_push_config(st, cfg);
- else
- cfg->cfg_slot = live_cfg->cfg_slot;
- }
+ ret = ad7124_request_config_slot(st, address);
+ if (ret)
+ return ret;
/* point channel to the config slot and enable */
- return ad7124_enable_channel(st, &st->channels[address]);
-}
-
-static int __ad7124_set_channel(struct ad_sigma_delta *sd, unsigned int channel)
-{
- struct ad7124_state *st = container_of(sd, struct ad7124_state, sd);
-
- return ad7124_prepare_read(st, channel);
+ return ad_sd_write_reg(&st->sd, AD7124_CHANNEL(address), 2,
+ st->channels[address].ain |
+ FIELD_PREP(AD7124_CHANNEL_SETUP, cfg->cfg_slot) |
+ AD7124_CHANNEL_ENABLE);
}
static int ad7124_set_channel(struct ad_sigma_delta *sd, unsigned int channel)
@@ -670,7 +627,7 @@ static int ad7124_set_channel(struct ad_sigma_delta *sd, unsigned int channel)
int ret;
mutex_lock(&st->cfgs_lock);
- ret = __ad7124_set_channel(sd, channel);
+ ret = ad7124_prepare_read(st, channel);
mutex_unlock(&st->cfgs_lock);
return ret;
@@ -700,6 +657,8 @@ static int ad7124_disable_one(struct ad_sigma_delta *sd, unsigned int chan)
{
struct ad7124_state *st = container_of(sd, struct ad7124_state, sd);
+ ad7124_release_config_slot(st, chan);
+
/* The relevant thing here is that AD7124_CHANNEL_ENABLE is cleared. */
return ad_sd_write_reg(&st->sd, AD7124_CHANNEL(chan), 2, 0);
}
@@ -709,7 +668,7 @@ static int ad7124_disable_all(struct ad_sigma_delta *sd)
int ret;
int i;
- for (i = 0; i < 16; i++) {
+ for (i = 0; i < AD7124_MAX_CHANNELS; i++) {
ret = ad7124_disable_one(sd, i);
if (ret < 0)
return ret;
@@ -921,9 +880,6 @@ static int ad7124_write_raw(struct iio_dev *indio_dev,
gain = DIV_ROUND_CLOSEST(res, val2);
res = ad7124_find_closest_match(ad7124_gain, ARRAY_SIZE(ad7124_gain), gain);
- if (st->channels[chan->address].cfg.pga_bits != res)
- st->channels[chan->address].cfg.live = false;
-
st->channels[chan->address].cfg.pga_bits = res;
return 0;
default:
@@ -965,7 +921,7 @@ static int ad7124_update_scan_mode(struct iio_dev *indio_dev,
for (i = 0; i < st->num_channels; i++) {
bit_set = test_bit(i, scan_mask);
if (bit_set)
- ret = __ad7124_set_channel(&st->sd, i);
+ ret = ad7124_prepare_read(st, i);
else
ret = ad7124_spi_write_mask(st, AD7124_CHANNEL(i), AD7124_CHANNEL_ENABLE,
0, 2);
@@ -1066,7 +1022,11 @@ static int ad7124_syscalib_locked(struct ad7124_state *st, const struct iio_chan
if (ret < 0)
return ret;
- ret = ad_sd_read_reg(&st->sd, AD7124_OFFSET(ch->cfg.cfg_slot), 3,
+ /*
+ * Making the assumption that a single conversion will always
+ * use configuration slot 0 for the OFFSET/GAIN registers.
+ */
+ ret = ad_sd_read_reg(&st->sd, AD7124_OFFSET(0), 3,
&ch->cfg.calibration_offset);
if (ret < 0)
return ret;
@@ -1081,7 +1041,7 @@ static int ad7124_syscalib_locked(struct ad7124_state *st, const struct iio_chan
if (ret < 0)
return ret;
- ret = ad_sd_read_reg(&st->sd, AD7124_GAIN(ch->cfg.cfg_slot), 3,
+ ret = ad_sd_read_reg(&st->sd, AD7124_GAIN(0), 3,
&ch->cfg.calibration_gain);
if (ret < 0)
return ret;
@@ -1172,7 +1132,6 @@ static int ad7124_set_filter_type_attr(struct iio_dev *dev,
guard(mutex)(&st->cfgs_lock);
- cfg->live = false;
cfg->filter_type = value;
ad7124_set_channel_odr(st, chan->address);
@@ -1305,7 +1264,6 @@ static int ad7124_parse_channel_config(struct iio_dev *indio_dev,
return dev_err_probe(dev, -EINVAL,
"diff-channels property of %pfwP contains invalid data\n", child);
- st->channels[channel].nr = channel;
st->channels[channel].ain = FIELD_PREP(AD7124_CHANNEL_AINP, ain[0]) |
FIELD_PREP(AD7124_CHANNEL_AINM, ain[1]);
@@ -1332,7 +1290,6 @@ static int ad7124_parse_channel_config(struct iio_dev *indio_dev,
if (num_channels < AD7124_MAX_CHANNELS) {
st->channels[num_channels] = (struct ad7124_channel) {
- .nr = num_channels,
.ain = FIELD_PREP(AD7124_CHANNEL_AINP, AD7124_CHANNEL_AINx_TEMPSENSOR) |
FIELD_PREP(AD7124_CHANNEL_AINM, AD7124_CHANNEL_AINx_AVSS),
.cfg = {
@@ -1358,6 +1315,7 @@ static int ad7124_parse_channel_config(struct iio_dev *indio_dev,
},
.address = num_channels,
.scan_index = num_channels,
+ .ext_info = ad7124_calibsys_ext_info,
};
}
@@ -1489,8 +1447,10 @@ static int ad7124_setup(struct ad7124_state *st)
st->adc_control &= ~AD7124_ADC_CONTROL_MODE;
st->adc_control |= FIELD_PREP(AD7124_ADC_CONTROL_MODE, AD_SD_MODE_IDLE);
- mutex_init(&st->cfgs_lock);
- INIT_KFIFO(st->live_cfgs_fifo);
+ ret = devm_mutex_init(dev, &st->cfgs_lock);
+ if (ret)
+ return ret;
+
for (i = 0; i < st->num_channels; i++) {
struct ad7124_channel_config *cfg = &st->channels[i].cfg;
@@ -1498,6 +1458,8 @@ static int ad7124_setup(struct ad7124_state *st)
if (ret < 0)
return ret;
+ cfg->cfg_slot = AD7124_CFG_SLOT_UNASSIGNED;
+
/* Default filter type on the ADC after reset. */
cfg->filter_type = AD7124_FILTER_TYPE_SINC4;
@@ -1559,9 +1521,9 @@ static int __ad7124_calibrate_all(struct ad7124_state *st, struct iio_dev *indio
* after full-scale calibration because the next
* ad_sd_calibrate() call overwrites this via
* ad_sigma_delta_set_channel() -> ad7124_set_channel()
- * ... -> ad7124_enable_channel().
+ * -> ad7124_prepare_read().
*/
- ret = ad_sd_read_reg(&st->sd, AD7124_GAIN(st->channels[i].cfg.cfg_slot), 3,
+ ret = ad_sd_read_reg(&st->sd, AD7124_GAIN(0), 3,
&st->channels[i].cfg.calibration_gain);
if (ret < 0)
return ret;
@@ -1571,7 +1533,11 @@ static int __ad7124_calibrate_all(struct ad7124_state *st, struct iio_dev *indio
if (ret < 0)
return ret;
- ret = ad_sd_read_reg(&st->sd, AD7124_OFFSET(st->channels[i].cfg.cfg_slot), 3,
+ /*
+ * Making the assumption that a single conversion will always
+ * use configuration slot 0 for the OFFSET/GAIN registers.
+ */
+ ret = ad_sd_read_reg(&st->sd, AD7124_OFFSET(0), 3,
&st->channels[i].cfg.calibration_offset);
if (ret < 0)
return ret;
@@ -1613,6 +1579,18 @@ static void ad7124_reg_disable(void *r)
regulator_disable(r);
}
+static void ad7124_debugfs_init(struct iio_dev *indio_dev)
+{
+ struct dentry *dentry = iio_get_debugfs_dentry(indio_dev);
+ struct ad7124_state *st = iio_priv(indio_dev);
+
+ if (!IS_ENABLED(CONFIG_DEBUG_FS))
+ return;
+
+ debugfs_create_bool("enable_single_cycle", 0644, dentry,
+ &st->enable_single_cycle);
+}
+
static int ad7124_probe(struct spi_device *spi)
{
const struct ad7124_chip_info *info;
@@ -1633,6 +1611,9 @@ static int ad7124_probe(struct spi_device *spi)
st->chip_info = info;
+ /* Only disabled for debug/testing purposes. */
+ st->enable_single_cycle = true;
+
indio_dev->name = st->chip_info->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &ad7124_info;
@@ -1690,6 +1671,8 @@ static int ad7124_probe(struct spi_device *spi)
if (ret < 0)
return dev_err_probe(dev, ret, "Failed to register iio device\n");
+ ad7124_debugfs_init(indio_dev);
+
return 0;
}
diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c
index 872c88d0c86c..d96802b7847a 100644
--- a/drivers/iio/adc/ad7768-1.c
+++ b/drivers/iio/adc/ad7768-1.c
@@ -899,7 +899,7 @@ static int ad7768_read_label(struct iio_dev *indio_dev,
{
struct ad7768_state *st = iio_priv(indio_dev);
- return sprintf(label, "%s\n", st->labels[chan->channel]);
+ return sysfs_emit(label, "%s\n", st->labels[chan->channel]);
}
static int ad7768_get_current_scan_type(const struct iio_dev *indio_dev,
diff --git a/drivers/iio/adc/ade9000.c b/drivers/iio/adc/ade9000.c
index 94e05e11abd9..2de8a718d62a 100644
--- a/drivers/iio/adc/ade9000.c
+++ b/drivers/iio/adc/ade9000.c
@@ -1629,7 +1629,7 @@ static const struct regmap_config ade9000_regmap_config = {
.val_bits = 32,
.max_register = 0x6bc,
.zero_flag_mask = true,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_read = ade9000_spi_read_reg,
.reg_write = ade9000_spi_write_reg,
.volatile_reg = ade9000_is_volatile_reg,
diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
index 1d5fd5f534b8..bf2bfd6bdc41 100644
--- a/drivers/iio/adc/aspeed_adc.c
+++ b/drivers/iio/adc/aspeed_adc.c
@@ -645,6 +645,16 @@ static const struct aspeed_adc_trim_locate ast2600_adc1_trim = {
.field = GENMASK(7, 4),
};
+static const struct aspeed_adc_trim_locate ast2700_adc0_trim = {
+ .offset = 0x820,
+ .field = GENMASK(3, 0),
+};
+
+static const struct aspeed_adc_trim_locate ast2700_adc1_trim = {
+ .offset = 0x820,
+ .field = GENMASK(7, 4),
+};
+
static const struct aspeed_adc_model_data ast2400_model_data = {
.model_name = "ast2400-adc",
.vref_fixed_mv = 2500,
@@ -689,11 +699,35 @@ static const struct aspeed_adc_model_data ast2600_adc1_model_data = {
.trim_locate = &ast2600_adc1_trim,
};
+static const struct aspeed_adc_model_data ast2700_adc0_model_data = {
+ .model_name = "ast2700-adc0",
+ .min_sampling_rate = 10000,
+ .max_sampling_rate = 500000,
+ .wait_init_sequence = true,
+ .bat_sense_sup = true,
+ .scaler_bit_width = 16,
+ .num_channels = 8,
+ .trim_locate = &ast2700_adc0_trim,
+};
+
+static const struct aspeed_adc_model_data ast2700_adc1_model_data = {
+ .model_name = "ast2700-adc1",
+ .min_sampling_rate = 10000,
+ .max_sampling_rate = 500000,
+ .wait_init_sequence = true,
+ .bat_sense_sup = true,
+ .scaler_bit_width = 16,
+ .num_channels = 8,
+ .trim_locate = &ast2700_adc1_trim,
+};
+
static const struct of_device_id aspeed_adc_matches[] = {
{ .compatible = "aspeed,ast2400-adc", .data = &ast2400_model_data },
{ .compatible = "aspeed,ast2500-adc", .data = &ast2500_model_data },
{ .compatible = "aspeed,ast2600-adc0", .data = &ast2600_adc0_model_data },
{ .compatible = "aspeed,ast2600-adc1", .data = &ast2600_adc1_model_data },
+ { .compatible = "aspeed,ast2700-adc0", .data = &ast2700_adc0_model_data },
+ { .compatible = "aspeed,ast2700-adc1", .data = &ast2700_adc1_model_data },
{ }
};
MODULE_DEVICE_TABLE(of, aspeed_adc_matches);
diff --git a/drivers/iio/adc/max14001.c b/drivers/iio/adc/max14001.c
new file mode 100644
index 000000000000..90ad4cb5868d
--- /dev/null
+++ b/drivers/iio/adc/max14001.c
@@ -0,0 +1,391 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+/*
+ * Analog Devices MAX14001/MAX14002 ADC driver
+ *
+ * Copyright (C) 2023-2025 Analog Devices Inc.
+ * Copyright (C) 2023 Kim Seer Paller <kimseer.paller@analog.com>
+ * Copyright (c) 2025 Marilene Andrade Garcia <marilene.agarcia@gmail.com>
+ *
+ * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/MAX14001-MAX14002.pdf
+ */
+
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/bitrev.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/types.h>
+#include <linux/units.h>
+#include <asm/byteorder.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/types.h>
+
+/* MAX14001 Registers Address */
+#define MAX14001_REG_ADC 0x00
+#define MAX14001_REG_FADC 0x01
+#define MAX14001_REG_FLAGS 0x02
+#define MAX14001_REG_FLTEN 0x03
+#define MAX14001_REG_THL 0x04
+#define MAX14001_REG_THU 0x05
+#define MAX14001_REG_INRR 0x06
+#define MAX14001_REG_INRT 0x07
+#define MAX14001_REG_INRP 0x08
+#define MAX14001_REG_CFG 0x09
+#define MAX14001_REG_ENBL 0x0A
+#define MAX14001_REG_ACT 0x0B
+#define MAX14001_REG_WEN 0x0C
+
+#define MAX14001_REG_VERIFICATION(x) ((x) + 0x10)
+
+#define MAX14001_REG_CFG_BIT_EXRF BIT(5)
+
+#define MAX14001_REG_WEN_VALUE_WRITE 0x294
+
+#define MAX14001_MASK_ADDR GENMASK(15, 11)
+#define MAX14001_MASK_WR BIT(10)
+#define MAX14001_MASK_DATA GENMASK(9, 0)
+
+struct max14001_state {
+ const struct max14001_chip_info *chip_info;
+ struct spi_device *spi;
+ struct regmap *regmap;
+ int vref_mV;
+ bool spi_hw_has_lsb_first;
+
+ /*
+ * The following buffers will be bit-reversed during device
+ * communication, because the device transmits and receives data
+ * LSB-first.
+ * DMA (thus cache coherency maintenance) requires the transfer
+ * buffers to live in their own cache lines.
+ */
+ union {
+ __be16 be;
+ __le16 le;
+ } spi_tx_buffer __aligned(IIO_DMA_MINALIGN);
+
+ union {
+ __be16 be;
+ __le16 le;
+ } spi_rx_buffer;
+};
+
+struct max14001_chip_info {
+ const char *name;
+};
+
+static int max14001_read(void *context, unsigned int reg, unsigned int *val)
+{
+ struct max14001_state *st = context;
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = &st->spi_tx_buffer,
+ .len = sizeof(st->spi_tx_buffer),
+ .cs_change = 1,
+ }, {
+ .rx_buf = &st->spi_rx_buffer,
+ .len = sizeof(st->spi_rx_buffer),
+ },
+ };
+ int ret;
+ unsigned int addr, data;
+
+ /*
+ * Prepare SPI transmit buffer 16 bit-value and reverse bit order
+ * to align with the LSB-first input on SDI port in order to meet
+ * the device communication requirements. If the controller supports
+ * SPI_LSB_FIRST, this step will be handled by the SPI controller.
+ */
+ addr = FIELD_PREP(MAX14001_MASK_ADDR, reg);
+
+ if (st->spi_hw_has_lsb_first)
+ st->spi_tx_buffer.le = cpu_to_le16(addr);
+ else
+ st->spi_tx_buffer.be = cpu_to_be16(bitrev16(addr));
+
+ ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
+ if (ret)
+ return ret;
+
+ /*
+ * Convert received 16-bit value to cpu-endian format and reverse
+ * bit order. If the controller supports SPI_LSB_FIRST, this step
+ * will be handled by the SPI controller.
+ */
+ if (st->spi_hw_has_lsb_first)
+ data = le16_to_cpu(st->spi_rx_buffer.le);
+ else
+ data = bitrev16(be16_to_cpu(st->spi_rx_buffer.be));
+
+ *val = FIELD_GET(MAX14001_MASK_DATA, data);
+
+ return 0;
+}
+
+static int max14001_write(struct max14001_state *st, unsigned int reg, unsigned int val)
+{
+ unsigned int addr;
+
+ /*
+ * Prepare SPI transmit buffer 16 bit-value and reverse bit order
+ * to align with the LSB-first input on SDI port in order to meet
+ * the device communication requirements. If the controller supports
+ * SPI_LSB_FIRST, this step will be handled by the SPI controller.
+ */
+ addr = FIELD_PREP(MAX14001_MASK_ADDR, reg) |
+ FIELD_PREP(MAX14001_MASK_WR, 1) |
+ FIELD_PREP(MAX14001_MASK_DATA, val);
+
+ if (st->spi_hw_has_lsb_first)
+ st->spi_tx_buffer.le = cpu_to_le16(addr);
+ else
+ st->spi_tx_buffer.be = cpu_to_be16(bitrev16(addr));
+
+ return spi_write(st->spi, &st->spi_tx_buffer, sizeof(st->spi_tx_buffer));
+}
+
+static int max14001_write_single_reg(void *context, unsigned int reg, unsigned int val)
+{
+ struct max14001_state *st = context;
+ int ret;
+
+ /* Enable writing to the SPI register. */
+ ret = max14001_write(st, MAX14001_REG_WEN, MAX14001_REG_WEN_VALUE_WRITE);
+ if (ret)
+ return ret;
+
+ /* Writing data into SPI register. */
+ ret = max14001_write(st, reg, val);
+ if (ret)
+ return ret;
+
+ /* Disable writing to the SPI register. */
+ return max14001_write(st, MAX14001_REG_WEN, 0);
+}
+
+static int max14001_write_verification_reg(struct max14001_state *st, unsigned int reg)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(st->regmap, reg, &val);
+ if (ret)
+ return ret;
+
+ return max14001_write(st, MAX14001_REG_VERIFICATION(reg), val);
+}
+
+static int max14001_disable_mv_fault(struct max14001_state *st)
+{
+ unsigned int reg;
+ int ret;
+
+ /* Enable writing to the SPI registers. */
+ ret = max14001_write(st, MAX14001_REG_WEN, MAX14001_REG_WEN_VALUE_WRITE);
+ if (ret)
+ return ret;
+
+ /*
+ * Reads all registers and writes the values to their appropriate
+ * verification registers to clear the Memory Validation fault.
+ */
+ for (reg = MAX14001_REG_FLTEN; reg <= MAX14001_REG_ENBL; reg++) {
+ ret = max14001_write_verification_reg(st, reg);
+ if (ret)
+ return ret;
+ }
+
+ /* Disable writing to the SPI registers. */
+ return max14001_write(st, MAX14001_REG_WEN, 0);
+}
+
+static int max14001_debugfs_reg_access(struct iio_dev *indio_dev,
+ unsigned int reg, unsigned int writeval,
+ unsigned int *readval)
+{
+ struct max14001_state *st = iio_priv(indio_dev);
+
+ if (readval)
+ return regmap_read(st->regmap, reg, readval);
+
+ return regmap_write(st->regmap, reg, writeval);
+}
+
+static int max14001_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct max14001_state *st = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = regmap_read(st->regmap, MAX14001_REG_ADC, val);
+ if (ret)
+ return ret;
+
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = st->vref_mV;
+ *val2 = 10;
+
+ return IIO_VAL_FRACTIONAL_LOG2;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct regmap_range max14001_regmap_rd_range[] = {
+ regmap_reg_range(MAX14001_REG_ADC, MAX14001_REG_ENBL),
+ regmap_reg_range(MAX14001_REG_WEN, MAX14001_REG_WEN),
+ regmap_reg_range(MAX14001_REG_VERIFICATION(MAX14001_REG_FLTEN),
+ MAX14001_REG_VERIFICATION(MAX14001_REG_ENBL)),
+};
+
+static const struct regmap_access_table max14001_regmap_rd_table = {
+ .yes_ranges = max14001_regmap_rd_range,
+ .n_yes_ranges = ARRAY_SIZE(max14001_regmap_rd_range),
+};
+
+static const struct regmap_range max14001_regmap_wr_range[] = {
+ regmap_reg_range(MAX14001_REG_FLTEN, MAX14001_REG_WEN),
+ regmap_reg_range(MAX14001_REG_VERIFICATION(MAX14001_REG_FLTEN),
+ MAX14001_REG_VERIFICATION(MAX14001_REG_ENBL)),
+};
+
+static const struct regmap_access_table max14001_regmap_wr_table = {
+ .yes_ranges = max14001_regmap_wr_range,
+ .n_yes_ranges = ARRAY_SIZE(max14001_regmap_wr_range),
+};
+
+static const struct regmap_config max14001_regmap_config = {
+ .reg_read = max14001_read,
+ .reg_write = max14001_write_single_reg,
+ .max_register = MAX14001_REG_VERIFICATION(MAX14001_REG_ENBL),
+ .rd_table = &max14001_regmap_rd_table,
+ .wr_table = &max14001_regmap_wr_table,
+};
+
+static const struct iio_info max14001_info = {
+ .read_raw = max14001_read_raw,
+ .debugfs_reg_access = max14001_debugfs_reg_access,
+};
+
+static const struct iio_chan_spec max14001_channel[] = {
+ {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ },
+};
+
+static int max14001_probe(struct spi_device *spi)
+{
+ struct device *dev = &spi->dev;
+ struct iio_dev *indio_dev;
+ struct max14001_state *st;
+ int ret;
+ bool use_ext_vrefin = false;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+ st->spi = spi;
+ st->spi_hw_has_lsb_first = spi->mode & SPI_LSB_FIRST;
+ st->chip_info = spi_get_device_match_data(spi);
+ if (!st->chip_info)
+ return -EINVAL;
+
+ indio_dev->name = st->chip_info->name;
+ indio_dev->info = &max14001_info;
+ indio_dev->channels = max14001_channel;
+ indio_dev->num_channels = ARRAY_SIZE(max14001_channel);
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ st->regmap = devm_regmap_init(dev, NULL, st, &max14001_regmap_config);
+ if (IS_ERR(st->regmap))
+ return dev_err_probe(dev, PTR_ERR(st->regmap), "Failed to initialize regmap\n");
+
+ ret = devm_regulator_get_enable(dev, "vdd");
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable Vdd supply\n");
+
+ ret = devm_regulator_get_enable(dev, "vddl");
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable Vddl supply\n");
+
+ ret = devm_regulator_get_enable_read_voltage(dev, "refin");
+ if (ret < 0 && ret != -ENODEV)
+ return dev_err_probe(dev, ret, "Failed to get REFIN voltage\n");
+
+ if (ret == -ENODEV)
+ ret = 1250000;
+ else
+ use_ext_vrefin = true;
+ st->vref_mV = ret / (MICRO / MILLI);
+
+ if (use_ext_vrefin) {
+ /*
+ * Configure the MAX14001/MAX14002 to use an external voltage
+ * reference source by setting the bit 5 of the configuration register.
+ */
+ ret = regmap_set_bits(st->regmap, MAX14001_REG_CFG,
+ MAX14001_REG_CFG_BIT_EXRF);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to set External REFIN in Configuration Register\n");
+ }
+
+ ret = max14001_disable_mv_fault(st);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to disable MV Fault\n");
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static struct max14001_chip_info max14001_chip_info = {
+ .name = "max14001",
+};
+
+static struct max14001_chip_info max14002_chip_info = {
+ .name = "max14002",
+};
+
+static const struct spi_device_id max14001_id_table[] = {
+ { "max14001", (kernel_ulong_t)&max14001_chip_info },
+ { "max14002", (kernel_ulong_t)&max14002_chip_info },
+ { }
+};
+
+static const struct of_device_id max14001_of_match[] = {
+ { .compatible = "adi,max14001", .data = &max14001_chip_info },
+ { .compatible = "adi,max14002", .data = &max14002_chip_info },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max14001_of_match);
+
+static struct spi_driver max14001_driver = {
+ .driver = {
+ .name = "max14001",
+ .of_match_table = max14001_of_match,
+ },
+ .probe = max14001_probe,
+ .id_table = max14001_id_table,
+};
+module_spi_driver(max14001_driver);
+
+MODULE_AUTHOR("Kim Seer Paller <kimseer.paller@analog.com>");
+MODULE_AUTHOR("Marilene Andrade Garcia <marilene.agarcia@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices MAX14001/MAX14002 ADCs driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/mcp3564.c b/drivers/iio/adc/mcp3564.c
index cd679ff10a97..fcdf13f49c48 100644
--- a/drivers/iio/adc/mcp3564.c
+++ b/drivers/iio/adc/mcp3564.c
@@ -987,7 +987,7 @@ static int mcp3564_read_label(struct iio_dev *indio_dev,
{
struct mcp3564_state *adc = iio_priv(indio_dev);
- return sprintf(label, "%s\n", adc->labels[chan->scan_index]);
+ return sysfs_emit(label, "%s\n", adc->labels[chan->scan_index]);
}
static int mcp3564_parse_fw_children(struct iio_dev *indio_dev)
diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c
index f7e7172ef4f6..47cd350498a0 100644
--- a/drivers/iio/adc/meson_saradc.c
+++ b/drivers/iio/adc/meson_saradc.c
@@ -1181,12 +1181,12 @@ static int read_label(struct iio_dev *indio_dev,
char *label)
{
if (chan->type == IIO_TEMP)
- return sprintf(label, "temp-sensor\n");
+ return sysfs_emit(label, "temp-sensor\n");
if (chan->type == IIO_VOLTAGE && chan->channel >= NUM_MUX_0_VSS)
- return sprintf(label, "%s\n",
+ return sysfs_emit(label, "%s\n",
chan7_mux_names[chan->channel - NUM_MUX_0_VSS]);
if (chan->type == IIO_VOLTAGE)
- return sprintf(label, "channel-%d\n", chan->channel);
+ return sysfs_emit(label, "channel-%d\n", chan->channel);
return 0;
}
diff --git a/drivers/iio/adc/mt6360-adc.c b/drivers/iio/adc/mt6360-adc.c
index 69b3569c90e5..e0e4df418612 100644
--- a/drivers/iio/adc/mt6360-adc.c
+++ b/drivers/iio/adc/mt6360-adc.c
@@ -216,7 +216,7 @@ static const char *mt6360_channel_labels[MT6360_CHAN_MAX] = {
static int mt6360_adc_read_label(struct iio_dev *iio_dev, const struct iio_chan_spec *chan,
char *label)
{
- return snprintf(label, PAGE_SIZE, "%s\n", mt6360_channel_labels[chan->channel]);
+ return sysfs_emit(label, "%s\n", mt6360_channel_labels[chan->channel]);
}
static const struct iio_info mt6360_adc_iio_info = {
diff --git a/drivers/iio/adc/pac1921.c b/drivers/iio/adc/pac1921.c
index 35433250b008..a0227b57f238 100644
--- a/drivers/iio/adc/pac1921.c
+++ b/drivers/iio/adc/pac1921.c
@@ -672,13 +672,13 @@ static int pac1921_read_label(struct iio_dev *indio_dev,
{
switch (chan->channel) {
case PAC1921_CHAN_VBUS:
- return sprintf(label, "vbus\n");
+ return sysfs_emit(label, "vbus\n");
case PAC1921_CHAN_VSENSE:
- return sprintf(label, "vsense\n");
+ return sysfs_emit(label, "vsense\n");
case PAC1921_CHAN_CURRENT:
- return sprintf(label, "current\n");
+ return sysfs_emit(label, "current\n");
case PAC1921_CHAN_POWER:
- return sprintf(label, "power\n");
+ return sysfs_emit(label, "power\n");
default:
return -EINVAL;
}
diff --git a/drivers/iio/adc/pac1934.c b/drivers/iio/adc/pac1934.c
index 48df16509260..ec96bb0f2ed6 100644
--- a/drivers/iio/adc/pac1934.c
+++ b/drivers/iio/adc/pac1934.c
@@ -768,7 +768,7 @@ static int pac1934_retrieve_data(struct pac1934_chip_info *info,
* Re-schedule the work for the read registers on timeout
* (to prevent chip registers saturation)
*/
- mod_delayed_work(system_wq, &info->work_chip_rfsh,
+ mod_delayed_work(system_percpu_wq, &info->work_chip_rfsh,
msecs_to_jiffies(PAC1934_MAX_RFSH_LIMIT_MS));
}
diff --git a/drivers/iio/adc/qcom-spmi-rradc.c b/drivers/iio/adc/qcom-spmi-rradc.c
index f61ad0510f04..b245416bae12 100644
--- a/drivers/iio/adc/qcom-spmi-rradc.c
+++ b/drivers/iio/adc/qcom-spmi-rradc.c
@@ -769,7 +769,7 @@ static int rradc_read_raw(struct iio_dev *indio_dev,
static int rradc_read_label(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, char *label)
{
- return snprintf(label, PAGE_SIZE, "%s\n",
+ return sysfs_emit(label, "%s\n",
rradc_chans[chan->address].label);
}
diff --git a/drivers/iio/adc/rohm-bd79112.c b/drivers/iio/adc/rohm-bd79112.c
index d15e06c8b94d..7420aa6627d5 100644
--- a/drivers/iio/adc/rohm-bd79112.c
+++ b/drivers/iio/adc/rohm-bd79112.c
@@ -168,15 +168,10 @@ static int _get_gpio_reg(unsigned int offset, unsigned int base)
#define GET_GPI_VAL_REG(offset) _get_gpio_reg((offset), BD79112_REG_GPI_VALUE_A0_A7)
static const struct regmap_range bd71815_volatile_ro_ranges[] = {
- {
- /* Read ADC data */
- .range_min = BD79112_REG_AGIO0A,
- .range_max = BD79112_REG_AGIO15B,
- }, {
- /* GPI state */
- .range_min = BD79112_REG_GPI_VALUE_B8_15,
- .range_max = BD79112_REG_GPI_VALUE_A0_A7,
- },
+ /* Read ADC data */
+ regmap_reg_range(BD79112_REG_AGIO0A, BD79112_REG_AGIO15B),
+ /* GPI state */
+ regmap_reg_range(BD79112_REG_GPI_VALUE_B8_15, BD79112_REG_GPI_VALUE_A0_A7),
};
static const struct regmap_access_table bd79112_volatile_regs = {
diff --git a/drivers/iio/adc/rohm-bd79124.c b/drivers/iio/adc/rohm-bd79124.c
index 06c55c8da93f..fc0452749b79 100644
--- a/drivers/iio/adc/rohm-bd79124.c
+++ b/drivers/iio/adc/rohm-bd79124.c
@@ -126,13 +126,8 @@ struct bd79124_data {
};
static const struct regmap_range bd79124_ro_ranges[] = {
- {
- .range_min = BD79124_REG_EVENT_FLAG,
- .range_max = BD79124_REG_EVENT_FLAG,
- }, {
- .range_min = BD79124_REG_RECENT_CH0_LSB,
- .range_max = BD79124_REG_RECENT_CH7_MSB,
- },
+ regmap_reg_range(BD79124_REG_EVENT_FLAG, BD79124_REG_EVENT_FLAG),
+ regmap_reg_range(BD79124_REG_RECENT_CH0_LSB, BD79124_REG_RECENT_CH7_MSB),
};
static const struct regmap_access_table bd79124_ro_regs = {
@@ -141,22 +136,11 @@ static const struct regmap_access_table bd79124_ro_regs = {
};
static const struct regmap_range bd79124_volatile_ranges[] = {
- {
- .range_min = BD79124_REG_RECENT_CH0_LSB,
- .range_max = BD79124_REG_RECENT_CH7_MSB,
- }, {
- .range_min = BD79124_REG_EVENT_FLAG,
- .range_max = BD79124_REG_EVENT_FLAG,
- }, {
- .range_min = BD79124_REG_EVENT_FLAG_HI,
- .range_max = BD79124_REG_EVENT_FLAG_HI,
- }, {
- .range_min = BD79124_REG_EVENT_FLAG_LO,
- .range_max = BD79124_REG_EVENT_FLAG_LO,
- }, {
- .range_min = BD79124_REG_SYSTEM_STATUS,
- .range_max = BD79124_REG_SYSTEM_STATUS,
- },
+ regmap_reg_range(BD79124_REG_RECENT_CH0_LSB, BD79124_REG_RECENT_CH7_MSB),
+ regmap_reg_range(BD79124_REG_EVENT_FLAG, BD79124_REG_EVENT_FLAG),
+ regmap_reg_range(BD79124_REG_EVENT_FLAG_HI, BD79124_REG_EVENT_FLAG_HI),
+ regmap_reg_range(BD79124_REG_EVENT_FLAG_LO, BD79124_REG_EVENT_FLAG_LO),
+ regmap_reg_range(BD79124_REG_SYSTEM_STATUS, BD79124_REG_SYSTEM_STATUS),
};
static const struct regmap_access_table bd79124_volatile_regs = {
@@ -165,13 +149,8 @@ static const struct regmap_access_table bd79124_volatile_regs = {
};
static const struct regmap_range bd79124_precious_ranges[] = {
- {
- .range_min = BD79124_REG_EVENT_FLAG_HI,
- .range_max = BD79124_REG_EVENT_FLAG_HI,
- }, {
- .range_min = BD79124_REG_EVENT_FLAG_LO,
- .range_max = BD79124_REG_EVENT_FLAG_LO,
- },
+ regmap_reg_range(BD79124_REG_EVENT_FLAG_HI, BD79124_REG_EVENT_FLAG_HI),
+ regmap_reg_range(BD79124_REG_EVENT_FLAG_LO, BD79124_REG_EVENT_FLAG_LO),
};
static const struct regmap_access_table bd79124_precious_regs = {
diff --git a/drivers/iio/adc/rzn1-adc.c b/drivers/iio/adc/rzn1-adc.c
new file mode 100644
index 000000000000..93b0feef8ea0
--- /dev/null
+++ b/drivers/iio/adc/rzn1-adc.c
@@ -0,0 +1,490 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas RZ/N1 ADC driver
+ *
+ * Copyright (C) 2025 Schneider-Electric
+ *
+ * Author: Herve Codina <herve.codina@bootlin.com>
+ *
+ * The RZ/N1 ADC controller can handle channels from its internal ADC1 and/or
+ * ADC2 cores. The driver use ADC1 and/or ADC2 cores depending on the presence
+ * of the related power supplies (AVDD and VREF) description in the device-tree.
+ */
+
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/clk.h>
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/iio/iio.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/types.h>
+
+#define RZN1_ADC_CONTROL_REG 0x02c
+#define RZN1_ADC_CONTROL_ADC_BUSY BIT(6)
+
+#define RZN1_ADC_FORCE_REG 0x030
+#define RZN1_ADC_SET_FORCE_REG 0x034
+#define RZN1_ADC_CLEAR_FORCE_REG 0x038
+#define RZN1_ADC_FORCE_VC(_n) BIT(_n)
+
+#define RZN1_ADC_CONFIG_REG 0x040
+#define RZN1_ADC_CONFIG_ADC_POWER_DOWN BIT(3)
+
+#define RZN1_ADC_VC_REG(_n) (0x0c0 + 4 * (_n))
+#define RZN1_ADC_VC_ADC2_ENABLE BIT(16)
+#define RZN1_ADC_VC_ADC1_ENABLE BIT(15)
+#define RZN1_ADC_VC_ADC2_CHANNEL_SEL_MASK GENMASK(5, 3)
+#define RZN1_ADC_VC_ADC1_CHANNEL_SEL_MASK GENMASK(2, 0)
+
+#define RZN1_ADC_ADC1_DATA_REG(_n) (0x100 + 4 * (_n))
+#define RZN1_ADC_ADC2_DATA_REG(_n) (0x140 + 4 * (_n))
+#define RZN1_ADC_ADCX_DATA_DATA_MASK GENMASK(11, 0)
+
+#define RZN1_ADC_NO_CHANNEL -1
+
+#define RZN1_ADC_CHANNEL_SHARED_SCALE(_ch, _ds_name) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = (_ch), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .datasheet_name = (_ds_name), \
+}
+
+#define RZN1_ADC_CHANNEL_SEPARATED_SCALE(_ch, _ds_name) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = (_ch), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .datasheet_name = (_ds_name), \
+}
+
+/*
+ * 8 ADC1_IN signals existed numbered 0..4, 6..8
+ * ADCx_IN5 doesn't exist in RZ/N1 datasheet
+ */
+static struct iio_chan_spec rzn1_adc1_channels[] = {
+ RZN1_ADC_CHANNEL_SHARED_SCALE(0, "ADC1_IN0"),
+ RZN1_ADC_CHANNEL_SHARED_SCALE(1, "ADC1_IN1"),
+ RZN1_ADC_CHANNEL_SHARED_SCALE(2, "ADC1_IN2"),
+ RZN1_ADC_CHANNEL_SHARED_SCALE(3, "ADC1_IN3"),
+ RZN1_ADC_CHANNEL_SHARED_SCALE(4, "ADC1_IN4"),
+ RZN1_ADC_CHANNEL_SHARED_SCALE(5, "ADC1_IN6"),
+ RZN1_ADC_CHANNEL_SHARED_SCALE(6, "ADC1_IN7"),
+ RZN1_ADC_CHANNEL_SHARED_SCALE(7, "ADC1_IN8"),
+};
+
+static struct iio_chan_spec rzn1_adc2_channels[] = {
+ RZN1_ADC_CHANNEL_SHARED_SCALE(8, "ADC2_IN0"),
+ RZN1_ADC_CHANNEL_SHARED_SCALE(9, "ADC2_IN1"),
+ RZN1_ADC_CHANNEL_SHARED_SCALE(10, "ADC2_IN2"),
+ RZN1_ADC_CHANNEL_SHARED_SCALE(11, "ADC2_IN3"),
+ RZN1_ADC_CHANNEL_SHARED_SCALE(12, "ADC2_IN4"),
+ RZN1_ADC_CHANNEL_SHARED_SCALE(13, "ADC2_IN6"),
+ RZN1_ADC_CHANNEL_SHARED_SCALE(14, "ADC2_IN7"),
+ RZN1_ADC_CHANNEL_SHARED_SCALE(15, "ADC2_IN8"),
+};
+
+/*
+ * If both ADCs core are used, scale cannot be common. Indeed, scale is
+ * based on Vref connected on each ADC core.
+ */
+static struct iio_chan_spec rzn1_adc1_adc2_channels[] = {
+ RZN1_ADC_CHANNEL_SEPARATED_SCALE(0, "ADC1_IN0"),
+ RZN1_ADC_CHANNEL_SEPARATED_SCALE(1, "ADC1_IN1"),
+ RZN1_ADC_CHANNEL_SEPARATED_SCALE(2, "ADC1_IN2"),
+ RZN1_ADC_CHANNEL_SEPARATED_SCALE(3, "ADC1_IN3"),
+ RZN1_ADC_CHANNEL_SEPARATED_SCALE(4, "ADC1_IN4"),
+ RZN1_ADC_CHANNEL_SEPARATED_SCALE(5, "ADC1_IN6"),
+ RZN1_ADC_CHANNEL_SEPARATED_SCALE(6, "ADC1_IN7"),
+ RZN1_ADC_CHANNEL_SEPARATED_SCALE(7, "ADC1_IN8"),
+ RZN1_ADC_CHANNEL_SEPARATED_SCALE(8, "ADC2_IN0"),
+ RZN1_ADC_CHANNEL_SEPARATED_SCALE(9, "ADC2_IN1"),
+ RZN1_ADC_CHANNEL_SEPARATED_SCALE(10, "ADC2_IN2"),
+ RZN1_ADC_CHANNEL_SEPARATED_SCALE(11, "ADC2_IN3"),
+ RZN1_ADC_CHANNEL_SEPARATED_SCALE(12, "ADC2_IN4"),
+ RZN1_ADC_CHANNEL_SEPARATED_SCALE(13, "ADC2_IN6"),
+ RZN1_ADC_CHANNEL_SEPARATED_SCALE(14, "ADC2_IN7"),
+ RZN1_ADC_CHANNEL_SEPARATED_SCALE(15, "ADC2_IN8"),
+};
+
+struct rzn1_adc {
+ struct device *dev;
+ void __iomem *regs;
+ struct mutex lock; /* ADC lock */
+ int adc1_vref_mV; /* ADC1 Vref in mV. Negative if ADC1 is not used */
+ int adc2_vref_mV; /* ADC2 Vref in mV. Negative if ADC2 is not used */
+};
+
+static int rzn1_adc_power(struct rzn1_adc *rzn1_adc, bool power)
+{
+ u32 v;
+
+ writel(power ? 0 : RZN1_ADC_CONFIG_ADC_POWER_DOWN,
+ rzn1_adc->regs + RZN1_ADC_CONFIG_REG);
+
+ /* Wait for the ADC_BUSY to clear */
+ return readl_poll_timeout_atomic(rzn1_adc->regs + RZN1_ADC_CONTROL_REG,
+ v, !(v & RZN1_ADC_CONTROL_ADC_BUSY),
+ 0, 500);
+}
+
+static void rzn1_adc_vc_setup_conversion(struct rzn1_adc *rzn1_adc, u32 ch,
+ int adc1_ch, int adc2_ch)
+{
+ u32 vc = 0;
+
+ if (adc1_ch != RZN1_ADC_NO_CHANNEL)
+ vc |= RZN1_ADC_VC_ADC1_ENABLE |
+ FIELD_PREP(RZN1_ADC_VC_ADC1_CHANNEL_SEL_MASK, adc1_ch);
+
+ if (adc2_ch != RZN1_ADC_NO_CHANNEL)
+ vc |= RZN1_ADC_VC_ADC2_ENABLE |
+ FIELD_PREP(RZN1_ADC_VC_ADC2_CHANNEL_SEL_MASK, adc2_ch);
+
+ writel(vc, rzn1_adc->regs + RZN1_ADC_VC_REG(ch));
+}
+
+static int rzn1_adc_vc_start_conversion(struct rzn1_adc *rzn1_adc, u32 ch)
+{
+ u32 val;
+
+ val = readl(rzn1_adc->regs + RZN1_ADC_FORCE_REG);
+ if (val & RZN1_ADC_FORCE_VC(ch))
+ return -EBUSY;
+
+ writel(RZN1_ADC_FORCE_VC(ch), rzn1_adc->regs + RZN1_ADC_SET_FORCE_REG);
+
+ return 0;
+}
+
+static void rzn1_adc_vc_stop_conversion(struct rzn1_adc *rzn1_adc, u32 ch)
+{
+ writel(RZN1_ADC_FORCE_VC(ch), rzn1_adc->regs + RZN1_ADC_CLEAR_FORCE_REG);
+}
+
+static int rzn1_adc_vc_wait_conversion(struct rzn1_adc *rzn1_adc, u32 ch,
+ u32 *adc1_data, u32 *adc2_data)
+{
+ u32 data_reg;
+ int ret;
+ u32 v;
+
+ /*
+ * When a VC is selected, it needs 20 ADC clocks to perform the
+ * conversion.
+ *
+ * The worst case is when the 16 VCs need to perform a conversion and
+ * our VC is the lowest in term of priority.
+ *
+ * In that case, the conversion is performed in 16 * 20 ADC clocks.
+ *
+ * The ADC clock can be set from 4MHz to 20MHz. This leads to a worst
+ * case of 16 * 20 * 1/4Mhz = 80us.
+ *
+ * Round it up to 100us.
+ */
+
+ /* Wait for the ADC_FORCE_VC(n) to clear */
+ ret = readl_poll_timeout_atomic(rzn1_adc->regs + RZN1_ADC_FORCE_REG,
+ v, !(v & RZN1_ADC_FORCE_VC(ch)),
+ 0, 100);
+ if (ret)
+ return ret;
+
+ if (adc1_data) {
+ data_reg = readl(rzn1_adc->regs + RZN1_ADC_ADC1_DATA_REG(ch));
+ *adc1_data = FIELD_GET(RZN1_ADC_ADCX_DATA_DATA_MASK, data_reg);
+ }
+
+ if (adc2_data) {
+ data_reg = readl(rzn1_adc->regs + RZN1_ADC_ADC2_DATA_REG(ch));
+ *adc2_data = FIELD_GET(RZN1_ADC_ADCX_DATA_DATA_MASK, data_reg);
+ }
+
+ return 0;
+}
+
+static int rzn1_adc_read_raw_ch(struct rzn1_adc *rzn1_adc, unsigned int chan, int *val)
+{
+ u32 *adc1_data, *adc2_data;
+ int adc1_ch, adc2_ch;
+ u32 adc_data;
+ int ret;
+
+ /*
+ * IIO chan are decoupled from chans used in rzn1_adc_vc_*() functions.
+ * The RZ/N1 ADC VC controller can handle on a single VC chan one
+ * channel from the ADC1 core and one channel from the ADC2 core.
+ *
+ * Even if IIO chans are mapped 1:1 to ADC core chans and so uses only
+ * a chan from ADC1 or a chan from ADC2, future improvements can define
+ * an IIO chan that uses one chan from ADC1 and one chan from ADC2.
+ */
+
+ if (chan < 8) {
+ /* chan 0..7 used to get ADC1 ch 0..7 */
+ adc1_ch = chan;
+ adc1_data = &adc_data;
+ adc2_ch = RZN1_ADC_NO_CHANNEL;
+ adc2_data = NULL;
+ } else if (chan < 16) {
+ /* chan 8..15 used to get ADC2 ch 0..7 */
+ adc1_ch = RZN1_ADC_NO_CHANNEL;
+ adc1_data = NULL;
+ adc2_ch = chan - 8;
+ adc2_data = &adc_data;
+ } else {
+ return -EINVAL;
+ }
+
+ ACQUIRE(pm_runtime_active_auto_try_enabled, pm)(rzn1_adc->dev);
+ ret = ACQUIRE_ERR(pm_runtime_active_auto_try_enabled, &pm);
+ if (ret < 0)
+ return ret;
+
+ scoped_guard(mutex, &rzn1_adc->lock) {
+ rzn1_adc_vc_setup_conversion(rzn1_adc, chan, adc1_ch, adc2_ch);
+
+ ret = rzn1_adc_vc_start_conversion(rzn1_adc, chan);
+ if (ret)
+ return ret;
+
+ ret = rzn1_adc_vc_wait_conversion(rzn1_adc, chan, adc1_data, adc2_data);
+ if (ret) {
+ rzn1_adc_vc_stop_conversion(rzn1_adc, chan);
+ return ret;
+ }
+ }
+
+ *val = adc_data;
+ ret = IIO_VAL_INT;
+
+ return 0;
+}
+
+static int rzn1_adc_get_vref_mV(struct rzn1_adc *rzn1_adc, unsigned int chan)
+{
+ /* chan 0..7 use ADC1 ch 0..7. Vref related to ADC1 core */
+ if (chan < 8)
+ return rzn1_adc->adc1_vref_mV;
+
+ /* chan 8..15 use ADC2 ch 0..7. Vref related to ADC2 core */
+ if (chan < 16)
+ return rzn1_adc->adc2_vref_mV;
+
+ return -EINVAL;
+}
+
+static int rzn1_adc_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct rzn1_adc *rzn1_adc = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = rzn1_adc_read_raw_ch(rzn1_adc, chan->channel, val);
+ if (ret)
+ return ret;
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ ret = rzn1_adc_get_vref_mV(rzn1_adc, chan->channel);
+ if (ret < 0)
+ return ret;
+ *val = ret;
+ *val2 = 12;
+ return IIO_VAL_FRACTIONAL_LOG2;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info rzn1_adc_info = {
+ .read_raw = &rzn1_adc_read_raw,
+};
+
+static int rzn1_adc_set_iio_dev_channels(struct rzn1_adc *rzn1_adc,
+ struct iio_dev *indio_dev)
+{
+ /*
+ * When an ADC core is not used, its related vref_mV is set to a
+ * negative error code. Use the correct IIO channels table based on
+ * those vref_mV values.
+ */
+ if (rzn1_adc->adc1_vref_mV >= 0) {
+ if (rzn1_adc->adc2_vref_mV >= 0) {
+ indio_dev->channels = rzn1_adc1_adc2_channels;
+ indio_dev->num_channels = ARRAY_SIZE(rzn1_adc1_adc2_channels);
+ } else {
+ indio_dev->channels = rzn1_adc1_channels;
+ indio_dev->num_channels = ARRAY_SIZE(rzn1_adc1_channels);
+ }
+ return 0;
+ }
+
+ if (rzn1_adc->adc2_vref_mV >= 0) {
+ indio_dev->channels = rzn1_adc2_channels;
+ indio_dev->num_channels = ARRAY_SIZE(rzn1_adc2_channels);
+ return 0;
+ }
+
+ return dev_err_probe(rzn1_adc->dev, -ENODEV,
+ "Failed to set IIO channels, no ADC core used\n");
+}
+
+static int rzn1_adc_core_get_regulators(struct rzn1_adc *rzn1_adc,
+ int *adc_vref_mV,
+ const char *avdd_name, const char *vref_name)
+{
+ struct device *dev = rzn1_adc->dev;
+ int ret;
+
+ /*
+ * For a given ADC core (ADC1 or ADC2), both regulators (AVDD and VREF)
+ * must be available in order to have the ADC core used.
+ *
+ * We use the regulators presence to check the usage of the related
+ * ADC core. If both regulators are available, the ADC core is used.
+ * Otherwise, the ADC core is not used.
+ *
+ * The adc_vref_mV value is set to a negative error code (-ENODEV) when
+ * the ADC core is not used. Otherwise it is set to the VRef mV value.
+ */
+
+ *adc_vref_mV = -ENODEV;
+
+ ret = devm_regulator_get_enable_optional(dev, avdd_name);
+ if (ret == -ENODEV)
+ return 0;
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to get '%s' regulator\n",
+ avdd_name);
+
+ ret = devm_regulator_get_enable_read_voltage(dev, vref_name);
+ if (ret == -ENODEV)
+ return 0;
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to get '%s' regulator\n",
+ vref_name);
+
+ /*
+ * Both regulators are available.
+ * Set adc_vref_mV to the Vref value in mV. This, as the value set is
+ * positive, also signals that the ADC is used.
+ */
+ *adc_vref_mV = ret / 1000;
+
+ return 0;
+}
+
+static int rzn1_adc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct iio_dev *indio_dev;
+ struct rzn1_adc *rzn1_adc;
+ struct clk *clk;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*rzn1_adc));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ rzn1_adc = iio_priv(indio_dev);
+ rzn1_adc->dev = dev;
+
+ ret = devm_mutex_init(dev, &rzn1_adc->lock);
+ if (ret)
+ return ret;
+
+ rzn1_adc->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(rzn1_adc->regs))
+ return PTR_ERR(rzn1_adc->regs);
+
+ clk = devm_clk_get_enabled(dev, "pclk");
+ if (IS_ERR(clk))
+ return dev_err_probe(dev, PTR_ERR(clk), "Failed to get pclk\n");
+
+ clk = devm_clk_get_enabled(dev, "adc");
+ if (IS_ERR(clk))
+ return dev_err_probe(dev, PTR_ERR(clk), "Failed to get adc clk\n");
+
+ ret = rzn1_adc_core_get_regulators(rzn1_adc, &rzn1_adc->adc1_vref_mV,
+ "adc1-avdd", "adc1-vref");
+ if (ret)
+ return ret;
+
+ ret = rzn1_adc_core_get_regulators(rzn1_adc, &rzn1_adc->adc2_vref_mV,
+ "adc2-avdd", "adc2-vref");
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, rzn1_adc);
+
+ indio_dev->name = "rzn1-adc";
+ indio_dev->info = &rzn1_adc_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ ret = rzn1_adc_set_iio_dev_channels(rzn1_adc, indio_dev);
+ if (ret)
+ return ret;
+
+ pm_runtime_set_autosuspend_delay(dev, 500);
+ pm_runtime_use_autosuspend(dev);
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable runtime PM\n");
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static int rzn1_adc_pm_runtime_suspend(struct device *dev)
+{
+ struct rzn1_adc *rzn1_adc = dev_get_drvdata(dev);
+
+ return rzn1_adc_power(rzn1_adc, false);
+}
+
+static int rzn1_adc_pm_runtime_resume(struct device *dev)
+{
+ struct rzn1_adc *rzn1_adc = dev_get_drvdata(dev);
+
+ return rzn1_adc_power(rzn1_adc, true);
+}
+
+static DEFINE_RUNTIME_DEV_PM_OPS(rzn1_adc_pm_ops,
+ rzn1_adc_pm_runtime_suspend,
+ rzn1_adc_pm_runtime_resume,
+ NULL);
+
+static const struct of_device_id rzn1_adc_of_match[] = {
+ { .compatible = "renesas,rzn1-adc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, rzn1_adc_of_match);
+
+static struct platform_driver rzn1_adc_driver = {
+ .probe = rzn1_adc_probe,
+ .driver = {
+ .name = "rzn1-adc",
+ .of_match_table = rzn1_adc_of_match,
+ .pm = pm_ptr(&rzn1_adc_pm_ops),
+ },
+};
+module_platform_driver(rzn1_adc_driver);
+
+MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
+MODULE_DESCRIPTION("Renesas RZ/N1 ADC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/rzt2h_adc.c b/drivers/iio/adc/rzt2h_adc.c
new file mode 100644
index 000000000000..33ce5cc44ff4
--- /dev/null
+++ b/drivers/iio/adc/rzt2h_adc.c
@@ -0,0 +1,304 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/bitfield.h>
+#include <linux/cleanup.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/iio/adc-helpers.h>
+#include <linux/iio/iio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/property.h>
+
+#define RZT2H_ADCSR_REG 0x00
+#define RZT2H_ADCSR_ADIE_MASK BIT(12)
+#define RZT2H_ADCSR_ADCS_MASK GENMASK(14, 13)
+#define RZT2H_ADCSR_ADCS_SINGLE 0b00
+#define RZT2H_ADCSR_ADST_MASK BIT(15)
+
+#define RZT2H_ADANSA0_REG 0x04
+#define RZT2H_ADANSA0_CH_MASK(x) BIT(x)
+
+#define RZT2H_ADDR_REG(x) (0x20 + 0x2 * (x))
+
+#define RZT2H_ADCALCTL_REG 0x1f0
+#define RZT2H_ADCALCTL_CAL_MASK BIT(0)
+#define RZT2H_ADCALCTL_CAL_RDY_MASK BIT(1)
+#define RZT2H_ADCALCTL_CAL_ERR_MASK BIT(2)
+
+#define RZT2H_ADC_MAX_CHANNELS 16
+
+struct rzt2h_adc {
+ void __iomem *base;
+ struct device *dev;
+
+ struct completion completion;
+ /* lock to protect against multiple access to the device */
+ struct mutex lock;
+
+ const struct iio_chan_spec *channels;
+ unsigned int num_channels;
+ unsigned int max_channels;
+};
+
+static void rzt2h_adc_start(struct rzt2h_adc *adc, unsigned int conversion_type)
+{
+ u16 reg;
+
+ reg = readw(adc->base + RZT2H_ADCSR_REG);
+
+ /* Set conversion type */
+ FIELD_MODIFY(RZT2H_ADCSR_ADCS_MASK, &reg, conversion_type);
+
+ /* Set end of conversion interrupt and start bit. */
+ reg |= RZT2H_ADCSR_ADIE_MASK | RZT2H_ADCSR_ADST_MASK;
+
+ writew(reg, adc->base + RZT2H_ADCSR_REG);
+}
+
+static void rzt2h_adc_stop(struct rzt2h_adc *adc)
+{
+ u16 reg;
+
+ reg = readw(adc->base + RZT2H_ADCSR_REG);
+
+ /* Clear end of conversion interrupt and start bit. */
+ reg &= ~(RZT2H_ADCSR_ADIE_MASK | RZT2H_ADCSR_ADST_MASK);
+
+ writew(reg, adc->base + RZT2H_ADCSR_REG);
+}
+
+static int rzt2h_adc_read_single(struct rzt2h_adc *adc, unsigned int ch, int *val)
+{
+ int ret;
+
+ ret = pm_runtime_resume_and_get(adc->dev);
+ if (ret)
+ return ret;
+
+ mutex_lock(&adc->lock);
+
+ reinit_completion(&adc->completion);
+
+ /* Enable a single channel */
+ writew(RZT2H_ADANSA0_CH_MASK(ch), adc->base + RZT2H_ADANSA0_REG);
+
+ rzt2h_adc_start(adc, RZT2H_ADCSR_ADCS_SINGLE);
+
+ /*
+ * Datasheet Page 2770, Table 41.1:
+ * 0.32us per channel when sample-and-hold circuits are not in use.
+ */
+ ret = wait_for_completion_timeout(&adc->completion, usecs_to_jiffies(1));
+ if (!ret) {
+ ret = -ETIMEDOUT;
+ goto disable;
+ }
+
+ *val = readw(adc->base + RZT2H_ADDR_REG(ch));
+ ret = IIO_VAL_INT;
+
+disable:
+ rzt2h_adc_stop(adc);
+
+ mutex_unlock(&adc->lock);
+
+ pm_runtime_put_autosuspend(adc->dev);
+
+ return ret;
+}
+
+static void rzt2h_adc_set_cal(struct rzt2h_adc *adc, bool cal)
+{
+ u16 val;
+
+ val = readw(adc->base + RZT2H_ADCALCTL_REG);
+ if (cal)
+ val |= RZT2H_ADCALCTL_CAL_MASK;
+ else
+ val &= ~RZT2H_ADCALCTL_CAL_MASK;
+
+ writew(val, adc->base + RZT2H_ADCALCTL_REG);
+}
+
+static int rzt2h_adc_calibrate(struct rzt2h_adc *adc)
+{
+ u16 val;
+ int ret;
+
+ rzt2h_adc_set_cal(adc, true);
+
+ ret = read_poll_timeout(readw, val, val & RZT2H_ADCALCTL_CAL_RDY_MASK,
+ 200, 1000, true, adc->base + RZT2H_ADCALCTL_REG);
+ if (ret) {
+ dev_err(adc->dev, "Calibration timed out: %d\n", ret);
+ return ret;
+ }
+
+ rzt2h_adc_set_cal(adc, false);
+
+ if (val & RZT2H_ADCALCTL_CAL_ERR_MASK) {
+ dev_err(adc->dev, "Calibration failed\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rzt2h_adc_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct rzt2h_adc *adc = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ return rzt2h_adc_read_single(adc, chan->channel, val);
+ case IIO_CHAN_INFO_SCALE:
+ *val = 1800;
+ *val2 = 12;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info rzt2h_adc_iio_info = {
+ .read_raw = rzt2h_adc_read_raw,
+};
+
+static irqreturn_t rzt2h_adc_isr(int irq, void *private)
+{
+ struct rzt2h_adc *adc = private;
+
+ complete(&adc->completion);
+
+ return IRQ_HANDLED;
+}
+
+static const struct iio_chan_spec rzt2h_adc_chan_template = {
+ .indexed = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .type = IIO_VOLTAGE,
+};
+
+static int rzt2h_adc_parse_properties(struct rzt2h_adc *adc)
+{
+ struct iio_chan_spec *chan_array;
+ unsigned int i;
+ int ret;
+
+ ret = devm_iio_adc_device_alloc_chaninfo_se(adc->dev,
+ &rzt2h_adc_chan_template,
+ RZT2H_ADC_MAX_CHANNELS - 1,
+ &chan_array);
+ if (ret < 0)
+ return dev_err_probe(adc->dev, ret, "Failed to read channel info");
+
+ adc->num_channels = ret;
+ adc->channels = chan_array;
+
+ for (i = 0; i < adc->num_channels; i++)
+ if (chan_array[i].channel + 1 > adc->max_channels)
+ adc->max_channels = chan_array[i].channel + 1;
+
+ return 0;
+}
+
+static int rzt2h_adc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct iio_dev *indio_dev;
+ struct rzt2h_adc *adc;
+ int ret, irq;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ adc = iio_priv(indio_dev);
+ adc->dev = dev;
+ init_completion(&adc->completion);
+
+ ret = devm_mutex_init(dev, &adc->lock);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, adc);
+
+ ret = rzt2h_adc_parse_properties(adc);
+ if (ret)
+ return ret;
+
+ adc->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(adc->base))
+ return PTR_ERR(adc->base);
+
+ pm_runtime_set_autosuspend_delay(dev, 300);
+ pm_runtime_use_autosuspend(dev);
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return ret;
+
+ irq = platform_get_irq_byname(pdev, "adi");
+ if (irq < 0)
+ return irq;
+
+ ret = devm_request_irq(dev, irq, rzt2h_adc_isr, 0, dev_name(dev), adc);
+ if (ret)
+ return ret;
+
+ indio_dev->name = "rzt2h-adc";
+ indio_dev->info = &rzt2h_adc_iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = adc->channels;
+ indio_dev->num_channels = adc->num_channels;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id rzt2h_adc_match[] = {
+ { .compatible = "renesas,r9a09g077-adc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, rzt2h_adc_match);
+
+static int rzt2h_adc_pm_runtime_resume(struct device *dev)
+{
+ struct rzt2h_adc *adc = dev_get_drvdata(dev);
+
+ /*
+ * Datasheet Page 2810, Section 41.5.6:
+ * After release from the module-stop state, wait for at least
+ * 0.5 µs before starting A/D conversion.
+ */
+ fsleep(1);
+
+ return rzt2h_adc_calibrate(adc);
+}
+
+static const struct dev_pm_ops rzt2h_adc_pm_ops = {
+ RUNTIME_PM_OPS(NULL, rzt2h_adc_pm_runtime_resume, NULL)
+};
+
+static struct platform_driver rzt2h_adc_driver = {
+ .probe = rzt2h_adc_probe,
+ .driver = {
+ .name = "rzt2h-adc",
+ .of_match_table = rzt2h_adc_match,
+ .pm = pm_ptr(&rzt2h_adc_pm_ops),
+ },
+};
+
+module_platform_driver(rzt2h_adc_driver);
+
+MODULE_AUTHOR("Cosmin Tanislav <cosmin-gabriel.tanislav.xa@renesas.com>");
+MODULE_DESCRIPTION("Renesas RZ/T2H / RZ/N2H ADC driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_DRIVER");
diff --git a/drivers/iio/adc/ti-ads131e08.c b/drivers/iio/adc/ti-ads131e08.c
index 742acc6d8cf9..c9a20024d6b1 100644
--- a/drivers/iio/adc/ti-ads131e08.c
+++ b/drivers/iio/adc/ti-ads131e08.c
@@ -848,7 +848,7 @@ static int ads131e08_probe(struct spi_device *spi)
ret = devm_iio_trigger_register(&spi->dev, st->trig);
if (ret) {
dev_err(&spi->dev, "failed to register IIO trigger\n");
- return -ENOMEM;
+ return ret;
}
indio_dev->trig = iio_trigger_get(st->trig);
diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c
index 99f274adc870..a1a28584de93 100644
--- a/drivers/iio/adc/ti_am335x_adc.c
+++ b/drivers/iio/adc/ti_am335x_adc.c
@@ -123,7 +123,7 @@ static void tiadc_step_config(struct iio_dev *indio_dev)
chan = adc_dev->channel_line[i];
- if (adc_dev->step_avg[i])
+ if (adc_dev->step_avg[i] && adc_dev->step_avg[i] <= STEPCONFIG_AVG_16)
stepconfig = STEPCONFIG_AVG(ffs(adc_dev->step_avg[i]) - 1) |
STEPCONFIG_FIFO1;
else