vcnl36825t: add trigger capability
Adds trigger capability to the Vishay VCNL36825T sensor. Signed-off-by: Juliane Schulze <juliane.schulze@deveritec.com>
This commit is contained in:
parent
a61484f7ad
commit
7adcebc675
@ -4,3 +4,4 @@
|
||||
zephyr_library()
|
||||
|
||||
zephyr_library_sources(vcnl36825t.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_VCNL36825T_TRIGGER vcnl36825t_trigger.c)
|
||||
|
||||
@ -10,3 +10,49 @@ config VCNL36825T
|
||||
select I2C
|
||||
help
|
||||
Enable driver for VCNL36825T sensors.
|
||||
|
||||
if VCNL36825T
|
||||
|
||||
config VCNL36825T_TRIGGER
|
||||
bool
|
||||
|
||||
choice VCNL36825T_TRIGGER_CHOICE
|
||||
prompt "trigger mode"
|
||||
default VCNL36825T_TRIGGER_NONE
|
||||
help
|
||||
Specify the type of triggering to be used by the driver.
|
||||
Note: Since figuring out which interrupt was triggered, using the Zephyr
|
||||
standard types will deactivate the other interrupt.
|
||||
|
||||
config VCNL36825T_TRIGGER_NONE
|
||||
bool "no trigger"
|
||||
|
||||
config VCNL36825T_TRIGGER_GLOBAL_THREAD
|
||||
bool "use global thread"
|
||||
select VCNL36825T_TRIGGER
|
||||
|
||||
config VCNL36825T_TRIGGER_OWN_THREAD
|
||||
bool "use own thread"
|
||||
select VCNL36825T_TRIGGER
|
||||
|
||||
endchoice
|
||||
|
||||
if VCNL36825T_TRIGGER
|
||||
|
||||
config VCNL36825T_THREAD_PRIORITY
|
||||
int "thread priority"
|
||||
depends on VCNL36825T_TRIGGER_OWN_THREAD
|
||||
default 10
|
||||
help
|
||||
Priority of thread used by the driver to handle interrupts.
|
||||
|
||||
config VCNL36825T_THREAD_STACK_SIZE
|
||||
int "thread stack size"
|
||||
depends on VCNL36825T_TRIGGER_OWN_THREAD
|
||||
default 1024
|
||||
help
|
||||
Stack size of thread used by the driver to handle interrupts.
|
||||
|
||||
endif # VCNL36825T_TRIGGER
|
||||
|
||||
endif # VCNL36825T
|
||||
|
||||
@ -11,14 +11,16 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <zephyr/drivers/i2c.h>
|
||||
#include <zephyr/drivers/sensor.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/pm/device.h>
|
||||
#include <zephyr/sys/byteorder.h>
|
||||
#include <zephyr/sys/check.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
|
||||
LOG_MODULE_REGISTER(VCNL36825T, CONFIG_SENSOR_LOG_LEVEL);
|
||||
|
||||
static int vcnl36825t_read(const struct i2c_dt_spec *spec, uint8_t reg_addr, uint16_t *value)
|
||||
int vcnl36825t_read(const struct i2c_dt_spec *spec, uint8_t reg_addr, uint16_t *value)
|
||||
{
|
||||
uint8_t rx_buf[2];
|
||||
int rc;
|
||||
@ -33,7 +35,7 @@ static int vcnl36825t_read(const struct i2c_dt_spec *spec, uint8_t reg_addr, uin
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vcnl36825t_write(const struct i2c_dt_spec *spec, uint8_t reg_addr, uint16_t value)
|
||||
int vcnl36825t_write(const struct i2c_dt_spec *spec, uint8_t reg_addr, uint16_t value)
|
||||
{
|
||||
uint8_t tx_buf[3] = {reg_addr};
|
||||
|
||||
@ -41,8 +43,8 @@ static int vcnl36825t_write(const struct i2c_dt_spec *spec, uint8_t reg_addr, ui
|
||||
return i2c_write_dt(spec, tx_buf, sizeof(tx_buf));
|
||||
}
|
||||
|
||||
static int vcnl36825t_update(const struct i2c_dt_spec *spec, uint8_t reg_addr, uint16_t mask,
|
||||
uint16_t value)
|
||||
int vcnl36825t_update(const struct i2c_dt_spec *spec, uint8_t reg_addr, uint16_t mask,
|
||||
uint16_t value)
|
||||
{
|
||||
int rc;
|
||||
uint16_t old_value, new_value;
|
||||
@ -210,6 +212,36 @@ static int vcnl36825t_channel_get(const struct device *dev, enum sensor_channel
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vcnl36825t_attr_set(const struct device *dev, enum sensor_channel chan,
|
||||
enum sensor_attribute attr, const struct sensor_value *val)
|
||||
{
|
||||
CHECKIF(dev == NULL) {
|
||||
LOG_ERR("dev: NULL");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
CHECKIF(val == NULL) {
|
||||
LOG_ERR("val: NULL");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int __maybe_unused rc;
|
||||
|
||||
switch (attr) {
|
||||
default:
|
||||
#if CONFIG_VCNL36825T_TRIGGER
|
||||
rc = vcnl36825t_trigger_attr_set(dev, chan, attr, val);
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
#else
|
||||
return -ENOTSUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief calculate measurement timeout in us
|
||||
*
|
||||
@ -485,6 +517,12 @@ static int vcnl36825t_init(const struct device *dev)
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if CONFIG_VCNL36825T_TRIGGER
|
||||
rc = vcnl36825t_trigger_init(dev);
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
rc = vcnl36825t_update(&config->i2c, VCNL36825T_REG_PS_CONF2, VCNL36825T_PS_ST_MSK,
|
||||
VCNL36825T_PS_ST_START);
|
||||
if (rc < 0) {
|
||||
@ -498,6 +536,10 @@ static int vcnl36825t_init(const struct device *dev)
|
||||
static const struct sensor_driver_api vcnl36825t_driver_api = {
|
||||
.sample_fetch = vcnl36825t_sample_fetch,
|
||||
.channel_get = vcnl36825t_channel_get,
|
||||
.attr_set = vcnl36825t_attr_set,
|
||||
#if CONFIG_VCNL36825T_TRIGGER
|
||||
.trigger_set = vcnl36825t_trigger_set,
|
||||
#endif
|
||||
};
|
||||
|
||||
#define VCNL36825T_DEFINE(inst) \
|
||||
@ -524,7 +566,11 @@ static const struct sensor_driver_api vcnl36825t_driver_api = {
|
||||
.laser_current = DT_INST_ENUM_IDX(inst, laser_current), \
|
||||
.high_dynamic_output = DT_INST_PROP(inst, high_dynamic_output), \
|
||||
.sunlight_cancellation = DT_INST_PROP(inst, sunlight_cancellation), \
|
||||
}; \
|
||||
IF_ENABLED(CONFIG_VCNL36825T_TRIGGER, \
|
||||
(.int_gpio = GPIO_DT_SPEC_INST_GET(inst, int_gpios), \
|
||||
.int_mode = DT_INST_ENUM_IDX(inst, int_mode), \
|
||||
.int_proximity_count = DT_INST_PROP(inst, int_proximity_count), \
|
||||
.int_smart_persistence = DT_INST_PROP(inst, int_smart_persistence)))}; \
|
||||
IF_ENABLED(CONFIG_PM_DEVICE, (PM_DEVICE_DT_INST_DEFINE(inst, vcnl36825t_pm_action))); \
|
||||
SENSOR_DEVICE_DT_INST_DEFINE( \
|
||||
inst, vcnl36825t_init, \
|
||||
|
||||
@ -56,7 +56,10 @@
|
||||
#define VCNL36825T_PS_MPS_POS 12
|
||||
#define VCNL36825T_PS_IT_POS 14
|
||||
|
||||
#define VCNL36825T_PS_ST_MSK GENMASK(0, 0)
|
||||
#define VCNL36825T_PS_ST_MSK GENMASK(0, 0)
|
||||
#define VCNL36825T_PS_SMART_PERS_MSK GENMASK(1, 1)
|
||||
#define VCNL36825T_PS_INT_MSK GENMASK(3, 2)
|
||||
#define VCNL36825T_PS_PERS_MSK GENMASK(5, 4)
|
||||
|
||||
#define VCNL36825T_PS_ST_START (0 << VCNL36825T_PS_ST_POS)
|
||||
#define VCNL36825T_PS_ST_STOP (1 << VCNL36825T_PS_ST_POS)
|
||||
@ -65,9 +68,9 @@
|
||||
#define VCNL36825T_PS_SMART_PERS_ENABLED (1 << VCNL36825T_PS_PS_SMART_PERS_POS)
|
||||
|
||||
#define VCNL36825T_PS_INT_DISABLE (0 << VCNL36825T_PS_INT_POS)
|
||||
#define VCNL36825T_PS_INT_THDH_PERS_LATCHED (1 << VCNL36825T_PS_INT_POS)
|
||||
#define VCNL36825T_PS_INT_THDH_FIRST_LATCHED (2 << VCNL36825T_PS_INT_POS)
|
||||
#define VCNL36825T_PS_INT_ENABLED (3 << VCNL36825T_PS_INT_POS)
|
||||
#define VCNL36825T_PS_INT_MODE_LOGIC_HIGH_LOW (1 << VCNL36825T_PS_INT_POS)
|
||||
#define VCNL36825T_PS_INT_MODE_FIRST_HIGH (2 << VCNL36825T_PS_INT_POS)
|
||||
#define VCNL36825T_PS_INT_MODE_NORMAL (3 << VCNL36825T_PS_INT_POS)
|
||||
|
||||
#define VCNL36825T_PS_PERS_1 (0 << VCNL36825T_PS_PERS_POS)
|
||||
#define VCNL36825T_PS_PERS_2 (1 << VCNL36825T_PS_PERS_POS)
|
||||
@ -281,6 +284,12 @@ enum vcnl38625t_laser_current {
|
||||
VCNL36825T_LASER_CURRENT_20MS,
|
||||
};
|
||||
|
||||
enum vcnl36825t_int_mode {
|
||||
VCNL36825T_INT_MODE_NORMAL,
|
||||
VCNL36825T_INT_MODE_FIRST_HIGH,
|
||||
VCNL36825T_INT_MODE_LOGIC_HIGH_LOW,
|
||||
};
|
||||
|
||||
struct vcnl36825t_config {
|
||||
struct i2c_dt_spec i2c;
|
||||
|
||||
@ -297,6 +306,13 @@ struct vcnl36825t_config {
|
||||
enum vcnl38625t_laser_current laser_current;
|
||||
bool high_dynamic_output;
|
||||
bool sunlight_cancellation;
|
||||
|
||||
#if CONFIG_VCNL36825T_TRIGGER
|
||||
struct gpio_dt_spec int_gpio;
|
||||
enum vcnl36825t_int_mode int_mode;
|
||||
uint8_t int_proximity_count;
|
||||
bool int_smart_persistence;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct vcnl36825t_data {
|
||||
@ -308,6 +324,42 @@ struct vcnl36825t_data {
|
||||
unsigned int meas_timeout_running_us;
|
||||
unsigned int meas_timeout_wakeup_us;
|
||||
#endif
|
||||
|
||||
#if CONFIG_VCNL36825T_TRIGGER
|
||||
const struct device *dev;
|
||||
const struct gpio_dt_spec *int_gpio;
|
||||
|
||||
const struct sensor_trigger *int_trigger;
|
||||
sensor_trigger_handler_t int_handler;
|
||||
|
||||
struct gpio_callback int_gpio_handler;
|
||||
|
||||
#if CONFIG_VCNL36825T_TRIGGER_OWN_THREAD
|
||||
K_KERNEL_STACK_MEMBER(int_thread_stack, CONFIG_VCNL36825T_THREAD_STACK_SIZE);
|
||||
struct k_thread int_thread;
|
||||
struct k_sem int_gpio_sem;
|
||||
#elif CONFIG_VCNL36825T_TRIGGER_GLOBAL_THREAD
|
||||
struct k_work int_work;
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
int vcnl36825t_read(const struct i2c_dt_spec *spec, uint8_t reg_addr, uint16_t *value);
|
||||
|
||||
int vcnl36825t_write(const struct i2c_dt_spec *spec, uint8_t reg_addr, uint16_t value);
|
||||
|
||||
int vcnl36825t_update(const struct i2c_dt_spec *spec, uint8_t reg_addr, uint16_t mask,
|
||||
uint16_t value);
|
||||
|
||||
#if CONFIG_VCNL36825T_TRIGGER
|
||||
int vcnl36825t_trigger_init(const struct device *dev);
|
||||
|
||||
int vcnl36825t_trigger_set(const struct device *dev, const struct sensor_trigger *trig,
|
||||
sensor_trigger_handler_t handler);
|
||||
|
||||
int vcnl36825t_trigger_attr_set(const struct device *dev, enum sensor_channel chan,
|
||||
enum sensor_attribute attr, const struct sensor_value *val);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
319
drivers/sensor/vishay/vcnl36825t/vcnl36825t_trigger.c
Normal file
319
drivers/sensor/vishay/vcnl36825t/vcnl36825t_trigger.c
Normal file
@ -0,0 +1,319 @@
|
||||
/*
|
||||
* Copyright (c) 2024 deveritec GmbH
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT vishay_vcnl36825t
|
||||
|
||||
#include "vcnl36825t.h"
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/kernel.h>
|
||||
|
||||
#include <zephyr/drivers/gpio.h>
|
||||
#include <zephyr/drivers/i2c.h>
|
||||
#include <zephyr/drivers/sensor.h>
|
||||
|
||||
#include <zephyr/sys/byteorder.h>
|
||||
#include <zephyr/sys/check.h>
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_DECLARE(VCNL36825T, CONFIG_SENSOR_LOG_LEVEL);
|
||||
|
||||
int vcnl36825t_trigger_attr_set(const struct device *dev, enum sensor_channel chan,
|
||||
enum sensor_attribute attr, const struct sensor_value *val)
|
||||
{
|
||||
CHECKIF(dev == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
CHECKIF(val == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
const struct vcnl36825t_config *config = dev->config;
|
||||
int rc;
|
||||
uint16_t reg_addr;
|
||||
|
||||
switch (attr) {
|
||||
case SENSOR_ATTR_UPPER_THRESH:
|
||||
reg_addr = VCNL36825T_REG_PS_THDH;
|
||||
break;
|
||||
case SENSOR_ATTR_LOWER_THRESH:
|
||||
reg_addr = VCNL36825T_REG_PS_THDL;
|
||||
break;
|
||||
default:
|
||||
LOG_ERR("unknown attribute %d", (int)attr);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
rc = vcnl36825t_write(&config->i2c, reg_addr, (uint16_t)val->val1);
|
||||
if (rc < 0) {
|
||||
LOG_ERR("error writing attribute %d", attr);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief callback called if a GPIO-interrupt is registered
|
||||
*
|
||||
* @param port device struct for the GPIO device
|
||||
* @param cb @ref struct gpio_callback owning this handler
|
||||
* @param pins mask of pins that triggered the callback handler
|
||||
*/
|
||||
static void vcnl36825t_gpio_callback(const struct device *port, struct gpio_callback *cb,
|
||||
uint32_t pins)
|
||||
{
|
||||
ARG_UNUSED(port);
|
||||
ARG_UNUSED(pins);
|
||||
|
||||
CHECKIF(!cb) {
|
||||
LOG_ERR("cb: NULL");
|
||||
return;
|
||||
}
|
||||
struct vcnl36825t_data *data = CONTAINER_OF(cb, struct vcnl36825t_data, int_gpio_handler);
|
||||
int rc;
|
||||
|
||||
rc = gpio_pin_interrupt_configure_dt(data->int_gpio, GPIO_INT_DISABLE);
|
||||
if (rc != 0) {
|
||||
LOG_ERR("error deactivating SoC interrupt %d", rc);
|
||||
}
|
||||
|
||||
#if CONFIG_VCNL36825T_TRIGGER_OWN_THREAD
|
||||
k_sem_give(&data->int_gpio_sem);
|
||||
#elif CONFIG_VCNL36825T_TRIGGER_GLOBAL_THREAD
|
||||
k_work_submit(&data->int_work);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void vcnl36825t_thread_cb(const struct device *dev)
|
||||
{
|
||||
const struct vcnl36825t_config *config = dev->config;
|
||||
struct vcnl36825t_data *data = dev->data;
|
||||
int rc;
|
||||
uint16_t reg_value;
|
||||
|
||||
if (data->int_handler != NULL) {
|
||||
data->int_handler(dev, data->int_trigger);
|
||||
}
|
||||
|
||||
rc = gpio_pin_interrupt_configure_dt(&config->int_gpio, GPIO_INT_EDGE_FALLING);
|
||||
if (rc < 0) {
|
||||
LOG_ERR("error activating SoC interrupt %d", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = vcnl36825t_read(&config->i2c, VCNL36825T_REG_INT_FLAG, ®_value);
|
||||
if (rc < 0) {
|
||||
LOG_ERR("error reading interrupt flag register %d", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
if (FIELD_GET(VCNL36825T_PS_IF_AWAY_MSK, reg_value) == 1) {
|
||||
LOG_INF("\"away\" trigger (PS below THDL)");
|
||||
} else if (FIELD_GET(VCNL36825T_PS_IF_CLOSE_MSK, reg_value) == 1) {
|
||||
LOG_INF("\"close\" trigger (PS above THDH)");
|
||||
} else if (FIELD_GET(VCNL36825T_PS_SPFLAG_MSK, reg_value) == 1) {
|
||||
LOG_INF("enter protection mode trigger");
|
||||
} else if (FIELD_GET(VCNL36825T_PS_ACFLAG_MSK, reg_value) == 1) {
|
||||
LOG_INF("finished auto calibration trigger");
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_VCNL36825T_TRIGGER_OWN_THREAD
|
||||
static void vcnl36825t_thread_main(void *p1, void *p2, void *p3)
|
||||
{
|
||||
ARG_UNUSED(p2);
|
||||
ARG_UNUSED(p3);
|
||||
|
||||
struct vcnl36825t_data *data = p1;
|
||||
|
||||
while (1) {
|
||||
k_sem_take(&data->int_gpio_sem, K_FOREVER);
|
||||
vcnl36825t_thread_cb(data->dev);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_VCNL36825T_TRIGGER_GLOBAL_THREAD
|
||||
static void vcnl36825t_work_cb(struct k_work *work)
|
||||
{
|
||||
struct vcnl36825t_data *data = CONTAINER_OF(work, struct vcnl36825t_data, int_work);
|
||||
|
||||
vcnl36825t_thread_cb(data->dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
int vcnl36825t_trigger_set(const struct device *dev, const struct sensor_trigger *trig,
|
||||
sensor_trigger_handler_t handler)
|
||||
{
|
||||
CHECKIF(dev == NULL) {
|
||||
LOG_ERR("dev: NULL");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
CHECKIF(trig == NULL) {
|
||||
LOG_ERR("trig: NULL");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
const struct vcnl36825t_config *config = dev->config;
|
||||
struct vcnl36825t_data *data = dev->data;
|
||||
|
||||
int rc;
|
||||
uint16_t regdata;
|
||||
|
||||
if (trig->chan != SENSOR_CHAN_PROX) {
|
||||
LOG_ERR("invalid channel %d", (int)trig->chan);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (trig->type != SENSOR_TRIG_THRESHOLD) {
|
||||
LOG_ERR("invalid trigger type %d", (int)trig->type);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
rc = gpio_pin_interrupt_configure_dt(&config->int_gpio, GPIO_INT_DISABLE);
|
||||
if (rc < 0) {
|
||||
LOG_ERR("error configuring SoC interrupt %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
data->int_trigger = trig;
|
||||
data->int_handler = handler;
|
||||
|
||||
if (handler == NULL) {
|
||||
regdata = VCNL36825T_PS_INT_DISABLE;
|
||||
} else {
|
||||
switch (config->int_mode) {
|
||||
case VCNL36825T_INT_MODE_NORMAL:
|
||||
regdata = VCNL36825T_PS_INT_MODE_NORMAL;
|
||||
break;
|
||||
case VCNL36825T_INT_MODE_FIRST_HIGH:
|
||||
regdata = VCNL36825T_PS_INT_MODE_FIRST_HIGH;
|
||||
break;
|
||||
case VCNL36825T_INT_MODE_LOGIC_HIGH_LOW:
|
||||
regdata = VCNL36825T_PS_INT_MODE_LOGIC_HIGH_LOW;
|
||||
break;
|
||||
default:
|
||||
LOG_ERR("unknown interrupt mode");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
}
|
||||
|
||||
rc = vcnl36825t_update(&config->i2c, VCNL36825T_REG_PS_CONF2, VCNL36825T_PS_INT_MSK,
|
||||
regdata);
|
||||
if (rc < 0) {
|
||||
LOG_ERR("error updating interrupt %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (handler) {
|
||||
rc = gpio_pin_interrupt_configure_dt(&config->int_gpio, GPIO_INT_EDGE_FALLING);
|
||||
if (rc < 0) {
|
||||
LOG_ERR("error configuring SoC interrupt %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* read interrupt register one time to clear any pending interrupt */
|
||||
rc = vcnl36825t_read(&config->i2c, VCNL36825T_REG_INT_FLAG, ®data);
|
||||
if (rc < 0) {
|
||||
LOG_ERR("error clearing interrupt flag register %d", rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vcnl36825t_trigger_init(const struct device *dev)
|
||||
{
|
||||
CHECKIF(dev == NULL) {
|
||||
LOG_ERR("dev: NULL");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
const struct vcnl36825t_config *config = dev->config;
|
||||
struct vcnl36825t_data *data = dev->data;
|
||||
|
||||
int rc;
|
||||
uint8_t reg_value;
|
||||
|
||||
if (!gpio_is_ready_dt(&config->int_gpio)) {
|
||||
LOG_ERR("interrupt GPIO not ready");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
data->dev = dev;
|
||||
data->int_gpio = &config->int_gpio;
|
||||
|
||||
rc = gpio_pin_configure_dt(data->int_gpio, GPIO_INPUT);
|
||||
if (rc < 0) {
|
||||
LOG_ERR("error setting interrupt gpio configuration %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* PS_CONF2 */
|
||||
reg_value = VCNL36825T_PS_INT_DISABLE;
|
||||
|
||||
if (config->int_smart_persistence) {
|
||||
reg_value |= VCNL36825T_PS_SMART_PERS_ENABLED;
|
||||
}
|
||||
|
||||
switch (config->int_proximity_count) {
|
||||
case 1:
|
||||
reg_value |= VCNL36825T_PS_PERS_1;
|
||||
break;
|
||||
case 2:
|
||||
reg_value |= VCNL36825T_PS_PERS_2;
|
||||
break;
|
||||
case 3:
|
||||
reg_value |= VCNL36825T_PS_PERS_3;
|
||||
break;
|
||||
case 4:
|
||||
__fallthrough;
|
||||
default:
|
||||
reg_value |= VCNL36825T_PS_PERS_4;
|
||||
}
|
||||
|
||||
rc = vcnl36825t_update(
|
||||
&config->i2c, VCNL36825T_REG_PS_CONF2,
|
||||
(VCNL36825T_PS_SMART_PERS_MSK | VCNL36825T_PS_INT_MSK | VCNL36825T_PS_PERS_MSK),
|
||||
reg_value);
|
||||
if (rc < 0) {
|
||||
LOG_ERR("could not write interrupt configuration %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if CONFIG_VCNL36825T_TRIGGER_OWN_THREAD
|
||||
k_sem_init(&data->int_gpio_sem, 0, K_SEM_MAX_LIMIT);
|
||||
|
||||
k_thread_create(&data->int_thread, data->int_thread_stack,
|
||||
CONFIG_VCNL36825T_THREAD_STACK_SIZE, vcnl36825t_thread_main, data, NULL,
|
||||
NULL, K_PRIO_COOP(CONFIG_VCNL36825T_THREAD_PRIORITY), 0, K_NO_WAIT);
|
||||
#elif CONFIG_VCNL36825T_TRIGGER_GLOBAL_THREAD
|
||||
k_work_init(&data->int_work, vcnl36825t_work_cb);
|
||||
#else
|
||||
#error "invalid interrupt threading configuration"
|
||||
#endif
|
||||
|
||||
gpio_init_callback(&data->int_gpio_handler, vcnl36825t_gpio_callback,
|
||||
BIT(config->int_gpio.pin));
|
||||
|
||||
rc = gpio_add_callback(config->int_gpio.port, &data->int_gpio_handler);
|
||||
if (rc < 0) {
|
||||
LOG_ERR("could not set gpio callback %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = gpio_pin_interrupt_configure_dt(&config->int_gpio, GPIO_INT_DISABLE);
|
||||
if (rc < 0) {
|
||||
LOG_ERR("could not set SoC interrupt configuration %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -90,3 +90,38 @@ properties:
|
||||
description: |
|
||||
Activate 16bit high dynamic output mode.
|
||||
Cannot be used with threshold interrupt.
|
||||
|
||||
int-gpios:
|
||||
type: phandle-array
|
||||
description: |
|
||||
The INT signal connection.
|
||||
The signal is active-low as produced by the sensor.
|
||||
|
||||
int-mode:
|
||||
type: string
|
||||
default: "normal"
|
||||
enum: ["normal", "first high", "logic high / low"]
|
||||
description: |
|
||||
Specifies the interrupt behavior.
|
||||
- "normal": signal if exceeds high or falls below lower threshold
|
||||
and proximity count is reached.
|
||||
- "first high": signal if exceeds high threshold first time and signal again
|
||||
if falls below lower threshold, and proximity count is reached.
|
||||
Do not trigger if high threshold was never exceeded.
|
||||
- "logic high / low": signal if high threshold is exceeded and proximity counts is reached,
|
||||
deactivate if falls below lower threshold.
|
||||
Defaults to "normal" as this is the easiest configurable mode.
|
||||
|
||||
int-proximity-count:
|
||||
type: int
|
||||
default: 1
|
||||
enum: [1, 2, 3, 4]
|
||||
description: |
|
||||
Number of consecutive measurements above/below threshold to signal an interrupt.
|
||||
Defaults to sensor reset value
|
||||
|
||||
int-smart-persistence:
|
||||
type: boolean
|
||||
description: |
|
||||
Activates "smart persistence" feature, aimed to reduce total reaction time
|
||||
until an interrupt is issued.
|
||||
|
||||
@ -882,6 +882,8 @@ test_i2c_vishay_vcnl36825t: vcnl36825t@81 {
|
||||
multi-pulse = <8>;
|
||||
|
||||
low-power;
|
||||
|
||||
int-gpios = <&test_gpio 0 0>;
|
||||
};
|
||||
|
||||
test_i2c_tmag5273: tmag5273@82 {
|
||||
|
||||
@ -63,4 +63,5 @@ CONFIG_TMD2620_TRIGGER_GLOBAL_THREAD=y
|
||||
CONFIG_TMP007_TRIGGER_GLOBAL_THREAD=y
|
||||
CONFIG_TSL2540_TRIGGER_GLOBAL_THREAD=y
|
||||
CONFIG_TSL2591_TRIGGER_GLOBAL_THREAD=y
|
||||
CONFIG_VCNL36825T_TRIGGER_GLOBAL_THREAD=y
|
||||
CONFIG_VCNL4040_TRIGGER_GLOBAL_THREAD=y
|
||||
|
||||
@ -64,4 +64,5 @@ CONFIG_TMD2620_TRIGGER_NONE=y
|
||||
CONFIG_TMP007_TRIGGER_NONE=y
|
||||
CONFIG_TSL2540_TRIGGER_NONE=y
|
||||
CONFIG_TSL2591_TRIGGER_NONE=y
|
||||
CONFIG_VCNL36825T_TRIGGER_NONE=y
|
||||
CONFIG_VCNL4040_TRIGGER_NONE=y
|
||||
|
||||
@ -60,4 +60,5 @@ CONFIG_TMAG5170_TRIGGER_OWN_THREAD=y
|
||||
CONFIG_TMP007_TRIGGER_OWN_THREAD=y
|
||||
CONFIG_TSL2540_TRIGGER_OWN_THREAD=y
|
||||
CONFIG_TSL2591_TRIGGER_OWN_THREAD=y
|
||||
CONFIG_VCNL36825T_TRIGGER_OWN_THREAD=y
|
||||
CONFIG_VCNL4040_TRIGGER_OWN_THREAD=y
|
||||
|
||||
Loading…
Reference in New Issue
Block a user