This is an automated email from the ASF dual-hosted git repository.
GUIDINGLI pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new e570885eb73 sensors: add ccs811 eCO2/TVOC driver
e570885eb73 is described below
commit e570885eb735d1ea2527ae383056fe4b268ec71d
Author: raiden00pl <[email protected]>
AuthorDate: Wed May 31 19:38:51 2023 +0200
sensors: add ccs811 eCO2/TVOC driver
Implement the ams CCS811 digital gas sensor
Assisted-by: Claude Code
Signed-off-by: raiden00pl <[email protected]>
---
drivers/sensors/CMakeLists.txt | 4 +
drivers/sensors/Kconfig | 17 ++
drivers/sensors/Make.defs | 4 +
drivers/sensors/ccs811_uorb.c | 666 +++++++++++++++++++++++++++++++++++++++++
include/nuttx/sensors/ccs811.h | 82 +++++
5 files changed, 773 insertions(+)
diff --git a/drivers/sensors/CMakeLists.txt b/drivers/sensors/CMakeLists.txt
index fc56aca87ea..893ada9b9d3 100644
--- a/drivers/sensors/CMakeLists.txt
+++ b/drivers/sensors/CMakeLists.txt
@@ -172,6 +172,10 @@ if(CONFIG_SENSORS)
list(APPEND SRCS lps25h.c)
endif()
+ if(CONFIG_SENSORS_CCS811)
+ list(APPEND SRCS ccs811_uorb.c)
+ endif()
+
if(CONFIG_ADXL345_I2C)
list(APPEND SRCS adxl345_i2c.c)
endif()
diff --git a/drivers/sensors/Kconfig b/drivers/sensors/Kconfig
index 52e2ad178c6..0cf4f6adba4 100644
--- a/drivers/sensors/Kconfig
+++ b/drivers/sensors/Kconfig
@@ -722,6 +722,23 @@ config SENSORS_BME688_THREAD_STACKSIZE
endif # SENSORS_BME688
+config SENSORS_CCS811
+ bool "ams CCS811 Gas Sensor"
+ default n
+ select I2C
+ ---help---
+ Enable driver for the ams CCS811 digital gas sensor for
monitoring
+ indoor air quality (eCO2 and TVOC).
+
+if SENSORS_CCS811
+
+config CCS811_I2C_FREQUENCY
+ int "CCS811 I2C frequency"
+ default 100000
+ range 1 400000
+
+endif # SENSORS_CCS811
+
config SENSORS_DHTXX
bool "DHTxx humidity/temperature Sensor support"
default n
diff --git a/drivers/sensors/Make.defs b/drivers/sensors/Make.defs
index 04b34616f08..306d57b9df2 100644
--- a/drivers/sensors/Make.defs
+++ b/drivers/sensors/Make.defs
@@ -226,6 +226,10 @@ ifeq ($(CONFIG_SENSORS_BME688),y)
CSRCS += bme688_uorb.c
endif
+ifeq ($(CONFIG_SENSORS_CCS811),y)
+ CSRCS += ccs811_uorb.c
+endif
+
ifeq ($(CONFIG_SENSORS_ISL29023),y)
CSRCS += isl29023.c
endif
diff --git a/drivers/sensors/ccs811_uorb.c b/drivers/sensors/ccs811_uorb.c
new file mode 100644
index 00000000000..ff9a15bb3cc
--- /dev/null
+++ b/drivers/sensors/ccs811_uorb.c
@@ -0,0 +1,666 @@
+/****************************************************************************
+ * drivers/sensors/ccs811_uorb.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <errno.h>
+#include <debug.h>
+#include <string.h>
+
+#include <nuttx/nuttx.h>
+#include <nuttx/arch.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/signal.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/sensors/sensor.h>
+#include <nuttx/sensors/ccs811.h>
+
+/****************************************************************************
+ * Pre-Processor Definitions
+ ****************************************************************************/
+
+/* Time to wait after a nWAKE falling edge before the CCS811 is ready for an
+ * I2C transaction (datasheet t_WAKE is 50us).
+ */
+
+#define CCS811_TWAKE_US (100)
+
+/* Number of times a single I2C transaction is retried. The first access
+ * after an idle gap occasionally NAKs while the sensor wakes.
+ */
+
+#define CCS811_XFER_RETRIES (3)
+
+/* Number of times the whole boot-to-application bring-up is retried. */
+
+#define CCS811_START_RETRIES (2)
+
+/* Registers */
+
+#define CCS811_STATUS (0x00)
+#define CCS811_MEAS_MODE (0x01)
+#define CCS811_ALG_RESULT_DATA (0x02)
+#define CCS811_RAW_DATA (0x03)
+#define CCS811_ENV_DATA (0x05)
+#define CCS811_THRESHOLDS (0x10)
+#define CCS811_BASELINE (0x11)
+#define CCS811_HW_ID (0x20)
+#define CCS811_HW_VERSION (0x21)
+#define CCS811_FW_BOOT_VERSION (0x23)
+#define CCS811_FW_APP_VERSION (0x24)
+#define CCS811_INTERNAL_STATE (0xa0)
+#define CCS811_ERROR_ID (0xe0)
+#define CCS811_SW_RESET (0xff)
+#define CCS811_APP_ERASE (0xf1)
+#define CCS811_APP_DATA (0xf2)
+#define CCS811_APP_VERIFY (0xf3)
+#define CCS811_APP_START (0xf4)
+
+/* HW_ID value */
+
+#define CCS811_DEVID (0x81)
+
+/* STATUS register bits */
+
+#define CCS811_STATUS_ERROR (1 << 0)
+#define CCS811_STATUS_DATARDY (1 << 3)
+#define CCS811_STATUS_APPVALID (1 << 4)
+#define CCS811_STATUS_FWMODE (1 << 7)
+
+/* MEAS_MODE drive modes */
+
+#define CCS811_DRIVE_MODE_IDLE (0 << 4) /* Idle, measurements disabled */
+#define CCS811_DRIVE_MODE_1SEC (1 << 4) /* Constant power, every 1 s */
+#define CCS811_DRIVE_MODE_10SEC (2 << 4) /* Pulse heating, every 10 s */
+#define CCS811_DRIVE_MODE_60SEC (3 << 4) /* Pulse heating, every 60 s */
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* Each measurement channel needs its own lower-half. */
+
+struct ccs811_sensor_s
+{
+ FAR struct sensor_lowerhalf_s lower; /* Lower-half driver */
+ FAR struct ccs811_dev_s *dev; /* Parent device */
+ bool enabled; /* Channel activated */
+};
+
+struct ccs811_dev_s
+{
+ struct ccs811_sensor_s co2; /* eCO2 lower-half */
+ struct ccs811_sensor_s tvoc; /* TVOC lower-half */
+ FAR struct i2c_master_s *i2c; /* I2C interface */
+ CODE void (*wake)(bool on); /* Board nWAKE control (may be NULL) */
+ uint8_t addr; /* I2C address */
+ bool wake_held; /* nWAKE kept low across a burst */
+ bool valid; /* Cached measurement available */
+ uint64_t timestamp; /* Cached measurement timestamp */
+ uint16_t eco2; /* Last eCO2 in ppm */
+ uint16_t etvoc; /* Last TVOC in ppb */
+ unsigned long interval; /* Polling interval in us */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int ccs811_read_regs(FAR struct ccs811_dev_s *priv, uint8_t regaddr,
+ FAR uint8_t *regvals, int len);
+static int ccs811_write(FAR struct ccs811_dev_s *priv, uint8_t regaddr,
+ FAR const uint8_t *regvals, int len);
+static int ccs811_appstart(FAR struct ccs811_dev_s *priv);
+static int ccs811_start(FAR struct ccs811_dev_s *priv);
+static int ccs811_measure(FAR struct ccs811_dev_s *priv);
+
+/* Sensor lower-half operations */
+
+static int ccs811_activate(FAR struct sensor_lowerhalf_s *lower,
+ FAR struct file *filep, bool enable);
+static int ccs811_set_interval(FAR struct sensor_lowerhalf_s *lower,
+ FAR struct file *filep,
+ FAR uint32_t *period_us);
+static int ccs811_fetch(FAR struct sensor_lowerhalf_s *lower,
+ FAR struct file *filep, FAR char *buffer,
+ size_t buflen);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct sensor_ops_s g_ccs811_ops =
+{
+ .activate = ccs811_activate,
+ .set_interval = ccs811_set_interval,
+ .fetch = ccs811_fetch,
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ccs811_wake_hold
+ *
+ * Description:
+ * Assert nWAKE and keep it asserted across a whole sequence of I2C
+ * transactions (the per-transaction pulse is suppressed while held). The
+ * boot->application transition must not be interrupted by nWAKE returning
+ * high, otherwise the sensor aborts the launch and stays in boot mode.
+ *
+ ****************************************************************************/
+
+static void ccs811_wake_hold(FAR struct ccs811_dev_s *priv, bool hold)
+{
+ if (priv->wake == NULL)
+ {
+ return;
+ }
+
+ if (hold)
+ {
+ priv->wake(true);
+ up_udelay(CCS811_TWAKE_US);
+ priv->wake_held = true;
+ }
+ else
+ {
+ priv->wake_held = false;
+ priv->wake(false);
+ }
+}
+
+/****************************************************************************
+ * Name: ccs811_read_regs
+ ****************************************************************************/
+
+static int ccs811_read_regs(FAR struct ccs811_dev_s *priv, uint8_t regaddr,
+ FAR uint8_t *regvals, int len)
+{
+ struct i2c_config_s config;
+ int ret = -EIO;
+ int i;
+
+ config.frequency = CONFIG_CCS811_I2C_FREQUENCY;
+ config.address = priv->addr;
+ config.addrlen = 7;
+
+ for (i = 0; i < CCS811_XFER_RETRIES; i++)
+ {
+ if (priv->wake != NULL && !priv->wake_held)
+ {
+ priv->wake(true); /* nWAKE falling edge */
+ up_udelay(CCS811_TWAKE_US);
+ }
+
+ ret = i2c_writeread(priv->i2c, &config, ®addr, 1, regvals, len);
+
+ if (priv->wake != NULL && !priv->wake_held)
+ {
+ priv->wake(false); /* release nWAKE */
+ }
+
+ if (ret >= 0)
+ {
+ break;
+ }
+
+ nxsig_usleep(2000);
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: ccs811_write
+ *
+ * Description:
+ * Write a command register optionally followed by data bytes.
+ *
+ ****************************************************************************/
+
+static int ccs811_write(FAR struct ccs811_dev_s *priv, uint8_t regaddr,
+ FAR const uint8_t *regvals, int len)
+{
+ struct i2c_config_s config;
+ uint8_t buf[2];
+ int ret = -EIO;
+ int i;
+
+ config.frequency = CONFIG_CCS811_I2C_FREQUENCY;
+ config.address = priv->addr;
+ config.addrlen = 7;
+
+ buf[0] = regaddr;
+ if (len > 0)
+ {
+ memcpy(&buf[1], regvals, len);
+ }
+
+ for (i = 0; i < CCS811_XFER_RETRIES; i++)
+ {
+ if (priv->wake != NULL && !priv->wake_held)
+ {
+ priv->wake(true); /* nWAKE falling edge */
+ up_udelay(CCS811_TWAKE_US);
+ }
+
+ ret = i2c_write(priv->i2c, &config, buf, len + 1);
+
+ if (priv->wake != NULL && !priv->wake_held)
+ {
+ priv->wake(false); /* release nWAKE */
+ }
+
+ if (ret >= 0)
+ {
+ break;
+ }
+
+ nxsig_usleep(2000);
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: ccs811_appstart
+ *
+ * Description:
+ * Verify the chip ID, switch to application mode and start periodic
+ * measurements. A single attempt.
+ *
+ ****************************************************************************/
+
+static int ccs811_appstart(FAR struct ccs811_dev_s *priv)
+{
+ uint8_t regval;
+ int retries;
+ int ret;
+
+ /* Wait for the sensor to respond and verify the hardware ID. These use
+ * the normal per-transaction nWAKE pulse so each attempt re-wakes the
+ * part.
+ */
+
+ retries = 20;
+ do
+ {
+ nxsig_usleep(20000);
+ ret = ccs811_read_regs(priv, CCS811_HW_ID, ®val, 1);
+ }
+ while (ret < 0 && --retries);
+
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ if (regval != CCS811_DEVID)
+ {
+ snerr("ERROR: Wrong device ID: 0x%02x\n", regval);
+ return -ENODEV;
+ }
+
+ /* Poll STATUS until a valid application is reported. */
+
+ retries = 20;
+ do
+ {
+ nxsig_usleep(20000);
+ ret = ccs811_read_regs(priv, CCS811_STATUS, ®val, 1);
+ if (ret < 0)
+ {
+ return ret;
+ }
+ }
+ while ((regval & CCS811_STATUS_APPVALID) == 0 && --retries);
+
+ if ((regval & CCS811_STATUS_APPVALID) == 0)
+ {
+ snerr("ERROR: CCS811 has no valid application (status=0x%02x)\n",
+ regval);
+ return -ENODEV;
+ }
+
+ /* Launch the application firmware. nWAKE must stay asserted (low) across
+ * the whole boot->application transition: the sensor aborts the launch
+ * and falls back to boot mode if nWAKE returns high (i.e. it is allowed
+ * to sleep) before the application is running. Hold nWAKE low, issue
+ * APP_START, then poll STATUS tightly (back-to-back reads keep the part
+ * awake) until it reports application mode. During the launch STATUS can
+ * read back as 0xff/0xfd garbage, so only accept a clean value: FWMODE
+ * set with all reserved bits clear.
+ */
+
+ ccs811_wake_hold(priv, true);
+
+ retries = 20;
+ do
+ {
+ ret = ccs811_write(priv, CCS811_APP_START, NULL, 0);
+ if (ret < 0)
+ {
+ goto errout;
+ }
+
+ up_udelay(2000);
+ ret = ccs811_read_regs(priv, CCS811_STATUS, ®val, 1);
+ }
+ while ((ret < 0 || (regval & 0x66) != 0 ||
+ (regval & CCS811_STATUS_FWMODE) == 0) && --retries);
+
+ if (ret < 0)
+ {
+ goto errout;
+ }
+
+ if ((regval & CCS811_STATUS_FWMODE) == 0)
+ {
+ snerr("ERROR: CCS811 failed to enter application mode (0x%02x)\n",
+ regval);
+ ret = -EIO;
+ goto errout;
+ }
+
+ /* Select constant-power measurement mode, one sample every second. */
+
+ regval = CCS811_DRIVE_MODE_1SEC;
+ ret = ccs811_write(priv, CCS811_MEAS_MODE, ®val, 1);
+
+errout:
+ ccs811_wake_hold(priv, false);
+ return ret;
+}
+
+/****************************************************************************
+ * Name: ccs811_start
+ *
+ * Description:
+ * Bring the CCS811 into measurement mode. The boot-to-application
+ * transition is occasionally unreliable after a warm reset, so retry the
+ * whole sequence a few times before giving up.
+ *
+ ****************************************************************************/
+
+static int ccs811_start(FAR struct ccs811_dev_s *priv)
+{
+ int ret = -EIO;
+ int i;
+
+ for (i = 0; i < CCS811_START_RETRIES; i++)
+ {
+ ret = ccs811_appstart(priv);
+ if (ret >= 0)
+ {
+ break;
+ }
+
+ nxsig_usleep(50000);
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: ccs811_measure
+ *
+ * Description:
+ * Refresh the cached eCO2/TVOC values from the algorithm result data.
+ * A single ALG_RESULT_DATA read returns both values and clears DATARDY,
+ * so the result is cached and shared by both lower-halves.
+ *
+ ****************************************************************************/
+
+static int ccs811_measure(FAR struct ccs811_dev_s *priv)
+{
+ uint8_t data[8];
+ uint8_t status = 0;
+ int ret;
+
+ ret = ccs811_read_regs(priv, CCS811_STATUS, &status, 1);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ /* If the sensor has dropped back into boot mode, re-run the application
+ * bring-up before trying to read a measurement.
+ */
+
+ if ((status & CCS811_STATUS_FWMODE) == 0)
+ {
+ ret = ccs811_appstart(priv);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ ret = ccs811_read_regs(priv, CCS811_STATUS, &status, 1);
+ if (ret < 0)
+ {
+ return ret;
+ }
+ }
+
+ /* No new sample is ready yet - keep the previously reported value. */
+
+ if ((status & CCS811_STATUS_DATARDY) == 0)
+ {
+ return -EAGAIN;
+ }
+
+ ret = ccs811_read_regs(priv, CCS811_ALG_RESULT_DATA, data, 8);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ /* data[4] holds the status, data[5] the error id */
+
+ if (data[4] & CCS811_STATUS_ERROR)
+ {
+ snerr("ERROR: CCS811 measurement error: 0x%02x\n", data[5]);
+ return -EIO;
+ }
+
+ priv->eco2 = data[0] << 8 | data[1];
+ priv->etvoc = data[2] << 8 | data[3];
+ priv->timestamp = sensor_get_timestamp();
+ priv->valid = true;
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: ccs811_activate
+ ****************************************************************************/
+
+static int ccs811_activate(FAR struct sensor_lowerhalf_s *lower,
+ FAR struct file *filep, bool enable)
+{
+ FAR struct ccs811_sensor_s *priv =
+ container_of(lower, FAR struct ccs811_sensor_s, lower);
+
+ priv->enabled = enable;
+ return OK;
+}
+
+/****************************************************************************
+ * Name: ccs811_set_interval
+ ****************************************************************************/
+
+static int ccs811_set_interval(FAR struct sensor_lowerhalf_s *lower,
+ FAR struct file *filep,
+ FAR uint32_t *period_us)
+{
+ FAR struct ccs811_sensor_s *priv =
+ container_of(lower, FAR struct ccs811_sensor_s, lower);
+
+ priv->dev->interval = *period_us;
+ return OK;
+}
+
+/****************************************************************************
+ * Name: ccs811_fetch
+ ****************************************************************************/
+
+static int ccs811_fetch(FAR struct sensor_lowerhalf_s *lower,
+ FAR struct file *filep, FAR char *buffer,
+ size_t buflen)
+{
+ FAR struct ccs811_sensor_s *priv =
+ container_of(lower, FAR struct ccs811_sensor_s, lower);
+ FAR struct ccs811_dev_s *dev = priv->dev;
+ int ret;
+
+ ret = ccs811_measure(dev);
+ if (ret < 0 && ret != -EAGAIN)
+ {
+ return ret;
+ }
+
+ if (!dev->valid)
+ {
+ return -EAGAIN;
+ }
+
+ if (lower->type == SENSOR_TYPE_CO2)
+ {
+ struct sensor_co2 co2;
+
+ if (buflen != sizeof(co2))
+ {
+ return -EINVAL;
+ }
+
+ co2.timestamp = dev->timestamp;
+ co2.co2 = (float)dev->eco2;
+ memcpy(buffer, &co2, sizeof(co2));
+ return sizeof(co2);
+ }
+ else
+ {
+ struct sensor_tvoc tvoc;
+
+ if (buflen != sizeof(tvoc))
+ {
+ return -EINVAL;
+ }
+
+ tvoc.timestamp = dev->timestamp;
+ tvoc.tvoc = (float)dev->etvoc / 1000.0f;
+ memcpy(buffer, &tvoc, sizeof(tvoc));
+ return sizeof(tvoc);
+ }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ccs811_register_uorb
+ *
+ * Description:
+ * Register the CCS811 eCO2 and TVOC sensors as UORB devices.
+ *
+ * Input Parameters:
+ * devno - The device number, used to build the device path.
+ * i2c - The I2C bus driver instance.
+ * addr - The I2C address of the CCS811.
+ * config - Board-specific configuration (may be NULL).
+ *
+ * Returned Value:
+ * Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int ccs811_register_uorb(int devno, FAR struct i2c_master_s *i2c,
+ uint8_t addr,
+ FAR const struct ccs811_config_s *config)
+{
+ FAR struct ccs811_dev_s *priv;
+ int ret;
+
+ DEBUGASSERT(i2c != NULL);
+
+ priv = kmm_zalloc(sizeof(struct ccs811_dev_s));
+ if (priv == NULL)
+ {
+ snerr("ERROR: Failed to allocate CCS811 instance\n");
+ return -ENOMEM;
+ }
+
+ priv->i2c = i2c;
+ priv->addr = addr;
+ priv->interval = 1000000;
+
+ if (config != NULL)
+ {
+ priv->wake = config->wake;
+ }
+
+ ret = ccs811_start(priv);
+ if (ret < 0)
+ {
+ snerr("ERROR: Failed to start CCS811: %d\n", ret);
+ goto errout;
+ }
+
+ /* Register the eCO2 lower-half */
+
+ priv->co2.dev = priv;
+ priv->co2.lower.ops = &g_ccs811_ops;
+ priv->co2.lower.type = SENSOR_TYPE_CO2;
+
+ ret = sensor_register(&priv->co2.lower, devno);
+ if (ret < 0)
+ {
+ snerr("ERROR: Failed to register CCS811 eCO2: %d\n", ret);
+ goto errout;
+ }
+
+ /* Register the TVOC lower-half */
+
+ priv->tvoc.dev = priv;
+ priv->tvoc.lower.ops = &g_ccs811_ops;
+ priv->tvoc.lower.type = SENSOR_TYPE_TVOC;
+
+ ret = sensor_register(&priv->tvoc.lower, devno);
+ if (ret < 0)
+ {
+ snerr("ERROR: Failed to register CCS811 TVOC: %d\n", ret);
+ sensor_unregister(&priv->co2.lower, devno);
+ goto errout;
+ }
+
+ sninfo("CCS811 registered\n");
+ return OK;
+
+errout:
+ kmm_free(priv);
+ return ret;
+}
diff --git a/include/nuttx/sensors/ccs811.h b/include/nuttx/sensors/ccs811.h
new file mode 100644
index 00000000000..6a1372d690d
--- /dev/null
+++ b/include/nuttx/sensors/ccs811.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+ * include/nuttx/sensors/ccs811.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __INCLUDE_NUTTX_SENSORS_CCS811_H
+#define __INCLUDE_NUTTX_SENSORS_CCS811_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdbool.h>
+
+#include <nuttx/i2c/i2c_master.h>
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+struct ccs811_config_s
+{
+ /* Optional board callback to control the CCS811 nWAKE line around each
+ * I2C transaction (on=true asserts nWAKE, on=false releases it). Leave
+ * NULL when nWAKE is tied low in hardware.
+ */
+
+ CODE void (*wake)(bool on);
+};
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Name: ccs811_register_uorb
+ *
+ * Description:
+ * Register the CCS811 eCO2 and TVOC sensors as UORB devices.
+ *
+ * Input Parameters:
+ * devno - The device number, used to build the device path.
+ * i2c - The I2C bus driver instance.
+ * addr - The I2C address of the CCS811.
+ * config - Board-specific configuration (may be NULL).
+ *
+ * Returned Value:
+ * Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int ccs811_register_uorb(int devno, FAR struct i2c_master_s *i2c,
+ uint8_t addr,
+ FAR const struct ccs811_config_s *config);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INCLUDE_NUTTX_SENSORS_CCS811_H */