From: Nikhil Gautam <nikhilgtr@gmail.com>
To: linux-iio@vger.kernel.org
Cc: jic23@kernel.org, dlechner@baylibre.com, nuno.sa@analog.com,
andy@kernel.org, lkp@intel.com,
Nikhil Gautam <nikhilgtr@gmail.com>
Subject: [PATCH v2] iio: chemical: ccs811: Make sampling frequency configurable
Date: Thu, 22 Oct 2026 20:36:52 +0530 [thread overview]
Message-ID: <20261022150652.4842-1-nikhilgtr@gmail.com> (raw)
In-Reply-To: <20261018170013.79443-1-nikhilgtr@gmail.com>
Allow userspace to configure the CCS811 IAQ measurement rate through
the IIO sampling_frequency attribute.
Support the three IAQ measurement modes with sampling frequencies of
1 Hz, 0.1 Hz, and approximately 0.016667 Hz, corresponding to
measurement intervals of 1, 10, and 60 seconds.
Preserve unrelated bits in the MEAS_MODE register when updating the
drive mode, and cache the selected mode after a successful register
write. Expose the supported frequencies through
sampling_frequency_available.
Signed-off-by: Nikhil Gautam <nikhilgtr@gmail.com>
---
drivers/iio/chemical/ccs811.c | 147 +++++++++++++++++++++++++++++++---
1 file changed, 138 insertions(+), 9 deletions(-)
diff --git a/drivers/iio/chemical/ccs811.c b/drivers/iio/chemical/ccs811.c
index d126ee12ffe5..a1cbc4fa6a82 100644
--- a/drivers/iio/chemical/ccs811.c
+++ b/drivers/iio/chemical/ccs811.c
@@ -9,10 +9,9 @@
* IIO driver for AMS CCS811 (I2C address 0x5A/0x5B set by ADDR Low/High)
*
* TODO:
- * 1. Make the drive mode selectable form userspace
- * 2. Add support for interrupts
- * 3. Adjust time to wait for data to be ready based on selected operation mode
- * 4. Read error register and put the information in logs
+ * 1. Add support for interrupts
+ * 2. Adjust time to wait for data to be ready based on selected operation mode
+ * 3. Read error register and put the information in logs
*/
#include <linux/cleanup.h>
@@ -54,6 +53,7 @@
#define CCS811_STATUS_FW_MODE_APPLICATION BIT(7)
/* Measurement modes */
+#define CCS811_MODE_MASK GENMASK(6, 4)
#define CCS811_MODE_IDLE 0x00
#define CCS811_MODE_IAQ_1SEC 0x10
#define CCS811_MODE_IAQ_10SEC 0x20
@@ -79,6 +79,7 @@ struct ccs811_data {
struct iio_trigger *drdy_trig;
struct gpio_desc *wakeup_gpio;
bool drdy_trig_on;
+ u8 drive_mode;
/* Ensures correct alignment of timestamp if present */
struct {
s16 channels[2];
@@ -86,6 +87,12 @@ struct ccs811_data {
} scan;
};
+static const int ccs811_samp_freq[] = {
+ 1, 0,
+ 0, 100000,
+ 0, 16667,
+};
+
static const struct iio_chan_spec ccs811_channels[] = {
{
.type = IIO_CURRENT,
@@ -103,6 +110,8 @@ static const struct iio_chan_spec ccs811_channels[] = {
.modified = 1,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.scan_index = 0,
.scan_type = {
.sign = 'u',
@@ -163,16 +172,21 @@ static int ccs811_start_sensor_application(struct i2c_client *client)
return 0;
}
-static int ccs811_setup(struct i2c_client *client)
+static int ccs811_setup(struct ccs811_data *data)
{
int ret;
- ret = ccs811_start_sensor_application(client);
+ ret = ccs811_start_sensor_application(data->client);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(data->client, CCS811_MEAS_MODE,
+ CCS811_MODE_IAQ_1SEC);
if (ret < 0)
return ret;
- return i2c_smbus_write_byte_data(client, CCS811_MEAS_MODE,
- CCS811_MODE_IAQ_1SEC);
+ data->drive_mode = CCS811_MODE_IAQ_1SEC;
+ return 0;
}
static void ccs811_set_wakeup(struct ccs811_data *data, bool enable)
@@ -188,6 +202,44 @@ static void ccs811_set_wakeup(struct ccs811_data *data, bool enable)
usleep_range(20, 30);
}
+static int ccs811_set_sampling_freq(struct ccs811_data *data,
+ int val, int val2)
+{
+ u8 drive_mode;
+ int ret;
+
+ if (val == 1 && val2 == 0)
+ drive_mode = CCS811_MODE_IAQ_1SEC;
+ else if (val == 0 && val2 == 100000)
+ drive_mode = CCS811_MODE_IAQ_10SEC;
+ else if (val == 0 && val2 == 16667)
+ drive_mode = CCS811_MODE_IAQ_60SEC;
+ else
+ return -EINVAL;
+
+ guard(mutex)(&data->lock);
+ ccs811_set_wakeup(data, true);
+
+ ret = i2c_smbus_read_byte_data(data->client, CCS811_MEAS_MODE);
+ if (ret < 0)
+ goto out;
+
+ ret &= ~CCS811_MODE_MASK;
+ ret |= drive_mode;
+
+ ret = i2c_smbus_write_byte_data(data->client,
+ CCS811_MEAS_MODE, ret);
+ if (ret < 0)
+ goto out;
+
+ data->drive_mode = drive_mode;
+ ret = 0;
+
+out:
+ ccs811_set_wakeup(data, false);
+ return ret;
+}
+
static int ccs811_get_measurement(struct ccs811_data *data)
{
int ret, tries = 11;
@@ -215,6 +267,31 @@ static int ccs811_get_measurement(struct ccs811_data *data)
return ret;
}
+static int ccs811_get_sampling_freq(struct ccs811_data *data,
+ int *val, int *val2)
+{
+ guard(mutex)(&data->lock);
+
+ switch (data->drive_mode) {
+ case CCS811_MODE_IAQ_1SEC:
+ *val = 1;
+ *val2 = 0;
+ break;
+ case CCS811_MODE_IAQ_10SEC:
+ *val = 0;
+ *val2 = 100000;
+ break;
+ case CCS811_MODE_IAQ_60SEC:
+ *val = 0;
+ *val2 = 16667;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return IIO_VAL_INT_PLUS_MICRO;
+}
+
static int ccs811_read_info_raw(struct ccs811_data *data,
struct iio_chan_spec const *chan,
int *val, int mask)
@@ -249,6 +326,28 @@ static int ccs811_read_info_raw(struct ccs811_data *data,
}
}
+static int ccs811_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct ccs811_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ ret = ccs811_set_sampling_freq(data, val, val2);
+
+ iio_device_release_direct(indio_dev);
+ return ret;
+
+ default:
+ return -EINVAL;
+ }
+}
+
static int ccs811_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
@@ -293,13 +392,43 @@ static int ccs811_read_raw(struct iio_dev *indio_dev,
default:
return -EINVAL;
}
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return ccs811_get_sampling_freq(data, val, val2);
default:
return -EINVAL;
}
}
+static int ccs811_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long mask)
+{
+ if (mask != IIO_CHAN_INFO_SAMP_FREQ)
+ return -EINVAL;
+
+ *vals = ccs811_samp_freq;
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ *length = ARRAY_SIZE(ccs811_samp_freq);
+
+ return IIO_AVAIL_LIST;
+}
+
+static int ccs811_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ long mask)
+{
+ if (mask == IIO_CHAN_INFO_SAMP_FREQ)
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ return -EINVAL;
+}
+
static const struct iio_info ccs811_info = {
.read_raw = ccs811_read_raw,
+ .write_raw = ccs811_write_raw,
+ .read_avail = ccs811_read_avail,
+ .write_raw_get_fmt = ccs811_write_raw_get_fmt,
};
static int ccs811_set_trigger_state(struct iio_trigger *trig,
@@ -460,7 +589,7 @@ static int ccs811_probe(struct i2c_client *client)
return -ENODEV;
}
- ret = ccs811_setup(client);
+ ret = ccs811_setup(data);
if (ret < 0) {
ccs811_set_wakeup(data, false);
return ret;
--
2.39.5
next prev parent reply other threads:[~2026-10-22 15:07 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-18 17:00 [PATCH] iio: chemical: ccs811: Make sampling frequency configurable Nikhil Gautam
2026-10-19 7:26 ` kernel test robot
2026-10-22 15:06 ` Nikhil Gautam [this message]
2026-10-22 17:12 ` [PATCH v2] " Andy Shevchenko
2026-10-22 17:20 ` Joshua Crofts
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261022150652.4842-1-nikhilgtr@gmail.com \
--to=nikhilgtr@gmail.com \
--cc=andy@kernel.org \
--cc=dlechner@baylibre.com \
--cc=jic23@kernel.org \
--cc=linux-iio@vger.kernel.org \
--cc=lkp@intel.com \
--cc=nuno.sa@analog.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.