You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2022/11/21 15:48:58 UTC

[incubator-nuttx] branch master updated: drivers/sensors: add LTR308 ambient light sensor

This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 039262484a drivers/sensors: add LTR308 ambient light sensor
039262484a is described below

commit 039262484ab349143474d62f4a163f51c5227e50
Author: Robert-Ionut Alexa <ro...@gmail.com>
AuthorDate: Sat Oct 8 11:31:29 2022 +0300

    drivers/sensors: add LTR308 ambient light sensor
    
    Add support for the LTR308 ambient light sensor through I2C. Currently,
    the interrupt-driven mode of operation is not supported.
    
    Signed-off-by: Robert-Ionut Alexa <ro...@gmail.com>
---
 drivers/sensors/Kconfig        |  32 ++
 drivers/sensors/Make.defs      |   4 +
 drivers/sensors/ltr308.c       | 655 +++++++++++++++++++++++++++++++++++++++++
 include/nuttx/sensors/ltr308.h |  91 ++++++
 4 files changed, 782 insertions(+)

diff --git a/drivers/sensors/Kconfig b/drivers/sensors/Kconfig
index 2b229964fc..057fca9786 100644
--- a/drivers/sensors/Kconfig
+++ b/drivers/sensors/Kconfig
@@ -1144,4 +1144,36 @@ config HDC1008_DEBUG
 		Enables debug features for the HDC1008
 
 endif # SENSORS_HDC1008
+
+config SENSORS_LTR308
+	bool "LTR308 Lite-On ambient light sensor"
+	default n
+  select I2C
+	---help---
+		Enable driver support for the LTR308 Lite-on ambient light sensor.
+
+if SENSORS_LTR308
+
+config SENSORS_LTR308_I2C_FREQUENCY
+	int "LTR308 I2C frequency"
+	default 400000
+	range 1 400000
+
+config SENSORS_LTR308_POLL_INTERVAL
+	int "Polling interval in microseconds, default 1 sec"
+	depends on SENSORS_LTR308
+	default 1000000
+	range 0 4294967295
+	---help---
+		The interval until a new sensor measurement will be triggered.
+
+config SENSORS_LTR308_THREAD_STACKSIZE
+	int "Worker thread stack size"
+	depends on SENSORS_LTR308
+	default 1024
+	---help---
+		The stack size for the worker thread.
+
+endif # SENSORS_LTR308
+
 endif # SENSORS
diff --git a/drivers/sensors/Make.defs b/drivers/sensors/Make.defs
index 4fb4c3ec45..593f32f783 100644
--- a/drivers/sensors/Make.defs
+++ b/drivers/sensors/Make.defs
@@ -228,6 +228,10 @@ ifeq ($(CONFIG_SENSORS_T67XX),y)
   CSRCS += t67xx.c
 endif
 
+ifeq ($(CONFIG_SENSORS_LTR308),y)
+  CSRCS += ltr308.c
+endif
+
 endif # CONFIG_I2C
 
 # These drivers depend on SPI support
diff --git a/drivers/sensors/ltr308.c b/drivers/sensors/ltr308.c
new file mode 100644
index 0000000000..2e203a5976
--- /dev/null
+++ b/drivers/sensors/ltr308.c
@@ -0,0 +1,655 @@
+/****************************************************************************
+ * drivers/sensors/ltr308.c
+ * Character driver for the LTR-308ALS-01 Lite-On ambient light sensor.
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <debug.h>
+
+#include <nuttx/nuttx.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/kthread.h>
+#include <nuttx/signal.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/sensors/sensor.h>
+#include <nuttx/sensors/ltr308.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_SENSORS_LTR308)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define LTR308_ADDR           0x53
+#define DEVID                 0xB1
+
+#define LTR308_CTRL           0x00
+#define LTR308_MEAS_RATE      0x04
+#define LTR308_ALS_GAIN       0x05
+#define LTR308_PART_ID        0x06
+#define LTR308_STATUS         0x07
+#define LTR308_DATA_0         0x0D
+
+/****************************************************************************
+ * Private Type Definitions
+ ****************************************************************************/
+
+struct ltr308_sensor_s
+{
+  struct sensor_lowerhalf_s lower;  /* Common lower interface */
+  uint8_t integration_time;         /* The interval between 2 ALS cycles */
+  uint8_t measurement_rate;         /* The interval between 2 data updates */
+  uint8_t gain;                     /* Sensor gain */
+};
+
+struct ltr308_dev_s
+{
+  struct ltr308_sensor_s dev;     /* Sensor private data */
+  FAR struct i2c_master_s *i2c;   /* I2C interface */
+  mutex_t dev_lock;               /* Manages exclusive access to the device */
+  sem_t run;                      /* Locks sensor thread */
+  bool enabled;                   /* Enable/Disable LTR308 */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int ltr308_activate(FAR struct sensor_lowerhalf_s *lower,
+                           FAR struct file *filep, bool enabled);
+static int ltr308_calibrate(FAR struct sensor_lowerhalf_s *lower,
+                            FAR struct file *filep,
+                            unsigned long arg);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct sensor_ops_s g_sensor_ops =
+{
+  NULL,               /* open */
+  NULL,               /* close */
+  ltr308_activate,    /* activate */
+  NULL,               /* set_interval */
+  NULL,               /* batch */
+  NULL,               /* fetch */
+  NULL,               /* selftest */
+  NULL,               /* set_calibvalue */
+  ltr308_calibrate,   /* calibrate */
+  NULL                /* control */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ltr308_set_reg8
+ *
+ * Description:
+ *   Write to an 8-bit LTR308 register
+ *
+ * Return value:
+ *   Zero (OK) on success; a negated errno value on failure
+ ****************************************************************************/
+
+static int ltr308_set_reg8(FAR struct ltr308_dev_s *priv, uint8_t regaddr,
+                           uint8_t regval)
+{
+  struct i2c_msg_s msg;
+  uint8_t txbuffer[2];
+  int ret;
+
+  txbuffer[0]   = regaddr;
+  txbuffer[1]   = regval;
+
+  msg.frequency = CONFIG_SENSORS_LTR308_I2C_FREQUENCY;
+  msg.addr      = LTR308_ADDR;
+  msg.flags     = 0;
+  msg.buffer    = txbuffer;
+  msg.length    = 2;
+
+  ret = I2C_TRANSFER(priv->i2c, &msg, 1);
+  if (ret < 0)
+    {
+      snerr("I2C_TRANSFER failed (err = %d)\n", ret);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: ltr308_get_reg8
+ *
+ * Description:
+ *   Read from an 8-bit LTR308 register
+ *
+ * Return value:
+ *   Zero (OK) on success; a negated errno value on failure
+ ****************************************************************************/
+
+static int ltr308_get_reg8(FAR struct ltr308_dev_s *priv, uint8_t regaddr,
+                           FAR uint8_t *regval)
+{
+  struct i2c_msg_s msg[2];
+  int ret;
+
+  msg[0].frequency = CONFIG_SENSORS_LTR308_I2C_FREQUENCY;
+  msg[0].addr      = LTR308_ADDR;
+  msg[0].flags     = 0;
+  msg[0].buffer    = &regaddr;
+  msg[0].length    = 1;
+
+  msg[1].frequency = CONFIG_SENSORS_LTR308_I2C_FREQUENCY;
+  msg[1].addr      = LTR308_ADDR;
+  msg[1].flags     = I2C_M_READ;
+  msg[1].buffer    = regval;
+  msg[1].length    = 1;
+
+  ret = I2C_TRANSFER(priv->i2c, msg, 2);
+  if (ret < 0)
+    {
+      snerr("ERROR: I2C_TRANSFER failed (err = %d)\n", ret);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: ltr308_get_reg24
+ *
+ * Description:
+ *   Read from 3 8-bit LTR308 registers
+ *
+ * Return value:
+ *   Zero (OK) on success; a negated errno value on failure
+ ****************************************************************************/
+
+static int ltr308_get_reg24(FAR struct ltr308_dev_s *priv, uint8_t regaddr,
+                            FAR uint32_t *val)
+{
+  int ret;
+  int i;
+
+  *val = 0;
+  for (i = 0; i < 3; i++, regaddr++)
+    {
+      ret = ltr308_get_reg8(priv, regaddr, ((uint8_t *)val) + i);
+      if (ret < 0)
+        {
+          return ret;
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: ltr308_checkid
+ *
+ * Description:
+ *   Read and verify the LTR308 chip ID
+ *
+ * Return value:
+ *   Zero (OK) on success; a negated errno value on failure
+ ****************************************************************************/
+
+static int ltr308_checkid(FAR struct ltr308_dev_s *priv)
+{
+  uint8_t devid;
+  int ret;
+
+  /* Read device ID */
+
+  ret = ltr308_get_reg8(priv, LTR308_PART_ID, &devid);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  sninfo("devid: 0x%02x\n", devid);
+
+  return (devid != DEVID) ? -ENODEV : OK;
+}
+
+/****************************************************************************
+ * Name: ltr308_get_status
+ *
+ * Description:
+ *   Get the status information of LTR308
+ *
+ * Return value:
+ *   Zero (OK) on success; a negated errno value on failure
+ ****************************************************************************/
+
+static int ltr308_get_status(FAR struct ltr308_dev_s *priv,
+                             FAR bool *power_on,
+                             FAR bool *interrupt_pending,
+                             FAR bool *data_pending)
+{
+  uint8_t status;
+  uint8_t ret;
+
+  ret = ltr308_get_reg8(priv, LTR308_STATUS, &status);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  if (power_on != NULL)
+    {
+      *power_on = status & 0x20;
+    }
+
+  if (interrupt_pending != NULL)
+    {
+      *interrupt_pending = status & 0x10;
+    }
+
+  if (data_pending != NULL)
+    {
+      *data_pending = status & 0x08;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: ltr308_get_lux
+ *
+ * Description:
+ *   Convert raw data to lux
+ *   @gain: see ltr308_calibrate()
+ *   @integration_time: see ltr308_calibrate()
+ *   @ch: result from ltr308_get_data()
+ *
+ * Return value:
+ *   Zero (OK) on success; a negated errno value on failure
+ ****************************************************************************/
+
+static int ltr308_get_lux(FAR struct ltr308_dev_s *priv, uint8_t gain,
+                          uint8_t integration_time, uint32_t data,
+                          FAR float *lux)
+{
+  float d0;
+
+  /* Determine if sensor is saturated. If so, abandon ship (calculation will
+   * not be accurate)
+   */
+
+  if (data == 0x000fffff)
+    {
+      *lux = 0.0;
+      return -ENODATA;
+    }
+
+  d0 = ((float)data * 0.6);
+  switch (gain)
+    {
+      case 0:
+        break;
+
+      case 1:
+        d0 /= 3;
+        break;
+
+      case 2:
+        d0 /= 6;
+        break;
+
+      case 3:
+        d0 /= 9;
+        break;
+
+      case 4:
+        d0 /= 18;
+        break;
+
+      default:
+        d0 = 0.0;
+        break;
+    }
+
+  switch (integration_time)
+    {
+      case 0:
+        *lux = d0 / 4;
+        break;
+
+      case 1:
+        *lux = d0 / 2;
+        break;
+
+      case 2:
+        *lux = d0;
+        break;
+
+      case 3:
+        *lux = d0 * 2;
+        break;
+
+      case 4:
+        *lux = d0 * 4;
+        break;
+
+      default:
+        *lux = 0.0;
+        break;
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: ltr308_activate
+ *
+ * Description:
+ *   Enable/Disable LTR308 sensor
+ *
+ * Return value:
+ *   Zero (OK) on success; a negated errno value on failure
+ ****************************************************************************/
+
+static int ltr308_activate(FAR struct sensor_lowerhalf_s *lower,
+                           FAR struct file *filep, bool enabled)
+{
+  FAR struct ltr308_sensor_s *dev = container_of(lower,
+                                                 FAR struct ltr308_sensor_s,
+                                                 lower);
+  FAR struct ltr308_dev_s *priv = container_of(dev,
+                                               FAR struct ltr308_dev_s,
+                                               dev);
+  int ret;
+
+  ret = ltr308_set_reg8(priv, LTR308_CTRL, enabled << 1);
+  if (ret < 0)
+    {
+      snerr("ERROR: Could not enable sensor\n");
+      return ret;
+    }
+
+  priv->enabled = enabled;
+  if (enabled == true)
+    {
+      /* Wake up the polling thread */
+
+      nxsem_post(&priv->run);
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: ltr308_calibrate
+ *
+ * Description:
+ *   Set the integration time, measurement rate and gain of LTR308
+ *   @integration_time - the measurement time for each ALS cycle
+ *   @measurement_rate - the interval between DATA_REGISTERS update. Must be
+ *                       set to be equal or greater than integration time
+ *   @gain             - the sensor gain
+ *
+ * Return value:
+ *   Zero (OK) on success; a negated errno value on failure
+ ****************************************************************************/
+
+static int ltr308_calibrate(FAR struct sensor_lowerhalf_s *lower,
+                            FAR struct file *filep,
+                            unsigned long arg)
+{
+  FAR struct ltr308_sensor_s *dev = container_of(lower,
+                                                 FAR struct ltr308_sensor_s,
+                                                 lower);
+  FAR struct ltr308_dev_s *priv = container_of(dev,
+                                               FAR struct ltr308_dev_s,
+                                               dev);
+  FAR struct ltr308_calibval *calibval =
+        (FAR struct ltr308_calibval *) arg;
+  uint8_t measurement = 0;
+  int ret;
+
+  /* Sanity checks */
+
+  if (calibval->integration_time >= 5)
+    {
+      calibval->integration_time = 0;
+    }
+
+  if (calibval->measurement_rate >= 6 || calibval->measurement_rate == 4)
+    {
+      calibval->measurement_rate = 0;
+    }
+
+  if (calibval->gain >= 5)
+    {
+      calibval->gain = 0;
+    }
+
+  /* Do not overwrite if the values have not been modified */
+
+  nxmutex_lock(&priv->dev_lock);
+
+  if (dev->integration_time != calibval->integration_time ||
+      dev->measurement_rate != calibval->measurement_rate)
+    {
+      dev->integration_time = calibval->integration_time;
+      dev->measurement_rate = calibval->measurement_rate;
+
+      measurement |= calibval->integration_time << 4;
+      measurement |= calibval->measurement_rate;
+
+      ret = ltr308_set_reg8(priv, LTR308_MEAS_RATE, measurement);
+      if (ret < 0)
+        {
+          goto err_out;
+        }
+    }
+
+  if (dev->gain != calibval->gain)
+    {
+      dev->gain = calibval->gain;
+
+      ret = ltr308_set_reg8(priv, LTR308_ALS_GAIN, calibval->gain);
+      if (ret < 0)
+        {
+          goto err_out;
+        }
+    }
+
+  nxmutex_unlock(&priv->dev_lock);
+  return OK;
+
+err_out:
+  nxmutex_unlock(&priv->dev_lock);
+  snerr("ERROR: Failed to calibrate sensor\n");
+  return ret;
+}
+
+/****************************************************************************
+ * Name: ltr308_thread
+ *
+ * Description:
+ *   Thread for performing data readings at fixed intervals, defined by
+ *   CONFIG_SENSORS_LTR308_POLL_INTERVAL
+ *   @argc - Number of arguments
+ *   @argv - Pointer to argument list
+ *
+ * Return value:
+ *   Zero (OK) on success; a negated errno value on failure
+ ****************************************************************************/
+
+static int ltr308_thread(int argc, char** argv)
+{
+  FAR struct ltr308_dev_s *priv = (FAR struct ltr308_dev_s *)
+        ((uintptr_t)strtoul(argv[1], NULL, 0));
+  struct sensor_light light;
+  uint32_t data = 0;
+  bool data_pending;
+  float lux;
+  int ret;
+
+  while (true)
+    {
+      if (priv->enabled == false)
+        {
+          /* Wait for the sensor to be enabled */
+
+          nxsem_wait(&priv->run);
+        }
+
+      /* Read the data registers and sleep if no change is detected
+       * or the sensor is saturated
+       */
+
+      ret = ltr308_get_status(priv, NULL, NULL, &data_pending);
+      if (ret < 0)
+        {
+          snerr("ERROR: Failed to read sensor's status\n");
+          return ret;
+        }
+
+      if (data_pending == false)
+        {
+          goto thread_sleep;
+        }
+
+      ret = ltr308_get_reg24(priv, LTR308_DATA_0, &data);
+      if (ret < 0)
+        {
+          snerr("ERROR: Failed to read data from sensor\n");
+          return ret;
+        }
+
+      ret = ltr308_get_lux(priv, priv->dev.gain, priv->dev.integration_time,
+                           data, &lux);
+      if (ret < 0)
+        {
+          goto thread_sleep;
+        }
+
+      light.timestamp = sensor_get_timestamp();
+      light.light = lux;
+      priv->dev.lower.push_event(priv->dev.lower.priv, &light,
+                                 sizeof(struct sensor_light));
+
+thread_sleep:
+      nxsig_usleep(CONFIG_SENSORS_LTR308_POLL_INTERVAL);
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ltr308_register
+ *
+ * Description:
+ *   Register the LTR308 character device
+ *   @devno - The user-specified device number, starting from 0
+ *   @i2c   - An instance of the I2C interface to use to communicate with
+ *           LTR308
+ *
+ * Return value:
+ *   Zero (OK) on success; a negated errno value on failure
+ ****************************************************************************/
+
+int ltr308_register(int devno, FAR struct i2c_master_s *i2c)
+{
+  FAR struct sensor_lowerhalf_s *lower;
+  FAR struct ltr308_dev_s *priv;
+  FAR char *argv[2];
+  char arg1[32];
+  int ret = OK;
+
+  DEBUGASSERT(i2c != NULL);
+
+  /* Initialize the LTR308 device structure */
+
+  priv = (FAR struct ltr308_dev_s *)kmm_zalloc(sizeof(struct ltr308_dev_s));
+  if (priv == NULL)
+    {
+      snerr("ERROR: Failed to allocate instance (err = %d)\n", ret);
+      return -ENOMEM;
+    }
+
+  priv->i2c = i2c;
+  priv->enabled = false;
+  nxmutex_init(&priv->dev_lock);
+  nxsem_init(&priv->run, 0, 0);
+
+  /* Check Device ID */
+
+  ret = ltr308_checkid(priv);
+  if (ret < 0)
+    {
+      snerr("ERROR: Wrong device ID!\n");
+      goto err_init;
+    }
+
+  /* Register the character driver */
+
+  lower = &priv->dev.lower;
+  lower->ops = &g_sensor_ops;
+  lower->type = SENSOR_TYPE_LIGHT;
+
+  ret = sensor_register(lower, 0);
+  if (ret < 0)
+    {
+      snerr("ERROR: Failed to register driver (err = %d)\n", ret);
+      goto err_init;
+    }
+
+  /* Create thread for polling sensor data */
+
+  snprintf(arg1, 16, "0x%" PRIxPTR, (uintptr_t)priv);
+  argv[0] = arg1;
+  argv[1] = NULL;
+  ret = kthread_create("ltr308_thread", SCHED_PRIORITY_DEFAULT,
+                       CONFIG_SENSORS_LTR308_THREAD_STACKSIZE,
+                       ltr308_thread, argv);
+  if (ret < 0)
+    {
+      snerr("ERROR: Failed to create poll thread (err = %d)\n", ret);
+      goto err_register;
+    }
+
+  sninfo("LTR308 driver loaded successfully!\n");
+  return OK;
+
+err_register:
+  sensor_unregister(lower, 0);
+err_init:
+  nxsem_destroy(&priv->run);
+  nxmutex_destroy(&priv->dev_lock);
+  kmm_free(priv);
+  return ret;
+}
+
+#endif /* CONFIG_I2C && CONFIG_SENSORS_LTR308 */
diff --git a/include/nuttx/sensors/ltr308.h b/include/nuttx/sensors/ltr308.h
new file mode 100644
index 0000000000..d02b028123
--- /dev/null
+++ b/include/nuttx/sensors/ltr308.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+ * include/nuttx/sensors/ltr308.h
+ * Character driver for the LTR-308ALS-01 Lite-On ambient light sensor.
+ *
+ * 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_LTR308_H
+#define __INCLUDE_NUTTX_SENSORS_LTR308_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/sensors/ioctl.h>
+
+/* Configuration ************************************************************
+ * Prerequisites:
+ *
+ * CONFIG_I2C
+ *   Enables support for I2C drivers
+ * CONFIG_SENSORS_LTR308
+ *   Enables support for the LTR308 driver
+ */
+
+#if defined(CONFIG_I2C) && defined(CONFIG_SENSORS_LTR308)
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+struct i2c_master_s;
+
+struct ltr308_calibval
+{
+  uint8_t integration_time;
+  uint8_t measurement_rate;
+  uint8_t gain;
+};
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Name: ltr308_register
+ *
+ * Description:
+ *   Register the LTR308 character device as 'devpath'.
+ *
+ * Input Parameters:
+ *   devno   - Number of device (i.e. ltr0, ltr1, ...)
+ *   i2c     - An I2C driver instance.
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int ltr308_register(int devno, FAR struct i2c_master_s *i2c);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CONFIG_I2C && CONFIG_SENSORS_LTR308 */
+#endif /* __INCLUDE_NUTTX_SENSORS_LTR308_H */