Add VCNL4040 I2C Light / Distance sensor support
authorNathael Pajani <nathael.pajani@ed3l.fr>
Thu, 15 Sep 2016 13:47:00 +0000 (15:47 +0200)
committerNathael Pajani <nathael.pajani@ed3l.fr>
Thu, 15 Sep 2016 13:47:00 +0000 (15:47 +0200)
extdrv/vcnl4040_sensor.c [new file with mode: 0644]
include/extdrv/vcnl4040_sensor.h [new file with mode: 0644]

diff --git a/extdrv/vcnl4040_sensor.c b/extdrv/vcnl4040_sensor.c
new file mode 100644 (file)
index 0000000..d201927
--- /dev/null
@@ -0,0 +1,167 @@
+/****************************************************************************
+ *   extdrv/vcnl4040_sensor.c
+ *
+ * VCNL4040 I2C Light / Distance sensor driver
+ *
+ * Copyright 2016 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+
+#include "lib/stdint.h"
+#include "lib/errno.h"
+#include "core/system.h"
+#include "drivers/i2c.h"
+#include "extdrv/vcnl4040_sensor.h"
+
+
+
+/* Check the sensor presence, return 1 if found */
+#define PROBE_BUF_SIZE  3
+int vcnl4040_probe_sensor(struct vcnl4040_sensor_config* conf)
+{
+       char cmd_buf[PROBE_BUF_SIZE] = { conf->addr, vcnl4040_dev_id, (conf->addr | I2C_READ_BIT), };
+       char ctrl_buf[PROBE_BUF_SIZE] = { I2C_CONT, I2C_DO_REPEATED_START, I2C_CONT, };
+       uint16_t dev_id = 0;
+       int ret = 0;
+
+    /* Did we already probe the sensor ? */
+    if (conf->probe_ok != 1) {
+        ret = i2c_read(conf->bus_num, &cmd_buf, PROBE_BUF_SIZE, ctrl_buf, &dev_id, 2);
+               if ((ret == 2) && (dev_id == 0x0186)) {
+                   conf->probe_ok = 1;
+               }
+    }
+    return conf->probe_ok;
+}
+
+/* Sensor Read
+ * Performs a read of the data from the sensor.
+ * 'prox', 'al' and 'white': integer addresses for conversion result.
+ * Return value(s):
+ *   Upon successfull completion, returns 0 and the value(s) read are placed in the
+ *   provided integer(s). On error, returns a negative integer equivalent to errors from
+ *   glibc.
+ */
+#define READ_BUF_SIZE  3
+int vcnl4040_sensor_read(struct vcnl4040_sensor_config* conf, uint16_t* prox, uint16_t* al, uint16_t* white)
+{
+    int ret = 0;
+       char cmd_buf[READ_BUF_SIZE] = { conf->addr, 0, (conf->addr | I2C_READ_BIT), };
+       char ctrl_buf[READ_BUF_SIZE] = { I2C_CONT, I2C_DO_REPEATED_START, I2C_CONT, };
+    uint16_t data;
+
+    if (conf->probe_ok != 1) {
+           if (vcnl4040_probe_sensor(conf) != 1) {
+                       return -ENODEV;
+           }
+               msleep(1);
+       }
+
+       /* Read sensor data */
+       if (prox != NULL) {
+               cmd_buf[1] = vcnl4040_ps_data;
+               ret = i2c_read(conf->bus_num, cmd_buf, READ_BUF_SIZE, ctrl_buf, (uint8_t*)(&data), 2);
+               if (ret != 2) {
+                       conf->probe_ok = 0;
+               return ret;
+               }
+               *prox = data;
+               msleep(1);
+       }
+       if (al != NULL) {
+               cmd_buf[1] = vcnl4040_als_data;
+               ret = i2c_read(conf->bus_num, cmd_buf, READ_BUF_SIZE, ctrl_buf, (uint8_t*)(&data), 2);
+               if (ret != 2) {
+                       conf->probe_ok = 0;
+               return ret;
+               }
+               *al = data;
+               msleep(1);
+       }
+       if (white != NULL) {
+               cmd_buf[1] = vcnl4040_white_data;
+               ret = i2c_read(conf->bus_num, cmd_buf, READ_BUF_SIZE, ctrl_buf, (uint8_t*)(&data), 2);
+               if (ret != 2) {
+                       conf->probe_ok = 0;
+               return ret;
+               }
+               *white = data;
+       }
+
+    return 0;
+}
+
+
+/* Sensor config
+ * Performs default configuration of the VCNL4040 sensor.
+ * This MUST be called before reading sensors values as the VCNL4040 start with all
+ *   sensors disabled.
+ * FIXME : allow more control of the sensor functionalities using the sensor
+ *   configuration structure, such as active sensors, interrupt behavior and threshold
+ *   values.
+ * Return value:
+ *   Upon successfull completion, returns 0. On error, returns a negative integer
+ *   equivalent to errors from glibc.
+ */
+#define CONF_BUF_SIZE 4
+int vcnl4040_configure(struct vcnl4040_sensor_config* conf)
+{
+    int ret = 0;
+    char cmd_buf[CONF_BUF_SIZE] = { conf->addr, 0, 0, 0 };
+
+    if (vcnl4040_probe_sensor(conf) != 1) {
+        return -ENODEV;
+    }
+       msleep(1);
+       /* Ambiant Light Sensor Configuration */
+       cmd_buf[1] = vcnl4040_als_conf;
+       cmd_buf[2] = conf->als_integration;
+    ret = i2c_write(conf->bus_num, cmd_buf, CONF_BUF_SIZE, NULL);
+    if (ret != CONF_BUF_SIZE) {
+               conf->probe_ok = 0;
+        return -EIO;
+    }
+       msleep(1);
+
+       /* Proximity Sensor Configuration */
+       /* Conf 1 and Conf 2 */
+       cmd_buf[1] = vcnl4040_ps_conf_1_2;
+       cmd_buf[2] = (conf->ps_irled_duty | conf->ps_integration);
+       cmd_buf[3] = (conf->ps_definition | conf->ps_int_type);
+    ret = i2c_write(conf->bus_num, cmd_buf, CONF_BUF_SIZE, NULL);
+    if (ret != CONF_BUF_SIZE) {
+               conf->probe_ok = 0;
+        return -EIO;
+    }
+       msleep(1);
+       /* Conf 3 and MS */
+       cmd_buf[1] = vcnl4040_ps_conf_3_ms;
+       cmd_buf[2] = 0;
+       cmd_buf[3] = (conf->ps_ms_led_current);
+    ret = i2c_write(conf->bus_num, cmd_buf, CONF_BUF_SIZE, NULL);
+    if (ret != CONF_BUF_SIZE) {
+               conf->probe_ok = 0;
+        return -EIO;
+    }
+
+    return 0;
+}
+
+
+
+
diff --git a/include/extdrv/vcnl4040_sensor.h b/include/extdrv/vcnl4040_sensor.h
new file mode 100644 (file)
index 0000000..e6bfd08
--- /dev/null
@@ -0,0 +1,151 @@
+/****************************************************************************
+ *   extdrv/vcnl4040_sensor.h
+ *
+ * VCNL4040 I2C Light / Distance sensor driver
+ *
+ * Copyright 2016 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#ifndef EXTDRV_VCNL4040_H
+#define EXTDRV_VCNL4040_H
+
+#include "lib/stdint.h"
+
+
+
+/* VCNL4040 sensor instance data.
+ * Note that the vcnl4040 sensor adress cannot be changed.
+ */
+struct vcnl4040_sensor_config {
+    uint8_t addr;
+       uint8_t bus_num;
+    uint8_t probe_ok;
+       /* Ambiant Light Sensor config */
+       uint8_t als_integration;
+       /* Proximity Sensor config */
+       uint8_t ps_irled_duty;
+       uint8_t ps_integration;
+       uint8_t ps_definition;
+       uint8_t ps_int_type;
+       uint8_t ps_ms_led_current;
+};
+
+
+enum vcnl4040_internal_regs {
+       /* Ambiant Light Sensor */
+       vcnl4040_als_conf = 0,
+       vcnl4040_als_high_int_threshold,
+       vcnl4040_als_low_int_threshold,
+       /* Proximity Sensor */
+       vcnl4040_ps_conf_1_2,
+       vcnl4040_ps_conf_3_ms,
+       vcnl4040_ps_cancel_lvl_setting,
+       vcnl4040_ps_low_int_threshold,
+       vcnl4040_ps_high_int_threshold,
+       /* Date */
+       vcnl4040_ps_data,
+       vcnl4040_als_data,
+       vcnl4040_white_data,
+       vcnl4040_intr_flag,
+       vcnl4040_dev_id,
+};
+
+#define VCNL4040_DATA_SIZE  6
+
+/* Defines for Ambiant Light Sensor configuration */
+/* Integration time */
+#define VCNL4040_ALS_INTEGR_80ms    (0)
+#define VCNL4040_ALS_INTEGR_160ms   (0x01 << 6)
+#define VCNL4040_ALS_INTEGR_320ms   (0x01 << 6)
+#define VCNL4040_ALS_INTEGR_640ms   (0x02 << 6)
+/* Interrupt persistance for ambiant light sensor */
+#define VCNL4040_ALS_INT_PERSIST(x) ((((x) - 1) & 0x03) << 2)
+/* Interrupt enable for ambiant light sensor */
+#define VCNL4040_ALS_INT_EN         (0x01 << 1)
+/* Ambiant Light Sensor Shutdown */
+#define VCNL4040_ALS_SHUTDOWN       (0x01 << 0)
+
+/* Defines for Proximity sensor config */
+/* Conf 1 */
+/* IR Led duty cycle for proximity sensor */
+#define VCNL4040_PS_DUTY_1_40       (0x00 << 6)
+#define VCNL4040_PS_DUTY_1_80       (0x01 << 6)
+#define VCNL4040_PS_DUTY_1_160      (0x02 << 6)
+#define VCNL4040_PS_DUTY_1_320      (0x03 << 6)
+/* Interrupt persistance for proximity sensor */
+#define VCNL4040_PS_INT_PERSIST(x)  ((((x) - 1) & 0x03) << 4)
+#define VCNL4040_PS_INTEGR_1_0T     (0x00 << 1)
+#define VCNL4040_PS_INTEGR_1_5T     (0x01 << 1)
+#define VCNL4040_PS_INTEGR_2_0T     (0x02 << 1)
+#define VCNL4040_PS_INTEGR_2_5T     (0x03 << 1)
+#define VCNL4040_PS_INTEGR_3_0T     (0x04 << 1)
+#define VCNL4040_PS_INTEGR_3_5T     (0x05 << 1)
+#define VCNL4040_PS_INTEGR_4_0T     (0x06 << 1)
+#define VCNL4040_PS_INTEGR_8_0T     (0x07 << 1)
+#define VCNL4040_PS_SHUTDOWN        (0x01 << 0)
+/* Conf 2 */
+/* Resolution of proximity sensor */
+#define VCNL4040_PS_HD_12bits       (0x00 << 3)
+#define VCNL4040_PS_HD_16bits       (0x01 << 3)
+/* Interrupt behavior for proximity sensor */
+#define VCNL4040_PS_INT_DISABLE     (0x00 << 0)
+#define VCNL4040_PS_INT_CLOSE       (0x01 << 0)
+#define VCNL4040_PS_INT_AWAY        (0x02 << 0)
+#define VCNL4040_PS_INT_BOTH        (0x03 << 0)
+/* Conf 3 */
+#define VCNL4040_PS_SMART_PERSIST   (0x01 << 4)
+#define VCNL4040_PS_ACTIVE_FORCE_EN (0x01 << 3)
+#define VCNL4040_PS_ACTIVE_TRIGGER  (0x01 << 2)
+/* Conf MS */
+#define VCNL4040_ILED_50mA          (0x00 << 0)
+#define VCNL4040_ILED_75mA          (0x01 << 0)
+#define VCNL4040_ILED_100mA         (0x02 << 0)
+#define VCNL4040_ILED_120mA         (0x03 << 0)
+#define VCNL4040_ILED_140mA         (0x04 << 0)
+#define VCNL4040_ILED_160mA         (0x05 << 0)
+#define VCNL4040_ILED_180mA         (0x06 << 0)
+#define VCNL4040_ILED_200mA         (0x07 << 0)
+
+
+
+/* Check the sensor presence, return 1 if found */
+int vcnl4040_probe_sensor(struct vcnl4040_sensor_config* conf);
+
+
+/* Sensor Read
+ * Performs a read of the data from the sensor.
+ * 'prox', 'al' and 'white': integer addresses for conversion result.
+ * Return value(s):
+ *   Upon successfull completion, returns 0 and the value(s) read are placed in the
+ *   provided integer(s). On error, returns a negative integer equivalent to errors from
+ *   glibc.
+ */
+int vcnl4040_sensor_read(struct vcnl4040_sensor_config* conf, uint16_t* prox, uint16_t* al, uint16_t* white);
+
+
+/* Sensor config
+ * Performs default configuration of the VCNL4040 sensor.
+ * Return value:
+ *   Upon successfull completion, returns 0. On error, returns a negative integer
+ *   equivalent to errors from glibc.
+ */
+int vcnl4040_configure(struct vcnl4040_sensor_config* conf);
+
+#endif /* EXTDRV_VCNL4040_H */
+
+