From 35056fd64742e954c537c35ef8e5a32a70d25467 Mon Sep 17 00:00:00 2001
From: Vincent Dupont <vincent@otakeys.com>
Date: Tue, 17 Jan 2017 18:02:44 +0100
Subject: [PATCH] drivers/adcxx1c: add ADC081C/ADC101C/ADC121C i2c adc support

---
 drivers/Makefile.dep                     |   5 +
 drivers/Makefile.include                 |   3 +
 drivers/adcxx1c/Makefile                 |   1 +
 drivers/adcxx1c/adcxx1c.c                | 148 +++++++++++++++++++++++
 drivers/adcxx1c/adcxx1c_saul.c           |  41 +++++++
 drivers/adcxx1c/include/adcxx1c_params.h |  97 +++++++++++++++
 drivers/adcxx1c/include/adcxx1c_regs.h   |  53 ++++++++
 drivers/include/adcxx1c.h                | 145 ++++++++++++++++++++++
 sys/auto_init/auto_init.c                |   4 +
 sys/auto_init/saul/auto_init_adcxx1c.c   |  71 +++++++++++
 tests/driver_adcxx1c/Makefile            |  21 ++++
 tests/driver_adcxx1c/main.c              |  68 +++++++++++
 12 files changed, 657 insertions(+)
 create mode 100644 drivers/adcxx1c/Makefile
 create mode 100644 drivers/adcxx1c/adcxx1c.c
 create mode 100644 drivers/adcxx1c/adcxx1c_saul.c
 create mode 100644 drivers/adcxx1c/include/adcxx1c_params.h
 create mode 100644 drivers/adcxx1c/include/adcxx1c_regs.h
 create mode 100644 drivers/include/adcxx1c.h
 create mode 100644 sys/auto_init/saul/auto_init_adcxx1c.c
 create mode 100644 tests/driver_adcxx1c/Makefile
 create mode 100644 tests/driver_adcxx1c/main.c

diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep
index 546f47851d..d8cf634064 100644
--- a/drivers/Makefile.dep
+++ b/drivers/Makefile.dep
@@ -239,3 +239,8 @@ ifneq (,$(filter lsm6dsl,$(USEMODULE)))
   FEATURES_REQUIRED += periph_i2c
   USEMODULE += xtimer
 endif
+
+ifneq (,$(filter adcxx1c,$(USEMODULE)))
+  FEATURES_REQUIRED += periph_gpio
+  FEATURES_REQUIRED += periph_i2c
+endif
diff --git a/drivers/Makefile.include b/drivers/Makefile.include
index 1f24aad678..8a4991b785 100644
--- a/drivers/Makefile.include
+++ b/drivers/Makefile.include
@@ -124,3 +124,6 @@ endif
 ifneq (,$(filter dsp0401,$(USEMODULE)))
     USEMODULE_INCLUDES += $(RIOTBASE)/drivers/dsp0401/include
 endif
+ifneq (,$(filter adcxx1c,$(USEMODULE)))
+    USEMODULE_INCLUDES += $(RIOTBASE)/drivers/adcxx1c/include
+endif
diff --git a/drivers/adcxx1c/Makefile b/drivers/adcxx1c/Makefile
new file mode 100644
index 0000000000..48422e909a
--- /dev/null
+++ b/drivers/adcxx1c/Makefile
@@ -0,0 +1 @@
+include $(RIOTBASE)/Makefile.base
diff --git a/drivers/adcxx1c/adcxx1c.c b/drivers/adcxx1c/adcxx1c.c
new file mode 100644
index 0000000000..33d2b8fe07
--- /dev/null
+++ b/drivers/adcxx1c/adcxx1c.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2017 OTA keys S.A.
+ *
+ * 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_adcxx1x
+ * @{
+ *
+ * @file
+ * @brief       ADCXX1C ADC device driver
+ *
+ * @author      Vincent Dupont <vincent@otakeys.com>
+ * @}
+ */
+
+#include "adcxx1c.h"
+#include "adcxx1c_params.h"
+#include "adcxx1c_regs.h"
+
+#include "periph/i2c.h"
+#include "periph/gpio.h"
+
+#define ENABLE_DEBUG (0)
+#include "debug.h"
+
+#define I2C_SPEED I2C_SPEED_FAST
+
+#define I2C (dev->params.i2c)
+#define ADDR (dev->params.addr)
+
+/* Configuration register test value
+ * value 0x20: cycle time = Tconvert x 64 */
+#define CONF_TEST_VALUE (0x20)
+
+int adcxx1c_init(adcxx1c_t *dev, const adcxx1c_params_t *params)
+{
+    assert(dev && params);
+
+    dev->params = *params;
+    dev->cb = NULL;
+
+    i2c_acquire(I2C);
+    if (i2c_init_master(I2C, I2C_SPEED) < 0) {
+        i2c_release(I2C);
+        DEBUG("[adcxx1c] init - error: unable to initialize I2C bus\n");
+        return ADCXX1C_NOI2C;
+    }
+
+    uint8_t reg = 0;
+
+    /* Test communication write and read configuration register */
+    i2c_write_reg(I2C, ADDR, ADCXX1C_CONF_ADDR, CONF_TEST_VALUE);
+    i2c_read_reg(I2C, ADDR, ADCXX1C_CONF_ADDR, &reg);
+
+    if (reg != CONF_TEST_VALUE) {
+        i2c_release(I2C);
+        DEBUG("[adcxx1c] init - error: unable to communicate with the device (reg=%x)\n", reg);
+        return ADCXX1C_NODEV;
+    }
+
+    reg = dev->params.cycle << 5;
+    i2c_write_reg(I2C, ADDR, ADCXX1C_CONF_ADDR, reg);
+    i2c_release(I2C);
+
+    adcxx1c_set_alert_parameters(dev, dev->params.low_limit,
+                                 dev->params.high_limit,
+                                 dev->params.hysteresis);
+
+    return ADCXX1C_OK;
+}
+
+int adcxx1c_read_raw(const adcxx1c_t *dev, int16_t *raw)
+{
+    uint8_t buf[2];
+    int status;
+
+    i2c_acquire(I2C);
+    status = i2c_read_regs(I2C, ADDR, ADCXX1C_CONV_RES_ADDR, buf, 2);
+    i2c_release(I2C);
+    if (status < 2) {
+        return ADCXX1C_NOI2C;
+    }
+
+    *raw = ((buf[0] & 0x0F) << 8 | buf[1]) >> (12 - dev->params.bits);
+
+    return ADCXX1C_OK;
+}
+
+static void _alert_cb(void *arg)
+{
+    adcxx1c_t *dev = arg;
+
+    if (dev->cb) {
+        dev->cb(dev->arg);
+    }
+}
+
+int adcxx1c_enable_alert(adcxx1c_t *dev, adcxx1c_cb_t cb, void *arg)
+{
+    uint8_t reg;
+
+    i2c_acquire(I2C);
+    i2c_read_reg(I2C, ADDR, ADCXX1C_CONF_ADDR, &reg);
+    reg |= (dev->params.alert_pin != GPIO_UNDEF ? ADCXX1C_CONF_ALERT_PIN_EN : 0)
+            | ADCXX1C_CONF_ALERT_FLAG_EN;
+    i2c_write_reg(I2C, ADDR, ADCXX1C_CONF_ADDR, reg);
+    i2c_release(I2C);
+
+    if (dev->params.alert_pin != GPIO_UNDEF) {
+        dev->cb = cb;
+        dev->arg = arg;
+        /* alert active low */
+        gpio_init_int(dev->params.alert_pin, GPIO_IN, GPIO_FALLING, _alert_cb, dev);
+    }
+
+    return ADCXX1C_OK;
+}
+
+int adcxx1c_set_alert_parameters(const adcxx1c_t *dev, int16_t low_limit,
+                                 int16_t high_limit, int16_t hysteresis)
+{
+    uint8_t buf[2];
+
+    i2c_acquire(I2C);
+
+    low_limit <<= (12 - dev->params.bits);
+    buf[0] = low_limit >> 8;
+    buf[1] = low_limit & 0xFF;
+    i2c_write_regs(I2C, ADDR, ADCXX1C_LOW_LIMIT_ADDR, buf, 2);
+
+    high_limit <<= (12 - dev->params.bits);
+    buf[0] = high_limit >> 8;
+    buf[1] = high_limit & 0xFF;
+    i2c_write_regs(I2C, ADDR, ADCXX1C_HIGH_LIMIT_ADDR, buf, 2);
+
+    hysteresis <<= (12 - dev->params.bits);
+    buf[0] = hysteresis >> 8;
+    buf[1] = hysteresis & 0xFF;
+    i2c_write_regs(I2C, ADDR, ADCXX1C_HYSTERESIS_ADDR, buf, 2);
+
+    i2c_release(I2C);
+
+    return ADCXX1C_OK;
+}
diff --git a/drivers/adcxx1c/adcxx1c_saul.c b/drivers/adcxx1c/adcxx1c_saul.c
new file mode 100644
index 0000000000..a697de47f1
--- /dev/null
+++ b/drivers/adcxx1c/adcxx1c_saul.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2017 OTA keys S.A.
+ *
+ * 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     driver_adcxx1c
+ * @{
+ *
+ * @file
+ * @brief       ADCxx1C adaption to the RIOT actuator/sensor interface
+ *
+ * @author      Vincent Dupont <vincent@otakeys.com>
+ *
+ * @}
+ */
+
+#include <string.h>
+#include <stdio.h>
+
+#include "saul.h"
+#include "adcxx1c.h"
+
+static int read_adc(void *dev, phydat_t *res)
+{
+    adcxx1c_read_raw((adcxx1c_t *)dev, res->val);
+
+    res->unit = UNIT_NONE;
+    res->scale = 0;
+
+    return 1;
+}
+
+const saul_driver_t adcxx1c_saul_driver = {
+    .read = read_adc,
+    .write = saul_notsup,
+    .type = SAUL_SENSE_ANALOG,
+};
diff --git a/drivers/adcxx1c/include/adcxx1c_params.h b/drivers/adcxx1c/include/adcxx1c_params.h
new file mode 100644
index 0000000000..6f8b6d83a3
--- /dev/null
+++ b/drivers/adcxx1c/include/adcxx1c_params.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2017 OTA keys S.A.
+ *
+ * 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_adcxx1x
+ * @{
+ *
+ * @file
+ * @brief       Default configuration for ADCXX1C devices
+ *
+ * @author      Vincent Dupont <vincent@otakeys.com>
+ */
+
+#ifndef ADCXX1C_PARAMS_H
+#define ADCXX1C_PARAMS_H
+
+#include "board.h"
+#include "saul_reg.h"
+#include "adcxx1c.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   Set default configuration parameters for the ADCXX1C driver
+ * @{
+ */
+#ifndef ADCXX1C_PARAM_I2C
+#define ADCXX1C_PARAM_I2C        (I2C_DEV(0))
+#endif
+#ifndef ADCXX1C_PARAM_ADDR
+#define ADCXX1C_PARAM_ADDR       (ADCXX1C_I2C_ADDRESS)
+#endif
+#ifndef ADCXX1C_PARAM_BITS
+#define ADCXX1C_PARAM_BITS       (ADCXX1C_RES_8BITS)
+#endif
+#ifndef ADCXX1C_PARAM_CYCLE
+#define ADCXX1C_PARAM_CYCLE      (ADCXX1C_CYCLE_DISABLED)
+#endif
+#ifndef ADCXX1C_PARAM_ALERT_PIN
+#define ADCXX1C_PARAM_ALERT_PIN  (GPIO_UNDEF)
+#endif
+#ifndef ADCXX1C_PARAM_LOW_LIMIT
+#define ADCXX1C_PARAM_LOW_LIMIT  (0)
+#endif
+#ifndef ADCXX1C_PARAM_HIGH_LIMIT
+#define ADCXX1C_PARAM_HIGH_LIMIT (0)
+#endif
+#ifndef ADCXX1C_PARAM_HYSTERESIS
+#define ADCXX1C_PARAM_HYSTERESIS (0)
+#endif
+
+#define ADCXX1C_PARAMS_DEFAULT  { .i2c        = ADCXX1C_PARAM_I2C, \
+                                  .addr       = ADCXX1C_PARAM_ADDR, \
+                                  .bits       = ADCXX1C_PARAM_BITS, \
+                                  .cycle      = ADCXX1C_PARAM_CYCLE, \
+                                  .alert_pin  = ADCXX1C_PARAM_ALERT_PIN, \
+                                  .low_limit  = ADCXX1C_PARAM_LOW_LIMIT, \
+                                  .high_limit = ADCXX1C_PARAM_HIGH_LIMIT, \
+                                  .hysteresis = ADCXX1C_PARAM_HYSTERESIS }
+/** @} */
+
+/**
+ * @brief   ADCXX1C configuration
+ */
+static const adcxx1c_params_t adcxx1c_params[] =
+{
+#ifdef ADCXX1C_PARAMS_BOARD
+    ADCXX1C_PARAMS_BOARD,
+#else
+    ADCXX1C_PARAMS_DEFAULT,
+#endif
+};
+
+
+/**
+ * @brief   Additional meta information to keep in the SAUL registry
+ */
+static const saul_reg_info_t adcxx1c_saul_info[] =
+{
+    {
+        .name = "adc081c",
+    },
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ADCXX1C_PARAMS_H */
+/** @} */
diff --git a/drivers/adcxx1c/include/adcxx1c_regs.h b/drivers/adcxx1c/include/adcxx1c_regs.h
new file mode 100644
index 0000000000..10e7c1854a
--- /dev/null
+++ b/drivers/adcxx1c/include/adcxx1c_regs.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2017 OTA keys S.A.
+ *
+ * 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_adcxx1x
+ * @{
+ *
+ * @file
+ * @brief       Register definition for ADCXX1C devices
+ *
+ * @author      Vincent Dupont <vincent@otakeys.com>
+ */
+
+#ifndef ADCXX1C_REGS_H
+#define ADCXX1C_REGS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @name ADCxx1C register addesses
+ * @{
+ */
+#define ADCXX1C_CONV_RES_ADDR      (0)
+#define ADCXX1C_ALERT_STATUS_ADDR  (1)
+#define ADCXX1C_CONF_ADDR          (2)
+#define ADCXX1C_LOW_LIMIT_ADDR     (3)
+#define ADCXX1C_HIGH_LIMIT_ADDR    (4)
+#define ADCXX1C_HYSTERESIS_ADDR    (5)
+#define ADCXX1C_LOWEST_CONV_ADDR   (6)
+#define ADCXX1C_HIGHEST_CONV_ADDR  (7)
+/** @} */
+
+/**
+ * @name ADCxx1C Config flags
+ * @{
+ */
+#define ADCXX1C_CONF_ALERT_PIN_EN   (1 << 2)
+#define ADCXX1C_CONF_ALERT_FLAG_EN  (1 << 3)
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ADCXX1C_REGS_H */
+/** @} */
diff --git a/drivers/include/adcxx1c.h b/drivers/include/adcxx1c.h
new file mode 100644
index 0000000000..c9fd9c2494
--- /dev/null
+++ b/drivers/include/adcxx1c.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2017 OTA keys S.A.
+ *
+ * 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_adcxx1x ADCXX1C ADC device driver
+ * @ingroup    drivers_sensors
+ * @{
+ *
+ * @file
+ * @brief       ADCXX1C ADC device driver
+ *
+ * @author      Vincent Dupont <vincent@otakeys.com>
+ */
+
+#ifndef ADCXX1C_H
+#define ADCXX1C_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "periph/i2c.h"
+#include "periph/gpio.h"
+
+#ifndef ADCXX1C_I2C_ADDRESS
+/** ADCxx1C default address (ADCxx1C021 address) */
+#define ADCXX1C_I2C_ADDRESS  (0x54)
+#endif
+
+/**
+ * @brief   ADC resolution
+ */
+enum {
+    ADCXX1C_RES_8BITS  = 8,  /**< 8 bits resolution (ADC081C family) */
+    ADCXX1C_RES_10BITS = 10, /**< 10 bits resolution (ADC101C family) */
+    ADCXX1C_RES_12BITS = 12, /**< 12 bits resolution (ADC121C family) */
+};
+
+/**
+ * @brief   Conversion interval configuration value
+ */
+enum {
+    ADCXX1C_CYCLE_DISABLED = 0,  /**< No cycle conversion */
+    ADCXX1C_CYCLE_32,            /**< Conversion cycle = Tconvert x 32 */
+    ADCXX1C_CYCLE_64,            /**< Conversion cycle = Tconvert x 64 */
+    ADCXX1C_CYCLE_128,           /**< Conversion cycle = Tconvert x 128 */
+    ADCXX1C_CYCLE_256,           /**< Conversion cycle = Tconvert x 256 */
+    ADCXX1C_CYCLE_512,           /**< Conversion cycle = Tconvert x 512 */
+    ADCXX1C_CYCLE_1024,          /**< Conversion cycle = Tconvert x 1024 */
+    ADCXX1C_CYCLE_2048,          /**< Conversion cycle = Tconvert x 2048 */
+};
+
+/**
+ * @brief   Named return values
+ */
+enum {
+    ADCXX1C_OK          =  0,       /**< everything was fine */
+    ADCXX1C_NOI2C       = -1,       /**< I2C communication failed */
+    ADCXX1C_NODEV       = -2,       /**< no ADCXX1C device found on the bus */
+    ADCXX1C_NODATA      = -3        /**< no data available */
+};
+
+/**
+ * @brief   ADCxx1C params
+ */
+typedef struct adcxx1c_params {
+    i2c_t i2c;            /**< i2c device */
+    uint8_t addr;         /**< i2c address */
+    uint8_t bits;         /**< resolution */
+    uint8_t cycle;        /**< conversion interval */
+    gpio_t alert_pin;     /**< alert pin (GPIO_UNDEF if not connected) */
+    int16_t low_limit;    /**< alert low value */
+    int16_t high_limit;   /**< alert high value */
+    int16_t hysteresis;   /**< alert hysteresis */
+} adcxx1c_params_t;
+
+/**
+ * @brief   ADCxx1C alert callback
+ */
+typedef void (*adcxx1c_cb_t)(void *);
+
+/**
+ * @brief   ADCxx1C device descriptor
+ */
+typedef struct adcxx1c {
+    adcxx1c_params_t params; /**< device driver configuration */
+    adcxx1c_cb_t cb;         /**< alert callback */
+    void *arg;               /**< alert callback param */
+} adcxx1c_t;
+
+/**
+ * @brief Initialize an ADCxx1C ADC device
+ *
+ * @param[in,out] dev  device descriptor
+ * @param[in] params   device configuration
+ *
+ * @return zero on successful initialization, non zero on error
+ */
+int adcxx1c_init(adcxx1c_t *dev, const adcxx1c_params_t *params);
+
+/**
+ * @brief Read a raw ADC value
+ *
+ * @param[in] dev   device descriptor
+ * @param[out] raw  read value
+ *
+ * @return zero on successful read, non zero on error
+ */
+int adcxx1c_read_raw(const adcxx1c_t *dev, int16_t *raw);
+
+/**
+ * @brief Enable alert interrupt
+ *
+ * @param[in] dev   device descriptor
+ * @param[in] cb    callback called when the alert fires
+ * @param[in] arg   callback argument
+ *
+ * @return zero on success, non zero on error
+ */
+int adcxx1c_enable_alert(adcxx1c_t *dev, adcxx1c_cb_t cb, void *arg);
+
+/**
+ * @brief Set the alert parameters
+ *
+ * @param[in,out] dev      device descriptor
+ * @param[in] low_limit    alert low limit
+ * @param[in] high_limit   alert high limit
+ * @param[in] hysteresis   alert hysteresis
+ *
+ * @return zero on success, non zero on error
+ */
+int adcxx1c_set_alert_parameters(const adcxx1c_t *dev, int16_t low_limit,
+                                 int16_t high_limit, int16_t hysteresis);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ADCXX1C_H */
+/** @} */
diff --git a/sys/auto_init/auto_init.c b/sys/auto_init/auto_init.c
index 6b868eb9d0..f204846dca 100644
--- a/sys/auto_init/auto_init.c
+++ b/sys/auto_init/auto_init.c
@@ -335,6 +335,10 @@ void auto_init(void)
     extern void auto_init_lsm6dsl(void);
     auto_init_lsm6dsl();
 #endif
+#ifdef MODULE_ADCXX1C
+    extern void auto_init_adcxx1c(void);
+    auto_init_adcxx1c();
+#endif
 
 #endif /* MODULE_AUTO_INIT_SAUL */
 
diff --git a/sys/auto_init/saul/auto_init_adcxx1c.c b/sys/auto_init/saul/auto_init_adcxx1c.c
new file mode 100644
index 0000000000..2470f4c7a8
--- /dev/null
+++ b/sys/auto_init/saul/auto_init_adcxx1c.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2017 OTA keys S.A.
+ *
+ * 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     auto_init_saul
+ * @{
+ *
+ * @file
+ * @brief       Auto initialization of ADCXX1C ADC
+ *
+ * @author      Vincent Dupont <vincent@otakeys.com>
+ *
+ * @}
+ */
+
+#ifdef MODULE_ADCXX1C
+
+#include "log.h"
+
+#include "saul_reg.h"
+#include "adcxx1c.h"
+#include "adcxx1c_params.h"
+
+/**
+ * @brief   Define the number of configured sensors
+ */
+#define ADCXX1C_NUM    (sizeof(adcxx1c_params)/sizeof(adcxx1c_params[0]))
+
+/**
+ * @brief   Allocate memory for the device descriptors
+ */
+static adcxx1c_t adcxx1c_devs[ADCXX1C_NUM];
+
+/**
+ * @brief   Memory for the SAUL registry entries
+ */
+static saul_reg_t saul_entries[ADCXX1C_NUM];
+
+/**
+ * @brief   Reference the driver struct
+ */
+extern saul_driver_t adcxx1c_saul_driver;
+
+
+void auto_init_adcxx1c(void)
+{
+    for (unsigned i = 0; i < ADCXX1C_NUM; i++) {
+        const adcxx1c_params_t *p = &adcxx1c_params[i];
+
+        LOG_DEBUG("[auto_init_saul] initializing adcxx1c #%d\n", i);
+        if (adcxx1c_init(&adcxx1c_devs[i], p) < 0) {
+            LOG_ERROR("[auto_init_saul] error initializing adcxx1c #%d\n", i);
+            continue;
+        }
+
+        saul_entries[i].dev = &(adcxx1c_devs[i]);
+        saul_entries[i].name = adcxx1c_saul_info[i].name;
+        saul_entries[i].driver = &adcxx1c_saul_driver;
+        saul_reg_add(&(saul_entries[i]));
+    }
+}
+
+#else
+typedef int dont_be_pedantic;
+#endif /* MODULE_ADCXX1C */
diff --git a/tests/driver_adcxx1c/Makefile b/tests/driver_adcxx1c/Makefile
new file mode 100644
index 0000000000..f9aa117608
--- /dev/null
+++ b/tests/driver_adcxx1c/Makefile
@@ -0,0 +1,21 @@
+APPLICATION = driver_adcxx1c
+include ../Makefile.tests_common
+
+FEATURES_REQUIRED = periph_i2c
+
+USEMODULE += adcxx1c
+USEMODULE += xtimer
+
+# set alert parameters in case they are undefined
+TEST_ADCXX1C_LOW_LIMIT     ?= 90
+TEST_ADCXX1C_HIGH_LIMIT    ?= 130
+TEST_ADCXX1C_HYSTERESIS    ?= 10
+TEST_ADCXX1C_CYCLE_TIME    ?= ADCXX1C_CYCLE_32
+
+# export parameters
+CFLAGS += -DADCXX1C_PARAM_LOW_LIMIT=$(TEST_ADCXX1C_LOW_LIMIT)
+CFLAGS += -DADCXX1C_PARAM_HIGH_LIMIT=$(TEST_ADCXX1C_HIGH_LIMIT)
+CFLAGS += -DADCXX1C_PARAM_HYSTERESIS=$(TEST_ADCXX1C_HYSTERESIS)
+CFLAGS += -DADCXX1C_PARAM_CYCLES=$(TEST_ADCXX1C_CYCLE_TIME)
+
+include $(RIOTBASE)/Makefile.include
diff --git a/tests/driver_adcxx1c/main.c b/tests/driver_adcxx1c/main.c
new file mode 100644
index 0000000000..2cc6fb4ad9
--- /dev/null
+++ b/tests/driver_adcxx1c/main.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2017 OTA keys S.A.
+ *
+ * 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 tests
+ * @{
+ *
+ * @file
+ * @brief       Test application for the ADCXX1C ADC driver
+ *
+ * @author      Vincent Dupont <vincent@otakeys.com>
+ * @}
+ */
+
+#include <stdio.h>
+
+#include "xtimer.h"
+#include "timex.h"
+#include "adcxx1c.h"
+#include "adcxx1c_params.h"
+
+#define SLEEP       (100 * US_PER_MS)
+
+static adcxx1c_t dev;
+
+static void alert_cb(void *arg)
+{
+    puts("[Alert]\n");
+}
+
+int main(void)
+{
+    int16_t data;
+
+    puts("ADCXX1C analog to digital driver test application\n");
+    printf("Initializing ADCXX1C analog to digital at I2C_DEV(%i)... ",
+           adcxx1c_params->i2c);
+
+    if (adcxx1c_init(&dev, adcxx1c_params) == ADCXX1C_OK) {
+        puts("[OK]\n");
+    }
+    else {
+        puts("[Failed]");
+        return -1;
+    }
+
+    puts("Enabling alert interrupt: ");
+    if (adcxx1c_enable_alert(&dev, alert_cb, NULL) == ADCXX1C_OK) {
+        puts("[OK]\n");
+    }
+    else {
+        puts("[Failed]");
+        return -1;
+    }
+
+    while (1) {
+        adcxx1c_read_raw(&dev, &data);
+        printf("Raw analog value: %d\n", data);
+        xtimer_usleep(SLEEP);
+    }
+
+    return 0;
+}
-- 
GitLab