From 78abd04ea19608dc8a025ba5b95cd21c5a86d3e6 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Sat, 7 Mar 2026 19:44:10 -0600 Subject: [PATCH 001/266] iio: buffer: check return value of iio_compute_scan_bytes() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check return value of iio_compute_scan_bytes() as it can return an error. The result is moved to an output parameter while we are touching this as we will need to add a second output parameter in a later change. The return type of iio_buffer_update_bytes_per_datum() also had to be changed to propagate the error. Signed-off-by: David Lechner Reviewed-by: Nuno Sá Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-buffer.c | 36 +++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 46f36a6ed271..71dfc81cb9e5 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -764,7 +764,8 @@ static int iio_storage_bytes_for_timestamp(struct iio_dev *indio_dev) } static int iio_compute_scan_bytes(struct iio_dev *indio_dev, - const unsigned long *mask, bool timestamp) + const unsigned long *mask, bool timestamp, + unsigned int *scan_bytes) { unsigned int bytes = 0; int length, i, largest = 0; @@ -790,8 +791,9 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev, largest = max(largest, length); } - bytes = ALIGN(bytes, largest); - return bytes; + *scan_bytes = ALIGN(bytes, largest); + + return 0; } static void iio_buffer_activate(struct iio_dev *indio_dev, @@ -836,18 +838,23 @@ static int iio_buffer_disable(struct iio_buffer *buffer, return buffer->access->disable(buffer, indio_dev); } -static void iio_buffer_update_bytes_per_datum(struct iio_dev *indio_dev, - struct iio_buffer *buffer) +static int iio_buffer_update_bytes_per_datum(struct iio_dev *indio_dev, + struct iio_buffer *buffer) { unsigned int bytes; + int ret; if (!buffer->access->set_bytes_per_datum) - return; + return 0; - bytes = iio_compute_scan_bytes(indio_dev, buffer->scan_mask, - buffer->scan_timestamp); + ret = iio_compute_scan_bytes(indio_dev, buffer->scan_mask, + buffer->scan_timestamp, &bytes); + if (ret) + return ret; buffer->access->set_bytes_per_datum(buffer, bytes); + + return 0; } static int iio_buffer_request_update(struct iio_dev *indio_dev, @@ -855,7 +862,10 @@ static int iio_buffer_request_update(struct iio_dev *indio_dev, { int ret; - iio_buffer_update_bytes_per_datum(indio_dev, buffer); + ret = iio_buffer_update_bytes_per_datum(indio_dev, buffer); + if (ret) + return ret; + if (buffer->access->request_update) { ret = buffer->access->request_update(buffer); if (ret) { @@ -898,6 +908,7 @@ static int iio_verify_update(struct iio_dev *indio_dev, struct iio_buffer *buffer; bool scan_timestamp; unsigned int modes; + int ret; if (insert_buffer && bitmap_empty(insert_buffer->scan_mask, masklength)) { @@ -985,8 +996,11 @@ static int iio_verify_update(struct iio_dev *indio_dev, scan_mask = compound_mask; } - config->scan_bytes = iio_compute_scan_bytes(indio_dev, - scan_mask, scan_timestamp); + ret = iio_compute_scan_bytes(indio_dev, scan_mask, scan_timestamp, + &config->scan_bytes); + if (ret) + return ret; + config->scan_mask = scan_mask; config->scan_timestamp = scan_timestamp; From cb27d8c18fa311ad87fca4c2e7f1d73ec0cb440d Mon Sep 17 00:00:00 2001 From: David Lechner Date: Sat, 7 Mar 2026 19:44:11 -0600 Subject: [PATCH 002/266] iio: buffer: cache timestamp offset in scan buffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cache the offset (in bytes) for the timestamp element in a scan buffer. This will be used later to ensure proper alignment of the timestamp element in the scan buffer. The new field could not be placed in struct iio_dev_opaque because we will need to access it in a static inline function later, so we make it __private instead. It is only intended to be used by core IIO code. Signed-off-by: David Lechner Reviewed-by: Nuno Sá Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-buffer.c | 14 +++++++++++--- include/linux/iio/iio.h | 3 +++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 71dfc81cb9e5..d59ab57dc994 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -765,7 +765,8 @@ static int iio_storage_bytes_for_timestamp(struct iio_dev *indio_dev) static int iio_compute_scan_bytes(struct iio_dev *indio_dev, const unsigned long *mask, bool timestamp, - unsigned int *scan_bytes) + unsigned int *scan_bytes, + unsigned int *timestamp_offset) { unsigned int bytes = 0; int length, i, largest = 0; @@ -787,6 +788,10 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev, return length; bytes = ALIGN(bytes, length); + + if (timestamp_offset) + *timestamp_offset = bytes; + bytes += length; largest = max(largest, length); } @@ -848,7 +853,7 @@ static int iio_buffer_update_bytes_per_datum(struct iio_dev *indio_dev, return 0; ret = iio_compute_scan_bytes(indio_dev, buffer->scan_mask, - buffer->scan_timestamp, &bytes); + buffer->scan_timestamp, &bytes, NULL); if (ret) return ret; @@ -892,6 +897,7 @@ struct iio_device_config { unsigned int watermark; const unsigned long *scan_mask; unsigned int scan_bytes; + unsigned int scan_timestamp_offset; bool scan_timestamp; }; @@ -997,7 +1003,8 @@ static int iio_verify_update(struct iio_dev *indio_dev, } ret = iio_compute_scan_bytes(indio_dev, scan_mask, scan_timestamp, - &config->scan_bytes); + &config->scan_bytes, + &config->scan_timestamp_offset); if (ret) return ret; @@ -1155,6 +1162,7 @@ static int iio_enable_buffers(struct iio_dev *indio_dev, indio_dev->active_scan_mask = config->scan_mask; ACCESS_PRIVATE(indio_dev, scan_timestamp) = config->scan_timestamp; indio_dev->scan_bytes = config->scan_bytes; + ACCESS_PRIVATE(indio_dev, scan_timestamp_offset) = config->scan_timestamp_offset; iio_dev_opaque->currentmode = config->mode; iio_update_demux(indio_dev); diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 2c91b7659ce9..ecbaeecbe0ac 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -584,6 +584,8 @@ struct iio_buffer_setup_ops { * and owner * @buffer: [DRIVER] any buffer present * @scan_bytes: [INTERN] num bytes captured to be fed to buffer demux + * @scan_timestamp_offset: [INTERN] cache of the offset (in bytes) for the + * timestamp in the scan buffer * @available_scan_masks: [DRIVER] optional array of allowed bitmasks. Sort the * array in order of preference, the most preferred * masks first. @@ -610,6 +612,7 @@ struct iio_dev { struct iio_buffer *buffer; int scan_bytes; + unsigned int __private scan_timestamp_offset; const unsigned long *available_scan_masks; unsigned int __private masklength; From 99577250145316cb5840867f0278ddd8e0de8689 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Sat, 7 Mar 2026 19:44:12 -0600 Subject: [PATCH 003/266] iio: buffer: ensure repeat alignment is a power of two MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use roundup_pow_of_two() in the calculation of iio_storage_bytes_for_si() when scan_type->repeat > 1 to ensure that the size is a power of two. storagebits is always going to be a power of two bytes, so we only need to apply this to the repeat factor. The storage size is also used for alignment, and we want to ensure that all alignments are a power of two. The only repeat in use in the kernel currently is for quaternions, which have a repeat of 4, so this does not change the result for existing users. Signed-off-by: David Lechner Reviewed-by: Nuno Sá Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index d59ab57dc994..252ce4a6f913 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -750,7 +750,7 @@ static int iio_storage_bytes_for_si(struct iio_dev *indio_dev, bytes = scan_type->storagebits / 8; if (scan_type->repeat > 1) - bytes *= scan_type->repeat; + bytes *= roundup_pow_of_two(scan_type->repeat); return bytes; } From d05e3c1460e47aa61e58cc6947cf7c9fc1371d7e Mon Sep 17 00:00:00 2001 From: David Lechner Date: Sat, 7 Mar 2026 19:44:13 -0600 Subject: [PATCH 004/266] iio: buffer: fix timestamp alignment when quaternion in scan MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix timestamp alignment when a scan buffer contains an element larger than sizeof(int64_t). Currently s32 quaternions are the only such element, and the one driver that has this (hid-sensor-rotation) has a workaround in place already so this change does not affect it. Previously, we assumed that the timestamp would always be 8-byte aligned relative to the end of the scan buffer, but in the case of a scan buffer a 16-byte quaternion vector, scan_bytes == 32, but the timestamp needs to be placed at offset 16, not 24. ts_offset is now a value in bytes so we have to change how the array access is done. Signed-off-by: David Lechner Reviewed-by: Nuno Sá Signed-off-by: Jonathan Cameron --- include/linux/iio/buffer.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h index d37f82678f71..8fd0d57d238f 100644 --- a/include/linux/iio/buffer.h +++ b/include/linux/iio/buffer.h @@ -34,8 +34,16 @@ static inline int iio_push_to_buffers_with_timestamp(struct iio_dev *indio_dev, void *data, int64_t timestamp) { if (ACCESS_PRIVATE(indio_dev, scan_timestamp)) { - size_t ts_offset = indio_dev->scan_bytes / sizeof(int64_t) - 1; - ((int64_t *)data)[ts_offset] = timestamp; + size_t ts_offset = ACCESS_PRIVATE(indio_dev, scan_timestamp_offset); + + /* + * The size of indio_dev->scan_bytes is always aligned to the + * largest scan element's alignment (see iio_compute_scan_bytes()). + * So there may be padding after the timestamp. ts_offset contains + * the offset in bytes that was already computed for correctly + * aligning the timestamp. + */ + *(int64_t *)(data + ts_offset) = timestamp; } return iio_push_to_buffers(indio_dev, data); From 5de55ae1300b4bd70eb39b6664b6c733eee08228 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Sat, 14 Mar 2026 16:38:25 -0500 Subject: [PATCH 005/266] iio: imu: bno055: add explicit scan buf layout Move the scan buf.chans array into a union along with a struct that gives the layout of the buffer with all channels enabled. Although not technically required in this case, if there had been a different number of items before the quaternion, there could have been a subtle bug with the special alignment needed for the quaternion channel data and the array would have been too small. Signed-off-by: David Lechner Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/imu/bno055/bno055.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/iio/imu/bno055/bno055.c b/drivers/iio/imu/bno055/bno055.c index c96fec2ebb3e..d0101607a9b3 100644 --- a/drivers/iio/imu/bno055/bno055.c +++ b/drivers/iio/imu/bno055/bno055.c @@ -210,9 +210,30 @@ struct bno055_priv { u8 uid[BNO055_UID_LEN]; struct gpio_desc *reset_gpio; bool sw_reset; - struct { - __le16 chans[BNO055_SCAN_CH_COUNT]; - aligned_s64 timestamp; + union { + IIO_DECLARE_BUFFER_WITH_TS(__le16, chans, BNO055_SCAN_CH_COUNT); + /* + * This struct is not used, but it is here to ensure proper size + * and alignment of the scan buffer above (because of the extra + * requirements of the quaternion field). Technically it is not + * needed in this case, because other fields just happen to make + * things correctly aligned already. But it is better to be + * explicit about the requirements anyway. The actual contents + * of the scan buffer will vary depending on which channels are + * enabled. + */ + struct { + __le16 acc[3]; + __le16 magn[3]; + __le16 gyr[3]; + __le16 yaw; + __le16 pitch; + __le16 roll; + IIO_DECLARE_QUATERNION(__le16, quaternion); + __le16 lia[3]; + __le16 gravity[3]; + aligned_s64 timestamp; + }; } buf; struct dentry *debugfs; }; From 45c45b3f83d636563d005e10e07c198c18b488db Mon Sep 17 00:00:00 2001 From: David Lechner Date: Sun, 1 Mar 2026 17:46:48 -0600 Subject: [PATCH 006/266] iio: orientation: hid-sensor-rotation: use ext_scan_type Make use of ext_scan_type to handle the dynamic realbits size of the quaternion data. This lets us implement it using static data rather than having to duplicate the channel info for each driver instance. Signed-off-by: David Lechner Reviewed-by: Andy Shevchenko Acked-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- drivers/iio/orientation/hid-sensor-rotation.c | 71 +++++++++++-------- 1 file changed, 43 insertions(+), 28 deletions(-) diff --git a/drivers/iio/orientation/hid-sensor-rotation.c b/drivers/iio/orientation/hid-sensor-rotation.c index 5a5e6e4fbe34..4a11e4555099 100644 --- a/drivers/iio/orientation/hid-sensor-rotation.c +++ b/drivers/iio/orientation/hid-sensor-rotation.c @@ -39,6 +39,27 @@ static const u32 rotation_sensitivity_addresses[] = { HID_USAGE_SENSOR_ORIENT_QUATERNION, }; +enum { + DEV_ROT_SCAN_TYPE_16BIT, + DEV_ROT_SCAN_TYPE_32BIT, +}; + +static const struct iio_scan_type dev_rot_scan_types[] = { + [DEV_ROT_SCAN_TYPE_16BIT] = { + .sign = 's', + .realbits = 16, + /* Storage bits has to stay 32 to not break userspace. */ + .storagebits = 32, + .repeat = 4, + }, + [DEV_ROT_SCAN_TYPE_32BIT] = { + .sign = 's', + .realbits = 32, + .storagebits = 32, + .repeat = 4, + }, +}; + /* Channel definitions */ static const struct iio_chan_spec dev_rot_channels[] = { { @@ -50,23 +71,14 @@ static const struct iio_chan_spec dev_rot_channels[] = { BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_HYSTERESIS), - .scan_index = 0 + .scan_index = 0, + .has_ext_scan_type = 1, + .ext_scan_type = dev_rot_scan_types, + .num_ext_scan_type = ARRAY_SIZE(dev_rot_scan_types), }, IIO_CHAN_SOFT_TIMESTAMP(1) }; -/* Adjust channel real bits based on report descriptor */ -static void dev_rot_adjust_channel_bit_mask(struct iio_chan_spec *chan, - int size) -{ - chan->scan_type.sign = 's'; - /* Real storage bits will change based on the report desc. */ - chan->scan_type.realbits = size * 8; - /* Maximum size of a sample to capture is u32 */ - chan->scan_type.storagebits = sizeof(u32) * 8; - chan->scan_type.repeat = 4; -} - /* Channel read_raw handler */ static int dev_rot_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, @@ -141,9 +153,25 @@ static int dev_rot_write_raw(struct iio_dev *indio_dev, return ret; } +static int dev_rot_get_current_scan_type(const struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct dev_rot_state *rot_state = iio_priv(indio_dev); + + switch (rot_state->quaternion.size / 4) { + case sizeof(s16): + return DEV_ROT_SCAN_TYPE_16BIT; + case sizeof(s32): + return DEV_ROT_SCAN_TYPE_32BIT; + default: + return -EINVAL; + } +} + static const struct iio_info dev_rot_info = { .read_raw_multi = &dev_rot_read_raw, .write_raw = &dev_rot_write_raw, + .get_current_scan_type = &dev_rot_get_current_scan_type, }; /* Callback handler to send event after all samples are received and captured */ @@ -212,7 +240,6 @@ static int dev_rot_capture_sample(struct hid_sensor_hub_device *hsdev, /* Parse report which is specific to an usage id*/ static int dev_rot_parse_report(struct platform_device *pdev, struct hid_sensor_hub_device *hsdev, - struct iio_chan_spec *channels, unsigned usage_id, struct dev_rot_state *st) { @@ -226,9 +253,6 @@ static int dev_rot_parse_report(struct platform_device *pdev, if (ret) return ret; - dev_rot_adjust_channel_bit_mask(&channels[0], - st->quaternion.size / 4); - dev_dbg(&pdev->dev, "dev_rot %x:%x\n", st->quaternion.index, st->quaternion.report_id); @@ -287,22 +311,13 @@ static int hid_dev_rot_probe(struct platform_device *pdev) return ret; } - indio_dev->channels = devm_kmemdup(&pdev->dev, dev_rot_channels, - sizeof(dev_rot_channels), - GFP_KERNEL); - if (!indio_dev->channels) { - dev_err(&pdev->dev, "failed to duplicate channels\n"); - return -ENOMEM; - } - - ret = dev_rot_parse_report(pdev, hsdev, - (struct iio_chan_spec *)indio_dev->channels, - hsdev->usage, rot_state); + ret = dev_rot_parse_report(pdev, hsdev, hsdev->usage, rot_state); if (ret) { dev_err(&pdev->dev, "failed to setup attributes\n"); return ret; } + indio_dev->channels = dev_rot_channels; indio_dev->num_channels = ARRAY_SIZE(dev_rot_channels); indio_dev->info = &dev_rot_info; indio_dev->name = name; From 5c2290c054f0746f34934540e7cb5160278f7e2b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 19 Feb 2026 15:39:36 +0100 Subject: [PATCH 007/266] iio: adc: ad7191: Don't check for specific errors when parsing properties Instead of checking for the specific error codes (that can be considered a layering violation to some extent) check for the property existence first and then either parse it, or apply a default value. Signed-off-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7191.c | 63 +++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/drivers/iio/adc/ad7191.c b/drivers/iio/adc/ad7191.c index d9cd903ffdd2..51ec199fb06f 100644 --- a/drivers/iio/adc/ad7191.c +++ b/drivers/iio/adc/ad7191.c @@ -154,27 +154,18 @@ static int ad7191_config_setup(struct iio_dev *indio_dev) const u32 gain[4] = { 1, 8, 64, 128 }; static u32 scale_buffer[4][2]; int odr_value, odr_index = 0, pga_value, pga_index = 0, i, ret; + const char *propname; u64 scale_uv; st->samp_freq_index = 0; st->scale_index = 0; - ret = device_property_read_u32(dev, "adi,odr-value", &odr_value); - if (ret && ret != -EINVAL) - return dev_err_probe(dev, ret, "Failed to get odr value.\n"); + propname = "adi,odr-value"; + if (device_property_present(dev, propname)) { + ret = device_property_read_u32(dev, propname, &odr_value); + if (ret) + return dev_err_probe(dev, ret, "Failed to get %s.\n", propname); - if (ret == -EINVAL) { - st->odr_gpios = devm_gpiod_get_array(dev, "odr", GPIOD_OUT_LOW); - if (IS_ERR(st->odr_gpios)) - return dev_err_probe(dev, PTR_ERR(st->odr_gpios), - "Failed to get odr gpios.\n"); - - if (st->odr_gpios->ndescs != 2) - return dev_err_probe(dev, -EINVAL, "Expected 2 odr gpio pins.\n"); - - st->samp_freq_avail = samp_freq; - st->samp_freq_avail_size = ARRAY_SIZE(samp_freq); - } else { for (i = 0; i < ARRAY_SIZE(samp_freq); i++) { if (odr_value != samp_freq[i]) continue; @@ -186,6 +177,17 @@ static int ad7191_config_setup(struct iio_dev *indio_dev) st->samp_freq_avail_size = 1; st->odr_gpios = NULL; + } else { + st->odr_gpios = devm_gpiod_get_array(dev, "odr", GPIOD_OUT_LOW); + if (IS_ERR(st->odr_gpios)) + return dev_err_probe(dev, PTR_ERR(st->odr_gpios), + "Failed to get odr gpios.\n"); + + if (st->odr_gpios->ndescs != 2) + return dev_err_probe(dev, -EINVAL, "Expected 2 odr gpio pins.\n"); + + st->samp_freq_avail = samp_freq; + st->samp_freq_avail_size = ARRAY_SIZE(samp_freq); } mutex_lock(&st->lock); @@ -200,22 +202,12 @@ static int ad7191_config_setup(struct iio_dev *indio_dev) mutex_unlock(&st->lock); - ret = device_property_read_u32(dev, "adi,pga-value", &pga_value); - if (ret && ret != -EINVAL) - return dev_err_probe(dev, ret, "Failed to get pga value.\n"); + propname = "adi,pga-value"; + if (device_property_present(dev, propname)) { + ret = device_property_read_u32(dev, propname, &pga_value); + if (ret) + return dev_err_probe(dev, ret, "Failed to get %s.\n", propname); - if (ret == -EINVAL) { - st->pga_gpios = devm_gpiod_get_array(dev, "pga", GPIOD_OUT_LOW); - if (IS_ERR(st->pga_gpios)) - return dev_err_probe(dev, PTR_ERR(st->pga_gpios), - "Failed to get pga gpios.\n"); - - if (st->pga_gpios->ndescs != 2) - return dev_err_probe(dev, -EINVAL, "Expected 2 pga gpio pins.\n"); - - st->scale_avail = scale_buffer; - st->scale_avail_size = ARRAY_SIZE(scale_buffer); - } else { for (i = 0; i < ARRAY_SIZE(gain); i++) { if (pga_value != gain[i]) continue; @@ -227,6 +219,17 @@ static int ad7191_config_setup(struct iio_dev *indio_dev) st->scale_avail_size = 1; st->pga_gpios = NULL; + } else { + st->pga_gpios = devm_gpiod_get_array(dev, "pga", GPIOD_OUT_LOW); + if (IS_ERR(st->pga_gpios)) + return dev_err_probe(dev, PTR_ERR(st->pga_gpios), + "Failed to get pga gpios.\n"); + + if (st->pga_gpios->ndescs != 2) + return dev_err_probe(dev, -EINVAL, "Expected 2 pga gpio pins.\n"); + + st->scale_avail = scale_buffer; + st->scale_avail_size = ARRAY_SIZE(scale_buffer); } st->temp_gpio = devm_gpiod_get(dev, "temp", GPIOD_OUT_LOW); From 7216b9f7e9fe34a1623cceee920caede8929078e Mon Sep 17 00:00:00 2001 From: Francesco Lavra Date: Tue, 24 Mar 2026 09:47:33 +0100 Subject: [PATCH 008/266] iio: imu: st_lsm6dsx: Fix check for invalid samples from FIFO The DRDY_MASK feature implemented in sensor chips marks gyroscope and accelerometer invalid samples (i.e. samples that have been acquired during the settling time of sensor filters) with the special values 0x7FFFh, 0x7FFE, and 0x7FFD. The driver checks FIFO samples against these special values in order to discard invalid samples; however, it does the check regardless of the type of samples being processed, whereas this feature is specific to gyroscope and accelerometer data. This could cause valid samples to be discarded. Fix the above check so that it takes into account the type of samples being processed. To avoid casting to __le16 * when checking sample values, clean up the type representation for data read from the FIFO. Fixes: 960506ed2c69 ("iio: imu: st_lsm6dsx: enable drdy-mask if available") Signed-off-by: Francesco Lavra Acked-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- .../iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c | 34 +++++++++++++------ 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c index 5b28a3ffcc3d..8b79ade8e7de 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c @@ -365,8 +365,6 @@ static inline int st_lsm6dsx_read_block(struct st_lsm6dsx_hw *hw, u8 addr, return 0; } -#define ST_LSM6DSX_IIO_BUFF_SIZE (ALIGN(ST_LSM6DSX_SAMPLE_SIZE, \ - sizeof(s64)) + sizeof(s64)) /** * st_lsm6dsx_read_fifo() - hw FIFO read routine * @hw: Pointer to instance of struct st_lsm6dsx_hw. @@ -537,16 +535,23 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw) } #define ST_LSM6DSX_INVALID_SAMPLE 0x7ffd -static int -st_lsm6dsx_push_tagged_data(struct st_lsm6dsx_hw *hw, u8 tag, - u8 *data, s64 ts) +static bool st_lsm6dsx_check_data(u8 tag, __le16 *data) +{ + if ((tag == ST_LSM6DSX_GYRO_TAG || tag == ST_LSM6DSX_ACC_TAG) && + (s16)le16_to_cpup(data) >= ST_LSM6DSX_INVALID_SAMPLE) + return false; + + return true; +} + +static int st_lsm6dsx_push_tagged_data(struct st_lsm6dsx_hw *hw, u8 tag, + __le16 *data, s64 ts) { - s16 val = le16_to_cpu(*(__le16 *)data); struct st_lsm6dsx_sensor *sensor; struct iio_dev *iio_dev; /* invalid sample during bootstrap phase */ - if (val >= ST_LSM6DSX_INVALID_SAMPLE) + if (!st_lsm6dsx_check_data(tag, data)) return -EINVAL; /* @@ -609,7 +614,13 @@ int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw) * must be passed a buffer that is aligned to 8 bytes so * as to allow insertion of a naturally aligned timestamp. */ - u8 iio_buff[ST_LSM6DSX_IIO_BUFF_SIZE] __aligned(8); + struct { + union { + __le16 data[3]; + __le32 fifo_ts; + }; + aligned_s64 timestamp; + } iio_buff = { }; u8 tag; bool reset_ts = false; int i, err, read_len; @@ -648,7 +659,7 @@ int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw) for (i = 0; i < pattern_len; i += ST_LSM6DSX_TAGGED_SAMPLE_SIZE) { - memcpy(iio_buff, &hw->buff[i + ST_LSM6DSX_TAG_SIZE], + memcpy(&iio_buff, &hw->buff[i + ST_LSM6DSX_TAG_SIZE], ST_LSM6DSX_SAMPLE_SIZE); tag = hw->buff[i] >> 3; @@ -659,7 +670,7 @@ int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw) * B0 = ts[7:0], B1 = ts[15:8], B2 = ts[23:16], * B3 = ts[31:24] */ - ts = le32_to_cpu(*((__le32 *)iio_buff)); + ts = le32_to_cpu(iio_buff.fifo_ts); /* * check if hw timestamp engine is going to * reset (the sensor generates an interrupt @@ -670,7 +681,8 @@ int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw) reset_ts = true; ts *= hw->ts_gain; } else { - st_lsm6dsx_push_tagged_data(hw, tag, iio_buff, + st_lsm6dsx_push_tagged_data(hw, tag, + iio_buff.data, ts); } } From fda05af070e7bc0403a487fc87378d2e1323f529 Mon Sep 17 00:00:00 2001 From: Francesco Lavra Date: Tue, 24 Mar 2026 09:47:40 +0100 Subject: [PATCH 009/266] iio: Replace 'sign' field with union in struct iio_scan_type This field is used to differentiate between signed and unsigned integers. A following commit will extend its use in order to add support for non- integer scan elements; therefore, replace it with a union that contains a more generic 'format' field. This union will be dropped when all drivers are changed to use the format field. Opportunistically replace character literals with symbolic constants that represent the set of allowed values for the format field. Signed-off-by: Francesco Lavra Signed-off-by: Jonathan Cameron --- Documentation/driver-api/iio/buffers.rst | 4 ++-- include/linux/iio/iio.h | 23 +++++++++++++++++++++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Documentation/driver-api/iio/buffers.rst b/Documentation/driver-api/iio/buffers.rst index 63f364e862d1..e16abaf826fe 100644 --- a/Documentation/driver-api/iio/buffers.rst +++ b/Documentation/driver-api/iio/buffers.rst @@ -78,7 +78,7 @@ fields in iio_chan_spec definition:: /* other members */ int scan_index struct { - char sign; + char format; u8 realbits; u8 storagebits; u8 shift; @@ -98,7 +98,7 @@ following channel definition:: /* other stuff here */ .scan_index = 0, .scan_type = { - .sign = 's', + .format = IIO_SCAN_FORMAT_SIGNED_INT, .realbits = 12, .storagebits = 16, .shift = 4, diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index ecbaeecbe0ac..e03b7e912d7d 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -176,9 +176,25 @@ struct iio_event_spec { unsigned long mask_shared_by_all; }; +/** + * define IIO_SCAN_FORMAT_SIGNED_INT - signed integer data format + * + * &iio_scan_type.format value for signed integers (two's complement). + */ +#define IIO_SCAN_FORMAT_SIGNED_INT 's' + +/** + * define IIO_SCAN_FORMAT_UNSIGNED_INT - unsigned integer data format + * + * &iio_scan_type.format value for unsigned integers. + */ +#define IIO_SCAN_FORMAT_UNSIGNED_INT 'u' + /** * struct iio_scan_type - specification for channel data format in buffer - * @sign: 's' or 'u' to specify signed or unsigned + * @sign: Deprecated, use @format instead. + * @format: Data format, can have any of the IIO_SCAN_FORMAT_* + * values. * @realbits: Number of valid bits of data * @storagebits: Realbits + padding * @shift: Shift right by this before masking out realbits. @@ -189,7 +205,10 @@ struct iio_event_spec { * @endianness: little or big endian */ struct iio_scan_type { - char sign; + union { + char sign; + char format; + }; u8 realbits; u8 storagebits; u8 shift; From cdd445d4b2a910ade742c3d6a86bc3fca4da9e0c Mon Sep 17 00:00:00 2001 From: Francesco Lavra Date: Tue, 24 Mar 2026 09:47:46 +0100 Subject: [PATCH 010/266] iio: tools: Add support for floating-point types in buffer scan elements A subsequent commit will add floating-point support to the ABI; enhance the iio_generic_buffer tool to be able to parse this new data format. Signed-off-by: Francesco Lavra Signed-off-by: Jonathan Cameron --- tools/iio/iio_generic_buffer.c | 70 ++++++++++++++++++++++++++++++---- tools/iio/iio_utils.c | 12 +++--- tools/iio/iio_utils.h | 4 +- 3 files changed, 70 insertions(+), 16 deletions(-) diff --git a/tools/iio/iio_generic_buffer.c b/tools/iio/iio_generic_buffer.c index bc82bb6a7a2a..000193612aad 100644 --- a/tools/iio/iio_generic_buffer.c +++ b/tools/iio/iio_generic_buffer.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -89,12 +90,19 @@ static void print1byte(uint8_t input, struct iio_channel_info *info) */ input >>= info->shift; input &= info->mask; - if (info->is_signed) { + switch (info->format) { + case 's': { int8_t val = (int8_t)(input << (8 - info->bits_used)) >> (8 - info->bits_used); printf("%05f ", ((float)val + info->offset) * info->scale); - } else { + break; + } + case 'u': printf("%05f ", ((float)input + info->offset) * info->scale); + break; + case 'f': + printf(" "); + break; } } @@ -112,12 +120,30 @@ static void print2byte(uint16_t input, struct iio_channel_info *info) */ input >>= info->shift; input &= info->mask; - if (info->is_signed) { + switch (info->format) { + case 's': { int16_t val = (int16_t)(input << (16 - info->bits_used)) >> (16 - info->bits_used); printf("%05f ", ((float)val + info->offset) * info->scale); - } else { + break; + } + case 'u': printf("%05f ", ((float)input + info->offset) * info->scale); + break; + case 'f': { +#if defined(__FLT16_MAX__) + union { + uint16_t u; + _Float16 f; + } converter; + + converter.u = input; + printf("%05f ", ((float)converter.f + info->offset) * info->scale); +#else + printf(" "); +#endif + break; + } } } @@ -135,12 +161,26 @@ static void print4byte(uint32_t input, struct iio_channel_info *info) */ input >>= info->shift; input &= info->mask; - if (info->is_signed) { + switch (info->format) { + case 's': { int32_t val = (int32_t)(input << (32 - info->bits_used)) >> (32 - info->bits_used); printf("%05f ", ((float)val + info->offset) * info->scale); - } else { + break; + } + case 'u': printf("%05f ", ((float)input + info->offset) * info->scale); + break; + case 'f': { + union { + uint32_t u; + float f; + } converter; + + converter.u = input; + printf("%05f ", (converter.f + info->offset) * info->scale); + break; + } } } @@ -158,7 +198,8 @@ static void print8byte(uint64_t input, struct iio_channel_info *info) */ input >>= info->shift; input &= info->mask; - if (info->is_signed) { + switch (info->format) { + case 's': { int64_t val = (int64_t)(input << (64 - info->bits_used)) >> (64 - info->bits_used); /* special case for timestamp */ @@ -167,8 +208,21 @@ static void print8byte(uint64_t input, struct iio_channel_info *info) else printf("%05f ", ((float)val + info->offset) * info->scale); - } else { + break; + } + case 'u': printf("%05f ", ((float)input + info->offset) * info->scale); + break; + case 'f': { + union { + uint64_t u; + double f; + } converter; + + converter.u = input; + printf("%05f ", (converter.f + info->offset) * info->scale); + break; + } } } diff --git a/tools/iio/iio_utils.c b/tools/iio/iio_utils.c index c5c5082cb24e..e274a0d8376b 100644 --- a/tools/iio/iio_utils.c +++ b/tools/iio/iio_utils.c @@ -70,7 +70,7 @@ int iioutils_break_up_name(const char *full_name, char **generic_name) /** * iioutils_get_type() - find and process _type attribute data - * @is_signed: output whether channel is signed + * @format: output channel format * @bytes: output how many bytes the channel storage occupies * @bits_used: output number of valid bits of data * @shift: output amount of bits to shift right data before applying bit mask @@ -83,7 +83,7 @@ int iioutils_break_up_name(const char *full_name, char **generic_name) * * Returns a value >= 0 on success, otherwise a negative error code. **/ -static int iioutils_get_type(unsigned int *is_signed, unsigned int *bytes, +static int iioutils_get_type(char *format, unsigned int *bytes, unsigned int *bits_used, unsigned int *shift, uint64_t *mask, unsigned int *be, const char *device_dir, int buffer_idx, @@ -93,7 +93,7 @@ static int iioutils_get_type(unsigned int *is_signed, unsigned int *bytes, int ret; DIR *dp; char *scan_el_dir, *builtname, *builtname_generic, *filename = 0; - char signchar, endianchar; + char formatchar, endianchar; unsigned padint; const struct dirent *ent; @@ -140,7 +140,7 @@ static int iioutils_get_type(unsigned int *is_signed, unsigned int *bytes, ret = fscanf(sysfsfp, "%ce:%c%u/%u>>%u", &endianchar, - &signchar, + &formatchar, bits_used, &padint, shift); if (ret < 0) { @@ -162,7 +162,7 @@ static int iioutils_get_type(unsigned int *is_signed, unsigned int *bytes, else *mask = (1ULL << *bits_used) - 1ULL; - *is_signed = (signchar == 's'); + *format = formatchar; if (fclose(sysfsfp)) { ret = -errno; fprintf(stderr, "Failed to close %s\n", @@ -487,7 +487,7 @@ int build_channel_array(const char *device_dir, int buffer_idx, if ((ret < 0) && (ret != -ENOENT)) goto error_cleanup_array; - ret = iioutils_get_type(¤t->is_signed, + ret = iioutils_get_type(¤t->format, ¤t->bytes, ¤t->bits_used, ¤t->shift, diff --git a/tools/iio/iio_utils.h b/tools/iio/iio_utils.h index 663c94a6c705..8c72f002d050 100644 --- a/tools/iio/iio_utils.h +++ b/tools/iio/iio_utils.h @@ -32,7 +32,7 @@ extern const char *iio_dir; * @shift: amount of bits to shift right data before applying bit mask * @mask: a bit mask for the raw output * @be: flag if data is big endian - * @is_signed: is the raw value stored signed + * @format: format of the raw value * @location: data offset for this channel inside the buffer (in bytes) **/ struct iio_channel_info { @@ -46,7 +46,7 @@ struct iio_channel_info { unsigned shift; uint64_t mask; unsigned be; - unsigned is_signed; + char format; unsigned location; }; From b29f00ef08a7afdedc0b36cc0bead579d6977ced Mon Sep 17 00:00:00 2001 From: Francesco Lavra Date: Tue, 24 Mar 2026 09:47:53 +0100 Subject: [PATCH 011/266] iio: ABI: Add support for floating-point numbers in buffer scan elements In the data storage description of a scan element, the first character after the colon can have the values 's' and 'u' to specify signed and unsigned integers, respectively. Add 'f' as an allowed value to specify floating-point numbers formatted according to the IEEE 754 standard. Signed-off-by: Francesco Lavra Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 33 +++++++++++++----------- Documentation/driver-api/iio/buffers.rst | 3 ++- Documentation/iio/iio_devbuf.rst | 3 ++- include/linux/iio/iio.h | 7 +++++ 4 files changed, 29 insertions(+), 17 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 4fc9f6bd4281..851cfe4f0a05 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -1510,21 +1510,24 @@ Contact: linux-iio@vger.kernel.org Description: Description of the scan element data storage within the buffer and hence the form in which it is read from user-space. - Form is [be|le]:[s|u]bits/storagebits[>>shift]. - be or le specifies big or little endian. s or u specifies if - signed (2's complement) or unsigned. bits is the number of bits - of data and storagebits is the space (after padding) that it - occupies in the buffer. shift if specified, is the shift that - needs to be applied prior to masking out unused bits. Some - devices put their data in the middle of the transferred elements - with additional information on both sides. Note that some - devices will have additional information in the unused bits - so to get a clean value, the bits value must be used to mask - the buffer output value appropriately. The storagebits value - also specifies the data alignment. So s48/64>>2 will be a - signed 48 bit integer stored in a 64 bit location aligned to - a 64 bit boundary. To obtain the clean value, shift right 2 - and apply a mask to zero the top 16 bits of the result. + Form is [be|le]:[f|s|u]bits/storagebits[>>shift]. + be or le specifies big or little endian. f means floating-point + (IEEE 754 binary format), s means signed (2's complement), u means + unsigned. bits is the number of bits of data and storagebits is the + space (after padding) that it occupies in the buffer; when using a + floating-point format, bits must be one of the width values defined + in the IEEE 754 standard for binary interchange formats (e.g. 16 + indicates the binary16 format for half-precision numbers). shift, + if specified, is the shift that needs to be applied prior to + masking out unused bits. Some devices put their data in the middle + of the transferred elements with additional information on both + sides. Note that some devices will have additional information in + the unused bits, so to get a clean value the bits value must be + used to mask the buffer output value appropriately. The storagebits + value also specifies the data alignment. So s48/64>>2 will be a + signed 48 bit integer stored in a 64 bit location aligned to a 64 + bit boundary. To obtain the clean value, shift right 2 and apply a + mask to zero the top 16 bits of the result. For other storage combinations this attribute will be extended appropriately. diff --git a/Documentation/driver-api/iio/buffers.rst b/Documentation/driver-api/iio/buffers.rst index e16abaf826fe..8779022e3da5 100644 --- a/Documentation/driver-api/iio/buffers.rst +++ b/Documentation/driver-api/iio/buffers.rst @@ -37,9 +37,10 @@ directory contains attributes of the following form: * :file:`index`, the scan_index of the channel. * :file:`type`, description of the scan element data storage within the buffer and hence the form in which it is read from user space. - Format is [be|le]:[s|u]bits/storagebits[Xrepeat][>>shift] . + Format is [be|le]:[f|s|u]bits/storagebits[Xrepeat][>>shift] . * *be* or *le*, specifies big or little endian. + * *f*, specifies if floating-point. * *s* or *u*, specifies if signed (2's complement) or unsigned. * *bits*, is the number of valid data bits. * *storagebits*, is the number of bits (after padding) that it occupies in the diff --git a/Documentation/iio/iio_devbuf.rst b/Documentation/iio/iio_devbuf.rst index dca1f0200b0d..e91730fa3cea 100644 --- a/Documentation/iio/iio_devbuf.rst +++ b/Documentation/iio/iio_devbuf.rst @@ -83,9 +83,10 @@ and the relevant _type attributes to establish the data storage format. Read-only attribute containing the description of the scan element data storage within the buffer and hence the form in which it is read from userspace. Format -is [be|le]:[s|u]bits/storagebits[Xrepeat][>>shift], where: +is [be|le]:[f|s|u]bits/storagebits[Xrepeat][>>shift], where: - **be** or **le** specifies big or little-endian. +- **f** specifies if floating-point. - **s** or **u** specifies if signed (2's complement) or unsigned. - **bits** is the number of valid data bits. - **storagebits** is the number of bits (after padding) that it occupies in the diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index e03b7e912d7d..96b05c86c325 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -190,6 +190,13 @@ struct iio_event_spec { */ #define IIO_SCAN_FORMAT_UNSIGNED_INT 'u' +/** + * define IIO_SCAN_FORMAT_FLOAT - floating-point data format + * + * &iio_scan_type.format value for IEEE 754 floating-point numbers. + */ +#define IIO_SCAN_FORMAT_FLOAT 'f' + /** * struct iio_scan_type - specification for channel data format in buffer * @sign: Deprecated, use @format instead. From dd59392a3ec23dbe3a3fabadcf3bb847e9592ccd Mon Sep 17 00:00:00 2001 From: Francesco Lavra Date: Tue, 24 Mar 2026 09:47:59 +0100 Subject: [PATCH 012/266] iio: ABI: Add quaternion axis modifier This modifier applies to the IIO_ROT channel type, and indicates a data representation that specifies the {x, y, z} components of the normalized quaternion vector. Signed-off-by: Francesco Lavra Reviewed-by: David Lechner Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 15 +++++++++++++++ drivers/iio/industrialio-core.c | 1 + include/uapi/linux/iio/types.h | 1 + tools/iio/iio_event_monitor.c | 1 + 4 files changed, 18 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 851cfe4f0a05..60dfeff8f2c9 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -1755,6 +1755,21 @@ Description: measurement from channel Y. Units after application of scale and offset are milliamps. +What: /sys/bus/iio/devices/iio:deviceX/in_rot_quaternionaxis_raw +KernelVersion: 7.1 +Contact: linux-iio@vger.kernel.org +Description: + Raw value of {x, y, z} components of the quaternion vector. These + components represent the axis about which a rotation occurs, and are + subject to the following constraints: + + - the quaternion vector is normalized, i.e. w^2 + x^2 + y^2 + z^2 = 1 + - the rotation angle is within the [-pi, pi] range, i.e. the w + component (which represents the amount of rotation) is non-negative + + These constraints allow the w value to be calculated from the other + components: w = sqrt(1 - (x^2 + y^2 + z^2)). + What: /sys/.../iio:deviceX/in_energy_en What: /sys/.../iio:deviceX/in_distance_en What: /sys/.../iio:deviceX/in_velocity_sqrt(x^2+y^2+z^2)_en diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 22eefd048ba9..bd6f4f9f4533 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -157,6 +157,7 @@ static const char * const iio_modifier_names[] = { [IIO_MOD_ACTIVE] = "active", [IIO_MOD_REACTIVE] = "reactive", [IIO_MOD_APPARENT] = "apparent", + [IIO_MOD_QUATERNION_AXIS] = "quaternionaxis", }; /* relies on pairs of these shared then separate */ diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h index 6d269b844271..d7c2bb223651 100644 --- a/include/uapi/linux/iio/types.h +++ b/include/uapi/linux/iio/types.h @@ -113,6 +113,7 @@ enum iio_modifier { IIO_MOD_ACTIVE, IIO_MOD_REACTIVE, IIO_MOD_APPARENT, + IIO_MOD_QUATERNION_AXIS, }; enum iio_event_type { diff --git a/tools/iio/iio_event_monitor.c b/tools/iio/iio_event_monitor.c index 03ca33869ce8..df6c43d7738d 100644 --- a/tools/iio/iio_event_monitor.c +++ b/tools/iio/iio_event_monitor.c @@ -145,6 +145,7 @@ static const char * const iio_modifier_names[] = { [IIO_MOD_ACTIVE] = "active", [IIO_MOD_REACTIVE] = "reactive", [IIO_MOD_APPARENT] = "apparent", + [IIO_MOD_QUATERNION_AXIS] = "quaternionaxis", }; static bool event_is_known(struct iio_event_data *event) From cd4e1141bff8b86c75c425acb84eca453e936a9d Mon Sep 17 00:00:00 2001 From: Francesco Lavra Date: Tue, 24 Mar 2026 09:48:07 +0100 Subject: [PATCH 013/266] iio: imu: st_lsm6dsx: Add support for rotation sensor Some IMU chips in the LSM6DSX family have sensor fusion features that combine data from the accelerometer and gyroscope. One of these features generates rotation vector data and makes it available in the hardware FIFO as a quaternion (more specifically, the X, Y and Z components of the quaternion vector, expressed as 16-bit half-precision floating-point numbers). Add support for a new sensor instance that allows receiving sensor fusion data, by defining a new struct st_lsm6dsx_fusion_settings (which contains chip-specific details for the sensor fusion functionality), and adding this struct as a new field in struct st_lsm6dsx_settings. In st_lsm6dsx_core.c, populate this new struct for the LSM6DSV and LSM6DSV16X chips, and add the logic to initialize an additional IIO device if this struct is populated for the hardware type being probed. Note: a new IIO device is being defined (as opposed to adding channels to an existing device) because the rate at which sensor fusion data is generated may not match the data rate from any of the existing devices. Tested on LSM6DSV16X. Signed-off-by: Francesco Lavra Acked-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/Makefile | 2 +- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h | 28 +- .../iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c | 9 +- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 58 +++++ .../iio/imu/st_lsm6dsx/st_lsm6dsx_fusion.c | 241 ++++++++++++++++++ 5 files changed, 331 insertions(+), 7 deletions(-) create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_fusion.c diff --git a/drivers/iio/imu/st_lsm6dsx/Makefile b/drivers/iio/imu/st_lsm6dsx/Makefile index 57cbcd67d64f..19a488254de3 100644 --- a/drivers/iio/imu/st_lsm6dsx/Makefile +++ b/drivers/iio/imu/st_lsm6dsx/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only st_lsm6dsx-y := st_lsm6dsx_core.o st_lsm6dsx_buffer.o \ - st_lsm6dsx_shub.o + st_lsm6dsx_shub.o st_lsm6dsx_fusion.o obj-$(CONFIG_IIO_ST_LSM6DSX) += st_lsm6dsx.o obj-$(CONFIG_IIO_ST_LSM6DSX_I2C) += st_lsm6dsx_i2c.o diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index 07b1773c87bd..767aadfe7061 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -294,6 +294,7 @@ enum st_lsm6dsx_sensor_id { ST_LSM6DSX_ID_EXT0, ST_LSM6DSX_ID_EXT1, ST_LSM6DSX_ID_EXT2, + ST_LSM6DSX_ID_FUSION, ST_LSM6DSX_ID_MAX }; @@ -301,6 +302,17 @@ enum st_lsm6dsx_ext_sensor_id { ST_LSM6DSX_ID_MAGN, }; +struct st_lsm6dsx_fusion_settings { + const struct iio_chan_spec *chan; + int chan_len; + struct st_lsm6dsx_reg odr_reg; + int odr_hz[ST_LSM6DSX_ODR_LIST_SIZE]; + int odr_len; + struct st_lsm6dsx_reg fifo_enable; + struct st_lsm6dsx_reg page_mux; + struct st_lsm6dsx_reg enable; +}; + /** * struct st_lsm6dsx_ext_dev_settings - i2c controller slave settings * @i2c_addr: I2c slave address list. @@ -388,6 +400,7 @@ struct st_lsm6dsx_settings { struct st_lsm6dsx_hw_ts_settings ts_settings; struct st_lsm6dsx_shub_settings shub_settings; struct st_lsm6dsx_event_settings event_settings; + struct st_lsm6dsx_fusion_settings fusion_settings; }; enum st_lsm6dsx_fifo_mode { @@ -510,6 +523,9 @@ int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u32 odr, u8 *val); int st_lsm6dsx_shub_probe(struct st_lsm6dsx_hw *hw, const char *name); int st_lsm6dsx_shub_set_enable(struct st_lsm6dsx_sensor *sensor, bool enable); int st_lsm6dsx_shub_read_output(struct st_lsm6dsx_hw *hw, u8 *data, int len); +int st_lsm6dsx_fusion_probe(struct st_lsm6dsx_hw *hw, const char *name); +int st_lsm6dsx_fusion_set_enable(struct st_lsm6dsx_sensor *sensor, bool enable); +int st_lsm6dsx_fusion_set_odr(struct st_lsm6dsx_sensor *sensor, bool enable); int st_lsm6dsx_set_page(struct st_lsm6dsx_hw *hw, bool enable); static inline int @@ -564,12 +580,14 @@ st_lsm6dsx_get_mount_matrix(const struct iio_dev *iio_dev, static inline int st_lsm6dsx_device_set_enable(struct st_lsm6dsx_sensor *sensor, bool enable) { - if (sensor->id == ST_LSM6DSX_ID_EXT0 || - sensor->id == ST_LSM6DSX_ID_EXT1 || - sensor->id == ST_LSM6DSX_ID_EXT2) + switch (sensor->id) { + case ST_LSM6DSX_ID_EXT0 ... ST_LSM6DSX_ID_EXT2: return st_lsm6dsx_shub_set_enable(sensor, enable); - - return st_lsm6dsx_sensor_set_enable(sensor, enable); + case ST_LSM6DSX_ID_FUSION: + return st_lsm6dsx_fusion_set_enable(sensor, enable); + default: + return st_lsm6dsx_sensor_set_enable(sensor, enable); + } } static const diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c index 8b79ade8e7de..777d479f10c0 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c @@ -88,6 +88,7 @@ enum st_lsm6dsx_fifo_tag { ST_LSM6DSX_EXT0_TAG = 0x0f, ST_LSM6DSX_EXT1_TAG = 0x10, ST_LSM6DSX_EXT2_TAG = 0x11, + ST_LSM6DSX_ROT_TAG = 0x13, }; static const @@ -226,8 +227,11 @@ static int st_lsm6dsx_set_fifo_odr(struct st_lsm6dsx_sensor *sensor, u8 data; /* Only internal sensors have a FIFO ODR configuration register. */ - if (sensor->id >= ARRAY_SIZE(hw->settings->batch)) + if (sensor->id >= ARRAY_SIZE(hw->settings->batch)) { + if (sensor->id == ST_LSM6DSX_ID_FUSION) + return st_lsm6dsx_fusion_set_odr(sensor, enable); return 0; + } batch_reg = &hw->settings->batch[sensor->id]; if (batch_reg->addr) { @@ -585,6 +589,9 @@ static int st_lsm6dsx_push_tagged_data(struct st_lsm6dsx_hw *hw, u8 tag, case ST_LSM6DSX_EXT2_TAG: iio_dev = hw->iio_devs[ST_LSM6DSX_ID_EXT2]; break; + case ST_LSM6DSX_ROT_TAG: + iio_dev = hw->iio_devs[ST_LSM6DSX_ID_FUSION]; + break; default: return -EINVAL; } diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 450cb5b47346..630e2cae6f19 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -94,6 +94,26 @@ #define ST_LSM6DSX_REG_WHOAMI_ADDR 0x0f +/* Raw values from the IMU are 16-bit half-precision floating-point numbers. */ +#define ST_LSM6DSX_CHANNEL_ROT \ +{ \ + .type = IIO_ROT, \ + .modified = 1, \ + .channel2 = IIO_MOD_QUATERNION_AXIS, \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_shared_by_all_available = \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_index = 0, \ + .scan_type = { \ + .format = IIO_SCAN_FORMAT_FLOAT, \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_LE, \ + .repeat = 3, \ + }, \ + .ext_info = st_lsm6dsx_ext_info, \ +} + static const struct iio_event_spec st_lsm6dsx_ev_motion[] = { { .type = IIO_EV_TYPE_THRESH, @@ -153,6 +173,11 @@ static const struct iio_chan_spec st_lsm6ds0_gyro_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(3), }; +static const struct iio_chan_spec st_lsm6dsx_fusion_channels[] = { + ST_LSM6DSX_CHANNEL_ROT, + IIO_CHAN_SOFT_TIMESTAMP(1), +}; + static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { { .reset = { @@ -1492,6 +1517,33 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, }, }, + .fusion_settings = { + .chan = st_lsm6dsx_fusion_channels, + .chan_len = ARRAY_SIZE(st_lsm6dsx_fusion_channels), + .odr_reg = { + .addr = 0x5e, + .mask = GENMASK(5, 3), + }, + .odr_hz[0] = 15, + .odr_hz[1] = 30, + .odr_hz[2] = 60, + .odr_hz[3] = 120, + .odr_hz[4] = 240, + .odr_hz[5] = 480, + .odr_len = 6, + .fifo_enable = { + .addr = 0x44, + .mask = BIT(1), + }, + .page_mux = { + .addr = 0x01, + .mask = BIT(7), + }, + .enable = { + .addr = 0x04, + .mask = BIT(1), + }, + }, }, { .reset = { @@ -2899,6 +2951,12 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, return err; } + if (hw->settings->fusion_settings.chan) { + err = st_lsm6dsx_fusion_probe(hw, name); + if (err) + return err; + } + if (hw->irq > 0) { err = st_lsm6dsx_irq_setup(hw); if (err < 0) diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_fusion.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_fusion.c new file mode 100644 index 000000000000..2e72c7ba94dd --- /dev/null +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_fusion.c @@ -0,0 +1,241 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * STMicroelectronics st_lsm6dsx IMU sensor fusion + * + * Copyright 2026 BayLibre, SAS + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "st_lsm6dsx.h" + +static int +st_lsm6dsx_fusion_get_odr_val(const struct st_lsm6dsx_fusion_settings *settings, + u32 odr_mHz, u8 *val) +{ + int odr_hz = odr_mHz / MILLI; + int i; + + for (i = 0; i < settings->odr_len; i++) { + if (settings->odr_hz[i] == odr_hz) + break; + } + if (i == settings->odr_len) + return -EINVAL; + + *val = i; + return 0; +} + +/** + * st_lsm6dsx_fusion_page_enable - Enable access to sensor fusion configuration + * registers. + * @hw: Sensor hardware instance. + * + * Return: 0 on success, negative value on error. + */ +static int st_lsm6dsx_fusion_page_enable(struct st_lsm6dsx_hw *hw) +{ + const struct st_lsm6dsx_reg *mux; + + mux = &hw->settings->fusion_settings.page_mux; + + return regmap_set_bits(hw->regmap, mux->addr, mux->mask); +} + +/** + * st_lsm6dsx_fusion_page_disable - Disable access to sensor fusion + * configuration registers. + * @hw: Sensor hardware instance. + * + * Return: 0 on success, negative value on error. + */ +static int st_lsm6dsx_fusion_page_disable(struct st_lsm6dsx_hw *hw) +{ + const struct st_lsm6dsx_reg *mux; + + mux = &hw->settings->fusion_settings.page_mux; + + return regmap_clear_bits(hw->regmap, mux->addr, mux->mask); +} + +static int st_lsm6dsx_fusion_set_odr_locked(struct st_lsm6dsx_sensor *sensor, + bool enable) +{ + const struct st_lsm6dsx_fusion_settings *settings; + struct st_lsm6dsx_hw *hw = sensor->hw; + int err; + + settings = &hw->settings->fusion_settings; + if (enable) { + const struct st_lsm6dsx_reg *reg = &settings->odr_reg; + u8 odr_val; + u8 data; + + st_lsm6dsx_fusion_get_odr_val(settings, sensor->hwfifo_odr_mHz, + &odr_val); + data = ST_LSM6DSX_SHIFT_VAL(odr_val, reg->mask); + err = regmap_update_bits(hw->regmap, reg->addr, reg->mask, + data); + if (err) + return err; + } + + return regmap_assign_bits(hw->regmap, settings->fifo_enable.addr, + settings->fifo_enable.mask, enable); +} + +int st_lsm6dsx_fusion_set_enable(struct st_lsm6dsx_sensor *sensor, bool enable) +{ + struct st_lsm6dsx_hw *hw = sensor->hw; + const struct st_lsm6dsx_reg *en_reg; + int err; + + guard(mutex)(&hw->page_lock); + + en_reg = &hw->settings->fusion_settings.enable; + err = st_lsm6dsx_fusion_page_enable(hw); + if (err) + return err; + + err = regmap_assign_bits(hw->regmap, en_reg->addr, en_reg->mask, enable); + if (err) { + st_lsm6dsx_fusion_page_disable(hw); + return err; + } + + return st_lsm6dsx_fusion_page_disable(hw); +} + +int st_lsm6dsx_fusion_set_odr(struct st_lsm6dsx_sensor *sensor, bool enable) +{ + struct st_lsm6dsx_hw *hw = sensor->hw; + int err; + + guard(mutex)(&hw->page_lock); + + err = st_lsm6dsx_fusion_page_enable(hw); + if (err) + return err; + + err = st_lsm6dsx_fusion_set_odr_locked(sensor, enable); + if (err) { + st_lsm6dsx_fusion_page_disable(hw); + return err; + } + + return st_lsm6dsx_fusion_page_disable(hw); +} + +static int st_lsm6dsx_fusion_read_raw(struct iio_dev *iio_dev, + struct iio_chan_spec const *ch, + int *val, int *val2, long mask) +{ + struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + *val = sensor->hwfifo_odr_mHz / MILLI; + *val2 = (sensor->hwfifo_odr_mHz % MILLI) * (MICRO / MILLI); + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static int st_lsm6dsx_fusion_write_raw(struct iio_dev *iio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); + const struct st_lsm6dsx_fusion_settings *settings; + int err; + + settings = &sensor->hw->settings->fusion_settings; + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: { + u32 odr_mHz = val * MILLI + val2 * (MILLI / MICRO); + u8 odr_val; + + /* check that the requested frequency is supported */ + err = st_lsm6dsx_fusion_get_odr_val(settings, odr_mHz, &odr_val); + if (err) + return err; + + sensor->hwfifo_odr_mHz = odr_mHz; + return 0; + } + default: + return -EINVAL; + } +} + +static int st_lsm6dsx_fusion_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, + int *length, long mask) +{ + struct st_lsm6dsx_sensor *sensor = iio_priv(indio_dev); + const struct st_lsm6dsx_fusion_settings *settings; + + settings = &sensor->hw->settings->fusion_settings; + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + *vals = settings->odr_hz; + *type = IIO_VAL_INT; + *length = settings->odr_len; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static const struct iio_info st_lsm6dsx_fusion_info = { + .read_raw = st_lsm6dsx_fusion_read_raw, + .read_avail = st_lsm6dsx_fusion_read_avail, + .write_raw = st_lsm6dsx_fusion_write_raw, + .hwfifo_set_watermark = st_lsm6dsx_set_watermark, +}; + +int st_lsm6dsx_fusion_probe(struct st_lsm6dsx_hw *hw, const char *name) +{ + const struct st_lsm6dsx_fusion_settings *settings; + struct st_lsm6dsx_sensor *sensor; + struct iio_dev *iio_dev; + int ret; + + iio_dev = devm_iio_device_alloc(hw->dev, sizeof(*sensor)); + if (!iio_dev) + return -ENOMEM; + + settings = &hw->settings->fusion_settings; + sensor = iio_priv(iio_dev); + sensor->id = ST_LSM6DSX_ID_FUSION; + sensor->hw = hw; + sensor->hwfifo_odr_mHz = settings->odr_hz[0] * MILLI; + sensor->watermark = 1; + iio_dev->modes = INDIO_DIRECT_MODE; + iio_dev->info = &st_lsm6dsx_fusion_info; + iio_dev->channels = settings->chan; + iio_dev->num_channels = settings->chan_len; + ret = snprintf(sensor->name, sizeof(sensor->name), "%s_fusion", name); + if (ret >= sizeof(sensor->name)) + return -E2BIG; + iio_dev->name = sensor->name; + + /* + * Put the IIO device pointer in the iio_devs array so that the caller + * can set up a buffer and register this IIO device. + */ + hw->iio_devs[ST_LSM6DSX_ID_FUSION] = iio_dev; + + return 0; +} From 671b8541c7d62818e0fb8ac7fe8a4086fc7c842e Mon Sep 17 00:00:00 2001 From: Carlos Jones Jr Date: Tue, 31 Mar 2026 09:24:56 +0800 Subject: [PATCH 014/266] iio: adc: ltc2309: add read delay for ltc2305 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The LTC2305 requires a minimum 1.6μs delay between the I2C write operation (channel selection) and the subsequent read operation to allow the chip to process the command and prepare the result. While not explicitly documented in the datasheet, this timing requirement was identified by the hardware designer as necessary for reliable operation. Add a read_delay_us field to both the ltc2309_chip_info and ltc2309 device structures to support chip-specific timing requirements. Use fsleep() to implement the delay when non-zero, with LTC2305 set to 2μs (1.6μs requirement rounded up). LTC2309 does not require additional delay beyond inherent I2C bus timing. This extends the existing LTC2305 support added in (commit 8625d418d24b ("iio: adc: ltc2309: add support for ltc2305")) with the missing inter-transaction delay. Signed-off-by: Carlos Jones Jr Reviewed-by: Nuno Sá Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ltc2309.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/iio/adc/ltc2309.c b/drivers/iio/adc/ltc2309.c index 316256edf150..094966289922 100644 --- a/drivers/iio/adc/ltc2309.c +++ b/drivers/iio/adc/ltc2309.c @@ -9,7 +9,9 @@ * * Copyright (c) 2023, Liam Beguin */ +#include #include +#include #include #include #include @@ -34,12 +36,14 @@ * @client: I2C reference * @lock: Lock to serialize data access * @vref_mv: Internal voltage reference + * @read_delay_us: Chip-specific read delay in microseconds */ struct ltc2309 { struct device *dev; struct i2c_client *client; struct mutex lock; /* serialize data access */ int vref_mv; + unsigned int read_delay_us; }; /* Order matches expected channel address, See datasheet Table 1. */ @@ -118,12 +122,14 @@ static const struct iio_chan_spec ltc2309_channels[] = { struct ltc2309_chip_info { const char *name; const struct iio_chan_spec *channels; + unsigned int read_delay_us; int num_channels; }; static const struct ltc2309_chip_info ltc2305_chip_info = { .name = "ltc2305", .channels = ltc2305_channels, + .read_delay_us = 2, .num_channels = ARRAY_SIZE(ltc2305_channels), }; @@ -151,6 +157,9 @@ static int ltc2309_read_raw_channel(struct ltc2309 *ltc2309, return ret; } + if (ltc2309->read_delay_us) + fsleep(ltc2309->read_delay_us); + ret = i2c_master_recv(ltc2309->client, (char *)&buf, 2); if (ret < 0) { dev_err(ltc2309->dev, "i2c read failed: %pe\n", ERR_PTR(ret)); @@ -206,6 +215,7 @@ static int ltc2309_probe(struct i2c_client *client) ltc2309->dev = &indio_dev->dev; ltc2309->client = client; + ltc2309->read_delay_us = chip_info->read_delay_us; indio_dev->name = chip_info->name; indio_dev->modes = INDIO_DIRECT_MODE; From 7a89047a361c347cafe98f432d3df1686592ecce Mon Sep 17 00:00:00 2001 From: Carlos Jones Jr Date: Tue, 31 Mar 2026 09:24:57 +0800 Subject: [PATCH 015/266] iio: adc: ltc2309: Optimize chip_info structure layout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Improve the ltc2309_chip_info structure with better type safety and memory efficiency: - Add __counted_by_ptr() annotation to the channels pointer, linking it to num_channels for improved bounds checking and kernel hardening - Reorder structure fields to minimize padding: * Place read_delay_us before num_channels * This reduces struct size and eliminates internal gaps - Reorder field initialization to match the structure definition order The __counted_by_ptr() attribute enables compile-time and runtime verification that array accesses to channels[] stay within the bounds specified by num_channels, improving memory safety. Signed-off-by: Carlos Jones Jr Reviewed-by: Nuno Sá Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ltc2309.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/ltc2309.c b/drivers/iio/adc/ltc2309.c index 094966289922..87b78d0353f1 100644 --- a/drivers/iio/adc/ltc2309.c +++ b/drivers/iio/adc/ltc2309.c @@ -121,22 +121,22 @@ static const struct iio_chan_spec ltc2309_channels[] = { struct ltc2309_chip_info { const char *name; - const struct iio_chan_spec *channels; unsigned int read_delay_us; int num_channels; + const struct iio_chan_spec *channels __counted_by_ptr(num_channels); }; static const struct ltc2309_chip_info ltc2305_chip_info = { .name = "ltc2305", - .channels = ltc2305_channels, .read_delay_us = 2, .num_channels = ARRAY_SIZE(ltc2305_channels), + .channels = ltc2305_channels, }; static const struct ltc2309_chip_info ltc2309_chip_info = { .name = "ltc2309", - .channels = ltc2309_channels, .num_channels = ARRAY_SIZE(ltc2309_channels), + .channels = ltc2309_channels, }; static int ltc2309_read_raw_channel(struct ltc2309 *ltc2309, From 3bfc60fc10121ea3640b11c5c11cb9be72817186 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 5 Apr 2026 21:39:23 -0700 Subject: [PATCH 016/266] iio: adc: ti-ads7950: switch to using guard() notation guard() notation allows early returns when encountering errors, making control flow more obvious. Use it. Reviewed-by: David Lechner Reviewed-by: Bartosz Golaszewski Signed-off-by: Dmitry Torokhov Tested-by: David Lechner Reviewed-by: Linus Walleij Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-ads7950.c | 79 +++++++++++++----------------------- 1 file changed, 29 insertions(+), 50 deletions(-) diff --git a/drivers/iio/adc/ti-ads7950.c b/drivers/iio/adc/ti-ads7950.c index 028acd42741f..6e9ea9cc33bf 100644 --- a/drivers/iio/adc/ti-ads7950.c +++ b/drivers/iio/adc/ti-ads7950.c @@ -299,18 +299,19 @@ static irqreturn_t ti_ads7950_trigger_handler(int irq, void *p) struct ti_ads7950_state *st = iio_priv(indio_dev); int ret; - mutex_lock(&st->slock); - ret = spi_sync(st->spi, &st->ring_msg); - if (ret < 0) - goto out; + do { + guard(mutex)(&st->slock); - iio_push_to_buffers_with_ts_unaligned(indio_dev, &st->rx_buf[2], - sizeof(*st->rx_buf) * - TI_ADS7950_MAX_CHAN, - iio_get_time_ns(indio_dev)); + ret = spi_sync(st->spi, &st->ring_msg); + if (ret) + break; + + iio_push_to_buffers_with_ts_unaligned(indio_dev, &st->rx_buf[2], + sizeof(*st->rx_buf) * + TI_ADS7950_MAX_CHAN, + iio_get_time_ns(indio_dev)); + } while (0); -out: - mutex_unlock(&st->slock); iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; @@ -321,20 +322,16 @@ static int ti_ads7950_scan_direct(struct iio_dev *indio_dev, unsigned int ch) struct ti_ads7950_state *st = iio_priv(indio_dev); int ret, cmd; - mutex_lock(&st->slock); + guard(mutex)(&st->slock); + cmd = TI_ADS7950_MAN_CMD(TI_ADS7950_CR_CHAN(ch)); st->single_tx = cmd; ret = spi_sync(st->spi, &st->scan_single_msg); if (ret) - goto out; + return ret; - ret = st->single_rx; - -out: - mutex_unlock(&st->slock); - - return ret; + return st->single_rx; } static int ti_ads7950_get_range(struct ti_ads7950_state *st) @@ -400,9 +397,8 @@ static int ti_ads7950_set(struct gpio_chip *chip, unsigned int offset, int value) { struct ti_ads7950_state *st = gpiochip_get_data(chip); - int ret; - mutex_lock(&st->slock); + guard(mutex)(&st->slock); if (value) st->cmd_settings_bitmask |= BIT(offset); @@ -410,11 +406,8 @@ static int ti_ads7950_set(struct gpio_chip *chip, unsigned int offset, st->cmd_settings_bitmask &= ~BIT(offset); st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st); - ret = spi_sync(st->spi, &st->scan_single_msg); - mutex_unlock(&st->slock); - - return ret; + return spi_sync(st->spi, &st->scan_single_msg); } static int ti_ads7950_get(struct gpio_chip *chip, unsigned int offset) @@ -423,13 +416,12 @@ static int ti_ads7950_get(struct gpio_chip *chip, unsigned int offset) bool state; int ret; - mutex_lock(&st->slock); + guard(mutex)(&st->slock); /* If set as output, return the output */ if (st->gpio_cmd_settings_bitmask & BIT(offset)) { state = st->cmd_settings_bitmask & BIT(offset); - ret = 0; - goto out; + return state; } /* GPIO data bit sets SDO bits 12-15 to GPIO input */ @@ -437,7 +429,7 @@ static int ti_ads7950_get(struct gpio_chip *chip, unsigned int offset) st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st); ret = spi_sync(st->spi, &st->scan_single_msg); if (ret) - goto out; + return ret; state = (st->single_rx >> 12) & BIT(offset); @@ -446,12 +438,9 @@ static int ti_ads7950_get(struct gpio_chip *chip, unsigned int offset) st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st); ret = spi_sync(st->spi, &st->scan_single_msg); if (ret) - goto out; + return ret; -out: - mutex_unlock(&st->slock); - - return ret ?: state; + return state; } static int ti_ads7950_get_direction(struct gpio_chip *chip, @@ -467,9 +456,8 @@ static int _ti_ads7950_set_direction(struct gpio_chip *chip, int offset, int input) { struct ti_ads7950_state *st = gpiochip_get_data(chip); - int ret = 0; - mutex_lock(&st->slock); + guard(mutex)(&st->slock); /* Only change direction if needed */ if (input && (st->gpio_cmd_settings_bitmask & BIT(offset))) @@ -477,15 +465,11 @@ static int _ti_ads7950_set_direction(struct gpio_chip *chip, int offset, else if (!input && !(st->gpio_cmd_settings_bitmask & BIT(offset))) st->gpio_cmd_settings_bitmask |= BIT(offset); else - goto out; + return 0; st->single_tx = TI_ADS7950_GPIO_CMD_SETTINGS(st); - ret = spi_sync(st->spi, &st->scan_single_msg); -out: - mutex_unlock(&st->slock); - - return ret; + return spi_sync(st->spi, &st->scan_single_msg); } static int ti_ads7950_direction_input(struct gpio_chip *chip, @@ -508,9 +492,9 @@ static int ti_ads7950_direction_output(struct gpio_chip *chip, static int ti_ads7950_init_hw(struct ti_ads7950_state *st) { - int ret = 0; + int ret; - mutex_lock(&st->slock); + guard(mutex)(&st->slock); /* Settings for Manual/Auto1/Auto2 commands */ /* Default to 5v ref */ @@ -518,17 +502,12 @@ static int ti_ads7950_init_hw(struct ti_ads7950_state *st) st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st); ret = spi_sync(st->spi, &st->scan_single_msg); if (ret) - goto out; + return ret; /* Settings for GPIO command */ st->gpio_cmd_settings_bitmask = 0x0; st->single_tx = TI_ADS7950_GPIO_CMD_SETTINGS(st); - ret = spi_sync(st->spi, &st->scan_single_msg); - -out: - mutex_unlock(&st->slock); - - return ret; + return spi_sync(st->spi, &st->scan_single_msg); } static int ti_ads7950_probe(struct spi_device *spi) From 1c3b46b9dec4349f81f432b8ad0829714d3757ba Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 5 Apr 2026 21:39:24 -0700 Subject: [PATCH 017/266] iio: adc: ti-ads7950: simplify check for spi_setup() failures spi_setup() specifies that it returns 0 on success or negative error on failure. Therefore we can simply check for the return code being 0 or not. Reviewed-by: David Lechner Reviewed-by: Bartosz Golaszewski Signed-off-by: Dmitry Torokhov Tested-by: David Lechner Reviewed-by: Linus Walleij Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-ads7950.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/adc/ti-ads7950.c b/drivers/iio/adc/ti-ads7950.c index 6e9ea9cc33bf..c31c706c92a9 100644 --- a/drivers/iio/adc/ti-ads7950.c +++ b/drivers/iio/adc/ti-ads7950.c @@ -520,7 +520,7 @@ static int ti_ads7950_probe(struct spi_device *spi) spi->bits_per_word = 16; spi->mode |= SPI_CS_WORD; ret = spi_setup(spi); - if (ret < 0) { + if (ret) { dev_err(&spi->dev, "Error in spi setup\n"); return ret; } From 86f6d0949e1272d97f91f550bf6f0ccd79fbf17e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 5 Apr 2026 21:39:25 -0700 Subject: [PATCH 018/266] iio: adc: ti-ads7950: switch to using devm_regulator_get_enable_read_voltage() The regulator is enabled for the entire time the driver is bound to the device, and we only need to access it to fetch voltage, which can be done at probe time. Switch to using devm_regulator_get_enable_read_voltage() which simplifies probing and unbinding code. Suggested-by: David Lechner Reviewed-by: Bartosz Golaszewski Signed-off-by: Dmitry Torokhov Tested-by: David Lechner Reviewed-by: Linus Walleij Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-ads7950.c | 48 ++++++++++-------------------------- 1 file changed, 13 insertions(+), 35 deletions(-) diff --git a/drivers/iio/adc/ti-ads7950.c b/drivers/iio/adc/ti-ads7950.c index c31c706c92a9..0b98c8e7385d 100644 --- a/drivers/iio/adc/ti-ads7950.c +++ b/drivers/iio/adc/ti-ads7950.c @@ -334,19 +334,9 @@ static int ti_ads7950_scan_direct(struct iio_dev *indio_dev, unsigned int ch) return st->single_rx; } -static int ti_ads7950_get_range(struct ti_ads7950_state *st) +static unsigned int ti_ads7950_get_range(struct ti_ads7950_state *st) { - int vref; - - if (st->vref_mv) { - vref = st->vref_mv; - } else { - vref = regulator_get_voltage(st->reg); - if (vref < 0) - return vref; - - vref /= 1000; - } + unsigned int vref = st->vref_mv; if (st->cmd_settings_bitmask & TI_ADS7950_CR_RANGE_5V) vref *= 2; @@ -375,11 +365,7 @@ static int ti_ads7950_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - ret = ti_ads7950_get_range(st); - if (ret < 0) - return ret; - - *val = ret; + *val = ti_ads7950_get_range(st); *val2 = (1 << chan->scan_type.realbits) - 1; return IIO_VAL_FRACTIONAL; @@ -573,30 +559,25 @@ static int ti_ads7950_probe(struct spi_device *spi) spi_message_init_with_transfers(&st->scan_single_msg, st->scan_single_xfer, 3); - /* Use hard coded value for reference voltage in ACPI case */ - if (ACPI_COMPANION(&spi->dev)) - st->vref_mv = TI_ADS7950_VA_MV_ACPI_DEFAULT; - mutex_init(&st->slock); - st->reg = devm_regulator_get(&spi->dev, "vref"); - if (IS_ERR(st->reg)) { - ret = dev_err_probe(&spi->dev, PTR_ERR(st->reg), - "Failed to get regulator \"vref\"\n"); - goto error_destroy_mutex; - } + /* Use hard coded value for reference voltage in ACPI case */ + if (ACPI_COMPANION(&spi->dev)) { + st->vref_mv = TI_ADS7950_VA_MV_ACPI_DEFAULT; + } else { + ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref"); + if (ret < 0) + return dev_err_probe(&spi->dev, ret, + "Failed to get regulator \"vref\"\n"); - ret = regulator_enable(st->reg); - if (ret) { - dev_err(&spi->dev, "Failed to enable regulator \"vref\"\n"); - goto error_destroy_mutex; + st->vref_mv = ret / 1000; } ret = iio_triggered_buffer_setup(indio_dev, NULL, &ti_ads7950_trigger_handler, NULL); if (ret) { dev_err(&spi->dev, "Failed to setup triggered buffer\n"); - goto error_disable_reg; + goto error_destroy_mutex; } ret = ti_ads7950_init_hw(st); @@ -636,8 +617,6 @@ static int ti_ads7950_probe(struct spi_device *spi) iio_device_unregister(indio_dev); error_cleanup_ring: iio_triggered_buffer_cleanup(indio_dev); -error_disable_reg: - regulator_disable(st->reg); error_destroy_mutex: mutex_destroy(&st->slock); @@ -652,7 +631,6 @@ static void ti_ads7950_remove(struct spi_device *spi) gpiochip_remove(&st->chip); iio_device_unregister(indio_dev); iio_triggered_buffer_cleanup(indio_dev); - regulator_disable(st->reg); mutex_destroy(&st->slock); } From 71ddf1d8ffe06a1c0ab8f1ab71c08d5b38983f75 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 5 Apr 2026 21:39:26 -0700 Subject: [PATCH 019/266] iio: adc: ti-ads7950: complete conversion to using managed resources All resources that the driver needs have managed API now. Switch to using them to make code clearer and drop ti_ads7950_remove(). Reviewed-by: David Lechner Signed-off-by: Dmitry Torokhov Reviewed-by: Bartosz Golaszewski Tested-by: David Lechner Reviewed-by: Linus Walleij Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-ads7950.c | 70 ++++++++++++------------------------ 1 file changed, 22 insertions(+), 48 deletions(-) diff --git a/drivers/iio/adc/ti-ads7950.c b/drivers/iio/adc/ti-ads7950.c index 0b98c8e7385d..882b280d9e0b 100644 --- a/drivers/iio/adc/ti-ads7950.c +++ b/drivers/iio/adc/ti-ads7950.c @@ -506,10 +506,8 @@ static int ti_ads7950_probe(struct spi_device *spi) spi->bits_per_word = 16; spi->mode |= SPI_CS_WORD; ret = spi_setup(spi); - if (ret) { - dev_err(&spi->dev, "Error in spi setup\n"); - return ret; - } + if (ret) + return dev_err_probe(&spi->dev, ret, "Error in spi setup\n"); indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (!indio_dev) @@ -517,8 +515,6 @@ static int ti_ads7950_probe(struct spi_device *spi) st = iio_priv(indio_dev); - spi_set_drvdata(spi, indio_dev); - st->spi = spi; info = spi_get_device_match_data(spi); @@ -559,7 +555,9 @@ static int ti_ads7950_probe(struct spi_device *spi) spi_message_init_with_transfers(&st->scan_single_msg, st->scan_single_xfer, 3); - mutex_init(&st->slock); + ret = devm_mutex_init(&spi->dev, &st->slock); + if (ret) + return ret; /* Use hard coded value for reference voltage in ACPI case */ if (ACPI_COMPANION(&spi->dev)) { @@ -573,24 +571,22 @@ static int ti_ads7950_probe(struct spi_device *spi) st->vref_mv = ret / 1000; } - ret = iio_triggered_buffer_setup(indio_dev, NULL, - &ti_ads7950_trigger_handler, NULL); - if (ret) { - dev_err(&spi->dev, "Failed to setup triggered buffer\n"); - goto error_destroy_mutex; - } + ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL, + &ti_ads7950_trigger_handler, + NULL); + if (ret) + return dev_err_probe(&spi->dev, ret, + "Failed to setup triggered buffer\n"); ret = ti_ads7950_init_hw(st); - if (ret) { - dev_err(&spi->dev, "Failed to init adc chip\n"); - goto error_cleanup_ring; - } + if (ret) + return dev_err_probe(&spi->dev, ret, + "Failed to init adc chip\n"); - ret = iio_device_register(indio_dev); - if (ret) { - dev_err(&spi->dev, "Failed to register iio device\n"); - goto error_cleanup_ring; - } + ret = devm_iio_device_register(&spi->dev, indio_dev); + if (ret) + return dev_err_probe(&spi->dev, ret, + "Failed to register iio device\n"); /* Add GPIO chip */ st->chip.label = dev_name(&st->spi->dev); @@ -605,33 +601,12 @@ static int ti_ads7950_probe(struct spi_device *spi) st->chip.get = ti_ads7950_get; st->chip.set = ti_ads7950_set; - ret = gpiochip_add_data(&st->chip, st); - if (ret) { - dev_err(&spi->dev, "Failed to init GPIOs\n"); - goto error_iio_device; - } + ret = devm_gpiochip_add_data(&spi->dev, &st->chip, st); + if (ret) + return dev_err_probe(&spi->dev, ret, + "Failed to init GPIOs\n"); return 0; - -error_iio_device: - iio_device_unregister(indio_dev); -error_cleanup_ring: - iio_triggered_buffer_cleanup(indio_dev); -error_destroy_mutex: - mutex_destroy(&st->slock); - - return ret; -} - -static void ti_ads7950_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct ti_ads7950_state *st = iio_priv(indio_dev); - - gpiochip_remove(&st->chip); - iio_device_unregister(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); - mutex_destroy(&st->slock); } static const struct spi_device_id ti_ads7950_id[] = { @@ -674,7 +649,6 @@ static struct spi_driver ti_ads7950_driver = { .of_match_table = ads7950_of_table, }, .probe = ti_ads7950_probe, - .remove = ti_ads7950_remove, .id_table = ti_ads7950_id, }; module_spi_driver(ti_ads7950_driver); From b9b7a64576b80020b99452f32cae5639403d4198 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 30 Mar 2026 14:18:44 +0300 Subject: [PATCH 020/266] iio: adc: ad7949: use dev_err_probe() Use dev_err_probe() instead of dev_err() in the probe path to ensure proper handling of deferred probing and to simplify error handling. Signed-off-by: Antoniu Miclaus Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7949.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/drivers/iio/adc/ad7949.c b/drivers/iio/adc/ad7949.c index b35d299a3977..ebc629bcfd4d 100644 --- a/drivers/iio/adc/ad7949.c +++ b/drivers/iio/adc/ad7949.c @@ -341,8 +341,8 @@ static int ad7949_spi_probe(struct spi_device *spi) } else if (spi_is_bpw_supported(spi, 8)) { spi->bits_per_word = 8; } else { - dev_err(dev, "unable to find common BPW with spi controller\n"); - return -EINVAL; + return dev_err_probe(dev, -EINVAL, + "unable to find common BPW with spi controller\n"); } /* Setup internal voltage reference */ @@ -357,8 +357,8 @@ static int ad7949_spi_probe(struct spi_device *spi) ad7949_adc->refsel = AD7949_CFG_VAL_REF_INT_4096; break; default: - dev_err(dev, "unsupported internal voltage reference\n"); - return -EINVAL; + return dev_err_probe(dev, -EINVAL, + "unsupported internal voltage reference\n"); } /* Setup external voltage reference, buffered? */ @@ -382,10 +382,9 @@ static int ad7949_spi_probe(struct spi_device *spi) if (ad7949_adc->refsel & AD7949_CFG_VAL_REF_EXTERNAL) { ret = regulator_enable(ad7949_adc->vref); - if (ret < 0) { - dev_err(dev, "fail to enable regulator\n"); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, + "fail to enable regulator\n"); ret = devm_add_action_or_reset(dev, ad7949_disable_reg, ad7949_adc->vref); @@ -396,16 +395,10 @@ static int ad7949_spi_probe(struct spi_device *spi) mutex_init(&ad7949_adc->lock); ret = ad7949_spi_init(ad7949_adc); - if (ret) { - dev_err(dev, "fail to init this device: %d\n", ret); - return ret; - } - - ret = devm_iio_device_register(dev, indio_dev); if (ret) - dev_err(dev, "fail to register iio device: %d\n", ret); + return dev_err_probe(dev, ret, "fail to init this device\n"); - return ret; + return devm_iio_device_register(dev, indio_dev); } static const struct of_device_id ad7949_spi_of_id[] = { From bca122aff0a3d4bc1e5725e6a5c52e82c323a840 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 30 Mar 2026 14:18:45 +0300 Subject: [PATCH 021/266] iio: adc: ad7780: add dev variable Add a local struct device pointer to simplify repeated &spi->dev dereferences throughout the probe function. Signed-off-by: Antoniu Miclaus Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7780.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/iio/adc/ad7780.c b/drivers/iio/adc/ad7780.c index 24d2dcad8f4d..4c1990e27213 100644 --- a/drivers/iio/adc/ad7780.c +++ b/drivers/iio/adc/ad7780.c @@ -307,11 +307,12 @@ static void ad7780_reg_disable(void *reg) static int ad7780_probe(struct spi_device *spi) { + struct device *dev = &spi->dev; struct ad7780_state *st; struct iio_dev *indio_dev; int ret; - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; @@ -329,11 +330,11 @@ static int ad7780_probe(struct spi_device *spi) indio_dev->num_channels = 1; indio_dev->info = &ad7780_info; - ret = ad7780_init_gpios(&spi->dev, st); + ret = ad7780_init_gpios(dev, st); if (ret) return ret; - st->reg = devm_regulator_get(&spi->dev, "avdd"); + st->reg = devm_regulator_get(dev, "avdd"); if (IS_ERR(st->reg)) return PTR_ERR(st->reg); @@ -343,15 +344,15 @@ static int ad7780_probe(struct spi_device *spi) return ret; } - ret = devm_add_action_or_reset(&spi->dev, ad7780_reg_disable, st->reg); + ret = devm_add_action_or_reset(dev, ad7780_reg_disable, st->reg); if (ret) return ret; - ret = devm_ad_sd_setup_buffer_and_trigger(&spi->dev, indio_dev); + ret = devm_ad_sd_setup_buffer_and_trigger(dev, indio_dev); if (ret) return ret; - return devm_iio_device_register(&spi->dev, indio_dev); + return devm_iio_device_register(dev, indio_dev); } static const struct spi_device_id ad7780_id[] = { From cd256a392bb5950a599962c328c6db07da2f02af Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 30 Mar 2026 14:18:46 +0300 Subject: [PATCH 022/266] iio: adc: ad7780: use dev_err_probe() Use dev_err_probe() instead of dev_err() in the probe path to ensure proper handling of deferred probing and to simplify error handling. Signed-off-by: Antoniu Miclaus Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7780.c | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/drivers/iio/adc/ad7780.c b/drivers/iio/adc/ad7780.c index 4c1990e27213..26382b1f8c9e 100644 --- a/drivers/iio/adc/ad7780.c +++ b/drivers/iio/adc/ad7780.c @@ -264,16 +264,12 @@ static const struct iio_info ad7780_info = { static int ad7780_init_gpios(struct device *dev, struct ad7780_state *st) { - int ret; - st->powerdown_gpio = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_LOW); - if (IS_ERR(st->powerdown_gpio)) { - ret = PTR_ERR(st->powerdown_gpio); - dev_err(dev, "Failed to request powerdown GPIO: %d\n", ret); - return ret; - } + if (IS_ERR(st->powerdown_gpio)) + return dev_err_probe(dev, PTR_ERR(st->powerdown_gpio), + "Failed to request powerdown GPIO\n"); if (!st->chip_info->is_ad778x) return 0; @@ -282,20 +278,16 @@ static int ad7780_init_gpios(struct device *dev, struct ad7780_state *st) st->gain_gpio = devm_gpiod_get_optional(dev, "adi,gain", GPIOD_OUT_HIGH); - if (IS_ERR(st->gain_gpio)) { - ret = PTR_ERR(st->gain_gpio); - dev_err(dev, "Failed to request gain GPIO: %d\n", ret); - return ret; - } + if (IS_ERR(st->gain_gpio)) + return dev_err_probe(dev, PTR_ERR(st->gain_gpio), + "Failed to request gain GPIO\n"); st->filter_gpio = devm_gpiod_get_optional(dev, "adi,filter", GPIOD_OUT_HIGH); - if (IS_ERR(st->filter_gpio)) { - ret = PTR_ERR(st->filter_gpio); - dev_err(dev, "Failed to request filter GPIO: %d\n", ret); - return ret; - } + if (IS_ERR(st->filter_gpio)) + return dev_err_probe(dev, PTR_ERR(st->filter_gpio), + "Failed to request filter GPIO\n"); return 0; } @@ -339,10 +331,9 @@ static int ad7780_probe(struct spi_device *spi) return PTR_ERR(st->reg); ret = regulator_enable(st->reg); - if (ret) { - dev_err(&spi->dev, "Failed to enable specified AVdd supply\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, + "Failed to enable specified AVdd supply\n"); ret = devm_add_action_or_reset(dev, ad7780_reg_disable, st->reg); if (ret) From b659f18deffce462caf1846a181141fa10dd648e Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 30 Mar 2026 14:18:47 +0300 Subject: [PATCH 023/266] iio: adc: ad7793: add dev variable Add a local struct device pointer to simplify repeated &spi->dev dereferences throughout the probe function. Signed-off-by: Antoniu Miclaus Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7793.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/iio/adc/ad7793.c b/drivers/iio/adc/ad7793.c index 8ff7b70d6632..21c667e37b31 100644 --- a/drivers/iio/adc/ad7793.c +++ b/drivers/iio/adc/ad7793.c @@ -774,7 +774,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { static int ad7793_probe(struct spi_device *spi) { - const struct ad7793_platform_data *pdata = dev_get_platdata(&spi->dev); + struct device *dev = &spi->dev; + const struct ad7793_platform_data *pdata = dev_get_platdata(dev); struct ad7793_state *st; struct iio_dev *indio_dev; int ret, vref_mv = 0; @@ -789,7 +790,7 @@ static int ad7793_probe(struct spi_device *spi) return -ENODEV; } - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; @@ -798,7 +799,7 @@ static int ad7793_probe(struct spi_device *spi) ad_sd_init(&st->sd, indio_dev, spi, &ad7793_sigma_delta_info); if (pdata->refsel != AD7793_REFSEL_INTERNAL) { - ret = devm_regulator_get_enable_read_voltage(&spi->dev, "refin"); + ret = devm_regulator_get_enable_read_voltage(dev, "refin"); if (ret < 0) return ret; @@ -816,7 +817,7 @@ static int ad7793_probe(struct spi_device *spi) indio_dev->num_channels = st->chip_info->num_channels; indio_dev->info = st->chip_info->iio_info; - ret = devm_ad_sd_setup_buffer_and_trigger(&spi->dev, indio_dev); + ret = devm_ad_sd_setup_buffer_and_trigger(dev, indio_dev); if (ret) return ret; @@ -824,7 +825,7 @@ static int ad7793_probe(struct spi_device *spi) if (ret) return ret; - return devm_iio_device_register(&spi->dev, indio_dev); + return devm_iio_device_register(dev, indio_dev); } static const struct spi_device_id ad7793_id[] = { From d145e05835bf853a00d28f4109b8883e5a3c67c9 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 30 Mar 2026 14:18:48 +0300 Subject: [PATCH 024/266] iio: adc: ad7793: use dev_err_probe() Use dev_err_probe() instead of dev_err() in the probe path to ensure proper handling of deferred probing and to simplify error handling. Signed-off-by: Antoniu Miclaus Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7793.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/iio/adc/ad7793.c b/drivers/iio/adc/ad7793.c index 21c667e37b31..624530cce938 100644 --- a/drivers/iio/adc/ad7793.c +++ b/drivers/iio/adc/ad7793.c @@ -278,8 +278,8 @@ static int ad7793_setup(struct iio_dev *indio_dev, id &= AD7793_ID_MASK; if (id != st->chip_info->id) { - ret = -ENODEV; - dev_err(&st->sd.spi->dev, "device ID query failed\n"); + ret = dev_err_probe(&st->sd.spi->dev, -ENODEV, + "device ID query failed\n"); goto out; } @@ -338,8 +338,7 @@ static int ad7793_setup(struct iio_dev *indio_dev, return 0; out: - dev_err(&st->sd.spi->dev, "setup failed\n"); - return ret; + return dev_err_probe(&st->sd.spi->dev, ret, "setup failed\n"); } static const u16 ad7793_sample_freq_avail[16] = {0, 470, 242, 123, 62, 50, 39, @@ -780,15 +779,11 @@ static int ad7793_probe(struct spi_device *spi) struct iio_dev *indio_dev; int ret, vref_mv = 0; - if (!pdata) { - dev_err(&spi->dev, "no platform data?\n"); - return -ENODEV; - } + if (!pdata) + return dev_err_probe(dev, -ENODEV, "no platform data?\n"); - if (!spi->irq) { - dev_err(&spi->dev, "no IRQ?\n"); - return -ENODEV; - } + if (!spi->irq) + return dev_err_probe(dev, -ENODEV, "no IRQ?\n"); indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (indio_dev == NULL) From 655c5e04e1aba4895525095863ac786ff51bd906 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 30 Mar 2026 14:18:49 +0300 Subject: [PATCH 025/266] iio: adc: ad7292: add dev variable Add a local struct device pointer to simplify repeated &spi->dev dereferences throughout the probe function. Signed-off-by: Antoniu Miclaus Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7292.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/ad7292.c b/drivers/iio/adc/ad7292.c index a398973f313d..64d40b053582 100644 --- a/drivers/iio/adc/ad7292.c +++ b/drivers/iio/adc/ad7292.c @@ -253,12 +253,13 @@ static const struct iio_info ad7292_info = { static int ad7292_probe(struct spi_device *spi) { + struct device *dev = &spi->dev; struct ad7292_state *st; struct iio_dev *indio_dev; bool diff_channels = false; int ret; - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; @@ -271,7 +272,7 @@ static int ad7292_probe(struct spi_device *spi) return -EINVAL; } - ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref"); + ret = devm_regulator_get_enable_read_voltage(dev, "vref"); if (ret < 0 && ret != -ENODEV) return ret; @@ -281,7 +282,7 @@ static int ad7292_probe(struct spi_device *spi) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &ad7292_info; - device_for_each_child_node_scoped(&spi->dev, child) { + device_for_each_child_node_scoped(dev, child) { diff_channels = fwnode_property_read_bool(child, "diff-channels"); if (diff_channels) @@ -296,7 +297,7 @@ static int ad7292_probe(struct spi_device *spi) indio_dev->channels = ad7292_channels; } - return devm_iio_device_register(&spi->dev, indio_dev); + return devm_iio_device_register(dev, indio_dev); } static const struct spi_device_id ad7292_id_table[] = { From 567485a8e6afac7162550286095335bfa9792bd8 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 30 Mar 2026 14:18:50 +0300 Subject: [PATCH 026/266] iio: adc: ad7292: use dev_err_probe() Use dev_err_probe() instead of dev_err() in the probe path to ensure proper handling of deferred probing and to simplify error handling. Signed-off-by: Antoniu Miclaus Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7292.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/ad7292.c b/drivers/iio/adc/ad7292.c index 64d40b053582..e5ad83d2240a 100644 --- a/drivers/iio/adc/ad7292.c +++ b/drivers/iio/adc/ad7292.c @@ -267,10 +267,9 @@ static int ad7292_probe(struct spi_device *spi) st->spi = spi; ret = ad7292_spi_reg_read(st, AD7292_REG_VENDOR_ID); - if (ret != ADI_VENDOR_ID) { - dev_err(&spi->dev, "Wrong vendor id 0x%x\n", ret); - return -EINVAL; - } + if (ret != ADI_VENDOR_ID) + return dev_err_probe(dev, -EINVAL, + "Wrong vendor id 0x%x\n", ret); ret = devm_regulator_get_enable_read_voltage(dev, "vref"); if (ret < 0 && ret != -ENODEV) From d9e85469a7db69ed2950eeb4a0ff7a87419dbd86 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 30 Mar 2026 14:18:51 +0300 Subject: [PATCH 027/266] iio: adc: ad7791: add dev variable Add a local struct device pointer to simplify repeated &spi->dev dereferences throughout the probe function. Signed-off-by: Antoniu Miclaus Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7791.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/iio/adc/ad7791.c b/drivers/iio/adc/ad7791.c index 041fc25e3209..ab1ab0d88492 100644 --- a/drivers/iio/adc/ad7791.c +++ b/drivers/iio/adc/ad7791.c @@ -407,7 +407,8 @@ static void ad7791_reg_disable(void *reg) static int ad7791_probe(struct spi_device *spi) { - const struct ad7791_platform_data *pdata = dev_get_platdata(&spi->dev); + struct device *dev = &spi->dev; + const struct ad7791_platform_data *pdata = dev_get_platdata(dev); struct iio_dev *indio_dev; struct ad7791_state *st; int ret; @@ -417,13 +418,13 @@ static int ad7791_probe(struct spi_device *spi) return -ENXIO; } - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; st = iio_priv(indio_dev); - st->reg = devm_regulator_get(&spi->dev, "refin"); + st->reg = devm_regulator_get(dev, "refin"); if (IS_ERR(st->reg)) return PTR_ERR(st->reg); @@ -431,7 +432,7 @@ static int ad7791_probe(struct spi_device *spi) if (ret) return ret; - ret = devm_add_action_or_reset(&spi->dev, ad7791_reg_disable, st->reg); + ret = devm_add_action_or_reset(dev, ad7791_reg_disable, st->reg); if (ret) return ret; @@ -447,7 +448,7 @@ static int ad7791_probe(struct spi_device *spi) else indio_dev->info = &ad7791_no_filter_info; - ret = devm_ad_sd_setup_buffer_and_trigger(&spi->dev, indio_dev); + ret = devm_ad_sd_setup_buffer_and_trigger(dev, indio_dev); if (ret) return ret; @@ -455,7 +456,7 @@ static int ad7791_probe(struct spi_device *spi) if (ret) return ret; - return devm_iio_device_register(&spi->dev, indio_dev); + return devm_iio_device_register(dev, indio_dev); } static const struct spi_device_id ad7791_spi_ids[] = { From db935b8cac8bb091e884fe68231835234a266a85 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 30 Mar 2026 14:18:52 +0300 Subject: [PATCH 028/266] iio: adc: ad7791: use dev_err_probe() Use dev_err_probe() instead of dev_err() in the probe path to ensure proper handling of deferred probing and to simplify error handling. Signed-off-by: Antoniu Miclaus Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7791.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/ad7791.c b/drivers/iio/adc/ad7791.c index ab1ab0d88492..bcdc19e799aa 100644 --- a/drivers/iio/adc/ad7791.c +++ b/drivers/iio/adc/ad7791.c @@ -413,10 +413,8 @@ static int ad7791_probe(struct spi_device *spi) struct ad7791_state *st; int ret; - if (!spi->irq) { - dev_err(&spi->dev, "Missing IRQ.\n"); - return -ENXIO; - } + if (!spi->irq) + return dev_err_probe(dev, -ENXIO, "Missing IRQ.\n"); indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) From a88442f40854ace0a078581d4dfda53f32d1a7f3 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 30 Mar 2026 14:18:53 +0300 Subject: [PATCH 029/266] iio: adc: ad7280a: use dev_err_probe() Use dev_err_probe() instead of dev_err() in the probe path to ensure proper handling of deferred probing and to simplify error handling. Signed-off-by: Antoniu Miclaus Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7280a.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/ad7280a.c b/drivers/iio/adc/ad7280a.c index ba12a3796e2b..f50e2b3121bf 100644 --- a/drivers/iio/adc/ad7280a.c +++ b/drivers/iio/adc/ad7280a.c @@ -990,8 +990,8 @@ static int ad7280_probe(struct spi_device *spi) st->acquisition_time = AD7280A_CTRL_LB_ACQ_TIME_1600ns; break; default: - dev_err(dev, "Firmware provided acquisition time is invalid\n"); - return -EINVAL; + return dev_err_probe(dev, -EINVAL, + "Firmware provided acquisition time is invalid\n"); } } else { st->acquisition_time = AD7280A_CTRL_LB_ACQ_TIME_400ns; From ba1ad6b2de799b6c1a869bd2add44bacf0a97344 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 30 Mar 2026 14:18:54 +0300 Subject: [PATCH 030/266] iio: adc: ad7768-1: use dev_err_probe() Use dev_err_probe() instead of dev_err() in the probe path to ensure proper handling of deferred probing and to simplify error handling. Signed-off-by: Antoniu Miclaus Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7768-1.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index 73fb734d06b2..598936e47fd2 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -1871,10 +1871,8 @@ static int ad7768_probe(struct spi_device *spi) return ret; ret = ad7768_setup(indio_dev); - if (ret < 0) { - dev_err(&spi->dev, "AD7768 setup failed\n"); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "AD7768 setup failed\n"); init_completion(&st->completion); ret = devm_mutex_init(&spi->dev, &st->pga_lock); From 8b6e7388290f71cad96fb5f9279ec7c933f40258 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 30 Mar 2026 14:18:55 +0300 Subject: [PATCH 031/266] iio: adc: ad9467: use dev_err_probe() Use dev_err_probe() instead of dev_err() in the probe path to ensure proper handling of deferred probing and to simplify error handling. Signed-off-by: Antoniu Miclaus Reviewed-by: Tomas Melin Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad9467.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/iio/adc/ad9467.c b/drivers/iio/adc/ad9467.c index 0bf67437508f..0c377f9a7f25 100644 --- a/drivers/iio/adc/ad9467.c +++ b/drivers/iio/adc/ad9467.c @@ -1349,11 +1349,10 @@ static int ad9467_probe(struct spi_device *spi) return ret; id = ad9467_spi_read(st, AN877_ADC_REG_CHIP_ID); - if (id != st->info->id) { - dev_err(dev, "Mismatch CHIP_ID, got 0x%X, expected 0x%X\n", - id, st->info->id); - return -ENODEV; - } + if (id != st->info->id) + return dev_err_probe(dev, -ENODEV, + "Mismatch CHIP_ID, got 0x%X, expected 0x%X\n", + id, st->info->id); if (st->info->num_scales > 1) indio_dev->info = &ad9467_info; From 5bcbbcfb7c91b9ab759397d7ca5b317a87284665 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 30 Mar 2026 14:18:56 +0300 Subject: [PATCH 032/266] iio: adc: ad4062: use dev_err_probe() Use dev_err_probe() instead of dev_err() in the probe path to ensure proper handling of deferred probing and to simplify error handling. Signed-off-by: Antoniu Miclaus Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad4062.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/ad4062.c b/drivers/iio/adc/ad4062.c index 222499a45b9b..8e5984055b15 100644 --- a/drivers/iio/adc/ad4062.c +++ b/drivers/iio/adc/ad4062.c @@ -436,10 +436,9 @@ static int ad4062_check_ids(struct ad4062_state *st) return ret; val = be16_to_cpu(st->buf.be16); - if (val != AD4062_I3C_VENDOR) { - dev_err(dev, "Vendor ID x%x does not match expected value\n", val); - return -ENODEV; - } + if (val != AD4062_I3C_VENDOR) + return dev_err_probe(dev, -ENODEV, + "Vendor ID x%x does not match expected value\n", val); return 0; } From 7328d444c19eb31a2b6033969ff4fd170309326c Mon Sep 17 00:00:00 2001 From: Gabriel Rondon Date: Mon, 30 Mar 2026 19:15:27 +0100 Subject: [PATCH 033/266] iio: adc: ti-ads8688: use read_avail for available attributes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert the in_voltage_scale_available and in_voltage_offset_available attributes from legacy IIO_DEVICE_ATTR with custom show functions to the IIO framework's read_avail callback. This uses the framework's built-in support for _available attributes, removing the need for manual sysfs formatting. Precompute the available scale values at probe time since they depend on the reference voltage which does not change after initialization. Reviewed-by: Nuno Sá Signed-off-by: Gabriel Rondon Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-ads8688.c | 70 ++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/drivers/iio/adc/ti-ads8688.c b/drivers/iio/adc/ti-ads8688.c index b0bf46cae0b6..ebd2826a7ff6 100644 --- a/drivers/iio/adc/ti-ads8688.c +++ b/drivers/iio/adc/ti-ads8688.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -17,7 +16,6 @@ #include #include #include -#include #define ADS8688_CMD_REG(x) (x << 8) #define ADS8688_CMD_REG_NOOP 0x00 @@ -66,6 +64,7 @@ struct ads8688_state { const struct ads8688_chip_info *chip_info; struct spi_device *spi; unsigned int vref_mv; + int scale_avail[3][2]; enum ads8688_range range[8]; union { __be32 d32; @@ -114,37 +113,9 @@ static const struct ads8688_ranges ads8688_range_def[5] = { } }; -static ssize_t ads8688_show_scales(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ads8688_state *st = iio_priv(dev_to_iio_dev(dev)); - - return sprintf(buf, "0.%09u 0.%09u 0.%09u\n", - ads8688_range_def[0].scale * st->vref_mv, - ads8688_range_def[1].scale * st->vref_mv, - ads8688_range_def[2].scale * st->vref_mv); -} - -static ssize_t ads8688_show_offsets(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%d %d\n", ads8688_range_def[0].offset, - ads8688_range_def[3].offset); -} - -static IIO_DEVICE_ATTR(in_voltage_scale_available, S_IRUGO, - ads8688_show_scales, NULL, 0); -static IIO_DEVICE_ATTR(in_voltage_offset_available, S_IRUGO, - ads8688_show_offsets, NULL, 0); - -static struct attribute *ads8688_attributes[] = { - &iio_dev_attr_in_voltage_scale_available.dev_attr.attr, - &iio_dev_attr_in_voltage_offset_available.dev_attr.attr, - NULL, -}; - -static const struct attribute_group ads8688_attribute_group = { - .attrs = ads8688_attributes, +static const int ads8688_offset_avail[] = { + -(1 << (ADS8688_REALBITS - 1)), + 0 }; #define ADS8688_CHAN(index) \ @@ -155,6 +126,9 @@ static const struct attribute_group ads8688_attribute_group = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) \ | BIT(IIO_CHAN_INFO_SCALE) \ | BIT(IIO_CHAN_INFO_OFFSET), \ + .info_mask_shared_by_type_available = \ + BIT(IIO_CHAN_INFO_SCALE) \ + | BIT(IIO_CHAN_INFO_OFFSET), \ .scan_index = index, \ .scan_type = { \ .sign = 'u', \ @@ -369,11 +343,34 @@ static int ads8688_write_raw_get_fmt(struct iio_dev *indio_dev, return -EINVAL; } +static int ads8688_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + struct ads8688_state *st = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + *vals = (const int *)st->scale_avail; + *type = IIO_VAL_INT_PLUS_NANO; + *length = ARRAY_SIZE(st->scale_avail) * 2; + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_OFFSET: + *vals = ads8688_offset_avail; + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(ads8688_offset_avail); + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + static const struct iio_info ads8688_info = { .read_raw = &ads8688_read_raw, + .read_avail = &ads8688_read_avail, .write_raw = &ads8688_write_raw, .write_raw_get_fmt = &ads8688_write_raw_get_fmt, - .attrs = &ads8688_attribute_group, }; static irqreturn_t ads8688_trigger_handler(int irq, void *p) @@ -426,6 +423,11 @@ static int ads8688_probe(struct spi_device *spi) st->vref_mv = ret == -ENODEV ? ADS8688_VREF_MV : ret / 1000; + for (unsigned int i = 0; i < ARRAY_SIZE(st->scale_avail); i++) { + st->scale_avail[i][0] = 0; + st->scale_avail[i][1] = ads8688_range_def[i].scale * st->vref_mv; + } + st->chip_info = &ads8688_chip_info_tbl[spi_get_device_id(spi)->driver_data]; spi->mode = SPI_MODE_1; From 2e8a75ac286a51eccd51b68715960563a2ee9c4d Mon Sep 17 00:00:00 2001 From: Joshua Crofts Date: Fri, 17 Apr 2026 13:02:24 +0000 Subject: [PATCH 034/266] iio: magnetometer: ak8975: remove unnecessary braces Remove unnecessary braces at single if statement block. No functional change. Signed-off-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/ak8975.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index b648b0afa573..44782c26698b 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -541,9 +541,9 @@ static int ak8975_set_mode(struct ak8975_data *data, enum ak_ctrl_mode mode) data->def->ctrl_modes[mode]; ret = i2c_smbus_write_byte_data(data->client, data->def->ctrl_regs[CNTL], regval); - if (ret < 0) { + if (ret < 0) return ret; - } + data->cntl_cache = regval; /* After mode change wait at least 100us */ usleep_range(100, 500); From d2ed8a2f630abe69d87eeffb2781df9237d7c1dd Mon Sep 17 00:00:00 2001 From: Sanjay Chitroda Date: Fri, 17 Apr 2026 18:19:17 +0530 Subject: [PATCH 035/266] iio: accel: adxl313_core: Use devm-managed mutex initialization Use devm_mutex_init() to tie the mutex lifetime to the device and improve debugging when CONFIG_DEBUG_MUTEXES is enabled. Signed-off-by: Sanjay Chitroda Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl313_core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/iio/accel/adxl313_core.c b/drivers/iio/accel/adxl313_core.c index bcc11dabdf22..1fc96b7b0f1f 100644 --- a/drivers/iio/accel/adxl313_core.c +++ b/drivers/iio/accel/adxl313_core.c @@ -1240,7 +1240,9 @@ int adxl313_core_probe(struct device *dev, data->regmap = regmap; data->chip_info = chip_info; - mutex_init(&data->lock); + ret = devm_mutex_init(dev, &data->lock); + if (ret) + return ret; indio_dev->name = chip_info->name; indio_dev->info = &adxl313_info; From c27837e49fd1fa0eae1b6d3988d2ae5a9d924739 Mon Sep 17 00:00:00 2001 From: Sanjay Chitroda Date: Fri, 17 Apr 2026 18:19:18 +0530 Subject: [PATCH 036/266] iio: accel: adxl313: Use dev_err_probe() dev_err_probe() makes error code handling simpler and handles deferred probe nicely (avoid spamming logs). Signed-off-by: Sanjay Chitroda Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl313_core.c | 6 ++---- drivers/iio/accel/adxl313_i2c.c | 10 ++++------ drivers/iio/accel/adxl313_spi.c | 11 ++++------- 3 files changed, 10 insertions(+), 17 deletions(-) diff --git a/drivers/iio/accel/adxl313_core.c b/drivers/iio/accel/adxl313_core.c index 1fc96b7b0f1f..6dc918c4ae17 100644 --- a/drivers/iio/accel/adxl313_core.c +++ b/drivers/iio/accel/adxl313_core.c @@ -1252,10 +1252,8 @@ int adxl313_core_probe(struct device *dev, indio_dev->available_scan_masks = adxl313_scan_masks; ret = adxl313_setup(dev, data, setup); - if (ret) { - dev_err(dev, "ADXL313 setup failed\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "ADXL313 setup failed\n"); int_line = adxl313_get_int_type(dev, &irq); if (int_line == ADXL313_INT_NONE) { diff --git a/drivers/iio/accel/adxl313_i2c.c b/drivers/iio/accel/adxl313_i2c.c index b67ff0b4dc54..6736b83f23bd 100644 --- a/drivers/iio/accel/adxl313_i2c.c +++ b/drivers/iio/accel/adxl313_i2c.c @@ -65,6 +65,7 @@ MODULE_DEVICE_TABLE(of, adxl313_of_match); static int adxl313_i2c_probe(struct i2c_client *client) { const struct adxl313_chip_info *chip_data; + struct device *dev = &client->dev; struct regmap *regmap; /* @@ -75,13 +76,10 @@ static int adxl313_i2c_probe(struct i2c_client *client) regmap = devm_regmap_init_i2c(client, &adxl31x_i2c_regmap_config[chip_data->type]); - if (IS_ERR(regmap)) { - dev_err(&client->dev, "Error initializing i2c regmap: %ld\n", - PTR_ERR(regmap)); - return PTR_ERR(regmap); - } + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), "Error initializing i2c regmap\n"); - return adxl313_core_probe(&client->dev, regmap, chip_data, NULL); + return adxl313_core_probe(dev, regmap, chip_data, NULL); } static struct i2c_driver adxl313_i2c_driver = { diff --git a/drivers/iio/accel/adxl313_spi.c b/drivers/iio/accel/adxl313_spi.c index dedb0885c277..d096ea0632ba 100644 --- a/drivers/iio/accel/adxl313_spi.c +++ b/drivers/iio/accel/adxl313_spi.c @@ -70,6 +70,7 @@ static int adxl313_spi_setup(struct device *dev, struct regmap *regmap) static int adxl313_spi_probe(struct spi_device *spi) { const struct adxl313_chip_info *chip_data; + struct device *dev = &spi->dev; struct regmap *regmap; int ret; @@ -83,14 +84,10 @@ static int adxl313_spi_probe(struct spi_device *spi) regmap = devm_regmap_init_spi(spi, &adxl31x_spi_regmap_config[chip_data->type]); - if (IS_ERR(regmap)) { - dev_err(&spi->dev, "Error initializing spi regmap: %ld\n", - PTR_ERR(regmap)); - return PTR_ERR(regmap); - } + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), "Error initializing spi regmap\n"); - return adxl313_core_probe(&spi->dev, regmap, - chip_data, &adxl313_spi_setup); + return adxl313_core_probe(dev, regmap, chip_data, &adxl313_spi_setup); } static const struct spi_device_id adxl313_spi_id[] = { From 1ed49c5e6b6da868ff226706d54919e1e10cf991 Mon Sep 17 00:00:00 2001 From: Sanjay Chitroda Date: Fri, 17 Apr 2026 18:19:19 +0530 Subject: [PATCH 037/266] iio: accel: adxl380: Use devm-managed mutex initialization Use devm_mutex_init() to tie the mutex lifetime to the device and improve debugging when CONFIG_DEBUG_MUTEXES is enabled. Signed-off-by: Sanjay Chitroda Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl380.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/iio/accel/adxl380.c b/drivers/iio/accel/adxl380.c index e7bb32fbc475..7dca5523091f 100644 --- a/drivers/iio/accel/adxl380.c +++ b/drivers/iio/accel/adxl380.c @@ -1967,7 +1967,9 @@ int adxl380_probe(struct device *dev, struct regmap *regmap, st->chip_info = chip_info; st->odr = ADXL380_ODR_DSM; - mutex_init(&st->lock); + ret = devm_mutex_init(dev, &st->lock); + if (ret) + return ret; indio_dev->channels = adxl380_channels; indio_dev->num_channels = ARRAY_SIZE(adxl380_channels); From 07fd62916c7d2adb65926b989d337c7bfc7b2357 Mon Sep 17 00:00:00 2001 From: Sanjay Chitroda Date: Fri, 17 Apr 2026 18:19:20 +0530 Subject: [PATCH 038/266] iio: accel: adxl355_core: Use devm-managed mutex initialization Use devm_mutex_init() to tie the mutex lifetime to the device and improve debugging when CONFIG_DEBUG_MUTEXES is enabled. Signed-off-by: Sanjay Chitroda Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl355_core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/iio/accel/adxl355_core.c b/drivers/iio/accel/adxl355_core.c index 8f90c58f4100..a310f8e37e3d 100644 --- a/drivers/iio/accel/adxl355_core.c +++ b/drivers/iio/accel/adxl355_core.c @@ -802,7 +802,9 @@ int adxl355_core_probe(struct device *dev, struct regmap *regmap, data->dev = dev; data->op_mode = ADXL355_STANDBY; data->chip_info = chip_info; - mutex_init(&data->lock); + ret = devm_mutex_init(dev, &data->lock); + if (ret) + return ret; indio_dev->name = chip_info->name; indio_dev->info = &adxl355_info; From 70cc2c65c23ba212c6de61a727131ebf94a66610 Mon Sep 17 00:00:00 2001 From: Sanjay Chitroda Date: Fri, 17 Apr 2026 18:19:21 +0530 Subject: [PATCH 039/266] iio: accel: adxl355: Use dev_err_probe() dev_err_probe() makes error code handling simpler and handles deferred probe nicely (avoid spamming logs). Signed-off-by: Sanjay Chitroda Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl355_core.c | 24 ++++++++---------------- drivers/iio/accel/adxl355_i2c.c | 11 ++++------- drivers/iio/accel/adxl355_spi.c | 11 ++++------- 3 files changed, 16 insertions(+), 30 deletions(-) diff --git a/drivers/iio/accel/adxl355_core.c b/drivers/iio/accel/adxl355_core.c index a310f8e37e3d..03e5744d9667 100644 --- a/drivers/iio/accel/adxl355_core.c +++ b/drivers/iio/accel/adxl355_core.c @@ -336,10 +336,8 @@ static int adxl355_setup(struct adxl355_data *data) return ret; do { - if (--retries == 0) { - dev_err(data->dev, "Shadow registers mismatch\n"); - return -EIO; - } + if (--retries == 0) + return dev_err_probe(data->dev, -EIO, "Shadow registers mismatch\n"); /* * Perform a software reset to make sure the device is in a consistent @@ -775,10 +773,8 @@ static int adxl355_probe_trigger(struct iio_dev *indio_dev, int irq) irq); ret = devm_iio_trigger_register(data->dev, data->dready_trig); - if (ret) { - dev_err(data->dev, "iio trigger register failed\n"); - return ret; - } + if (ret) + return dev_err_probe(data->dev, ret, "iio trigger register failed\n"); indio_dev->trig = iio_trigger_get(data->dready_trig); @@ -814,18 +810,14 @@ int adxl355_core_probe(struct device *dev, struct regmap *regmap, indio_dev->available_scan_masks = adxl355_avail_scan_masks; ret = adxl355_setup(data); - if (ret) { - dev_err(dev, "ADXL355 setup failed\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "ADXL355 setup failed\n"); ret = devm_iio_triggered_buffer_setup(dev, indio_dev, &iio_pollfunc_store_time, &adxl355_trigger_handler, NULL); - if (ret) { - dev_err(dev, "iio triggered buffer setup failed\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "iio triggered buffer setup failed\n"); irq = fwnode_irq_get_byname(dev_fwnode(dev), "DRDY"); if (irq > 0) { diff --git a/drivers/iio/accel/adxl355_i2c.c b/drivers/iio/accel/adxl355_i2c.c index 1a512c7b792b..19490a6e1f35 100644 --- a/drivers/iio/accel/adxl355_i2c.c +++ b/drivers/iio/accel/adxl355_i2c.c @@ -23,6 +23,7 @@ static const struct regmap_config adxl355_i2c_regmap_config = { static int adxl355_i2c_probe(struct i2c_client *client) { struct regmap *regmap; + struct device *dev = &client->dev; const struct adxl355_chip_info *chip_data; chip_data = i2c_get_match_data(client); @@ -30,14 +31,10 @@ static int adxl355_i2c_probe(struct i2c_client *client) return -ENODEV; regmap = devm_regmap_init_i2c(client, &adxl355_i2c_regmap_config); - if (IS_ERR(regmap)) { - dev_err(&client->dev, "Error initializing i2c regmap: %ld\n", - PTR_ERR(regmap)); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), "Error initializing i2c regmap\n"); - return PTR_ERR(regmap); - } - - return adxl355_core_probe(&client->dev, regmap, chip_data); + return adxl355_core_probe(dev, regmap, chip_data); } static const struct i2c_device_id adxl355_i2c_id[] = { diff --git a/drivers/iio/accel/adxl355_spi.c b/drivers/iio/accel/adxl355_spi.c index 869e3e57d6f7..347ed62b6582 100644 --- a/drivers/iio/accel/adxl355_spi.c +++ b/drivers/iio/accel/adxl355_spi.c @@ -26,6 +26,7 @@ static const struct regmap_config adxl355_spi_regmap_config = { static int adxl355_spi_probe(struct spi_device *spi) { const struct adxl355_chip_info *chip_data; + struct device *dev = &spi->dev; struct regmap *regmap; chip_data = spi_get_device_match_data(spi); @@ -33,14 +34,10 @@ static int adxl355_spi_probe(struct spi_device *spi) return -EINVAL; regmap = devm_regmap_init_spi(spi, &adxl355_spi_regmap_config); - if (IS_ERR(regmap)) { - dev_err(&spi->dev, "Error initializing spi regmap: %ld\n", - PTR_ERR(regmap)); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), "Error initializing spi regmap\n"); - return PTR_ERR(regmap); - } - - return adxl355_core_probe(&spi->dev, regmap, chip_data); + return adxl355_core_probe(dev, regmap, chip_data); } static const struct spi_device_id adxl355_spi_id[] = { From f710a0fa462ce5fc356ab4a77787b49fc1f47f7b Mon Sep 17 00:00:00 2001 From: Sanjay Chitroda Date: Fri, 17 Apr 2026 18:19:22 +0530 Subject: [PATCH 040/266] iio: accel: adxl367: Use devm-managed mutex initialization Use devm_mutex_init() to tie the mutex lifetime to the device and improve debugging when CONFIG_DEBUG_MUTEXES is enabled. Signed-off-by: Sanjay Chitroda Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl367.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/iio/accel/adxl367.c b/drivers/iio/accel/adxl367.c index 0c04b2bb7efb..63a0b182824f 100644 --- a/drivers/iio/accel/adxl367.c +++ b/drivers/iio/accel/adxl367.c @@ -1445,7 +1445,9 @@ int adxl367_probe(struct device *dev, const struct adxl367_ops *ops, st->context = context; st->ops = ops; - mutex_init(&st->lock); + ret = devm_mutex_init(dev, &st->lock); + if (ret) + return ret; indio_dev->channels = adxl367_channels; indio_dev->num_channels = ARRAY_SIZE(adxl367_channels); From 24ab1d9a2fc4c1e4f2546bebcee2b420295120a0 Mon Sep 17 00:00:00 2001 From: Sanjay Chitroda Date: Fri, 17 Apr 2026 18:19:23 +0530 Subject: [PATCH 041/266] iio: accel: adxl372: Use devm-managed mutex initialization Use devm_mutex_init() to tie the mutex lifetime to the device and improve debugging when CONFIG_DEBUG_MUTEXES is enabled. Signed-off-by: Sanjay Chitroda Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl372.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/iio/accel/adxl372.c b/drivers/iio/accel/adxl372.c index 545a21e5a308..1a6ba94f54f4 100644 --- a/drivers/iio/accel/adxl372.c +++ b/drivers/iio/accel/adxl372.c @@ -1299,7 +1299,9 @@ int adxl372_probe(struct device *dev, struct regmap *regmap, st->irq = irq; st->chip_info = chip_info; - mutex_init(&st->threshold_m); + ret = devm_mutex_init(dev, &st->threshold_m); + if (ret < 0) + return ret; indio_dev->channels = adxl372_channels; indio_dev->num_channels = ARRAY_SIZE(adxl372_channels); From d47d6bdc81cfe56a1e7af40528ac81162a547e1b Mon Sep 17 00:00:00 2001 From: Sanjay Chitroda Date: Fri, 17 Apr 2026 18:19:24 +0530 Subject: [PATCH 042/266] iio: accel: adxl372: Use dev_err_probe() dev_err_probe() makes error code handling simpler and handles deferred probe nicely (avoid spamming logs). Signed-off-by: Sanjay Chitroda Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl372.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/accel/adxl372.c b/drivers/iio/accel/adxl372.c index 1a6ba94f54f4..e375d068a3f5 100644 --- a/drivers/iio/accel/adxl372.c +++ b/drivers/iio/accel/adxl372.c @@ -1316,10 +1316,8 @@ int adxl372_probe(struct device *dev, struct regmap *regmap, } ret = adxl372_setup(st); - if (ret < 0) { - dev_err(dev, "ADXL372 setup failed\n"); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "ADXL372 setup failed\n"); if (chip_info->fifo_supported) { ret = adxl372_buffer_setup(indio_dev); From 0ce10ae5eb91235e69901b55b9a6d8d90e9cbf6a Mon Sep 17 00:00:00 2001 From: Joshua Crofts Date: Fri, 17 Apr 2026 10:16:22 +0000 Subject: [PATCH 043/266] iio: frequency: ad9832: remove kernel.h proxy header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove kernel.h proxy header and add replacement headers (array_size.h, dev_printk.h, kstrtox.h, mod_devicetable.h, mutex, types.h, asm/byteorder.h) to maintain atomicity. Moved asm/div64.h header below generic headers. Additionally, add bitops.h for BIT_ULL() macro. Audited using the include-what-you-use tool. Signed-off-by: Joshua Crofts Reviewed-by: Nuno Sá Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/staging/iio/frequency/ad9832.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/staging/iio/frequency/ad9832.c b/drivers/staging/iio/frequency/ad9832.c index b87ea1781b27..c0b7852f1c84 100644 --- a/drivers/staging/iio/frequency/ad9832.c +++ b/drivers/staging/iio/frequency/ad9832.c @@ -5,21 +5,25 @@ * Copyright 2011 Analog Devices Inc. */ -#include - +#include #include -#include +#include #include -#include +#include #include -#include +#include +#include #include +#include #include -#include #include #include +#include #include +#include +#include + #include #include From 13af23fb52a836e0636cdd5b8814d5c96af2aa39 Mon Sep 17 00:00:00 2001 From: Joshua Crofts Date: Thu, 16 Apr 2026 09:32:40 +0000 Subject: [PATCH 044/266] iio: frequency: ad9834: clean up includes Cleanup include headers by removing proxy kernel.h header and unnecessary list.h, interrupt.h, workqueue.h and slab.h headers. Added additional headers that were previously included from kernel.h. Verified using the include-what-you-use tool. Signed-off-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/staging/iio/frequency/ad9834.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c index bdb2580e29bf..330db78fe766 100644 --- a/drivers/staging/iio/frequency/ad9834.c +++ b/drivers/staging/iio/frequency/ad9834.c @@ -5,18 +5,21 @@ * Copyright 2010-2011 Analog Devices Inc. */ +#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include +#include +#include #include +#include +#include +#include +#include +#include +#include + +#include #include #include From dcc80f2fdff721ced4ea1ef7a3ea43f3fbe0b27a Mon Sep 17 00:00:00 2001 From: Sanjay Chitroda Date: Wed, 15 Apr 2026 10:37:43 +0530 Subject: [PATCH 045/266] iio: ssp_sensors: cleanup codestyle warning Reported by checkpatch: FILE: drivers/iio/common/ssp_sensors/ssp_spi.c WARNING: Prefer __packed over __attribute__((__packed__)) +} __attribute__((__packed__)); Signed-off-by: Sanjay Chitroda Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/common/ssp_sensors/ssp_spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/common/ssp_sensors/ssp_spi.c b/drivers/iio/common/ssp_sensors/ssp_spi.c index 6c81c0385fb5..8c1e15d61db7 100644 --- a/drivers/iio/common/ssp_sensors/ssp_spi.c +++ b/drivers/iio/common/ssp_sensors/ssp_spi.c @@ -29,7 +29,7 @@ struct ssp_msg_header { __le16 length; __le16 options; __le32 data; -} __attribute__((__packed__)); +} __packed; struct ssp_msg { u16 length; From a9ecd9a121752f2d7bb69da264bda65b6b6e6c6e Mon Sep 17 00:00:00 2001 From: Sanjay Chitroda Date: Wed, 15 Apr 2026 10:37:44 +0530 Subject: [PATCH 046/266] iio: ssp_sensors: cleanup codestyle check Reported by checkpatch: FILE: drivers/iio/common/ssp_sensors/ssp_spi.c CHECK: Macro argument '...' may be better as '(...)' to avoid precedence issues Signed-off-by: Sanjay Chitroda Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/common/ssp_sensors/ssp_spi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iio/common/ssp_sensors/ssp_spi.c b/drivers/iio/common/ssp_sensors/ssp_spi.c index 8c1e15d61db7..08ed92859be0 100644 --- a/drivers/iio/common/ssp_sensors/ssp_spi.c +++ b/drivers/iio/common/ssp_sensors/ssp_spi.c @@ -6,7 +6,7 @@ #include "ssp.h" #define SSP_DEV (&data->spi->dev) -#define SSP_GET_MESSAGE_TYPE(data) (data & (3 << SSP_RW)) +#define SSP_GET_MESSAGE_TYPE(data) ((data) & (3 << SSP_RW)) /* * SSP -> AP Instruction @@ -119,9 +119,9 @@ static inline void ssp_get_buffer(struct ssp_msg *m, unsigned int offset, } #define SSP_GET_BUFFER_AT_INDEX(m, index) \ - (m->buffer[SSP_HEADER_SIZE_ALIGNED + index]) + ((m)->buffer[SSP_HEADER_SIZE_ALIGNED + (index)]) #define SSP_SET_BUFFER_AT_INDEX(m, index, val) \ - (m->buffer[SSP_HEADER_SIZE_ALIGNED + index] = val) + ((m)->buffer[SSP_HEADER_SIZE_ALIGNED + (index)] = val) static void ssp_clean_msg(struct ssp_msg *m) { From f4d618c6185101efa072fd5845000fee2074b8b8 Mon Sep 17 00:00:00 2001 From: Nikhil Gautam Date: Tue, 14 Apr 2026 22:33:06 +0530 Subject: [PATCH 047/266] iio: dac: mcp4821: fix spelling mistake in enum name Fix a typo in the enum name mcp4821_supported_drvice_ids by renaming it to mcp4821_supported_device_ids. This improves code readability and consistency. Signed-off-by: Nikhil Gautam Reviewed-by: David Lechner Signed-off-by: Jonathan Cameron --- drivers/iio/dac/mcp4821.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/dac/mcp4821.c b/drivers/iio/dac/mcp4821.c index 748bdca9a964..29187f2a9d3c 100644 --- a/drivers/iio/dac/mcp4821.c +++ b/drivers/iio/dac/mcp4821.c @@ -31,7 +31,7 @@ /* DAC uses an internal Voltage reference of 4.096V at a gain of 2x */ #define MCP4821_2X_GAIN_VREF_MV 4096 -enum mcp4821_supported_drvice_ids { +enum mcp4821_supported_device_ids { ID_MCP4801, ID_MCP4802, ID_MCP4811, From 090839ecff2b30fa87b73f5001cdb150673a4d4c Mon Sep 17 00:00:00 2001 From: Nikhil Gautam Date: Tue, 14 Apr 2026 22:33:07 +0530 Subject: [PATCH 048/266] iio: dac: mcp4821: move state initialization outside switch Move the iio_priv() call outside the switch statement in mcp4821_read_raw() to avoid repeating it in multiple cases. No functional change. Signed-off-by: Nikhil Gautam Reviewed-by: David Lechner Signed-off-by: Jonathan Cameron --- drivers/iio/dac/mcp4821.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/iio/dac/mcp4821.c b/drivers/iio/dac/mcp4821.c index 29187f2a9d3c..102ae3718514 100644 --- a/drivers/iio/dac/mcp4821.c +++ b/drivers/iio/dac/mcp4821.c @@ -115,11 +115,10 @@ static int mcp4821_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { - struct mcp4821_state *state; + struct mcp4821_state *state = iio_priv(indio_dev); switch (mask) { case IIO_CHAN_INFO_RAW: - state = iio_priv(indio_dev); *val = state->dac_value[chan->channel]; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: From 416e983c913742cfae1720982720fe06fc7d3bba Mon Sep 17 00:00:00 2001 From: Nikhil Gautam Date: Tue, 14 Apr 2026 22:33:08 +0530 Subject: [PATCH 049/266] iio: dac: mcp4821: add configurable gain support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for configuring the DAC gain using the GA bit The MCP4821 supports two gain settings: - 1x gain → 2.048V full-scale - 2x gain → 4.096V full-scale Scale write support is added in the IIO interface. Only scale values advertised via the scale_available attribute are accepted, ensuring consistency between the configured gain and exposed scale values. Signed-off-by: Nikhil Gautam Reviewed-by: David Lechner Signed-off-by: Jonathan Cameron --- drivers/iio/dac/mcp4821.c | 132 +++++++++++++++++++++++++++++++------- 1 file changed, 110 insertions(+), 22 deletions(-) diff --git a/drivers/iio/dac/mcp4821.c b/drivers/iio/dac/mcp4821.c index 102ae3718514..18b5934fb8a2 100644 --- a/drivers/iio/dac/mcp4821.c +++ b/drivers/iio/dac/mcp4821.c @@ -12,13 +12,13 @@ * MCP48x2: https://ww1.microchip.com/downloads/en/DeviceDoc/20002249B.pdf * * TODO: - * - Configurable gain * - Regulator control */ #include #include #include +#include #include #include @@ -26,10 +26,30 @@ #include #define MCP4821_ACTIVE_MODE BIT(12) +#define MCP4821_GAIN_ENABLE BIT(13) #define MCP4802_SECOND_CHAN BIT(15) -/* DAC uses an internal Voltage reference of 4.096V at a gain of 2x */ -#define MCP4821_2X_GAIN_VREF_MV 4096 +/* DAC uses an internal Voltage reference of 2.048V */ +#define MCP4821_VREF_MV 2048 + +/* + * MCP48xx DAC output: + * + * Vout = (Vref * D / 2^N) * G + * + * where: + * - Vref = 2.048V (internal reference) + * - N = DAC resolution (12 bits for MCP4821) + * - G = gain selection: + * 1x when GA bit = 1 + * 2x when GA bit = 0 (default) + * + * Therefore full-scale voltage is: + * - 1x gain: 2.048V + * - 2x gain: 4.096V + * + * Scale = Vfull-scale / 2^N + */ enum mcp4821_supported_device_ids { ID_MCP4801, @@ -43,6 +63,8 @@ enum mcp4821_supported_device_ids { struct mcp4821_state { struct spi_device *spi; u16 dac_value[2]; + int gain; + int scale_avail[4]; }; struct mcp4821_chip_info { @@ -57,6 +79,7 @@ struct mcp4821_chip_info { .channel = (channel_id), \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE), \ .scan_type = { \ .realbits = (resolution), \ .shift = 12 - (resolution), \ @@ -121,8 +144,9 @@ static int mcp4821_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_RAW: *val = state->dac_value[chan->channel]; return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: - *val = MCP4821_2X_GAIN_VREF_MV; + *val = MCP4821_VREF_MV * state->gain; *val2 = chan->scan_type.realbits; return IIO_VAL_FRACTIONAL_LOG2; default: @@ -130,6 +154,17 @@ static int mcp4821_read_raw(struct iio_dev *indio_dev, } } +static void mcp4821_calc_scale(int vref_mv, int resolution, + int *val, int *val2) +{ + s64 tmp; + int micro; + + tmp = (s64)vref_mv * MICRO >> resolution; + *val = div_s64_rem(tmp, MICRO, µ); + *val2 = micro; +} + static int mcp4821_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) @@ -138,35 +173,85 @@ static int mcp4821_write_raw(struct iio_dev *indio_dev, u16 write_val; __be16 write_buffer; int ret; + int v, v2; - if (val2 != 0) + switch (mask) { + case IIO_CHAN_INFO_RAW: + + if (val2 != 0) + return -EINVAL; + + if (val < 0 || val >= BIT(chan->scan_type.realbits)) + return -EINVAL; + + write_val = MCP4821_ACTIVE_MODE | val << chan->scan_type.shift; + if (chan->channel) + write_val |= MCP4802_SECOND_CHAN; + + /* GA bit = 1 -> 1x gain */ + if (state->gain == 1) + write_val |= MCP4821_GAIN_ENABLE; + + write_buffer = cpu_to_be16(write_val); + ret = spi_write(state->spi, &write_buffer, sizeof(write_buffer)); + if (ret) { + dev_err(&state->spi->dev, "Failed to write to device: %d", ret); + return ret; + } + + state->dac_value[chan->channel] = val; + return 0; + + case IIO_CHAN_INFO_SCALE: + mcp4821_calc_scale(MCP4821_VREF_MV, chan->scan_type.realbits, &v, &v2); + if (val == v && val2 == v2) { + state->gain = 1; + return 0; + } + + mcp4821_calc_scale(MCP4821_VREF_MV * 2, + chan->scan_type.realbits, &v, &v2); + if (val == v && val2 == v2) { + state->gain = 2; + return 0; + } return -EINVAL; - - if (val < 0 || val >= BIT(chan->scan_type.realbits)) + default: return -EINVAL; - - if (mask != IIO_CHAN_INFO_RAW) - return -EINVAL; - - write_val = MCP4821_ACTIVE_MODE | val << chan->scan_type.shift; - if (chan->channel) - write_val |= MCP4802_SECOND_CHAN; - - write_buffer = cpu_to_be16(write_val); - ret = spi_write(state->spi, &write_buffer, sizeof(write_buffer)); - if (ret) { - dev_err(&state->spi->dev, "Failed to write to device: %d", ret); - return ret; } +} - state->dac_value[chan->channel] = val; +static inline void mcp4821_init_avail_gain(struct mcp4821_state *state, + int resolution) +{ + state->scale_avail[0] = MCP4821_VREF_MV; + state->scale_avail[1] = resolution; + state->scale_avail[2] = MCP4821_VREF_MV * 2; + state->scale_avail[3] = resolution; +} - return 0; +static int mcp4821_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long info) +{ + struct mcp4821_state *state = iio_priv(indio_dev); + + switch (info) { + case IIO_CHAN_INFO_SCALE: + *vals = state->scale_avail; + *type = IIO_VAL_FRACTIONAL_LOG2; + *length = ARRAY_SIZE(state->scale_avail); + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } } static const struct iio_info mcp4821_info = { .read_raw = &mcp4821_read_raw, .write_raw = &mcp4821_write_raw, + .read_avail = &mcp4821_read_avail, }; static int mcp4821_probe(struct spi_device *spi) @@ -182,12 +267,15 @@ static int mcp4821_probe(struct spi_device *spi) state = iio_priv(indio_dev); state->spi = spi; + /* default gain is 2x */ + state->gain = 2; info = spi_get_device_match_data(spi); indio_dev->name = info->name; indio_dev->info = &mcp4821_info; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = info->channels; indio_dev->num_channels = info->num_channels; + mcp4821_init_avail_gain(state, info->channels[0].scan_type.realbits); return devm_iio_device_register(&spi->dev, indio_dev); } From 4617091a7616aeaa174506045733b20a5398c2a9 Mon Sep 17 00:00:00 2001 From: Erikas Bitovtas Date: Tue, 14 Apr 2026 15:37:17 +0300 Subject: [PATCH 050/266] iio: light: vcnl4000: validate device by prod ID instead of table ID Add a new field for vcnl4000_chip_spec and check if we have the right device by that instead of the index from enum table. This leaves the enum table being used only for picking the right vcnl4000_chip_spec, allowing us to drop it later on. Reviewed-by: Andy Shevchenko Signed-off-by: Erikas Bitovtas Signed-off-by: Jonathan Cameron --- drivers/iio/light/vcnl4000.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c index 9650dbc41f2b..72d68d54864e 100644 --- a/drivers/iio/light/vcnl4000.c +++ b/drivers/iio/light/vcnl4000.c @@ -234,6 +234,7 @@ struct vcnl4000_chip_spec { const int(*als_it_times)[][2]; const int num_als_it_times; const unsigned int ulux_step; + const int prod_id; }; static const struct i2c_device_id vcnl4000_id[] = { @@ -265,12 +266,12 @@ static int vcnl4000_init(struct vcnl4000_data *data) prod_id = ret >> 4; switch (prod_id) { case VCNL4000_PROD_ID: - if (data->id != VCNL4000) + if (data->chip_spec->prod_id != VCNL4000_PROD_ID) dev_warn(&data->client->dev, "wrong device id, use vcnl4000"); break; case VCNL4010_PROD_ID: - if (data->id != VCNL4010) + if (data->chip_spec->prod_id != VCNL4010_PROD_ID) dev_warn(&data->client->dev, "wrong device id, use vcnl4010/4020"); break; @@ -1901,6 +1902,7 @@ static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = { .int_reg = VCNL4040_INT_FLAGS, .ps_it_times = &vcnl4040_ps_it_times, .num_ps_it_times = ARRAY_SIZE(vcnl4040_ps_it_times), + .prod_id = VCNL4040_PROD_ID, }, [VCNL4000] = { .prod = "VCNL4000", @@ -1911,6 +1913,7 @@ static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = { .channels = vcnl4000_channels, .num_channels = ARRAY_SIZE(vcnl4000_channels), .info = &vcnl4000_info, + .prod_id = VCNL4000_PROD_ID, }, [VCNL4010] = { .prod = "VCNL4010/4020", @@ -1924,6 +1927,7 @@ static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = { .irq_thread = vcnl4010_irq_thread, .trig_buffer_func = vcnl4010_trigger_handler, .buffer_setup_ops = &vcnl4010_buffer_ops, + .prod_id = VCNL4010_PROD_ID, }, [VCNL4040] = { .prod = "VCNL4040", @@ -1941,6 +1945,7 @@ static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = { .als_it_times = &vcnl4040_als_it_times, .num_als_it_times = ARRAY_SIZE(vcnl4040_als_it_times), .ulux_step = 100000, + .prod_id = VCNL4040_PROD_ID, }, [VCNL4200] = { .prod = "VCNL4200", @@ -1958,6 +1963,7 @@ static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = { .als_it_times = &vcnl4200_als_it_times, .num_als_it_times = ARRAY_SIZE(vcnl4200_als_it_times), .ulux_step = 24000, + .prod_id = VCNL4200_PROD_ID, }, }; From b2362b824f977a0a08f8d16c36510cabd6f58ce8 Mon Sep 17 00:00:00 2001 From: Erikas Bitovtas Date: Tue, 14 Apr 2026 15:37:18 +0300 Subject: [PATCH 051/266] iio: light: vcnl4000: drop enum id table in favor of chip structs Instead of creating an enum table with chip IDs, store pointers to structs directly. This drops the association between chip structs and enum IDs and allows for easier addition or removal of new devices. Reviewed-by: Andy Shevchenko Signed-off-by: Erikas Bitovtas Signed-off-by: Jonathan Cameron --- drivers/iio/light/vcnl4000.c | 205 +++++++++++++++++------------------ 1 file changed, 98 insertions(+), 107 deletions(-) diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c index 72d68d54864e..cbe0a9e056ec 100644 --- a/drivers/iio/light/vcnl4000.c +++ b/drivers/iio/light/vcnl4000.c @@ -185,14 +185,6 @@ static const int vcnl4040_ps_oversampling_ratio[] = {1, 2, 4, 8}; #define VCNL4000_SLEEP_DELAY_MS 2000 /* before we enter pm_runtime_suspend */ -enum vcnl4000_device_ids { - CM36672P, - VCNL4000, - VCNL4010, - VCNL4040, - VCNL4200, -}; - struct vcnl4200_channel { u8 reg; ktime_t last_measurement; @@ -202,7 +194,6 @@ struct vcnl4200_channel { struct vcnl4000_data { struct i2c_client *client; - enum vcnl4000_device_ids id; int rev; int al_scale; int ps_scale; @@ -237,18 +228,6 @@ struct vcnl4000_chip_spec { const int prod_id; }; -static const struct i2c_device_id vcnl4000_id[] = { - { "cm36672p", CM36672P }, - { "cm36686", VCNL4040 }, - { "vcnl4000", VCNL4000 }, - { "vcnl4010", VCNL4010 }, - { "vcnl4020", VCNL4010 }, - { "vcnl4040", VCNL4040 }, - { "vcnl4200", VCNL4200 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, vcnl4000_id); - static int vcnl4000_set_power_state(struct vcnl4000_data *data, bool on) { /* no suspend op */ @@ -1889,82 +1868,84 @@ static const struct iio_info vcnl4040_info = { .read_avail = vcnl4040_read_avail, }; -static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = { - [CM36672P] = { - .prod = "CM36672P", - .init = vcnl4200_init, - .measure_proximity = vcnl4200_measure_proximity, - .set_power_state = vcnl4200_set_power_state, - .channels = cm36672p_channels, - .num_channels = ARRAY_SIZE(cm36672p_channels), - .info = &vcnl4040_info, - .irq_thread = vcnl4040_irq_thread, - .int_reg = VCNL4040_INT_FLAGS, - .ps_it_times = &vcnl4040_ps_it_times, - .num_ps_it_times = ARRAY_SIZE(vcnl4040_ps_it_times), - .prod_id = VCNL4040_PROD_ID, - }, - [VCNL4000] = { - .prod = "VCNL4000", - .init = vcnl4000_init, - .measure_light = vcnl4000_measure_light, - .measure_proximity = vcnl4000_measure_proximity, - .set_power_state = vcnl4000_set_power_state, - .channels = vcnl4000_channels, - .num_channels = ARRAY_SIZE(vcnl4000_channels), - .info = &vcnl4000_info, - .prod_id = VCNL4000_PROD_ID, - }, - [VCNL4010] = { - .prod = "VCNL4010/4020", - .init = vcnl4000_init, - .measure_light = vcnl4000_measure_light, - .measure_proximity = vcnl4000_measure_proximity, - .set_power_state = vcnl4000_set_power_state, - .channels = vcnl4010_channels, - .num_channels = ARRAY_SIZE(vcnl4010_channels), - .info = &vcnl4010_info, - .irq_thread = vcnl4010_irq_thread, - .trig_buffer_func = vcnl4010_trigger_handler, - .buffer_setup_ops = &vcnl4010_buffer_ops, - .prod_id = VCNL4010_PROD_ID, - }, - [VCNL4040] = { - .prod = "VCNL4040", - .init = vcnl4200_init, - .measure_light = vcnl4200_measure_light, - .measure_proximity = vcnl4200_measure_proximity, - .set_power_state = vcnl4200_set_power_state, - .channels = vcnl4040_channels, - .num_channels = ARRAY_SIZE(vcnl4040_channels), - .info = &vcnl4040_info, - .irq_thread = vcnl4040_irq_thread, - .int_reg = VCNL4040_INT_FLAGS, - .ps_it_times = &vcnl4040_ps_it_times, - .num_ps_it_times = ARRAY_SIZE(vcnl4040_ps_it_times), - .als_it_times = &vcnl4040_als_it_times, - .num_als_it_times = ARRAY_SIZE(vcnl4040_als_it_times), - .ulux_step = 100000, - .prod_id = VCNL4040_PROD_ID, - }, - [VCNL4200] = { - .prod = "VCNL4200", - .init = vcnl4200_init, - .measure_light = vcnl4200_measure_light, - .measure_proximity = vcnl4200_measure_proximity, - .set_power_state = vcnl4200_set_power_state, - .channels = vcnl4040_channels, - .num_channels = ARRAY_SIZE(vcnl4000_channels), - .info = &vcnl4040_info, - .irq_thread = vcnl4040_irq_thread, - .int_reg = VCNL4200_INT_FLAGS, - .ps_it_times = &vcnl4200_ps_it_times, - .num_ps_it_times = ARRAY_SIZE(vcnl4200_ps_it_times), - .als_it_times = &vcnl4200_als_it_times, - .num_als_it_times = ARRAY_SIZE(vcnl4200_als_it_times), - .ulux_step = 24000, - .prod_id = VCNL4200_PROD_ID, - }, +static const struct vcnl4000_chip_spec cm36672p_spec = { + .prod = "CM36672P", + .init = vcnl4200_init, + .measure_proximity = vcnl4200_measure_proximity, + .set_power_state = vcnl4200_set_power_state, + .channels = cm36672p_channels, + .num_channels = ARRAY_SIZE(cm36672p_channels), + .info = &vcnl4040_info, + .irq_thread = vcnl4040_irq_thread, + .int_reg = VCNL4040_INT_FLAGS, + .ps_it_times = &vcnl4040_ps_it_times, + .num_ps_it_times = ARRAY_SIZE(vcnl4040_ps_it_times), + .prod_id = VCNL4040_PROD_ID, +}; + +static const struct vcnl4000_chip_spec vcnl4000_spec = { + .prod = "VCNL4000", + .init = vcnl4000_init, + .measure_light = vcnl4000_measure_light, + .measure_proximity = vcnl4000_measure_proximity, + .set_power_state = vcnl4000_set_power_state, + .channels = vcnl4000_channels, + .num_channels = ARRAY_SIZE(vcnl4000_channels), + .info = &vcnl4000_info, + .prod_id = VCNL4000_PROD_ID, +}; + +static const struct vcnl4000_chip_spec vcnl4010_spec = { + .prod = "VCNL4010/4020", + .init = vcnl4000_init, + .measure_light = vcnl4000_measure_light, + .measure_proximity = vcnl4000_measure_proximity, + .set_power_state = vcnl4000_set_power_state, + .channels = vcnl4010_channels, + .num_channels = ARRAY_SIZE(vcnl4010_channels), + .info = &vcnl4010_info, + .irq_thread = vcnl4010_irq_thread, + .trig_buffer_func = vcnl4010_trigger_handler, + .buffer_setup_ops = &vcnl4010_buffer_ops, + .prod_id = VCNL4010_PROD_ID, +}; + +static const struct vcnl4000_chip_spec vcnl4040_spec = { + .prod = "VCNL4040", + .init = vcnl4200_init, + .measure_light = vcnl4200_measure_light, + .measure_proximity = vcnl4200_measure_proximity, + .set_power_state = vcnl4200_set_power_state, + .channels = vcnl4040_channels, + .num_channels = ARRAY_SIZE(vcnl4040_channels), + .info = &vcnl4040_info, + .irq_thread = vcnl4040_irq_thread, + .int_reg = VCNL4040_INT_FLAGS, + .ps_it_times = &vcnl4040_ps_it_times, + .num_ps_it_times = ARRAY_SIZE(vcnl4040_ps_it_times), + .als_it_times = &vcnl4040_als_it_times, + .num_als_it_times = ARRAY_SIZE(vcnl4040_als_it_times), + .ulux_step = 100000, + .prod_id = VCNL4040_PROD_ID, +}; + +static const struct vcnl4000_chip_spec vcnl4200_spec = { + .prod = "VCNL4200", + .init = vcnl4200_init, + .measure_light = vcnl4200_measure_light, + .measure_proximity = vcnl4200_measure_proximity, + .set_power_state = vcnl4200_set_power_state, + .channels = vcnl4040_channels, + .num_channels = ARRAY_SIZE(vcnl4000_channels), + .info = &vcnl4040_info, + .irq_thread = vcnl4040_irq_thread, + .int_reg = VCNL4200_INT_FLAGS, + .ps_it_times = &vcnl4200_ps_it_times, + .num_ps_it_times = ARRAY_SIZE(vcnl4200_ps_it_times), + .als_it_times = &vcnl4200_als_it_times, + .num_als_it_times = ARRAY_SIZE(vcnl4200_als_it_times), + .ulux_step = 24000, + .prod_id = VCNL4200_PROD_ID, }; static const struct iio_trigger_ops vcnl4010_trigger_ops = { @@ -1991,7 +1972,6 @@ static int vcnl4010_probe_trigger(struct iio_dev *indio_dev) static int vcnl4000_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); const char * const regulator_names[] = { "vdd", "vio", "vled" }; struct device *dev = &client->dev; struct vcnl4000_data *data; @@ -2005,8 +1985,7 @@ static int vcnl4000_probe(struct i2c_client *client) data = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); data->client = client; - data->id = id->driver_data; - data->chip_spec = &vcnl4000_chip_spec_cfg[data->id]; + data->chip_spec = i2c_get_match_data(client); ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulator_names), regulator_names); @@ -2081,32 +2060,32 @@ static int vcnl4000_probe(struct i2c_client *client) static const struct of_device_id vcnl_4000_of_match[] = { { .compatible = "capella,cm36672p", - .data = (void *)CM36672P, + .data = &cm36672p_spec, }, /* Capella CM36686 is fully compatible with Vishay VCNL4040 */ { .compatible = "capella,cm36686", - .data = (void *)VCNL4040, + .data = &vcnl4040_spec, }, { .compatible = "vishay,vcnl4000", - .data = (void *)VCNL4000, + .data = &vcnl4000_spec, }, { .compatible = "vishay,vcnl4010", - .data = (void *)VCNL4010, + .data = &vcnl4010_spec, }, { .compatible = "vishay,vcnl4020", - .data = (void *)VCNL4010, + .data = &vcnl4010_spec, }, { .compatible = "vishay,vcnl4040", - .data = (void *)VCNL4040, + .data = &vcnl4040_spec, }, { .compatible = "vishay,vcnl4200", - .data = (void *)VCNL4200, + .data = &vcnl4200_spec, }, { } }; @@ -2148,6 +2127,18 @@ static int vcnl4000_runtime_resume(struct device *dev) static DEFINE_RUNTIME_DEV_PM_OPS(vcnl4000_pm_ops, vcnl4000_runtime_suspend, vcnl4000_runtime_resume, NULL); +static const struct i2c_device_id vcnl4000_id[] = { + { "cm36672p", (kernel_ulong_t)&cm36672p_spec }, + { "cm36686", (kernel_ulong_t)&vcnl4040_spec }, + { "vcnl4000", (kernel_ulong_t)&vcnl4000_spec }, + { "vcnl4010", (kernel_ulong_t)&vcnl4010_spec }, + { "vcnl4020", (kernel_ulong_t)&vcnl4010_spec }, + { "vcnl4040", (kernel_ulong_t)&vcnl4040_spec }, + { "vcnl4200", (kernel_ulong_t)&vcnl4200_spec }, + { } +}; +MODULE_DEVICE_TABLE(i2c, vcnl4000_id); + static struct i2c_driver vcnl4000_driver = { .driver = { .name = VCNL4000_DRV_NAME, From 8078daf88638ef0a280447ebba7ed8a496711e2e Mon Sep 17 00:00:00 2001 From: Erikas Bitovtas Date: Tue, 14 Apr 2026 15:37:19 +0300 Subject: [PATCH 052/266] iio: light: vcnl4000: move device tree entries into one line Make device tree entries one line each to save space and LOC. Signed-off-by: Erikas Bitovtas Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/light/vcnl4000.c | 35 +++++++---------------------------- 1 file changed, 7 insertions(+), 28 deletions(-) diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c index cbe0a9e056ec..52f60b372d2f 100644 --- a/drivers/iio/light/vcnl4000.c +++ b/drivers/iio/light/vcnl4000.c @@ -2058,35 +2058,14 @@ static int vcnl4000_probe(struct i2c_client *client) } static const struct of_device_id vcnl_4000_of_match[] = { - { - .compatible = "capella,cm36672p", - .data = &cm36672p_spec, - }, + { .compatible = "capella,cm36672p", .data = &cm36672p_spec }, /* Capella CM36686 is fully compatible with Vishay VCNL4040 */ - { - .compatible = "capella,cm36686", - .data = &vcnl4040_spec, - }, - { - .compatible = "vishay,vcnl4000", - .data = &vcnl4000_spec, - }, - { - .compatible = "vishay,vcnl4010", - .data = &vcnl4010_spec, - }, - { - .compatible = "vishay,vcnl4020", - .data = &vcnl4010_spec, - }, - { - .compatible = "vishay,vcnl4040", - .data = &vcnl4040_spec, - }, - { - .compatible = "vishay,vcnl4200", - .data = &vcnl4200_spec, - }, + { .compatible = "capella,cm36686", .data = &vcnl4040_spec }, + { .compatible = "vishay,vcnl4000", .data = &vcnl4000_spec }, + { .compatible = "vishay,vcnl4010", .data = &vcnl4010_spec }, + { .compatible = "vishay,vcnl4020", .data = &vcnl4010_spec }, + { .compatible = "vishay,vcnl4040", .data = &vcnl4040_spec }, + { .compatible = "vishay,vcnl4200", .data = &vcnl4200_spec }, { } }; MODULE_DEVICE_TABLE(of, vcnl_4000_of_match); From 857cb79df06b2890c2338295ab2f35e943f30d7b Mon Sep 17 00:00:00 2001 From: Erikas Bitovtas Date: Tue, 14 Apr 2026 15:37:20 +0300 Subject: [PATCH 053/266] iio: light: vcnl4000: move power state function into device-managed action Move power state setting into a device-managed action to get rid of fail_poweroff goto label and remove it from vcnl4000_remove() function. Signed-off-by: Erikas Bitovtas Signed-off-by: Jonathan Cameron --- drivers/iio/light/vcnl4000.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c index 52f60b372d2f..1e636e6f51da 100644 --- a/drivers/iio/light/vcnl4000.c +++ b/drivers/iio/light/vcnl4000.c @@ -1970,6 +1970,18 @@ static int vcnl4010_probe_trigger(struct iio_dev *indio_dev) return devm_iio_trigger_register(&client->dev, trigger); } +static void vcnl4000_cleanup(void *data) +{ + struct iio_dev *indio_dev = data; + struct vcnl4000_data *chip = iio_priv(indio_dev); + struct device *dev = &chip->client->dev; + int ret; + + ret = chip->chip_spec->set_power_state(chip, false); + if (ret) + dev_warn(dev, "Failed to power down (%pe)", ERR_PTR(ret)); +} + static int vcnl4000_probe(struct i2c_client *client) { const char * const regulator_names[] = { "vdd", "vio", "vled" }; @@ -2004,6 +2016,10 @@ static int vcnl4000_probe(struct i2c_client *client) if (ret) return ret; + ret = devm_add_action_or_reset(dev, vcnl4000_cleanup, indio_dev); + if (ret) + return ret; + dev_dbg(dev, "%s Ambient light/proximity sensor, Rev: %02x\n", data->chip_spec->prod, data->rev); @@ -2041,19 +2057,20 @@ static int vcnl4000_probe(struct i2c_client *client) ret = pm_runtime_set_active(dev); if (ret < 0) - goto fail_poweroff; + return ret; ret = iio_device_register(indio_dev); if (ret < 0) - goto fail_poweroff; + goto fail_register; pm_runtime_enable(dev); pm_runtime_set_autosuspend_delay(dev, VCNL4000_SLEEP_DELAY_MS); pm_runtime_use_autosuspend(dev); return 0; -fail_poweroff: - data->chip_spec->set_power_state(data, false); + +fail_register: + pm_runtime_set_suspended(dev); return ret; } @@ -2073,18 +2090,11 @@ MODULE_DEVICE_TABLE(of, vcnl_4000_of_match); static void vcnl4000_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); - struct vcnl4000_data *data = iio_priv(indio_dev); - int ret; pm_runtime_dont_use_autosuspend(&client->dev); pm_runtime_disable(&client->dev); iio_device_unregister(indio_dev); pm_runtime_set_suspended(&client->dev); - - ret = data->chip_spec->set_power_state(data, false); - if (ret) - dev_warn(&client->dev, "Failed to power down (%pe)\n", - ERR_PTR(ret)); } static int vcnl4000_runtime_suspend(struct device *dev) From de1839edfe36642328ed7b3fd49b948a4aca03c8 Mon Sep 17 00:00:00 2001 From: Erikas Bitovtas Date: Tue, 14 Apr 2026 15:37:21 +0300 Subject: [PATCH 054/266] iio: light: vcnl4000: make pm_runtime_enable() device-managed Replace pm_runtime_set_active() and pm_runtime_enable() with their device-managed counterpart to remove them from vcnl4000_remove(). Reviewed-by: Andy Shevchenko Signed-off-by: Erikas Bitovtas Signed-off-by: Jonathan Cameron --- drivers/iio/light/vcnl4000.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c index 1e636e6f51da..3d0287799ba5 100644 --- a/drivers/iio/light/vcnl4000.c +++ b/drivers/iio/light/vcnl4000.c @@ -2055,23 +2055,18 @@ static int vcnl4000_probe(struct i2c_client *client) return ret; } - ret = pm_runtime_set_active(dev); - if (ret < 0) + ret = devm_pm_runtime_set_active_enabled(dev); + if (ret) return ret; ret = iio_device_register(indio_dev); if (ret < 0) - goto fail_register; + return ret; - pm_runtime_enable(dev); pm_runtime_set_autosuspend_delay(dev, VCNL4000_SLEEP_DELAY_MS); pm_runtime_use_autosuspend(dev); return 0; - -fail_register: - pm_runtime_set_suspended(dev); - return ret; } static const struct of_device_id vcnl_4000_of_match[] = { @@ -2091,10 +2086,7 @@ static void vcnl4000_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); - pm_runtime_dont_use_autosuspend(&client->dev); - pm_runtime_disable(&client->dev); iio_device_unregister(indio_dev); - pm_runtime_set_suspended(&client->dev); } static int vcnl4000_runtime_suspend(struct device *dev) From de1cbc4b213d034d76164ebbfd4172ffbc5f618d Mon Sep 17 00:00:00 2001 From: Erikas Bitovtas Date: Tue, 14 Apr 2026 15:37:22 +0300 Subject: [PATCH 055/266] iio: light: vcnl4000: register an IIO device with a device-managed function Use a device-managed counterpart of iio_device_register() and remove the redundant iio_device_unregister() call in driver remove function, allowing us to remove vcnl4000_remove() function altogether. Reviewed-by: Andy Shevchenko Signed-off-by: Erikas Bitovtas Signed-off-by: Jonathan Cameron --- drivers/iio/light/vcnl4000.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c index 3d0287799ba5..c08927e34b4e 100644 --- a/drivers/iio/light/vcnl4000.c +++ b/drivers/iio/light/vcnl4000.c @@ -2059,8 +2059,8 @@ static int vcnl4000_probe(struct i2c_client *client) if (ret) return ret; - ret = iio_device_register(indio_dev); - if (ret < 0) + ret = devm_iio_device_register(dev, indio_dev); + if (ret) return ret; pm_runtime_set_autosuspend_delay(dev, VCNL4000_SLEEP_DELAY_MS); @@ -2082,13 +2082,6 @@ static const struct of_device_id vcnl_4000_of_match[] = { }; MODULE_DEVICE_TABLE(of, vcnl_4000_of_match); -static void vcnl4000_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - - iio_device_unregister(indio_dev); -} - static int vcnl4000_runtime_suspend(struct device *dev) { struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); @@ -2128,7 +2121,6 @@ static struct i2c_driver vcnl4000_driver = { }, .probe = vcnl4000_probe, .id_table = vcnl4000_id, - .remove = vcnl4000_remove, }; module_i2c_driver(vcnl4000_driver); From d4c8667bc90ea2442ca2c814c19900242cceb4e7 Mon Sep 17 00:00:00 2001 From: Archit Anant Date: Sun, 12 Apr 2026 15:07:35 +0530 Subject: [PATCH 056/266] iio: adc: ad799x: sort headers alphabetically Reorder header includes to maintain proper alphabetical ordering. No functional changes. Reviewed-by: David Lechner Signed-off-by: Archit Anant Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad799x.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c index 108bb22162ef..f37f1fda2dc4 100644 --- a/drivers/iio/adc/ad799x.c +++ b/drivers/iio/adc/ad799x.c @@ -18,23 +18,23 @@ * ad7998 and similar chips. */ -#include +#include #include -#include -#include -#include -#include -#include -#include #include +#include +#include +#include #include #include -#include +#include +#include +#include +#include +#include +#include #include #include -#include -#include #include #include From fa2d96d2896093a01115491c8e672d5694b4e23a Mon Sep 17 00:00:00 2001 From: Archit Anant Date: Sun, 12 Apr 2026 15:07:36 +0530 Subject: [PATCH 057/266] iio: adc: ad799x: use local device pointer in probe Introduce a local device pointer 'dev' in ad799x_probe() and use it throughout the function instead of accessing &client->dev repeatedly. Suggested-by: Andy Shevchenko Reviewed-by: David Lechner Signed-off-by: Archit Anant Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad799x.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c index f37f1fda2dc4..bf0575585a59 100644 --- a/drivers/iio/adc/ad799x.c +++ b/drivers/iio/adc/ad799x.c @@ -783,6 +783,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { static int ad799x_probe(struct i2c_client *client) { + struct device *dev = &client->dev; const struct i2c_device_id *id = i2c_client_get_device_id(client); int ret; int extra_config = 0; @@ -791,7 +792,7 @@ static int ad799x_probe(struct i2c_client *client) const struct ad799x_chip_info *chip_info = &ad799x_chip_info_tbl[id->driver_data]; - indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; @@ -807,7 +808,7 @@ static int ad799x_probe(struct i2c_client *client) /* TODO: Add pdata options for filtering and bit delay */ - st->reg = devm_regulator_get(&client->dev, "vcc"); + st->reg = devm_regulator_get(dev, "vcc"); if (IS_ERR(st->reg)) return PTR_ERR(st->reg); ret = regulator_enable(st->reg); @@ -816,17 +817,17 @@ static int ad799x_probe(struct i2c_client *client) /* check if an external reference is supplied */ if (chip_info->has_vref) { - st->vref = devm_regulator_get_optional(&client->dev, "vref"); + st->vref = devm_regulator_get_optional(dev, "vref"); ret = PTR_ERR_OR_ZERO(st->vref); if (ret) { if (ret != -ENODEV) goto error_disable_reg; st->vref = NULL; - dev_info(&client->dev, "Using VCC reference voltage\n"); + dev_info(dev, "Using VCC reference voltage\n"); } if (st->vref) { - dev_info(&client->dev, "Using external reference voltage\n"); + dev_info(dev, "Using external reference voltage\n"); extra_config |= AD7991_REF_SEL; ret = regulator_enable(st->vref); if (ret) @@ -853,7 +854,7 @@ static int ad799x_probe(struct i2c_client *client) goto error_disable_vref; if (client->irq > 0) { - ret = devm_request_threaded_irq(&client->dev, + ret = devm_request_threaded_irq(dev, client->irq, NULL, ad799x_event_handler, From 21450969a7e86ee46dd6c546ae639057aa403b53 Mon Sep 17 00:00:00 2001 From: Archit Anant Date: Sun, 12 Apr 2026 15:07:37 +0530 Subject: [PATCH 058/266] iio: adc: ad799x: use a static buffer for scan data Currently, rx_buf is dynamically allocated using kmalloc() every time ad799x_update_scan_mode() is called. This can lead to memory leaks if the scan mask is updated multiple times. Drop the dynamic allocation and replace it with a static buffer at the end of the state structure using IIO_DECLARE_BUFFER_WITH_TS(). This eliminates the allocation overhead, prevents leaks, and removes the need for manual kfree() on driver removal. Suggested-by: David Lechner Reviewed-by: David Lechner Signed-off-by: Archit Anant Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad799x.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c index bf0575585a59..d8389b6e19b5 100644 --- a/drivers/iio/adc/ad799x.c +++ b/drivers/iio/adc/ad799x.c @@ -39,6 +39,7 @@ #include #define AD799X_CHANNEL_SHIFT 4 +#define AD799X_MAX_CHANNELS 8 /* * AD7991, AD7995 and AD7999 defines @@ -133,8 +134,8 @@ struct ad799x_state { unsigned int id; u16 config; - u8 *rx_buf; unsigned int transfer_size; + IIO_DECLARE_BUFFER_WITH_TS(__be16, rx_buf, AD799X_MAX_CHANNELS); }; static int ad799x_write_config(struct ad799x_state *st, u16 val) @@ -217,7 +218,8 @@ static irqreturn_t ad799x_trigger_handler(int irq, void *p) } b_sent = i2c_smbus_read_i2c_block_data(st->client, - cmd, st->transfer_size, st->rx_buf); + cmd, st->transfer_size, + (u8 *)st->rx_buf); if (b_sent < 0) goto out; @@ -234,11 +236,6 @@ static int ad799x_update_scan_mode(struct iio_dev *indio_dev, { struct ad799x_state *st = iio_priv(indio_dev); - kfree(st->rx_buf); - st->rx_buf = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); - if (!st->rx_buf) - return -ENOMEM; - st->transfer_size = bitmap_weight(scan_mask, iio_get_masklength(indio_dev)) * 2; @@ -896,7 +893,6 @@ static void ad799x_remove(struct i2c_client *client) if (st->vref) regulator_disable(st->vref); regulator_disable(st->reg); - kfree(st->rx_buf); } static int ad799x_suspend(struct device *dev) From 97c3fae0dbc4bf62eac7a1798b723c258e85980d Mon Sep 17 00:00:00 2001 From: Archit Anant Date: Sun, 12 Apr 2026 15:07:38 +0530 Subject: [PATCH 059/266] iio: adc: ad799x: cache regulator voltages during probe Since the reference voltage for this ADC is not expected to change at runtime, determine the active reference voltage (either VREF or VCC) during probe() and cache it in a single variable in the state structure. Suggested-by: Jonathan Cameron Suggested-by: David Lechner Reviewed-by: David Lechner Signed-off-by: Archit Anant Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad799x.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c index d8389b6e19b5..e37bb64edd2b 100644 --- a/drivers/iio/adc/ad799x.c +++ b/drivers/iio/adc/ad799x.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -135,6 +136,9 @@ struct ad799x_state { u16 config; unsigned int transfer_size; + + int vref_uV; + IIO_DECLARE_BUFFER_WITH_TS(__be16, rx_buf, AD799X_MAX_CHANNELS); }; @@ -303,14 +307,7 @@ static int ad799x_read_raw(struct iio_dev *indio_dev, GENMASK(chan->scan_type.realbits - 1, 0); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - if (st->vref) - ret = regulator_get_voltage(st->vref); - else - ret = regulator_get_voltage(st->reg); - - if (ret < 0) - return ret; - *val = ret / 1000; + *val = st->vref_uV / (MICRO / MILLI); *val2 = chan->scan_type.realbits; return IIO_VAL_FRACTIONAL_LOG2; } @@ -829,9 +826,20 @@ static int ad799x_probe(struct i2c_client *client) ret = regulator_enable(st->vref); if (ret) goto error_disable_reg; + ret = regulator_get_voltage(st->vref); + if (ret < 0) + goto error_disable_vref; + st->vref_uV = ret; } } + if (!st->vref) { + ret = regulator_get_voltage(st->reg); + if (ret < 0) + goto error_disable_reg; + st->vref_uV = ret; + } + st->client = client; indio_dev->name = id->name; From 99d709987276632a9260dc75e36c15e61b4b5083 Mon Sep 17 00:00:00 2001 From: Archit Anant Date: Sun, 12 Apr 2026 15:07:39 +0530 Subject: [PATCH 060/266] iio: adc: ad799x: convert to fully managed resources and drop remove() Convert the driver's remaining manual resource management to use the devm_ infrastructure, allowing for the complete removal of the ad799x_remove() function and the simplification of the probe error paths. Specifically: - Initialize the mutex using devm_mutex_init() and move it to the top of probe() (before IRQ registration) to prevent a race condition where an interrupt could attempt to take an uninitialized lock. - Use devm_add_action_or_reset() to ensure that the VCC and VREF regulators are disabled safely and in the correct order during driver teardown or probe failure. - Refactor the optional VREF error handling path for better readability. - Convert iio_triggered_buffer_setup() and iio_device_register() to their devm_ variants. Because all resources are now managed by the devm core, the unwinding order is guaranteed to follow the reverse order of allocation. All manual error handling goto labels in ad799x_probe() have been removed. Suggested-by: Jonathan Cameron Suggested-by: David Lechner Suggested-by: Andy Shevchenko Reviewed-by: David Lechner Signed-off-by: Archit Anant Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad799x.c | 70 +++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 41 deletions(-) diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c index e37bb64edd2b..0ceedea5df0b 100644 --- a/drivers/iio/adc/ad799x.c +++ b/drivers/iio/adc/ad799x.c @@ -775,6 +775,11 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { }, }; +static void ad799x_reg_disable(void *reg) +{ + regulator_disable(reg); +} + static int ad799x_probe(struct i2c_client *client) { struct device *dev = &client->dev; @@ -794,6 +799,10 @@ static int ad799x_probe(struct i2c_client *client) /* this is only used for device removal purposes */ i2c_set_clientdata(client, indio_dev); + ret = devm_mutex_init(dev, &st->lock); + if (ret) + return ret; + st->id = id->driver_data; if (client->irq > 0 && chip_info->irq_config.info) st->chip_config = &chip_info->irq_config; @@ -809,15 +818,19 @@ static int ad799x_probe(struct i2c_client *client) if (ret) return ret; + ret = devm_add_action_or_reset(dev, ad799x_reg_disable, st->reg); + if (ret) + return ret; + /* check if an external reference is supplied */ if (chip_info->has_vref) { st->vref = devm_regulator_get_optional(dev, "vref"); ret = PTR_ERR_OR_ZERO(st->vref); - if (ret) { - if (ret != -ENODEV) - goto error_disable_reg; + if (ret == -ENODEV) { st->vref = NULL; dev_info(dev, "Using VCC reference voltage\n"); + } else if (ret) { + return ret; } if (st->vref) { @@ -825,10 +838,15 @@ static int ad799x_probe(struct i2c_client *client) extra_config |= AD7991_REF_SEL; ret = regulator_enable(st->vref); if (ret) - goto error_disable_reg; + return ret; + + ret = devm_add_action_or_reset(dev, ad799x_reg_disable, st->vref); + if (ret) + return ret; + ret = regulator_get_voltage(st->vref); if (ret < 0) - goto error_disable_vref; + return ret; st->vref_uV = ret; } } @@ -836,7 +854,7 @@ static int ad799x_probe(struct i2c_client *client) if (!st->vref) { ret = regulator_get_voltage(st->reg); if (ret < 0) - goto error_disable_reg; + return ret; st->vref_uV = ret; } @@ -851,12 +869,12 @@ static int ad799x_probe(struct i2c_client *client) ret = ad799x_update_config(st, st->chip_config->default_config | extra_config); if (ret) - goto error_disable_vref; + return ret; - ret = iio_triggered_buffer_setup(indio_dev, NULL, + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, &ad799x_trigger_handler, NULL); if (ret) - goto error_disable_vref; + return ret; if (client->irq > 0) { ret = devm_request_threaded_irq(dev, @@ -868,39 +886,10 @@ static int ad799x_probe(struct i2c_client *client) client->name, indio_dev); if (ret) - goto error_cleanup_ring; + return ret; } - mutex_init(&st->lock); - - ret = iio_device_register(indio_dev); - if (ret) - goto error_cleanup_ring; - - return 0; - -error_cleanup_ring: - iio_triggered_buffer_cleanup(indio_dev); -error_disable_vref: - if (st->vref) - regulator_disable(st->vref); -error_disable_reg: - regulator_disable(st->reg); - - return ret; -} - -static void ad799x_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - struct ad799x_state *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - - iio_triggered_buffer_cleanup(indio_dev); - if (st->vref) - regulator_disable(st->vref); - regulator_disable(st->reg); + return devm_iio_device_register(dev, indio_dev); } static int ad799x_suspend(struct device *dev) @@ -970,7 +959,6 @@ static struct i2c_driver ad799x_driver = { .pm = pm_sleep_ptr(&ad799x_pm_ops), }, .probe = ad799x_probe, - .remove = ad799x_remove, .id_table = ad799x_id, }; module_i2c_driver(ad799x_driver); From e0c6843248ec45c691695b04d1676c67870d6d59 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Sat, 11 Apr 2026 17:13:33 -0500 Subject: [PATCH 061/266] iio: adc: ti-ads7950: use spi_optimize_message() Use spi_optimize_message() to reduce CPU usage during buffered reads. On hardware with support for SPI_CS_WORD, this reduced the CPU usage of the threaded interrupt by about 5%. On hardware without support, this should reduce CPU usage even more since it won't have to split the SPI transfers each time the interrupt handler is called. The .update_scan_mode() callback hand to be moved to the buffer preenable callback since the SPI transfer mode can't be changed after spi_optimize_message() has been called. (The buffer postenable callback can't be used because it happens after the trigger is enabled, so the SPI message needs to be optimized before that.) The indent of the pointer to ti_ads7950_read_raw() in the assignment is changed since there is no longer anything else in the struct to align with since removal of use of the pointer to ti_ads7950_update_scan_mode(). Signed-off-by: David Lechner Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-ads7950.c | 65 ++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/drivers/iio/adc/ti-ads7950.c b/drivers/iio/adc/ti-ads7950.c index 882b280d9e0b..39a074bce6d5 100644 --- a/drivers/iio/adc/ti-ads7950.c +++ b/drivers/iio/adc/ti-ads7950.c @@ -267,31 +267,6 @@ static const struct ti_ads7950_chip_info ti_ads7961_chip_info = { .num_channels = ARRAY_SIZE(ti_ads7961_channels), }; -/* - * ti_ads7950_update_scan_mode() setup the spi transfer buffer for the new - * scan mask - */ -static int ti_ads7950_update_scan_mode(struct iio_dev *indio_dev, - const unsigned long *active_scan_mask) -{ - struct ti_ads7950_state *st = iio_priv(indio_dev); - int i, cmd, len; - - len = 0; - for_each_set_bit(i, active_scan_mask, indio_dev->num_channels) { - cmd = TI_ADS7950_MAN_CMD(TI_ADS7950_CR_CHAN(i)); - st->tx_buf[len++] = cmd; - } - - /* Data for the 1st channel is not returned until the 3rd transfer */ - st->tx_buf[len++] = 0; - st->tx_buf[len++] = 0; - - st->ring_xfer.len = len * 2; - - return 0; -} - static irqreturn_t ti_ads7950_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; @@ -375,8 +350,42 @@ static int ti_ads7950_read_raw(struct iio_dev *indio_dev, } static const struct iio_info ti_ads7950_info = { - .read_raw = &ti_ads7950_read_raw, - .update_scan_mode = ti_ads7950_update_scan_mode, + .read_raw = &ti_ads7950_read_raw, +}; + +static int ti_ads7950_buffer_preenable(struct iio_dev *indio_dev) +{ + struct ti_ads7950_state *st = iio_priv(indio_dev); + u32 len = 0; + u32 i; + u16 cmd; + + for_each_set_bit(i, indio_dev->active_scan_mask, indio_dev->num_channels) { + cmd = TI_ADS7950_MAN_CMD(TI_ADS7950_CR_CHAN(i)); + st->tx_buf[len++] = cmd; + } + + /* Data for the 1st channel is not returned until the 3rd transfer */ + st->tx_buf[len++] = 0; + st->tx_buf[len++] = 0; + + st->ring_xfer.len = len * 2; + + return spi_optimize_message(st->spi, &st->ring_msg); +} + +static int ti_ads7950_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct ti_ads7950_state *st = iio_priv(indio_dev); + + spi_unoptimize_message(&st->ring_msg); + + return 0; +} + +static const struct iio_buffer_setup_ops ti_ads7950_buffer_setup_ops = { + .preenable = ti_ads7950_buffer_preenable, + .postdisable = ti_ads7950_buffer_postdisable, }; static int ti_ads7950_set(struct gpio_chip *chip, unsigned int offset, @@ -573,7 +582,7 @@ static int ti_ads7950_probe(struct spi_device *spi) ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL, &ti_ads7950_trigger_handler, - NULL); + &ti_ads7950_buffer_setup_ops); if (ret) return dev_err_probe(&spi->dev, ret, "Failed to setup triggered buffer\n"); From 1619d52fce78b47021a2f1aa5b95f7986ab66c0f Mon Sep 17 00:00:00 2001 From: Piyush Patle Date: Sat, 11 Apr 2026 10:46:47 +0530 Subject: [PATCH 062/266] iio: dac: ad3552r: use field_get() for power-down bit read MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use field_get() for the per-channel DAC power-down bit instead of an open-coded mask-and-shift sequence. No functional change. Signed-off-by: Piyush Patle Reviewed-by: Nuno Sá Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad3552r.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/iio/dac/ad3552r.c b/drivers/iio/dac/ad3552r.c index 93c33bc3e1be..f206bba3a701 100644 --- a/drivers/iio/dac/ad3552r.c +++ b/drivers/iio/dac/ad3552r.c @@ -167,8 +167,7 @@ static int ad3552r_read_raw(struct iio_dev *indio_dev, mutex_unlock(&dac->lock); if (err < 0) return err; - *val = !((tmp_val & AD3552R_MASK_CH_DAC_POWERDOWN(ch)) >> - __ffs(AD3552R_MASK_CH_DAC_POWERDOWN(ch))); + *val = !field_get(AD3552R_MASK_CH_DAC_POWERDOWN(ch), tmp_val); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: *val = dac->ch_data[ch].scale_int; From 6cc18c0dc2886df14095b89a84d016b6d4c84fb3 Mon Sep 17 00:00:00 2001 From: Piyush Patle Date: Sat, 11 Apr 2026 03:11:25 +0530 Subject: [PATCH 063/266] iio: adc: nxp-sar-adc: use field_get() for EOC bit check Use field_get() here now that runtime-mask support exists, and drop the obsolete TODO. Since NXP_SAR_ADC_EOC_CH(c) is BIT(c), the resulting !-test is semantically identical. No functional change. Reviewed-by: David Lechner Signed-off-by: Piyush Patle Acked-by: Daniel Lezcano Signed-off-by: Jonathan Cameron --- drivers/iio/adc/nxp-sar-adc.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/iio/adc/nxp-sar-adc.c b/drivers/iio/adc/nxp-sar-adc.c index 9d9f2c76bed4..8340c041e7bc 100644 --- a/drivers/iio/adc/nxp-sar-adc.c +++ b/drivers/iio/adc/nxp-sar-adc.c @@ -317,11 +317,7 @@ static int nxp_sar_adc_read_data(struct nxp_sar_adc *info, unsigned int chan) ceocfr = readl(NXP_SAR_ADC_CEOCFR0(info->regs)); - /* - * FIELD_GET() can not be used here because EOC_CH is not constant. - * TODO: Switch to field_get() when it will be available. - */ - if (!(NXP_SAR_ADC_EOC_CH(chan) & ceocfr)) + if (!field_get(NXP_SAR_ADC_EOC_CH(chan), ceocfr)) return -EIO; cdr = readl(NXP_SAR_ADC_CDR(info->regs, chan)); From e15c8934e6ed27624e4b2ed37619074c98be52ac Mon Sep 17 00:00:00 2001 From: David Carlier Date: Fri, 10 Apr 2026 20:37:31 +0100 Subject: [PATCH 064/266] iio: dac: ad3552r: Use devm_mutex_init() Use devm_mutex_init() which is helpful with CONFIG_DEBUG_MUTEXES. Signed-off-by: David Carlier Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad3552r.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/iio/dac/ad3552r.c b/drivers/iio/dac/ad3552r.c index f206bba3a701..16db94fef9d4 100644 --- a/drivers/iio/dac/ad3552r.c +++ b/drivers/iio/dac/ad3552r.c @@ -628,7 +628,9 @@ static int ad3552r_probe(struct spi_device *spi) if (!dac->model_data) return -EINVAL; - mutex_init(&dac->lock); + err = devm_mutex_init(&spi->dev, &dac->lock); + if (err) + return err; err = ad3552r_init(dac); if (err) From de960173ae966b92ccc5426347c8d7f4db488a8e Mon Sep 17 00:00:00 2001 From: David Carlier Date: Fri, 10 Apr 2026 20:37:32 +0100 Subject: [PATCH 065/266] iio: dac: ad7303: Use devm_mutex_init() Use devm_mutex_init() which is helpful with CONFIG_DEBUG_MUTEXES. Signed-off-by: David Carlier Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad7303.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/iio/dac/ad7303.c b/drivers/iio/dac/ad7303.c index a88cc639047d..1c2960fa9743 100644 --- a/drivers/iio/dac/ad7303.c +++ b/drivers/iio/dac/ad7303.c @@ -218,7 +218,9 @@ static int ad7303_probe(struct spi_device *spi) st->spi = spi; - mutex_init(&st->lock); + ret = devm_mutex_init(&spi->dev, &st->lock); + if (ret) + return ret; st->vdd_reg = devm_regulator_get(&spi->dev, "Vdd"); if (IS_ERR(st->vdd_reg)) From b8c15f8589e6a716e5141ef87c742a542553ed65 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Fri, 10 Apr 2026 20:37:33 +0100 Subject: [PATCH 066/266] iio: dac: ad5758: Use devm_mutex_init() Use devm_mutex_init() which is helpful with CONFIG_DEBUG_MUTEXES. Signed-off-by: David Carlier Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad5758.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/iio/dac/ad5758.c b/drivers/iio/dac/ad5758.c index 4ed4fda76ea9..8e6fb46cce4d 100644 --- a/drivers/iio/dac/ad5758.c +++ b/drivers/iio/dac/ad5758.c @@ -851,7 +851,9 @@ static int ad5758_probe(struct spi_device *spi) st->spi = spi; - mutex_init(&st->lock); + ret = devm_mutex_init(&spi->dev, &st->lock); + if (ret) + return ret; indio_dev->name = spi_get_device_id(spi)->name; indio_dev->info = &ad5758_info; From e7394ce0e5bb7fe86b8f9b3ceabf197ff40287a8 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Fri, 10 Apr 2026 20:37:34 +0100 Subject: [PATCH 067/266] iio: dac: ad5755: Use devm_mutex_init() Use devm_mutex_init() which is helpful with CONFIG_DEBUG_MUTEXES. Signed-off-by: David Carlier Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad5755.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/iio/dac/ad5755.c b/drivers/iio/dac/ad5755.c index d0e5f35462b1..cc6d56140d66 100644 --- a/drivers/iio/dac/ad5755.c +++ b/drivers/iio/dac/ad5755.c @@ -827,8 +827,9 @@ static int ad5755_probe(struct spi_device *spi) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->num_channels = AD5755_NUM_CHANNELS; - mutex_init(&st->lock); - + ret = devm_mutex_init(&spi->dev, &st->lock); + if (ret) + return ret; pdata = ad5755_parse_fw(&spi->dev); if (!pdata) { From 81227f33a84db1448caab226f25f6b9e21bf18ac Mon Sep 17 00:00:00 2001 From: David Carlier Date: Fri, 10 Apr 2026 20:37:35 +0100 Subject: [PATCH 068/266] iio: dac: ad5686: Use devm_mutex_init() Use devm_mutex_init() which is helpful with CONFIG_DEBUG_MUTEXES. Signed-off-by: David Carlier Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad5686.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c index 4b18498aa074..9a384c50929b 100644 --- a/drivers/iio/dac/ad5686.c +++ b/drivers/iio/dac/ad5686.c @@ -494,7 +494,9 @@ int ad5686_probe(struct device *dev, indio_dev->channels = st->chip_info->channels; indio_dev->num_channels = st->chip_info->num_channels; - mutex_init(&st->lock); + ret = devm_mutex_init(dev, &st->lock); + if (ret) + return ret; switch (st->chip_info->regmap_type) { case AD5310_REGMAP: From be186094ee51c26bfb0e8cd6a46286e7e413abe7 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Fri, 10 Apr 2026 20:37:36 +0100 Subject: [PATCH 069/266] iio: dac: ltc2664: Use devm_mutex_init() Use devm_mutex_init() which is helpful with CONFIG_DEBUG_MUTEXES. Signed-off-by: David Carlier Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ltc2664.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/iio/dac/ltc2664.c b/drivers/iio/dac/ltc2664.c index 67f14046cf77..616806615d3d 100644 --- a/drivers/iio/dac/ltc2664.c +++ b/drivers/iio/dac/ltc2664.c @@ -675,7 +675,9 @@ static int ltc2664_probe(struct spi_device *spi) st->chip_info = chip_info; - mutex_init(&st->lock); + ret = devm_mutex_init(dev, &st->lock); + if (ret) + return ret; st->regmap = devm_regmap_init_spi(spi, <c2664_regmap_config); if (IS_ERR(st->regmap)) From 8eedc312f1a1ac69ff322e846bb5d58362017945 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Fri, 10 Apr 2026 20:37:37 +0100 Subject: [PATCH 070/266] iio: addac: ad74115: Use devm_mutex_init() Use devm_mutex_init() which is helpful with CONFIG_DEBUG_MUTEXES. Signed-off-by: David Carlier Signed-off-by: Jonathan Cameron --- drivers/iio/addac/ad74115.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/iio/addac/ad74115.c b/drivers/iio/addac/ad74115.c index f8b04d86b01f..41e0b1d334cc 100644 --- a/drivers/iio/addac/ad74115.c +++ b/drivers/iio/addac/ad74115.c @@ -1835,7 +1835,10 @@ static int ad74115_probe(struct spi_device *spi) st = iio_priv(indio_dev); st->spi = spi; - mutex_init(&st->lock); + ret = devm_mutex_init(dev, &st->lock); + if (ret) + return ret; + init_completion(&st->adc_data_completion); indio_dev->name = AD74115_NAME; From 77fb0dc77249891340160063a5c91b2225d2a1be Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Wed, 1 Apr 2026 08:58:02 -0300 Subject: [PATCH 071/266] dt-bindings: iio: adc: ad4130: Document interrupts property The Data Ready/FIFO interrupt has a special behavior that inverts the IRQ polarity when devices with FIFO support enter FIFO mode, while using normal polarity for data ready. Document the interrupts property to clarify this special behavior for users. Acked-by: Krzysztof Kozlowski Signed-off-by: Jonathan Santos Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml index d00690a8d3fb..fcc00e5cfd54 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml @@ -32,6 +32,10 @@ properties: interrupts: maxItems: 1 + description: | + Data Ready / FIFO interrupt. For devices with FIFO support, the + interrupt polarity specified here is inverted when the device enters + FIFO mode, and normal for data ready. interrupt-names: description: | From 277a2d241c089fa885f734e6cf57f30883399571 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Wed, 1 Apr 2026 08:58:12 -0300 Subject: [PATCH 072/266] dt-bindings: iio: adc: ad4130: Add new supported parts Extend binding support for AD4129-4/8, AD4130-4, and AD4131-4/8 ADC variants. Dropped a reference to driver in the binding whilst here. Acked-by: Krzysztof Kozlowski Signed-off-by: Jonathan Santos Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/adc/adi,ad4130.yaml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml index fcc00e5cfd54..cc38617bb829 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml @@ -5,19 +5,30 @@ $id: http://devicetree.org/schemas/iio/adc/adi,ad4130.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Analog Devices AD4130 ADC device driver +title: Analog Devices AD4130 family ADCs maintainers: - Cosmin Tanislav description: | - Bindings for the Analog Devices AD4130 ADC. Datasheet can be found here: + Bindings for the Analog Devices AD4130 family ADCs. + Datasheets can be found here: + https://www.analog.com/media/en/technical-documentation/data-sheets/AD4129-4.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/AD4129-8.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/AD4130-4.pdf https://www.analog.com/media/en/technical-documentation/data-sheets/AD4130-8.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/AD4131-4.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/AD4131-8.pdf properties: compatible: enum: + - adi,ad4129-4 + - adi,ad4129-8 + - adi,ad4130-4 - adi,ad4130 + - adi,ad4131-4 + - adi,ad4131-8 reg: maxItems: 1 From 1ebc22b9b32fc4319538f95bd65f9dee5a5e6c38 Mon Sep 17 00:00:00 2001 From: Guilherme Ivo Bozi Date: Sun, 5 Apr 2026 18:37:26 -0300 Subject: [PATCH 073/266] iio: adc: ad4170: use lookup table for gpio mask selection Both ad4170_gpio_direction_input() and ad4170_gpio_direction_output() duplicate the same switch statement to map a GPIO offset to its corresponding mask. Replace the switch with a static lookup table, simplifying the code and avoiding duplication. This also makes future extensions easier. No functional change intended. Signed-off-by: Guilherme Ivo Bozi Acked-by: Marcelo Schmitt Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad4170-4.c | 47 ++++++++++++-------------------------- 1 file changed, 15 insertions(+), 32 deletions(-) diff --git a/drivers/iio/adc/ad4170-4.c b/drivers/iio/adc/ad4170-4.c index 77af0e6b2c59..627cbf5a37b0 100644 --- a/drivers/iio/adc/ad4170-4.c +++ b/drivers/iio/adc/ad4170-4.c @@ -1699,34 +1699,29 @@ static int ad4170_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) return ret; } +static const unsigned long gpio_masks[] = { + AD4170_GPIO_MODE_GPIO0_MSK, + AD4170_GPIO_MODE_GPIO1_MSK, + AD4170_GPIO_MODE_GPIO2_MSK, + AD4170_GPIO_MODE_GPIO3_MSK, +}; + static int ad4170_gpio_direction_input(struct gpio_chip *gc, unsigned int offset) { struct iio_dev *indio_dev = gpiochip_get_data(gc); struct ad4170_state *st = iio_priv(indio_dev); - unsigned long gpio_mask; int ret; if (!iio_device_claim_direct(indio_dev)) return -EBUSY; - switch (offset) { - case 0: - gpio_mask = AD4170_GPIO_MODE_GPIO0_MSK; - break; - case 1: - gpio_mask = AD4170_GPIO_MODE_GPIO1_MSK; - break; - case 2: - gpio_mask = AD4170_GPIO_MODE_GPIO2_MSK; - break; - case 3: - gpio_mask = AD4170_GPIO_MODE_GPIO3_MSK; - break; - default: + if (offset >= ARRAY_SIZE(gpio_masks)) { ret = -EINVAL; goto err_release; } - ret = regmap_update_bits(st->regmap, AD4170_GPIO_MODE_REG, gpio_mask, + + ret = regmap_update_bits(st->regmap, AD4170_GPIO_MODE_REG, + gpio_masks[offset], AD4170_GPIO_MODE_GPIO_INPUT << (2 * offset)); err_release: @@ -1740,7 +1735,6 @@ static int ad4170_gpio_direction_output(struct gpio_chip *gc, { struct iio_dev *indio_dev = gpiochip_get_data(gc); struct ad4170_state *st = iio_priv(indio_dev); - unsigned long gpio_mask; int ret; ret = ad4170_gpio_set(gc, offset, value); @@ -1750,24 +1744,13 @@ static int ad4170_gpio_direction_output(struct gpio_chip *gc, if (!iio_device_claim_direct(indio_dev)) return -EBUSY; - switch (offset) { - case 0: - gpio_mask = AD4170_GPIO_MODE_GPIO0_MSK; - break; - case 1: - gpio_mask = AD4170_GPIO_MODE_GPIO1_MSK; - break; - case 2: - gpio_mask = AD4170_GPIO_MODE_GPIO2_MSK; - break; - case 3: - gpio_mask = AD4170_GPIO_MODE_GPIO3_MSK; - break; - default: + if (offset >= ARRAY_SIZE(gpio_masks)) { ret = -EINVAL; goto err_release; } - ret = regmap_update_bits(st->regmap, AD4170_GPIO_MODE_REG, gpio_mask, + + ret = regmap_update_bits(st->regmap, AD4170_GPIO_MODE_REG, + gpio_masks[offset], AD4170_GPIO_MODE_GPIO_OUTPUT << (2 * offset)); err_release: From d01d624c28e77bc592ed8e1a9e817edec5826031 Mon Sep 17 00:00:00 2001 From: Joshua Crofts Date: Tue, 21 Apr 2026 06:58:37 +0000 Subject: [PATCH 074/266] iio: magnetometer: hid-sensor-magn-3d: prefer 'u32' type Use 'u32' instead of bare 'unsigned' to resolve checkpatch.pl warnings and correct type use as defined in the struct hid_sensor_hub_callbacks. No functional change. Acked-by: Srinivas Pandruvada Reviewed-by: Andy Shevchenko Signed-off-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/hid-sensor-magn-3d.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c index c673f9323e47..b01dd53eb100 100644 --- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c +++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c @@ -280,7 +280,7 @@ static const struct iio_info magn_3d_info = { /* Callback handler to send event after all samples are received and captured */ static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev, - unsigned usage_id, + u32 usage_id, void *priv) { struct iio_dev *indio_dev = platform_get_drvdata(priv); @@ -302,7 +302,7 @@ static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev, /* Capture samples in local storage */ static int magn_3d_capture_sample(struct hid_sensor_hub_device *hsdev, - unsigned usage_id, + u32 usage_id, size_t raw_len, char *raw_data, void *priv) { @@ -350,7 +350,7 @@ static int magn_3d_parse_report(struct platform_device *pdev, struct hid_sensor_hub_device *hsdev, struct iio_chan_spec **channels, int *chan_count, - unsigned usage_id, + u32 usage_id, struct magn_3d_state *st) { int i; From ce80292ead5bb42b50a6b63e44fd95c0edf9d334 Mon Sep 17 00:00:00 2001 From: Kevin Tung Date: Mon, 20 Apr 2026 20:52:52 +0800 Subject: [PATCH 075/266] iio: adc: rtq6056: add i2c_device_id support Add i2c_device_id table to support legacy I2C instantiation. Update probe to use i2c_get_match_data() so device data can be retrieved consistently for both OF and legacy I2C instantiation. Signed-off-by: Kevin Tung Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/rtq6056.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/iio/adc/rtq6056.c b/drivers/iio/adc/rtq6056.c index 2bf3a09ac6b0..e2b1da13c0d3 100644 --- a/drivers/iio/adc/rtq6056.c +++ b/drivers/iio/adc/rtq6056.c @@ -728,7 +728,7 @@ static int rtq6056_probe(struct i2c_client *i2c) if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_WORD_DATA)) return -EOPNOTSUPP; - devdata = device_get_match_data(dev); + devdata = i2c_get_match_data(i2c); if (!devdata) return dev_err_probe(dev, -EINVAL, "Invalid dev data\n"); @@ -871,6 +871,13 @@ static const struct richtek_dev_data rtq6059_devdata = { .set_average = rtq6059_adc_set_average, }; +static const struct i2c_device_id rtq6056_id[] = { + { "rtq6056", (kernel_ulong_t)&rtq6056_devdata }, + { "rtq6059", (kernel_ulong_t)&rtq6059_devdata }, + { } +}; +MODULE_DEVICE_TABLE(i2c, rtq6056_id); + static const struct of_device_id rtq6056_device_match[] = { { .compatible = "richtek,rtq6056", .data = &rtq6056_devdata }, { .compatible = "richtek,rtq6059", .data = &rtq6059_devdata }, @@ -885,6 +892,7 @@ static struct i2c_driver rtq6056_driver = { .pm = pm_ptr(&rtq6056_pm_ops), }, .probe = rtq6056_probe, + .id_table = rtq6056_id, }; module_i2c_driver(rtq6056_driver); From 0179a95bbb8ce2fc36ba3766c7db5c7b4dd180b9 Mon Sep 17 00:00:00 2001 From: Giorgi Tchankvetadze Date: Mon, 20 Apr 2026 15:34:45 +0400 Subject: [PATCH 076/266] iio: adc: ti-ads7924: Use guard(mutex) in ADC read helper Replace mutex_lock()/mutex_unlock() pair with guard(mutex)() and move the lock into ads7924_get_adc_result(). Keeping the guard in the helper makes the locking scope match the operation being protected. Suggested-by: Jonathan Cameron Signed-off-by: Giorgi Tchankvetadze Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-ads7924.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/ti-ads7924.c b/drivers/iio/adc/ti-ads7924.c index bbcc4fc22b6e..5f294595a415 100644 --- a/drivers/iio/adc/ti-ads7924.c +++ b/drivers/iio/adc/ti-ads7924.c @@ -12,6 +12,7 @@ */ #include +#include #include #include #include @@ -198,6 +199,8 @@ static int ads7924_get_adc_result(struct ads7924_data *data, if (chan->channel < 0 || chan->channel >= ADS7924_CHANNELS) return -EINVAL; + guard(mutex)(&data->lock); + if (data->conv_invalid) { int conv_time; @@ -227,9 +230,7 @@ static int ads7924_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - mutex_lock(&data->lock); ret = ads7924_get_adc_result(data, chan, val); - mutex_unlock(&data->lock); if (ret < 0) return ret; From 2c5ebb7708274ac1e41cbd3248ed87aa3a1cee71 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Wed, 1 Apr 2026 08:58:22 -0300 Subject: [PATCH 077/266] iio: adc: ad4130: Add SPI device ID table Add SPI device ID table to enable non-device tree based device binding. The id_table provides a fallback matching mechanism when of_match_table cannot be used, which is required for proper SPI driver registration. Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Santos Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad4130.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/iio/adc/ad4130.c b/drivers/iio/adc/ad4130.c index 5567ae5dee88..d7aaf57ab87a 100644 --- a/drivers/iio/adc/ad4130.c +++ b/drivers/iio/adc/ad4130.c @@ -2109,12 +2109,19 @@ static const struct of_device_id ad4130_of_match[] = { }; MODULE_DEVICE_TABLE(of, ad4130_of_match); +static const struct spi_device_id ad4130_id_table[] = { + { "ad4130" }, + { } +}; +MODULE_DEVICE_TABLE(spi, ad4130_id_table); + static struct spi_driver ad4130_driver = { .driver = { .name = AD4130_NAME, .of_match_table = ad4130_of_match, }, .probe = ad4130_probe, + .id_table = ad4130_id_table, }; module_spi_driver(ad4130_driver); From 71c1a1b376b3a7520c8f59f81ab6a28d77938ff5 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Wed, 1 Apr 2026 08:58:34 -0300 Subject: [PATCH 078/266] iio: adc: ad4130: introduce chip info for future multidevice support Introduce a chip_info structure to abstract device-specific parameters and prepare the driver for supporting multiple AD4130 family variants. Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Santos Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad4130.c | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/drivers/iio/adc/ad4130.c b/drivers/iio/adc/ad4130.c index d7aaf57ab87a..b064744e8da8 100644 --- a/drivers/iio/adc/ad4130.c +++ b/drivers/iio/adc/ad4130.c @@ -224,6 +224,14 @@ enum ad4130_pin_function { AD4130_PIN_FN_VBIAS = BIT(3), }; +struct ad4130_chip_info { + const char *name; + unsigned int max_analog_pins; + const struct iio_info *info; + const unsigned int *reg_size; + const unsigned int reg_size_length; +}; + /* * If you make adaptations in this struct, you most likely also have to adapt * ad4130_setup_info_eq(), too. @@ -268,6 +276,7 @@ struct ad4130_state { struct regmap *regmap; struct spi_device *spi; struct clk *mclk; + const struct ad4130_chip_info *chip_info; struct regulator_bulk_data regulators[4]; u32 irq_trigger; u32 inv_irq_trigger; @@ -394,10 +403,10 @@ static const char * const ad4130_filter_types_str[] = { static int ad4130_get_reg_size(struct ad4130_state *st, unsigned int reg, unsigned int *size) { - if (reg >= ARRAY_SIZE(ad4130_reg_size)) + if (reg >= st->chip_info->reg_size_length) return -EINVAL; - *size = ad4130_reg_size[reg]; + *size = st->chip_info->reg_size[reg]; return 0; } @@ -1291,6 +1300,14 @@ static const struct iio_info ad4130_info = { .debugfs_reg_access = ad4130_reg_access, }; +static const struct ad4130_chip_info ad4130_8_chip_info = { + .name = "ad4130-8", + .max_analog_pins = 16, + .info = &ad4130_info, + .reg_size = ad4130_reg_size, + .reg_size_length = ARRAY_SIZE(ad4130_reg_size), +}; + static int ad4130_buffer_postenable(struct iio_dev *indio_dev) { struct ad4130_state *st = iio_priv(indio_dev); @@ -1504,7 +1521,7 @@ static int ad4130_validate_diff_channel(struct ad4130_state *st, u32 pin) return dev_err_probe(dev, -EINVAL, "Invalid differential channel %u\n", pin); - if (pin >= AD4130_MAX_ANALOG_PINS) + if (pin >= st->chip_info->max_analog_pins) return 0; if (st->pins_fn[pin] == AD4130_PIN_FN_SPECIAL) @@ -1536,7 +1553,7 @@ static int ad4130_validate_excitation_pin(struct ad4130_state *st, u32 pin) { struct device *dev = &st->spi->dev; - if (pin >= AD4130_MAX_ANALOG_PINS) + if (pin >= st->chip_info->max_analog_pins) return dev_err_probe(dev, -EINVAL, "Invalid excitation pin %u\n", pin); @@ -1554,7 +1571,7 @@ static int ad4130_validate_vbias_pin(struct ad4130_state *st, u32 pin) { struct device *dev = &st->spi->dev; - if (pin >= AD4130_MAX_ANALOG_PINS) + if (pin >= st->chip_info->max_analog_pins) return dev_err_probe(dev, -EINVAL, "Invalid vbias pin %u\n", pin); @@ -1730,7 +1747,7 @@ static int ad4310_parse_fw(struct iio_dev *indio_dev) ret = device_property_count_u32(dev, "adi,vbias-pins"); if (ret > 0) { - if (ret > AD4130_MAX_ANALOG_PINS) + if (ret > st->chip_info->max_analog_pins) return dev_err_probe(dev, -EINVAL, "Too many vbias pins %u\n", ret); @@ -1994,6 +2011,8 @@ static int ad4130_probe(struct spi_device *spi) st = iio_priv(indio_dev); + st->chip_info = device_get_match_data(dev); + memset(st->reset_buf, 0xff, sizeof(st->reset_buf)); init_completion(&st->completion); mutex_init(&st->lock); @@ -2011,9 +2030,9 @@ static int ad4130_probe(struct spi_device *spi) spi_message_init_with_transfers(&st->fifo_msg, st->fifo_xfer, ARRAY_SIZE(st->fifo_xfer)); - indio_dev->name = AD4130_NAME; + indio_dev->name = st->chip_info->name; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->info = &ad4130_info; + indio_dev->info = st->chip_info->info; st->regmap = devm_regmap_init(dev, NULL, st, &ad4130_regmap_config); if (IS_ERR(st->regmap)) @@ -2056,7 +2075,7 @@ static int ad4130_probe(struct spi_device *spi) ad4130_fill_scale_tbls(st); st->gc.owner = THIS_MODULE; - st->gc.label = AD4130_NAME; + st->gc.label = st->chip_info->name; st->gc.base = -1; st->gc.ngpio = AD4130_MAX_GPIOS; st->gc.parent = dev; @@ -2104,13 +2123,14 @@ static int ad4130_probe(struct spi_device *spi) static const struct of_device_id ad4130_of_match[] = { { .compatible = "adi,ad4130", + .data = &ad4130_8_chip_info }, { } }; MODULE_DEVICE_TABLE(of, ad4130_of_match); static const struct spi_device_id ad4130_id_table[] = { - { "ad4130" }, + { "ad4130", (kernel_ulong_t)&ad4130_8_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad4130_id_table); From ec98c3b501573fa6649b228b4881cde33f0ae6de Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Wed, 1 Apr 2026 08:58:50 -0300 Subject: [PATCH 079/266] iio: adc: ad4130: add new supported parts Add support for AD4129-4/8, AD4130-4, and AD4131-4/8 variants. The AD4129 series supports the same FIFO interface as the AD4130 but with reduced resolution (16-bit). The AD4131 series lacks FIFO support, so triggered buffer functionality is introduced. The 4-channel variants feature fewer analog inputs, GPIOs, and sparse pin mappings for VBIAS, analog inputs, and excitation currents. The driver now handles these differences with chip-specific configurations, including pin mappings and GPIO counts. Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Santos Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad4130.c | 452 ++++++++++++++++++++++++++++++++------- 1 file changed, 376 insertions(+), 76 deletions(-) diff --git a/drivers/iio/adc/ad4130.c b/drivers/iio/adc/ad4130.c index b064744e8da8..7f39f3484062 100644 --- a/drivers/iio/adc/ad4130.c +++ b/drivers/iio/adc/ad4130.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,7 @@ #include #include #include +#include #include #include @@ -30,6 +32,9 @@ #include #include #include +#include +#include +#include #define AD4130_NAME "ad4130" @@ -40,6 +45,7 @@ #define AD4130_ADC_CONTROL_REG 0x01 #define AD4130_ADC_CONTROL_BIPOLAR_MASK BIT(14) #define AD4130_ADC_CONTROL_INT_REF_VAL_MASK BIT(13) +#define AD4130_ADC_CONTROL_CONT_READ_MASK BIT(11) #define AD4130_INT_REF_2_5V 2500000 #define AD4130_INT_REF_1_25V 1250000 #define AD4130_ADC_CONTROL_CSB_EN_MASK BIT(9) @@ -54,7 +60,9 @@ #define AD4130_IO_CONTROL_REG 0x03 #define AD4130_IO_CONTROL_INT_PIN_SEL_MASK GENMASK(9, 8) #define AD4130_IO_CONTROL_GPIO_DATA_MASK GENMASK(7, 4) +#define AD4130_4_IO_CONTROL_GPIO_DATA_MASK GENMASK(7, 6) #define AD4130_IO_CONTROL_GPIO_CTRL_MASK GENMASK(3, 0) +#define AD4130_4_IO_CONTROL_GPIO_CTRL_MASK GENMASK(3, 2) #define AD4130_VBIAS_REG 0x04 @@ -125,6 +133,28 @@ #define AD4130_INVALID_SLOT -1 +static const unsigned int ad4129_reg_size[] = { + [AD4130_STATUS_REG] = 1, + [AD4130_ADC_CONTROL_REG] = 2, + [AD4130_DATA_REG] = 2, + [AD4130_IO_CONTROL_REG] = 2, + [AD4130_VBIAS_REG] = 2, + [AD4130_ID_REG] = 1, + [AD4130_ERROR_REG] = 2, + [AD4130_ERROR_EN_REG] = 2, + [AD4130_MCLK_COUNT_REG] = 1, + [AD4130_CHANNEL_X_REG(0) ... AD4130_CHANNEL_X_REG(AD4130_MAX_CHANNELS - 1)] = 3, + [AD4130_CONFIG_X_REG(0) ... AD4130_CONFIG_X_REG(AD4130_MAX_SETUPS - 1)] = 2, + [AD4130_FILTER_X_REG(0) ... AD4130_FILTER_X_REG(AD4130_MAX_SETUPS - 1)] = 3, + [AD4130_OFFSET_X_REG(0) ... AD4130_OFFSET_X_REG(AD4130_MAX_SETUPS - 1)] = 2, + [AD4130_GAIN_X_REG(0) ... AD4130_GAIN_X_REG(AD4130_MAX_SETUPS - 1)] = 2, + [AD4130_MISC_REG] = 2, + [AD4130_FIFO_CONTROL_REG] = 3, + [AD4130_FIFO_STATUS_REG] = 1, + [AD4130_FIFO_THRESHOLD_REG] = 3, + [AD4130_FIFO_DATA_REG] = 2, +}; + static const unsigned int ad4130_reg_size[] = { [AD4130_STATUS_REG] = 1, [AD4130_ADC_CONTROL_REG] = 2, @@ -147,6 +177,24 @@ static const unsigned int ad4130_reg_size[] = { [AD4130_FIFO_DATA_REG] = 3, }; +static const unsigned int ad4131_reg_size[] = { + [AD4130_STATUS_REG] = 1, + [AD4130_ADC_CONTROL_REG] = 2, + [AD4130_DATA_REG] = 2, + [AD4130_IO_CONTROL_REG] = 2, + [AD4130_VBIAS_REG] = 2, + [AD4130_ID_REG] = 1, + [AD4130_ERROR_REG] = 2, + [AD4130_ERROR_EN_REG] = 2, + [AD4130_MCLK_COUNT_REG] = 1, + [AD4130_CHANNEL_X_REG(0) ... AD4130_CHANNEL_X_REG(AD4130_MAX_CHANNELS - 1)] = 3, + [AD4130_CONFIG_X_REG(0) ... AD4130_CONFIG_X_REG(AD4130_MAX_SETUPS - 1)] = 2, + [AD4130_FILTER_X_REG(0) ... AD4130_FILTER_X_REG(AD4130_MAX_SETUPS - 1)] = 3, + [AD4130_OFFSET_X_REG(0) ... AD4130_OFFSET_X_REG(AD4130_MAX_SETUPS - 1)] = 2, + [AD4130_GAIN_X_REG(0) ... AD4130_GAIN_X_REG(AD4130_MAX_SETUPS - 1)] = 2, + [AD4130_MISC_REG] = 2, +}; + enum ad4130_int_ref_val { AD4130_INT_REF_VAL_2_5V, AD4130_INT_REF_VAL_1_25V, @@ -224,12 +272,26 @@ enum ad4130_pin_function { AD4130_PIN_FN_VBIAS = BIT(3), }; +/* Pin mapping for AIN0..AIN7, VBIAS_0..VBIAS_7 */ +static const u8 ad4130_4_pin_map[] = { + 0x00, 0x01, 0x04, 0x05, 0x0A, 0x0B, 0x0E, 0x0F, /* 0 - 7 */ +}; + +/* Pin mapping for AIN0..AIN15, VBIAS_0..VBIAS_15 */ +static const u8 ad4130_8_pin_map[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0 - 7 */ + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* 8 - 15 */ +}; + struct ad4130_chip_info { const char *name; unsigned int max_analog_pins; + unsigned int num_gpios; const struct iio_info *info; const unsigned int *reg_size; const unsigned int reg_size_length; + const u8 *pin_map; + bool has_fifo; }; /* @@ -303,6 +365,7 @@ struct ad4130_state { u32 mclk_sel; bool int_ref_en; bool bipolar; + bool buffer_wait_for_irq; unsigned int num_enabled_channels; unsigned int effective_watermark; @@ -310,6 +373,7 @@ struct ad4130_state { struct spi_message fifo_msg; struct spi_transfer fifo_xfer[2]; + struct iio_trigger *trig; /* * DMA (thus cache coherency maintenance) requires any transfer @@ -321,9 +385,13 @@ struct ad4130_state { u8 reg_write_tx_buf[4]; u8 reg_read_tx_buf[1]; u8 reg_read_rx_buf[3]; - u8 fifo_tx_buf[2]; - u8 fifo_rx_buf[AD4130_FIFO_SIZE * - AD4130_FIFO_MAX_SAMPLE_SIZE]; + union { + struct { + u8 fifo_tx_buf[2]; + u8 fifo_rx_buf[AD4130_FIFO_SIZE * AD4130_FIFO_MAX_SAMPLE_SIZE]; + }; + IIO_DECLARE_BUFFER_WITH_TS(u32, scan_channels, AD4130_MAX_CHANNELS); + }; }; static const char * const ad4130_int_pin_names[] = { @@ -514,7 +582,8 @@ static int ad4130_gpio_init_valid_mask(struct gpio_chip *gc, /* * Output-only GPIO functionality is available on pins AIN2 through - * AIN5. If these pins are used for anything else, do not expose them. + * AIN5 for some parts and AIN2 through AIN3 for others. If these pins + * are used for anything else, do not expose them. */ for (i = 0; i < ngpios; i++) { unsigned int pin = i + AD4130_AIN2_P1; @@ -535,8 +604,14 @@ static int ad4130_gpio_set(struct gpio_chip *gc, unsigned int offset, int value) { struct ad4130_state *st = gpiochip_get_data(gc); - unsigned int mask = FIELD_PREP(AD4130_IO_CONTROL_GPIO_DATA_MASK, - BIT(offset)); + unsigned int mask; + + if (st->chip_info->num_gpios == AD4130_MAX_GPIOS) + mask = FIELD_PREP(AD4130_IO_CONTROL_GPIO_DATA_MASK, + BIT(offset)); + else + mask = FIELD_PREP(AD4130_4_IO_CONTROL_GPIO_DATA_MASK, + BIT(offset)); return regmap_update_bits(st->regmap, AD4130_IO_CONTROL_REG, mask, value ? mask : 0); @@ -597,10 +672,43 @@ static irqreturn_t ad4130_irq_handler(int irq, void *private) struct iio_dev *indio_dev = private; struct ad4130_state *st = iio_priv(indio_dev); - if (iio_buffer_enabled(indio_dev)) - ad4130_push_fifo_data(indio_dev); - else + if (iio_buffer_enabled(indio_dev)) { + if (st->chip_info->has_fifo) + ad4130_push_fifo_data(indio_dev); + else if (st->buffer_wait_for_irq) + complete(&st->completion); + else + iio_trigger_poll(st->trig); + } else { complete(&st->completion); + } + + return IRQ_HANDLED; +} + +static irqreturn_t ad4130_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct ad4130_state *st = iio_priv(indio_dev); + unsigned int data_reg_size = ad4130_data_reg_size(st); + struct spi_transfer xfer = { }; + unsigned int num_en_chn; + int ret; + + num_en_chn = bitmap_weight(indio_dev->active_scan_mask, + iio_get_masklength(indio_dev)); + xfer.rx_buf = st->scan_channels; + xfer.len = data_reg_size * num_en_chn; + ret = spi_sync_transfer(st->spi, &xfer, 1); + if (ret < 0) + goto err_out; + + iio_push_to_buffers_with_timestamp(indio_dev, &st->scan_channels, + iio_get_time_ns(indio_dev)); + +err_out: + iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; } @@ -1300,12 +1408,77 @@ static const struct iio_info ad4130_info = { .debugfs_reg_access = ad4130_reg_access, }; -static const struct ad4130_chip_info ad4130_8_chip_info = { - .name = "ad4130-8", +static const struct iio_info ad4131_info = { + .read_raw = ad4130_read_raw, + .read_avail = ad4130_read_avail, + .write_raw_get_fmt = ad4130_write_raw_get_fmt, + .write_raw = ad4130_write_raw, + .update_scan_mode = ad4130_update_scan_mode, + .debugfs_reg_access = ad4130_reg_access, +}; + +static const struct ad4130_chip_info ad4129_4_chip_info = { + .name = "ad4129-4", + .max_analog_pins = 8, + .num_gpios = 2, + .info = &ad4130_info, + .reg_size = ad4129_reg_size, + .reg_size_length = ARRAY_SIZE(ad4129_reg_size), + .has_fifo = true, + .pin_map = ad4130_4_pin_map, +}; + +static const struct ad4130_chip_info ad4129_8_chip_info = { + .name = "ad4129-8", .max_analog_pins = 16, + .num_gpios = 4, + .info = &ad4130_info, + .reg_size = ad4129_reg_size, + .reg_size_length = ARRAY_SIZE(ad4129_reg_size), + .has_fifo = true, + .pin_map = ad4130_8_pin_map, +}; + +static const struct ad4130_chip_info ad4130_4_chip_info = { + .name = "ad4130-4", + .max_analog_pins = 16, + .num_gpios = 2, .info = &ad4130_info, .reg_size = ad4130_reg_size, .reg_size_length = ARRAY_SIZE(ad4130_reg_size), + .has_fifo = true, + .pin_map = ad4130_4_pin_map, +}; + +static const struct ad4130_chip_info ad4130_8_chip_info = { + .name = "ad4130-8", + .max_analog_pins = 16, + .num_gpios = 4, + .info = &ad4130_info, + .reg_size = ad4130_reg_size, + .reg_size_length = ARRAY_SIZE(ad4130_reg_size), + .has_fifo = true, + .pin_map = ad4130_8_pin_map, +}; + +static const struct ad4130_chip_info ad4131_4_chip_info = { + .name = "ad4131-4", + .max_analog_pins = 8, + .num_gpios = 2, + .info = &ad4131_info, + .reg_size = ad4131_reg_size, + .reg_size_length = ARRAY_SIZE(ad4131_reg_size), + .pin_map = ad4130_4_pin_map, +}; + +static const struct ad4130_chip_info ad4131_8_chip_info = { + .name = "ad4131-8", + .max_analog_pins = 16, + .num_gpios = 4, + .info = &ad4131_info, + .reg_size = ad4131_reg_size, + .reg_size_length = ARRAY_SIZE(ad4131_reg_size), + .pin_map = ad4130_8_pin_map, }; static int ad4130_buffer_postenable(struct iio_dev *indio_dev) @@ -1315,44 +1488,89 @@ static int ad4130_buffer_postenable(struct iio_dev *indio_dev) guard(mutex)(&st->lock); - ret = ad4130_set_watermark_interrupt_en(st, true); + if (st->chip_info->has_fifo) { + ret = ad4130_set_watermark_interrupt_en(st, true); + if (ret) + return ret; + + ret = irq_set_irq_type(st->spi->irq, st->inv_irq_trigger); + if (ret) + return ret; + + ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_WM); + if (ret) + return ret; + } + + ret = ad4130_set_mode(st, AD4130_MODE_CONTINUOUS); if (ret) return ret; - ret = irq_set_irq_type(st->spi->irq, st->inv_irq_trigger); - if (ret) - return ret; + /* + * When using triggered buffer, Entering continuous read mode must + * be the last command sent. No configuration changes are allowed until + * exiting this mode. + */ + if (!st->chip_info->has_fifo) { + ret = regmap_update_bits(st->regmap, AD4130_ADC_CONTROL_REG, + AD4130_ADC_CONTROL_CONT_READ_MASK, + FIELD_PREP(AD4130_ADC_CONTROL_CONT_READ_MASK, 1)); + if (ret) + return ret; + } - ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_WM); - if (ret) - return ret; - - return ad4130_set_mode(st, AD4130_MODE_CONTINUOUS); + return 0; } static int ad4130_buffer_predisable(struct iio_dev *indio_dev) { struct ad4130_state *st = iio_priv(indio_dev); unsigned int i; + u32 temp; int ret; guard(mutex)(&st->lock); + if (!st->chip_info->has_fifo) { + temp = 0x42; + reinit_completion(&st->completion); + + /* + * In continuous read mode, when all samples are read, the data + * ready signal returns high until the next conversion result is + * ready. To exit this mode, the command must be sent when data + * ready is low. In order to ensure that condition, wait for the + * next interrupt (when the new conversion is finished), allowing + * data ready to return low before sending the exit command. + */ + st->buffer_wait_for_irq = true; + if (!wait_for_completion_timeout(&st->completion, msecs_to_jiffies(1000))) + dev_warn(&st->spi->dev, "Conversion timed out\n"); + st->buffer_wait_for_irq = false; + + /* Perform a read data command to exit continuous read mode (0x42) */ + ret = spi_write(st->spi, &temp, 1); + if (ret) + return ret; + } + ret = ad4130_set_mode(st, AD4130_MODE_IDLE); if (ret) return ret; - ret = irq_set_irq_type(st->spi->irq, st->irq_trigger); - if (ret) - return ret; + if (st->chip_info->has_fifo) { + ret = irq_set_irq_type(st->spi->irq, st->irq_trigger); + if (ret) + return ret; - ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_DISABLED); - if (ret) - return ret; + ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_DISABLED); + if (ret) + return ret; - ret = ad4130_set_watermark_interrupt_en(st, false); - if (ret) - return ret; + ret = ad4130_set_watermark_interrupt_en(st, false); + if (ret) + return ret; + } /* * update_scan_mode() is not called in the disable path, disable all @@ -1427,6 +1645,34 @@ static const struct iio_dev_attr *ad4130_fifo_attributes[] = { NULL }; +static const struct iio_trigger_ops ad4130_trigger_ops = { + .validate_device = iio_trigger_validate_own_device, +}; + +static int ad4130_triggered_buffer_setup(struct iio_dev *indio_dev) +{ + struct ad4130_state *st = iio_priv(indio_dev); + int ret; + + st->trig = devm_iio_trigger_alloc(indio_dev->dev.parent, "%s-dev%d", + indio_dev->name, iio_device_id(indio_dev)); + if (!st->trig) + return -ENOMEM; + + st->trig->ops = &ad4130_trigger_ops; + iio_trigger_set_drvdata(st->trig, indio_dev); + ret = devm_iio_trigger_register(indio_dev->dev.parent, st->trig); + if (ret) + return ret; + + indio_dev->trig = iio_trigger_get(st->trig); + + return devm_iio_triggered_buffer_setup(indio_dev->dev.parent, indio_dev, + &iio_pollfunc_store_time, + &ad4130_trigger_handler, + &ad4130_buffer_ops); +} + static int _ad4130_find_table_index(const unsigned int *tbl, size_t len, unsigned int val) { @@ -1513,6 +1759,17 @@ static int ad4130_parse_fw_setup(struct ad4130_state *st, return 0; } +static unsigned int ad4130_translate_pin(struct ad4130_state *st, + unsigned int logical_pin) +{ + /* For analog input pins, use the chip-specific pin mapping */ + if (logical_pin < st->chip_info->max_analog_pins) + return st->chip_info->pin_map[logical_pin]; + + /* For internal channels, pass through unchanged */ + return logical_pin; +} + static int ad4130_validate_diff_channel(struct ad4130_state *st, u32 pin) { struct device *dev = &st->spi->dev; @@ -1931,9 +2188,14 @@ static int ad4130_setup(struct iio_dev *indio_dev) * function of P2 takes priority over the GPIO out function. */ val = 0; - for (i = 0; i < AD4130_MAX_GPIOS; i++) - if (st->pins_fn[i + AD4130_AIN2_P1] == AD4130_PIN_FN_NONE) - val |= FIELD_PREP(AD4130_IO_CONTROL_GPIO_CTRL_MASK, BIT(i)); + for (i = 0; i < st->chip_info->num_gpios; i++) { + if (st->pins_fn[i + AD4130_AIN2_P1] == AD4130_PIN_FN_NONE) { + if (st->chip_info->num_gpios == 2) + val |= FIELD_PREP(AD4130_4_IO_CONTROL_GPIO_CTRL_MASK, BIT(i)); + else + val |= FIELD_PREP(AD4130_IO_CONTROL_GPIO_CTRL_MASK, BIT(i)); + } + } val |= FIELD_PREP(AD4130_IO_CONTROL_INT_PIN_SEL_MASK, st->int_pin_sel); @@ -1943,21 +2205,23 @@ static int ad4130_setup(struct iio_dev *indio_dev) val = 0; for (i = 0; i < st->num_vbias_pins; i++) - val |= BIT(st->vbias_pins[i]); + val |= BIT(ad4130_translate_pin(st, st->vbias_pins[i])); ret = regmap_write(st->regmap, AD4130_VBIAS_REG, val); if (ret) return ret; - ret = regmap_clear_bits(st->regmap, AD4130_FIFO_CONTROL_REG, - AD4130_FIFO_CONTROL_HEADER_MASK); - if (ret) - return ret; + if (st->chip_info->has_fifo) { + ret = regmap_clear_bits(st->regmap, AD4130_FIFO_CONTROL_REG, + AD4130_FIFO_CONTROL_HEADER_MASK); + if (ret) + return ret; - /* FIFO watermark interrupt starts out as enabled, disable it. */ - ret = ad4130_set_watermark_interrupt_en(st, false); - if (ret) - return ret; + /* FIFO watermark interrupt starts out as enabled, disable it. */ + ret = ad4130_set_watermark_interrupt_en(st, false); + if (ret) + return ret; + } /* Setup channels. */ for (i = 0; i < indio_dev->num_channels; i++) { @@ -1965,10 +2229,14 @@ static int ad4130_setup(struct iio_dev *indio_dev) struct iio_chan_spec *chan = &st->chans[i]; unsigned int val; - val = FIELD_PREP(AD4130_CHANNEL_AINP_MASK, chan->channel) | - FIELD_PREP(AD4130_CHANNEL_AINM_MASK, chan->channel2) | - FIELD_PREP(AD4130_CHANNEL_IOUT1_MASK, chan_info->iout0) | - FIELD_PREP(AD4130_CHANNEL_IOUT2_MASK, chan_info->iout1); + val = FIELD_PREP(AD4130_CHANNEL_AINP_MASK, + ad4130_translate_pin(st, chan->channel)) | + FIELD_PREP(AD4130_CHANNEL_AINM_MASK, + ad4130_translate_pin(st, chan->channel2)) | + FIELD_PREP(AD4130_CHANNEL_IOUT1_MASK, + ad4130_translate_pin(st, chan_info->iout0)) | + FIELD_PREP(AD4130_CHANNEL_IOUT2_MASK, + ad4130_translate_pin(st, chan_info->iout1)); ret = regmap_write(st->regmap, AD4130_CHANNEL_X_REG(i), val); if (ret) @@ -2018,17 +2286,19 @@ static int ad4130_probe(struct spi_device *spi) mutex_init(&st->lock); st->spi = spi; - /* - * Xfer: [ XFR1 ] [ XFR2 ] - * Master: 0x7D N ...................... - * Slave: ...... DATA1 DATA2 ... DATAN - */ - st->fifo_tx_buf[0] = AD4130_COMMS_READ_MASK | AD4130_FIFO_DATA_REG; - st->fifo_xfer[0].tx_buf = st->fifo_tx_buf; - st->fifo_xfer[0].len = sizeof(st->fifo_tx_buf); - st->fifo_xfer[1].rx_buf = st->fifo_rx_buf; - spi_message_init_with_transfers(&st->fifo_msg, st->fifo_xfer, - ARRAY_SIZE(st->fifo_xfer)); + if (st->chip_info->has_fifo) { + /* + * Xfer: [ XFR1 ] [ XFR2 ] + * Master: 0x7D N ...................... + * Slave: ...... DATA1 DATA2 ... DATAN + */ + st->fifo_tx_buf[0] = AD4130_COMMS_READ_MASK | AD4130_FIFO_DATA_REG; + st->fifo_xfer[0].tx_buf = st->fifo_tx_buf; + st->fifo_xfer[0].len = sizeof(st->fifo_tx_buf); + st->fifo_xfer[1].rx_buf = st->fifo_rx_buf; + spi_message_init_with_transfers(&st->fifo_msg, st->fifo_xfer, + ARRAY_SIZE(st->fifo_xfer)); + } indio_dev->name = st->chip_info->name; indio_dev->modes = INDIO_DIRECT_MODE; @@ -2077,7 +2347,7 @@ static int ad4130_probe(struct spi_device *spi) st->gc.owner = THIS_MODULE; st->gc.label = st->chip_info->name; st->gc.base = -1; - st->gc.ngpio = AD4130_MAX_GPIOS; + st->gc.ngpio = st->chip_info->num_gpios; st->gc.parent = dev; st->gc.can_sleep = true; st->gc.init_valid_mask = ad4130_gpio_init_valid_mask; @@ -2088,9 +2358,12 @@ static int ad4130_probe(struct spi_device *spi) if (ret) return ret; - ret = devm_iio_kfifo_buffer_setup_ext(dev, indio_dev, - &ad4130_buffer_ops, - ad4130_fifo_attributes); + if (st->chip_info->has_fifo) + ret = devm_iio_kfifo_buffer_setup_ext(dev, indio_dev, + &ad4130_buffer_ops, + ad4130_fifo_attributes); + else + ret = ad4130_triggered_buffer_setup(indio_dev); if (ret) return ret; @@ -2100,37 +2373,64 @@ static int ad4130_probe(struct spi_device *spi) if (ret) return dev_err_probe(dev, ret, "Failed to request irq\n"); - /* - * When the chip enters FIFO mode, IRQ polarity is inverted. - * When the chip exits FIFO mode, IRQ polarity returns to normal. - * See datasheet pages: 65, FIFO Watermark Interrupt section, - * and 71, Bit Descriptions for STATUS Register, RDYB. - * Cache the normal and inverted IRQ triggers to set them when - * entering and exiting FIFO mode. - */ - st->irq_trigger = irq_get_trigger_type(spi->irq); - if (st->irq_trigger & IRQF_TRIGGER_RISING) - st->inv_irq_trigger = IRQF_TRIGGER_FALLING; - else if (st->irq_trigger & IRQF_TRIGGER_FALLING) - st->inv_irq_trigger = IRQF_TRIGGER_RISING; - else - return dev_err_probe(dev, -EINVAL, "Invalid irq flags: %u\n", - st->irq_trigger); + if (st->chip_info->has_fifo) { + /* + * When the chip enters FIFO mode, IRQ polarity is inverted. + * When the chip exits FIFO mode, IRQ polarity returns to normal. + * See datasheet pages: 65, FIFO Watermark Interrupt section, + * and 71, Bit Descriptions for STATUS Register, RDYB. + * Cache the normal and inverted IRQ triggers to set them when + * entering and exiting FIFO mode. + */ + st->irq_trigger = irq_get_trigger_type(spi->irq); + if (st->irq_trigger & IRQF_TRIGGER_RISING) + st->inv_irq_trigger = IRQF_TRIGGER_FALLING; + else if (st->irq_trigger & IRQF_TRIGGER_FALLING) + st->inv_irq_trigger = IRQF_TRIGGER_RISING; + else + return dev_err_probe(dev, -EINVAL, "Invalid irq flags: %u\n", + st->irq_trigger); + } return devm_iio_device_register(dev, indio_dev); } static const struct of_device_id ad4130_of_match[] = { + { + .compatible = "adi,ad4129-4", + .data = &ad4129_4_chip_info + }, + { + .compatible = "adi,ad4129-8", + .data = &ad4129_8_chip_info + }, + { + .compatible = "adi,ad4130-4", + .data = &ad4130_4_chip_info + }, { .compatible = "adi,ad4130", .data = &ad4130_8_chip_info }, + { + .compatible = "adi,ad4131-4", + .data = &ad4131_4_chip_info + }, + { + .compatible = "adi,ad4131-8", + .data = &ad4131_8_chip_info + }, { } }; MODULE_DEVICE_TABLE(of, ad4130_of_match); static const struct spi_device_id ad4130_id_table[] = { + { "ad4129-4", (kernel_ulong_t)&ad4129_4_chip_info }, + { "ad4129-8", (kernel_ulong_t)&ad4129_8_chip_info }, + { "ad4130-4", (kernel_ulong_t)&ad4130_4_chip_info }, { "ad4130", (kernel_ulong_t)&ad4130_8_chip_info }, + { "ad4131-4", (kernel_ulong_t)&ad4131_4_chip_info }, + { "ad4131-8", (kernel_ulong_t)&ad4131_8_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad4130_id_table); From af6dd359cd9682bff5cdd087d0982a153937b9c9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 23 Apr 2026 19:35:46 +0200 Subject: [PATCH 080/266] iio: adc: qcom: Unify user-visible "Qualcomm" name Various names for Qualcomm as a company are used in user-visible config options: QCOM, Qualcomm and Qualcomm Technologies. Switch to unified "Qualcomm" so it will be easier for users to identify the options when for example running menuconfig. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index a9dedbb8eb46..1115e81ac45b 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -1354,7 +1354,7 @@ config QCOM_SPMI_VADC be called qcom-spmi-vadc. config QCOM_SPMI_ADC5 - tristate "Qualcomm Technologies Inc. SPMI PMIC5 ADC" + tristate "Qualcomm SPMI PMIC5 ADC" depends on SPMI select REGMAP_SPMI select QCOM_VADC_COMMON @@ -1374,7 +1374,7 @@ config QCOM_SPMI_ADC5 be called qcom-spmi-adc5. config QCOM_SPMI_ADC5_GEN3 - tristate "Qualcomm Technologies Inc. SPMI PMIC5 GEN3 ADC" + tristate "Qualcomm SPMI PMIC5 GEN3 ADC" depends on SPMI && THERMAL select REGMAP_SPMI select QCOM_VADC_COMMON From d7117c14cd6b3cfdf7206395d8e9c4d7d96107ff Mon Sep 17 00:00:00 2001 From: Lucas Ivars Cadima Ciziks Date: Fri, 24 Apr 2026 09:43:39 -0300 Subject: [PATCH 081/266] iio: adc: ad7280a: Extract chan->address bit fields into named local variables Extract the upper and lower bytes of chan->address into named local variables devaddr and ch across ad7280_read_raw(), ad7280_show_balance_timer() and ad7280_store_balance_timer() to improve readability and avoid inline bit manipulation in function calls. Suggested-by: Andy Shevchenko Signed-off-by: Lucas Ivars Cadima Ciziks Co-developed-by: Matheus Giarola Signed-off-by: Matheus Giarola Co-developed-by: Felipe Ribeiro de Souza Signed-off-by: Felipe Ribeiro de Souza Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7280a.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/iio/adc/ad7280a.c b/drivers/iio/adc/ad7280a.c index f50e2b3121bf..5a01c3fc7cbb 100644 --- a/drivers/iio/adc/ad7280a.c +++ b/drivers/iio/adc/ad7280a.c @@ -516,12 +516,13 @@ static ssize_t ad7280_show_balance_timer(struct iio_dev *indio_dev, char *buf) { struct ad7280_state *st = iio_priv(indio_dev); + u8 devaddr = chan->address >> 8; + u8 ch = chan->address & 0xFF; unsigned int msecs; int ret; mutex_lock(&st->lock); - ret = ad7280_read_reg(st, chan->address >> 8, - (chan->address & 0xFF) + AD7280A_CB1_TIMER_REG); + ret = ad7280_read_reg(st, devaddr, ch + AD7280A_CB1_TIMER_REG); mutex_unlock(&st->lock); if (ret < 0) @@ -538,6 +539,8 @@ static ssize_t ad7280_store_balance_timer(struct iio_dev *indio_dev, const char *buf, size_t len) { struct ad7280_state *st = iio_priv(indio_dev); + u8 devaddr = chan->address >> 8; + u8 ch = chan->address & 0xFF; int val, val2; int ret; @@ -552,8 +555,7 @@ static ssize_t ad7280_store_balance_timer(struct iio_dev *indio_dev, return -EINVAL; mutex_lock(&st->lock); - ret = ad7280_write(st, chan->address >> 8, - (chan->address & 0xFF) + AD7280A_CB1_TIMER_REG, 0, + ret = ad7280_write(st, devaddr, ch + AD7280A_CB1_TIMER_REG, 0, FIELD_PREP(AD7280A_CB_TIMER_VAL_MSK, val)); mutex_unlock(&st->lock); @@ -881,6 +883,8 @@ static int ad7280_read_raw(struct iio_dev *indio_dev, long m) { struct ad7280_state *st = iio_priv(indio_dev); + u8 devaddr = chan->address >> 8; + u8 ch = chan->address & 0xFF; int ret; switch (m) { @@ -889,8 +893,7 @@ static int ad7280_read_raw(struct iio_dev *indio_dev, if (chan->address == AD7280A_ALL_CELLS) ret = ad7280_read_all_channels(st, st->scan_cnt, NULL); else - ret = ad7280_read_channel(st, chan->address >> 8, - chan->address & 0xFF); + ret = ad7280_read_channel(st, devaddr, ch); mutex_unlock(&st->lock); if (ret < 0) @@ -900,7 +903,7 @@ static int ad7280_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - if ((chan->address & 0xFF) <= AD7280A_CELL_VOLTAGE_6_REG) + if (ch <= AD7280A_CELL_VOLTAGE_6_REG) *val = 4000; else *val = 5000; From 9d5129c73bd0151e0f165b88e968a91ceef91275 Mon Sep 17 00:00:00 2001 From: Lucas Ivars Cadima Ciziks Date: Fri, 24 Apr 2026 09:43:40 -0300 Subject: [PATCH 082/266] iio: adc: ad7280a: use cleanup helpers guard() and scoped_guard() for mutex locking Replace open-coded mutex_lock/unlock pairs with the cleanup-based guard() and scoped_guard() helpers in ad7280a_write_thresh(), ad7280_show_balance_timer(), ad7280_store_balance_sw(), ad7280_store_balance_timer() and ad7280_read_raw(). This removes the need for the err_unlock label and explicit mutex_unlock() calls, as the lock is now automatically released when the function returns or the guarded scope exits, regardless of the exit path. Signed-off-by: Lucas Ivars Cadima Ciziks Co-developed-by: Matheus Giarola Signed-off-by: Matheus Giarola Co-developed-by: Felipe Ribeiro de Souza Signed-off-by: Felipe Ribeiro de Souza Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7280a.c | 56 ++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 33 deletions(-) diff --git a/drivers/iio/adc/ad7280a.c b/drivers/iio/adc/ad7280a.c index 5a01c3fc7cbb..01c2f55a680c 100644 --- a/drivers/iio/adc/ad7280a.c +++ b/drivers/iio/adc/ad7280a.c @@ -496,7 +496,8 @@ static ssize_t ad7280_store_balance_sw(struct iio_dev *indio_dev, devaddr = chan->address >> 8; ch = chan->address & 0xFF; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); + if (readin) st->cb_mask[devaddr] |= BIT(ch); else @@ -505,7 +506,6 @@ static ssize_t ad7280_store_balance_sw(struct iio_dev *indio_dev, ret = ad7280_write(st, devaddr, AD7280A_CELL_BALANCE_REG, 0, FIELD_PREP(AD7280A_CELL_BALANCE_CHAN_BITMAP_MSK, st->cb_mask[devaddr])); - mutex_unlock(&st->lock); return ret ? ret : len; } @@ -521,10 +521,8 @@ static ssize_t ad7280_show_balance_timer(struct iio_dev *indio_dev, unsigned int msecs; int ret; - mutex_lock(&st->lock); - ret = ad7280_read_reg(st, devaddr, ch + AD7280A_CB1_TIMER_REG); - mutex_unlock(&st->lock); - + scoped_guard(mutex, &st->lock) + ret = ad7280_read_reg(st, devaddr, ch + AD7280A_CB1_TIMER_REG); if (ret < 0) return ret; @@ -554,10 +552,10 @@ static ssize_t ad7280_store_balance_timer(struct iio_dev *indio_dev, if (val > 31) return -EINVAL; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); + ret = ad7280_write(st, devaddr, ch + AD7280A_CB1_TIMER_REG, 0, FIELD_PREP(AD7280A_CB_TIMER_VAL_MSK, val)); - mutex_unlock(&st->lock); return ret ? ret : len; } @@ -739,7 +737,8 @@ static int ad7280a_write_thresh(struct iio_dev *indio_dev, if (val2 != 0) return -EINVAL; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); + switch (chan->type) { case IIO_VOLTAGE: value = ((val - 1000) * 100) / 1568; /* LSB 15.68mV */ @@ -750,22 +749,20 @@ static int ad7280a_write_thresh(struct iio_dev *indio_dev, ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, addr, 1, value); if (ret) - break; + return ret; st->cell_threshhigh = value; - break; + return 0; case IIO_EV_DIR_FALLING: addr = AD7280A_CELL_UNDERVOLTAGE_REG; ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, addr, 1, value); if (ret) - break; + return ret; st->cell_threshlow = value; - break; + return 0; default: - ret = -EINVAL; - goto err_unlock; + return -EINVAL; } - break; case IIO_TEMP: value = (val * 10) / 196; /* LSB 19.6mV */ value = clamp(value, 0L, 0xFFL); @@ -775,31 +772,23 @@ static int ad7280a_write_thresh(struct iio_dev *indio_dev, ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, addr, 1, value); if (ret) - break; + return ret; st->aux_threshhigh = value; - break; + return 0; case IIO_EV_DIR_FALLING: addr = AD7280A_AUX_ADC_UNDERVOLTAGE_REG; ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, addr, 1, value); if (ret) - break; + return ret; st->aux_threshlow = value; - break; + return 0; default: - ret = -EINVAL; - goto err_unlock; + return -EINVAL; } - break; default: - ret = -EINVAL; - goto err_unlock; + return -EINVAL; } - -err_unlock: - mutex_unlock(&st->lock); - - return ret; } static irqreturn_t ad7280_event_handler(int irq, void *private) @@ -888,13 +877,13 @@ static int ad7280_read_raw(struct iio_dev *indio_dev, int ret; switch (m) { - case IIO_CHAN_INFO_RAW: - mutex_lock(&st->lock); + case IIO_CHAN_INFO_RAW: { + guard(mutex)(&st->lock); + if (chan->address == AD7280A_ALL_CELLS) ret = ad7280_read_all_channels(st, st->scan_cnt, NULL); else ret = ad7280_read_channel(st, devaddr, ch); - mutex_unlock(&st->lock); if (ret < 0) return ret; @@ -902,6 +891,7 @@ static int ad7280_read_raw(struct iio_dev *indio_dev, *val = ret; return IIO_VAL_INT; + } case IIO_CHAN_INFO_SCALE: if (ch <= AD7280A_CELL_VOLTAGE_6_REG) *val = 4000; From fde18a8a1dd7e8384d1db17435e7b3813b0512cc Mon Sep 17 00:00:00 2001 From: Ariana Lazar Date: Wed, 22 Apr 2026 14:56:59 +0300 Subject: [PATCH 083/266] dt-bindings: iio: dac: mcp47feb02: Fix I2C address in example Change example reg value from 0 to 0x60 in order to use a valid I2C address Signed-off-by: Ariana Lazar Acked-by: Conor Dooley Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/dac/microchip,mcp47feb02.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/dac/microchip,mcp47feb02.yaml b/Documentation/devicetree/bindings/iio/dac/microchip,mcp47feb02.yaml index d2466aa6bda2..350e80e4dbe0 100644 --- a/Documentation/devicetree/bindings/iio/dac/microchip,mcp47feb02.yaml +++ b/Documentation/devicetree/bindings/iio/dac/microchip,mcp47feb02.yaml @@ -280,9 +280,9 @@ examples: #address-cells = <1>; #size-cells = <0>; - dac@0 { + dac@60 { compatible = "microchip,mcp47feb02"; - reg = <0>; + reg = <0x60>; vdd-supply = <&vdac_vdd>; vref-supply = <&vref_reg>; From 6d78ab5687ff2b949680b86d3e57fa8d7c6a21fa Mon Sep 17 00:00:00 2001 From: Ariana Lazar Date: Wed, 22 Apr 2026 14:53:14 +0300 Subject: [PATCH 084/266] dt-bindings: iio: dac: mcp47feb02: fix reg property value bounds Replace minItems/maxItems with minimum/maximum to describe the reg property as a single channel number with 8 possible values (0-7) Signed-off-by: Ariana Lazar Acked-by: Conor Dooley Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/dac/microchip,mcp47feb02.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/dac/microchip,mcp47feb02.yaml b/Documentation/devicetree/bindings/iio/dac/microchip,mcp47feb02.yaml index 350e80e4dbe0..b4ca5b6e743a 100644 --- a/Documentation/devicetree/bindings/iio/dac/microchip,mcp47feb02.yaml +++ b/Documentation/devicetree/bindings/iio/dac/microchip,mcp47feb02.yaml @@ -161,8 +161,8 @@ patternProperties: properties: reg: description: The channel number. - minItems: 1 - maxItems: 8 + minimum: 0 + maximum: 7 label: description: Unique name to identify which channel this is. From 96aa96c029bf4b4309b27ffb17dcbe0c0d660e2a Mon Sep 17 00:00:00 2001 From: Ariana Lazar Date: Wed, 22 Apr 2026 16:40:52 +0300 Subject: [PATCH 085/266] dt-bindings: iio: dac: mcp47feb02: fix example indentation Correct inconsistent indentation in the example and use consistent 4-space indentation. Signed-off-by: Ariana Lazar Acked-by: Conor Dooley Signed-off-by: Jonathan Cameron --- .../iio/dac/microchip,mcp47feb02.yaml | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/dac/microchip,mcp47feb02.yaml b/Documentation/devicetree/bindings/iio/dac/microchip,mcp47feb02.yaml index b4ca5b6e743a..d131f136bd15 100644 --- a/Documentation/devicetree/bindings/iio/dac/microchip,mcp47feb02.yaml +++ b/Documentation/devicetree/bindings/iio/dac/microchip,mcp47feb02.yaml @@ -281,22 +281,22 @@ examples: #address-cells = <1>; #size-cells = <0>; dac@60 { - compatible = "microchip,mcp47feb02"; - reg = <0x60>; - vdd-supply = <&vdac_vdd>; - vref-supply = <&vref_reg>; + compatible = "microchip,mcp47feb02"; + reg = <0x60>; + vdd-supply = <&vdac_vdd>; + vref-supply = <&vref_reg>; - #address-cells = <1>; - #size-cells = <0>; - channel@0 { - reg = <0>; - label = "Adjustable_voltage_ch0"; - }; + #address-cells = <1>; + #size-cells = <0>; + channel@0 { + reg = <0>; + label = "Adjustable_voltage_ch0"; + }; - channel@1 { - reg = <0x1>; - label = "Adjustable_voltage_ch1"; - }; - }; + channel@1 { + reg = <0x1>; + label = "Adjustable_voltage_ch1"; + }; + }; }; ... From 2450368e2e81716d9bd04a4631f5a480581881ec Mon Sep 17 00:00:00 2001 From: Maxwell Doose Date: Wed, 22 Apr 2026 07:45:05 -0500 Subject: [PATCH 086/266] iio: proximity: srf08: Replace sprintf() with sysfs_emit() Replace sprintf() function calls with sysfs_emit() and sysfs_emit_at(). While the current code is fine, sysfs_emit() is preferred over sprintf(), and will help modernize the driver. Signed-off-by: Maxwell Doose Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/srf08.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/iio/proximity/srf08.c b/drivers/iio/proximity/srf08.c index d7e4cc48cfbf..92a37ba331f6 100644 --- a/drivers/iio/proximity/srf08.c +++ b/drivers/iio/proximity/srf08.c @@ -226,7 +226,7 @@ static int srf08_read_raw(struct iio_dev *indio_dev, static ssize_t srf08_show_range_mm_available(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "[0.043 0.043 11.008]\n"); + return sysfs_emit(buf, "[0.043 0.043 11.008]\n"); } static IIO_DEVICE_ATTR(sensor_max_range_available, S_IRUGO, @@ -238,8 +238,8 @@ static ssize_t srf08_show_range_mm(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct srf08_data *data = iio_priv(indio_dev); - return sprintf(buf, "%d.%03d\n", data->range_mm / 1000, - data->range_mm % 1000); + return sysfs_emit(buf, "%d.%03d\n", + data->range_mm / 1000, data->range_mm % 1000); } /* @@ -316,10 +316,10 @@ static ssize_t srf08_show_sensitivity_available(struct device *dev, for (i = 0; i < data->chip_info->num_sensitivity_avail; i++) if (data->chip_info->sensitivity_avail[i]) - len += sprintf(buf + len, "%d ", - data->chip_info->sensitivity_avail[i]); + len += sysfs_emit_at(buf, len, "%d ", + data->chip_info->sensitivity_avail[i]); - len += sprintf(buf + len, "\n"); + len += sysfs_emit_at(buf, len, "\n"); return len; } @@ -332,11 +332,8 @@ static ssize_t srf08_show_sensitivity(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct srf08_data *data = iio_priv(indio_dev); - int len; - len = sprintf(buf, "%d\n", data->sensitivity); - - return len; + return sysfs_emit(buf, "%d\n", data->sensitivity); } static ssize_t srf08_write_sensitivity(struct srf08_data *data, From 1a5fc4b5ddeeebacb22fead349b9dba3b2a1056a Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Sat, 25 Apr 2026 15:54:27 +0300 Subject: [PATCH 087/266] dt-bindings: iio: light: Document Avago APDS9900/9901 ALS/Proximity sensor Document Avago APDS-9900/9901 combined ALS/IR-LED/Proximity sensor. Signed-off-by: Svyatoslav Ryhel Acked-by: Rob Herring (Arm) Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/light/tsl2772.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/light/tsl2772.yaml b/Documentation/devicetree/bindings/iio/light/tsl2772.yaml index d81229857944..9921ccaa64a0 100644 --- a/Documentation/devicetree/bindings/iio/light/tsl2772.yaml +++ b/Documentation/devicetree/bindings/iio/light/tsl2772.yaml @@ -26,6 +26,8 @@ properties: - amstaos,tmd2672 - amstaos,tsl2772 - amstaos,tmd2772 + - avago,apds9900 + - avago,apds9901 - avago,apds9930 reg: From 2f640a4d0fe181b6b02ea570bb64969e6e9322bd Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Sat, 25 Apr 2026 15:54:28 +0300 Subject: [PATCH 088/266] iio: tsl2772: Add support for Avago APDS9900/9901 ALS/Proximity sensor The Avago APDS9900/9901 has a similar register layout to the TAOS/AMS TSL2772 but features a unique set of configurations. Add support for the APDS9900/9901 into the TSL2772 driver by adding the required device-specific configurations. Signed-off-by: Svyatoslav Ryhel Signed-off-by: Jonathan Cameron --- drivers/iio/light/tsl2772.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/iio/light/tsl2772.c b/drivers/iio/light/tsl2772.c index c8f15ba95267..9ba8140c8bc1 100644 --- a/drivers/iio/light/tsl2772.c +++ b/drivers/iio/light/tsl2772.c @@ -127,6 +127,7 @@ enum { tmd2672, tsl2772, tmd2772, + apds9900, apds9930, }; @@ -221,6 +222,12 @@ static const struct tsl2772_lux tmd2x72_lux_table[TSL2772_DEF_LUX_TABLE_SZ] = { { 0, 0 }, }; +static const struct tsl2772_lux apds9900_lux_table[TSL2772_DEF_LUX_TABLE_SZ] = { + { 52000, 115960 }, + { 36400, 73840 }, + { 0, 0 }, +}; + static const struct tsl2772_lux apds9930_lux_table[TSL2772_DEF_LUX_TABLE_SZ] = { { 52000, 96824 }, { 38792, 67132 }, @@ -238,6 +245,7 @@ static const struct tsl2772_lux *tsl2772_default_lux_table_group[] = { [tmd2672] = tmd2x72_lux_table, [tsl2772] = tsl2x72_lux_table, [tmd2772] = tmd2x72_lux_table, + [apds9900] = apds9900_lux_table, [apds9930] = apds9930_lux_table, }; @@ -289,6 +297,7 @@ static const int tsl2772_int_time_avail[][6] = { [tmd2672] = { 0, 2730, 0, 2730, 0, 699000 }, [tsl2772] = { 0, 2730, 0, 2730, 0, 699000 }, [tmd2772] = { 0, 2730, 0, 2730, 0, 699000 }, + [apds9900] = { 0, 2720, 0, 2720, 0, 696000 }, [apds9930] = { 0, 2730, 0, 2730, 0, 699000 }, }; @@ -316,6 +325,7 @@ static const u8 device_channel_config[] = { [tmd2672] = PRX2, [tsl2772] = ALSPRX2, [tmd2772] = ALSPRX2, + [apds9900] = ALSPRX, [apds9930] = ALSPRX2, }; @@ -530,6 +540,7 @@ static int tsl2772_get_prox(struct iio_dev *indio_dev) case tmd2672: case tsl2772: case tmd2772: + case apds9900: case apds9930: if (!(ret & TSL2772_STA_PRX_VALID)) { ret = -EINVAL; @@ -1367,6 +1378,7 @@ static int tsl2772_device_id_verif(int id, int target) return (id & 0xf0) == TRITON_ID; case tmd2671: case tmd2771: + case apds9900: return (id & 0xf0) == HALIBUT_ID; case tsl2572: case tsl2672: @@ -1898,6 +1910,8 @@ static const struct i2c_device_id tsl2772_idtable[] = { { "tmd2672", tmd2672 }, { "tsl2772", tsl2772 }, { "tmd2772", tmd2772 }, + { "apds9900", apds9900 }, + { "apds9901", apds9900 }, { "apds9930", apds9930 }, { } }; @@ -1915,6 +1929,8 @@ static const struct of_device_id tsl2772_of_match[] = { { .compatible = "amstaos,tmd2672" }, { .compatible = "amstaos,tsl2772" }, { .compatible = "amstaos,tmd2772" }, + { .compatible = "avago,apds9900" }, + { .compatible = "avago,apds9901" }, { .compatible = "avago,apds9930" }, { } }; From 9c482946235362f81bf20da94e1c1f467a03c08f Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Sat, 25 Apr 2026 15:54:29 +0300 Subject: [PATCH 089/266] misc: Remove old APDS990x driver The APDS990x driver in misc lacks DeviceTree support, and no mainline pre-DT board files configured this device using apds990x_platform_data. This driver belongs to a legacy group of ambient light sensor drivers in drivers/misc/ that predates the migration to DT and the standard IIO ABI. Since the Avago APDS9900/9901 ALS/Proximity sensor is now supported by the tsl2772 IIO driver and there are no active users in the kernel tree, remove this old implementation. Acked-by: Greg Kroah-Hartman Signed-off-by: Svyatoslav Ryhel Signed-off-by: Jonathan Cameron --- Documentation/misc-devices/apds990x.rst | 128 --- Documentation/misc-devices/index.rst | 1 - drivers/misc/Kconfig | 10 - drivers/misc/Makefile | 1 - drivers/misc/apds990x.c | 1284 ----------------------- include/linux/platform_data/apds990x.h | 65 -- 6 files changed, 1489 deletions(-) delete mode 100644 Documentation/misc-devices/apds990x.rst delete mode 100644 drivers/misc/apds990x.c delete mode 100644 include/linux/platform_data/apds990x.h diff --git a/Documentation/misc-devices/apds990x.rst b/Documentation/misc-devices/apds990x.rst deleted file mode 100644 index e2f75577f731..000000000000 --- a/Documentation/misc-devices/apds990x.rst +++ /dev/null @@ -1,128 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -====================== -Kernel driver apds990x -====================== - -Supported chips: -Avago APDS990X - -Data sheet: -Not freely available - -Author: -Samu Onkalo - -Description ------------ - -APDS990x is a combined ambient light and proximity sensor. ALS and proximity -functionality are highly connected. ALS measurement path must be running -while the proximity functionality is enabled. - -ALS produces raw measurement values for two channels: Clear channel -(infrared + visible light) and IR only. However, threshold comparisons happen -using clear channel only. Lux value and the threshold level on the HW -might vary quite much depending the spectrum of the light source. - -Driver makes necessary conversions to both directions so that user handles -only lux values. Lux value is calculated using information from the both -channels. HW threshold level is calculated from the given lux value to match -with current type of the lightning. Sometimes inaccuracy of the estimations -lead to false interrupt, but that doesn't harm. - -ALS contains 4 different gain steps. Driver automatically -selects suitable gain step. After each measurement, reliability of the results -is estimated and new measurement is triggered if necessary. - -Platform data can provide tuned values to the conversion formulas if -values are known. Otherwise plain sensor default values are used. - -Proximity side is little bit simpler. There is no need for complex conversions. -It produces directly usable values. - -Driver controls chip operational state using pm_runtime framework. -Voltage regulators are controlled based on chip operational state. - -SYSFS ------ - - -chip_id - RO - shows detected chip type and version - -power_state - RW - enable / disable chip. Uses counting logic - - 1 enables the chip - 0 disables the chip -lux0_input - RO - measured lux value - - sysfs_notify called when threshold interrupt occurs - -lux0_sensor_range - RO - lux0_input max value. - - Actually never reaches since sensor tends - to saturate much before that. Real max value varies depending - on the light spectrum etc. - -lux0_rate - RW - measurement rate in Hz - -lux0_rate_avail - RO - supported measurement rates - -lux0_calibscale - RW - calibration value. - - Set to neutral value by default. - Output results are multiplied with calibscale / calibscale_default - value. - -lux0_calibscale_default - RO - neutral calibration value - -lux0_thresh_above_value - RW - HI level threshold value. - - All results above the value - trigs an interrupt. 65535 (i.e. sensor_range) disables the above - interrupt. - -lux0_thresh_below_value - RW - LO level threshold value. - - All results below the value - trigs an interrupt. 0 disables the below interrupt. - -prox0_raw - RO - measured proximity value - - sysfs_notify called when threshold interrupt occurs - -prox0_sensor_range - RO - prox0_raw max value (1023) - -prox0_raw_en - RW - enable / disable proximity - uses counting logic - - - 1 enables the proximity - - 0 disables the proximity - -prox0_reporting_mode - RW - trigger / periodic. - - In "trigger" mode the driver tells two possible - values: 0 or prox0_sensor_range value. 0 means no proximity, - 1023 means proximity. This causes minimal number of interrupts. - In "periodic" mode the driver reports all values above - prox0_thresh_above. This causes more interrupts, but it can give - _rough_ estimate about the distance. - -prox0_reporting_mode_avail - RO - accepted values to prox0_reporting_mode (trigger, periodic) - -prox0_thresh_above_value - RW - threshold level which trigs proximity events. diff --git a/Documentation/misc-devices/index.rst b/Documentation/misc-devices/index.rst index 081e79415e38..f911edaecbfa 100644 --- a/Documentation/misc-devices/index.rst +++ b/Documentation/misc-devices/index.rst @@ -13,7 +13,6 @@ fit into other categories. ad525x_dpot amd-sbi - apds990x bh1770glc c2port dw-xdata-pcie diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 00683bf06258..390256ed91f4 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -381,16 +381,6 @@ config SENSORS_BH1770 To compile this driver as a module, choose M here: the module will be called bh1770glc. If unsure, say N here. -config SENSORS_APDS990X - tristate "APDS990X combined als and proximity sensors" - depends on I2C - help - Say Y here if you want to build a driver for Avago APDS990x - combined ambient light and proximity sensor chip. - - To compile this driver as a module, choose M here: the - module will be called apds990x. If unsure, say N here. - config HMC6352 tristate "Honeywell HMC6352 compass" depends on I2C diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index b32a2597d246..fed47c7672b9 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -20,7 +20,6 @@ obj-$(CONFIG_RPMB) += rpmb-core.o obj-$(CONFIG_QCOM_COINCELL) += qcom-coincell.o obj-$(CONFIG_QCOM_FASTRPC) += fastrpc.o obj-$(CONFIG_SENSORS_BH1770) += bh1770glc.o -obj-$(CONFIG_SENSORS_APDS990X) += apds990x.o obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o obj-$(CONFIG_KGDB_TESTS) += kgdbts.o obj-$(CONFIG_SGI_XP) += sgi-xp/ diff --git a/drivers/misc/apds990x.c b/drivers/misc/apds990x.c deleted file mode 100644 index b69c3a1c94d1..000000000000 --- a/drivers/misc/apds990x.c +++ /dev/null @@ -1,1284 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * This file is part of the APDS990x sensor driver. - * Chip is combined proximity and ambient light sensor. - * - * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). - * - * Contact: Samu Onkalo - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Register map */ -#define APDS990X_ENABLE 0x00 /* Enable of states and interrupts */ -#define APDS990X_ATIME 0x01 /* ALS ADC time */ -#define APDS990X_PTIME 0x02 /* Proximity ADC time */ -#define APDS990X_WTIME 0x03 /* Wait time */ -#define APDS990X_AILTL 0x04 /* ALS interrupt low threshold low byte */ -#define APDS990X_AILTH 0x05 /* ALS interrupt low threshold hi byte */ -#define APDS990X_AIHTL 0x06 /* ALS interrupt hi threshold low byte */ -#define APDS990X_AIHTH 0x07 /* ALS interrupt hi threshold hi byte */ -#define APDS990X_PILTL 0x08 /* Proximity interrupt low threshold low byte */ -#define APDS990X_PILTH 0x09 /* Proximity interrupt low threshold hi byte */ -#define APDS990X_PIHTL 0x0a /* Proximity interrupt hi threshold low byte */ -#define APDS990X_PIHTH 0x0b /* Proximity interrupt hi threshold hi byte */ -#define APDS990X_PERS 0x0c /* Interrupt persistence filters */ -#define APDS990X_CONFIG 0x0d /* Configuration */ -#define APDS990X_PPCOUNT 0x0e /* Proximity pulse count */ -#define APDS990X_CONTROL 0x0f /* Gain control register */ -#define APDS990X_REV 0x11 /* Revision Number */ -#define APDS990X_ID 0x12 /* Device ID */ -#define APDS990X_STATUS 0x13 /* Device status */ -#define APDS990X_CDATAL 0x14 /* Clear ADC low data register */ -#define APDS990X_CDATAH 0x15 /* Clear ADC high data register */ -#define APDS990X_IRDATAL 0x16 /* IR ADC low data register */ -#define APDS990X_IRDATAH 0x17 /* IR ADC high data register */ -#define APDS990X_PDATAL 0x18 /* Proximity ADC low data register */ -#define APDS990X_PDATAH 0x19 /* Proximity ADC high data register */ - -/* Control */ -#define APDS990X_MAX_AGAIN 3 - -/* Enable register */ -#define APDS990X_EN_PIEN (0x1 << 5) -#define APDS990X_EN_AIEN (0x1 << 4) -#define APDS990X_EN_WEN (0x1 << 3) -#define APDS990X_EN_PEN (0x1 << 2) -#define APDS990X_EN_AEN (0x1 << 1) -#define APDS990X_EN_PON (0x1 << 0) -#define APDS990X_EN_DISABLE_ALL 0 - -/* Status register */ -#define APDS990X_ST_PINT (0x1 << 5) -#define APDS990X_ST_AINT (0x1 << 4) - -/* I2C access types */ -#define APDS990x_CMD_TYPE_MASK (0x03 << 5) -#define APDS990x_CMD_TYPE_RB (0x00 << 5) /* Repeated byte */ -#define APDS990x_CMD_TYPE_INC (0x01 << 5) /* Auto increment */ -#define APDS990x_CMD_TYPE_SPE (0x03 << 5) /* Special function */ - -#define APDS990x_ADDR_SHIFT 0 -#define APDS990x_CMD 0x80 - -/* Interrupt ack commands */ -#define APDS990X_INT_ACK_ALS 0x6 -#define APDS990X_INT_ACK_PS 0x5 -#define APDS990X_INT_ACK_BOTH 0x7 - -/* ptime */ -#define APDS990X_PTIME_DEFAULT 0xff /* Recommended conversion time 2.7ms*/ - -/* wtime */ -#define APDS990X_WTIME_DEFAULT 0xee /* ~50ms wait time */ - -#define APDS990X_TIME_TO_ADC 1024 /* One timetick as ADC count value */ - -/* Persistence */ -#define APDS990X_APERS_SHIFT 0 -#define APDS990X_PPERS_SHIFT 4 - -/* Supported ID:s */ -#define APDS990X_ID_0 0x0 -#define APDS990X_ID_4 0x4 -#define APDS990X_ID_29 0x29 - -/* pgain and pdiode settings */ -#define APDS_PGAIN_1X 0x0 -#define APDS_PDIODE_IR 0x2 - -#define APDS990X_LUX_OUTPUT_SCALE 10 - -/* Reverse chip factors for threshold calculation */ -struct reverse_factors { - u32 afactor; - int cf1; - int irf1; - int cf2; - int irf2; -}; - -struct apds990x_chip { - struct apds990x_platform_data *pdata; - struct i2c_client *client; - struct mutex mutex; /* avoid parallel access */ - struct regulator_bulk_data regs[2]; - wait_queue_head_t wait; - - int prox_en; - bool prox_continuous_mode; - bool lux_wait_fresh_res; - - /* Chip parameters */ - struct apds990x_chip_factors cf; - struct reverse_factors rcf; - u16 atime; /* als integration time */ - u16 arate; /* als reporting rate */ - u16 a_max_result; /* Max possible ADC value with current atime */ - u8 again_meas; /* Gain used in last measurement */ - u8 again_next; /* Next calculated gain */ - u8 pgain; - u8 pdiode; - u8 pdrive; - u8 lux_persistence; - u8 prox_persistence; - - u32 lux_raw; - u32 lux; - u16 lux_clear; - u16 lux_ir; - u16 lux_calib; - u32 lux_thres_hi; - u32 lux_thres_lo; - - u32 prox_thres; - u16 prox_data; - u16 prox_calib; - - char chipname[10]; - u8 revision; -}; - -#define APDS_CALIB_SCALER 8192 -#define APDS_LUX_NEUTRAL_CALIB_VALUE (1 * APDS_CALIB_SCALER) -#define APDS_PROX_NEUTRAL_CALIB_VALUE (1 * APDS_CALIB_SCALER) - -#define APDS_PROX_DEF_THRES 600 -#define APDS_PROX_HYSTERESIS 50 -#define APDS_LUX_DEF_THRES_HI 101 -#define APDS_LUX_DEF_THRES_LO 100 -#define APDS_DEFAULT_PROX_PERS 1 - -#define APDS_TIMEOUT 2000 -#define APDS_STARTUP_DELAY 25000 /* us */ -#define APDS_RANGE 65535 -#define APDS_PROX_RANGE 1023 -#define APDS_LUX_GAIN_LO_LIMIT 100 -#define APDS_LUX_GAIN_LO_LIMIT_STRICT 25 - -#define TIMESTEP 87 /* 2.7ms is about 87 / 32 */ -#define TIME_STEP_SCALER 32 - -#define APDS_LUX_AVERAGING_TIME 50 /* tolerates 50/60Hz ripple */ -#define APDS_LUX_DEFAULT_RATE 200 - -static const u8 again[] = {1, 8, 16, 120}; /* ALS gain steps */ - -/* Following two tables must match i.e 10Hz rate means 1 as persistence value */ -static const u16 arates_hz[] = {10, 5, 2, 1}; -static const u8 apersis[] = {1, 2, 4, 5}; - -/* Regulators */ -static const char reg_vcc[] = "Vdd"; -static const char reg_vled[] = "Vled"; - -static int apds990x_read_byte(struct apds990x_chip *chip, u8 reg, u8 *data) -{ - struct i2c_client *client = chip->client; - s32 ret; - - reg &= ~APDS990x_CMD_TYPE_MASK; - reg |= APDS990x_CMD | APDS990x_CMD_TYPE_RB; - - ret = i2c_smbus_read_byte_data(client, reg); - *data = ret; - return (int)ret; -} - -static int apds990x_read_word(struct apds990x_chip *chip, u8 reg, u16 *data) -{ - struct i2c_client *client = chip->client; - s32 ret; - - reg &= ~APDS990x_CMD_TYPE_MASK; - reg |= APDS990x_CMD | APDS990x_CMD_TYPE_INC; - - ret = i2c_smbus_read_word_data(client, reg); - *data = ret; - return (int)ret; -} - -static int apds990x_write_byte(struct apds990x_chip *chip, u8 reg, u8 data) -{ - struct i2c_client *client = chip->client; - s32 ret; - - reg &= ~APDS990x_CMD_TYPE_MASK; - reg |= APDS990x_CMD | APDS990x_CMD_TYPE_RB; - - ret = i2c_smbus_write_byte_data(client, reg, data); - return (int)ret; -} - -static int apds990x_write_word(struct apds990x_chip *chip, u8 reg, u16 data) -{ - struct i2c_client *client = chip->client; - s32 ret; - - reg &= ~APDS990x_CMD_TYPE_MASK; - reg |= APDS990x_CMD | APDS990x_CMD_TYPE_INC; - - ret = i2c_smbus_write_word_data(client, reg, data); - return (int)ret; -} - -static int apds990x_mode_on(struct apds990x_chip *chip) -{ - /* ALS is mandatory, proximity optional */ - u8 reg = APDS990X_EN_AIEN | APDS990X_EN_PON | APDS990X_EN_AEN | - APDS990X_EN_WEN; - - if (chip->prox_en) - reg |= APDS990X_EN_PIEN | APDS990X_EN_PEN; - - return apds990x_write_byte(chip, APDS990X_ENABLE, reg); -} - -static u16 apds990x_lux_to_threshold(struct apds990x_chip *chip, u32 lux) -{ - u32 thres; - u32 cpl; - u32 ir; - - if (lux == 0) - return 0; - else if (lux == APDS_RANGE) - return APDS_RANGE; - - /* - * Reported LUX value is a combination of the IR and CLEAR channel - * values. However, interrupt threshold is only for clear channel. - * This function approximates needed HW threshold value for a given - * LUX value in the current lightning type. - * IR level compared to visible light varies heavily depending on the - * source of the light - * - * Calculate threshold value for the next measurement period. - * Math: threshold = lux * cpl where - * cpl = atime * again / (glass_attenuation * device_factor) - * (count-per-lux) - * - * First remove calibration. Division by four is to avoid overflow - */ - lux = lux * (APDS_CALIB_SCALER / 4) / (chip->lux_calib / 4); - - /* Multiplication by 64 is to increase accuracy */ - cpl = ((u32)chip->atime * (u32)again[chip->again_next] * - APDS_PARAM_SCALE * 64) / (chip->cf.ga * chip->cf.df); - - thres = lux * cpl / 64; - /* - * Convert IR light from the latest result to match with - * new gain step. This helps to adapt with the current - * source of light. - */ - ir = (u32)chip->lux_ir * (u32)again[chip->again_next] / - (u32)again[chip->again_meas]; - - /* - * Compensate count with IR light impact - * IAC1 > IAC2 (see apds990x_get_lux for formulas) - */ - if (chip->lux_clear * APDS_PARAM_SCALE >= - chip->rcf.afactor * chip->lux_ir) - thres = (chip->rcf.cf1 * thres + chip->rcf.irf1 * ir) / - APDS_PARAM_SCALE; - else - thres = (chip->rcf.cf2 * thres + chip->rcf.irf2 * ir) / - APDS_PARAM_SCALE; - - if (thres >= chip->a_max_result) - thres = chip->a_max_result - 1; - return thres; -} - -static inline int apds990x_set_atime(struct apds990x_chip *chip, u32 time_ms) -{ - u8 reg_value; - - chip->atime = time_ms; - /* Formula is specified in the data sheet */ - reg_value = 256 - ((time_ms * TIME_STEP_SCALER) / TIMESTEP); - /* Calculate max ADC value for given integration time */ - chip->a_max_result = (u16)(256 - reg_value) * APDS990X_TIME_TO_ADC; - return apds990x_write_byte(chip, APDS990X_ATIME, reg_value); -} - -/* Called always with mutex locked */ -static int apds990x_refresh_pthres(struct apds990x_chip *chip, int data) -{ - int ret, lo, hi; - - /* If the chip is not in use, don't try to access it */ - if (pm_runtime_suspended(&chip->client->dev)) - return 0; - - if (data < chip->prox_thres) { - lo = 0; - hi = chip->prox_thres; - } else { - lo = chip->prox_thres - APDS_PROX_HYSTERESIS; - if (chip->prox_continuous_mode) - hi = chip->prox_thres; - else - hi = APDS_RANGE; - } - - ret = apds990x_write_word(chip, APDS990X_PILTL, lo); - ret |= apds990x_write_word(chip, APDS990X_PIHTL, hi); - return ret; -} - -/* Called always with mutex locked */ -static int apds990x_refresh_athres(struct apds990x_chip *chip) -{ - int ret; - /* If the chip is not in use, don't try to access it */ - if (pm_runtime_suspended(&chip->client->dev)) - return 0; - - ret = apds990x_write_word(chip, APDS990X_AILTL, - apds990x_lux_to_threshold(chip, chip->lux_thres_lo)); - ret |= apds990x_write_word(chip, APDS990X_AIHTL, - apds990x_lux_to_threshold(chip, chip->lux_thres_hi)); - - return ret; -} - -/* Called always with mutex locked */ -static void apds990x_force_a_refresh(struct apds990x_chip *chip) -{ - /* This will force ALS interrupt after the next measurement. */ - apds990x_write_word(chip, APDS990X_AILTL, APDS_LUX_DEF_THRES_LO); - apds990x_write_word(chip, APDS990X_AIHTL, APDS_LUX_DEF_THRES_HI); -} - -/* Called always with mutex locked */ -static void apds990x_force_p_refresh(struct apds990x_chip *chip) -{ - /* This will force proximity interrupt after the next measurement. */ - apds990x_write_word(chip, APDS990X_PILTL, APDS_PROX_DEF_THRES - 1); - apds990x_write_word(chip, APDS990X_PIHTL, APDS_PROX_DEF_THRES); -} - -/* Called always with mutex locked */ -static int apds990x_calc_again(struct apds990x_chip *chip) -{ - int curr_again = chip->again_meas; - int next_again = chip->again_meas; - int ret = 0; - - /* Calculate suitable als gain */ - if (chip->lux_clear == chip->a_max_result) - next_again -= 2; /* ALS saturated. Decrease gain by 2 steps */ - else if (chip->lux_clear > chip->a_max_result / 2) - next_again--; - else if (chip->lux_clear < APDS_LUX_GAIN_LO_LIMIT_STRICT) - next_again += 2; /* Too dark. Increase gain by 2 steps */ - else if (chip->lux_clear < APDS_LUX_GAIN_LO_LIMIT) - next_again++; - - /* Limit gain to available range */ - if (next_again < 0) - next_again = 0; - else if (next_again > APDS990X_MAX_AGAIN) - next_again = APDS990X_MAX_AGAIN; - - /* Let's check can we trust the measured result */ - if (chip->lux_clear == chip->a_max_result) - /* Result can be totally garbage due to saturation */ - ret = -ERANGE; - else if (next_again != curr_again && - chip->lux_clear < APDS_LUX_GAIN_LO_LIMIT_STRICT) - /* - * Gain is changed and measurement result is very small. - * Result can be totally garbage due to underflow - */ - ret = -ERANGE; - - chip->again_next = next_again; - apds990x_write_byte(chip, APDS990X_CONTROL, - (chip->pdrive << 6) | - (chip->pdiode << 4) | - (chip->pgain << 2) | - (chip->again_next << 0)); - - /* - * Error means bad result -> re-measurement is needed. The forced - * refresh uses fastest possible persistence setting to get result - * as soon as possible. - */ - if (ret < 0) - apds990x_force_a_refresh(chip); - else - apds990x_refresh_athres(chip); - - return ret; -} - -/* Called always with mutex locked */ -static int apds990x_get_lux(struct apds990x_chip *chip, int clear, int ir) -{ - int iac, iac1, iac2; /* IR adjusted counts */ - u32 lpc; /* Lux per count */ - - /* Formulas: - * iac1 = CF1 * CLEAR_CH - IRF1 * IR_CH - * iac2 = CF2 * CLEAR_CH - IRF2 * IR_CH - */ - iac1 = (chip->cf.cf1 * clear - chip->cf.irf1 * ir) / APDS_PARAM_SCALE; - iac2 = (chip->cf.cf2 * clear - chip->cf.irf2 * ir) / APDS_PARAM_SCALE; - - iac = max(iac1, iac2); - iac = max(iac, 0); - - lpc = APDS990X_LUX_OUTPUT_SCALE * (chip->cf.df * chip->cf.ga) / - (u32)(again[chip->again_meas] * (u32)chip->atime); - - return (iac * lpc) / APDS_PARAM_SCALE; -} - -static int apds990x_ack_int(struct apds990x_chip *chip, u8 mode) -{ - struct i2c_client *client = chip->client; - s32 ret; - u8 reg = APDS990x_CMD | APDS990x_CMD_TYPE_SPE; - - switch (mode & (APDS990X_ST_AINT | APDS990X_ST_PINT)) { - case APDS990X_ST_AINT: - reg |= APDS990X_INT_ACK_ALS; - break; - case APDS990X_ST_PINT: - reg |= APDS990X_INT_ACK_PS; - break; - default: - reg |= APDS990X_INT_ACK_BOTH; - break; - } - - ret = i2c_smbus_read_byte_data(client, reg); - return (int)ret; -} - -static irqreturn_t apds990x_irq(int irq, void *data) -{ - struct apds990x_chip *chip = data; - u8 status; - - apds990x_read_byte(chip, APDS990X_STATUS, &status); - apds990x_ack_int(chip, status); - - mutex_lock(&chip->mutex); - if (!pm_runtime_suspended(&chip->client->dev)) { - if (status & APDS990X_ST_AINT) { - apds990x_read_word(chip, APDS990X_CDATAL, - &chip->lux_clear); - apds990x_read_word(chip, APDS990X_IRDATAL, - &chip->lux_ir); - /* Store used gain for calculations */ - chip->again_meas = chip->again_next; - - chip->lux_raw = apds990x_get_lux(chip, - chip->lux_clear, - chip->lux_ir); - - if (apds990x_calc_again(chip) == 0) { - /* Result is valid */ - chip->lux = chip->lux_raw; - chip->lux_wait_fresh_res = false; - wake_up(&chip->wait); - sysfs_notify(&chip->client->dev.kobj, - NULL, "lux0_input"); - } - } - - if ((status & APDS990X_ST_PINT) && chip->prox_en) { - u16 clr_ch; - - apds990x_read_word(chip, APDS990X_CDATAL, &clr_ch); - /* - * If ALS channel is saturated at min gain, - * proximity gives false posivite values. - * Just ignore them. - */ - if (chip->again_meas == 0 && - clr_ch == chip->a_max_result) - chip->prox_data = 0; - else - apds990x_read_word(chip, - APDS990X_PDATAL, - &chip->prox_data); - - apds990x_refresh_pthres(chip, chip->prox_data); - if (chip->prox_data < chip->prox_thres) - chip->prox_data = 0; - else if (!chip->prox_continuous_mode) - chip->prox_data = APDS_PROX_RANGE; - sysfs_notify(&chip->client->dev.kobj, - NULL, "prox0_raw"); - } - } - mutex_unlock(&chip->mutex); - return IRQ_HANDLED; -} - -static int apds990x_configure(struct apds990x_chip *chip) -{ - /* It is recommended to use disabled mode during these operations */ - apds990x_write_byte(chip, APDS990X_ENABLE, APDS990X_EN_DISABLE_ALL); - - /* conversion and wait times for different state machince states */ - apds990x_write_byte(chip, APDS990X_PTIME, APDS990X_PTIME_DEFAULT); - apds990x_write_byte(chip, APDS990X_WTIME, APDS990X_WTIME_DEFAULT); - apds990x_set_atime(chip, APDS_LUX_AVERAGING_TIME); - - apds990x_write_byte(chip, APDS990X_CONFIG, 0); - - /* Persistence levels */ - apds990x_write_byte(chip, APDS990X_PERS, - (chip->lux_persistence << APDS990X_APERS_SHIFT) | - (chip->prox_persistence << APDS990X_PPERS_SHIFT)); - - apds990x_write_byte(chip, APDS990X_PPCOUNT, chip->pdata->ppcount); - - /* Start with relatively small gain */ - chip->again_meas = 1; - chip->again_next = 1; - apds990x_write_byte(chip, APDS990X_CONTROL, - (chip->pdrive << 6) | - (chip->pdiode << 4) | - (chip->pgain << 2) | - (chip->again_next << 0)); - return 0; -} - -static int apds990x_detect(struct apds990x_chip *chip) -{ - struct i2c_client *client = chip->client; - int ret; - u8 id; - - ret = apds990x_read_byte(chip, APDS990X_ID, &id); - if (ret < 0) { - dev_err(&client->dev, "ID read failed\n"); - return ret; - } - - ret = apds990x_read_byte(chip, APDS990X_REV, &chip->revision); - if (ret < 0) { - dev_err(&client->dev, "REV read failed\n"); - return ret; - } - - switch (id) { - case APDS990X_ID_0: - case APDS990X_ID_4: - case APDS990X_ID_29: - snprintf(chip->chipname, sizeof(chip->chipname), "APDS-990x"); - break; - default: - ret = -ENODEV; - break; - } - return ret; -} - -#ifdef CONFIG_PM -static int apds990x_chip_on(struct apds990x_chip *chip) -{ - int err = regulator_bulk_enable(ARRAY_SIZE(chip->regs), - chip->regs); - if (err < 0) - return err; - - usleep_range(APDS_STARTUP_DELAY, 2 * APDS_STARTUP_DELAY); - - /* Refresh all configs in case of regulators were off */ - chip->prox_data = 0; - apds990x_configure(chip); - apds990x_mode_on(chip); - return 0; -} -#endif - -static int apds990x_chip_off(struct apds990x_chip *chip) -{ - apds990x_write_byte(chip, APDS990X_ENABLE, APDS990X_EN_DISABLE_ALL); - regulator_bulk_disable(ARRAY_SIZE(chip->regs), chip->regs); - return 0; -} - -static ssize_t apds990x_lux_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct apds990x_chip *chip = dev_get_drvdata(dev); - ssize_t ret; - u32 result; - long time_left; - - if (pm_runtime_suspended(dev)) - return -EIO; - - time_left = wait_event_interruptible_timeout(chip->wait, - !chip->lux_wait_fresh_res, - msecs_to_jiffies(APDS_TIMEOUT)); - if (!time_left) - return -EIO; - - mutex_lock(&chip->mutex); - result = (chip->lux * chip->lux_calib) / APDS_CALIB_SCALER; - if (result > (APDS_RANGE * APDS990X_LUX_OUTPUT_SCALE)) - result = APDS_RANGE * APDS990X_LUX_OUTPUT_SCALE; - - ret = sprintf(buf, "%d.%d\n", - result / APDS990X_LUX_OUTPUT_SCALE, - result % APDS990X_LUX_OUTPUT_SCALE); - mutex_unlock(&chip->mutex); - return ret; -} - -static DEVICE_ATTR(lux0_input, S_IRUGO, apds990x_lux_show, NULL); - -static ssize_t apds990x_lux_range_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%u\n", APDS_RANGE); -} - -static DEVICE_ATTR(lux0_sensor_range, S_IRUGO, apds990x_lux_range_show, NULL); - -static ssize_t apds990x_lux_calib_format_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%u\n", APDS_CALIB_SCALER); -} - -static DEVICE_ATTR(lux0_calibscale_default, S_IRUGO, - apds990x_lux_calib_format_show, NULL); - -static ssize_t apds990x_lux_calib_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct apds990x_chip *chip = dev_get_drvdata(dev); - - return sprintf(buf, "%u\n", chip->lux_calib); -} - -static ssize_t apds990x_lux_calib_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct apds990x_chip *chip = dev_get_drvdata(dev); - unsigned long value; - int ret; - - ret = kstrtoul(buf, 0, &value); - if (ret) - return ret; - - chip->lux_calib = value; - - return len; -} - -static DEVICE_ATTR(lux0_calibscale, S_IRUGO | S_IWUSR, apds990x_lux_calib_show, - apds990x_lux_calib_store); - -static ssize_t apds990x_rate_avail(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int i; - int pos = 0; - - for (i = 0; i < ARRAY_SIZE(arates_hz); i++) - pos += sprintf(buf + pos, "%d ", arates_hz[i]); - sprintf(buf + pos - 1, "\n"); - return pos; -} - -static ssize_t apds990x_rate_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct apds990x_chip *chip = dev_get_drvdata(dev); - - return sprintf(buf, "%d\n", chip->arate); -} - -static int apds990x_set_arate(struct apds990x_chip *chip, int rate) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(arates_hz); i++) - if (rate >= arates_hz[i]) - break; - - if (i == ARRAY_SIZE(arates_hz)) - return -EINVAL; - - /* Pick up corresponding persistence value */ - chip->lux_persistence = apersis[i]; - chip->arate = arates_hz[i]; - - /* If the chip is not in use, don't try to access it */ - if (pm_runtime_suspended(&chip->client->dev)) - return 0; - - /* Persistence levels */ - return apds990x_write_byte(chip, APDS990X_PERS, - (chip->lux_persistence << APDS990X_APERS_SHIFT) | - (chip->prox_persistence << APDS990X_PPERS_SHIFT)); -} - -static ssize_t apds990x_rate_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct apds990x_chip *chip = dev_get_drvdata(dev); - unsigned long value; - int ret; - - ret = kstrtoul(buf, 0, &value); - if (ret) - return ret; - - mutex_lock(&chip->mutex); - ret = apds990x_set_arate(chip, value); - mutex_unlock(&chip->mutex); - - if (ret < 0) - return ret; - return len; -} - -static DEVICE_ATTR(lux0_rate_avail, S_IRUGO, apds990x_rate_avail, NULL); - -static DEVICE_ATTR(lux0_rate, S_IRUGO | S_IWUSR, apds990x_rate_show, - apds990x_rate_store); - -static ssize_t apds990x_prox_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - ssize_t ret; - struct apds990x_chip *chip = dev_get_drvdata(dev); - - if (pm_runtime_suspended(dev) || !chip->prox_en) - return -EIO; - - mutex_lock(&chip->mutex); - ret = sprintf(buf, "%d\n", chip->prox_data); - mutex_unlock(&chip->mutex); - return ret; -} - -static DEVICE_ATTR(prox0_raw, S_IRUGO, apds990x_prox_show, NULL); - -static ssize_t apds990x_prox_range_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%u\n", APDS_PROX_RANGE); -} - -static DEVICE_ATTR(prox0_sensor_range, S_IRUGO, apds990x_prox_range_show, NULL); - -static ssize_t apds990x_prox_enable_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct apds990x_chip *chip = dev_get_drvdata(dev); - - return sprintf(buf, "%d\n", chip->prox_en); -} - -static ssize_t apds990x_prox_enable_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct apds990x_chip *chip = dev_get_drvdata(dev); - unsigned long value; - int ret; - - ret = kstrtoul(buf, 0, &value); - if (ret) - return ret; - - mutex_lock(&chip->mutex); - - if (!chip->prox_en) - chip->prox_data = 0; - - if (value) - chip->prox_en++; - else if (chip->prox_en > 0) - chip->prox_en--; - - if (!pm_runtime_suspended(dev)) - apds990x_mode_on(chip); - mutex_unlock(&chip->mutex); - return len; -} - -static DEVICE_ATTR(prox0_raw_en, S_IRUGO | S_IWUSR, apds990x_prox_enable_show, - apds990x_prox_enable_store); - -static const char *reporting_modes[] = {"trigger", "periodic"}; - -static ssize_t apds990x_prox_reporting_mode_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct apds990x_chip *chip = dev_get_drvdata(dev); - - return sprintf(buf, "%s\n", - reporting_modes[!!chip->prox_continuous_mode]); -} - -static ssize_t apds990x_prox_reporting_mode_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct apds990x_chip *chip = dev_get_drvdata(dev); - int ret; - - ret = sysfs_match_string(reporting_modes, buf); - if (ret < 0) - return ret; - - chip->prox_continuous_mode = ret; - return len; -} - -static DEVICE_ATTR(prox0_reporting_mode, S_IRUGO | S_IWUSR, - apds990x_prox_reporting_mode_show, - apds990x_prox_reporting_mode_store); - -static ssize_t apds990x_prox_reporting_avail_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%s %s\n", reporting_modes[0], reporting_modes[1]); -} - -static DEVICE_ATTR(prox0_reporting_mode_avail, S_IRUGO | S_IWUSR, - apds990x_prox_reporting_avail_show, NULL); - - -static ssize_t apds990x_lux_thresh_above_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct apds990x_chip *chip = dev_get_drvdata(dev); - - return sprintf(buf, "%d\n", chip->lux_thres_hi); -} - -static ssize_t apds990x_lux_thresh_below_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct apds990x_chip *chip = dev_get_drvdata(dev); - - return sprintf(buf, "%d\n", chip->lux_thres_lo); -} - -static ssize_t apds990x_set_lux_thresh(struct apds990x_chip *chip, u32 *target, - const char *buf) -{ - unsigned long thresh; - int ret; - - ret = kstrtoul(buf, 0, &thresh); - if (ret) - return ret; - - if (thresh > APDS_RANGE) - return -EINVAL; - - mutex_lock(&chip->mutex); - *target = thresh; - /* - * Don't update values in HW if we are still waiting for - * first interrupt to come after device handle open call. - */ - if (!chip->lux_wait_fresh_res) - apds990x_refresh_athres(chip); - mutex_unlock(&chip->mutex); - return ret; - -} - -static ssize_t apds990x_lux_thresh_above_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct apds990x_chip *chip = dev_get_drvdata(dev); - int ret = apds990x_set_lux_thresh(chip, &chip->lux_thres_hi, buf); - - if (ret < 0) - return ret; - return len; -} - -static ssize_t apds990x_lux_thresh_below_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct apds990x_chip *chip = dev_get_drvdata(dev); - int ret = apds990x_set_lux_thresh(chip, &chip->lux_thres_lo, buf); - - if (ret < 0) - return ret; - return len; -} - -static DEVICE_ATTR(lux0_thresh_above_value, S_IRUGO | S_IWUSR, - apds990x_lux_thresh_above_show, - apds990x_lux_thresh_above_store); - -static DEVICE_ATTR(lux0_thresh_below_value, S_IRUGO | S_IWUSR, - apds990x_lux_thresh_below_show, - apds990x_lux_thresh_below_store); - -static ssize_t apds990x_prox_threshold_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct apds990x_chip *chip = dev_get_drvdata(dev); - - return sprintf(buf, "%d\n", chip->prox_thres); -} - -static ssize_t apds990x_prox_threshold_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct apds990x_chip *chip = dev_get_drvdata(dev); - unsigned long value; - int ret; - - ret = kstrtoul(buf, 0, &value); - if (ret) - return ret; - - if ((value > APDS_RANGE) || (value == 0) || - (value < APDS_PROX_HYSTERESIS)) - return -EINVAL; - - mutex_lock(&chip->mutex); - chip->prox_thres = value; - - apds990x_force_p_refresh(chip); - mutex_unlock(&chip->mutex); - return len; -} - -static DEVICE_ATTR(prox0_thresh_above_value, S_IRUGO | S_IWUSR, - apds990x_prox_threshold_show, - apds990x_prox_threshold_store); - -static ssize_t apds990x_power_state_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", !pm_runtime_suspended(dev)); -} - -static ssize_t apds990x_power_state_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct apds990x_chip *chip = dev_get_drvdata(dev); - unsigned long value; - int ret; - - ret = kstrtoul(buf, 0, &value); - if (ret) - return ret; - - if (value) { - pm_runtime_get_sync(dev); - mutex_lock(&chip->mutex); - chip->lux_wait_fresh_res = true; - apds990x_force_a_refresh(chip); - apds990x_force_p_refresh(chip); - mutex_unlock(&chip->mutex); - } else { - if (!pm_runtime_suspended(dev)) - pm_runtime_put(dev); - } - return len; -} - -static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR, - apds990x_power_state_show, - apds990x_power_state_store); - -static ssize_t apds990x_chip_id_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct apds990x_chip *chip = dev_get_drvdata(dev); - - return sprintf(buf, "%s %d\n", chip->chipname, chip->revision); -} - -static DEVICE_ATTR(chip_id, S_IRUGO, apds990x_chip_id_show, NULL); - -static struct attribute *sysfs_attrs_ctrl[] = { - &dev_attr_lux0_calibscale.attr, - &dev_attr_lux0_calibscale_default.attr, - &dev_attr_lux0_input.attr, - &dev_attr_lux0_sensor_range.attr, - &dev_attr_lux0_rate.attr, - &dev_attr_lux0_rate_avail.attr, - &dev_attr_lux0_thresh_above_value.attr, - &dev_attr_lux0_thresh_below_value.attr, - &dev_attr_prox0_raw_en.attr, - &dev_attr_prox0_raw.attr, - &dev_attr_prox0_sensor_range.attr, - &dev_attr_prox0_thresh_above_value.attr, - &dev_attr_prox0_reporting_mode.attr, - &dev_attr_prox0_reporting_mode_avail.attr, - &dev_attr_chip_id.attr, - &dev_attr_power_state.attr, - NULL -}; - -static const struct attribute_group apds990x_attribute_group[] = { - {.attrs = sysfs_attrs_ctrl }, -}; - -static int apds990x_probe(struct i2c_client *client) -{ - struct apds990x_chip *chip; - int err; - - chip = kzalloc_obj(*chip); - if (!chip) - return -ENOMEM; - - i2c_set_clientdata(client, chip); - chip->client = client; - - init_waitqueue_head(&chip->wait); - mutex_init(&chip->mutex); - chip->pdata = client->dev.platform_data; - - if (chip->pdata == NULL) { - dev_err(&client->dev, "platform data is mandatory\n"); - err = -EINVAL; - goto fail1; - } - - if (chip->pdata->cf.ga == 0) { - /* set uncovered sensor default parameters */ - chip->cf.ga = 1966; /* 0.48 * APDS_PARAM_SCALE */ - chip->cf.cf1 = 4096; /* 1.00 * APDS_PARAM_SCALE */ - chip->cf.irf1 = 9134; /* 2.23 * APDS_PARAM_SCALE */ - chip->cf.cf2 = 2867; /* 0.70 * APDS_PARAM_SCALE */ - chip->cf.irf2 = 5816; /* 1.42 * APDS_PARAM_SCALE */ - chip->cf.df = 52; - } else { - chip->cf = chip->pdata->cf; - } - - /* precalculate inverse chip factors for threshold control */ - chip->rcf.afactor = - (chip->cf.irf1 - chip->cf.irf2) * APDS_PARAM_SCALE / - (chip->cf.cf1 - chip->cf.cf2); - chip->rcf.cf1 = APDS_PARAM_SCALE * APDS_PARAM_SCALE / - chip->cf.cf1; - chip->rcf.irf1 = chip->cf.irf1 * APDS_PARAM_SCALE / - chip->cf.cf1; - chip->rcf.cf2 = APDS_PARAM_SCALE * APDS_PARAM_SCALE / - chip->cf.cf2; - chip->rcf.irf2 = chip->cf.irf2 * APDS_PARAM_SCALE / - chip->cf.cf2; - - /* Set something to start with */ - chip->lux_thres_hi = APDS_LUX_DEF_THRES_HI; - chip->lux_thres_lo = APDS_LUX_DEF_THRES_LO; - chip->lux_calib = APDS_LUX_NEUTRAL_CALIB_VALUE; - - chip->prox_thres = APDS_PROX_DEF_THRES; - chip->pdrive = chip->pdata->pdrive; - chip->pdiode = APDS_PDIODE_IR; - chip->pgain = APDS_PGAIN_1X; - chip->prox_calib = APDS_PROX_NEUTRAL_CALIB_VALUE; - chip->prox_persistence = APDS_DEFAULT_PROX_PERS; - chip->prox_continuous_mode = false; - - chip->regs[0].supply = reg_vcc; - chip->regs[1].supply = reg_vled; - - err = regulator_bulk_get(&client->dev, - ARRAY_SIZE(chip->regs), chip->regs); - if (err < 0) { - dev_err(&client->dev, "Cannot get regulators\n"); - goto fail1; - } - - err = regulator_bulk_enable(ARRAY_SIZE(chip->regs), chip->regs); - if (err < 0) { - dev_err(&client->dev, "Cannot enable regulators\n"); - goto fail2; - } - - usleep_range(APDS_STARTUP_DELAY, 2 * APDS_STARTUP_DELAY); - - err = apds990x_detect(chip); - if (err < 0) { - dev_err(&client->dev, "APDS990X not found\n"); - goto fail3; - } - - pm_runtime_set_active(&client->dev); - - apds990x_configure(chip); - apds990x_set_arate(chip, APDS_LUX_DEFAULT_RATE); - apds990x_mode_on(chip); - - pm_runtime_enable(&client->dev); - - if (chip->pdata->setup_resources) { - err = chip->pdata->setup_resources(); - if (err) { - err = -EINVAL; - goto fail4; - } - } - - err = sysfs_create_group(&chip->client->dev.kobj, - apds990x_attribute_group); - if (err < 0) { - dev_err(&chip->client->dev, "Sysfs registration failed\n"); - goto fail5; - } - - err = request_threaded_irq(client->irq, NULL, - apds990x_irq, - IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW | - IRQF_ONESHOT, - "apds990x", chip); - if (err) { - dev_err(&client->dev, "could not get IRQ %d\n", - client->irq); - goto fail6; - } - return err; -fail6: - sysfs_remove_group(&chip->client->dev.kobj, - &apds990x_attribute_group[0]); -fail5: - if (chip->pdata && chip->pdata->release_resources) - chip->pdata->release_resources(); -fail4: - pm_runtime_disable(&client->dev); -fail3: - regulator_bulk_disable(ARRAY_SIZE(chip->regs), chip->regs); -fail2: - regulator_bulk_free(ARRAY_SIZE(chip->regs), chip->regs); -fail1: - kfree(chip); - return err; -} - -static void apds990x_remove(struct i2c_client *client) -{ - struct apds990x_chip *chip = i2c_get_clientdata(client); - - free_irq(client->irq, chip); - sysfs_remove_group(&chip->client->dev.kobj, - apds990x_attribute_group); - - if (chip->pdata && chip->pdata->release_resources) - chip->pdata->release_resources(); - - if (!pm_runtime_suspended(&client->dev)) - apds990x_chip_off(chip); - - pm_runtime_disable(&client->dev); - pm_runtime_set_suspended(&client->dev); - - regulator_bulk_free(ARRAY_SIZE(chip->regs), chip->regs); - - kfree(chip); -} - -#ifdef CONFIG_PM_SLEEP -static int apds990x_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct apds990x_chip *chip = i2c_get_clientdata(client); - - apds990x_chip_off(chip); - return 0; -} - -static int apds990x_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct apds990x_chip *chip = i2c_get_clientdata(client); - - /* - * If we were enabled at suspend time, it is expected - * everything works nice and smoothly. Chip_on is enough - */ - apds990x_chip_on(chip); - - return 0; -} -#endif - -#ifdef CONFIG_PM -static int apds990x_runtime_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct apds990x_chip *chip = i2c_get_clientdata(client); - - apds990x_chip_off(chip); - return 0; -} - -static int apds990x_runtime_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct apds990x_chip *chip = i2c_get_clientdata(client); - - apds990x_chip_on(chip); - return 0; -} - -#endif - -static const struct i2c_device_id apds990x_id[] = { - { "apds990x" }, - {} -}; - -MODULE_DEVICE_TABLE(i2c, apds990x_id); - -static const struct dev_pm_ops apds990x_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(apds990x_suspend, apds990x_resume) - SET_RUNTIME_PM_OPS(apds990x_runtime_suspend, - apds990x_runtime_resume, - NULL) -}; - -static struct i2c_driver apds990x_driver = { - .driver = { - .name = "apds990x", - .pm = &apds990x_pm_ops, - }, - .probe = apds990x_probe, - .remove = apds990x_remove, - .id_table = apds990x_id, -}; - -module_i2c_driver(apds990x_driver); - -MODULE_DESCRIPTION("APDS990X combined ALS and proximity sensor"); -MODULE_AUTHOR("Samu Onkalo, Nokia Corporation"); -MODULE_LICENSE("GPL v2"); diff --git a/include/linux/platform_data/apds990x.h b/include/linux/platform_data/apds990x.h deleted file mode 100644 index 37684f68c04f..000000000000 --- a/include/linux/platform_data/apds990x.h +++ /dev/null @@ -1,65 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * This file is part of the APDS990x sensor driver. - * Chip is combined proximity and ambient light sensor. - * - * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). - * - * Contact: Samu Onkalo - */ - -#ifndef __APDS990X_H__ -#define __APDS990X_H__ - - -#define APDS_IRLED_CURR_12mA 0x3 -#define APDS_IRLED_CURR_25mA 0x2 -#define APDS_IRLED_CURR_50mA 0x1 -#define APDS_IRLED_CURR_100mA 0x0 - -/** - * struct apds990x_chip_factors - defines effect of the cover window - * @ga: Total glass attenuation - * @cf1: clear channel factor 1 for raw to lux conversion - * @irf1: IR channel factor 1 for raw to lux conversion - * @cf2: clear channel factor 2 for raw to lux conversion - * @irf2: IR channel factor 2 for raw to lux conversion - * @df: device factor for conversion formulas - * - * Structure for tuning ALS calculation to match with environment. - * Values depend on the material above the sensor and the sensor - * itself. If the GA is zero, driver will use uncovered sensor default values - * format: decimal value * APDS_PARAM_SCALE except df which is plain integer. - */ -struct apds990x_chip_factors { - int ga; - int cf1; - int irf1; - int cf2; - int irf2; - int df; -}; -#define APDS_PARAM_SCALE 4096 - -/** - * struct apds990x_platform_data - platform data for apsd990x.c driver - * @cf: chip factor data - * @pdrive: IR-led driving current - * @ppcount: number of IR pulses used for proximity estimation - * @setup_resources: interrupt line setup call back function - * @release_resources: interrupt line release call back function - * - * Proximity detection result depends heavily on correct ppcount, pdrive - * and cover window. - * - */ - -struct apds990x_platform_data { - struct apds990x_chip_factors cf; - u8 pdrive; - u8 ppcount; - int (*setup_resources)(void); - int (*release_resources)(void); -}; - -#endif From 793e056d44b76e284afa33d47de4c5ac75c8941a Mon Sep 17 00:00:00 2001 From: Vishwas Rajashekar Date: Sat, 18 Apr 2026 00:11:09 +0530 Subject: [PATCH 090/266] dt-bindings: iio: gyroscope: add mount-matrix for bmg160 The mount-matrix property supplies a 3x3 matrix that is used to transform the values from the gyroscope to get vector values that are relative to the way the sensor has been mounted on the device. When the property is not specified, the identity matrix is used. This change adds mount-matrix as an optional property to the dt-bindings for the bmg160 gyroscope. Signed-off-by: Vishwas Rajashekar Reviewed-by: Rob Herring (Arm) Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/gyroscope/bosch,bmg160.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/gyroscope/bosch,bmg160.yaml b/Documentation/devicetree/bindings/iio/gyroscope/bosch,bmg160.yaml index fcbd4b430e48..8e094651381c 100644 --- a/Documentation/devicetree/bindings/iio/gyroscope/bosch,bmg160.yaml +++ b/Documentation/devicetree/bindings/iio/gyroscope/bosch,bmg160.yaml @@ -26,6 +26,9 @@ properties: vdd-supply: true vddio-supply: true + mount-matrix: + description: an optional 3x3 mounting rotation matrix. + spi-max-frequency: maximum: 10000000 @@ -56,6 +59,9 @@ examples: reg = <0x69>; interrupt-parent = <&gpio6>; interrupts = <18 IRQ_TYPE_EDGE_RISING>; + mount-matrix = "0", "1", "0", + "1", "0", "0", + "0", "0", "1"; }; }; ... From 129c5499819bee611ea1a05f8307692ff75161ce Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 20 Apr 2026 13:12:23 +0300 Subject: [PATCH 091/266] iio: backend: add devm_iio_backend_get_by_index() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a new function to get an IIO backend by its index in the io-backends device tree property. This is useful for multi-channel devices that have multiple backends, where looking up by index is more straightforward than using named backends. Extract __devm_iio_backend_fwnode_get_by_index() from the existing __devm_iio_backend_fwnode_get(), taking the index directly as a parameter. The new public API devm_iio_backend_get_by_index() uses the index to find the backend reference in the io-backends property, avoiding the need for io-backend-names. Reviewed-by: David Lechner Reviewed-by: Nuno Sá Signed-off-by: Antoniu Miclaus Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-backend.c | 53 +++++++++++++++++++++--------- include/linux/iio/backend.h | 1 + 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-backend.c index 10e689f49441..138ebebc9c0d 100644 --- a/drivers/iio/industrialio-backend.c +++ b/drivers/iio/industrialio-backend.c @@ -964,23 +964,13 @@ int iio_backend_data_transfer_addr(struct iio_backend *back, u32 address) } EXPORT_SYMBOL_NS_GPL(iio_backend_data_transfer_addr, "IIO_BACKEND"); -static struct iio_backend *__devm_iio_backend_fwnode_get(struct device *dev, const char *name, - struct fwnode_handle *fwnode) +static struct iio_backend *__devm_iio_backend_fwnode_get_by_index(struct device *dev, + struct fwnode_handle *fwnode, + unsigned int index) { struct iio_backend *back; - unsigned int index; int ret; - if (name) { - ret = device_property_match_string(dev, "io-backend-names", - name); - if (ret < 0) - return ERR_PTR(ret); - index = ret; - } else { - index = 0; - } - struct fwnode_handle *fwnode_back __free(fwnode_handle) = fwnode_find_reference(fwnode, "io-backends", index); if (IS_ERR(fwnode_back)) @@ -996,8 +986,7 @@ static struct iio_backend *__devm_iio_backend_fwnode_get(struct device *dev, con if (ret) return ERR_PTR(ret); - if (name) - back->idx = index; + back->idx = index; return back; } @@ -1005,6 +994,24 @@ static struct iio_backend *__devm_iio_backend_fwnode_get(struct device *dev, con return ERR_PTR(-EPROBE_DEFER); } +static struct iio_backend *__devm_iio_backend_fwnode_get(struct device *dev, const char *name, + struct fwnode_handle *fwnode) +{ + unsigned int index; + int ret; + + if (name) { + ret = device_property_match_string(dev, "io-backend-names", name); + if (ret < 0) + return ERR_PTR(ret); + index = ret; + } else { + index = 0; + } + + return __devm_iio_backend_fwnode_get_by_index(dev, fwnode, index); +} + /** * devm_iio_backend_get - Device managed backend device get * @dev: Consumer device for the backend @@ -1021,6 +1028,22 @@ struct iio_backend *devm_iio_backend_get(struct device *dev, const char *name) } EXPORT_SYMBOL_NS_GPL(devm_iio_backend_get, "IIO_BACKEND"); +/** + * devm_iio_backend_get_by_index - Device managed backend device get by index + * @dev: Consumer device for the backend + * @index: Index of the backend in the io-backends property + * + * Gets the backend at @index associated with @dev. + * + * RETURNS: + * A backend pointer, negative error pointer otherwise. + */ +struct iio_backend *devm_iio_backend_get_by_index(struct device *dev, unsigned int index) +{ + return __devm_iio_backend_fwnode_get_by_index(dev, dev_fwnode(dev), index); +} +EXPORT_SYMBOL_NS_GPL(devm_iio_backend_get_by_index, "IIO_BACKEND"); + /** * devm_iio_backend_fwnode_get - Device managed backend firmware node get * @dev: Consumer device for the backend diff --git a/include/linux/iio/backend.h b/include/linux/iio/backend.h index 4d15c2a9802c..3f95ed1fdf9e 100644 --- a/include/linux/iio/backend.h +++ b/include/linux/iio/backend.h @@ -261,6 +261,7 @@ int iio_backend_extend_chan_spec(struct iio_backend *back, bool iio_backend_has_caps(struct iio_backend *back, u32 caps); void *iio_backend_get_priv(const struct iio_backend *conv); struct iio_backend *devm_iio_backend_get(struct device *dev, const char *name); +struct iio_backend *devm_iio_backend_get_by_index(struct device *dev, unsigned int index); struct iio_backend *devm_iio_backend_fwnode_get(struct device *dev, const char *name, struct fwnode_handle *fwnode); From 80cc6d13d16d5c78cc088cea8a3d33ec853e3e22 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 20 Apr 2026 13:12:24 +0300 Subject: [PATCH 092/266] dt-bindings: iio: adc: ad4080: add AD4880 support Add support for the AD4880, a dual-channel 20-bit 40MSPS SAR ADC with integrated fully differential amplifiers (FDA). The AD4880 has two independent ADC channels, each with its own SPI configuration interface. This requires: - Two entries in reg property for primary and secondary channel chip selects - Two io-backends entries for the two data channels Acked-by: Conor Dooley Reviewed-by: David Lechner Signed-off-by: Antoniu Miclaus Signed-off-by: Jonathan Cameron --- .../bindings/iio/adc/adi,ad4080.yaml | 53 ++++++++++++++++++- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad4080.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad4080.yaml index 79df2696ef24..9c6a56c7c8ef 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad4080.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad4080.yaml @@ -18,7 +18,11 @@ description: | service a wide variety of precision, wide bandwidth data acquisition applications. + The AD4880 is a dual-channel variant with two independent ADC channels, + each with its own SPI configuration interface. + https://www.analog.com/media/en/technical-documentation/data-sheets/ad4080.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/ad4880.pdf $ref: /schemas/spi/spi-peripheral-props.yaml# @@ -34,9 +38,15 @@ properties: - adi,ad4086 - adi,ad4087 - adi,ad4088 + - adi,ad4880 reg: - maxItems: 1 + minItems: 1 + maxItems: 2 + description: + SPI chip select(s). For single-channel devices, one chip select. + For multi-channel devices like AD4880, two chip selects are required + as each channel has its own SPI configuration interface. spi-max-frequency: description: Configuration of the SPI bus. @@ -60,7 +70,10 @@ properties: vrefin-supply: true io-backends: - maxItems: 1 + minItems: 1 + items: + - description: Backend for channel A (primary) + - description: Backend for channel B (secondary) adi,lvds-cnv-enable: description: Enable the LVDS signal type on the CNV pin. Default is CMOS. @@ -81,6 +94,25 @@ required: - vdd33-supply - vrefin-supply +allOf: + - if: + properties: + compatible: + contains: + const: adi,ad4880 + then: + properties: + reg: + minItems: 2 + io-backends: + minItems: 2 + else: + properties: + reg: + maxItems: 1 + io-backends: + maxItems: 1 + additionalProperties: false examples: @@ -101,4 +133,21 @@ examples: io-backends = <&iio_backend>; }; }; + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + + adc@0 { + compatible = "adi,ad4880"; + reg = <0>, <1>; + spi-max-frequency = <10000000>; + vdd33-supply = <&vdd33>; + vddldo-supply = <&vddldo>; + vrefin-supply = <&vrefin>; + clocks = <&cnv>; + clock-names = "cnv"; + io-backends = <&iio_backend_cha>, <&iio_backend_chb>; + }; + }; ... From 370461ac8d51c530e7194efd4764dcb738dc52d7 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 20 Apr 2026 13:12:25 +0300 Subject: [PATCH 093/266] iio: adc: ad4080: add support for AD4880 dual-channel ADC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the AD4880, a dual-channel 20-bit 40MSPS SAR ADC with integrated fully differential amplifiers (FDA). The AD4880 has two independent ADC channels, each with its own SPI configuration interface. The driver uses spi_new_ancillary_device() to create an additional SPI device for the second channel, allowing both channels to share the same SPI bus with different chip selects. Reviewed-by: David Lechner Reviewed-by: Nuno Sá Signed-off-by: Antoniu Miclaus Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad4080.c | 257 +++++++++++++++++++++++++++++---------- 1 file changed, 195 insertions(+), 62 deletions(-) diff --git a/drivers/iio/adc/ad4080.c b/drivers/iio/adc/ad4080.c index 204ad198342b..265d85ac171a 100644 --- a/drivers/iio/adc/ad4080.c +++ b/drivers/iio/adc/ad4080.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -134,6 +135,9 @@ #define AD4086_CHIP_ID 0x0056 #define AD4087_CHIP_ID 0x0057 #define AD4088_CHIP_ID 0x0058 +#define AD4880_CHIP_ID 0x0750 + +#define AD4080_MAX_CHANNELS 2 #define AD4080_LVDS_CNV_CLK_CNT_MAX 7 @@ -179,8 +183,9 @@ struct ad4080_chip_info { }; struct ad4080_state { - struct regmap *regmap; - struct iio_backend *back; + struct spi_device *spi[AD4080_MAX_CHANNELS]; + struct regmap *regmap[AD4080_MAX_CHANNELS]; + struct iio_backend *back[AD4080_MAX_CHANNELS]; const struct ad4080_chip_info *info; /* * Synchronize access to members the of driver state, and ensure @@ -189,7 +194,7 @@ struct ad4080_state { struct mutex lock; unsigned int num_lanes; unsigned long clk_rate; - enum ad4080_filter_type filter_type; + enum ad4080_filter_type filter_type[AD4080_MAX_CHANNELS]; bool lvds_cnv_en; }; @@ -206,9 +211,9 @@ static int ad4080_reg_access(struct iio_dev *indio_dev, unsigned int reg, struct ad4080_state *st = iio_priv(indio_dev); if (readval) - return regmap_read(st->regmap, reg, readval); + return regmap_read(st->regmap[0], reg, readval); - return regmap_write(st->regmap, reg, writeval); + return regmap_write(st->regmap[0], reg, writeval); } static int ad4080_get_scale(struct ad4080_state *st, int *val, int *val2) @@ -229,8 +234,9 @@ static unsigned int ad4080_get_dec_rate(struct iio_dev *dev, struct ad4080_state *st = iio_priv(dev); int ret; unsigned int data; + unsigned int ch = chan->channel; - ret = regmap_read(st->regmap, AD4080_REG_FILTER_CONFIG, &data); + ret = regmap_read(st->regmap[ch], AD4080_REG_FILTER_CONFIG, &data); if (ret) return ret; @@ -242,13 +248,14 @@ static int ad4080_set_dec_rate(struct iio_dev *dev, unsigned int mode) { struct ad4080_state *st = iio_priv(dev); + unsigned int ch = chan->channel; guard(mutex)(&st->lock); - if ((st->filter_type >= SINC_5 && mode >= 512) || mode < 2) + if ((st->filter_type[ch] >= SINC_5 && mode >= 512) || mode < 2) return -EINVAL; - return regmap_update_bits(st->regmap, AD4080_REG_FILTER_CONFIG, + return regmap_update_bits(st->regmap[ch], AD4080_REG_FILTER_CONFIG, AD4080_FILTER_CONFIG_SINC_DEC_RATE_MSK, FIELD_PREP(AD4080_FILTER_CONFIG_SINC_DEC_RATE_MSK, (ilog2(mode) - 1))); @@ -268,15 +275,15 @@ static int ad4080_read_raw(struct iio_dev *indio_dev, dec_rate = ad4080_get_dec_rate(indio_dev, chan); if (dec_rate < 0) return dec_rate; - if (st->filter_type == SINC_5_COMP) + if (st->filter_type[chan->channel] == SINC_5_COMP) dec_rate *= 2; - if (st->filter_type) + if (st->filter_type[chan->channel]) *val = DIV_ROUND_CLOSEST(st->clk_rate, dec_rate); else *val = st->clk_rate; return IIO_VAL_INT; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - if (st->filter_type == FILTER_NONE) { + if (st->filter_type[chan->channel] == FILTER_NONE) { *val = 1; } else { *val = ad4080_get_dec_rate(indio_dev, chan); @@ -297,7 +304,7 @@ static int ad4080_write_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - if (st->filter_type == FILTER_NONE && val > 1) + if (st->filter_type[chan->channel] == FILTER_NONE && val > 1) return -EINVAL; return ad4080_set_dec_rate(indio_dev, chan, val); @@ -306,23 +313,23 @@ static int ad4080_write_raw(struct iio_dev *indio_dev, } } -static int ad4080_lvds_sync_write(struct ad4080_state *st) +static int ad4080_lvds_sync_write(struct ad4080_state *st, unsigned int ch) { - struct device *dev = regmap_get_device(st->regmap); + struct device *dev = regmap_get_device(st->regmap[ch]); int ret; - ret = regmap_set_bits(st->regmap, AD4080_REG_ADC_DATA_INTF_CONFIG_A, + ret = regmap_set_bits(st->regmap[ch], AD4080_REG_ADC_DATA_INTF_CONFIG_A, AD4080_ADC_DATA_INTF_CONFIG_A_INTF_CHK_EN); if (ret) return ret; - ret = iio_backend_interface_data_align(st->back, 10000); + ret = iio_backend_interface_data_align(st->back[ch], 10000); if (ret) return dev_err_probe(dev, ret, "Data alignment process failed\n"); dev_dbg(dev, "Success: Pattern correct and Locked!\n"); - return regmap_clear_bits(st->regmap, AD4080_REG_ADC_DATA_INTF_CONFIG_A, + return regmap_clear_bits(st->regmap[ch], AD4080_REG_ADC_DATA_INTF_CONFIG_A, AD4080_ADC_DATA_INTF_CONFIG_A_INTF_CHK_EN); } @@ -331,9 +338,10 @@ static int ad4080_get_filter_type(struct iio_dev *dev, { struct ad4080_state *st = iio_priv(dev); unsigned int data; + unsigned int ch = chan->channel; int ret; - ret = regmap_read(st->regmap, AD4080_REG_FILTER_CONFIG, &data); + ret = regmap_read(st->regmap[ch], AD4080_REG_FILTER_CONFIG, &data); if (ret) return ret; @@ -345,6 +353,7 @@ static int ad4080_set_filter_type(struct iio_dev *dev, unsigned int mode) { struct ad4080_state *st = iio_priv(dev); + unsigned int ch = chan->channel; int dec_rate; int ret; @@ -357,18 +366,18 @@ static int ad4080_set_filter_type(struct iio_dev *dev, if (mode >= SINC_5 && dec_rate >= 512) return -EINVAL; - ret = iio_backend_filter_type_set(st->back, mode); + ret = iio_backend_filter_type_set(st->back[ch], mode); if (ret) return ret; - ret = regmap_update_bits(st->regmap, AD4080_REG_FILTER_CONFIG, + ret = regmap_update_bits(st->regmap[ch], AD4080_REG_FILTER_CONFIG, AD4080_FILTER_CONFIG_FILTER_SEL_MSK, FIELD_PREP(AD4080_FILTER_CONFIG_FILTER_SEL_MSK, mode)); if (ret) return ret; - st->filter_type = mode; + st->filter_type[ch] = mode; return 0; } @@ -382,14 +391,14 @@ static int ad4080_read_avail(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - switch (st->filter_type) { + switch (st->filter_type[chan->channel]) { case FILTER_NONE: *vals = ad4080_dec_rate_none; *length = ARRAY_SIZE(ad4080_dec_rate_none); break; default: *vals = ad4080_dec_rate_avail; - *length = st->filter_type >= SINC_5 ? + *length = st->filter_type[chan->channel] >= SINC_5 ? (ARRAY_SIZE(ad4080_dec_rate_avail) - 2) : ARRAY_SIZE(ad4080_dec_rate_avail); break; @@ -401,6 +410,28 @@ static int ad4080_read_avail(struct iio_dev *indio_dev, } } +static int ad4880_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *scan_mask) +{ + struct ad4080_state *st = iio_priv(indio_dev); + int ret; + + for (unsigned int ch = 0; ch < st->info->num_channels; ch++) { + /* + * Each backend has a single channel (channel 0 from the + * backend's perspective), so always use channel index 0. + */ + if (test_bit(ch, scan_mask)) + ret = iio_backend_chan_enable(st->back[ch], 0); + else + ret = iio_backend_chan_disable(st->back[ch], 0); + if (ret) + return ret; + } + + return 0; +} + static const struct iio_info ad4080_iio_info = { .debugfs_reg_access = ad4080_reg_access, .read_raw = ad4080_read_raw, @@ -408,6 +439,19 @@ static const struct iio_info ad4080_iio_info = { .read_avail = ad4080_read_avail, }; +/* + * AD4880 needs update_scan_mode to enable/disable individual backend channels. + * Single-channel devices don't need this as their backends may not implement + * chan_enable/chan_disable operations. + */ +static const struct iio_info ad4880_iio_info = { + .debugfs_reg_access = ad4080_reg_access, + .read_raw = ad4080_read_raw, + .write_raw = ad4080_write_raw, + .read_avail = ad4080_read_avail, + .update_scan_mode = ad4880_update_scan_mode, +}; + static const struct iio_enum ad4080_filter_type_enum = { .items = ad4080_filter_type_iio_enum, .num_items = ARRAY_SIZE(ad4080_filter_type_iio_enum), @@ -422,17 +466,28 @@ static struct iio_chan_spec_ext_info ad4080_ext_info[] = { { } }; -#define AD4080_CHANNEL_DEFINE(bits, storage) { \ +/* + * AD4880 needs per-channel filter configuration since each channel has + * its own independent ADC with separate SPI interface. + */ +static struct iio_chan_spec_ext_info ad4880_ext_info[] = { + IIO_ENUM("filter_type", IIO_SEPARATE, &ad4080_filter_type_enum), + IIO_ENUM_AVAILABLE("filter_type", IIO_SEPARATE, + &ad4080_filter_type_enum), + { } +}; + +#define AD4080_CHANNEL_DEFINE(bits, storage, idx) { \ .type = IIO_VOLTAGE, \ .indexed = 1, \ - .channel = 0, \ + .channel = (idx), \ .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_index = (idx), \ .scan_type = { \ .sign = 's', \ .realbits = (bits), \ @@ -440,23 +495,51 @@ static struct iio_chan_spec_ext_info ad4080_ext_info[] = { }, \ } -static const struct iio_chan_spec ad4080_channel = AD4080_CHANNEL_DEFINE(20, 32); +/* + * AD4880 has per-channel attributes (filter_type, oversampling_ratio, + * sampling_frequency) since each channel has its own independent ADC + * with separate SPI configuration interface. + */ +#define AD4880_CHANNEL_DEFINE(bits, storage, idx) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = (idx), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .info_mask_separate_available = \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .ext_info = ad4880_ext_info, \ + .scan_index = (idx), \ + .scan_type = { \ + .sign = 's', \ + .realbits = (bits), \ + .storagebits = (storage), \ + }, \ +} -static const struct iio_chan_spec ad4081_channel = AD4080_CHANNEL_DEFINE(20, 32); +static const struct iio_chan_spec ad4080_channel = AD4080_CHANNEL_DEFINE(20, 32, 0); -static const struct iio_chan_spec ad4082_channel = AD4080_CHANNEL_DEFINE(20, 32); +static const struct iio_chan_spec ad4081_channel = AD4080_CHANNEL_DEFINE(20, 32, 0); -static const struct iio_chan_spec ad4083_channel = AD4080_CHANNEL_DEFINE(16, 16); +static const struct iio_chan_spec ad4082_channel = AD4080_CHANNEL_DEFINE(20, 32, 0); -static const struct iio_chan_spec ad4084_channel = AD4080_CHANNEL_DEFINE(16, 16); +static const struct iio_chan_spec ad4083_channel = AD4080_CHANNEL_DEFINE(16, 16, 0); -static const struct iio_chan_spec ad4085_channel = AD4080_CHANNEL_DEFINE(16, 16); +static const struct iio_chan_spec ad4084_channel = AD4080_CHANNEL_DEFINE(16, 16, 0); -static const struct iio_chan_spec ad4086_channel = AD4080_CHANNEL_DEFINE(14, 16); +static const struct iio_chan_spec ad4085_channel = AD4080_CHANNEL_DEFINE(16, 16, 0); -static const struct iio_chan_spec ad4087_channel = AD4080_CHANNEL_DEFINE(14, 16); +static const struct iio_chan_spec ad4086_channel = AD4080_CHANNEL_DEFINE(14, 16, 0); -static const struct iio_chan_spec ad4088_channel = AD4080_CHANNEL_DEFINE(14, 16); +static const struct iio_chan_spec ad4087_channel = AD4080_CHANNEL_DEFINE(14, 16, 0); + +static const struct iio_chan_spec ad4088_channel = AD4080_CHANNEL_DEFINE(14, 16, 0); + +static const struct iio_chan_spec ad4880_channels[] = { + AD4880_CHANNEL_DEFINE(20, 32, 0), + AD4880_CHANNEL_DEFINE(20, 32, 1), +}; static const struct ad4080_chip_info ad4080_chip_info = { .name = "ad4080", @@ -548,25 +631,34 @@ static const struct ad4080_chip_info ad4088_chip_info = { .lvds_cnv_clk_cnt_max = 8, }; -static int ad4080_setup(struct iio_dev *indio_dev) +static const struct ad4080_chip_info ad4880_chip_info = { + .name = "ad4880", + .product_id = AD4880_CHIP_ID, + .scale_table = ad4080_scale_table, + .num_scales = ARRAY_SIZE(ad4080_scale_table), + .num_channels = 2, + .channels = ad4880_channels, + .lvds_cnv_clk_cnt_max = AD4080_LVDS_CNV_CLK_CNT_MAX, +}; + +static int ad4080_setup_channel(struct ad4080_state *st, unsigned int ch) { - struct ad4080_state *st = iio_priv(indio_dev); - struct device *dev = regmap_get_device(st->regmap); + struct device *dev = regmap_get_device(st->regmap[ch]); __le16 id_le; u16 id; int ret; - ret = regmap_write(st->regmap, AD4080_REG_INTERFACE_CONFIG_A, + ret = regmap_write(st->regmap[ch], AD4080_REG_INTERFACE_CONFIG_A, AD4080_INTERFACE_CONFIG_A_SW_RESET); if (ret) return ret; - ret = regmap_write(st->regmap, AD4080_REG_INTERFACE_CONFIG_A, + ret = regmap_write(st->regmap[ch], AD4080_REG_INTERFACE_CONFIG_A, AD4080_INTERFACE_CONFIG_A_SDO_ENABLE); if (ret) return ret; - ret = regmap_bulk_read(st->regmap, AD4080_REG_PRODUCT_ID_L, &id_le, + ret = regmap_bulk_read(st->regmap[ch], AD4080_REG_PRODUCT_ID_L, &id_le, sizeof(id_le)); if (ret) return ret; @@ -575,18 +667,18 @@ static int ad4080_setup(struct iio_dev *indio_dev) 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, + ret = regmap_set_bits(st->regmap[ch], AD4080_REG_GPIO_CONFIG_A, AD4080_GPIO_CONFIG_A_GPO_1_EN); if (ret) return ret; - ret = regmap_write(st->regmap, AD4080_REG_GPIO_CONFIG_B, + ret = regmap_write(st->regmap[ch], AD4080_REG_GPIO_CONFIG_B, FIELD_PREP(AD4080_GPIO_CONFIG_B_GPIO_1_SEL_MSK, AD4080_GPIO_CONFIG_B_GPIO_FILTER_RES_RDY)); if (ret) return ret; - ret = iio_backend_num_lanes_set(st->back, st->num_lanes); + ret = iio_backend_num_lanes_set(st->back[ch], st->num_lanes); if (ret) return ret; @@ -594,7 +686,7 @@ static int ad4080_setup(struct iio_dev *indio_dev) return 0; /* Set maximum LVDS Data Transfer Latency */ - ret = regmap_update_bits(st->regmap, + ret = regmap_update_bits(st->regmap[ch], 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, @@ -603,24 +695,38 @@ static int ad4080_setup(struct iio_dev *indio_dev) return ret; if (st->num_lanes > 1) { - ret = regmap_set_bits(st->regmap, AD4080_REG_ADC_DATA_INTF_CONFIG_A, + ret = regmap_set_bits(st->regmap[ch], AD4080_REG_ADC_DATA_INTF_CONFIG_A, AD4080_ADC_DATA_INTF_CONFIG_A_SPI_LVDS_LANES); if (ret) return ret; } - ret = regmap_set_bits(st->regmap, + ret = regmap_set_bits(st->regmap[ch], AD4080_REG_ADC_DATA_INTF_CONFIG_B, AD4080_ADC_DATA_INTF_CONFIG_B_LVDS_CNV_EN); if (ret) return ret; - return ad4080_lvds_sync_write(st); + return ad4080_lvds_sync_write(st, ch); } -static int ad4080_properties_parse(struct ad4080_state *st) +static int ad4080_setup(struct iio_dev *indio_dev) +{ + struct ad4080_state *st = iio_priv(indio_dev); + int ret; + + for (unsigned int ch = 0; ch < st->info->num_channels; ch++) { + ret = ad4080_setup_channel(st, ch); + if (ret) + return ret; + } + + return 0; +} + +static int ad4080_properties_parse(struct ad4080_state *st, + struct device *dev) { - struct device *dev = regmap_get_device(st->regmap); st->lvds_cnv_en = device_property_read_bool(dev, "adi,lvds-cnv-enable"); @@ -655,14 +761,28 @@ static int ad4080_probe(struct spi_device *spi) return dev_err_probe(dev, ret, "failed to get and enable supplies\n"); - st->regmap = devm_regmap_init_spi(spi, &ad4080_regmap_config); - if (IS_ERR(st->regmap)) - return PTR_ERR(st->regmap); + /* Setup primary SPI device (channel 0) */ + st->spi[0] = spi; + st->regmap[0] = devm_regmap_init_spi(spi, &ad4080_regmap_config); + if (IS_ERR(st->regmap[0])) + return PTR_ERR(st->regmap[0]); st->info = spi_get_device_match_data(spi); if (!st->info) return -ENODEV; + /* Setup ancillary SPI devices for additional channels */ + for (unsigned int ch = 1; ch < st->info->num_channels; ch++) { + st->spi[ch] = devm_spi_new_ancillary_device(spi, spi_get_chipselect(spi, ch)); + if (IS_ERR(st->spi[ch])) + return dev_err_probe(dev, PTR_ERR(st->spi[ch]), + "failed to register ancillary device\n"); + + st->regmap[ch] = devm_regmap_init_spi(st->spi[ch], &ad4080_regmap_config); + if (IS_ERR(st->regmap[ch])) + return PTR_ERR(st->regmap[ch]); + } + ret = devm_mutex_init(dev, &st->lock); if (ret) return ret; @@ -670,9 +790,10 @@ static int ad4080_probe(struct spi_device *spi) indio_dev->name = st->info->name; indio_dev->channels = st->info->channels; indio_dev->num_channels = st->info->num_channels; - indio_dev->info = &ad4080_iio_info; + indio_dev->info = st->info->num_channels > 1 ? + &ad4880_iio_info : &ad4080_iio_info; - ret = ad4080_properties_parse(st); + ret = ad4080_properties_parse(st, dev); if (ret) return ret; @@ -682,15 +803,25 @@ static int ad4080_probe(struct spi_device *spi) st->clk_rate = clk_get_rate(clk); - st->back = devm_iio_backend_get(dev, NULL); - if (IS_ERR(st->back)) - return PTR_ERR(st->back); + /* Get backends for all channels */ + for (unsigned int ch = 0; ch < st->info->num_channels; ch++) { + st->back[ch] = devm_iio_backend_get_by_index(dev, ch); + if (IS_ERR(st->back[ch])) + return PTR_ERR(st->back[ch]); - ret = devm_iio_backend_request_buffer(dev, st->back, indio_dev); - if (ret) - return ret; + ret = devm_iio_backend_enable(dev, st->back[ch]); + if (ret) + return ret; + } - ret = devm_iio_backend_enable(dev, st->back); + /* + * Request buffer from the first backend only. For multi-channel + * devices (e.g., AD4880), the FPGA uses two axi_ad408x IP instances + * (one per ADC channel) whose outputs are combined by a packer block + * that interleaves all channel data into a single DMA stream routed + * through the first backend's clock domain. + */ + ret = devm_iio_backend_request_buffer(dev, st->back[0], indio_dev); if (ret) return ret; @@ -711,6 +842,7 @@ static const struct spi_device_id ad4080_id[] = { { "ad4086", (kernel_ulong_t)&ad4086_chip_info }, { "ad4087", (kernel_ulong_t)&ad4087_chip_info }, { "ad4088", (kernel_ulong_t)&ad4088_chip_info }, + { "ad4880", (kernel_ulong_t)&ad4880_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad4080_id); @@ -725,6 +857,7 @@ static const struct of_device_id ad4080_of_match[] = { { .compatible = "adi,ad4086", &ad4086_chip_info }, { .compatible = "adi,ad4087", &ad4087_chip_info }, { .compatible = "adi,ad4088", &ad4088_chip_info }, + { .compatible = "adi,ad4880", &ad4880_chip_info }, { } }; MODULE_DEVICE_TABLE(of, ad4080_of_match); From 74c3923344c6ad4b7199948d54dc947504c39483 Mon Sep 17 00:00:00 2001 From: Sanjay Chitroda Date: Sun, 26 Apr 2026 14:47:02 +0530 Subject: [PATCH 094/266] iio: ssp_sensors: cleanup codestyle warning Reported by checkpatch: FILE: drivers/iio/common/ssp_sensors/ssp_dev.c WARNING: Prefer __packed over __attribute__((__packed__)) +} __attribute__((__packed__)); Signed-off-by: Sanjay Chitroda Signed-off-by: Jonathan Cameron --- drivers/iio/common/ssp_sensors/ssp_dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/common/ssp_sensors/ssp_dev.c b/drivers/iio/common/ssp_sensors/ssp_dev.c index da09c9f3ceb6..7d07fae295fd 100644 --- a/drivers/iio/common/ssp_sensors/ssp_dev.c +++ b/drivers/iio/common/ssp_sensors/ssp_dev.c @@ -28,7 +28,7 @@ struct ssp_instruction { __le32 a; __le32 b; u8 c; -} __attribute__((__packed__)); +} __packed__; static const u8 ssp_magnitude_table[] = {110, 85, 171, 71, 203, 195, 0, 67, 208, 56, 175, 244, 206, 213, 0, 92, 250, 0, 55, 48, 189, 252, 171, From c09f950fd87ad6505cc7bdbac4e0a125b6ed313c Mon Sep 17 00:00:00 2001 From: Giorgi Tchankvetadze Date: Sat, 25 Apr 2026 11:16:16 +0400 Subject: [PATCH 095/266] iio: adc: ad7625: fix type mismatch in clamp() macro clamp() expects compatible operand types. The period calculation uses nanosecond constants, while the local target variable was narrower than the upper bound expression. Make target unsigned long and use unsigned long bounds, including NSEC_PER_USEC for the upper limit. This keeps the operands naturally aligned without adding casts. Suggested-by: Andy Shevchenko Signed-off-by: Giorgi Tchankvetadze Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7625.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/ad7625.c b/drivers/iio/adc/ad7625.c index 0466c0c7eae4..f1ee29f35fa8 100644 --- a/drivers/iio/adc/ad7625.c +++ b/drivers/iio/adc/ad7625.c @@ -175,12 +175,12 @@ enum ad7960_mode { static int ad7625_set_sampling_freq(struct ad7625_state *st, u32 freq) { - u32 target; struct pwm_waveform clk_gate_wf = { }, cnv_wf = { }; + unsigned long target; int ret; target = DIV_ROUND_UP(NSEC_PER_SEC, freq); - cnv_wf.period_length_ns = clamp(target, 100, 10 * KILO); + cnv_wf.period_length_ns = clamp(target, 100UL, 10UL * NSEC_PER_USEC); /* * Use the maximum conversion time t_CNVH from the datasheet as From 2e43816512876d41a7ce1771ba949b846f5bb7dd Mon Sep 17 00:00:00 2001 From: Alexis Czezar Torreno Date: Mon, 27 Apr 2026 14:23:16 +0800 Subject: [PATCH 096/266] dt-bindings: iio: dac: Add ADI AD5706R Add device tree binding documentation for the Analog Devices AD5706R 4-channel 16-bit current output digital-to-analog converter. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexis Czezar Torreno Signed-off-by: Jonathan Cameron --- .../bindings/iio/dac/adi,ad5706r.yaml | 105 ++++++++++++++++++ MAINTAINERS | 7 ++ 2 files changed, 112 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/dac/adi,ad5706r.yaml diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5706r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5706r.yaml new file mode 100644 index 000000000000..19cc744a9f0f --- /dev/null +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5706r.yaml @@ -0,0 +1,105 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/dac/adi,ad5706r.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices AD5706R 4-Channel Current Output DAC + +maintainers: + - Alexis Czezar Torreno + +description: | + The AD5706R is a 4-channel, 16-bit resolution, current output + digital-to-analog converter (DAC) with programmable output current + ranges (50mA, 150mA, 200mA, 300mA), an integrated 2.5V voltage + reference, and load DAC, A/B toggle, and dither functions. + + Datasheet: + https://www.analog.com/en/products/ad5706r.html + +properties: + compatible: + enum: + - adi,ad5706r + + reg: + maxItems: 1 + + avdd-supply: + description: Analog power supply (2.9V to 3.6V). + + iovdd-supply: + description: Logic power supply (1.14V to 1.89V). + + pvdd0-supply: + description: Power supply for IDAC0 channel (1.65V to AVDD). + + pvdd1-supply: + description: Power supply for IDAC1 channel (1.65V to AVDD). + + pvdd2-supply: + description: Power supply for IDAC2 channel (1.65V to AVDD). + + pvdd3-supply: + description: Power supply for IDAC3 channel (1.65V to AVDD). + + vref-supply: + description: + Optional external 2.5V voltage reference. If not provided, the + internal 2.5V reference is used. + + pwms: + maxItems: 1 + description: + Optional PWM connected to the LDAC/TGP/DCK pin for hardware + triggered DAC updates, toggle, or dither clock generation. + + reset-gpios: + maxItems: 1 + description: + GPIO connected to the active low RESET pin. If not provided, + software reset is used. + + enable-gpios: + maxItems: 1 + description: + GPIO connected to the active low OUT_EN pin. Controls whether + the current outputs are enabled or in high-Z/ground state. + +required: + - compatible + - reg + - avdd-supply + - iovdd-supply + +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + + spi { + #address-cells = <1>; + #size-cells = <0>; + + dac@0 { + compatible = "adi,ad5706r"; + reg = <0>; + avdd-supply = <&avdd>; + iovdd-supply = <&iovdd>; + pvdd0-supply = <&pvdd>; + pvdd1-supply = <&pvdd>; + pvdd2-supply = <&pvdd>; + pvdd3-supply = <&pvdd>; + vref-supply = <&vref>; + spi-max-frequency = <50000000>; + pwms = <&pwm0 0 1000000 0>; + reset-gpios = <&gpio0 10 GPIO_ACTIVE_LOW>; + enable-gpios = <&gpio0 12 GPIO_ACTIVE_LOW>; + }; + }; +... diff --git a/MAINTAINERS b/MAINTAINERS index 2fb1c75afd16..fff2bf304357 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1498,6 +1498,13 @@ W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/adc/adi,ad4851.yaml F: drivers/iio/adc/ad4851.c +ANALOG DEVICES INC AD5706R DRIVER +M: Alexis Czezar Torreno +L: linux-iio@vger.kernel.org +S: Supported +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/iio/dac/adi,ad5706r.yaml + ANALOG DEVICES INC AD7091R DRIVER M: Marcelo Schmitt L: linux-iio@vger.kernel.org From 081ce276d801d7c0a3dc41aa9a02ff73eb96c94a Mon Sep 17 00:00:00 2001 From: Alexis Czezar Torreno Date: Mon, 27 Apr 2026 14:23:17 +0800 Subject: [PATCH 097/266] iio: dac: ad5706r: Add support for AD5706R DAC Add support for the Analog Devices AD5706R, a 4-channel 16-bit current output digital-to-analog converter with SPI interface. Reviewed-by: Andy Shevchenko Signed-off-by: Alexis Czezar Torreno Signed-off-by: Jonathan Cameron --- MAINTAINERS | 1 + drivers/iio/dac/Kconfig | 11 ++ drivers/iio/dac/Makefile | 1 + drivers/iio/dac/ad5706r.c | 253 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 266 insertions(+) create mode 100644 drivers/iio/dac/ad5706r.c diff --git a/MAINTAINERS b/MAINTAINERS index fff2bf304357..31c4db07e99b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1504,6 +1504,7 @@ L: linux-iio@vger.kernel.org S: Supported W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/dac/adi,ad5706r.yaml +F: drivers/iio/dac/ad5706r.c ANALOG DEVICES INC AD7091R DRIVER M: Marcelo Schmitt diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index cd4870b65415..657c68e75542 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -178,6 +178,17 @@ config AD5624R_SPI Say yes here to build support for Analog Devices AD5624R, AD5644R and AD5664R converters (DAC). This driver uses the common SPI interface. +config AD5706R + tristate "Analog Devices AD5706R DAC driver" + depends on SPI + select REGMAP + help + Say yes here to build support for Analog Devices AD5706R 4-channel, + 16-bit current output DAC. + + To compile this driver as a module, choose M here: the + module will be called ad5706r. + config AD9739A tristate "Analog Devices AD9739A RF DAC spi driver" depends on SPI diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile index 2a80bbf4e80a..003431798498 100644 --- a/drivers/iio/dac/Makefile +++ b/drivers/iio/dac/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_AD5449) += ad5449.o obj-$(CONFIG_AD5592R_BASE) += ad5592r-base.o obj-$(CONFIG_AD5592R) += ad5592r.o obj-$(CONFIG_AD5593R) += ad5593r.o +obj-$(CONFIG_AD5706R) += ad5706r.o obj-$(CONFIG_AD5755) += ad5755.o obj-$(CONFIG_AD5758) += ad5758.o obj-$(CONFIG_AD5761) += ad5761.o diff --git a/drivers/iio/dac/ad5706r.c b/drivers/iio/dac/ad5706r.c new file mode 100644 index 000000000000..f7872e92dc01 --- /dev/null +++ b/drivers/iio/dac/ad5706r.c @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * AD5706R 16-bit Current Output Digital to Analog Converter + * + * Copyright 2026 Analog Devices Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* SPI frame layout */ +#define AD5706R_RD_MASK BIT(15) +#define AD5706R_ADDR_MASK GENMASK(11, 0) + +/* Registers */ +#define AD5706R_REG_DAC_INPUT_A_CH(x) (0x60 + ((x) * 2)) +#define AD5706R_REG_DAC_DATA_READBACK_CH(x) (0x68 + ((x) * 2)) + +#define AD5706R_DAC_RESOLUTION 16 +#define AD5706R_DAC_MAX_CODE GENMASK(15, 0) +#define AD5706R_MULTIBYTE_REG_START 0x14 +#define AD5706R_MULTIBYTE_REG_END 0x71 +#define AD5706R_MAX_REG 0x77 + +struct ad5706r_state { + struct spi_device *spi; + struct regmap *regmap; + + u8 tx_buf[4] __aligned(IIO_DMA_MINALIGN); + u8 rx_buf[4]; +}; + +static int ad5706r_reg_len(unsigned int reg) +{ + if (reg >= AD5706R_MULTIBYTE_REG_START && reg <= AD5706R_MULTIBYTE_REG_END) + return 2; + + return 1; +} + +static int ad5706r_regmap_write(void *context, const void *data, size_t count) +{ + struct ad5706r_state *st = context; + unsigned int num_bytes; + u16 reg, val; + + if (count != 4) + return -EINVAL; + + reg = get_unaligned_be16(data); + val = get_unaligned_be16(data + 2); + num_bytes = ad5706r_reg_len(reg); + + struct spi_transfer xfer = { + .tx_buf = st->tx_buf, + .len = num_bytes + 2, + }; + + put_unaligned_be16(reg, &st->tx_buf[0]); + + if (num_bytes == 1) + st->tx_buf[2] = (u8)val; + else if (num_bytes == 2) + put_unaligned_be16(val, &st->tx_buf[2]); + else + return -EINVAL; + + return spi_sync_transfer(st->spi, &xfer, 1); +} + +static int ad5706r_regmap_read(void *context, const void *reg_buf, + size_t reg_size, void *val_buf, size_t val_size) +{ + struct ad5706r_state *st = context; + unsigned int num_bytes; + u16 reg, cmd, val; + int ret; + + if (reg_size != 2 || val_size != 2) + return -EINVAL; + + reg = get_unaligned_be16(reg_buf); + num_bytes = ad5706r_reg_len(reg); + + /* Full duplex, device responds immediately after command */ + struct spi_transfer xfer = { + .tx_buf = st->tx_buf, + .rx_buf = st->rx_buf, + .len = 2 + num_bytes, + }; + + cmd = AD5706R_RD_MASK | (reg & AD5706R_ADDR_MASK); + put_unaligned_be16(cmd, &st->tx_buf[0]); + put_unaligned_be16(0, &st->tx_buf[2]); + + ret = spi_sync_transfer(st->spi, &xfer, 1); + if (ret) + return ret; + + /* Extract value from response (skip 2-byte command echo) */ + if (num_bytes == 1) + val = st->rx_buf[2]; + else if (num_bytes == 2) + val = get_unaligned_be16(&st->rx_buf[2]); + else + return -EINVAL; + + put_unaligned_be16(val, val_buf); + + return 0; +} + +static int ad5706r_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct ad5706r_state *st = iio_priv(indio_dev); + unsigned int reg, reg_val; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + reg = AD5706R_REG_DAC_DATA_READBACK_CH(chan->channel); + ret = regmap_read(st->regmap, reg, ®_val); + if (ret) + return ret; + + *val = reg_val; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 50; + *val2 = AD5706R_DAC_RESOLUTION; + return IIO_VAL_FRACTIONAL_LOG2; + default: + return -EINVAL; + } +} + +static int ad5706r_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct ad5706r_state *st = iio_priv(indio_dev); + unsigned int reg; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (val < 0 || val > AD5706R_DAC_MAX_CODE) + return -EINVAL; + + reg = AD5706R_REG_DAC_INPUT_A_CH(chan->channel); + return regmap_write(st->regmap, reg, val); + default: + return -EINVAL; + } +} + +static const struct regmap_bus ad5706r_regmap_bus = { + .write = ad5706r_regmap_write, + .read = ad5706r_regmap_read, + .reg_format_endian_default = REGMAP_ENDIAN_BIG, + .val_format_endian_default = REGMAP_ENDIAN_BIG, +}; + +static const struct regmap_config ad5706r_regmap_config = { + .reg_bits = 16, + .val_bits = 16, + .max_register = AD5706R_MAX_REG, +}; + +static const struct iio_info ad5706r_info = { + .read_raw = ad5706r_read_raw, + .write_raw = ad5706r_write_raw, +}; + +#define AD5706R_CHAN(_channel) { \ + .type = IIO_CURRENT, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .output = 1, \ + .indexed = 1, \ + .channel = _channel, \ +} + +static const struct iio_chan_spec ad5706r_channels[] = { + AD5706R_CHAN(0), + AD5706R_CHAN(1), + AD5706R_CHAN(2), + AD5706R_CHAN(3), +}; + +static int ad5706r_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct iio_dev *indio_dev; + struct ad5706r_state *st; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + st->spi = spi; + + st->regmap = devm_regmap_init(dev, &ad5706r_regmap_bus, + st, &ad5706r_regmap_config); + if (IS_ERR(st->regmap)) + return dev_err_probe(dev, PTR_ERR(st->regmap), + "Failed to init regmap\n"); + + indio_dev->name = "ad5706r"; + indio_dev->info = &ad5706r_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = ad5706r_channels; + indio_dev->num_channels = ARRAY_SIZE(ad5706r_channels); + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct of_device_id ad5706r_of_match[] = { + { .compatible = "adi,ad5706r" }, + { } +}; +MODULE_DEVICE_TABLE(of, ad5706r_of_match); + +static const struct spi_device_id ad5706r_id[] = { + { "ad5706r" }, + { } +}; +MODULE_DEVICE_TABLE(spi, ad5706r_id); + +static struct spi_driver ad5706r_driver = { + .driver = { + .name = "ad5706r", + .of_match_table = ad5706r_of_match, + }, + .probe = ad5706r_probe, + .id_table = ad5706r_id, +}; +module_spi_driver(ad5706r_driver); + +MODULE_AUTHOR("Alexis Czezar Torreno "); +MODULE_DESCRIPTION("AD5706R 16-bit Current Output DAC driver"); +MODULE_LICENSE("GPL"); From 095ae2f2e72f56d442ec0e476f873fd4d92c81de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rahman=20Mahmutovi=C4=87?= Date: Mon, 27 Apr 2026 22:20:16 +0200 Subject: [PATCH 098/266] iio: temperature: maxim_thermocouple: Fix indentation in of_match table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace leading spaces with tabs in the of_device_id table entries to comply with kernel coding style. Signed-off-by: Rahman Mahmutović Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/maxim_thermocouple.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iio/temperature/maxim_thermocouple.c b/drivers/iio/temperature/maxim_thermocouple.c index 205939680fd4..e898f56d1196 100644 --- a/drivers/iio/temperature/maxim_thermocouple.c +++ b/drivers/iio/temperature/maxim_thermocouple.c @@ -277,8 +277,8 @@ static const struct spi_device_id maxim_thermocouple_id[] = { MODULE_DEVICE_TABLE(spi, maxim_thermocouple_id); static const struct of_device_id maxim_thermocouple_of_match[] = { - { .compatible = "maxim,max6675" }, - { .compatible = "maxim,max31855" }, + { .compatible = "maxim,max6675" }, + { .compatible = "maxim,max31855" }, { .compatible = "maxim,max31855k" }, { .compatible = "maxim,max31855j" }, { .compatible = "maxim,max31855n" }, @@ -286,7 +286,7 @@ static const struct of_device_id maxim_thermocouple_of_match[] = { { .compatible = "maxim,max31855t" }, { .compatible = "maxim,max31855e" }, { .compatible = "maxim,max31855r" }, - { }, + { }, }; MODULE_DEVICE_TABLE(of, maxim_thermocouple_of_match); From c0536d61f30417b0aeac7ea8734525ab7a01a93b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 27 Apr 2026 20:51:47 +0200 Subject: [PATCH 099/266] iio: buffer: Move from int64_t to s64 for timestamp iio_push_to_buffers_with_ts_unaligned() uses int64_t for timestamp. Move it from int64_t to s64 to make consistent with: - iio_push_to_buffers_with_ts() - all current users that supply s64 anyway This will reduce potential of wrong type being chosen when using this API. Signed-off-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-buffer.c | 2 +- include/linux/iio/buffer.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 252ce4a6f913..9d66510a1d49 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -2444,7 +2444,7 @@ EXPORT_SYMBOL_GPL(iio_push_to_buffers); int iio_push_to_buffers_with_ts_unaligned(struct iio_dev *indio_dev, const void *data, size_t data_sz, - int64_t timestamp) + s64 timestamp) { struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h index 8fd0d57d238f..745c98ef4e04 100644 --- a/include/linux/iio/buffer.h +++ b/include/linux/iio/buffer.h @@ -79,7 +79,7 @@ static inline int iio_push_to_buffers_with_ts(struct iio_dev *indio_dev, int iio_push_to_buffers_with_ts_unaligned(struct iio_dev *indio_dev, const void *data, size_t data_sz, - int64_t timestamp); + s64 timestamp); bool iio_validate_scan_mask_onehot(struct iio_dev *indio_dev, const unsigned long *mask); From 5b382bf01a377ea96612089b1d68d9547882359f Mon Sep 17 00:00:00 2001 From: Joshua Crofts Date: Sun, 19 Apr 2026 20:36:23 +0200 Subject: [PATCH 100/266] iio: frequency: ad9832: simplify bitwise math MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactor the ad9832_calc_freqreg by removing the redundant u64 casts and 1L bitwise left shift and replacing the multiplication by a bit shift, as multiplying integers by a power of two is identical to a bitwise left shift. Signed-off-by: Joshua Crofts Reviewed-by: Nuno Sá Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/staging/iio/frequency/ad9832.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/iio/frequency/ad9832.c b/drivers/staging/iio/frequency/ad9832.c index c0b7852f1c84..659821a1e2cb 100644 --- a/drivers/staging/iio/frequency/ad9832.c +++ b/drivers/staging/iio/frequency/ad9832.c @@ -117,8 +117,8 @@ struct ad9832_state { static unsigned long ad9832_calc_freqreg(unsigned long mclk, unsigned long fout) { - unsigned long long freqreg = (u64)fout * - (u64)((u64)1L << AD9832_FREQ_BITS); + u64 freqreg = (u64)fout << AD9832_FREQ_BITS; + do_div(freqreg, mclk); return freqreg; } From 31b9486cd91e5d1054d508166ed5e5ae38c38198 Mon Sep 17 00:00:00 2001 From: "Rafael G. Dias" Date: Tue, 28 Apr 2026 13:13:38 -0300 Subject: [PATCH 101/266] iio: light: stk3310: Sort headers alphabetically Sort the included headers alphabetically and group the headers separately from the generic headers. Co-developed-by: Felipe Khoury Dayoub Signed-off-by: Felipe Khoury Dayoub Signed-off-by: Rafael G. Dias Reviewed-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/iio/light/stk3310.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c index a75a83594a7e..1fad9367c2d4 100644 --- a/drivers/iio/light/stk3310.c +++ b/drivers/iio/light/stk3310.c @@ -10,9 +10,10 @@ #include #include #include -#include #include +#include #include + #include #include #include From 9cba9d97ac7453ce4f0d589fdc05f5e1abfd6eb5 Mon Sep 17 00:00:00 2001 From: "Rafael G. Dias" Date: Tue, 28 Apr 2026 13:13:39 -0300 Subject: [PATCH 102/266] iio: light: stk3310: Update includes to match IWYU Clean up the included headers in stk3310.c according to the Include-What-You-Use (IWYU) tool. Remove the generic header and add explicit dependencies to improve compilation accuracy. Co-developed-by: Felipe Khoury Dayoub Signed-off-by: Felipe Khoury Dayoub Signed-off-by: Rafael G. Dias Reviewed-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/iio/light/stk3310.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c index 1fad9367c2d4..63920fe134bc 100644 --- a/drivers/iio/light/stk3310.c +++ b/drivers/iio/light/stk3310.c @@ -7,16 +7,28 @@ * IIO driver for STK3310/STK3311. 7-bit I2C address: 0x48. */ +#include +#include +#include +#include #include #include -#include #include #include +#include +#include +#include #include +#include +#include +#include #include #include #include +#include + +#include #define STK3310_REG_STATE 0x00 #define STK3310_REG_PSCTRL 0x01 From b4e9ede52a6094b4a7fcf584f7348542d0619632 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 29 Apr 2026 21:27:23 +0200 Subject: [PATCH 103/266] iio: adc: rcar: Fix up Marek Vasut MAINTAINERS entry Use up to date address. No functional change. Signed-off-by: Marek Vasut Signed-off-by: Jonathan Cameron --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 31c4db07e99b..c316e3b44e19 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22602,7 +22602,7 @@ F: Documentation/devicetree/bindings/mtd/renesas-nandc.yaml F: drivers/mtd/nand/raw/renesas-nand-controller.c RENESAS R-CAR GYROADC DRIVER -M: Marek Vasut +M: Marek Vasut L: linux-iio@vger.kernel.org S: Supported F: Documentation/devicetree/bindings/iio/adc/renesas,rcar-gyroadc.yaml From 19f2c27251d86cf1272d475c52a190d01e9f996b Mon Sep 17 00:00:00 2001 From: Angus Gardner Date: Mon, 4 May 2026 19:20:57 +1000 Subject: [PATCH 104/266] staging: iio: ad9834: simplify -ENOMEM return in probe devm_iio_device_alloc() failure returns -ENOMEM via a local variable unnecessarily. Return -ENOMEM directly instead. Signed-off-by: Angus Gardner Reviewed-by: Maxwell Doose Signed-off-by: Jonathan Cameron --- drivers/staging/iio/frequency/ad9834.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c index 330db78fe766..e7aee3307061 100644 --- a/drivers/staging/iio/frequency/ad9834.c +++ b/drivers/staging/iio/frequency/ad9834.c @@ -392,10 +392,8 @@ static int ad9834_probe(struct spi_device *spi) return dev_err_probe(&spi->dev, ret, "Failed to enable specified AVDD supply\n"); indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); - if (!indio_dev) { - ret = -ENOMEM; - return ret; - } + if (!indio_dev) + return -ENOMEM; st = iio_priv(indio_dev); mutex_init(&st->lock); st->mclk = devm_clk_get_enabled(&spi->dev, NULL); From 8b8e850eada20e96ef22621b87f58a72b69566cf Mon Sep 17 00:00:00 2001 From: Angus Gardner Date: Mon, 4 May 2026 19:20:58 +1000 Subject: [PATCH 105/266] staging: iio: ad9834: use dev_err_probe() in probe function Replace open-coded dev_err() + return sequences with dev_err_probe(), which is the preferred pattern for probe error paths as it handles deferred probing correctly and reduces boilerplate. Convert all three remaining instances in ad9834_probe(): - master clock enable failure - device init SPI sync failure The avdd regulator path already used dev_err_probe(). Signed-off-by: Angus Gardner Reviewed-by: Maxwell Doose Signed-off-by: Jonathan Cameron --- drivers/staging/iio/frequency/ad9834.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c index e7aee3307061..8c0699460ae1 100644 --- a/drivers/staging/iio/frequency/ad9834.c +++ b/drivers/staging/iio/frequency/ad9834.c @@ -397,10 +397,9 @@ static int ad9834_probe(struct spi_device *spi) st = iio_priv(indio_dev); mutex_init(&st->lock); st->mclk = devm_clk_get_enabled(&spi->dev, NULL); - if (IS_ERR(st->mclk)) { - dev_err(&spi->dev, "Failed to enable master clock\n"); - return PTR_ERR(st->mclk); - } + if (IS_ERR(st->mclk)) + return dev_err_probe(&spi->dev, PTR_ERR(st->mclk), + "Failed to enable master clock\n"); st->spi = spi; st->devid = spi_get_device_id(spi)->driver_data; @@ -442,10 +441,9 @@ static int ad9834_probe(struct spi_device *spi) st->data = cpu_to_be16(AD9834_REG_CMD | st->control); ret = spi_sync(st->spi, &st->msg); - if (ret) { - dev_err(&spi->dev, "device init failed\n"); - return ret; - } + if (ret) + return dev_err_probe(&spi->dev, ret, + "device init failed\n"); ret = ad9834_write_frequency(st, AD9834_REG_FREQ0, 1000000); if (ret) From 11aa529f27c7c8656ab57a6d79111b2e525f7b19 Mon Sep 17 00:00:00 2001 From: Angus Gardner Date: Mon, 4 May 2026 19:20:59 +1000 Subject: [PATCH 106/266] staging: iio: ad9834: fix chip name typo in comments Two comments incorrectly refer to 'AD9843' instead of 'AD9834'. Fix the copy-paste typo. Signed-off-by: Angus Gardner Reviewed-by: Maxwell Doose Signed-off-by: Jonathan Cameron --- drivers/staging/iio/frequency/ad9834.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c index 8c0699460ae1..4359b358e0e5 100644 --- a/drivers/staging/iio/frequency/ad9834.c +++ b/drivers/staging/iio/frequency/ad9834.c @@ -167,7 +167,7 @@ static ssize_t ad9834_write(struct device *dev, break; case AD9834_OPBITEN: if (st->control & AD9834_MODE) { - ret = -EINVAL; /* AD9843 reserved mode */ + ret = -EINVAL; /* AD9834 reserved mode */ break; } @@ -242,7 +242,7 @@ static ssize_t ad9834_store_wavetype(struct device *dev, st->control &= ~AD9834_OPBITEN; st->control |= AD9834_MODE; } else if (st->control & AD9834_OPBITEN) { - ret = -EINVAL; /* AD9843 reserved mode */ + ret = -EINVAL; /* AD9834 reserved mode */ } else { st->control |= AD9834_MODE; } From 9c1d639e90cf42f5c1401f91f38ffd89af6dd970 Mon Sep 17 00:00:00 2001 From: Miao Li Date: Mon, 4 May 2026 11:04:06 +0800 Subject: [PATCH 107/266] iio: light: stk3310: Deal with the ps interrupt issue in PM On the Inspur HS326 laptop(which integrated with HiSilicon M900 processor), if the STK3311-X chip's PS interrupt is configured in "Recommended interrupt mode", the interrupt cannot be triggered normally after waking from suspend or hibernation. In this case, neither disabling and re-enabling the interrupt nor resetting the PS threshold register can restore the interrupt to normal operation. If the interrupt is disabled in suspend() then reset the PS threshold register and enable the interrupt in resume(). This resolves the issue. Signed-off-by: Miao Li Signed-off-by: Jonathan Cameron --- drivers/iio/light/stk3310.c | 76 +++++++++++++++++++++++++++++++++---- 1 file changed, 69 insertions(+), 7 deletions(-) diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c index 63920fe134bc..21118b746789 100644 --- a/drivers/iio/light/stk3310.c +++ b/drivers/iio/light/stk3310.c @@ -130,6 +130,9 @@ struct stk3310_data { struct mutex lock; bool als_enabled; bool ps_enabled; + bool ps_int_enabled; + uint32_t ps_thdl; + uint32_t ps_thdh; uint32_t ps_near_level; u64 timestamp; struct regmap *regmap; @@ -309,10 +312,17 @@ static int stk3310_write_event(struct iio_dev *indio_dev, buf = cpu_to_be16(val); ret = regmap_bulk_write(data->regmap, reg, &buf, 2); - if (ret < 0) + if (ret < 0) { dev_err(&client->dev, "failed to set PS threshold!\n"); + return ret; + } - return ret; + if (reg == STK3310_REG_THDH_PS) + data->ps_thdh = val; + else + data->ps_thdl = val; + + return 0; } static int stk3310_read_event_config(struct iio_dev *indio_dev, @@ -344,11 +354,17 @@ static int stk3310_write_event_config(struct iio_dev *indio_dev, /* Set INT_PS value */ mutex_lock(&data->lock); ret = regmap_field_write(data->reg_int_ps, state); - if (ret < 0) + if (ret < 0) { dev_err(&client->dev, "failed to set interrupt mode\n"); + mutex_unlock(&data->lock); + return ret; + } + + data->ps_int_enabled = state; + mutex_unlock(&data->lock); - return ret; + return 0; } static int stk3310_read_raw(struct iio_dev *indio_dev, @@ -517,10 +533,15 @@ static int stk3310_init(struct iio_dev *indio_dev) /* Enable PS interrupts */ ret = regmap_field_write(data->reg_int_ps, STK3310_PSINT_EN); - if (ret < 0) + if (ret < 0) { dev_err(&client->dev, "failed to enable interrupts!\n"); + return ret; + } - return ret; + data->ps_int_enabled = true; + data->ps_thdh = STK3310_PS_MAX_VAL; + + return 0; } static bool stk3310_is_volatile_reg(struct device *dev, unsigned int reg) @@ -684,9 +705,18 @@ static void stk3310_remove(struct i2c_client *client) static int stk3310_suspend(struct device *dev) { struct stk3310_data *data; + int ret; data = iio_priv(i2c_get_clientdata(to_i2c_client(dev))); + if (data->ps_int_enabled) { + ret = regmap_field_write(data->reg_int_ps, 0x0); + if (ret < 0) { + dev_err(dev, "failed to disable ps int at suspend.\n"); + return ret; + } + } + return stk3310_set_state(data, STK3310_STATE_STANDBY); } @@ -694,6 +724,8 @@ static int stk3310_resume(struct device *dev) { u8 state = 0; struct stk3310_data *data; + __be16 buf; + int ret; data = iio_priv(i2c_get_clientdata(to_i2c_client(dev))); if (data->ps_enabled) @@ -701,7 +733,37 @@ static int stk3310_resume(struct device *dev) if (data->als_enabled) state |= STK3310_STATE_EN_ALS; - return stk3310_set_state(data, state); + ret = stk3310_set_state(data, state); + if (ret < 0) + return ret; + + if (data->ps_thdl != 0x0) { + buf = cpu_to_be16(data->ps_thdl); + ret = regmap_bulk_write(data->regmap, STK3310_REG_THDL_PS, &buf, 2); + if (ret < 0) { + dev_err(dev, "failed to set reg THDL_PS at resume.\n"); + return ret; + } + } + + if (data->ps_thdh != STK3310_PS_MAX_VAL) { + buf = cpu_to_be16(data->ps_thdh); + ret = regmap_bulk_write(data->regmap, STK3310_REG_THDH_PS, &buf, 2); + if (ret < 0) { + dev_err(dev, "failed to set reg THDH_PS at resume.\n"); + return ret; + } + } + + if (data->ps_int_enabled) { + ret = regmap_field_write(data->reg_int_ps, STK3310_PSINT_EN); + if (ret < 0) { + dev_err(dev, "failed to enable ps int at resume.\n"); + return ret; + } + } + + return 0; } static DEFINE_SIMPLE_DEV_PM_OPS(stk3310_pm_ops, stk3310_suspend, From ac4129478a2416eecdb09e78f7d7b5d7286b9ac6 Mon Sep 17 00:00:00 2001 From: Miao Li Date: Mon, 4 May 2026 11:04:07 +0800 Subject: [PATCH 108/266] iio: light: stk3310: Replace uint32_t with u32 and reorder members to eliminate padding Replace the uint32_t type members in struct stk3310_data with u32 to adhere to the unified kernel coding style, and reorder the member variables to eliminate memory padding holes. Suggested-by: Andy Shevchenko Signed-off-by: Miao Li Reviewed-by: Joshua Crofts Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/light/stk3310.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c index 21118b746789..fb3d9821edee 100644 --- a/drivers/iio/light/stk3310.c +++ b/drivers/iio/light/stk3310.c @@ -128,12 +128,6 @@ static const int stk3310_it_table[][2] = { struct stk3310_data { struct i2c_client *client; struct mutex lock; - bool als_enabled; - bool ps_enabled; - bool ps_int_enabled; - uint32_t ps_thdl; - uint32_t ps_thdh; - uint32_t ps_near_level; u64 timestamp; struct regmap *regmap; struct regmap_field *reg_state; @@ -144,6 +138,12 @@ struct stk3310_data { struct regmap_field *reg_int_ps; struct regmap_field *reg_flag_psint; struct regmap_field *reg_flag_nf; + u32 ps_thdl; + u32 ps_thdh; + u32 ps_near_level; + bool als_enabled; + bool ps_enabled; + bool ps_int_enabled; }; static const struct iio_event_spec stk3310_events[] = { From a4c18ea894e5587bcc6be787fcd77c0c19beaa1d Mon Sep 17 00:00:00 2001 From: Miao Li Date: Mon, 4 May 2026 11:04:08 +0800 Subject: [PATCH 109/266] iio: light: stk3310: Use sizeof() for regmap_bulk_read/write count parameter Convert the hardcoded count parameter to sizeof(buf) for all regmap_bulk_write() and regmap_bulk_read() calls in this driver to improve code maintainability. For details, see [1]. Link: https://lore.kernel.org/all/20260428192213.7c5c80e5@jic23-huawei/ #[1] Signed-off-by: Miao Li Reviewed-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/iio/light/stk3310.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c index fb3d9821edee..60407bc87ccf 100644 --- a/drivers/iio/light/stk3310.c +++ b/drivers/iio/light/stk3310.c @@ -271,7 +271,7 @@ static int stk3310_read_event(struct iio_dev *indio_dev, return -EINVAL; mutex_lock(&data->lock); - ret = regmap_bulk_read(data->regmap, reg, &buf, 2); + ret = regmap_bulk_read(data->regmap, reg, &buf, sizeof(buf)); mutex_unlock(&data->lock); if (ret < 0) { dev_err(&data->client->dev, "register read failed\n"); @@ -311,7 +311,7 @@ static int stk3310_write_event(struct iio_dev *indio_dev, return -EINVAL; buf = cpu_to_be16(val); - ret = regmap_bulk_write(data->regmap, reg, &buf, 2); + ret = regmap_bulk_write(data->regmap, reg, &buf, sizeof(buf)); if (ret < 0) { dev_err(&client->dev, "failed to set PS threshold!\n"); return ret; @@ -389,7 +389,7 @@ static int stk3310_read_raw(struct iio_dev *indio_dev, reg = STK3310_REG_PS_DATA_MSB; mutex_lock(&data->lock); - ret = regmap_bulk_read(data->regmap, reg, &buf, 2); + ret = regmap_bulk_read(data->regmap, reg, &buf, sizeof(buf)); if (ret < 0) { dev_err(&client->dev, "register read failed\n"); mutex_unlock(&data->lock); @@ -739,7 +739,7 @@ static int stk3310_resume(struct device *dev) if (data->ps_thdl != 0x0) { buf = cpu_to_be16(data->ps_thdl); - ret = regmap_bulk_write(data->regmap, STK3310_REG_THDL_PS, &buf, 2); + ret = regmap_bulk_write(data->regmap, STK3310_REG_THDL_PS, &buf, sizeof(buf)); if (ret < 0) { dev_err(dev, "failed to set reg THDL_PS at resume.\n"); return ret; @@ -748,7 +748,7 @@ static int stk3310_resume(struct device *dev) if (data->ps_thdh != STK3310_PS_MAX_VAL) { buf = cpu_to_be16(data->ps_thdh); - ret = regmap_bulk_write(data->regmap, STK3310_REG_THDH_PS, &buf, 2); + ret = regmap_bulk_write(data->regmap, STK3310_REG_THDH_PS, &buf, sizeof(buf)); if (ret < 0) { dev_err(dev, "failed to set reg THDH_PS at resume.\n"); return ret; From c49965ae6b0c1a6362737fbce1e06617882f51fc Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 5 May 2026 12:29:04 +0200 Subject: [PATCH 110/266] iio: Move MODULE_DEVICE_TABLE next to the table itself By convention MODULE_DEVICE_TABLE() immediately follows the ID table it exports, because this is easier to read and verify. It also makes more sense since #ifdef for ACPI or OF could hide both of them. Most of the drivers already have this correctly placed, so adjust the missing ones. No functional impact. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/sgp30.c | 3 +-- drivers/iio/light/cm3232.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/chemical/sgp30.c b/drivers/iio/chemical/sgp30.c index 21730d62b5c8..d42b62b7081e 100644 --- a/drivers/iio/chemical/sgp30.c +++ b/drivers/iio/chemical/sgp30.c @@ -498,6 +498,7 @@ static const struct of_device_id sgp_dt_ids[] = { { .compatible = "sensirion,sgpc3", .data = &sgp_devices[SGPC3] }, { } }; +MODULE_DEVICE_TABLE(of, sgp_dt_ids); static int sgp_probe(struct i2c_client *client) { @@ -566,9 +567,7 @@ static const struct i2c_device_id sgp_id[] = { { "sgpc3", (kernel_ulong_t)&sgp_devices[SGPC3] }, { } }; - MODULE_DEVICE_TABLE(i2c, sgp_id); -MODULE_DEVICE_TABLE(of, sgp_dt_ids); static struct i2c_driver sgp_driver = { .driver = { diff --git a/drivers/iio/light/cm3232.c b/drivers/iio/light/cm3232.c index 3a3ad6b4c468..90aa77e3a03b 100644 --- a/drivers/iio/light/cm3232.c +++ b/drivers/iio/light/cm3232.c @@ -369,6 +369,7 @@ static const struct i2c_device_id cm3232_id[] = { { "cm3232" }, { } }; +MODULE_DEVICE_TABLE(i2c, cm3232_id); static int cm3232_suspend(struct device *dev) { @@ -400,8 +401,6 @@ static int cm3232_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(cm3232_pm_ops, cm3232_suspend, cm3232_resume); -MODULE_DEVICE_TABLE(i2c, cm3232_id); - static const struct of_device_id cm3232_of_match[] = { {.compatible = "capella,cm3232"}, { } From ccf300c36bd6c79eeef4f4122fd2e58acfa46dbb Mon Sep 17 00:00:00 2001 From: Guilherme Dias Date: Mon, 4 May 2026 16:04:25 -0300 Subject: [PATCH 111/266] iio: gyro: adxrs290: Use guard(mutex) in lieu of manual lock+unlock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use guard(mutex)() to automatically release the lock on scope exit, simplifying the error handling path and removing the need for explicit unlock and goto-based cleanup. Signed-off-by: Guilherme Dias Co-developed-by: João Paulo Menezes Linaris Signed-off-by: João Paulo Menezes Linaris Reviewed-by: Andy Shevchenko Reviewed-by: Maxwell Doose Signed-off-by: Jonathan Cameron --- drivers/iio/gyro/adxrs290.c | 75 +++++++++++++++---------------------- 1 file changed, 31 insertions(+), 44 deletions(-) diff --git a/drivers/iio/gyro/adxrs290.c b/drivers/iio/gyro/adxrs290.c index 3efe385ebedc..35928383d4f2 100644 --- a/drivers/iio/gyro/adxrs290.c +++ b/drivers/iio/gyro/adxrs290.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -115,65 +116,53 @@ static const int adxrs290_hpf_3db_freq_hz_table[][2] = { static int adxrs290_get_rate_data(struct iio_dev *indio_dev, const u8 cmd, int *val) { struct adxrs290_state *st = iio_priv(indio_dev); - int ret = 0; int temp; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); + temp = spi_w8r16(st->spi, cmd); - if (temp < 0) { - ret = temp; - goto err_unlock; - } + if (temp < 0) + return temp; *val = sign_extend32(temp, 15); -err_unlock: - mutex_unlock(&st->lock); - return ret; + return 0; } static int adxrs290_get_temp_data(struct iio_dev *indio_dev, int *val) { const u8 cmd = ADXRS290_READ_REG(ADXRS290_REG_TEMP0); struct adxrs290_state *st = iio_priv(indio_dev); - int ret = 0; int temp; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); + temp = spi_w8r16(st->spi, cmd); - if (temp < 0) { - ret = temp; - goto err_unlock; - } + if (temp < 0) + return temp; /* extract lower 12 bits temperature reading */ *val = sign_extend32(temp, 11); -err_unlock: - mutex_unlock(&st->lock); - return ret; + return 0; } static int adxrs290_get_3db_freq(struct iio_dev *indio_dev, u8 *val, u8 *val2) { const u8 cmd = ADXRS290_READ_REG(ADXRS290_REG_FILTER); struct adxrs290_state *st = iio_priv(indio_dev); - int ret = 0; short temp; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); + temp = spi_w8r8(st->spi, cmd); - if (temp < 0) { - ret = temp; - goto err_unlock; - } + if (temp < 0) + return temp; *val = FIELD_GET(ADXRS290_LPF_MASK, temp); *val2 = FIELD_GET(ADXRS290_HPF_MASK, temp); -err_unlock: - mutex_unlock(&st->lock); - return ret; + return 0; } static int adxrs290_spi_write_reg(struct spi_device *spi, const u8 reg, @@ -220,11 +209,11 @@ static int adxrs290_set_mode(struct iio_dev *indio_dev, enum adxrs290_mode mode) if (st->mode == mode) return 0; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); ret = spi_w8r8(st->spi, ADXRS290_READ_REG(ADXRS290_REG_POWER_CTL)); if (ret < 0) - goto out_unlock; + return ret; val = ret; @@ -236,21 +225,18 @@ static int adxrs290_set_mode(struct iio_dev *indio_dev, enum adxrs290_mode mode) val |= ADXRS290_MEASUREMENT; break; default: - ret = -EINVAL; - goto out_unlock; + return -EINVAL; } ret = adxrs290_spi_write_reg(st->spi, ADXRS290_REG_POWER_CTL, val); if (ret < 0) { dev_err(&st->spi->dev, "unable to set mode: %d\n", ret); - goto out_unlock; + return ret; } /* update cached mode */ st->mode = mode; -out_unlock: - mutex_unlock(&st->lock); return ret; } @@ -506,19 +492,20 @@ static irqreturn_t adxrs290_trigger_handler(int irq, void *p) u8 tx = ADXRS290_READ_REG(ADXRS290_REG_DATAX0); int ret; - mutex_lock(&st->lock); + do { + guard(mutex)(&st->lock); - /* exercise a bulk data capture starting from reg DATAX0... */ - ret = spi_write_then_read(st->spi, &tx, sizeof(tx), st->buffer.channels, - sizeof(st->buffer.channels)); - if (ret < 0) - goto out_unlock_notify; + /* exercise a bulk data capture starting from reg DATAX0... */ + ret = spi_write_then_read(st->spi, &tx, sizeof(tx), + st->buffer.channels, + sizeof(st->buffer.channels)); + if (ret < 0) + break; - iio_push_to_buffers_with_timestamp(indio_dev, &st->buffer, - pf->timestamp); + iio_push_to_buffers_with_timestamp(indio_dev, &st->buffer, + pf->timestamp); + } while (0); -out_unlock_notify: - mutex_unlock(&st->lock); iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; From 0a5f45ed2342aabae1e32c72558d15be28940a95 Mon Sep 17 00:00:00 2001 From: Joshua Crofts Date: Tue, 5 May 2026 09:31:26 +0200 Subject: [PATCH 112/266] iio: light: si1133: reset counter to prevent race condition Sashiko reported a potential race condition happening when the driver returns an errno after a timeout in the si1133_command() function. The premature exit causes the hardware and software counters to become out of sync by not updating data->rsp_seq, therefore the internal hardware counter keeps incrementing. Fix this by adding a call to si1133_cmd_reset_counter() before returning from timeout. Fixes: e01e7eaf37d8 ("iio: light: introduce si1133") Reported-by: sashiko-bot Closes: https://sashiko.dev/#/message/20260428-si1133-checkup-v2-5-70ad14bfefe2%40gmail.com Assisted-by: gemini:gemini-3.1-pro-preview Signed-off-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/iio/light/si1133.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/iio/light/si1133.c b/drivers/iio/light/si1133.c index 44fa152dbd24..c88c79202be2 100644 --- a/drivers/iio/light/si1133.c +++ b/drivers/iio/light/si1133.c @@ -427,6 +427,11 @@ static int si1133_command(struct si1133_data *data, u8 cmd) dev_warn(dev, "Failed to read command 0x%02x, ret=%d\n", cmd, err); + /* + * Reset counter on err to prevent software and hardware + * counters being out of sync. + */ + si1133_cmd_reset_counter(data); goto out; } } From 8c50a95ceb230d17801758a9e41ffbbbe46f8b4d Mon Sep 17 00:00:00 2001 From: Joshua Crofts Date: Tue, 5 May 2026 09:31:27 +0200 Subject: [PATCH 113/266] iio: light: si1133: prevent race condition on timeout Sashiko reported a bug where the si1133_command exits on timeout without halting the sensor or masking the interrupt. If the sensor completes the command later, any subsequent command to the sensor will cause the IRQ handler to complete immediately, returning stale data to the driver all while the command hasn't finished yet, shifting all potential reads in the future. Fix this by masking the IRQ if wait_for_completion_timeout() fails. When initiating a new command, do a dummy read of the IRQ_STATUS register and turn the IRQ back on. Fixes: e01e7eaf37d8 ("iio: light: introduce si1133") Reported-by: sashiko-bot Closes: https://sashiko.dev/#/message/20260428-si1133-checkup-v2-5-70ad14bfefe2%40gmail.com Assisted-by: gemini:gemini-3.1-pro-preview Signed-off-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/iio/light/si1133.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/iio/light/si1133.c b/drivers/iio/light/si1133.c index c88c79202be2..bf7bf0f1631d 100644 --- a/drivers/iio/light/si1133.c +++ b/drivers/iio/light/si1133.c @@ -395,8 +395,14 @@ static int si1133_command(struct si1133_data *data, u8 cmd) expected_seq = (data->rsp_seq + 1) & SI1133_MAX_CMD_CTR; - if (cmd == SI1133_CMD_FORCE) + if (cmd == SI1133_CMD_FORCE) { + /* Flush pending IRQs from a previous timeout. */ + regmap_read(data->regmap, SI1133_REG_IRQ_STATUS, &resp); + regmap_write(data->regmap, SI1133_REG_IRQ_ENABLE, + SI1133_IRQ_CHANNEL_ENABLE); + reinit_completion(&data->completion); + } err = regmap_write(data->regmap, SI1133_REG_COMMAND, cmd); if (err) { @@ -409,6 +415,7 @@ static int si1133_command(struct si1133_data *data, u8 cmd) /* wait for irq */ if (!wait_for_completion_timeout(&data->completion, msecs_to_jiffies(SI1133_COMPLETION_TIMEOUT_MS))) { + regmap_write(data->regmap, SI1133_REG_IRQ_ENABLE, 0); err = -ETIMEDOUT; goto out; } From ff032cc038d57bf91986be60dfabf4f5262c4198 Mon Sep 17 00:00:00 2001 From: Joshua Crofts Date: Tue, 5 May 2026 09:31:28 +0200 Subject: [PATCH 114/266] iio: light: si1133: remove unused macros Remove unused macros unrelated to hardware definition. No functional change. Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Signed-off-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/iio/light/si1133.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/iio/light/si1133.c b/drivers/iio/light/si1133.c index bf7bf0f1631d..ed9b3e0a12d6 100644 --- a/drivers/iio/light/si1133.c +++ b/drivers/iio/light/si1133.c @@ -86,13 +86,9 @@ #define SI1133_CMD_MINSLEEP_US_LOW 5000 #define SI1133_CMD_MINSLEEP_US_HIGH 7500 #define SI1133_CMD_TIMEOUT_MS 25 -#define SI1133_CMD_LUX_TIMEOUT_MS 5000 -#define SI1133_CMD_TIMEOUT_US SI1133_CMD_TIMEOUT_MS * 1000 #define SI1133_REG_HOSTOUT(x) (x) + 0x13 -#define SI1133_MEASUREMENT_FREQUENCY 1250 - #define SI1133_X_ORDER_MASK 0x0070 #define SI1133_Y_ORDER_MASK 0x0007 #define si1133_get_x_order(m) ((m) & SI1133_X_ORDER_MASK) >> 4 From a3bed7bfc42d647f527361ffb5ed64eadfefc76b Mon Sep 17 00:00:00 2001 From: Joshua Crofts Date: Tue, 5 May 2026 09:31:29 +0200 Subject: [PATCH 115/266] iio: light: si1133: prefer complex macros enclosed in parenthesis Enclose complex macros in parenthesis per checkpatch.pl error to improve code style. Reviewed-by: Andy Shevchenko Signed-off-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/iio/light/si1133.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/iio/light/si1133.c b/drivers/iio/light/si1133.c index ed9b3e0a12d6..9abc0a7e2ecf 100644 --- a/drivers/iio/light/si1133.c +++ b/drivers/iio/light/si1133.c @@ -50,23 +50,23 @@ #define SI1133_MAX_CMD_CTR 0xF #define SI1133_PARAM_REG_CHAN_LIST 0x01 -#define SI1133_PARAM_REG_ADCCONFIG(x) ((x) * 4) + 2 -#define SI1133_PARAM_REG_ADCSENS(x) ((x) * 4) + 3 -#define SI1133_PARAM_REG_ADCPOST(x) ((x) * 4) + 4 +#define SI1133_PARAM_REG_ADCCONFIG(x) (((x) * 4) + 2) +#define SI1133_PARAM_REG_ADCSENS(x) (((x) * 4) + 3) +#define SI1133_PARAM_REG_ADCPOST(x) (((x) * 4) + 4) #define SI1133_ADCMUX_MASK 0x1F -#define SI1133_ADCCONFIG_DECIM_RATE(x) (x) << 5 +#define SI1133_ADCCONFIG_DECIM_RATE(x) ((x) << 5) #define SI1133_ADCSENS_SCALE_MASK 0x70 #define SI1133_ADCSENS_SCALE_SHIFT 4 #define SI1133_ADCSENS_HSIG_MASK BIT(7) #define SI1133_ADCSENS_HSIG_SHIFT 7 #define SI1133_ADCSENS_HW_GAIN_MASK 0xF -#define SI1133_ADCSENS_NB_MEAS(x) fls(x) << SI1133_ADCSENS_SCALE_SHIFT +#define SI1133_ADCSENS_NB_MEAS(x) (fls(x) << SI1133_ADCSENS_SCALE_SHIFT) #define SI1133_ADCPOST_24BIT_EN BIT(6) -#define SI1133_ADCPOST_POSTSHIFT_BITQTY(x) (x & GENMASK(2, 0)) << 3 +#define SI1133_ADCPOST_POSTSHIFT_BITQTY(x) (((x) & GENMASK(2, 0)) << 3) #define SI1133_PARAM_ADCMUX_SMALL_IR 0x0 #define SI1133_PARAM_ADCMUX_MED_IR 0x1 @@ -87,11 +87,11 @@ #define SI1133_CMD_MINSLEEP_US_HIGH 7500 #define SI1133_CMD_TIMEOUT_MS 25 -#define SI1133_REG_HOSTOUT(x) (x) + 0x13 +#define SI1133_REG_HOSTOUT(x) ((x) + 0x13) #define SI1133_X_ORDER_MASK 0x0070 #define SI1133_Y_ORDER_MASK 0x0007 -#define si1133_get_x_order(m) ((m) & SI1133_X_ORDER_MASK) >> 4 +#define si1133_get_x_order(m) (((m) & SI1133_X_ORDER_MASK) >> 4) #define si1133_get_y_order(m) ((m) & SI1133_Y_ORDER_MASK) #define SI1133_LUX_ADC_MASK 0xE From dd2701f0b2a38f416332605e7fbb0470521591f6 Mon Sep 17 00:00:00 2001 From: Joshua Crofts Date: Tue, 5 May 2026 09:31:30 +0200 Subject: [PATCH 116/266] iio: light: si1133: add missing include headers Add missing include headers to prevent compilation relying on transient dependencies (array_size.h, bitops.h, completion.h, dev_printk.h, err.h, jiffies.h, math.h, mod_devicetable.h, mutex.h, types.h). Reviewed-by: Andy Shevchenko Signed-off-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/iio/light/si1133.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/iio/light/si1133.c b/drivers/iio/light/si1133.c index 9abc0a7e2ecf..ab66a5a9ffb4 100644 --- a/drivers/iio/light/si1133.c +++ b/drivers/iio/light/si1133.c @@ -6,11 +6,21 @@ * Copyright 2018 Maxime Roussin-Belanger */ +#include +#include +#include #include +#include +#include #include #include +#include +#include +#include #include +#include #include +#include #include #include From fb94aeb67415cbeb3de944e6e570c55f75c0d62c Mon Sep 17 00:00:00 2001 From: Joshua Crofts Date: Tue, 5 May 2026 09:31:31 +0200 Subject: [PATCH 117/266] iio: light: si1133: group generic headers Group generic include headers to improve code style. No functional change. Reviewed-by: Andy Shevchenko Signed-off-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/iio/light/si1133.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/light/si1133.c b/drivers/iio/light/si1133.c index ab66a5a9ffb4..fdffdee16e49 100644 --- a/drivers/iio/light/si1133.c +++ b/drivers/iio/light/si1133.c @@ -21,14 +21,12 @@ #include #include #include +#include +#include #include #include -#include - -#include - #define SI1133_REG_PART_ID 0x00 #define SI1133_REG_REV_ID 0x01 #define SI1133_REG_MFR_ID 0x02 From 82108871f44483ab7e0291f1c70b5461ed233ab8 Mon Sep 17 00:00:00 2001 From: Joshua Crofts Date: Tue, 5 May 2026 09:31:32 +0200 Subject: [PATCH 118/266] iio: light: si1133: add local variable for timeout Add local variable for timeout to improve readability. No functional change. Suggested-by: Jonathan Cameron Signed-off-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/iio/light/si1133.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/iio/light/si1133.c b/drivers/iio/light/si1133.c index fdffdee16e49..ef5c38e303a6 100644 --- a/drivers/iio/light/si1133.c +++ b/drivers/iio/light/si1133.c @@ -390,6 +390,7 @@ static int si1133_cmd_reset_counter(struct si1133_data *data) static int si1133_command(struct si1133_data *data, u8 cmd) { + unsigned long timeout; struct device *dev = &data->client->dev; u32 resp; int err; @@ -417,8 +418,8 @@ static int si1133_command(struct si1133_data *data, u8 cmd) if (cmd == SI1133_CMD_FORCE) { /* wait for irq */ - if (!wait_for_completion_timeout(&data->completion, - msecs_to_jiffies(SI1133_COMPLETION_TIMEOUT_MS))) { + timeout = msecs_to_jiffies(SI1133_COMPLETION_TIMEOUT_MS); + if (!wait_for_completion_timeout(&data->completion, timeout)) { regmap_write(data->regmap, SI1133_REG_IRQ_ENABLE, 0); err = -ETIMEDOUT; goto out; From d0b396cab2f7d56126a9b36dba9d6c52292aa7bc Mon Sep 17 00:00:00 2001 From: Joshua Crofts Date: Tue, 5 May 2026 09:31:33 +0200 Subject: [PATCH 119/266] iio: light: si1133: use guard(mutex)() macro Remove mutex_lock()/mutex_unlock() and goto instances and add guard(mutex)() macro to modernize driver and improve mutex handling. Reviewed-by: Andy Shevchenko Signed-off-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/iio/light/si1133.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/iio/light/si1133.c b/drivers/iio/light/si1133.c index ef5c38e303a6..655fa778b4a6 100644 --- a/drivers/iio/light/si1133.c +++ b/drivers/iio/light/si1133.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -396,7 +397,7 @@ static int si1133_command(struct si1133_data *data, u8 cmd) int err; int expected_seq; - mutex_lock(&data->mutex); + guard(mutex)(&data->mutex); expected_seq = (data->rsp_seq + 1) & SI1133_MAX_CMD_CTR; @@ -413,7 +414,7 @@ static int si1133_command(struct si1133_data *data, u8 cmd) if (err) { dev_warn(dev, "Failed to write command 0x%02x, ret=%d\n", cmd, err); - goto out; + return err; } if (cmd == SI1133_CMD_FORCE) { @@ -421,12 +422,11 @@ static int si1133_command(struct si1133_data *data, u8 cmd) timeout = msecs_to_jiffies(SI1133_COMPLETION_TIMEOUT_MS); if (!wait_for_completion_timeout(&data->completion, timeout)) { regmap_write(data->regmap, SI1133_REG_IRQ_ENABLE, 0); - err = -ETIMEDOUT; - goto out; + return -ETIMEDOUT; } err = regmap_read(data->regmap, SI1133_REG_RESPONSE0, &resp); if (err) - goto out; + return err; } else { err = regmap_read_poll_timeout(data->regmap, SI1133_REG_RESPONSE0, resp, @@ -444,7 +444,7 @@ static int si1133_command(struct si1133_data *data, u8 cmd) * counters being out of sync. */ si1133_cmd_reset_counter(data); - goto out; + return err; } } @@ -455,9 +455,6 @@ static int si1133_command(struct si1133_data *data, u8 cmd) data->rsp_seq = expected_seq; } -out: - mutex_unlock(&data->mutex); - return err; } From 5a6249110e0f845bfe181ccc0c275995f26469cf Mon Sep 17 00:00:00 2001 From: Maxwell Doose Date: Thu, 30 Apr 2026 07:41:47 -0500 Subject: [PATCH 120/266] iio: magnetometer: rm3100: Modernize locking and refactor control flow Replace mutex_lock() and mutex_unlock() calls in rm3100-core.c with the more modern guard(mutex)() family. This will help modernize the driver and bring it up-to-date with modern available macros/functions. While replacing mutex_lock() and mutex_unlock(), the critical sections of rm3100_read_mag() and rm3100_get_samp_freq() have been extended to include negligible operations for cleaner logic. Add new helper-wrapper function rm3100_regmap_bulk_read_locked() to help keep rm3100_trigger_handler() switch-cases clean while maintaining mutex locking and avoiding re-entrancy risks from potential callbacks. While at it, remove redundant gotos where applicable, and use direct returns instead. In addition, remove regmap variable in rm3100_trigger_handler() as its references have been replaced with variable data. Suggested-by: Jonathan Cameron Reviewed-by: Andy Shevchenko Signed-off-by: Maxwell Doose Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/rm3100-core.c | 94 ++++++++++++++------------ 1 file changed, 51 insertions(+), 43 deletions(-) diff --git a/drivers/iio/magnetometer/rm3100-core.c b/drivers/iio/magnetometer/rm3100-core.c index 2b2884425746..ac3f9f7fc808 100644 --- a/drivers/iio/magnetometer/rm3100-core.c +++ b/drivers/iio/magnetometer/rm3100-core.c @@ -204,27 +204,23 @@ static int rm3100_read_mag(struct rm3100_data *data, int idx, int *val) u8 buffer[3]; int ret; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); + ret = regmap_write(regmap, RM3100_REG_POLL, BIT(4 + idx)); if (ret < 0) - goto unlock_return; + return ret; ret = rm3100_wait_measurement(data); if (ret < 0) - goto unlock_return; + return ret; ret = regmap_bulk_read(regmap, RM3100_REG_MX2 + 3 * idx, buffer, 3); if (ret < 0) - goto unlock_return; - mutex_unlock(&data->lock); + return ret; *val = sign_extend32(get_unaligned_be24(&buffer[0]), 23); return IIO_VAL_INT; - -unlock_return: - mutex_unlock(&data->lock); - return ret; } #define RM3100_CHANNEL(axis, idx) \ @@ -284,11 +280,12 @@ static int rm3100_get_samp_freq(struct rm3100_data *data, int *val, int *val2) unsigned int tmp; int ret; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); + ret = regmap_read(data->regmap, RM3100_REG_TMRC, &tmp); - mutex_unlock(&data->lock); if (ret < 0) return ret; + *val = rm3100_samp_rates[tmp - RM3100_TMRC_OFFSET][0]; *val2 = rm3100_samp_rates[tmp - RM3100_TMRC_OFFSET][1]; @@ -338,56 +335,50 @@ static int rm3100_set_samp_freq(struct iio_dev *indio_dev, int val, int val2) int ret; int i; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); + /* All cycle count registers use the same value. */ ret = regmap_read(regmap, RM3100_REG_CC_X, &cycle_count); if (ret < 0) - goto unlock_return; + return ret; for (i = 0; i < RM3100_SAMP_NUM; i++) { if (val == rm3100_samp_rates[i][0] && val2 == rm3100_samp_rates[i][1]) break; } - if (i == RM3100_SAMP_NUM) { - ret = -EINVAL; - goto unlock_return; - } + if (i == RM3100_SAMP_NUM) + return -EINVAL; ret = regmap_write(regmap, RM3100_REG_TMRC, i + RM3100_TMRC_OFFSET); if (ret < 0) - goto unlock_return; + return ret; /* Checking if cycle count registers need changing. */ if (val == 600 && cycle_count == 200) { ret = rm3100_set_cycle_count(data, 100); if (ret < 0) - goto unlock_return; + return ret; } else if (val != 600 && cycle_count == 100) { ret = rm3100_set_cycle_count(data, 200); if (ret < 0) - goto unlock_return; + return ret; } if (iio_buffer_enabled(indio_dev)) { /* Writing TMRC registers requires CMM reset. */ ret = regmap_write(regmap, RM3100_REG_CMM, 0); if (ret < 0) - goto unlock_return; + return ret; ret = regmap_write(data->regmap, RM3100_REG_CMM, (*indio_dev->active_scan_mask & 0x7) << RM3100_CMM_AXIS_SHIFT | RM3100_CMM_START); if (ret < 0) - goto unlock_return; + return ret; } - mutex_unlock(&data->lock); data->conversion_time = rm3100_samp_rates[i][2] * 2; return 0; - -unlock_return: - mutex_unlock(&data->lock); - return ret; } static int rm3100_read_raw(struct iio_dev *indio_dev, @@ -458,6 +449,27 @@ static const struct iio_buffer_setup_ops rm3100_buffer_ops = { .postdisable = rm3100_buffer_postdisable, }; +/** + * rm3100_regmap_bulk_read_locked() - Wrapper around regmap_bulk_read() with a mutex + * + * @data: Data structure containing regmap and mutex + * @reg: First register to be read from, passed to regmap_bulk_read() + * @val: Pointer to store read value, in native register size for device, + * passed to regmap_bulk_read() + * @val_count: Number of registers to read, passed to regmap_bulk_read() + * + * Intended for use only in rm3100_trigger_handler(). + * + * Return: + * A value of zero on success, a negative errno in error cases. + */ +static int rm3100_regmap_bulk_read_locked(struct rm3100_data *data, unsigned int reg, + void *val, size_t val_count) +{ + guard(mutex)(&data->lock); + return regmap_bulk_read(data->regmap, reg, val, val_count); +} + static irqreturn_t rm3100_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; @@ -465,14 +477,12 @@ static irqreturn_t rm3100_trigger_handler(int irq, void *p) unsigned long scan_mask = *indio_dev->active_scan_mask; unsigned int mask_len = iio_get_masklength(indio_dev); struct rm3100_data *data = iio_priv(indio_dev); - struct regmap *regmap = data->regmap; int ret, i, bit; - mutex_lock(&data->lock); switch (scan_mask) { case BIT(0) | BIT(1) | BIT(2): - ret = regmap_bulk_read(regmap, RM3100_REG_MX2, data->buffer, 9); - mutex_unlock(&data->lock); + ret = rm3100_regmap_bulk_read_locked(data, RM3100_REG_MX2, + data->buffer, 9); if (ret < 0) goto done; /* Convert XXXYYYZZZxxx to XXXxYYYxZZZx. x for paddings. */ @@ -480,36 +490,34 @@ static irqreturn_t rm3100_trigger_handler(int irq, void *p) memmove(data->buffer + i * 4, data->buffer + i * 3, 3); break; case BIT(0) | BIT(1): - ret = regmap_bulk_read(regmap, RM3100_REG_MX2, data->buffer, 6); - mutex_unlock(&data->lock); + ret = rm3100_regmap_bulk_read_locked(data, RM3100_REG_MX2, + data->buffer, 6); if (ret < 0) goto done; memmove(data->buffer + 4, data->buffer + 3, 3); break; case BIT(1) | BIT(2): - ret = regmap_bulk_read(regmap, RM3100_REG_MY2, data->buffer, 6); - mutex_unlock(&data->lock); + ret = rm3100_regmap_bulk_read_locked(data, RM3100_REG_MY2, + data->buffer, 6); if (ret < 0) goto done; memmove(data->buffer + 4, data->buffer + 3, 3); break; case BIT(0) | BIT(2): - ret = regmap_bulk_read(regmap, RM3100_REG_MX2, data->buffer, 9); - mutex_unlock(&data->lock); + ret = rm3100_regmap_bulk_read_locked(data, RM3100_REG_MX2, + data->buffer, 9); if (ret < 0) goto done; memmove(data->buffer + 4, data->buffer + 6, 3); break; default: for_each_set_bit(bit, &scan_mask, mask_len) { - ret = regmap_bulk_read(regmap, RM3100_REG_MX2 + 3 * bit, - data->buffer, 3); - if (ret < 0) { - mutex_unlock(&data->lock); + ret = rm3100_regmap_bulk_read_locked(data, + RM3100_REG_MX2 + 3 * bit, + data->buffer, 3); + if (ret < 0) goto done; - } } - mutex_unlock(&data->lock); } /* * Always using the same buffer so that we wouldn't need to set the From 0c794147f2450a7948f22820698607b4e1b7c49e Mon Sep 17 00:00:00 2001 From: Marcelo Machado Lage Date: Wed, 29 Apr 2026 19:44:00 -0300 Subject: [PATCH 121/266] iio: adc: mcp3422: rewrite mask macros with help of bits.h APIs Rewrite MCP3422_CHANNEL_MASK, MCP3422_SRATE_MASK, MCP3422_PGA_MASK and MCP3422_CONT_SAMPLING using GENMASK() and BIT() macros from bits.h. The other macros MCP3422_SRATE_{240, 60, 15, 3} were not changed because they are also used as array indices. Signed-off-by: Marcelo Machado Lage Co-developed-by: Vinicius Lira Signed-off-by: Vinicius Lira Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/mcp3422.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c index 50834fdcf738..0cd0e7d39e39 100644 --- a/drivers/iio/adc/mcp3422.c +++ b/drivers/iio/adc/mcp3422.c @@ -13,6 +13,7 @@ * voltage unit is nV. */ +#include #include #include #include @@ -24,10 +25,10 @@ #include #include -/* Masks */ -#define MCP3422_CHANNEL_MASK 0x60 -#define MCP3422_PGA_MASK 0x03 -#define MCP3422_SRATE_MASK 0x0C +#define MCP3422_CHANNEL_MASK GENMASK(6, 5) +#define MCP3422_SRATE_MASK GENMASK(3, 2) +#define MCP3422_PGA_MASK GENMASK(1, 0) + #define MCP3422_SRATE_240 0x0 #define MCP3422_SRATE_60 0x1 #define MCP3422_SRATE_15 0x2 @@ -36,7 +37,7 @@ #define MCP3422_PGA_2 1 #define MCP3422_PGA_4 2 #define MCP3422_PGA_8 3 -#define MCP3422_CONT_SAMPLING 0x10 +#define MCP3422_CONT_SAMPLING BIT(4) #define MCP3422_CHANNEL(config) (((config) & MCP3422_CHANNEL_MASK) >> 5) #define MCP3422_PGA(config) ((config) & MCP3422_PGA_MASK) From 484f68c753373d5f5c02a6014bdc8aa28fb820a3 Mon Sep 17 00:00:00 2001 From: Marcelo Machado Lage Date: Wed, 29 Apr 2026 19:44:01 -0300 Subject: [PATCH 122/266] iio: adc: mcp3422: write bit operations using bitfield.h APIs Replace manual bit manipulations with FIELD_GET(), FIELD_PREP() and FIELD_MODIFY() calls. The resulting code is more readable and maintainable, and 6 macros previously defined in the header are not needed anymore. Signed-off-by: Marcelo Machado Lage Co-developed-by: Vinicius Lira Signed-off-by: Vinicius Lira Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/mcp3422.c | 54 +++++++++++++++------------------------ 1 file changed, 21 insertions(+), 33 deletions(-) diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c index 0cd0e7d39e39..0cbd7a874798 100644 --- a/drivers/iio/adc/mcp3422.c +++ b/drivers/iio/adc/mcp3422.c @@ -13,6 +13,7 @@ * voltage unit is nV. */ +#include #include #include #include @@ -39,14 +40,6 @@ #define MCP3422_PGA_8 3 #define MCP3422_CONT_SAMPLING BIT(4) -#define MCP3422_CHANNEL(config) (((config) & MCP3422_CHANNEL_MASK) >> 5) -#define MCP3422_PGA(config) ((config) & MCP3422_PGA_MASK) -#define MCP3422_SAMPLE_RATE(config) (((config) & MCP3422_SRATE_MASK) >> 2) - -#define MCP3422_CHANNEL_VALUE(value) (((value) << 5) & MCP3422_CHANNEL_MASK) -#define MCP3422_PGA_VALUE(value) ((value) & MCP3422_PGA_MASK) -#define MCP3422_SAMPLE_RATE_VALUE(value) ((value << 2) & MCP3422_SRATE_MASK) - #define MCP3422_CHAN(_index) \ { \ .type = IIO_VOLTAGE, \ @@ -109,7 +102,7 @@ static int mcp3422_update_config(struct mcp3422 *adc, u8 newconfig) static int mcp3422_read(struct mcp3422 *adc, int *value, u8 *config) { int ret = 0; - u8 sample_rate = MCP3422_SAMPLE_RATE(adc->config); + u8 sample_rate = FIELD_GET(MCP3422_SRATE_MASK, adc->config); u8 buf[4] = {0, 0, 0, 0}; u32 temp; @@ -137,18 +130,18 @@ static int mcp3422_read_channel(struct mcp3422 *adc, mutex_lock(&adc->lock); - if (req_channel != MCP3422_CHANNEL(adc->config)) { + if (req_channel != FIELD_GET(MCP3422_CHANNEL_MASK, adc->config)) { config = adc->config; - config &= ~MCP3422_CHANNEL_MASK; - config |= MCP3422_CHANNEL_VALUE(req_channel); - config &= ~MCP3422_PGA_MASK; - config |= MCP3422_PGA_VALUE(adc->pga[req_channel]); + + FIELD_MODIFY(MCP3422_CHANNEL_MASK, &config, req_channel); + FIELD_MODIFY(MCP3422_PGA_MASK, &config, adc->pga[req_channel]); + ret = mcp3422_update_config(adc, config); if (ret < 0) { mutex_unlock(&adc->lock); return ret; } - msleep(mcp3422_read_times[MCP3422_SAMPLE_RATE(adc->config)]); + msleep(mcp3422_read_times[FIELD_GET(MCP3422_SRATE_MASK, adc->config)]); } ret = mcp3422_read(adc, value, &config); @@ -164,9 +157,8 @@ static int mcp3422_read_raw(struct iio_dev *iio, { struct mcp3422 *adc = iio_priv(iio); int err; - - u8 sample_rate = MCP3422_SAMPLE_RATE(adc->config); - u8 pga = MCP3422_PGA(adc->config); + u8 sample_rate = FIELD_GET(MCP3422_SRATE_MASK, adc->config); + u8 pga = FIELD_GET(MCP3422_PGA_MASK, adc->config); switch (mask) { case IIO_CHAN_INFO_RAW: @@ -182,7 +174,7 @@ static int mcp3422_read_raw(struct iio_dev *iio, return IIO_VAL_INT_PLUS_NANO; case IIO_CHAN_INFO_SAMP_FREQ: - *val1 = mcp3422_sample_rates[MCP3422_SAMPLE_RATE(adc->config)]; + *val1 = mcp3422_sample_rates[FIELD_GET(MCP3422_SRATE_MASK, adc->config)]; return IIO_VAL_INT; default: @@ -200,7 +192,7 @@ static int mcp3422_write_raw(struct iio_dev *iio, u8 temp; u8 config = adc->config; u8 req_channel = channel->channel; - u8 sample_rate = MCP3422_SAMPLE_RATE(config); + u8 sample_rate = FIELD_GET(MCP3422_SRATE_MASK, config); u8 i; switch (mask) { @@ -212,10 +204,8 @@ static int mcp3422_write_raw(struct iio_dev *iio, if (val2 == mcp3422_scales[sample_rate][i]) { adc->pga[req_channel] = i; - config &= ~MCP3422_CHANNEL_MASK; - config |= MCP3422_CHANNEL_VALUE(req_channel); - config &= ~MCP3422_PGA_MASK; - config |= MCP3422_PGA_VALUE(adc->pga[req_channel]); + FIELD_MODIFY(MCP3422_CHANNEL_MASK, &config, req_channel); + FIELD_MODIFY(MCP3422_PGA_MASK, &config, adc->pga[req_channel]); return mcp3422_update_config(adc, config); } @@ -242,10 +232,8 @@ static int mcp3422_write_raw(struct iio_dev *iio, return -EINVAL; } - config &= ~MCP3422_CHANNEL_MASK; - config |= MCP3422_CHANNEL_VALUE(req_channel); - config &= ~MCP3422_SRATE_MASK; - config |= MCP3422_SAMPLE_RATE_VALUE(temp); + FIELD_MODIFY(MCP3422_CHANNEL_MASK, &config, req_channel); + FIELD_MODIFY(MCP3422_SRATE_MASK, &config, temp); return mcp3422_update_config(adc, config); @@ -284,7 +272,7 @@ static ssize_t mcp3422_show_scales(struct device *dev, struct device_attribute *attr, char *buf) { struct mcp3422 *adc = iio_priv(dev_to_iio_dev(dev)); - u8 sample_rate = MCP3422_SAMPLE_RATE(adc->config); + u8 sample_rate = FIELD_GET(MCP3422_SRATE_MASK, adc->config); return sprintf(buf, "0.%09u 0.%09u 0.%09u 0.%09u\n", mcp3422_scales[sample_rate][0], @@ -377,10 +365,10 @@ static int mcp3422_probe(struct i2c_client *client) } /* meaningful default configuration */ - config = (MCP3422_CONT_SAMPLING - | MCP3422_CHANNEL_VALUE(0) - | MCP3422_PGA_VALUE(MCP3422_PGA_1) - | MCP3422_SAMPLE_RATE_VALUE(MCP3422_SRATE_240)); + config = MCP3422_CONT_SAMPLING | + FIELD_PREP(MCP3422_CHANNEL_MASK, 0) | + FIELD_PREP(MCP3422_PGA_MASK, MCP3422_PGA_1) | + FIELD_PREP(MCP3422_SRATE_MASK, MCP3422_SRATE_240); err = mcp3422_update_config(adc, config); if (err < 0) return err; From 4bb316664b7b857a1e57280164813f95a7e05a6a Mon Sep 17 00:00:00 2001 From: Pedro Barletta Gennari Date: Tue, 28 Apr 2026 22:29:54 -0300 Subject: [PATCH 123/266] iio: light: iqs621-als: use lock guards Use guard(mutex)() for handling mutex lock instead of manually locking and unlocking the mutex. This prevents forgotten locks due to early exits and removes the need of gotos. Signed-off-by: Pedro Barletta Gennari Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/light/iqs621-als.c | 93 ++++++++++++---------------------- 1 file changed, 31 insertions(+), 62 deletions(-) diff --git a/drivers/iio/light/iqs621-als.c b/drivers/iio/light/iqs621-als.c index b9f230210f07..25a655b328fc 100644 --- a/drivers/iio/light/iqs621-als.c +++ b/drivers/iio/light/iqs621-als.c @@ -5,6 +5,7 @@ * Copyright (C) 2019 Jeff LaBundy */ +#include #include #include #include @@ -107,26 +108,20 @@ static int iqs621_als_notifier(struct notifier_block *notifier, indio_dev = iqs621_als->indio_dev; timestamp = iio_get_time_ns(indio_dev); - mutex_lock(&iqs621_als->lock); + guard(mutex)(&iqs621_als->lock); if (event_flags & BIT(IQS62X_EVENT_SYS_RESET)) { ret = iqs621_als_init(iqs621_als); if (ret) { dev_err(indio_dev->dev.parent, "Failed to re-initialize device: %d\n", ret); - ret = NOTIFY_BAD; - } else { - ret = NOTIFY_OK; + return NOTIFY_BAD; } - - goto err_mutex; + return NOTIFY_OK; } - if (!iqs621_als->light_en && !iqs621_als->range_en && - !iqs621_als->prox_en) { - ret = NOTIFY_DONE; - goto err_mutex; - } + if (!iqs621_als->light_en && !iqs621_als->range_en && !iqs621_als->prox_en) + return NOTIFY_DONE; /* IQS621 only */ light_new = event_data->als_flags & IQS621_ALS_FLAGS_LIGHT; @@ -181,12 +176,7 @@ static int iqs621_als_notifier(struct notifier_block *notifier, iqs621_als->als_flags = event_data->als_flags; iqs621_als->ir_flags = event_data->ir_flags; - ret = NOTIFY_OK; - -err_mutex: - mutex_unlock(&iqs621_als->lock); - - return ret; + return NOTIFY_OK; } static void iqs621_als_notifier_unregister(void *context) @@ -241,30 +231,22 @@ static int iqs621_als_read_event_config(struct iio_dev *indio_dev, enum iio_event_direction dir) { struct iqs621_als_private *iqs621_als = iio_priv(indio_dev); - int ret; - mutex_lock(&iqs621_als->lock); + guard(mutex)(&iqs621_als->lock); switch (chan->type) { case IIO_LIGHT: - ret = iqs621_als->light_en; - break; + return iqs621_als->light_en; case IIO_INTENSITY: - ret = iqs621_als->range_en; - break; + return iqs621_als->range_en; case IIO_PROXIMITY: - ret = iqs621_als->prox_en; - break; + return iqs621_als->prox_en; default: - ret = -EINVAL; + return -EINVAL; } - - mutex_unlock(&iqs621_als->lock); - - return ret; } static int iqs621_als_write_event_config(struct iio_dev *indio_dev, @@ -278,11 +260,11 @@ static int iqs621_als_write_event_config(struct iio_dev *indio_dev, unsigned int val; int ret; - mutex_lock(&iqs621_als->lock); + guard(mutex)(&iqs621_als->lock); ret = regmap_read(iqs62x->regmap, iqs62x->dev_desc->als_flags, &val); if (ret) - goto err_mutex; + return ret; iqs621_als->als_flags = val; switch (chan->type) { @@ -293,7 +275,7 @@ static int iqs621_als_write_event_config(struct iio_dev *indio_dev, 0xFF); if (!ret) iqs621_als->light_en = state; - break; + return ret; case IIO_INTENSITY: ret = regmap_update_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK, @@ -302,12 +284,12 @@ static int iqs621_als_write_event_config(struct iio_dev *indio_dev, 0xFF); if (!ret) iqs621_als->range_en = state; - break; + return ret; case IIO_PROXIMITY: ret = regmap_read(iqs62x->regmap, IQS622_IR_FLAGS, &val); if (ret) - goto err_mutex; + return ret; iqs621_als->ir_flags = val; ret = regmap_update_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK, @@ -315,16 +297,11 @@ static int iqs621_als_write_event_config(struct iio_dev *indio_dev, state ? 0 : 0xFF); if (!ret) iqs621_als->prox_en = state; - break; + return ret; default: - ret = -EINVAL; + return -EINVAL; } - -err_mutex: - mutex_unlock(&iqs621_als->lock); - - return ret; } static int iqs621_als_read_event_value(struct iio_dev *indio_dev, @@ -335,33 +312,28 @@ static int iqs621_als_read_event_value(struct iio_dev *indio_dev, int *val, int *val2) { struct iqs621_als_private *iqs621_als = iio_priv(indio_dev); - int ret = IIO_VAL_INT; - mutex_lock(&iqs621_als->lock); + guard(mutex)(&iqs621_als->lock); switch (dir) { case IIO_EV_DIR_RISING: *val = iqs621_als->thresh_light * 16; - break; + return IIO_VAL_INT; case IIO_EV_DIR_FALLING: *val = iqs621_als->thresh_dark * 4; - break; + return IIO_VAL_INT; case IIO_EV_DIR_EITHER: if (iqs621_als->ir_flags_mask == IQS622_IR_FLAGS_TOUCH) *val = iqs621_als->thresh_prox * 4; else *val = iqs621_als->thresh_prox; - break; + return IIO_VAL_INT; default: - ret = -EINVAL; + return -EINVAL; } - - mutex_unlock(&iqs621_als->lock); - - return ret; } static int iqs621_als_write_event_value(struct iio_dev *indio_dev, @@ -375,9 +347,9 @@ static int iqs621_als_write_event_value(struct iio_dev *indio_dev, struct iqs62x_core *iqs62x = iqs621_als->iqs62x; unsigned int thresh_reg, thresh_val; u8 ir_flags_mask, *thresh_cache; - int ret = -EINVAL; + int ret; - mutex_lock(&iqs621_als->lock); + guard(mutex)(&iqs621_als->lock); switch (dir) { case IIO_EV_DIR_RISING: @@ -426,30 +398,27 @@ static int iqs621_als_write_event_value(struct iio_dev *indio_dev, break; default: - goto err_mutex; + return -EINVAL; } thresh_cache = &iqs621_als->thresh_prox; break; default: - goto err_mutex; + return -EINVAL; } if (thresh_val > 0xFF) - goto err_mutex; + return -EINVAL; ret = regmap_write(iqs62x->regmap, thresh_reg, thresh_val); if (ret) - goto err_mutex; + return ret; *thresh_cache = thresh_val; iqs621_als->ir_flags_mask = ir_flags_mask; -err_mutex: - mutex_unlock(&iqs621_als->lock); - - return ret; + return 0; } static const struct iio_info iqs621_als_info = { From f326d8f8f00676f07a40a5f3fbd1c89d854b89bd Mon Sep 17 00:00:00 2001 From: Pedro Barletta Gennari Date: Tue, 28 Apr 2026 22:29:55 -0300 Subject: [PATCH 124/266] iio: light: iqs621-als: prefer early error handling over if (!ret) Handle errors as early as possible by replacing 'if (!ret)' with the more common form 'if (ret)'. This makes the code easier to read. Signed-off-by: Pedro Barletta Gennari Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/light/iqs621-als.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/drivers/iio/light/iqs621-als.c b/drivers/iio/light/iqs621-als.c index 25a655b328fc..cd5843e3e2c3 100644 --- a/drivers/iio/light/iqs621-als.c +++ b/drivers/iio/light/iqs621-als.c @@ -273,18 +273,22 @@ static int iqs621_als_write_event_config(struct iio_dev *indio_dev, iqs62x->dev_desc->als_mask, iqs621_als->range_en || state ? 0 : 0xFF); - if (!ret) - iqs621_als->light_en = state; - return ret; + if (ret) + return ret; + iqs621_als->light_en = state; + + return 0; case IIO_INTENSITY: ret = regmap_update_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK, iqs62x->dev_desc->als_mask, iqs621_als->light_en || state ? 0 : 0xFF); - if (!ret) - iqs621_als->range_en = state; - return ret; + if (ret) + return ret; + iqs621_als->range_en = state; + + return 0; case IIO_PROXIMITY: ret = regmap_read(iqs62x->regmap, IQS622_IR_FLAGS, &val); @@ -295,9 +299,11 @@ static int iqs621_als_write_event_config(struct iio_dev *indio_dev, ret = regmap_update_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK, iqs62x->dev_desc->ir_mask, state ? 0 : 0xFF); - if (!ret) - iqs621_als->prox_en = state; - return ret; + if (ret) + return ret; + iqs621_als->prox_en = state; + + return 0; default: return -EINVAL; From f2c7187e266c16c7a0034731ee468d76c0492644 Mon Sep 17 00:00:00 2001 From: Wang Zihan Date: Tue, 5 May 2026 17:22:43 +0800 Subject: [PATCH 125/266] iio: adxl313: fix typos in documentation Add missing space in "ADXL313is" and improve grammar for "a single types of channels" to "multiple channels of a single type" as suggested by Jonathan Cameron. Wrap long line as suggested by Andy Shevchenko. Signed-off-by: Wang Zihan Signed-off-by: Jonathan Cameron --- Documentation/iio/adxl313.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/iio/adxl313.rst b/Documentation/iio/adxl313.rst index 966e72c0109a..cc0829be0447 100644 --- a/Documentation/iio/adxl313.rst +++ b/Documentation/iio/adxl313.rst @@ -11,7 +11,7 @@ This driver supports Analog Device's ADXL313 on SPI/I2C bus. * `ADXL313 `_ -The ADXL313is a low noise density, low power, 3-axis accelerometer with +The ADXL313 is a low noise density, low power, 3-axis accelerometer with selectable measurement ranges. The ADXL313 supports the ±0.5 g, ±1 g, ±2 g and ±4 g ranges. @@ -112,9 +112,9 @@ apply the following formula: Where _offset and _scale are device attributes. If no _offset attribute is present, simply assume its value is 0. -The ADXL313 driver offers data for a single types of channels, the table below -shows the measurement units for the processed value, which are defined by the -IIO framework: +The ADXL313 driver offers data for multiple channels of a single type. +The table below shows the measurement units for the processed value, +which are defined by the IIO framework: +-------------------------------------+---------------------------+ | Channel type | Measurement unit | From 67f4f2b31da5120dcdb409b2fe33383437a4bad7 Mon Sep 17 00:00:00 2001 From: Kim Seer Paller Date: Tue, 5 May 2026 12:34:31 +0800 Subject: [PATCH 126/266] iio: ABI: Add DAC 500ohm, 3.85kohm, and 16kohm powerdown modes Add powerdown mode entries for DACs with 500 Ohm, 3.85 kOhm, and 16 kOhm resistor to ground output impedance states. These are used by the AD3531/AD3531R 4-channel DAC. Signed-off-by: Kim Seer Paller Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 60dfeff8f2c9..925a33fd309a 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -764,10 +764,13 @@ Contact: linux-iio@vger.kernel.org Description: Specifies the output powerdown mode. DAC output stage is disconnected from the amplifier and + 500ohm_to_gnd: connected to ground via a 500Ohm resistor, 1kohm_to_gnd: connected to ground via an 1kOhm resistor, 2.5kohm_to_gnd: connected to ground via a 2.5kOhm resistor, + 3.85kohm_to_gnd: connected to ground via a 3.85kOhm resistor, 6kohm_to_gnd: connected to ground via a 6kOhm resistor, 7.7kohm_to_gnd: connected to ground via a 7.7kOhm resistor, + 16kohm_to_gnd: connected to ground via a 16kOhm resistor, 20kohm_to_gnd: connected to ground via a 20kOhm resistor, 32kohm_to_gnd: connected to ground via a 32kOhm resistor, 42kohm_to_gnd: connected to ground via a 42kOhm resistor, From e94944d7364d3ddb273539492f9bd9c9a622549a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 6 May 2026 10:27:55 +0200 Subject: [PATCH 127/266] iio: magnetometer: ak8975: Add missed pm_runtime_put_autosuspend() call On the failure in the ak8975_read_axis() the PM runtime gets unbalanced. Balance it by calling pm_runtime_put_autosuspend() on error path as well. Fixes: cde4cb5dd422 ("iio: magn: ak8975: deploy runtime and system PM") Reported-by: Sashiko Closes: https://sashiko.dev/#/patchset/20260505-magnetometer-fixes-v5-0-831b9b5550fc%40gmail.com Signed-off-by: Andy Shevchenko Reviewed-by: Joshua Crofts Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/ak8975.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index 44782c26698b..e70101abfcd3 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -784,6 +784,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val) exit: mutex_unlock(&data->lock); + pm_runtime_put_autosuspend(&data->client->dev); dev_err(&client->dev, "Error in reading axis\n"); return ret; } From bde5858a2773dcc588b1b9a61943a645d5f1115f Mon Sep 17 00:00:00 2001 From: Joshua Crofts Date: Tue, 5 May 2026 13:45:57 +0200 Subject: [PATCH 128/266] iio: magnetometer: ak8975: sort headers alphabetically Sort include headers alphabetically to improve coding style and readability. No functional change. Signed-off-by: Joshua Crofts Reviewed-by: Maxwell Doose Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/ak8975.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index e70101abfcd3..e8d9151dc330 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -7,23 +7,23 @@ * Copyright (c) 2010, NVIDIA Corporation. */ -#include -#include -#include -#include +#include +#include +#include +#include #include #include -#include +#include +#include +#include #include -#include -#include -#include -#include #include +#include +#include +#include #include #include -#include #include #include #include From 9d59def370123edfb32b96b590dcba78a5bd6bf1 Mon Sep 17 00:00:00 2001 From: Joshua Crofts Date: Tue, 5 May 2026 13:45:58 +0200 Subject: [PATCH 129/266] iio: magnetometer: ak8975: update headers per IWYU principle Remove kernel.h proxy header and unused headers (slab.h, iio/sysfs.h, iio/trigger.h). Add missing headers to ensure atomicity (array_size.h, dev_printk.h, asm/byteorder.h, irqreturn.h, minmax.h, property.h, types.h, wait.h). Audited using the include-what-you-use tool. Reviewed-by: Andy Shevchenko Signed-off-by: Joshua Crofts Reviewed-by: Maxwell Doose Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/ak8975.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index e8d9151dc330..c401120a5f8b 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -7,24 +7,29 @@ * Copyright (c) 2010, NVIDIA Corporation. */ +#include #include #include +#include #include #include #include #include -#include +#include +#include #include #include #include #include +#include #include -#include +#include +#include + +#include #include #include -#include -#include #include #include From 1fcd1fef65145caa465f2fe967ad7d90ddcfbc95 Mon Sep 17 00:00:00 2001 From: Joshua Crofts Date: Tue, 5 May 2026 13:45:59 +0200 Subject: [PATCH 130/266] iio: magnetometer: ak8975: replace usleep_range() with fsleep() Replace usleep_range() calls with fsleep(), passing the minimum value required by the sensor for hardware delays. fsleep() automatically selects the optimal sleep mechanism, simplifying driver code and time management. Signed-off-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/ak8975.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index c401120a5f8b..b15ac73b37ed 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -461,7 +461,8 @@ static int ak8975_power_on(const struct ak8975_data *data) * and the minimum wait time before mode setting is 100us, in * total 300us. Add some margin and say minimum 500us here. */ - usleep_range(500, 1000); + fsleep(500); + return 0; } @@ -551,7 +552,7 @@ static int ak8975_set_mode(struct ak8975_data *data, enum ak_ctrl_mode mode) data->cntl_cache = regval; /* After mode change wait at least 100us */ - usleep_range(100, 500); + fsleep(100); return 0; } From 833ca882b76425a7ec12cc8090a390959d0b190f Mon Sep 17 00:00:00 2001 From: Joshua Crofts Date: Tue, 5 May 2026 13:46:00 +0200 Subject: [PATCH 131/266] iio: magnetometer: ak8975: change 'u8*' to 'u8 *' in cast Change 'u8*' cast to 'u8 *' as the former triggers a checkpatch error. Also fix the indentation of parameters in i2c_smbus_read_i2c_block_data_or_emulated() function. No functional change. Signed-off-by: Joshua Crofts Reviewed-by: Andy Shevchenko Reviewed-by: Maxwell Doose Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/ak8975.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index b15ac73b37ed..159c619bd26a 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -759,9 +759,10 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val) if (ret) goto exit; - ret = i2c_smbus_read_i2c_block_data_or_emulated( - client, def->data_regs[index], - sizeof(rval), (u8*)&rval); + ret = i2c_smbus_read_i2c_block_data_or_emulated(client, + def->data_regs[index], + sizeof(rval), + (u8 *)&rval); if (ret < 0) goto exit; From acea3560f387a749990567e151e6003ccc249e46 Mon Sep 17 00:00:00 2001 From: Joshua Crofts Date: Tue, 5 May 2026 13:46:01 +0200 Subject: [PATCH 132/266] iio: magnetometer: ak8975: fix wrong errno on return The driver currently returns -EINVAL on polling timeout instead of -ETIMEDOUT. Replace return code for -ETIMEDOUT and remove unnecessary error message as -ETIMEDOUT is a standard POSIX error. Also replace instances of -EINVAL in comments. Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Signed-off-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/ak8975.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index 159c619bd26a..9511528cdd7b 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -662,10 +662,8 @@ static int wait_conversion_complete_gpio(struct ak8975_data *data) break; timeout_ms -= AK8975_CONVERSION_DONE_POLL_TIME; } - if (!timeout_ms) { - dev_err(&client->dev, "Conversion timeout happened\n"); - return -EINVAL; - } + if (!timeout_ms) + return -ETIMEDOUT; ret = i2c_smbus_read_byte_data(client, data->def->ctrl_regs[ST1]); if (ret < 0) @@ -695,15 +693,13 @@ static int wait_conversion_complete_polled(struct ak8975_data *data) break; timeout_ms -= AK8975_CONVERSION_DONE_POLL_TIME; } - if (!timeout_ms) { - dev_err(&client->dev, "Conversion timeout happened\n"); - return -EINVAL; - } + if (!timeout_ms) + return -ETIMEDOUT; return read_status; } -/* Returns 0 if the end of conversion interrupt occurred or -ETIME otherwise */ +/* Returns 0 if the end of conversion interrupt occurred or -ETIMEDOUT otherwise */ static int wait_conversion_complete_interrupt(struct ak8975_data *data) { int ret; @@ -713,7 +709,7 @@ static int wait_conversion_complete_interrupt(struct ak8975_data *data) AK8975_DATA_READY_TIMEOUT); clear_bit(0, &data->flags); - return ret > 0 ? 0 : -ETIME; + return ret > 0 ? 0 : -ETIMEDOUT; } static int ak8975_start_read_axis(struct ak8975_data *data, From c0b3561c8e4a1a7c03177fa21376c04f554b3a57 Mon Sep 17 00:00:00 2001 From: Joshua Crofts Date: Tue, 5 May 2026 13:46:02 +0200 Subject: [PATCH 133/266] iio: magnetometer: ak8975: pass conversion timeouts as arguments Refactor wait_conversion_complete*_() helper function to accept poll and timeout values directly as parameters. This improves the readability of the code and does not rely on hardcoded macros. Besides that, fix the home grown and obviously wrong in some cases the jiffy-based timeout. Co-developed-by: Andy Shevchenko Signed-off-by: Andy Shevchenko Signed-off-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/ak8975.c | 37 ++++++++++++++----------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index 9511528cdd7b..dcb281149a9d 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -132,13 +133,6 @@ #define AK09912_MAX_REGS AK09912_REG_ASAZ -/* - * Miscellaneous values. - */ -#define AK8975_MAX_CONVERSION_TIMEOUT 500 -#define AK8975_CONVERSION_DONE_POLL_TIME 10 -#define AK8975_DATA_READY_TIMEOUT ((100*HZ)/1000) - /* * Precalculate scale factor (in Gauss units) for each axis and * store in the device data. @@ -649,18 +643,19 @@ static int ak8975_setup(struct i2c_client *client) return 0; } -static int wait_conversion_complete_gpio(struct ak8975_data *data) +static int wait_conversion_complete_gpio(struct ak8975_data *data, + unsigned int poll_ms, + unsigned int timeout_ms) { struct i2c_client *client = data->client; - u32 timeout_ms = AK8975_MAX_CONVERSION_TIMEOUT; int ret; /* Wait for the conversion to complete. */ while (timeout_ms) { - msleep(AK8975_CONVERSION_DONE_POLL_TIME); + msleep(poll_ms); if (gpiod_get_value(data->eoc_gpiod)) break; - timeout_ms -= AK8975_CONVERSION_DONE_POLL_TIME; + timeout_ms -= poll_ms; } if (!timeout_ms) return -ETIMEDOUT; @@ -672,16 +667,17 @@ static int wait_conversion_complete_gpio(struct ak8975_data *data) return ret; } -static int wait_conversion_complete_polled(struct ak8975_data *data) +static int wait_conversion_complete_polled(struct ak8975_data *data, + unsigned int poll_ms, + unsigned int timeout_ms) { struct i2c_client *client = data->client; u8 read_status; - u32 timeout_ms = AK8975_MAX_CONVERSION_TIMEOUT; int ret; /* Wait for the conversion to complete. */ while (timeout_ms) { - msleep(AK8975_CONVERSION_DONE_POLL_TIME); + msleep(poll_ms); ret = i2c_smbus_read_byte_data(client, data->def->ctrl_regs[ST1]); if (ret < 0) { @@ -691,7 +687,7 @@ static int wait_conversion_complete_polled(struct ak8975_data *data) read_status = ret; if (read_status) break; - timeout_ms -= AK8975_CONVERSION_DONE_POLL_TIME; + timeout_ms -= poll_ms; } if (!timeout_ms) return -ETIMEDOUT; @@ -700,13 +696,14 @@ static int wait_conversion_complete_polled(struct ak8975_data *data) } /* Returns 0 if the end of conversion interrupt occurred or -ETIMEDOUT otherwise */ -static int wait_conversion_complete_interrupt(struct ak8975_data *data) +static int wait_conversion_complete_interrupt(struct ak8975_data *data, + unsigned int timeout_ms) { int ret; ret = wait_event_timeout(data->data_ready_queue, test_bit(0, &data->flags), - AK8975_DATA_READY_TIMEOUT); + msecs_to_jiffies(timeout_ms)); clear_bit(0, &data->flags); return ret > 0 ? 0 : -ETIMEDOUT; @@ -725,11 +722,11 @@ static int ak8975_start_read_axis(struct ak8975_data *data, /* Wait for the conversion to complete. */ if (data->eoc_irq) - ret = wait_conversion_complete_interrupt(data); + ret = wait_conversion_complete_interrupt(data, 100); else if (data->eoc_gpiod) - ret = wait_conversion_complete_gpio(data); + ret = wait_conversion_complete_gpio(data, 10, 500); else - ret = wait_conversion_complete_polled(data); + ret = wait_conversion_complete_polled(data, 10, 500); if (ret < 0) return ret; From 4cff98838322d488016c1b0edfa980fc336de630 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 5 May 2026 13:46:05 +0200 Subject: [PATCH 134/266] iio: magnetometer: ak8975: avoid using temporary variable Avoid using temporary variable in ak8975_read_axis(). With that being done, the clamp_t() call becomes idiomatic in the driver and can be factored out to a helper later on (and if needed). Signed-off-by: Andy Shevchenko Signed-off-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/ak8975.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index dcb281149a9d..b9fe2d7eeef8 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -741,7 +741,6 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val) const struct i2c_client *client = data->client; const struct ak_def *def = data->def; __le16 rval; - u16 buff; int ret; pm_runtime_get_sync(&data->client->dev); @@ -778,8 +777,8 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val) pm_runtime_put_autosuspend(&data->client->dev); /* Swap bytes and convert to valid range. */ - buff = le16_to_cpu(rval); - *val = clamp_t(s16, buff, -def->range, def->range); + *val = clamp_t(s16, le16_to_cpu(rval), -def->range, def->range); + return IIO_VAL_INT; exit: From 6982743df9e70280caf337671db22c9b4afd4b45 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 5 May 2026 13:46:06 +0200 Subject: [PATCH 135/266] iio: magnetometer: ak8975: drop duplicate NULL check The gpiod_set_consumer_name() is NULL-aware, no need to perform the same check in the caller. Signed-off-by: Andy Shevchenko Signed-off-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/ak8975.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index b9fe2d7eeef8..00ac19325da6 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -919,8 +919,7 @@ static int ak8975_probe(struct i2c_client *client) eoc_gpiod = devm_gpiod_get_optional(&client->dev, NULL, GPIOD_IN); if (IS_ERR(eoc_gpiod)) return PTR_ERR(eoc_gpiod); - if (eoc_gpiod) - gpiod_set_consumer_name(eoc_gpiod, "ak_8975"); + gpiod_set_consumer_name(eoc_gpiod, "ak_8975"); /* * According to AK09911 datasheet, if reset GPIO is provided then From 77e75249448a9b40b5a1a21756fd5a4c9573aa5b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 5 May 2026 13:46:07 +0200 Subject: [PATCH 136/266] iio: magnetometer: ak8975: remove duplicate error message The devm_request_irq() already prints an error message. Remove the duplicate. Signed-off-by: Andy Shevchenko Signed-off-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/ak8975.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index 00ac19325da6..31e9c7c52c18 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -583,17 +583,14 @@ static int ak8975_setup_irq(struct ak8975_data *data) rc = devm_request_irq(&client->dev, irq, ak8975_irq_handler, IRQF_TRIGGER_RISING, dev_name(&client->dev), data); - if (rc < 0) { - dev_err(&client->dev, "irq %d request failed: %d\n", irq, rc); + if (rc < 0) return rc; - } data->eoc_irq = irq; return rc; } - /* * Perform some start-of-day setup, including reading the asa calibration * values and caching them. From dbb1f2fa2bba8df30927419d8cb7c56016452a5c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 5 May 2026 13:46:08 +0200 Subject: [PATCH 137/266] iio: magnetometer: ak8975: reduce usage of magic lengths of the buffer Reduce usage of magic lengths of the supplied buffer by replacing them with the corresponding sizeof():s. Signed-off-by: Andy Shevchenko Signed-off-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/ak8975.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index 31e9c7c52c18..d51028b447f6 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -489,8 +489,10 @@ static int ak8975_who_i_am(struct i2c_client *client, * AK8975 | DEVICE_ID | NA * AK8963 | DEVICE_ID | NA */ - ret = i2c_smbus_read_i2c_block_data_or_emulated( - client, AK09912_REG_WIA1, 2, wia_val); + ret = i2c_smbus_read_i2c_block_data_or_emulated(client, + AK09912_REG_WIA1, + sizeof(wia_val), + wia_val); if (ret < 0) { dev_err(&client->dev, "Error reading WIA\n"); return ret; @@ -609,9 +611,10 @@ static int ak8975_setup(struct i2c_client *client) } /* Get asa data and store in the device data. */ - ret = i2c_smbus_read_i2c_block_data_or_emulated( - client, data->def->ctrl_regs[ASA_BASE], - 3, data->asa); + ret = i2c_smbus_read_i2c_block_data_or_emulated(client, + data->def->ctrl_regs[ASA_BASE], + sizeof(data->asa), + data->asa); if (ret < 0) { dev_err(&client->dev, "Not able to read asa data\n"); return ret; @@ -866,7 +869,7 @@ static void ak8975_fill_buffer(struct iio_dev *indio_dev) */ ret = i2c_smbus_read_i2c_block_data_or_emulated(client, def->data_regs[0], - 3 * sizeof(fval[0]), + sizeof(fval), (u8 *)fval); if (ret < 0) goto unlock; From a474d5cbdf306e65dc3a219c480a55b5a07893ed Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 5 May 2026 13:46:09 +0200 Subject: [PATCH 138/266] iio: magnetometer: ak8975: unify return code variable name In one case 'rc' is used in the other 'err', the most use 'ret'. Make the latter use the former, id est 'ret'. While at it, drop unneeded ' < 0' checks. Signed-off-by: Andy Shevchenko Signed-off-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/ak8975.c | 46 +++++++++++++++---------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index d51028b447f6..6be72e1cc0a8 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -572,8 +572,8 @@ static irqreturn_t ak8975_irq_handler(int irq, void *data) static int ak8975_setup_irq(struct ak8975_data *data) { struct i2c_client *client = data->client; - int rc; int irq; + int ret; init_waitqueue_head(&data->data_ready_queue); clear_bit(0, &data->flags); @@ -582,15 +582,15 @@ static int ak8975_setup_irq(struct ak8975_data *data) else irq = gpiod_to_irq(data->eoc_gpiod); - rc = devm_request_irq(&client->dev, irq, ak8975_irq_handler, - IRQF_TRIGGER_RISING, - dev_name(&client->dev), data); - if (rc < 0) - return rc; + ret = devm_request_irq(&client->dev, irq, ak8975_irq_handler, + IRQF_TRIGGER_RISING, + dev_name(&client->dev), data); + if (ret) + return ret; data->eoc_irq = irq; - return rc; + return 0; } /* @@ -908,8 +908,8 @@ static int ak8975_probe(struct i2c_client *client) struct iio_dev *indio_dev; struct gpio_desc *eoc_gpiod; struct gpio_desc *reset_gpiod; - int err; const char *name = NULL; + int ret; /* * Grab and set up the supplied GPIO. @@ -944,9 +944,9 @@ static int ak8975_probe(struct i2c_client *client) data->reset_gpiod = reset_gpiod; data->eoc_irq = 0; - err = iio_read_mount_matrix(&client->dev, &data->orientation); - if (err) - return err; + ret = iio_read_mount_matrix(&client->dev, &data->orientation); + if (ret) + return ret; /* id will be NULL when enumerated via ACPI */ data->def = i2c_get_match_data(client); @@ -967,20 +967,20 @@ static int ak8975_probe(struct i2c_client *client) if (IS_ERR(data->vid)) return PTR_ERR(data->vid); - err = ak8975_power_on(data); - if (err) - return err; + ret = ak8975_power_on(data); + if (ret) + return ret; - err = ak8975_who_i_am(client, data->def->type); - if (err < 0) { + ret = ak8975_who_i_am(client, data->def->type); + if (ret) { dev_err(&client->dev, "Unexpected device\n"); goto power_off; } dev_dbg(&client->dev, "Asahi compass chip %s\n", name); /* Perform some basic start-of-day setup of the device. */ - err = ak8975_setup(client); - if (err < 0) { + ret = ak8975_setup(client); + if (ret) { dev_err(&client->dev, "%s initialization fails\n", name); goto power_off; } @@ -993,15 +993,15 @@ static int ak8975_probe(struct i2c_client *client) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->name = name; - err = iio_triggered_buffer_setup(indio_dev, NULL, ak8975_handle_trigger, + ret = iio_triggered_buffer_setup(indio_dev, NULL, ak8975_handle_trigger, NULL); - if (err) { + if (ret) { dev_err(&client->dev, "triggered buffer setup failed\n"); goto power_off; } - err = iio_device_register(indio_dev); - if (err) { + ret = iio_device_register(indio_dev); + if (ret) { dev_err(&client->dev, "device register failed\n"); goto cleanup_buffer; } @@ -1024,7 +1024,7 @@ static int ak8975_probe(struct i2c_client *client) iio_triggered_buffer_cleanup(indio_dev); power_off: ak8975_power_off(data); - return err; + return ret; } static void ak8975_remove(struct i2c_client *client) From a3c9f6785954f0919cb9d9ed7ef2fe76972eaa68 Mon Sep 17 00:00:00 2001 From: Felipe Ribeiro de Souza Date: Tue, 5 May 2026 23:24:28 -0300 Subject: [PATCH 139/266] iio: adc: ingenic-adc: rename ingenic_adc_enable_unlocked() function Rename ingenic_adc_enable_unlocked() to __ingenic_adc_enable() to better reflect that this helper must be called with the lock held. Signed-off-by: Felipe Ribeiro de Souza Co-developed-by: Lucas Ivars Cadima Ciziks Signed-off-by: Lucas Ivars Cadima Ciziks Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ingenic-adc.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/iio/adc/ingenic-adc.c b/drivers/iio/adc/ingenic-adc.c index 1e802c8779a4..231ff8d584c2 100644 --- a/drivers/iio/adc/ingenic-adc.c +++ b/drivers/iio/adc/ingenic-adc.c @@ -181,9 +181,8 @@ static void ingenic_adc_set_config(struct ingenic_adc *adc, mutex_unlock(&adc->lock); } -static void ingenic_adc_enable_unlocked(struct ingenic_adc *adc, - int engine, - bool enabled) +static void __ingenic_adc_enable(struct ingenic_adc *adc, int engine, + bool enabled) { u8 val; @@ -202,7 +201,7 @@ static void ingenic_adc_enable(struct ingenic_adc *adc, bool enabled) { mutex_lock(&adc->lock); - ingenic_adc_enable_unlocked(adc, engine, enabled); + __ingenic_adc_enable(adc, engine, enabled); mutex_unlock(&adc->lock); } @@ -222,11 +221,11 @@ static int ingenic_adc_capture(struct ingenic_adc *adc, cfg = readl(adc->base + JZ_ADC_REG_CFG); writel(cfg & ~JZ_ADC_REG_CFG_CMD_SEL, adc->base + JZ_ADC_REG_CFG); - ingenic_adc_enable_unlocked(adc, engine, true); + __ingenic_adc_enable(adc, engine, true); ret = readb_poll_timeout(adc->base + JZ_ADC_REG_ENABLE, val, !(val & BIT(engine)), 250, 1000); if (ret) - ingenic_adc_enable_unlocked(adc, engine, false); + __ingenic_adc_enable(adc, engine, false); writel(cfg, adc->base + JZ_ADC_REG_CFG); mutex_unlock(&adc->lock); From 7ea43bebc7966cc7c5c36bfaa9a3a1a404b32908 Mon Sep 17 00:00:00 2001 From: Felipe Ribeiro de Souza Date: Tue, 5 May 2026 23:24:29 -0300 Subject: [PATCH 140/266] iio: adc: ingenic-adc: refactor ingenic_adc_read_chan_info_raw() Extract the sample logic from ingenic_adc_read_chan_info_raw() into a new helper function __ingenic_adc_read_chan() to improve code readability and modularity. The helper handles the mutex-protected section for sampling channels, while the main function manages mutex and clock enabling/disabling. Signed-off-by: Felipe Ribeiro de Souza Co-developed-by: Lucas Ivars Cadima Ciziks Signed-off-by: Lucas Ivars Cadima Ciziks Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ingenic-adc.c | 40 +++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/drivers/iio/adc/ingenic-adc.c b/drivers/iio/adc/ingenic-adc.c index 231ff8d584c2..91e3ea661594 100644 --- a/drivers/iio/adc/ingenic-adc.c +++ b/drivers/iio/adc/ingenic-adc.c @@ -627,22 +627,12 @@ static int ingenic_adc_read_avail(struct iio_dev *iio_dev, } } -static int ingenic_adc_read_chan_info_raw(struct iio_dev *iio_dev, - struct iio_chan_spec const *chan, - int *val) +static int __ingenic_adc_read_chan(struct ingenic_adc *adc, + struct iio_chan_spec const *chan, + int *val) { int cmd, ret, engine = (chan->channel == INGENIC_ADC_BATTERY); - struct ingenic_adc *adc = iio_priv(iio_dev); - ret = clk_enable(adc->clk); - if (ret) { - dev_err(iio_dev->dev.parent, "Failed to enable clock: %d\n", - ret); - return ret; - } - - /* We cannot sample the aux channels in parallel. */ - mutex_lock(&adc->aux_lock); if (adc->soc_data->has_aux_md && engine == 0) { switch (chan->channel) { case INGENIC_ADC_AUX0: @@ -661,7 +651,7 @@ static int ingenic_adc_read_chan_info_raw(struct iio_dev *iio_dev, ret = ingenic_adc_capture(adc, engine); if (ret) - goto out; + return ret; switch (chan->channel) { case INGENIC_ADC_AUX0: @@ -674,9 +664,27 @@ static int ingenic_adc_read_chan_info_raw(struct iio_dev *iio_dev, break; } - ret = IIO_VAL_INT; -out: + return IIO_VAL_INT; +} + +static int ingenic_adc_read_chan_info_raw(struct iio_dev *iio_dev, + struct iio_chan_spec const *chan, + int *val) +{ + struct ingenic_adc *adc = iio_priv(iio_dev); + int ret; + + ret = clk_enable(adc->clk); + if (ret) { + dev_err(iio_dev->dev.parent, "Failed to enable clock: %d\n", ret); + return ret; + } + + /* We cannot sample the aux channels in parallel. */ + mutex_lock(&adc->aux_lock); + ret = __ingenic_adc_read_chan(adc, chan, val); mutex_unlock(&adc->aux_lock); + clk_disable(adc->clk); return ret; From a42fea859692c424fce81b830fbd4ff258d390a6 Mon Sep 17 00:00:00 2001 From: Felipe Ribeiro de Souza Date: Tue, 5 May 2026 23:24:30 -0300 Subject: [PATCH 141/266] iio: adc: ingenic-adc: use guard()() and scoped_guard() to handle synchronisation Replace mutex_lock() and mutex_unlock() calls with guard()() in functions ingenic_adc_set_adcmd(), ingenic_adc_set_config(), ingenic_adc_enable(), ingenic_adc_capture(), and with scoped_guard() in function ingenic_adc_read_chan_info_raw(). This removes the need to call the unlock function, as the lock is automatically released when the function return or the scope exits for any other case. Signed-off-by: Felipe Ribeiro de Souza Co-developed-by: Lucas Ivars Cadima Ciziks Signed-off-by: Lucas Ivars Cadima Ciziks Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ingenic-adc.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/drivers/iio/adc/ingenic-adc.c b/drivers/iio/adc/ingenic-adc.c index 91e3ea661594..414f69acab7b 100644 --- a/drivers/iio/adc/ingenic-adc.c +++ b/drivers/iio/adc/ingenic-adc.c @@ -7,6 +7,8 @@ */ #include + +#include #include #include #include @@ -115,7 +117,7 @@ static void ingenic_adc_set_adcmd(struct iio_dev *iio_dev, unsigned long mask) { struct ingenic_adc *adc = iio_priv(iio_dev); - mutex_lock(&adc->lock); + guard(mutex)(&adc->lock); /* Init ADCMD */ readl(adc->base + JZ_ADC_REG_ADCMD); @@ -162,8 +164,6 @@ static void ingenic_adc_set_adcmd(struct iio_dev *iio_dev, unsigned long mask) /* We're done */ writel(0, adc->base + JZ_ADC_REG_ADCMD); - - mutex_unlock(&adc->lock); } static void ingenic_adc_set_config(struct ingenic_adc *adc, @@ -172,13 +172,11 @@ static void ingenic_adc_set_config(struct ingenic_adc *adc, { uint32_t cfg; - mutex_lock(&adc->lock); + guard(mutex)(&adc->lock); cfg = readl(adc->base + JZ_ADC_REG_CFG) & ~mask; cfg |= val; writel(cfg, adc->base + JZ_ADC_REG_CFG); - - mutex_unlock(&adc->lock); } static void __ingenic_adc_enable(struct ingenic_adc *adc, int engine, @@ -200,9 +198,8 @@ static void ingenic_adc_enable(struct ingenic_adc *adc, int engine, bool enabled) { - mutex_lock(&adc->lock); + guard(mutex)(&adc->lock); __ingenic_adc_enable(adc, engine, enabled); - mutex_unlock(&adc->lock); } static int ingenic_adc_capture(struct ingenic_adc *adc, @@ -217,7 +214,7 @@ static int ingenic_adc_capture(struct ingenic_adc *adc, * probably due to the switch of VREF. We must keep the lock here to * avoid races with the buffer enable/disable functions. */ - mutex_lock(&adc->lock); + guard(mutex)(&adc->lock); cfg = readl(adc->base + JZ_ADC_REG_CFG); writel(cfg & ~JZ_ADC_REG_CFG_CMD_SEL, adc->base + JZ_ADC_REG_CFG); @@ -228,7 +225,6 @@ static int ingenic_adc_capture(struct ingenic_adc *adc, __ingenic_adc_enable(adc, engine, false); writel(cfg, adc->base + JZ_ADC_REG_CFG); - mutex_unlock(&adc->lock); return ret; } @@ -681,9 +677,8 @@ static int ingenic_adc_read_chan_info_raw(struct iio_dev *iio_dev, } /* We cannot sample the aux channels in parallel. */ - mutex_lock(&adc->aux_lock); - ret = __ingenic_adc_read_chan(adc, chan, val); - mutex_unlock(&adc->aux_lock); + scoped_guard(mutex, &adc->aux_lock) + ret = __ingenic_adc_read_chan(adc, chan, val); clk_disable(adc->clk); From 4452b868d669fbf6d5333cd03ab2bd8fbadb91a3 Mon Sep 17 00:00:00 2001 From: Maxwell Doose Date: Thu, 7 May 2026 12:24:04 -0500 Subject: [PATCH 142/266] MAINTAINERS: Add myself as SCD30 maintainer The current maintainer's email is no longer valid and the driver is being orphaned. Replace his entry with mine, as I am volunteering to take over. Link: https://lore.kernel.org/linux-iio/20260507170950.37a46820@jic23-huawei/T/#t Signed-off-by: Maxwell Doose Reviewed-by: Stepan Ionichev Signed-off-by: Jonathan Cameron --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index c316e3b44e19..80b1577cf9d1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -24193,7 +24193,7 @@ F: Documentation/devicetree/bindings/iio/chemical/senseair,sunrise.yaml F: drivers/iio/chemical/sunrise_co2.c SENSIRION SCD30 CARBON DIOXIDE SENSOR DRIVER -M: Tomasz Duszynski +M: Maxwell Doose S: Maintained F: Documentation/devicetree/bindings/iio/chemical/sensirion,scd30.yaml F: drivers/iio/chemical/scd30.h From 10ecf78420e647f1d5d52c4d5f852885624cf928 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 8 May 2026 08:08:33 +0200 Subject: [PATCH 143/266] iio: magnetometer: yamaha-yas530: Get rid of i2c_client_get_device_id() Instead of relying on the name from ID table, which might be ambiguous in some cases, use explicit product label in the driver data. With that being done, get rid of i2c_client_get_device_id() call. Signed-off-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/yamaha-yas530.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c index 140c422773f6..5acd23c6b97c 100644 --- a/drivers/iio/magnetometer/yamaha-yas530.c +++ b/drivers/iio/magnetometer/yamaha-yas530.c @@ -168,6 +168,7 @@ struct yas5xx; /** * struct yas5xx_chip_info - device-specific data and function pointers * @devid: device ID number + * @product_label: product label used in Linux * @product_name: product name of the YAS variant * @version_names: version letters or namings * @volatile_reg: device-specific volatile registers @@ -189,6 +190,7 @@ struct yas5xx; */ struct yas5xx_chip_info { unsigned int devid; + const char *product_label; const char *product_name; const char *version_names[2]; const int *volatile_reg; @@ -1323,6 +1325,7 @@ static int yas537_power_on(struct yas5xx *yas5xx) static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = { [yas530] = { .devid = YAS530_DEVICE_ID, + .product_label = "yas530", .product_name = "YAS530 MS-3E", .version_names = { "A", "B" }, .volatile_reg = yas530_volatile_reg, @@ -1338,6 +1341,7 @@ static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = { }, [yas532] = { .devid = YAS532_DEVICE_ID, + .product_label = "yas532", .product_name = "YAS532 MS-3R", .version_names = { "AB", "AC" }, .volatile_reg = yas530_volatile_reg, @@ -1353,6 +1357,7 @@ static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = { }, [yas533] = { .devid = YAS532_DEVICE_ID, + .product_label = "yas533", .product_name = "YAS533 MS-3F", .version_names = { "AB", "AC" }, .volatile_reg = yas530_volatile_reg, @@ -1368,6 +1373,7 @@ static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = { }, [yas537] = { .devid = YAS537_DEVICE_ID, + .product_label = "yas537", .product_name = "YAS537 MS-3T", .version_names = { "v0", "v1" }, /* version naming unknown */ .volatile_reg = yas537_volatile_reg, @@ -1385,7 +1391,6 @@ static const struct yas5xx_chip_info yas5xx_chip_info_tbl[] = { static int yas5xx_probe(struct i2c_client *i2c) { - const struct i2c_device_id *id = i2c_client_get_device_id(i2c); struct iio_dev *indio_dev; struct device *dev = &i2c->dev; struct yas5xx *yas5xx; @@ -1443,7 +1448,7 @@ static int yas5xx_probe(struct i2c_client *i2c) if (id_check != ci->devid) { ret = dev_err_probe(dev, -ENODEV, "device ID %02x doesn't match %s\n", - id_check, id->name); + id_check, ci->product_label); goto assert_reset; } @@ -1469,7 +1474,7 @@ static int yas5xx_probe(struct i2c_client *i2c) indio_dev->info = &yas5xx_info; indio_dev->available_scan_masks = yas5xx_scan_masks; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->name = id->name; + indio_dev->name = ci->product_label; indio_dev->channels = yas5xx_channels; indio_dev->num_channels = ARRAY_SIZE(yas5xx_channels); From 6a0814f6f97de97fd109f5749a7dcd90fbdd574c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 8 May 2026 08:08:34 +0200 Subject: [PATCH 144/266] iio: magnetometer: yamaha-yas530: Use devm_mutex_init() for mutex initialization Use devm_mutex_init() since it brings some benefits when CONFIG_DEBUG_MUTEXES is enabled. Signed-off-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/yamaha-yas530.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c index 5acd23c6b97c..b3ee4351a0bf 100644 --- a/drivers/iio/magnetometer/yamaha-yas530.c +++ b/drivers/iio/magnetometer/yamaha-yas530.c @@ -1405,7 +1405,10 @@ static int yas5xx_probe(struct i2c_client *i2c) yas5xx = iio_priv(indio_dev); i2c_set_clientdata(i2c, indio_dev); yas5xx->dev = dev; - mutex_init(&yas5xx->lock); + + ret = devm_mutex_init(dev, &yas5xx->lock); + if (ret) + return ret; ret = iio_read_mount_matrix(dev, &yas5xx->orientation); if (ret) From 49d7edc9bd8a2e9a50c918008338273a7c2fc071 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 8 May 2026 08:08:35 +0200 Subject: [PATCH 145/266] iio: magnetometer: yamaha-yas530: replace usleep_range() with fsleep() Replace usleep_range() with fsleep() to allow the kernel to select the most appropriate delay mechanism based on duration. Using USEC_PER_MSEC makes the unit conversion explicit. Signed-off-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/yamaha-yas530.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c index b3ee4351a0bf..6bd0535e5eb1 100644 --- a/drivers/iio/magnetometer/yamaha-yas530.c +++ b/drivers/iio/magnetometer/yamaha-yas530.c @@ -1317,7 +1317,7 @@ static int yas537_power_on(struct yas5xx *yas5xx) return ret; /* Wait until the coil has ramped up */ - usleep_range(YAS537_MAG_RCOIL_TIME_US, YAS537_MAG_RCOIL_TIME_US + 100); + fsleep(YAS537_MAG_RCOIL_TIME_US); return 0; } @@ -1426,7 +1426,7 @@ static int yas5xx_probe(struct i2c_client *i2c) return dev_err_probe(dev, ret, "cannot enable regulators\n"); /* See comment in runtime resume callback */ - usleep_range(31000, 40000); + fsleep(31 * USEC_PER_MSEC); /* This will take the device out of reset if need be */ yas5xx->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); @@ -1565,7 +1565,7 @@ static int yas5xx_runtime_resume(struct device *dev) * for all voltages to settle. The YAS532 is 10ms then 4ms for the * I2C to come online. Let's keep it safe and put this at 31ms. */ - usleep_range(31000, 40000); + fsleep(31 * USEC_PER_MSEC); gpiod_set_value_cansleep(yas5xx->reset, 0); ret = ci->power_on(yas5xx); From ae008f65398c2071b0b5510998d86f51d285a77d Mon Sep 17 00:00:00 2001 From: Giorgi Tchankvetadze Date: Fri, 8 May 2026 17:39:17 +0400 Subject: [PATCH 146/266] iio: chemical: scd30: make command lookup table const scd30_i2c_cmd_lookup_tbl contains fixed opcodes and is only read by scd30_i2c_command(). Make it const to document that it's immutable and allow it to be placed in read-only memory. Signed-off-by: Giorgi Tchankvetadze Reviewed-by: Stepan Ionichev Acked-by: Maxwell Doose Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/scd30_i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/chemical/scd30_i2c.c b/drivers/iio/chemical/scd30_i2c.c index 436df9c61a71..bf465cc71be7 100644 --- a/drivers/iio/chemical/scd30_i2c.c +++ b/drivers/iio/chemical/scd30_i2c.c @@ -20,7 +20,7 @@ #define SCD30_I2C_MAX_BUF_SIZE 18 #define SCD30_I2C_CRC8_POLYNOMIAL 0x31 -static u16 scd30_i2c_cmd_lookup_tbl[] = { +static const u16 scd30_i2c_cmd_lookup_tbl[] = { [CMD_START_MEAS] = 0x0010, [CMD_STOP_MEAS] = 0x0104, [CMD_MEAS_INTERVAL] = 0x4600, From 8e9c394520844fb11404b4f9f16749f90e1d8627 Mon Sep 17 00:00:00 2001 From: Stepan Ionichev Date: Thu, 7 May 2026 20:28:00 +0500 Subject: [PATCH 147/266] iio: chemical: scd30: reject (response=NULL, size>0) in scd30_i2c_command() scd30_i2c_command() takes an opaque "response" buffer plus its size. At the start of the function the code already checks if response is NULL (via the rsp local), but the response-decoding loop after the i2c transfer always dereferences rsp without re-checking. With the current callers in scd30_core.c this is harmless, since write commands pass response=NULL together with size=0 (so the loop body is never entered). The (response=NULL, size>0) combination has no useful meaning: there is nowhere to put the bytes that come back from the chip. Treat it as an invalid argument and bail out at the top of the function with -EINVAL, instead of silently doing the i2c transfer and dereferencing a NULL pointer in the decode loop. smatch flagged the inconsistency: drivers/iio/chemical/scd30_i2c.c:104 scd30_i2c_command() error: we previously assumed rsp could be null (see line 77) No functional change for the existing callers, which only ever use (response=NULL, size=0) for writes and (response!=NULL, size>0) for reads. Signed-off-by: Stepan Ionichev Acked-by: Maxwell Doose Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/scd30_i2c.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/iio/chemical/scd30_i2c.c b/drivers/iio/chemical/scd30_i2c.c index bf465cc71be7..9e841f565149 100644 --- a/drivers/iio/chemical/scd30_i2c.c +++ b/drivers/iio/chemical/scd30_i2c.c @@ -71,6 +71,9 @@ static int scd30_i2c_command(struct scd30_state *state, enum scd30_cmd cmd, u16 int i, ret; char crc; + if (!response && size != 0) + return -EINVAL; + put_unaligned_be16(scd30_i2c_cmd_lookup_tbl[cmd], buf); i = 2; From a67d263922b7a4a8c30863ee4d8d20a482117f37 Mon Sep 17 00:00:00 2001 From: Stepan Ionichev Date: Mon, 11 May 2026 10:30:43 +0500 Subject: [PATCH 148/266] iio: adc: ad7793: replace usleep_range() with fsleep() The AD7792/AD7793 datasheet (Rev. B, page 25, RESET section) says: "When a reset is initiated, the user must allow a period of 500 us before accessing any of the on-chip registers." Use fsleep(500) instead of usleep_range(500, 2000). The 500 us minimum stays the same; fsleep() picks the upper slack itself (about +25% on a default config -- narrower than the original 2000 us). Add a code comment with the datasheet reference so the "why" of the wait is visible at the call site. Signed-off-by: Stepan Ionichev Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7793.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/iio/adc/ad7793.c b/drivers/iio/adc/ad7793.c index 624530cce938..ea1c192e2142 100644 --- a/drivers/iio/adc/ad7793.c +++ b/drivers/iio/adc/ad7793.c @@ -268,7 +268,12 @@ static int ad7793_setup(struct iio_dev *indio_dev, ret = ad_sd_reset(&st->sd); if (ret < 0) goto out; - usleep_range(500, 2000); /* Wait for at least 500us */ + + /* + * Per AD7792/AD7793 datasheet (Rev. B, page 25, RESET section), + * allow 500 us after a reset before accessing on-chip registers. + */ + fsleep(500); /* write/read test for device presence */ ret = ad_sd_read_reg(&st->sd, AD7793_REG_ID, 1, &id); From af74304c9fe93c32e9ab2d0fc7c2717ba99a45a1 Mon Sep 17 00:00:00 2001 From: Stepan Ionichev Date: Mon, 11 May 2026 10:44:41 +0500 Subject: [PATCH 149/266] iio: frequency: adrf6780: replace usleep_range() with fsleep() The ADRF6780 datasheet (Rev. D, page 23, ADC section) says: "Wait approximately 200 us for the ADC to be ready." fsleep(200) expands to the same usleep_range(200, 250). Use the flexible sleep helper, which picks the right primitive for the given microsecond delay. Replace the generic "Recommended delay for the ADC to be ready" comment with the datasheet reference so the "why" of the wait is visible at the call site. No functional change. Signed-off-by: Stepan Ionichev Reviewed-by: Andy Shevchenko Reviewed-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/iio/frequency/adrf6780.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/iio/frequency/adrf6780.c b/drivers/iio/frequency/adrf6780.c index 257fd31a0b0e..9911b5273b22 100644 --- a/drivers/iio/frequency/adrf6780.c +++ b/drivers/iio/frequency/adrf6780.c @@ -188,8 +188,11 @@ static int adrf6780_read_adc_raw(struct adrf6780_state *st, unsigned int *read_v if (ret) goto exit; - /* Recommended delay for the ADC to be ready*/ - usleep_range(200, 250); + /* + * Per ADRF6780 datasheet (Rev. D, page 23, ADC section), + * wait approximately 200 us for the ADC to be ready. + */ + fsleep(200); ret = __adrf6780_spi_read(st, ADRF6780_REG_ADC_OUTPUT, read_val); if (ret) From d0f23d8a9091f43329e79bcd29bcac6bf81205e5 Mon Sep 17 00:00:00 2001 From: Md Shofiqul Islam Date: Sun, 10 May 2026 22:34:35 +0300 Subject: [PATCH 150/266] iio: adc: ti-ads1298: Fix incorrect timeout comment At the lowest supported data rate of 250Hz, one conversion period is 4ms, not 40ms. The 50ms timeout is deliberately conservative to allow for kernel scheduling latency, which can be significant under load or on slow machines. Fix the comment to state the correct conversion time, use "lowest sample rate" for clarity, and explain that the extra margin exists to absorb scheduling latency so that no one is tempted to shrink the timeout to match the conversion period. Also drop the redundant ret variable assignment by using the return value of wait_for_completion_timeout() directly in the if() condition. Signed-off-by: Md Shofiqul Islam Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-ads1298.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/ti-ads1298.c b/drivers/iio/adc/ti-ads1298.c index ae30b47e4514..25261163d3e2 100644 --- a/drivers/iio/adc/ti-ads1298.c +++ b/drivers/iio/adc/ti-ads1298.c @@ -210,9 +210,11 @@ static int ads1298_read_one(struct ads1298_private *priv, int chan_index) return ret; } - /* Cannot take longer than 40ms (250Hz) */ - ret = wait_for_completion_timeout(&priv->completion, msecs_to_jiffies(50)); - if (!ret) + /* + * One conversion takes at most 4ms at the lowest sample rate (250Hz). + * Use 50ms to allow for kernel scheduling latency. + */ + if (!wait_for_completion_timeout(&priv->completion, msecs_to_jiffies(50))) return -ETIMEDOUT; return 0; From 5d7b3df5c1be8f46c2d3eabd1c1fd7b27294cbd3 Mon Sep 17 00:00:00 2001 From: Md Shofiqul Islam Date: Sat, 9 May 2026 18:19:57 +0300 Subject: [PATCH 151/266] iio: adc: ti-ads1298: Add parentheses around macro parameter ADS1298_REG_CHnSET() is missing parentheses around the parameter 'n'. Add them to follow kernel macro coding style and prevent potential operator precedence issues if the argument is an expression. Signed-off-by: Md Shofiqul Islam Reviewed-by: Stepan Ionichev Acked-by: Mike Looijmans Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-ads1298.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/adc/ti-ads1298.c b/drivers/iio/adc/ti-ads1298.c index 25261163d3e2..69911b0cde84 100644 --- a/drivers/iio/adc/ti-ads1298.c +++ b/drivers/iio/adc/ti-ads1298.c @@ -66,7 +66,7 @@ #define ADS1298_MASK_CONFIG3_VREF_4V BIT(5) #define ADS1298_REG_LOFF 0x04 -#define ADS1298_REG_CHnSET(n) (0x05 + n) +#define ADS1298_REG_CHnSET(n) (0x05 + (n)) #define ADS1298_MASK_CH_PD BIT(7) #define ADS1298_MASK_CH_PGA GENMASK(6, 4) #define ADS1298_MASK_CH_MUX GENMASK(2, 0) From 01437ab5111f57005be54005f5b575dc06cb682e Mon Sep 17 00:00:00 2001 From: Md Shofiqul Islam Date: Sat, 9 May 2026 18:19:59 +0300 Subject: [PATCH 152/266] iio: adc: ti-ads1298: Remove unnecessary CONFIG2 write during init The driver was enabling the internal test signal (INT_TEST), double amplitude (TEST_AMP), and fast frequency (TEST_FREQ_FAST) bits in CONFIG2 during initialization. These bits activate an internal square wave generator intended for device testing and calibration, not normal ECG operation. CONFIG2 defaults to having only the RESERVED bit set after reset, which is the correct value for normal operation. Remove the write entirely since it would just be writing the reset default value. Suggested-by: Mike Looijmans Signed-off-by: Md Shofiqul Islam Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-ads1298.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/iio/adc/ti-ads1298.c b/drivers/iio/adc/ti-ads1298.c index 69911b0cde84..579200e06cbd 100644 --- a/drivers/iio/adc/ti-ads1298.c +++ b/drivers/iio/adc/ti-ads1298.c @@ -617,15 +617,6 @@ static int ads1298_init(struct iio_dev *indio_dev) if (!indio_dev->name) return -ENOMEM; - /* Enable internal test signal, double amplitude, double frequency */ - ret = regmap_write(priv->regmap, ADS1298_REG_CONFIG2, - ADS1298_MASK_CONFIG2_RESERVED | - ADS1298_MASK_CONFIG2_INT_TEST | - ADS1298_MASK_CONFIG2_TEST_AMP | - ADS1298_MASK_CONFIG2_TEST_FREQ_FAST); - if (ret) - return ret; - val = ADS1298_MASK_CONFIG3_RESERVED; /* Must write 1 always */ if (!priv->reg_vref) { /* Enable internal reference */ From 7e6a73eda92ac7aeda7587c65a1acd32b31a5c3b Mon Sep 17 00:00:00 2001 From: Stepan Ionichev Date: Mon, 11 May 2026 07:55:44 +0500 Subject: [PATCH 153/266] iio: adc: ad7192: replace usleep_range() with fsleep() The AD7192 datasheet (Rev. A, page 34, RESET section) says: "When a reset is initiated, the user must allow a period of 500 us before accessing any of the on-chip registers." Use fsleep(500) instead of usleep_range(500, 1000). Signed-off-by: Stepan Ionichev Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7192.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c index 8b1664f6b102..ba27614c89b4 100644 --- a/drivers/iio/adc/ad7192.c +++ b/drivers/iio/adc/ad7192.c @@ -576,7 +576,12 @@ static int ad7192_setup(struct iio_dev *indio_dev, struct device *dev) ret = ad_sd_reset(&st->sd); if (ret < 0) return ret; - usleep_range(500, 1000); /* Wait for at least 500us */ + + /* + * Per AD7192 datasheet (Rev. A, page 34, RESET section), allow + * 500 us after a reset before accessing on-chip registers. + */ + fsleep(500); /* write/read test for device presence */ ret = ad_sd_read_reg(&st->sd, AD7192_REG_ID, 1, &id); From 01b7517513e884ca2fa42852427ccb1ff6b849d7 Mon Sep 17 00:00:00 2001 From: Stepan Ionichev Date: Sun, 10 May 2026 16:38:52 +0500 Subject: [PATCH 154/266] iio: accel: adxl355: replace usleep_range() with fsleep() The "at least 5ms" wait after software reset has no specific upper bound. Use fsleep() with 5 * USEC_PER_MSEC to make the unit explicit at the call site. No functional change. Signed-off-by: Stepan Ionichev Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl355_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/accel/adxl355_core.c b/drivers/iio/accel/adxl355_core.c index 03e5744d9667..89ac62ff4d04 100644 --- a/drivers/iio/accel/adxl355_core.c +++ b/drivers/iio/accel/adxl355_core.c @@ -349,7 +349,7 @@ static int adxl355_setup(struct adxl355_data *data) return ret; /* Wait at least 5ms after software reset */ - usleep_range(5000, 10000); + fsleep(5 * USEC_PER_MSEC); /* Read shadow registers for comparison */ ret = regmap_bulk_read(data->regmap, From fcec89dfec1cb8fcd5ee7fb2b7d458633c4a8457 Mon Sep 17 00:00:00 2001 From: Antony Kurniawan Soemardi Date: Sun, 10 May 2026 07:01:41 +0000 Subject: [PATCH 155/266] iio: adc: qcom-pm8xxx-xoadc: remove redundant error logs when reading values Drop dev_err() logging for -EINVAL and -ETIMEDOUT cases and rely on return values to report errors, reducing unnecessary log noise. Reviewed-by: Dmitry Baryshkov Reviewed-by: Andy Shevchenko Signed-off-by: Antony Kurniawan Soemardi Signed-off-by: Jonathan Cameron --- drivers/iio/adc/qcom-pm8xxx-xoadc.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/iio/adc/qcom-pm8xxx-xoadc.c b/drivers/iio/adc/qcom-pm8xxx-xoadc.c index 31f88cf7f7f1..282a67b46a5e 100644 --- a/drivers/iio/adc/qcom-pm8xxx-xoadc.c +++ b/drivers/iio/adc/qcom-pm8xxx-xoadc.c @@ -535,10 +535,7 @@ static int pm8xxx_read_channel_rsv(struct pm8xxx_xoadc *adc, goto unlock; /* Next the interrupt occurs */ - ret = wait_for_completion_timeout(&adc->complete, - VADC_CONV_TIME_MAX_US); - if (!ret) { - dev_err(adc->dev, "conversion timed out\n"); + if (!wait_for_completion_timeout(&adc->complete, VADC_CONV_TIME_MAX_US)) { ret = -ETIMEDOUT; goto unlock; } @@ -657,11 +654,8 @@ static int pm8xxx_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_PROCESSED: ch = pm8xxx_get_channel(adc, chan->address); - if (!ch) { - dev_err(adc->dev, "no such channel %lu\n", - chan->address); + if (!ch) return -EINVAL; - } ret = pm8xxx_read_channel(adc, ch, &adc_code); if (ret) return ret; @@ -677,11 +671,8 @@ static int pm8xxx_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_RAW: ch = pm8xxx_get_channel(adc, chan->address); - if (!ch) { - dev_err(adc->dev, "no such channel %lu\n", - chan->address); + if (!ch) return -EINVAL; - } ret = pm8xxx_read_channel(adc, ch, &adc_code); if (ret) return ret; From 70a1012793056852df6eda5a89cbf0476e0590e9 Mon Sep 17 00:00:00 2001 From: Antony Kurniawan Soemardi Date: Sun, 10 May 2026 07:01:45 +0000 Subject: [PATCH 156/266] iio: adc: qcom-pm8xxx-xoadc: add support for reading channel labels Implement the .read_label callback to allow userspace to identify ADC channels via the "label" property in the device tree. The name field in pm8xxx_chan_info is renamed to label to better reflect its purpose. If no label is provided in the device tree, it defaults to the hardware datasheet name. The change has been tested on Sony Xperia SP (PM8921). Reviewed-by: Dmitry Baryshkov Signed-off-by: Antony Kurniawan Soemardi Reviewed-by: Linus Walleij Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/qcom-pm8xxx-xoadc.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/iio/adc/qcom-pm8xxx-xoadc.c b/drivers/iio/adc/qcom-pm8xxx-xoadc.c index 282a67b46a5e..4a1a0cfb4699 100644 --- a/drivers/iio/adc/qcom-pm8xxx-xoadc.c +++ b/drivers/iio/adc/qcom-pm8xxx-xoadc.c @@ -369,7 +369,7 @@ static const struct xoadc_channel pm8921_xoadc_channels[] = { /** * struct pm8xxx_chan_info - ADC channel information - * @name: name of this channel + * @label: label of this channel from device tree (defaults to datasheet name if not specified) * @hwchan: pointer to hardware channel information (muxing & scaling settings) * @calibration: whether to use absolute or ratiometric calibration * @decimation: 0,1,2,3 @@ -377,7 +377,7 @@ static const struct xoadc_channel pm8921_xoadc_channels[] = { * calibration: 0, 1, 2, 4, 5. */ struct pm8xxx_chan_info { - const char *name; + const char *label; const struct xoadc_channel *hwchan; enum vadc_calibration calibration; u8 decimation:2; @@ -446,7 +446,7 @@ static int pm8xxx_read_channel_rsv(struct pm8xxx_xoadc *adc, u8 lsb, msb; dev_dbg(adc->dev, "read channel \"%s\", amux %d, prescale/mux: %d, rsv %d\n", - ch->name, ch->hwchan->amux_channel, ch->hwchan->pre_scale_mux, rsv); + ch->label, ch->hwchan->amux_channel, ch->hwchan->pre_scale_mux, rsv); mutex_lock(&adc->lock); @@ -716,8 +716,21 @@ static int pm8xxx_fwnode_xlate(struct iio_dev *indio_dev, return -EINVAL; } +static int pm8xxx_read_label(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, char *label) +{ + struct pm8xxx_xoadc *adc = iio_priv(indio_dev); + const struct pm8xxx_chan_info *ch; + + ch = pm8xxx_get_channel(adc, chan->address); + if (!ch) + return -EINVAL; + return sysfs_emit(label, "%s\n", ch->label); +} + static const struct iio_info pm8xxx_xoadc_info = { .fwnode_xlate = pm8xxx_fwnode_xlate, + .read_label = pm8xxx_read_label, .read_raw = pm8xxx_read_raw, }; @@ -761,7 +774,8 @@ static int pm8xxx_xoadc_parse_channel(struct device *dev, pre_scale_mux, amux_channel); return -EINVAL; } - ch->name = name; + ch->label = hwchan->datasheet_name; + fwnode_property_read_string(fwnode, "label", &ch->label); ch->hwchan = hwchan; /* Everyone seems to use absolute calibration except in special cases */ ch->calibration = VADC_CALIB_ABSOLUTE; @@ -803,7 +817,7 @@ static int pm8xxx_xoadc_parse_channel(struct device *dev, dev_dbg(dev, "channel [PRESCALE/MUX: %02x AMUX: %02x] \"%s\" ref voltage: %d, decimation %d prescale %d/%d, scale function %d\n", - hwchan->pre_scale_mux, hwchan->amux_channel, ch->name, + hwchan->pre_scale_mux, hwchan->amux_channel, ch->label, ch->amux_ip_rsv, ch->decimation, hwchan->prescale.numerator, hwchan->prescale.denominator, hwchan->scale_fn_type); From 92767f9f574c985fdf9ff9c25e59624a74db58a1 Mon Sep 17 00:00:00 2001 From: Antony Kurniawan Soemardi Date: Sun, 10 May 2026 07:01:33 +0000 Subject: [PATCH 157/266] dt-bindings: iio: adc: qcom,pm8018-adc: add label property for ADC channels Add a new optional label property for ADC channels to help users identify each channel when reading values from the sysfs interface. Signed-off-by: Antony Kurniawan Soemardi Reviewed-by: Linus Walleij Signed-off-by: Jonathan Cameron --- .../bindings/iio/adc/qcom,pm8018-adc.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/adc/qcom,pm8018-adc.yaml b/Documentation/devicetree/bindings/iio/adc/qcom,pm8018-adc.yaml index c978c3a3e31a..63aac8de22ad 100644 --- a/Documentation/devicetree/bindings/iio/adc/qcom,pm8018-adc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/qcom,pm8018-adc.yaml @@ -78,6 +78,10 @@ patternProperties: reg: maxItems: 1 + label: + description: | + Unique name to identify which channel this is. + qcom,decimation: $ref: /schemas/types.yaml#/definitions/uint32 description: | @@ -130,36 +134,47 @@ examples: vcoin: adc-channel@0 { reg = <0x00 0x00>; + label = "vcoin"; }; vbat: adc-channel@1 { reg = <0x00 0x01>; + label = "vbat"; }; dcin: adc-channel@2 { reg = <0x00 0x02>; + label = "dcin"; }; ichg: adc-channel@3 { reg = <0x00 0x03>; + label = "ichg"; }; vph_pwr: adc-channel@4 { reg = <0x00 0x04>; + label = "vph_pwr"; }; usb_vbus: adc-channel@a { reg = <0x00 0x0a>; + label = "usb_vbus"; }; die_temp: adc-channel@b { reg = <0x00 0x0b>; + label = "die_temp"; }; ref_625mv: adc-channel@c { reg = <0x00 0x0c>; + label = "ref_625mv"; }; ref_1250mv: adc-channel@d { reg = <0x00 0x0d>; + label = "ref_1250mv"; }; ref_325mv: adc-channel@e { reg = <0x00 0x0e>; + label = "ref_325mv"; }; ref_muxoff: adc-channel@f { reg = <0x00 0x0f>; + label = "ref_muxoff"; }; }; }; From d20605e18129079876485d652992c7ab48aaecde Mon Sep 17 00:00:00 2001 From: Piyush Patle Date: Mon, 11 May 2026 23:13:26 +0530 Subject: [PATCH 158/266] dt-bindings: iio: adc: hx711: clean up existing binding text Rewrite the binding description and property text so it describes the existing HX711 hardware behavior directly instead of documenting old driver implementation details. Also clarify that clock-frequency controls the SCK bit-bang timing. No functional change. Signed-off-by: Piyush Patle Reviewed-by: Andy Shevchenko Acked-by: Conor Dooley Signed-off-by: Jonathan Cameron --- .../bindings/iio/adc/avia-hx711.yaml | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml b/Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml index 9c57eb13f892..1ea60dff98d5 100644 --- a/Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml +++ b/Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml @@ -10,14 +10,9 @@ maintainers: - Andreas Klinger description: | - Bit-banging driver using two GPIOs: - - sck-gpio gives a clock to the sensor with 24 cycles for data retrieval - and up to 3 cycles for selection of the input channel and gain for the - next measurement - - dout-gpio is the sensor data the sensor responds to the clock - - Specifications about the driver can be found at: - http://www.aviaic.com/ENProducts.aspx + The HX711 is a 24-bit ADC with selectable gain (32/64/128) and two + differential input channels. Channel A supports gain 64 and 128; + channel B supports gain 32. properties: compatible: @@ -26,23 +21,23 @@ properties: sck-gpios: description: - Definition of the GPIO for the clock (output). In the datasheet it is - named PD_SCK + GPIO for the clock output (PD_SCK in the datasheet). maxItems: 1 dout-gpios: description: - Definition of the GPIO for the data-out sent by the sensor in - response to the clock (input). - See Documentation/devicetree/bindings/gpio/gpio.txt for information - on how to specify a consumer gpio. + GPIO for the data output from the sensor (DOUT in the datasheet). maxItems: 1 avdd-supply: description: - Definition of the regulator used as analog supply + Analog supply voltage (AVDD). clock-frequency: + description: + Controls the SCK bit-bang timing. The value is used to derive the + delay between SCK edges; keep the SCK high time below 60 us to + avoid triggering chip power-down mode. minimum: 20000 maximum: 2500000 default: 400000 From 0ce8e3b445a3fec83a023f11512f63ff6da0d460 Mon Sep 17 00:00:00 2001 From: Piyush Patle Date: Mon, 11 May 2026 23:13:30 +0530 Subject: [PATCH 159/266] iio: adc: hx711: move scale computation to per-device storage The gain-to-scale table is global today, so probe-time scale updates for one device overwrite the values used by any earlier device instance. Fix this by making the gain table const and storing the computed scale values per device in hx711_data. No functional change for single-sensor configurations. Signed-off-by: Piyush Patle Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/hx711.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c index 1db8b68a8f64..86d2a70dd3de 100644 --- a/drivers/iio/adc/hx711.c +++ b/drivers/iio/adc/hx711.c @@ -28,22 +28,20 @@ struct hx711_gain_to_scale { int gain; int gain_pulse; - int scale; int channel; }; /* * .scale depends on AVDD which in turn is known as soon as the regulator - * is available - * therefore we set .scale in hx711_probe() + * is available; it is stored per device in hx711_data.gain_scale[] * * channel A in documentation is channel 0 in source code * channel B in documentation is channel 1 in source code */ -static struct hx711_gain_to_scale hx711_gain_to_scale[HX711_GAIN_MAX] = { - { 128, 1, 0, 0 }, - { 32, 2, 0, 1 }, - { 64, 3, 0, 0 } +static const struct hx711_gain_to_scale hx711_gain_to_scale[HX711_GAIN_MAX] = { + { 128, 1, 0 }, + { 32, 2, 1 }, + { 64, 3, 0 }, }; static int hx711_get_gain_to_pulse(int gain) @@ -56,22 +54,22 @@ static int hx711_get_gain_to_pulse(int gain) return 1; } -static int hx711_get_gain_to_scale(int gain) +static int hx711_get_gain_to_scale(const int *gain_scale, int gain) { int i; for (i = 0; i < HX711_GAIN_MAX; i++) if (hx711_gain_to_scale[i].gain == gain) - return hx711_gain_to_scale[i].scale; + return gain_scale[i]; return 0; } -static int hx711_get_scale_to_gain(int scale) +static int hx711_get_scale_to_gain(const int *gain_scale, int scale) { int i; for (i = 0; i < HX711_GAIN_MAX; i++) - if (hx711_gain_to_scale[i].scale == scale) + if (gain_scale[i] == scale) return hx711_gain_to_scale[i].gain; return -EINVAL; } @@ -82,6 +80,7 @@ struct hx711_data { struct gpio_desc *gpiod_dout; int gain_set; /* gain set on device */ int gain_chan_a; /* gain for channel A */ + int gain_scale[HX711_GAIN_MAX]; struct mutex lock; /* * triggered buffer @@ -290,7 +289,8 @@ static int hx711_read_raw(struct iio_dev *indio_dev, *val = 0; mutex_lock(&hx711_data->lock); - *val2 = hx711_get_gain_to_scale(hx711_data->gain_set); + *val2 = hx711_get_gain_to_scale(hx711_data->gain_scale, + hx711_data->gain_set); mutex_unlock(&hx711_data->lock); @@ -321,7 +321,7 @@ static int hx711_write_raw(struct iio_dev *indio_dev, mutex_lock(&hx711_data->lock); - gain = hx711_get_scale_to_gain(val2); + gain = hx711_get_scale_to_gain(hx711_data->gain_scale, val2); if (gain < 0) { mutex_unlock(&hx711_data->lock); return gain; @@ -386,6 +386,7 @@ static ssize_t hx711_scale_available_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct hx711_data *hx711_data = iio_priv(dev_to_iio_dev(dev)); struct iio_dev_attr *iio_attr = to_iio_dev_attr(attr); int channel = iio_attr->address; int i, len = 0; @@ -393,7 +394,7 @@ static ssize_t hx711_scale_available_show(struct device *dev, for (i = 0; i < HX711_GAIN_MAX; i++) if (hx711_gain_to_scale[i].channel == channel) len += sprintf(buf + len, "0.%09d ", - hx711_gain_to_scale[i].scale); + hx711_data->gain_scale[i]); len += sprintf(buf + len, "\n"); @@ -511,7 +512,7 @@ static int hx711_probe(struct platform_device *pdev) ret *= 100; for (i = 0; i < HX711_GAIN_MAX; i++) - hx711_gain_to_scale[i].scale = + hx711_data->gain_scale[i] = ret / hx711_gain_to_scale[i].gain / 1678; hx711_data->gain_set = 128; From 3f439a2a5b37e9d72a8f4eb6974adbe7c34e1a4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Tue, 12 May 2026 14:50:34 +0200 Subject: [PATCH 160/266] iio: Drop unused driver_data in four i2c drivers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For the four drivers the .driver_data member of i2c_device_id is write-only. Drop the explicit assignment. While touching these arrays use a named initializer to assign the .name member, which is easier to parse for a human. Signed-off-by: Uwe Kleine-König (The Capable Hub) Signed-off-by: Jonathan Cameron --- drivers/iio/adc/pac1921.c | 2 +- drivers/iio/light/apds9160.c | 2 +- drivers/iio/light/tsl2563.c | 8 ++++---- drivers/iio/light/tsl2583.c | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/iio/adc/pac1921.c b/drivers/iio/adc/pac1921.c index bce7185953ec..68bdd2f30bad 100644 --- a/drivers/iio/adc/pac1921.c +++ b/drivers/iio/adc/pac1921.c @@ -1310,7 +1310,7 @@ static int pac1921_probe(struct i2c_client *client) } static const struct i2c_device_id pac1921_id[] = { - { .name = "pac1921", 0 }, + { .name = "pac1921" }, { } }; MODULE_DEVICE_TABLE(i2c, pac1921_id); diff --git a/drivers/iio/light/apds9160.c b/drivers/iio/light/apds9160.c index 3da0bdac04cf..8dacb1730429 100644 --- a/drivers/iio/light/apds9160.c +++ b/drivers/iio/light/apds9160.c @@ -1572,7 +1572,7 @@ static const struct of_device_id apds9160_of_match[] = { MODULE_DEVICE_TABLE(of, apds9160_of_match); static const struct i2c_device_id apds9160_id[] = { - { "apds9160", 0 }, + { .name = "apds9160" }, { } }; MODULE_DEVICE_TABLE(i2c, apds9160_id); diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c index f2af1cd7c2d1..7e277bc6a8b1 100644 --- a/drivers/iio/light/tsl2563.c +++ b/drivers/iio/light/tsl2563.c @@ -839,10 +839,10 @@ static DEFINE_SIMPLE_DEV_PM_OPS(tsl2563_pm_ops, tsl2563_suspend, tsl2563_resume); static const struct i2c_device_id tsl2563_id[] = { - { "tsl2560", 0 }, - { "tsl2561", 1 }, - { "tsl2562", 2 }, - { "tsl2563", 3 }, + { .name = "tsl2560" }, + { .name = "tsl2561" }, + { .name = "tsl2562" }, + { .name = "tsl2563" }, { } }; MODULE_DEVICE_TABLE(i2c, tsl2563_id); diff --git a/drivers/iio/light/tsl2583.c b/drivers/iio/light/tsl2583.c index 8801a491de77..a0dd122af2cf 100644 --- a/drivers/iio/light/tsl2583.c +++ b/drivers/iio/light/tsl2583.c @@ -913,9 +913,9 @@ static DEFINE_RUNTIME_DEV_PM_OPS(tsl2583_pm_ops, tsl2583_suspend, tsl2583_resume, NULL); static const struct i2c_device_id tsl2583_idtable[] = { - { "tsl2580", 0 }, - { "tsl2581", 1 }, - { "tsl2583", 2 }, + { .name = "tsl2580" }, + { .name = "tsl2581" }, + { .name = "tsl2583" }, { } }; MODULE_DEVICE_TABLE(i2c, tsl2583_idtable); From d350cb2b23aee0f9a5107e87dc80929f93a04b00 Mon Sep 17 00:00:00 2001 From: Sanjay Chitroda Date: Mon, 11 May 2026 22:46:42 +0530 Subject: [PATCH 161/266] MAINTAINERS: Update Analog Devices IIO drivers entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lars-Peter Clausen is currently busy and is therefore removed from the ANALOG DEVICES INC IIO DRIVERS entry, with input from Jonathan. Add Analog Devices mailing list as contact and Nuno Sá as maintainer for the ANALOG DEVICES INC IIO DRIVERS entry for coverage support. Suggested-by: Jonathan Cameron Acked-by: Nuno Sá Signed-off-by: Sanjay Chitroda Signed-off-by: Jonathan Cameron --- MAINTAINERS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 80b1577cf9d1..0139dda4e2f8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1852,8 +1852,9 @@ W: https://ez.analog.com/linux-software-drivers F: drivers/dma/dma-axi-dmac.c ANALOG DEVICES INC IIO DRIVERS -M: Lars-Peter Clausen +M: Nuno Sá M: Michael Hennerich +L: linux@analog.com S: Supported W: http://wiki.analog.com/ W: https://ez.analog.com/linux-software-drivers From bdc573d5c33b90a21c3799c1b3f08dc8092188af Mon Sep 17 00:00:00 2001 From: Sanjay Chitroda Date: Mon, 11 May 2026 22:46:43 +0530 Subject: [PATCH 162/266] MAINTAINERS: Update maintainer for IIO drivers The listed Analog Devices domain email for Cosmin Tanislav is no longer valid, and he is no longer maintaining these IIO drivers. Add Marcelo Schmitt as the maintainer from Analog Devices to continue support and maintenance of the affected drivers. Signed-off-by: Sanjay Chitroda Reviewed-by: Marcelo Schmitt Signed-off-by: Jonathan Cameron --- MAINTAINERS | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 0139dda4e2f8..d28e54838e7a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -633,7 +633,7 @@ F: drivers/iio/accel/adxl355_i2c.c F: drivers/iio/accel/adxl355_spi.c ADXL367 THREE-AXIS DIGITAL ACCELEROMETER DRIVER -M: Cosmin Tanislav +M: Marcelo Schmitt L: linux-iio@vger.kernel.org S: Supported W: https://ez.analog.com/linux-software-drivers @@ -1452,7 +1452,7 @@ F: Documentation/devicetree/bindings/iio/adc/adi,ad4080.yaml F: drivers/iio/adc/ad4080.c ANALOG DEVICES INC AD4130 DRIVER -M: Cosmin Tanislav +M: Marcelo Schmitt L: linux-iio@vger.kernel.org S: Supported W: https://ez.analog.com/linux-software-drivers @@ -1548,7 +1548,7 @@ F: Documentation/devicetree/bindings/iio/dac/adi,ad7293.yaml F: drivers/iio/dac/ad7293.c ANALOG DEVICES INC AD74115 DRIVER -M: Cosmin Tanislav +M: Marcelo Schmitt L: linux-iio@vger.kernel.org S: Supported W: https://ez.analog.com/linux-software-drivers @@ -1556,7 +1556,7 @@ F: Documentation/devicetree/bindings/iio/addac/adi,ad74115.yaml F: drivers/iio/addac/ad74115.c ANALOG DEVICES INC AD74413R DRIVER -M: Cosmin Tanislav +M: Marcelo Schmitt L: linux-iio@vger.kernel.org S: Supported W: https://ez.analog.com/linux-software-drivers From cfa30b4330677e351d6d26a0a12bfe505bc9f31d Mon Sep 17 00:00:00 2001 From: Joshua Crofts Date: Mon, 11 May 2026 13:26:10 +0200 Subject: [PATCH 163/266] iio: magnetometer: ak8975: modernize polling loops with iopoll() macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver currently uses while loops and msleep() for polling during conversion waits. Replace the custom polling loops with readx_poll_timeout() and read_poll_timeout() macros from . This reduces boilerplate, standardizes timeout handling and improves overall code readability, keeping the original timing and error behaviour. Add for USEC_PER_MSEC macro instead of using magic numbers. Assisted-by: Gemini:3.1-Pro Reviewed-by: Andy Shevchenko Reviewed-by: Nuno Sá Signed-off-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/ak8975.c | 43 +++++++++++++------------------ 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index 6be72e1cc0a8..b990c123e280 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -649,16 +650,14 @@ static int wait_conversion_complete_gpio(struct ak8975_data *data, { struct i2c_client *client = data->client; int ret; + int val; /* Wait for the conversion to complete. */ - while (timeout_ms) { - msleep(poll_ms); - if (gpiod_get_value(data->eoc_gpiod)) - break; - timeout_ms -= poll_ms; - } - if (!timeout_ms) - return -ETIMEDOUT; + ret = readx_poll_timeout(gpiod_get_value, data->eoc_gpiod, val, val != 0, + poll_ms * USEC_PER_MSEC, + timeout_ms * USEC_PER_MSEC); + if (ret) + return ret; ret = i2c_smbus_read_byte_data(client, data->def->ctrl_regs[ST1]); if (ret < 0) @@ -672,27 +671,21 @@ static int wait_conversion_complete_polled(struct ak8975_data *data, unsigned int timeout_ms) { struct i2c_client *client = data->client; - u8 read_status; int ret; + int val; /* Wait for the conversion to complete. */ - while (timeout_ms) { - msleep(poll_ms); - ret = i2c_smbus_read_byte_data(client, - data->def->ctrl_regs[ST1]); - if (ret < 0) { - dev_err(&client->dev, "Error in reading ST1\n"); - return ret; - } - read_status = ret; - if (read_status) - break; - timeout_ms -= poll_ms; - } - if (!timeout_ms) - return -ETIMEDOUT; + ret = read_poll_timeout(i2c_smbus_read_byte_data, val, val != 0, + poll_ms * USEC_PER_MSEC, + timeout_ms * USEC_PER_MSEC, + true, + client, data->def->ctrl_regs[ST1]); + if (ret) + return ret; + if (val < 0) + dev_err(&client->dev, "Error in reading ST1\n"); - return read_status; + return val; } /* Returns 0 if the end of conversion interrupt occurred or -ETIMEDOUT otherwise */ From 46dd701a39f0b6b1796e75a9eb87822b8b3a98f1 Mon Sep 17 00:00:00 2001 From: Joshua Crofts Date: Mon, 11 May 2026 13:26:11 +0200 Subject: [PATCH 164/266] iio: magnetometer: ak8975: check if gpiod read was successful MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a check that ensures that valid data has been read from GPIOD. If not, log an error and return the negative read value. Suggested-by: Jonathan Cameron Reviewed-by: Nuno Sá Signed-off-by: Joshua Crofts Reviewed-by: Maxwell Doose Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/ak8975.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index b990c123e280..63b6e8465f5f 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -658,6 +658,10 @@ static int wait_conversion_complete_gpio(struct ak8975_data *data, timeout_ms * USEC_PER_MSEC); if (ret) return ret; + if (val < 0) { + dev_err(&client->dev, "Error in reading GPIOD\n"); + return val; + } ret = i2c_smbus_read_byte_data(client, data->def->ctrl_regs[ST1]); if (ret < 0) From 79ab48ae4f9e06512263377c81fad1ab1adace4c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 11 May 2026 13:26:13 +0200 Subject: [PATCH 165/266] iio: magnetometer: ak8975: consistently use 'data' parameter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some of the functions use 'client', some use 'data', and some use both. Refactor the driver to consistently use 'data' in all cases. Signed-off-by: Andy Shevchenko Reviewed-by: Nuno Sá Signed-off-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/ak8975.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index 63b6e8465f5f..dbab4d0bba34 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -474,9 +474,10 @@ static void ak8975_power_off(const struct ak8975_data *data) * Return 0 if the i2c device is the one we expect. * return a negative error number otherwise */ -static int ak8975_who_i_am(struct i2c_client *client, +static int ak8975_who_i_am(const struct ak8975_data *data, enum asahi_compass_chipset type) { + struct i2c_client *client = data->client; u8 wia_val[2]; int ret; @@ -598,10 +599,9 @@ static int ak8975_setup_irq(struct ak8975_data *data) * Perform some start-of-day setup, including reading the asa calibration * values and caching them. */ -static int ak8975_setup(struct i2c_client *client) +static int ak8975_setup(struct ak8975_data *data) { - struct iio_dev *indio_dev = i2c_get_clientdata(client); - struct ak8975_data *data = iio_priv(indio_dev); + struct i2c_client *client = data->client; int ret; /* Write the fused rom access mode. */ @@ -706,12 +706,13 @@ static int wait_conversion_complete_interrupt(struct ak8975_data *data, return ret > 0 ? 0 : -ETIMEDOUT; } -static int ak8975_start_read_axis(struct ak8975_data *data, - const struct i2c_client *client) +static int ak8975_start_read_axis(struct ak8975_data *data) { - /* Set up the device for taking a sample. */ - int ret = ak8975_set_mode(data, MODE_ONCE); + struct i2c_client *client = data->client; + int ret; + /* Set up the device for taking a sample. */ + ret = ak8975_set_mode(data, MODE_ONCE); if (ret < 0) { dev_err(&client->dev, "Error in setting operating mode\n"); return ret; @@ -744,7 +745,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val) mutex_lock(&data->lock); - ret = ak8975_start_read_axis(data, client); + ret = ak8975_start_read_axis(data); if (ret) goto exit; @@ -856,7 +857,7 @@ static void ak8975_fill_buffer(struct iio_dev *indio_dev) mutex_lock(&data->lock); - ret = ak8975_start_read_axis(data, client); + ret = ak8975_start_read_axis(data); if (ret) goto unlock; @@ -968,7 +969,7 @@ static int ak8975_probe(struct i2c_client *client) if (ret) return ret; - ret = ak8975_who_i_am(client, data->def->type); + ret = ak8975_who_i_am(data, data->def->type); if (ret) { dev_err(&client->dev, "Unexpected device\n"); goto power_off; @@ -976,7 +977,7 @@ static int ak8975_probe(struct i2c_client *client) dev_dbg(&client->dev, "Asahi compass chip %s\n", name); /* Perform some basic start-of-day setup of the device. */ - ret = ak8975_setup(client); + ret = ak8975_setup(data); if (ret) { dev_err(&client->dev, "%s initialization fails\n", name); goto power_off; From 8bf3e7a9defcfa889976258919d99fa2e8465189 Mon Sep 17 00:00:00 2001 From: Hungyu Lin Date: Mon, 11 May 2026 14:06:41 +0000 Subject: [PATCH 166/266] staging: iio: addac: adt7316: document SPI interface switching sequence The device powers up in I2C mode. Switching to SPI mode requires sending a sequence of SPI writes as described in the datasheet. During this sequence, the device may still be in I2C mode, so SPI transactions may not be recognized and can fail. Such errors are therefore ignored. Add a comment to clarify this behavior. Datasheet: https://www.analog.com/en/products/adt7316.html Reviewed-by: Maxwell Doose Reviewed-by: Andy Shevchenko Signed-off-by: Hungyu Lin Signed-off-by: Jonathan Cameron --- drivers/staging/iio/addac/adt7316-spi.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/staging/iio/addac/adt7316-spi.c b/drivers/staging/iio/addac/adt7316-spi.c index f91325d11394..1debcc36c1af 100644 --- a/drivers/staging/iio/addac/adt7316-spi.c +++ b/drivers/staging/iio/addac/adt7316-spi.c @@ -106,7 +106,18 @@ static int adt7316_spi_probe(struct spi_device *spi_dev) return -EINVAL; } - /* switch from default I2C protocol to SPI protocol */ + /* + * The device powers up in I2C mode. Switching to SPI mode + * requires sending a sequence of SPI writes as described in + * the datasheet "ADT7316/ADT7317/ADT7318", Rev. B, + * in the "Serial Interface Selection" section. + * + * During this sequence, the device may still be in I2C mode, + * so SPI transactions may not be recognized and can fail. + * Such errors are therefore ignored. + * + * TL;DR: Do not change this! + */ adt7316_spi_write(spi_dev, 0, 0); adt7316_spi_write(spi_dev, 0, 0); adt7316_spi_write(spi_dev, 0, 0); From eaead586b3d95890832449f2887283b067426ecc Mon Sep 17 00:00:00 2001 From: Joshua Crofts Date: Wed, 13 May 2026 16:35:52 +0200 Subject: [PATCH 167/266] iio: magnetometer: ak8975: ensure device is awake for buffered capture Currently, the ak8975_start_read_axis() can be called while the device is autosuspended, causing two issues: 1. I2C transfers in the aforementioned function will fail or timeout because ak8975_runtime_suspend() disables the device regulators. 2. Since ak8975_fill_buffer() does not hold runtime references, ak8975_runtime_suspend() can run concurrently, and since PM callbacks do not use a locking mechanism, it may cause a race accessing the control register via the I2C bus. Fix this issue by adding struct iio_buffer_setup_ops that contains preenable and postdisable functions to ensure correct that device is powered on when running a buffered capture. Fixes: bc11ca4a0b84 ("iio:magnetometer:ak8975: triggered buffer support") Reported-by: Sashiko Closes: https://sashiko.dev/#/patchset/20260511-magnetometer-fixes-post-pickup-v7-0-9d910faa28b6%40gmail.com Cc: Signed-off-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/ak8975.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index dbab4d0bba34..0fb2fd03d11c 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -899,6 +899,28 @@ static irqreturn_t ak8975_handle_trigger(int irq, void *p) return IRQ_HANDLED; } +static int ak8975_buffer_preenable(struct iio_dev *indio_dev) +{ + struct ak8975_data *data = iio_priv(indio_dev); + struct device *dev = &data->client->dev; + + return pm_runtime_resume_and_get(dev); +} + +static int ak8975_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct ak8975_data *data = iio_priv(indio_dev); + struct device *dev = &data->client->dev; + + pm_runtime_put_autosuspend(dev); + + return 0; +} + +static const struct iio_buffer_setup_ops ak8975_buffer_setup_ops = { + .preenable = ak8975_buffer_preenable, + .postdisable = ak8975_buffer_postdisable, +}; static int ak8975_probe(struct i2c_client *client) { const struct i2c_device_id *id = i2c_client_get_device_id(client); @@ -992,7 +1014,7 @@ static int ak8975_probe(struct i2c_client *client) indio_dev->name = name; ret = iio_triggered_buffer_setup(indio_dev, NULL, ak8975_handle_trigger, - NULL); + &ak8975_buffer_setup_ops); if (ret) { dev_err(&client->dev, "triggered buffer setup failed\n"); goto power_off; From a9a00d727b7bbc5e913a919530a9dd468935bf95 Mon Sep 17 00:00:00 2001 From: Joshua Crofts Date: Fri, 15 May 2026 12:28:23 +0200 Subject: [PATCH 168/266] iio: magnetometer: ak8975: fix potential kernel stack memory leak Currently in the AK8975 driver there are four instances where potential uninitialized kernel stack memory leaks can occur. If i2c_smbus_read_i2c_block_data_or_emulated() returns a value less than the size of the buffer, uninitialized bytes are retained in the buffer and later the buffer is passed on to IIO buffers, potentially leaking memory to userspace. Fix this by adding checks whether the return value of the function is equal to the size of the buffer and subsequently if the value is lesser than zero to distinguish from a returned error code. Fixes: bc11ca4a0b84 ("iio:magnetometer:ak8975: triggered buffer support") Reported-by: Sashiko Closes: https://sashiko.dev/#/patchset/20260513-ak8975-fix-v1-1-104ea605dd54%40gmail.com Signed-off-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/ak8975.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index 0fb2fd03d11c..bb74abb648f1 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -499,6 +499,10 @@ static int ak8975_who_i_am(const struct ak8975_data *data, dev_err(&client->dev, "Error reading WIA\n"); return ret; } + if (ret != sizeof(wia_val)) { + dev_err(&client->dev, "Error reading WIA\n"); + return -EIO; + } if (wia_val[0] != AK8975_DEVICE_ID) return -ENODEV; @@ -620,6 +624,10 @@ static int ak8975_setup(struct ak8975_data *data) dev_err(&client->dev, "Not able to read asa data\n"); return ret; } + if (ret != sizeof(data->asa)) { + dev_err(&client->dev, "Error reading asa data\n"); + return -EIO; + } /* After reading fuse ROM data set power-down mode */ ret = ak8975_set_mode(data, POWER_DOWN); @@ -755,6 +763,10 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val) (u8 *)&rval); if (ret < 0) goto exit; + if (ret != sizeof(rval)) { + ret = -EIO; + goto exit; + } /* Read out ST2 for release lock on measurement data. */ ret = i2c_smbus_read_byte_data(client, data->def->ctrl_regs[ST2]); @@ -871,6 +883,8 @@ static void ak8975_fill_buffer(struct iio_dev *indio_dev) (u8 *)fval); if (ret < 0) goto unlock; + if (ret != sizeof(fval)) + goto unlock; mutex_unlock(&data->lock); From 29bf2693c9e31616244cad88fac06a3a3046b069 Mon Sep 17 00:00:00 2001 From: Maxwell Doose Date: Thu, 14 May 2026 20:16:39 -0500 Subject: [PATCH 169/266] dt-bindings: iio: chemical: sensirion,scd30: Update maintainers field Tomasz Duszynski is no longer the maintainer of the SCD30 driver. Replace his entry with mine. Link: https://lore.kernel.org/linux-iio/20260507172404.80435-1-m32285159@gmail.com/ Signed-off-by: Maxwell Doose Acked-by: Krzysztof Kozlowski Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/chemical/sensirion,scd30.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/iio/chemical/sensirion,scd30.yaml b/Documentation/devicetree/bindings/iio/chemical/sensirion,scd30.yaml index 40d87346ff4c..a5b0debe85b1 100644 --- a/Documentation/devicetree/bindings/iio/chemical/sensirion,scd30.yaml +++ b/Documentation/devicetree/bindings/iio/chemical/sensirion,scd30.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Sensirion SCD30 carbon dioxide sensor maintainers: - - Tomasz Duszynski + - Maxwell Doose description: | Air quality sensor capable of measuring co2 concentration, temperature From 469ad4d50fb34dc9abc9a47f879f7c07be614ae1 Mon Sep 17 00:00:00 2001 From: Raffael Raiel Trindade Date: Thu, 14 May 2026 17:11:49 -0300 Subject: [PATCH 170/266] iio: light: vcnl4000: use lock guard() Use guard() and scoped_guard() for handling mutex lock instead of manually locking and unlocking. Remove gotos in error handling logic. This prevents forgotten locks on early exits. Signed-off-by: Raffael Raiel Trindade Co-developed-by: Kim Carvalho Signed-off-by: Kim Carvalho Signed-off-by: Jonathan Cameron --- drivers/iio/light/vcnl4000.c | 152 +++++++++++------------------------ 1 file changed, 45 insertions(+), 107 deletions(-) diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c index c08927e34b4e..88fc7424ae35 100644 --- a/drivers/iio/light/vcnl4000.c +++ b/drivers/iio/light/vcnl4000.c @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -268,46 +269,36 @@ static ssize_t vcnl4000_write_als_enable(struct vcnl4000_data *data, bool en) { int ret; - mutex_lock(&data->vcnl4000_lock); + guard(mutex)(&data->vcnl4000_lock); ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF); if (ret < 0) - goto out; + return ret; if (en) ret &= ~VCNL4040_ALS_CONF_ALS_SHUTDOWN; else ret |= VCNL4040_ALS_CONF_ALS_SHUTDOWN; - ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, ret); - -out: - mutex_unlock(&data->vcnl4000_lock); - - return ret; + return i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, ret); } static ssize_t vcnl4000_write_ps_enable(struct vcnl4000_data *data, bool en) { int ret; - mutex_lock(&data->vcnl4000_lock); + guard(mutex)(&data->vcnl4000_lock); ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1); if (ret < 0) - goto out; + return ret; if (en) ret &= ~VCNL4040_PS_CONF1_PS_SHUTDOWN; else ret |= VCNL4040_PS_CONF1_PS_SHUTDOWN; - ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, ret); - -out: - mutex_unlock(&data->vcnl4000_lock); - - return ret; + return i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, ret); } static int vcnl4200_set_power_state(struct vcnl4000_data *data, bool on) @@ -442,18 +433,18 @@ static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask, int tries = 20; int ret; - mutex_lock(&data->vcnl4000_lock); + guard(mutex)(&data->vcnl4000_lock); ret = i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND, req_mask); if (ret < 0) - goto fail; + return ret; /* wait for data to become ready */ while (tries--) { ret = i2c_smbus_read_byte_data(data->client, VCNL4000_COMMAND); if (ret < 0) - goto fail; + return ret; if (ret & rdy_mask) break; msleep(20); /* measurement takes up to 100 ms */ @@ -462,21 +453,10 @@ static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask, if (tries < 0) { dev_err(&data->client->dev, "vcnl4000_measure() failed, data not ready\n"); - ret = -EIO; - goto fail; + return -EIO; } - ret = vcnl4000_read_data(data, data_reg, val); - if (ret < 0) - goto fail; - - mutex_unlock(&data->vcnl4000_lock); - - return 0; - -fail: - mutex_unlock(&data->vcnl4000_lock); - return ret; + return vcnl4000_read_data(data, data_reg, val); } static int vcnl4200_measure(struct vcnl4000_data *data, @@ -486,16 +466,14 @@ static int vcnl4200_measure(struct vcnl4000_data *data, s64 delta; ktime_t next_measurement; - mutex_lock(&chan->lock); - - next_measurement = ktime_add(chan->last_measurement, - chan->sampling_rate); - delta = ktime_us_delta(next_measurement, ktime_get()); - if (delta > 0) - usleep_range(delta, delta + 500); - chan->last_measurement = ktime_get(); - - mutex_unlock(&chan->lock); + scoped_guard(mutex, &chan->lock) { + next_measurement = ktime_add(chan->last_measurement, + chan->sampling_rate); + delta = ktime_us_delta(next_measurement, ktime_get()); + if (delta > 0) + usleep_range(delta, delta + 500); + chan->last_measurement = ktime_get(); + } ret = i2c_smbus_read_word_data(data->client, chan->reg); if (ret < 0) @@ -606,21 +584,15 @@ static ssize_t vcnl4040_write_als_it(struct vcnl4000_data *data, int val) (*data->chip_spec->als_it_times)[0][1]), val); - mutex_lock(&data->vcnl4000_lock); + guard(mutex)(&data->vcnl4000_lock); ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF); if (ret < 0) - goto out_unlock; + return ret; regval = FIELD_PREP(VCNL4040_ALS_CONF_IT, i); regval |= (ret & ~VCNL4040_ALS_CONF_IT); - ret = i2c_smbus_write_word_data(data->client, - VCNL4200_AL_CONF, - regval); - -out_unlock: - mutex_unlock(&data->vcnl4000_lock); - return ret; + return i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, regval); } static int vcnl4040_read_ps_it(struct vcnl4000_data *data, int *val, int *val2) @@ -660,20 +632,15 @@ static ssize_t vcnl4040_write_ps_it(struct vcnl4000_data *data, int val) data->vcnl4200_ps.sampling_rate = ktime_set(0, val * 60 * NSEC_PER_USEC); - mutex_lock(&data->vcnl4000_lock); + guard(mutex)(&data->vcnl4000_lock); ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1); if (ret < 0) - goto out; + return ret; regval = (ret & ~VCNL4040_PS_CONF2_PS_IT) | FIELD_PREP(VCNL4040_PS_CONF2_PS_IT, index); - ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, - regval); - -out: - mutex_unlock(&data->vcnl4000_lock); - return ret; + return i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, regval); } static ssize_t vcnl4040_read_als_period(struct vcnl4000_data *data, int *val, int *val2) @@ -721,20 +688,15 @@ static ssize_t vcnl4040_write_als_period(struct vcnl4000_data *data, int val, in break; } - mutex_lock(&data->vcnl4000_lock); + guard(mutex)(&data->vcnl4000_lock); ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF); if (ret < 0) - goto out_unlock; + return ret; regval = FIELD_PREP(VCNL4040_ALS_CONF_PERS, i); regval |= (ret & ~VCNL4040_ALS_CONF_PERS); - ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, - regval); - -out_unlock: - mutex_unlock(&data->vcnl4000_lock); - return ret; + return i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, regval); } static ssize_t vcnl4040_read_ps_period(struct vcnl4000_data *data, int *val, int *val2) @@ -783,20 +745,15 @@ static ssize_t vcnl4040_write_ps_period(struct vcnl4000_data *data, int val, int } } - mutex_lock(&data->vcnl4000_lock); + guard(mutex)(&data->vcnl4000_lock); ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1); if (ret < 0) - goto out_unlock; + return ret; regval = FIELD_PREP(VCNL4040_CONF1_PS_PERS, i); regval |= (ret & ~VCNL4040_CONF1_PS_PERS); - ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, - regval); - -out_unlock: - mutex_unlock(&data->vcnl4000_lock); - return ret; + return i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, regval); } static ssize_t vcnl4040_read_ps_oversampling_ratio(struct vcnl4000_data *data, int *val) @@ -830,20 +787,15 @@ static ssize_t vcnl4040_write_ps_oversampling_ratio(struct vcnl4000_data *data, if (i >= ARRAY_SIZE(vcnl4040_ps_oversampling_ratio)) return -EINVAL; - mutex_lock(&data->vcnl4000_lock); + guard(mutex)(&data->vcnl4000_lock); ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF3); if (ret < 0) - goto out_unlock; + return ret; regval = FIELD_PREP(VCNL4040_PS_CONF3_MPS, i); regval |= (ret & ~VCNL4040_PS_CONF3_MPS); - ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF3, - regval); - -out_unlock: - mutex_unlock(&data->vcnl4000_lock); - return ret; + return i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF3, regval); } static ssize_t vcnl4040_read_ps_calibbias(struct vcnl4000_data *data, int *val, int *val2) @@ -878,20 +830,15 @@ static ssize_t vcnl4040_write_ps_calibbias(struct vcnl4000_data *data, int val) if (i >= ARRAY_SIZE(vcnl4040_ps_calibbias_ua)) return -EINVAL; - mutex_lock(&data->vcnl4000_lock); + guard(mutex)(&data->vcnl4000_lock); ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF3); if (ret < 0) - goto out_unlock; + return ret; regval = (ret & ~VCNL4040_PS_MS_LED_I); regval |= FIELD_PREP(VCNL4040_PS_MS_LED_I, i); - ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF3, - regval); - -out_unlock: - mutex_unlock(&data->vcnl4000_lock); - return ret; + return i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF3, regval); } static int vcnl4000_read_raw(struct iio_dev *indio_dev, @@ -1476,17 +1423,17 @@ static int vcnl4040_write_event_config(struct iio_dev *indio_dev, enum iio_event_direction dir, bool state) { - int ret = -EINVAL; + int ret; u16 val, mask; struct vcnl4000_data *data = iio_priv(indio_dev); - mutex_lock(&data->vcnl4000_lock); + guard(mutex)(&data->vcnl4000_lock); switch (chan->type) { case IIO_LIGHT: ret = i2c_smbus_read_word_data(data->client, VCNL4200_AL_CONF); if (ret < 0) - goto out; + return ret; mask = VCNL4040_ALS_CONF_INT_EN; if (state) @@ -1495,13 +1442,11 @@ static int vcnl4040_write_event_config(struct iio_dev *indio_dev, val = (ret & ~mask); data->als_int = FIELD_GET(VCNL4040_ALS_CONF_INT_EN, val); - ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, - val); - break; + return i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, val); case IIO_PROXIMITY: ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1); if (ret < 0) - goto out; + return ret; if (dir == IIO_EV_DIR_RISING) mask = VCNL4040_PS_IF_AWAY; @@ -1511,17 +1456,10 @@ static int vcnl4040_write_event_config(struct iio_dev *indio_dev, val = state ? (ret | mask) : (ret & ~mask); data->ps_int = FIELD_GET(VCNL4040_PS_CONF2_PS_INT, val); - ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, - val); - break; + return i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, val); default: - break; + return -EINVAL; } - -out: - mutex_unlock(&data->vcnl4000_lock); - - return ret; } static irqreturn_t vcnl4040_irq_thread(int irq, void *p) From b049fb4081527c8d52834c46cef38c0bb65468ed Mon Sep 17 00:00:00 2001 From: Stepan Ionichev Date: Wed, 13 May 2026 15:13:32 +0500 Subject: [PATCH 171/266] iio: adc: ad7192: fix GPOCON register access annotation The comment next to AD7192_REG_GPOCON marks the register as RO, but the AD7192 datasheet (Rev. A, page 24, GPOCON REGISTER) says: "The GPOCON register is an 8-bit register from which data can be read or to which data can be written." The driver itself uses ad_sd_write_reg() against this register in ad7192_show_scale() / write paths to control the bridge power-down switch and digital outputs, which matches the RW datasheet description. Update the comment to RW so it does not mislead future readers. Signed-off-by: Stepan Ionichev Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7192.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c index ba27614c89b4..caf4473ad643 100644 --- a/drivers/iio/adc/ad7192.c +++ b/drivers/iio/adc/ad7192.c @@ -39,7 +39,7 @@ #define AD7192_REG_CONF 2 /* Configuration Register (RW, 24-bit) */ #define AD7192_REG_DATA 3 /* Data Register (RO, 24/32-bit) */ #define AD7192_REG_ID 4 /* ID Register (RO, 8-bit) */ -#define AD7192_REG_GPOCON 5 /* GPOCON Register (RO, 8-bit) */ +#define AD7192_REG_GPOCON 5 /* GPOCON Register (RW, 8-bit) */ #define AD7192_REG_OFFSET 6 /* Offset Register (RW, 16-bit */ /* (AD7792)/24-bit (AD7192)) */ #define AD7192_REG_FULLSALE 7 /* Full-Scale Register */ From 2f856ad3f729e09a1a046272c68437d058c50621 Mon Sep 17 00:00:00 2001 From: Stepan Ionichev Date: Thu, 14 May 2026 13:51:57 +0500 Subject: [PATCH 172/266] Documentation: iio: fix typo in triggered-buffers example In the "IIO triggered buffer setup" example, iio_triggered_buffer_setup() is called with "sensor_iio_polfunc" (single 'l') while the function is defined and later referenced as "sensor_iio_pollfunc" (double 'l'). Fix the misspelling so the example is consistent. Signed-off-by: Stepan Ionichev Reviewed-by: Andy Shevchenko Reviewed-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- Documentation/driver-api/iio/triggered-buffers.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/driver-api/iio/triggered-buffers.rst b/Documentation/driver-api/iio/triggered-buffers.rst index 417555dbbdf4..23b82357eba6 100644 --- a/Documentation/driver-api/iio/triggered-buffers.rst +++ b/Documentation/driver-api/iio/triggered-buffers.rst @@ -43,7 +43,7 @@ A typical triggered buffer setup looks like this:: } /* setup triggered buffer, usually in probe function */ - iio_triggered_buffer_setup(indio_dev, sensor_iio_polfunc, + iio_triggered_buffer_setup(indio_dev, sensor_iio_pollfunc, sensor_trigger_handler, sensor_buffer_setup_ops); From f608e9c032dac51d1e6410fddcbcddeddb261cdf Mon Sep 17 00:00:00 2001 From: Stepan Ionichev Date: Wed, 13 May 2026 15:07:52 +0500 Subject: [PATCH 173/266] Documentation: iio: make ADXL Y-axis calibbias description consistent The Y-axis calibbias rows in adxl345.rst, adxl313.rst and adxl380.rst use a different wording than the matching X-axis and Z-axis rows in the same tables: the X/Z rows say "Calibration offset for the X/Z-axis accelerometer channel." while the Y row says "Y-axis (or y-axis) acceleration offset correction". Make the Y-axis row match the other two so each driver's sysfs table has consistent capitalisation and wording. Signed-off-by: Stepan Ionichev Signed-off-by: Jonathan Cameron --- Documentation/iio/adxl313.rst | 2 +- Documentation/iio/adxl345.rst | 2 +- Documentation/iio/adxl380.rst | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/iio/adxl313.rst b/Documentation/iio/adxl313.rst index cc0829be0447..3641193bf647 100644 --- a/Documentation/iio/adxl313.rst +++ b/Documentation/iio/adxl313.rst @@ -38,7 +38,7 @@ specific device folder path ``/sys/bus/iio/devices/iio:deviceX``. +---------------------------------------------------+----------------------------------------------------------+ | in_accel_x_raw | Raw X-axis accelerometer channel value. | +---------------------------------------------------+----------------------------------------------------------+ -| in_accel_y_calibbias | y-axis acceleration offset correction | +| in_accel_y_calibbias | Calibration offset for the Y-axis accelerometer channel. | +---------------------------------------------------+----------------------------------------------------------+ | in_accel_y_raw | Raw Y-axis accelerometer channel value. | +---------------------------------------------------+----------------------------------------------------------+ diff --git a/Documentation/iio/adxl345.rst b/Documentation/iio/adxl345.rst index 978f746a8198..0aa33a852412 100644 --- a/Documentation/iio/adxl345.rst +++ b/Documentation/iio/adxl345.rst @@ -47,7 +47,7 @@ specific device folder path ``/sys/bus/iio/devices/iio:deviceX``. +-------------------------------------------+----------------------------------------------------------+ | in_accel_x_raw | Raw X-axis accelerometer channel value. | +-------------------------------------------+----------------------------------------------------------+ -| in_accel_y_calibbias | Y-axis acceleration offset correction | +| in_accel_y_calibbias | Calibration offset for the Y-axis accelerometer channel. | +-------------------------------------------+----------------------------------------------------------+ | in_accel_y_raw | Raw Y-axis accelerometer channel value. | +-------------------------------------------+----------------------------------------------------------+ diff --git a/Documentation/iio/adxl380.rst b/Documentation/iio/adxl380.rst index 61cafa2f98bf..654d4c0e84a1 100644 --- a/Documentation/iio/adxl380.rst +++ b/Documentation/iio/adxl380.rst @@ -51,7 +51,7 @@ specific device folder path ``/sys/bus/iio/devices/iio:deviceX``. +---------------------------------------------------+----------------------------------------------------------+ | in_accel_x_raw | Raw X-axis accelerometer channel value. | +---------------------------------------------------+----------------------------------------------------------+ -| in_accel_y_calibbias | y-axis acceleration offset correction | +| in_accel_y_calibbias | Calibration offset for the Y-axis accelerometer channel. | +---------------------------------------------------+----------------------------------------------------------+ | in_accel_y_raw | Raw Y-axis accelerometer channel value. | +---------------------------------------------------+----------------------------------------------------------+ From ecedfa46a2e5db329925bac8cab9ac8cbad55755 Mon Sep 17 00:00:00 2001 From: Vladislav Kulikov Date: Mon, 11 May 2026 19:11:34 +0000 Subject: [PATCH 174/266] dt-bindings: iio: magnetometer: add MEMSIC MMC5983MA Add a Devicetree binding for the MEMSIC MMC5983MA 3-axis magnetometer. MMC5983MA is not register-compatible with the existing MEMSIC magnetometer drivers. It has a different register map, 18-bit output data format, and I2C/SPI transport support. Reviewed-by: David Lechner Acked-by: Conor Dooley Signed-off-by: Vladislav Kulikov Signed-off-by: Jonathan Cameron --- .../iio/magnetometer/memsic,mmc5983.yaml | 63 +++++++++++++++++++ MAINTAINERS | 6 ++ 2 files changed, 69 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/magnetometer/memsic,mmc5983.yaml diff --git a/Documentation/devicetree/bindings/iio/magnetometer/memsic,mmc5983.yaml b/Documentation/devicetree/bindings/iio/magnetometer/memsic,mmc5983.yaml new file mode 100644 index 000000000000..4a4df6bb70fe --- /dev/null +++ b/Documentation/devicetree/bindings/iio/magnetometer/memsic,mmc5983.yaml @@ -0,0 +1,63 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/magnetometer/memsic,mmc5983.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MEMSIC MMC5983MA 3-axis magnetic sensor + +maintainers: + - Vladislav Kulikov + +properties: + compatible: + const: memsic,mmc5983 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + vdd-supply: + description: Regulator that provides power to the sensor + + vddio-supply: + description: Regulator that provides power to the digital interface and INT pin + +required: + - compatible + - reg + - vdd-supply + +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +unevaluatedProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + magnetometer@30 { + compatible = "memsic,mmc5983"; + reg = <0x30>; + vdd-supply = <&vdd_3v3_reg>; + vddio-supply = <&vdd_3v3_reg>; + }; + }; + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + + magnetometer@0 { + compatible = "memsic,mmc5983"; + reg = <0>; + spi-max-frequency = <10000000>; + vdd-supply = <&vdd_3v3_reg>; + vddio-supply = <&vdd_3v3_reg>; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index d28e54838e7a..a80dfbbee2ef 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17179,6 +17179,12 @@ F: drivers/mtd/ F: include/linux/mtd/ F: include/uapi/mtd/ +MEMSIC MMC5983 MAGNETOMETER DRIVER +M: Vladislav Kulikov +L: linux-iio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/iio/magnetometer/memsic,mmc5983.yaml + MEN A21 WATCHDOG DRIVER M: Johannes Thumshirn L: linux-watchdog@vger.kernel.org From 243a738ccdabb8f997a5c6678e22f60761dbadf1 Mon Sep 17 00:00:00 2001 From: Vladislav Kulikov Date: Mon, 11 May 2026 19:11:35 +0000 Subject: [PATCH 175/266] iio: magnetometer: add driver for MEMSIC MMC5983MA Add support for the MEMSIC MMC5983MA 3-axis magnetometer. The driver provides raw magnetic field readings via IIO sysfs with SET/RESET offset cancellation for each measurement. Reviewed-by: David Lechner Signed-off-by: Vladislav Kulikov Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- MAINTAINERS | 1 + drivers/iio/magnetometer/Kconfig | 11 + drivers/iio/magnetometer/Makefile | 1 + drivers/iio/magnetometer/mmc5983.c | 348 +++++++++++++++++++++++++++++ 4 files changed, 361 insertions(+) create mode 100644 drivers/iio/magnetometer/mmc5983.c diff --git a/MAINTAINERS b/MAINTAINERS index a80dfbbee2ef..640192835bd3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17184,6 +17184,7 @@ M: Vladislav Kulikov L: linux-iio@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/iio/magnetometer/memsic,mmc5983.yaml +F: drivers/iio/magnetometer/mmc5983.c MEN A21 WATCHDOG DRIVER M: Johannes Thumshirn diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig index fb313e591e85..ea2697fb5ab6 100644 --- a/drivers/iio/magnetometer/Kconfig +++ b/drivers/iio/magnetometer/Kconfig @@ -151,6 +151,17 @@ config MMC5633 To compile this driver as a module, choose M here: the module will be called mmc5633 +config MMC5983 + tristate "MEMSIC MMC5983 3-axis magnetic sensor" + depends on I2C + select REGMAP_I2C + help + Say yes here to build support for the MEMSIC MMC5983 3-axis + magnetic sensor. + + To compile this driver as a module, choose M here: the module + will be called mmc5983 + config IIO_ST_MAGN_3AXIS tristate "STMicroelectronics magnetometers 3-Axis Driver" depends on (I2C || SPI_MASTER) && SYSFS diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile index 5bd227f8c120..7fd9b3fd914e 100644 --- a/drivers/iio/magnetometer/Makefile +++ b/drivers/iio/magnetometer/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_MAG3110) += mag3110.o obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o obj-$(CONFIG_MMC35240) += mmc35240.o obj-$(CONFIG_MMC5633) += mmc5633.o +obj-$(CONFIG_MMC5983) += mmc5983.o obj-$(CONFIG_IIO_ST_MAGN_3AXIS) += st_magn.o st_magn-y := st_magn_core.o diff --git a/drivers/iio/magnetometer/mmc5983.c b/drivers/iio/magnetometer/mmc5983.c new file mode 100644 index 000000000000..a67b13393b6b --- /dev/null +++ b/drivers/iio/magnetometer/mmc5983.c @@ -0,0 +1,348 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * MMC5983 - MEMSIC 3-axis Magnetic Sensor + * + * Copyright (c) 2026, Vlad Kulikov + * + * IIO driver for MMC5983 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MMC5983_REG_XOUT0 0x00 +#define MMC5983_REG_XOUT1 0x01 +#define MMC5983_REG_YOUT0 0x02 +#define MMC5983_REG_YOUT1 0x03 +#define MMC5983_REG_ZOUT0 0x04 +#define MMC5983_REG_ZOUT1 0x05 +#define MMC5983_REG_XYZOUT2 0x06 + +#define MMC5983_REG_STATUS 0x08 + +#define MMC5983_REG_CTRL0 0x09 +#define MMC5983_REG_CTRL1 0x0A +#define MMC5983_REG_CTRL2 0x0B +#define MMC5983_REG_CTRL3 0x0C + +#define MMC5983_REG_ID 0x2F + +#define MMC5983_PRODUCT_ID 0x30 + +#define MMC5983_STATUS_MEAS_M_DONE_BIT BIT(0) +#define MMC5983_STATUS_OTP_RD_DONE_BIT BIT(4) + +#define MMC5983_CTRL0_TM_M_BIT BIT(0) +#define MMC5983_CTRL0_SET_BIT BIT(3) +#define MMC5983_CTRL0_RESET_BIT BIT(4) +#define MMC5983_CTRL0_OTP_RD_BIT BIT(6) + +#define MMC5983_CTRL1_SW_RST_BIT BIT(7) + +enum mmc5983_axis { + MMC5983_AXIS_X, + MMC5983_AXIS_Y, + MMC5983_AXIS_Z, +}; + +struct mmc5983_data { + struct regmap *regmap; + /* Protects chip access during SET/RESET measurement sequence */ + struct mutex mutex; +}; + +#define MMC5983_CHANNEL(_axis) { \ + .type = IIO_MAGN, \ + .modified = 1, \ + .channel2 = IIO_MOD_##_axis, \ + .address = MMC5983_AXIS_##_axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ +} + +static const struct iio_chan_spec mmc5983_channels[] = { + MMC5983_CHANNEL(X), + MMC5983_CHANNEL(Y), + MMC5983_CHANNEL(Z), +}; + +static int mmc5983_pulse_coil(struct mmc5983_data *data, unsigned int coil_bit) +{ + int ret; + + ret = regmap_write(data->regmap, MMC5983_REG_CTRL0, coil_bit); + if (ret) + return ret; + + /* + * Datasheet page 15: SET/RESET coil pulse is 500 ns. + * Vendor sample code waits 500 us before the next operation. + */ + fsleep(500); + + return 0; +} + +static int mmc5983_take_measurement(struct mmc5983_data *data, int m[3]) +{ + unsigned int status; + u8 buf[7]; + int ret; + + ret = regmap_write(data->regmap, MMC5983_REG_CTRL0, + MMC5983_CTRL0_TM_M_BIT); + if (ret) + return ret; + + /* + * Datasheet page 15: measurement time is 8 ms at BW=00 (default, + * slowest setting). Use a 50 ms timeout for margin. + */ + ret = regmap_read_poll_timeout(data->regmap, MMC5983_REG_STATUS, + status, + status & MMC5983_STATUS_MEAS_M_DONE_BIT, + 10 * USEC_PER_MSEC, + 50 * USEC_PER_MSEC); + if (ret) + return ret; + + ret = regmap_bulk_read(data->regmap, MMC5983_REG_XOUT0, buf, + sizeof(buf)); + if (ret) + return ret; + + m[0] = (buf[0] << 10) | (buf[1] << 2) | ((buf[6] >> 6) & 0x3); + m[1] = (buf[2] << 10) | (buf[3] << 2) | ((buf[6] >> 4) & 0x3); + m[2] = (buf[4] << 10) | (buf[5] << 2) | ((buf[6] >> 2) & 0x3); + + return 0; +} + +static int mmc5983_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, int *val, + int *val2, long mask) +{ + struct mmc5983_data *data = iio_priv(indio_dev); + int m1[3], m2[3]; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: { + guard(mutex)(&data->mutex); + + /* SET: magnetize sensor elements in forward direction */ + ret = mmc5983_pulse_coil(data, MMC5983_CTRL0_SET_BIT); + if (ret) + return ret; + + ret = mmc5983_take_measurement(data, m1); + if (ret) + return ret; + + /* RESET: magnetize sensor elements in reverse direction */ + ret = mmc5983_pulse_coil(data, MMC5983_CTRL0_RESET_BIT); + if (ret) + return ret; + + ret = mmc5983_take_measurement(data, m2); + if (ret) + return ret; + + *val = (m1[chan->address] - m2[chan->address]) / 2; + return IIO_VAL_INT; + } + case IIO_CHAN_INFO_SCALE: + *val = 0; + *val2 = 61035; + return IIO_VAL_INT_PLUS_NANO; + default: + return -EINVAL; + } +} + +static const struct iio_info mmc5983_info = { + .read_raw = mmc5983_read_raw, +}; + +static bool mmc5983_is_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MMC5983_REG_CTRL0: + case MMC5983_REG_CTRL1: + case MMC5983_REG_CTRL2: + case MMC5983_REG_CTRL3: + return true; + default: + return false; + } +} + +static bool mmc5983_is_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MMC5983_REG_XOUT0: + case MMC5983_REG_XOUT1: + case MMC5983_REG_YOUT0: + case MMC5983_REG_YOUT1: + case MMC5983_REG_ZOUT0: + case MMC5983_REG_ZOUT1: + case MMC5983_REG_XYZOUT2: + case MMC5983_REG_STATUS: + case MMC5983_REG_CTRL0: + case MMC5983_REG_CTRL1: + case MMC5983_REG_CTRL2: + case MMC5983_REG_CTRL3: + case MMC5983_REG_ID: + return true; + default: + return false; + } +} + +static bool mmc5983_is_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MMC5983_REG_XOUT0: + case MMC5983_REG_XOUT1: + case MMC5983_REG_YOUT0: + case MMC5983_REG_YOUT1: + case MMC5983_REG_ZOUT0: + case MMC5983_REG_ZOUT1: + case MMC5983_REG_XYZOUT2: + case MMC5983_REG_STATUS: + case MMC5983_REG_CTRL0: + case MMC5983_REG_CTRL1: + return true; + default: + return false; + } +} + +static const struct regmap_config mmc5983_regmap_config = { + .name = "mmc5983_regmap", + .reg_bits = 8, + .val_bits = 8, + .max_register = MMC5983_REG_ID, + .writeable_reg = mmc5983_is_writeable_reg, + .readable_reg = mmc5983_is_readable_reg, + .volatile_reg = mmc5983_is_volatile_reg, +}; + +static int mmc5983_init(struct mmc5983_data *data) +{ + struct regmap *regmap = data->regmap; + struct device *dev = regmap_get_device(regmap); + unsigned int reg_id, status; + int ret; + + ret = regmap_read(regmap, MMC5983_REG_ID, ®_id); + if (ret) + return dev_err_probe(dev, ret, "Error reading product id\n"); + + if (reg_id != MMC5983_PRODUCT_ID) + dev_info(dev, "unexpected product id 0x%02x\n", reg_id); + + ret = regmap_write(regmap, MMC5983_REG_CTRL1, MMC5983_CTRL1_SW_RST_BIT); + if (ret) + return ret; + + /* Datasheet page 15: power-on time after SW_RST is 10 ms */ + fsleep(10 * USEC_PER_MSEC); + + ret = regmap_write(regmap, MMC5983_REG_CTRL0, MMC5983_CTRL0_OTP_RD_BIT); + if (ret) + return ret; + + /* + * Datasheet page 15: OTP read completes and self-clears. No separate + * OTP refresh timeout is specified, so use the 10 ms power-on time as + * a conservative upper bound. + */ + ret = regmap_read_poll_timeout(regmap, MMC5983_REG_STATUS, status, + status & MMC5983_STATUS_OTP_RD_DONE_BIT, + USEC_PER_MSEC, + 10 * USEC_PER_MSEC); + if (ret) + return ret; + + /* SET: magnetize sensor elements in forward direction */ + ret = mmc5983_pulse_coil(data, MMC5983_CTRL0_SET_BIT); + if (ret) + return ret; + + /* RESET: magnetize sensor elements in reverse direction */ + return mmc5983_pulse_coil(data, MMC5983_CTRL0_RESET_BIT); +} + +static int mmc5983_probe(struct i2c_client *i2c) +{ + struct device *dev = &i2c->dev; + struct mmc5983_data *data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + + ret = devm_mutex_init(dev, &data->mutex); + if (ret) + return ret; + + data->regmap = devm_regmap_init_i2c(i2c, &mmc5983_regmap_config); + if (IS_ERR(data->regmap)) + return dev_err_probe(dev, PTR_ERR(data->regmap), + "failed to allocate register map\n"); + + indio_dev->info = &mmc5983_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->name = "mmc5983"; + indio_dev->channels = mmc5983_channels; + indio_dev->num_channels = ARRAY_SIZE(mmc5983_channels); + + ret = mmc5983_init(data); + if (ret) + return dev_err_probe(dev, ret, "mmc5983 chip init failed\n"); + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct of_device_id mmc5983_of_match[] = { + { .compatible = "memsic,mmc5983" }, + { } +}; +MODULE_DEVICE_TABLE(of, mmc5983_of_match); + +static const struct i2c_device_id mmc5983_id[] = { + { "mmc5983" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mmc5983_id); + +static struct i2c_driver mmc5983_driver = { + .driver = { + .name = "mmc5983", + .of_match_table = mmc5983_of_match, + }, + .probe = mmc5983_probe, + .id_table = mmc5983_id, +}; +module_i2c_driver(mmc5983_driver); + +MODULE_AUTHOR("Vladislav Kulikov "); +MODULE_DESCRIPTION("MEMSIC MMC5983 magnetic sensor driver"); +MODULE_LICENSE("GPL"); From b622051675183c37c4b1d4699233528f5744eb8c Mon Sep 17 00:00:00 2001 From: Joshua Crofts Date: Tue, 12 May 2026 12:57:22 +0200 Subject: [PATCH 176/266] iio: light: opt3001: make headers conform to iwyu Remove kernel.h proxy header, device.h, irq.h, slab.h as they are unnecessary and add missing headers (array_size.h, dev_printk.h, errno.h, jiffies.h, wait.h) to enforce IWYU principle and reduce transitive dependencies. Also, replace bitops.h with bits.h as only the BIT() macro is used. Signed-off-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/iio/light/opt3001.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/iio/light/opt3001.c b/drivers/iio/light/opt3001.c index 53bc455b7bad..e6c3665f46be 100644 --- a/drivers/iio/light/opt3001.c +++ b/drivers/iio/light/opt3001.c @@ -8,18 +8,19 @@ * Based on previous work from: Felipe Balbi */ -#include +#include +#include #include -#include +#include +#include #include #include -#include -#include -#include +#include #include +#include #include -#include #include +#include #include #include From 8402b3266173e3c282244246354b9863bca92ffd Mon Sep 17 00:00:00 2001 From: Joshua Crofts Date: Tue, 12 May 2026 12:57:23 +0200 Subject: [PATCH 177/266] iio: light: opt3001: use macros from bits.h header Use GENMASK() and BIT() macros from bits.h header where it makes sense. While at it, remove unused macro. No functional change. Signed-off-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/iio/light/opt3001.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/iio/light/opt3001.c b/drivers/iio/light/opt3001.c index e6c3665f46be..dac3d3818d0a 100644 --- a/drivers/iio/light/opt3001.c +++ b/drivers/iio/light/opt3001.c @@ -33,17 +33,16 @@ #define OPT3001_MANUFACTURER_ID 0x7e #define OPT3001_DEVICE_ID 0x7f -#define OPT3001_CONFIGURATION_RN_MASK (0xf << 12) +#define OPT3001_CONFIGURATION_RN_MASK GENMASK(15, 12) #define OPT3001_CONFIGURATION_RN_AUTO (0xc << 12) #define OPT3001_CONFIGURATION_CT BIT(11) -#define OPT3001_CONFIGURATION_M_MASK (3 << 9) +#define OPT3001_CONFIGURATION_M_MASK GENMASK(10, 9) #define OPT3001_CONFIGURATION_M_SHUTDOWN (0 << 9) #define OPT3001_CONFIGURATION_M_SINGLE (1 << 9) #define OPT3001_CONFIGURATION_M_CONTINUOUS (2 << 9) /* also 3 << 9 */ -#define OPT3001_CONFIGURATION_OVF BIT(8) #define OPT3001_CONFIGURATION_CRF BIT(7) #define OPT3001_CONFIGURATION_FH BIT(6) #define OPT3001_CONFIGURATION_FL BIT(5) @@ -51,7 +50,7 @@ #define OPT3001_CONFIGURATION_POL BIT(3) #define OPT3001_CONFIGURATION_ME BIT(2) -#define OPT3001_CONFIGURATION_FC_MASK (3 << 0) +#define OPT3001_CONFIGURATION_FC_MASK GENMASK(1, 0) /* The end-of-conversion enable is located in the low-limit register */ #define OPT3001_LOW_LIMIT_EOC_ENABLE 0xc000 From 947eb6f0a274f8b15a0248051a65b069effd5057 Mon Sep 17 00:00:00 2001 From: Guilherme Ivo Bozi Date: Tue, 12 May 2026 21:31:50 -0300 Subject: [PATCH 178/266] iio: adc: xilinx-ams: fix out-of-bounds channel lookup in event handling ams_event_to_channel() may return a pointer past the end of dev->channels when no matching scan_index is found. This can lead to invalid memory access in ams_handle_event(). Add a bounds check in ams_event_to_channel() and return NULL when no channel is found. Also guard the caller to safely handle this case. Fixes: d5c70627a794 ("iio: adc: Add Xilinx AMS driver") Signed-off-by: Guilherme Ivo Bozi Reviewed-by: Salih Erim Tested-by: Salih Erim Signed-off-by: Jonathan Cameron --- drivers/iio/adc/xilinx-ams.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/iio/adc/xilinx-ams.c b/drivers/iio/adc/xilinx-ams.c index 124470c92529..6191cd1b29a5 100644 --- a/drivers/iio/adc/xilinx-ams.c +++ b/drivers/iio/adc/xilinx-ams.c @@ -871,6 +871,9 @@ static const struct iio_chan_spec *ams_event_to_channel(struct iio_dev *dev, if (dev->channels[i].scan_index == scan_index) break; + if (i == dev->num_channels) + return NULL; + return &dev->channels[i]; } @@ -1012,6 +1015,8 @@ static void ams_handle_event(struct iio_dev *indio_dev, u32 event) const struct iio_chan_spec *chan; chan = ams_event_to_channel(indio_dev, event); + if (!chan) + return; if (chan->type == IIO_TEMP) { /* From f3c1ef2bca5c128b62b5b804a50ad3f6f64a3098 Mon Sep 17 00:00:00 2001 From: Guilherme Ivo Bozi Date: Tue, 12 May 2026 21:31:51 -0300 Subject: [PATCH 179/266] iio: adc: xilinx-ams: use guard(mutex) for automatic locking Replace open-coded mutex_lock()/mutex_unlock() pairs with guard(mutex) to simplify locking and ensure proper unlock on all control flow paths. This removes explicit unlock handling, reduces boilerplate, and avoids potential mistakes in error paths while keeping the behavior unchanged. Signed-off-by: Guilherme Ivo Bozi Reviewed-by: Andy Shevchenko Reviewed-by: Salih Erim Tested-by: Salih Erim Signed-off-by: Jonathan Cameron --- drivers/iio/adc/xilinx-ams.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/iio/adc/xilinx-ams.c b/drivers/iio/adc/xilinx-ams.c index 6191cd1b29a5..70a1f97f6dad 100644 --- a/drivers/iio/adc/xilinx-ams.c +++ b/drivers/iio/adc/xilinx-ams.c @@ -720,22 +720,20 @@ static int ams_read_raw(struct iio_dev *indio_dev, int ret; switch (mask) { - case IIO_CHAN_INFO_RAW: - mutex_lock(&ams->lock); + case IIO_CHAN_INFO_RAW: { + guard(mutex)(&ams->lock); if (chan->scan_index >= AMS_CTRL_SEQ_BASE) { ret = ams_read_vcc_reg(ams, chan->address, val); if (ret) - goto unlock_mutex; + return ret; ams_enable_channel_sequence(indio_dev); } else if (chan->scan_index >= AMS_PS_SEQ_MAX) *val = readl(ams->pl_base + chan->address); else *val = readl(ams->ps_base + chan->address); - ret = IIO_VAL_INT; -unlock_mutex: - mutex_unlock(&ams->lock); - return ret; + return IIO_VAL_INT; + } case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_VOLTAGE: @@ -939,7 +937,7 @@ static int ams_write_event_config(struct iio_dev *indio_dev, alarm = ams_get_alarm_mask(chan->scan_index); - mutex_lock(&ams->lock); + guard(mutex)(&ams->lock); if (state) ams->alarm_mask |= alarm; @@ -948,8 +946,6 @@ static int ams_write_event_config(struct iio_dev *indio_dev, ams_update_alarm(ams, ams->alarm_mask); - mutex_unlock(&ams->lock); - return 0; } @@ -962,15 +958,13 @@ static int ams_read_event_value(struct iio_dev *indio_dev, struct ams *ams = iio_priv(indio_dev); unsigned int offset = ams_get_alarm_offset(chan->scan_index, dir); - mutex_lock(&ams->lock); + guard(mutex)(&ams->lock); if (chan->scan_index >= AMS_PS_SEQ_MAX) *val = readl(ams->pl_base + offset); else *val = readl(ams->ps_base + offset); - mutex_unlock(&ams->lock); - return IIO_VAL_INT; } @@ -983,7 +977,7 @@ static int ams_write_event_value(struct iio_dev *indio_dev, struct ams *ams = iio_priv(indio_dev); unsigned int offset; - mutex_lock(&ams->lock); + guard(mutex)(&ams->lock); /* Set temperature channel threshold to direct threshold */ if (chan->type == IIO_TEMP) { @@ -1005,8 +999,6 @@ static int ams_write_event_value(struct iio_dev *indio_dev, else writel(val, ams->ps_base + offset); - mutex_unlock(&ams->lock); - return 0; } From 43a66cae2e9dc97b309a296deb141a9b3446eb1a Mon Sep 17 00:00:00 2001 From: Guilherme Ivo Bozi Date: Tue, 12 May 2026 21:31:52 -0300 Subject: [PATCH 180/266] iio: adc: xilinx-ams: refactor alarm mapping to table-driven approach Replace multiple open-coded switch statements that map between scan_index, alarm bits, and register offsets with a centralized table-driven approach. Introduce a struct-based alarm_map to describe the relationship between scan indices and alarm offsets, and add a helper to translate scan_index to event IDs. This removes duplicated logic across ams_get_alarm_offset(), ams_event_to_channel(), and ams_get_alarm_mask(). The new approach improves maintainability, reduces code size, and makes it easier to extend or modify alarm mappings in the future, while preserving existing behavior. Signed-off-by: Guilherme Ivo Bozi Reviewed-by: Salih Erim Tested-by: Salih Erim Signed-off-by: Jonathan Cameron --- drivers/iio/adc/xilinx-ams.c | 161 +++++++++++++---------------------- 1 file changed, 58 insertions(+), 103 deletions(-) diff --git a/drivers/iio/adc/xilinx-ams.c b/drivers/iio/adc/xilinx-ams.c index 70a1f97f6dad..d38c4401dfce 100644 --- a/drivers/iio/adc/xilinx-ams.c +++ b/drivers/iio/adc/xilinx-ams.c @@ -102,6 +102,7 @@ #define AMS_PS_SEQ_MASK GENMASK(21, 0) #define AMS_PL_SEQ_MASK GENMASK_ULL(59, 22) +#define AMS_ALARM_NONE 0x000 /* not a real offset */ #define AMS_ALARM_TEMP 0x140 #define AMS_ALARM_SUPPLY1 0x144 #define AMS_ALARM_SUPPLY2 0x148 @@ -763,9 +764,49 @@ static int ams_read_raw(struct iio_dev *indio_dev, } } +struct ams_alarm_map { + enum ams_ps_pl_seq scan_index; + unsigned int base_offset; +}; + +/* + * Array index matches enum ams_alarm_bit. + * Entries with base_offset == AMS_ALARM_NONE are unused/invalid + * (e.g. RESERVED) and must be skipped. + */ +static const struct ams_alarm_map alarm_map[] = { + [AMS_ALARM_BIT_TEMP] = { AMS_SEQ_TEMP, AMS_ALARM_TEMP }, + [AMS_ALARM_BIT_SUPPLY1] = { AMS_SEQ_SUPPLY1, AMS_ALARM_SUPPLY1 }, + [AMS_ALARM_BIT_SUPPLY2] = { AMS_SEQ_SUPPLY2, AMS_ALARM_SUPPLY2 }, + [AMS_ALARM_BIT_SUPPLY3] = { AMS_SEQ_SUPPLY3, AMS_ALARM_SUPPLY3 }, + [AMS_ALARM_BIT_SUPPLY4] = { AMS_SEQ_SUPPLY4, AMS_ALARM_SUPPLY4 }, + [AMS_ALARM_BIT_SUPPLY5] = { AMS_SEQ_SUPPLY5, AMS_ALARM_SUPPLY5 }, + [AMS_ALARM_BIT_SUPPLY6] = { AMS_SEQ_SUPPLY6, AMS_ALARM_SUPPLY6 }, + [AMS_ALARM_BIT_RESERVED] = { 0, AMS_ALARM_NONE }, + [AMS_ALARM_BIT_SUPPLY7] = { AMS_SEQ_SUPPLY7, AMS_ALARM_SUPPLY7 }, + [AMS_ALARM_BIT_SUPPLY8] = { AMS_SEQ_SUPPLY8, AMS_ALARM_SUPPLY8 }, + [AMS_ALARM_BIT_SUPPLY9] = { AMS_SEQ_SUPPLY9, AMS_ALARM_SUPPLY9 }, + [AMS_ALARM_BIT_SUPPLY10] = { AMS_SEQ_SUPPLY10, AMS_ALARM_SUPPLY10 }, + [AMS_ALARM_BIT_VCCAMS] = { AMS_SEQ_VCCAMS, AMS_ALARM_VCCAMS }, + [AMS_ALARM_BIT_TEMP_REMOTE] = { AMS_SEQ_TEMP_REMOTE, AMS_ALARM_TEMP_REMOTE }, +}; + +static int ams_scan_index_to_event(int scan_index) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(alarm_map); i++) { + if (alarm_map[i].base_offset == AMS_ALARM_NONE) + continue; + + if (alarm_map[i].scan_index == scan_index) + return i; + } + + return -EINVAL; +} + static int ams_get_alarm_offset(int scan_index, enum iio_event_direction dir) { - int offset; + int offset, event; if (scan_index >= AMS_PS_SEQ_MAX) scan_index -= AMS_PS_SEQ_MAX; @@ -779,36 +820,11 @@ static int ams_get_alarm_offset(int scan_index, enum iio_event_direction dir) offset = 0; } - switch (scan_index) { - case AMS_SEQ_TEMP: - return AMS_ALARM_TEMP + offset; - case AMS_SEQ_SUPPLY1: - return AMS_ALARM_SUPPLY1 + offset; - case AMS_SEQ_SUPPLY2: - return AMS_ALARM_SUPPLY2 + offset; - case AMS_SEQ_SUPPLY3: - return AMS_ALARM_SUPPLY3 + offset; - case AMS_SEQ_SUPPLY4: - return AMS_ALARM_SUPPLY4 + offset; - case AMS_SEQ_SUPPLY5: - return AMS_ALARM_SUPPLY5 + offset; - case AMS_SEQ_SUPPLY6: - return AMS_ALARM_SUPPLY6 + offset; - case AMS_SEQ_SUPPLY7: - return AMS_ALARM_SUPPLY7 + offset; - case AMS_SEQ_SUPPLY8: - return AMS_ALARM_SUPPLY8 + offset; - case AMS_SEQ_SUPPLY9: - return AMS_ALARM_SUPPLY9 + offset; - case AMS_SEQ_SUPPLY10: - return AMS_ALARM_SUPPLY10 + offset; - case AMS_SEQ_VCCAMS: - return AMS_ALARM_VCCAMS + offset; - case AMS_SEQ_TEMP_REMOTE: - return AMS_ALARM_TEMP_REMOTE + offset; - default: + event = ams_scan_index_to_event(scan_index); + if (event < 0 || alarm_map[event].base_offset == AMS_ALARM_NONE) return 0; - } + + return alarm_map[event].base_offset + offset; } static const struct iio_chan_spec *ams_event_to_channel(struct iio_dev *dev, @@ -821,49 +837,13 @@ static const struct iio_chan_spec *ams_event_to_channel(struct iio_dev *dev, scan_index = AMS_PS_SEQ_MAX; } - switch (event) { - case AMS_ALARM_BIT_TEMP: - scan_index += AMS_SEQ_TEMP; - break; - case AMS_ALARM_BIT_SUPPLY1: - scan_index += AMS_SEQ_SUPPLY1; - break; - case AMS_ALARM_BIT_SUPPLY2: - scan_index += AMS_SEQ_SUPPLY2; - break; - case AMS_ALARM_BIT_SUPPLY3: - scan_index += AMS_SEQ_SUPPLY3; - break; - case AMS_ALARM_BIT_SUPPLY4: - scan_index += AMS_SEQ_SUPPLY4; - break; - case AMS_ALARM_BIT_SUPPLY5: - scan_index += AMS_SEQ_SUPPLY5; - break; - case AMS_ALARM_BIT_SUPPLY6: - scan_index += AMS_SEQ_SUPPLY6; - break; - case AMS_ALARM_BIT_SUPPLY7: - scan_index += AMS_SEQ_SUPPLY7; - break; - case AMS_ALARM_BIT_SUPPLY8: - scan_index += AMS_SEQ_SUPPLY8; - break; - case AMS_ALARM_BIT_SUPPLY9: - scan_index += AMS_SEQ_SUPPLY9; - break; - case AMS_ALARM_BIT_SUPPLY10: - scan_index += AMS_SEQ_SUPPLY10; - break; - case AMS_ALARM_BIT_VCCAMS: - scan_index += AMS_SEQ_VCCAMS; - break; - case AMS_ALARM_BIT_TEMP_REMOTE: - scan_index += AMS_SEQ_TEMP_REMOTE; - break; - default: - break; - } + if (event >= ARRAY_SIZE(alarm_map)) + return NULL; + + if (alarm_map[event].base_offset == AMS_ALARM_NONE) + return NULL; + + scan_index += alarm_map[event].scan_index; for (i = 0; i < dev->num_channels; i++) if (dev->channels[i].scan_index == scan_index) @@ -877,43 +857,18 @@ static const struct iio_chan_spec *ams_event_to_channel(struct iio_dev *dev, static int ams_get_alarm_mask(int scan_index) { - int bit = 0; + int bit = 0, event; if (scan_index >= AMS_PS_SEQ_MAX) { bit = AMS_PL_ALARM_START; scan_index -= AMS_PS_SEQ_MAX; } - switch (scan_index) { - case AMS_SEQ_TEMP: - return BIT(AMS_ALARM_BIT_TEMP + bit); - case AMS_SEQ_SUPPLY1: - return BIT(AMS_ALARM_BIT_SUPPLY1 + bit); - case AMS_SEQ_SUPPLY2: - return BIT(AMS_ALARM_BIT_SUPPLY2 + bit); - case AMS_SEQ_SUPPLY3: - return BIT(AMS_ALARM_BIT_SUPPLY3 + bit); - case AMS_SEQ_SUPPLY4: - return BIT(AMS_ALARM_BIT_SUPPLY4 + bit); - case AMS_SEQ_SUPPLY5: - return BIT(AMS_ALARM_BIT_SUPPLY5 + bit); - case AMS_SEQ_SUPPLY6: - return BIT(AMS_ALARM_BIT_SUPPLY6 + bit); - case AMS_SEQ_SUPPLY7: - return BIT(AMS_ALARM_BIT_SUPPLY7 + bit); - case AMS_SEQ_SUPPLY8: - return BIT(AMS_ALARM_BIT_SUPPLY8 + bit); - case AMS_SEQ_SUPPLY9: - return BIT(AMS_ALARM_BIT_SUPPLY9 + bit); - case AMS_SEQ_SUPPLY10: - return BIT(AMS_ALARM_BIT_SUPPLY10 + bit); - case AMS_SEQ_VCCAMS: - return BIT(AMS_ALARM_BIT_VCCAMS + bit); - case AMS_SEQ_TEMP_REMOTE: - return BIT(AMS_ALARM_BIT_TEMP_REMOTE + bit); - default: + event = ams_scan_index_to_event(scan_index); + if (event < 0) return 0; - } + + return BIT(event + bit); } static int ams_read_event_config(struct iio_dev *indio_dev, From 9ad241c71106d3dfb5d194e66b83462a18412cba Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Thu, 14 May 2026 14:01:12 +1300 Subject: [PATCH 181/266] iio: light: veml6030: remove unnecessary read of IT index This is dead code as the IT index is not used by gts to set the new scale. In its current form, the value is read but not used afterward. Remove the dead code. Signed-off-by: Javier Carrasco Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/light/veml6030.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/iio/light/veml6030.c b/drivers/iio/light/veml6030.c index 6bcacae3863c..745cf3ad7092 100644 --- a/drivers/iio/light/veml6030.c +++ b/drivers/iio/light/veml6030.c @@ -521,13 +521,9 @@ static int veml6030_write_persistence(struct iio_dev *indio_dev, static int veml6030_set_scale(struct iio_dev *indio_dev, int val, int val2) { - int ret, gain_sel, it_idx, it_sel; + int ret, gain_sel, it_sel; struct veml6030_data *data = iio_priv(indio_dev); - ret = regmap_field_read(data->rf.it, &it_idx); - if (ret) - return ret; - ret = iio_gts_find_gain_time_sel_for_scale(&data->gts, val, val2, &gain_sel, &it_sel); if (ret) From 24245b93873bfef91657658775be3918e052d52f Mon Sep 17 00:00:00 2001 From: Michal Piekos Date: Sat, 16 May 2026 07:34:14 +0200 Subject: [PATCH 182/266] dt-bindings: iio: adc: Add GPADC for Allwinner A523 Add support for the GPADC for the Allwinner A523. It differs from the D1/T113s/R329/T507 by having two clocks. Acked-by: Conor Dooley Signed-off-by: Michal Piekos Signed-off-by: Jonathan Cameron --- .../iio/adc/allwinner,sun20i-d1-gpadc.yaml | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/iio/adc/allwinner,sun20i-d1-gpadc.yaml b/Documentation/devicetree/bindings/iio/adc/allwinner,sun20i-d1-gpadc.yaml index da605a051b94..6467800d30e2 100644 --- a/Documentation/devicetree/bindings/iio/adc/allwinner,sun20i-d1-gpadc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/allwinner,sun20i-d1-gpadc.yaml @@ -14,6 +14,7 @@ properties: oneOf: - enum: - allwinner,sun20i-d1-gpadc + - allwinner,sun55i-a523-gpadc - items: - enum: - allwinner,sun50i-h616-gpadc @@ -29,7 +30,12 @@ properties: const: 0 clocks: - maxItems: 1 + minItems: 1 + maxItems: 2 + + clock-names: + minItems: 1 + maxItems: 2 interrupts: maxItems: 1 @@ -40,6 +46,30 @@ properties: resets: maxItems: 1 +allOf: + - if: + properties: + compatible: + enum: + - allwinner,sun55i-a523-gpadc + then: + properties: + clocks: + items: + - description: Bus clock + - description: Module clock + clock-names: + items: + - const: bus + - const: mod + required: + - clock-names + else: + properties: + clocks: + maxItems: 1 + clock-names: false + patternProperties: "^channel@[0-9a-f]+$": $ref: adc.yaml From 8114f4420360260576cbd6d0633b28a607321f0b Mon Sep 17 00:00:00 2001 From: Michal Piekos Date: Sat, 16 May 2026 07:34:15 +0200 Subject: [PATCH 183/266] iio: adc: sun20i-gpadc: add A523 gpadc support A523 differs from existing sun20i-gpadc-iio by having two clocks; bus clock and module clock. Change driver to enable all clocks. Signed-off-by: Michal Piekos Signed-off-by: Jonathan Cameron --- drivers/iio/adc/sun20i-gpadc-iio.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/iio/adc/sun20i-gpadc-iio.c b/drivers/iio/adc/sun20i-gpadc-iio.c index 861c14da75ad..f5fd2240b808 100644 --- a/drivers/iio/adc/sun20i-gpadc-iio.c +++ b/drivers/iio/adc/sun20i-gpadc-iio.c @@ -177,10 +177,10 @@ static int sun20i_gpadc_alloc_channels(struct iio_dev *indio_dev, static int sun20i_gpadc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct iio_dev *indio_dev; struct sun20i_gpadc_iio *info; + struct clk_bulk_data *clks; struct reset_control *rst; - struct clk *clk; + struct iio_dev *indio_dev; int irq; int ret; @@ -205,9 +205,11 @@ static int sun20i_gpadc_probe(struct platform_device *pdev) if (IS_ERR(info->regs)) return PTR_ERR(info->regs); - clk = devm_clk_get_enabled(dev, NULL); - if (IS_ERR(clk)) - return dev_err_probe(dev, PTR_ERR(clk), "failed to enable bus clock\n"); + ret = devm_clk_bulk_get_all_enabled(dev, &clks); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to enable clocks\n"); + if (ret == 0) + return dev_err_probe(dev, -ENODEV, "needs at least one clocks\n"); rst = devm_reset_control_get_exclusive(dev, NULL); if (IS_ERR(rst)) @@ -243,6 +245,7 @@ static int sun20i_gpadc_probe(struct platform_device *pdev) static const struct of_device_id sun20i_gpadc_of_id[] = { { .compatible = "allwinner,sun20i-d1-gpadc" }, + { .compatible = "allwinner,sun55i-a523-gpadc" }, { } }; MODULE_DEVICE_TABLE(of, sun20i_gpadc_of_id); From 44f38b46298dc2b0e007e88381d46fb92172a81d Mon Sep 17 00:00:00 2001 From: Michal Piekos Date: Sat, 16 May 2026 07:48:37 +0200 Subject: [PATCH 184/266] iio: adc: sun20i-gpadc: support non-contiguous channel lookups Using consumer driver like iio-hwmon which resolve channels through io-channels phandles will fail for sparse channels because IIO core by default treats phandle argument as index into channel array. eg. <&gpadc 1> will fail if there is only channel@1 specified Add .fwnode_xlate() which maps DT phandle to the registered channel whose chan->channel matches the hardware channel number. It allows sparse channel maps to be consumed by drivers like iio-hwmon. Tested on Radxa Cubie A5E. Reviewed-by: Andy Shevchenko Signed-off-by: Michal Piekos Signed-off-by: Jonathan Cameron --- drivers/iio/adc/sun20i-gpadc-iio.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/iio/adc/sun20i-gpadc-iio.c b/drivers/iio/adc/sun20i-gpadc-iio.c index f5fd2240b808..81fc4610e15e 100644 --- a/drivers/iio/adc/sun20i-gpadc-iio.c +++ b/drivers/iio/adc/sun20i-gpadc-iio.c @@ -139,8 +139,23 @@ static irqreturn_t sun20i_gpadc_irq_handler(int irq, void *data) return IRQ_HANDLED; } +static int +sun20i_gpadc_fwnode_xlate(struct iio_dev *indio_dev, + const struct fwnode_reference_args *iiospec) +{ + if (iiospec->nargs != 1) + return -EINVAL; + + for (unsigned int i = 0; i < indio_dev->num_channels; i++) + if (indio_dev->channels[i].channel == iiospec->args[0]) + return i; + + return -EINVAL; +} + static const struct iio_info sun20i_gpadc_iio_info = { .read_raw = sun20i_gpadc_read_raw, + .fwnode_xlate = sun20i_gpadc_fwnode_xlate, }; static void sun20i_gpadc_reset_assert(void *data) From 20c598e82cd0b37334dc3e95fbd460f594460c3c Mon Sep 17 00:00:00 2001 From: Nikhil Gautam Date: Mon, 20 Apr 2026 13:54:36 +0530 Subject: [PATCH 185/266] iio: chemical: bme680: use BME680_NUM_CHANNELS for scan buffer Use BME680_NUM_CHANNELS instead of the hardcoded channel count in the scan buffer. This avoids use of a magic number and improves code readability and maintainability. Suggested-by: Jonathan Cameron Signed-off-by: Nikhil Gautam Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/bme680_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/chemical/bme680_core.c b/drivers/iio/chemical/bme680_core.c index 6aeac132394c..ac9a737481dc 100644 --- a/drivers/iio/chemical/bme680_core.c +++ b/drivers/iio/chemical/bme680_core.c @@ -128,7 +128,7 @@ struct bme680_data { u16 heater_temp; struct { - s32 chan[4]; + s32 chan[BME680_NUM_CHANNELS]; aligned_s64 ts; } scan; From cc116c10f7874be109bd956a9080df113c246feb Mon Sep 17 00:00:00 2001 From: Taha Ed-Dafili <0rayn.dev@gmail.com> Date: Sat, 9 May 2026 15:20:40 +0100 Subject: [PATCH 186/266] iio: dac: ad5504: sort headers alphabetically Rearrange the include headers in alphabetical order to follow the standard kernel coding style. This is a preparatory cleanup with no functional changes. Reviewed-by: Andy Shevchenko Signed-off-by: Taha Ed-Dafili <0rayn.dev@gmail.com> Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad5504.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c index 355bcb6a8ba0..03ce37e2c616 100644 --- a/drivers/iio/dac/ad5504.c +++ b/drivers/iio/dac/ad5504.c @@ -5,21 +5,21 @@ * Copyright 2011 Analog Devices Inc. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include -#include -#include #define AD5504_RES_MASK GENMASK(11, 0) #define AD5504_CMD_READ BIT(15) From 97d30982aa5ae2b2f1778fdc91cc8f6e26e15453 Mon Sep 17 00:00:00 2001 From: Taha Ed-Dafili <0rayn.dev@gmail.com> Date: Sat, 9 May 2026 15:20:42 +0100 Subject: [PATCH 187/266] iio: dac: ad5504: introduce local dev pointer Replace &spi->dev with a local dev pointer to shorten lines, fix alignment, and improve overall readability in the probe function. Signed-off-by: Taha Ed-Dafili <0rayn.dev@gmail.com> Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad5504.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c index 03ce37e2c616..5e586185d857 100644 --- a/drivers/iio/dac/ad5504.c +++ b/drivers/iio/dac/ad5504.c @@ -270,25 +270,26 @@ static const struct iio_chan_spec ad5504_channels[] = { static int ad5504_probe(struct spi_device *spi) { - const struct ad5504_platform_data *pdata = dev_get_platdata(&spi->dev); + struct device *dev = &spi->dev; + const struct ad5504_platform_data *pdata = dev_get_platdata(dev); struct iio_dev *indio_dev; struct ad5504_state *st; int ret; - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; st = iio_priv(indio_dev); - ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vcc"); + ret = devm_regulator_get_enable_read_voltage(dev, "vcc"); if (ret < 0 && ret != -ENODEV) return ret; if (ret == -ENODEV) { if (pdata->vref_mv) st->vref_mv = pdata->vref_mv; else - dev_warn(&spi->dev, "reference voltage unspecified\n"); + dev_warn(dev, "reference voltage unspecified\n"); } else { st->vref_mv = ret / 1000; } @@ -304,17 +305,17 @@ static int ad5504_probe(struct spi_device *spi) indio_dev->modes = INDIO_DIRECT_MODE; if (spi->irq) { - ret = devm_request_threaded_irq(&spi->dev, spi->irq, - NULL, - &ad5504_event_handler, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - spi_get_device_id(st->spi)->name, - indio_dev); + ret = devm_request_threaded_irq(dev, spi->irq, + NULL, + &ad5504_event_handler, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + spi_get_device_id(st->spi)->name, + indio_dev); if (ret) return ret; } - return devm_iio_device_register(&spi->dev, indio_dev); + return devm_iio_device_register(dev, indio_dev); } static const struct spi_device_id ad5504_id[] = { From 5bdff291d20c31b365d9ddfe9c426fbfb41da5bb Mon Sep 17 00:00:00 2001 From: Sanjay Chitroda Date: Tue, 5 May 2026 23:16:31 +0530 Subject: [PATCH 188/266] iio: accel: mma8452: handle I2C read error(s) in mma8452_read() Currently, If i2c_smbus_read_i2c_block_data() fails but mma8452_set_runtime_pm_state() succeeds, mma8452_read() returns 0. As a result, the caller mma8452_read_raw() assumes the read was successful and proceeds to use a buffer containing uninitialized stack memory. Add proper checking of the I2C read return value and propagate errors to the caller. Fixes: 96c0cb2bbfe0 ("iio: mma8452: add support for runtime power management") Signed-off-by: Sanjay Chitroda Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma8452.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 15172ba2972c..cefc7cf4bd83 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -252,6 +252,8 @@ static int mma8452_read(struct mma8452_data *data, __be16 buf[3]) ret = i2c_smbus_read_i2c_block_data(data->client, MMA8452_OUT_X, 3 * sizeof(__be16), (u8 *)buf); + if (ret < 0) + return ret; ret = mma8452_set_runtime_pm_state(data->client, false); From 0a6726ec20cd4c0101f2de0ca485a11676224dea Mon Sep 17 00:00:00 2001 From: Sanjay Chitroda Date: Tue, 5 May 2026 23:16:32 +0530 Subject: [PATCH 189/266] iio: accel: mma8452: switch to non-devm request_threaded_irq() Avoid using devm_request_threaded_irq() as the driver requires explicit error-handling path(s). Using devm_* API together with goto-based unwinding breaks the expected LIFO resource release model. Add explicit IRQ cleanup in the driver teardown paths to follow kernel resource management conventions. Signed-off-by: Sanjay Chitroda Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma8452.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index cefc7cf4bd83..279a9b364886 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -1682,18 +1682,16 @@ static int mma8452_probe(struct i2c_client *client) goto trigger_cleanup; if (client->irq) { - ret = devm_request_threaded_irq(&client->dev, - client->irq, - NULL, mma8452_interrupt, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, - client->name, indio_dev); + ret = request_threaded_irq(client->irq, NULL, mma8452_interrupt, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + client->name, indio_dev); if (ret) goto buffer_cleanup; } ret = pm_runtime_set_active(&client->dev); if (ret < 0) - goto buffer_cleanup; + goto free_irq; pm_runtime_enable(&client->dev); pm_runtime_set_autosuspend_delay(&client->dev, @@ -1702,7 +1700,7 @@ static int mma8452_probe(struct i2c_client *client) ret = iio_device_register(indio_dev); if (ret < 0) - goto buffer_cleanup; + goto free_irq; ret = mma8452_set_freefall_mode(data, false); if (ret < 0) @@ -1713,6 +1711,10 @@ static int mma8452_probe(struct i2c_client *client) unregister_device: iio_device_unregister(indio_dev); +free_irq: + if (client->irq) + free_irq(client->irq, indio_dev); + buffer_cleanup: iio_triggered_buffer_cleanup(indio_dev); @@ -1738,6 +1740,9 @@ static void mma8452_remove(struct i2c_client *client) pm_runtime_disable(&client->dev); pm_runtime_set_suspended(&client->dev); + if (client->irq) + free_irq(client->irq, indio_dev); + iio_triggered_buffer_cleanup(indio_dev); mma8452_trigger_cleanup(indio_dev); mma8452_standby(iio_priv(indio_dev)); From b4f6b124467f5d770e170d93e6e12a2fe3977927 Mon Sep 17 00:00:00 2001 From: Sanjay Chitroda Date: Tue, 5 May 2026 23:16:33 +0530 Subject: [PATCH 190/266] iio: accel: mma8452: cleanup codestyle warning Reported by checkpatch: FILE: drivers/iio/accel/mma8452.c CHECK: Alignment should match open parenthesis Signed-off-by: Sanjay Chitroda Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma8452.c | 47 +++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 279a9b364886..916631519d3f 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -706,8 +706,8 @@ static int mma8452_set_hp_filter_frequency(struct mma8452_data *data, } static int __mma8452_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, int val2, long mask) + struct iio_chan_spec const *chan, + int val, int val2, long mask) { struct mma8452_data *data = iio_priv(indio_dev); int i, j, ret; @@ -788,8 +788,9 @@ static int mma8452_write_raw(struct iio_dev *indio_dev, } static int mma8452_get_event_regs(struct mma8452_data *data, - const struct iio_chan_spec *chan, enum iio_event_direction dir, - const struct mma8452_event_regs **ev_reg) + const struct iio_chan_spec *chan, + enum iio_event_direction dir, + const struct mma8452_event_regs **ev_reg) { if (!chan) return -EINVAL; @@ -818,11 +819,11 @@ static int mma8452_get_event_regs(struct mma8452_data *data, } static int mma8452_read_event_value(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir, - enum iio_event_info info, - int *val, int *val2) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) { struct mma8452_data *data = iio_priv(indio_dev); int ret, us, power_mode; @@ -881,11 +882,11 @@ static int mma8452_read_event_value(struct iio_dev *indio_dev, } static int mma8452_write_event_value(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir, - enum iio_event_info info, - int val, int val2) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) { struct mma8452_data *data = iio_priv(indio_dev); int ret, reg, steps; @@ -955,8 +956,7 @@ static int mma8452_read_event_config(struct iio_dev *indio_dev, case IIO_EV_DIR_FALLING: return mma8452_freefall_mode_enabled(data); case IIO_EV_DIR_RISING: - ret = i2c_smbus_read_byte_data(data->client, - ev_regs->ev_cfg); + ret = i2c_smbus_read_byte_data(data->client, ev_regs->ev_cfg); if (ret < 0) return ret; @@ -1193,7 +1193,7 @@ static const struct attribute_group mma8452_event_attribute_group = { static const struct iio_mount_matrix * mma8452_get_mount_matrix(const struct iio_dev *indio_dev, - const struct iio_chan_spec *chan) + const struct iio_chan_spec *chan) { struct mma8452_data *data = iio_priv(indio_dev); @@ -1516,8 +1516,9 @@ static int mma8452_reset(struct i2c_client *client) * The following code will read the reset register, and check whether * this reset works. */ - i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG2, - MMA8452_CTRL_REG2_RST); + i2c_smbus_write_byte_data(client, + MMA8452_CTRL_REG2, + MMA8452_CTRL_REG2_RST); for (i = 0; i < 10; i++) { usleep_range(100, 200); @@ -1647,8 +1648,8 @@ static int mma8452_probe(struct i2c_client *client) dev_dbg(&client->dev, "using interrupt line INT2\n"); } else { ret = i2c_smbus_write_byte_data(client, - MMA8452_CTRL_REG5, - data->chip_info->all_events); + MMA8452_CTRL_REG5, + data->chip_info->all_events); if (ret < 0) goto disable_regulators; @@ -1656,8 +1657,8 @@ static int mma8452_probe(struct i2c_client *client) } ret = i2c_smbus_write_byte_data(client, - MMA8452_CTRL_REG4, - data->chip_info->enabled_events); + MMA8452_CTRL_REG4, + data->chip_info->enabled_events); if (ret < 0) goto disable_regulators; From e9f143941584ae27e9981649a3f9916c322ee01d Mon Sep 17 00:00:00 2001 From: Sanjay Chitroda Date: Tue, 5 May 2026 23:16:34 +0530 Subject: [PATCH 191/266] iio: accel: mma8452: sort headers alphabetically Sort include headers alphabetically to improve readability. Signed-off-by: Sanjay Chitroda Reviewed-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma8452.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 916631519d3f..d227ce3d5f67 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -18,21 +18,22 @@ * TODO: orientation events */ -#include -#include -#include +#include #include +#include +#include +#include +#include +#include +#include + +#include +#include #include #include -#include #include #include #include -#include -#include -#include -#include -#include #define MMA8452_STATUS 0x00 #define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0)) From 32a5c04d457540af67507494f30261580213df94 Mon Sep 17 00:00:00 2001 From: Sanjay Chitroda Date: Tue, 5 May 2026 23:16:35 +0530 Subject: [PATCH 192/266] iio: accel: mma8452: Use dev_err_probe() dev_err_probe() makes error code handling simpler and handle deferred probe nicely (avoid spamming logs). Signed-off-by: Sanjay Chitroda Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma8452.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index d227ce3d5f67..b49949792190 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -1548,6 +1548,7 @@ MODULE_DEVICE_TABLE(of, mma8452_dt_ids); static int mma8452_probe(struct i2c_client *client) { + struct device *dev = &client->dev; struct mma8452_data *data; struct iio_dev *indio_dev; int ret; @@ -1580,14 +1581,12 @@ static int mma8452_probe(struct i2c_client *client) "failed to get VDDIO regulator!\n"); ret = regulator_enable(data->vdd_reg); - if (ret) { - dev_err(&client->dev, "failed to enable VDD regulator!\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "failed to enable VDD regulator!\n"); ret = regulator_enable(data->vddio_reg); if (ret) { - dev_err(&client->dev, "failed to enable VDDIO regulator!\n"); + dev_err_probe(dev, ret, "failed to enable VDDIO regulator!\n"); goto disable_regulator_vdd; } From db95bd7933c6c5c033f468ce70332e6e7bb9f7c5 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 16 May 2026 12:32:19 +0100 Subject: [PATCH 193/266] iio: trigger: drop generic interrupt trigger. There is no way to bind to this driver from firmware and no explicit platform device creation calls exist in mainline. As such it is dead code. So drop it rather than potentially wasting time modernizing it (see #1) Link: https://lore.kernel.org/all/20260511063229.1433-1-sozdayvek@gmail.com/ #1 Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/trigger/Kconfig | 9 -- drivers/iio/trigger/Makefile | 1 - drivers/iio/trigger/iio-trig-interrupt.c | 109 ----------------------- 3 files changed, 119 deletions(-) delete mode 100644 drivers/iio/trigger/iio-trig-interrupt.c diff --git a/drivers/iio/trigger/Kconfig b/drivers/iio/trigger/Kconfig index 7ecb69725b1d..52899c22d57c 100644 --- a/drivers/iio/trigger/Kconfig +++ b/drivers/iio/trigger/Kconfig @@ -16,15 +16,6 @@ config IIO_HRTIMER_TRIGGER To compile this driver as a module, choose M here: the module will be called iio-trig-hrtimer. -config IIO_INTERRUPT_TRIGGER - tristate "Generic interrupt trigger" - help - Provides support for using an interrupt of any type as an IIO - trigger. This may be provided by a gpio driver for example. - - To compile this driver as a module, choose M here: the - module will be called iio-trig-interrupt. - config IIO_STM32_LPTIMER_TRIGGER tristate "STM32 Low-Power Timer Trigger" depends on MFD_STM32_LPTIMER || COMPILE_TEST diff --git a/drivers/iio/trigger/Makefile b/drivers/iio/trigger/Makefile index f3d11acb8a0b..fc1fd5661c94 100644 --- a/drivers/iio/trigger/Makefile +++ b/drivers/iio/trigger/Makefile @@ -6,7 +6,6 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_IIO_HRTIMER_TRIGGER) += iio-trig-hrtimer.o -obj-$(CONFIG_IIO_INTERRUPT_TRIGGER) += iio-trig-interrupt.o obj-$(CONFIG_IIO_STM32_LPTIMER_TRIGGER) += stm32-lptimer-trigger.o obj-$(CONFIG_IIO_STM32_TIMER_TRIGGER) += stm32-timer-trigger.o obj-$(CONFIG_IIO_SYSFS_TRIGGER) += iio-trig-sysfs.o diff --git a/drivers/iio/trigger/iio-trig-interrupt.c b/drivers/iio/trigger/iio-trig-interrupt.c deleted file mode 100644 index a100c2e3a0d9..000000000000 --- a/drivers/iio/trigger/iio-trig-interrupt.c +++ /dev/null @@ -1,109 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Industrial I/O - generic interrupt based trigger support - * - * Copyright (c) 2008-2013 Jonathan Cameron - */ - -#include -#include -#include -#include -#include - -#include -#include - - -struct iio_interrupt_trigger_info { - unsigned int irq; -}; - -static irqreturn_t iio_interrupt_trigger_poll(int irq, void *private) -{ - iio_trigger_poll(private); - return IRQ_HANDLED; -} - -static int iio_interrupt_trigger_probe(struct platform_device *pdev) -{ - struct iio_interrupt_trigger_info *trig_info; - struct iio_trigger *trig; - unsigned long irqflags; - struct resource *irq_res; - int irq, ret = 0; - - irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - - if (irq_res == NULL) - return -ENODEV; - - irqflags = (irq_res->flags & IRQF_TRIGGER_MASK) | IRQF_SHARED; - - irq = irq_res->start; - - trig = iio_trigger_alloc(NULL, "irqtrig%d", irq); - if (!trig) { - ret = -ENOMEM; - goto error_ret; - } - - trig_info = kzalloc_obj(*trig_info); - if (!trig_info) { - ret = -ENOMEM; - goto error_free_trigger; - } - iio_trigger_set_drvdata(trig, trig_info); - trig_info->irq = irq; - ret = request_irq(irq, iio_interrupt_trigger_poll, - irqflags, trig->name, trig); - if (ret) { - dev_err(&pdev->dev, - "request IRQ-%d failed", irq); - goto error_free_trig_info; - } - - ret = iio_trigger_register(trig); - if (ret) - goto error_release_irq; - platform_set_drvdata(pdev, trig); - - return 0; - -/* First clean up the partly allocated trigger */ -error_release_irq: - free_irq(irq, trig); -error_free_trig_info: - kfree(trig_info); -error_free_trigger: - iio_trigger_free(trig); -error_ret: - return ret; -} - -static void iio_interrupt_trigger_remove(struct platform_device *pdev) -{ - struct iio_trigger *trig; - struct iio_interrupt_trigger_info *trig_info; - - trig = platform_get_drvdata(pdev); - trig_info = iio_trigger_get_drvdata(trig); - iio_trigger_unregister(trig); - free_irq(trig_info->irq, trig); - kfree(trig_info); - iio_trigger_free(trig); -} - -static struct platform_driver iio_interrupt_trigger_driver = { - .probe = iio_interrupt_trigger_probe, - .remove = iio_interrupt_trigger_remove, - .driver = { - .name = "iio_interrupt_trigger", - }, -}; - -module_platform_driver(iio_interrupt_trigger_driver); - -MODULE_AUTHOR("Jonathan Cameron "); -MODULE_DESCRIPTION("Interrupt trigger for the iio subsystem"); -MODULE_LICENSE("GPL v2"); From 8b44f074a76c310e4b311fb4509586254f251dcb Mon Sep 17 00:00:00 2001 From: David Lechner Date: Sun, 17 May 2026 12:00:58 -0500 Subject: [PATCH 194/266] MAINTAINERS: add match for IIO API docs Add a match for Documentation/driver-api/iio/ to the IIO subsystem in MAINTAINERS. Any changes to the IIO API documentation should be reviewed IIO folks. Signed-off-by: David Lechner Reviewed-by: Stepan Ionichev Signed-off-by: Jonathan Cameron --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 640192835bd3..1533337900da 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12503,6 +12503,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git F: Documentation/ABI/testing/configfs-iio* F: Documentation/ABI/testing/sysfs-bus-iio* F: Documentation/devicetree/bindings/iio/ +F: Documentation/driver-api/iio/ F: Documentation/iio/ F: drivers/iio/ F: drivers/staging/iio/ From 6bce70d0a9bc907cedb12f498ebc4cd5f7ac7cee Mon Sep 17 00:00:00 2001 From: David Lechner Date: Sun, 17 May 2026 12:00:59 -0500 Subject: [PATCH 195/266] docs: iio: triggered-buffers: use new helpers in example Update the "typical" triggered buffer example to use various new helpers that have been added in the last year or so. This reflects current expectations of how similar code should be written. Also zero-initialize the buffer so we don't leak stack data. And fix a missing semicolon while we're at it. Signed-off-by: David Lechner Reviewed-by: Stepan Ionichev Signed-off-by: Jonathan Cameron --- Documentation/driver-api/iio/triggered-buffers.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/driver-api/iio/triggered-buffers.rst b/Documentation/driver-api/iio/triggered-buffers.rst index 23b82357eba6..23762b06fdc6 100644 --- a/Documentation/driver-api/iio/triggered-buffers.rst +++ b/Documentation/driver-api/iio/triggered-buffers.rst @@ -29,14 +29,14 @@ A typical triggered buffer setup looks like this:: irqreturn_t sensor_trigger_handler(int irq, void *p) { - u16 buf[8]; + IIO_DECLARE_BUFFER_WITH_TS(u16, buf, 3) = { }; int i = 0; /* read data for each active channel */ - for_each_set_bit(bit, active_scan_mask, masklength) - buf[i++] = sensor_get_data(bit) + iio_for_each_active_channel(indio_dev, bit) + buf[i++] = sensor_get_data(bit); - iio_push_to_buffers_with_timestamp(indio_dev, buf, timestamp); + iio_push_to_buffers_with_ts(indio_dev, buf, sizeof(buf), timestamp); iio_trigger_notify_done(trigger); return IRQ_HANDLED; From 97caa67b1c68674cef84b43cba0bd7973b401240 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Sun, 17 May 2026 12:29:35 -0500 Subject: [PATCH 196/266] iio: common: ssp: remove SSP_CHAN_TIMESTAMP() macro Remove the SSP_CHAN_TIMESTAMP() macro and replace users with the IIO_CHAN_SOFT_TIMESTAMP() macro. The SSP_CHAN_TIMESTAMP() macro is identical to the IIO_CHAN_SOFT_TIMESTAMP() macro, so we don't need a separate macro for it. Signed-off-by: David Lechner Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/accel/ssp_accel_sensor.c | 2 +- drivers/iio/common/ssp_sensors/ssp_iio_sensor.h | 12 ------------ drivers/iio/gyro/ssp_gyro_sensor.c | 2 +- 3 files changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/iio/accel/ssp_accel_sensor.c b/drivers/iio/accel/ssp_accel_sensor.c index 3e572af2ec03..d1687cdd33ea 100644 --- a/drivers/iio/accel/ssp_accel_sensor.c +++ b/drivers/iio/accel/ssp_accel_sensor.c @@ -76,7 +76,7 @@ static const struct iio_chan_spec ssp_acc_channels[] = { SSP_CHANNEL_AG(IIO_ACCEL, IIO_MOD_X, SSP_CHANNEL_SCAN_INDEX_X), SSP_CHANNEL_AG(IIO_ACCEL, IIO_MOD_Y, SSP_CHANNEL_SCAN_INDEX_Y), SSP_CHANNEL_AG(IIO_ACCEL, IIO_MOD_Z, SSP_CHANNEL_SCAN_INDEX_Z), - SSP_CHAN_TIMESTAMP(SSP_CHANNEL_SCAN_INDEX_TIME), + IIO_CHAN_SOFT_TIMESTAMP(SSP_CHANNEL_SCAN_INDEX_TIME), }; static int ssp_process_accel_data(struct iio_dev *indio_dev, void *buf, diff --git a/drivers/iio/common/ssp_sensors/ssp_iio_sensor.h b/drivers/iio/common/ssp_sensors/ssp_iio_sensor.h index 4528ab55eb68..05fcad61c848 100644 --- a/drivers/iio/common/ssp_sensors/ssp_iio_sensor.h +++ b/drivers/iio/common/ssp_sensors/ssp_iio_sensor.h @@ -18,18 +18,6 @@ },\ } -/* It is defined here as it is a mixed timestamp */ -#define SSP_CHAN_TIMESTAMP(_si) { \ - .type = IIO_TIMESTAMP, \ - .channel = -1, \ - .scan_index = _si, \ - .scan_type = { \ - .sign = 's', \ - .realbits = 64, \ - .storagebits = 64, \ - }, \ -} - #define SSP_MS_PER_S 1000 #define SSP_INVERTED_SCALING_FACTOR 1000000U diff --git a/drivers/iio/gyro/ssp_gyro_sensor.c b/drivers/iio/gyro/ssp_gyro_sensor.c index d9b41cf8d799..1acbbc1eeec3 100644 --- a/drivers/iio/gyro/ssp_gyro_sensor.c +++ b/drivers/iio/gyro/ssp_gyro_sensor.c @@ -76,7 +76,7 @@ static const struct iio_chan_spec ssp_gyro_channels[] = { SSP_CHANNEL_AG(IIO_ANGL_VEL, IIO_MOD_X, SSP_CHANNEL_SCAN_INDEX_X), SSP_CHANNEL_AG(IIO_ANGL_VEL, IIO_MOD_Y, SSP_CHANNEL_SCAN_INDEX_Y), SSP_CHANNEL_AG(IIO_ANGL_VEL, IIO_MOD_Z, SSP_CHANNEL_SCAN_INDEX_Z), - SSP_CHAN_TIMESTAMP(SSP_CHANNEL_SCAN_INDEX_TIME), + IIO_CHAN_SOFT_TIMESTAMP(SSP_CHANNEL_SCAN_INDEX_TIME), }; static int ssp_process_gyro_data(struct iio_dev *indio_dev, void *buf, From e50856dc41e8353237863d618a55d7496072c325 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Tue, 19 May 2026 10:13:04 +0200 Subject: [PATCH 197/266] iio: accel: bmc150: Explicitly set .driver_data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is one id entry that has an explicit assignment to .driver_data. To make the intention clearer, assign BOSCH_UNKNOWN (which is also 0) for all previously ids that had .driver_data = 0 implicitly before. While touching all entries in this array, convert to named initializers. Signed-off-by: Uwe Kleine-König (The Capable Hub) Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bmc150-accel-i2c.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/iio/accel/bmc150-accel-i2c.c b/drivers/iio/accel/bmc150-accel-i2c.c index b4604f441553..3315172742d0 100644 --- a/drivers/iio/accel/bmc150-accel-i2c.c +++ b/drivers/iio/accel/bmc150-accel-i2c.c @@ -245,16 +245,16 @@ static const struct acpi_device_id bmc150_accel_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match); static const struct i2c_device_id bmc150_accel_id[] = { - {"bma222"}, - {"bma222e"}, - {"bma250e"}, - {"bma253"}, - {"bma254"}, - {"bma255"}, - {"bma280"}, - {"bmc150_accel"}, - {"bmc156_accel", BOSCH_BMC156}, - {"bmi055_accel"}, + { .name = "bma222", .driver_data = BOSCH_UNKNOWN }, + { .name = "bma222e", .driver_data = BOSCH_UNKNOWN }, + { .name = "bma250e", .driver_data = BOSCH_UNKNOWN }, + { .name = "bma253", .driver_data = BOSCH_UNKNOWN }, + { .name = "bma254", .driver_data = BOSCH_UNKNOWN }, + { .name = "bma255", .driver_data = BOSCH_UNKNOWN }, + { .name = "bma280", .driver_data = BOSCH_UNKNOWN }, + { .name = "bmc150_accel", .driver_data = BOSCH_UNKNOWN }, + { .name = "bmc156_accel", .driver_data = BOSCH_BMC156 }, + { .name = "bmi055_accel", .driver_data = BOSCH_UNKNOWN }, { } }; From abd69c09a73bb9a74f899526b4c7a60169dcbb27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Tue, 19 May 2026 10:13:05 +0200 Subject: [PATCH 198/266] iio: adc: ad7091r5: Simplify driver_data handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver only supports a single device type. So the return value of i2c_get_match_data() is already known and can just be hardcoded without type casting. While at it also remove the unused .data of the single of_device_id entry. Signed-off-by: Uwe Kleine-König (The Capable Hub) Reviewed-by: Marcelo Schmitt Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7091r5.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/iio/adc/ad7091r5.c b/drivers/iio/adc/ad7091r5.c index bd4877268689..7bf7d538abd9 100644 --- a/drivers/iio/adc/ad7091r5.c +++ b/drivers/iio/adc/ad7091r5.c @@ -101,23 +101,17 @@ static const struct ad7091r_init_info ad7091r5_init_info = { static int ad7091r5_i2c_probe(struct i2c_client *i2c) { - const struct ad7091r_init_info *init_info; - - init_info = i2c_get_match_data(i2c); - if (!init_info) - return -EINVAL; - - return ad7091r_probe(&i2c->dev, init_info, i2c->irq); + return ad7091r_probe(&i2c->dev, &ad7091r5_init_info, i2c->irq); } static const struct of_device_id ad7091r5_dt_ids[] = { - { .compatible = "adi,ad7091r5", .data = &ad7091r5_init_info }, + { .compatible = "adi,ad7091r5" }, { } }; MODULE_DEVICE_TABLE(of, ad7091r5_dt_ids); static const struct i2c_device_id ad7091r5_i2c_ids[] = { - { "ad7091r5", (kernel_ulong_t)&ad7091r5_init_info }, + { .name = "ad7091r5" }, { } }; MODULE_DEVICE_TABLE(i2c, ad7091r5_i2c_ids); From a7ee2d07013bd369285a0b87f219bd81a1f103ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Tue, 19 May 2026 10:13:06 +0200 Subject: [PATCH 199/266] iio: dac: max5821: Drop unused i2c driver data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .driver_data member of the single i2c_device_id array entry is unused in the driver. Drop it and also the then unused definition. While at it, convert the i2c_device_id array to a better readable named initializer. Signed-off-by: Uwe Kleine-König (The Capable Hub) Signed-off-by: Jonathan Cameron --- drivers/iio/dac/max5821.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/iio/dac/max5821.c b/drivers/iio/dac/max5821.c index e7e29359f8fe..f3ebbdff5487 100644 --- a/drivers/iio/dac/max5821.c +++ b/drivers/iio/dac/max5821.c @@ -26,10 +26,6 @@ #define MAX5821_EXTENDED_DAC_A 0x04 #define MAX5821_EXTENDED_DAC_B 0x08 -enum max5821_device_ids { - ID_MAX5821, -}; - struct max5821_data { struct i2c_client *client; unsigned short vref_mv; @@ -332,7 +328,7 @@ static int max5821_probe(struct i2c_client *client) } static const struct i2c_device_id max5821_id[] = { - { "max5821", ID_MAX5821 }, + { .name = "max5821" }, { } }; MODULE_DEVICE_TABLE(i2c, max5821_id); From eb3fdf3d9bcc555a535dfa771129ad048abf042e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Tue, 19 May 2026 10:13:07 +0200 Subject: [PATCH 200/266] iio: proximity: sx9324: Drop unused driver data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The value assigned in the three device_id entries (ACPI, of and i2c) are unused, directly in the driver and also the sx_common support lib. Drop them and while touching these arrays, convert to named initializers. Signed-off-by: Uwe Kleine-König (The Capable Hub) Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/sx9324.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iio/proximity/sx9324.c b/drivers/iio/proximity/sx9324.c index f61eff39751d..36c45d101336 100644 --- a/drivers/iio/proximity/sx9324.c +++ b/drivers/iio/proximity/sx9324.c @@ -1123,19 +1123,19 @@ static int sx9324_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(sx9324_pm_ops, sx9324_suspend, sx9324_resume); static const struct acpi_device_id sx9324_acpi_match[] = { - { "STH9324", SX9324_WHOAMI_VALUE }, + { .id = "STH9324" }, { } }; MODULE_DEVICE_TABLE(acpi, sx9324_acpi_match); static const struct of_device_id sx9324_of_match[] = { - { .compatible = "semtech,sx9324", (void *)SX9324_WHOAMI_VALUE }, + { .compatible = "semtech,sx9324" }, { } }; MODULE_DEVICE_TABLE(of, sx9324_of_match); static const struct i2c_device_id sx9324_id[] = { - { "sx9324", SX9324_WHOAMI_VALUE }, + { .name = "sx9324" }, { } }; MODULE_DEVICE_TABLE(i2c, sx9324_id); From ab233e4f9a9578faa30c1870f5436591d86c37b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Tue, 19 May 2026 10:13:08 +0200 Subject: [PATCH 201/266] iio: proximity: sx9360: Drop unused driver data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The value assigned in the three device_id entries (ACPI, of and i2c) are unused, directly in the driver and also the sx_common support lib. Drop them and while touching these arrays, convert to named initializers. Signed-off-by: Uwe Kleine-König (The Capable Hub) Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/sx9360.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/iio/proximity/sx9360.c b/drivers/iio/proximity/sx9360.c index 4448988d4e7e..4b9498022b22 100644 --- a/drivers/iio/proximity/sx9360.c +++ b/drivers/iio/proximity/sx9360.c @@ -832,20 +832,20 @@ static int sx9360_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(sx9360_pm_ops, sx9360_suspend, sx9360_resume); static const struct acpi_device_id sx9360_acpi_match[] = { - { "STH9360", SX9360_WHOAMI_VALUE }, - { "SAMM0208", SX9360_WHOAMI_VALUE }, + { .id = "STH9360" }, + { .id = "SAMM0208" }, { } }; MODULE_DEVICE_TABLE(acpi, sx9360_acpi_match); static const struct of_device_id sx9360_of_match[] = { - { .compatible = "semtech,sx9360", (void *)SX9360_WHOAMI_VALUE }, + { .compatible = "semtech,sx9360" }, { } }; MODULE_DEVICE_TABLE(of, sx9360_of_match); static const struct i2c_device_id sx9360_id[] = { - {"sx9360", SX9360_WHOAMI_VALUE }, + { .name = "sx9360" }, { } }; MODULE_DEVICE_TABLE(i2c, sx9360_id); From c4657858d43ada628e2f4eaf591c43efb3649933 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Tue, 19 May 2026 16:06:20 +0200 Subject: [PATCH 202/266] staging: iio: Use named initializers for struct i2c_device_id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While being less compact, using named initializers allows to more easily see which members of the structs are assigned which value without having to lookup the declaration of the struct. And it's also more robust against changes to the struct definition. This patch doesn't modify the compiled arrays, only their representation in source form benefits. The former was confirmed with x86 and arm64 builds. Signed-off-by: Uwe Kleine-König (The Capable Hub) Reviewed-by: Stepan Ionichev Reviewed-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/staging/iio/addac/adt7316-i2c.c | 12 ++++++------ drivers/staging/iio/impedance-analyzer/ad5933.c | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/staging/iio/addac/adt7316-i2c.c b/drivers/staging/iio/addac/adt7316-i2c.c index 3bdaee925dee..98f2e23c6a4b 100644 --- a/drivers/staging/iio/addac/adt7316-i2c.c +++ b/drivers/staging/iio/addac/adt7316-i2c.c @@ -109,12 +109,12 @@ static int adt7316_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id adt7316_i2c_id[] = { - { "adt7316" }, - { "adt7317" }, - { "adt7318" }, - { "adt7516" }, - { "adt7517" }, - { "adt7519" }, + { .name = "adt7316" }, + { .name = "adt7317" }, + { .name = "adt7318" }, + { .name = "adt7516" }, + { .name = "adt7517" }, + { .name = "adt7519" }, { } }; diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c index dde2ec9d1f6a..798e62bae29b 100644 --- a/drivers/staging/iio/impedance-analyzer/ad5933.c +++ b/drivers/staging/iio/impedance-analyzer/ad5933.c @@ -726,8 +726,8 @@ static int ad5933_probe(struct i2c_client *client) } static const struct i2c_device_id ad5933_id[] = { - { "ad5933" }, - { "ad5934" }, + { .name = "ad5933" }, + { .name = "ad5934" }, { } }; From f68afce8e8a74f52a879f56f607dfedf552b5ab5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Tue, 19 May 2026 10:13:09 +0200 Subject: [PATCH 203/266] iio: Initialize i2c_device_id arrays using member names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While being less compact, using named initializers allows to more easily see which members of the structs are assigned which value without having to lookup the declaration of the struct. And it's also more robust against changes to the struct definition. The mentioned robustness is relevant for a planned change to struct i2c_device_id that replaces .driver_data by an anonymous union. This patch doesn't modify the compiled arrays, only their representation in source form benefits. The former was confirmed with x86 and arm64 builds. Signed-off-by: Uwe Kleine-König (The Capable Hub) Reviewed-by: Siratul Islam Reviewed-by: Matti Vaittinen Signed-off-by: Jonathan Cameron --- drivers/iio/accel/adxl345_i2c.c | 4 +- drivers/iio/accel/adxl355_i2c.c | 4 +- drivers/iio/accel/adxl367_i2c.c | 2 +- drivers/iio/accel/adxl372_i2c.c | 4 +- drivers/iio/accel/adxl380_i2c.c | 8 +- drivers/iio/accel/bma180.c | 10 +- drivers/iio/accel/bma220_i2c.c | 2 +- drivers/iio/accel/bma400_i2c.c | 2 +- drivers/iio/accel/bmi088-accel-i2c.c | 6 +- drivers/iio/accel/da280.c | 6 +- drivers/iio/accel/da311.c | 2 +- drivers/iio/accel/dmard06.c | 6 +- drivers/iio/accel/dmard09.c | 2 +- drivers/iio/accel/dmard10.c | 2 +- drivers/iio/accel/fxls8962af-i2c.c | 8 +- drivers/iio/accel/kxcjk-1013.c | 10 +- drivers/iio/accel/kxsd9-i2c.c | 2 +- drivers/iio/accel/mc3230.c | 4 +- drivers/iio/accel/mma7455_i2c.c | 4 +- drivers/iio/accel/mma7660.c | 2 +- drivers/iio/accel/mma8452.c | 12 +-- drivers/iio/accel/mma9551.c | 2 +- drivers/iio/accel/mma9553.c | 2 +- drivers/iio/accel/mxc4005.c | 4 +- drivers/iio/accel/mxc6255.c | 4 +- drivers/iio/accel/st_accel_i2c.c | 52 +++++----- drivers/iio/accel/stk8312.c | 4 +- drivers/iio/accel/stk8ba50.c | 2 +- drivers/iio/adc/ad7291.c | 2 +- drivers/iio/adc/ad799x.c | 16 ++-- drivers/iio/adc/gehc-pmc-adc.c | 2 +- drivers/iio/adc/ina2xx-adc.c | 12 +-- drivers/iio/adc/ltc2309.c | 4 +- drivers/iio/adc/ltc2471.c | 4 +- drivers/iio/adc/ltc2485.c | 2 +- drivers/iio/adc/ltc2497.c | 4 +- drivers/iio/adc/max34408.c | 4 +- drivers/iio/adc/mcp3422.c | 16 ++-- drivers/iio/adc/nau7802.c | 2 +- drivers/iio/adc/rohm-bd79124.c | 2 +- drivers/iio/adc/ti-adc081c.c | 6 +- drivers/iio/adc/ti-ads1015.c | 6 +- drivers/iio/adc/ti-ads1100.c | 4 +- drivers/iio/adc/ti-ads1119.c | 2 +- drivers/iio/adc/ti-ads7138.c | 4 +- drivers/iio/adc/ti-ads7924.c | 2 +- drivers/iio/cdc/ad7150.c | 6 +- drivers/iio/cdc/ad7746.c | 6 +- drivers/iio/chemical/ags02ma.c | 2 +- drivers/iio/chemical/ams-iaq-core.c | 2 +- drivers/iio/chemical/atlas-ezo-sensor.c | 6 +- drivers/iio/chemical/atlas-sensor.c | 10 +- drivers/iio/chemical/bme680_i2c.c | 2 +- drivers/iio/chemical/ccs811.c | 4 +- drivers/iio/chemical/ens160_i2c.c | 2 +- drivers/iio/chemical/sgp30.c | 4 +- drivers/iio/chemical/sgp40.c | 2 +- drivers/iio/chemical/sps30_i2c.c | 2 +- drivers/iio/chemical/vz89x.c | 4 +- drivers/iio/dac/ad5064.c | 94 +++++++++---------- drivers/iio/dac/ad5380.c | 32 +++---- drivers/iio/dac/ad5446-i2c.c | 12 +-- drivers/iio/dac/ad5696-i2c.c | 32 +++---- drivers/iio/dac/ds4424.c | 8 +- drivers/iio/dac/m62332.c | 2 +- drivers/iio/dac/max517.c | 10 +- drivers/iio/dac/mcp4725.c | 4 +- drivers/iio/dac/mcp4728.c | 2 +- drivers/iio/dac/mcp47feb02.c | 48 +++++----- drivers/iio/dac/ti-dac5571.c | 22 ++--- drivers/iio/gyro/bmg160_i2c.c | 6 +- drivers/iio/gyro/fxas21002c_i2c.c | 2 +- drivers/iio/gyro/itg3200_core.c | 2 +- drivers/iio/gyro/mpu3050-i2c.c | 2 +- drivers/iio/gyro/st_gyro_i2c.c | 18 ++-- drivers/iio/health/afe4404.c | 2 +- drivers/iio/health/max30100.c | 2 +- drivers/iio/health/max30102.c | 6 +- drivers/iio/humidity/am2315.c | 2 +- drivers/iio/humidity/ens210.c | 12 +-- drivers/iio/humidity/hdc100x.c | 12 +-- drivers/iio/humidity/hdc2010.c | 4 +- drivers/iio/humidity/hdc3020.c | 6 +- drivers/iio/humidity/hts221_i2c.c | 2 +- drivers/iio/humidity/htu21.c | 4 +- drivers/iio/humidity/si7005.c | 4 +- drivers/iio/humidity/si7020.c | 4 +- drivers/iio/imu/bmi160/bmi160_i2c.c | 4 +- drivers/iio/imu/bmi270/bmi270_i2c.c | 4 +- drivers/iio/imu/bmi323/bmi323_i2c.c | 2 +- drivers/iio/imu/bno055/bno055_i2c.c | 2 +- drivers/iio/imu/fxos8700_i2c.c | 2 +- .../iio/imu/inv_icm42600/inv_icm42600_i2c.c | 14 +-- .../iio/imu/inv_icm45600/inv_icm45600_i2c.c | 16 ++-- drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c | 36 +++---- drivers/iio/imu/kmx61.c | 2 +- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c | 48 +++++----- drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c | 4 +- drivers/iio/light/adjd_s311.c | 2 +- drivers/iio/light/adux1020.c | 2 +- drivers/iio/light/al3000a.c | 2 +- drivers/iio/light/al3010.c | 2 +- drivers/iio/light/al3320a.c | 2 +- drivers/iio/light/apds9300.c | 2 +- drivers/iio/light/apds9960.c | 2 +- drivers/iio/light/as73211.c | 4 +- drivers/iio/light/bh1745.c | 2 +- drivers/iio/light/bh1750.c | 10 +- drivers/iio/light/bh1780.c | 2 +- drivers/iio/light/cm3232.c | 2 +- drivers/iio/light/cm3323.c | 2 +- drivers/iio/light/cm36651.c | 2 +- drivers/iio/light/gp2ap002.c | 2 +- drivers/iio/light/gp2ap020a00f.c | 2 +- drivers/iio/light/isl29018.c | 6 +- drivers/iio/light/isl29028.c | 4 +- drivers/iio/light/isl29125.c | 2 +- drivers/iio/light/isl76682.c | 2 +- drivers/iio/light/jsa1212.c | 2 +- drivers/iio/light/ltr390.c | 2 +- drivers/iio/light/ltr501.c | 8 +- drivers/iio/light/ltrf216a.c | 4 +- drivers/iio/light/lv0104cs.c | 2 +- drivers/iio/light/max44000.c | 2 +- drivers/iio/light/max44009.c | 2 +- drivers/iio/light/noa1305.c | 2 +- drivers/iio/light/opt3001.c | 4 +- drivers/iio/light/opt4001.c | 4 +- drivers/iio/light/opt4060.c | 2 +- drivers/iio/light/pa12203001.c | 2 +- drivers/iio/light/rpr0521.c | 2 +- drivers/iio/light/si1133.c | 2 +- drivers/iio/light/si1145.c | 14 +-- drivers/iio/light/st_uvis25_i2c.c | 2 +- drivers/iio/light/stk3310.c | 8 +- drivers/iio/light/tcs3414.c | 2 +- drivers/iio/light/tcs3472.c | 2 +- drivers/iio/light/tsl2772.c | 26 ++--- drivers/iio/light/tsl4531.c | 2 +- drivers/iio/light/us5182d.c | 2 +- drivers/iio/light/vcnl4000.c | 14 +-- drivers/iio/light/vcnl4035.c | 2 +- drivers/iio/light/veml3235.c | 2 +- drivers/iio/light/veml6030.c | 6 +- drivers/iio/light/veml6040.c | 2 +- drivers/iio/light/veml6046x00.c | 2 +- drivers/iio/light/veml6070.c | 2 +- drivers/iio/light/veml6075.c | 2 +- drivers/iio/light/vl6180.c | 2 +- drivers/iio/light/zopt2201.c | 2 +- drivers/iio/magnetometer/af8133j.c | 2 +- drivers/iio/magnetometer/ak8974.c | 8 +- drivers/iio/magnetometer/ak8975.c | 14 +-- drivers/iio/magnetometer/bmc150_magn_i2c.c | 6 +- drivers/iio/magnetometer/hmc5843_i2c.c | 8 +- drivers/iio/magnetometer/mag3110.c | 2 +- drivers/iio/magnetometer/mmc35240.c | 2 +- drivers/iio/magnetometer/mmc5633.c | 4 +- drivers/iio/magnetometer/si7210.c | 2 +- drivers/iio/magnetometer/st_magn_i2c.c | 18 ++-- drivers/iio/magnetometer/tlv493d.c | 2 +- drivers/iio/magnetometer/tmag5273.c | 2 +- drivers/iio/magnetometer/yamaha-yas530.c | 8 +- drivers/iio/potentiometer/ad5272.c | 10 +- drivers/iio/potentiometer/ds1803.c | 8 +- drivers/iio/potentiometer/tpl0102.c | 8 +- drivers/iio/potentiostat/lmp91000.c | 4 +- drivers/iio/pressure/abp060mg.c | 90 +++++++++++------- drivers/iio/pressure/abp2030pa_i2c.c | 2 +- drivers/iio/pressure/adp810.c | 2 +- drivers/iio/pressure/bmp280-i2c.c | 12 +-- drivers/iio/pressure/dlhl60d.c | 4 +- drivers/iio/pressure/dps310.c | 2 +- drivers/iio/pressure/hp03.c | 2 +- drivers/iio/pressure/hp206c.c | 2 +- drivers/iio/pressure/hsc030pa_i2c.c | 2 +- drivers/iio/pressure/icp10100.c | 2 +- drivers/iio/pressure/mpl115_i2c.c | 2 +- drivers/iio/pressure/mpl3115.c | 2 +- drivers/iio/pressure/mprls0025pa_i2c.c | 2 +- drivers/iio/pressure/ms5611_i2c.c | 4 +- drivers/iio/pressure/ms5637.c | 8 +- drivers/iio/pressure/rohm-bm1390.c | 2 +- drivers/iio/pressure/sdp500.c | 2 +- drivers/iio/pressure/st_pressure_i2c.c | 16 ++-- drivers/iio/pressure/t5403.c | 2 +- drivers/iio/pressure/zpa2326_i2c.c | 2 +- drivers/iio/proximity/aw96103.c | 4 +- drivers/iio/proximity/hx9023s.c | 2 +- drivers/iio/proximity/isl29501.c | 2 +- drivers/iio/proximity/mb1232.c | 14 +-- .../iio/proximity/pulsedlight-lidar-lite-v2.c | 4 +- drivers/iio/proximity/rfd77402.c | 2 +- drivers/iio/proximity/srf08.c | 6 +- drivers/iio/proximity/sx9310.c | 4 +- drivers/iio/proximity/sx9500.c | 2 +- drivers/iio/proximity/vl53l0x-i2c.c | 2 +- drivers/iio/proximity/vl53l1x-i2c.c | 2 +- drivers/iio/temperature/max30208.c | 2 +- drivers/iio/temperature/mcp9600.c | 4 +- drivers/iio/temperature/mlx90614.c | 4 +- drivers/iio/temperature/mlx90632.c | 2 +- drivers/iio/temperature/mlx90635.c | 2 +- drivers/iio/temperature/tmp006.c | 2 +- drivers/iio/temperature/tmp007.c | 2 +- drivers/iio/temperature/tmp117.c | 4 +- drivers/iio/temperature/tsys01.c | 2 +- drivers/iio/temperature/tsys02d.c | 2 +- 208 files changed, 680 insertions(+), 658 deletions(-) diff --git a/drivers/iio/accel/adxl345_i2c.c b/drivers/iio/accel/adxl345_i2c.c index af84c0043c6c..511fb610436c 100644 --- a/drivers/iio/accel/adxl345_i2c.c +++ b/drivers/iio/accel/adxl345_i2c.c @@ -43,8 +43,8 @@ static const struct adxl345_chip_info adxl375_i2c_info = { }; static const struct i2c_device_id adxl345_i2c_id[] = { - { "adxl345", (kernel_ulong_t)&adxl345_i2c_info }, - { "adxl375", (kernel_ulong_t)&adxl375_i2c_info }, + { .name = "adxl345", .driver_data = (kernel_ulong_t)&adxl345_i2c_info }, + { .name = "adxl375", .driver_data = (kernel_ulong_t)&adxl375_i2c_info }, { } }; MODULE_DEVICE_TABLE(i2c, adxl345_i2c_id); diff --git a/drivers/iio/accel/adxl355_i2c.c b/drivers/iio/accel/adxl355_i2c.c index 19490a6e1f35..0b6b016bd358 100644 --- a/drivers/iio/accel/adxl355_i2c.c +++ b/drivers/iio/accel/adxl355_i2c.c @@ -38,8 +38,8 @@ static int adxl355_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id adxl355_i2c_id[] = { - { "adxl355", (kernel_ulong_t)&adxl35x_chip_info[ADXL355] }, - { "adxl359", (kernel_ulong_t)&adxl35x_chip_info[ADXL359] }, + { .name = "adxl355", .driver_data = (kernel_ulong_t)&adxl35x_chip_info[ADXL355] }, + { .name = "adxl359", .driver_data = (kernel_ulong_t)&adxl35x_chip_info[ADXL359] }, { } }; MODULE_DEVICE_TABLE(i2c, adxl355_i2c_id); diff --git a/drivers/iio/accel/adxl367_i2c.c b/drivers/iio/accel/adxl367_i2c.c index 1c7d2eb054a2..fb50ded68bae 100644 --- a/drivers/iio/accel/adxl367_i2c.c +++ b/drivers/iio/accel/adxl367_i2c.c @@ -61,7 +61,7 @@ static int adxl367_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id adxl367_i2c_id[] = { - { "adxl367" }, + { .name = "adxl367" }, { } }; MODULE_DEVICE_TABLE(i2c, adxl367_i2c_id); diff --git a/drivers/iio/accel/adxl372_i2c.c b/drivers/iio/accel/adxl372_i2c.c index ca2cabf24938..ddb125075778 100644 --- a/drivers/iio/accel/adxl372_i2c.c +++ b/drivers/iio/accel/adxl372_i2c.c @@ -44,8 +44,8 @@ static int adxl372_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id adxl372_i2c_id[] = { - { "adxl371", (kernel_ulong_t)&adxl371_chip_info }, - { "adxl372", (kernel_ulong_t)&adxl372_chip_info }, + { .name = "adxl371", .driver_data = (kernel_ulong_t)&adxl371_chip_info }, + { .name = "adxl372", .driver_data = (kernel_ulong_t)&adxl372_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, adxl372_i2c_id); diff --git a/drivers/iio/accel/adxl380_i2c.c b/drivers/iio/accel/adxl380_i2c.c index bd8782d08c7d..367a29298047 100644 --- a/drivers/iio/accel/adxl380_i2c.c +++ b/drivers/iio/accel/adxl380_i2c.c @@ -33,10 +33,10 @@ static int adxl380_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id adxl380_i2c_id[] = { - { "adxl318", (kernel_ulong_t)&adxl318_chip_info }, - { "adxl319", (kernel_ulong_t)&adxl319_chip_info }, - { "adxl380", (kernel_ulong_t)&adxl380_chip_info }, - { "adxl382", (kernel_ulong_t)&adxl382_chip_info }, + { .name = "adxl318", .driver_data = (kernel_ulong_t)&adxl318_chip_info }, + { .name = "adxl319", .driver_data = (kernel_ulong_t)&adxl319_chip_info }, + { .name = "adxl380", .driver_data = (kernel_ulong_t)&adxl380_chip_info }, + { .name = "adxl382", .driver_data = (kernel_ulong_t)&adxl382_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, adxl380_i2c_id); diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index 7bc6761f5135..e643bc73eefe 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -1083,11 +1083,11 @@ static int bma180_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(bma180_pm_ops, bma180_suspend, bma180_resume); static const struct i2c_device_id bma180_ids[] = { - { "bma023", (kernel_ulong_t)&bma180_part_info[BMA023] }, - { "bma150", (kernel_ulong_t)&bma180_part_info[BMA150] }, - { "bma180", (kernel_ulong_t)&bma180_part_info[BMA180] }, - { "bma250", (kernel_ulong_t)&bma180_part_info[BMA250] }, - { "smb380", (kernel_ulong_t)&bma180_part_info[BMA150] }, + { .name = "bma023", .driver_data = (kernel_ulong_t)&bma180_part_info[BMA023] }, + { .name = "bma150", .driver_data = (kernel_ulong_t)&bma180_part_info[BMA150] }, + { .name = "bma180", .driver_data = (kernel_ulong_t)&bma180_part_info[BMA180] }, + { .name = "bma250", .driver_data = (kernel_ulong_t)&bma180_part_info[BMA250] }, + { .name = "smb380", .driver_data = (kernel_ulong_t)&bma180_part_info[BMA150] }, { } }; diff --git a/drivers/iio/accel/bma220_i2c.c b/drivers/iio/accel/bma220_i2c.c index 8b6f8e305c8c..b058e97bc6a6 100644 --- a/drivers/iio/accel/bma220_i2c.c +++ b/drivers/iio/accel/bma220_i2c.c @@ -47,7 +47,7 @@ static const struct of_device_id bma220_i2c_match[] = { MODULE_DEVICE_TABLE(of, bma220_i2c_match); static const struct i2c_device_id bma220_i2c_id[] = { - { "bma220" }, + { .name = "bma220" }, { } }; MODULE_DEVICE_TABLE(i2c, bma220_i2c_id); diff --git a/drivers/iio/accel/bma400_i2c.c b/drivers/iio/accel/bma400_i2c.c index 24a390c3ae66..23d394c5a791 100644 --- a/drivers/iio/accel/bma400_i2c.c +++ b/drivers/iio/accel/bma400_i2c.c @@ -28,7 +28,7 @@ static int bma400_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id bma400_i2c_ids[] = { - { "bma400" }, + { .name = "bma400" }, { } }; MODULE_DEVICE_TABLE(i2c, bma400_i2c_ids); diff --git a/drivers/iio/accel/bmi088-accel-i2c.c b/drivers/iio/accel/bmi088-accel-i2c.c index 310f863029bb..d9468b1c5aee 100644 --- a/drivers/iio/accel/bmi088-accel-i2c.c +++ b/drivers/iio/accel/bmi088-accel-i2c.c @@ -45,9 +45,9 @@ static const struct of_device_id bmi088_of_match[] = { MODULE_DEVICE_TABLE(of, bmi088_of_match); static const struct i2c_device_id bmi088_accel_id[] = { - { "bmi085-accel", BOSCH_BMI085 }, - { "bmi088-accel", BOSCH_BMI088 }, - { "bmi090l-accel", BOSCH_BMI090L }, + { .name = "bmi085-accel", .driver_data = BOSCH_BMI085 }, + { .name = "bmi088-accel", .driver_data = BOSCH_BMI088 }, + { .name = "bmi090l-accel", .driver_data = BOSCH_BMI090L }, { } }; MODULE_DEVICE_TABLE(i2c, bmi088_accel_id); diff --git a/drivers/iio/accel/da280.c b/drivers/iio/accel/da280.c index c2dd123b9021..15acbe1c2cbd 100644 --- a/drivers/iio/accel/da280.c +++ b/drivers/iio/accel/da280.c @@ -162,9 +162,9 @@ static const struct acpi_device_id da280_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, da280_acpi_match); static const struct i2c_device_id da280_i2c_id[] = { - { "da217", (kernel_ulong_t)&da217_match_data }, - { "da226", (kernel_ulong_t)&da226_match_data }, - { "da280", (kernel_ulong_t)&da280_match_data }, + { .name = "da217", .driver_data = (kernel_ulong_t)&da217_match_data }, + { .name = "da226", .driver_data = (kernel_ulong_t)&da226_match_data }, + { .name = "da280", .driver_data = (kernel_ulong_t)&da280_match_data }, { } }; MODULE_DEVICE_TABLE(i2c, da280_i2c_id); diff --git a/drivers/iio/accel/da311.c b/drivers/iio/accel/da311.c index e1df7b009d89..dcb69c8eaf09 100644 --- a/drivers/iio/accel/da311.c +++ b/drivers/iio/accel/da311.c @@ -268,7 +268,7 @@ static int da311_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(da311_pm_ops, da311_suspend, da311_resume); static const struct i2c_device_id da311_i2c_id[] = { - { "da311" }, + { .name = "da311" }, { } }; MODULE_DEVICE_TABLE(i2c, da311_i2c_id); diff --git a/drivers/iio/accel/dmard06.c b/drivers/iio/accel/dmard06.c index 33f225d73e7b..2957bf55d110 100644 --- a/drivers/iio/accel/dmard06.c +++ b/drivers/iio/accel/dmard06.c @@ -199,9 +199,9 @@ static DEFINE_SIMPLE_DEV_PM_OPS(dmard06_pm_ops, dmard06_suspend, dmard06_resume); static const struct i2c_device_id dmard06_id[] = { - { "dmard05" }, - { "dmard06" }, - { "dmard07" }, + { .name = "dmard05" }, + { .name = "dmard06" }, + { .name = "dmard07" }, { } }; MODULE_DEVICE_TABLE(i2c, dmard06_id); diff --git a/drivers/iio/accel/dmard09.c b/drivers/iio/accel/dmard09.c index d9290e3b9c46..fe35a1270786 100644 --- a/drivers/iio/accel/dmard09.c +++ b/drivers/iio/accel/dmard09.c @@ -123,7 +123,7 @@ static int dmard09_probe(struct i2c_client *client) } static const struct i2c_device_id dmard09_id[] = { - { "dmard09" }, + { .name = "dmard09" }, { } }; diff --git a/drivers/iio/accel/dmard10.c b/drivers/iio/accel/dmard10.c index 575e8510e1bd..8ba00fd57901 100644 --- a/drivers/iio/accel/dmard10.c +++ b/drivers/iio/accel/dmard10.c @@ -229,7 +229,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(dmard10_pm_ops, dmard10_suspend, dmard10_resume); static const struct i2c_device_id dmard10_i2c_id[] = { - { "dmard10" }, + { .name = "dmard10" }, { } }; MODULE_DEVICE_TABLE(i2c, dmard10_i2c_id); diff --git a/drivers/iio/accel/fxls8962af-i2c.c b/drivers/iio/accel/fxls8962af-i2c.c index 106198a12474..fa46f5aa34f7 100644 --- a/drivers/iio/accel/fxls8962af-i2c.c +++ b/drivers/iio/accel/fxls8962af-i2c.c @@ -28,10 +28,10 @@ static int fxls8962af_probe(struct i2c_client *client) } static const struct i2c_device_id fxls8962af_id[] = { - { "fxls8962af", fxls8962af }, - { "fxls8964af", fxls8964af }, - { "fxls8967af", fxls8967af }, - { "fxls8974cf", fxls8974cf }, + { .name = "fxls8962af", .driver_data = fxls8962af }, + { .name = "fxls8964af", .driver_data = fxls8964af }, + { .name = "fxls8967af", .driver_data = fxls8967af }, + { .name = "fxls8974cf", .driver_data = fxls8974cf }, { } }; MODULE_DEVICE_TABLE(i2c, fxls8962af_id); diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 2823ddde4bf2..8a082ff034dd 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -1630,11 +1630,11 @@ static const struct dev_pm_ops kxcjk1013_pm_ops = { }; static const struct i2c_device_id kxcjk1013_id[] = { - { "kxcjk1013", (kernel_ulong_t)&kxcjk1013_info }, - { "kxcj91008", (kernel_ulong_t)&kxcj91008_info }, - { "kxtj21009", (kernel_ulong_t)&kxtj21009_info }, - { "kxtf9", (kernel_ulong_t)&kxtf9_info }, - { "kx023-1025", (kernel_ulong_t)&kx0231025_info }, + { .name = "kxcjk1013", .driver_data = (kernel_ulong_t)&kxcjk1013_info }, + { .name = "kxcj91008", .driver_data = (kernel_ulong_t)&kxcj91008_info }, + { .name = "kxtj21009", .driver_data = (kernel_ulong_t)&kxtj21009_info }, + { .name = "kxtf9", .driver_data = (kernel_ulong_t)&kxtf9_info }, + { .name = "kx023-1025", .driver_data = (kernel_ulong_t)&kx0231025_info }, { } }; MODULE_DEVICE_TABLE(i2c, kxcjk1013_id); diff --git a/drivers/iio/accel/kxsd9-i2c.c b/drivers/iio/accel/kxsd9-i2c.c index 1fa88b99149e..8f3314db82d2 100644 --- a/drivers/iio/accel/kxsd9-i2c.c +++ b/drivers/iio/accel/kxsd9-i2c.c @@ -43,7 +43,7 @@ static const struct of_device_id kxsd9_of_match[] = { MODULE_DEVICE_TABLE(of, kxsd9_of_match); static const struct i2c_device_id kxsd9_i2c_id[] = { - { "kxsd9" }, + { .name = "kxsd9" }, { } }; MODULE_DEVICE_TABLE(i2c, kxsd9_i2c_id); diff --git a/drivers/iio/accel/mc3230.c b/drivers/iio/accel/mc3230.c index 3e494f9ddc56..b45897210a62 100644 --- a/drivers/iio/accel/mc3230.c +++ b/drivers/iio/accel/mc3230.c @@ -230,8 +230,8 @@ static int mc3230_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(mc3230_pm_ops, mc3230_suspend, mc3230_resume); static const struct i2c_device_id mc3230_i2c_id[] = { - { "mc3230", (kernel_ulong_t)&mc3230_chip_info }, - { "mc3510c", (kernel_ulong_t)&mc3510c_chip_info }, + { .name = "mc3230", .driver_data = (kernel_ulong_t)&mc3230_chip_info }, + { .name = "mc3510c", .driver_data = (kernel_ulong_t)&mc3510c_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, mc3230_i2c_id); diff --git a/drivers/iio/accel/mma7455_i2c.c b/drivers/iio/accel/mma7455_i2c.c index 2ff8eb1f9ce9..9588fd133b1e 100644 --- a/drivers/iio/accel/mma7455_i2c.c +++ b/drivers/iio/accel/mma7455_i2c.c @@ -32,8 +32,8 @@ static void mma7455_i2c_remove(struct i2c_client *i2c) } static const struct i2c_device_id mma7455_i2c_ids[] = { - { "mma7455" }, - { "mma7456" }, + { .name = "mma7455" }, + { .name = "mma7456" }, { } }; MODULE_DEVICE_TABLE(i2c, mma7455_i2c_ids); diff --git a/drivers/iio/accel/mma7660.c b/drivers/iio/accel/mma7660.c index be3213600cf4..0ecf6c06dcc6 100644 --- a/drivers/iio/accel/mma7660.c +++ b/drivers/iio/accel/mma7660.c @@ -259,7 +259,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(mma7660_pm_ops, mma7660_suspend, mma7660_resume); static const struct i2c_device_id mma7660_i2c_id[] = { - { "mma7660" }, + { .name = "mma7660" }, { } }; MODULE_DEVICE_TABLE(i2c, mma7660_i2c_id); diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index b49949792190..1403b32e2b21 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -1829,12 +1829,12 @@ static const struct dev_pm_ops mma8452_pm_ops = { }; static const struct i2c_device_id mma8452_id[] = { - { "fxls8471", (kernel_ulong_t)&mma_chip_info_table[fxls8471] }, - { "mma8451", (kernel_ulong_t)&mma_chip_info_table[mma8451] }, - { "mma8452", (kernel_ulong_t)&mma_chip_info_table[mma8452] }, - { "mma8453", (kernel_ulong_t)&mma_chip_info_table[mma8453] }, - { "mma8652", (kernel_ulong_t)&mma_chip_info_table[mma8652] }, - { "mma8653", (kernel_ulong_t)&mma_chip_info_table[mma8653] }, + { .name = "fxls8471", .driver_data = (kernel_ulong_t)&mma_chip_info_table[fxls8471] }, + { .name = "mma8451", .driver_data = (kernel_ulong_t)&mma_chip_info_table[mma8451] }, + { .name = "mma8452", .driver_data = (kernel_ulong_t)&mma_chip_info_table[mma8452] }, + { .name = "mma8453", .driver_data = (kernel_ulong_t)&mma_chip_info_table[mma8453] }, + { .name = "mma8652", .driver_data = (kernel_ulong_t)&mma_chip_info_table[mma8652] }, + { .name = "mma8653", .driver_data = (kernel_ulong_t)&mma_chip_info_table[mma8653] }, { } }; MODULE_DEVICE_TABLE(i2c, mma8452_id); diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c index 02195deada49..020370b0ec07 100644 --- a/drivers/iio/accel/mma9551.c +++ b/drivers/iio/accel/mma9551.c @@ -582,7 +582,7 @@ static const struct acpi_device_id mma9551_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, mma9551_acpi_match); static const struct i2c_device_id mma9551_id[] = { - { "mma9551" }, + { .name = "mma9551" }, { } }; diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c index f85384a7908f..90ce86244ee8 100644 --- a/drivers/iio/accel/mma9553.c +++ b/drivers/iio/accel/mma9553.c @@ -1219,7 +1219,7 @@ static const struct acpi_device_id mma9553_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, mma9553_acpi_match); static const struct i2c_device_id mma9553_id[] = { - { "mma9553" }, + { .name = "mma9553" }, { } }; diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c index a2c3cf13d098..434971fbfb12 100644 --- a/drivers/iio/accel/mxc4005.c +++ b/drivers/iio/accel/mxc4005.c @@ -580,8 +580,8 @@ static const struct of_device_id mxc4005_of_match[] = { MODULE_DEVICE_TABLE(of, mxc4005_of_match); static const struct i2c_device_id mxc4005_id[] = { - { "mxc4005" }, - { "mxc6655" }, + { .name = "mxc4005" }, + { .name = "mxc6655" }, { } }; MODULE_DEVICE_TABLE(i2c, mxc4005_id); diff --git a/drivers/iio/accel/mxc6255.c b/drivers/iio/accel/mxc6255.c index fc3ed84d1933..901f2b9f16a2 100644 --- a/drivers/iio/accel/mxc6255.c +++ b/drivers/iio/accel/mxc6255.c @@ -171,8 +171,8 @@ static const struct acpi_device_id mxc6255_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, mxc6255_acpi_match); static const struct i2c_device_id mxc6255_id[] = { - { "mxc6225" }, - { "mxc6255" }, + { .name = "mxc6225" }, + { .name = "mxc6255" }, { } }; MODULE_DEVICE_TABLE(i2c, mxc6255_id); diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c index f24449500533..eecc7fcdb06e 100644 --- a/drivers/iio/accel/st_accel_i2c.c +++ b/drivers/iio/accel/st_accel_i2c.c @@ -138,32 +138,32 @@ static const struct acpi_device_id st_accel_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, st_accel_acpi_match); static const struct i2c_device_id st_accel_id_table[] = { - { LSM303DLH_ACCEL_DEV_NAME }, - { LSM303DLHC_ACCEL_DEV_NAME }, - { LIS3DH_ACCEL_DEV_NAME }, - { LSM330D_ACCEL_DEV_NAME }, - { LSM330DL_ACCEL_DEV_NAME }, - { LSM330DLC_ACCEL_DEV_NAME }, - { LIS331DLH_ACCEL_DEV_NAME }, - { LSM303DL_ACCEL_DEV_NAME }, - { LSM303DLM_ACCEL_DEV_NAME }, - { LSM330_ACCEL_DEV_NAME }, - { LSM303AGR_ACCEL_DEV_NAME }, - { LIS2DH12_ACCEL_DEV_NAME }, - { LIS3L02DQ_ACCEL_DEV_NAME }, - { LNG2DM_ACCEL_DEV_NAME }, - { H3LIS331DL_ACCEL_DEV_NAME }, - { LIS331DL_ACCEL_DEV_NAME }, - { LIS3LV02DL_ACCEL_DEV_NAME }, - { LIS2DW12_ACCEL_DEV_NAME }, - { LIS3DE_ACCEL_DEV_NAME }, - { LIS2DE12_ACCEL_DEV_NAME }, - { LIS2DS12_ACCEL_DEV_NAME }, - { LIS2HH12_ACCEL_DEV_NAME }, - { LIS302DL_ACCEL_DEV_NAME }, - { LSM303C_ACCEL_DEV_NAME }, - { SC7A20_ACCEL_DEV_NAME }, - { IIS328DQ_ACCEL_DEV_NAME }, + { .name = LSM303DLH_ACCEL_DEV_NAME }, + { .name = LSM303DLHC_ACCEL_DEV_NAME }, + { .name = LIS3DH_ACCEL_DEV_NAME }, + { .name = LSM330D_ACCEL_DEV_NAME }, + { .name = LSM330DL_ACCEL_DEV_NAME }, + { .name = LSM330DLC_ACCEL_DEV_NAME }, + { .name = LIS331DLH_ACCEL_DEV_NAME }, + { .name = LSM303DL_ACCEL_DEV_NAME }, + { .name = LSM303DLM_ACCEL_DEV_NAME }, + { .name = LSM330_ACCEL_DEV_NAME }, + { .name = LSM303AGR_ACCEL_DEV_NAME }, + { .name = LIS2DH12_ACCEL_DEV_NAME }, + { .name = LIS3L02DQ_ACCEL_DEV_NAME }, + { .name = LNG2DM_ACCEL_DEV_NAME }, + { .name = H3LIS331DL_ACCEL_DEV_NAME }, + { .name = LIS331DL_ACCEL_DEV_NAME }, + { .name = LIS3LV02DL_ACCEL_DEV_NAME }, + { .name = LIS2DW12_ACCEL_DEV_NAME }, + { .name = LIS3DE_ACCEL_DEV_NAME }, + { .name = LIS2DE12_ACCEL_DEV_NAME }, + { .name = LIS2DS12_ACCEL_DEV_NAME }, + { .name = LIS2HH12_ACCEL_DEV_NAME }, + { .name = LIS302DL_ACCEL_DEV_NAME }, + { .name = LSM303C_ACCEL_DEV_NAME }, + { .name = SC7A20_ACCEL_DEV_NAME }, + { .name = IIS328DQ_ACCEL_DEV_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, st_accel_id_table); diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index f31c6ab3392d..8b5a3e0489e9 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -630,8 +630,8 @@ static DEFINE_SIMPLE_DEV_PM_OPS(stk8312_pm_ops, stk8312_suspend, static const struct i2c_device_id stk8312_i2c_id[] = { /* Deprecated in favour of lowercase form */ - { "STK8312" }, - { "stk8312" }, + { .name = "STK8312" }, + { .name = "stk8312" }, { } }; MODULE_DEVICE_TABLE(i2c, stk8312_i2c_id); diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c index a9ff2a273fe1..ccea1331cafc 100644 --- a/drivers/iio/accel/stk8ba50.c +++ b/drivers/iio/accel/stk8ba50.c @@ -519,7 +519,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(stk8ba50_pm_ops, stk8ba50_suspend, stk8ba50_resume); static const struct i2c_device_id stk8ba50_i2c_id[] = { - { "stk8ba50" }, + { .name = "stk8ba50" }, { } }; MODULE_DEVICE_TABLE(i2c, stk8ba50_i2c_id); diff --git a/drivers/iio/adc/ad7291.c b/drivers/iio/adc/ad7291.c index 60e12faa3207..6a1493e27a30 100644 --- a/drivers/iio/adc/ad7291.c +++ b/drivers/iio/adc/ad7291.c @@ -536,7 +536,7 @@ static int ad7291_probe(struct i2c_client *client) } static const struct i2c_device_id ad7291_id[] = { - { "ad7291" }, + { .name = "ad7291" }, { } }; diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c index 0ceedea5df0b..bb076d8f5dd5 100644 --- a/drivers/iio/adc/ad799x.c +++ b/drivers/iio/adc/ad799x.c @@ -940,14 +940,14 @@ static int ad799x_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(ad799x_pm_ops, ad799x_suspend, ad799x_resume); static const struct i2c_device_id ad799x_id[] = { - { "ad7991", ad7991 }, - { "ad7995", ad7995 }, - { "ad7999", ad7999 }, - { "ad7992", ad7992 }, - { "ad7993", ad7993 }, - { "ad7994", ad7994 }, - { "ad7997", ad7997 }, - { "ad7998", ad7998 }, + { .name = "ad7991", .driver_data = ad7991 }, + { .name = "ad7995", .driver_data = ad7995 }, + { .name = "ad7999", .driver_data = ad7999 }, + { .name = "ad7992", .driver_data = ad7992 }, + { .name = "ad7993", .driver_data = ad7993 }, + { .name = "ad7994", .driver_data = ad7994 }, + { .name = "ad7997", .driver_data = ad7997 }, + { .name = "ad7998", .driver_data = ad7998 }, { } }; diff --git a/drivers/iio/adc/gehc-pmc-adc.c b/drivers/iio/adc/gehc-pmc-adc.c index d1167818b17d..24193e941494 100644 --- a/drivers/iio/adc/gehc-pmc-adc.c +++ b/drivers/iio/adc/gehc-pmc-adc.c @@ -207,7 +207,7 @@ static const struct of_device_id pmc_adc_of_match[] = { MODULE_DEVICE_TABLE(of, pmc_adc_of_match); static const struct i2c_device_id pmc_adc_id_table[] = { - { "pmc-adc" }, + { .name = "pmc-adc" }, { } }; MODULE_DEVICE_TABLE(i2c, pmc_adc_id_table); diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c index 7c04e3ec1cbc..c412f5ed46a1 100644 --- a/drivers/iio/adc/ina2xx-adc.c +++ b/drivers/iio/adc/ina2xx-adc.c @@ -1078,12 +1078,12 @@ static void ina2xx_remove(struct i2c_client *client) } static const struct i2c_device_id ina2xx_id[] = { - { "ina219", ina219 }, - { "ina220", ina219 }, - { "ina226", ina226 }, - { "ina230", ina226 }, - { "ina231", ina226 }, - { "ina236", ina236 }, + { .name = "ina219", .driver_data = ina219 }, + { .name = "ina220", .driver_data = ina219 }, + { .name = "ina226", .driver_data = ina226 }, + { .name = "ina230", .driver_data = ina226 }, + { .name = "ina231", .driver_data = ina226 }, + { .name = "ina236", .driver_data = ina236 }, { } }; MODULE_DEVICE_TABLE(i2c, ina2xx_id); diff --git a/drivers/iio/adc/ltc2309.c b/drivers/iio/adc/ltc2309.c index 87b78d0353f1..1ad533270a39 100644 --- a/drivers/iio/adc/ltc2309.c +++ b/drivers/iio/adc/ltc2309.c @@ -243,8 +243,8 @@ static const struct of_device_id ltc2309_of_match[] = { MODULE_DEVICE_TABLE(of, ltc2309_of_match); static const struct i2c_device_id ltc2309_id[] = { - { "ltc2305", (kernel_ulong_t)<c2305_chip_info }, - { "ltc2309", (kernel_ulong_t)<c2309_chip_info }, + { .name = "ltc2305", .driver_data = (kernel_ulong_t)<c2305_chip_info }, + { .name = "ltc2309", .driver_data = (kernel_ulong_t)<c2309_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, ltc2309_id); diff --git a/drivers/iio/adc/ltc2471.c b/drivers/iio/adc/ltc2471.c index a579107fd5c9..369af700969f 100644 --- a/drivers/iio/adc/ltc2471.c +++ b/drivers/iio/adc/ltc2471.c @@ -136,8 +136,8 @@ static int ltc2471_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id ltc2471_i2c_id[] = { - { "ltc2471", ltc2471 }, - { "ltc2473", ltc2473 }, + { .name = "ltc2471", .driver_data = ltc2471 }, + { .name = "ltc2473", .driver_data = ltc2473 }, { } }; MODULE_DEVICE_TABLE(i2c, ltc2471_i2c_id); diff --git a/drivers/iio/adc/ltc2485.c b/drivers/iio/adc/ltc2485.c index 060651dd4130..8c3806e061dd 100644 --- a/drivers/iio/adc/ltc2485.c +++ b/drivers/iio/adc/ltc2485.c @@ -124,7 +124,7 @@ static int ltc2485_probe(struct i2c_client *client) } static const struct i2c_device_id ltc2485_id[] = { - { "ltc2485" }, + { .name = "ltc2485" }, { } }; MODULE_DEVICE_TABLE(i2c, ltc2485_id); diff --git a/drivers/iio/adc/ltc2497.c b/drivers/iio/adc/ltc2497.c index eb9d521e86e5..8e899d6ffcfa 100644 --- a/drivers/iio/adc/ltc2497.c +++ b/drivers/iio/adc/ltc2497.c @@ -142,8 +142,8 @@ static const struct ltc2497_chip_info ltc2497_info[] = { }; static const struct i2c_device_id ltc2497_id[] = { - { "ltc2497", (kernel_ulong_t)<c2497_info[TYPE_LTC2497] }, - { "ltc2499", (kernel_ulong_t)<c2497_info[TYPE_LTC2499] }, + { .name = "ltc2497", .driver_data = (kernel_ulong_t)<c2497_info[TYPE_LTC2497] }, + { .name = "ltc2499", .driver_data = (kernel_ulong_t)<c2497_info[TYPE_LTC2499] }, { } }; MODULE_DEVICE_TABLE(i2c, ltc2497_id); diff --git a/drivers/iio/adc/max34408.c b/drivers/iio/adc/max34408.c index 4f45fd22a90c..da847eaed84e 100644 --- a/drivers/iio/adc/max34408.c +++ b/drivers/iio/adc/max34408.c @@ -256,8 +256,8 @@ static const struct of_device_id max34408_of_match[] = { MODULE_DEVICE_TABLE(of, max34408_of_match); static const struct i2c_device_id max34408_id[] = { - { "max34408", (kernel_ulong_t)&max34408_model_data }, - { "max34409", (kernel_ulong_t)&max34409_model_data }, + { .name = "max34408", .driver_data = (kernel_ulong_t)&max34408_model_data }, + { .name = "max34409", .driver_data = (kernel_ulong_t)&max34409_model_data }, { } }; MODULE_DEVICE_TABLE(i2c, max34408_id); diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c index 0cbd7a874798..f49cde672958 100644 --- a/drivers/iio/adc/mcp3422.c +++ b/drivers/iio/adc/mcp3422.c @@ -383,14 +383,14 @@ static int mcp3422_probe(struct i2c_client *client) } static const struct i2c_device_id mcp3422_id[] = { - { "mcp3421", 1 }, - { "mcp3422", 2 }, - { "mcp3423", 3 }, - { "mcp3424", 4 }, - { "mcp3425", 5 }, - { "mcp3426", 6 }, - { "mcp3427", 7 }, - { "mcp3428", 8 }, + { .name = "mcp3421", .driver_data = 1 }, + { .name = "mcp3422", .driver_data = 2 }, + { .name = "mcp3423", .driver_data = 3 }, + { .name = "mcp3424", .driver_data = 4 }, + { .name = "mcp3425", .driver_data = 5 }, + { .name = "mcp3426", .driver_data = 6 }, + { .name = "mcp3427", .driver_data = 7 }, + { .name = "mcp3428", .driver_data = 8 }, { } }; MODULE_DEVICE_TABLE(i2c, mcp3422_id); diff --git a/drivers/iio/adc/nau7802.c b/drivers/iio/adc/nau7802.c index 970afb27b839..836c9b49c721 100644 --- a/drivers/iio/adc/nau7802.c +++ b/drivers/iio/adc/nau7802.c @@ -531,7 +531,7 @@ static int nau7802_probe(struct i2c_client *client) } static const struct i2c_device_id nau7802_i2c_id[] = { - { "nau7802" }, + { .name = "nau7802" }, { } }; MODULE_DEVICE_TABLE(i2c, nau7802_i2c_id); diff --git a/drivers/iio/adc/rohm-bd79124.c b/drivers/iio/adc/rohm-bd79124.c index 40d00bd0cc9d..864f3b1366b5 100644 --- a/drivers/iio/adc/rohm-bd79124.c +++ b/drivers/iio/adc/rohm-bd79124.c @@ -1104,7 +1104,7 @@ static const struct of_device_id bd79124_of_match[] = { MODULE_DEVICE_TABLE(of, bd79124_of_match); static const struct i2c_device_id bd79124_id[] = { - { "bd79124" }, + { .name = "bd79124" }, { } }; MODULE_DEVICE_TABLE(i2c, bd79124_id); diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c index 8ef51c57912d..33f82bdfeb94 100644 --- a/drivers/iio/adc/ti-adc081c.c +++ b/drivers/iio/adc/ti-adc081c.c @@ -199,9 +199,9 @@ static int adc081c_probe(struct i2c_client *client) } static const struct i2c_device_id adc081c_id[] = { - { "adc081c", (kernel_ulong_t)&adc081c_model }, - { "adc101c", (kernel_ulong_t)&adc101c_model }, - { "adc121c", (kernel_ulong_t)&adc121c_model }, + { .name = "adc081c", .driver_data = (kernel_ulong_t)&adc081c_model }, + { .name = "adc101c", .driver_data = (kernel_ulong_t)&adc101c_model }, + { .name = "adc121c", .driver_data = (kernel_ulong_t)&adc121c_model }, { } }; MODULE_DEVICE_TABLE(i2c, adc081c_id); diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c index c7ffe47449e2..8a272af69f7d 100644 --- a/drivers/iio/adc/ti-ads1015.c +++ b/drivers/iio/adc/ti-ads1015.c @@ -1128,9 +1128,9 @@ static const struct ads1015_chip_data tla2024_data = { }; static const struct i2c_device_id ads1015_id[] = { - { "ads1015", (kernel_ulong_t)&ads1015_data }, - { "ads1115", (kernel_ulong_t)&ads1115_data }, - { "tla2024", (kernel_ulong_t)&tla2024_data }, + { .name = "ads1015", .driver_data = (kernel_ulong_t)&ads1015_data }, + { .name = "ads1115", .driver_data = (kernel_ulong_t)&ads1115_data }, + { .name = "tla2024", .driver_data = (kernel_ulong_t)&tla2024_data }, { } }; MODULE_DEVICE_TABLE(i2c, ads1015_id); diff --git a/drivers/iio/adc/ti-ads1100.c b/drivers/iio/adc/ti-ads1100.c index aa8946063c7d..9fe8d54cce83 100644 --- a/drivers/iio/adc/ti-ads1100.c +++ b/drivers/iio/adc/ti-ads1100.c @@ -400,8 +400,8 @@ static DEFINE_RUNTIME_DEV_PM_OPS(ads1100_pm_ops, NULL); static const struct i2c_device_id ads1100_id[] = { - { "ads1100" }, - { "ads1000" }, + { .name = "ads1100" }, + { .name = "ads1000" }, { } }; diff --git a/drivers/iio/adc/ti-ads1119.c b/drivers/iio/adc/ti-ads1119.c index 2320be0efb50..d31f3d6eb781 100644 --- a/drivers/iio/adc/ti-ads1119.c +++ b/drivers/iio/adc/ti-ads1119.c @@ -804,7 +804,7 @@ static const struct of_device_id __maybe_unused ads1119_of_match[] = { MODULE_DEVICE_TABLE(of, ads1119_of_match); static const struct i2c_device_id ads1119_id[] = { - { "ads1119" }, + { .name = "ads1119" }, { } }; MODULE_DEVICE_TABLE(i2c, ads1119_id); diff --git a/drivers/iio/adc/ti-ads7138.c b/drivers/iio/adc/ti-ads7138.c index ee5c1b8e3a8e..af87f5f19a0f 100644 --- a/drivers/iio/adc/ti-ads7138.c +++ b/drivers/iio/adc/ti-ads7138.c @@ -727,8 +727,8 @@ static const struct of_device_id ads7138_of_match[] = { MODULE_DEVICE_TABLE(of, ads7138_of_match); static const struct i2c_device_id ads7138_device_ids[] = { - { "ads7128", (kernel_ulong_t)&ads7128_data }, - { "ads7138", (kernel_ulong_t)&ads7138_data }, + { .name = "ads7128", .driver_data = (kernel_ulong_t)&ads7128_data }, + { .name = "ads7138", .driver_data = (kernel_ulong_t)&ads7138_data }, { } }; MODULE_DEVICE_TABLE(i2c, ads7138_device_ids); diff --git a/drivers/iio/adc/ti-ads7924.c b/drivers/iio/adc/ti-ads7924.c index 5f294595a415..ff30a52d2850 100644 --- a/drivers/iio/adc/ti-ads7924.c +++ b/drivers/iio/adc/ti-ads7924.c @@ -442,7 +442,7 @@ static int ads7924_probe(struct i2c_client *client) } static const struct i2c_device_id ads7924_id[] = { - { "ads7924" }, + { .name = "ads7924" }, { } }; MODULE_DEVICE_TABLE(i2c, ads7924_id); diff --git a/drivers/iio/cdc/ad7150.c b/drivers/iio/cdc/ad7150.c index 8106a6a83561..cb9fff3bd67f 100644 --- a/drivers/iio/cdc/ad7150.c +++ b/drivers/iio/cdc/ad7150.c @@ -628,9 +628,9 @@ static int ad7150_probe(struct i2c_client *client) } static const struct i2c_device_id ad7150_id[] = { - { "ad7150", AD7150 }, - { "ad7151", AD7151 }, - { "ad7156", AD7150 }, + { .name = "ad7150", .driver_data = AD7150 }, + { .name = "ad7151", .driver_data = AD7151 }, + { .name = "ad7156", .driver_data = AD7150 }, { } }; diff --git a/drivers/iio/cdc/ad7746.c b/drivers/iio/cdc/ad7746.c index cb97e3c978d8..cf68b882bc49 100644 --- a/drivers/iio/cdc/ad7746.c +++ b/drivers/iio/cdc/ad7746.c @@ -789,9 +789,9 @@ static int ad7746_probe(struct i2c_client *client) } static const struct i2c_device_id ad7746_id[] = { - { "ad7745", 7745 }, - { "ad7746", 7746 }, - { "ad7747", 7747 }, + { .name = "ad7745", .driver_data = 7745 }, + { .name = "ad7746", .driver_data = 7746 }, + { .name = "ad7747", .driver_data = 7747 }, { } }; MODULE_DEVICE_TABLE(i2c, ad7746_id); diff --git a/drivers/iio/chemical/ags02ma.c b/drivers/iio/chemical/ags02ma.c index 151178d4e8f4..8b97ea4a9515 100644 --- a/drivers/iio/chemical/ags02ma.c +++ b/drivers/iio/chemical/ags02ma.c @@ -139,7 +139,7 @@ static int ags02ma_probe(struct i2c_client *client) } static const struct i2c_device_id ags02ma_id_table[] = { - { "ags02ma" }, + { .name = "ags02ma" }, { } }; MODULE_DEVICE_TABLE(i2c, ags02ma_id_table); diff --git a/drivers/iio/chemical/ams-iaq-core.c b/drivers/iio/chemical/ams-iaq-core.c index 10156d794092..7aa7841c530e 100644 --- a/drivers/iio/chemical/ams-iaq-core.c +++ b/drivers/iio/chemical/ams-iaq-core.c @@ -163,7 +163,7 @@ static int ams_iaqcore_probe(struct i2c_client *client) } static const struct i2c_device_id ams_iaqcore_id[] = { - { "ams-iaq-core" }, + { .name = "ams-iaq-core" }, { } }; MODULE_DEVICE_TABLE(i2c, ams_iaqcore_id); diff --git a/drivers/iio/chemical/atlas-ezo-sensor.c b/drivers/iio/chemical/atlas-ezo-sensor.c index 59f3a4fa9e9f..05da3b8a92ab 100644 --- a/drivers/iio/chemical/atlas-ezo-sensor.c +++ b/drivers/iio/chemical/atlas-ezo-sensor.c @@ -186,9 +186,9 @@ static const struct iio_info atlas_info = { }; static const struct i2c_device_id atlas_ezo_id[] = { - { "atlas-co2-ezo", (kernel_ulong_t)&atlas_ezo_devices[ATLAS_CO2_EZO] }, - { "atlas-o2-ezo", (kernel_ulong_t)&atlas_ezo_devices[ATLAS_O2_EZO] }, - { "atlas-hum-ezo", (kernel_ulong_t)&atlas_ezo_devices[ATLAS_HUM_EZO] }, + { .name = "atlas-co2-ezo", .driver_data = (kernel_ulong_t)&atlas_ezo_devices[ATLAS_CO2_EZO] }, + { .name = "atlas-o2-ezo", .driver_data = (kernel_ulong_t)&atlas_ezo_devices[ATLAS_O2_EZO] }, + { .name = "atlas-hum-ezo", .driver_data = (kernel_ulong_t)&atlas_ezo_devices[ATLAS_HUM_EZO] }, { } }; MODULE_DEVICE_TABLE(i2c, atlas_ezo_id); diff --git a/drivers/iio/chemical/atlas-sensor.c b/drivers/iio/chemical/atlas-sensor.c index 8bbba85af699..0e2edcff63f9 100644 --- a/drivers/iio/chemical/atlas-sensor.c +++ b/drivers/iio/chemical/atlas-sensor.c @@ -586,11 +586,11 @@ static const struct iio_info atlas_info = { }; static const struct i2c_device_id atlas_id[] = { - { "atlas-ph-sm", (kernel_ulong_t)&atlas_devices[ATLAS_PH_SM] }, - { "atlas-ec-sm", (kernel_ulong_t)&atlas_devices[ATLAS_EC_SM] }, - { "atlas-orp-sm", (kernel_ulong_t)&atlas_devices[ATLAS_ORP_SM] }, - { "atlas-do-sm", (kernel_ulong_t)&atlas_devices[ATLAS_DO_SM] }, - { "atlas-rtd-sm", (kernel_ulong_t)&atlas_devices[ATLAS_RTD_SM] }, + { .name = "atlas-ph-sm", .driver_data = (kernel_ulong_t)&atlas_devices[ATLAS_PH_SM] }, + { .name = "atlas-ec-sm", .driver_data = (kernel_ulong_t)&atlas_devices[ATLAS_EC_SM] }, + { .name = "atlas-orp-sm", .driver_data = (kernel_ulong_t)&atlas_devices[ATLAS_ORP_SM] }, + { .name = "atlas-do-sm", .driver_data = (kernel_ulong_t)&atlas_devices[ATLAS_DO_SM] }, + { .name = "atlas-rtd-sm", .driver_data = (kernel_ulong_t)&atlas_devices[ATLAS_RTD_SM] }, { } }; MODULE_DEVICE_TABLE(i2c, atlas_id); diff --git a/drivers/iio/chemical/bme680_i2c.c b/drivers/iio/chemical/bme680_i2c.c index 5560ea708b36..4cc0e491621a 100644 --- a/drivers/iio/chemical/bme680_i2c.c +++ b/drivers/iio/chemical/bme680_i2c.c @@ -36,7 +36,7 @@ static int bme680_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id bme680_i2c_id[] = { - { "bme680" }, + { .name = "bme680" }, { } }; MODULE_DEVICE_TABLE(i2c, bme680_i2c_id); diff --git a/drivers/iio/chemical/ccs811.c b/drivers/iio/chemical/ccs811.c index 998c9239c4c7..ce7187ccd706 100644 --- a/drivers/iio/chemical/ccs811.c +++ b/drivers/iio/chemical/ccs811.c @@ -552,8 +552,8 @@ static void ccs811_remove(struct i2c_client *client) } static const struct i2c_device_id ccs811_id[] = { - { "ccs811" }, - { } + { .name = "ccs811" }, + { } }; MODULE_DEVICE_TABLE(i2c, ccs811_id); diff --git a/drivers/iio/chemical/ens160_i2c.c b/drivers/iio/chemical/ens160_i2c.c index aa0dfe639245..ab0e8dcce011 100644 --- a/drivers/iio/chemical/ens160_i2c.c +++ b/drivers/iio/chemical/ens160_i2c.c @@ -34,7 +34,7 @@ static int ens160_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id ens160_i2c_id[] = { - { "ens160" }, + { .name = "ens160" }, { } }; MODULE_DEVICE_TABLE(i2c, ens160_i2c_id); diff --git a/drivers/iio/chemical/sgp30.c b/drivers/iio/chemical/sgp30.c index d42b62b7081e..8b88be85602c 100644 --- a/drivers/iio/chemical/sgp30.c +++ b/drivers/iio/chemical/sgp30.c @@ -563,8 +563,8 @@ static void sgp_remove(struct i2c_client *client) } static const struct i2c_device_id sgp_id[] = { - { "sgp30", (kernel_ulong_t)&sgp_devices[SGP30] }, - { "sgpc3", (kernel_ulong_t)&sgp_devices[SGPC3] }, + { .name = "sgp30", .driver_data = (kernel_ulong_t)&sgp_devices[SGP30] }, + { .name = "sgpc3", .driver_data = (kernel_ulong_t)&sgp_devices[SGPC3] }, { } }; MODULE_DEVICE_TABLE(i2c, sgp_id); diff --git a/drivers/iio/chemical/sgp40.c b/drivers/iio/chemical/sgp40.c index 07d8ab830211..b2b5e32a9eb2 100644 --- a/drivers/iio/chemical/sgp40.c +++ b/drivers/iio/chemical/sgp40.c @@ -355,7 +355,7 @@ static int sgp40_probe(struct i2c_client *client) } static const struct i2c_device_id sgp40_id[] = { - { "sgp40" }, + { .name = "sgp40" }, { } }; diff --git a/drivers/iio/chemical/sps30_i2c.c b/drivers/iio/chemical/sps30_i2c.c index c92f04990c34..61781aaabd85 100644 --- a/drivers/iio/chemical/sps30_i2c.c +++ b/drivers/iio/chemical/sps30_i2c.c @@ -232,7 +232,7 @@ static int sps30_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id sps30_i2c_id[] = { - { "sps30" }, + { .name = "sps30" }, { } }; MODULE_DEVICE_TABLE(i2c, sps30_i2c_id); diff --git a/drivers/iio/chemical/vz89x.c b/drivers/iio/chemical/vz89x.c index 5b358bcd311b..4deacf10b6ef 100644 --- a/drivers/iio/chemical/vz89x.c +++ b/drivers/iio/chemical/vz89x.c @@ -385,8 +385,8 @@ static int vz89x_probe(struct i2c_client *client) } static const struct i2c_device_id vz89x_id[] = { - { "vz89x", (kernel_ulong_t)&vz89x_chips[VZ89X] }, - { "vz89te", (kernel_ulong_t)&vz89x_chips[VZ89TE] }, + { .name = "vz89x", .driver_data = (kernel_ulong_t)&vz89x_chips[VZ89X] }, + { .name = "vz89te", .driver_data = (kernel_ulong_t)&vz89x_chips[VZ89TE] }, { } }; MODULE_DEVICE_TABLE(i2c, vz89x_id); diff --git a/drivers/iio/dac/ad5064.c b/drivers/iio/dac/ad5064.c index 84be5174babd..b5ec33f5c317 100644 --- a/drivers/iio/dac/ad5064.c +++ b/drivers/iio/dac/ad5064.c @@ -1001,53 +1001,53 @@ static int ad5064_i2c_probe(struct i2c_client *i2c) } static const struct i2c_device_id ad5064_i2c_ids[] = { - {"ad5625", ID_AD5625 }, - {"ad5625r-1v25", ID_AD5625R_1V25 }, - {"ad5625r-2v5", ID_AD5625R_2V5 }, - {"ad5627", ID_AD5627 }, - {"ad5627r-1v25", ID_AD5627R_1V25 }, - {"ad5627r-2v5", ID_AD5627R_2V5 }, - {"ad5629-1", ID_AD5629_1}, - {"ad5629-2", ID_AD5629_2}, - {"ad5629-3", ID_AD5629_2}, /* similar enough to ad5629-2 */ - {"ad5645r-1v25", ID_AD5645R_1V25 }, - {"ad5645r-2v5", ID_AD5645R_2V5 }, - {"ad5665", ID_AD5665 }, - {"ad5665r-1v25", ID_AD5665R_1V25 }, - {"ad5665r-2v5", ID_AD5665R_2V5 }, - {"ad5667", ID_AD5667 }, - {"ad5667r-1v25", ID_AD5667R_1V25 }, - {"ad5667r-2v5", ID_AD5667R_2V5 }, - {"ad5669-1", ID_AD5669_1}, - {"ad5669-2", ID_AD5669_2}, - {"ad5669-3", ID_AD5669_2}, /* similar enough to ad5669-2 */ - {"ltc2606", ID_LTC2606}, - {"ltc2607", ID_LTC2607}, - {"ltc2609", ID_LTC2609}, - {"ltc2616", ID_LTC2616}, - {"ltc2617", ID_LTC2617}, - {"ltc2619", ID_LTC2619}, - {"ltc2626", ID_LTC2626}, - {"ltc2627", ID_LTC2627}, - {"ltc2629", ID_LTC2629}, - {"ltc2631-l12", ID_LTC2631_L12}, - {"ltc2631-h12", ID_LTC2631_H12}, - {"ltc2631-l10", ID_LTC2631_L10}, - {"ltc2631-h10", ID_LTC2631_H10}, - {"ltc2631-l8", ID_LTC2631_L8}, - {"ltc2631-h8", ID_LTC2631_H8}, - {"ltc2633-l12", ID_LTC2633_L12}, - {"ltc2633-h12", ID_LTC2633_H12}, - {"ltc2633-l10", ID_LTC2633_L10}, - {"ltc2633-h10", ID_LTC2633_H10}, - {"ltc2633-l8", ID_LTC2633_L8}, - {"ltc2633-h8", ID_LTC2633_H8}, - {"ltc2635-l12", ID_LTC2635_L12}, - {"ltc2635-h12", ID_LTC2635_H12}, - {"ltc2635-l10", ID_LTC2635_L10}, - {"ltc2635-h10", ID_LTC2635_H10}, - {"ltc2635-l8", ID_LTC2635_L8}, - {"ltc2635-h8", ID_LTC2635_H8}, + { .name = "ad5625", .driver_data = ID_AD5625 }, + { .name = "ad5625r-1v25", .driver_data = ID_AD5625R_1V25 }, + { .name = "ad5625r-2v5", .driver_data = ID_AD5625R_2V5 }, + { .name = "ad5627", .driver_data = ID_AD5627 }, + { .name = "ad5627r-1v25", .driver_data = ID_AD5627R_1V25 }, + { .name = "ad5627r-2v5", .driver_data = ID_AD5627R_2V5 }, + { .name = "ad5629-1", .driver_data = ID_AD5629_1 }, + { .name = "ad5629-2", .driver_data = ID_AD5629_2 }, + { .name = "ad5629-3", .driver_data = ID_AD5629_2 }, /* similar enough to ad5629-2 */ + { .name = "ad5645r-1v25", .driver_data = ID_AD5645R_1V25 }, + { .name = "ad5645r-2v5", .driver_data = ID_AD5645R_2V5 }, + { .name = "ad5665", .driver_data = ID_AD5665 }, + { .name = "ad5665r-1v25", .driver_data = ID_AD5665R_1V25 }, + { .name = "ad5665r-2v5", .driver_data = ID_AD5665R_2V5 }, + { .name = "ad5667", .driver_data = ID_AD5667 }, + { .name = "ad5667r-1v25", .driver_data = ID_AD5667R_1V25 }, + { .name = "ad5667r-2v5", .driver_data = ID_AD5667R_2V5 }, + { .name = "ad5669-1", .driver_data = ID_AD5669_1 }, + { .name = "ad5669-2", .driver_data = ID_AD5669_2 }, + { .name = "ad5669-3", .driver_data = ID_AD5669_2 }, /* similar enough to ad5669-2 */ + { .name = "ltc2606", .driver_data = ID_LTC2606 }, + { .name = "ltc2607", .driver_data = ID_LTC2607 }, + { .name = "ltc2609", .driver_data = ID_LTC2609 }, + { .name = "ltc2616", .driver_data = ID_LTC2616 }, + { .name = "ltc2617", .driver_data = ID_LTC2617 }, + { .name = "ltc2619", .driver_data = ID_LTC2619 }, + { .name = "ltc2626", .driver_data = ID_LTC2626 }, + { .name = "ltc2627", .driver_data = ID_LTC2627 }, + { .name = "ltc2629", .driver_data = ID_LTC2629 }, + { .name = "ltc2631-l12", .driver_data = ID_LTC2631_L12 }, + { .name = "ltc2631-h12", .driver_data = ID_LTC2631_H12 }, + { .name = "ltc2631-l10", .driver_data = ID_LTC2631_L10 }, + { .name = "ltc2631-h10", .driver_data = ID_LTC2631_H10 }, + { .name = "ltc2631-l8", .driver_data = ID_LTC2631_L8 }, + { .name = "ltc2631-h8", .driver_data = ID_LTC2631_H8 }, + { .name = "ltc2633-l12", .driver_data = ID_LTC2633_L12 }, + { .name = "ltc2633-h12", .driver_data = ID_LTC2633_H12 }, + { .name = "ltc2633-l10", .driver_data = ID_LTC2633_L10 }, + { .name = "ltc2633-h10", .driver_data = ID_LTC2633_H10 }, + { .name = "ltc2633-l8", .driver_data = ID_LTC2633_L8 }, + { .name = "ltc2633-h8", .driver_data = ID_LTC2633_H8 }, + { .name = "ltc2635-l12", .driver_data = ID_LTC2635_L12 }, + { .name = "ltc2635-h12", .driver_data = ID_LTC2635_H12 }, + { .name = "ltc2635-l10", .driver_data = ID_LTC2635_L10 }, + { .name = "ltc2635-h10", .driver_data = ID_LTC2635_H10 }, + { .name = "ltc2635-l8", .driver_data = ID_LTC2635_L8 }, + { .name = "ltc2635-h8", .driver_data = ID_LTC2635_H8 }, { } }; MODULE_DEVICE_TABLE(i2c, ad5064_i2c_ids); diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c index 8b813cee7625..2e587bdd3214 100644 --- a/drivers/iio/dac/ad5380.c +++ b/drivers/iio/dac/ad5380.c @@ -513,22 +513,22 @@ static int ad5380_i2c_probe(struct i2c_client *i2c) } static const struct i2c_device_id ad5380_i2c_ids[] = { - { "ad5380-3", ID_AD5380_3 }, - { "ad5380-5", ID_AD5380_5 }, - { "ad5381-3", ID_AD5381_3 }, - { "ad5381-5", ID_AD5381_5 }, - { "ad5382-3", ID_AD5382_3 }, - { "ad5382-5", ID_AD5382_5 }, - { "ad5383-3", ID_AD5383_3 }, - { "ad5383-5", ID_AD5383_5 }, - { "ad5384-3", ID_AD5380_3 }, - { "ad5384-5", ID_AD5380_5 }, - { "ad5390-3", ID_AD5390_3 }, - { "ad5390-5", ID_AD5390_5 }, - { "ad5391-3", ID_AD5391_3 }, - { "ad5391-5", ID_AD5391_5 }, - { "ad5392-3", ID_AD5392_3 }, - { "ad5392-5", ID_AD5392_5 }, + { .name = "ad5380-3", .driver_data = ID_AD5380_3 }, + { .name = "ad5380-5", .driver_data = ID_AD5380_5 }, + { .name = "ad5381-3", .driver_data = ID_AD5381_3 }, + { .name = "ad5381-5", .driver_data = ID_AD5381_5 }, + { .name = "ad5382-3", .driver_data = ID_AD5382_3 }, + { .name = "ad5382-5", .driver_data = ID_AD5382_5 }, + { .name = "ad5383-3", .driver_data = ID_AD5383_3 }, + { .name = "ad5383-5", .driver_data = ID_AD5383_5 }, + { .name = "ad5384-3", .driver_data = ID_AD5380_3 }, + { .name = "ad5384-5", .driver_data = ID_AD5380_5 }, + { .name = "ad5390-3", .driver_data = ID_AD5390_3 }, + { .name = "ad5390-5", .driver_data = ID_AD5390_5 }, + { .name = "ad5391-3", .driver_data = ID_AD5391_3 }, + { .name = "ad5391-5", .driver_data = ID_AD5391_5 }, + { .name = "ad5392-3", .driver_data = ID_AD5392_3 }, + { .name = "ad5392-5", .driver_data = ID_AD5392_5 }, { } }; MODULE_DEVICE_TABLE(i2c, ad5380_i2c_ids); diff --git a/drivers/iio/dac/ad5446-i2c.c b/drivers/iio/dac/ad5446-i2c.c index 40fe7e17fce4..2d4c8908d91e 100644 --- a/drivers/iio/dac/ad5446-i2c.c +++ b/drivers/iio/dac/ad5446-i2c.c @@ -65,12 +65,12 @@ static const struct ad5446_chip_info ad5622_chip_info = { }; static const struct i2c_device_id ad5446_i2c_ids[] = { - {"ad5301", (kernel_ulong_t)&ad5602_chip_info}, - {"ad5311", (kernel_ulong_t)&ad5612_chip_info}, - {"ad5321", (kernel_ulong_t)&ad5622_chip_info}, - {"ad5602", (kernel_ulong_t)&ad5602_chip_info}, - {"ad5612", (kernel_ulong_t)&ad5612_chip_info}, - {"ad5622", (kernel_ulong_t)&ad5622_chip_info}, + { .name = "ad5301", .driver_data = (kernel_ulong_t)&ad5602_chip_info }, + { .name = "ad5311", .driver_data = (kernel_ulong_t)&ad5612_chip_info }, + { .name = "ad5321", .driver_data = (kernel_ulong_t)&ad5622_chip_info }, + { .name = "ad5602", .driver_data = (kernel_ulong_t)&ad5602_chip_info }, + { .name = "ad5612", .driver_data = (kernel_ulong_t)&ad5612_chip_info }, + { .name = "ad5622", .driver_data = (kernel_ulong_t)&ad5622_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, ad5446_i2c_ids); diff --git a/drivers/iio/dac/ad5696-i2c.c b/drivers/iio/dac/ad5696-i2c.c index d3327bca0e07..56625e1da817 100644 --- a/drivers/iio/dac/ad5696-i2c.c +++ b/drivers/iio/dac/ad5696-i2c.c @@ -66,22 +66,22 @@ static int ad5686_i2c_probe(struct i2c_client *i2c) } static const struct i2c_device_id ad5686_i2c_id[] = { - {"ad5311r", ID_AD5311R}, - {"ad5337r", ID_AD5337R}, - {"ad5338r", ID_AD5338R}, - {"ad5671r", ID_AD5671R}, - {"ad5673r", ID_AD5673R}, - {"ad5675r", ID_AD5675R}, - {"ad5677r", ID_AD5677R}, - {"ad5691r", ID_AD5691R}, - {"ad5692r", ID_AD5692R}, - {"ad5693", ID_AD5693}, - {"ad5693r", ID_AD5693R}, - {"ad5694", ID_AD5694}, - {"ad5694r", ID_AD5694R}, - {"ad5695r", ID_AD5695R}, - {"ad5696", ID_AD5696}, - {"ad5696r", ID_AD5696R}, + { .name = "ad5311r", .driver_data = ID_AD5311R }, + { .name = "ad5337r", .driver_data = ID_AD5337R }, + { .name = "ad5338r", .driver_data = ID_AD5338R }, + { .name = "ad5671r", .driver_data = ID_AD5671R }, + { .name = "ad5673r", .driver_data = ID_AD5673R }, + { .name = "ad5675r", .driver_data = ID_AD5675R }, + { .name = "ad5677r", .driver_data = ID_AD5677R }, + { .name = "ad5691r", .driver_data = ID_AD5691R }, + { .name = "ad5692r", .driver_data = ID_AD5692R }, + { .name = "ad5693", .driver_data = ID_AD5693 }, + { .name = "ad5693r", .driver_data = ID_AD5693R }, + { .name = "ad5694", .driver_data = ID_AD5694 }, + { .name = "ad5694r", .driver_data = ID_AD5694R }, + { .name = "ad5695r", .driver_data = ID_AD5695R }, + { .name = "ad5696", .driver_data = ID_AD5696 }, + { .name = "ad5696r", .driver_data = ID_AD5696R }, { } }; MODULE_DEVICE_TABLE(i2c, ad5686_i2c_id); diff --git a/drivers/iio/dac/ds4424.c b/drivers/iio/dac/ds4424.c index 085f73de3f02..b6430b832cf0 100644 --- a/drivers/iio/dac/ds4424.c +++ b/drivers/iio/dac/ds4424.c @@ -401,10 +401,10 @@ static void ds4424_remove(struct i2c_client *client) } static const struct i2c_device_id ds4424_id[] = { - { "ds4402", (kernel_ulong_t)&ds4402_info }, - { "ds4404", (kernel_ulong_t)&ds4404_info }, - { "ds4422", (kernel_ulong_t)&ds4422_info }, - { "ds4424", (kernel_ulong_t)&ds4424_info }, + { .name = "ds4402", .driver_data = (kernel_ulong_t)&ds4402_info }, + { .name = "ds4404", .driver_data = (kernel_ulong_t)&ds4404_info }, + { .name = "ds4422", .driver_data = (kernel_ulong_t)&ds4422_info }, + { .name = "ds4424", .driver_data = (kernel_ulong_t)&ds4424_info }, { } }; diff --git a/drivers/iio/dac/m62332.c b/drivers/iio/dac/m62332.c index 3497513854d7..7e80c0eb5cc1 100644 --- a/drivers/iio/dac/m62332.c +++ b/drivers/iio/dac/m62332.c @@ -228,7 +228,7 @@ static void m62332_remove(struct i2c_client *client) } static const struct i2c_device_id m62332_id[] = { - { "m62332", }, + { .name = "m62332" }, { } }; MODULE_DEVICE_TABLE(i2c, m62332_id); diff --git a/drivers/iio/dac/max517.c b/drivers/iio/dac/max517.c index d334c67821ad..d2ddc72e0e50 100644 --- a/drivers/iio/dac/max517.c +++ b/drivers/iio/dac/max517.c @@ -187,11 +187,11 @@ static int max517_probe(struct i2c_client *client) } static const struct i2c_device_id max517_id[] = { - { "max517", ID_MAX517 }, - { "max518", ID_MAX518 }, - { "max519", ID_MAX519 }, - { "max520", ID_MAX520 }, - { "max521", ID_MAX521 }, + { .name = "max517", .driver_data = ID_MAX517 }, + { .name = "max518", .driver_data = ID_MAX518 }, + { .name = "max519", .driver_data = ID_MAX519 }, + { .name = "max520", .driver_data = ID_MAX520 }, + { .name = "max521", .driver_data = ID_MAX521 }, { } }; MODULE_DEVICE_TABLE(i2c, max517_id); diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c index 23b9e3a09ec8..2d6bcfd5deaa 100644 --- a/drivers/iio/dac/mcp4725.c +++ b/drivers/iio/dac/mcp4725.c @@ -523,8 +523,8 @@ static const struct mcp4725_chip_info mcp4726 = { }; static const struct i2c_device_id mcp4725_id[] = { - { "mcp4725", (kernel_ulong_t)&mcp4725 }, - { "mcp4726", (kernel_ulong_t)&mcp4726 }, + { .name = "mcp4725", .driver_data = (kernel_ulong_t)&mcp4725 }, + { .name = "mcp4726", .driver_data = (kernel_ulong_t)&mcp4726 }, { } }; MODULE_DEVICE_TABLE(i2c, mcp4725_id); diff --git a/drivers/iio/dac/mcp4728.c b/drivers/iio/dac/mcp4728.c index 4f30b99110b7..64bd9490fc19 100644 --- a/drivers/iio/dac/mcp4728.c +++ b/drivers/iio/dac/mcp4728.c @@ -572,7 +572,7 @@ static int mcp4728_probe(struct i2c_client *client) } static const struct i2c_device_id mcp4728_id[] = { - { "mcp4728" }, + { .name = "mcp4728" }, { } }; MODULE_DEVICE_TABLE(i2c, mcp4728_id); diff --git a/drivers/iio/dac/mcp47feb02.c b/drivers/iio/dac/mcp47feb02.c index faccb804a5ed..217f78e44af1 100644 --- a/drivers/iio/dac/mcp47feb02.c +++ b/drivers/iio/dac/mcp47feb02.c @@ -1170,30 +1170,30 @@ static int mcp47feb02_probe(struct i2c_client *client) } static const struct i2c_device_id mcp47feb02_id[] = { - { "mcp47feb01", (kernel_ulong_t)&mcp47feb01_chip_features }, - { "mcp47feb02", (kernel_ulong_t)&mcp47feb02_chip_features }, - { "mcp47feb04", (kernel_ulong_t)&mcp47feb04_chip_features }, - { "mcp47feb08", (kernel_ulong_t)&mcp47feb08_chip_features }, - { "mcp47feb11", (kernel_ulong_t)&mcp47feb11_chip_features }, - { "mcp47feb12", (kernel_ulong_t)&mcp47feb12_chip_features }, - { "mcp47feb14", (kernel_ulong_t)&mcp47feb14_chip_features }, - { "mcp47feb18", (kernel_ulong_t)&mcp47feb18_chip_features }, - { "mcp47feb21", (kernel_ulong_t)&mcp47feb21_chip_features }, - { "mcp47feb22", (kernel_ulong_t)&mcp47feb22_chip_features }, - { "mcp47feb24", (kernel_ulong_t)&mcp47feb24_chip_features }, - { "mcp47feb28", (kernel_ulong_t)&mcp47feb28_chip_features }, - { "mcp47fvb01", (kernel_ulong_t)&mcp47fvb01_chip_features }, - { "mcp47fvb02", (kernel_ulong_t)&mcp47fvb02_chip_features }, - { "mcp47fvb04", (kernel_ulong_t)&mcp47fvb04_chip_features }, - { "mcp47fvb08", (kernel_ulong_t)&mcp47fvb08_chip_features }, - { "mcp47fvb11", (kernel_ulong_t)&mcp47fvb11_chip_features }, - { "mcp47fvb12", (kernel_ulong_t)&mcp47fvb12_chip_features }, - { "mcp47fvb14", (kernel_ulong_t)&mcp47fvb14_chip_features }, - { "mcp47fvb18", (kernel_ulong_t)&mcp47fvb18_chip_features }, - { "mcp47fvb21", (kernel_ulong_t)&mcp47fvb21_chip_features }, - { "mcp47fvb22", (kernel_ulong_t)&mcp47fvb22_chip_features }, - { "mcp47fvb24", (kernel_ulong_t)&mcp47fvb24_chip_features }, - { "mcp47fvb28", (kernel_ulong_t)&mcp47fvb28_chip_features }, + { .name = "mcp47feb01", .driver_data = (kernel_ulong_t)&mcp47feb01_chip_features }, + { .name = "mcp47feb02", .driver_data = (kernel_ulong_t)&mcp47feb02_chip_features }, + { .name = "mcp47feb04", .driver_data = (kernel_ulong_t)&mcp47feb04_chip_features }, + { .name = "mcp47feb08", .driver_data = (kernel_ulong_t)&mcp47feb08_chip_features }, + { .name = "mcp47feb11", .driver_data = (kernel_ulong_t)&mcp47feb11_chip_features }, + { .name = "mcp47feb12", .driver_data = (kernel_ulong_t)&mcp47feb12_chip_features }, + { .name = "mcp47feb14", .driver_data = (kernel_ulong_t)&mcp47feb14_chip_features }, + { .name = "mcp47feb18", .driver_data = (kernel_ulong_t)&mcp47feb18_chip_features }, + { .name = "mcp47feb21", .driver_data = (kernel_ulong_t)&mcp47feb21_chip_features }, + { .name = "mcp47feb22", .driver_data = (kernel_ulong_t)&mcp47feb22_chip_features }, + { .name = "mcp47feb24", .driver_data = (kernel_ulong_t)&mcp47feb24_chip_features }, + { .name = "mcp47feb28", .driver_data = (kernel_ulong_t)&mcp47feb28_chip_features }, + { .name = "mcp47fvb01", .driver_data = (kernel_ulong_t)&mcp47fvb01_chip_features }, + { .name = "mcp47fvb02", .driver_data = (kernel_ulong_t)&mcp47fvb02_chip_features }, + { .name = "mcp47fvb04", .driver_data = (kernel_ulong_t)&mcp47fvb04_chip_features }, + { .name = "mcp47fvb08", .driver_data = (kernel_ulong_t)&mcp47fvb08_chip_features }, + { .name = "mcp47fvb11", .driver_data = (kernel_ulong_t)&mcp47fvb11_chip_features }, + { .name = "mcp47fvb12", .driver_data = (kernel_ulong_t)&mcp47fvb12_chip_features }, + { .name = "mcp47fvb14", .driver_data = (kernel_ulong_t)&mcp47fvb14_chip_features }, + { .name = "mcp47fvb18", .driver_data = (kernel_ulong_t)&mcp47fvb18_chip_features }, + { .name = "mcp47fvb21", .driver_data = (kernel_ulong_t)&mcp47fvb21_chip_features }, + { .name = "mcp47fvb22", .driver_data = (kernel_ulong_t)&mcp47fvb22_chip_features }, + { .name = "mcp47fvb24", .driver_data = (kernel_ulong_t)&mcp47fvb24_chip_features }, + { .name = "mcp47fvb28", .driver_data = (kernel_ulong_t)&mcp47fvb28_chip_features }, { } }; MODULE_DEVICE_TABLE(i2c, mcp47feb02_id); diff --git a/drivers/iio/dac/ti-dac5571.c b/drivers/iio/dac/ti-dac5571.c index 455d61fc3f13..b9efd704e996 100644 --- a/drivers/iio/dac/ti-dac5571.c +++ b/drivers/iio/dac/ti-dac5571.c @@ -402,17 +402,17 @@ static const struct of_device_id dac5571_of_id[] = { MODULE_DEVICE_TABLE(of, dac5571_of_id); static const struct i2c_device_id dac5571_id[] = { - {"dac081c081", (kernel_ulong_t)&dac5571_spec[single_8bit] }, - {"dac121c081", (kernel_ulong_t)&dac5571_spec[single_12bit] }, - {"dac5571", (kernel_ulong_t)&dac5571_spec[single_8bit] }, - {"dac6571", (kernel_ulong_t)&dac5571_spec[single_10bit] }, - {"dac7571", (kernel_ulong_t)&dac5571_spec[single_12bit] }, - {"dac5574", (kernel_ulong_t)&dac5571_spec[quad_8bit] }, - {"dac6574", (kernel_ulong_t)&dac5571_spec[quad_10bit] }, - {"dac7574", (kernel_ulong_t)&dac5571_spec[quad_12bit] }, - {"dac5573", (kernel_ulong_t)&dac5571_spec[quad_8bit] }, - {"dac6573", (kernel_ulong_t)&dac5571_spec[quad_10bit] }, - {"dac7573", (kernel_ulong_t)&dac5571_spec[quad_12bit] }, + { .name = "dac081c081", .driver_data = (kernel_ulong_t)&dac5571_spec[single_8bit] }, + { .name = "dac121c081", .driver_data = (kernel_ulong_t)&dac5571_spec[single_12bit] }, + { .name = "dac5571", .driver_data = (kernel_ulong_t)&dac5571_spec[single_8bit] }, + { .name = "dac6571", .driver_data = (kernel_ulong_t)&dac5571_spec[single_10bit] }, + { .name = "dac7571", .driver_data = (kernel_ulong_t)&dac5571_spec[single_12bit] }, + { .name = "dac5574", .driver_data = (kernel_ulong_t)&dac5571_spec[quad_8bit] }, + { .name = "dac6574", .driver_data = (kernel_ulong_t)&dac5571_spec[quad_10bit] }, + { .name = "dac7574", .driver_data = (kernel_ulong_t)&dac5571_spec[quad_12bit] }, + { .name = "dac5573", .driver_data = (kernel_ulong_t)&dac5571_spec[quad_8bit] }, + { .name = "dac6573", .driver_data = (kernel_ulong_t)&dac5571_spec[quad_10bit] }, + { .name = "dac7573", .driver_data = (kernel_ulong_t)&dac5571_spec[quad_12bit] }, { } }; MODULE_DEVICE_TABLE(i2c, dac5571_id); diff --git a/drivers/iio/gyro/bmg160_i2c.c b/drivers/iio/gyro/bmg160_i2c.c index 1fb8a7969c25..028e5e29c6a1 100644 --- a/drivers/iio/gyro/bmg160_i2c.c +++ b/drivers/iio/gyro/bmg160_i2c.c @@ -47,9 +47,9 @@ static const struct acpi_device_id bmg160_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, bmg160_acpi_match); static const struct i2c_device_id bmg160_i2c_id[] = { - { "bmg160" }, - { "bmi055_gyro" }, - { "bmi088_gyro" }, + { .name = "bmg160" }, + { .name = "bmi055_gyro" }, + { .name = "bmi088_gyro" }, { } }; diff --git a/drivers/iio/gyro/fxas21002c_i2c.c b/drivers/iio/gyro/fxas21002c_i2c.c index 43c6b3079487..d537e91caaaf 100644 --- a/drivers/iio/gyro/fxas21002c_i2c.c +++ b/drivers/iio/gyro/fxas21002c_i2c.c @@ -39,7 +39,7 @@ static void fxas21002c_i2c_remove(struct i2c_client *i2c) } static const struct i2c_device_id fxas21002c_i2c_id[] = { - { "fxas21002c" }, + { .name = "fxas21002c" }, { } }; MODULE_DEVICE_TABLE(i2c, fxas21002c_i2c_id); diff --git a/drivers/iio/gyro/itg3200_core.c b/drivers/iio/gyro/itg3200_core.c index bfe95ec1abda..6b13d54d9b01 100644 --- a/drivers/iio/gyro/itg3200_core.c +++ b/drivers/iio/gyro/itg3200_core.c @@ -389,7 +389,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(itg3200_pm_ops, itg3200_suspend, itg3200_resume); static const struct i2c_device_id itg3200_id[] = { - { "itg3200" }, + { .name = "itg3200" }, { } }; MODULE_DEVICE_TABLE(i2c, itg3200_id); diff --git a/drivers/iio/gyro/mpu3050-i2c.c b/drivers/iio/gyro/mpu3050-i2c.c index 6549b22e643d..2a5bcec7272c 100644 --- a/drivers/iio/gyro/mpu3050-i2c.c +++ b/drivers/iio/gyro/mpu3050-i2c.c @@ -92,7 +92,7 @@ static void mpu3050_i2c_remove(struct i2c_client *client) * supported by this driver */ static const struct i2c_device_id mpu3050_i2c_id[] = { - { "mpu3050" }, + { .name = "mpu3050" }, { } }; MODULE_DEVICE_TABLE(i2c, mpu3050_i2c_id); diff --git a/drivers/iio/gyro/st_gyro_i2c.c b/drivers/iio/gyro/st_gyro_i2c.c index aef5ec8f9dee..b07cb39051b3 100644 --- a/drivers/iio/gyro/st_gyro_i2c.c +++ b/drivers/iio/gyro/st_gyro_i2c.c @@ -93,15 +93,15 @@ static int st_gyro_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id st_gyro_id_table[] = { - { L3G4200D_GYRO_DEV_NAME }, - { LSM330D_GYRO_DEV_NAME }, - { LSM330DL_GYRO_DEV_NAME }, - { LSM330DLC_GYRO_DEV_NAME }, - { L3GD20_GYRO_DEV_NAME }, - { L3GD20H_GYRO_DEV_NAME }, - { L3G4IS_GYRO_DEV_NAME }, - { LSM330_GYRO_DEV_NAME }, - { LSM9DS0_GYRO_DEV_NAME }, + { .name = L3G4200D_GYRO_DEV_NAME }, + { .name = LSM330D_GYRO_DEV_NAME }, + { .name = LSM330DL_GYRO_DEV_NAME }, + { .name = LSM330DLC_GYRO_DEV_NAME }, + { .name = L3GD20_GYRO_DEV_NAME }, + { .name = L3GD20H_GYRO_DEV_NAME }, + { .name = L3G4IS_GYRO_DEV_NAME }, + { .name = LSM330_GYRO_DEV_NAME }, + { .name = LSM9DS0_GYRO_DEV_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, st_gyro_id_table); diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c index 032da52a96d0..2357e2dd7017 100644 --- a/drivers/iio/health/afe4404.c +++ b/drivers/iio/health/afe4404.c @@ -575,7 +575,7 @@ static int afe4404_probe(struct i2c_client *client) } static const struct i2c_device_id afe4404_ids[] = { - { "afe4404" }, + { .name = "afe4404" }, { } }; MODULE_DEVICE_TABLE(i2c, afe4404_ids); diff --git a/drivers/iio/health/max30100.c b/drivers/iio/health/max30100.c index 7dfdb5eb305e..97352485f5e2 100644 --- a/drivers/iio/health/max30100.c +++ b/drivers/iio/health/max30100.c @@ -507,7 +507,7 @@ static void max30100_remove(struct i2c_client *client) } static const struct i2c_device_id max30100_id[] = { - { "max30100" }, + { .name = "max30100" }, { } }; MODULE_DEVICE_TABLE(i2c, max30100_id); diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c index 47da44efd68b..c830eaf286f7 100644 --- a/drivers/iio/health/max30102.c +++ b/drivers/iio/health/max30102.c @@ -596,9 +596,9 @@ static void max30102_remove(struct i2c_client *client) } static const struct i2c_device_id max30102_id[] = { - { "max30101", max30105 }, - { "max30102", max30102 }, - { "max30105", max30105 }, + { .name = "max30101", .driver_data = max30105 }, + { .name = "max30102", .driver_data = max30102 }, + { .name = "max30105", .driver_data = max30105 }, { } }; MODULE_DEVICE_TABLE(i2c, max30102_id); diff --git a/drivers/iio/humidity/am2315.c b/drivers/iio/humidity/am2315.c index 02ca23eb8991..f29baa251f9f 100644 --- a/drivers/iio/humidity/am2315.c +++ b/drivers/iio/humidity/am2315.c @@ -250,7 +250,7 @@ static int am2315_probe(struct i2c_client *client) } static const struct i2c_device_id am2315_i2c_id[] = { - { "am2315" }, + { .name = "am2315" }, { } }; MODULE_DEVICE_TABLE(i2c, am2315_i2c_id); diff --git a/drivers/iio/humidity/ens210.c b/drivers/iio/humidity/ens210.c index 77418d97f30d..22ad208e6aa6 100644 --- a/drivers/iio/humidity/ens210.c +++ b/drivers/iio/humidity/ens210.c @@ -314,12 +314,12 @@ static const struct of_device_id ens210_of_match[] = { MODULE_DEVICE_TABLE(of, ens210_of_match); static const struct i2c_device_id ens210_id_table[] = { - { "ens210", (kernel_ulong_t)&ens210_chip_info_data }, - { "ens210a", (kernel_ulong_t)&ens210a_chip_info_data }, - { "ens211", (kernel_ulong_t)&ens211_chip_info_data }, - { "ens212", (kernel_ulong_t)&ens212_chip_info_data }, - { "ens213a", (kernel_ulong_t)&ens213a_chip_info_data }, - { "ens215", (kernel_ulong_t)&ens215_chip_info_data }, + { .name = "ens210", .driver_data = (kernel_ulong_t)&ens210_chip_info_data }, + { .name = "ens210a", .driver_data = (kernel_ulong_t)&ens210a_chip_info_data }, + { .name = "ens211", .driver_data = (kernel_ulong_t)&ens211_chip_info_data }, + { .name = "ens212", .driver_data = (kernel_ulong_t)&ens212_chip_info_data }, + { .name = "ens213a", .driver_data = (kernel_ulong_t)&ens213a_chip_info_data }, + { .name = "ens215", .driver_data = (kernel_ulong_t)&ens215_chip_info_data }, { } }; MODULE_DEVICE_TABLE(i2c, ens210_id_table); diff --git a/drivers/iio/humidity/hdc100x.c b/drivers/iio/humidity/hdc100x.c index c2b36e682e06..87194802cc4f 100644 --- a/drivers/iio/humidity/hdc100x.c +++ b/drivers/iio/humidity/hdc100x.c @@ -380,12 +380,12 @@ static int hdc100x_probe(struct i2c_client *client) } static const struct i2c_device_id hdc100x_id[] = { - { "hdc100x" }, - { "hdc1000" }, - { "hdc1008" }, - { "hdc1010" }, - { "hdc1050" }, - { "hdc1080" }, + { .name = "hdc100x" }, + { .name = "hdc1000" }, + { .name = "hdc1008" }, + { .name = "hdc1010" }, + { .name = "hdc1050" }, + { .name = "hdc1080" }, { } }; MODULE_DEVICE_TABLE(i2c, hdc100x_id); diff --git a/drivers/iio/humidity/hdc2010.c b/drivers/iio/humidity/hdc2010.c index 1a0f18251381..82d68987556d 100644 --- a/drivers/iio/humidity/hdc2010.c +++ b/drivers/iio/humidity/hdc2010.c @@ -317,8 +317,8 @@ static void hdc2010_remove(struct i2c_client *client) } static const struct i2c_device_id hdc2010_id[] = { - { "hdc2010" }, - { "hdc2080" }, + { .name = "hdc2010" }, + { .name = "hdc2080" }, { } }; MODULE_DEVICE_TABLE(i2c, hdc2010_id); diff --git a/drivers/iio/humidity/hdc3020.c b/drivers/iio/humidity/hdc3020.c index 78b2c171c8da..1ae8702ada54 100644 --- a/drivers/iio/humidity/hdc3020.c +++ b/drivers/iio/humidity/hdc3020.c @@ -873,9 +873,9 @@ static int hdc3020_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(hdc3020_pm_ops, hdc3020_suspend, hdc3020_resume); static const struct i2c_device_id hdc3020_id[] = { - { "hdc3020" }, - { "hdc3021" }, - { "hdc3022" }, + { .name = "hdc3020" }, + { .name = "hdc3021" }, + { .name = "hdc3022" }, { } }; MODULE_DEVICE_TABLE(i2c, hdc3020_id); diff --git a/drivers/iio/humidity/hts221_i2c.c b/drivers/iio/humidity/hts221_i2c.c index cbaa7d1af6c4..e823d37384d7 100644 --- a/drivers/iio/humidity/hts221_i2c.c +++ b/drivers/iio/humidity/hts221_i2c.c @@ -53,7 +53,7 @@ static const struct of_device_id hts221_i2c_of_match[] = { MODULE_DEVICE_TABLE(of, hts221_i2c_of_match); static const struct i2c_device_id hts221_i2c_id_table[] = { - { HTS221_DEV_NAME }, + { .name = HTS221_DEV_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, hts221_i2c_id_table); diff --git a/drivers/iio/humidity/htu21.c b/drivers/iio/humidity/htu21.c index 7f1775bd26fd..9ba7507f105e 100644 --- a/drivers/iio/humidity/htu21.c +++ b/drivers/iio/humidity/htu21.c @@ -230,8 +230,8 @@ static int htu21_probe(struct i2c_client *client) } static const struct i2c_device_id htu21_id[] = { - {"htu21", HTU21}, - {"ms8607-humidity", MS8607}, + { .name = "htu21", .driver_data = HTU21 }, + { .name = "ms8607-humidity", .driver_data = MS8607 }, { } }; MODULE_DEVICE_TABLE(i2c, htu21_id); diff --git a/drivers/iio/humidity/si7005.c b/drivers/iio/humidity/si7005.c index 0797ece1fcba..0c11d0d3afe0 100644 --- a/drivers/iio/humidity/si7005.c +++ b/drivers/iio/humidity/si7005.c @@ -163,8 +163,8 @@ static int si7005_probe(struct i2c_client *client) } static const struct i2c_device_id si7005_id[] = { - { "si7005" }, - { "th02" }, + { .name = "si7005" }, + { .name = "th02" }, { } }; MODULE_DEVICE_TABLE(i2c, si7005_id); diff --git a/drivers/iio/humidity/si7020.c b/drivers/iio/humidity/si7020.c index ff2dba50c0a5..9fb1e3ede3ff 100644 --- a/drivers/iio/humidity/si7020.c +++ b/drivers/iio/humidity/si7020.c @@ -267,8 +267,8 @@ static int si7020_probe(struct i2c_client *client) } static const struct i2c_device_id si7020_id[] = { - { "si7020" }, - { "th06" }, + { .name = "si7020" }, + { .name = "th06" }, { } }; MODULE_DEVICE_TABLE(i2c, si7020_id); diff --git a/drivers/iio/imu/bmi160/bmi160_i2c.c b/drivers/iio/imu/bmi160/bmi160_i2c.c index 3e2758f4e0d3..29f3c4acb123 100644 --- a/drivers/iio/imu/bmi160/bmi160_i2c.c +++ b/drivers/iio/imu/bmi160/bmi160_i2c.c @@ -38,8 +38,8 @@ static int bmi160_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id bmi160_i2c_id[] = { - { "bmi120" }, - { "bmi160" }, + { .name = "bmi120" }, + { .name = "bmi160" }, { } }; MODULE_DEVICE_TABLE(i2c, bmi160_i2c_id); diff --git a/drivers/iio/imu/bmi270/bmi270_i2c.c b/drivers/iio/imu/bmi270/bmi270_i2c.c index b92da4e0776f..1e6839f9669e 100644 --- a/drivers/iio/imu/bmi270/bmi270_i2c.c +++ b/drivers/iio/imu/bmi270/bmi270_i2c.c @@ -33,8 +33,8 @@ static int bmi270_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id bmi270_i2c_id[] = { - { "bmi260", (kernel_ulong_t)&bmi260_chip_info }, - { "bmi270", (kernel_ulong_t)&bmi270_chip_info }, + { .name = "bmi260", .driver_data = (kernel_ulong_t)&bmi260_chip_info }, + { .name = "bmi270", .driver_data = (kernel_ulong_t)&bmi270_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, bmi270_i2c_id); diff --git a/drivers/iio/imu/bmi323/bmi323_i2c.c b/drivers/iio/imu/bmi323/bmi323_i2c.c index 8457fe304db8..328733ddeed7 100644 --- a/drivers/iio/imu/bmi323/bmi323_i2c.c +++ b/drivers/iio/imu/bmi323/bmi323_i2c.c @@ -114,7 +114,7 @@ static const struct acpi_device_id bmi323_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, bmi323_acpi_match); static const struct i2c_device_id bmi323_i2c_ids[] = { - { "bmi323" }, + { .name = "bmi323" }, { } }; MODULE_DEVICE_TABLE(i2c, bmi323_i2c_ids); diff --git a/drivers/iio/imu/bno055/bno055_i2c.c b/drivers/iio/imu/bno055/bno055_i2c.c index f49d0905ee33..000bc9392480 100644 --- a/drivers/iio/imu/bno055/bno055_i2c.c +++ b/drivers/iio/imu/bno055/bno055_i2c.c @@ -30,7 +30,7 @@ static int bno055_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id bno055_i2c_id[] = { - { "bno055" }, + { .name = "bno055" }, { } }; MODULE_DEVICE_TABLE(i2c, bno055_i2c_id); diff --git a/drivers/iio/imu/fxos8700_i2c.c b/drivers/iio/imu/fxos8700_i2c.c index 2cc4a27a4527..c81e48c9d8e2 100644 --- a/drivers/iio/imu/fxos8700_i2c.c +++ b/drivers/iio/imu/fxos8700_i2c.c @@ -36,7 +36,7 @@ static int fxos8700_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id fxos8700_i2c_id[] = { - { "fxos8700" }, + { .name = "fxos8700" }, { } }; MODULE_DEVICE_TABLE(i2c, fxos8700_i2c_id); diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c index 7e4d3ea68721..99d37ac53bbe 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c @@ -75,13 +75,13 @@ static int inv_icm42600_probe(struct i2c_client *client) * supported by this driver */ static const struct i2c_device_id inv_icm42600_id[] = { - { "icm42600", INV_CHIP_ICM42600 }, - { "icm42602", INV_CHIP_ICM42602 }, - { "icm42605", INV_CHIP_ICM42605 }, - { "icm42686", INV_CHIP_ICM42686 }, - { "icm42622", INV_CHIP_ICM42622 }, - { "icm42688", INV_CHIP_ICM42688 }, - { "icm42631", INV_CHIP_ICM42631 }, + { .name = "icm42600", .driver_data = INV_CHIP_ICM42600 }, + { .name = "icm42602", .driver_data = INV_CHIP_ICM42602 }, + { .name = "icm42605", .driver_data = INV_CHIP_ICM42605 }, + { .name = "icm42686", .driver_data = INV_CHIP_ICM42686 }, + { .name = "icm42622", .driver_data = INV_CHIP_ICM42622 }, + { .name = "icm42688", .driver_data = INV_CHIP_ICM42688 }, + { .name = "icm42631", .driver_data = INV_CHIP_ICM42631 }, { } }; MODULE_DEVICE_TABLE(i2c, inv_icm42600_id); diff --git a/drivers/iio/imu/inv_icm45600/inv_icm45600_i2c.c b/drivers/iio/imu/inv_icm45600/inv_icm45600_i2c.c index 5ebc18121a11..26fba538a3cf 100644 --- a/drivers/iio/imu/inv_icm45600/inv_icm45600_i2c.c +++ b/drivers/iio/imu/inv_icm45600/inv_icm45600_i2c.c @@ -39,14 +39,14 @@ static int inv_icm45600_probe(struct i2c_client *client) * supported by this driver. */ static const struct i2c_device_id inv_icm45600_id[] = { - { "icm45605", (kernel_ulong_t)&inv_icm45605_chip_info }, - { "icm45606", (kernel_ulong_t)&inv_icm45606_chip_info }, - { "icm45608", (kernel_ulong_t)&inv_icm45608_chip_info }, - { "icm45634", (kernel_ulong_t)&inv_icm45634_chip_info }, - { "icm45686", (kernel_ulong_t)&inv_icm45686_chip_info }, - { "icm45687", (kernel_ulong_t)&inv_icm45687_chip_info }, - { "icm45688p", (kernel_ulong_t)&inv_icm45688p_chip_info }, - { "icm45689", (kernel_ulong_t)&inv_icm45689_chip_info }, + { .name = "icm45605", .driver_data = (kernel_ulong_t)&inv_icm45605_chip_info }, + { .name = "icm45606", .driver_data = (kernel_ulong_t)&inv_icm45606_chip_info }, + { .name = "icm45608", .driver_data = (kernel_ulong_t)&inv_icm45608_chip_info }, + { .name = "icm45634", .driver_data = (kernel_ulong_t)&inv_icm45634_chip_info }, + { .name = "icm45686", .driver_data = (kernel_ulong_t)&inv_icm45686_chip_info }, + { .name = "icm45687", .driver_data = (kernel_ulong_t)&inv_icm45687_chip_info }, + { .name = "icm45688p", .driver_data = (kernel_ulong_t)&inv_icm45688p_chip_info }, + { .name = "icm45689", .driver_data = (kernel_ulong_t)&inv_icm45689_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, inv_icm45600_id); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c index 8dc61812a8fc..4868e1576cee 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c @@ -174,24 +174,24 @@ static void inv_mpu_remove(struct i2c_client *client) * supported by this driver */ static const struct i2c_device_id inv_mpu_id[] = { - {"mpu6050", INV_MPU6050}, - {"mpu6500", INV_MPU6500}, - {"mpu6515", INV_MPU6515}, - {"mpu6880", INV_MPU6880}, - {"mpu9150", INV_MPU9150}, - {"mpu9250", INV_MPU9250}, - {"mpu9255", INV_MPU9255}, - {"icm20608", INV_ICM20608}, - {"icm20608d", INV_ICM20608D}, - {"icm20609", INV_ICM20609}, - {"icm20689", INV_ICM20689}, - {"icm20600", INV_ICM20600}, - {"icm20602", INV_ICM20602}, - {"icm20690", INV_ICM20690}, - {"iam20380", INV_IAM20380}, - {"iam20680", INV_IAM20680}, - {"iam20680hp", INV_IAM20680HP}, - {"iam20680ht", INV_IAM20680HT}, + { .name = "mpu6050", .driver_data = INV_MPU6050 }, + { .name = "mpu6500", .driver_data = INV_MPU6500 }, + { .name = "mpu6515", .driver_data = INV_MPU6515 }, + { .name = "mpu6880", .driver_data = INV_MPU6880 }, + { .name = "mpu9150", .driver_data = INV_MPU9150 }, + { .name = "mpu9250", .driver_data = INV_MPU9250 }, + { .name = "mpu9255", .driver_data = INV_MPU9255 }, + { .name = "icm20608", .driver_data = INV_ICM20608 }, + { .name = "icm20608d", .driver_data = INV_ICM20608D }, + { .name = "icm20609", .driver_data = INV_ICM20609 }, + { .name = "icm20689", .driver_data = INV_ICM20689 }, + { .name = "icm20600", .driver_data = INV_ICM20600 }, + { .name = "icm20602", .driver_data = INV_ICM20602 }, + { .name = "icm20690", .driver_data = INV_ICM20690 }, + { .name = "iam20380", .driver_data = INV_IAM20380 }, + { .name = "iam20680", .driver_data = INV_IAM20680 }, + { .name = "iam20680hp", .driver_data = INV_IAM20680HP }, + { .name = "iam20680ht", .driver_data = INV_IAM20680HT }, { } }; diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c index 3cd91d8a89ee..a4d176f81f0e 100644 --- a/drivers/iio/imu/kmx61.c +++ b/drivers/iio/imu/kmx61.c @@ -1481,7 +1481,7 @@ static const struct dev_pm_ops kmx61_pm_ops = { }; static const struct i2c_device_id kmx61_id[] = { - { "kmx611021" }, + { .name = "kmx611021" }, { } }; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c index b2a7c2eaf50d..edec898cb11f 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c @@ -150,30 +150,30 @@ static const struct acpi_device_id st_lsm6dsx_i2c_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, st_lsm6dsx_i2c_acpi_match); static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = { - { ST_LSM6DS3_DEV_NAME, ST_LSM6DS3_ID }, - { ST_LSM6DS3H_DEV_NAME, ST_LSM6DS3H_ID }, - { ST_LSM6DSL_DEV_NAME, ST_LSM6DSL_ID }, - { ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID }, - { ST_ISM330DLC_DEV_NAME, ST_ISM330DLC_ID }, - { ST_LSM6DSO_DEV_NAME, ST_LSM6DSO_ID }, - { ST_ASM330LHH_DEV_NAME, ST_ASM330LHH_ID }, - { ST_LSM6DSOX_DEV_NAME, ST_LSM6DSOX_ID }, - { ST_LSM6DSR_DEV_NAME, ST_LSM6DSR_ID }, - { ST_LSM6DS3TRC_DEV_NAME, ST_LSM6DS3TRC_ID }, - { ST_ISM330DHCX_DEV_NAME, ST_ISM330DHCX_ID }, - { ST_LSM9DS1_DEV_NAME, ST_LSM9DS1_ID }, - { ST_LSM6DS0_DEV_NAME, ST_LSM6DS0_ID }, - { ST_LSM6DSRX_DEV_NAME, ST_LSM6DSRX_ID }, - { ST_LSM6DST_DEV_NAME, ST_LSM6DST_ID }, - { ST_LSM6DSOP_DEV_NAME, ST_LSM6DSOP_ID }, - { ST_ASM330LHHX_DEV_NAME, ST_ASM330LHHX_ID }, - { ST_LSM6DSTX_DEV_NAME, ST_LSM6DSTX_ID }, - { ST_LSM6DSV_DEV_NAME, ST_LSM6DSV_ID }, - { ST_LSM6DSV16X_DEV_NAME, ST_LSM6DSV16X_ID }, - { ST_LSM6DSO16IS_DEV_NAME, ST_LSM6DSO16IS_ID }, - { ST_ISM330IS_DEV_NAME, ST_ISM330IS_ID }, - { ST_ASM330LHB_DEV_NAME, ST_ASM330LHB_ID }, - { ST_ASM330LHHXG1_DEV_NAME, ST_ASM330LHHXG1_ID }, + { .name = ST_LSM6DS3_DEV_NAME, .driver_data = ST_LSM6DS3_ID }, + { .name = ST_LSM6DS3H_DEV_NAME, .driver_data = ST_LSM6DS3H_ID }, + { .name = ST_LSM6DSL_DEV_NAME, .driver_data = ST_LSM6DSL_ID }, + { .name = ST_LSM6DSM_DEV_NAME, .driver_data = ST_LSM6DSM_ID }, + { .name = ST_ISM330DLC_DEV_NAME, .driver_data = ST_ISM330DLC_ID }, + { .name = ST_LSM6DSO_DEV_NAME, .driver_data = ST_LSM6DSO_ID }, + { .name = ST_ASM330LHH_DEV_NAME, .driver_data = ST_ASM330LHH_ID }, + { .name = ST_LSM6DSOX_DEV_NAME, .driver_data = ST_LSM6DSOX_ID }, + { .name = ST_LSM6DSR_DEV_NAME, .driver_data = ST_LSM6DSR_ID }, + { .name = ST_LSM6DS3TRC_DEV_NAME, .driver_data = ST_LSM6DS3TRC_ID }, + { .name = ST_ISM330DHCX_DEV_NAME, .driver_data = ST_ISM330DHCX_ID }, + { .name = ST_LSM9DS1_DEV_NAME, .driver_data = ST_LSM9DS1_ID }, + { .name = ST_LSM6DS0_DEV_NAME, .driver_data = ST_LSM6DS0_ID }, + { .name = ST_LSM6DSRX_DEV_NAME, .driver_data = ST_LSM6DSRX_ID }, + { .name = ST_LSM6DST_DEV_NAME, .driver_data = ST_LSM6DST_ID }, + { .name = ST_LSM6DSOP_DEV_NAME, .driver_data = ST_LSM6DSOP_ID }, + { .name = ST_ASM330LHHX_DEV_NAME, .driver_data = ST_ASM330LHHX_ID }, + { .name = ST_LSM6DSTX_DEV_NAME, .driver_data = ST_LSM6DSTX_ID }, + { .name = ST_LSM6DSV_DEV_NAME, .driver_data = ST_LSM6DSV_ID }, + { .name = ST_LSM6DSV16X_DEV_NAME, .driver_data = ST_LSM6DSV16X_ID }, + { .name = ST_LSM6DSO16IS_DEV_NAME, .driver_data = ST_LSM6DSO16IS_ID }, + { .name = ST_ISM330IS_DEV_NAME, .driver_data = ST_ISM330IS_ID }, + { .name = ST_ASM330LHB_DEV_NAME, .driver_data = ST_ASM330LHB_ID }, + { .name = ST_ASM330LHHXG1_DEV_NAME, .driver_data = ST_ASM330LHHXG1_ID }, { } }; MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table); diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c index 4232a9d800fc..f71ae7a59a22 100644 --- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c @@ -33,8 +33,8 @@ static const struct of_device_id st_lsm9ds0_of_match[] = { MODULE_DEVICE_TABLE(of, st_lsm9ds0_of_match); static const struct i2c_device_id st_lsm9ds0_id_table[] = { - { LSM303D_IMU_DEV_NAME }, - { LSM9DS0_IMU_DEV_NAME }, + { .name = LSM303D_IMU_DEV_NAME }, + { .name = LSM9DS0_IMU_DEV_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, st_lsm9ds0_id_table); diff --git a/drivers/iio/light/adjd_s311.c b/drivers/iio/light/adjd_s311.c index edb3d9dc8bed..088b9431d10a 100644 --- a/drivers/iio/light/adjd_s311.c +++ b/drivers/iio/light/adjd_s311.c @@ -260,7 +260,7 @@ static int adjd_s311_probe(struct i2c_client *client) } static const struct i2c_device_id adjd_s311_id[] = { - { "adjd_s311" }, + { .name = "adjd_s311" }, { } }; MODULE_DEVICE_TABLE(i2c, adjd_s311_id); diff --git a/drivers/iio/light/adux1020.c b/drivers/iio/light/adux1020.c index 66ff9c5fb66a..633a105fd7f0 100644 --- a/drivers/iio/light/adux1020.c +++ b/drivers/iio/light/adux1020.c @@ -818,7 +818,7 @@ static int adux1020_probe(struct i2c_client *client) } static const struct i2c_device_id adux1020_id[] = { - { "adux1020" }, + { .name = "adux1020" }, { } }; MODULE_DEVICE_TABLE(i2c, adux1020_id); diff --git a/drivers/iio/light/al3000a.c b/drivers/iio/light/al3000a.c index 9871096cbab3..d4e6fedf3d9e 100644 --- a/drivers/iio/light/al3000a.c +++ b/drivers/iio/light/al3000a.c @@ -183,7 +183,7 @@ static int al3000a_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(al3000a_pm_ops, al3000a_suspend, al3000a_resume); static const struct i2c_device_id al3000a_id[] = { - { "al3000a" }, + { .name = "al3000a" }, { } }; MODULE_DEVICE_TABLE(i2c, al3000a_id); diff --git a/drivers/iio/light/al3010.c b/drivers/iio/light/al3010.c index 0932fa2b49fa..f48420135320 100644 --- a/drivers/iio/light/al3010.c +++ b/drivers/iio/light/al3010.c @@ -218,7 +218,7 @@ static int al3010_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(al3010_pm_ops, al3010_suspend, al3010_resume); static const struct i2c_device_id al3010_id[] = { - {"al3010", }, + { .name = "al3010" }, { } }; MODULE_DEVICE_TABLE(i2c, al3010_id); diff --git a/drivers/iio/light/al3320a.c b/drivers/iio/light/al3320a.c index 63f5a85912fc..617b4f15ea3f 100644 --- a/drivers/iio/light/al3320a.c +++ b/drivers/iio/light/al3320a.c @@ -246,7 +246,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(al3320a_pm_ops, al3320a_suspend, al3320a_resume); static const struct i2c_device_id al3320a_id[] = { - { "al3320a" }, + { .name = "al3320a" }, { } }; MODULE_DEVICE_TABLE(i2c, al3320a_id); diff --git a/drivers/iio/light/apds9300.c b/drivers/iio/light/apds9300.c index 05ba21675063..d60ade1209f3 100644 --- a/drivers/iio/light/apds9300.c +++ b/drivers/iio/light/apds9300.c @@ -492,7 +492,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(apds9300_pm_ops, apds9300_suspend, apds9300_resume); static const struct i2c_device_id apds9300_id[] = { - { APDS9300_DRV_NAME }, + { .name = APDS9300_DRV_NAME }, { } }; diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c index 785c5dbe2d08..2686c3b0c03b 100644 --- a/drivers/iio/light/apds9960.c +++ b/drivers/iio/light/apds9960.c @@ -1154,7 +1154,7 @@ static const struct dev_pm_ops apds9960_pm_ops = { }; static const struct i2c_device_id apds9960_id[] = { - { "apds9960" }, + { .name = "apds9960" }, { } }; MODULE_DEVICE_TABLE(i2c, apds9960_id); diff --git a/drivers/iio/light/as73211.c b/drivers/iio/light/as73211.c index 9fe830dac679..67f33bbe1c13 100644 --- a/drivers/iio/light/as73211.c +++ b/drivers/iio/light/as73211.c @@ -875,8 +875,8 @@ static const struct of_device_id as73211_of_match[] = { MODULE_DEVICE_TABLE(of, as73211_of_match); static const struct i2c_device_id as73211_id[] = { - { "as73211", (kernel_ulong_t)&as73211_spec }, - { "as7331", (kernel_ulong_t)&as7331_spec }, + { .name = "as73211", .driver_data = (kernel_ulong_t)&as73211_spec }, + { .name = "as7331", .driver_data = (kernel_ulong_t)&as7331_spec }, { } }; MODULE_DEVICE_TABLE(i2c, as73211_id); diff --git a/drivers/iio/light/bh1745.c b/drivers/iio/light/bh1745.c index 10b00344bbed..0aa8e5cc6c56 100644 --- a/drivers/iio/light/bh1745.c +++ b/drivers/iio/light/bh1745.c @@ -874,7 +874,7 @@ static int bh1745_probe(struct i2c_client *client) } static const struct i2c_device_id bh1745_idtable[] = { - { "bh1745" }, + { .name = "bh1745" }, { } }; MODULE_DEVICE_TABLE(i2c, bh1745_idtable); diff --git a/drivers/iio/light/bh1750.c b/drivers/iio/light/bh1750.c index 764f88826fcb..a51ac98c83c8 100644 --- a/drivers/iio/light/bh1750.c +++ b/drivers/iio/light/bh1750.c @@ -319,11 +319,11 @@ static int bh1750_suspend(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(bh1750_pm_ops, bh1750_suspend, NULL); static const struct i2c_device_id bh1750_id[] = { - { "bh1710", BH1710 }, - { "bh1715", BH1750 }, - { "bh1721", BH1721 }, - { "bh1750", BH1750 }, - { "bh1751", BH1750 }, + { .name = "bh1710", .driver_data = BH1710 }, + { .name = "bh1715", .driver_data = BH1750 }, + { .name = "bh1721", .driver_data = BH1721 }, + { .name = "bh1750", .driver_data = BH1750 }, + { .name = "bh1751", .driver_data = BH1750 }, { } }; MODULE_DEVICE_TABLE(i2c, bh1750_id); diff --git a/drivers/iio/light/bh1780.c b/drivers/iio/light/bh1780.c index a740d1f992a8..ead98fb82af9 100644 --- a/drivers/iio/light/bh1780.c +++ b/drivers/iio/light/bh1780.c @@ -255,7 +255,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(bh1780_dev_pm_ops, bh1780_runtime_suspend, bh1780_runtime_resume, NULL); static const struct i2c_device_id bh1780_id[] = { - { "bh1780" }, + { .name = "bh1780" }, { } }; diff --git a/drivers/iio/light/cm3232.c b/drivers/iio/light/cm3232.c index 90aa77e3a03b..fec233d06602 100644 --- a/drivers/iio/light/cm3232.c +++ b/drivers/iio/light/cm3232.c @@ -366,7 +366,7 @@ static void cm3232_remove(struct i2c_client *client) } static const struct i2c_device_id cm3232_id[] = { - { "cm3232" }, + { .name = "cm3232" }, { } }; MODULE_DEVICE_TABLE(i2c, cm3232_id); diff --git a/drivers/iio/light/cm3323.c b/drivers/iio/light/cm3323.c index 79ad6e2209ca..0fd4ddb69c06 100644 --- a/drivers/iio/light/cm3323.c +++ b/drivers/iio/light/cm3323.c @@ -250,7 +250,7 @@ static int cm3323_probe(struct i2c_client *client) } static const struct i2c_device_id cm3323_id[] = { - { "cm3323" }, + { .name = "cm3323" }, { } }; MODULE_DEVICE_TABLE(i2c, cm3323_id); diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c index 446dd54d5037..6ebd8ce4ca12 100644 --- a/drivers/iio/light/cm36651.c +++ b/drivers/iio/light/cm36651.c @@ -713,7 +713,7 @@ static void cm36651_remove(struct i2c_client *client) } static const struct i2c_device_id cm36651_id[] = { - { "cm36651" }, + { .name = "cm36651" }, { } }; diff --git a/drivers/iio/light/gp2ap002.c b/drivers/iio/light/gp2ap002.c index a0d8a58f2704..c83f67ff2464 100644 --- a/drivers/iio/light/gp2ap002.c +++ b/drivers/iio/light/gp2ap002.c @@ -690,7 +690,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(gp2ap002_dev_pm_ops, gp2ap002_runtime_suspend, gp2ap002_runtime_resume, NULL); static const struct i2c_device_id gp2ap002_id_table[] = { - { "gp2ap002" }, + { .name = "gp2ap002" }, { } }; MODULE_DEVICE_TABLE(i2c, gp2ap002_id_table); diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c index 7e388319ee2e..c218bb3519df 100644 --- a/drivers/iio/light/gp2ap020a00f.c +++ b/drivers/iio/light/gp2ap020a00f.c @@ -1525,7 +1525,7 @@ static void gp2ap020a00f_remove(struct i2c_client *client) } static const struct i2c_device_id gp2ap020a00f_id[] = { - { "gp2ap020a00f" }, + { .name = "gp2ap020a00f" }, { } }; MODULE_DEVICE_TABLE(i2c, gp2ap020a00f_id); diff --git a/drivers/iio/light/isl29018.c b/drivers/iio/light/isl29018.c index b6ab726d1dae..8a39afaa2a37 100644 --- a/drivers/iio/light/isl29018.c +++ b/drivers/iio/light/isl29018.c @@ -829,9 +829,9 @@ static const struct acpi_device_id isl29018_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, isl29018_acpi_match); static const struct i2c_device_id isl29018_id[] = { - {"isl29018", isl29018}, - {"isl29023", isl29023}, - {"isl29035", isl29035}, + { .name = "isl29018", .driver_data = isl29018 }, + { .name = "isl29023", .driver_data = isl29023 }, + { .name = "isl29035", .driver_data = isl29035 }, { } }; MODULE_DEVICE_TABLE(i2c, isl29018_id); diff --git a/drivers/iio/light/isl29028.c b/drivers/iio/light/isl29028.c index 374bccad9119..b88e7c4eae3e 100644 --- a/drivers/iio/light/isl29028.c +++ b/drivers/iio/light/isl29028.c @@ -673,8 +673,8 @@ static DEFINE_RUNTIME_DEV_PM_OPS(isl29028_pm_ops, isl29028_suspend, isl29028_resume, NULL); static const struct i2c_device_id isl29028_id[] = { - { "isl29028" }, - { "isl29030" }, + { .name = "isl29028" }, + { .name = "isl29030" }, { } }; MODULE_DEVICE_TABLE(i2c, isl29028_id); diff --git a/drivers/iio/light/isl29125.c b/drivers/iio/light/isl29125.c index 3acb8a4f1d12..9e0b7e6a3ecf 100644 --- a/drivers/iio/light/isl29125.c +++ b/drivers/iio/light/isl29125.c @@ -325,7 +325,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(isl29125_pm_ops, isl29125_suspend, isl29125_resume); static const struct i2c_device_id isl29125_id[] = { - { "isl29125" }, + { .name = "isl29125" }, { } }; MODULE_DEVICE_TABLE(i2c, isl29125_id); diff --git a/drivers/iio/light/isl76682.c b/drivers/iio/light/isl76682.c index b6f2fc9978f6..9b9052d08e41 100644 --- a/drivers/iio/light/isl76682.c +++ b/drivers/iio/light/isl76682.c @@ -319,7 +319,7 @@ static int isl76682_probe(struct i2c_client *client) } static const struct i2c_device_id isl76682_id[] = { - { "isl76682" }, + { .name = "isl76682" }, { } }; MODULE_DEVICE_TABLE(i2c, isl76682_id); diff --git a/drivers/iio/light/jsa1212.c b/drivers/iio/light/jsa1212.c index 6978d02a4df5..cc0a7c4a33dd 100644 --- a/drivers/iio/light/jsa1212.c +++ b/drivers/iio/light/jsa1212.c @@ -428,7 +428,7 @@ static const struct acpi_device_id jsa1212_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, jsa1212_acpi_match); static const struct i2c_device_id jsa1212_id[] = { - { JSA1212_DRIVER_NAME }, + { .name = JSA1212_DRIVER_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, jsa1212_id); diff --git a/drivers/iio/light/ltr390.c b/drivers/iio/light/ltr390.c index f1702aca582d..bdc74b8226c8 100644 --- a/drivers/iio/light/ltr390.c +++ b/drivers/iio/light/ltr390.c @@ -889,7 +889,7 @@ static const struct dev_pm_ops ltr390_pm_ops = { }; static const struct i2c_device_id ltr390_id[] = { - { "ltr390" }, + { .name = "ltr390" }, { } }; MODULE_DEVICE_TABLE(i2c, ltr390_id); diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c index 4d99ae336f61..15dd82ecf745 100644 --- a/drivers/iio/light/ltr501.c +++ b/drivers/iio/light/ltr501.c @@ -1601,10 +1601,10 @@ static const struct acpi_device_id ltr_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, ltr_acpi_match); static const struct i2c_device_id ltr501_id[] = { - { "ltr501", ltr501 }, - { "ltr559", ltr559 }, - { "ltr301", ltr301 }, - { "ltr303", ltr303 }, + { .name = "ltr501", .driver_data = ltr501 }, + { .name = "ltr559", .driver_data = ltr559 }, + { .name = "ltr301", .driver_data = ltr301 }, + { .name = "ltr303", .driver_data = ltr303 }, { } }; MODULE_DEVICE_TABLE(i2c, ltr501_id); diff --git a/drivers/iio/light/ltrf216a.c b/drivers/iio/light/ltrf216a.c index 5f27f754fe1c..aad96fc91565 100644 --- a/drivers/iio/light/ltrf216a.c +++ b/drivers/iio/light/ltrf216a.c @@ -551,8 +551,8 @@ static const struct ltr_chip_info ltrf216a_chip_info = { }; static const struct i2c_device_id ltrf216a_id[] = { - { "ltr308", .driver_data = (kernel_ulong_t)<r308_chip_info }, - { "ltrf216a", .driver_data = (kernel_ulong_t)<rf216a_chip_info }, + { .name = "ltr308", .driver_data = (kernel_ulong_t)<r308_chip_info }, + { .name = "ltrf216a", .driver_data = (kernel_ulong_t)<rf216a_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, ltrf216a_id); diff --git a/drivers/iio/light/lv0104cs.c b/drivers/iio/light/lv0104cs.c index 916109ec3217..eba82c334d70 100644 --- a/drivers/iio/light/lv0104cs.c +++ b/drivers/iio/light/lv0104cs.c @@ -510,7 +510,7 @@ static int lv0104cs_probe(struct i2c_client *client) } static const struct i2c_device_id lv0104cs_id[] = { - { "lv0104cs" }, + { .name = "lv0104cs" }, { } }; MODULE_DEVICE_TABLE(i2c, lv0104cs_id); diff --git a/drivers/iio/light/max44000.c b/drivers/iio/light/max44000.c index 039d45af3a7f..6594054c40c7 100644 --- a/drivers/iio/light/max44000.c +++ b/drivers/iio/light/max44000.c @@ -598,7 +598,7 @@ static int max44000_probe(struct i2c_client *client) } static const struct i2c_device_id max44000_id[] = { - { "max44000" }, + { .name = "max44000" }, { } }; MODULE_DEVICE_TABLE(i2c, max44000_id); diff --git a/drivers/iio/light/max44009.c b/drivers/iio/light/max44009.c index 8cd7f5664e5b..82b8a806c5fa 100644 --- a/drivers/iio/light/max44009.c +++ b/drivers/iio/light/max44009.c @@ -534,7 +534,7 @@ static const struct of_device_id max44009_of_match[] = { MODULE_DEVICE_TABLE(of, max44009_of_match); static const struct i2c_device_id max44009_id[] = { - { "max44009" }, + { .name = "max44009" }, { } }; MODULE_DEVICE_TABLE(i2c, max44009_id); diff --git a/drivers/iio/light/noa1305.c b/drivers/iio/light/noa1305.c index 25f63da70297..6731f1d9ec1c 100644 --- a/drivers/iio/light/noa1305.c +++ b/drivers/iio/light/noa1305.c @@ -315,7 +315,7 @@ static const struct of_device_id noa1305_of_match[] = { MODULE_DEVICE_TABLE(of, noa1305_of_match); static const struct i2c_device_id noa1305_ids[] = { - { "noa1305" }, + { .name = "noa1305" }, { } }; MODULE_DEVICE_TABLE(i2c, noa1305_ids); diff --git a/drivers/iio/light/opt3001.c b/drivers/iio/light/opt3001.c index dac3d3818d0a..03c7a87b4a8e 100644 --- a/drivers/iio/light/opt3001.c +++ b/drivers/iio/light/opt3001.c @@ -948,8 +948,8 @@ static const struct opt3001_chip_info opt3002_chip_information = { }; static const struct i2c_device_id opt3001_id[] = { - { "opt3001", (kernel_ulong_t)&opt3001_chip_information }, - { "opt3002", (kernel_ulong_t)&opt3002_chip_information }, + { .name = "opt3001", .driver_data = (kernel_ulong_t)&opt3001_chip_information }, + { .name = "opt3002", .driver_data = (kernel_ulong_t)&opt3002_chip_information }, { } /* Terminating Entry */ }; MODULE_DEVICE_TABLE(i2c, opt3001_id); diff --git a/drivers/iio/light/opt4001.c b/drivers/iio/light/opt4001.c index 95167273bb90..dd152d921b48 100644 --- a/drivers/iio/light/opt4001.c +++ b/drivers/iio/light/opt4001.c @@ -438,8 +438,8 @@ static int opt4001_probe(struct i2c_client *client) * opt4001 packaging */ static const struct i2c_device_id opt4001_id[] = { - { "opt4001-sot-5x3", (kernel_ulong_t)&opt4001_sot_5x3_info }, - { "opt4001-picostar", (kernel_ulong_t)&opt4001_picostar_info }, + { .name = "opt4001-sot-5x3", .driver_data = (kernel_ulong_t)&opt4001_sot_5x3_info }, + { .name = "opt4001-picostar", .driver_data = (kernel_ulong_t)&opt4001_picostar_info }, { } }; MODULE_DEVICE_TABLE(i2c, opt4001_id); diff --git a/drivers/iio/light/opt4060.c b/drivers/iio/light/opt4060.c index d6e915ab355d..c391ad3271c6 100644 --- a/drivers/iio/light/opt4060.c +++ b/drivers/iio/light/opt4060.c @@ -1297,7 +1297,7 @@ static int opt4060_probe(struct i2c_client *client) } static const struct i2c_device_id opt4060_id[] = { - { "opt4060", }, + { .name = "opt4060" }, { } }; MODULE_DEVICE_TABLE(i2c, opt4060_id); diff --git a/drivers/iio/light/pa12203001.c b/drivers/iio/light/pa12203001.c index 98a1f1624c75..c0f4db8d95f7 100644 --- a/drivers/iio/light/pa12203001.c +++ b/drivers/iio/light/pa12203001.c @@ -457,7 +457,7 @@ static const struct acpi_device_id pa12203001_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, pa12203001_acpi_match); static const struct i2c_device_id pa12203001_id[] = { - { "txcpa122" }, + { .name = "txcpa122" }, { } }; diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c index 9341c1d58cbe..2ac06dad6d19 100644 --- a/drivers/iio/light/rpr0521.c +++ b/drivers/iio/light/rpr0521.c @@ -1102,7 +1102,7 @@ static const struct acpi_device_id rpr0521_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, rpr0521_acpi_match); static const struct i2c_device_id rpr0521_id[] = { - { "rpr0521" }, + { .name = "rpr0521" }, { } }; diff --git a/drivers/iio/light/si1133.c b/drivers/iio/light/si1133.c index 655fa778b4a6..2812a2be99dd 100644 --- a/drivers/iio/light/si1133.c +++ b/drivers/iio/light/si1133.c @@ -1069,7 +1069,7 @@ static int si1133_probe(struct i2c_client *client) } static const struct i2c_device_id si1133_ids[] = { - { "si1133" }, + { .name = "si1133" }, { } }; MODULE_DEVICE_TABLE(i2c, si1133_ids); diff --git a/drivers/iio/light/si1145.c b/drivers/iio/light/si1145.c index ef0abc4499b7..4601ae5d2009 100644 --- a/drivers/iio/light/si1145.c +++ b/drivers/iio/light/si1145.c @@ -1334,13 +1334,13 @@ static int si1145_probe(struct i2c_client *client) } static const struct i2c_device_id si1145_ids[] = { - { "si1132", SI1132 }, - { "si1141", SI1141 }, - { "si1142", SI1142 }, - { "si1143", SI1143 }, - { "si1145", SI1145 }, - { "si1146", SI1146 }, - { "si1147", SI1147 }, + { .name = "si1132", .driver_data = SI1132 }, + { .name = "si1141", .driver_data = SI1141 }, + { .name = "si1142", .driver_data = SI1142 }, + { .name = "si1143", .driver_data = SI1143 }, + { .name = "si1145", .driver_data = SI1145 }, + { .name = "si1146", .driver_data = SI1146 }, + { .name = "si1147", .driver_data = SI1147 }, { } }; MODULE_DEVICE_TABLE(i2c, si1145_ids); diff --git a/drivers/iio/light/st_uvis25_i2c.c b/drivers/iio/light/st_uvis25_i2c.c index 5d9bb4d9be63..ed8cac5b8766 100644 --- a/drivers/iio/light/st_uvis25_i2c.c +++ b/drivers/iio/light/st_uvis25_i2c.c @@ -46,7 +46,7 @@ static const struct of_device_id st_uvis25_i2c_of_match[] = { MODULE_DEVICE_TABLE(of, st_uvis25_i2c_of_match); static const struct i2c_device_id st_uvis25_i2c_id_table[] = { - { ST_UVIS25_DEV_NAME }, + { .name = ST_UVIS25_DEV_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, st_uvis25_i2c_id_table); diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c index 60407bc87ccf..8380df7ffa98 100644 --- a/drivers/iio/light/stk3310.c +++ b/drivers/iio/light/stk3310.c @@ -770,10 +770,10 @@ static DEFINE_SIMPLE_DEV_PM_OPS(stk3310_pm_ops, stk3310_suspend, stk3310_resume); static const struct i2c_device_id stk3310_i2c_id[] = { - { "STK3013" }, - { "STK3310" }, - { "STK3311" }, - { "STK3335" }, + { .name = "STK3013" }, + { .name = "STK3310" }, + { .name = "STK3311" }, + { .name = "STK3335" }, { } }; MODULE_DEVICE_TABLE(i2c, stk3310_i2c_id); diff --git a/drivers/iio/light/tcs3414.c b/drivers/iio/light/tcs3414.c index 5be461e6dbdb..458178fb629f 100644 --- a/drivers/iio/light/tcs3414.c +++ b/drivers/iio/light/tcs3414.c @@ -362,7 +362,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(tcs3414_pm_ops, tcs3414_suspend, tcs3414_resume); static const struct i2c_device_id tcs3414_id[] = { - { "tcs3414" }, + { .name = "tcs3414" }, { } }; MODULE_DEVICE_TABLE(i2c, tcs3414_id); diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c index 12429a3261b3..5a14f8d39aa4 100644 --- a/drivers/iio/light/tcs3472.c +++ b/drivers/iio/light/tcs3472.c @@ -597,7 +597,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(tcs3472_pm_ops, tcs3472_suspend, tcs3472_resume); static const struct i2c_device_id tcs3472_id[] = { - { "tcs3472" }, + { .name = "tcs3472" }, { } }; MODULE_DEVICE_TABLE(i2c, tcs3472_id); diff --git a/drivers/iio/light/tsl2772.c b/drivers/iio/light/tsl2772.c index 9ba8140c8bc1..244f44379c36 100644 --- a/drivers/iio/light/tsl2772.c +++ b/drivers/iio/light/tsl2772.c @@ -1900,19 +1900,19 @@ static int tsl2772_resume(struct device *dev) } static const struct i2c_device_id tsl2772_idtable[] = { - { "tsl2571", tsl2571 }, - { "tsl2671", tsl2671 }, - { "tmd2671", tmd2671 }, - { "tsl2771", tsl2771 }, - { "tmd2771", tmd2771 }, - { "tsl2572", tsl2572 }, - { "tsl2672", tsl2672 }, - { "tmd2672", tmd2672 }, - { "tsl2772", tsl2772 }, - { "tmd2772", tmd2772 }, - { "apds9900", apds9900 }, - { "apds9901", apds9900 }, - { "apds9930", apds9930 }, + { .name = "tsl2571", .driver_data = tsl2571 }, + { .name = "tsl2671", .driver_data = tsl2671 }, + { .name = "tmd2671", .driver_data = tmd2671 }, + { .name = "tsl2771", .driver_data = tsl2771 }, + { .name = "tmd2771", .driver_data = tmd2771 }, + { .name = "tsl2572", .driver_data = tsl2572 }, + { .name = "tsl2672", .driver_data = tsl2672 }, + { .name = "tmd2672", .driver_data = tmd2672 }, + { .name = "tsl2772", .driver_data = tsl2772 }, + { .name = "tmd2772", .driver_data = tmd2772 }, + { .name = "apds9900", .driver_data = apds9900 }, + { .name = "apds9901", .driver_data = apds9900 }, + { .name = "apds9930", .driver_data = apds9930 }, { } }; diff --git a/drivers/iio/light/tsl4531.c b/drivers/iio/light/tsl4531.c index a5788c09ad02..2f91ed8a9876 100644 --- a/drivers/iio/light/tsl4531.c +++ b/drivers/iio/light/tsl4531.c @@ -227,7 +227,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(tsl4531_pm_ops, tsl4531_suspend, tsl4531_resume); static const struct i2c_device_id tsl4531_id[] = { - { "tsl4531" }, + { .name = "tsl4531" }, { } }; MODULE_DEVICE_TABLE(i2c, tsl4531_id); diff --git a/drivers/iio/light/us5182d.c b/drivers/iio/light/us5182d.c index d2f5a44892a8..d335e5e551f1 100644 --- a/drivers/iio/light/us5182d.c +++ b/drivers/iio/light/us5182d.c @@ -949,7 +949,7 @@ static const struct acpi_device_id us5182d_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, us5182d_acpi_match); static const struct i2c_device_id us5182d_id[] = { - { "usd5182" }, + { .name = "usd5182" }, { } }; diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c index 88fc7424ae35..128ae3f94074 100644 --- a/drivers/iio/light/vcnl4000.c +++ b/drivers/iio/light/vcnl4000.c @@ -2040,13 +2040,13 @@ static DEFINE_RUNTIME_DEV_PM_OPS(vcnl4000_pm_ops, vcnl4000_runtime_suspend, vcnl4000_runtime_resume, NULL); static const struct i2c_device_id vcnl4000_id[] = { - { "cm36672p", (kernel_ulong_t)&cm36672p_spec }, - { "cm36686", (kernel_ulong_t)&vcnl4040_spec }, - { "vcnl4000", (kernel_ulong_t)&vcnl4000_spec }, - { "vcnl4010", (kernel_ulong_t)&vcnl4010_spec }, - { "vcnl4020", (kernel_ulong_t)&vcnl4010_spec }, - { "vcnl4040", (kernel_ulong_t)&vcnl4040_spec }, - { "vcnl4200", (kernel_ulong_t)&vcnl4200_spec }, + { .name = "cm36672p", .driver_data = (kernel_ulong_t)&cm36672p_spec }, + { .name = "cm36686", .driver_data = (kernel_ulong_t)&vcnl4040_spec }, + { .name = "vcnl4000", .driver_data = (kernel_ulong_t)&vcnl4000_spec }, + { .name = "vcnl4010", .driver_data = (kernel_ulong_t)&vcnl4010_spec }, + { .name = "vcnl4020", .driver_data = (kernel_ulong_t)&vcnl4010_spec }, + { .name = "vcnl4040", .driver_data = (kernel_ulong_t)&vcnl4040_spec }, + { .name = "vcnl4200", .driver_data = (kernel_ulong_t)&vcnl4200_spec }, { } }; MODULE_DEVICE_TABLE(i2c, vcnl4000_id); diff --git a/drivers/iio/light/vcnl4035.c b/drivers/iio/light/vcnl4035.c index 16aeb17067bc..bf3a49b4351d 100644 --- a/drivers/iio/light/vcnl4035.c +++ b/drivers/iio/light/vcnl4035.c @@ -662,7 +662,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(vcnl4035_pm_ops, vcnl4035_runtime_suspend, vcnl4035_runtime_resume, NULL); static const struct i2c_device_id vcnl4035_id[] = { - { "vcnl4035" }, + { .name = "vcnl4035" }, { } }; MODULE_DEVICE_TABLE(i2c, vcnl4035_id); diff --git a/drivers/iio/light/veml3235.c b/drivers/iio/light/veml3235.c index 9309ad83ca9e..d8a39223009b 100644 --- a/drivers/iio/light/veml3235.c +++ b/drivers/iio/light/veml3235.c @@ -525,7 +525,7 @@ static const struct of_device_id veml3235_of_match[] = { MODULE_DEVICE_TABLE(of, veml3235_of_match); static const struct i2c_device_id veml3235_id[] = { - { "veml3235" }, + { .name = "veml3235" }, { } }; MODULE_DEVICE_TABLE(i2c, veml3235_id); diff --git a/drivers/iio/light/veml6030.c b/drivers/iio/light/veml6030.c index 745cf3ad7092..a1b4e7fadf80 100644 --- a/drivers/iio/light/veml6030.c +++ b/drivers/iio/light/veml6030.c @@ -1214,9 +1214,9 @@ static const struct of_device_id veml6030_of_match[] = { MODULE_DEVICE_TABLE(of, veml6030_of_match); static const struct i2c_device_id veml6030_id[] = { - { "veml6030", (kernel_ulong_t)&veml6030_chip}, - { "veml6035", (kernel_ulong_t)&veml6035_chip}, - { "veml7700", (kernel_ulong_t)&veml7700_chip}, + { .name = "veml6030", .driver_data = (kernel_ulong_t)&veml6030_chip }, + { .name = "veml6035", .driver_data = (kernel_ulong_t)&veml6035_chip }, + { .name = "veml7700", .driver_data = (kernel_ulong_t)&veml7700_chip }, { } }; MODULE_DEVICE_TABLE(i2c, veml6030_id); diff --git a/drivers/iio/light/veml6040.c b/drivers/iio/light/veml6040.c index f563f9f0ee67..0960784b8866 100644 --- a/drivers/iio/light/veml6040.c +++ b/drivers/iio/light/veml6040.c @@ -254,7 +254,7 @@ static int veml6040_probe(struct i2c_client *client) } static const struct i2c_device_id veml6040_id_table[] = { - {"veml6040"}, + { .name = "veml6040" }, { } }; MODULE_DEVICE_TABLE(i2c, veml6040_id_table); diff --git a/drivers/iio/light/veml6046x00.c b/drivers/iio/light/veml6046x00.c index e60f24d46e7b..f23d63291f73 100644 --- a/drivers/iio/light/veml6046x00.c +++ b/drivers/iio/light/veml6046x00.c @@ -1009,7 +1009,7 @@ static const struct of_device_id veml6046x00_of_match[] = { MODULE_DEVICE_TABLE(of, veml6046x00_of_match); static const struct i2c_device_id veml6046x00_id[] = { - { "veml6046x00" }, + { .name = "veml6046x00" }, { } }; MODULE_DEVICE_TABLE(i2c, veml6046x00_id); diff --git a/drivers/iio/light/veml6070.c b/drivers/iio/light/veml6070.c index 74d7246e5225..aa7e52628d2a 100644 --- a/drivers/iio/light/veml6070.c +++ b/drivers/iio/light/veml6070.c @@ -300,7 +300,7 @@ static int veml6070_probe(struct i2c_client *client) } static const struct i2c_device_id veml6070_id[] = { - { "veml6070" }, + { .name = "veml6070" }, { } }; MODULE_DEVICE_TABLE(i2c, veml6070_id); diff --git a/drivers/iio/light/veml6075.c b/drivers/iio/light/veml6075.c index edbb43407054..105bae7be899 100644 --- a/drivers/iio/light/veml6075.c +++ b/drivers/iio/light/veml6075.c @@ -451,7 +451,7 @@ static int veml6075_probe(struct i2c_client *client) } static const struct i2c_device_id veml6075_id[] = { - { "veml6075" }, + { .name = "veml6075" }, { } }; MODULE_DEVICE_TABLE(i2c, veml6075_id); diff --git a/drivers/iio/light/vl6180.c b/drivers/iio/light/vl6180.c index c1314b144367..6cb965418dba 100644 --- a/drivers/iio/light/vl6180.c +++ b/drivers/iio/light/vl6180.c @@ -750,7 +750,7 @@ static const struct of_device_id vl6180_of_match[] = { MODULE_DEVICE_TABLE(of, vl6180_of_match); static const struct i2c_device_id vl6180_id[] = { - { "vl6180" }, + { .name = "vl6180" }, { } }; MODULE_DEVICE_TABLE(i2c, vl6180_id); diff --git a/drivers/iio/light/zopt2201.c b/drivers/iio/light/zopt2201.c index 0990e4d266eb..b53be5f7354e 100644 --- a/drivers/iio/light/zopt2201.c +++ b/drivers/iio/light/zopt2201.c @@ -516,7 +516,7 @@ static int zopt2201_probe(struct i2c_client *client) } static const struct i2c_device_id zopt2201_id[] = { - { "zopt2201" }, + { .name = "zopt2201" }, { } }; MODULE_DEVICE_TABLE(i2c, zopt2201_id); diff --git a/drivers/iio/magnetometer/af8133j.c b/drivers/iio/magnetometer/af8133j.c index b1768c3aa8f3..352f53edad9a 100644 --- a/drivers/iio/magnetometer/af8133j.c +++ b/drivers/iio/magnetometer/af8133j.c @@ -504,7 +504,7 @@ static const struct of_device_id af8133j_of_match[] = { MODULE_DEVICE_TABLE(of, af8133j_of_match); static const struct i2c_device_id af8133j_id[] = { - { "af8133j" }, + { .name = "af8133j" }, { } }; MODULE_DEVICE_TABLE(i2c, af8133j_id); diff --git a/drivers/iio/magnetometer/ak8974.c b/drivers/iio/magnetometer/ak8974.c index 817b18257608..18dc36945a97 100644 --- a/drivers/iio/magnetometer/ak8974.c +++ b/drivers/iio/magnetometer/ak8974.c @@ -1017,10 +1017,10 @@ static DEFINE_RUNTIME_DEV_PM_OPS(ak8974_dev_pm_ops, ak8974_runtime_suspend, ak8974_runtime_resume, NULL); static const struct i2c_device_id ak8974_id[] = { - { "ami305" }, - { "ami306" }, - { "ak8974" }, - { "hscdtd008a" }, + { .name = "ami305" }, + { .name = "ami306" }, + { .name = "ak8974" }, + { .name = "hscdtd008a" }, { } }; MODULE_DEVICE_TABLE(i2c, ak8974_id); diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index bb74abb648f1..d045ea091205 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -1132,13 +1132,13 @@ static const struct acpi_device_id ak_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, ak_acpi_match); static const struct i2c_device_id ak8975_id[] = { - {"AK8963", (kernel_ulong_t)&ak_def_array[AK8963] }, - {"ak8963", (kernel_ulong_t)&ak_def_array[AK8963] }, - {"ak8975", (kernel_ulong_t)&ak_def_array[AK8975] }, - {"ak09911", (kernel_ulong_t)&ak_def_array[AK09911] }, - {"ak09912", (kernel_ulong_t)&ak_def_array[AK09912] }, - {"ak09916", (kernel_ulong_t)&ak_def_array[AK09916] }, - {"ak09918", (kernel_ulong_t)&ak_def_array[AK09918] }, + { .name = "AK8963", .driver_data = (kernel_ulong_t)&ak_def_array[AK8963] }, + { .name = "ak8963", .driver_data = (kernel_ulong_t)&ak_def_array[AK8963] }, + { .name = "ak8975", .driver_data = (kernel_ulong_t)&ak_def_array[AK8975] }, + { .name = "ak09911", .driver_data = (kernel_ulong_t)&ak_def_array[AK09911] }, + { .name = "ak09912", .driver_data = (kernel_ulong_t)&ak_def_array[AK09912] }, + { .name = "ak09916", .driver_data = (kernel_ulong_t)&ak_def_array[AK09916] }, + { .name = "ak09918", .driver_data = (kernel_ulong_t)&ak_def_array[AK09918] }, { } }; MODULE_DEVICE_TABLE(i2c, ak8975_id); diff --git a/drivers/iio/magnetometer/bmc150_magn_i2c.c b/drivers/iio/magnetometer/bmc150_magn_i2c.c index b110791f688a..7d3cca8cedbe 100644 --- a/drivers/iio/magnetometer/bmc150_magn_i2c.c +++ b/drivers/iio/magnetometer/bmc150_magn_i2c.c @@ -39,9 +39,9 @@ static void bmc150_magn_i2c_remove(struct i2c_client *client) } static const struct i2c_device_id bmc150_magn_i2c_id[] = { - { "bmc150_magn" }, - { "bmc156_magn" }, - { "bmm150_magn" }, + { .name = "bmc150_magn" }, + { .name = "bmc156_magn" }, + { .name = "bmm150_magn" }, { } }; MODULE_DEVICE_TABLE(i2c, bmc150_magn_i2c_id); diff --git a/drivers/iio/magnetometer/hmc5843_i2c.c b/drivers/iio/magnetometer/hmc5843_i2c.c index b41709959e2b..4c454b0057b1 100644 --- a/drivers/iio/magnetometer/hmc5843_i2c.c +++ b/drivers/iio/magnetometer/hmc5843_i2c.c @@ -71,10 +71,10 @@ static void hmc5843_i2c_remove(struct i2c_client *client) } static const struct i2c_device_id hmc5843_id[] = { - { "hmc5843", HMC5843_ID }, - { "hmc5883", HMC5883_ID }, - { "hmc5883l", HMC5883L_ID }, - { "hmc5983", HMC5983_ID }, + { .name = "hmc5843", .driver_data = HMC5843_ID }, + { .name = "hmc5883", .driver_data = HMC5883_ID }, + { .name = "hmc5883l", .driver_data = HMC5883L_ID }, + { .name = "hmc5983", .driver_data = HMC5983_ID }, { } }; MODULE_DEVICE_TABLE(i2c, hmc5843_id); diff --git a/drivers/iio/magnetometer/mag3110.c b/drivers/iio/magnetometer/mag3110.c index ff09250a06e7..479a12ece8f6 100644 --- a/drivers/iio/magnetometer/mag3110.c +++ b/drivers/iio/magnetometer/mag3110.c @@ -619,7 +619,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(mag3110_pm_ops, mag3110_suspend, mag3110_resume); static const struct i2c_device_id mag3110_id[] = { - { "mag3110" }, + { .name = "mag3110" }, { } }; MODULE_DEVICE_TABLE(i2c, mag3110_id); diff --git a/drivers/iio/magnetometer/mmc35240.c b/drivers/iio/magnetometer/mmc35240.c index f3d48d03f7c3..bad36c8dd598 100644 --- a/drivers/iio/magnetometer/mmc35240.c +++ b/drivers/iio/magnetometer/mmc35240.c @@ -560,7 +560,7 @@ static const struct acpi_device_id mmc35240_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, mmc35240_acpi_match); static const struct i2c_device_id mmc35240_id[] = { - { "mmc35240" }, + { .name = "mmc35240" }, { } }; MODULE_DEVICE_TABLE(i2c, mmc35240_id); diff --git a/drivers/iio/magnetometer/mmc5633.c b/drivers/iio/magnetometer/mmc5633.c index 9d8e27486963..f82cb68f9c57 100644 --- a/drivers/iio/magnetometer/mmc5633.c +++ b/drivers/iio/magnetometer/mmc5633.c @@ -532,8 +532,8 @@ static const struct of_device_id mmc5633_of_match[] = { MODULE_DEVICE_TABLE(of, mmc5633_of_match); static const struct i2c_device_id mmc5633_i2c_id[] = { - { "mmc5603" }, - { "mmc5633" }, + { .name = "mmc5603" }, + { .name = "mmc5633" }, { } }; MODULE_DEVICE_TABLE(i2c, mmc5633_i2c_id); diff --git a/drivers/iio/magnetometer/si7210.c b/drivers/iio/magnetometer/si7210.c index 2a36abd1c99d..5b3fc3030703 100644 --- a/drivers/iio/magnetometer/si7210.c +++ b/drivers/iio/magnetometer/si7210.c @@ -413,7 +413,7 @@ static int si7210_probe(struct i2c_client *client) } static const struct i2c_device_id si7210_id[] = { - { "si7210" }, + { .name = "si7210" }, { } }; MODULE_DEVICE_TABLE(i2c, si7210_id); diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c index ed70e782af5e..26d1edd1e779 100644 --- a/drivers/iio/magnetometer/st_magn_i2c.c +++ b/drivers/iio/magnetometer/st_magn_i2c.c @@ -93,15 +93,15 @@ static int st_magn_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id st_magn_id_table[] = { - { LSM303DLH_MAGN_DEV_NAME }, - { LSM303DLHC_MAGN_DEV_NAME }, - { LSM303DLM_MAGN_DEV_NAME }, - { LIS3MDL_MAGN_DEV_NAME }, - { LSM303AGR_MAGN_DEV_NAME }, - { LIS2MDL_MAGN_DEV_NAME }, - { LSM9DS1_MAGN_DEV_NAME }, - { IIS2MDC_MAGN_DEV_NAME }, - { LSM303C_MAGN_DEV_NAME }, + { .name = LSM303DLH_MAGN_DEV_NAME }, + { .name = LSM303DLHC_MAGN_DEV_NAME }, + { .name = LSM303DLM_MAGN_DEV_NAME }, + { .name = LIS3MDL_MAGN_DEV_NAME }, + { .name = LSM303AGR_MAGN_DEV_NAME }, + { .name = LIS2MDL_MAGN_DEV_NAME }, + { .name = LSM9DS1_MAGN_DEV_NAME }, + { .name = IIS2MDC_MAGN_DEV_NAME }, + { .name = LSM303C_MAGN_DEV_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, st_magn_id_table); diff --git a/drivers/iio/magnetometer/tlv493d.c b/drivers/iio/magnetometer/tlv493d.c index e5e050af2b74..c8eb136cea6f 100644 --- a/drivers/iio/magnetometer/tlv493d.c +++ b/drivers/iio/magnetometer/tlv493d.c @@ -499,7 +499,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(tlv493d_pm_ops, tlv493d_runtime_suspend, tlv493d_runtime_resume, NULL); static const struct i2c_device_id tlv493d_id[] = { - { "tlv493d" }, + { .name = "tlv493d" }, { } }; MODULE_DEVICE_TABLE(i2c, tlv493d_id); diff --git a/drivers/iio/magnetometer/tmag5273.c b/drivers/iio/magnetometer/tmag5273.c index 2adc3c036ab4..155294b66924 100644 --- a/drivers/iio/magnetometer/tmag5273.c +++ b/drivers/iio/magnetometer/tmag5273.c @@ -708,7 +708,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(tmag5273_pm_ops, NULL); static const struct i2c_device_id tmag5273_id[] = { - { "tmag5273" }, + { .name = "tmag5273" }, { } }; MODULE_DEVICE_TABLE(i2c, tmag5273_id); diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c index 6bd0535e5eb1..fec084c16b17 100644 --- a/drivers/iio/magnetometer/yamaha-yas530.c +++ b/drivers/iio/magnetometer/yamaha-yas530.c @@ -1587,10 +1587,10 @@ static DEFINE_RUNTIME_DEV_PM_OPS(yas5xx_dev_pm_ops, yas5xx_runtime_suspend, yas5xx_runtime_resume, NULL); static const struct i2c_device_id yas5xx_id[] = { - {"yas530", (kernel_ulong_t)&yas5xx_chip_info_tbl[yas530] }, - {"yas532", (kernel_ulong_t)&yas5xx_chip_info_tbl[yas532] }, - {"yas533", (kernel_ulong_t)&yas5xx_chip_info_tbl[yas533] }, - {"yas537", (kernel_ulong_t)&yas5xx_chip_info_tbl[yas537] }, + { .name = "yas530", .driver_data = (kernel_ulong_t)&yas5xx_chip_info_tbl[yas530] }, + { .name = "yas532", .driver_data = (kernel_ulong_t)&yas5xx_chip_info_tbl[yas532] }, + { .name = "yas533", .driver_data = (kernel_ulong_t)&yas5xx_chip_info_tbl[yas533] }, + { .name = "yas537", .driver_data = (kernel_ulong_t)&yas5xx_chip_info_tbl[yas537] }, { } }; MODULE_DEVICE_TABLE(i2c, yas5xx_id); diff --git a/drivers/iio/potentiometer/ad5272.c b/drivers/iio/potentiometer/ad5272.c index 672b1ca3a920..ac342127d59e 100644 --- a/drivers/iio/potentiometer/ad5272.c +++ b/drivers/iio/potentiometer/ad5272.c @@ -204,11 +204,11 @@ static const struct of_device_id ad5272_dt_ids[] = { MODULE_DEVICE_TABLE(of, ad5272_dt_ids); static const struct i2c_device_id ad5272_id[] = { - { "ad5272-020", AD5272_020 }, - { "ad5272-050", AD5272_050 }, - { "ad5272-100", AD5272_100 }, - { "ad5274-020", AD5274_020 }, - { "ad5274-100", AD5274_100 }, + { .name = "ad5272-020", .driver_data = AD5272_020 }, + { .name = "ad5272-050", .driver_data = AD5272_050 }, + { .name = "ad5272-100", .driver_data = AD5272_100 }, + { .name = "ad5274-020", .driver_data = AD5274_020 }, + { .name = "ad5274-100", .driver_data = AD5274_100 }, { } }; MODULE_DEVICE_TABLE(i2c, ad5272_id); diff --git a/drivers/iio/potentiometer/ds1803.c b/drivers/iio/potentiometer/ds1803.c index 8a64d93f7e7b..42394343b5a9 100644 --- a/drivers/iio/potentiometer/ds1803.c +++ b/drivers/iio/potentiometer/ds1803.c @@ -235,10 +235,10 @@ static const struct of_device_id ds1803_dt_ids[] = { MODULE_DEVICE_TABLE(of, ds1803_dt_ids); static const struct i2c_device_id ds1803_id[] = { - { "ds1803-010", (kernel_ulong_t)&ds1803_cfg[DS1803_010] }, - { "ds1803-050", (kernel_ulong_t)&ds1803_cfg[DS1803_050] }, - { "ds1803-100", (kernel_ulong_t)&ds1803_cfg[DS1803_100] }, - { "ds3502", (kernel_ulong_t)&ds1803_cfg[DS3502] }, + { .name = "ds1803-010", .driver_data = (kernel_ulong_t)&ds1803_cfg[DS1803_010] }, + { .name = "ds1803-050", .driver_data = (kernel_ulong_t)&ds1803_cfg[DS1803_050] }, + { .name = "ds1803-100", .driver_data = (kernel_ulong_t)&ds1803_cfg[DS1803_100] }, + { .name = "ds3502", .driver_data = (kernel_ulong_t)&ds1803_cfg[DS3502] }, { } }; MODULE_DEVICE_TABLE(i2c, ds1803_id); diff --git a/drivers/iio/potentiometer/tpl0102.c b/drivers/iio/potentiometer/tpl0102.c index a42b57733363..77149908e1bf 100644 --- a/drivers/iio/potentiometer/tpl0102.c +++ b/drivers/iio/potentiometer/tpl0102.c @@ -149,10 +149,10 @@ static int tpl0102_probe(struct i2c_client *client) } static const struct i2c_device_id tpl0102_id[] = { - { "cat5140-503", CAT5140_503 }, - { "cat5140-104", CAT5140_104 }, - { "tpl0102-104", TPL0102_104 }, - { "tpl0401-103", TPL0401_103 }, + { .name = "cat5140-503", .driver_data = CAT5140_503 }, + { .name = "cat5140-104", .driver_data = CAT5140_104 }, + { .name = "tpl0102-104", .driver_data = TPL0102_104 }, + { .name = "tpl0401-103", .driver_data = TPL0401_103 }, { } }; MODULE_DEVICE_TABLE(i2c, tpl0102_id); diff --git a/drivers/iio/potentiostat/lmp91000.c b/drivers/iio/potentiostat/lmp91000.c index eccc2a34358f..359dffa47091 100644 --- a/drivers/iio/potentiostat/lmp91000.c +++ b/drivers/iio/potentiostat/lmp91000.c @@ -403,8 +403,8 @@ static const struct of_device_id lmp91000_of_match[] = { MODULE_DEVICE_TABLE(of, lmp91000_of_match); static const struct i2c_device_id lmp91000_id[] = { - { "lmp91000" }, - { "lmp91002" }, + { .name = "lmp91000" }, + { .name = "lmp91002" }, { } }; MODULE_DEVICE_TABLE(i2c, lmp91000_id); diff --git a/drivers/iio/pressure/abp060mg.c b/drivers/iio/pressure/abp060mg.c index 699b0fd64985..fd48bed35088 100644 --- a/drivers/iio/pressure/abp060mg.c +++ b/drivers/iio/pressure/abp060mg.c @@ -209,44 +209,66 @@ static int abp060mg_probe(struct i2c_client *client) static const struct i2c_device_id abp060mg_id_table[] = { /* mbar & kPa variants (abp060m [60 mbar] == abp006k [6 kPa]) */ /* gage: */ - { "abp060mg", ABP006KG }, { "abp006kg", ABP006KG }, - { "abp100mg", ABP010KG }, { "abp010kg", ABP010KG }, - { "abp160mg", ABP016KG }, { "abp016kg", ABP016KG }, - { "abp250mg", ABP025KG }, { "abp025kg", ABP025KG }, - { "abp400mg", ABP040KG }, { "abp040kg", ABP040KG }, - { "abp600mg", ABP060KG }, { "abp060kg", ABP060KG }, - { "abp001bg", ABP100KG }, { "abp100kg", ABP100KG }, - { "abp1_6bg", ABP160KG }, { "abp160kg", ABP160KG }, - { "abp2_5bg", ABP250KG }, { "abp250kg", ABP250KG }, - { "abp004bg", ABP400KG }, { "abp400kg", ABP400KG }, - { "abp006bg", ABP600KG }, { "abp600kg", ABP600KG }, - { "abp010bg", ABP001GG }, { "abp001gg", ABP001GG }, + { .name = "abp060mg", .driver_data = ABP006KG }, + { .name = "abp006kg", .driver_data = ABP006KG }, + { .name = "abp100mg", .driver_data = ABP010KG }, + { .name = "abp010kg", .driver_data = ABP010KG }, + { .name = "abp160mg", .driver_data = ABP016KG }, + { .name = "abp016kg", .driver_data = ABP016KG }, + { .name = "abp250mg", .driver_data = ABP025KG }, + { .name = "abp025kg", .driver_data = ABP025KG }, + { .name = "abp400mg", .driver_data = ABP040KG }, + { .name = "abp040kg", .driver_data = ABP040KG }, + { .name = "abp600mg", .driver_data = ABP060KG }, + { .name = "abp060kg", .driver_data = ABP060KG }, + { .name = "abp001bg", .driver_data = ABP100KG }, + { .name = "abp100kg", .driver_data = ABP100KG }, + { .name = "abp1_6bg", .driver_data = ABP160KG }, + { .name = "abp160kg", .driver_data = ABP160KG }, + { .name = "abp2_5bg", .driver_data = ABP250KG }, + { .name = "abp250kg", .driver_data = ABP250KG }, + { .name = "abp004bg", .driver_data = ABP400KG }, + { .name = "abp400kg", .driver_data = ABP400KG }, + { .name = "abp006bg", .driver_data = ABP600KG }, + { .name = "abp600kg", .driver_data = ABP600KG }, + { .name = "abp010bg", .driver_data = ABP001GG }, + { .name = "abp001gg", .driver_data = ABP001GG }, /* differential: */ - { "abp060md", ABP006KD }, { "abp006kd", ABP006KD }, - { "abp100md", ABP010KD }, { "abp010kd", ABP010KD }, - { "abp160md", ABP016KD }, { "abp016kd", ABP016KD }, - { "abp250md", ABP025KD }, { "abp025kd", ABP025KD }, - { "abp400md", ABP040KD }, { "abp040kd", ABP040KD }, - { "abp600md", ABP060KD }, { "abp060kd", ABP060KD }, - { "abp001bd", ABP100KD }, { "abp100kd", ABP100KD }, - { "abp1_6bd", ABP160KD }, { "abp160kd", ABP160KD }, - { "abp2_5bd", ABP250KD }, { "abp250kd", ABP250KD }, - { "abp004bd", ABP400KD }, { "abp400kd", ABP400KD }, + { .name = "abp060md", .driver_data = ABP006KD }, + { .name = "abp006kd", .driver_data = ABP006KD }, + { .name = "abp100md", .driver_data = ABP010KD }, + { .name = "abp010kd", .driver_data = ABP010KD }, + { .name = "abp160md", .driver_data = ABP016KD }, + { .name = "abp016kd", .driver_data = ABP016KD }, + { .name = "abp250md", .driver_data = ABP025KD }, + { .name = "abp025kd", .driver_data = ABP025KD }, + { .name = "abp400md", .driver_data = ABP040KD }, + { .name = "abp040kd", .driver_data = ABP040KD }, + { .name = "abp600md", .driver_data = ABP060KD }, + { .name = "abp060kd", .driver_data = ABP060KD }, + { .name = "abp001bd", .driver_data = ABP100KD }, + { .name = "abp100kd", .driver_data = ABP100KD }, + { .name = "abp1_6bd", .driver_data = ABP160KD }, + { .name = "abp160kd", .driver_data = ABP160KD }, + { .name = "abp2_5bd", .driver_data = ABP250KD }, + { .name = "abp250kd", .driver_data = ABP250KD }, + { .name = "abp004bd", .driver_data = ABP400KD }, + { .name = "abp400kd", .driver_data = ABP400KD }, /* psi variants */ /* gage: */ - { "abp001pg", ABP001PG }, - { "abp005pg", ABP005PG }, - { "abp015pg", ABP015PG }, - { "abp030pg", ABP030PG }, - { "abp060pg", ABP060PG }, - { "abp100pg", ABP100PG }, - { "abp150pg", ABP150PG }, + { .name = "abp001pg", .driver_data = ABP001PG }, + { .name = "abp005pg", .driver_data = ABP005PG }, + { .name = "abp015pg", .driver_data = ABP015PG }, + { .name = "abp030pg", .driver_data = ABP030PG }, + { .name = "abp060pg", .driver_data = ABP060PG }, + { .name = "abp100pg", .driver_data = ABP100PG }, + { .name = "abp150pg", .driver_data = ABP150PG }, /* differential: */ - { "abp001pd", ABP001PD }, - { "abp005pd", ABP005PD }, - { "abp015pd", ABP015PD }, - { "abp030pd", ABP030PD }, - { "abp060pd", ABP060PD }, + { .name = "abp001pd", .driver_data = ABP001PD }, + { .name = "abp005pd", .driver_data = ABP005PD }, + { .name = "abp015pd", .driver_data = ABP015PD }, + { .name = "abp030pd", .driver_data = ABP030PD }, + { .name = "abp060pd", .driver_data = ABP060PD }, { } }; MODULE_DEVICE_TABLE(i2c, abp060mg_id_table); diff --git a/drivers/iio/pressure/abp2030pa_i2c.c b/drivers/iio/pressure/abp2030pa_i2c.c index 9f1c1c8a9afb..e71dc8e8e957 100644 --- a/drivers/iio/pressure/abp2030pa_i2c.c +++ b/drivers/iio/pressure/abp2030pa_i2c.c @@ -69,7 +69,7 @@ static const struct of_device_id abp2_i2c_match[] = { MODULE_DEVICE_TABLE(of, abp2_i2c_match); static const struct i2c_device_id abp2_i2c_id[] = { - { "abp2030pa" }, + { .name = "abp2030pa" }, { } }; MODULE_DEVICE_TABLE(i2c, abp2_i2c_id); diff --git a/drivers/iio/pressure/adp810.c b/drivers/iio/pressure/adp810.c index 5282612d1309..47c5ad564c7f 100644 --- a/drivers/iio/pressure/adp810.c +++ b/drivers/iio/pressure/adp810.c @@ -199,7 +199,7 @@ static int adp810_probe(struct i2c_client *client) } static const struct i2c_device_id adp810_id_table[] = { - { "adp810" }, + { .name = "adp810" }, { } }; MODULE_DEVICE_TABLE(i2c, adp810_id_table); diff --git a/drivers/iio/pressure/bmp280-i2c.c b/drivers/iio/pressure/bmp280-i2c.c index 8e459b6c97ff..3f6e0723a9d7 100644 --- a/drivers/iio/pressure/bmp280-i2c.c +++ b/drivers/iio/pressure/bmp280-i2c.c @@ -38,12 +38,12 @@ static const struct of_device_id bmp280_of_i2c_match[] = { MODULE_DEVICE_TABLE(of, bmp280_of_i2c_match); static const struct i2c_device_id bmp280_i2c_id[] = { - {"bmp085", (kernel_ulong_t)&bmp085_chip_info }, - {"bmp180", (kernel_ulong_t)&bmp180_chip_info }, - {"bmp280", (kernel_ulong_t)&bmp280_chip_info }, - {"bme280", (kernel_ulong_t)&bme280_chip_info }, - {"bmp380", (kernel_ulong_t)&bmp380_chip_info }, - {"bmp580", (kernel_ulong_t)&bmp580_chip_info }, + { .name = "bmp085", .driver_data = (kernel_ulong_t)&bmp085_chip_info }, + { .name = "bmp180", .driver_data = (kernel_ulong_t)&bmp180_chip_info }, + { .name = "bmp280", .driver_data = (kernel_ulong_t)&bmp280_chip_info }, + { .name = "bme280", .driver_data = (kernel_ulong_t)&bme280_chip_info }, + { .name = "bmp380", .driver_data = (kernel_ulong_t)&bmp380_chip_info }, + { .name = "bmp580", .driver_data = (kernel_ulong_t)&bmp580_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, bmp280_i2c_id); diff --git a/drivers/iio/pressure/dlhl60d.c b/drivers/iio/pressure/dlhl60d.c index 46feb27fe632..01a873165923 100644 --- a/drivers/iio/pressure/dlhl60d.c +++ b/drivers/iio/pressure/dlhl60d.c @@ -340,8 +340,8 @@ static const struct of_device_id dlh_of_match[] = { MODULE_DEVICE_TABLE(of, dlh_of_match); static const struct i2c_device_id dlh_id[] = { - { "dlhl60d", (kernel_ulong_t)&dlhl60d_info }, - { "dlhl60g", (kernel_ulong_t)&dlhl60g_info }, + { .name = "dlhl60d", .driver_data = (kernel_ulong_t)&dlhl60d_info }, + { .name = "dlhl60g", .driver_data = (kernel_ulong_t)&dlhl60g_info }, { } }; MODULE_DEVICE_TABLE(i2c, dlh_id); diff --git a/drivers/iio/pressure/dps310.c b/drivers/iio/pressure/dps310.c index 8edaa4d10a70..f45af72a0554 100644 --- a/drivers/iio/pressure/dps310.c +++ b/drivers/iio/pressure/dps310.c @@ -887,7 +887,7 @@ static int dps310_probe(struct i2c_client *client) } static const struct i2c_device_id dps310_id[] = { - { DPS310_DEV_NAME }, + { .name = DPS310_DEV_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, dps310_id); diff --git a/drivers/iio/pressure/hp03.c b/drivers/iio/pressure/hp03.c index cbb4aaf45e2c..424523345060 100644 --- a/drivers/iio/pressure/hp03.c +++ b/drivers/iio/pressure/hp03.c @@ -266,7 +266,7 @@ static int hp03_probe(struct i2c_client *client) } static const struct i2c_device_id hp03_id[] = { - { "hp03" }, + { .name = "hp03" }, { } }; MODULE_DEVICE_TABLE(i2c, hp03_id); diff --git a/drivers/iio/pressure/hp206c.c b/drivers/iio/pressure/hp206c.c index abe10ccb6770..be14202855cf 100644 --- a/drivers/iio/pressure/hp206c.c +++ b/drivers/iio/pressure/hp206c.c @@ -395,7 +395,7 @@ static int hp206c_probe(struct i2c_client *client) } static const struct i2c_device_id hp206c_id[] = { - {"hp206c"}, + { .name = "hp206c" }, { } }; MODULE_DEVICE_TABLE(i2c, hp206c_id); diff --git a/drivers/iio/pressure/hsc030pa_i2c.c b/drivers/iio/pressure/hsc030pa_i2c.c index 3500bda03d75..f4ea30b2980d 100644 --- a/drivers/iio/pressure/hsc030pa_i2c.c +++ b/drivers/iio/pressure/hsc030pa_i2c.c @@ -58,7 +58,7 @@ static const struct of_device_id hsc_i2c_match[] = { MODULE_DEVICE_TABLE(of, hsc_i2c_match); static const struct i2c_device_id hsc_i2c_id[] = { - { "hsc030pa" }, + { .name = "hsc030pa" }, { } }; MODULE_DEVICE_TABLE(i2c, hsc_i2c_id); diff --git a/drivers/iio/pressure/icp10100.c b/drivers/iio/pressure/icp10100.c index 3d83d0098a57..02b363c5c45b 100644 --- a/drivers/iio/pressure/icp10100.c +++ b/drivers/iio/pressure/icp10100.c @@ -633,7 +633,7 @@ static const struct of_device_id icp10100_of_match[] = { MODULE_DEVICE_TABLE(of, icp10100_of_match); static const struct i2c_device_id icp10100_id[] = { - { "icp10100" }, + { .name = "icp10100" }, { } }; MODULE_DEVICE_TABLE(i2c, icp10100_id); diff --git a/drivers/iio/pressure/mpl115_i2c.c b/drivers/iio/pressure/mpl115_i2c.c index 3db9ef4e2770..4a43eba078a8 100644 --- a/drivers/iio/pressure/mpl115_i2c.c +++ b/drivers/iio/pressure/mpl115_i2c.c @@ -45,7 +45,7 @@ static int mpl115_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id mpl115_i2c_id[] = { - { "mpl115" }, + { .name = "mpl115" }, { } }; MODULE_DEVICE_TABLE(i2c, mpl115_i2c_id); diff --git a/drivers/iio/pressure/mpl3115.c b/drivers/iio/pressure/mpl3115.c index aeac1586f12e..f20fa6ad16fe 100644 --- a/drivers/iio/pressure/mpl3115.c +++ b/drivers/iio/pressure/mpl3115.c @@ -783,7 +783,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(mpl3115_pm_ops, mpl3115_suspend, mpl3115_resume); static const struct i2c_device_id mpl3115_id[] = { - { "mpl3115" }, + { .name = "mpl3115" }, { } }; MODULE_DEVICE_TABLE(i2c, mpl3115_id); diff --git a/drivers/iio/pressure/mprls0025pa_i2c.c b/drivers/iio/pressure/mprls0025pa_i2c.c index 0fe8cfe0d7e7..92edaf3005eb 100644 --- a/drivers/iio/pressure/mprls0025pa_i2c.c +++ b/drivers/iio/pressure/mprls0025pa_i2c.c @@ -69,7 +69,7 @@ static const struct of_device_id mpr_i2c_match[] = { MODULE_DEVICE_TABLE(of, mpr_i2c_match); static const struct i2c_device_id mpr_i2c_id[] = { - { "mprls0025pa" }, + { .name = "mprls0025pa" }, { } }; MODULE_DEVICE_TABLE(i2c, mpr_i2c_id); diff --git a/drivers/iio/pressure/ms5611_i2c.c b/drivers/iio/pressure/ms5611_i2c.c index 1c041b9085fb..b5be6a6daf02 100644 --- a/drivers/iio/pressure/ms5611_i2c.c +++ b/drivers/iio/pressure/ms5611_i2c.c @@ -113,8 +113,8 @@ static const struct of_device_id ms5611_i2c_matches[] = { MODULE_DEVICE_TABLE(of, ms5611_i2c_matches); static const struct i2c_device_id ms5611_id[] = { - { "ms5611", MS5611 }, - { "ms5607", MS5607 }, + { .name = "ms5611", .driver_data = MS5611 }, + { .name = "ms5607", .driver_data = MS5607 }, { } }; MODULE_DEVICE_TABLE(i2c, ms5611_id); diff --git a/drivers/iio/pressure/ms5637.c b/drivers/iio/pressure/ms5637.c index 59705a666979..03945a4fc718 100644 --- a/drivers/iio/pressure/ms5637.c +++ b/drivers/iio/pressure/ms5637.c @@ -215,10 +215,10 @@ static const struct ms_tp_data ms8607_data = { }; static const struct i2c_device_id ms5637_id[] = { - {"ms5637", (kernel_ulong_t)&ms5637_data }, - {"ms5805", (kernel_ulong_t)&ms5805_data }, - {"ms5837", (kernel_ulong_t)&ms5837_data }, - {"ms8607-temppressure", (kernel_ulong_t)&ms8607_data }, + { .name = "ms5637", .driver_data = (kernel_ulong_t)&ms5637_data }, + { .name = "ms5805", .driver_data = (kernel_ulong_t)&ms5805_data }, + { .name = "ms5837", .driver_data = (kernel_ulong_t)&ms5837_data }, + { .name = "ms8607-temppressure", .driver_data = (kernel_ulong_t)&ms8607_data }, { } }; MODULE_DEVICE_TABLE(i2c, ms5637_id); diff --git a/drivers/iio/pressure/rohm-bm1390.c b/drivers/iio/pressure/rohm-bm1390.c index 08146ca0f91d..b3be9de03678 100644 --- a/drivers/iio/pressure/rohm-bm1390.c +++ b/drivers/iio/pressure/rohm-bm1390.c @@ -888,7 +888,7 @@ static const struct of_device_id bm1390_of_match[] = { MODULE_DEVICE_TABLE(of, bm1390_of_match); static const struct i2c_device_id bm1390_id[] = { - { "bm1390glv-z", }, + { .name = "bm1390glv-z" }, { } }; MODULE_DEVICE_TABLE(i2c, bm1390_id); diff --git a/drivers/iio/pressure/sdp500.c b/drivers/iio/pressure/sdp500.c index 9828c73c4855..ba80dc21faad 100644 --- a/drivers/iio/pressure/sdp500.c +++ b/drivers/iio/pressure/sdp500.c @@ -130,7 +130,7 @@ static int sdp500_probe(struct i2c_client *client) } static const struct i2c_device_id sdp500_id[] = { - { "sdp500" }, + { .name = "sdp500" }, { } }; MODULE_DEVICE_TABLE(i2c, sdp500_id); diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c index 0f50bac1fb4d..816bfcfd62ae 100644 --- a/drivers/iio/pressure/st_pressure_i2c.c +++ b/drivers/iio/pressure/st_pressure_i2c.c @@ -61,14 +61,14 @@ static const struct acpi_device_id st_press_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, st_press_acpi_match); static const struct i2c_device_id st_press_id_table[] = { - { LPS001WP_PRESS_DEV_NAME, LPS001WP }, - { LPS25H_PRESS_DEV_NAME, LPS25H }, - { LPS331AP_PRESS_DEV_NAME, LPS331AP }, - { LPS22HB_PRESS_DEV_NAME, LPS22HB }, - { LPS33HW_PRESS_DEV_NAME, LPS33HW }, - { LPS35HW_PRESS_DEV_NAME, LPS35HW }, - { LPS22HH_PRESS_DEV_NAME, LPS22HH }, - { LPS22DF_PRESS_DEV_NAME, LPS22DF }, + { .name = LPS001WP_PRESS_DEV_NAME, .driver_data = LPS001WP }, + { .name = LPS25H_PRESS_DEV_NAME, .driver_data = LPS25H }, + { .name = LPS331AP_PRESS_DEV_NAME, .driver_data = LPS331AP }, + { .name = LPS22HB_PRESS_DEV_NAME, .driver_data = LPS22HB }, + { .name = LPS33HW_PRESS_DEV_NAME, .driver_data = LPS33HW }, + { .name = LPS35HW_PRESS_DEV_NAME, .driver_data = LPS35HW }, + { .name = LPS22HH_PRESS_DEV_NAME, .driver_data = LPS22HH }, + { .name = LPS22DF_PRESS_DEV_NAME, .driver_data = LPS22DF }, { } }; MODULE_DEVICE_TABLE(i2c, st_press_id_table); diff --git a/drivers/iio/pressure/t5403.c b/drivers/iio/pressure/t5403.c index c7cb0fd816d3..ab30f6745181 100644 --- a/drivers/iio/pressure/t5403.c +++ b/drivers/iio/pressure/t5403.c @@ -251,7 +251,7 @@ static int t5403_probe(struct i2c_client *client) } static const struct i2c_device_id t5403_id[] = { - { "t5403" }, + { .name = "t5403" }, { } }; MODULE_DEVICE_TABLE(i2c, t5403_id); diff --git a/drivers/iio/pressure/zpa2326_i2c.c b/drivers/iio/pressure/zpa2326_i2c.c index a6034bf05d97..2d8af33f6a29 100644 --- a/drivers/iio/pressure/zpa2326_i2c.c +++ b/drivers/iio/pressure/zpa2326_i2c.c @@ -58,7 +58,7 @@ static void zpa2326_remove_i2c(struct i2c_client *client) } static const struct i2c_device_id zpa2326_i2c_ids[] = { - { "zpa2326" }, + { .name = "zpa2326" }, { } }; MODULE_DEVICE_TABLE(i2c, zpa2326_i2c_ids); diff --git a/drivers/iio/proximity/aw96103.c b/drivers/iio/proximity/aw96103.c index 3472a2c36e44..8fbb755dcae0 100644 --- a/drivers/iio/proximity/aw96103.c +++ b/drivers/iio/proximity/aw96103.c @@ -825,8 +825,8 @@ static const struct of_device_id aw96103_dt_match[] = { MODULE_DEVICE_TABLE(of, aw96103_dt_match); static const struct i2c_device_id aw96103_i2c_id[] = { - { "aw96103", (kernel_ulong_t)&aw_chip_info_tbl[AW96103_VAL] }, - { "aw96105", (kernel_ulong_t)&aw_chip_info_tbl[AW96105_VAL] }, + { .name = "aw96103", .driver_data = (kernel_ulong_t)&aw_chip_info_tbl[AW96103_VAL] }, + { .name = "aw96105", .driver_data = (kernel_ulong_t)&aw_chip_info_tbl[AW96105_VAL] }, { } }; MODULE_DEVICE_TABLE(i2c, aw96103_i2c_id); diff --git a/drivers/iio/proximity/hx9023s.c b/drivers/iio/proximity/hx9023s.c index 9efaa5b6b5bd..c3a93c0e2b64 100644 --- a/drivers/iio/proximity/hx9023s.c +++ b/drivers/iio/proximity/hx9023s.c @@ -1199,7 +1199,7 @@ static const struct of_device_id hx9023s_of_match[] = { MODULE_DEVICE_TABLE(of, hx9023s_of_match); static const struct i2c_device_id hx9023s_id[] = { - { "hx9023s" }, + { .name = "hx9023s" }, { } }; MODULE_DEVICE_TABLE(i2c, hx9023s_id); diff --git a/drivers/iio/proximity/isl29501.c b/drivers/iio/proximity/isl29501.c index f69db6f2f380..016626f21218 100644 --- a/drivers/iio/proximity/isl29501.c +++ b/drivers/iio/proximity/isl29501.c @@ -995,7 +995,7 @@ static int isl29501_probe(struct i2c_client *client) } static const struct i2c_device_id isl29501_id[] = { - { "isl29501" }, + { .name = "isl29501" }, { } }; diff --git a/drivers/iio/proximity/mb1232.c b/drivers/iio/proximity/mb1232.c index 34b49c54e68b..1e8ecb9e9c56 100644 --- a/drivers/iio/proximity/mb1232.c +++ b/drivers/iio/proximity/mb1232.c @@ -244,13 +244,13 @@ static const struct of_device_id of_mb1232_match[] = { MODULE_DEVICE_TABLE(of, of_mb1232_match); static const struct i2c_device_id mb1232_id[] = { - { "maxbotix-mb1202", }, - { "maxbotix-mb1212", }, - { "maxbotix-mb1222", }, - { "maxbotix-mb1232", }, - { "maxbotix-mb1242", }, - { "maxbotix-mb7040", }, - { "maxbotix-mb7137", }, + { .name = "maxbotix-mb1202" }, + { .name = "maxbotix-mb1212" }, + { .name = "maxbotix-mb1222" }, + { .name = "maxbotix-mb1232" }, + { .name = "maxbotix-mb1242" }, + { .name = "maxbotix-mb7040" }, + { .name = "maxbotix-mb7137" }, { } }; MODULE_DEVICE_TABLE(i2c, mb1232_id); diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c index 21336b8f122a..5e9e04540393 100644 --- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c +++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c @@ -319,8 +319,8 @@ static void lidar_remove(struct i2c_client *client) } static const struct i2c_device_id lidar_id[] = { - { "lidar-lite-v2" }, - { "lidar-lite-v3" }, + { .name = "lidar-lite-v2" }, + { .name = "lidar-lite-v3" }, { } }; MODULE_DEVICE_TABLE(i2c, lidar_id); diff --git a/drivers/iio/proximity/rfd77402.c b/drivers/iio/proximity/rfd77402.c index 81b8daf17a54..db1e94fc5658 100644 --- a/drivers/iio/proximity/rfd77402.c +++ b/drivers/iio/proximity/rfd77402.c @@ -433,7 +433,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(rfd77402_pm_ops, rfd77402_suspend, rfd77402_resume); static const struct i2c_device_id rfd77402_id[] = { - { "rfd77402" }, + { .name = "rfd77402" }, { } }; MODULE_DEVICE_TABLE(i2c, rfd77402_id); diff --git a/drivers/iio/proximity/srf08.c b/drivers/iio/proximity/srf08.c index 92a37ba331f6..35eb3fd7e700 100644 --- a/drivers/iio/proximity/srf08.c +++ b/drivers/iio/proximity/srf08.c @@ -530,9 +530,9 @@ static const struct of_device_id of_srf08_match[] = { MODULE_DEVICE_TABLE(of, of_srf08_match); static const struct i2c_device_id srf08_id[] = { - { "srf02", SRF02 }, - { "srf08", SRF08 }, - { "srf10", SRF10 }, + { .name = "srf02", .driver_data = SRF02 }, + { .name = "srf08", .driver_data = SRF08 }, + { .name = "srf10", .driver_data = SRF10 }, { } }; MODULE_DEVICE_TABLE(i2c, srf08_id); diff --git a/drivers/iio/proximity/sx9310.c b/drivers/iio/proximity/sx9310.c index fb02eac78ed4..602f7b95c83e 100644 --- a/drivers/iio/proximity/sx9310.c +++ b/drivers/iio/proximity/sx9310.c @@ -1007,8 +1007,8 @@ static const struct of_device_id sx9310_of_match[] = { MODULE_DEVICE_TABLE(of, sx9310_of_match); static const struct i2c_device_id sx9310_id[] = { - { "sx9310", (kernel_ulong_t)&sx9310_info }, - { "sx9311", (kernel_ulong_t)&sx9311_info }, + { .name = "sx9310", .driver_data = (kernel_ulong_t)&sx9310_info }, + { .name = "sx9311", .driver_data = (kernel_ulong_t)&sx9311_info }, { } }; MODULE_DEVICE_TABLE(i2c, sx9310_id); diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c index 6c67bae7488c..dadce9b44227 100644 --- a/drivers/iio/proximity/sx9500.c +++ b/drivers/iio/proximity/sx9500.c @@ -1025,7 +1025,7 @@ static const struct of_device_id sx9500_of_match[] = { MODULE_DEVICE_TABLE(of, sx9500_of_match); static const struct i2c_device_id sx9500_id[] = { - { "sx9500" }, + { .name = "sx9500" }, { } }; MODULE_DEVICE_TABLE(i2c, sx9500_id); diff --git a/drivers/iio/proximity/vl53l0x-i2c.c b/drivers/iio/proximity/vl53l0x-i2c.c index ad3e46d47fa8..21579331c6c3 100644 --- a/drivers/iio/proximity/vl53l0x-i2c.c +++ b/drivers/iio/proximity/vl53l0x-i2c.c @@ -393,7 +393,7 @@ static int vl53l0x_probe(struct i2c_client *client) } static const struct i2c_device_id vl53l0x_id[] = { - { "vl53l0x" }, + { .name = "vl53l0x" }, { } }; MODULE_DEVICE_TABLE(i2c, vl53l0x_id); diff --git a/drivers/iio/proximity/vl53l1x-i2c.c b/drivers/iio/proximity/vl53l1x-i2c.c index 4d9cb3983dba..ff56bfcf8bd2 100644 --- a/drivers/iio/proximity/vl53l1x-i2c.c +++ b/drivers/iio/proximity/vl53l1x-i2c.c @@ -730,7 +730,7 @@ static int vl53l1x_probe(struct i2c_client *client) } static const struct i2c_device_id vl53l1x_id[] = { - { "vl53l1x" }, + { .name = "vl53l1x" }, { } }; MODULE_DEVICE_TABLE(i2c, vl53l1x_id); diff --git a/drivers/iio/temperature/max30208.c b/drivers/iio/temperature/max30208.c index 720469f9dc36..6172abc6d533 100644 --- a/drivers/iio/temperature/max30208.c +++ b/drivers/iio/temperature/max30208.c @@ -218,7 +218,7 @@ static int max30208_probe(struct i2c_client *i2c) } static const struct i2c_device_id max30208_id_table[] = { - { "max30208" }, + { .name = "max30208" }, { } }; MODULE_DEVICE_TABLE(i2c, max30208_id_table); diff --git a/drivers/iio/temperature/mcp9600.c b/drivers/iio/temperature/mcp9600.c index aa42c2b1a369..2091733738b7 100644 --- a/drivers/iio/temperature/mcp9600.c +++ b/drivers/iio/temperature/mcp9600.c @@ -551,8 +551,8 @@ static const struct mcp_chip_info mcp9601_chip_info = { }; static const struct i2c_device_id mcp9600_id[] = { - { "mcp9600", .driver_data = (kernel_ulong_t)&mcp9600_chip_info }, - { "mcp9601", .driver_data = (kernel_ulong_t)&mcp9601_chip_info }, + { .name = "mcp9600", .driver_data = (kernel_ulong_t)&mcp9600_chip_info }, + { .name = "mcp9601", .driver_data = (kernel_ulong_t)&mcp9601_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, mcp9600_id); diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c index 1ad21b73e1b4..342f2e4f80d1 100644 --- a/drivers/iio/temperature/mlx90614.c +++ b/drivers/iio/temperature/mlx90614.c @@ -699,8 +699,8 @@ static const struct mlx_chip_info mlx90615_chip_info = { }; static const struct i2c_device_id mlx90614_id[] = { - { "mlx90614", .driver_data = (kernel_ulong_t)&mlx90614_chip_info }, - { "mlx90615", .driver_data = (kernel_ulong_t)&mlx90615_chip_info }, + { .name = "mlx90614", .driver_data = (kernel_ulong_t)&mlx90614_chip_info }, + { .name = "mlx90615", .driver_data = (kernel_ulong_t)&mlx90615_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, mlx90614_id); diff --git a/drivers/iio/temperature/mlx90632.c b/drivers/iio/temperature/mlx90632.c index b44f7036c2cc..3ab7687c4146 100644 --- a/drivers/iio/temperature/mlx90632.c +++ b/drivers/iio/temperature/mlx90632.c @@ -1276,7 +1276,7 @@ static int mlx90632_probe(struct i2c_client *client) } static const struct i2c_device_id mlx90632_id[] = { - { "mlx90632" }, + { .name = "mlx90632" }, { } }; MODULE_DEVICE_TABLE(i2c, mlx90632_id); diff --git a/drivers/iio/temperature/mlx90635.c b/drivers/iio/temperature/mlx90635.c index 1c8948ca54df..8c8bdab106dd 100644 --- a/drivers/iio/temperature/mlx90635.c +++ b/drivers/iio/temperature/mlx90635.c @@ -1026,7 +1026,7 @@ static int mlx90635_probe(struct i2c_client *client) } static const struct i2c_device_id mlx90635_id[] = { - { "mlx90635" }, + { .name = "mlx90635" }, { } }; MODULE_DEVICE_TABLE(i2c, mlx90635_id); diff --git a/drivers/iio/temperature/tmp006.c b/drivers/iio/temperature/tmp006.c index d8d8c8936d17..9939b9cd4796 100644 --- a/drivers/iio/temperature/tmp006.c +++ b/drivers/iio/temperature/tmp006.c @@ -391,7 +391,7 @@ static const struct of_device_id tmp006_of_match[] = { MODULE_DEVICE_TABLE(of, tmp006_of_match); static const struct i2c_device_id tmp006_id[] = { - { "tmp006" }, + { .name = "tmp006" }, { } }; MODULE_DEVICE_TABLE(i2c, tmp006_id); diff --git a/drivers/iio/temperature/tmp007.c b/drivers/iio/temperature/tmp007.c index 043283b02c4d..d9eea06ff540 100644 --- a/drivers/iio/temperature/tmp007.c +++ b/drivers/iio/temperature/tmp007.c @@ -563,7 +563,7 @@ static const struct of_device_id tmp007_of_match[] = { MODULE_DEVICE_TABLE(of, tmp007_of_match); static const struct i2c_device_id tmp007_id[] = { - { "tmp007" }, + { .name = "tmp007" }, { } }; MODULE_DEVICE_TABLE(i2c, tmp007_id); diff --git a/drivers/iio/temperature/tmp117.c b/drivers/iio/temperature/tmp117.c index 8972083d903a..6bc18616ad15 100644 --- a/drivers/iio/temperature/tmp117.c +++ b/drivers/iio/temperature/tmp117.c @@ -209,8 +209,8 @@ static const struct of_device_id tmp117_of_match[] = { MODULE_DEVICE_TABLE(of, tmp117_of_match); static const struct i2c_device_id tmp117_id[] = { - { "tmp116", (kernel_ulong_t)&tmp116_channels_info }, - { "tmp117", (kernel_ulong_t)&tmp117_channels_info }, + { .name = "tmp116", .driver_data = (kernel_ulong_t)&tmp116_channels_info }, + { .name = "tmp117", .driver_data = (kernel_ulong_t)&tmp117_channels_info }, { } }; MODULE_DEVICE_TABLE(i2c, tmp117_id); diff --git a/drivers/iio/temperature/tsys01.c b/drivers/iio/temperature/tsys01.c index 334bba6fdae6..92c73369b06f 100644 --- a/drivers/iio/temperature/tsys01.c +++ b/drivers/iio/temperature/tsys01.c @@ -206,7 +206,7 @@ static int tsys01_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id tsys01_id[] = { - { "tsys01" }, + { .name = "tsys01" }, { } }; MODULE_DEVICE_TABLE(i2c, tsys01_id); diff --git a/drivers/iio/temperature/tsys02d.c b/drivers/iio/temperature/tsys02d.c index 0cad27205667..3ef72347456e 100644 --- a/drivers/iio/temperature/tsys02d.c +++ b/drivers/iio/temperature/tsys02d.c @@ -168,7 +168,7 @@ static int tsys02d_probe(struct i2c_client *client) } static const struct i2c_device_id tsys02d_id[] = { - { "tsys02d" }, + { .name = "tsys02d" }, { } }; MODULE_DEVICE_TABLE(i2c, tsys02d_id); From f9f99197a88260046b56cf4d24e51aff849bd45b Mon Sep 17 00:00:00 2001 From: David Lechner Date: Thu, 21 May 2026 20:25:29 -0500 Subject: [PATCH 204/266] iio: humidity: ens210: remove compiler warning workaround Rewrite IIO_CHAN_INFO_RAW case to avoid needing to add unreachable code to work around a compiler warning. When scoped_guard() was first introduced, compilers could not see when it returned unconditionally from inside the hidden for loop. This has since been fixed in the macro definition. So removing the `return -EINVAL` should be enough. Still, we can improve readability, decrease indentation and avoid the hidden for loop by rewriting the case without scoped_guard(). Signed-off-by: David Lechner Signed-off-by: Jonathan Cameron --- drivers/iio/humidity/ens210.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/iio/humidity/ens210.c b/drivers/iio/humidity/ens210.c index 22ad208e6aa6..49543fc389bf 100644 --- a/drivers/iio/humidity/ens210.c +++ b/drivers/iio/humidity/ens210.c @@ -149,15 +149,16 @@ static int ens210_read_raw(struct iio_dev *indio_dev, int ret; switch (mask) { - case IIO_CHAN_INFO_RAW: - scoped_guard(mutex, &data->lock) { - ret = ens210_get_measurement( - indio_dev, channel->type == IIO_TEMP, val); - if (ret) - return ret; - return IIO_VAL_INT; - } - return -EINVAL; /* compiler warning workaround */ + case IIO_CHAN_INFO_RAW: { + guard(mutex)(&data->lock); + + ret = ens210_get_measurement(indio_dev, channel->type == IIO_TEMP, + val); + if (ret) + return ret; + + return IIO_VAL_INT; + } case IIO_CHAN_INFO_SCALE: if (channel->type == IIO_TEMP) { *val = 15; From f9242e31d16dec9958d0b65d8071823e2efdd9f6 Mon Sep 17 00:00:00 2001 From: Maxwell Doose Date: Thu, 21 May 2026 17:30:43 -0500 Subject: [PATCH 205/266] iio: imu: kmx61: Use guard(mutex)() over manual locking Include linux/cleanup.h to take advantage of new macros. Replace manual mutex_lock() and mutex_unlock() calls across the file with guard(mutex)() and scoped_guard() where appropriate to simplify error paths and eliminate manual locking calls. Add new helper function kmx61_read_for_each_active_channel() to mitigate certain style issues and to prevent notifying that the IRQ is finished whilst holding the lock. Update certain returns, and add default case to return -EINVAL in kmx61_read_raw(). Remove now-redundant gotos and ret variables, as the new RAII macros make them unneeded. Signed-off-by: Maxwell Doose Signed-off-by: Jonathan Cameron --- drivers/iio/imu/kmx61.c | 129 +++++++++++++++++++++------------------- 1 file changed, 67 insertions(+), 62 deletions(-) diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c index a4d176f81f0e..b8a8297b39af 100644 --- a/drivers/iio/imu/kmx61.c +++ b/drivers/iio/imu/kmx61.c @@ -7,6 +7,7 @@ * IIO driver for KMX61 (7-bit I2C slave address 0x0E or 0x0F). */ +#include #include #include #include @@ -783,7 +784,7 @@ static int kmx61_read_raw(struct iio_dev *indio_dev, struct kmx61_data *data = kmx61_get_data(indio_dev); switch (mask) { - case IIO_CHAN_INFO_RAW: + case IIO_CHAN_INFO_RAW: { switch (chan->type) { case IIO_ACCEL: base_reg = KMX61_ACC_XOUT_L; @@ -794,28 +795,24 @@ static int kmx61_read_raw(struct iio_dev *indio_dev, default: return -EINVAL; } - mutex_lock(&data->lock); + guard(mutex)(&data->lock); ret = kmx61_set_power_state(data, true, chan->address); - if (ret) { - mutex_unlock(&data->lock); + if (ret) return ret; - } ret = kmx61_read_measurement(data, base_reg, chan->scan_index); if (ret < 0) { kmx61_set_power_state(data, false, chan->address); - mutex_unlock(&data->lock); return ret; } *val = sign_extend32(ret >> chan->scan_type.shift, chan->scan_type.realbits - 1); ret = kmx61_set_power_state(data, false, chan->address); - - mutex_unlock(&data->lock); if (ret) return ret; return IIO_VAL_INT; + } case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_ACCEL: @@ -830,45 +827,46 @@ static int kmx61_read_raw(struct iio_dev *indio_dev, default: return -EINVAL; } - case IIO_CHAN_INFO_SAMP_FREQ: + case IIO_CHAN_INFO_SAMP_FREQ: { if (chan->type != IIO_ACCEL && chan->type != IIO_MAGN) return -EINVAL; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); + ret = kmx61_get_odr(data, val, val2, chan->address); - mutex_unlock(&data->lock); if (ret) return -EINVAL; return IIO_VAL_INT_PLUS_MICRO; } - return -EINVAL; + default: + return -EINVAL; + } } static int kmx61_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) { - int ret; struct kmx61_data *data = kmx61_get_data(indio_dev); switch (mask) { - case IIO_CHAN_INFO_SAMP_FREQ: + case IIO_CHAN_INFO_SAMP_FREQ: { if (chan->type != IIO_ACCEL && chan->type != IIO_MAGN) return -EINVAL; - mutex_lock(&data->lock); - ret = kmx61_set_odr(data, val, val2, chan->address); - mutex_unlock(&data->lock); - return ret; + guard(mutex)(&data->lock); + + return kmx61_set_odr(data, val, val2, chan->address); + } case IIO_CHAN_INFO_SCALE: switch (chan->type) { - case IIO_ACCEL: + case IIO_ACCEL: { if (val != 0) return -EINVAL; - mutex_lock(&data->lock); - ret = kmx61_set_scale(data, val2); - mutex_unlock(&data->lock); - return ret; + guard(mutex)(&data->lock); + + return kmx61_set_scale(data, val2); + } default: return -EINVAL; } @@ -945,29 +943,26 @@ static int kmx61_write_event_config(struct iio_dev *indio_dev, if (state && data->ev_enable_state) return 0; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); if (!state && data->motion_trig_on) { data->ev_enable_state = false; - goto err_unlock; + return ret; } ret = kmx61_set_power_state(data, state, KMX61_ACC); if (ret < 0) - goto err_unlock; + return ret; ret = kmx61_setup_any_motion_interrupt(data, state); if (ret < 0) { kmx61_set_power_state(data, false, KMX61_ACC); - goto err_unlock; + return ret; } data->ev_enable_state = state; -err_unlock: - mutex_unlock(&data->lock); - - return ret; + return 0; } static int kmx61_acc_validate_trigger(struct iio_dev *indio_dev, @@ -1020,11 +1015,11 @@ static int kmx61_data_rdy_trigger_set_state(struct iio_trigger *trig, struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); struct kmx61_data *data = kmx61_get_data(indio_dev); - mutex_lock(&data->lock); + guard(mutex)(&data->lock); if (!state && data->ev_enable_state && data->motion_trig_on) { data->motion_trig_on = false; - goto err_unlock; + return ret; } if (data->acc_dready_trig == trig || data->motion_trig == trig) @@ -1034,7 +1029,7 @@ static int kmx61_data_rdy_trigger_set_state(struct iio_trigger *trig, ret = kmx61_set_power_state(data, state, device); if (ret < 0) - goto err_unlock; + return ret; if (data->acc_dready_trig == trig || data->mag_dready_trig == trig) ret = kmx61_setup_new_data_interrupt(data, state, device); @@ -1042,7 +1037,7 @@ static int kmx61_data_rdy_trigger_set_state(struct iio_trigger *trig, ret = kmx61_setup_any_motion_interrupt(data, state); if (ret < 0) { kmx61_set_power_state(data, false, device); - goto err_unlock; + return ret; } if (data->acc_dready_trig == trig) @@ -1051,10 +1046,8 @@ static int kmx61_data_rdy_trigger_set_state(struct iio_trigger *trig, data->mag_dready_trig_on = state; else data->motion_trig_on = state; -err_unlock: - mutex_unlock(&data->lock); - return ret; + return 0; } static void kmx61_trig_reenable(struct iio_trigger *trig) @@ -1181,30 +1174,49 @@ static irqreturn_t kmx61_data_rdy_trig_poll(int irq, void *private) return IRQ_HANDLED; } -static irqreturn_t kmx61_trigger_handler(int irq, void *p) +/** + * kmx61_read_for_each_active_channel() - Read each active channel into a buffer + * + * @indio_dev: IIO Device struct to read from + * @buffer: Destination buffer to write to, the array must be of at least size 8 + * + * Return: + * 0 on success, negative errno on failure. + */ +static int kmx61_read_for_each_active_channel(struct iio_dev *indio_dev, s16 *buffer) { - struct iio_poll_func *pf = p; - struct iio_dev *indio_dev = pf->indio_dev; struct kmx61_data *data = kmx61_get_data(indio_dev); - int bit, ret, i = 0; u8 base; - s16 buffer[8] = { }; + int ret, bit; + int i = 0; if (indio_dev == data->acc_indio_dev) base = KMX61_ACC_XOUT_L; else base = KMX61_MAG_XOUT_L; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); + iio_for_each_active_channel(indio_dev, bit) { ret = kmx61_read_measurement(data, base, bit); - if (ret < 0) { - mutex_unlock(&data->lock); - goto err; - } + if (ret < 0) + return ret; buffer[i++] = ret; } - mutex_unlock(&data->lock); + + return 0; +} + +static irqreturn_t kmx61_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + int ret; + s16 buffer[8] = { }; + + ret = kmx61_read_for_each_active_channel(indio_dev, buffer); + if (ret < 0) + goto err; iio_push_to_buffers(indio_dev, buffer); err: @@ -1419,22 +1431,18 @@ static void kmx61_remove(struct i2c_client *client) iio_trigger_unregister(data->motion_trig); } - mutex_lock(&data->lock); + guard(mutex)(&data->lock); + kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, true); - mutex_unlock(&data->lock); } static int kmx61_suspend(struct device *dev) { - int ret; struct kmx61_data *data = i2c_get_clientdata(to_i2c_client(dev)); - mutex_lock(&data->lock); - ret = kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, - false); - mutex_unlock(&data->lock); + guard(mutex)(&data->lock); - return ret; + return kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, false); } static int kmx61_resume(struct device *dev) @@ -1453,13 +1461,10 @@ static int kmx61_resume(struct device *dev) static int kmx61_runtime_suspend(struct device *dev) { struct kmx61_data *data = i2c_get_clientdata(to_i2c_client(dev)); - int ret; - mutex_lock(&data->lock); - ret = kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, true); - mutex_unlock(&data->lock); + guard(mutex)(&data->lock); - return ret; + return kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, true); } static int kmx61_runtime_resume(struct device *dev) From 94574dff234074addb0066e39005b8eac8351627 Mon Sep 17 00:00:00 2001 From: Stepan Ionichev Date: Thu, 21 May 2026 00:08:50 +0500 Subject: [PATCH 206/266] iio: imu: bno055: terminate dev_err() strings with a newline Two dev_err() calls in bno055_ser_write_reg() and bno055_ser_read_reg() are missing the trailing newline, so the kernel log buffer continues the next message on the same line. Add the missing \n. Signed-off-by: Stepan Ionichev Reviewed-by: Maxwell Doose Signed-off-by: Jonathan Cameron --- drivers/iio/imu/bno055/bno055_ser_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/imu/bno055/bno055_ser_core.c b/drivers/iio/imu/bno055/bno055_ser_core.c index 48669dabb37b..733f9112de06 100644 --- a/drivers/iio/imu/bno055/bno055_ser_core.c +++ b/drivers/iio/imu/bno055/bno055_ser_core.c @@ -288,7 +288,7 @@ static int bno055_ser_write_reg(void *context, const void *_data, size_t count) struct bno055_ser_priv *priv = context; if (count < 2) { - dev_err(&priv->serdev->dev, "Invalid write count %zu", count); + dev_err(&priv->serdev->dev, "Invalid write count %zu\n", count); return -EINVAL; } @@ -306,7 +306,7 @@ static int bno055_ser_read_reg(void *context, struct bno055_ser_priv *priv = context; if (val_size > 128) { - dev_err(&priv->serdev->dev, "Invalid read valsize %zu", val_size); + dev_err(&priv->serdev->dev, "Invalid read valsize %zu\n", val_size); return -EINVAL; } From ab568cb755600dda283541179e9338e1f0faed9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nat=C3=A1lia=20Salvino=20Andr=C3=A9?= Date: Tue, 19 May 2026 20:40:43 -0300 Subject: [PATCH 207/266] iio: accel: HID: hid-sensor-accel-3d: Refactor channel initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clean up the channel initialization loop and replace the local accel_3d_adjust_channel_bit_mask() function with a compound literal to improve code readability. Signed-off-by: Natália Salvino André Co-developed-by: Pietro Di Consolo Gregorio Signed-off-by: Pietro Di Consolo Gregorio Signed-off-by: Jonathan Cameron --- drivers/iio/accel/hid-sensor-accel-3d.c | 27 +++++++++---------------- 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c index 2ff591b3458f..2bf05ab5235e 100644 --- a/drivers/iio/accel/hid-sensor-accel-3d.c +++ b/drivers/iio/accel/hid-sensor-accel-3d.c @@ -3,6 +3,7 @@ * HID Sensors Driver * Copyright (c) 2012, Intel Corporation. */ +#include #include #include #include @@ -119,17 +120,6 @@ static const struct iio_chan_spec gravity_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP), }; -/* Adjust channel real bits based on report descriptor */ -static void accel_3d_adjust_channel_bit_mask(struct iio_chan_spec *channels, - int channel, int size) -{ - channels[channel].scan_type.sign = 's'; - /* Real storage bits will change based on the report desc. */ - channels[channel].scan_type.realbits = size * 8; - /* Maximum size of a sample to capture is u32 */ - channels[channel].scan_type.storagebits = sizeof(u32) * 8; -} - /* Channel read_raw handler */ static int accel_3d_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, @@ -297,19 +287,20 @@ static int accel_3d_parse_report(struct platform_device *pdev, struct accel_3d_state *st) { int ret; - int i; - for (i = 0; i <= CHANNEL_SCAN_INDEX_Z; ++i) { + for (unsigned int ch = CHANNEL_SCAN_INDEX_X; ch <= CHANNEL_SCAN_INDEX_Z; ch++) { ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT, usage_id, - HID_USAGE_SENSOR_ACCEL_X_AXIS + i, - &st->accel[CHANNEL_SCAN_INDEX_X + i]); + HID_USAGE_SENSOR_ACCEL_X_AXIS + ch, + &st->accel[ch]); if (ret < 0) break; - accel_3d_adjust_channel_bit_mask(channels, - CHANNEL_SCAN_INDEX_X + i, - st->accel[CHANNEL_SCAN_INDEX_X + i].size); + channels[ch].scan_type = (struct iio_scan_type) { + .format = 's', + .realbits = BYTES_TO_BITS(st->accel[ch].size), + .storagebits = BITS_PER_TYPE(u32), + }; } dev_dbg(&pdev->dev, "accel_3d %x:%x, %x:%x, %x:%x\n", st->accel[0].index, From 3a7f08f66ec31b23822f107444e7c6816909ec1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nat=C3=A1lia=20Salvino=20Andr=C3=A9?= Date: Tue, 19 May 2026 20:40:44 -0300 Subject: [PATCH 208/266] iio: gyro: HID: hid-sensor-gyro-3d: Refactor channel initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the local gyro_3d_adjust_channel_bit_mask() function with a compound literal for scan_type initialization to improve code readability. Additionaly, clean up the channel initialization loop by iterating directly over the channel scan indices. Signed-off-by: Natália Salvino André Co-developed-by: Pietro Di Consolo Gregorio Signed-off-by: Pietro Di Consolo Gregorio Signed-off-by: Jonathan Cameron --- drivers/iio/gyro/hid-sensor-gyro-3d.c | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c index c340cc899a7c..e48c25c87b6d 100644 --- a/drivers/iio/gyro/hid-sensor-gyro-3d.c +++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c @@ -3,6 +3,7 @@ * HID Sensors Driver * Copyright (c) 2012, Intel Corporation. */ +#include #include #include #include @@ -82,17 +83,6 @@ static const struct iio_chan_spec gyro_3d_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP) }; -/* Adjust channel real bits based on report descriptor */ -static void gyro_3d_adjust_channel_bit_mask(struct iio_chan_spec *channels, - int channel, int size) -{ - channels[channel].scan_type.sign = 's'; - /* Real storage bits will change based on the report desc. */ - channels[channel].scan_type.realbits = size * 8; - /* Maximum size of a sample to capture is u32 */ - channels[channel].scan_type.storagebits = sizeof(u32) * 8; -} - /* Channel read_raw handler */ static int gyro_3d_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, @@ -248,19 +238,20 @@ static int gyro_3d_parse_report(struct platform_device *pdev, struct gyro_3d_state *st) { int ret; - int i; - for (i = 0; i <= CHANNEL_SCAN_INDEX_Z; ++i) { + for (unsigned int ch = CHANNEL_SCAN_INDEX_X; ch <= CHANNEL_SCAN_INDEX_Z; ch++) { ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT, usage_id, - HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS + i, - &st->gyro[CHANNEL_SCAN_INDEX_X + i]); + HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS + ch, + &st->gyro[ch]); if (ret < 0) break; - gyro_3d_adjust_channel_bit_mask(channels, - CHANNEL_SCAN_INDEX_X + i, - st->gyro[CHANNEL_SCAN_INDEX_X + i].size); + channels[ch].scan_type = (struct iio_scan_type) { + .format = 's', + .realbits = BYTES_TO_BITS(st->gyro[ch].size), + .storagebits = BITS_PER_TYPE(u32), + }; } dev_dbg(&pdev->dev, "gyro_3d %x:%x, %x:%x, %x:%x\n", st->gyro[0].index, From cded217233845577e58b0720a61ebce556196f08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nat=C3=A1lia=20Salvino=20Andr=C3=A9?= Date: Tue, 19 May 2026 20:40:45 -0300 Subject: [PATCH 209/266] iio: light: HID: hid-sensor-als: Refactor channel initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the local als_adjust_channel_bit_mask() function with a compound literal for scan_type initialization to improve code readability. Signed-off-by: Natália Salvino André Co-developed-by: Pietro Di Consolo Gregorio Signed-off-by: Pietro Di Consolo Gregorio Signed-off-by: Jonathan Cameron --- drivers/iio/light/hid-sensor-als.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c index 384572844162..d72e260b8266 100644 --- a/drivers/iio/light/hid-sensor-als.c +++ b/drivers/iio/light/hid-sensor-als.c @@ -3,6 +3,7 @@ * HID Sensors Driver * Copyright (c) 2012, Intel Corporation. */ +#include #include #include #include @@ -117,17 +118,6 @@ static const struct iio_chan_spec als_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP) }; -/* Adjust channel real bits based on report descriptor */ -static void als_adjust_channel_bit_mask(struct iio_chan_spec *channels, - int channel, int size) -{ - channels[channel].scan_type.sign = 's'; - /* Real storage bits will change based on the report desc. */ - channels[channel].scan_type.realbits = size * 8; - /* Maximum size of a sample to capture is u32 */ - channels[channel].scan_type.storagebits = sizeof(u32) * 8; -} - /* Channel read_raw handler */ static int als_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, @@ -335,7 +325,11 @@ static int als_parse_report(struct platform_device *pdev, channels[index] = als_channels[i]; st->als_scan_mask[0] |= BIT(i); - als_adjust_channel_bit_mask(channels, index, st->als[i].size); + channels[index].scan_type = (struct iio_scan_type) { + .format = 's', + .realbits = BYTES_TO_BITS(st->als[i].size), + .storagebits = BITS_PER_TYPE(u32), + }; ++index; dev_dbg(&pdev->dev, "als %x:%x\n", st->als[i].index, From e6cd87745a456548e1a2f9ae90927e18a10b57fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nat=C3=A1lia=20Salvino=20Andr=C3=A9?= Date: Tue, 19 May 2026 20:40:46 -0300 Subject: [PATCH 210/266] iio: light: HID: hid-sensor-prox: Refactor channel initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the local prox_adjust_channel_bit_mask() function with a compound literal for scan_type initialization to improve code readability. Signed-off-by: Natália Salvino André Co-developed-by: Pietro Di Consolo Gregorio Signed-off-by: Pietro Di Consolo Gregorio Signed-off-by: Jonathan Cameron --- drivers/iio/light/hid-sensor-prox.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c index efa904a70d0e..edc9274a2c07 100644 --- a/drivers/iio/light/hid-sensor-prox.c +++ b/drivers/iio/light/hid-sensor-prox.c @@ -3,6 +3,7 @@ * HID Sensors Driver * Copyright (c) 2014, Intel Corporation. */ +#include #include #include #include @@ -67,17 +68,6 @@ static const struct iio_chan_spec prox_channels[] = { PROX_CHANNEL(false, 0), }; -/* Adjust channel real bits based on report descriptor */ -static void prox_adjust_channel_bit_mask(struct iio_chan_spec *channels, - int channel, int size) -{ - channels[channel].scan_type.sign = 's'; - /* Real storage bits will change based on the report desc. */ - channels[channel].scan_type.realbits = size * 8; - /* Maximum size of a sample to capture is u32 */ - channels[channel].scan_type.storagebits = sizeof(u32) * 8; -} - /* Channel read_raw handler */ static int prox_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, @@ -250,8 +240,11 @@ static int prox_parse_report(struct platform_device *pdev, st->scan_mask[0] |= BIT(index); channels[index] = prox_channels[i]; channels[index].scan_index = index; - prox_adjust_channel_bit_mask(channels, index, - st->prox_attr[index].size); + channels[index].scan_type = (struct iio_scan_type) { + .format = 's', + .realbits = BYTES_TO_BITS(st->prox_attr[index].size), + .storagebits = BITS_PER_TYPE(u32), + }; dev_dbg(&pdev->dev, "prox %x:%x\n", st->prox_attr[index].index, st->prox_attr[index].report_id); st->scale_precision[index] = From 339002636932e56191ba810975a876fe4a3e223f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nat=C3=A1lia=20Salvino=20Andr=C3=A9?= Date: Tue, 19 May 2026 20:40:47 -0300 Subject: [PATCH 211/266] iio: magnetometer: HID: hid-sensor-magn-3d: Refactor channel initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the local magn_3d_adjust_channel_bit_mask() function with a compound literal for scan_type initialization to improve code readability. Signed-off-by: Natália Salvino André Co-developed-by: Pietro Di Consolo Gregorio Signed-off-by: Pietro Di Consolo Gregorio Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/hid-sensor-magn-3d.c | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c index b01dd53eb100..23884825eb00 100644 --- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c +++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c @@ -3,6 +3,7 @@ * HID Sensors Driver * Copyright (c) 2012, Intel Corporation. */ +#include #include #include #include @@ -132,17 +133,6 @@ static const struct iio_chan_spec magn_3d_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(7) }; -/* Adjust channel real bits based on report descriptor */ -static void magn_3d_adjust_channel_bit_mask(struct iio_chan_spec *channels, - int channel, int size) -{ - channels[channel].scan_type.sign = 's'; - /* Real storage bits will change based on the report desc. */ - channels[channel].scan_type.realbits = size * 8; - /* Maximum size of a sample to capture is u32 */ - channels[channel].scan_type.storagebits = sizeof(u32) * 8; -} - /* Channel read_raw handler */ static int magn_3d_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, @@ -418,9 +408,11 @@ static int magn_3d_parse_report(struct platform_device *pdev, if (i != CHANNEL_SCAN_INDEX_TIMESTAMP) { /* Set magn_val_addr to iio value address */ st->magn_val_addr[i] = &st->iio_vals[*chan_count]; - magn_3d_adjust_channel_bit_mask(_channels, - *chan_count, - st->magn[i].size); + _channels[*chan_count].scan_type = (struct iio_scan_type) { + .format = 's', + .realbits = BYTES_TO_BITS(st->magn[i].size), + .storagebits = BITS_PER_TYPE(u32), + }; } (*chan_count)++; } From f1cb3d3afd1024269ec1887a36b28efd9ea849a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nat=C3=A1lia=20Salvino=20Andr=C3=A9?= Date: Tue, 19 May 2026 20:40:48 -0300 Subject: [PATCH 212/266] iio: pressure: HID: hid-sensor-press: Refactor channel initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the local press_adjust_channel_bit_mask() function with a compound literal for scan_type initialization to improve code readability. Signed-off-by: Natália Salvino André Co-developed-by: Pietro Di Consolo Gregorio Signed-off-by: Pietro Di Consolo Gregorio Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/hid-sensor-press.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/iio/pressure/hid-sensor-press.c b/drivers/iio/pressure/hid-sensor-press.c index 5f1d6abda3e4..a039b99d9851 100644 --- a/drivers/iio/pressure/hid-sensor-press.c +++ b/drivers/iio/pressure/hid-sensor-press.c @@ -3,6 +3,7 @@ * HID Sensors Driver * Copyright (c) 2014, Intel Corporation. */ +#include #include #include #include @@ -53,17 +54,6 @@ static const struct iio_chan_spec press_channels[] = { }; -/* Adjust channel real bits based on report descriptor */ -static void press_adjust_channel_bit_mask(struct iio_chan_spec *channels, - int channel, int size) -{ - channels[channel].scan_type.sign = 's'; - /* Real storage bits will change based on the report desc. */ - channels[channel].scan_type.realbits = size * 8; - /* Maximum size of a sample to capture is u32 */ - channels[channel].scan_type.storagebits = sizeof(u32) * 8; -} - /* Channel read_raw handler */ static int press_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, @@ -225,8 +215,11 @@ static int press_parse_report(struct platform_device *pdev, &st->press_attr); if (ret < 0) return ret; - press_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_PRESSURE, - st->press_attr.size); + channels[CHANNEL_SCAN_INDEX_PRESSURE].scan_type = (struct iio_scan_type) { + .format = 's', + .realbits = BYTES_TO_BITS(st->press_attr.size), + .storagebits = BITS_PER_TYPE(u32), + }; dev_dbg(&pdev->dev, "press %x:%x\n", st->press_attr.index, st->press_attr.report_id); From b39f3bb9f5580d19bc0c10dea9224d75fed45f1d Mon Sep 17 00:00:00 2001 From: Aldo Conte Date: Fri, 22 May 2026 14:34:12 +0200 Subject: [PATCH 213/266] iio: tcs3472: power down chip on probe failure If tcs3472_probe() fails after enabling the chip (by writing PON | AEN to the ENABLE register), the error paths return without powering down the device. Add an 'error_powerdown' label at the end of the cleanup chain that calls tcs3472_powerdown() to power down the chip. The existing label cascade is rerouted to fall through to the new label. Move tcs3472_powerdown() above tcs3472_probe() so the probe can call it without a forward declaration. Found by code inspection while reviewing the probe error paths in preparation for the devm_ conversion. Fixes: eb869ade30a6 ("iio: Add tcs3472 color light sensor driver") Signed-off-by: Aldo Conte Signed-off-by: Jonathan Cameron --- drivers/iio/light/tcs3472.c | 38 +++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c index 5a14f8d39aa4..6f055b0967a9 100644 --- a/drivers/iio/light/tcs3472.c +++ b/drivers/iio/light/tcs3472.c @@ -440,6 +440,23 @@ static const struct iio_info tcs3472_info = { .attrs = &tcs3472_attribute_group, }; +static int tcs3472_powerdown(struct tcs3472_data *data) +{ + int ret; + u8 enable_mask = TCS3472_ENABLE_AEN | TCS3472_ENABLE_PON; + + mutex_lock(&data->lock); + + ret = i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE, + data->enable & ~enable_mask); + if (!ret) + data->enable &= ~enable_mask; + + mutex_unlock(&data->lock); + + return ret; +} + static int tcs3472_probe(struct i2c_client *client) { struct tcs3472_data *data; @@ -513,7 +530,7 @@ static int tcs3472_probe(struct i2c_client *client) ret = iio_triggered_buffer_setup(indio_dev, NULL, tcs3472_trigger_handler, NULL); if (ret < 0) - return ret; + goto error_powerdown; if (client->irq) { ret = request_threaded_irq(client->irq, NULL, @@ -536,23 +553,8 @@ static int tcs3472_probe(struct i2c_client *client) free_irq(client->irq, indio_dev); buffer_cleanup: iio_triggered_buffer_cleanup(indio_dev); - return ret; -} - -static int tcs3472_powerdown(struct tcs3472_data *data) -{ - int ret; - u8 enable_mask = TCS3472_ENABLE_AEN | TCS3472_ENABLE_PON; - - mutex_lock(&data->lock); - - ret = i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE, - data->enable & ~enable_mask); - if (!ret) - data->enable &= ~enable_mask; - - mutex_unlock(&data->lock); - +error_powerdown: + tcs3472_powerdown(data); return ret; } From 6283163e2a5c70e8d9d8d34df8b8a6d81507e966 Mon Sep 17 00:00:00 2001 From: Aldo Conte Date: Fri, 22 May 2026 14:34:13 +0200 Subject: [PATCH 214/266] iio: tcs3472: sort headers alphabetically Sort the #include directives in alphabetical order in preparation for adding new headers in upcoming patches. No functional change. Suggested-by: Andy Shevchenko Reviewed-by: Joshua Crofts Signed-off-by: Aldo Conte Signed-off-by: Jonathan Cameron --- drivers/iio/light/tcs3472.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c index 6f055b0967a9..68d9032973dc 100644 --- a/drivers/iio/light/tcs3472.c +++ b/drivers/iio/light/tcs3472.c @@ -13,16 +13,16 @@ * TODO: wait time */ -#include -#include #include +#include +#include #include +#include +#include #include #include -#include #include -#include #include #define TCS3472_DRV_NAME "tcs3472" From 0e6a62767a1235b1b52e9faaf6c916a4c786a3df Mon Sep 17 00:00:00 2001 From: Aldo Conte Date: Fri, 22 May 2026 14:34:14 +0200 Subject: [PATCH 215/266] iio: tcs3472: convert remaining locking to guard(mutex) Convert several functions to use guard(mutex)() This avoids manual unlock calls on each return path, drops the goto in tcs3472_write_event(), and removes 'ret' variables only needed to return after the unlock. While the conversion is in progress, take the opportunity to make a few small cleanups that guard() enables: - In tcs3472_read_event_config(), replace '!!(...)' with '(...) ? 1 : 0' for readability. - In tcs3472_write_event_config(), tcs3472_powerdown() and tcs3472_resume() use an early return on the I2C write failure path. No functional change. Signed-off-by: Aldo Conte Signed-off-by: Jonathan Cameron --- drivers/iio/light/tcs3472.c | 78 ++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 45 deletions(-) diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c index 68d9032973dc..8956ed058a20 100644 --- a/drivers/iio/light/tcs3472.c +++ b/drivers/iio/light/tcs3472.c @@ -13,6 +13,7 @@ * TODO: wait time */ +#include #include #include #include @@ -220,32 +221,24 @@ static int tcs3472_read_event(struct iio_dev *indio_dev, int *val2) { struct tcs3472_data *data = iio_priv(indio_dev); - int ret; unsigned int period; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); switch (info) { case IIO_EV_INFO_VALUE: *val = (dir == IIO_EV_DIR_RISING) ? data->high_thresh : data->low_thresh; - ret = IIO_VAL_INT; - break; + return IIO_VAL_INT; case IIO_EV_INFO_PERIOD: period = (256 - data->atime) * 2400 * tcs3472_intr_pers[data->apers]; *val = period / USEC_PER_SEC; *val2 = period % USEC_PER_SEC; - ret = IIO_VAL_INT_PLUS_MICRO; - break; + return IIO_VAL_INT_PLUS_MICRO; default: - ret = -EINVAL; - break; + return -EINVAL; } - - mutex_unlock(&data->lock); - - return ret; } static int tcs3472_write_event(struct iio_dev *indio_dev, @@ -259,7 +252,8 @@ static int tcs3472_write_event(struct iio_dev *indio_dev, int period; int i; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); + switch (info) { case IIO_EV_INFO_VALUE: switch (dir) { @@ -270,18 +264,18 @@ static int tcs3472_write_event(struct iio_dev *indio_dev, command = TCS3472_AILT; break; default: - ret = -EINVAL; - goto error; + return -EINVAL; } ret = i2c_smbus_write_word_data(data->client, command, val); if (ret) - goto error; + return ret; if (dir == IIO_EV_DIR_RISING) data->high_thresh = val; else data->low_thresh = val; - break; + + return 0; case IIO_EV_INFO_PERIOD: period = val * USEC_PER_SEC + val2; for (i = 1; i < ARRAY_SIZE(tcs3472_intr_pers) - 1; i++) { @@ -291,18 +285,14 @@ static int tcs3472_write_event(struct iio_dev *indio_dev, } ret = i2c_smbus_write_byte_data(data->client, TCS3472_PERS, i); if (ret) - goto error; + return ret; data->apers = i; - break; - default: - ret = -EINVAL; - break; - } -error: - mutex_unlock(&data->lock); - return ret; + return 0; + default: + return -EINVAL; + } } static int tcs3472_read_event_config(struct iio_dev *indio_dev, @@ -310,13 +300,10 @@ static int tcs3472_read_event_config(struct iio_dev *indio_dev, enum iio_event_direction dir) { struct tcs3472_data *data = iio_priv(indio_dev); - int ret; - mutex_lock(&data->lock); - ret = !!(data->enable & TCS3472_ENABLE_AIEN); - mutex_unlock(&data->lock); + guard(mutex)(&data->lock); - return ret; + return (data->enable & TCS3472_ENABLE_AIEN) ? 1 : 0; } static int tcs3472_write_event_config(struct iio_dev *indio_dev, @@ -327,7 +314,7 @@ static int tcs3472_write_event_config(struct iio_dev *indio_dev, int ret = 0; u8 enable_old; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); enable_old = data->enable; @@ -339,12 +326,13 @@ static int tcs3472_write_event_config(struct iio_dev *indio_dev, if (enable_old != data->enable) { ret = i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE, data->enable); - if (ret) + if (ret) { data->enable = enable_old; + return ret; + } } - mutex_unlock(&data->lock); - return ret; + return 0; } static irqreturn_t tcs3472_event_handler(int irq, void *priv) @@ -445,16 +433,16 @@ static int tcs3472_powerdown(struct tcs3472_data *data) int ret; u8 enable_mask = TCS3472_ENABLE_AEN | TCS3472_ENABLE_PON; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); ret = i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE, data->enable & ~enable_mask); - if (!ret) - data->enable &= ~enable_mask; + if (ret) + return ret; - mutex_unlock(&data->lock); + data->enable &= ~enable_mask; - return ret; + return 0; } static int tcs3472_probe(struct i2c_client *client) @@ -583,16 +571,16 @@ static int tcs3472_resume(struct device *dev) int ret; u8 enable_mask = TCS3472_ENABLE_AEN | TCS3472_ENABLE_PON; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); ret = i2c_smbus_write_byte_data(data->client, TCS3472_ENABLE, data->enable | enable_mask); - if (!ret) - data->enable |= enable_mask; + if (ret) + return ret; - mutex_unlock(&data->lock); + data->enable |= enable_mask; - return ret; + return 0; } static DEFINE_SIMPLE_DEV_PM_OPS(tcs3472_pm_ops, tcs3472_suspend, From 2e84e69c92233b601e3892887aec7c56fd4fe13b Mon Sep 17 00:00:00 2001 From: Aldo Conte Date: Fri, 22 May 2026 14:34:15 +0200 Subject: [PATCH 216/266] iio: tcs3472: use ! instead of explicit NULL check Replace 'if (indio_dev == NULL)' with 'if (!indio_dev)' in tcs3472_probe() to follow the preferred kernel style. No functional change. Suggested-by: Joshua Crofts Signed-off-by: Aldo Conte Signed-off-by: Jonathan Cameron --- drivers/iio/light/tcs3472.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c index 8956ed058a20..36d3c106e70d 100644 --- a/drivers/iio/light/tcs3472.c +++ b/drivers/iio/light/tcs3472.c @@ -452,7 +452,7 @@ static int tcs3472_probe(struct i2c_client *client) int ret; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); - if (indio_dev == NULL) + if (!indio_dev) return -ENOMEM; data = iio_priv(indio_dev); From df94df71711516298719a4507a792f0bb9fd0837 Mon Sep 17 00:00:00 2001 From: Aldo Conte Date: Fri, 22 May 2026 14:34:16 +0200 Subject: [PATCH 217/266] iio: tcs3472: use devm for resource management Convert the driver to use device-managed resource allocation: - Add tcs3472_powerdown_action() and register it with devm_add_action_or_reset() to ensure the device is powered down on cleanup. - Replace iio_triggered_buffer_setup() with devm_iio_triggered_buffer_setup(). - Replace request_threaded_irq() with devm_request_threaded_irq(). - Replace iio_device_register() with devm_iio_device_register(). - Replace mutex_init() with devm_mutex_init(). - Remove tcs3472_remove() as all cleanup is now handled by devm. Use a local 'dev = &client->dev' in tcs3472_probe() to keep the devm calls compact. Signed-off-by: Aldo Conte Signed-off-by: Jonathan Cameron --- drivers/iio/light/tcs3472.c | 63 +++++++++++++++---------------------- 1 file changed, 26 insertions(+), 37 deletions(-) diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c index 36d3c106e70d..b0e8d5661567 100644 --- a/drivers/iio/light/tcs3472.c +++ b/drivers/iio/light/tcs3472.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -445,20 +446,28 @@ static int tcs3472_powerdown(struct tcs3472_data *data) return 0; } +static void tcs3472_powerdown_action(void *data) +{ + tcs3472_powerdown(data); +} + static int tcs3472_probe(struct i2c_client *client) { + struct device *dev = &client->dev; struct tcs3472_data *data; struct iio_dev *indio_dev; int ret; - indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); if (!indio_dev) return -ENOMEM; data = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); data->client = client; - mutex_init(&data->lock); + ret = devm_mutex_init(dev, &data->lock); + if (ret) + return ret; indio_dev->info = &tcs3472_info; indio_dev->name = TCS3472_DRV_NAME; @@ -515,46 +524,27 @@ static int tcs3472_probe(struct i2c_client *client) if (ret < 0) return ret; - ret = iio_triggered_buffer_setup(indio_dev, NULL, - tcs3472_trigger_handler, NULL); + ret = devm_add_action_or_reset(dev, tcs3472_powerdown_action, data); + if (ret) + return ret; + + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, + tcs3472_trigger_handler, NULL); if (ret < 0) - goto error_powerdown; + return ret; if (client->irq) { - ret = request_threaded_irq(client->irq, NULL, - tcs3472_event_handler, - IRQF_TRIGGER_FALLING | IRQF_SHARED | - IRQF_ONESHOT, - client->name, indio_dev); + ret = devm_request_threaded_irq(dev, client->irq, NULL, + tcs3472_event_handler, + IRQF_TRIGGER_FALLING | + IRQF_SHARED | + IRQF_ONESHOT, + client->name, indio_dev); if (ret) - goto buffer_cleanup; + return ret; } - ret = iio_device_register(indio_dev); - if (ret < 0) - goto free_irq; - - return 0; - -free_irq: - if (client->irq) - free_irq(client->irq, indio_dev); -buffer_cleanup: - iio_triggered_buffer_cleanup(indio_dev); -error_powerdown: - tcs3472_powerdown(data); - return ret; -} - -static void tcs3472_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - - iio_device_unregister(indio_dev); - if (client->irq) - free_irq(client->irq, indio_dev); - iio_triggered_buffer_cleanup(indio_dev); - tcs3472_powerdown(iio_priv(indio_dev)); + return devm_iio_device_register(dev, indio_dev); } static int tcs3472_suspend(struct device *dev) @@ -598,7 +588,6 @@ static struct i2c_driver tcs3472_driver = { .pm = pm_sleep_ptr(&tcs3472_pm_ops), }, .probe = tcs3472_probe, - .remove = tcs3472_remove, .id_table = tcs3472_id, }; module_i2c_driver(tcs3472_driver); From c9dc65030e5705d17c9605a17732d15b71898d0b Mon Sep 17 00:00:00 2001 From: Aldo Conte Date: Fri, 22 May 2026 14:34:17 +0200 Subject: [PATCH 218/266] iio: tcs3472: use local struct device * for remaining cases Use the local 'struct device *dev' variable introduced for the devm calls also for the dev_info() calls in tcs3472_probe(), to keep the probe function consistent. No functional change. Signed-off-by: Aldo Conte Signed-off-by: Jonathan Cameron --- drivers/iio/light/tcs3472.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c index b0e8d5661567..24b71d4543c5 100644 --- a/drivers/iio/light/tcs3472.c +++ b/drivers/iio/light/tcs3472.c @@ -480,9 +480,9 @@ static int tcs3472_probe(struct i2c_client *client) return ret; if (ret == 0x44) - dev_info(&client->dev, "TCS34721/34725 found\n"); + dev_info(dev, "TCS34721/34725 found\n"); else if (ret == 0x4d) - dev_info(&client->dev, "TCS34723/34727 found\n"); + dev_info(dev, "TCS34723/34727 found\n"); else return -ENODEV; From 1ccae88c0a1023e0c9f757dc6b1fbca463b32b36 Mon Sep 17 00:00:00 2001 From: Aldo Conte Date: Fri, 22 May 2026 14:34:18 +0200 Subject: [PATCH 219/266] iio: tcs3472: move standalone return to default case Move the trailing 'return -EINVAL' statements at the end of tcs3472_read_raw() and tcs3472_write_raw() into explicit default: cases inside the respective switch statements. This removes the need for a separate return statement after the switch. No functional change. Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Reviewed-by: Joshua Crofts Signed-off-by: Aldo Conte Signed-off-by: Jonathan Cameron --- drivers/iio/light/tcs3472.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c index 24b71d4543c5..b61442c5c1be 100644 --- a/drivers/iio/light/tcs3472.c +++ b/drivers/iio/light/tcs3472.c @@ -166,8 +166,9 @@ static int tcs3472_read_raw(struct iio_dev *indio_dev, *val = 0; *val2 = (256 - data->atime) * 2400; return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; } - return -EINVAL; } static int tcs3472_write_raw(struct iio_dev *indio_dev, @@ -204,8 +205,9 @@ static int tcs3472_write_raw(struct iio_dev *indio_dev, } return -EINVAL; + default: + return -EINVAL; } - return -EINVAL; } /* From d2b3d461a09e0db6a6a8237db4081a32f71a04b9 Mon Sep 17 00:00:00 2001 From: Maxwell Doose Date: Sat, 23 May 2026 13:15:36 -0500 Subject: [PATCH 220/266] iio: chemical: sps30: Replace manual locking with RAII locking Replace manual mutex_lock() and mutex_unlock() calls with the much newer guard(mutex)() macro to enable RAII patterns, modernize the driver, and to increase readability. Move mutex locking into sps30_do_meas() and tune it up to use guard()(), as every caller takes the lock anyways. Signed-off-by: Maxwell Doose Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/sps30.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/drivers/iio/chemical/sps30.c b/drivers/iio/chemical/sps30.c index a934bf0298dd..8e15baa31423 100644 --- a/drivers/iio/chemical/sps30.c +++ b/drivers/iio/chemical/sps30.c @@ -5,6 +5,7 @@ * Copyright (c) Tomasz Duszynski */ +#include #include #include #include @@ -69,6 +70,8 @@ static int sps30_do_meas(struct sps30_state *state, s32 *data, int size) { int i, ret; + guard(mutex)(&state->lock); + if (state->state == RESET) { ret = state->ops->start_meas(state); if (ret) @@ -111,9 +114,7 @@ static irqreturn_t sps30_trigger_handler(int irq, void *p) aligned_s64 ts; } scan; - mutex_lock(&state->lock); ret = sps30_do_meas(state, scan.data, ARRAY_SIZE(scan.data)); - mutex_unlock(&state->lock); if (ret) goto err; @@ -136,7 +137,6 @@ static int sps30_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_PROCESSED: switch (chan->type) { case IIO_MASSCONCENTRATION: - mutex_lock(&state->lock); /* read up to the number of bytes actually needed */ switch (chan->channel2) { case IIO_MOD_PM1: @@ -152,7 +152,6 @@ static int sps30_read_raw(struct iio_dev *indio_dev, ret = sps30_do_meas(state, data, 4); break; } - mutex_unlock(&state->lock); if (ret) return ret; @@ -197,9 +196,9 @@ static ssize_t start_cleaning_store(struct device *dev, if (kstrtoint(buf, 0, &val) || val != 1) return -EINVAL; - mutex_lock(&state->lock); + guard(mutex)(&state->lock); + ret = state->ops->clean_fan(state); - mutex_unlock(&state->lock); if (ret) return ret; @@ -215,9 +214,9 @@ static ssize_t cleaning_period_show(struct device *dev, __be32 val; int ret; - mutex_lock(&state->lock); + guard(mutex)(&state->lock); + ret = state->ops->read_cleaning_period(state, &val); - mutex_unlock(&state->lock); if (ret) return ret; @@ -238,12 +237,11 @@ static ssize_t cleaning_period_store(struct device *dev, struct device_attribute (val > SPS30_AUTO_CLEANING_PERIOD_MAX)) return -EINVAL; - mutex_lock(&state->lock); + guard(mutex)(&state->lock); + ret = state->ops->write_cleaning_period(state, cpu_to_be32(val)); - if (ret) { - mutex_unlock(&state->lock); + if (ret) return ret; - } msleep(20); @@ -256,8 +254,6 @@ static ssize_t cleaning_period_store(struct device *dev, struct device_attribute dev_warn(dev, "period changed but reads will return the old value\n"); - mutex_unlock(&state->lock); - return len; } From 8a2f9c41b9cc3b7570e4b8476220db11bd6a1030 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sun, 24 May 2026 20:38:33 -0500 Subject: [PATCH 221/266] iio: Convert IIO_CHAN_SOFT_TIMESTAMP() to be compound literal Currently IIO_CHAN_SOFT_TIMESTAMP() can only be used to fill the static data. In some cases it would be convenient to use it as right value in the assignment operation. But it can't be done as is, because compiler has no clue about the data layout. Converting it to be a compound literal allows the above mentioned usage. While at it, tidy up the indentation. We also have to change existing uses of compound literal at the same time to avoid compiler errors. Signed-off-by: Andy Shevchenko Signed-off-by: David Lechner Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7606.c | 2 +- drivers/iio/adc/max11410.c | 2 +- include/linux/iio/iio.h | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c index d9271894f091..cebb8ed8dcb1 100644 --- a/drivers/iio/adc/ad7606.c +++ b/drivers/iio/adc/ad7606.c @@ -1475,7 +1475,7 @@ static int ad7606_probe_channels(struct iio_dev *indio_dev) } if (slow_bus) - channels[i] = (struct iio_chan_spec)IIO_CHAN_SOFT_TIMESTAMP(i); + channels[i] = IIO_CHAN_SOFT_TIMESTAMP(i); indio_dev->channels = channels; diff --git a/drivers/iio/adc/max11410.c b/drivers/iio/adc/max11410.c index 69351f4f10bb..dc1b96356592 100644 --- a/drivers/iio/adc/max11410.c +++ b/drivers/iio/adc/max11410.c @@ -804,7 +804,7 @@ static int max11410_parse_channels(struct max11410_state *st, chan_idx++; } - channels[chan_idx] = (struct iio_chan_spec)IIO_CHAN_SOFT_TIMESTAMP(chan_idx); + channels[chan_idx] = IIO_CHAN_SOFT_TIMESTAMP(chan_idx); indio_dev->num_channels = chan_idx + 1; indio_dev->channels = channels; diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 96b05c86c325..711c00f67371 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -353,15 +353,15 @@ static inline bool iio_channel_has_available(const struct iio_chan_spec *chan, (chan->info_mask_shared_by_all_available & BIT(type)); } -#define IIO_CHAN_SOFT_TIMESTAMP(_si) { \ +#define IIO_CHAN_SOFT_TIMESTAMP(_si) (struct iio_chan_spec) { \ .type = IIO_TIMESTAMP, \ .channel = -1, \ .scan_index = _si, \ .scan_type = { \ .sign = 's', \ - .realbits = 64, \ + .realbits = 64, \ .storagebits = 64, \ - }, \ + }, \ } s64 iio_get_time_ns(const struct iio_dev *indio_dev); From c73b6d7f0b7f2b2279134746cbacbb880222f374 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Sun, 24 May 2026 20:38:34 -0500 Subject: [PATCH 222/266] iio: common: scmi_sensors: simplify timestamp channel definition Use IIO_CHAN_SOFT_TIMESTAMP() to define the timestamp channel instead of manually filling in the struct iio_chan_spec fields. This makes the code less verbose and mistake-prone. In fact, there was an error here as the sign should be 's' instead of 'u' which is now changed to 's' by using IIO_CHAN_SOFT_TIMESTAMP(). If we find that this breaks userspace, we will have to revert this change, but seems unlikely since the timestamp channel is well-known to be a signed 64-bit integer globally. Signed-off-by: David Lechner Signed-off-by: Jonathan Cameron --- drivers/iio/common/scmi_sensors/scmi_iio.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/iio/common/scmi_sensors/scmi_iio.c b/drivers/iio/common/scmi_sensors/scmi_iio.c index 5136ad9ada04..442b40ef27cf 100644 --- a/drivers/iio/common/scmi_sensors/scmi_iio.c +++ b/drivers/iio/common/scmi_sensors/scmi_iio.c @@ -419,17 +419,6 @@ static const struct iio_chan_spec_ext_info scmi_iio_ext_info[] = { { } }; -static void scmi_iio_set_timestamp_channel(struct iio_chan_spec *iio_chan, - int scan_index) -{ - iio_chan->type = IIO_TIMESTAMP; - iio_chan->channel = -1; - iio_chan->scan_index = scan_index; - iio_chan->scan_type.sign = 'u'; - iio_chan->scan_type.realbits = 64; - iio_chan->scan_type.storagebits = 64; -} - static void scmi_iio_set_data_channel(struct iio_chan_spec *iio_chan, enum iio_chan_type type, enum iio_modifier mod, int scan_index) @@ -629,7 +618,7 @@ scmi_alloc_iiodev(struct scmi_device *sdev, "Error in registering sensor update notifier for sensor %s\n", sensor->sensor_info->name); - scmi_iio_set_timestamp_channel(&iio_channels[i], i); + iio_channels[i] = IIO_CHAN_SOFT_TIMESTAMP(i); iiodev->channels = iio_channels; return iiodev; } From 98f548bb911908dd2a60073c006ccebf9ce7c60a Mon Sep 17 00:00:00 2001 From: David Lechner Date: Sun, 24 May 2026 20:38:35 -0500 Subject: [PATCH 223/266] iio: adc: dln2-adc: simplify timestamp channel definition Use IIO_CHAN_SOFT_TIMESTAMP() to define the timestamp channel instead of manually filling in the struct iio_chan_spec fields. This makes the code less verbose and mistake-prone. Signed-off-by: David Lechner Signed-off-by: Jonathan Cameron --- drivers/iio/adc/dln2-adc.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/iio/adc/dln2-adc.c b/drivers/iio/adc/dln2-adc.c index eb902a946efe..b01c6f5a73b1 100644 --- a/drivers/iio/adc/dln2-adc.c +++ b/drivers/iio/adc/dln2-adc.c @@ -444,16 +444,6 @@ static int dln2_update_scan_mode(struct iio_dev *indio_dev, lval.scan_type.endianness = IIO_LE; \ } -/* Assignment version of IIO_CHAN_SOFT_TIMESTAMP */ -#define IIO_CHAN_SOFT_TIMESTAMP_ASSIGN(lval, _si) { \ - lval.type = IIO_TIMESTAMP; \ - lval.channel = -1; \ - lval.scan_index = _si; \ - lval.scan_type.sign = 's'; \ - lval.scan_type.realbits = 64; \ - lval.scan_type.storagebits = 64; \ -} - static const struct iio_info dln2_adc_info = { .read_raw = dln2_adc_read_raw, .write_raw = dln2_adc_write_raw, @@ -614,7 +604,7 @@ static int dln2_adc_probe(struct platform_device *pdev) for (i = 0; i < chans; ++i) DLN2_ADC_CHAN(dln2->iio_channels[i], i) - IIO_CHAN_SOFT_TIMESTAMP_ASSIGN(dln2->iio_channels[i], i); + dln2->iio_channels[i] = IIO_CHAN_SOFT_TIMESTAMP(i); indio_dev->name = DLN2_ADC_MOD_NAME; indio_dev->info = &dln2_adc_info; From f97661c4c713fa2bdf2649c76b181772e27cf325 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Sun, 24 May 2026 20:38:36 -0500 Subject: [PATCH 224/266] iio: adc: at91_adc: simplify timestamp channel definition Use IIO_CHAN_SOFT_TIMESTAMP() to define the timestamp channel instead of manually filling in the struct iio_chan_spec fields. This makes the code less verbose and mistake-prone. Signed-off-by: David Lechner Signed-off-by: Jonathan Cameron --- drivers/iio/adc/at91_adc.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 6e1930f7c65d..f610ad729bf3 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -481,7 +481,7 @@ static irqreturn_t at91_adc_9x5_interrupt(int irq, void *private) static int at91_adc_channel_init(struct iio_dev *idev) { struct at91_adc_state *st = iio_priv(idev); - struct iio_chan_spec *chan_array, *timestamp; + struct iio_chan_spec *chan_array; int bit, idx = 0; unsigned long rsvd_mask = 0; @@ -519,14 +519,8 @@ static int at91_adc_channel_init(struct iio_dev *idev) chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); idx++; } - timestamp = chan_array + idx; - timestamp->type = IIO_TIMESTAMP; - timestamp->channel = -1; - timestamp->scan_index = idx; - timestamp->scan_type.sign = 's'; - timestamp->scan_type.realbits = 64; - timestamp->scan_type.storagebits = 64; + chan_array[idx] = IIO_CHAN_SOFT_TIMESTAMP(idx); idev->channels = chan_array; return idev->num_channels; From f5b317d043cd73aaa806121f763fb2aa93afc7aa Mon Sep 17 00:00:00 2001 From: David Lechner Date: Sun, 24 May 2026 20:38:37 -0500 Subject: [PATCH 225/266] iio: adc: cc10001_adc: simplify timestamp channel definition Use IIO_CHAN_SOFT_TIMESTAMP() to define the timestamp channel instead of manually filling in the struct iio_chan_spec fields. This makes the code less verbose and mistake-prone. Signed-off-by: David Lechner Signed-off-by: Jonathan Cameron --- drivers/iio/adc/cc10001_adc.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/iio/adc/cc10001_adc.c b/drivers/iio/adc/cc10001_adc.c index 2c51b90b7101..d42b747325aa 100644 --- a/drivers/iio/adc/cc10001_adc.c +++ b/drivers/iio/adc/cc10001_adc.c @@ -262,7 +262,7 @@ static const struct iio_info cc10001_adc_info = { static int cc10001_adc_channel_init(struct iio_dev *indio_dev, unsigned long channel_map) { - struct iio_chan_spec *chan_array, *timestamp; + struct iio_chan_spec *chan_array; unsigned int bit, idx = 0; indio_dev->num_channels = bitmap_weight(&channel_map, @@ -289,13 +289,7 @@ static int cc10001_adc_channel_init(struct iio_dev *indio_dev, idx++; } - timestamp = &chan_array[idx]; - timestamp->type = IIO_TIMESTAMP; - timestamp->channel = -1; - timestamp->scan_index = idx; - timestamp->scan_type.sign = 's'; - timestamp->scan_type.realbits = 64; - timestamp->scan_type.storagebits = 64; + chan_array[idx] = IIO_CHAN_SOFT_TIMESTAMP(idx); indio_dev->channels = chan_array; From 404edaf1e885a7f047f3d2090d29bdf4c5cf77a2 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Sun, 24 May 2026 20:38:38 -0500 Subject: [PATCH 226/266] iio: adc: stm32-adc: simplify timestamp channel definition Use IIO_CHAN_SOFT_TIMESTAMP() to define the timestamp channel instead of manually filling in the struct iio_chan_spec fields. This makes the code less verbose and mistake-prone. Signed-off-by: David Lechner Signed-off-by: Jonathan Cameron --- drivers/iio/adc/stm32-adc.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 46106200bb86..5c5170b19b56 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -2443,15 +2443,7 @@ static int stm32_adc_chan_fw_init(struct iio_dev *indio_dev, bool timestamping) scan_index = ret; if (timestamping) { - struct iio_chan_spec *timestamp = &channels[scan_index]; - - timestamp->type = IIO_TIMESTAMP; - timestamp->channel = -1; - timestamp->scan_index = scan_index; - timestamp->scan_type.sign = 's'; - timestamp->scan_type.realbits = 64; - timestamp->scan_type.storagebits = 64; - + channels[scan_index] = IIO_CHAN_SOFT_TIMESTAMP(scan_index); scan_index++; } From b3405ec8496272d42dcded5633cb547e586bad6e Mon Sep 17 00:00:00 2001 From: David Lechner Date: Sun, 24 May 2026 20:38:39 -0500 Subject: [PATCH 227/266] iio: common: cros_ec_sensors: simplify timestamp channel definition Use IIO_CHAN_SOFT_TIMESTAMP() to define the timestamp channel instead of manually filling in the struct iio_chan_spec fields. This makes the code less verbose and mistake-prone. Also drop obvious comment while we're at it. Signed-off-by: David Lechner Signed-off-by: Jonathan Cameron --- drivers/iio/common/cros_ec_sensors/cros_ec_activity.c | 8 +------- drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c | 8 +------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_activity.c b/drivers/iio/common/cros_ec_sensors/cros_ec_activity.c index 6e38d115b6fe..6762685e6876 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_activity.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_activity.c @@ -279,13 +279,7 @@ static int cros_ec_sensors_probe(struct platform_device *pdev) channel++; } - /* Timestamp */ - channel->scan_index = index; - channel->type = IIO_TIMESTAMP; - channel->channel = -1; - channel->scan_type.sign = 's'; - channel->scan_type.realbits = 64; - channel->scan_type.storagebits = 64; + *channel = IIO_CHAN_SOFT_TIMESTAMP(index); indio_dev->channels = st->channels; indio_dev->num_channels = index + 1; diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c index f34e2bbba2d1..651632ccfe0d 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c @@ -279,13 +279,7 @@ static int cros_ec_sensors_probe(struct platform_device *pdev) } } - /* Timestamp */ - channel->type = IIO_TIMESTAMP; - channel->channel = -1; - channel->scan_index = CROS_EC_SENSOR_MAX_AXIS; - channel->scan_type.sign = 's'; - channel->scan_type.realbits = 64; - channel->scan_type.storagebits = 64; + *channel = IIO_CHAN_SOFT_TIMESTAMP(CROS_EC_SENSOR_MAX_AXIS); indio_dev->channels = state->channels; indio_dev->num_channels = CROS_EC_SENSORS_MAX_CHANNELS; From 6a0861ce6f725891e8f31971512915a7374a541e Mon Sep 17 00:00:00 2001 From: David Lechner Date: Sun, 24 May 2026 20:38:40 -0500 Subject: [PATCH 228/266] iio: light: cros_ec_light_prox: simplify timestamp channel definition Use IIO_CHAN_SOFT_TIMESTAMP() to define the timestamp channel instead of manually filling in the struct iio_chan_spec fields. This makes the code less verbose and mistake-prone. Also drop obvious comment while we're at it. Signed-off-by: David Lechner Signed-off-by: Jonathan Cameron --- drivers/iio/light/cros_ec_light_prox.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/iio/light/cros_ec_light_prox.c b/drivers/iio/light/cros_ec_light_prox.c index 815806ceb5c8..d09dea9c0782 100644 --- a/drivers/iio/light/cros_ec_light_prox.c +++ b/drivers/iio/light/cros_ec_light_prox.c @@ -223,14 +223,8 @@ static int cros_ec_light_prox_probe(struct platform_device *pdev) return -EINVAL; } - /* Timestamp */ channel++; - channel->type = IIO_TIMESTAMP; - channel->channel = -1; - channel->scan_index = 1; - channel->scan_type.sign = 's'; - channel->scan_type.realbits = 64; - channel->scan_type.storagebits = 64; + *channel = IIO_CHAN_SOFT_TIMESTAMP(1); indio_dev->channels = state->channels; From 391c3ec1b15e9f5880812cb045f470ac45c8ba8f Mon Sep 17 00:00:00 2001 From: David Lechner Date: Sun, 24 May 2026 20:46:52 -0500 Subject: [PATCH 229/266] iio: pressure: cros_ec_baro: simplify timestamp channel definition Use IIO_CHAN_SOFT_TIMESTAMP() to define the timestamp channel instead of manually filling in the struct iio_chan_spec fields. This makes the code less verbose and mistake-prone. Also drop obvious comment while we're at it. Signed-off-by: David Lechner Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/cros_ec_baro.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/iio/pressure/cros_ec_baro.c b/drivers/iio/pressure/cros_ec_baro.c index c6b950c596c1..6cbde48d5be3 100644 --- a/drivers/iio/pressure/cros_ec_baro.c +++ b/drivers/iio/pressure/cros_ec_baro.c @@ -170,14 +170,8 @@ static int cros_ec_baro_probe(struct platform_device *pdev) return -EINVAL; } - /* Timestamp */ channel++; - channel->type = IIO_TIMESTAMP; - channel->channel = -1; - channel->scan_index = 1; - channel->scan_type.sign = 's'; - channel->scan_type.realbits = 64; - channel->scan_type.storagebits = 64; + *channel = IIO_CHAN_SOFT_TIMESTAMP(1); indio_dev->channels = state->channels; indio_dev->num_channels = CROS_EC_BARO_MAX_CHANNELS; From 2fab7499006ddc87c8937b149b769b8eb4a65217 Mon Sep 17 00:00:00 2001 From: Rodrigo Gobbi Date: Tue, 26 May 2026 22:36:39 -0300 Subject: [PATCH 230/266] iio: adc: spear_adc: sort includes alphabetically Sort includes alphabetically, no functional change Signed-off-by: Rodrigo Gobbi Signed-off-by: Jonathan Cameron --- drivers/iio/adc/spear_adc.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/iio/adc/spear_adc.c b/drivers/iio/adc/spear_adc.c index 91995489bb1c..efde6afc54fd 100644 --- a/drivers/iio/adc/spear_adc.c +++ b/drivers/iio/adc/spear_adc.c @@ -5,19 +5,19 @@ * Copyright 2012 Stefan Roese */ +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include #include -#include -#include -#include #include -#include -#include -#include -#include -#include #include #include From f6ae81a98a7b72674d4ffef8daa87f4c958dd92b Mon Sep 17 00:00:00 2001 From: Rodrigo Gobbi Date: Tue, 26 May 2026 22:36:40 -0300 Subject: [PATCH 231/266] iio: adc: spear_adc: align headers with IWYU principle Remove unused includes and add what is being used: #include // for ARRAY_SIZE #include // for GENMASKxx #include // for dev_err_probe, dev_info #include // for DIV_ROUND_UP #include // for struct mutex #include // for uXX definitions #include // for IIO_CHAN_INFO_* Signed-off-by: Rodrigo Gobbi Signed-off-by: Jonathan Cameron --- drivers/iio/adc/spear_adc.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/spear_adc.c b/drivers/iio/adc/spear_adc.c index efde6afc54fd..4be722406bb5 100644 --- a/drivers/iio/adc/spear_adc.c +++ b/drivers/iio/adc/spear_adc.c @@ -5,22 +5,25 @@ * Copyright 2012 Stefan Roese */ +#include #include +#include #include #include -#include +#include #include #include #include -#include +#include #include #include +#include #include #include -#include +#include #include -#include +#include /* SPEAR registers definitions */ #define SPEAR600_ADC_SCAN_RATE_LO(x) ((x) & 0xFFFF) From 46968e058cbc77a87f0771739eeea31aba7e08c1 Mon Sep 17 00:00:00 2001 From: "Jose A. Perez de Azpillaga" Date: Tue, 26 May 2026 09:55:15 +0200 Subject: [PATCH 232/266] dt-bindings: iio: light: add Broadcom APDS9999 Add Device Tree binding for the Broadcom APDS9999 ambient light and proximity sensor. A separate binding file is used rather than merging with avago,apds9300.yaml because the APDS9999 has an additional vcsel-supply for the VCSEL. The APDS9999 features individual R, G, B, and IR channels with a green channel that uses optical coating to approximate the human eye spectral response for ALS/lux measurements. Calibrated RGB color sensing is not yet implemented in the driver. Signed-off-by: Jose A. Perez de Azpillaga Reviewed-by: Conor Dooley Signed-off-by: Jonathan Cameron --- .../bindings/iio/light/brcm,apds9999.yaml | 54 +++++++++++++++++++ MAINTAINERS | 6 +++ 2 files changed, 60 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/light/brcm,apds9999.yaml diff --git a/Documentation/devicetree/bindings/iio/light/brcm,apds9999.yaml b/Documentation/devicetree/bindings/iio/light/brcm,apds9999.yaml new file mode 100644 index 000000000000..9f5b3b294c2c --- /dev/null +++ b/Documentation/devicetree/bindings/iio/light/brcm,apds9999.yaml @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/light/brcm,apds9999.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# +title: Broadcom APDS-9999 Digital Proximity and RGB Sensor + +maintainers: + - Jose A. Perez de Azpillaga + +description: | + Broadcom APDS-9999 is a digital proximity and RGB sensor with + ambient light sensing (ALS) capability. The device uses individual + R, G, B, and IR channels plus a Vertical Cavity Surface Emitting + Laser (VCSEL) for proximity detection. + + Datasheet: https://docs.broadcom.com/docs/APDS-9999-DS + +properties: + compatible: + enum: + - brcm,apds9999 + + reg: + maxItems: 1 + + vdd-supply: true + + vcsel-supply: + description: VCSEL power supply (VVCSEL pin) + + interrupts: + maxItems: 1 + +additionalProperties: false + +required: + - compatible + - reg + - vdd-supply + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + light-sensor@52 { + compatible = "brcm,apds9999"; + reg = <0x52>; + vdd-supply = <&vdd_reg>; + vcsel-supply = <&vcsel_reg>; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 1533337900da..44b84c8857ca 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4992,6 +4992,12 @@ S: Maintained F: Documentation/devicetree/bindings/iio/light/brcm,apds9160.yaml F: drivers/iio/light/apds9160.c +BROADCOM APDS9999 AMBIENT LIGHT SENSOR DRIVER +M: Jose A. Perez de Azpillaga +L: linux-iio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/iio/light/brcm,apds9999.yaml + BROADCOM ASP 2.0 ETHERNET DRIVER M: Justin Chen M: Florian Fainelli From 5f9363e523000f05bfbd5440fecfa08ec5d08094 Mon Sep 17 00:00:00 2001 From: "Jose A. Perez de Azpillaga" Date: Tue, 26 May 2026 09:55:46 +0200 Subject: [PATCH 233/266] iio: light: add support for APDS9999 sensor Add IIO driver for Broadcom APDS9999 ambient light sensor. The APDS9999 is a digital proximity and RGB sensor with ALS capability. The driver implements the ALS/Lux functionality using the green channel, which uses optical coating technology to approximate the human eye spectral response. Raw IIO_INTENSITY channels are exposed for red, green, blue, and IR so userspace can compute its own weighted lux. Proximity (PS) support is not yet implemented. Signed-off-by: Jose A. Perez de Azpillaga Signed-off-by: Jonathan Cameron --- MAINTAINERS | 1 + drivers/iio/light/Kconfig | 14 ++ drivers/iio/light/Makefile | 1 + drivers/iio/light/apds9999.c | 333 +++++++++++++++++++++++++++++++++++ 4 files changed, 349 insertions(+) create mode 100644 drivers/iio/light/apds9999.c diff --git a/MAINTAINERS b/MAINTAINERS index 44b84c8857ca..9e69cc754cf5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4997,6 +4997,7 @@ M: Jose A. Perez de Azpillaga L: linux-iio@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/iio/light/brcm,apds9999.yaml +F: drivers/iio/light/apds9999.c BROADCOM ASP 2.0 ETHERNET DRIVER M: Justin Chen diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index eff33e456c70..da4807a3fd3d 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -119,6 +119,20 @@ config APDS9960 To compile this driver as a module, choose M here: the module will be called apds9960 +config APDS9999 + tristate "Broadcom APDS9999 ALS, RGB and proximity sensor" + depends on I2C + help + Say Y here if you want to build support for the Broadcom APDS9999 + ALS, RGB and proximity sensor with I2C interface. + + This driver provides ambient light sensing (ALS/Lux), raw + intensity data for red, green, blue and IR channels, plus + proximity detection support. + + To compile this driver as a module, choose M here: the + module will be called apds9999. + config AS73211 tristate "AMS AS73211 XYZ color sensor and AMS AS7331 UV sensor" depends on I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index c0048e0d5ca8..39e62dfc10c7 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_APDS9160) += apds9160.o obj-$(CONFIG_APDS9300) += apds9300.o obj-$(CONFIG_APDS9306) += apds9306.o obj-$(CONFIG_APDS9960) += apds9960.o +obj-$(CONFIG_APDS9999) += apds9999.o obj-$(CONFIG_AS73211) += as73211.o obj-$(CONFIG_BH1745) += bh1745.o obj-$(CONFIG_BH1750) += bh1750.o diff --git a/drivers/iio/light/apds9999.c b/drivers/iio/light/apds9999.c new file mode 100644 index 000000000000..7a0df5252078 --- /dev/null +++ b/drivers/iio/light/apds9999.c @@ -0,0 +1,333 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * IIO driver for Broadcom APDS9999 Lux Light Sensor + * + * Copyright (C) 2026 + * Author: Jose A. Perez de Azpillaga + * + * TODO: proximity sensor + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define APDS9999_REG_MAIN_CTRL 0x00 +#define APDS9999_MAIN_CTRL_LS_EN BIT(1) +#define APDS9999_REG_LS_MEAS_RATE 0x04 +#define APDS9999_LS_RES_MASK GENMASK(6, 4) +#define APDS9999_LS_RATE_MASK GENMASK(2, 0) +#define APDS9999_REG_LS_GAIN 0x05 +#define APDS9999_REG_PART_ID 0x06 +#define APDS9999_REG_MAIN_STATUS 0x07 +#define APDS9999_MAIN_STATUS_LS_DATA BIT(3) +#define APDS9999_REG_LS_DATA_IR_0 0x0A +#define APDS9999_REG_LS_DATA_GREEN_0 0x0D +#define APDS9999_REG_LS_DATA_BLUE_0 0x10 +#define APDS9999_REG_LS_DATA_RED_0 0x13 + +#define APDS9999_PART_ID 0xC2 + +#define APDS9999_GAIN_1X 0 +#define APDS9999_GAIN_3X 1 +#define APDS9999_GAIN_6X 2 +#define APDS9999_GAIN_9X 3 +#define APDS9999_GAIN_18X 4 + +static const int apds9999_gains[] = { + [APDS9999_GAIN_1X] = 1, + [APDS9999_GAIN_3X] = 3, + [APDS9999_GAIN_6X] = 6, + [APDS9999_GAIN_9X] = 9, + [APDS9999_GAIN_18X] = 18, +}; + +#define APDS9999_RES_20BIT 0 +#define APDS9999_RES_19BIT 1 +#define APDS9999_RES_18BIT 2 +#define APDS9999_RES_17BIT 3 +#define APDS9999_RES_16BIT 4 +#define APDS9999_RES_13BIT 5 + +static const int apds9999_itimes_us[] = { + [APDS9999_RES_20BIT] = 400 * USEC_PER_MSEC, + [APDS9999_RES_19BIT] = 200 * USEC_PER_MSEC, + [APDS9999_RES_18BIT] = 100 * USEC_PER_MSEC, + [APDS9999_RES_17BIT] = 50 * USEC_PER_MSEC, + [APDS9999_RES_16BIT] = 25 * USEC_PER_MSEC, + [APDS9999_RES_13BIT] = 3125, +}; + +#define APDS9999_RATE_25_MS 0 +#define APDS9999_RATE_50_MS 1 +#define APDS9999_RATE_100_MS 2 +#define APDS9999_RATE_200_MS 3 +#define APDS9999_RATE_500_MS 4 +#define APDS9999_RATE_1000_MS 5 +#define APDS9999_RATE_2000_MS 6 + +struct apds9999_data { + struct i2c_client *client; + /* lock: serializes access to device registers and cached values */ + struct mutex lock; + int als_gain_idx; + int als_res; + int als_rate; +}; + +static void apds9999_standby(void *client) +{ + i2c_smbus_write_byte_data(client, APDS9999_REG_MAIN_CTRL, 0); +} + +/* + * Apply power-on defaults: 18-bit / 100 ms resolution and rate, + * 3x gain. These match the datasheet reset values. + */ +static int apds9999_init(struct apds9999_data *data) +{ + struct device *dev = &data->client->dev; + struct i2c_client *client = data->client; + u8 regval; + int ret; + + ret = devm_add_action_or_reset(dev, apds9999_standby, client); + if (ret) + return ret; + + guard(mutex)(&data->lock); + + regval = FIELD_PREP(APDS9999_LS_RES_MASK, APDS9999_RES_18BIT) | + FIELD_PREP(APDS9999_LS_RATE_MASK, APDS9999_RATE_100_MS); + ret = i2c_smbus_write_byte_data(client, APDS9999_REG_LS_MEAS_RATE, + regval); + if (ret) + return ret; + data->als_res = APDS9999_RES_18BIT; + data->als_rate = APDS9999_RATE_100_MS; + + ret = i2c_smbus_write_byte_data(client, APDS9999_REG_LS_GAIN, + APDS9999_GAIN_3X); + if (ret) + return ret; + data->als_gain_idx = APDS9999_GAIN_3X; + + return i2c_smbus_write_byte_data(client, APDS9999_REG_MAIN_CTRL, + APDS9999_MAIN_CTRL_LS_EN); +} + +static int apds9999_read_channel(struct apds9999_data *data, u8 reg, + u32 *counts) +{ + struct i2c_client *client = data->client; + u8 buf[3]; + int ret, tries; + + guard(mutex)(&data->lock); + + /* + * Poll MAIN_STATUS for new data. Timeout: ~2 integration periods + * plus margin. Each try sleeps 20 ms. + */ + tries = max(2, (apds9999_itimes_us[data->als_res] * 2) / 20000); + + while (tries--) { + ret = i2c_smbus_read_byte_data(client, + APDS9999_REG_MAIN_STATUS); + if (ret < 0) + return ret; + if (ret & APDS9999_MAIN_STATUS_LS_DATA) + break; + fsleep(20000); + } + + if (tries < 0) + return -ETIMEDOUT; + + ret = i2c_smbus_read_i2c_block_data(client, reg, sizeof(buf), buf); + if (ret < 0) + return ret; + if (ret != sizeof(buf)) + return -EIO; + + *counts = get_unaligned_le24(buf) & GENMASK(19, 0); + return 0; +} + +static int apds9999_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct apds9999_data *data = iio_priv(indio_dev); + int gain, itime_us; + u64 scale_nano; + u32 counts; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = apds9999_read_channel(data, chan->address, &counts); + if (ret) + return ret; + *val = (int)counts; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: { + u32 remainder; + + /* + * Scale (lux per count) = 54 / (gain * integration_time_ms) + * + * The constant 54 is derived from the datasheet table: + * at gain = 3x, itime = 100 ms -> 0.180 lux/count + * -> C = 0.180 * 3 * 100 = 54 + * + * Expressed as IIO_VAL_INT_PLUS_NANO. + */ + gain = apds9999_gains[data->als_gain_idx]; + itime_us = apds9999_itimes_us[data->als_res]; + + /* scale_nano = 54 * 1e12 / (gain * itime_us) nano-lux/count */ + scale_nano = div_u64(54ULL * NSEC_PER_SEC * USEC_PER_MSEC, (u32)(gain * itime_us)); + *val = (int)div_u64_rem(scale_nano, NSEC_PER_SEC, &remainder); + *val2 = (int)remainder; + return IIO_VAL_INT_PLUS_NANO; + } + case IIO_CHAN_INFO_INT_TIME: + *val = 0; + *val2 = apds9999_itimes_us[data->als_res]; + return IIO_VAL_INT_PLUS_MICRO; + + default: + return -EINVAL; + } +} + +static const struct iio_info apds9999_info = { + .read_raw = apds9999_read_raw, +}; + +/* + * The green channel uses optical coating to approximate the human eye + * spectral response. IIO_INTENSITY channels provide raw ADC data for + * red, green, blue, and IR so userspace can compute weighted lux. + */ +static const struct iio_chan_spec apds9999_channels[] = { + { + .type = IIO_LIGHT, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), + .address = APDS9999_REG_LS_DATA_GREEN_0, + }, + { + .type = IIO_INTENSITY, + .modified = 1, + .channel2 = IIO_MOD_LIGHT_RED, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), + .address = APDS9999_REG_LS_DATA_RED_0, + }, + { + .type = IIO_INTENSITY, + .modified = 1, + .channel2 = IIO_MOD_LIGHT_GREEN, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), + .address = APDS9999_REG_LS_DATA_GREEN_0, + }, + { + .type = IIO_INTENSITY, + .modified = 1, + .channel2 = IIO_MOD_LIGHT_BLUE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), + .address = APDS9999_REG_LS_DATA_BLUE_0, + }, + { + .type = IIO_INTENSITY, + .modified = 1, + .channel2 = IIO_MOD_LIGHT_IR, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), + .address = APDS9999_REG_LS_DATA_IR_0, + }, +}; + +static int apds9999_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct apds9999_data *data; + struct iio_dev *indio_dev; + int ret, part_id; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + data->client = client; + + ret = devm_mutex_init(dev, &data->lock); + if (ret) + return ret; + + part_id = i2c_smbus_read_byte_data(client, APDS9999_REG_PART_ID); + if (part_id < 0) + return dev_err_probe(dev, part_id, "failed to read PART_ID\n"); + if (part_id != APDS9999_PART_ID) + dev_info(dev, "unexpected PART_ID 0x%02x (expected 0x%02x)\n", + part_id, APDS9999_PART_ID); + + ret = apds9999_init(data); + if (ret) + return dev_err_probe(dev, ret, "failed to initialize device\n"); + + indio_dev->name = "apds9999"; + indio_dev->info = &apds9999_info; + indio_dev->channels = apds9999_channels; + indio_dev->num_channels = ARRAY_SIZE(apds9999_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = devm_iio_device_register(dev, indio_dev); + if (ret) + return dev_err_probe(dev, ret, "failed to register IIO device\n"); + + return 0; +} + +static const struct i2c_device_id apds9999_id[] = { + { .name = "apds9999" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, apds9999_id); + +static const struct of_device_id apds9999_of_match[] = { + { .compatible = "brcm,apds9999" }, + { } +}; +MODULE_DEVICE_TABLE(of, apds9999_of_match); + +static struct i2c_driver apds9999_driver = { + .driver = { + .name = "apds9999", + .of_match_table = apds9999_of_match, + }, + .probe = apds9999_probe, + .id_table = apds9999_id, +}; +module_i2c_driver(apds9999_driver); + +MODULE_AUTHOR("Jose A. Perez de Azpillaga "); +MODULE_DESCRIPTION("APDS-9999 Lux Light Sensor IIO Driver"); +MODULE_LICENSE("GPL"); From 434c150752675f44dc52c384a7fa22e5176bc35a Mon Sep 17 00:00:00 2001 From: Liviu Stan Date: Mon, 25 May 2026 19:39:28 +0300 Subject: [PATCH 234/266] iio: temperature: ltc2983: Fix n_wires default bypassing rotation check When adi,number-of-wires is absent, n_wires is left at 0. The binding documents a default of 2 wires, matching the hardware default. However the current-rotate validation checks n_wires == 2 || n_wires == 3, so with n_wires = 0 the guard is bypassed and adi,current-rotate is accepted for a 2-wire RTD. Initialize n_wires = 2 to match the binding default and ensure the rotation check fires correctly when the property is absent. Fixes: f110f3188e56 ("iio: temperature: Add support for LTC2983") Signed-off-by: Liviu Stan Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/ltc2983.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/temperature/ltc2983.c b/drivers/iio/temperature/ltc2983.c index 38e6f8dfd3b8..1f835e326b93 100644 --- a/drivers/iio/temperature/ltc2983.c +++ b/drivers/iio/temperature/ltc2983.c @@ -741,7 +741,7 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st, struct ltc2983_rtd *rtd; int ret = 0; struct device *dev = &st->spi->dev; - u32 excitation_current = 0, n_wires = 0; + u32 excitation_current = 0, n_wires = 2; rtd = devm_kzalloc(dev, sizeof(*rtd), GFP_KERNEL); if (!rtd) From 5cb9fdb446bfc3ae0524496f53fb68e67051701b Mon Sep 17 00:00:00 2001 From: Liviu Stan Date: Mon, 25 May 2026 19:39:29 +0300 Subject: [PATCH 235/266] iio: temperature: ltc2983: Fix reinit_completion() called after conversion start reinit_completion() was called after regmap_write() initiated the hardware conversion, creating a race window where the interrupt could fire and call complete() before reinit_completion() reset the completion. Move reinit_completion() before the regmap_write() to close the race. ltc2983_eeprom_cmd() already does it in the correct order. Fixes: f110f3188e56 ("iio: temperature: Add support for LTC2983") Signed-off-by: Liviu Stan Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/ltc2983.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/iio/temperature/ltc2983.c b/drivers/iio/temperature/ltc2983.c index 1f835e326b93..2bc5cd46a72f 100644 --- a/drivers/iio/temperature/ltc2983.c +++ b/drivers/iio/temperature/ltc2983.c @@ -1177,12 +1177,11 @@ static int ltc2983_chan_read(struct ltc2983_data *st, start_conversion |= LTC2983_STATUS_CHAN_SEL(sensor->chan); dev_dbg(&st->spi->dev, "Start conversion on chan:%d, status:%02X\n", sensor->chan, start_conversion); + reinit_completion(&st->completion); /* start conversion */ ret = regmap_write(st->regmap, LTC2983_STATUS_REG, start_conversion); if (ret) return ret; - - reinit_completion(&st->completion); /* * wait for conversion to complete. * 300 ms should be more than enough to complete the conversion. From 53f4fda3c0efa77bb239dc5e357ae80644fcb400 Mon Sep 17 00:00:00 2001 From: Liviu Stan Date: Mon, 25 May 2026 19:39:30 +0300 Subject: [PATCH 236/266] iio: temperature: ltc2983: Fix macro parenthesization and rename Wrap the 'chan' parameter in LTC2983_CHAN_START_ADDR() and LTC2983_CHAN_RES_ADDR() with parentheses to prevent potential macro argument expansion issues. Also rename LTC2983_CHAN_START_ADDR to LTC2983_CHAN_ASSIGN_ADDR and LTC2983_CHAN_RES_ADDR to LTC2983_RESULT_ADDR, to better reflect the datasheet names and avoid them being confused as related. Reviewed-by: Joshua Crofts Signed-off-by: Liviu Stan Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/ltc2983.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/iio/temperature/ltc2983.c b/drivers/iio/temperature/ltc2983.c index 2bc5cd46a72f..4bae90f03002 100644 --- a/drivers/iio/temperature/ltc2983.c +++ b/drivers/iio/temperature/ltc2983.c @@ -56,10 +56,10 @@ #define LTC2983_EEPROM_WRITE_TIME_MS 2600 #define LTC2983_EEPROM_READ_TIME_MS 20 -#define LTC2983_CHAN_START_ADDR(chan) \ - (((chan - 1) * 4) + LTC2983_CHAN_ASSIGN_START_REG) -#define LTC2983_CHAN_RES_ADDR(chan) \ - (((chan - 1) * 4) + LTC2983_TEMP_RES_START_REG) +#define LTC2983_CHAN_ASSIGN_ADDR(chan) \ + ((((chan) - 1) * 4) + LTC2983_CHAN_ASSIGN_START_REG) +#define LTC2983_RESULT_ADDR(chan) \ + ((((chan) - 1) * 4) + LTC2983_TEMP_RES_START_REG) #define LTC2983_THERMOCOUPLE_DIFF_MASK BIT(3) #define LTC2983_THERMOCOUPLE_SGL(x) \ FIELD_PREP(LTC2983_THERMOCOUPLE_DIFF_MASK, x) @@ -351,7 +351,7 @@ static int __ltc2983_chan_assign_common(struct ltc2983_data *st, const struct ltc2983_sensor *sensor, u32 chan_val) { - u32 reg = LTC2983_CHAN_START_ADDR(sensor->chan); + u32 reg = LTC2983_CHAN_ASSIGN_ADDR(sensor->chan); chan_val |= LTC2983_CHAN_TYPE(sensor->type); dev_dbg(&st->spi->dev, "Assign reg:0x%04X, val:0x%08X\n", reg, @@ -1196,7 +1196,7 @@ static int ltc2983_chan_read(struct ltc2983_data *st, } /* read the converted data */ - ret = regmap_bulk_read(st->regmap, LTC2983_CHAN_RES_ADDR(sensor->chan), + ret = regmap_bulk_read(st->regmap, LTC2983_RESULT_ADDR(sensor->chan), &st->temp, sizeof(st->temp)); if (ret) return ret; From 6b047d099703c9b4f6846dcb98e2e3ca7a0ff773 Mon Sep 17 00:00:00 2001 From: Liviu Stan Date: Mon, 25 May 2026 19:39:31 +0300 Subject: [PATCH 237/266] iio: temperature: ltc2983: Use local device pointer consistently Some functions define a local 'dev' pointer but still use bare '&st->spi->dev' in some code paths, and some don't have it at all. Replace bare references with the local pointer for consistency and collapse some wrapped lines that now fit within 80 characters. Reviewed-by: Joshua Crofts Signed-off-by: Liviu Stan Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/ltc2983.c | 87 +++++++++++++++++-------------- 1 file changed, 47 insertions(+), 40 deletions(-) diff --git a/drivers/iio/temperature/ltc2983.c b/drivers/iio/temperature/ltc2983.c index 4bae90f03002..8b0b6b4884f6 100644 --- a/drivers/iio/temperature/ltc2983.c +++ b/drivers/iio/temperature/ltc2983.c @@ -351,11 +351,11 @@ static int __ltc2983_chan_assign_common(struct ltc2983_data *st, const struct ltc2983_sensor *sensor, u32 chan_val) { + struct device *dev = &st->spi->dev; u32 reg = LTC2983_CHAN_ASSIGN_ADDR(sensor->chan); chan_val |= LTC2983_CHAN_TYPE(sensor->type); - dev_dbg(&st->spi->dev, "Assign reg:0x%04X, val:0x%08X\n", reg, - chan_val); + dev_dbg(dev, "Assign reg:0x%04X, val:0x%08X\n", reg, chan_val); st->chan_val = cpu_to_be32(chan_val); return regmap_bulk_write(st->regmap, reg, &st->chan_val, sizeof(st->chan_val)); @@ -656,11 +656,12 @@ static struct ltc2983_sensor * ltc2983_thermocouple_new(const struct fwnode_handle *child, struct ltc2983_data *st, const struct ltc2983_sensor *sensor) { + struct device *dev = &st->spi->dev; struct ltc2983_thermocouple *thermo; u32 oc_current; int ret; - thermo = devm_kzalloc(&st->spi->dev, sizeof(*thermo), GFP_KERNEL); + thermo = devm_kzalloc(dev, sizeof(*thermo), GFP_KERNEL); if (!thermo) return ERR_PTR(-ENOMEM); @@ -687,7 +688,7 @@ ltc2983_thermocouple_new(const struct fwnode_handle *child, struct ltc2983_data LTC2983_THERMOCOUPLE_OC_CURR(3); break; default: - return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + return dev_err_ptr_probe(dev, -EINVAL, "Invalid open circuit current:%u\n", oc_current); } @@ -697,7 +698,7 @@ ltc2983_thermocouple_new(const struct fwnode_handle *child, struct ltc2983_data /* validate channel index */ if (!(thermo->sensor_config & LTC2983_THERMOCOUPLE_DIFF_MASK) && sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) - return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + return dev_err_ptr_probe(dev, -EINVAL, "Invalid chann:%d for differential thermocouple\n", sensor->chan); @@ -712,7 +713,7 @@ ltc2983_thermocouple_new(const struct fwnode_handle *child, struct ltc2983_data * This would be caught later but we can just return * the error right away. */ - return dev_err_ptr_probe(&st->spi->dev, ret, + return dev_err_ptr_probe(dev, ret, "Property reg must be given\n"); } @@ -823,7 +824,7 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st, } else { /* same as differential case */ if (sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) - return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + return dev_err_ptr_probe(dev, -EINVAL, "Invalid chann:%d for RTD\n", sensor->chan); } @@ -873,7 +874,7 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st, rtd->excitation_current = 0x08; break; default: - return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + return dev_err_ptr_probe(dev, -EINVAL, "Invalid value for excitation current(%u)\n", excitation_current); } @@ -922,7 +923,7 @@ ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *s /* validate channel index */ if (!(thermistor->sensor_config & LTC2983_THERMISTOR_DIFF_MASK) && sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) - return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + return dev_err_ptr_probe(dev, -EINVAL, "Invalid chann:%d for differential thermistor\n", sensor->chan); @@ -964,7 +965,7 @@ ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *s case 0: /* auto range */ if (sensor->type >= LTC2983_SENSOR_THERMISTOR_STEINHART) - return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + return dev_err_ptr_probe(dev, -EINVAL, "Auto Range not allowed for custom sensors\n"); thermistor->excitation_current = 0x0c; @@ -1003,7 +1004,7 @@ ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *s thermistor->excitation_current = 0x0b; break; default: - return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + return dev_err_ptr_probe(dev, -EINVAL, "Invalid value for excitation current(%u)\n", excitation_current); } @@ -1016,11 +1017,12 @@ static struct ltc2983_sensor * ltc2983_diode_new(const struct fwnode_handle *child, const struct ltc2983_data *st, const struct ltc2983_sensor *sensor) { + struct device *dev = &st->spi->dev; struct ltc2983_diode *diode; u32 temp = 0, excitation_current = 0; int ret; - diode = devm_kzalloc(&st->spi->dev, sizeof(*diode), GFP_KERNEL); + diode = devm_kzalloc(dev, sizeof(*diode), GFP_KERNEL); if (!diode) return ERR_PTR(-ENOMEM); @@ -1036,7 +1038,7 @@ ltc2983_diode_new(const struct fwnode_handle *child, const struct ltc2983_data * /* validate channel index */ if (!(diode->sensor_config & LTC2983_DIODE_DIFF_MASK) && sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) - return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + return dev_err_ptr_probe(dev, -EINVAL, "Invalid chann:%d for differential thermistor\n", sensor->chan); @@ -1061,7 +1063,7 @@ ltc2983_diode_new(const struct fwnode_handle *child, const struct ltc2983_data * diode->excitation_current = 0x03; break; default: - return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + return dev_err_ptr_probe(dev, -EINVAL, "Invalid value for excitation current(%u)\n", excitation_current); } @@ -1079,23 +1081,24 @@ static struct ltc2983_sensor *ltc2983_r_sense_new(struct fwnode_handle *child, struct ltc2983_data *st, const struct ltc2983_sensor *sensor) { + struct device *dev = &st->spi->dev; struct ltc2983_rsense *rsense; int ret; u32 temp; - rsense = devm_kzalloc(&st->spi->dev, sizeof(*rsense), GFP_KERNEL); + rsense = devm_kzalloc(dev, sizeof(*rsense), GFP_KERNEL); if (!rsense) return ERR_PTR(-ENOMEM); /* validate channel index */ if (sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) - return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + return dev_err_ptr_probe(dev, -EINVAL, "Invalid chann:%d for r_sense\n", sensor->chan); ret = fwnode_property_read_u32(child, "adi,rsense-val-milli-ohms", &temp); if (ret) - return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + return dev_err_ptr_probe(dev, -EINVAL, "Property adi,rsense-val-milli-ohms missing\n"); /* * Times 1000 because we have milli-ohms and __convert_to_raw @@ -1115,9 +1118,10 @@ static struct ltc2983_sensor *ltc2983_adc_new(struct fwnode_handle *child, struct ltc2983_data *st, const struct ltc2983_sensor *sensor) { + struct device *dev = &st->spi->dev; struct ltc2983_adc *adc; - adc = devm_kzalloc(&st->spi->dev, sizeof(*adc), GFP_KERNEL); + adc = devm_kzalloc(dev, sizeof(*adc), GFP_KERNEL); if (!adc) return ERR_PTR(-ENOMEM); @@ -1125,7 +1129,7 @@ static struct ltc2983_sensor *ltc2983_adc_new(struct fwnode_handle *child, adc->single_ended = true; if (!adc->single_ended && sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) - return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + return dev_err_ptr_probe(dev, -EINVAL, "Invalid chan:%d for differential adc\n", sensor->chan); @@ -1140,9 +1144,10 @@ static struct ltc2983_sensor *ltc2983_temp_new(struct fwnode_handle *child, struct ltc2983_data *st, const struct ltc2983_sensor *sensor) { + struct device *dev = &st->spi->dev; struct ltc2983_temp *temp; - temp = devm_kzalloc(&st->spi->dev, sizeof(*temp), GFP_KERNEL); + temp = devm_kzalloc(dev, sizeof(*temp), GFP_KERNEL); if (!temp) return ERR_PTR(-ENOMEM); @@ -1150,7 +1155,7 @@ static struct ltc2983_sensor *ltc2983_temp_new(struct fwnode_handle *child, temp->single_ended = true; if (!temp->single_ended && sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) - return dev_err_ptr_probe(&st->spi->dev, -EINVAL, + return dev_err_ptr_probe(dev, -EINVAL, "Invalid chan:%d for differential temp\n", sensor->chan); @@ -1169,13 +1174,14 @@ static struct ltc2983_sensor *ltc2983_temp_new(struct fwnode_handle *child, static int ltc2983_chan_read(struct ltc2983_data *st, const struct ltc2983_sensor *sensor, int *val) { + struct device *dev = &st->spi->dev; u32 start_conversion = 0; int ret; unsigned long time; start_conversion = LTC2983_STATUS_START(true); start_conversion |= LTC2983_STATUS_CHAN_SEL(sensor->chan); - dev_dbg(&st->spi->dev, "Start conversion on chan:%d, status:%02X\n", + dev_dbg(dev, "Start conversion on chan:%d, status:%02X\n", sensor->chan, start_conversion); reinit_completion(&st->completion); /* start conversion */ @@ -1191,7 +1197,7 @@ static int ltc2983_chan_read(struct ltc2983_data *st, time = wait_for_completion_timeout(&st->completion, msecs_to_jiffies(300)); if (!time) { - dev_warn(&st->spi->dev, "Conversion timed out\n"); + dev_warn(dev, "Conversion timed out\n"); return -ETIMEDOUT; } @@ -1204,7 +1210,7 @@ static int ltc2983_chan_read(struct ltc2983_data *st, *val = __be32_to_cpu(st->temp); if (!(LTC2983_RES_VALID_MASK & *val)) { - dev_err(&st->spi->dev, "Invalid conversion detected\n"); + dev_err(dev, "Invalid conversion detected\n"); return -EIO; } @@ -1221,12 +1227,12 @@ static int ltc2983_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { struct ltc2983_data *st = iio_priv(indio_dev); + struct device *dev = &st->spi->dev; int ret; /* sanity check */ if (chan->address >= st->num_channels) { - dev_err(&st->spi->dev, "Invalid chan address:%ld", - chan->address); + dev_err(dev, "Invalid chan address:%ld", chan->address); return -EINVAL; } @@ -1302,7 +1308,7 @@ static int ltc2983_parse_fw(struct ltc2983_data *st) st->num_channels = device_get_child_node_count(dev); if (!st->num_channels) - return dev_err_probe(&st->spi->dev, -EINVAL, + return dev_err_probe(dev, -EINVAL, "At least one channel must be given!\n"); st->sensors = devm_kcalloc(dev, st->num_channels, sizeof(*st->sensors), @@ -1390,6 +1396,7 @@ static int ltc2983_eeprom_cmd(struct ltc2983_data *st, unsigned int cmd, unsigned int wait_time, unsigned int status_reg, unsigned long status_fail_mask) { + struct device *dev = &st->spi->dev; unsigned long time; unsigned int val; int ret; @@ -1409,7 +1416,7 @@ static int ltc2983_eeprom_cmd(struct ltc2983_data *st, unsigned int cmd, time = wait_for_completion_timeout(&st->completion, msecs_to_jiffies(wait_time)); if (!time) - return dev_err_probe(&st->spi->dev, -ETIMEDOUT, + return dev_err_probe(dev, -ETIMEDOUT, "EEPROM command timed out\n"); ret = regmap_read(st->regmap, status_reg, &val); @@ -1417,7 +1424,7 @@ static int ltc2983_eeprom_cmd(struct ltc2983_data *st, unsigned int cmd, return ret; if (val & status_fail_mask) - return dev_err_probe(&st->spi->dev, -EINVAL, + return dev_err_probe(dev, -EINVAL, "EEPROM command failed: 0x%02X\n", val); return 0; @@ -1426,6 +1433,7 @@ static int ltc2983_eeprom_cmd(struct ltc2983_data *st, unsigned int cmd, static int ltc2983_setup(struct ltc2983_data *st, bool assign_iio) { u32 iio_chan_t = 0, iio_chan_v = 0, chan, iio_idx = 0, status; + struct device *dev = &st->spi->dev; int ret; /* make sure the device is up: start bit (7) is 0 and done bit (6) is 1 */ @@ -1433,8 +1441,7 @@ static int ltc2983_setup(struct ltc2983_data *st, bool assign_iio) LTC2983_STATUS_UP(status) == 1, 25000, 25000 * 10); if (ret) - return dev_err_probe(&st->spi->dev, ret, - "Device startup timed out\n"); + return dev_err_probe(dev, ret, "Device startup timed out\n"); ret = regmap_update_bits(st->regmap, LTC2983_GLOBAL_CONFIG_REG, LTC2983_NOTCH_FREQ_MASK, @@ -1534,12 +1541,13 @@ static const struct iio_info ltc2983_iio_info = { static int ltc2983_probe(struct spi_device *spi) { + struct device *dev = &spi->dev; struct ltc2983_data *st; struct iio_dev *indio_dev; struct gpio_desc *gpio; int ret; - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; @@ -1551,7 +1559,7 @@ static int ltc2983_probe(struct spi_device *spi) st->regmap = devm_regmap_init_spi(spi, <c2983_regmap_config); if (IS_ERR(st->regmap)) - return dev_err_probe(&spi->dev, PTR_ERR(st->regmap), + return dev_err_probe(dev, PTR_ERR(st->regmap), "Failed to initialize regmap\n"); mutex_init(&st->lock); @@ -1564,11 +1572,11 @@ static int ltc2983_probe(struct spi_device *spi) if (ret) return ret; - ret = devm_regulator_get_enable(&spi->dev, "vdd"); + ret = devm_regulator_get_enable(dev, "vdd"); if (ret) return ret; - gpio = devm_gpiod_get_optional(&st->spi->dev, "reset", GPIOD_OUT_HIGH); + gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(gpio)) return PTR_ERR(gpio); @@ -1578,7 +1586,7 @@ static int ltc2983_probe(struct spi_device *spi) gpiod_set_value_cansleep(gpio, 0); } - st->iio_chan = devm_kzalloc(&spi->dev, + st->iio_chan = devm_kzalloc(dev, st->iio_channels * sizeof(*st->iio_chan), GFP_KERNEL); if (!st->iio_chan) @@ -1588,11 +1596,10 @@ static int ltc2983_probe(struct spi_device *spi) if (ret) return ret; - ret = devm_request_irq(&spi->dev, spi->irq, ltc2983_irq_handler, + ret = devm_request_irq(dev, spi->irq, ltc2983_irq_handler, IRQF_TRIGGER_RISING, st->info->name, st); if (ret) - return dev_err_probe(&spi->dev, ret, - "failed to request an irq\n"); + return dev_err_probe(dev, ret, "failed to request an irq\n"); if (st->info->has_eeprom) { ret = ltc2983_eeprom_cmd(st, LTC2983_EEPROM_WRITE_CMD, @@ -1609,7 +1616,7 @@ static int ltc2983_probe(struct spi_device *spi) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = <c2983_iio_info; - return devm_iio_device_register(&spi->dev, indio_dev); + return devm_iio_device_register(dev, indio_dev); } static int ltc2983_resume(struct device *dev) From ae81c43f6c01a441ea8ce77f37903853595b6bb3 Mon Sep 17 00:00:00 2001 From: Liviu Stan Date: Mon, 25 May 2026 19:39:32 +0300 Subject: [PATCH 238/266] iio: temperature: ltc2983: Fix inconsistent channel wording in messages Replace occurrences of the abbreviated 'chann' and 'chan' with 'channel' in error and debug messages throughout the driver. Also changed the diode invalid channel error message from "thermistor" to "diode". Reviewed-by: Joshua Crofts Signed-off-by: Liviu Stan Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/ltc2983.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/iio/temperature/ltc2983.c b/drivers/iio/temperature/ltc2983.c index 8b0b6b4884f6..fc904c0a42b4 100644 --- a/drivers/iio/temperature/ltc2983.c +++ b/drivers/iio/temperature/ltc2983.c @@ -699,7 +699,7 @@ ltc2983_thermocouple_new(const struct fwnode_handle *child, struct ltc2983_data if (!(thermo->sensor_config & LTC2983_THERMOCOUPLE_DIFF_MASK) && sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) return dev_err_ptr_probe(dev, -EINVAL, - "Invalid chann:%d for differential thermocouple\n", + "Invalid channel %d for differential thermocouple\n", sensor->chan); struct fwnode_handle *ref __free(fwnode_handle) = @@ -797,7 +797,7 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st, /* * rtd channel indexes are a bit more complicated to validate. * For 4wire RTD with rotation, the channel selection cannot be - * >=19 since the chann + 1 is used in this configuration. + * >=19 since the channel + 1 is used in this configuration. * For 4wire RTDs with kelvin rsense, the rsense channel cannot be * <=1 since channel - 1 and channel - 2 are used. */ @@ -814,18 +814,18 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st, (rtd->r_sense_chan <= min)) /* kelvin rsense*/ return dev_err_ptr_probe(dev, -EINVAL, - "Invalid rsense chann:%d to use in kelvin rsense\n", + "Invalid channel %d for kelvin rsense\n", rtd->r_sense_chan); if (sensor->chan < min || sensor->chan > max) return dev_err_ptr_probe(dev, -EINVAL, - "Invalid chann:%d for the rtd config\n", + "Invalid channel %d for RTD config\n", sensor->chan); } else { /* same as differential case */ if (sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) return dev_err_ptr_probe(dev, -EINVAL, - "Invalid chann:%d for RTD\n", + "Invalid channel %d for RTD\n", sensor->chan); } @@ -924,7 +924,7 @@ ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *s if (!(thermistor->sensor_config & LTC2983_THERMISTOR_DIFF_MASK) && sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) return dev_err_ptr_probe(dev, -EINVAL, - "Invalid chann:%d for differential thermistor\n", + "Invalid channel %d for differential thermistor\n", sensor->chan); /* check custom sensor */ @@ -1039,7 +1039,7 @@ ltc2983_diode_new(const struct fwnode_handle *child, const struct ltc2983_data * if (!(diode->sensor_config & LTC2983_DIODE_DIFF_MASK) && sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) return dev_err_ptr_probe(dev, -EINVAL, - "Invalid chann:%d for differential thermistor\n", + "Invalid channel %d for differential diode\n", sensor->chan); /* set common parameters */ @@ -1093,7 +1093,7 @@ static struct ltc2983_sensor *ltc2983_r_sense_new(struct fwnode_handle *child, /* validate channel index */ if (sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) return dev_err_ptr_probe(dev, -EINVAL, - "Invalid chann:%d for r_sense\n", + "Invalid channel %d for r_sense\n", sensor->chan); ret = fwnode_property_read_u32(child, "adi,rsense-val-milli-ohms", &temp); @@ -1130,7 +1130,7 @@ static struct ltc2983_sensor *ltc2983_adc_new(struct fwnode_handle *child, if (!adc->single_ended && sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) return dev_err_ptr_probe(dev, -EINVAL, - "Invalid chan:%d for differential adc\n", + "Invalid channel %d for differential ADC\n", sensor->chan); /* set common parameters */ @@ -1156,7 +1156,7 @@ static struct ltc2983_sensor *ltc2983_temp_new(struct fwnode_handle *child, if (!temp->single_ended && sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) return dev_err_ptr_probe(dev, -EINVAL, - "Invalid chan:%d for differential temp\n", + "Invalid channel %d for differential temp\n", sensor->chan); temp->custom = __ltc2983_custom_sensor_new(st, child, "adi,custom-temp", @@ -1181,7 +1181,7 @@ static int ltc2983_chan_read(struct ltc2983_data *st, start_conversion = LTC2983_STATUS_START(true); start_conversion |= LTC2983_STATUS_CHAN_SEL(sensor->chan); - dev_dbg(dev, "Start conversion on chan:%d, status:%02X\n", + dev_dbg(dev, "Start conversion on channel:%d, status:%02X\n", sensor->chan, start_conversion); reinit_completion(&st->completion); /* start conversion */ @@ -1232,7 +1232,7 @@ static int ltc2983_read_raw(struct iio_dev *indio_dev, /* sanity check */ if (chan->address >= st->num_channels) { - dev_err(dev, "Invalid chan address:%ld", chan->address); + dev_err(dev, "Invalid channel address: %ld\n", chan->address); return -EINVAL; } @@ -1329,14 +1329,14 @@ static int ltc2983_parse_fw(struct ltc2983_data *st) if (sensor.chan < LTC2983_MIN_CHANNELS_NR || sensor.chan > st->info->max_channels_nr) return dev_err_probe(dev, -EINVAL, - "chan:%d must be from %u to %u\n", + "channel:%d must be from %u to %u\n", sensor.chan, LTC2983_MIN_CHANNELS_NR, st->info->max_channels_nr); if (channel_avail_mask & BIT(sensor.chan)) return dev_err_probe(dev, -EINVAL, - "chan:%d already in use\n", + "channel:%d already in use\n", sensor.chan); ret = fwnode_property_read_u32(child, "adi,sensor-type", &sensor.type); @@ -1344,7 +1344,7 @@ static int ltc2983_parse_fw(struct ltc2983_data *st) return dev_err_probe(dev, ret, "adi,sensor-type property must given for child nodes\n"); - dev_dbg(dev, "Create new sensor, type %u, chann %u", + dev_dbg(dev, "Create new sensor, type %u, channel %u", sensor.type, sensor.chan); if (sensor.type >= LTC2983_SENSOR_THERMOCOUPLE && From b46696afbceffd926adbeb62180554c2096cee78 Mon Sep 17 00:00:00 2001 From: Liviu Stan Date: Mon, 25 May 2026 19:39:33 +0300 Subject: [PATCH 239/266] iio: temperature: ltc2983: Use fwnode_property_present() for optional properties Checking fwnode_property_read_u32() return value with if (!ret) silently swallows meaningful error codes when a property is present but malformed. Use fwnode_property_present() first so that absence uses the default while a present but unreadable property returns a proper error. Signed-off-by: Liviu Stan Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/ltc2983.c | 84 +++++++++++++++++++++---------- 1 file changed, 58 insertions(+), 26 deletions(-) diff --git a/drivers/iio/temperature/ltc2983.c b/drivers/iio/temperature/ltc2983.c index fc904c0a42b4..130ab7fddc2f 100644 --- a/drivers/iio/temperature/ltc2983.c +++ b/drivers/iio/temperature/ltc2983.c @@ -668,8 +668,14 @@ ltc2983_thermocouple_new(const struct fwnode_handle *child, struct ltc2983_data if (fwnode_property_read_bool(child, "adi,single-ended")) thermo->sensor_config = LTC2983_THERMOCOUPLE_SGL(1); - ret = fwnode_property_read_u32(child, "adi,sensor-oc-current-microamp", &oc_current); - if (!ret) { + if (fwnode_property_present(child, "adi,sensor-oc-current-microamp")) { + ret = fwnode_property_read_u32(child, + "adi,sensor-oc-current-microamp", + &oc_current); + if (ret) + return dev_err_ptr_probe(dev, ret, + "Failed to read adi,sensor-oc-current-microamp\n"); + switch (oc_current) { case 10: thermo->sensor_config |= @@ -759,8 +765,12 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st, return dev_err_ptr_probe(dev, ret, "Property reg must be given\n"); - ret = fwnode_property_read_u32(child, "adi,number-of-wires", &n_wires); - if (!ret) { + if (fwnode_property_present(child, "adi,number-of-wires")) { + ret = fwnode_property_read_u32(child, "adi,number-of-wires", &n_wires); + if (ret) + return dev_err_ptr_probe(dev, ret, + "Failed to read adi,number-of-wires\n"); + switch (n_wires) { case 2: rtd->sensor_config = LTC2983_RTD_N_WIRES(0); @@ -842,12 +852,13 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st, rtd->sensor.fault_handler = ltc2983_common_fault_handler; rtd->sensor.assign_chan = ltc2983_rtd_assign_chan; - ret = fwnode_property_read_u32(child, "adi,excitation-current-microamp", - &excitation_current); - if (ret) { - /* default to 5uA */ - rtd->excitation_current = 1; - } else { + if (fwnode_property_present(child, "adi,excitation-current-microamp")) { + ret = fwnode_property_read_u32(child, "adi,excitation-current-microamp", + &excitation_current); + if (ret) + return dev_err_ptr_probe(dev, ret, + "Failed to read adi,excitation-current-microamp\n"); + switch (excitation_current) { case 5: rtd->excitation_current = 0x01; @@ -878,9 +889,17 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st, "Invalid value for excitation current(%u)\n", excitation_current); } + } else { + /* default to 5uA */ + rtd->excitation_current = 1; } - fwnode_property_read_u32(child, "adi,rtd-curve", &rtd->rtd_curve); + if (fwnode_property_present(child, "adi,rtd-curve")) { + ret = fwnode_property_read_u32(child, "adi,rtd-curve", &rtd->rtd_curve); + if (ret) + return dev_err_ptr_probe(dev, ret, + "Failed to read adi,rtd-curve\n"); + } return &rtd->sensor; } @@ -950,17 +969,13 @@ ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *s thermistor->sensor.fault_handler = ltc2983_common_fault_handler; thermistor->sensor.assign_chan = ltc2983_thermistor_assign_chan; - ret = fwnode_property_read_u32(child, "adi,excitation-current-nanoamp", - &excitation_current); - if (ret) { - /* Auto range is not allowed for custom sensors */ - if (sensor->type >= LTC2983_SENSOR_THERMISTOR_STEINHART) - /* default to 1uA */ - thermistor->excitation_current = 0x03; - else - /* default to auto-range */ - thermistor->excitation_current = 0x0c; - } else { + if (fwnode_property_present(child, "adi,excitation-current-nanoamp")) { + ret = fwnode_property_read_u32(child, "adi,excitation-current-nanoamp", + &excitation_current); + if (ret) + return dev_err_ptr_probe(dev, ret, + "Failed to read adi,excitation-current-nanoamp\n"); + switch (excitation_current) { case 0: /* auto range */ @@ -1008,6 +1023,14 @@ ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *s "Invalid value for excitation current(%u)\n", excitation_current); } + } else { + /* Auto range is not allowed for custom sensors */ + if (sensor->type >= LTC2983_SENSOR_THERMISTOR_STEINHART) + /* default to 1uA */ + thermistor->excitation_current = 0x03; + else + /* default to auto-range */ + thermistor->excitation_current = 0x0c; } return &thermistor->sensor; @@ -1046,9 +1069,13 @@ ltc2983_diode_new(const struct fwnode_handle *child, const struct ltc2983_data * diode->sensor.fault_handler = ltc2983_common_fault_handler; diode->sensor.assign_chan = ltc2983_diode_assign_chan; - ret = fwnode_property_read_u32(child, "adi,excitation-current-microamp", - &excitation_current); - if (!ret) { + if (fwnode_property_present(child, "adi,excitation-current-microamp")) { + ret = fwnode_property_read_u32(child, "adi,excitation-current-microamp", + &excitation_current); + if (ret) + return dev_err_ptr_probe(dev, ret, + "Failed to read adi,excitation-current-microamp\n"); + switch (excitation_current) { case 10: diode->excitation_current = 0x00; @@ -1069,7 +1096,12 @@ ltc2983_diode_new(const struct fwnode_handle *child, const struct ltc2983_data * } } - fwnode_property_read_u32(child, "adi,ideal-factor-value", &temp); + if (fwnode_property_present(child, "adi,ideal-factor-value")) { + ret = fwnode_property_read_u32(child, "adi,ideal-factor-value", &temp); + if (ret) + return dev_err_ptr_probe(dev, ret, + "Failed to read adi,ideal-factor-value\n"); + } /* 2^20 resolution */ diode->ideal_factor_value = __convert_to_raw(temp, 1048576); From 622775dbc56a6349fc98b368041e3224bfeeb9de Mon Sep 17 00:00:00 2001 From: Liviu Stan Date: Mon, 25 May 2026 19:39:34 +0300 Subject: [PATCH 240/266] iio: core: Add IIO_COVERAGE channel type Add a new channel type for sensors that report fractional coverage as a percentage. The sysfs attribute is in_coverageY_raw; after applying in_coverageY_scale the value is in percent. The first user is the ADT7604 leak detector, where the value represents the portion of the sensing element that is wetted. Signed-off-by: Liviu Stan Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 17 +++++++++++++++++ drivers/iio/industrialio-core.c | 1 + include/uapi/linux/iio/types.h | 1 + tools/iio/iio_event_monitor.c | 2 ++ 4 files changed, 21 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 925a33fd309a..d8d6d85235b0 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -1980,6 +1980,23 @@ Description: Raw (unscaled no offset etc.) resistance reading. Units after application of scale and offset are ohms. +What: /sys/bus/iio/devices/iio:deviceX/in_coverageY_raw +KernelVersion: 7.2 +Contact: linux-iio@vger.kernel.org +Description: + Raw (unscaled no offset etc.) coverage reading. Used for sensors + that report fractional coverage as a percentage, such as leak + detectors where the value represents what portion of the sensing + element is wetted. Units after application of scale and offset are + percent. + +What: /sys/bus/iio/devices/iio:deviceX/in_coverageY_scale +KernelVersion: 7.2 +Contact: linux-iio@vger.kernel.org +Description: + Scale to be applied to in_coverageY_raw to obtain coverage + in percent. + What: /sys/bus/iio/devices/iio:deviceX/heater_enable KernelVersion: 4.1.0 Contact: linux-iio@vger.kernel.org diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index bd6f4f9f4533..ffe0dc49c4b9 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -98,6 +98,7 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_CHROMATICITY] = "chromaticity", [IIO_ATTENTION] = "attention", [IIO_ALTCURRENT] = "altcurrent", + [IIO_COVERAGE] = "coverage", }; static const char * const iio_modifier_names[] = { diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h index d7c2bb223651..c9295c707041 100644 --- a/include/uapi/linux/iio/types.h +++ b/include/uapi/linux/iio/types.h @@ -53,6 +53,7 @@ enum iio_chan_type { IIO_CHROMATICITY, IIO_ATTENTION, IIO_ALTCURRENT, + IIO_COVERAGE, }; enum iio_modifier { diff --git a/tools/iio/iio_event_monitor.c b/tools/iio/iio_event_monitor.c index df6c43d7738d..bc3ef4c77c2b 100644 --- a/tools/iio/iio_event_monitor.c +++ b/tools/iio/iio_event_monitor.c @@ -65,6 +65,7 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_CHROMATICITY] = "chromaticity", [IIO_ATTENTION] = "attention", [IIO_ALTCURRENT] = "altcurrent", + [IIO_COVERAGE] = "coverage", }; static const char * const iio_ev_type_text[] = { @@ -194,6 +195,7 @@ static bool event_is_known(struct iio_event_data *event) case IIO_CHROMATICITY: case IIO_ATTENTION: case IIO_ALTCURRENT: + case IIO_COVERAGE: break; default: return false; From a496ba27dd68a5830cd57ec6c5c6e735fd113b1b Mon Sep 17 00:00:00 2001 From: Liviu Stan Date: Mon, 25 May 2026 19:39:35 +0300 Subject: [PATCH 241/266] dt-bindings: iio: temperature: Add ADT7604 support to adi,ltc2983 The ADT7604 shares the same die as the LTC2984. It repurposes the custom RTD sensor type (18) as a copper trace resistance sensor and the custom thermistor type (27) as a leak detector, and removes thermocouple, diode and direct ADC sensor types. Add adi,adt7604 to the compatible list and introduce two new sensor node types specific to this device: - copper-trace@: maps to the custom RTD sensor type (18). Two variants: sub-ohm (< 1 ohm, adi,copper-trace-sub-ohm boolean, no custom table and excitation current) and standard (> 1 ohm, required adi,custom-copper-trace table, optional excitation current defaulting to the datasheet recommended value). Primary output is resistance in ohms. For > 1 ohm copper traces with a custom table, the chip also outputs temperature in millidegrees Celsius. - leak-detector@: maps to the custom thermistor sensor type (27). Takes a required adi,custom-leak-detector lookup table encoding resistance (uOhm) against coverage data (%). Two outputs: resistance in ohms and coverage in percent. Separate node types are used rather than extending the existing rtd@ and thermistor@ nodes because adi,custom-rtd is required for sensor type 18, and several properties (adi,number-of-wires, adi,rtd-curve, adi,rsense-share, adi,single-ended, adi,current-rotate) have no meaning for the new sensor types, since the configuration is hardcoded, and would need to be explicitly forbidden or ignored in the driver. allOf conditions are added to restrict thermocouple, diode, direct ADC and active temperature nodes to non-ADT7604 devices, and to restrict copper-trace and leak-detector nodes to the ADT7604 (some parts only). Signed-off-by: Liviu Stan Acked-by: Conor Dooley Signed-off-by: Jonathan Cameron --- .../bindings/iio/temperature/adi,ltc2983.yaml | 217 +++++++++++++++++- 1 file changed, 214 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/temperature/adi,ltc2983.yaml b/Documentation/devicetree/bindings/iio/temperature/adi,ltc2983.yaml index a22725f7619b..13e5f29f0588 100644 --- a/Documentation/devicetree/bindings/iio/temperature/adi,ltc2983.yaml +++ b/Documentation/devicetree/bindings/iio/temperature/adi,ltc2983.yaml @@ -4,14 +4,18 @@ $id: http://devicetree.org/schemas/iio/temperature/adi,ltc2983.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Analog Devices LTC2983, LTC2986, LTM2985 Multi-sensor Temperature system +title: Analog Devices LTC2983 and similar Multi-sensor Temperature systems maintainers: - Nuno Sá description: | - Analog Devices LTC2983, LTC2984, LTC2986, LTM2985 Multi-Sensor Digital - Temperature Measurement Systems + Analog Devices Multi-Sensor Digital Temperature Measurement Systems: + - ADT7604 + - LTC2983 + - LTC2984 + - LTC2986 + - LTM2985 https://www.analog.com/media/en/technical-documentation/data-sheets/2983fc.pdf https://www.analog.com/media/en/technical-documentation/data-sheets/2984fb.pdf @@ -43,6 +47,7 @@ properties: compatible: oneOf: - enum: + - adi,adt7604 - adi,ltc2983 - adi,ltc2986 - adi,ltm2985 @@ -436,6 +441,121 @@ patternProperties: required: - adi,custom-temp + '^copper-trace@': + $ref: '#/$defs/sensor-node' + unevaluatedProperties: false + description: | + Copper trace resistance sensor (some parts only). Two variants exist: + sub-ohm (< 1 ohm, no custom table allowed) and standard (> 1 ohm, + required custom table). + + properties: + reg: + minimum: 2 + maximum: 20 + + adi,sensor-type: + description: Sensor type for copper trace sensors. + $ref: /schemas/types.yaml#/definitions/uint32 + const: 32 + + adi,rsense-handle: + description: Associated sense resistor sensor. + $ref: /schemas/types.yaml#/definitions/phandle + + adi,copper-trace-sub-ohm: + description: + Select the sub-ohm (< 1 ohm) copper trace variant. Custom table + and excitation current are not allowed in this mode. + type: boolean + + adi,excitation-current-microamp: + description: + Excitation current applied to the copper trace. Not used in + sub-ohm mode. The datasheet recommends 1mA for copper trace + sensors due to their typically small resistance. + enum: [5, 10, 25, 50, 100, 250, 500, 1000] + default: 1000 + + adi,custom-copper-trace: + description: + Resistance-to-temperature table for copper trace sensors with + resistance > 1 ohm. Required when adi,copper-trace-sub-ohm is not + set. See Page 36 of the datasheet. + $ref: /schemas/types.yaml#/definitions/uint64-matrix + minItems: 3 + maxItems: 64 + items: + items: + - description: Resistance point in uOhms. + - description: Temperature point in uK. + + required: + - adi,rsense-handle + + allOf: + - if: + required: + - adi,copper-trace-sub-ohm + then: + properties: + adi,custom-copper-trace: false + adi,excitation-current-microamp: false + - if: + not: + required: + - adi,copper-trace-sub-ohm + then: + required: + - adi,custom-copper-trace + + '^leak-detector@': + $ref: '#/$defs/sensor-node' + unevaluatedProperties: false + description: | + Leak detector sensor (some parts only). Outputs resistance in ohms and + a coverage percentage via IIO_COVERAGE (raw/1024 = coverage %). + + properties: + reg: + minimum: 2 + maximum: 20 + + adi,sensor-type: + description: Sensor type for leak detector sensors. + $ref: /schemas/types.yaml#/definitions/uint32 + const: 33 + + adi,rsense-handle: + description: Associated sense resistor sensor. + $ref: /schemas/types.yaml#/definitions/phandle + + adi,excitation-current-nanoamp: + description: + Excitation current applied to the leak detector. The correct value + depends on the electrical characteristics of the liquid being sensed. + For example, 10000 (10µA) is recommended for PG25 (see datasheet + Table 39). + enum: [250, 500, 1000, 5000, 10000, 25000, 50000, 100000, 250000, + 500000, 1000000] + + adi,custom-leak-detector: + description: | + Lookup table mapping resistance to coverage percentage. Entries must + be in ascending resistance order. + $ref: /schemas/types.yaml#/definitions/uint64-matrix + minItems: 3 + maxItems: 64 + items: + items: + - description: Resistance point in uOhms. + - description: Coverage data percentage (0 to 100). + + required: + - adi,rsense-handle + - adi,excitation-current-nanoamp + - adi,custom-leak-detector + '^rsense@': $ref: '#/$defs/sensor-node' unevaluatedProperties: false @@ -477,6 +597,32 @@ allOf: patternProperties: '^temp@': false + - if: + properties: + compatible: + contains: + const: adi,adt7604 + then: + patternProperties: + '^thermocouple@': false + '^diode@': false + '^adc@': false + '^temp@': false + '^rtd@': + properties: + adi,sensor-type: + not: + const: 18 + '^thermistor@': + properties: + adi,sensor-type: + not: + const: 27 + else: + patternProperties: + '^copper-trace@': false + '^leak-detector@': false + examples: - | #include @@ -556,4 +702,69 @@ examples: }; }; }; + + - | + #include + spi { + #address-cells = <1>; + #size-cells = <0>; + + temperature-sensor@0 { + compatible = "adi,adt7604"; + reg = <0>; + interrupt-parent = <&gpio>; + interrupts = <25 IRQ_TYPE_EDGE_RISING>; + + #address-cells = <1>; + #size-cells = <0>; + vdd-supply = <&supply>; + + trace_rsense: rsense@2 { + reg = <2>; + adi,sensor-type = <29>; + adi,rsense-val-milli-ohms = <100000>; // 100 ohm + }; + + copper-trace@4 { + reg = <4>; + adi,sensor-type = <32>; + adi,rsense-handle = <&trace_rsense>; + adi,copper-trace-sub-ohm; + }; + + r_sense: rsense@12 { + reg = <12>; + adi,sensor-type = <29>; + adi,rsense-val-milli-ohms = <1000000>; // 1 kohm + }; + + leak-detector@14 { + reg = <14>; + adi,sensor-type = <33>; + adi,rsense-handle = <&r_sense>; + adi,excitation-current-nanoamp = <10000>; + adi,custom-leak-detector = + /bits/ 64 < 0 100>, + /bits/ 64 < 202020000 99>, + /bits/ 64 < 285710000 70>, + /bits/ 64 < 333330000 60>, + /bits/ 64 < 400000000 50>, + /bits/ 64 < 500000000 40>, + /bits/ 64 < 666670000 30>, + /bits/ 64 < 1000000000 20>, + /bits/ 64 < 2000000000 10>, + /bits/ 64 <1000000000000 0>; + }; + + rtd@18 { + reg = <18>; + adi,sensor-type = <12>; // PT100 + adi,rsense-handle = <&r_sense>; + adi,number-of-wires = <2>; + adi,rsense-share; + adi,excitation-current-microamp = <500>; + adi,rtd-curve = <0>; + }; + }; + }; ... From 3dd0c048409e335320418c632966f149be628fd4 Mon Sep 17 00:00:00 2001 From: Liviu Stan Date: Mon, 25 May 2026 19:39:36 +0300 Subject: [PATCH 242/266] iio: temperature: ltc2983: Add support for ADT7604 The ADT7604 shares the same die as the LTC2984. It repurposes the custom RTD sensor type (18) as a copper trace resistance sensor and the custom thermistor type (27) as a leak detector, and removes thermocouple, diode and direct ADC sensor types. Two new software sensor type values are introduced (LTC2983_SENSOR_COPPER_TRACE = 32, LTC2983_SENSOR_LEAK_DETECTOR = 33) that map to the hardware register values 18 and 27 respectively. Dedicated structs (ltc2983_copper_trace, ltc2983_leak_detector) and parser functions are added rather than extending the existing RTD and thermistor paths, as the hardware configuration bits are fully hardcoded and several RTD/thermistor properties would need to be explicitly forbidden or ignored. Custom RTD (type 18) becomes the copper trace sensor. Sensor configuration bits are hardcoded to 0b1001 per the datasheet. Two variants are supported via the adi,copper-trace-sub-ohm DT property: sub-ohm traces (< 1 ohm) have bits 17:0 cleared with no excitation current or custom table; standard traces (> 1 ohm) have a required resistance-to-temperature table. Custom thermistor (type 27) becomes the leak detector. Sensor configuration bits are hardcoded to 0b001. The custom table uses a resolution of 16 instead of 64, and is specified via the required adi,custom-leak-detector DT property. Both sensor types expose an IIO_RESISTANCE channel reading from the resistance result register bank (0x0060-0x00AF). Added a "base" parameter to the LTC2983_RESULT_ADDR macro and a "base_reg" parameter to the ltc2983_chan_read function so we can read from both result register banks. The resistance register encodes the measured resistance with 10 fractional bits, so dividing by 1024 gives ohms. Since the sense resistor is specified in ohms, the output is in ohms for both sensor types and a single 1/1024 scale applies to both. For > 1 ohm copper traces and for leak detectors, a secondary channel also appears: IIO_TEMP (millidegrees Celsius) for copper trace and IIO_COVERAGE (percent) for leak detector. The ltc2983_chip_info struct is extended with a u64 supported_sensors bitmask using BIT_ULL() to safely represent the new sensor type bits 32 and 33 on 32-bit builds. A LTC2983_SENSOR_NUM sentinel is added to the enum so that the bounds check uses >= LTC2983_SENSOR_NUM rather than hardcoding the last sensor type. Tested on EVAL-ADT7604-AZ connected to Raspberry Pi 5 via SPI. Signed-off-by: Liviu Stan Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/ltc2983.c | 413 ++++++++++++++++++++++++++++-- 1 file changed, 394 insertions(+), 19 deletions(-) diff --git a/drivers/iio/temperature/ltc2983.c b/drivers/iio/temperature/ltc2983.c index 130ab7fddc2f..fc65d8352d12 100644 --- a/drivers/iio/temperature/ltc2983.c +++ b/drivers/iio/temperature/ltc2983.c @@ -28,6 +28,8 @@ #define LTC2983_STATUS_REG 0x0000 #define LTC2983_TEMP_RES_START_REG 0x0010 #define LTC2983_TEMP_RES_END_REG 0x005F +#define ADT7604_RES_RES_START_REG 0x0060 +#define ADT7604_RES_RES_END_REG 0x00AF #define LTC2983_EEPROM_KEY_REG 0x00B0 #define LTC2983_EEPROM_READ_STATUS_REG 0x00D0 #define LTC2983_GLOBAL_CONFIG_REG 0x00F0 @@ -58,8 +60,8 @@ #define LTC2983_CHAN_ASSIGN_ADDR(chan) \ ((((chan) - 1) * 4) + LTC2983_CHAN_ASSIGN_START_REG) -#define LTC2983_RESULT_ADDR(chan) \ - ((((chan) - 1) * 4) + LTC2983_TEMP_RES_START_REG) +#define LTC2983_RESULT_ADDR(chan, base) \ + ((((chan) - 1) * 4) + (base)) #define LTC2983_THERMOCOUPLE_DIFF_MASK BIT(3) #define LTC2983_THERMOCOUPLE_SGL(x) \ FIELD_PREP(LTC2983_THERMOCOUPLE_DIFF_MASK, x) @@ -186,17 +188,44 @@ enum { LTC2983_SENSOR_SENSE_RESISTOR = 29, LTC2983_SENSOR_DIRECT_ADC = 30, LTC2983_SENSOR_ACTIVE_TEMP = 31, + /* Sensor types for some parts only; map to RTD_CUSTOM/THERMISTOR_CUSTOM in HW */ + LTC2983_SENSOR_COPPER_TRACE = 32, + LTC2983_SENSOR_LEAK_DETECTOR = 33, + LTC2983_SENSOR_NUM }; +/* Bitmask of sensor types supported by LTC2983/LTC2984 and derivatives */ +#define LTC2983_COMMON_SENSORS \ + (GENMASK_ULL(LTC2983_SENSOR_THERMOCOUPLE_CUSTOM, LTC2983_SENSOR_THERMOCOUPLE) | \ + GENMASK_ULL(LTC2983_SENSOR_RTD_CUSTOM, LTC2983_SENSOR_RTD) | \ + GENMASK_ULL(LTC2983_SENSOR_THERMISTOR_CUSTOM, LTC2983_SENSOR_THERMISTOR) | \ + BIT_ULL(LTC2983_SENSOR_DIODE) | \ + BIT_ULL(LTC2983_SENSOR_SENSE_RESISTOR) | \ + BIT_ULL(LTC2983_SENSOR_DIRECT_ADC)) + +/* Bitmask of sensor types supported by ADT7604 */ +#define ADT7604_SENSORS \ + (GENMASK_ULL(LTC2983_SENSOR_RTD_CUSTOM - 1, LTC2983_SENSOR_RTD) | \ + GENMASK_ULL(LTC2983_SENSOR_THERMISTOR_CUSTOM - 1, LTC2983_SENSOR_THERMISTOR) | \ + BIT_ULL(LTC2983_SENSOR_SENSE_RESISTOR) | \ + BIT_ULL(LTC2983_SENSOR_COPPER_TRACE) | \ + BIT_ULL(LTC2983_SENSOR_LEAK_DETECTOR)) + #define to_thermocouple(_sensor) \ container_of(_sensor, struct ltc2983_thermocouple, sensor) #define to_rtd(_sensor) \ container_of(_sensor, struct ltc2983_rtd, sensor) +#define to_copper_trace(_sensor) \ + container_of(_sensor, struct ltc2983_copper_trace, sensor) + #define to_thermistor(_sensor) \ container_of(_sensor, struct ltc2983_thermistor, sensor) +#define to_leak_detector(_sensor) \ + container_of(_sensor, struct ltc2983_leak_detector, sensor) + #define to_diode(_sensor) \ container_of(_sensor, struct ltc2983_diode, sensor) @@ -212,7 +241,7 @@ enum { struct ltc2983_chip_info { const char *name; unsigned int max_channels_nr; - bool has_temp; + u64 supported_sensors; bool has_eeprom; }; @@ -247,6 +276,8 @@ struct ltc2983_sensor { u32 chan; /* sensor type */ u32 type; + /* number of IIO channels this sensor produces */ + u8 n_iio_chan; }; struct ltc2983_custom_sensor { @@ -274,6 +305,25 @@ struct ltc2983_rtd { u32 rtd_curve; }; +struct ltc2983_copper_trace { + struct ltc2983_sensor sensor; + struct ltc2983_custom_sensor *custom; + u32 r_sense_chan; + u32 excitation_current; + /* selects the <1Ω variant: bits 17:0 of the channel word are zeroed, + * disabling excitation current and custom table fields (ADT7604 + * datasheet Table 26) + */ + bool is_sub_ohm; +}; + +struct ltc2983_leak_detector { + struct ltc2983_sensor sensor; + struct ltc2983_custom_sensor *custom; + u32 r_sense_chan; + u32 excitation_current; +}; + struct ltc2983_thermistor { struct ltc2983_sensor sensor; struct ltc2983_custom_sensor *custom; @@ -353,8 +403,14 @@ static int __ltc2983_chan_assign_common(struct ltc2983_data *st, { struct device *dev = &st->spi->dev; u32 reg = LTC2983_CHAN_ASSIGN_ADDR(sensor->chan); + u32 hw_type = sensor->type; - chan_val |= LTC2983_CHAN_TYPE(sensor->type); + if (hw_type == LTC2983_SENSOR_COPPER_TRACE) + hw_type = LTC2983_SENSOR_RTD_CUSTOM; + else if (hw_type == LTC2983_SENSOR_LEAK_DETECTOR) + hw_type = LTC2983_SENSOR_THERMISTOR_CUSTOM; + + chan_val |= LTC2983_CHAN_TYPE(hw_type); dev_dbg(dev, "Assign reg:0x%04X, val:0x%08X\n", reg, chan_val); st->chan_val = cpu_to_be32(chan_val); return regmap_bulk_write(st->regmap, reg, &st->chan_val, @@ -485,6 +541,14 @@ __ltc2983_custom_sensor_new(struct ltc2983_data *st, const struct fwnode_handle for (index = 0; index < n_entries; index++) { u64 temp = ((u64 *)new_custom->table)[index]; + /* + * Users specify plain coverage percentage (0-100). Convert + * to µK so __convert_to_raw() produces the correct hardware + * encoding: P + 273.15 K. + */ + if ((index % 2) != 0 && !strcmp(propname, "adi,custom-leak-detector")) + temp = temp * 1000000 + 273150000; + if ((index % 2) != 0) temp = __convert_to_raw(temp, 1024); else if (has_signed && (s64)temp < 0) @@ -578,6 +642,31 @@ static int ltc2983_rtd_assign_chan(struct ltc2983_data *st, return __ltc2983_chan_assign_common(st, sensor, chan_val); } +static int ltc2983_copper_trace_assign_chan(struct ltc2983_data *st, + const struct ltc2983_sensor *sensor) +{ + struct ltc2983_copper_trace *ct = to_copper_trace(sensor); + u32 chan_val; + + chan_val = LTC2983_CHAN_ASSIGN(ct->r_sense_chan); + /* Sensor config bits 21:18 must be 0b1001 (ADT7604 datasheet Table 26) */ + chan_val |= LTC2983_RTD_CFG(0x9); + + if (ct->is_sub_ohm) { + chan_val &= ~GENMASK(17, 0); + } else { + int ret; + + chan_val |= LTC2983_RTD_EXC_CURRENT(ct->excitation_current); + ret = __ltc2983_chan_custom_sensor_assign(st, ct->custom, + &chan_val); + if (ret) + return ret; + } + + return __ltc2983_chan_assign_common(st, sensor, chan_val); +} + static int ltc2983_thermistor_assign_chan(struct ltc2983_data *st, const struct ltc2983_sensor *sensor) { @@ -601,6 +690,25 @@ static int ltc2983_thermistor_assign_chan(struct ltc2983_data *st, return __ltc2983_chan_assign_common(st, sensor, chan_val); } +static int ltc2983_leak_detector_assign_chan(struct ltc2983_data *st, + const struct ltc2983_sensor *sensor) +{ + struct ltc2983_leak_detector *ld = to_leak_detector(sensor); + u32 chan_val; + int ret; + + chan_val = LTC2983_CHAN_ASSIGN(ld->r_sense_chan); + /* bits 21:19 must be 0b001 (ADT7604 datasheet Table 38) */ + chan_val |= LTC2983_THERMISTOR_CFG(1); + chan_val |= LTC2983_THERMISTOR_EXC_CURRENT(ld->excitation_current); + + ret = __ltc2983_chan_custom_sensor_assign(st, ld->custom, &chan_val); + if (ret) + return ret; + + return __ltc2983_chan_assign_common(st, sensor, chan_val); +} + static int ltc2983_diode_assign_chan(struct ltc2983_data *st, const struct ltc2983_sensor *sensor) { @@ -1036,6 +1144,195 @@ ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *s return &thermistor->sensor; } +static struct ltc2983_sensor * +ltc2983_copper_trace_new(const struct fwnode_handle *child, struct ltc2983_data *st, + const struct ltc2983_sensor *sensor) +{ + struct device *dev = &st->spi->dev; + struct ltc2983_copper_trace *ct; + int ret; + + if (sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) + return dev_err_ptr_probe(dev, -EINVAL, + "Invalid channel %d for copper trace\n", + sensor->chan); + + ct = devm_kzalloc(dev, sizeof(*ct), GFP_KERNEL); + if (!ct) + return ERR_PTR(-ENOMEM); + + struct fwnode_handle *ref __free(fwnode_handle) = + fwnode_find_reference(child, "adi,rsense-handle", 0); + if (IS_ERR(ref)) + return dev_err_cast_probe(dev, ref, + "Property adi,rsense-handle missing or invalid\n"); + + ret = fwnode_property_read_u32(ref, "reg", &ct->r_sense_chan); + if (ret) + return dev_err_ptr_probe(dev, ret, "Property reg must be given\n"); + + ct->is_sub_ohm = fwnode_property_read_bool(child, "adi,copper-trace-sub-ohm"); + + if (ct->is_sub_ohm && fwnode_property_present(child, "adi,custom-copper-trace")) + return dev_err_ptr_probe(dev, -EINVAL, + "sub-ohm copper trace cannot have a custom table\n"); + + if (!ct->is_sub_ohm) { + u32 excitation_current = 0; + + if (!fwnode_property_present(child, "adi,custom-copper-trace")) + return dev_err_ptr_probe(dev, -EINVAL, + "adi,custom-copper-trace is required for >1 ohm copper trace\n"); + + ct->custom = __ltc2983_custom_sensor_new(st, child, "adi,custom-copper-trace", + false, 2048, false); + if (IS_ERR(ct->custom)) + return ERR_CAST(ct->custom); + + if (fwnode_property_present(child, "adi,excitation-current-microamp")) { + ret = fwnode_property_read_u32(child, "adi,excitation-current-microamp", + &excitation_current); + if (ret) + return dev_err_ptr_probe(dev, ret, + "Failed to read adi,excitation-current-microamp\n"); + + switch (excitation_current) { + case 5: + ct->excitation_current = 0x01; + break; + case 10: + ct->excitation_current = 0x02; + break; + case 25: + ct->excitation_current = 0x03; + break; + case 50: + ct->excitation_current = 0x04; + break; + case 100: + ct->excitation_current = 0x05; + break; + case 250: + ct->excitation_current = 0x06; + break; + case 500: + ct->excitation_current = 0x07; + break; + case 1000: + ct->excitation_current = 0x08; + break; + default: + return dev_err_ptr_probe(dev, -EINVAL, + "Invalid value for excitation current(%u)\n", + excitation_current); + } + } else { + /* default to 1mA per datasheet recommendation for copper trace */ + ct->excitation_current = 0x08; + } + } + + ct->sensor.fault_handler = ltc2983_common_fault_handler; + ct->sensor.assign_chan = ltc2983_copper_trace_assign_chan; + if (ct->is_sub_ohm) + ct->sensor.n_iio_chan = 1; + else + ct->sensor.n_iio_chan = 2; + + return &ct->sensor; +} + +static struct ltc2983_sensor * +ltc2983_leak_detector_new(const struct fwnode_handle *child, struct ltc2983_data *st, + const struct ltc2983_sensor *sensor) +{ + struct device *dev = &st->spi->dev; + struct ltc2983_leak_detector *ld; + int ret; + u32 excitation_current = 0; + + if (sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) + return dev_err_ptr_probe(dev, -EINVAL, + "Invalid channel %d for leak detector\n", + sensor->chan); + + ld = devm_kzalloc(dev, sizeof(*ld), GFP_KERNEL); + if (!ld) + return ERR_PTR(-ENOMEM); + + struct fwnode_handle *ref __free(fwnode_handle) = + fwnode_find_reference(child, "adi,rsense-handle", 0); + if (IS_ERR(ref)) + return dev_err_cast_probe(dev, ref, + "Property adi,rsense-handle missing or invalid\n"); + + ret = fwnode_property_read_u32(ref, "reg", &ld->r_sense_chan); + if (ret) + return dev_err_ptr_probe(dev, ret, + "rsense channel must be configured\n"); + + if (!fwnode_property_present(child, "adi,custom-leak-detector")) + return dev_err_ptr_probe(dev, -EINVAL, + "adi,custom-leak-detector is required for leak detectors\n"); + + ld->custom = __ltc2983_custom_sensor_new(st, child, "adi,custom-leak-detector", + false, 16, false); + if (IS_ERR(ld->custom)) + return ERR_CAST(ld->custom); + + ret = fwnode_property_read_u32(child, "adi,excitation-current-nanoamp", + &excitation_current); + if (ret) + return dev_err_ptr_probe(dev, ret, + "adi,excitation-current-nanoamp is required for leak detectors\n"); + + switch (excitation_current) { + case 250: + ld->excitation_current = 0x01; + break; + case 500: + ld->excitation_current = 0x02; + break; + case 1000: + ld->excitation_current = 0x03; + break; + case 5000: + ld->excitation_current = 0x04; + break; + case 10000: + ld->excitation_current = 0x05; + break; + case 25000: + ld->excitation_current = 0x06; + break; + case 50000: + ld->excitation_current = 0x07; + break; + case 100000: + ld->excitation_current = 0x08; + break; + case 250000: + ld->excitation_current = 0x09; + break; + case 500000: + ld->excitation_current = 0x0a; + break; + case 1000000: + ld->excitation_current = 0x0b; + break; + default: + return dev_err_ptr_probe(dev, -EINVAL, + "Invalid value for excitation current(%u)\n", + excitation_current); + } + + ld->sensor.fault_handler = ltc2983_common_fault_handler; + ld->sensor.assign_chan = ltc2983_leak_detector_assign_chan; + ld->sensor.n_iio_chan = 2; + + return &ld->sensor; +} + static struct ltc2983_sensor * ltc2983_diode_new(const struct fwnode_handle *child, const struct ltc2983_data *st, const struct ltc2983_sensor *sensor) @@ -1204,7 +1501,8 @@ static struct ltc2983_sensor *ltc2983_temp_new(struct fwnode_handle *child, } static int ltc2983_chan_read(struct ltc2983_data *st, - const struct ltc2983_sensor *sensor, int *val) + const struct ltc2983_sensor *sensor, + u32 base_reg, int *val) { struct device *dev = &st->spi->dev; u32 start_conversion = 0; @@ -1234,13 +1532,23 @@ static int ltc2983_chan_read(struct ltc2983_data *st, } /* read the converted data */ - ret = regmap_bulk_read(st->regmap, LTC2983_RESULT_ADDR(sensor->chan), + ret = regmap_bulk_read(st->regmap, LTC2983_RESULT_ADDR(sensor->chan, base_reg), &st->temp, sizeof(st->temp)); if (ret) return ret; *val = __be32_to_cpu(st->temp); + if (base_reg == ADT7604_RES_RES_START_REG) { + /* + * Resistance result register gives a plain unsigned value, + * D31 is always 0, no valid bit, no fault bits. Read bits[30:0] + * directly — the temperature result format does not apply here. + */ + *val &= GENMASK(30, 0); + return 0; + } + if (!(LTC2983_RES_VALID_MASK & *val)) { dev_err(dev, "Invalid conversion detected\n"); return -EIO; @@ -1271,7 +1579,16 @@ static int ltc2983_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: mutex_lock(&st->lock); - ret = ltc2983_chan_read(st, st->sensors[chan->address], val); + switch (chan->type) { + case IIO_RESISTANCE: + ret = ltc2983_chan_read(st, st->sensors[chan->address], + ADT7604_RES_RES_START_REG, val); + break; + default: + ret = ltc2983_chan_read(st, st->sensors[chan->address], + LTC2983_TEMP_RES_START_REG, val); + break; + } mutex_unlock(&st->lock); return ret ?: IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: @@ -1288,6 +1605,13 @@ static int ltc2983_read_raw(struct iio_dev *indio_dev, /* 2^21 */ *val2 = 2097152; return IIO_VAL_FRACTIONAL; + case IIO_RESISTANCE: + case IIO_COVERAGE: + /* value in ohm/percent */ + *val = 1; + /* 2^10 */ + *val2 = 1024; + return IIO_VAL_FRACTIONAL; default: return -EINVAL; } @@ -1348,7 +1672,7 @@ static int ltc2983_parse_fw(struct ltc2983_data *st) if (!st->sensors) return -ENOMEM; - st->iio_channels = st->num_channels; + st->iio_channels = 0; device_for_each_child_node_scoped(dev, child) { struct ltc2983_sensor sensor; @@ -1376,6 +1700,12 @@ static int ltc2983_parse_fw(struct ltc2983_data *st) return dev_err_probe(dev, ret, "adi,sensor-type property must given for child nodes\n"); + if (sensor.type >= LTC2983_SENSOR_NUM || + !(st->info->supported_sensors & BIT_ULL(sensor.type))) + return dev_err_probe(dev, -EINVAL, + "sensor type %d not supported on %s\n", + sensor.type, st->info->name); + dev_dbg(dev, "Create new sensor, type %u, channel %u", sensor.type, sensor.chan); @@ -1396,13 +1726,14 @@ static int ltc2983_parse_fw(struct ltc2983_data *st) } else if (sensor.type == LTC2983_SENSOR_SENSE_RESISTOR) { st->sensors[chan] = ltc2983_r_sense_new(child, st, &sensor); - /* don't add rsense to iio */ - st->iio_channels--; } else if (sensor.type == LTC2983_SENSOR_DIRECT_ADC) { st->sensors[chan] = ltc2983_adc_new(child, st, &sensor); - } else if (st->info->has_temp && - sensor.type == LTC2983_SENSOR_ACTIVE_TEMP) { + } else if (sensor.type == LTC2983_SENSOR_ACTIVE_TEMP) { st->sensors[chan] = ltc2983_temp_new(child, st, &sensor); + } else if (sensor.type == LTC2983_SENSOR_COPPER_TRACE) { + st->sensors[chan] = ltc2983_copper_trace_new(child, st, &sensor); + } else if (sensor.type == LTC2983_SENSOR_LEAK_DETECTOR) { + st->sensors[chan] = ltc2983_leak_detector_new(child, st, &sensor); } else { return dev_err_probe(dev, -EINVAL, "Unknown sensor type %d\n", @@ -1417,6 +1748,16 @@ static int ltc2983_parse_fw(struct ltc2983_data *st) st->sensors[chan]->chan = sensor.chan; st->sensors[chan]->type = sensor.type; + /* + * Dedicated functions set n_iio_chan themselves; for all other + * sensor types rsense produces 0 channels, everything else 1. + */ + if (!st->sensors[chan]->n_iio_chan) { + if (sensor.type != LTC2983_SENSOR_SENSE_RESISTOR) + st->sensors[chan]->n_iio_chan = 1; + } + st->iio_channels += st->sensors[chan]->n_iio_chan; + channel_avail_mask |= BIT(sensor.chan); chan++; } @@ -1464,8 +1805,9 @@ static int ltc2983_eeprom_cmd(struct ltc2983_data *st, unsigned int cmd, static int ltc2983_setup(struct ltc2983_data *st, bool assign_iio) { - u32 iio_chan_t = 0, iio_chan_v = 0, chan, iio_idx = 0, status; struct device *dev = &st->spi->dev; + u32 iio_chan_t = 0, iio_chan_v = 0, iio_chan_r = 0, iio_chan_c = 0; + u32 chan, iio_idx = 0, status; int ret; /* make sure the device is up: start bit (7) is 0 and done bit (6) is 1 */ @@ -1512,12 +1854,33 @@ static int ltc2983_setup(struct ltc2983_data *st, bool assign_iio) continue; /* assign iio channel */ - if (st->sensors[chan]->type != LTC2983_SENSOR_DIRECT_ADC) { - chan_type = IIO_TEMP; - iio_chan = &iio_chan_t; - } else { + switch (st->sensors[chan]->type) { + case LTC2983_SENSOR_COPPER_TRACE: + if (st->sensors[chan]->n_iio_chan == 1) { + /* sub-ohm copper traces produce only a resistance result */ + st->iio_chan[iio_idx++] = + LTC2983_CHAN(IIO_RESISTANCE, iio_chan_r++, chan); + } else { + st->iio_chan[iio_idx++] = + LTC2983_CHAN(IIO_TEMP, iio_chan_t++, chan); + st->iio_chan[iio_idx++] = + LTC2983_CHAN(IIO_RESISTANCE, iio_chan_r++, chan); + } + continue; + case LTC2983_SENSOR_LEAK_DETECTOR: + st->iio_chan[iio_idx++] = + LTC2983_CHAN(IIO_COVERAGE, iio_chan_c++, chan); + st->iio_chan[iio_idx++] = + LTC2983_CHAN(IIO_RESISTANCE, iio_chan_r++, chan); + continue; + case LTC2983_SENSOR_DIRECT_ADC: chan_type = IIO_VOLTAGE; iio_chan = &iio_chan_v; + break; + default: + chan_type = IIO_TEMP; + iio_chan = &iio_chan_t; + break; } /* @@ -1534,6 +1897,7 @@ static int ltc2983_setup(struct ltc2983_data *st, bool assign_iio) static const struct regmap_range ltc2983_reg_ranges[] = { regmap_reg_range(LTC2983_STATUS_REG, LTC2983_STATUS_REG), regmap_reg_range(LTC2983_TEMP_RES_START_REG, LTC2983_TEMP_RES_END_REG), + regmap_reg_range(ADT7604_RES_RES_START_REG, ADT7604_RES_RES_END_REG), regmap_reg_range(LTC2983_EEPROM_KEY_REG, LTC2983_EEPROM_KEY_REG), regmap_reg_range(LTC2983_EEPROM_READ_STATUS_REG, LTC2983_EEPROM_READ_STATUS_REG), @@ -1672,32 +2036,42 @@ static int ltc2983_suspend(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(ltc2983_pm_ops, ltc2983_suspend, ltc2983_resume); +static const struct ltc2983_chip_info adt7604_chip_info_data = { + .name = "adt7604", + .max_channels_nr = 20, + .has_eeprom = true, + .supported_sensors = ADT7604_SENSORS, +}; + static const struct ltc2983_chip_info ltc2983_chip_info_data = { .name = "ltc2983", .max_channels_nr = 20, + .supported_sensors = LTC2983_COMMON_SENSORS, }; static const struct ltc2983_chip_info ltc2984_chip_info_data = { .name = "ltc2984", .max_channels_nr = 20, .has_eeprom = true, + .supported_sensors = LTC2983_COMMON_SENSORS, }; static const struct ltc2983_chip_info ltc2986_chip_info_data = { .name = "ltc2986", .max_channels_nr = 10, - .has_temp = true, .has_eeprom = true, + .supported_sensors = LTC2983_COMMON_SENSORS | BIT_ULL(LTC2983_SENSOR_ACTIVE_TEMP), }; static const struct ltc2983_chip_info ltm2985_chip_info_data = { .name = "ltm2985", .max_channels_nr = 10, - .has_temp = true, .has_eeprom = true, + .supported_sensors = LTC2983_COMMON_SENSORS | BIT_ULL(LTC2983_SENSOR_ACTIVE_TEMP), }; static const struct spi_device_id ltc2983_id_table[] = { + { "adt7604", (kernel_ulong_t)&adt7604_chip_info_data }, { "ltc2983", (kernel_ulong_t)<c2983_chip_info_data }, { "ltc2984", (kernel_ulong_t)<c2984_chip_info_data }, { "ltc2986", (kernel_ulong_t)<c2986_chip_info_data }, @@ -1707,6 +2081,7 @@ static const struct spi_device_id ltc2983_id_table[] = { MODULE_DEVICE_TABLE(spi, ltc2983_id_table); static const struct of_device_id ltc2983_of_match[] = { + { .compatible = "adi,adt7604", .data = &adt7604_chip_info_data }, { .compatible = "adi,ltc2983", .data = <c2983_chip_info_data }, { .compatible = "adi,ltc2984", .data = <c2984_chip_info_data }, { .compatible = "adi,ltc2986", .data = <c2986_chip_info_data }, From 36862727e0079f8edcb2869d994a0d394513d857 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Thu, 28 May 2026 12:16:49 +0200 Subject: [PATCH 243/266] iio: Use named initializers for platform_device_id arrays MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Named initializers are better readable and more robust to changes of the struct definition. This robustness is relevant for a planned change to struct platform_device_id replacing .driver_data by an anonymous union. Signed-off-by: Uwe Kleine-König (The Capable Hub) Signed-off-by: Jonathan Cameron --- drivers/iio/adc/88pm886-gpadc.c | 2 +- drivers/iio/adc/max77541-adc.c | 2 +- drivers/iio/adc/sun4i-gpadc-iio.c | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/iio/adc/88pm886-gpadc.c b/drivers/iio/adc/88pm886-gpadc.c index cffe35136685..4435f3d5e2b8 100644 --- a/drivers/iio/adc/88pm886-gpadc.c +++ b/drivers/iio/adc/88pm886-gpadc.c @@ -373,7 +373,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(pm886_gpadc_pm_ops, pm886_gpadc_runtime_resume, NULL); static const struct platform_device_id pm886_gpadc_id[] = { - { "88pm886-gpadc" }, + { .name = "88pm886-gpadc" }, { } }; MODULE_DEVICE_TABLE(platform, pm886_gpadc_id); diff --git a/drivers/iio/adc/max77541-adc.c b/drivers/iio/adc/max77541-adc.c index 0aa04d143ad4..013da014bccd 100644 --- a/drivers/iio/adc/max77541-adc.c +++ b/drivers/iio/adc/max77541-adc.c @@ -175,7 +175,7 @@ static int max77541_adc_probe(struct platform_device *pdev) } static const struct platform_device_id max77541_adc_platform_id[] = { - { "max77541-adc" }, + { .name = "max77541-adc" }, { } }; MODULE_DEVICE_TABLE(platform, max77541_adc_platform_id); diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c index 479115ea50bf..203459ca9907 100644 --- a/drivers/iio/adc/sun4i-gpadc-iio.c +++ b/drivers/iio/adc/sun4i-gpadc-iio.c @@ -679,9 +679,9 @@ static void sun4i_gpadc_remove(struct platform_device *pdev) } static const struct platform_device_id sun4i_gpadc_id[] = { - { "sun4i-a10-gpadc-iio", (kernel_ulong_t)&sun4i_gpadc_data }, - { "sun5i-a13-gpadc-iio", (kernel_ulong_t)&sun5i_gpadc_data }, - { "sun6i-a31-gpadc-iio", (kernel_ulong_t)&sun6i_gpadc_data }, + { .name = "sun4i-a10-gpadc-iio", .driver_data = (kernel_ulong_t)&sun4i_gpadc_data }, + { .name = "sun5i-a13-gpadc-iio", .driver_data = (kernel_ulong_t)&sun5i_gpadc_data }, + { .name = "sun6i-a31-gpadc-iio", .driver_data = (kernel_ulong_t)&sun6i_gpadc_data }, { } }; MODULE_DEVICE_TABLE(platform, sun4i_gpadc_id); From 40d7dc96cf14e2e37fb9501e7d25fde10b858596 Mon Sep 17 00:00:00 2001 From: Matheus Silveira Date: Thu, 28 May 2026 15:55:12 -0300 Subject: [PATCH 244/266] light: tsl2591: simplify tsl2591_persist functions via lookup table Replace switch statements with an indexed lookup table for persist cycle conversions. Both functions contain redundant switch statements. This reduces code duplication and makes future updates to TSL2591_PRST_ALS_INT_CYCLE_* definitions easier to maintain by keeping the mapping in a single place. Signed-off-by: Matheus Silveira Co-developed-by: Lucas Rabaquim Signed-off-by: Lucas Rabaquim Signed-off-by: Jonathan Cameron --- drivers/iio/light/tsl2591.c | 94 +++++++++++-------------------------- 1 file changed, 28 insertions(+), 66 deletions(-) diff --git a/drivers/iio/light/tsl2591.c b/drivers/iio/light/tsl2591.c index c5557867ea43..ac5e1822b993 100644 --- a/drivers/iio/light/tsl2591.c +++ b/drivers/iio/light/tsl2591.c @@ -192,6 +192,24 @@ static const int tsl2591_calibscale_available[] = { 1, 25, 428, 9876, }; +static const u8 tsl2591_persist_table[] = { + [TSL2591_PRST_ALS_INT_CYCLE_ANY] = 1, + [TSL2591_PRST_ALS_INT_CYCLE_2] = 2, + [TSL2591_PRST_ALS_INT_CYCLE_3] = 3, + [TSL2591_PRST_ALS_INT_CYCLE_5] = 5, + [TSL2591_PRST_ALS_INT_CYCLE_10] = 10, + [TSL2591_PRST_ALS_INT_CYCLE_15] = 15, + [TSL2591_PRST_ALS_INT_CYCLE_20] = 20, + [TSL2591_PRST_ALS_INT_CYCLE_25] = 25, + [TSL2591_PRST_ALS_INT_CYCLE_30] = 30, + [TSL2591_PRST_ALS_INT_CYCLE_35] = 35, + [TSL2591_PRST_ALS_INT_CYCLE_40] = 40, + [TSL2591_PRST_ALS_INT_CYCLE_45] = 45, + [TSL2591_PRST_ALS_INT_CYCLE_50] = 50, + [TSL2591_PRST_ALS_INT_CYCLE_55] = 55, + [TSL2591_PRST_ALS_INT_CYCLE_60] = 60, +}; + static int tsl2591_set_als_lower_threshold(struct tsl2591_chip *chip, u16 als_lower_threshold); static int tsl2591_set_als_upper_threshold(struct tsl2591_chip *chip, @@ -231,78 +249,22 @@ static int tsl2591_multiplier_to_gain(const u32 multiplier) static int tsl2591_persist_cycle_to_lit(const u8 als_persist) { - switch (als_persist) { - case TSL2591_PRST_ALS_INT_CYCLE_ANY: - return 1; - case TSL2591_PRST_ALS_INT_CYCLE_2: - return 2; - case TSL2591_PRST_ALS_INT_CYCLE_3: - return 3; - case TSL2591_PRST_ALS_INT_CYCLE_5: - return 5; - case TSL2591_PRST_ALS_INT_CYCLE_10: - return 10; - case TSL2591_PRST_ALS_INT_CYCLE_15: - return 15; - case TSL2591_PRST_ALS_INT_CYCLE_20: - return 20; - case TSL2591_PRST_ALS_INT_CYCLE_25: - return 25; - case TSL2591_PRST_ALS_INT_CYCLE_30: - return 30; - case TSL2591_PRST_ALS_INT_CYCLE_35: - return 35; - case TSL2591_PRST_ALS_INT_CYCLE_40: - return 40; - case TSL2591_PRST_ALS_INT_CYCLE_45: - return 45; - case TSL2591_PRST_ALS_INT_CYCLE_50: - return 50; - case TSL2591_PRST_ALS_INT_CYCLE_55: - return 55; - case TSL2591_PRST_ALS_INT_CYCLE_60: - return 60; - default: + if (als_persist >= ARRAY_SIZE(tsl2591_persist_table) || + !tsl2591_persist_table[als_persist]) return -EINVAL; - } + + return tsl2591_persist_table[als_persist]; } static int tsl2591_persist_lit_to_cycle(const u8 als_persist) { - switch (als_persist) { - case 1: - return TSL2591_PRST_ALS_INT_CYCLE_ANY; - case 2: - return TSL2591_PRST_ALS_INT_CYCLE_2; - case 3: - return TSL2591_PRST_ALS_INT_CYCLE_3; - case 5: - return TSL2591_PRST_ALS_INT_CYCLE_5; - case 10: - return TSL2591_PRST_ALS_INT_CYCLE_10; - case 15: - return TSL2591_PRST_ALS_INT_CYCLE_15; - case 20: - return TSL2591_PRST_ALS_INT_CYCLE_20; - case 25: - return TSL2591_PRST_ALS_INT_CYCLE_25; - case 30: - return TSL2591_PRST_ALS_INT_CYCLE_30; - case 35: - return TSL2591_PRST_ALS_INT_CYCLE_35; - case 40: - return TSL2591_PRST_ALS_INT_CYCLE_40; - case 45: - return TSL2591_PRST_ALS_INT_CYCLE_45; - case 50: - return TSL2591_PRST_ALS_INT_CYCLE_50; - case 55: - return TSL2591_PRST_ALS_INT_CYCLE_55; - case 60: - return TSL2591_PRST_ALS_INT_CYCLE_60; - default: - return -EINVAL; + for (unsigned int i = TSL2591_PRST_ALS_INT_CYCLE_ANY; + i < ARRAY_SIZE(tsl2591_persist_table); i++) { + if (als_persist == tsl2591_persist_table[i]) + return i; } + + return -EINVAL; } static int tsl2591_compatible_int_time(struct tsl2591_chip *chip, From 4bff2ca299740182d2b05f425c02295e23177390 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Fri, 29 May 2026 17:13:52 +0300 Subject: [PATCH 245/266] dt-bindings: iio: adc: ad4080: add AD4884 support Add AD4884 compatible string to the AD4080 devicetree binding. The AD4884 is a dual-channel, 16-bit, 40 MSPS SAR ADC, sharing the same register map and interface as the AD4080 family. Like the AD4880, it requires two SPI chip selects and two io-backends for its independent ADC channels. The AD4884 differs from the AD4880 in resolution (16-bit vs 20-bit), which requires distinct channel configuration in the driver, precluding a fallback compatible. Acked-by: Conor Dooley Signed-off-by: Antoniu Miclaus Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/adc/adi,ad4080.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad4080.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad4080.yaml index 9c6a56c7c8ef..4a3f7d3e05c3 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad4080.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad4080.yaml @@ -39,6 +39,7 @@ properties: - adi,ad4087 - adi,ad4088 - adi,ad4880 + - adi,ad4884 reg: minItems: 1 @@ -99,7 +100,9 @@ allOf: properties: compatible: contains: - const: adi,ad4880 + enum: + - adi,ad4880 + - adi,ad4884 then: properties: reg: From 7853cf5b65d2b70834cf49c7fb1ff6810120a8e7 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Fri, 29 May 2026 17:13:53 +0300 Subject: [PATCH 246/266] iio: adc: ad4080: add support for AD4884 Add support for the AD4884, a dual-channel, 16-bit, 40 MSPS SAR ADC. The AD4884 is the dual-channel variant of the AD4084, sharing the same register map and SPI interface as the rest of the AD4080 family. Like the AD4880, it uses two independent ADC channels, each with its own SPI configuration interface. Signed-off-by: Antoniu Miclaus Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad4080.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/iio/adc/ad4080.c b/drivers/iio/adc/ad4080.c index 265d85ac171a..764d49eca9e0 100644 --- a/drivers/iio/adc/ad4080.c +++ b/drivers/iio/adc/ad4080.c @@ -136,6 +136,7 @@ #define AD4087_CHIP_ID 0x0057 #define AD4088_CHIP_ID 0x0058 #define AD4880_CHIP_ID 0x0750 +#define AD4884_CHIP_ID 0x005C #define AD4080_MAX_CHANNELS 2 @@ -541,6 +542,11 @@ static const struct iio_chan_spec ad4880_channels[] = { AD4880_CHANNEL_DEFINE(20, 32, 1), }; +static const struct iio_chan_spec ad4884_channels[] = { + AD4880_CHANNEL_DEFINE(16, 16, 0), + AD4880_CHANNEL_DEFINE(16, 16, 1), +}; + static const struct ad4080_chip_info ad4080_chip_info = { .name = "ad4080", .product_id = AD4080_CHIP_ID, @@ -641,6 +647,16 @@ static const struct ad4080_chip_info ad4880_chip_info = { .lvds_cnv_clk_cnt_max = AD4080_LVDS_CNV_CLK_CNT_MAX, }; +static const struct ad4080_chip_info ad4884_chip_info = { + .name = "ad4884", + .product_id = AD4884_CHIP_ID, + .scale_table = ad4080_scale_table, + .num_scales = ARRAY_SIZE(ad4080_scale_table), + .num_channels = 2, + .channels = ad4884_channels, + .lvds_cnv_clk_cnt_max = 2, +}; + static int ad4080_setup_channel(struct ad4080_state *st, unsigned int ch) { struct device *dev = regmap_get_device(st->regmap[ch]); @@ -843,6 +859,7 @@ static const struct spi_device_id ad4080_id[] = { { "ad4087", (kernel_ulong_t)&ad4087_chip_info }, { "ad4088", (kernel_ulong_t)&ad4088_chip_info }, { "ad4880", (kernel_ulong_t)&ad4880_chip_info }, + { "ad4884", (kernel_ulong_t)&ad4884_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad4080_id); @@ -858,6 +875,7 @@ static const struct of_device_id ad4080_of_match[] = { { .compatible = "adi,ad4087", &ad4087_chip_info }, { .compatible = "adi,ad4088", &ad4088_chip_info }, { .compatible = "adi,ad4880", &ad4880_chip_info }, + { .compatible = "adi,ad4884", &ad4884_chip_info }, { } }; MODULE_DEVICE_TABLE(of, ad4080_of_match); From 1ea5792ad7c75e8d6ec62fcaccfbf38fa82ef978 Mon Sep 17 00:00:00 2001 From: Radu Sabau Date: Fri, 29 May 2026 13:15:00 +0300 Subject: [PATCH 247/266] dt-bindings: iio: adc: add AD4691 family Add DT bindings for the Analog Devices AD4691 family of multichannel SAR ADCs (AD4691, AD4692, AD4693, AD4694). The four variants are not compatible with each other: AD4691/AD4692 have 16 analog input channels while AD4693/AD4694 have 8, and AD4691/AD4693 top out at 500 kSPS while AD4692/AD4694 reach 1 MSPS. These differences in channel count and maximum sample rate require distinct compatible strings so the driver can select the correct channel configuration and rate limits. Acked-by: Conor Dooley Signed-off-by: Radu Sabau Signed-off-by: Jonathan Cameron --- .../bindings/iio/adc/adi,ad4691.yaml | 180 ++++++++++++++++++ MAINTAINERS | 7 + 2 files changed, 187 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/adi,ad4691.yaml diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad4691.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad4691.yaml new file mode 100644 index 000000000000..af28a0c1cfa9 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad4691.yaml @@ -0,0 +1,180 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/adi,ad4691.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices AD4691 Family Multichannel SAR ADCs + +maintainers: + - Radu Sabau + +description: | + The AD4691 family are high-speed, low-power, multichannel successive + approximation register (SAR) analog-to-digital converters (ADCs) with + an SPI-compatible serial interface. The ADC supports CNV Burst Mode, + where an external PWM drives the CNV pin, and Manual Mode, where CNV + is directly tied to the SPI chip-select. + + Datasheets: + * https://www.analog.com/en/products/ad4691.html + * https://www.analog.com/en/products/ad4692.html + * https://www.analog.com/en/products/ad4693.html + * https://www.analog.com/en/products/ad4694.html + +$ref: /schemas/spi/spi-peripheral-props.yaml# + +properties: + compatible: + enum: + - adi,ad4691 + - adi,ad4692 + - adi,ad4693 + - adi,ad4694 + + reg: + maxItems: 1 + + spi-max-frequency: + maximum: 40000000 + + spi-cpol: true + spi-cpha: true + + avdd-supply: + description: Analog power supply (4.5V to 5.5V). + + vdd-supply: + description: + External 1.8V digital core supply. When present, the internal LDO is + disabled (LDO_EN = 0). Mutually exclusive with ldo-in-supply. + + ldo-in-supply: + description: + LDO input supply (2.4V to 5.5V). When present and vdd-supply is absent, + the internal LDO generates 1.8V VDD from this input (LDO_EN = 1). + Mutually exclusive with vdd-supply. + + vio-supply: + description: I/O voltage supply (1.71V to 1.89V or VDD). + + ref-supply: + description: External reference voltage supply (2.4V to 5.25V). + + refin-supply: + description: Internal reference buffer input supply. + + reset-gpios: + description: + GPIO line controlling the hardware reset pin (active-low). + maxItems: 1 + + pwms: + description: + PWM connected to the CNV pin. When present, selects CNV Burst Mode where + the PWM drives the conversion rate. When absent, Manual Mode is used + (CNV tied to SPI CS). + maxItems: 1 + + interrupts: + description: + Interrupt lines connected to the ADC GP pins. Each GP pin can be + physically wired to an interrupt-capable input on the SoC. + maxItems: 4 + + interrupt-names: + description: Names of the interrupt lines, matching the GP pin names. + minItems: 1 + maxItems: 4 + items: + enum: + - gp0 + - gp1 + - gp2 + - gp3 + + gpio-controller: true + + '#gpio-cells': + const: 2 + + '#trigger-source-cells': + description: + This node can act as a trigger source. The single cell in a consumer + reference specifies the GP pin number (0-3) used as the trigger output. + const: 1 + +required: + - compatible + - reg + - avdd-supply + - vio-supply + +allOf: + # vdd-supply and ldo-in-supply are mutually exclusive, one is required: + # either an external 1.8V VDD is provided or the internal LDO is fed from + # ldo-in-supply to generate VDD. + - oneOf: + - required: + - vdd-supply + - required: + - ldo-in-supply + # ref-supply and refin-supply are mutually exclusive, one is required + - oneOf: + - required: + - ref-supply + - required: + - refin-supply + +unevaluatedProperties: false + +examples: + - | + #include + /* AD4692 in CNV Burst Mode with SPI offload */ + spi { + #address-cells = <1>; + #size-cells = <0>; + + adc@0 { + compatible = "adi,ad4692"; + reg = <0>; + spi-cpol; + spi-cpha; + spi-max-frequency = <40000000>; + + avdd-supply = <&avdd_supply>; + ldo-in-supply = <&avdd_supply>; + vio-supply = <&vio_supply>; + ref-supply = <&ref_5v>; + + reset-gpios = <&gpio0 15 GPIO_ACTIVE_LOW>; + + pwms = <&pwm_gen 0 0>; + + #trigger-source-cells = <1>; + }; + }; + + - | + #include + /* AD4692 in Manual Mode (CNV tied to SPI CS) */ + spi { + #address-cells = <1>; + #size-cells = <0>; + + adc@0 { + compatible = "adi,ad4692"; + reg = <0>; + spi-cpol; + spi-cpha; + spi-max-frequency = <31250000>; + + avdd-supply = <&avdd_supply>; + ldo-in-supply = <&avdd_supply>; + vio-supply = <&vio_supply>; + refin-supply = <&refin_supply>; + + reset-gpios = <&gpio0 15 GPIO_ACTIVE_LOW>; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 9e69cc754cf5..95ba426ef56e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1476,6 +1476,13 @@ W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/adc/adi,ad4170-4.yaml F: drivers/iio/adc/ad4170-4.c +ANALOG DEVICES INC AD4691 DRIVER +M: Radu Sabau +L: linux-iio@vger.kernel.org +S: Supported +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/iio/adc/adi,ad4691.yaml + ANALOG DEVICES INC AD4695 DRIVER M: Michael Hennerich M: Nuno Sá From 40850443aa1239f71fc65b870a0f0ecd54e42c9d Mon Sep 17 00:00:00 2001 From: Radu Sabau Date: Fri, 29 May 2026 13:15:01 +0300 Subject: [PATCH 248/266] iio: adc: ad4691: add initial driver for AD4691 family MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the Analog Devices AD4691 family of high-speed, low-power multichannel SAR ADCs: AD4691 (16-ch, 500 kSPS), AD4692 (16-ch, 1 MSPS), AD4693 (8-ch, 500 kSPS) and AD4694 (8-ch, 1 MSPS). The driver implements a custom regmap layer over raw SPI to handle the device's mixed 1/2/3/4-byte register widths and uses the standard IIO read_raw/write_raw interface for single-channel reads. The chip idles in Autonomous Mode so that single-shot read_raw can use the internal oscillator without disturbing the hardware configuration. Three voltage supply domains are managed: avdd (required), vio, and a reference supply on either the REF pin (ref-supply, external buffer) or the REFIN pin (refin-supply, uses the on-chip reference buffer; REFBUF_EN is set accordingly). Hardware reset is performed by asserting then deasserting the reset-gpios GPIO line (tRESETL minimum pulse width is 10 ns, satisfied by function-call overhead); the driver then waits 300 µs for the chip to complete its internal reset sequence. A software reset via SPI_CONFIG_A is used as fallback when no reset GPIO is provided. Accumulator channel masking for single-shot reads uses ACC_MASK_REG via an ADDR_DESCENDING SPI write, which covers both mask bytes in a single 16-bit transfer. Reviewed-by: David Lechner Signed-off-by: Radu Sabau Signed-off-by: Jonathan Cameron --- MAINTAINERS | 1 + drivers/iio/adc/Kconfig | 12 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ad4691.c | 783 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 797 insertions(+) create mode 100644 drivers/iio/adc/ad4691.c diff --git a/MAINTAINERS b/MAINTAINERS index 95ba426ef56e..4cb938531c64 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1482,6 +1482,7 @@ L: linux-iio@vger.kernel.org S: Supported W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/adc/adi,ad4691.yaml +F: drivers/iio/adc/ad4691.c ANALOG DEVICES INC AD4695 DRIVER M: Michael Hennerich diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 1115e81ac45b..d07e4d839f25 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -144,6 +144,18 @@ config AD4170_4 To compile this driver as a module, choose M here: the module will be called ad4170-4. +config AD4691 + tristate "Analog Devices AD4691 Family ADC Driver" + depends on SPI + depends on REGULATOR || COMPILE_TEST + select REGMAP + help + Say yes here to build support for Analog Devices AD4691 Family MuxSAR + SPI analog to digital converters (ADC). + + To compile this driver as a module, choose M here: the module will be + called ad4691. + config AD4695 tristate "Analog Device AD4695 ADC Driver" depends on SPI diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 097357d146ba..707dd708912f 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_AD4080) += ad4080.o obj-$(CONFIG_AD4130) += ad4130.o obj-$(CONFIG_AD4134) += ad4134.o obj-$(CONFIG_AD4170_4) += ad4170-4.o +obj-$(CONFIG_AD4691) += ad4691.o obj-$(CONFIG_AD4695) += ad4695.o obj-$(CONFIG_AD4851) += ad4851.o obj-$(CONFIG_AD7091R) += ad7091r-base.o diff --git a/drivers/iio/adc/ad4691.c b/drivers/iio/adc/ad4691.c new file mode 100644 index 000000000000..e1febf80f21d --- /dev/null +++ b/drivers/iio/adc/ad4691.c @@ -0,0 +1,783 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2024-2026 Analog Devices, Inc. + * Author: Radu Sabau + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define AD4691_VREF_uV_MIN 2400000 +#define AD4691_VREF_uV_MAX 5250000 +#define AD4691_VREF_2P5_uV_MAX 2750000 +#define AD4691_VREF_3P0_uV_MAX 3250000 +#define AD4691_VREF_3P3_uV_MAX 3750000 +#define AD4691_VREF_4P096_uV_MAX 4500000 + +#define AD4691_CNV_DUTY_CYCLE_NS 380 +#define AD4691_CNV_HIGH_TIME_NS 430 + +#define AD4691_SPI_CONFIG_A_REG 0x000 +#define AD4691_SW_RESET (BIT(7) | BIT(0)) + +#define AD4691_STATUS_REG 0x014 +#define AD4691_CLAMP_STATUS1_REG 0x01A +#define AD4691_CLAMP_STATUS2_REG 0x01B +#define AD4691_DEVICE_SETUP 0x020 +#define AD4691_MANUAL_MODE BIT(2) +#define AD4691_LDO_EN BIT(4) +#define AD4691_REF_CTRL 0x021 +#define AD4691_REF_CTRL_MASK GENMASK(4, 2) +#define AD4691_REFBUF_EN BIT(0) +#define AD4691_OSC_FREQ_REG 0x023 +#define AD4691_OSC_FREQ_MASK GENMASK(3, 0) +#define AD4691_STD_SEQ_CONFIG 0x025 +#define AD4691_SEQ_ALL_CHANNELS_OFF 0x00 +#define AD4691_SPARE_CONTROL 0x02A + +#define AD4691_MAX_CHANNELS 16 + +#define AD4691_NOOP 0x00 +#define AD4691_ADC_CHAN(ch) ((0x10 + (ch)) << 3) + +#define AD4691_OSC_EN_REG 0x180 +#define AD4691_STATE_RESET_REG 0x181 +#define AD4691_STATE_RESET_ALL BIT(0) +#define AD4691_ADC_SETUP 0x182 +#define AD4691_ADC_MODE_MASK GENMASK(1, 0) +#define AD4691_CNV_BURST_MODE 0x01 +#define AD4691_AUTONOMOUS_MODE 0x02 +/* + * ACC_MASK_REG covers both mask bytes via ADDR_DESCENDING SPI: writing a + * 16-bit BE value to 0x185 auto-decrements to 0x184 for the second byte. + */ +#define AD4691_ACC_MASK_REG 0x185 +#define AD4691_ACC_DEPTH_IN(n) (0x186 + (n)) +#define AD4691_GPIO_MODE1_REG 0x196 +#define AD4691_GPIO_MODE2_REG 0x197 +#define AD4691_GP_MODE_MASK GENMASK(3, 0) +#define AD4691_GP_MODE_DATA_READY 0x06 +#define AD4691_GPIO_READ 0x1A0 +#define AD4691_ACC_STATUS_FULL1_REG 0x1B0 +#define AD4691_ACC_STATUS_FULL2_REG 0x1B1 +#define AD4691_ACC_STATUS_OVERRUN1_REG 0x1B2 +#define AD4691_ACC_STATUS_OVERRUN2_REG 0x1B3 +#define AD4691_ACC_STATUS_SAT1_REG 0x1B4 +#define AD4691_ACC_STATUS_SAT2_REG 0x1BE +#define AD4691_ACC_SAT_OVR_REG(n) (0x1C0 + (n)) +#define AD4691_AVG_IN(n) (0x201 + (2 * (n))) +#define AD4691_AVG_STS_IN(n) (0x222 + (3 * (n))) +#define AD4691_ACC_IN(n) (0x252 + (3 * (n))) +#define AD4691_ACC_STS_DATA(n) (0x283 + (4 * (n))) + + +static const char * const ad4691_supplies[] = { "avdd", "vio" }; + +enum ad4691_ref_ctrl { + AD4691_VREF_2P5, + AD4691_VREF_3P0, + AD4691_VREF_3P3, + AD4691_VREF_4P096, + AD4691_VREF_5P0 +}; + +struct ad4691_channel_info { + const struct iio_chan_spec *channels __counted_by_ptr(num_channels); + unsigned int num_channels; +}; + +struct ad4691_chip_info { + const char *name; + unsigned int max_rate; + const struct ad4691_channel_info *sw_info; +}; + +#define AD4691_CHANNEL(ch) \ + { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) \ + | BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_shared_by_all_available = \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .channel = ch, \ + .scan_type = { \ + .realbits = 16, \ + }, \ + } + +static const struct iio_chan_spec ad4691_channels[] = { + AD4691_CHANNEL(0), + AD4691_CHANNEL(1), + AD4691_CHANNEL(2), + AD4691_CHANNEL(3), + AD4691_CHANNEL(4), + AD4691_CHANNEL(5), + AD4691_CHANNEL(6), + AD4691_CHANNEL(7), + AD4691_CHANNEL(8), + AD4691_CHANNEL(9), + AD4691_CHANNEL(10), + AD4691_CHANNEL(11), + AD4691_CHANNEL(12), + AD4691_CHANNEL(13), + AD4691_CHANNEL(14), + AD4691_CHANNEL(15), +}; + +static const struct iio_chan_spec ad4693_channels[] = { + AD4691_CHANNEL(0), + AD4691_CHANNEL(1), + AD4691_CHANNEL(2), + AD4691_CHANNEL(3), + AD4691_CHANNEL(4), + AD4691_CHANNEL(5), + AD4691_CHANNEL(6), + AD4691_CHANNEL(7), +}; + +static const struct ad4691_channel_info ad4691_sw_info = { + .channels = ad4691_channels, + .num_channels = ARRAY_SIZE(ad4691_channels), +}; + +static const struct ad4691_channel_info ad4693_sw_info = { + .channels = ad4693_channels, + .num_channels = ARRAY_SIZE(ad4693_channels), +}; + +/* + * Internal oscillator frequency table. Index is the OSC_FREQ_REG[3:0] value. + * Index 0 (1 MHz) is only valid for AD4692/AD4694; AD4691/AD4693 support + * up to 500 kHz and use index 1 as their highest valid rate. + */ +static const int ad4691_osc_freqs_Hz[] = { + [0x0] = 1000000, + [0x1] = 500000, + [0x2] = 400000, + [0x3] = 250000, + [0x4] = 200000, + [0x5] = 167000, + [0x6] = 133000, + [0x7] = 125000, + [0x8] = 100000, + [0x9] = 50000, + [0xA] = 25000, + [0xB] = 12500, + [0xC] = 10000, + [0xD] = 5000, + [0xE] = 2500, + [0xF] = 1250, +}; + +static const struct ad4691_chip_info ad4691_chip_info = { + .name = "ad4691", + .max_rate = 500 * HZ_PER_KHZ, + .sw_info = &ad4691_sw_info, +}; + +static const struct ad4691_chip_info ad4692_chip_info = { + .name = "ad4692", + .max_rate = 1 * HZ_PER_MHZ, + .sw_info = &ad4691_sw_info, +}; + +static const struct ad4691_chip_info ad4693_chip_info = { + .name = "ad4693", + .max_rate = 500 * HZ_PER_KHZ, + .sw_info = &ad4693_sw_info, +}; + +static const struct ad4691_chip_info ad4694_chip_info = { + .name = "ad4694", + .max_rate = 1 * HZ_PER_MHZ, + .sw_info = &ad4693_sw_info, +}; + +struct ad4691_state { + const struct ad4691_chip_info *info; + struct regmap *regmap; + struct spi_device *spi; + + int vref_uV; + + bool refbuf_en; + bool ldo_en; + /* + * Synchronize access to members of the driver state, and ensure + * atomicity of consecutive SPI operations. + */ + struct mutex lock; +}; + +static int ad4691_reg_read(void *context, unsigned int reg, unsigned int *val) +{ + struct spi_device *spi = context; + u8 tx[2], rx[4]; + int ret; + + /* Set bit 15 to mark the operation as READ. */ + put_unaligned_be16(0x8000 | reg, tx); + + switch (reg) { + case 0 ... AD4691_OSC_FREQ_REG: + case AD4691_SPARE_CONTROL ... AD4691_ACC_MASK_REG - 1: + case AD4691_ACC_MASK_REG + 1 ... AD4691_ACC_SAT_OVR_REG(15): + ret = spi_write_then_read(spi, tx, sizeof(tx), rx, 1); + if (ret) + return ret; + *val = rx[0]; + return 0; + case AD4691_ACC_MASK_REG: + case AD4691_STD_SEQ_CONFIG: + case AD4691_AVG_IN(0) ... AD4691_AVG_IN(15): + ret = spi_write_then_read(spi, tx, sizeof(tx), rx, 2); + if (ret) + return ret; + *val = get_unaligned_be16(rx); + return 0; + case AD4691_AVG_STS_IN(0) ... AD4691_AVG_STS_IN(15): + case AD4691_ACC_IN(0) ... AD4691_ACC_IN(15): + ret = spi_write_then_read(spi, tx, sizeof(tx), rx, 3); + if (ret) + return ret; + *val = get_unaligned_be24(rx); + return 0; + case AD4691_ACC_STS_DATA(0) ... AD4691_ACC_STS_DATA(15): + ret = spi_write_then_read(spi, tx, sizeof(tx), rx, 4); + if (ret) + return ret; + *val = get_unaligned_be32(rx); + return 0; + default: + return -EINVAL; + } +} + +static int ad4691_reg_write(void *context, unsigned int reg, unsigned int val) +{ + struct spi_device *spi = context; + u8 tx[4]; + + put_unaligned_be16(reg, tx); + + switch (reg) { + case 0 ... AD4691_OSC_FREQ_REG: + case AD4691_SPARE_CONTROL ... AD4691_ACC_MASK_REG - 1: + case AD4691_ACC_MASK_REG + 1 ... AD4691_GPIO_MODE2_REG: + if (val > U8_MAX) + return -EINVAL; + tx[2] = val; + return spi_write_then_read(spi, tx, 3, NULL, 0); + case AD4691_ACC_MASK_REG: + case AD4691_STD_SEQ_CONFIG: + if (val > U16_MAX) + return -EINVAL; + put_unaligned_be16(val, &tx[2]); + return spi_write_then_read(spi, tx, 4, NULL, 0); + default: + return -EINVAL; + } +} + +static bool ad4691_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case AD4691_STATUS_REG: + case AD4691_CLAMP_STATUS1_REG: + case AD4691_CLAMP_STATUS2_REG: + case AD4691_GPIO_READ: + case AD4691_ACC_STATUS_FULL1_REG ... AD4691_ACC_STATUS_SAT2_REG: + case AD4691_ACC_SAT_OVR_REG(0) ... AD4691_ACC_SAT_OVR_REG(15): + case AD4691_AVG_IN(0) ... AD4691_AVG_IN(15): + case AD4691_AVG_STS_IN(0) ... AD4691_AVG_STS_IN(15): + case AD4691_ACC_IN(0) ... AD4691_ACC_IN(15): + case AD4691_ACC_STS_DATA(0) ... AD4691_ACC_STS_DATA(15): + return true; + default: + return false; + } +} + +static bool ad4691_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0 ... AD4691_OSC_FREQ_REG: + case AD4691_SPARE_CONTROL ... AD4691_ACC_SAT_OVR_REG(15): + case AD4691_STD_SEQ_CONFIG: + return true; + default: + break; + } + + /* + * Multi-byte result registers have non-unit strides; only the base + * address of each entry is a valid single-register read. + */ + if (reg >= AD4691_AVG_IN(0) && reg <= AD4691_AVG_IN(15)) + return (reg - AD4691_AVG_IN(0)) % 2 == 0; + if (reg >= AD4691_AVG_STS_IN(0) && reg <= AD4691_AVG_STS_IN(15)) + return (reg - AD4691_AVG_STS_IN(0)) % 3 == 0; + if (reg >= AD4691_ACC_IN(0) && reg <= AD4691_ACC_IN(15)) + return (reg - AD4691_ACC_IN(0)) % 3 == 0; + if (reg >= AD4691_ACC_STS_DATA(0) && reg <= AD4691_ACC_STS_DATA(15)) + return (reg - AD4691_ACC_STS_DATA(0)) % 4 == 0; + + return false; +} + +static bool ad4691_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0 ... AD4691_OSC_FREQ_REG: + case AD4691_STD_SEQ_CONFIG: + case AD4691_SPARE_CONTROL ... AD4691_GPIO_MODE2_REG: + return true; + default: + return false; + } +} + +static const struct regmap_config ad4691_regmap_config = { + .reg_bits = 16, + .val_bits = 32, + .reg_read = ad4691_reg_read, + .reg_write = ad4691_reg_write, + .volatile_reg = ad4691_volatile_reg, + .readable_reg = ad4691_readable_reg, + .writeable_reg = ad4691_writeable_reg, + .max_register = AD4691_ACC_STS_DATA(15), + .cache_type = REGCACHE_MAPLE, +}; + +/* + * Index 0 in ad4691_osc_freqs_Hz is 1 MHz — valid only for AD4692/AD4694 + * (max_rate == 1 MHz). AD4691/AD4693 cap at 500 kHz so their valid range + * starts at index 1. + */ +static unsigned int ad4691_samp_freq_start(const struct ad4691_chip_info *info) +{ + return (info->max_rate == 1 * HZ_PER_MHZ) ? 0 : 1; +} + +static int ad4691_get_sampling_freq(struct ad4691_state *st, int *val) +{ + unsigned int reg_val; + int ret; + + guard(mutex)(&st->lock); + + ret = regmap_read(st->regmap, AD4691_OSC_FREQ_REG, ®_val); + if (ret) + return ret; + + *val = ad4691_osc_freqs_Hz[FIELD_GET(AD4691_OSC_FREQ_MASK, reg_val)]; + return IIO_VAL_INT; +} + +static int ad4691_set_sampling_freq(struct ad4691_state *st, int freq) +{ + unsigned int start = ad4691_samp_freq_start(st->info); + + guard(mutex)(&st->lock); + + for (unsigned int i = start; i < ARRAY_SIZE(ad4691_osc_freqs_Hz); i++) { + if (ad4691_osc_freqs_Hz[i] != freq) + continue; + return regmap_update_bits(st->regmap, AD4691_OSC_FREQ_REG, + AD4691_OSC_FREQ_MASK, i); + } + + return -EINVAL; +} + +static int ad4691_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, + int *length, long mask) +{ + struct ad4691_state *st = iio_priv(indio_dev); + unsigned int start = ad4691_samp_freq_start(st->info); + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + *vals = &ad4691_osc_freqs_Hz[start]; + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(ad4691_osc_freqs_Hz) - start; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int ad4691_single_shot_read(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val) +{ + struct ad4691_state *st = iio_priv(indio_dev); + unsigned int reg_val, osc_idx, period_us; + int ret; + + guard(mutex)(&st->lock); + + /* Use AUTONOMOUS mode for single-shot reads. */ + ret = regmap_write(st->regmap, AD4691_STATE_RESET_REG, AD4691_STATE_RESET_ALL); + if (ret) + return ret; + + ret = regmap_write(st->regmap, AD4691_STD_SEQ_CONFIG, + BIT(chan->channel)); + if (ret) + return ret; + + ret = regmap_write(st->regmap, AD4691_ACC_MASK_REG, + ~BIT(chan->channel) & GENMASK(15, 0)); + if (ret) + return ret; + + ret = regmap_read(st->regmap, AD4691_OSC_FREQ_REG, ®_val); + if (ret) + return ret; + + ret = regmap_write(st->regmap, AD4691_OSC_EN_REG, 1); + if (ret) + return ret; + + osc_idx = FIELD_GET(AD4691_OSC_FREQ_MASK, reg_val); + /* Wait 2 oscillator periods for the conversion to complete. */ + period_us = DIV_ROUND_UP(2UL * USEC_PER_SEC, ad4691_osc_freqs_Hz[osc_idx]); + fsleep(period_us); + + ret = regmap_write(st->regmap, AD4691_OSC_EN_REG, 0); + if (ret) + return ret; + + ret = regmap_read(st->regmap, AD4691_AVG_IN(chan->channel), ®_val); + if (ret) + return ret; + + *val = reg_val; + + ret = regmap_write(st->regmap, AD4691_STATE_RESET_REG, AD4691_STATE_RESET_ALL); + if (ret) + return ret; + + return IIO_VAL_INT; +} + +static int ad4691_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long info) +{ + struct ad4691_state *st = iio_priv(indio_dev); + + switch (info) { + case IIO_CHAN_INFO_RAW: { + IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim); + if (IIO_DEV_ACQUIRE_FAILED(claim)) + return -EBUSY; + + return ad4691_single_shot_read(indio_dev, chan, val); + } + case IIO_CHAN_INFO_SAMP_FREQ: + return ad4691_get_sampling_freq(st, val); + case IIO_CHAN_INFO_SCALE: + *val = st->vref_uV / (MICRO / MILLI); + *val2 = chan->scan_type.realbits; + return IIO_VAL_FRACTIONAL_LOG2; + default: + return -EINVAL; + } +} + +static int ad4691_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct ad4691_state *st = iio_priv(indio_dev); + + IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim); + if (IIO_DEV_ACQUIRE_FAILED(claim)) + return -EBUSY; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + return ad4691_set_sampling_freq(st, val); + default: + return -EINVAL; + } +} + +static int ad4691_reg_access(struct iio_dev *indio_dev, unsigned int reg, + unsigned int writeval, unsigned int *readval) +{ + struct ad4691_state *st = iio_priv(indio_dev); + + guard(mutex)(&st->lock); + + if (readval) + return regmap_read(st->regmap, reg, readval); + + return regmap_write(st->regmap, reg, writeval); +} + +static const struct iio_info ad4691_info = { + .read_raw = ad4691_read_raw, + .write_raw = ad4691_write_raw, + .read_avail = ad4691_read_avail, + .debugfs_reg_access = ad4691_reg_access, +}; + +static int ad4691_regulator_setup(struct ad4691_state *st) +{ + struct device *dev = regmap_get_device(st->regmap); + int ret; + + ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(ad4691_supplies), + ad4691_supplies); + if (ret) + return dev_err_probe(dev, ret, "Failed to get and enable supplies\n"); + + /* + * vdd-supply and ldo-in-supply are mutually exclusive: + * vdd-supply present → external 1.8V VDD; disable internal LDO. + * vdd-supply absent → enable internal LDO fed from ldo-in-supply. + * Having both simultaneously is strongly inadvisable per the datasheet. + */ + if (device_property_present(dev, "vdd-supply")) { + ret = devm_regulator_get_enable(dev, "vdd"); + if (ret) + return dev_err_probe(dev, ret, + "Failed to get and enable VDD\n"); + } else if (device_property_present(dev, "ldo-in-supply")) { + ret = devm_regulator_get_enable(dev, "ldo-in"); + if (ret) + return dev_err_probe(dev, ret, + "Failed to get and enable LDO-IN\n"); + st->ldo_en = true; + } else { + return dev_err_probe(dev, -EINVAL, + "missing one of vdd-supply, ldo-in-supply\n"); + } + + if (device_property_present(dev, "ref-supply")) { + st->vref_uV = devm_regulator_get_enable_read_voltage(dev, "ref"); + if (st->vref_uV < 0) + return dev_err_probe(dev, st->vref_uV, + "Failed to get REF supply voltage\n"); + } else if (device_property_present(dev, "refin-supply")) { + st->vref_uV = devm_regulator_get_enable_read_voltage(dev, "refin"); + if (st->vref_uV < 0) + return dev_err_probe(dev, st->vref_uV, + "Failed to get REFIN supply voltage\n"); + st->refbuf_en = true; + } else { + return dev_err_probe(dev, -EINVAL, + "missing one of ref-supply, refin-supply\n"); + } + + if (st->vref_uV < AD4691_VREF_uV_MIN || st->vref_uV > AD4691_VREF_uV_MAX) + return dev_err_probe(dev, -EINVAL, + "vref(%d) must be in the range [%u...%u]\n", + st->vref_uV, AD4691_VREF_uV_MIN, + AD4691_VREF_uV_MAX); + + return 0; +} + +static int ad4691_reset(struct ad4691_state *st) +{ + struct device *dev = regmap_get_device(st->regmap); + struct reset_control *rst; + int ret; + + rst = devm_reset_control_get_optional_exclusive(dev, NULL); + if (IS_ERR(rst)) + return dev_err_probe(dev, PTR_ERR(rst), "Failed to get reset\n"); + + if (rst) { + /* + * Assert the reset line to guarantee a clean reset pulse on + * every probe, including driver reloads where the line may + * already be deasserted (reset_control_put() does not + * re-assert on release). tRESETL (minimum pulse width) = 10 ns + * (Table 5); kernel function-call overhead alone exceeds this, + * so no explicit delay is needed between assert and deassert. + */ + reset_control_assert(rst); + ret = reset_control_deassert(rst); + if (ret) + return ret; + } else { + /* No hardware reset available, fall back to software reset. */ + ret = regmap_write(st->regmap, AD4691_SPI_CONFIG_A_REG, + AD4691_SW_RESET); + if (ret) + return ret; + } + + /* + * Wait 300 µs (Table 5) for the device to complete its internal reset + * sequence before accepting SPI commands. + */ + fsleep(300); + return 0; +} + +static int ad4691_config(struct ad4691_state *st) +{ + struct device *dev = regmap_get_device(st->regmap); + enum ad4691_ref_ctrl ref_val; + unsigned int val; + int ret; + + switch (st->vref_uV) { + case AD4691_VREF_uV_MIN ... AD4691_VREF_2P5_uV_MAX: + ref_val = AD4691_VREF_2P5; + break; + case AD4691_VREF_2P5_uV_MAX + 1 ... AD4691_VREF_3P0_uV_MAX: + ref_val = AD4691_VREF_3P0; + break; + case AD4691_VREF_3P0_uV_MAX + 1 ... AD4691_VREF_3P3_uV_MAX: + ref_val = AD4691_VREF_3P3; + break; + case AD4691_VREF_3P3_uV_MAX + 1 ... AD4691_VREF_4P096_uV_MAX: + ref_val = AD4691_VREF_4P096; + break; + case AD4691_VREF_4P096_uV_MAX + 1 ... AD4691_VREF_uV_MAX: + ref_val = AD4691_VREF_5P0; + break; + default: + return dev_err_probe(dev, -EINVAL, + "Unsupported vref voltage: %d uV\n", + st->vref_uV); + } + + val = FIELD_PREP(AD4691_REF_CTRL_MASK, ref_val); + if (st->refbuf_en) + val |= AD4691_REFBUF_EN; + + ret = regmap_write(st->regmap, AD4691_REF_CTRL, val); + if (ret) + return dev_err_probe(dev, ret, "Failed to write REF_CTRL\n"); + + ret = regmap_assign_bits(st->regmap, AD4691_DEVICE_SETUP, + AD4691_LDO_EN, st->ldo_en); + if (ret) + return dev_err_probe(dev, ret, "Failed to write DEVICE_SETUP\n"); + + /* + * Set the internal oscillator to the highest rate this chip supports. + * Index 0 (1 MHz) exceeds the 500 kHz max of AD4691/AD4693, so those + * chips start at index 1 (500 kHz). + */ + ret = regmap_write(st->regmap, AD4691_OSC_FREQ_REG, + ad4691_samp_freq_start(st->info)); + if (ret) + return dev_err_probe(dev, ret, "Failed to write OSC_FREQ\n"); + + ret = regmap_update_bits(st->regmap, AD4691_ADC_SETUP, + AD4691_ADC_MODE_MASK, AD4691_AUTONOMOUS_MODE); + if (ret) + return dev_err_probe(dev, ret, "Failed to write ADC_SETUP\n"); + + return 0; +} + +static int ad4691_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct iio_dev *indio_dev; + struct ad4691_state *st; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + st->spi = spi; + st->info = spi_get_device_match_data(spi); + if (!st->info) + return -ENODEV; + + ret = devm_mutex_init(dev, &st->lock); + if (ret) + return ret; + + st->regmap = devm_regmap_init(dev, NULL, spi, &ad4691_regmap_config); + if (IS_ERR(st->regmap)) + return dev_err_probe(dev, PTR_ERR(st->regmap), + "Failed to initialize regmap\n"); + + ret = ad4691_regulator_setup(st); + if (ret) + return ret; + + ret = ad4691_reset(st); + if (ret) + return ret; + + ret = ad4691_config(st); + if (ret) + return ret; + + indio_dev->name = st->info->name; + indio_dev->info = &ad4691_info; + indio_dev->modes = INDIO_DIRECT_MODE; + + indio_dev->channels = st->info->sw_info->channels; + indio_dev->num_channels = st->info->sw_info->num_channels; + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct of_device_id ad4691_of_match[] = { + { .compatible = "adi,ad4691", .data = &ad4691_chip_info }, + { .compatible = "adi,ad4692", .data = &ad4692_chip_info }, + { .compatible = "adi,ad4693", .data = &ad4693_chip_info }, + { .compatible = "adi,ad4694", .data = &ad4694_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(of, ad4691_of_match); + +static const struct spi_device_id ad4691_id[] = { + { .name = "ad4691", .driver_data = (kernel_ulong_t)&ad4691_chip_info }, + { .name = "ad4692", .driver_data = (kernel_ulong_t)&ad4692_chip_info }, + { .name = "ad4693", .driver_data = (kernel_ulong_t)&ad4693_chip_info }, + { .name = "ad4694", .driver_data = (kernel_ulong_t)&ad4694_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(spi, ad4691_id); + +static struct spi_driver ad4691_driver = { + .driver = { + .name = "ad4691", + .of_match_table = ad4691_of_match, + }, + .probe = ad4691_probe, + .id_table = ad4691_id, +}; +module_spi_driver(ad4691_driver); + +MODULE_AUTHOR("Radu Sabau "); +MODULE_DESCRIPTION("Analog Devices AD4691 Family ADC Driver"); +MODULE_LICENSE("GPL"); From 41297c6bd8dd04c0b23bd7b14e00632cc806688b Mon Sep 17 00:00:00 2001 From: Radu Sabau Date: Fri, 29 May 2026 13:15:02 +0300 Subject: [PATCH 249/266] iio: adc: ad4691: add triggered buffer support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add buffered capture support using the IIO triggered buffer framework. CNV Burst Mode: the GP pin identified by interrupt-names in the device tree is configured as DATA_READY output. The IRQ handler stops conversions and fires the IIO trigger; the trigger handler executes a pre-built SPI message that reads all active channels from the AVG_IN accumulator registers and then resets accumulator state and restarts conversions for the next cycle. Manual Mode: CNV is tied to SPI CS so each transfer simultaneously reads the previous result and starts the next conversion (pipelined N+1 scheme). At preenable time a pre-built, optimised SPI message of N+1 transfers is constructed (N channel reads plus one NOOP to drain the pipeline). The trigger handler executes the message in a single spi_sync() call and collects the results. An external trigger (e.g. iio-trig-hrtimer) is required to drive the trigger at the desired sample rate. Both modes share the same trigger handler and push a complete scan — one big-endian 16-bit (__be16) slot per active channel, densely packed in scan_index order, followed by a timestamp. The CNV Burst Mode sampling frequency (PWM period) is exposed as a buffer-level attribute via IIO_DEVICE_ATTR. Signed-off-by: Radu Sabau Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 2 + drivers/iio/adc/ad4691.c | 574 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 572 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index d07e4d839f25..a0b7a4eaa36e 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -148,6 +148,8 @@ config AD4691 tristate "Analog Devices AD4691 Family ADC Driver" depends on SPI depends on REGULATOR || COMPILE_TEST + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER select REGMAP help Say yes here to build support for Analog Devices AD4691 Family MuxSAR diff --git a/drivers/iio/adc/ad4691.c b/drivers/iio/adc/ad4691.c index e1febf80f21d..0b737cf6d795 100644 --- a/drivers/iio/adc/ad4691.c +++ b/drivers/iio/adc/ad4691.c @@ -11,19 +11,29 @@ #include #include #include +#include +#include #include #include #include #include +#include +#include #include #include #include +#include #include #include #include #include +#include #include +#include +#include +#include +#include #define AD4691_VREF_uV_MIN 2400000 #define AD4691_VREF_uV_MAX 5250000 @@ -57,6 +67,7 @@ #define AD4691_NOOP 0x00 #define AD4691_ADC_CHAN(ch) ((0x10 + (ch)) << 3) +#define AD4691_EXIT_COMMAND 0x5000 #define AD4691_OSC_EN_REG 0x180 #define AD4691_STATE_RESET_REG 0x181 @@ -120,8 +131,12 @@ struct ad4691_chip_info { .info_mask_shared_by_all_available = \ BIT(IIO_CHAN_INFO_SAMP_FREQ), \ .channel = ch, \ + .scan_index = ch, \ .scan_type = { \ + .format = 'u', \ .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_BE, \ }, \ } @@ -142,6 +157,7 @@ static const struct iio_chan_spec ad4691_channels[] = { AD4691_CHANNEL(13), AD4691_CHANNEL(14), AD4691_CHANNEL(15), + IIO_CHAN_SOFT_TIMESTAMP(16), }; static const struct iio_chan_spec ad4693_channels[] = { @@ -153,6 +169,7 @@ static const struct iio_chan_spec ad4693_channels[] = { AD4691_CHANNEL(5), AD4691_CHANNEL(6), AD4691_CHANNEL(7), + IIO_CHAN_SOFT_TIMESTAMP(8), }; static const struct ad4691_channel_info ad4691_sw_info = { @@ -189,6 +206,8 @@ static const int ad4691_osc_freqs_Hz[] = { [0xF] = 1250, }; +static const char * const ad4691_gp_names[] = { "gp0", "gp1", "gp2", "gp3" }; + static const struct ad4691_chip_info ad4691_chip_info = { .name = "ad4691", .max_rate = 500 * HZ_PER_KHZ, @@ -218,8 +237,13 @@ struct ad4691_state { struct regmap *regmap; struct spi_device *spi; + struct pwm_device *conv_trigger; + int irq; int vref_uV; + u32 cnv_period_ns; + bool manual_mode; + bool irq_enabled; bool refbuf_en; bool ldo_en; /* @@ -227,8 +251,56 @@ struct ad4691_state { * atomicity of consecutive SPI operations. */ struct mutex lock; + /* + * Per-buffer-enable lifetime resources: + * Manual Mode - a pre-built SPI message that clocks out N+1 + * transfers in one go. + * CNV Burst Mode - a pre-built SPI message that clocks out 2*N + * transfers in one go. + */ + struct spi_message scan_msg; + /* + * max 16 + 1 NOOP (manual) or 2*16 + 1 state-reset (CNV burst). + */ + struct spi_transfer scan_xfers[34]; + /* + * CNV burst: 16 AVG_IN addresses = 16. Manual: 16 channel cmds + + * 1 NOOP = 17. Stored as native u16; put_unaligned_be16() fills each + * slot so the SPI controller (bits_per_word=8) sends bytes MSB-first. + */ + u16 scan_tx[17] __aligned(IIO_DMA_MINALIGN); + /* + * CNV burst state-reset: 4-byte write [addr_hi, addr_lo, + * STATE_RESET_ALL, OSC_EN=1]. CS is asserted throughout, so + * ADDR_DESCENDING writes byte[3]=1 to OSC_EN_REG (0x180) as a + * deliberate side-write, keeping the oscillator enabled. Shared + * with the offload path (mutually exclusive at probe). + */ + u8 scan_tx_reset[4] __aligned(IIO_DMA_MINALIGN); + /* + * Scan buffer: one BE16 slot per active channel, plus timestamp. + * DMA-aligned because scan_xfers point rx_buf directly into vals[]. + */ + IIO_DECLARE_DMA_BUFFER_WITH_TS(__be16, vals, 16); }; +/* + * Configure the given GP pin (0-3) as DATA_READY output. + * GP0/GP1 → GPIO_MODE1_REG, GP2/GP3 → GPIO_MODE2_REG. + * Even pins occupy bits [3:0], odd pins bits [7:4]. + */ +static int ad4691_gpio_setup(struct ad4691_state *st, unsigned int gp_num) +{ + unsigned int bit_off = gp_num % 2; + unsigned int reg_off = gp_num / 2; + unsigned int shift = 4 * bit_off; + + return regmap_update_bits(st->regmap, + AD4691_GPIO_MODE1_REG + reg_off, + AD4691_GP_MODE_MASK << shift, + AD4691_GP_MODE_DATA_READY << shift); +} + static int ad4691_reg_read(void *context, unsigned int reg, unsigned int *val) { struct spi_device *spi = context; @@ -539,13 +611,411 @@ static int ad4691_reg_access(struct iio_dev *indio_dev, unsigned int reg, return regmap_write(st->regmap, reg, writeval); } -static const struct iio_info ad4691_info = { +static int ad4691_set_pwm_freq(struct ad4691_state *st, unsigned int freq) +{ + if (!freq) + return -EINVAL; + + st->cnv_period_ns = DIV_ROUND_UP(NSEC_PER_SEC, freq); + return 0; +} + +static int ad4691_sampling_enable(struct ad4691_state *st, bool enable) +{ + struct pwm_state conv_state = { + .period = st->cnv_period_ns, + .duty_cycle = AD4691_CNV_DUTY_CYCLE_NS, + .polarity = PWM_POLARITY_NORMAL, + .enabled = enable, + }; + + return pwm_apply_might_sleep(st->conv_trigger, &conv_state); +} + +/* + * ad4691_enter_conversion_mode - Switch the chip to its buffer conversion mode. + * + * Configures the ADC hardware registers for the mode selected at probe + * (CNV_BURST or MANUAL). Called from buffer preenable before starting + * sampling. The chip is in AUTONOMOUS mode during idle (for read_raw). + */ +static int ad4691_enter_conversion_mode(struct ad4691_state *st) +{ + int ret; + + if (st->manual_mode) + return regmap_update_bits(st->regmap, AD4691_DEVICE_SETUP, + AD4691_MANUAL_MODE, AD4691_MANUAL_MODE); + + ret = regmap_update_bits(st->regmap, AD4691_ADC_SETUP, + AD4691_ADC_MODE_MASK, AD4691_CNV_BURST_MODE); + if (ret) + return ret; + + return regmap_write(st->regmap, AD4691_STATE_RESET_REG, + AD4691_STATE_RESET_ALL); +} + +static int ad4691_transfer(struct ad4691_state *st, u16 cmd) +{ + u8 buf[2]; + + put_unaligned_be16(cmd, buf); + + return spi_write_then_read(st->spi, buf, sizeof(buf), NULL, 0); +} + +/* + * ad4691_exit_conversion_mode - Return the chip to AUTONOMOUS mode. + * + * Called from buffer postdisable to restore the chip to the + * idle state used by read_raw. Clears the sequencer and resets state. + */ +static int ad4691_exit_conversion_mode(struct ad4691_state *st) +{ + if (st->manual_mode) + return ad4691_transfer(st, AD4691_EXIT_COMMAND); + + return regmap_update_bits(st->regmap, AD4691_ADC_SETUP, + AD4691_ADC_MODE_MASK, AD4691_AUTONOMOUS_MODE); +} + +static int ad4691_manual_buffer_preenable(struct iio_dev *indio_dev) +{ + struct ad4691_state *st = iio_priv(indio_dev); + unsigned int k, i; + int ret; + + memset(st->scan_xfers, 0, sizeof(st->scan_xfers)); + memset(st->scan_tx, 0, sizeof(st->scan_tx)); + + spi_message_init(&st->scan_msg); + + k = 0; + iio_for_each_active_channel(indio_dev, i) { + /* + * Channel-select command occupies the first (high) byte of the + * 16-bit DIN frame; the second byte is a don't-care zero pad. + * put_unaligned_be16() writes [cmd, 0x00] in memory so the + * SPI controller sends the command byte first on the wire. + */ + put_unaligned_be16((u16)(AD4691_ADC_CHAN(i) << 8), &st->scan_tx[k]); + st->scan_xfers[k].tx_buf = &st->scan_tx[k]; + /* + * The pipeline means xfer[0] receives the residual from the + * previous sequence, not a valid sample. Discard it (rx_buf=NULL) + * to avoid aliasing vals[0] across two concurrent DMA mappings. + * xfer[1] (or the NOOP when only one channel is active) writes + * the real ch[0] result to vals[0]. Subsequent transfers write + * into vals[k-1] so each result lands at the next dense slot. + */ + st->scan_xfers[k].rx_buf = (k == 0) ? NULL : &st->vals[k - 1]; + st->scan_xfers[k].len = sizeof(*st->scan_tx); + st->scan_xfers[k].cs_change = 1; + st->scan_xfers[k].cs_change_delay.value = AD4691_CNV_HIGH_TIME_NS; + st->scan_xfers[k].cs_change_delay.unit = SPI_DELAY_UNIT_NSECS; + spi_message_add_tail(&st->scan_xfers[k], &st->scan_msg); + k++; + } + + /* Final NOOP transfer retrieves the last channel's result. */ + st->scan_xfers[k].tx_buf = &st->scan_tx[k]; /* scan_tx[k] == 0 == NOOP */ + st->scan_xfers[k].rx_buf = &st->vals[k - 1]; + st->scan_xfers[k].len = sizeof(*st->scan_tx); + spi_message_add_tail(&st->scan_xfers[k], &st->scan_msg); + + ret = spi_optimize_message(st->spi, &st->scan_msg); + if (ret) + return ret; + + ret = ad4691_enter_conversion_mode(st); + if (ret) { + spi_unoptimize_message(&st->scan_msg); + return ret; + } + + return 0; +} + +static int ad4691_manual_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct ad4691_state *st = iio_priv(indio_dev); + int ret; + + ret = ad4691_exit_conversion_mode(st); + spi_unoptimize_message(&st->scan_msg); + return ret; +} + +static const struct iio_buffer_setup_ops ad4691_manual_buffer_setup_ops = { + .preenable = ad4691_manual_buffer_preenable, + .postdisable = ad4691_manual_buffer_postdisable, +}; + +static int ad4691_cnv_burst_buffer_preenable(struct iio_dev *indio_dev) +{ + struct ad4691_state *st = iio_priv(indio_dev); + unsigned int acc_mask, std_seq_config; + unsigned int k, i; + int ret; + + memset(st->scan_xfers, 0, sizeof(st->scan_xfers)); + memset(st->scan_tx, 0, sizeof(st->scan_tx)); + + spi_message_init(&st->scan_msg); + + /* + * Each AVG_IN read needs two transfers: a 2-byte address write phase + * followed by a 2-byte data read phase. CS toggles between channels + * (cs_change=1 on the read phase of all but the last channel). + */ + k = 0; + iio_for_each_active_channel(indio_dev, i) { + put_unaligned_be16(0x8000 | AD4691_AVG_IN(i), &st->scan_tx[k]); + st->scan_xfers[2 * k].tx_buf = &st->scan_tx[k]; + st->scan_xfers[2 * k].len = sizeof(*st->scan_tx); + spi_message_add_tail(&st->scan_xfers[2 * k], &st->scan_msg); + st->scan_xfers[2 * k + 1].rx_buf = &st->vals[k]; + st->scan_xfers[2 * k + 1].len = sizeof(*st->scan_tx); + st->scan_xfers[2 * k + 1].cs_change = 1; + spi_message_add_tail(&st->scan_xfers[2 * k + 1], &st->scan_msg); + k++; + } + + /* + * Append a 4-byte state-reset transfer [addr_hi, addr_lo, + * STATE_RESET_ALL, OSC_EN=1]. CS is asserted throughout, so + * ADDR_DESCENDING writes byte[3]=1 to OSC_EN_REG (0x180) as a + * deliberate side-write, keeping the oscillator enabled. + * STATE_RESET_ALL starts the next burst; the hardware does not + * accumulate new conversions until after a STATE_RESET pulse, so + * no in-progress data is lost. No cs_change here — CS must + * deassert normally at end of message to frame the next command. + */ + put_unaligned_be16(AD4691_STATE_RESET_REG, st->scan_tx_reset); + st->scan_tx_reset[2] = AD4691_STATE_RESET_ALL; + st->scan_tx_reset[3] = 1; + st->scan_xfers[2 * k].tx_buf = st->scan_tx_reset; + st->scan_xfers[2 * k].len = sizeof(st->scan_tx_reset); + spi_message_add_tail(&st->scan_xfers[2 * k], &st->scan_msg); + + ret = spi_optimize_message(st->spi, &st->scan_msg); + if (ret) + return ret; + + std_seq_config = bitmap_read(indio_dev->active_scan_mask, 0, + iio_get_masklength(indio_dev)) & GENMASK(15, 0); + ret = regmap_write(st->regmap, AD4691_STD_SEQ_CONFIG, std_seq_config); + if (ret) + goto err_unoptimize; + + acc_mask = ~std_seq_config & GENMASK(15, 0); + ret = regmap_write(st->regmap, AD4691_ACC_MASK_REG, acc_mask); + if (ret) + goto err_unoptimize; + + ret = ad4691_enter_conversion_mode(st); + if (ret) + goto err_unoptimize; + + return 0; + +err_unoptimize: + spi_unoptimize_message(&st->scan_msg); + return ret; +} + +static int ad4691_cnv_burst_buffer_postenable(struct iio_dev *indio_dev) +{ + struct ad4691_state *st = iio_priv(indio_dev); + int ret; + + /* + * Start the PWM and unmask the IRQ here in postenable, not in + * preenable. The IIO core attaches the trigger poll function between + * preenable and postenable; enabling sampling or unmasking the IRQ + * before that point risks a DATA_READY assertion landing before the + * poll function is registered. iio_trigger_poll() would drop the + * event, disable_irq_nosync() would fire, and enable_irq() would + * never be called, leaving the IRQ permanently masked. + */ + ret = ad4691_sampling_enable(st, true); + if (ret) + return ret; + + enable_irq(st->irq); + st->irq_enabled = true; + return 0; +} + +static int ad4691_cnv_burst_buffer_predisable(struct iio_dev *indio_dev) +{ + struct ad4691_state *st = iio_priv(indio_dev); + + if (st->irq_enabled) { + disable_irq(st->irq); + st->irq_enabled = false; + } + return ad4691_sampling_enable(st, false); +} + +static int ad4691_cnv_burst_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct ad4691_state *st = iio_priv(indio_dev); + int ret; + + ret = ad4691_exit_conversion_mode(st); + spi_unoptimize_message(&st->scan_msg); + return ret; +} + +static const struct iio_buffer_setup_ops ad4691_cnv_burst_buffer_setup_ops = { + .preenable = ad4691_cnv_burst_buffer_preenable, + .postenable = ad4691_cnv_burst_buffer_postenable, + .predisable = ad4691_cnv_burst_buffer_predisable, + .postdisable = ad4691_cnv_burst_buffer_postdisable, +}; + +static ssize_t sampling_frequency_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct ad4691_state *st = iio_priv(indio_dev); + + return sysfs_emit(buf, "%lu\n", NSEC_PER_SEC / st->cnv_period_ns); +} + +static ssize_t sampling_frequency_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct ad4691_state *st = iio_priv(indio_dev); + unsigned int freq; + int ret; + + ret = kstrtouint(buf, 10, &freq); + if (ret) + return ret; + + IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim); + if (IIO_DEV_ACQUIRE_FAILED(claim)) + return -EBUSY; + + ret = ad4691_set_pwm_freq(st, freq); + if (ret) + return ret; + + return len; +} + +static IIO_DEVICE_ATTR_RW(sampling_frequency, 0); + +static const struct iio_dev_attr *ad4691_buffer_attrs[] = { + &iio_dev_attr_sampling_frequency, + NULL +}; + +static irqreturn_t ad4691_irq(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct ad4691_state *st = iio_priv(indio_dev); + + /* + * Disable the IRQ before calling iio_trigger_poll(). The IRQ is + * re-enabled via the trigger .reenable callback, which the IIO core + * calls inside iio_trigger_notify_done() once use_count reaches zero. + * Re-enabling here (before notify_done) would race: a DATA_READY + * between enable_irq() and notify_done() calls iio_trigger_poll() + * while use_count > 0, dropping the event and permanently masking + * the IRQ. + */ + disable_irq_nosync(st->irq); + iio_trigger_poll(indio_dev->trig); + + return IRQ_HANDLED; +} + +static void ad4691_trigger_reenable(struct iio_trigger *trig) +{ + struct ad4691_state *st = iio_trigger_get_drvdata(trig); + + enable_irq(st->irq); +} + +static const struct iio_trigger_ops ad4691_trigger_ops = { + .reenable = ad4691_trigger_reenable, + .validate_device = iio_trigger_validate_own_device, +}; + +static void ad4691_read_scan(struct iio_dev *indio_dev, s64 ts) +{ + struct ad4691_state *st = iio_priv(indio_dev); + int ret; + + guard(mutex)(&st->lock); + + ret = spi_sync(st->spi, &st->scan_msg); + if (ret) { + dev_err_ratelimited(regmap_get_device(st->regmap), + "SPI scan failed: %d\n", ret); + return; + } + + /* + * rx_buf pointers in scan_xfers point directly into scan.vals, so no + * copy is needed. The scan_msg already includes a STATE_RESET at the + * end (appended in preenable), so no explicit reset is needed here. + */ + iio_push_to_buffers_with_ts(indio_dev, st->vals, sizeof(st->vals), ts); +} + +static irqreturn_t ad4691_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + + ad4691_read_scan(indio_dev, pf->timestamp); + iio_trigger_notify_done(indio_dev->trig); + return IRQ_HANDLED; +} + +/* + * CNV burst mode: only allow our own trigger (driven by DATA_READY IRQ). + * Manual mode: external triggers (e.g. iio-trig-hrtimer) must be allowed + * because manual mode has no DATA_READY IRQ to fire the internal trigger. + * iio_trigger_ops.validate_device = iio_trigger_validate_own_device is + * correct in both modes — it prevents other devices from hijacking our + * internal trigger; the distinction here is only for iio_info.validate_trigger. + */ +static const struct iio_info ad4691_cnv_burst_info = { + .read_raw = ad4691_read_raw, + .write_raw = ad4691_write_raw, + .read_avail = ad4691_read_avail, + .debugfs_reg_access = ad4691_reg_access, + .validate_trigger = iio_validate_own_trigger, +}; + +static const struct iio_info ad4691_manual_info = { .read_raw = ad4691_read_raw, .write_raw = ad4691_write_raw, .read_avail = ad4691_read_avail, .debugfs_reg_access = ad4691_reg_access, }; +static int ad4691_pwm_setup(struct ad4691_state *st) +{ + struct device *dev = regmap_get_device(st->regmap); + + st->conv_trigger = devm_pwm_get(dev, "cnv"); + if (IS_ERR(st->conv_trigger)) + return dev_err_probe(dev, PTR_ERR(st->conv_trigger), + "Failed to get CNV PWM\n"); + + return ad4691_set_pwm_freq(st, st->info->max_rate); +} + static int ad4691_regulator_setup(struct ad4691_state *st) { struct device *dev = regmap_get_device(st->regmap); @@ -649,6 +1119,22 @@ static int ad4691_config(struct ad4691_state *st) unsigned int val; int ret; + /* + * Determine buffer conversion mode from DT: if a PWM is provided it + * drives the CNV pin (CNV_BURST_MODE); otherwise CNV is tied to CS + * and each SPI transfer triggers a conversion (MANUAL_MODE). + * Both modes idle in AUTONOMOUS mode so that read_raw can use the + * internal oscillator without disturbing the hardware configuration. + */ + if (device_property_present(dev, "pwms")) { + st->manual_mode = false; + ret = ad4691_pwm_setup(st); + if (ret) + return ret; + } else { + st->manual_mode = true; + } + switch (st->vref_uV) { case AD4691_VREF_uV_MIN ... AD4691_VREF_2P5_uV_MAX: ref_val = AD4691_VREF_2P5; @@ -702,6 +1188,86 @@ static int ad4691_config(struct ad4691_state *st) return 0; } +static int ad4691_setup_triggered_buffer(struct iio_dev *indio_dev, + struct ad4691_state *st) +{ + struct device *dev = regmap_get_device(st->regmap); + struct iio_trigger *trig; + unsigned int i; + int irq, ret; + + indio_dev->channels = st->info->sw_info->channels; + indio_dev->num_channels = st->info->sw_info->num_channels; + indio_dev->info = st->manual_mode ? &ad4691_manual_info : &ad4691_cnv_burst_info; + + /* + * Manual mode relies on an external trigger (e.g. iio-trig-hrtimer); + * no internal trigger is needed or registered. + */ + if (st->manual_mode) + return devm_iio_triggered_buffer_setup(dev, indio_dev, + iio_pollfunc_store_time, + ad4691_trigger_handler, + &ad4691_manual_buffer_setup_ops); + + /* + * CNV burst mode: allocate an internal trigger driven by the + * DATA_READY IRQ on the GP pin. + */ + trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, + iio_device_id(indio_dev)); + if (!trig) + return -ENOMEM; + + trig->ops = &ad4691_trigger_ops; + iio_trigger_set_drvdata(trig, st); + + ret = devm_iio_trigger_register(dev, trig); + if (ret) + return dev_err_probe(dev, ret, "IIO trigger register failed\n"); + + indio_dev->trig = iio_trigger_get(trig); + + /* + * The GP pin named in interrupt-names asserts at end-of-conversion. + * The IRQ handler fires the IIO trigger so the trigger handler can + * read and push the sample to the buffer. The IRQ is kept disabled + * until the buffer is enabled. + */ + irq = -ENXIO; + for (i = 0; i < ARRAY_SIZE(ad4691_gp_names); i++) { + irq = fwnode_irq_get_byname(dev_fwnode(dev), + ad4691_gp_names[i]); + if (irq > 0 || irq == -EPROBE_DEFER) + break; + } + if (irq < 0) + return dev_err_probe(dev, irq, "failed to get GP interrupt\n"); + + st->irq = irq; + + ret = ad4691_gpio_setup(st, i); + if (ret) + return ret; + + /* + * The handler only calls disable_irq_nosync() and iio_trigger_poll(), + * both safe in hardirq context, so register as a hard IRQ handler. + * IRQF_NO_AUTOEN keeps it disabled until the buffer is enabled. + */ + ret = devm_request_irq(dev, irq, ad4691_irq, IRQF_NO_AUTOEN, + indio_dev->name, indio_dev); + if (ret) + return ret; + + return devm_iio_triggered_buffer_setup_ext(dev, indio_dev, + iio_pollfunc_store_time, + ad4691_trigger_handler, + IIO_BUFFER_DIRECTION_IN, + &ad4691_cnv_burst_buffer_setup_ops, + ad4691_buffer_attrs); +} + static int ad4691_probe(struct spi_device *spi) { struct device *dev = &spi->dev; @@ -741,11 +1307,11 @@ static int ad4691_probe(struct spi_device *spi) return ret; indio_dev->name = st->info->name; - indio_dev->info = &ad4691_info; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = st->info->sw_info->channels; - indio_dev->num_channels = st->info->sw_info->num_channels; + ret = ad4691_setup_triggered_buffer(indio_dev, st); + if (ret) + return ret; return devm_iio_device_register(dev, indio_dev); } From ad4f8513aa4ab949bb2986d64720a0b56f882cbc Mon Sep 17 00:00:00 2001 From: Radu Sabau Date: Fri, 29 May 2026 13:15:03 +0300 Subject: [PATCH 250/266] iio: adc: ad4691: add SPI offload support Add SPI offload support to enable DMA-based, CPU-independent data acquisition using the SPI Engine offload framework. When an SPI offload is available (devm_spi_offload_get() succeeds), the driver registers a DMA engine IIO buffer and uses dedicated buffer setup operations. If no offload is available the existing software triggered buffer path is used unchanged. Both CNV Burst Mode and Manual Mode support offload, but use different trigger mechanisms: CNV Burst Mode: the SPI Engine is triggered by the ADC's DATA_READY signal on the GP pin specified by the trigger-source consumer reference in the device tree (one cell = GP pin number 0-3). For this mode the driver acts as both an SPI offload consumer (DMA RX stream, message optimization) and a trigger source provider: it registers the GP/DATA_READY output via devm_spi_offload_trigger_register() so the offload framework can match the '#trigger-source-cells' phandle and automatically fire the SPI Engine DMA transfer at end-of-conversion. Manual Mode: the SPI Engine is triggered by a periodic trigger at the configured sampling frequency. The pre-built SPI message uses the pipelined CNV-on-CS protocol: N+1 16-bit transfers are issued for N active channels (the first result is discarded as garbage from the pipeline flush) and the remaining N results are captured by DMA. All offload transfers use 16-bit frames (bits_per_word=16, len=2). The SPI Engine assembles received bits into native 16-bit words before DMA, so offload samples land in CPU-native byte order (IIO_CPU). Dedicated channel arrays (AD4691_OFFLOAD_CHANNEL) reflect this: they omit IIO_BE and carry no soft timestamp (DMA delivers data directly to userspace). The software triggered-buffer path retains its IIO_BE channels because bits_per_word=8 causes SPI to deliver bytes MSB-first into memory, making the on-disk layout big-endian. Both paths use storagebits=16 as transfers are 16 bits wide in both cases. IIO_BUFFER_DMAENGINE is selected because the offload path uses devm_iio_dmaengine_buffer_setup_with_handle() to allocate and attach the DMA RX buffer to the IIO device. Signed-off-by: Radu Sabau Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 2 + drivers/iio/adc/ad4691.c | 444 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 443 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index a0b7a4eaa36e..a3a93a47b43d 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -149,8 +149,10 @@ config AD4691 depends on SPI depends on REGULATOR || COMPILE_TEST select IIO_BUFFER + select IIO_BUFFER_DMAENGINE select IIO_TRIGGERED_BUFFER select REGMAP + select SPI_OFFLOAD help Say yes here to build support for Analog Devices AD4691 Family MuxSAR SPI analog to digital converters (ADC). diff --git a/drivers/iio/adc/ad4691.c b/drivers/iio/adc/ad4691.c index 0b737cf6d795..aa4263fa17bf 100644 --- a/drivers/iio/adc/ad4691.c +++ b/drivers/iio/adc/ad4691.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -24,11 +25,15 @@ #include #include #include +#include +#include #include #include #include #include +#include +#include #include #include #include @@ -44,6 +49,11 @@ #define AD4691_CNV_DUTY_CYCLE_NS 380 #define AD4691_CNV_HIGH_TIME_NS 430 +/* + * Conservative default for the manual offload periodic trigger. Low enough + * to work safely out of the box across all OSR and channel count combinations. + */ +#define AD4691_OFFLOAD_INITIAL_TRIGGER_HZ (100 * HZ_PER_KHZ) #define AD4691_SPI_CONFIG_A_REG 0x000 #define AD4691_SW_RESET (BIT(7) | BIT(0)) @@ -119,6 +129,7 @@ struct ad4691_chip_info { const char *name; unsigned int max_rate; const struct ad4691_channel_info *sw_info; + const struct ad4691_channel_info *offload_info; }; #define AD4691_CHANNEL(ch) \ @@ -140,6 +151,30 @@ struct ad4691_chip_info { }, \ } +/* + * Offload path (bits_per_word=16): the SPI Engine assembles received + * bits into native 16-bit words before DMA, so samples are in + * CPU-native byte order (IIO_CPU). storagebits=16 matches the 16-bit + * DMA word size. + */ +#define AD4691_OFFLOAD_CHANNEL(ch) \ + { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) \ + | BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_shared_by_all_available = \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .channel = ch, \ + .scan_index = ch, \ + .scan_type = { \ + .format = 'u', \ + .realbits = 16, \ + .storagebits = 16, \ + }, \ + } + static const struct iio_chan_spec ad4691_channels[] = { AD4691_CHANNEL(0), AD4691_CHANNEL(1), @@ -172,6 +207,40 @@ static const struct iio_chan_spec ad4693_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(8), }; +/* + * Offload channel arrays: no IIO_CHAN_SOFT_TIMESTAMP because DMA delivers + * data directly to userspace without a software timestamp. + */ +static const struct iio_chan_spec ad4691_offload_channels[] = { + AD4691_OFFLOAD_CHANNEL(0), + AD4691_OFFLOAD_CHANNEL(1), + AD4691_OFFLOAD_CHANNEL(2), + AD4691_OFFLOAD_CHANNEL(3), + AD4691_OFFLOAD_CHANNEL(4), + AD4691_OFFLOAD_CHANNEL(5), + AD4691_OFFLOAD_CHANNEL(6), + AD4691_OFFLOAD_CHANNEL(7), + AD4691_OFFLOAD_CHANNEL(8), + AD4691_OFFLOAD_CHANNEL(9), + AD4691_OFFLOAD_CHANNEL(10), + AD4691_OFFLOAD_CHANNEL(11), + AD4691_OFFLOAD_CHANNEL(12), + AD4691_OFFLOAD_CHANNEL(13), + AD4691_OFFLOAD_CHANNEL(14), + AD4691_OFFLOAD_CHANNEL(15), +}; + +static const struct iio_chan_spec ad4693_offload_channels[] = { + AD4691_OFFLOAD_CHANNEL(0), + AD4691_OFFLOAD_CHANNEL(1), + AD4691_OFFLOAD_CHANNEL(2), + AD4691_OFFLOAD_CHANNEL(3), + AD4691_OFFLOAD_CHANNEL(4), + AD4691_OFFLOAD_CHANNEL(5), + AD4691_OFFLOAD_CHANNEL(6), + AD4691_OFFLOAD_CHANNEL(7), +}; + static const struct ad4691_channel_info ad4691_sw_info = { .channels = ad4691_channels, .num_channels = ARRAY_SIZE(ad4691_channels), @@ -182,6 +251,16 @@ static const struct ad4691_channel_info ad4693_sw_info = { .num_channels = ARRAY_SIZE(ad4693_channels), }; +static const struct ad4691_channel_info ad4691_offload_info = { + .channels = ad4691_offload_channels, + .num_channels = ARRAY_SIZE(ad4691_offload_channels), +}; + +static const struct ad4691_channel_info ad4693_offload_info = { + .channels = ad4693_offload_channels, + .num_channels = ARRAY_SIZE(ad4693_offload_channels), +}; + /* * Internal oscillator frequency table. Index is the OSC_FREQ_REG[3:0] value. * Index 0 (1 MHz) is only valid for AD4692/AD4694; AD4691/AD4693 support @@ -212,24 +291,28 @@ static const struct ad4691_chip_info ad4691_chip_info = { .name = "ad4691", .max_rate = 500 * HZ_PER_KHZ, .sw_info = &ad4691_sw_info, + .offload_info = &ad4691_offload_info, }; static const struct ad4691_chip_info ad4692_chip_info = { .name = "ad4692", .max_rate = 1 * HZ_PER_MHZ, .sw_info = &ad4691_sw_info, + .offload_info = &ad4691_offload_info, }; static const struct ad4691_chip_info ad4693_chip_info = { .name = "ad4693", .max_rate = 500 * HZ_PER_KHZ, .sw_info = &ad4693_sw_info, + .offload_info = &ad4693_offload_info, }; static const struct ad4691_chip_info ad4694_chip_info = { .name = "ad4694", .max_rate = 1 * HZ_PER_MHZ, .sw_info = &ad4693_sw_info, + .offload_info = &ad4693_offload_info, }; struct ad4691_state { @@ -251,6 +334,10 @@ struct ad4691_state { * atomicity of consecutive SPI operations. */ struct mutex lock; + /* NULL when no SPI offload hardware is present. */ + struct spi_offload *offload; + struct spi_offload_trigger *offload_trigger; + u64 trigger_hz; /* * Per-buffer-enable lifetime resources: * Manual Mode - a pre-built SPI message that clocks out N+1 @@ -265,8 +352,11 @@ struct ad4691_state { struct spi_transfer scan_xfers[34]; /* * CNV burst: 16 AVG_IN addresses = 16. Manual: 16 channel cmds + - * 1 NOOP = 17. Stored as native u16; put_unaligned_be16() fills each - * slot so the SPI controller (bits_per_word=8) sends bytes MSB-first. + * 1 NOOP = 17. Stored as native u16. The non-offload path fills slots + * with put_unaligned_be16() (bits_per_word=8, bytes go out in memory + * order). The offload path assigns native values directly + * (bits_per_word=bpw, SPI reads each slot as a native 16-bit word and + * shifts it out MSB-first). */ u16 scan_tx[17] __aligned(IIO_DMA_MINALIGN); /* @@ -301,6 +391,45 @@ static int ad4691_gpio_setup(struct ad4691_state *st, unsigned int gp_num) AD4691_GP_MODE_DATA_READY << shift); } +static const struct spi_offload_config ad4691_offload_config = { + .capability_flags = SPI_OFFLOAD_CAP_TRIGGER | + SPI_OFFLOAD_CAP_RX_STREAM_DMA, +}; + +static bool ad4691_offload_trigger_match(struct spi_offload_trigger *trigger, + enum spi_offload_trigger_type type, + u64 *args, u32 nargs) +{ + return type == SPI_OFFLOAD_TRIGGER_DATA_READY && nargs == 1 && args[0] <= 3; +} + +static int ad4691_offload_trigger_request(struct spi_offload_trigger *trigger, + enum spi_offload_trigger_type type, + u64 *args, u32 nargs) +{ + struct ad4691_state *st = spi_offload_trigger_get_priv(trigger); + + if (nargs != 1 || args[0] > 3) + return -EINVAL; + + return ad4691_gpio_setup(st, args[0]); +} + +static int ad4691_offload_trigger_validate(struct spi_offload_trigger *trigger, + struct spi_offload_trigger_config *config) +{ + if (config->type != SPI_OFFLOAD_TRIGGER_DATA_READY) + return -EINVAL; + + return 0; +} + +static const struct spi_offload_trigger_ops ad4691_offload_trigger_ops = { + .match = ad4691_offload_trigger_match, + .request = ad4691_offload_trigger_request, + .validate = ad4691_offload_trigger_validate, +}; + static int ad4691_reg_read(void *context, unsigned int reg, unsigned int *val) { struct spi_device *spi = context; @@ -876,6 +1005,218 @@ static const struct iio_buffer_setup_ops ad4691_cnv_burst_buffer_setup_ops = { .postdisable = ad4691_cnv_burst_buffer_postdisable, }; +static int ad4691_manual_offload_buffer_postenable(struct iio_dev *indio_dev) +{ + struct ad4691_state *st = iio_priv(indio_dev); + struct device *dev = regmap_get_device(st->regmap); + struct spi_device *spi = to_spi_device(dev); + struct spi_offload_trigger_config config = { + .type = SPI_OFFLOAD_TRIGGER_PERIODIC, + }; + unsigned int bpw = indio_dev->channels[0].scan_type.realbits; + unsigned int bit, k; + int ret; + + ret = ad4691_enter_conversion_mode(st); + if (ret) + return ret; + + memset(st->scan_xfers, 0, sizeof(st->scan_xfers)); + memset(st->scan_tx, 0, sizeof(st->scan_tx)); + + /* + * N+1 transfers for N channels. Each CS-low period triggers + * a conversion AND returns the previous result (pipelined). + * TX: [AD4691_ADC_CHAN(n), 0x00] + * RX: [data_hi, data_lo] (storagebits=16, shift=0) + * Transfer 0 RX is garbage; transfers 1..N carry real data. + * scan_tx is reused for TX commands (mutually exclusive with the + * non-offload triggered-buffer path). + * + * bits_per_word=bpw: the SPI controller reads tx_buf as a native + * 16-bit word and shifts it out MSB-first. Store the exact 16-bit + * value we want on the wire as a plain native u16 — no endianness + * macro — so the wire bytes are correct on both LE and BE hosts. + * The channel-select command is a single byte; shift it to the MSB + * position so SPI sends it first, with a zero pad in the LSB. + */ + k = 0; + iio_for_each_active_channel(indio_dev, bit) { + st->scan_tx[k] = AD4691_ADC_CHAN(bit) << 8; + st->scan_xfers[k].tx_buf = &st->scan_tx[k]; + st->scan_xfers[k].len = sizeof(*st->scan_tx); + st->scan_xfers[k].bits_per_word = bpw; + st->scan_xfers[k].cs_change = 1; + st->scan_xfers[k].cs_change_delay.value = AD4691_CNV_HIGH_TIME_NS; + st->scan_xfers[k].cs_change_delay.unit = SPI_DELAY_UNIT_NSECS; + /* First transfer RX is garbage — skip it. */ + if (k > 0) + st->scan_xfers[k].offload_flags = SPI_OFFLOAD_XFER_RX_STREAM; + k++; + } + + /* Final NOOP transfer retrieves the last channel's result. */ + st->scan_xfers[k].tx_buf = &st->scan_tx[k]; /* scan_tx[k] == 0 == NOOP */ + st->scan_xfers[k].len = sizeof(*st->scan_tx); + st->scan_xfers[k].bits_per_word = bpw; + st->scan_xfers[k].offload_flags = SPI_OFFLOAD_XFER_RX_STREAM; + k++; + + spi_message_init_with_transfers(&st->scan_msg, st->scan_xfers, k); + st->scan_msg.offload = st->offload; + + ret = spi_optimize_message(spi, &st->scan_msg); + if (ret) + goto err_exit_conversion; + + config.periodic.frequency_hz = st->trigger_hz; + ret = spi_offload_trigger_enable(st->offload, st->offload_trigger, &config); + if (ret) + goto err_unoptimize; + + return 0; + +err_unoptimize: + spi_unoptimize_message(&st->scan_msg); +err_exit_conversion: + ad4691_exit_conversion_mode(st); + return ret; +} + +static int ad4691_manual_offload_buffer_predisable(struct iio_dev *indio_dev) +{ + struct ad4691_state *st = iio_priv(indio_dev); + + spi_offload_trigger_disable(st->offload, st->offload_trigger); + spi_unoptimize_message(&st->scan_msg); + + return ad4691_exit_conversion_mode(st); +} + +static const struct iio_buffer_setup_ops ad4691_manual_offload_buffer_setup_ops = { + .postenable = ad4691_manual_offload_buffer_postenable, + .predisable = ad4691_manual_offload_buffer_predisable, +}; + +static int ad4691_cnv_burst_offload_buffer_postenable(struct iio_dev *indio_dev) +{ + struct ad4691_state *st = iio_priv(indio_dev); + struct device *dev = regmap_get_device(st->regmap); + struct spi_device *spi = to_spi_device(dev); + struct spi_offload_trigger_config config = { + .type = SPI_OFFLOAD_TRIGGER_DATA_READY, + }; + unsigned int bpw = indio_dev->channels[0].scan_type.realbits; + unsigned int acc_mask, std_seq_config; + unsigned int bit, k; + int ret; + + std_seq_config = bitmap_read(indio_dev->active_scan_mask, 0, + iio_get_masklength(indio_dev)) & GENMASK(15, 0); + ret = regmap_write(st->regmap, AD4691_STD_SEQ_CONFIG, std_seq_config); + if (ret) + return ret; + + acc_mask = ~std_seq_config & GENMASK(15, 0); + ret = regmap_write(st->regmap, AD4691_ACC_MASK_REG, acc_mask); + if (ret) + return ret; + + ret = ad4691_enter_conversion_mode(st); + if (ret) + return ret; + + memset(st->scan_xfers, 0, sizeof(st->scan_xfers)); + memset(st->scan_tx, 0, sizeof(st->scan_tx)); + + /* + * Each AVG_IN register read uses two transfers: + * TX: [reg_hi | 0x80, reg_lo] (address phase, CS stays asserted) + * RX: [data_hi, data_lo] (bpw-wide data phase, storagebits=16) + * Both TX and RX use bits_per_word=bpw: the SPI controller reads tx_buf + * as a native 16-bit word and shifts it out MSB-first. Store the exact + * 16-bit wire value as a plain native u16 — no endianness macro — so the + * wire bytes are correct on both LE and BE hosts. The read-address + * (0x8000 | reg) is already the 16-bit value we want on the wire. + * scan_tx is reused for TX addresses (mutually exclusive with the + * non-offload triggered-buffer path). + */ + k = 0; + iio_for_each_active_channel(indio_dev, bit) { + st->scan_tx[k] = 0x8000 | AD4691_AVG_IN(bit); + + /* TX: address phase, CS stays asserted into data phase */ + st->scan_xfers[2 * k].tx_buf = &st->scan_tx[k]; + st->scan_xfers[2 * k].len = sizeof(*st->scan_tx); + st->scan_xfers[2 * k].bits_per_word = bpw; + + /* RX: data phase, CS toggles after to delimit the next register op */ + st->scan_xfers[2 * k + 1].len = sizeof(*st->scan_tx); + st->scan_xfers[2 * k + 1].bits_per_word = bpw; + st->scan_xfers[2 * k + 1].offload_flags = SPI_OFFLOAD_XFER_RX_STREAM; + st->scan_xfers[2 * k + 1].cs_change = 1; + k++; + } + + /* + * State reset: single 4-byte write [addr_hi, addr_lo, STATE_RESET_ALL, + * OSC_EN=1]. ADDR_DESCENDING writes byte[3]=1 to OSC_EN_REG (0x180) as + * a deliberate side-write, keeping the oscillator enabled. + * scan_tx_reset is shared with the non-offload path (len=4 here vs + * len=3 there) since the two paths are mutually exclusive at probe. + */ + put_unaligned_be16(AD4691_STATE_RESET_REG, st->scan_tx_reset); + st->scan_tx_reset[2] = AD4691_STATE_RESET_ALL; + st->scan_tx_reset[3] = 1; + st->scan_xfers[2 * k].tx_buf = st->scan_tx_reset; + st->scan_xfers[2 * k].len = sizeof(st->scan_tx_reset); + /* + * 4-byte u8 buffer assembled with put_unaligned_be16(); leave + * bits_per_word at the default (8) so bytes go out in memory order. + */ + + spi_message_init_with_transfers(&st->scan_msg, st->scan_xfers, 2 * k + 1); + st->scan_msg.offload = st->offload; + + ret = spi_optimize_message(spi, &st->scan_msg); + if (ret) + goto err_exit_conversion; + + ret = spi_offload_trigger_enable(st->offload, st->offload_trigger, &config); + if (ret) + goto err_unoptimize; + + ret = ad4691_sampling_enable(st, true); + if (ret) + goto err_disable_trigger; + + return 0; + +err_disable_trigger: + spi_offload_trigger_disable(st->offload, st->offload_trigger); +err_unoptimize: + spi_unoptimize_message(&st->scan_msg); +err_exit_conversion: + ad4691_exit_conversion_mode(st); + return ret; +} + +static int ad4691_cnv_burst_offload_buffer_predisable(struct iio_dev *indio_dev) +{ + struct ad4691_state *st = iio_priv(indio_dev); + + ad4691_sampling_enable(st, false); + spi_offload_trigger_disable(st->offload, st->offload_trigger); + spi_unoptimize_message(&st->scan_msg); + + return ad4691_exit_conversion_mode(st); +} + +static const struct iio_buffer_setup_ops ad4691_cnv_burst_offload_buffer_setup_ops = { + .postenable = ad4691_cnv_burst_offload_buffer_postenable, + .predisable = ad4691_cnv_burst_offload_buffer_predisable, +}; + static ssize_t sampling_frequency_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -883,6 +1224,9 @@ static ssize_t sampling_frequency_show(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad4691_state *st = iio_priv(indio_dev); + if (st->manual_mode && st->offload) + return sysfs_emit(buf, "%llu\n", READ_ONCE(st->trigger_hz)); + return sysfs_emit(buf, "%lu\n", NSEC_PER_SEC / st->cnv_period_ns); } @@ -903,6 +1247,20 @@ static ssize_t sampling_frequency_store(struct device *dev, if (IIO_DEV_ACQUIRE_FAILED(claim)) return -EBUSY; + if (st->manual_mode && st->offload) { + struct spi_offload_trigger_config config = { + .type = SPI_OFFLOAD_TRIGGER_PERIODIC, + .periodic = { .frequency_hz = freq }, + }; + + ret = spi_offload_trigger_validate(st->offload_trigger, &config); + if (ret) + return ret; + + WRITE_ONCE(st->trigger_hz, config.periodic.frequency_hz); + return len; + } + ret = ad4691_set_pwm_freq(st, freq); if (ret) return ret; @@ -1268,9 +1626,77 @@ static int ad4691_setup_triggered_buffer(struct iio_dev *indio_dev, ad4691_buffer_attrs); } +static int ad4691_setup_offload(struct iio_dev *indio_dev, + struct ad4691_state *st, + struct spi_offload *spi_offload) +{ + struct device *dev = regmap_get_device(st->regmap); + struct dma_chan *rx_dma; + int ret; + + st->offload = spi_offload; + + indio_dev->channels = st->info->offload_info->channels; + indio_dev->num_channels = st->info->offload_info->num_channels; + /* + * Offload path uses DMA directly; no IIO trigger is involved, so + * external triggers are not restricted (no validate_trigger). + */ + indio_dev->info = &ad4691_manual_info; + + if (st->manual_mode) { + st->offload_trigger = + devm_spi_offload_trigger_get(dev, st->offload, + SPI_OFFLOAD_TRIGGER_PERIODIC); + if (IS_ERR(st->offload_trigger)) + return dev_err_probe(dev, PTR_ERR(st->offload_trigger), + "Failed to get periodic offload trigger\n"); + + st->trigger_hz = AD4691_OFFLOAD_INITIAL_TRIGGER_HZ; + } else { + struct spi_offload_trigger_info trigger_info = { + .fwnode = dev_fwnode(dev), + .ops = &ad4691_offload_trigger_ops, + .priv = st, + }; + + ret = devm_spi_offload_trigger_register(dev, &trigger_info); + if (ret) + return dev_err_probe(dev, ret, + "Failed to register offload trigger\n"); + + st->offload_trigger = + devm_spi_offload_trigger_get(dev, st->offload, + SPI_OFFLOAD_TRIGGER_DATA_READY); + if (IS_ERR(st->offload_trigger)) + return dev_err_probe(dev, PTR_ERR(st->offload_trigger), + "Failed to get DATA_READY offload trigger\n"); + } + + rx_dma = devm_spi_offload_rx_stream_request_dma_chan(dev, st->offload); + if (IS_ERR(rx_dma)) + return dev_err_probe(dev, PTR_ERR(rx_dma), + "Failed to get offload RX DMA channel\n"); + + if (st->manual_mode) + indio_dev->setup_ops = &ad4691_manual_offload_buffer_setup_ops; + else + indio_dev->setup_ops = &ad4691_cnv_burst_offload_buffer_setup_ops; + + ret = devm_iio_dmaengine_buffer_setup_with_handle(dev, indio_dev, rx_dma, + IIO_BUFFER_DIRECTION_IN); + if (ret) + return ret; + + indio_dev->buffer->attrs = ad4691_buffer_attrs; + + return 0; +} + static int ad4691_probe(struct spi_device *spi) { struct device *dev = &spi->dev; + struct spi_offload *spi_offload; struct iio_dev *indio_dev; struct ad4691_state *st; int ret; @@ -1306,10 +1732,20 @@ static int ad4691_probe(struct spi_device *spi) if (ret) return ret; + spi_offload = devm_spi_offload_get(dev, spi, &ad4691_offload_config); + ret = PTR_ERR_OR_ZERO(spi_offload); + if (ret == -ENODEV) + spi_offload = NULL; + else if (ret) + return dev_err_probe(dev, ret, "Failed to get SPI offload\n"); + indio_dev->name = st->info->name; indio_dev->modes = INDIO_DIRECT_MODE; - ret = ad4691_setup_triggered_buffer(indio_dev, st); + if (spi_offload) + ret = ad4691_setup_offload(indio_dev, st, spi_offload); + else + ret = ad4691_setup_triggered_buffer(indio_dev, st); if (ret) return ret; @@ -1347,3 +1783,5 @@ module_spi_driver(ad4691_driver); MODULE_AUTHOR("Radu Sabau "); MODULE_DESCRIPTION("Analog Devices AD4691 Family ADC Driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_DMA_BUFFER"); +MODULE_IMPORT_NS("IIO_DMAENGINE_BUFFER"); From 6d9e7161bfbcce8960e946280fc92e6f5dc70569 Mon Sep 17 00:00:00 2001 From: Radu Sabau Date: Fri, 29 May 2026 13:15:04 +0300 Subject: [PATCH 251/266] iio: adc: ad4691: add oversampling support Add oversampling ratio (OSR) support for CNV burst mode. The accumulator depth register (ACC_DEPTH_IN(0)) is programmed with the selected OSR at buffer enable time and before each single-shot read. Supported OSR values: 1, 2, 4, 8, 16, 32. Introduce AD4691_MANUAL_CHANNEL() for manual mode channels, which do not expose the oversampling_ratio attribute since OSR is not applicable in that mode. A separate manual_channels array is added to struct ad4691_channel_info and selected at probe time. The OSR is shared across all channels (in_voltage_sampling_frequency and in_voltage_oversampling_ratio are info_mask_shared_by_all) because the chip has one internal oscillator and a single accumulator depth register (ACC_DEPTH_IN(0)) for all channels. in_voltage_sampling_frequency represents the effective output rate, defined as osc_freq / osr. Writing it computes needed_osc = freq * osr and snaps down to the largest oscillator table entry that satisfies both osc <= needed_osc and osc % osr == 0, guaranteeing an exact integer read-back. The result is stored in target_osc_freq_Hz and written to OSC_FREQ_REG at buffer enable and single-shot time, so sampling_frequency and oversampling_ratio can be set in any order. in_voltage_sampling_frequency_available is precomputed at probe for each OSR value, listing only oscillator table entries that divide evenly by that OSR, expressed as effective rates (osc_freq / osr). The list becomes sparser as OSR increases, capping at max_rate / osr. read_avail picks the precomputed list for the current OSR, making the returned pointer stable and race-free. Writing oversampling_ratio stores the new shared OSR and snaps target_osc_freq_Hz to the largest oscillator table entry that is both <= old_effective_rate * new_osr and evenly divisible by new_osr. This preserves an integer read-back of in_voltage_sampling_frequency after the OSR change while keeping the oscillator as close as possible to the previous effective rate. OSR defaults to 1 (no accumulation). Signed-off-by: Radu Sabau Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad4691.c | 357 +++++++++++++++++++++++++++++++++++---- 1 file changed, 327 insertions(+), 30 deletions(-) diff --git a/drivers/iio/adc/ad4691.c b/drivers/iio/adc/ad4691.c index aa4263fa17bf..548678adc2a4 100644 --- a/drivers/iio/adc/ad4691.c +++ b/drivers/iio/adc/ad4691.c @@ -122,6 +122,7 @@ enum ad4691_ref_ctrl { struct ad4691_channel_info { const struct iio_chan_spec *channels __counted_by_ptr(num_channels); + const struct iio_chan_spec *manual_channels __counted_by_ptr(num_channels); unsigned int num_channels; }; @@ -132,7 +133,34 @@ struct ad4691_chip_info { const struct ad4691_channel_info *offload_info; }; +/* CNV burst mode channel — exposes oversampling ratio. */ #define AD4691_CHANNEL(ch) \ + { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) \ + | BIT(IIO_CHAN_INFO_SAMP_FREQ) \ + | BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .info_mask_shared_by_all_available = \ + BIT(IIO_CHAN_INFO_SAMP_FREQ) \ + | BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .channel = ch, \ + .scan_index = ch, \ + .scan_type = { \ + .format = 'u', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_BE, \ + }, \ + } + +/* + * Manual mode channel — no oversampling ratio attribute. OSR is not + * supported in manual mode; ACC_DEPTH_IN is not configured during manual + * buffer enable. + */ +#define AD4691_MANUAL_CHANNEL(ch) \ { \ .type = IIO_VOLTAGE, \ .indexed = 1, \ @@ -156,8 +184,33 @@ struct ad4691_chip_info { * bits into native 16-bit words before DMA, so samples are in * CPU-native byte order (IIO_CPU). storagebits=16 matches the 16-bit * DMA word size. + * + * CNV burst offload configures ACC_DEPTH_IN per channel, so the + * oversampling_ratio attribute is exposed. Manual offload does not; + * use AD4691_OFFLOAD_MANUAL_CHANNEL for that path. */ #define AD4691_OFFLOAD_CHANNEL(ch) \ + { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) \ + | BIT(IIO_CHAN_INFO_SAMP_FREQ) \ + | BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .info_mask_shared_by_all_available = \ + BIT(IIO_CHAN_INFO_SAMP_FREQ) \ + | BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .channel = ch, \ + .scan_index = ch, \ + .scan_type = { \ + .format = 'u', \ + .realbits = 16, \ + .storagebits = 16, \ + }, \ + } + +/* Manual offload — same IIO_CPU layout but no oversampling_ratio attribute. */ +#define AD4691_OFFLOAD_MANUAL_CHANNEL(ch) \ { \ .type = IIO_VOLTAGE, \ .indexed = 1, \ @@ -241,23 +294,91 @@ static const struct iio_chan_spec ad4693_offload_channels[] = { AD4691_OFFLOAD_CHANNEL(7), }; +static const struct iio_chan_spec ad4691_manual_channels[] = { + AD4691_MANUAL_CHANNEL(0), + AD4691_MANUAL_CHANNEL(1), + AD4691_MANUAL_CHANNEL(2), + AD4691_MANUAL_CHANNEL(3), + AD4691_MANUAL_CHANNEL(4), + AD4691_MANUAL_CHANNEL(5), + AD4691_MANUAL_CHANNEL(6), + AD4691_MANUAL_CHANNEL(7), + AD4691_MANUAL_CHANNEL(8), + AD4691_MANUAL_CHANNEL(9), + AD4691_MANUAL_CHANNEL(10), + AD4691_MANUAL_CHANNEL(11), + AD4691_MANUAL_CHANNEL(12), + AD4691_MANUAL_CHANNEL(13), + AD4691_MANUAL_CHANNEL(14), + AD4691_MANUAL_CHANNEL(15), + IIO_CHAN_SOFT_TIMESTAMP(16), +}; + +static const struct iio_chan_spec ad4693_manual_channels[] = { + AD4691_MANUAL_CHANNEL(0), + AD4691_MANUAL_CHANNEL(1), + AD4691_MANUAL_CHANNEL(2), + AD4691_MANUAL_CHANNEL(3), + AD4691_MANUAL_CHANNEL(4), + AD4691_MANUAL_CHANNEL(5), + AD4691_MANUAL_CHANNEL(6), + AD4691_MANUAL_CHANNEL(7), + IIO_CHAN_SOFT_TIMESTAMP(8), +}; + +static const struct iio_chan_spec ad4691_offload_manual_channels[] = { + AD4691_OFFLOAD_MANUAL_CHANNEL(0), + AD4691_OFFLOAD_MANUAL_CHANNEL(1), + AD4691_OFFLOAD_MANUAL_CHANNEL(2), + AD4691_OFFLOAD_MANUAL_CHANNEL(3), + AD4691_OFFLOAD_MANUAL_CHANNEL(4), + AD4691_OFFLOAD_MANUAL_CHANNEL(5), + AD4691_OFFLOAD_MANUAL_CHANNEL(6), + AD4691_OFFLOAD_MANUAL_CHANNEL(7), + AD4691_OFFLOAD_MANUAL_CHANNEL(8), + AD4691_OFFLOAD_MANUAL_CHANNEL(9), + AD4691_OFFLOAD_MANUAL_CHANNEL(10), + AD4691_OFFLOAD_MANUAL_CHANNEL(11), + AD4691_OFFLOAD_MANUAL_CHANNEL(12), + AD4691_OFFLOAD_MANUAL_CHANNEL(13), + AD4691_OFFLOAD_MANUAL_CHANNEL(14), + AD4691_OFFLOAD_MANUAL_CHANNEL(15), +}; + +static const struct iio_chan_spec ad4693_offload_manual_channels[] = { + AD4691_OFFLOAD_MANUAL_CHANNEL(0), + AD4691_OFFLOAD_MANUAL_CHANNEL(1), + AD4691_OFFLOAD_MANUAL_CHANNEL(2), + AD4691_OFFLOAD_MANUAL_CHANNEL(3), + AD4691_OFFLOAD_MANUAL_CHANNEL(4), + AD4691_OFFLOAD_MANUAL_CHANNEL(5), + AD4691_OFFLOAD_MANUAL_CHANNEL(6), + AD4691_OFFLOAD_MANUAL_CHANNEL(7), +}; + +static const int ad4691_oversampling_ratios[] = { 1, 2, 4, 8, 16, 32 }; + static const struct ad4691_channel_info ad4691_sw_info = { .channels = ad4691_channels, + .manual_channels = ad4691_manual_channels, .num_channels = ARRAY_SIZE(ad4691_channels), }; static const struct ad4691_channel_info ad4693_sw_info = { .channels = ad4693_channels, + .manual_channels = ad4693_manual_channels, .num_channels = ARRAY_SIZE(ad4693_channels), }; static const struct ad4691_channel_info ad4691_offload_info = { .channels = ad4691_offload_channels, + .manual_channels = ad4691_offload_manual_channels, .num_channels = ARRAY_SIZE(ad4691_offload_channels), }; static const struct ad4691_channel_info ad4693_offload_info = { .channels = ad4693_offload_channels, + .manual_channels = ad4693_offload_manual_channels, .num_channels = ARRAY_SIZE(ad4693_offload_channels), }; @@ -324,6 +445,25 @@ struct ad4691_state { int irq; int vref_uV; u32 cnv_period_ns; + /* + * Snapped oscillator frequency (Hz) shared by all channels. Set when + * sampling_frequency or oversampling_ratio is written; written to + * OSC_FREQ_REG at buffer enable and single-shot time so both attributes + * can be set in any order. Reading in_voltage_sampling_frequency + * returns target_osc_freq_Hz / osr — the effective rate given the + * shared oversampling ratio. + */ + u32 target_osc_freq_Hz; + /* Shared oversampling ratio across all channels; always 1 in manual mode. */ + unsigned int osr; + /* + * Precomputed effective-rate lists, one row per entry in + * ad4691_oversampling_ratios[]. Populated at probe; read_avail picks + * the row for the current shared OSR. The tables are stable after + * probe so returning a pointer into them from read_avail is race-free. + */ + int samp_freq_avail[ARRAY_SIZE(ad4691_oversampling_ratios)][ARRAY_SIZE(ad4691_osc_freqs_Hz)]; + int samp_freq_avail_len[ARRAY_SIZE(ad4691_oversampling_ratios)]; bool manual_mode; bool irq_enabled; @@ -580,35 +720,95 @@ static unsigned int ad4691_samp_freq_start(const struct ad4691_chip_info *info) return (info->max_rate == 1 * HZ_PER_MHZ) ? 0 : 1; } -static int ad4691_get_sampling_freq(struct ad4691_state *st, int *val) +/* + * Find the largest oscillator table entry that is both <= needed_osc and + * evenly divisible by osr (guaranteeing an integer effective rate on + * read-back). Returns 0 if no such entry exists in the chip's valid range. + */ +static unsigned int ad4691_find_osc_freq(struct ad4691_state *st, + unsigned int needed_osc, + unsigned int osr) { - unsigned int reg_val; - int ret; + unsigned int start = ad4691_samp_freq_start(st->info); - guard(mutex)(&st->lock); + for (unsigned int i = start; i < ARRAY_SIZE(ad4691_osc_freqs_Hz); i++) { + if ((unsigned int)ad4691_osc_freqs_Hz[i] > needed_osc) + continue; + if (ad4691_osc_freqs_Hz[i] % osr) + continue; + return ad4691_osc_freqs_Hz[i]; + } + return 0; +} - ret = regmap_read(st->regmap, AD4691_OSC_FREQ_REG, ®_val); - if (ret) - return ret; +/* Write target_osc_freq_Hz to OSC_FREQ_REG. Called at use time. */ +static int ad4691_write_osc_freq(struct ad4691_state *st) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(ad4691_osc_freqs_Hz); i++) { + if (ad4691_osc_freqs_Hz[i] == st->target_osc_freq_Hz) + return regmap_write(st->regmap, AD4691_OSC_FREQ_REG, i); + } + return -EINVAL; +} - *val = ad4691_osc_freqs_Hz[FIELD_GET(AD4691_OSC_FREQ_MASK, reg_val)]; - return IIO_VAL_INT; +/* Return the index of osr in ad4691_oversampling_ratios[], defaulting to 0. */ +static unsigned int ad4691_osr_index(unsigned int osr) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(ad4691_oversampling_ratios) - 1; i++) { + if ((unsigned int)ad4691_oversampling_ratios[i] == osr) + return i; + } + return ARRAY_SIZE(ad4691_oversampling_ratios) - 1; +} + +/* + * Precompute samp_freq_avail[][]: for each OSR value, list the oscillator + * table entries that divide evenly by that OSR, expressed as effective rates + * (osc_freq / osr). Called once at probe after st->info is set. + */ +static void ad4691_precompute_samp_freq_avail(struct ad4691_state *st) +{ + unsigned int start = ad4691_samp_freq_start(st->info); + + for (unsigned int i = 0; i < ARRAY_SIZE(ad4691_oversampling_ratios); i++) { + unsigned int osr = ad4691_oversampling_ratios[i]; + int n = 0; + + for (unsigned int j = start; j < ARRAY_SIZE(ad4691_osc_freqs_Hz); j++) { + if (ad4691_osc_freqs_Hz[j] % osr) + continue; + st->samp_freq_avail[i][n++] = ad4691_osc_freqs_Hz[j] / osr; + } + st->samp_freq_avail_len[i] = n; + } } static int ad4691_set_sampling_freq(struct ad4691_state *st, int freq) { - unsigned int start = ad4691_samp_freq_start(st->info); + unsigned int osr, found; + /* + * Read osr under st->lock: osr and target_osc_freq_Hz are modified + * together under the lock; reading after acquiring it ensures we see + * a consistent snapshot with no concurrent write racing us. + */ guard(mutex)(&st->lock); + osr = st->osr; - for (unsigned int i = start; i < ARRAY_SIZE(ad4691_osc_freqs_Hz); i++) { - if (ad4691_osc_freqs_Hz[i] != freq) - continue; - return regmap_update_bits(st->regmap, AD4691_OSC_FREQ_REG, - AD4691_OSC_FREQ_MASK, i); - } + if (freq <= 0 || (unsigned int)freq > st->info->max_rate / osr) + return -EINVAL; - return -EINVAL; + found = ad4691_find_osc_freq(st, (unsigned int)freq * osr, osr); + if (!found) + return -EINVAL; + + /* + * Store the snapped oscillator frequency; OSC_FREQ_REG is written at + * buffer enable and single-shot time so that sampling_frequency and + * oversampling_ratio can be set in any order. + */ + st->target_osc_freq_Hz = found; + return 0; } static int ad4691_read_avail(struct iio_dev *indio_dev, @@ -617,13 +817,27 @@ static int ad4691_read_avail(struct iio_dev *indio_dev, int *length, long mask) { struct ad4691_state *st = iio_priv(indio_dev); - unsigned int start = ad4691_samp_freq_start(st->info); switch (mask) { - case IIO_CHAN_INFO_SAMP_FREQ: - *vals = &ad4691_osc_freqs_Hz[start]; + case IIO_CHAN_INFO_SAMP_FREQ: { + unsigned int osr_idx; + + /* + * The precomputed tables are stable after probe; only the + * current OSR needs to be read under the lock to pick the + * right row atomically. + */ + guard(mutex)(&st->lock); + osr_idx = ad4691_osr_index(st->osr); + *vals = st->samp_freq_avail[osr_idx]; *type = IIO_VAL_INT; - *length = ARRAY_SIZE(ad4691_osc_freqs_Hz) - start; + *length = st->samp_freq_avail_len[osr_idx]; + return IIO_AVAIL_LIST; + } + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *vals = ad4691_oversampling_ratios; + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(ad4691_oversampling_ratios); return IIO_AVAIL_LIST; default: return -EINVAL; @@ -634,7 +848,7 @@ static int ad4691_single_shot_read(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val) { struct ad4691_state *st = iio_priv(indio_dev); - unsigned int reg_val, osc_idx, period_us; + unsigned int reg_val, period_us; int ret; guard(mutex)(&st->lock); @@ -654,7 +868,11 @@ static int ad4691_single_shot_read(struct iio_dev *indio_dev, if (ret) return ret; - ret = regmap_read(st->regmap, AD4691_OSC_FREQ_REG, ®_val); + ret = regmap_write(st->regmap, AD4691_ACC_DEPTH_IN(0), st->osr); + if (ret) + return ret; + + ret = ad4691_write_osc_freq(st); if (ret) return ret; @@ -662,9 +880,12 @@ static int ad4691_single_shot_read(struct iio_dev *indio_dev, if (ret) return ret; - osc_idx = FIELD_GET(AD4691_OSC_FREQ_MASK, reg_val); - /* Wait 2 oscillator periods for the conversion to complete. */ - period_us = DIV_ROUND_UP(2UL * USEC_PER_SEC, ad4691_osc_freqs_Hz[osc_idx]); + /* + * Wait osr + 1 oscillator periods: osr for accumulation, +1 for the + * pipeline margin (one extra period ensures the final result is ready). + */ + period_us = DIV_ROUND_UP((st->osr + 1) * USEC_PER_SEC, + st->target_osc_freq_Hz); fsleep(period_us); ret = regmap_write(st->regmap, AD4691_OSC_EN_REG, 0); @@ -698,8 +919,22 @@ static int ad4691_read_raw(struct iio_dev *indio_dev, return ad4691_single_shot_read(indio_dev, chan, val); } - case IIO_CHAN_INFO_SAMP_FREQ: - return ad4691_get_sampling_freq(st, val); + case IIO_CHAN_INFO_SAMP_FREQ: { + /* + * Read target_osc_freq_Hz and osr under st->lock to get a + * consistent snapshot: write_raw for SAMP_FREQ or OSR modifies + * both fields under the lock, so a concurrent read without the + * lock could observe a new oscillator frequency with the old OSR. + */ + guard(mutex)(&st->lock); + *val = st->target_osc_freq_Hz / st->osr; + return IIO_VAL_INT; + } + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: { + guard(mutex)(&st->lock); + *val = st->osr; + return IIO_VAL_INT; + } case IIO_CHAN_INFO_SCALE: *val = st->vref_uV / (MICRO / MILLI); *val2 = chan->scan_type.realbits; @@ -722,6 +957,33 @@ static int ad4691_write_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: return ad4691_set_sampling_freq(st, val); + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: { + unsigned int old_effective, found, osr_idx; + + osr_idx = ad4691_osr_index(val); + if (ad4691_oversampling_ratios[osr_idx] != val) + return -EINVAL; + + /* + * Hold st->lock while computing the new oscillator frequency + * and updating both target_osc_freq_Hz and osr atomically: + * read_raw for SAMP_FREQ reads both fields under the lock and + * must see a consistent pair (new osc ↔ new osr). + * + * Snap target_osc_freq_Hz to the largest table entry that is + * both <= old_effective * new_osr and evenly divisible by + * new_osr, preserving an integer read-back of + * in_voltage_sampling_frequency after the OSR change. + */ + guard(mutex)(&st->lock); + old_effective = st->target_osc_freq_Hz / st->osr; + found = ad4691_find_osc_freq(st, old_effective * (unsigned int)val, val); + if (!found) + return -EINVAL; + st->target_osc_freq_Hz = found; + st->osr = val; + return 0; + } default: return -EINVAL; } @@ -776,6 +1038,10 @@ static int ad4691_enter_conversion_mode(struct ad4691_state *st) return regmap_update_bits(st->regmap, AD4691_DEVICE_SETUP, AD4691_MANUAL_MODE, AD4691_MANUAL_MODE); + ret = ad4691_write_osc_freq(st); + if (ret) + return ret; + ret = regmap_update_bits(st->regmap, AD4691_ADC_SETUP, AD4691_ADC_MODE_MASK, AD4691_CNV_BURST_MODE); if (ret) @@ -943,6 +1209,10 @@ static int ad4691_cnv_burst_buffer_preenable(struct iio_dev *indio_dev) if (ret) goto err_unoptimize; + ret = regmap_write(st->regmap, AD4691_ACC_DEPTH_IN(0), st->osr); + if (ret) + goto err_unoptimize; + ret = ad4691_enter_conversion_mode(st); if (ret) goto err_unoptimize; @@ -1122,6 +1392,10 @@ static int ad4691_cnv_burst_offload_buffer_postenable(struct iio_dev *indio_dev) if (ret) return ret; + ret = regmap_write(st->regmap, AD4691_ACC_DEPTH_IN(0), st->osr); + if (ret) + return ret; + ret = ad4691_enter_conversion_mode(st); if (ret) return ret; @@ -1538,11 +1812,15 @@ static int ad4691_config(struct ad4691_state *st) if (ret) return dev_err_probe(dev, ret, "Failed to write OSC_FREQ\n"); + st->target_osc_freq_Hz = ad4691_osc_freqs_Hz[ad4691_samp_freq_start(st->info)]; + ret = regmap_update_bits(st->regmap, AD4691_ADC_SETUP, AD4691_ADC_MODE_MASK, AD4691_AUTONOMOUS_MODE); if (ret) return dev_err_probe(dev, ret, "Failed to write ADC_SETUP\n"); + ad4691_precompute_samp_freq_avail(st); + return 0; } @@ -1554,7 +1832,14 @@ static int ad4691_setup_triggered_buffer(struct iio_dev *indio_dev, unsigned int i; int irq, ret; - indio_dev->channels = st->info->sw_info->channels; + /* + * Manual mode exposes channels without the oversampling_ratio attribute + * because ACC_DEPTH_IN is not configured in manual mode. + */ + if (st->manual_mode) + indio_dev->channels = st->info->sw_info->manual_channels; + else + indio_dev->channels = st->info->sw_info->channels; indio_dev->num_channels = st->info->sw_info->num_channels; indio_dev->info = st->manual_mode ? &ad4691_manual_info : &ad4691_cnv_burst_info; @@ -1636,7 +1921,18 @@ static int ad4691_setup_offload(struct iio_dev *indio_dev, st->offload = spi_offload; - indio_dev->channels = st->info->offload_info->channels; + /* + * CNV burst offload exposes oversampling_ratio (ACC_DEPTH_IN is + * configured per channel at buffer enable). Manual offload does not + * configure ACC_DEPTH_IN, so it uses a separate channel array + * without the oversampling_ratio attribute. Both paths use IIO_CPU + * (no .endianness annotation) because bits_per_word=16 causes the + * SPI Engine to produce native 16-bit DMA words. + */ + if (st->manual_mode) + indio_dev->channels = st->info->offload_info->manual_channels; + else + indio_dev->channels = st->info->offload_info->channels; indio_dev->num_channels = st->info->offload_info->num_channels; /* * Offload path uses DMA directly; no IIO trigger is involved, so @@ -1710,6 +2006,7 @@ static int ad4691_probe(struct spi_device *spi) st->info = spi_get_device_match_data(spi); if (!st->info) return -ENODEV; + st->osr = 1; ret = devm_mutex_init(dev, &st->lock); if (ret) From 4e8327ccb9098a8d71dfb000a02e844f4a002c00 Mon Sep 17 00:00:00 2001 From: Radu Sabau Date: Fri, 29 May 2026 13:15:05 +0300 Subject: [PATCH 252/266] docs: iio: adc: ad4691: add driver documentation Add RST documentation for the AD4691 family ADC driver covering supported devices, IIO channels, operating modes, oversampling, reference voltage, LDO supply, reset, GP pins, SPI offload support, and buffer data format. Signed-off-by: Radu Sabau Signed-off-by: Jonathan Cameron --- Documentation/iio/ad4691.rst | 227 +++++++++++++++++++++++++++++++++++ Documentation/iio/index.rst | 1 + MAINTAINERS | 1 + 3 files changed, 229 insertions(+) create mode 100644 Documentation/iio/ad4691.rst diff --git a/Documentation/iio/ad4691.rst b/Documentation/iio/ad4691.rst new file mode 100644 index 000000000000..e45733341a4b --- /dev/null +++ b/Documentation/iio/ad4691.rst @@ -0,0 +1,227 @@ +.. SPDX-License-Identifier: GPL-2.0-only + +============= +AD4691 driver +============= + +ADC driver for Analog Devices Inc. AD4691 family of multichannel SAR ADCs. +The module name is ``ad4691``. + + +Supported devices +================= + +The following chips are supported by this driver: + +* `AD4691 `_ — 16-channel, 500 kSPS +* `AD4692 `_ — 16-channel, 1 MSPS +* `AD4693 `_ — 8-channel, 500 kSPS +* `AD4694 `_ — 8-channel, 1 MSPS + + +IIO channels +============ + +Each physical ADC input maps to one IIO voltage channel. The AD4691 and AD4692 +expose 16 channels (``voltage0`` through ``voltage15``); the AD4693 and AD4694 +expose 8 channels (``voltage0`` through ``voltage7``). + +All channels share a common scale (``in_voltage_scale``), derived from the +reference voltage. Each channel exposes: + +* ``in_voltageN_raw`` — single-shot ADC result + +The following attributes are shared across all channels: + +* ``in_voltage_sampling_frequency`` — effective output rate, defined as the + internal oscillator frequency divided by the oversampling ratio. Writing this + attribute selects the nearest achievable rate for the current OSR; the value + read back reflects the actual rate after snapping to the closest valid + oscillator entry. +* ``in_voltage_sampling_frequency_available`` — list of achievable effective + rates for the current oversampling ratio. The list updates dynamically when + the oversampling ratio changes. + +The following attributes are shared across all channels and only available in +CNV Burst Mode: + +* ``in_voltage_oversampling_ratio`` — hardware oversampling depth applied to + all channels; see `Oversampling`_ below. +* ``in_voltage_oversampling_ratio_available`` — valid ratios: 1, 2, 4, 8, 16, + 32. + + +Operating modes +=============== + +The driver supports two operating modes, selected automatically from the +device tree at probe time. + +Manual Mode +----------- + +Selected when no ``pwms`` property is present in the device tree. The CNV pin +is tied to the SPI chip-select: every CS assertion triggers a conversion and +returns the previous result. A user-defined IIO trigger (e.g. hrtimer trigger) +drives the buffer. + +Oversampling is not supported in Manual Mode. + +CNV Burst Mode +-------------- + +Selected when a ``pwms`` property is present in the device tree. A PWM drives +the CNV pin at the configured conversion rate. A GP pin wired to the SoC and +declared in the device tree signals DATA_READY at the end of each burst, +triggering a readout of all active channel results into the IIO buffer. + +The buffer output rate is controlled by the ``sampling_frequency`` attribute +on the IIO buffer. In practice the PWM rate should be set low enough to allow +the SPI readout to complete before the next conversion burst begins. + +Autonomous Mode (idle / single-shot) +------------------------------------- + +When the IIO buffer is disabled, ``in_voltageN_raw`` reads perform a single +conversion on the requested channel using the internal oscillator. The +oscillator is started and stopped around each read to save power. + + +Oversampling +============ + +In CNV Burst Mode a shared hardware accumulator averages a configurable number +of successive conversions across all active channels. The result is always a +16-bit mean, so the buffer data type (shown in ``buffer0/in_voltageN_type``) +is unaffected by the oversampling ratio. Valid ratios are 1, 2, 4, 8, 16 and +32; the default is 1 (no averaging). Oversampling is not supported in Manual +Mode. + +.. code-block:: bash + + # Set oversampling ratio to 16 (shared across all channels) + echo 16 > /sys/bus/iio/devices/iio:device0/in_voltage_oversampling_ratio + + # Read the resulting effective sampling frequency + cat /sys/bus/iio/devices/iio:device0/in_voltage_sampling_frequency + +Writing ``in_voltage_oversampling_ratio`` stores the new shared depth and snaps +the internal oscillator to the largest valid table entry that is both less than +or equal to ``old_effective_rate × new_osr`` and evenly divisible by +``new_osr``. This preserves an integer read-back of +``in_voltage_sampling_frequency`` after the change and keeps the oscillator as +close as possible to the previous effective rate. + + +Reference voltage +================= + +The driver supports two reference configurations, mutually exclusive: + +* **External reference** (``ref-supply``): a voltage between 2.4 V and 5.25 V + supplied externally. +* **Buffered internal reference** (``refin-supply``): an internal reference + buffer is enabled by the driver. + +Exactly one of ``ref-supply`` or ``refin-supply`` must be present in the +device tree. The reference voltage determines the full-scale range reported +via ``in_voltage_scale``. + + +LDO supply +========== + +The chip contains an internal LDO that powers part of the analog front-end. +The supply configuration is mutually exclusive: + +* **External VDD** (``vdd-supply``): an external 1.8 V supply is used directly; + the internal LDO is disabled. +* **Internal LDO** (``ldo-in-supply``): the internal LDO is enabled and fed + from the ``ldo-in`` regulator. Use this when no external 1.8 V VDD is present. + +Exactly one of ``vdd-supply`` or ``ldo-in-supply`` must be provided. + + +Reset +===== + +The driver supports two reset mechanisms: + +* **Hardware reset** (``reset-gpios`` in device tree): the GPIO line is + asserted then deasserted at probe; the driver waits 300 µs for the chip + to complete its internal reset sequence before accepting SPI commands. +* **Software reset** (fallback when ``reset-gpios`` is absent): written + automatically at probe. + + +GP pins and interrupts +====================== + +The chip exposes up to four general-purpose (GP) pins. In CNV Burst Mode +(non-offload), one GP pin must be wired to an interrupt-capable SoC input and +declared in the device tree using the ``interrupts`` and ``interrupt-names`` +properties. The ``interrupt-names`` value identifies which GP pin is used +(``"gp0"`` through ``"gp3"``). + +Example device tree fragment:: + + adc@0 { + compatible = "adi,ad4692"; + ... + interrupt-parent = <&gpio0>; + interrupts = <17 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "gp0"; + }; + + +SPI offload support +=================== + +When a SPI offload engine (e.g. the AXI SPI Engine) is present, the driver +uses DMA-backed transfers for CPU-independent, high-throughput data capture. +SPI offload is detected automatically at probe; if no offload hardware is +available the driver falls back to the software triggered-buffer path. + +Two SPI offload sub-modes exist: + +CNV Burst offload +----------------- + +Used when a ``pwms`` property is present and SPI offload is available. The PWM +drives CNV at the configured rate; on DATA_READY the offload engine reads all +active channel results and streams them directly to the IIO DMA buffer with no +CPU involvement. The GP pin used as DATA_READY trigger is supplied by the +trigger-source consumer at buffer enable time; no ``interrupt-names`` entry is +required. + +Manual offload +-------------- + +Used when no ``pwms`` property is present and SPI offload is available. A +periodic SPI offload trigger controls the conversion rate and the offload engine +streams results directly to the IIO DMA buffer. + +The ``sampling_frequency`` attribute on the IIO buffer controls the trigger +rate (in Hz). The initial rate is 100 kHz. + +Oversampling is not supported in Manual Mode. + + +Buffer data format +================== + +The sample format in the IIO buffer depends on whether SPI offload is in use. + +Software triggered-buffer path (no SPI offload) +------------------------------------------------ + +Each active channel occupies one 16-bit big-endian slot (``storagebits=16``, +``endianness=be``). Active channels are packed densely in scan-index order, +followed by a 64-bit software timestamp appended by the IIO core. + +SPI offload path +---------------- + +Each active channel occupies one 16-bit CPU-native slot (``storagebits=16``, +``endianness=cpu``). The SPI offload engine streams 16-bit words directly from +the SPI Engine into the DMA buffer; no software timestamp is appended. diff --git a/Documentation/iio/index.rst b/Documentation/iio/index.rst index ba3e609c6a13..007e0a1fcc5a 100644 --- a/Documentation/iio/index.rst +++ b/Documentation/iio/index.rst @@ -23,6 +23,7 @@ Industrial I/O Kernel Drivers ad4000 ad4030 ad4062 + ad4691 ad4695 ad7191 ad7380 diff --git a/MAINTAINERS b/MAINTAINERS index 4cb938531c64..9e9457c7bba6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1482,6 +1482,7 @@ L: linux-iio@vger.kernel.org S: Supported W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/adc/adi,ad4691.yaml +F: Documentation/iio/ad4691.rst F: drivers/iio/adc/ad4691.c ANALOG DEVICES INC AD4695 DRIVER From 278b9d0fce2f462e8870d0effed0dc83c3cc7314 Mon Sep 17 00:00:00 2001 From: Joshua Crofts Date: Sun, 31 May 2026 18:56:35 +0200 Subject: [PATCH 253/266] dt-bindings: iio: light: veml6030: add veml3328 The Vishay VEML3328 is an RGBCIR light sensor that shares similar devicetree properties as other existing VEMLxxxx sensors in the kernel. Acked-by: Krzysztof Kozlowski Signed-off-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/light/vishay,veml6030.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/iio/light/vishay,veml6030.yaml b/Documentation/devicetree/bindings/iio/light/vishay,veml6030.yaml index 4ea69f1fdd63..0041e1db6838 100644 --- a/Documentation/devicetree/bindings/iio/light/vishay,veml6030.yaml +++ b/Documentation/devicetree/bindings/iio/light/vishay,veml6030.yaml @@ -4,7 +4,7 @@ $id: http://devicetree.org/schemas/iio/light/vishay,veml6030.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: VEML3235, VEML6030, VEML6035 and VEML7700 Ambient Light Sensors (ALS) +title: VEML3235, VEML3328, VEML6030, VEML6035 and VEML7700 Ambient Light Sensors (ALS) maintainers: - Rishi Gupta @@ -21,6 +21,7 @@ description: | Specifications about the sensors can be found at: https://www.vishay.com/docs/80131/veml3235.pdf + https://www.vishay.com/docs/84968/veml3328.pdf https://www.vishay.com/docs/84366/veml6030.pdf https://www.vishay.com/docs/84889/veml6035.pdf https://www.vishay.com/docs/84286/veml7700.pdf @@ -29,6 +30,7 @@ properties: compatible: enum: - vishay,veml3235 + - vishay,veml3328 - vishay,veml6030 - vishay,veml6035 - vishay,veml7700 @@ -79,6 +81,7 @@ allOf: compatible: enum: - vishay,veml3235 + - vishay,veml3328 - vishay,veml7700 then: properties: From e45a44f2196e0d6aa22fd80beff1c18dee9e9348 Mon Sep 17 00:00:00 2001 From: Joshua Crofts Date: Sun, 31 May 2026 18:56:36 +0200 Subject: [PATCH 254/266] iio: light: veml3328: add support for new device Add support for the Vishay VEML3328 RGB/IR light sensor communicating via I2C (SMBus compatible). Also add a new entry for said driver into Kconfig and Makefile. Assisted-by: Gemini:3.1-Pro Signed-off-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- MAINTAINERS | 5 + drivers/iio/light/Kconfig | 11 + drivers/iio/light/Makefile | 1 + drivers/iio/light/veml3328.c | 423 +++++++++++++++++++++++++++++++++++ 4 files changed, 440 insertions(+) create mode 100644 drivers/iio/light/veml3328.c diff --git a/MAINTAINERS b/MAINTAINERS index 9e9457c7bba6..a893a1a1181e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -28402,6 +28402,11 @@ S: Maintained F: Documentation/devicetree/bindings/iio/light/vishay,veml6030.yaml F: drivers/iio/light/veml3235.c +VISHAY VEML3328 RGB IR LIGHT SENSOR DRIVER +M: Joshua Crofts +S: Maintained +F: drivers/iio/light/veml3328.c + VISHAY VEML6030 AMBIENT LIGHT SENSOR DRIVER M: Javier Carrasco S: Maintained diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index da4807a3fd3d..ef36824f312f 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -713,6 +713,17 @@ config VEML3235 To compile this driver as a module, choose M here: the module will be called veml3235. +config VEML3328 + tristate "VEML3328 RGBCIR light sensor" + select REGMAP_I2C + depends on I2C + help + Say Y here if you want to build a driver for the Vishay VEML3328 + RGB IR light sensor. + + To compile this driver as a module, choose M here: the + module will be called veml3328 + config VEML6030 tristate "VEML6030 and VEML6035 ambient light sensors" select REGMAP_I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index 39e62dfc10c7..64e354c49ed8 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -66,6 +66,7 @@ obj-$(CONFIG_US5182D) += us5182d.o obj-$(CONFIG_VCNL4000) += vcnl4000.o obj-$(CONFIG_VCNL4035) += vcnl4035.o obj-$(CONFIG_VEML3235) += veml3235.o +obj-$(CONFIG_VEML3328) += veml3328.o obj-$(CONFIG_VEML6030) += veml6030.o obj-$(CONFIG_VEML6040) += veml6040.o obj-$(CONFIG_VEML6046X00) += veml6046x00.o diff --git a/drivers/iio/light/veml3328.c b/drivers/iio/light/veml3328.c new file mode 100644 index 000000000000..9309deb5bf19 --- /dev/null +++ b/drivers/iio/light/veml3328.c @@ -0,0 +1,423 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Vishay VEML3328 RGBCIR light sensor driver + * + * Copyright (c) 2026 Joshua Crofts + * + * Datasheet: https://www.vishay.com/docs/84968/veml3328.pdf + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define VEML3328_REG_CONF 0x00 +#define VEML3328_REG_ID 0x0c +#define VEML3328_REG_DATA_C 0x04 +#define VEML3328_REG_DATA_R 0x05 +#define VEML3328_REG_DATA_G 0x06 +#define VEML3328_REG_DATA_B 0x07 +#define VEML3328_REG_DATA_IR 0x08 + +#define VEML3328_CONF_IT_MASK GENMASK(5, 4) +#define VEML3328_CONF_GAIN_MASK GENMASK(11, 10) + +#define VEML3328_MAX_IT_TIME (400 * USEC_PER_MSEC) + +#define VEML3328_ID_VAL 0x28 + +#define VEML3328_SHUTDOWN (BIT(0) | BIT(15)) + +struct veml3328_data { + struct regmap *regmap; + /* Ensure read-modify-write sequences are not interrupted. */ + struct mutex lock; +}; + +static const struct regmap_config veml3328_regmap_config = { + .name = "veml3328", + .reg_bits = 8, + .val_bits = 16, + .max_register = VEML3328_REG_ID, + .val_format_endian = REGMAP_ENDIAN_LITTLE, +}; + +#define VEML3328_CHAN_SPEC(_color, _addr) { \ + .type = IIO_INTENSITY, \ + .modified = 1, \ + .channel2 = IIO_MOD_LIGHT_##_color, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), \ + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME), \ + .address = _addr, \ +} + +static const struct iio_chan_spec veml3328_channels[] = { + { + .type = IIO_LIGHT, + + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME), + .address = VEML3328_REG_DATA_G, + }, + VEML3328_CHAN_SPEC(CLEAR, VEML3328_REG_DATA_C), + VEML3328_CHAN_SPEC(RED, VEML3328_REG_DATA_R), + VEML3328_CHAN_SPEC(GREEN, VEML3328_REG_DATA_G), + VEML3328_CHAN_SPEC(BLUE, VEML3328_REG_DATA_B), + VEML3328_CHAN_SPEC(IR, VEML3328_REG_DATA_IR), +}; + +/* + * Precomputed scale values (micro units). + * Formula for calculation: 0.384 * (50000 / IT_us) * (1 / Gain) + * Gain indexes: 0 (x0.5), 1 (x1), 2 (x2), 3 (x4) + * IT indexes: 0 (50ms), 1 (100ms), 2 (200ms), 3 (400ms) + */ +static const int veml3328_scale_vals[4][8] = { + { 0, 768000, 0, 384000, 0, 192000, 0, 96000 }, + { 0, 384000, 0, 192000, 0, 96000, 0, 48000 }, + { 0, 192000, 0, 96000, 0, 48000, 0, 24000 }, + { 0, 96000, 0, 48000, 0, 24000, 0, 12000 }, +}; + +/* integration times in microseconds */ +static const int veml3328_it_times[][2] = { + { 0, 50 * USEC_PER_MSEC }, + { 0, 100 * USEC_PER_MSEC }, + { 0, 200 * USEC_PER_MSEC }, + { 0, 400 * USEC_PER_MSEC }, +}; + +static int veml3328_power_down(struct veml3328_data *data) +{ + return regmap_set_bits(data->regmap, VEML3328_REG_CONF, + VEML3328_SHUTDOWN); +} + +static int veml3328_power_up(struct veml3328_data *data) +{ + int ret; + + ret = regmap_clear_bits(data->regmap, VEML3328_REG_CONF, + VEML3328_SHUTDOWN); + if (ret) + return ret; + + /* + * Sleep for maximum integration time to ensure sensor is powered on + * correctly. + */ + fsleep(VEML3328_MAX_IT_TIME); + + return 0; +} + +static void veml3328_power_down_action(void *data) +{ + veml3328_power_down(data); +} + +static int veml3328_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct veml3328_data *data = iio_priv(indio_dev); + struct regmap *regmap = data->regmap; + struct device *dev = regmap_get_device(regmap); + unsigned int reg_val; + int it_inx, gain_inx; + int ret; + + PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) + return ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = regmap_read(regmap, chan->address, ®_val); + if (ret) + return ret; + + *val = reg_val; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_INT_TIME: + ret = regmap_read(regmap, VEML3328_REG_CONF, ®_val); + if (ret) + return ret; + + it_inx = FIELD_GET(VEML3328_CONF_IT_MASK, reg_val); + if (it_inx >= ARRAY_SIZE(veml3328_it_times)) + return -EINVAL; + + *val = veml3328_it_times[it_inx][0]; + *val2 = veml3328_it_times[it_inx][1]; + return IIO_VAL_INT_PLUS_MICRO; + + case IIO_CHAN_INFO_SCALE: + ret = regmap_read(regmap, VEML3328_REG_CONF, ®_val); + if (ret) + return ret; + + it_inx = FIELD_GET(VEML3328_CONF_IT_MASK, reg_val); + gain_inx = FIELD_GET(VEML3328_CONF_GAIN_MASK, reg_val); + + if (it_inx >= ARRAY_SIZE(veml3328_it_times) || gain_inx >= 4) + return -EINVAL; + + /* Stride by 2 through the flattened array to match (val, val2) */ + *val = veml3328_scale_vals[it_inx][gain_inx * 2]; + *val2 = veml3328_scale_vals[it_inx][gain_inx * 2 + 1]; + + return IIO_VAL_INT_PLUS_MICRO; + + default: + return -EINVAL; + } +} + +static int veml3328_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + struct veml3328_data *data = iio_priv(indio_dev); + struct regmap *regmap = data->regmap; + struct device *dev = regmap_get_device(data->regmap); + unsigned int reg_val; + int ret, it_inx; + + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + *length = ARRAY_SIZE(veml3328_it_times) * 2; + *vals = (const int *)veml3328_it_times; + *type = IIO_VAL_INT_PLUS_MICRO; + return IIO_AVAIL_LIST; + + case IIO_CHAN_INFO_SCALE: { + PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) + return ret; + + ret = regmap_read(regmap, VEML3328_REG_CONF, ®_val); + if (ret) + return ret; + + it_inx = FIELD_GET(VEML3328_CONF_IT_MASK, reg_val); + if (it_inx >= ARRAY_SIZE(veml3328_it_times)) + return -EINVAL; + + *length = 8; + *vals = (const int *)veml3328_scale_vals[it_inx]; + *type = IIO_VAL_INT_PLUS_MICRO; + return IIO_AVAIL_LIST; + } + default: + return -EINVAL; + } +} + +static int veml3328_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct veml3328_data *data = iio_priv(indio_dev); + struct regmap *regmap = data->regmap; + struct device *dev = regmap_get_device(regmap); + unsigned int reg_val; + int i, it_inx; + int ret; + + PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) + return ret; + + guard(mutex)(&data->lock); + + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + if (val != 0) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(veml3328_it_times); i++) { + if (veml3328_it_times[i][1] == val2) + break; + } + + if (i == ARRAY_SIZE(veml3328_it_times)) + return -EINVAL; + + return regmap_update_bits(regmap, VEML3328_REG_CONF, + VEML3328_CONF_IT_MASK, + FIELD_PREP(VEML3328_CONF_IT_MASK, i)); + + case IIO_CHAN_INFO_SCALE: + ret = regmap_read(regmap, VEML3328_REG_CONF, ®_val); + if (ret) + return ret; + + it_inx = FIELD_GET(VEML3328_CONF_IT_MASK, reg_val); + if (it_inx >= ARRAY_SIZE(veml3328_it_times)) + return -EINVAL; + + for (i = 0; i < 4; i++) { + if (val == veml3328_scale_vals[it_inx][i * 2] && + val2 == veml3328_scale_vals[it_inx][i * 2 + 1]) + break; + } + + if (i == 4) + return -EINVAL; + + return regmap_update_bits(regmap, VEML3328_REG_CONF, + VEML3328_CONF_GAIN_MASK, + FIELD_PREP(VEML3328_CONF_GAIN_MASK, i)); + + default: + return -EINVAL; + } +} + +static const struct iio_info veml3328_info = { + .read_raw = veml3328_read_raw, + .write_raw = veml3328_write_raw, + .read_avail = veml3328_read_avail, +}; + +static int veml3328_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct veml3328_data *data; + struct iio_dev *indio_dev; + unsigned int reg_val; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + + data->regmap = devm_regmap_init_i2c(client, &veml3328_regmap_config); + if (IS_ERR(data->regmap)) + return dev_err_probe(dev, PTR_ERR(data->regmap), + "Failed to initialize regmap\n"); + + ret = devm_mutex_init(dev, &data->lock); + if (ret) + return ret; + + ret = devm_regulator_get_enable(dev, "vdd"); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable regulator\n"); + + ret = regmap_read(data->regmap, VEML3328_REG_ID, ®_val); + if (ret) + return dev_err_probe(dev, ret, "Failed to read ID register\n"); + + if ((reg_val & 0xff) != VEML3328_ID_VAL) + dev_warn(dev, "Unknown device ID: 0x%02x\n", reg_val & 0xff); + + ret = veml3328_power_up(data); + if (ret) + return dev_err_probe(dev, ret, "Failed to power on sensor\n"); + + ret = devm_add_action_or_reset(dev, veml3328_power_down_action, data); + if (ret) + return dev_err_probe(dev, ret, "Failed to register teardown\n"); + + indio_dev->name = "veml3328"; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &veml3328_info; + indio_dev->channels = veml3328_channels; + indio_dev->num_channels = ARRAY_SIZE(veml3328_channels); + + pm_runtime_set_active(dev); + pm_runtime_set_autosuspend_delay(dev, 2000); + 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 veml3328_runtime_suspend(struct device *dev) +{ + struct veml3328_data *data = iio_priv(dev_get_drvdata(dev)); + int ret; + + ret = veml3328_power_down(data); + if (ret) + dev_err(dev, "Failed to suspend: %d\n", ret); + + return ret; +} + +static int veml3328_runtime_resume(struct device *dev) +{ + struct veml3328_data *data = iio_priv(dev_get_drvdata(dev)); + int ret; + + ret = veml3328_power_up(data); + if (ret) + dev_err(dev, "Failed to resume: %d\n", ret); + + return ret; +} + +static DEFINE_RUNTIME_DEV_PM_OPS(veml3328_pm_ops, + veml3328_runtime_suspend, + veml3328_runtime_resume, + NULL); + +static const struct of_device_id veml3328_of_match[] = { + { .compatible = "vishay,veml3328" }, + { } +}; +MODULE_DEVICE_TABLE(of, veml3328_of_match); + +static const struct i2c_device_id veml3328_id[] = { + { .name = "veml3328" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, veml3328_id); + +static struct i2c_driver veml3328_driver = { + .driver = { + .name = "veml3328", + .of_match_table = veml3328_of_match, + .pm = pm_ptr(&veml3328_pm_ops), + }, + .probe = veml3328_probe, + .id_table = veml3328_id, +}; +module_i2c_driver(veml3328_driver); + +MODULE_AUTHOR("Joshua Crofts "); +MODULE_DESCRIPTION("VEML3328 RGBCIR Light Sensor"); +MODULE_LICENSE("GPL"); From 3f2d03ecf22b09da1d92ba06e1ba6e20d16060e9 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Tue, 2 Jun 2026 11:40:19 +0300 Subject: [PATCH 255/266] iio: adc: ad4080: fix AD4880 chip ID The AD4880 chip ID was incorrectly set to 0x0750. According to the datasheet, the product ID registers read 0x00 (PRODUCT_ID_H) and 0x59 (PRODUCT_ID_L), giving a combined chip ID of 0x0059. Fix the value to match the actual hardware. Signed-off-by: Antoniu Miclaus Reviewed-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad4080.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/adc/ad4080.c b/drivers/iio/adc/ad4080.c index 764d49eca9e0..8d2953341b15 100644 --- a/drivers/iio/adc/ad4080.c +++ b/drivers/iio/adc/ad4080.c @@ -135,7 +135,7 @@ #define AD4086_CHIP_ID 0x0056 #define AD4087_CHIP_ID 0x0057 #define AD4088_CHIP_ID 0x0058 -#define AD4880_CHIP_ID 0x0750 +#define AD4880_CHIP_ID 0x0059 #define AD4884_CHIP_ID 0x005C #define AD4080_MAX_CHANNELS 2 From 628105e8f7af69c3b1d56c67896916b758f6f9c0 Mon Sep 17 00:00:00 2001 From: Rodrigo Alencar Date: Sun, 24 May 2026 11:17:01 +0100 Subject: [PATCH 256/266] iio: dac: ad5686: refactor include headers Apply IWYU principle, replacing unused/generic headers for specific/missing headers. The resulting include directive lists are sorted accordingly. Reviewed-by: Andy Shevchenko Signed-off-by: Rodrigo Alencar Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad5686-spi.c | 9 +++++++-- drivers/iio/dac/ad5686.c | 13 ++++++------- drivers/iio/dac/ad5686.h | 5 ++--- drivers/iio/dac/ad5696-i2c.c | 10 +++++++--- 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/drivers/iio/dac/ad5686-spi.c b/drivers/iio/dac/ad5686-spi.c index df8619e0c092..cec784b617e6 100644 --- a/drivers/iio/dac/ad5686-spi.c +++ b/drivers/iio/dac/ad5686-spi.c @@ -8,11 +8,16 @@ * Copyright 2018 Analog Devices Inc. */ -#include "ad5686.h" - +#include +#include +#include #include #include +#include + +#include "ad5686.h" + static int ad5686_spi_write(struct ad5686_state *st, u8 cmd, u8 addr, u16 val) { diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c index 19440b17645b..6f403b68cbec 100644 --- a/drivers/iio/dac/ad5686.c +++ b/drivers/iio/dac/ad5686.c @@ -5,17 +5,16 @@ * Copyright 2011 Analog Devices Inc. */ -#include -#include -#include +#include +#include +#include +#include +#include #include -#include -#include -#include #include +#include #include -#include #include "ad5686.h" diff --git a/drivers/iio/dac/ad5686.h b/drivers/iio/dac/ad5686.h index 36e16c5c4581..d08160e7fad9 100644 --- a/drivers/iio/dac/ad5686.h +++ b/drivers/iio/dac/ad5686.h @@ -8,10 +8,9 @@ #ifndef __DRIVERS_IIO_DAC_AD5686_H__ #define __DRIVERS_IIO_DAC_AD5686_H__ -#include -#include +#include #include -#include +#include #include diff --git a/drivers/iio/dac/ad5696-i2c.c b/drivers/iio/dac/ad5696-i2c.c index 56625e1da817..645ef441c463 100644 --- a/drivers/iio/dac/ad5696-i2c.c +++ b/drivers/iio/dac/ad5696-i2c.c @@ -7,10 +7,14 @@ * Copyright 2018 Analog Devices Inc. */ -#include "ad5686.h" - -#include +#include #include +#include +#include + +#include + +#include "ad5686.h" static int ad5686_i2c_read(struct ad5686_state *st, u8 addr) { From 126c78684073ca17c8dc2a174404f30b038d6881 Mon Sep 17 00:00:00 2001 From: Rodrigo Alencar Date: Sun, 24 May 2026 11:17:02 +0100 Subject: [PATCH 257/266] iio: dac: ad5686: remove redundant register definition AD5683_REGMAP and AD5693_REGMAP behave the same way in the common code, and that is because they target single channel devices from the same sub-family. There is no reason to separate them and it will make things simpler when refactoring the chip info table. Reviewed-by: Andy Shevchenko Signed-off-by: Rodrigo Alencar Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad5686.c | 19 +++++-------------- drivers/iio/dac/ad5686.h | 2 -- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c index 6f403b68cbec..1df1145f35b3 100644 --- a/drivers/iio/dac/ad5686.c +++ b/drivers/iio/dac/ad5686.c @@ -116,10 +116,6 @@ static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev, if (chan->channel > 0x7) address = 0x8; break; - case AD5693_REGMAP: - shift = 13; - ref_bit_msk = AD5693_REF_BIT_MSK; - break; default: return -EINVAL; } @@ -300,7 +296,7 @@ static const struct ad5686_chip_info ad5686_chip_info_tbl[] = { .channels = ad5311r_channels, .int_vref_mv = 2500, .num_channels = 1, - .regmap_type = AD5693_REGMAP, + .regmap_type = AD5683_REGMAP, }, [ID_AD5337R] = { .channels = ad5337r_channels, @@ -422,24 +418,24 @@ static const struct ad5686_chip_info ad5686_chip_info_tbl[] = { .channels = ad5691r_channels, .int_vref_mv = 2500, .num_channels = 1, - .regmap_type = AD5693_REGMAP, + .regmap_type = AD5683_REGMAP, }, [ID_AD5692R] = { .channels = ad5692r_channels, .int_vref_mv = 2500, .num_channels = 1, - .regmap_type = AD5693_REGMAP, + .regmap_type = AD5683_REGMAP, }, [ID_AD5693] = { .channels = ad5693_channels, .num_channels = 1, - .regmap_type = AD5693_REGMAP, + .regmap_type = AD5683_REGMAP, }, [ID_AD5693R] = { .channels = ad5693_channels, .int_vref_mv = 2500, .num_channels = 1, - .regmap_type = AD5693_REGMAP, + .regmap_type = AD5683_REGMAP, }, [ID_AD5694] = { .channels = ad5684_channels, @@ -540,11 +536,6 @@ int ad5686_probe(struct device *dev, cmd = AD5686_CMD_INTERNAL_REFER_SETUP; ref_bit_msk = AD5686_REF_BIT_MSK; break; - case AD5693_REGMAP: - cmd = AD5686_CMD_CONTROL_REG; - ref_bit_msk = AD5693_REF_BIT_MSK; - st->use_internal_vref = !has_external_vref; - break; default: return -EINVAL; } diff --git a/drivers/iio/dac/ad5686.h b/drivers/iio/dac/ad5686.h index d08160e7fad9..af15994c01ad 100644 --- a/drivers/iio/dac/ad5686.h +++ b/drivers/iio/dac/ad5686.h @@ -46,7 +46,6 @@ #define AD5310_REF_BIT_MSK BIT(8) #define AD5683_REF_BIT_MSK BIT(12) #define AD5686_REF_BIT_MSK BIT(0) -#define AD5693_REF_BIT_MSK BIT(12) /** * ad5686_supported_device_ids: @@ -89,7 +88,6 @@ enum ad5686_regmap_type { AD5310_REGMAP, AD5683_REGMAP, AD5686_REGMAP, - AD5693_REGMAP }; struct ad5686_state; From 0eb1728461a1a84613188f394e38921e29325d30 Mon Sep 17 00:00:00 2001 From: Rodrigo Alencar Date: Sun, 24 May 2026 11:17:03 +0100 Subject: [PATCH 258/266] iio: dac: ad5686: drop enum id Split chip info table into separate structs and expose them to the spi i2c drivers. That is the preferrable approach and allows for the drivers to have knowledge of the device info before the common probe function gets called. Those chip info structs may be shared by SPI and I2C driver variants. Channel declaration definitions are grouped according to channel count and DECLARE_AD5693_CHANNELS() macro is renamed to DECLARE_AD5683_CHANNELS() to match the regmap_type enum. Use spi_get_device_match_data() and i2c_get_match_data() to get chip info struct reference, passing it as parameter to the core probe function. Reviewed-by: Andy Shevchenko Signed-off-by: Rodrigo Alencar Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad5686-spi.c | 38 ++-- drivers/iio/dac/ad5686.c | 358 ++++++++++++++++------------------- drivers/iio/dac/ad5686.h | 66 +++---- drivers/iio/dac/ad5696-i2c.c | 65 ++++--- 4 files changed, 241 insertions(+), 286 deletions(-) diff --git a/drivers/iio/dac/ad5686-spi.c b/drivers/iio/dac/ad5686-spi.c index cec784b617e6..3a2eafedce92 100644 --- a/drivers/iio/dac/ad5686-spi.c +++ b/drivers/iio/dac/ad5686-spi.c @@ -94,29 +94,27 @@ static int ad5686_spi_read(struct ad5686_state *st, u8 addr) static int ad5686_spi_probe(struct spi_device *spi) { - const struct spi_device_id *id = spi_get_device_id(spi); - - return ad5686_probe(&spi->dev, id->driver_data, id->name, - ad5686_spi_write, ad5686_spi_read); + return ad5686_probe(&spi->dev, spi_get_device_match_data(spi), + spi->modalias, ad5686_spi_write, ad5686_spi_read); } static const struct spi_device_id ad5686_spi_id[] = { - {"ad5310r", ID_AD5310R}, - {"ad5672r", ID_AD5672R}, - {"ad5674r", ID_AD5674R}, - {"ad5676", ID_AD5676}, - {"ad5676r", ID_AD5676R}, - {"ad5679r", ID_AD5679R}, - {"ad5681r", ID_AD5681R}, - {"ad5682r", ID_AD5682R}, - {"ad5683", ID_AD5683}, - {"ad5683r", ID_AD5683R}, - {"ad5684", ID_AD5684}, - {"ad5684r", ID_AD5684R}, - {"ad5685", ID_AD5685R}, /* Does not exist */ - {"ad5685r", ID_AD5685R}, - {"ad5686", ID_AD5686}, - {"ad5686r", ID_AD5686R}, + { .name = "ad5310r", .driver_data = (kernel_ulong_t)&ad5310r_chip_info }, + { .name = "ad5672r", .driver_data = (kernel_ulong_t)&ad5672r_chip_info }, + { .name = "ad5674r", .driver_data = (kernel_ulong_t)&ad5674r_chip_info }, + { .name = "ad5676", .driver_data = (kernel_ulong_t)&ad5676_chip_info }, + { .name = "ad5676r", .driver_data = (kernel_ulong_t)&ad5676r_chip_info }, + { .name = "ad5679r", .driver_data = (kernel_ulong_t)&ad5679r_chip_info }, + { .name = "ad5681r", .driver_data = (kernel_ulong_t)&ad5681r_chip_info }, + { .name = "ad5682r", .driver_data = (kernel_ulong_t)&ad5682r_chip_info }, + { .name = "ad5683", .driver_data = (kernel_ulong_t)&ad5683_chip_info }, + { .name = "ad5683r", .driver_data = (kernel_ulong_t)&ad5683r_chip_info }, + { .name = "ad5684", .driver_data = (kernel_ulong_t)&ad5684_chip_info }, + { .name = "ad5684r", .driver_data = (kernel_ulong_t)&ad5684r_chip_info }, + { .name = "ad5685", .driver_data = (kernel_ulong_t)&ad5685r_chip_info }, /* nonexistent */ + { .name = "ad5685r", .driver_data = (kernel_ulong_t)&ad5685r_chip_info }, + { .name = "ad5686", .driver_data = (kernel_ulong_t)&ad5686_chip_info }, + { .name = "ad5686r", .driver_data = (kernel_ulong_t)&ad5686r_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad5686_spi_id); diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c index 1df1145f35b3..431e7650704e 100644 --- a/drivers/iio/dac/ad5686.c +++ b/drivers/iio/dac/ad5686.c @@ -219,7 +219,7 @@ static const struct iio_chan_spec_ext_info ad5686_ext_info[] = { .ext_info = ad5686_ext_info, \ } -#define DECLARE_AD5693_CHANNELS(name, bits, _shift) \ +#define DECLARE_AD5683_CHANNELS(name, bits, _shift) \ static const struct iio_chan_spec name[] = { \ AD5868_CHANNEL(0, 0, bits, _shift), \ } @@ -270,205 +270,172 @@ static const struct iio_chan_spec name[] = { \ AD5868_CHANNEL(15, 15, bits, _shift), \ } -DECLARE_AD5693_CHANNELS(ad5310r_channels, 10, 2); -DECLARE_AD5693_CHANNELS(ad5311r_channels, 10, 6); +/* single-channel */ +DECLARE_AD5683_CHANNELS(ad5310r_channels, 10, 2); +DECLARE_AD5683_CHANNELS(ad5311r_channels, 10, 6); +DECLARE_AD5683_CHANNELS(ad5681r_channels, 12, 4); +DECLARE_AD5683_CHANNELS(ad5682r_channels, 14, 2); +DECLARE_AD5683_CHANNELS(ad5683r_channels, 16, 0); + +/* dual-channel */ DECLARE_AD5338_CHANNELS(ad5337r_channels, 8, 8); DECLARE_AD5338_CHANNELS(ad5338r_channels, 10, 6); -DECLARE_AD5676_CHANNELS(ad5672_channels, 12, 4); -DECLARE_AD5679_CHANNELS(ad5674r_channels, 12, 4); -DECLARE_AD5676_CHANNELS(ad5676_channels, 16, 0); -DECLARE_AD5679_CHANNELS(ad5679r_channels, 16, 0); -DECLARE_AD5686_CHANNELS(ad5684_channels, 12, 4); -DECLARE_AD5686_CHANNELS(ad5685r_channels, 14, 2); -DECLARE_AD5686_CHANNELS(ad5686_channels, 16, 0); -DECLARE_AD5693_CHANNELS(ad5693_channels, 16, 0); -DECLARE_AD5693_CHANNELS(ad5692r_channels, 14, 2); -DECLARE_AD5693_CHANNELS(ad5691r_channels, 12, 4); -static const struct ad5686_chip_info ad5686_chip_info_tbl[] = { - [ID_AD5310R] = { - .channels = ad5310r_channels, - .int_vref_mv = 2500, - .num_channels = 1, - .regmap_type = AD5310_REGMAP, - }, - [ID_AD5311R] = { - .channels = ad5311r_channels, - .int_vref_mv = 2500, - .num_channels = 1, - .regmap_type = AD5683_REGMAP, - }, - [ID_AD5337R] = { - .channels = ad5337r_channels, - .int_vref_mv = 2500, - .num_channels = 2, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5338R] = { - .channels = ad5338r_channels, - .int_vref_mv = 2500, - .num_channels = 2, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5671R] = { - .channels = ad5672_channels, - .int_vref_mv = 2500, - .num_channels = 8, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5672R] = { - .channels = ad5672_channels, - .int_vref_mv = 2500, - .num_channels = 8, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5673R] = { - .channels = ad5674r_channels, - .int_vref_mv = 2500, - .num_channels = 16, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5674R] = { - .channels = ad5674r_channels, - .int_vref_mv = 2500, - .num_channels = 16, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5675R] = { - .channels = ad5676_channels, - .int_vref_mv = 2500, - .num_channels = 8, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5676] = { - .channels = ad5676_channels, - .num_channels = 8, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5676R] = { - .channels = ad5676_channels, - .int_vref_mv = 2500, - .num_channels = 8, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5677R] = { - .channels = ad5679r_channels, - .int_vref_mv = 2500, - .num_channels = 16, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5679R] = { - .channels = ad5679r_channels, - .int_vref_mv = 2500, - .num_channels = 16, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5681R] = { - .channels = ad5691r_channels, - .int_vref_mv = 2500, - .num_channels = 1, - .regmap_type = AD5683_REGMAP, - }, - [ID_AD5682R] = { - .channels = ad5692r_channels, - .int_vref_mv = 2500, - .num_channels = 1, - .regmap_type = AD5683_REGMAP, - }, - [ID_AD5683] = { - .channels = ad5693_channels, - .num_channels = 1, - .regmap_type = AD5683_REGMAP, - }, - [ID_AD5683R] = { - .channels = ad5693_channels, - .int_vref_mv = 2500, - .num_channels = 1, - .regmap_type = AD5683_REGMAP, - }, - [ID_AD5684] = { - .channels = ad5684_channels, - .num_channels = 4, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5684R] = { - .channels = ad5684_channels, - .int_vref_mv = 2500, - .num_channels = 4, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5685R] = { - .channels = ad5685r_channels, - .int_vref_mv = 2500, - .num_channels = 4, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5686] = { - .channels = ad5686_channels, - .num_channels = 4, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5686R] = { - .channels = ad5686_channels, - .int_vref_mv = 2500, - .num_channels = 4, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5691R] = { - .channels = ad5691r_channels, - .int_vref_mv = 2500, - .num_channels = 1, - .regmap_type = AD5683_REGMAP, - }, - [ID_AD5692R] = { - .channels = ad5692r_channels, - .int_vref_mv = 2500, - .num_channels = 1, - .regmap_type = AD5683_REGMAP, - }, - [ID_AD5693] = { - .channels = ad5693_channels, - .num_channels = 1, - .regmap_type = AD5683_REGMAP, - }, - [ID_AD5693R] = { - .channels = ad5693_channels, - .int_vref_mv = 2500, - .num_channels = 1, - .regmap_type = AD5683_REGMAP, - }, - [ID_AD5694] = { - .channels = ad5684_channels, - .num_channels = 4, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5694R] = { - .channels = ad5684_channels, - .int_vref_mv = 2500, - .num_channels = 4, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5695R] = { - .channels = ad5685r_channels, - .int_vref_mv = 2500, - .num_channels = 4, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5696] = { - .channels = ad5686_channels, - .num_channels = 4, - .regmap_type = AD5686_REGMAP, - }, - [ID_AD5696R] = { - .channels = ad5686_channels, - .int_vref_mv = 2500, - .num_channels = 4, - .regmap_type = AD5686_REGMAP, - }, +/* quad-channel */ +DECLARE_AD5686_CHANNELS(ad5684r_channels, 12, 4); +DECLARE_AD5686_CHANNELS(ad5685r_channels, 14, 2); +DECLARE_AD5686_CHANNELS(ad5686r_channels, 16, 0); + +/* 8-channel */ +DECLARE_AD5676_CHANNELS(ad5672r_channels, 12, 4); +DECLARE_AD5676_CHANNELS(ad5676r_channels, 16, 0); + +/* 16-channel */ +DECLARE_AD5679_CHANNELS(ad5674r_channels, 12, 4); +DECLARE_AD5679_CHANNELS(ad5679r_channels, 16, 0); + +const struct ad5686_chip_info ad5310r_chip_info = { + .channels = ad5310r_channels, + .int_vref_mv = 2500, + .num_channels = 1, + .regmap_type = AD5310_REGMAP, }; +EXPORT_SYMBOL_NS_GPL(ad5310r_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5311r_chip_info = { + .channels = ad5311r_channels, + .int_vref_mv = 2500, + .num_channels = 1, + .regmap_type = AD5683_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5311r_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5681r_chip_info = { + .channels = ad5681r_channels, + .int_vref_mv = 2500, + .num_channels = 1, + .regmap_type = AD5683_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5681r_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5682r_chip_info = { + .channels = ad5682r_channels, + .int_vref_mv = 2500, + .num_channels = 1, + .regmap_type = AD5683_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5682r_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5683_chip_info = { + .channels = ad5683r_channels, + .num_channels = 1, + .regmap_type = AD5683_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5683_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5683r_chip_info = { + .channels = ad5683r_channels, + .int_vref_mv = 2500, + .num_channels = 1, + .regmap_type = AD5683_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5683r_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5337r_chip_info = { + .channels = ad5337r_channels, + .int_vref_mv = 2500, + .num_channels = 2, + .regmap_type = AD5686_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5337r_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5338r_chip_info = { + .channels = ad5338r_channels, + .int_vref_mv = 2500, + .num_channels = 2, + .regmap_type = AD5686_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5338r_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5684_chip_info = { + .channels = ad5684r_channels, + .num_channels = 4, + .regmap_type = AD5686_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5684_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5684r_chip_info = { + .channels = ad5684r_channels, + .int_vref_mv = 2500, + .num_channels = 4, + .regmap_type = AD5686_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5684r_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5685r_chip_info = { + .channels = ad5685r_channels, + .int_vref_mv = 2500, + .num_channels = 4, + .regmap_type = AD5686_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5685r_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5686_chip_info = { + .channels = ad5686r_channels, + .num_channels = 4, + .regmap_type = AD5686_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5686_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5686r_chip_info = { + .channels = ad5686r_channels, + .int_vref_mv = 2500, + .num_channels = 4, + .regmap_type = AD5686_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5686r_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5672r_chip_info = { + .channels = ad5672r_channels, + .int_vref_mv = 2500, + .num_channels = 8, + .regmap_type = AD5686_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5672r_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5676_chip_info = { + .channels = ad5676r_channels, + .num_channels = 8, + .regmap_type = AD5686_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5676_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5676r_chip_info = { + .channels = ad5676r_channels, + .int_vref_mv = 2500, + .num_channels = 8, + .regmap_type = AD5686_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5676r_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5674r_chip_info = { + .channels = ad5674r_channels, + .int_vref_mv = 2500, + .num_channels = 16, + .regmap_type = AD5686_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5674r_chip_info, "IIO_AD5686"); + +const struct ad5686_chip_info ad5679r_chip_info = { + .channels = ad5679r_channels, + .int_vref_mv = 2500, + .num_channels = 16, + .regmap_type = AD5686_REGMAP, +}; +EXPORT_SYMBOL_NS_GPL(ad5679r_chip_info, "IIO_AD5686"); int ad5686_probe(struct device *dev, - enum ad5686_supported_device_ids chip_type, + const struct ad5686_chip_info *chip_info, const char *name, ad5686_write_func write, ad5686_read_func read) { @@ -488,8 +455,7 @@ int ad5686_probe(struct device *dev, st->dev = dev; st->write = write; st->read = read; - - st->chip_info = &ad5686_chip_info_tbl[chip_type]; + st->chip_info = chip_info; ret = devm_regulator_get_enable_read_voltage(dev, "vcc"); if (ret < 0 && ret != -ENODEV) diff --git a/drivers/iio/dac/ad5686.h b/drivers/iio/dac/ad5686.h index af15994c01ad..caadc7403da1 100644 --- a/drivers/iio/dac/ad5686.h +++ b/drivers/iio/dac/ad5686.h @@ -47,42 +47,6 @@ #define AD5683_REF_BIT_MSK BIT(12) #define AD5686_REF_BIT_MSK BIT(0) -/** - * ad5686_supported_device_ids: - */ -enum ad5686_supported_device_ids { - ID_AD5310R, - ID_AD5311R, - ID_AD5337R, - ID_AD5338R, - ID_AD5671R, - ID_AD5672R, - ID_AD5673R, - ID_AD5674R, - ID_AD5675R, - ID_AD5676, - ID_AD5676R, - ID_AD5677R, - ID_AD5679R, - ID_AD5681R, - ID_AD5682R, - ID_AD5683, - ID_AD5683R, - ID_AD5684, - ID_AD5684R, - ID_AD5685R, - ID_AD5686, - ID_AD5686R, - ID_AD5691R, - ID_AD5692R, - ID_AD5693, - ID_AD5693R, - ID_AD5694, - ID_AD5694R, - ID_AD5695R, - ID_AD5696, - ID_AD5696R, -}; enum ad5686_regmap_type { AD5310_REGMAP, @@ -112,6 +76,34 @@ struct ad5686_chip_info { enum ad5686_regmap_type regmap_type; }; +/* single-channel instances */ +extern const struct ad5686_chip_info ad5310r_chip_info; +extern const struct ad5686_chip_info ad5311r_chip_info; +extern const struct ad5686_chip_info ad5681r_chip_info; +extern const struct ad5686_chip_info ad5682r_chip_info; +extern const struct ad5686_chip_info ad5683_chip_info; +extern const struct ad5686_chip_info ad5683r_chip_info; + +/* dual-channel instances */ +extern const struct ad5686_chip_info ad5337r_chip_info; +extern const struct ad5686_chip_info ad5338r_chip_info; + +/* quad-channel instances */ +extern const struct ad5686_chip_info ad5684_chip_info; +extern const struct ad5686_chip_info ad5684r_chip_info; +extern const struct ad5686_chip_info ad5685r_chip_info; +extern const struct ad5686_chip_info ad5686_chip_info; +extern const struct ad5686_chip_info ad5686r_chip_info; + +/* 8-channel instances */ +extern const struct ad5686_chip_info ad5672r_chip_info; +extern const struct ad5686_chip_info ad5676_chip_info; +extern const struct ad5686_chip_info ad5676r_chip_info; + +/* 16-channel instances */ +extern const struct ad5686_chip_info ad5674r_chip_info; +extern const struct ad5686_chip_info ad5679r_chip_info; + /** * struct ad5686_state - driver instance specific data * @spi: spi_device @@ -149,7 +141,7 @@ struct ad5686_state { int ad5686_probe(struct device *dev, - enum ad5686_supported_device_ids chip_type, + const struct ad5686_chip_info *chip_info, const char *name, ad5686_write_func write, ad5686_read_func read); diff --git a/drivers/iio/dac/ad5696-i2c.c b/drivers/iio/dac/ad5696-i2c.c index 645ef441c463..c1f3cebabaf8 100644 --- a/drivers/iio/dac/ad5696-i2c.c +++ b/drivers/iio/dac/ad5696-i2c.c @@ -64,47 +64,46 @@ static int ad5686_i2c_write(struct ad5686_state *st, static int ad5686_i2c_probe(struct i2c_client *i2c) { - const struct i2c_device_id *id = i2c_client_get_device_id(i2c); - return ad5686_probe(&i2c->dev, id->driver_data, id->name, - ad5686_i2c_write, ad5686_i2c_read); + return ad5686_probe(&i2c->dev, i2c_get_match_data(i2c), + i2c->name, ad5686_i2c_write, ad5686_i2c_read); } static const struct i2c_device_id ad5686_i2c_id[] = { - { .name = "ad5311r", .driver_data = ID_AD5311R }, - { .name = "ad5337r", .driver_data = ID_AD5337R }, - { .name = "ad5338r", .driver_data = ID_AD5338R }, - { .name = "ad5671r", .driver_data = ID_AD5671R }, - { .name = "ad5673r", .driver_data = ID_AD5673R }, - { .name = "ad5675r", .driver_data = ID_AD5675R }, - { .name = "ad5677r", .driver_data = ID_AD5677R }, - { .name = "ad5691r", .driver_data = ID_AD5691R }, - { .name = "ad5692r", .driver_data = ID_AD5692R }, - { .name = "ad5693", .driver_data = ID_AD5693 }, - { .name = "ad5693r", .driver_data = ID_AD5693R }, - { .name = "ad5694", .driver_data = ID_AD5694 }, - { .name = "ad5694r", .driver_data = ID_AD5694R }, - { .name = "ad5695r", .driver_data = ID_AD5695R }, - { .name = "ad5696", .driver_data = ID_AD5696 }, - { .name = "ad5696r", .driver_data = ID_AD5696R }, + { .name = "ad5311r", .driver_data = (kernel_ulong_t)&ad5311r_chip_info }, + { .name = "ad5337r", .driver_data = (kernel_ulong_t)&ad5337r_chip_info }, + { .name = "ad5338r", .driver_data = (kernel_ulong_t)&ad5338r_chip_info }, + { .name = "ad5671r", .driver_data = (kernel_ulong_t)&ad5672r_chip_info }, + { .name = "ad5673r", .driver_data = (kernel_ulong_t)&ad5674r_chip_info }, + { .name = "ad5675r", .driver_data = (kernel_ulong_t)&ad5676r_chip_info }, + { .name = "ad5677r", .driver_data = (kernel_ulong_t)&ad5679r_chip_info }, + { .name = "ad5691r", .driver_data = (kernel_ulong_t)&ad5681r_chip_info }, + { .name = "ad5692r", .driver_data = (kernel_ulong_t)&ad5682r_chip_info }, + { .name = "ad5693", .driver_data = (kernel_ulong_t)&ad5683_chip_info }, + { .name = "ad5693r", .driver_data = (kernel_ulong_t)&ad5683r_chip_info }, + { .name = "ad5694", .driver_data = (kernel_ulong_t)&ad5684_chip_info }, + { .name = "ad5694r", .driver_data = (kernel_ulong_t)&ad5684r_chip_info }, + { .name = "ad5695r", .driver_data = (kernel_ulong_t)&ad5685r_chip_info }, + { .name = "ad5696", .driver_data = (kernel_ulong_t)&ad5686_chip_info }, + { .name = "ad5696r", .driver_data = (kernel_ulong_t)&ad5686r_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, ad5686_i2c_id); static const struct of_device_id ad5686_of_match[] = { - { .compatible = "adi,ad5311r" }, - { .compatible = "adi,ad5337r" }, - { .compatible = "adi,ad5338r" }, - { .compatible = "adi,ad5671r" }, - { .compatible = "adi,ad5675r" }, - { .compatible = "adi,ad5691r" }, - { .compatible = "adi,ad5692r" }, - { .compatible = "adi,ad5693" }, - { .compatible = "adi,ad5693r" }, - { .compatible = "adi,ad5694" }, - { .compatible = "adi,ad5694r" }, - { .compatible = "adi,ad5695r" }, - { .compatible = "adi,ad5696" }, - { .compatible = "adi,ad5696r" }, + { .compatible = "adi,ad5311r", .data = &ad5311r_chip_info }, + { .compatible = "adi,ad5337r", .data = &ad5337r_chip_info }, + { .compatible = "adi,ad5338r", .data = &ad5338r_chip_info }, + { .compatible = "adi,ad5671r", .data = &ad5672r_chip_info }, + { .compatible = "adi,ad5675r", .data = &ad5676r_chip_info }, + { .compatible = "adi,ad5691r", .data = &ad5681r_chip_info }, + { .compatible = "adi,ad5692r", .data = &ad5682r_chip_info }, + { .compatible = "adi,ad5693", .data = &ad5683_chip_info }, + { .compatible = "adi,ad5693r", .data = &ad5683r_chip_info }, + { .compatible = "adi,ad5694", .data = &ad5684_chip_info }, + { .compatible = "adi,ad5694r", .data = &ad5684r_chip_info }, + { .compatible = "adi,ad5695r", .data = &ad5685r_chip_info }, + { .compatible = "adi,ad5696", .data = &ad5686_chip_info }, + { .compatible = "adi,ad5696r", .data = &ad5686r_chip_info }, { } }; MODULE_DEVICE_TABLE(of, ad5686_of_match); From 34222a45490910141053aa7c46601bb2c27ac82c Mon Sep 17 00:00:00 2001 From: Rodrigo Alencar Date: Sun, 24 May 2026 11:17:04 +0100 Subject: [PATCH 259/266] iio: dac: ad5686: add of_match table to the spi driver Add of_match table for the SPI device variants to be consistent with the AD5696 I2C driver. Reviewed-by: Andy Shevchenko Signed-off-by: Rodrigo Alencar Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad5686-spi.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/iio/dac/ad5686-spi.c b/drivers/iio/dac/ad5686-spi.c index 3a2eafedce92..7eddffe86c00 100644 --- a/drivers/iio/dac/ad5686-spi.c +++ b/drivers/iio/dac/ad5686-spi.c @@ -119,9 +119,30 @@ static const struct spi_device_id ad5686_spi_id[] = { }; MODULE_DEVICE_TABLE(spi, ad5686_spi_id); +static const struct of_device_id ad5686_of_match[] = { + { .compatible = "adi,ad5310r", .data = &ad5310r_chip_info }, + { .compatible = "adi,ad5672r", .data = &ad5672r_chip_info }, + { .compatible = "adi,ad5674r", .data = &ad5674r_chip_info }, + { .compatible = "adi,ad5676", .data = &ad5676_chip_info }, + { .compatible = "adi,ad5676r", .data = &ad5676r_chip_info }, + { .compatible = "adi,ad5679r", .data = &ad5679r_chip_info }, + { .compatible = "adi,ad5681r", .data = &ad5681r_chip_info }, + { .compatible = "adi,ad5682r", .data = &ad5682r_chip_info }, + { .compatible = "adi,ad5683", .data = &ad5683_chip_info }, + { .compatible = "adi,ad5683r", .data = &ad5683r_chip_info }, + { .compatible = "adi,ad5684", .data = &ad5684_chip_info }, + { .compatible = "adi,ad5684r", .data = &ad5684r_chip_info }, + { .compatible = "adi,ad5685r", .data = &ad5685r_chip_info }, + { .compatible = "adi,ad5686", .data = &ad5686_chip_info }, + { .compatible = "adi,ad5686r", .data = &ad5686r_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(of, ad5686_of_match); + static struct spi_driver ad5686_spi_driver = { .driver = { .name = "ad5686", + .of_match_table = ad5686_of_match, }, .probe = ad5686_spi_probe, .id_table = ad5686_spi_id, From 16fc40c250198d970ae6dafbecf000fe68773c4d Mon Sep 17 00:00:00 2001 From: Rodrigo Alencar Date: Sun, 24 May 2026 11:17:05 +0100 Subject: [PATCH 260/266] iio: dac: ad5686: add helpers to handle powerdown masks Add ad5686_pd_field_set() and ad5686_pd_field_get() helpers to cleanup powerdown mask control. Define AD5686_PD_* constants, e.g. AD5686_PD_MSK to hold powerdown mask value for a single channel. AD5686_LDAC_PWRDN_* macros are replaced by AD5686_PD_MODE_*, because they are unused and the LDAC feature for async load of DAC channel values is not related to power down control. Signed-off-by: Rodrigo Alencar Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad5686.c | 40 ++++++++++++++++++++++++++-------------- drivers/iio/dac/ad5686.h | 13 ++++++++----- 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c index 431e7650704e..3409b551dbf7 100644 --- a/drivers/iio/dac/ad5686.c +++ b/drivers/iio/dac/ad5686.c @@ -33,28 +33,40 @@ static inline unsigned int ad5686_pd_mask_shift(const struct iio_chan_spec *chan return __ffs(chan->address) * 2; } +static inline void ad5686_pd_field_set(const struct iio_chan_spec *chan, + unsigned int *pd, unsigned int val) +{ + unsigned int shift = ad5686_pd_mask_shift(chan); + + *pd = (*pd & ~(AD5686_PD_MSK << shift)) | ((val & AD5686_PD_MSK) << shift); +} + +static inline unsigned int ad5686_pd_field_get(const struct iio_chan_spec *chan, + unsigned int pd) +{ + unsigned int shift = ad5686_pd_mask_shift(chan); + + return (pd >> shift) & AD5686_PD_MSK; +} + static int ad5686_get_powerdown_mode(struct iio_dev *indio_dev, const struct iio_chan_spec *chan) { - unsigned int shift = ad5686_pd_mask_shift(chan); struct ad5686_state *st = iio_priv(indio_dev); guard(mutex)(&st->lock); - return ((st->pwr_down_mode >> shift) & 0x3U) - 1; + return ad5686_pd_field_get(chan, st->pwr_down_mode) - 1; } static int ad5686_set_powerdown_mode(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, unsigned int mode) { - unsigned int shift = ad5686_pd_mask_shift(chan); struct ad5686_state *st = iio_priv(indio_dev); guard(mutex)(&st->lock); - - st->pwr_down_mode &= ~(0x3U << shift); - st->pwr_down_mode |= (mode + 1) << shift; + ad5686_pd_field_set(chan, &st->pwr_down_mode, mode + 1); return 0; } @@ -69,12 +81,12 @@ static const struct iio_enum ad5686_powerdown_mode_enum = { static ssize_t ad5686_read_dac_powerdown(struct iio_dev *indio_dev, uintptr_t private, const struct iio_chan_spec *chan, char *buf) { - unsigned int shift = ad5686_pd_mask_shift(chan); struct ad5686_state *st = iio_priv(indio_dev); guard(mutex)(&st->lock); - return sysfs_emit(buf, "%d\n", !!(st->pwr_down_mask & (0x3U << shift))); + return sysfs_emit(buf, "%d\n", + !!ad5686_pd_field_get(chan, st->pwr_down_mask)); } static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev, @@ -96,9 +108,9 @@ static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev, guard(mutex)(&st->lock); if (readin) - st->pwr_down_mask |= 0x3U << ad5686_pd_mask_shift(chan); + ad5686_pd_field_set(chan, &st->pwr_down_mask, AD5686_PD_MSK_PWR_DOWN); else - st->pwr_down_mask &= ~(0x3U << ad5686_pd_mask_shift(chan)); + ad5686_pd_field_set(chan, &st->pwr_down_mask, AD5686_PD_MSK_PWR_UP); switch (st->chip_info->regmap_type) { case AD5310_REGMAP: @@ -471,10 +483,10 @@ int ad5686_probe(struct device *dev, /* Set all the power down mode for all channels to 1K pulldown */ for (i = 0; i < st->chip_info->num_channels; i++) { - shift = ad5686_pd_mask_shift(&st->chip_info->channels[i]); - st->pwr_down_mask &= ~(0x3U << shift); /* powered up state */ - st->pwr_down_mode &= ~(0x3U << shift); - st->pwr_down_mode |= 0x01U << shift; + ad5686_pd_field_set(&st->chip_info->channels[i], + &st->pwr_down_mask, AD5686_PD_MSK_PWR_UP); + ad5686_pd_field_set(&st->chip_info->channels[i], + &st->pwr_down_mode, AD5686_PD_MODE_1K_TO_GND); } indio_dev->name = name; diff --git a/drivers/iio/dac/ad5686.h b/drivers/iio/dac/ad5686.h index caadc7403da1..176d41966985 100644 --- a/drivers/iio/dac/ad5686.h +++ b/drivers/iio/dac/ad5686.h @@ -35,11 +35,6 @@ #define AD5686_CMD_DAISY_CHAIN_ENABLE 0x8 #define AD5686_CMD_READBACK_ENABLE 0x9 -#define AD5686_LDAC_PWRDN_NONE 0x0 -#define AD5686_LDAC_PWRDN_1K 0x1 -#define AD5686_LDAC_PWRDN_100K 0x2 -#define AD5686_LDAC_PWRDN_3STATE 0x3 - #define AD5686_CMD_CONTROL_REG 0x4 #define AD5686_CMD_READBACK_ENABLE_V2 0x5 @@ -47,6 +42,14 @@ #define AD5683_REF_BIT_MSK BIT(12) #define AD5686_REF_BIT_MSK BIT(0) +#define AD5686_PD_MSK GENMASK(1, 0) + +#define AD5686_PD_MODE_1K_TO_GND 0x1 +#define AD5686_PD_MODE_100K_TO_GND 0x2 +#define AD5686_PD_MODE_THREE_STATE 0x3 + +#define AD5686_PD_MSK_PWR_UP 0x0 +#define AD5686_PD_MSK_PWR_DOWN 0x3 enum ad5686_regmap_type { AD5310_REGMAP, From 592b378791d620ba479428eac6fb3c4bc2b18388 Mon Sep 17 00:00:00 2001 From: Rodrigo Alencar Date: Sun, 24 May 2026 11:17:06 +0100 Subject: [PATCH 261/266] iio: dac: ad5686: add control_sync() for single-channel devices Create ad5310_control_sync() and ad5683_control_sync() functions that properly consume the mask definitions with FIELD_PREP(). This allows to reuse a function that updates the control register with cached values, without relying on confusing logic that depends on st->use_internal_vref, which is initialized earlier in ad5686_probe() because it is also applicable to the AD5686_REGMAP case, removing the need for the has_external_vref. Powerdown masks initialization is simplified as *_control_sync() masks outs any unused bits for the single-channel case. The change cleans up ad5686_write_dac_powerdown() and ad5686_probe(), organizing the code for feature extension, e.g. gain control support for single-channel devices. Signed-off-by: Rodrigo Alencar Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad5686.c | 94 +++++++++++++++++++++++----------------- drivers/iio/dac/ad5686.h | 7 ++- 2 files changed, 59 insertions(+), 42 deletions(-) diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c index 3409b551dbf7..86bc944a1acd 100644 --- a/drivers/iio/dac/ad5686.c +++ b/drivers/iio/dac/ad5686.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -13,6 +14,7 @@ #include #include #include +#include #include @@ -24,6 +26,24 @@ static const char * const ad5686_powerdown_modes[] = { "three_state" }; +static int ad5310_control_sync(struct ad5686_state *st) +{ + unsigned int pd_val = st->pwr_down_mask & st->pwr_down_mode; + + return st->write(st, AD5686_CMD_CONTROL_REG, 0, + FIELD_PREP(AD5310_PD_MSK, pd_val & AD5686_PD_MSK) | + FIELD_PREP(AD5310_REF_BIT_MSK, st->use_internal_vref ? 0 : 1)); +} + +static int ad5683_control_sync(struct ad5686_state *st) +{ + unsigned int pd_val = st->pwr_down_mask & st->pwr_down_mode; + + return st->write(st, AD5686_CMD_CONTROL_REG, 0, + FIELD_PREP(AD5683_PD_MSK, pd_val & AD5686_PD_MSK) | + FIELD_PREP(AD5683_REF_BIT_MSK, st->use_internal_vref ? 0 : 1)); +} + static inline unsigned int ad5686_pd_mask_shift(const struct iio_chan_spec *chan) { if (chan->channel == chan->address) @@ -98,8 +118,8 @@ static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev, bool readin; int ret; struct ad5686_state *st = iio_priv(indio_dev); - unsigned int val, ref_bit_msk; - u8 shift, address = 0; + unsigned int val; + u8 address; ret = kstrtobool(buf, &readin); if (ret) @@ -114,32 +134,34 @@ static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev, switch (st->chip_info->regmap_type) { case AD5310_REGMAP: - shift = 9; - ref_bit_msk = AD5310_REF_BIT_MSK; + ret = ad5310_control_sync(st); + if (ret) + return ret; break; case AD5683_REGMAP: - shift = 13; - ref_bit_msk = AD5683_REF_BIT_MSK; + ret = ad5683_control_sync(st); + if (ret) + return ret; break; case AD5686_REGMAP: - shift = 0; - ref_bit_msk = 0; /* AD5674R/AD5679R have 16 channels and 2 powerdown registers */ - if (chan->channel > 0x7) + val = st->pwr_down_mask & st->pwr_down_mode; + if (chan->channel > 0x7) { address = 0x8; + val = upper_16_bits(val); + } else { + address = 0x0; + val = lower_16_bits(val); + } + ret = st->write(st, AD5686_CMD_POWERDOWN_DAC, address, val); + if (ret) + return ret; break; default: return -EINVAL; } - val = ((st->pwr_down_mask & st->pwr_down_mode) << shift); - if (!st->use_internal_vref) - val |= ref_bit_msk; - - ret = st->write(st, AD5686_CMD_POWERDOWN_DAC, - address, val >> (address * 2)); - - return ret ? ret : len; + return len; } static int ad5686_read_raw(struct iio_dev *indio_dev, @@ -453,9 +475,6 @@ int ad5686_probe(struct device *dev, { struct ad5686_state *st; struct iio_dev *indio_dev; - unsigned int val, ref_bit_msk, shift; - bool has_external_vref; - u8 cmd; int ret, i; indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); @@ -473,13 +492,12 @@ int ad5686_probe(struct device *dev, if (ret < 0 && ret != -ENODEV) return ret; - has_external_vref = ret != -ENODEV; - st->vref_mv = has_external_vref ? ret / 1000 : st->chip_info->int_vref_mv; + st->use_internal_vref = ret == -ENODEV; + st->vref_mv = st->use_internal_vref ? st->chip_info->int_vref_mv : ret / 1000; - /* Initialize masks to all ones provided the max shift (last channel) */ - shift = ad5686_pd_mask_shift(&st->chip_info->channels[st->chip_info->num_channels - 1]); - st->pwr_down_mask = GENMASK(shift + 1, 0); - st->pwr_down_mode = GENMASK(shift + 1, 0); + /* Initialize masks to all ones */ + st->pwr_down_mask = ~0; + st->pwr_down_mode = ~0; /* Set all the power down mode for all channels to 1K pulldown */ for (i = 0; i < st->chip_info->num_channels; i++) { @@ -501,29 +519,25 @@ int ad5686_probe(struct device *dev, switch (st->chip_info->regmap_type) { case AD5310_REGMAP: - cmd = AD5686_CMD_CONTROL_REG; - ref_bit_msk = AD5310_REF_BIT_MSK; - st->use_internal_vref = !has_external_vref; + ret = ad5310_control_sync(st); + if (ret) + return ret; break; case AD5683_REGMAP: - cmd = AD5686_CMD_CONTROL_REG; - ref_bit_msk = AD5683_REF_BIT_MSK; - st->use_internal_vref = !has_external_vref; + ret = ad5683_control_sync(st); + if (ret) + return ret; break; case AD5686_REGMAP: - cmd = AD5686_CMD_INTERNAL_REFER_SETUP; - ref_bit_msk = AD5686_REF_BIT_MSK; + ret = st->write(st, AD5686_CMD_INTERNAL_REFER_SETUP, 0, + st->use_internal_vref ? 0 : AD5686_REF_BIT_MSK); + if (ret) + return ret; break; default: return -EINVAL; } - val = has_external_vref ? ref_bit_msk : 0; - - ret = st->write(st, cmd, 0, val); - if (ret) - return ret; - return devm_iio_device_register(dev, indio_dev); } EXPORT_SYMBOL_NS_GPL(ad5686_probe, "IIO_AD5686"); diff --git a/drivers/iio/dac/ad5686.h b/drivers/iio/dac/ad5686.h index 176d41966985..17980c54839c 100644 --- a/drivers/iio/dac/ad5686.h +++ b/drivers/iio/dac/ad5686.h @@ -39,9 +39,12 @@ #define AD5686_CMD_READBACK_ENABLE_V2 0x5 #define AD5310_REF_BIT_MSK BIT(8) -#define AD5683_REF_BIT_MSK BIT(12) -#define AD5686_REF_BIT_MSK BIT(0) +#define AD5310_PD_MSK GENMASK(10, 9) +#define AD5683_REF_BIT_MSK BIT(12) +#define AD5683_PD_MSK GENMASK(14, 13) + +#define AD5686_REF_BIT_MSK BIT(0) #define AD5686_PD_MSK GENMASK(1, 0) #define AD5686_PD_MODE_1K_TO_GND 0x1 From 883a752cc4c6420a2a6ce9cf572564963d4bcadc Mon Sep 17 00:00:00 2001 From: Rodrigo Alencar Date: Sun, 24 May 2026 11:17:07 +0100 Subject: [PATCH 262/266] iio: dac: ad5686: cleanup doc header of local structs Review documentation comment header for ad5686_chip_info and ad5686_state. Update variable names and description and remove unnecessary blank line between comment and struct declaration. Reviewed-by: Andy Shevchenko Signed-off-by: Rodrigo Alencar Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad5686.h | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/iio/dac/ad5686.h b/drivers/iio/dac/ad5686.h index 17980c54839c..3945f5fb6b7e 100644 --- a/drivers/iio/dac/ad5686.h +++ b/drivers/iio/dac/ad5686.h @@ -69,12 +69,11 @@ typedef int (*ad5686_read_func)(struct ad5686_state *st, u8 addr); /** * struct ad5686_chip_info - chip specific information - * @int_vref_mv: AD5620/40/60: the internal reference voltage + * @int_vref_mv: the internal reference voltage * @num_channels: number of channels * @channel: channel specification * @regmap_type: register map layout variant */ - struct ad5686_chip_info { u16 int_vref_mv; unsigned int num_channels; @@ -112,16 +111,16 @@ extern const struct ad5686_chip_info ad5679r_chip_info; /** * struct ad5686_state - driver instance specific data - * @spi: spi_device + * @dev: device instance * @chip_info: chip model specific constants, available modes etc * @vref_mv: actual reference voltage used * @pwr_down_mask: power down mask * @pwr_down_mode: current power down mode * @use_internal_vref: set to true if the internal reference voltage is used - * @lock lock to protect the data buffer during regmap ops - * @data: spi transfer buffers + * @lock: lock to protect access to state fields, which includes + * the data buffer during regmap ops + * @data: transfer buffers */ - struct ad5686_state { struct device *dev; const struct ad5686_chip_info *chip_info; From ae8360f3715aa61714864fc81f39790cbb883d40 Mon Sep 17 00:00:00 2001 From: Rodrigo Alencar Date: Sun, 24 May 2026 11:17:08 +0100 Subject: [PATCH 263/266] iio: dac: ad5686: create bus ops struct Create struct with bus operations, which will be used to extend bus implementation features. Auxiliary functions ad5686_write() and ad5686_read() are created and ad5686_probe() now receives an ops struct pointer rather than individual read and write functions. Reviewed-by: Andy Shevchenko Signed-off-by: Rodrigo Alencar Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad5686-spi.c | 7 ++++++- drivers/iio/dac/ad5686.c | 32 ++++++++++++++------------------ drivers/iio/dac/ad5686.h | 29 +++++++++++++++++++++-------- drivers/iio/dac/ad5696-i2c.c | 7 ++++++- 4 files changed, 47 insertions(+), 28 deletions(-) diff --git a/drivers/iio/dac/ad5686-spi.c b/drivers/iio/dac/ad5686-spi.c index 7eddffe86c00..6b6ef1d7071f 100644 --- a/drivers/iio/dac/ad5686-spi.c +++ b/drivers/iio/dac/ad5686-spi.c @@ -92,10 +92,15 @@ static int ad5686_spi_read(struct ad5686_state *st, u8 addr) return be32_to_cpu(st->data[2].d32); } +static const struct ad5686_bus_ops ad5686_spi_ops = { + .write = ad5686_spi_write, + .read = ad5686_spi_read, +}; + static int ad5686_spi_probe(struct spi_device *spi) { return ad5686_probe(&spi->dev, spi_get_device_match_data(spi), - spi->modalias, ad5686_spi_write, ad5686_spi_read); + spi->modalias, &ad5686_spi_ops); } static const struct spi_device_id ad5686_spi_id[] = { diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c index 86bc944a1acd..5840fda4b011 100644 --- a/drivers/iio/dac/ad5686.c +++ b/drivers/iio/dac/ad5686.c @@ -30,18 +30,18 @@ static int ad5310_control_sync(struct ad5686_state *st) { unsigned int pd_val = st->pwr_down_mask & st->pwr_down_mode; - return st->write(st, AD5686_CMD_CONTROL_REG, 0, - FIELD_PREP(AD5310_PD_MSK, pd_val & AD5686_PD_MSK) | - FIELD_PREP(AD5310_REF_BIT_MSK, st->use_internal_vref ? 0 : 1)); + return ad5686_write(st, AD5686_CMD_CONTROL_REG, 0, + FIELD_PREP(AD5310_PD_MSK, pd_val & AD5686_PD_MSK) | + FIELD_PREP(AD5310_REF_BIT_MSK, st->use_internal_vref ? 0 : 1)); } static int ad5683_control_sync(struct ad5686_state *st) { unsigned int pd_val = st->pwr_down_mask & st->pwr_down_mode; - return st->write(st, AD5686_CMD_CONTROL_REG, 0, - FIELD_PREP(AD5683_PD_MSK, pd_val & AD5686_PD_MSK) | - FIELD_PREP(AD5683_REF_BIT_MSK, st->use_internal_vref ? 0 : 1)); + return ad5686_write(st, AD5686_CMD_CONTROL_REG, 0, + FIELD_PREP(AD5683_PD_MSK, pd_val & AD5686_PD_MSK) | + FIELD_PREP(AD5683_REF_BIT_MSK, st->use_internal_vref ? 0 : 1)); } static inline unsigned int ad5686_pd_mask_shift(const struct iio_chan_spec *chan) @@ -153,7 +153,7 @@ static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev, address = 0x0; val = lower_16_bits(val); } - ret = st->write(st, AD5686_CMD_POWERDOWN_DAC, address, val); + ret = ad5686_write(st, AD5686_CMD_POWERDOWN_DAC, address, val); if (ret) return ret; break; @@ -176,7 +176,7 @@ static int ad5686_read_raw(struct iio_dev *indio_dev, switch (m) { case IIO_CHAN_INFO_RAW: mutex_lock(&st->lock); - ret = st->read(st, chan->address); + ret = ad5686_read(st, chan->address); mutex_unlock(&st->lock); if (ret < 0) return ret; @@ -206,10 +206,8 @@ static int ad5686_write_raw(struct iio_dev *indio_dev, return -EINVAL; mutex_lock(&st->lock); - ret = st->write(st, - AD5686_CMD_WRITE_INPUT_N_UPDATE_N, - chan->address, - val << chan->scan_type.shift); + ret = ad5686_write(st, AD5686_CMD_WRITE_INPUT_N_UPDATE_N, + chan->address, val << chan->scan_type.shift); mutex_unlock(&st->lock); break; default: @@ -470,8 +468,7 @@ EXPORT_SYMBOL_NS_GPL(ad5679r_chip_info, "IIO_AD5686"); int ad5686_probe(struct device *dev, const struct ad5686_chip_info *chip_info, - const char *name, ad5686_write_func write, - ad5686_read_func read) + const char *name, const struct ad5686_bus_ops *ops) { struct ad5686_state *st; struct iio_dev *indio_dev; @@ -484,8 +481,7 @@ int ad5686_probe(struct device *dev, st = iio_priv(indio_dev); st->dev = dev; - st->write = write; - st->read = read; + st->ops = ops; st->chip_info = chip_info; ret = devm_regulator_get_enable_read_voltage(dev, "vcc"); @@ -529,8 +525,8 @@ int ad5686_probe(struct device *dev, return ret; break; case AD5686_REGMAP: - ret = st->write(st, AD5686_CMD_INTERNAL_REFER_SETUP, 0, - st->use_internal_vref ? 0 : AD5686_REF_BIT_MSK); + ret = ad5686_write(st, AD5686_CMD_INTERNAL_REFER_SETUP, 0, + st->use_internal_vref ? 0 : AD5686_REF_BIT_MSK); if (ret) return ret; break; diff --git a/drivers/iio/dac/ad5686.h b/drivers/iio/dac/ad5686.h index 3945f5fb6b7e..a06fe7d89305 100644 --- a/drivers/iio/dac/ad5686.h +++ b/drivers/iio/dac/ad5686.h @@ -62,10 +62,15 @@ enum ad5686_regmap_type { struct ad5686_state; -typedef int (*ad5686_write_func)(struct ad5686_state *st, - u8 cmd, u8 addr, u16 val); - -typedef int (*ad5686_read_func)(struct ad5686_state *st, u8 addr); +/** + * struct ad5686_bus_ops - bus specific read/write operations + * @read: read a register value at the given address + * @write: write a command, address and value to the device + */ +struct ad5686_bus_ops { + int (*read)(struct ad5686_state *st, u8 addr); + int (*write)(struct ad5686_state *st, u8 cmd, u8 addr, u16 val); +}; /** * struct ad5686_chip_info - chip specific information @@ -113,6 +118,7 @@ extern const struct ad5686_chip_info ad5679r_chip_info; * struct ad5686_state - driver instance specific data * @dev: device instance * @chip_info: chip model specific constants, available modes etc + * @ops: bus specific operations * @vref_mv: actual reference voltage used * @pwr_down_mask: power down mask * @pwr_down_mode: current power down mode @@ -124,11 +130,10 @@ extern const struct ad5686_chip_info ad5679r_chip_info; struct ad5686_state { struct device *dev; const struct ad5686_chip_info *chip_info; + const struct ad5686_bus_ops *ops; unsigned short vref_mv; unsigned int pwr_down_mask; unsigned int pwr_down_mode; - ad5686_write_func write; - ad5686_read_func read; bool use_internal_vref; struct mutex lock; @@ -147,8 +152,16 @@ struct ad5686_state { int ad5686_probe(struct device *dev, const struct ad5686_chip_info *chip_info, - const char *name, ad5686_write_func write, - ad5686_read_func read); + const char *name, const struct ad5686_bus_ops *ops); +static inline int ad5686_write(struct ad5686_state *st, u8 cmd, u8 addr, u16 val) +{ + return st->ops->write(st, cmd, addr, val); +} + +static inline int ad5686_read(struct ad5686_state *st, u8 addr) +{ + return st->ops->read(st, addr); +} #endif /* __DRIVERS_IIO_DAC_AD5686_H__ */ diff --git a/drivers/iio/dac/ad5696-i2c.c b/drivers/iio/dac/ad5696-i2c.c index c1f3cebabaf8..279309329b64 100644 --- a/drivers/iio/dac/ad5696-i2c.c +++ b/drivers/iio/dac/ad5696-i2c.c @@ -62,10 +62,15 @@ static int ad5686_i2c_write(struct ad5686_state *st, return (ret != 3) ? -EIO : 0; } +static const struct ad5686_bus_ops ad5686_i2c_ops = { + .write = ad5686_i2c_write, + .read = ad5686_i2c_read, +}; + static int ad5686_i2c_probe(struct i2c_client *i2c) { return ad5686_probe(&i2c->dev, i2c_get_match_data(i2c), - i2c->name, ad5686_i2c_write, ad5686_i2c_read); + i2c->name, &ad5686_i2c_ops); } static const struct i2c_device_id ad5686_i2c_id[] = { From b1d1bfa26c661ad18a37456a3153b8f15826e0ad Mon Sep 17 00:00:00 2001 From: Lucas Rabaquim Date: Tue, 2 Jun 2026 15:11:49 -0300 Subject: [PATCH 264/266] iio: light: tsl2591: remove unneeded tsl2591_compatible_als_persist_cycle() The function was only used to verify if als_persist is a TSL2591_PRST_ALS_INT_CYCLE_* value. However, before its call in tsl2591_write_event_value(), the line als_persist = tsl2591_persist_lit_to_cycle(period) is executed, meaning that by the time tsl2591_compatible_als_persist_cycle() is reached, als_persist is a TSL2591_PRST_ALS_INT_CYCLE_* value, making the verification pointless. Suggested-by: Sashiko Link: https://sashiko.dev/#/patchset/20260528185912.24774-1-matheus.feitosa%40usp.br Signed-off-by: Lucas Rabaquim Co-developed-by: Matheus Silveira Signed-off-by: Matheus Silveira Signed-off-by: Jonathan Cameron --- drivers/iio/light/tsl2591.c | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/drivers/iio/light/tsl2591.c b/drivers/iio/light/tsl2591.c index ac5e1822b993..f3ffa9721ad5 100644 --- a/drivers/iio/light/tsl2591.c +++ b/drivers/iio/light/tsl2591.c @@ -308,31 +308,6 @@ static int tsl2591_compatible_gain(struct tsl2591_chip *chip, const u8 als_gain) } } -static int tsl2591_compatible_als_persist_cycle(struct tsl2591_chip *chip, - const u32 als_persist) -{ - switch (als_persist) { - case TSL2591_PRST_ALS_INT_CYCLE_ANY: - case TSL2591_PRST_ALS_INT_CYCLE_2: - case TSL2591_PRST_ALS_INT_CYCLE_3: - case TSL2591_PRST_ALS_INT_CYCLE_5: - case TSL2591_PRST_ALS_INT_CYCLE_10: - case TSL2591_PRST_ALS_INT_CYCLE_15: - case TSL2591_PRST_ALS_INT_CYCLE_20: - case TSL2591_PRST_ALS_INT_CYCLE_25: - case TSL2591_PRST_ALS_INT_CYCLE_30: - case TSL2591_PRST_ALS_INT_CYCLE_35: - case TSL2591_PRST_ALS_INT_CYCLE_40: - case TSL2591_PRST_ALS_INT_CYCLE_45: - case TSL2591_PRST_ALS_INT_CYCLE_50: - case TSL2591_PRST_ALS_INT_CYCLE_55: - case TSL2591_PRST_ALS_INT_CYCLE_60: - return 0; - default: - return -EINVAL; - } -} - static int tsl2591_check_als_valid(struct i2c_client *client) { int ret; @@ -914,10 +889,6 @@ static int tsl2591_write_event_value(struct iio_dev *indio_dev, goto err_unlock; } - ret = tsl2591_compatible_als_persist_cycle(chip, als_persist); - if (ret < 0) - goto err_unlock; - ret = tsl2591_set_als_persist_cycle(chip, als_persist); if (ret < 0) goto err_unlock; From eb60a24b35bfb9e85a272e561379833e49a12a79 Mon Sep 17 00:00:00 2001 From: Maxwell Doose Date: Sun, 31 May 2026 18:38:28 -0500 Subject: [PATCH 265/266] iio: chemical: scd30: Replace manual locking with RAII locking scd30_core.c currently uses manual mutex_lock() and mutex_unlock() calls. Replace them with the newer guard(mutex)() for cleaner RAII patterns and to improve maintainability. Add new helper function scd30_trigger_handler_helper() containing the critical section for scd30_trigger_handler(). In addition, small refactor to replace "?:" operator with regular if/else returns. Signed-off-by: Maxwell Doose Reviewed-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/scd30_core.c | 66 ++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 24 deletions(-) diff --git a/drivers/iio/chemical/scd30_core.c b/drivers/iio/chemical/scd30_core.c index 11d6bc1b63e6..4e99b29f4518 100644 --- a/drivers/iio/chemical/scd30_core.c +++ b/drivers/iio/chemical/scd30_core.c @@ -368,11 +368,13 @@ static ssize_t calibration_auto_enable_show(struct device *dev, struct device_at int ret; u16 val; - mutex_lock(&state->lock); - ret = scd30_command_read(state, CMD_ASC, &val); - mutex_unlock(&state->lock); + guard(mutex)(&state->lock); - return ret ?: sysfs_emit(buf, "%d\n", val); + ret = scd30_command_read(state, CMD_ASC, &val); + if (ret) + return ret; + + return sysfs_emit(buf, "%d\n", val); } static ssize_t calibration_auto_enable_store(struct device *dev, struct device_attribute *attr, @@ -387,11 +389,13 @@ static ssize_t calibration_auto_enable_store(struct device *dev, struct device_a if (ret) return ret; - mutex_lock(&state->lock); - ret = scd30_command_write(state, CMD_ASC, val); - mutex_unlock(&state->lock); + guard(mutex)(&state->lock); - return ret ?: len; + ret = scd30_command_write(state, CMD_ASC, val); + if (ret) + return ret; + + return len; } static ssize_t calibration_forced_value_show(struct device *dev, struct device_attribute *attr, @@ -402,11 +406,13 @@ static ssize_t calibration_forced_value_show(struct device *dev, struct device_a int ret; u16 val; - mutex_lock(&state->lock); - ret = scd30_command_read(state, CMD_FRC, &val); - mutex_unlock(&state->lock); + guard(mutex)(&state->lock); - return ret ?: sysfs_emit(buf, "%d\n", val); + ret = scd30_command_read(state, CMD_FRC, &val); + if (ret) + return ret; + + return sysfs_emit(buf, "%d\n", val); } static ssize_t calibration_forced_value_store(struct device *dev, struct device_attribute *attr, @@ -424,11 +430,13 @@ static ssize_t calibration_forced_value_store(struct device *dev, struct device_ if (val < SCD30_FRC_MIN_PPM || val > SCD30_FRC_MAX_PPM) return -EINVAL; - mutex_lock(&state->lock); - ret = scd30_command_write(state, CMD_FRC, val); - mutex_unlock(&state->lock); + guard(mutex)(&state->lock); - return ret ?: len; + ret = scd30_command_write(state, CMD_FRC, val); + if (ret) + return ret; + + return len; } static IIO_DEVICE_ATTR_RO(sampling_frequency_available, 0); @@ -579,24 +587,34 @@ static irqreturn_t scd30_irq_thread_handler(int irq, void *priv) return IRQ_HANDLED; } +static int scd30_trigger_handler_helper(struct iio_dev *indio_dev, int *scan_data, + size_t scan_data_size) +{ + struct scd30_state *state = iio_priv(indio_dev); + int ret; + + guard(mutex)(&state->lock); + + if (!iio_trigger_using_own(indio_dev)) + ret = scd30_read_poll(state); + else + ret = scd30_read_meas(state); + memcpy(scan_data, state->meas, scan_data_size); + + return ret; +} + static irqreturn_t scd30_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; - struct scd30_state *state = iio_priv(indio_dev); struct { int data[SCD30_MEAS_COUNT]; aligned_s64 ts; } scan = { }; int ret; - mutex_lock(&state->lock); - if (!iio_trigger_using_own(indio_dev)) - ret = scd30_read_poll(state); - else - ret = scd30_read_meas(state); - memcpy(scan.data, state->meas, sizeof(state->meas)); - mutex_unlock(&state->lock); + ret = scd30_trigger_handler_helper(indio_dev, scan.data, sizeof(scan.data)); if (ret) goto out; From ae696dfa47c30016cd429b9db5e70b259b8f509e Mon Sep 17 00:00:00 2001 From: Stepan Ionichev Date: Mon, 18 May 2026 23:11:38 +0500 Subject: [PATCH 266/266] iio: adc: nxp-sar-adc: harden buffer ISR against per-channel read failure nxp_sar_adc_isr_buffer() bails on the first channel-read failure without calling iio_trigger_notify_done(), so the trigger use_count is left incremented and iio_trigger_poll_chained() drops subsequent dispatches until the device is rebound. Reaching this path means a state machine has gone wrong (driver bug or the SAR ADC in an unexpected state) rather than a transient bus issue, so this is hardening rather than a bug fix. If the underlying condition persists the device is wedged and needs an unbind anyway. Call iio_trigger_notify_done() on the error exit too, matching the success path. The nxp_sar_adc_read_notify() duplication is intentional and avoids a goto label for a two-line bail-out, as suggested by David. Signed-off-by: Stepan Ionichev Signed-off-by: Jonathan Cameron --- drivers/iio/adc/nxp-sar-adc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/adc/nxp-sar-adc.c b/drivers/iio/adc/nxp-sar-adc.c index 01f3da56e987..15c7432808f4 100644 --- a/drivers/iio/adc/nxp-sar-adc.c +++ b/drivers/iio/adc/nxp-sar-adc.c @@ -346,6 +346,7 @@ static void nxp_sar_adc_isr_buffer(struct iio_dev *indio_dev) ret = nxp_sar_adc_read_data(info, info->buffered_chan[i]); if (ret < 0) { nxp_sar_adc_read_notify(info); + iio_trigger_notify_done(indio_dev->trig); return; }