From 3a6a3b8b143ca741ada6f88d69fdb79261ac817b Mon Sep 17 00:00:00 2001
From: Alexandre Abadie <alexandre.abadie@inria.fr>
Date: Thu, 23 Mar 2017 14:11:44 +0100
Subject: [PATCH] drivers/si114x: initial basic support

---
 drivers/Makefile.dep                      |   6 +
 drivers/Makefile.include                  |   4 +
 drivers/include/si114x.h                  | 141 +++++++++++
 drivers/si114x/Makefile                   |   1 +
 drivers/si114x/include/si114x_internals.h | 207 ++++++++++++++++
 drivers/si114x/include/si114x_params.h    |  69 ++++++
 drivers/si114x/si114x.c                   | 272 ++++++++++++++++++++++
 drivers/si114x/si114x_saul.c              |  89 +++++++
 makefiles/pseudomodules.inc.mk            |   5 +
 9 files changed, 794 insertions(+)
 create mode 100644 drivers/include/si114x.h
 create mode 100644 drivers/si114x/Makefile
 create mode 100644 drivers/si114x/include/si114x_internals.h
 create mode 100644 drivers/si114x/include/si114x_params.h
 create mode 100644 drivers/si114x/si114x.c
 create mode 100644 drivers/si114x/si114x_saul.c

diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep
index de911d403b..bb24f336e2 100644
--- a/drivers/Makefile.dep
+++ b/drivers/Makefile.dep
@@ -280,6 +280,12 @@ ifneq (,$(filter sht11,$(USEMODULE)))
   USEMODULE += xtimer
 endif
 
+ifneq (,$(filter si114%,$(USEMODULE)))
+  USEMODULE += xtimer
+  FEATURES_REQUIRED += periph_i2c
+  USEMODULE += si114x
+endif
+
 ifneq (,$(filter si70%,$(USEMODULE)))
   USEMODULE += xtimer
   FEATURES_REQUIRED += periph_i2c
diff --git a/drivers/Makefile.include b/drivers/Makefile.include
index 03b3308775..4f6c8687e6 100644
--- a/drivers/Makefile.include
+++ b/drivers/Makefile.include
@@ -190,6 +190,10 @@ ifneq (,$(filter sdcard_spi,$(USEMODULE)))
   USEMODULE_INCLUDES += $(RIOTBASE)/drivers/sdcard_spi/include
 endif
 
+ifneq (,$(filter si114x,$(USEMODULE)))
+  USEMODULE_INCLUDES += $(RIOTBASE)/drivers/si114x/include
+endif
+
 ifneq (,$(filter si70xx,$(USEMODULE)))
   USEMODULE_INCLUDES += $(RIOTBASE)/drivers/si70xx/include
 endif
diff --git a/drivers/include/si114x.h b/drivers/include/si114x.h
new file mode 100644
index 0000000000..828d7192c1
--- /dev/null
+++ b/drivers/include/si114x.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2016-2018 Inria
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @defgroup    drivers_si114x Si1145/6/7 UV/Ambient light/Proximity sensors
+ * @ingroup     drivers_sensors
+ * @brief       Device driver for the Si1145/6/7 sensors family
+ * @{
+ *
+ * @file
+ * @brief       Device driver interface for the Si114x sensors family
+ *
+ * @author      Alexandre Abadie <alexandre.abadie@inria.fr>
+ *              Bas Stottelaar <basstottelaar@gmail.com>
+ */
+
+#ifndef SI114X_H
+#define SI114X_H
+
+#include "saul.h"
+#include "periph/i2c.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Initialization return codes
+ */
+typedef enum {
+    SI114X_OK,
+    SI114X_ERR_I2C,
+    SI114X_ERR_NODEV
+} si114x_ret_code_t;
+
+/**
+ * @brief Active LED current parameters
+ */
+typedef enum {
+    SI114X_PS_LED1 = 1,                /**< 5.6mA */
+    SI114X_PS_LED2,                    /**< 11.2mA */
+    SI114X_PS_LED3,                    /**< 22.4mA */
+    SI114X_PS_LED4,                    /**< 45mA */
+    SI114X_PS_LED5,                    /**< 67mA */
+    SI114X_PS_LED6,                    /**< 90mA */
+    SI114X_PS_LED7,                    /**< 112mA */
+    SI114X_PS_LED8,                    /**< 135mA */
+    SI114X_PS_LED9,                    /**< 157mA */
+    SI114X_PS_LED10,                   /**< 180mA */
+    SI114X_PS_LED11,                   /**< 202mA */
+    SI114X_PS_LED12,                   /**< 224mA */
+    SI114X_PS_LED13,                   /**< 269mA */
+    SI114X_PS_LED14,                   /**< 314mA */
+    SI114X_PS_LED15                    /**< 359mA */
+} si114x_led_current_t;
+
+/**
+ * @brief Device initialization parameters
+ */
+typedef struct {
+    i2c_t i2c_dev;                     /**< I2C device which is used */
+    si114x_led_current_t led_current;  /**< Proximity LED current */
+} si114x_params_t;
+
+
+/**
+ * @brief Device descriptor for the Si114x sensor
+ */
+typedef struct {
+    si114x_params_t params;           /**< Si114x initialization parameters */
+} si114x_t;
+
+/**
+ * @brief Initialize the given Si114x device
+ *
+ * @param[out] dev          Initialized device descriptor of Si114x device
+ * @param[in]  params       Initialization parameters
+ *
+ * @return                  SI114X_OK: all good
+ * @return                  -SI114X_ERR_I2C: I2C bus cannot be initialized
+ * @return                  -SI114X_ERR_NODEV: not a valid Si114x device
+ */
+int8_t si114x_init(si114x_t *dev, const si114x_params_t * params);
+
+/**
+ * @brief Read UV index from the given Si114x device
+ *
+ * @param[in] dev           Device descriptor of Si114x device to read from
+ *
+ * @return                  UV index
+ */
+uint16_t si114x_read_uv(si114x_t *dev);
+
+/**
+ * @brief Read IR light value from the given Si114x device, returned in lx
+ *
+ * @param[in]  dev          Device descriptor of Si114x device to read from
+ *
+ * @return                  IR light in lx
+ */
+uint16_t si114x_read_ir(si114x_t *dev);
+
+/**
+ * @brief Read visible light value from the given Si114x device, returned in lx
+ *
+ * @param[in]  dev          Device descriptor of Si114x device to read from
+ *
+ * @return                  Visible light in lx
+ */
+uint16_t si114x_read_visible(si114x_t *dev);
+
+/**
+ * @brief Read distance measure from the given Si114x device, returned in ADC
+ *        counts.
+ *
+ * @param[in]  dev          Device descriptor of Si114x device to read from
+ *
+ * @return                  Distance in ADC counts
+ */
+uint16_t si114x_read_distance(si114x_t *dev);
+
+/**
+ * @brief Read the response register.
+ *
+ * @param[in]  dev          Device descriptor of Si114x device to read from
+ *
+ * @return                  Device response register contents
+ */
+uint8_t si114x_read_response(si114x_t *dev);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SI114X_H */
+/** @} */
diff --git a/drivers/si114x/Makefile b/drivers/si114x/Makefile
new file mode 100644
index 0000000000..48422e909a
--- /dev/null
+++ b/drivers/si114x/Makefile
@@ -0,0 +1 @@
+include $(RIOTBASE)/Makefile.base
diff --git a/drivers/si114x/include/si114x_internals.h b/drivers/si114x/include/si114x_internals.h
new file mode 100644
index 0000000000..bb7081b921
--- /dev/null
+++ b/drivers/si114x/include/si114x_internals.h
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2016-2018 Inria
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup     drivers_si114x
+ * @brief       Internal addresses, registers, constants for the Si114x sensors family.
+ * @{
+ *
+ * @file
+ * @brief       Internal addresses, registers, constants for the Si114x sensor.
+ *
+ * @author      Alexandre Abadie <alexandre.abadie@inria.fr>
+ */
+
+#ifndef SI114X_INTERNALS_H
+#define SI114X_INTERNALS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Si114x I2C address
+ */
+#define SI114X_ADDR                            (0x60)
+
+/**
+ * @name Si114x commands
+ * @{
+ */
+#define SI114X_PARAM_QUERY                     (0x80)
+#define SI114X_PARAM_SET                       (0xA0)
+#define SI114X_NOP                             (0x00)
+#define SI114X_RESET                           (0x01)
+#define SI114X_BUSADDR                         (0x02)
+#define SI114X_PS_FORCE                        (0x05)
+#define SI114X_ALS_FORCE                       (0x06)
+#define SI114X_PS_ALS_FORCE                    (0x07)
+#define SI114X_PS_PAUSE                        (0x09)
+#define SI114X_ALS_PAUSE                       (0x0A)
+#define SI114X_PS_ALS_PAUSE                    (0x0B)
+#define SI114X_PS_AUTO                         (0x0D)
+#define SI114X_ALS_AUTO                        (0x0E)
+#define SI114X_PS_ALS_AUTO                     (0x0F)
+#define SI114X_GET_CAL                         (0x12)
+/** @} */
+
+/**
+ * @name Si114x registers
+ * @{
+ */
+#define SI114X_REG_PART_ID                     (0x00)
+#define SI114X_REG_REV_ID                      (0x01)
+#define SI114X_REG_SEQ_ID                      (0x02)
+#define SI114X_REG_INT_CFG                     (0x03)
+#define SI114X_REG_IRQ_ENABLE                  (0x04)
+#define SI114X_REG_IRQ_MODE1                   (0x05)
+#define SI114X_REG_IRQ_MODE2                   (0x06)
+#define SI114X_REG_HW_KEY                      (0x07)
+#define SI114X_REG_MEAS_RATE0                  (0x08)
+#define SI114X_REG_MEAS_RATE1                  (0x09)
+#define SI114X_REG_PS_LED21                    (0x0F)
+#define SI114X_REG_PS_LED3                     (0x10)
+#define SI114X_REG_UCOEF0                      (0x13)
+#define SI114X_REG_UCOEF1                      (0x14)
+#define SI114X_REG_UCOEF2                      (0x15)
+#define SI114X_REG_UCOEF3                      (0x16)
+#define SI114X_REG_PARAM_WR                    (0x17)
+#define SI114X_REG_COMMAND                     (0x18)
+#define SI114X_REG_RESPONSE                    (0x20)
+#define SI114X_REG_IRQ_STATUS                  (0x21)
+#define SI114X_REG_ALS_VIS_DATA0               (0x22)
+#define SI114X_REG_ALS_VIS_DATA1               (0x23)
+#define SI114X_REG_ALS_IR_DATA0                (0x24)
+#define SI114X_REG_ALS_IR_DATA1                (0x25)
+#define SI114X_REG_PS1_DATA0                   (0x26)
+#define SI114X_REG_PS1_DATA1                   (0x27)
+#define SI114X_REG_PS2_DATA0                   (0x28)
+#define SI114X_REG_PS2_DATA1                   (0x29)
+#define SI114X_REG_PS3_DATA0                   (0x2A)
+#define SI114X_REG_PS3_DATA1                   (0x2B)
+#define SI114X_REG_UV_INDEX0                   (0x2C)
+#define SI114X_REG_UV_INDEX1                   (0x2D)
+#define SI114X_REG_PARAM_RD                    (0x2E)
+#define SI114X_REG_CHIP_STAT                   (0x30)
+/** @} */
+
+/**
+ * @name Si114x response register error codes
+ * @{
+ */
+#define SI114X_NO_ERROR                        (0x00)
+#define SI114X_INVALID_SETTING                 (0x80)
+#define SI114X_PS1_ADC_OVERFLOW                (0x88)
+#define SI114X_PS2_ADC_OVERFLOW                (0x89)
+#define SI114X_PS3_ADC_OVERFLOW                (0x8A)
+#define SI114X_ALS_VIS_ADC_OVERFLOW            (0x8C)
+#define SI114X_ALS_IR_ADC_OVERFLOW             (0x8D)
+#define SI114X_UV_ADC_OVERFLOW                 (0x8E)
+/** @} */
+
+/**
+ * @name Si114x parameters RAM
+ *
+ * @note These parameter can be accessed indirectly using PARAM_QUERY or
+ *       PARAM_SET commands.
+ * @{
+ */
+#define SI114X_I2C_ADDR                        (0x00)
+#define SI114X_PARAM_CHLIST                    (0x01)
+#define SI114X_PARAM_CHLIST_ENUV               (0x80)
+#define SI114X_PARAM_CHLIST_ENAUX              (0x40)
+#define SI114X_PARAM_CHLIST_ENALSIR            (0x20)
+#define SI114X_PARAM_CHLIST_ENALSVIS           (0x10)
+#define SI114X_PARAM_CHLIST_ENPS1              (0x01)
+#define SI114X_PARAM_CHLIST_ENPS2              (0x02)
+#define SI114X_PARAM_CHLIST_ENPS3              (0x04)
+#define SI114X_PARAM_PSLED12SEL                (0x02)
+#define SI114X_PARAM_PSLED12SEL_PS2NONE        (0x00)
+#define SI114X_PARAM_PSLED12SEL_PS2LED1        (0x10)
+#define SI114X_PARAM_PSLED12SEL_PS2LED2        (0x20)
+#define SI114X_PARAM_PSLED12SEL_PS2LED3        (0x40)
+#define SI114X_PARAM_PSLED12SEL_PS1NONE        (0x00)
+#define SI114X_PARAM_PSLED12SEL_PS1LED1        (0x01)
+#define SI114X_PARAM_PSLED12SEL_PS1LED2        (0x02)
+#define SI114X_PARAM_PSLED12SEL_PS1LED3        (0x04)
+#define SI114X_PARAM_PSLED3SEL                 (0x03)
+#define SI114X_PARAM_PSENCODE                  (0x05)
+#define SI114X_PARAM_ALSENCODE                 (0x06)
+#define SI114X_PARAM_PS1ADCMUX                 (0x07)
+#define SI114X_PARAM_PS2ADCMUX                 (0x08)
+#define SI114X_PARAM_PS3ADCMUX                 (0x09)
+#define SI114X_PARAM_PSADCOUNTER               (0x0A)
+#define SI114X_PARAM_PSADCGAIN                 (0x0B)
+#define SI114X_PARAM_PSADCMISC                 (0x0C)
+#define SI114X_PARAM_PSADCMISC_RANGE           (0x20)
+#define SI114X_PARAM_PSADCMISC_PSMODE          (0x04)
+#define SI114X_PARAM_ALSIRADCMUX               (0x0E)
+#define SI114X_PARAM_AUXADCMUX                 (0x0F)
+#define SI114X_PARAM_ALSVISADCOUNTER           (0x10)
+#define SI114X_PARAM_ALSVISADCGAIN             (0x11)
+#define SI114X_PARAM_ALSVISADCMISC             (0x12)
+#define SI114X_PARAM_ALSVISADCMISC_VISRANGE    (0x20)
+#define SI114X_PARAM_ALSIRADCOUNTER            (0x1D)
+#define SI114X_PARAM_ALSIRADCGAIN              (0x1E)
+#define SI114X_PARAM_ALSIRADCMISC              (0x1F)
+#define SI114X_PARAM_ALSIRADCMISC_RANGE        (0x20)
+#define SI114X_PARAM_ADCMUX_SMALLIR            (0x00)
+#define SI114X_PARAM_ADCMUX_LARGEIR            (0x03)
+/** @} */
+
+/**
+ * @name Si114x constants
+ * @{
+ */
+#define SI1145_ID                              (0x45)
+#define SI1146_ID                              (0x46)
+#define SI1147_ID                              (0x47)
+#define SI114X_STARTUP_TIME                    (25000UL) /* 25ms */
+#define SI114X_WAIT_10MS                       (10000UL) /* 10ms */
+#define SI114X_INIT_VALUE                      (0x17)
+#define SI114X_UCOEF0_DEFAULT                  (0x29)
+#define SI114X_UCOEF1_DEFAULT                  (0x89)
+#define SI114X_UCOEF2_DEFAULT                  (0x02)
+#define SI114X_UCOEF3_DEFAULT                  (0x00)
+#define SI114X_ADC_REC_CLK                     (0x70) /* 511 ADC Clock */
+/** @} */
+
+/**
+ * @name Si114x register bits
+ * @{
+ */
+#define SI114X_EN_UV                           (0x80)
+#define SI114X_EN_AUX                          (0x40)
+#define SI114X_EN_ALS_IR                       (0x20)
+#define SI114X_EN_ALS_VIS                      (0x10)
+
+#define SI114X_EN_PS3_IE                       (0x10)
+#define SI114X_EN_PS2_IE                       (0x08)
+#define SI114X_EN_PS1_IE                       (0x04)
+#define SI114X_EN_ALS_IE                       (0x01)
+
+#define SI114X_INTCFG_INTOE                    (0x01)
+#define SI114X_INTCFG_INTMODE                  (0x02)
+
+#define SI114X_PS3_ALIGN                       (0x40)
+#define SI114X_PS2_ALIGN                       (0x20)
+#define SI114X_PS1_ALIGN                       (0x10)
+#define SI114X_ALS_IR_ALIGN                    (0x20)
+#define SI114X_ALS_VIS_ALIGN                   (0x10)
+#define SI114X_PS_RANGE                        (0x20)
+#define SI114X_PS_ADC_MODE                     (0x04)
+#define SI114X_VIS_RANGE                       (0x20)
+#define SI114X_IR_RANGE                        (0x20)
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SI114X_INTERNALS_H */
+/** @} */
diff --git a/drivers/si114x/include/si114x_params.h b/drivers/si114x/include/si114x_params.h
new file mode 100644
index 0000000000..d261613b10
--- /dev/null
+++ b/drivers/si114x/include/si114x_params.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016-2018 Inria
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup     drivers_si114x
+ *
+ * @{
+ * @file
+ * @brief       Default configuration for SI114x
+ *
+ * @author      Alexandre Abadie <alexandre.abadie@inria.fr>
+ */
+
+#ifndef SI114X_PARAMS_H
+#define SI114X_PARAMS_H
+
+#include "board.h"
+#include "si114x.h"
+#include "saul_reg.h"
+#include "si114x_internals.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @name    Set default configuration parameters for the Si114x
+ * @{
+ */
+#ifndef SI114X_PARAM_I2C_DEV
+#define SI114X_PARAM_I2C_DEV         I2C_DEV(1)
+#endif
+
+#ifndef SI114X_PARAMS
+#define SI114X_PARAMS                { .i2c_dev     = SI114X_PARAM_I2C_DEV, \
+                                       .led_current = SI114X_PS_LED1 }
+#endif
+#ifndef SI114X_SAUL_INFO
+#define SI114X_SAUL_INFO             { .name = "si114x" }
+#endif
+/**@}*/
+
+/**
+ * @brief   Configure Si114x
+ */
+static const si114x_params_t si114x_params[] =
+{
+    SI114X_PARAMS
+};
+
+/**
+ * @brief   Allocate and configure entries to the SAUL registry
+ */
+saul_reg_t si114x_saul_reg_info[] =
+{
+    SI114X_SAUL_INFO
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SI114X_PARAMS_H */
+/** @} */
diff --git a/drivers/si114x/si114x.c b/drivers/si114x/si114x.c
new file mode 100644
index 0000000000..4a65f82b73
--- /dev/null
+++ b/drivers/si114x/si114x.c
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2016-2018 Inria
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup     drivers_si114x
+ * @{
+ *
+ * @file
+ * @brief       Device driver implementation for the Si114x proximity/UV/Ambient
+ *              light sensor with I2C interface.
+ *
+ * @author      Alexandre Abadie <alexandre.abadie@inria.fr>
+ *              Bas Stottelaar <basstottelaar@gmail.com>
+ *
+ * @}
+ */
+
+#include <math.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "xtimer.h"
+
+#include "periph/i2c.h"
+
+#include "si114x.h"
+#include "si114x_internals.h"
+
+#define ENABLE_DEBUG        (0)
+#include "debug.h"
+
+#define DEV_I2C (dev->params.i2c_dev)
+
+/* Internal function prototypes */
+static void _reset(si114x_t *dev);
+static void _initialize(si114x_t *dev);
+static void _set_param(si114x_t *dev, uint8_t param, uint8_t value);
+
+/*---------------------------------------------------------------------------*
+ *                          Si114x Core API                                  *
+ *---------------------------------------------------------------------------*/
+
+int8_t si114x_init(si114x_t *dev, const si114x_params_t *params)
+{
+    dev->params = *params;
+
+    /* wait before sensor is ready */
+    xtimer_usleep(SI114X_STARTUP_TIME);
+
+    /* initialize I2C interface */
+    if (i2c_init_master(DEV_I2C, I2C_SPEED_NORMAL)) {
+        DEBUG("[Error] I2C device not enabled\n");
+        return -SI114X_ERR_I2C;
+    }
+
+    /* acquire exclusive access */
+    i2c_acquire(DEV_I2C);
+
+    /* check sensor ID */
+    char checkid = 0;
+    i2c_read_reg(DEV_I2C, SI114X_ADDR, SI114X_REG_PART_ID, &checkid);
+    if ((checkid != SI1145_ID) && (checkid != SI1146_ID) && (checkid != SI1147_ID)) {
+        DEBUG("[Error] The given i2c is not enabled.\n");
+        i2c_release(DEV_I2C);
+        return -SI114X_ERR_NODEV;
+    }
+
+    /* reset sensor */
+    _reset(dev);
+
+    /* initialize internals registers */
+    _initialize(dev);
+
+    /* release I2C device */
+    i2c_release(DEV_I2C);
+
+    return SI114X_OK;
+}
+
+uint16_t si114x_read_uv(si114x_t *dev)
+{
+    /* acquire exclusive access */
+    i2c_acquire(DEV_I2C);
+
+    uint8_t buffer[2];
+    i2c_read_regs(DEV_I2C, SI114X_ADDR,
+                  SI114X_REG_UV_INDEX0, &buffer, 2);
+
+    /* release I2C device */
+    i2c_release(DEV_I2C);
+
+    return (uint16_t)(((buffer[1] << 8) | buffer[0]) / 100);
+}
+
+uint16_t si114x_read_ir(si114x_t *dev)
+{
+    /* acquire exclusive access */
+    i2c_acquire(DEV_I2C);
+
+    uint8_t buffer[2];
+    i2c_read_regs(DEV_I2C, SI114X_ADDR,
+                  SI114X_REG_ALS_IR_DATA0, &buffer, 2);
+
+    /* release I2C device */
+    i2c_release(DEV_I2C);
+
+    return (uint16_t)((buffer[1] << 8) | buffer[0]);
+}
+
+uint16_t si114x_read_visible(si114x_t *dev)
+{
+    /* acquire exclusive access */
+    i2c_acquire(DEV_I2C);
+
+    uint8_t buffer[2];
+    i2c_read_regs(DEV_I2C, SI114X_ADDR,
+                  SI114X_REG_ALS_VIS_DATA0, &buffer, 2);
+
+    /* release I2C device */
+    i2c_release(DEV_I2C);
+
+    return (uint16_t)((buffer[1] << 8) | buffer[0]);
+}
+
+uint16_t si114x_read_distance(si114x_t *dev)
+{
+    /* acquire exclusive access */
+    i2c_acquire(DEV_I2C);
+
+    uint8_t buffer[2];
+    i2c_read_regs(DEV_I2C, SI114X_ADDR,
+                  SI114X_REG_PS1_DATA0, &buffer, 2);
+
+    /* release I2C device */
+    i2c_release(DEV_I2C);
+
+    return (uint16_t)((buffer[1] << 8) | buffer[0]);
+}
+
+uint8_t si114x_read_response(si114x_t *dev)
+{
+    /* acquire exclusive access */
+    i2c_acquire(DEV_I2C);
+
+    uint8_t buffer[1];
+    i2c_read_regs(DEV_I2C, SI114X_ADDR,
+                  SI114X_REG_RESPONSE, &buffer, 1);
+
+    /* release I2C device */
+    i2c_release(DEV_I2C);
+
+    return buffer[0];
+}
+
+/*------------------------------------------------------------------------------------*/
+/*                                Internal functions                                  */
+/*------------------------------------------------------------------------------------*/
+
+void _reset(si114x_t *dev)
+{
+    DEBUG("Resetting sensor.\n");
+
+    /* write configuration values */
+    i2c_write_reg(DEV_I2C, SI114X_ADDR,
+                  SI114X_REG_MEAS_RATE0, 0);
+    i2c_write_reg(DEV_I2C, SI114X_ADDR,
+                  SI114X_REG_MEAS_RATE1, 0);
+    i2c_write_reg(DEV_I2C, SI114X_ADDR,
+                  SI114X_REG_IRQ_ENABLE, 0);
+    i2c_write_reg(DEV_I2C, SI114X_ADDR,
+                  SI114X_REG_IRQ_MODE1, 0);
+    i2c_write_reg(DEV_I2C, SI114X_ADDR,
+                  SI114X_REG_IRQ_MODE2, 0);
+    i2c_write_reg(DEV_I2C, SI114X_ADDR,
+                  SI114X_REG_INT_CFG, 0);
+    i2c_write_reg(DEV_I2C, SI114X_ADDR,
+                  SI114X_REG_IRQ_STATUS, 0xFF);
+
+    /* perform RESET command */
+    i2c_write_reg(DEV_I2C, SI114X_ADDR,
+                  SI114X_REG_COMMAND, SI114X_RESET);
+    xtimer_usleep(SI114X_WAIT_10MS);
+
+    /* write HW_KEY for proper operation */
+    i2c_write_reg(DEV_I2C, SI114X_ADDR,
+                  SI114X_REG_HW_KEY, SI114X_INIT_VALUE);
+    xtimer_usleep(SI114X_WAIT_10MS);
+}
+
+
+void _initialize(si114x_t *dev)
+{
+    DEBUG("Initializing sensor.\n");
+
+    /* set default UV measurement coefs */
+    i2c_write_reg(DEV_I2C, SI114X_ADDR,
+                  SI114X_REG_UCOEF0, SI114X_UCOEF0_DEFAULT);
+    i2c_write_reg(DEV_I2C, SI114X_ADDR,
+                  SI114X_REG_UCOEF1, SI114X_UCOEF1_DEFAULT);
+    i2c_write_reg(DEV_I2C, SI114X_ADDR,
+                  SI114X_REG_UCOEF2, SI114X_UCOEF2_DEFAULT);
+    i2c_write_reg(DEV_I2C, SI114X_ADDR,
+                  SI114X_REG_UCOEF3, SI114X_UCOEF3_DEFAULT);
+
+    /* enable measures */
+    _set_param(dev, SI114X_PARAM_CHLIST,
+               SI114X_PARAM_CHLIST_ENUV | SI114X_PARAM_CHLIST_ENALSIR |
+               SI114X_PARAM_CHLIST_ENALSVIS | SI114X_PARAM_CHLIST_ENPS1);
+
+    /* enable interrupt on every sample */
+    i2c_write_reg(DEV_I2C, SI114X_ADDR,
+                  SI114X_REG_INT_CFG, SI114X_INTCFG_INTOE);
+    i2c_write_reg(DEV_I2C, SI114X_ADDR,
+                  SI114X_REG_IRQ_ENABLE, SI114X_EN_ALS_IE | SI114X_EN_PS1_IE);
+
+    /* active LED current */
+    i2c_write_reg(DEV_I2C, SI114X_ADDR,
+                  SI114X_REG_PS_LED21, dev->params.led_current);
+
+    _set_param(dev, SI114X_PARAM_PS1ADCMUX, SI114X_PARAM_ADCMUX_LARGEIR);
+
+    /* proximity sensor uses LED1 */
+    _set_param(dev, SI114X_PARAM_PSLED12SEL, SI114X_PARAM_PSLED12SEL_PS1LED1);
+
+    /* ADC gain */
+    _set_param(dev, SI114X_PARAM_PSADCGAIN, 0);
+    _set_param(dev, SI114X_PARAM_PSADCOUNTER, SI114X_ADC_REC_CLK);
+
+    /* proximity range */
+    _set_param(dev, SI114X_PARAM_PSADCMISC,
+               SI114X_PARAM_PSADCMISC_RANGE | SI114X_PARAM_PSADCMISC_PSMODE);
+    _set_param(dev, SI114X_PARAM_ALSIRADCMUX, SI114X_PARAM_ADCMUX_SMALLIR);
+
+    /* clocks configuration */
+    _set_param(dev, SI114X_PARAM_ALSIRADCGAIN, 0);
+    _set_param(dev, SI114X_PARAM_ALSIRADCOUNTER, SI114X_ADC_REC_CLK);
+
+    /* high range mode */
+    _set_param(dev, SI114X_PARAM_ALSIRADCMISC, SI114X_PARAM_ALSIRADCMISC_RANGE);
+
+    /* clocks config */
+    _set_param(dev, SI114X_PARAM_ALSVISADCGAIN, 0);
+    _set_param(dev, SI114X_PARAM_ALSVISADCOUNTER, SI114X_ADC_REC_CLK);
+
+    _set_param(dev, SI114X_PARAM_ALSVISADCMISC,
+               SI114X_PARAM_ALSVISADCMISC_VISRANGE);
+    i2c_write_reg(DEV_I2C, SI114X_ADDR,
+                  SI114X_REG_MEAS_RATE0, 0xFF);
+    i2c_write_reg(DEV_I2C, SI114X_ADDR,
+                  SI114X_REG_MEAS_RATE1, 0x00);
+
+    /* auto-run */
+    i2c_write_reg(DEV_I2C, SI114X_ADDR,
+                  SI114X_REG_COMMAND, SI114X_PS_ALS_AUTO);
+}
+
+void _set_param(si114x_t *dev, uint8_t param, uint8_t value)
+{
+    i2c_write_reg(DEV_I2C, SI114X_ADDR,
+                  SI114X_REG_PARAM_WR, value);
+    i2c_write_reg(DEV_I2C, SI114X_ADDR,
+                  SI114X_REG_COMMAND, param | SI114X_PARAM_SET);
+
+    uint8_t ret;
+    i2c_read_reg(DEV_I2C, SI114X_ADDR,
+                 SI114X_REG_PARAM_RD, &ret);
+}
diff --git a/drivers/si114x/si114x_saul.c b/drivers/si114x/si114x_saul.c
new file mode 100644
index 0000000000..96f48c5eaf
--- /dev/null
+++ b/drivers/si114x/si114x_saul.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2016-2018 Inria
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup     drivers_si114x
+ * @{
+ *
+ * @file
+ * @brief       SAUL adaption for Si114x devices family
+ *
+ * @author      Alexandre Abadie <alexandre.abadie@inria.fr>
+ *
+ * @}
+ */
+
+#include <string.h>
+
+#include "saul.h"
+#include "si114x.h"
+#include "xtimer.h"
+
+static int read_uv(const void *dev, phydat_t *res)
+{
+    si114x_t *d = (si114x_t *)dev;
+
+    res->val[0] = si114x_read_uv(d);
+    res->unit = UNIT_NONE;
+    res->scale = 0;
+    return 1;
+}
+
+static int read_ir(const void *dev, phydat_t *res)
+{
+    si114x_t *d = (si114x_t *)dev;
+
+    res->val[0] = si114x_read_ir(d);
+    res->unit = UNIT_LUX;
+    res->scale = 0;
+    return 1;
+}
+
+static int read_visible(const void *dev, phydat_t *res)
+{
+    si114x_t *d = (si114x_t *)dev;
+
+    res->val[0] = si114x_read_visible(d);
+    res->unit = UNIT_LUX;
+    res->scale = 0;
+    return 1;
+}
+
+static int read_distance(const void *dev, phydat_t *res)
+{
+    si114x_t *d = (si114x_t *)dev;
+
+    res->val[0] = si114x_read_distance(d);
+    res->unit = UNIT_M;
+    res->scale = 0;
+    return 1;
+}
+
+const saul_driver_t si114x_uv_saul_driver = {
+    .read = read_uv,
+    .write = saul_notsup,
+    .type = SAUL_SENSE_ANY
+};
+
+const saul_driver_t si114x_ir_saul_driver = {
+    .read = read_ir,
+    .write = saul_notsup,
+    .type = SAUL_SENSE_ANY
+};
+
+const saul_driver_t si114x_visible_saul_driver = {
+    .read = read_visible,
+    .write = saul_notsup,
+    .type = SAUL_SENSE_ANY
+};
+
+const saul_driver_t si114x_distance_saul_driver = {
+    .read = read_distance,
+    .write = saul_notsup,
+    .type = SAUL_SENSE_ANY
+};
diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk
index 868ed9b21e..4fec53670a 100644
--- a/makefiles/pseudomodules.inc.mk
+++ b/makefiles/pseudomodules.inc.mk
@@ -93,6 +93,11 @@ PSEUDOMODULES += adc121c
 PSEUDOMODULES += sx1272
 PSEUDOMODULES += sx1276
 
+# include variants of Si114x drivers as pseudo modules
+PSEUDOMODULES += si1145
+PSEUDOMODULES += si1146
+PSEUDOMODULES += si1147
+
 # include variants of Si70xx drivers as pseudo modules
 PSEUDOMODULES += si7006
 PSEUDOMODULES += si7013
-- 
GitLab