From 0d6553f7ef3f7c0935a76a9357d497583b858a07 Mon Sep 17 00:00:00 2001 From: Nathael Pajani Date: Thu, 15 Sep 2016 15:47:00 +0200 Subject: [PATCH] Add VCNL4040 I2C Light / Distance sensor support --- extdrv/vcnl4040_sensor.c | 167 +++++++++++++++++++++++++++++++ include/extdrv/vcnl4040_sensor.h | 151 ++++++++++++++++++++++++++++ 2 files changed, 318 insertions(+) create mode 100644 extdrv/vcnl4040_sensor.c create mode 100644 include/extdrv/vcnl4040_sensor.h diff --git a/extdrv/vcnl4040_sensor.c b/extdrv/vcnl4040_sensor.c new file mode 100644 index 0000000..d201927 --- /dev/null +++ b/extdrv/vcnl4040_sensor.c @@ -0,0 +1,167 @@ +/**************************************************************************** + * extdrv/vcnl4040_sensor.c + * + * VCNL4040 I2C Light / Distance sensor driver + * + * Copyright 2016 Nathael Pajani + * + * + * 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 . + * + *************************************************************************** */ + + +#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 index 0000000..e6bfd08 --- /dev/null +++ b/include/extdrv/vcnl4040_sensor.h @@ -0,0 +1,151 @@ +/**************************************************************************** + * extdrv/vcnl4040_sensor.h + * + * VCNL4040 I2C Light / Distance sensor driver + * + * Copyright 2016 Nathael Pajani + * + * + * 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 . + * + *************************************************************************** */ + +#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 */ + + -- 2.43.0