[PATCH 2/2] iio: light: ltr390: Add conditional data freshness check with sysfs control

From: Akshay Jindal
Date: Mon Jul 21 2025 - 15:55:17 EST


Add logic to check the sensor’s data freshness status bit before reading
data, and skip reads if the data is stale.

Introduce a new boolean sysfs attribute, `data_fresh_check_enable`, to allow
users to enable or disable this behavior at runtime:

- 1: Enable data freshness check (default)
- 0: Disable data freshness check

This provides flexibility to choose between ensuring fresh data and allowing
faster reads when occasional staleness is acceptable.

Document the new attribute under Documentation/ABI/testing/sysfs-bus-iio.

Signed-off-by: Akshay Jindal <akshayaj.lkd@xxxxxxxxx>
---
-> Tested on Raspberrypi 4B. Follow for more details.

akshayajpi@raspberrypi:~ $ uname -r
6.12.35-v8+
akshayajpi@raspberrypi:~ $ uname -a
Linux raspberrypi 6.12.35-v8+ #5 SMP PREEMPT Tue Jul 15 17:38:06 IST 2025 aarch64 GNU/Linux

-> Sensor Detection, overlaying of device tree and Driver loading
akshayajpi@raspberrypi:~ $ i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- 53 -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
akshayajpi@raspberrypi:~ $ sudo dtoverlay i2c-sensor ltr390
akshayajpi@raspberrypi:~ $ lsmod|grep ltr390
ltr390 16384 0
industrialio 110592 1 ltr390
regmap_i2c 12288 1 ltr390

-> Sysfs Attribute Creation validation
akshayajpi@raspberrypi:~ $ ls -ltrh /sys/bus/iio/devices/iio\:device0/
total 0
-rw-r--r-- 1 root root 4.0K Jul 21 23:52 uevent
-r--r--r-- 1 root root 4.0K Jul 21 23:52 name
-r--r--r-- 1 root root 4.0K Jul 21 23:52 waiting_for_supplier
lrwxrwxrwx 1 root root 0 Jul 21 23:52 subsystem -> ../../../../../../../bus/iio
-r--r--r-- 1 root root 4.0K Jul 21 23:52 scale_available
-r--r--r-- 1 root root 4.0K Jul 21 23:52 sampling_frequency_available
-rw-r--r-- 1 root root 4.0K Jul 21 23:52 sampling_frequency
drwxr-xr-x 2 root root 0 Jul 21 23:52 power
lrwxrwxrwx 1 root root 0 Jul 21 23:52 of_node -> ../../../../../../../firmware/devicetree/base/soc/i2c@7e804000/ltr390@53
-rw-r--r-- 1 root root 4.0K Jul 21 23:52 in_uvindex_scale
-rw-r--r-- 1 root root 4.0K Jul 21 23:52 in_uvindex_raw
-r--r--r-- 1 root root 4.0K Jul 21 23:52 integration_time_available
-rw-r--r-- 1 root root 4.0K Jul 21 23:52 integration_time
-rw-r--r-- 1 root root 4.0K Jul 21 23:52 in_illuminance_scale
-rw-r--r-- 1 root root 4.0K Jul 21 23:52 in_illuminance_raw
drwxr-xr-x 2 root root 0 Jul 21 23:52 events
-r--r--r-- 1 root root 4.0K Jul 21 23:52 dev
-rw-r--r-- 1 root root 4.0K Jul 21 23:52 data_fresh_check_enable<-----
-r--r--r-- 1 root root 4.0K Jul 21 23:52 data_fresh

-> Default value 1 for data_fresh_check_enable
akshayajpi@raspberrypi:~ $ cat /sys/bus/iio/devices/iio\:device0/data_fresh
1
akshayajpi@raspberrypi:~ $ cat /sys/bus/iio/devices/iio\:device0/data_fresh_check_enable
1

-> Disable fresh measurement in the sensor
akshayajpi@raspberrypi:~ $ i2cset -f -y 1 0x53 0x0 0x0
akshayajpi@raspberrypi:~ $ cat /sys/bus/iio/devices/iio\:device0/data_fresh_check_enable
1
akshayajpi@raspberrypi:~ $ cat /sys/bus/iio/devices/iio\:device0/data_fresh_check_enable
1
akshayajpi@raspberrypi:~ $ cat /sys/bus/iio/devices/iio\:device0/in_illuminance_raw
647
akshayajpi@raspberrypi:~ $ cat /sys/bus/iio/devices/iio\:device0/data_fresh
0

-> Since data_fresh_enable_check is enabled by default, driver skips
stale data read and emits -EAGAIN.
akshayajpi@raspberrypi:~ $ cat /sys/bus/iio/devices/iio\:device0/in_illuminance_raw
cat: '/sys/bus/iio/devices/iio:device0/in_illuminance_raw': Resource temporarily unavailable
akshayajpi@raspberrypi:~ $ cat /sys/bus/iio/devices/iio\:device0/in_illuminance_raw
cat: '/sys/bus/iio/devices/iio:device0/in_illuminance_raw': Resource temporarily unavailable
akshayajpi@raspberrypi:~ $

-> Disable data_fresh_check_en
akshayajpi@raspberrypi:~ $ echo 0 | sudo tee /sys/bus/iio/devices/iio\:device0/data_fresh_check_enable
0
akshayajpi@raspberrypi:~ $ cat /sys/bus/iio/devices/iio\:device0/data_fresh_check_enable
0
akshayajpi@raspberrypi:~ $ cat /sys/bus/iio/devices/iio\:device0/data_fresh
0

-> Since freshness check is disabled, driver reads and prints stale
data.
akshayajpi@raspberrypi:~ $ cat /sys/bus/iio/devices/iio\:device0/in_illuminance_raw
647
akshayajpi@raspberrypi:~ $ cat /sys/bus/iio/devices/iio\:device0/in_illuminance_raw
647
akshayajpi@raspberrypi:~ $ cat /sys/bus/iio/devices/iio\:device0/in_illuminance_raw
647

-> Re-enabling freshness check, results in driver emitting -EAGAIN.
akshayajpi@raspberrypi:~ $ echo 1 | sudo tee /sys/bus/iio/devices/iio\:device0/data_fresh_check_enable
1
akshayajpi@raspberrypi:~ $ cat /sys/bus/iio/devices/iio\:device0/data_fresh_check_enable
1
akshayajpi@raspberrypi:~ $ cat /sys/bus/iio/devices/iio\:device0/in_illuminance_raw
cat: '/sys/bus/iio/devices/iio:device0/in_illuminance_raw': Resource temporarily unavailable
akshayajpi@raspberrypi:~ $ cat /sys/bus/iio/devices/iio\:device0/in_illuminance_raw
cat: '/sys/bus/iio/devices/iio:device0/in_illuminance_raw': Resource temporarily unavailable

Documentation/ABI/testing/sysfs-bus-iio | 12 ++++++
drivers/iio/light/ltr390.c | 55 ++++++++++++++++++++++++-
2 files changed, 66 insertions(+), 1 deletion(-)

diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
index 5d176d46c15d..da881e16ee3d 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio
+++ b/Documentation/ABI/testing/sysfs-bus-iio
@@ -2397,3 +2397,15 @@ Description:

Provides userspace visibility into data_freshness status which
can be used for debugging and informational use.
+
+What: /sys/.../iio:deviceX/data_fresh_check_enable
+KernelVersion: 6.16
+Contact: linux-iio@xxxxxxxxxxxxxxx
+Description:
+ Read-write boolean attribute controlling whether the driver
+ checks the data freshness status bit before reading sensor data.
+
+ 0 - Freshness check disabled
+ 1 - Enable check; driver will skip reading stale data (default)
+
+ This flag affects the behavior of data reads.
diff --git a/drivers/iio/light/ltr390.c b/drivers/iio/light/ltr390.c
index 5af0ffd3df1d..b13f01835aeb 100644
--- a/drivers/iio/light/ltr390.c
+++ b/drivers/iio/light/ltr390.c
@@ -98,6 +98,7 @@ struct ltr390_data {
enum ltr390_mode mode;
int gain;
int int_time_us;
+ bool data_fresh_check_en;
};

static const struct regmap_config ltr390_regmap_config = {
@@ -199,10 +200,40 @@ static ssize_t data_fresh_show(struct device *dev,
return sysfs_emit(buf, "%d\n", !!(status & LTR390_DATA_STATUS_MASK));
}

+static ssize_t data_fresh_check_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ltr390_data *data = iio_priv(dev_to_iio_dev(dev));
+
+ guard(mutex)(&data->lock);
+
+ return sysfs_emit(buf, "%d\n", data->data_fresh_check_en);
+}
+
+static ssize_t data_fresh_check_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ int ret;
+ bool data_fresh_check_en;
+ struct ltr390_data *data = iio_priv(dev_to_iio_dev(dev));
+
+ ret = kstrtobool(buf, &data_fresh_check_en);
+ if (ret)
+ return ret;
+
+ guard(mutex)(&data->lock);
+
+ data->data_fresh_check_en = data_fresh_check_en;
+ return len;
+}
+
static IIO_DEVICE_ATTR_RO(data_fresh, 0);
+static IIO_DEVICE_ATTR_RW(data_fresh_check_enable, 0);

static struct attribute *ltr390_attributes[] = {
&iio_dev_attr_data_fresh.dev_attr.attr,
+ &iio_dev_attr_data_fresh_check_enable.dev_attr.attr,
NULL
};

@@ -214,7 +245,7 @@ static int ltr390_read_raw(struct iio_dev *iio_device,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
{
- int ret;
+ int ret, status;
struct ltr390_data *data = iio_priv(iio_device);

guard(mutex)(&data->lock);
@@ -226,6 +257,16 @@ static int ltr390_read_raw(struct iio_dev *iio_device,
if (ret < 0)
return ret;

+ if (data->data_fresh_check_en) {
+ ret = ltr390_register_read(data, LTR390_MAIN_STATUS);
+ if (ret < 0)
+ return ret;
+
+ status = ret;
+ if (!(status & LTR390_DATA_STATUS_MASK))
+ return -EAGAIN;
+ }
+
ret = ltr390_register_read(data, LTR390_UVS_DATA);
if (ret < 0)
return ret;
@@ -236,6 +277,16 @@ static int ltr390_read_raw(struct iio_dev *iio_device,
if (ret < 0)
return ret;

+ if (data->data_fresh_check_en) {
+ ret = ltr390_register_read(data, LTR390_MAIN_STATUS);
+ if (ret < 0)
+ return ret;
+
+ status = ret;
+ if (!(status & LTR390_DATA_STATUS_MASK))
+ return -EAGAIN;
+ }
+
ret = ltr390_register_read(data, LTR390_ALS_DATA);
if (ret < 0)
return ret;
@@ -687,6 +738,8 @@ static int ltr390_probe(struct i2c_client *client)
data->gain = 3;
/* default mode for ltr390 is ALS mode */
data->mode = LTR390_SET_ALS_MODE;
+ /* default value for data_fresh_check_en is 1 */
+ data->data_fresh_check_en = 1;

mutex_init(&data->lock);

--
2.43.0