drivers: sensors: itds: Add support for WSEN-ITDS 3-axis accel sensor
Add support for wsen-itds 3-axis accel sensor, provides acceleration, temperature data reading and supports configuring of output data rate, operating mode and scale. Signed-off-by: Saravanan Sekar <saravanan@linumiz.com>
This commit is contained in:
parent
57e7148613
commit
9ac3c9d42a
10 changed files with 733 additions and 0 deletions
|
@ -70,6 +70,7 @@ add_subdirectory_ifdef(CONFIG_TMP116 tmp116)
|
||||||
add_subdirectory_ifdef(CONFIG_VL53L0X vl53l0x)
|
add_subdirectory_ifdef(CONFIG_VL53L0X vl53l0x)
|
||||||
add_subdirectory_ifdef(CONFIG_TEMP_KINETIS nxp_kinetis_temp)
|
add_subdirectory_ifdef(CONFIG_TEMP_KINETIS nxp_kinetis_temp)
|
||||||
add_subdirectory_ifdef(CONFIG_TACH_XEC mchp_tach_xec)
|
add_subdirectory_ifdef(CONFIG_TACH_XEC mchp_tach_xec)
|
||||||
|
add_subdirectory_ifdef(CONFIG_ITDS wsen_itds)
|
||||||
|
|
||||||
zephyr_sources_ifdef(CONFIG_USERSPACE sensor_handlers.c)
|
zephyr_sources_ifdef(CONFIG_USERSPACE sensor_handlers.c)
|
||||||
zephyr_sources_ifdef(CONFIG_SENSOR_SHELL sensor_shell.c)
|
zephyr_sources_ifdef(CONFIG_SENSOR_SHELL sensor_shell.c)
|
||||||
|
|
|
@ -169,4 +169,6 @@ source "drivers/sensor/vl53l0x/Kconfig"
|
||||||
|
|
||||||
source "drivers/sensor/nxp_kinetis_temp/Kconfig"
|
source "drivers/sensor/nxp_kinetis_temp/Kconfig"
|
||||||
|
|
||||||
|
source "drivers/sensor/wsen_itds/Kconfig"
|
||||||
|
|
||||||
endif # SENSOR
|
endif # SENSOR
|
||||||
|
|
6
drivers/sensor/wsen_itds/CMakeLists.txt
Normal file
6
drivers/sensor/wsen_itds/CMakeLists.txt
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
zephyr_library()
|
||||||
|
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_ITDS itds.c)
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_ITDS_TRIGGER itds_trigger.c)
|
20
drivers/sensor/wsen_itds/Kconfig
Normal file
20
drivers/sensor/wsen_itds/Kconfig
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
# Copyright (c) 2020 Linumiz
|
||||||
|
|
||||||
|
config ITDS
|
||||||
|
bool "WSEN-ITDS 3-axis accel sensor"
|
||||||
|
depends on I2C
|
||||||
|
help
|
||||||
|
Enable Wurth Elektronik WSEN-ITDS 3-axis acceleration sensor
|
||||||
|
provides acceleration and die temperature measurement.
|
||||||
|
|
||||||
|
if ITDS
|
||||||
|
|
||||||
|
config ITDS_TRIGGER
|
||||||
|
bool "Trigger mode"
|
||||||
|
help
|
||||||
|
Set to enable trigger mode using gpio interrupt, interrupts are
|
||||||
|
configured to line INT0.
|
||||||
|
|
||||||
|
endif # ITDS
|
405
drivers/sensor/wsen_itds/itds.c
Normal file
405
drivers/sensor/wsen_itds/itds.c
Normal file
|
@ -0,0 +1,405 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Würth Elektronic WSEN-ITDS 3-axis accel sensor driver
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Linumiz
|
||||||
|
* Author: Saravanan Sekar <saravanan@linumiz.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <init.h>
|
||||||
|
#include <drivers/sensor.h>
|
||||||
|
#include <sys/byteorder.h>
|
||||||
|
#include <kernel.h>
|
||||||
|
#include <sys/__assert.h>
|
||||||
|
#include <logging/log.h>
|
||||||
|
#include "itds.h"
|
||||||
|
|
||||||
|
#define DT_DRV_COMPAT we_wsen_itds
|
||||||
|
#define ITDS_TEMP_CONST 62500
|
||||||
|
|
||||||
|
LOG_MODULE_REGISTER(ITDS, CONFIG_SENSOR_LOG_LEVEL);
|
||||||
|
|
||||||
|
static const struct itds_odr itds_odr_map[ITDS_ODR_MAX] = {
|
||||||
|
{0}, {1, 600}, {12, 500}, {25}, {50}, {100}, {200},
|
||||||
|
{400}, {800}, {1600}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const unsigned int itds_sensitivity_scale[][ITDS_ACCL_RANGE_END] = {
|
||||||
|
{976, 1952, 3904, 7808},
|
||||||
|
|
||||||
|
/* high performance mode */
|
||||||
|
{244, 488, 976, 1952}
|
||||||
|
};
|
||||||
|
|
||||||
|
static int itds_get_odr_for_index(struct device *dev, enum itds_odr_const idx,
|
||||||
|
uint16_t *freq, uint16_t *mfreq)
|
||||||
|
{
|
||||||
|
struct itds_device_data *ddata = dev->driver_data;
|
||||||
|
int start, end;
|
||||||
|
bool hp_mode;
|
||||||
|
|
||||||
|
hp_mode = !!(ddata->op_mode & ITDS_OP_MODE_HIGH_PERF);
|
||||||
|
if (hp_mode) {
|
||||||
|
start = ITDS_ODR_12_5;
|
||||||
|
end = ITDS_ODR_1600;
|
||||||
|
} else {
|
||||||
|
start = ITDS_ODR_1_6;
|
||||||
|
end = ITDS_ODR_200;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx < start || idx > end) {
|
||||||
|
LOG_ERR("invalid odr for the operating mode");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*freq = itds_odr_map[idx].freq;
|
||||||
|
*mfreq = itds_odr_map[idx].mfreq;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int itds_accl_odr_set(struct device *dev, uint16_t freq, uint16_t mfreq)
|
||||||
|
{
|
||||||
|
struct itds_device_data *ddata = dev->driver_data;
|
||||||
|
const struct itds_device_config *cfg = dev->config_info;
|
||||||
|
int start, end, i;
|
||||||
|
bool hp_mode;
|
||||||
|
|
||||||
|
hp_mode = !!(ddata->op_mode & ITDS_OP_MODE_HIGH_PERF);
|
||||||
|
if (hp_mode) {
|
||||||
|
start = ITDS_ODR_12_5;
|
||||||
|
end = ITDS_ODR_1600;
|
||||||
|
} else {
|
||||||
|
start = ITDS_ODR_1_6;
|
||||||
|
end = ITDS_ODR_200;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = start; i <= end; i++) {
|
||||||
|
if ((freq == itds_odr_map[i].freq) &&
|
||||||
|
(mfreq == itds_odr_map[i].mfreq)) {
|
||||||
|
|
||||||
|
return i2c_reg_update_byte(ddata->i2c, cfg->i2c_addr,
|
||||||
|
ITDS_REG_CTRL1, ITDS_MASK_ODR, i << 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_ERR("invalid odr, not in range");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int itds_accl_range_set(struct device *dev, int32_t range)
|
||||||
|
{
|
||||||
|
struct itds_device_data *ddata = dev->driver_data;
|
||||||
|
const struct itds_device_config *cfg = dev->config_info;
|
||||||
|
int i, ret;
|
||||||
|
bool hp_mode;
|
||||||
|
|
||||||
|
for (i = 0; i < ITDS_ACCL_RANGE_END; i++) {
|
||||||
|
if (range <= (2 << i)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == ITDS_ACCL_RANGE_END) {
|
||||||
|
LOG_ERR("Accl out of range");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = i2c_reg_update_byte(ddata->i2c, cfg->i2c_addr, ITDS_REG_CTRL6,
|
||||||
|
ITDS_MASK_SCALE, i << 4);
|
||||||
|
if (ret) {
|
||||||
|
LOG_ERR("Accl set full scale failed %d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
hp_mode = !!(ddata->op_mode & ITDS_OP_MODE_HIGH_PERF);
|
||||||
|
ddata->scale = itds_sensitivity_scale[hp_mode][i];
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int itds_attr_set(struct device *dev, enum sensor_channel chan,
|
||||||
|
enum sensor_attribute attr,
|
||||||
|
const struct sensor_value *val)
|
||||||
|
{
|
||||||
|
if (chan != SENSOR_CHAN_ACCEL_X &&
|
||||||
|
chan != SENSOR_CHAN_ACCEL_Y &&
|
||||||
|
chan != SENSOR_CHAN_ACCEL_Z &&
|
||||||
|
chan != SENSOR_CHAN_ACCEL_XYZ) {
|
||||||
|
LOG_ERR("attr_set() not supported on this channel.");
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (attr) {
|
||||||
|
case SENSOR_ATTR_FULL_SCALE:
|
||||||
|
return itds_accl_range_set(dev, sensor_ms2_to_g(val));
|
||||||
|
|
||||||
|
case SENSOR_ATTR_SAMPLING_FREQUENCY:
|
||||||
|
return itds_accl_odr_set(dev, val->val1, val->val2 / 1000);
|
||||||
|
|
||||||
|
default:
|
||||||
|
LOG_ERR("Accel attribute not supported.");
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int itds_fetch_temprature(struct itds_device_data *ddata,
|
||||||
|
const struct itds_device_config *cfg)
|
||||||
|
{
|
||||||
|
uint8_t rval;
|
||||||
|
int16_t temp_raw = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = i2c_reg_read_byte(ddata->i2c, cfg->i2c_addr,
|
||||||
|
ITDS_REG_STATUS_DETECT, &rval);
|
||||||
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(rval & ITDS_EVENT_DRDY_T)) {
|
||||||
|
return -EAGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = i2c_burst_read(ddata->i2c, cfg->i2c_addr, ITDS_REG_TEMP_L,
|
||||||
|
(uint8_t *)&temp_raw, sizeof(uint16_t));
|
||||||
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ddata->temprature = sys_le16_to_cpu(temp_raw);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int itds_fetch_accel(struct itds_device_data *ddata,
|
||||||
|
const struct itds_device_config *cfg)
|
||||||
|
{
|
||||||
|
size_t i, ret;
|
||||||
|
uint8_t rval;
|
||||||
|
|
||||||
|
ret = i2c_reg_read_byte(ddata->i2c, cfg->i2c_addr,
|
||||||
|
ITDS_REG_STATUS, &rval);
|
||||||
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(rval & ITDS_EVENT_DRDY)) {
|
||||||
|
return -EAGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = i2c_burst_read(ddata->i2c, cfg->i2c_addr, ITDS_REG_X_OUT_L,
|
||||||
|
(uint8_t *)ddata->samples,
|
||||||
|
sizeof(uint16_t) * ITDS_SAMPLE_SIZE);
|
||||||
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* convert samples to cpu endianness */
|
||||||
|
for (i = 0; i < ITDS_SAMPLE_SIZE; i += 2) {
|
||||||
|
int16_t *sample = (int16_t *) &ddata->samples[i];
|
||||||
|
|
||||||
|
*sample = sys_le16_to_cpu(*sample);
|
||||||
|
if (ddata->op_mode & ITDS_OP_MODE_NORMAL ||
|
||||||
|
ddata->op_mode & ITDS_OP_MODE_HIGH_PERF) {
|
||||||
|
*sample = *sample >> 2;
|
||||||
|
} else {
|
||||||
|
*sample = *sample >> 4;
|
||||||
|
}
|
||||||
|
LOG_DBG("itds sample %d %X\n", i, *sample);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int itds_sample_fetch(struct device *dev, enum sensor_channel chan)
|
||||||
|
{
|
||||||
|
struct itds_device_data *ddata = dev->driver_data;
|
||||||
|
const struct itds_device_config *cfg = dev->config_info;
|
||||||
|
|
||||||
|
switch (chan) {
|
||||||
|
case SENSOR_CHAN_ACCEL_XYZ:
|
||||||
|
case SENSOR_CHAN_ACCEL_X:
|
||||||
|
case SENSOR_CHAN_ACCEL_Y:
|
||||||
|
case SENSOR_CHAN_ACCEL_Z:
|
||||||
|
return itds_fetch_accel(ddata, cfg);
|
||||||
|
|
||||||
|
case SENSOR_CHAN_DIE_TEMP:
|
||||||
|
return itds_fetch_temprature(ddata, cfg);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void itds_accl_channel_get(struct device *dev,
|
||||||
|
enum sensor_channel chan,
|
||||||
|
struct sensor_value *val)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct itds_device_data *ddata = dev->driver_data;
|
||||||
|
uint8_t ofs_start, ofs_stop;
|
||||||
|
|
||||||
|
switch (chan) {
|
||||||
|
case SENSOR_CHAN_ACCEL_X:
|
||||||
|
ofs_start = ofs_stop = 0U;
|
||||||
|
break;
|
||||||
|
case SENSOR_CHAN_ACCEL_Y:
|
||||||
|
ofs_start = ofs_stop = 1U;
|
||||||
|
break;
|
||||||
|
case SENSOR_CHAN_ACCEL_Z:
|
||||||
|
ofs_start = ofs_stop = 2U;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ofs_start = 0U; ofs_stop = 2U;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = ofs_start; i <= ofs_stop ; i++, val++) {
|
||||||
|
int64_t dval;
|
||||||
|
|
||||||
|
/* Sensitivity is exposed in ug/LSB */
|
||||||
|
/* Convert to m/s^2 */
|
||||||
|
dval = (int64_t)((ddata->samples[i] * ddata->scale * SENSOR_G) /
|
||||||
|
1000000LL);
|
||||||
|
val->val1 = (int32_t)(dval / 1000000);
|
||||||
|
val->val2 = (int32_t)(dval % 1000000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int itds_temp_channel_get(struct device *dev, struct sensor_value *val)
|
||||||
|
{
|
||||||
|
int32_t temp_processed;
|
||||||
|
struct itds_device_data *ddata = dev->driver_data;
|
||||||
|
|
||||||
|
temp_processed = (ddata->temprature >> 4) * ITDS_TEMP_CONST;
|
||||||
|
|
||||||
|
val->val1 = ITDS_TEMP_OFFSET;
|
||||||
|
val->val2 = temp_processed;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int itds_channel_get(struct device *dev,
|
||||||
|
enum sensor_channel chan,
|
||||||
|
struct sensor_value *val)
|
||||||
|
{
|
||||||
|
switch (chan) {
|
||||||
|
case SENSOR_CHAN_ACCEL_X:
|
||||||
|
case SENSOR_CHAN_ACCEL_Y:
|
||||||
|
case SENSOR_CHAN_ACCEL_Z:
|
||||||
|
case SENSOR_CHAN_ACCEL_XYZ:
|
||||||
|
itds_accl_channel_get(dev, chan, val);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case SENSOR_CHAN_DIE_TEMP:
|
||||||
|
return itds_temp_channel_get(dev, val);
|
||||||
|
|
||||||
|
default:
|
||||||
|
LOG_ERR("Channel not supported.");
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int itds_init(struct device *dev)
|
||||||
|
{
|
||||||
|
struct itds_device_data *ddata = dev->driver_data;
|
||||||
|
const struct itds_device_config *cfg = dev->config_info;
|
||||||
|
int ret;
|
||||||
|
uint16_t freq, mfreq;
|
||||||
|
uint8_t rval;
|
||||||
|
|
||||||
|
ddata->i2c = device_get_binding(cfg->bus_name);
|
||||||
|
if (!ddata->i2c) {
|
||||||
|
LOG_ERR("I2C controller not found: %s.", cfg->bus_name);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = i2c_reg_read_byte(ddata->i2c, cfg->i2c_addr,
|
||||||
|
ITDS_REG_DEV_ID, &rval);
|
||||||
|
if (ret) {
|
||||||
|
LOG_ERR("device init fail: %d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rval != ITDS_DEVICE_ID) {
|
||||||
|
LOG_ERR("device ID mismatch: %x", rval);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = i2c_reg_update_byte(ddata->i2c, cfg->i2c_addr, ITDS_REG_CTRL2,
|
||||||
|
ITDS_MASK_BDU_INC_ADD, ITDS_MASK_BDU_INC_ADD);
|
||||||
|
if (ret) {
|
||||||
|
LOG_ERR("unable to set block data update %d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = i2c_reg_write_byte(ddata->i2c, cfg->i2c_addr,
|
||||||
|
ITDS_REG_WAKEUP_EVENT, 0);
|
||||||
|
if (ret) {
|
||||||
|
LOG_ERR("disable wakeup event fail %d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = i2c_reg_update_byte(ddata->i2c, cfg->i2c_addr, ITDS_REG_CTRL1,
|
||||||
|
ITDS_MASK_MODE, 1 << cfg->def_op_mode);
|
||||||
|
if (ret) {
|
||||||
|
LOG_ERR("set operating mode fail %d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ddata->op_mode = 1 << cfg->def_op_mode;
|
||||||
|
|
||||||
|
ret = itds_get_odr_for_index(dev, cfg->def_odr, &freq, &mfreq);
|
||||||
|
if (ret) {
|
||||||
|
LOG_ERR("odr not in range for operating mode %d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = itds_accl_odr_set(dev, freq, mfreq);
|
||||||
|
if (ret) {
|
||||||
|
LOG_ERR("odr not in range for operating mode %d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_ITDS_TRIGGER
|
||||||
|
ret = itds_trigger_mode_init(dev);
|
||||||
|
if (ret) {
|
||||||
|
LOG_ERR("trigger mode init failed %d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct sensor_driver_api itds_api = {
|
||||||
|
.attr_set = itds_attr_set,
|
||||||
|
#ifdef CONFIG_ITDS_TRIGGER
|
||||||
|
.trigger_set = itds_trigger_set,
|
||||||
|
#endif
|
||||||
|
.sample_fetch = itds_sample_fetch,
|
||||||
|
.channel_get = itds_channel_get,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define WSEN_ITDS_INIT(idx) \
|
||||||
|
\
|
||||||
|
static struct itds_device_data itds_data_##idx; \
|
||||||
|
\
|
||||||
|
static const struct itds_device_config itds_config_##idx = { \
|
||||||
|
.i2c_addr = DT_INST_REG_ADDR(idx), \
|
||||||
|
.bus_name = DT_INST_BUS_LABEL(idx), \
|
||||||
|
.gpio_port = DT_INST_GPIO_LABEL(idx, int_gpios), \
|
||||||
|
.int_pin = DT_INST_GPIO_PIN(idx, int_gpios), \
|
||||||
|
.int_flags = DT_INST_GPIO_FLAGS(idx, int_gpios), \
|
||||||
|
.def_odr = DT_ENUM_IDX(DT_DRV_INST(idx), odr), \
|
||||||
|
.def_op_mode = DT_ENUM_IDX(DT_DRV_INST(idx), op_mode), \
|
||||||
|
}; \
|
||||||
|
\
|
||||||
|
DEVICE_AND_API_INIT(itds_##idx, DT_INST_LABEL(idx), itds_init, \
|
||||||
|
&itds_data_##idx, &itds_config_##idx, \
|
||||||
|
POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \
|
||||||
|
&itds_api); \
|
||||||
|
|
||||||
|
DT_INST_FOREACH_STATUS_OKAY(WSEN_ITDS_INIT)
|
127
drivers/sensor/wsen_itds/itds.h
Normal file
127
drivers/sensor/wsen_itds/itds.h
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
/* Würth Elektronic WSEN-ITDS 3-axis Accel sensor driver
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Linumiz
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZEPHYR_DRIVERS_SENSOR_ITDS_H_
|
||||||
|
#define ZEPHYR_DRIVERS_SENSOR_ITDS_H_
|
||||||
|
|
||||||
|
#include <drivers/gpio.h>
|
||||||
|
#include <drivers/i2c.h>
|
||||||
|
#include <sys/util.h>
|
||||||
|
|
||||||
|
/* registers */
|
||||||
|
#define ITDS_REG_TEMP_L 0x0d
|
||||||
|
#define ITDS_REG_DEV_ID 0x0f
|
||||||
|
#define ITDS_REG_CTRL1 0x20
|
||||||
|
#define ITDS_REG_CTRL2 0x21
|
||||||
|
#define ITDS_REG_CTRL3 0x22
|
||||||
|
#define ITDS_REG_CTRL4 0x23
|
||||||
|
#define ITDS_REG_CTRL5 0x24
|
||||||
|
#define ITDS_REG_CTRL6 0x25
|
||||||
|
#define ITDS_REG_STATUS 0x27
|
||||||
|
#define ITDS_REG_X_OUT_L 0x28
|
||||||
|
#define ITDS_REG_Y_OUT_L 0x2a
|
||||||
|
#define ITDS_REG_Z_OUT_L 0x2c
|
||||||
|
#define ITDS_REG_FIFO_CTRL 0x2e
|
||||||
|
#define ITDS_REG_FIFO_SAMPLES 0x2f
|
||||||
|
#define ITDS_REG_STATUS_DETECT 0x37
|
||||||
|
#define ITDS_REG_WAKEUP_EVENT 0x38
|
||||||
|
#define ITDS_REG_CTRL7 0x3f
|
||||||
|
|
||||||
|
/* bitfields */
|
||||||
|
#define ITDS_MASK_SCALE GENMASK(5, 4)
|
||||||
|
#define ITDS_MASK_BDU_INC_ADD GENMASK(3, 2)
|
||||||
|
#define ITDS_MASK_FIFOTH GENMASK(4, 0)
|
||||||
|
#define ITDS_MASK_FIFOMODE GENMASK(7, 5)
|
||||||
|
#define ITDS_MASK_MODE GENMASK(3, 0)
|
||||||
|
#define ITDS_MASK_SAMPLES_COUNT GENMASK(5, 0)
|
||||||
|
#define ITDS_MASK_ODR GENMASK(7, 4)
|
||||||
|
#define ITDS_MASK_INT_DRDY BIT(0)
|
||||||
|
#define ITDS_MASK_INT_FIFOTH BIT(1)
|
||||||
|
#define ITDS_MASK_INT_EN BIT(5)
|
||||||
|
|
||||||
|
#define ITDS_EVENT_DRDY BIT(0)
|
||||||
|
#define ITDS_EVENT_DRDY_T BIT(6)
|
||||||
|
#define ITDS_EVENT_FIFO_TH BIT(7)
|
||||||
|
#define ITDS_FIFO_MODE_BYPASS 0
|
||||||
|
#define ITDS_FIFO_MODE_FIFO BIT(5)
|
||||||
|
#define ITDS_DEVICE_ID 0x44
|
||||||
|
#define ITDS_ACCL_FIFO_SIZE 32
|
||||||
|
#define ITDS_TEMP_OFFSET 25
|
||||||
|
|
||||||
|
enum operation_mode {
|
||||||
|
ITDS_OP_MODE_LOW_POWER = BIT(0),
|
||||||
|
ITDS_OP_MODE_NORMAL = BIT(1),
|
||||||
|
ITDS_OP_MODE_HIGH_PERF = BIT(2),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum itds_accel_range_const {
|
||||||
|
ITDS_ACCL_RANGE_2G,
|
||||||
|
ITDS_ACCL_RANGE_4G,
|
||||||
|
ITDS_ACCL_RANGE_8G,
|
||||||
|
ITDS_ACCL_RANGE_16G,
|
||||||
|
ITDS_ACCL_RANGE_END
|
||||||
|
};
|
||||||
|
|
||||||
|
enum itds_odr_const {
|
||||||
|
ITDS_ODR_0,
|
||||||
|
ITDS_ODR_1_6,
|
||||||
|
ITDS_ODR_12_5,
|
||||||
|
ITDS_ODR_25,
|
||||||
|
ITDS_ODR_50,
|
||||||
|
ITDS_ODR_100,
|
||||||
|
ITDS_ODR_200,
|
||||||
|
ITDS_ODR_400,
|
||||||
|
ITDS_ODR_800,
|
||||||
|
ITDS_ODR_1600,
|
||||||
|
ITDS_ODR_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
struct itds_odr {
|
||||||
|
uint16_t freq;
|
||||||
|
uint16_t mfreq;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct itds_accel_range {
|
||||||
|
uint16_t range;
|
||||||
|
uint8_t reg_val;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct itds_device_config {
|
||||||
|
const char *bus_name;
|
||||||
|
uint16_t i2c_addr;
|
||||||
|
const char *gpio_port;
|
||||||
|
gpio_pin_t int_pin;
|
||||||
|
gpio_dt_flags_t int_flags;
|
||||||
|
int def_odr;
|
||||||
|
int def_op_mode;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ITDS_SAMPLE_SIZE 3
|
||||||
|
struct itds_device_data {
|
||||||
|
struct device *i2c;
|
||||||
|
#ifdef CONFIG_ITDS_TRIGGER
|
||||||
|
struct device *gpio;
|
||||||
|
struct gpio_callback gpio_cb;
|
||||||
|
struct k_work work;
|
||||||
|
#endif
|
||||||
|
int16_t samples[ITDS_SAMPLE_SIZE];
|
||||||
|
int16_t temprature;
|
||||||
|
uint16_t scale;
|
||||||
|
enum operation_mode op_mode;
|
||||||
|
struct device *dev;
|
||||||
|
|
||||||
|
#ifdef CONFIG_ITDS_TRIGGER
|
||||||
|
sensor_trigger_handler_t handler_drdy;
|
||||||
|
#endif /* CONFIG_ITDS_TRIGGER */
|
||||||
|
};
|
||||||
|
|
||||||
|
int itds_trigger_mode_init(struct device *dev);
|
||||||
|
int itds_trigger_set(struct device *dev,
|
||||||
|
const struct sensor_trigger *trig,
|
||||||
|
sensor_trigger_handler_t handler);
|
||||||
|
|
||||||
|
#endif /* ZEPHYR_DRIVERS_SENSOR_ITDS_H_*/
|
121
drivers/sensor/wsen_itds/itds_trigger.c
Normal file
121
drivers/sensor/wsen_itds/itds_trigger.c
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Würth Elektronic WSEN-ITDS 3-axis accel sensor driver
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Linumiz
|
||||||
|
* Author: Saravanan Sekar <saravanan@linumiz.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <kernel.h>
|
||||||
|
#include <drivers/sensor.h>
|
||||||
|
#include <drivers/gpio.h>
|
||||||
|
#include <logging/log.h>
|
||||||
|
|
||||||
|
#include "itds.h"
|
||||||
|
LOG_MODULE_DECLARE(ITDS, CONFIG_SENSOR_LOG_LEVEL);
|
||||||
|
|
||||||
|
static int itds_trigger_drdy_set(struct device *dev,
|
||||||
|
enum sensor_channel chan,
|
||||||
|
sensor_trigger_handler_t handler)
|
||||||
|
{
|
||||||
|
struct itds_device_data *ddata = dev->driver_data;
|
||||||
|
const struct itds_device_config *cfg = dev->config_info;
|
||||||
|
uint8_t drdy_en = 0U;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ddata->handler_drdy = handler;
|
||||||
|
if (ddata->handler_drdy) {
|
||||||
|
drdy_en = ITDS_MASK_INT_DRDY;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = i2c_reg_update_byte(ddata->i2c, cfg->i2c_addr, ITDS_REG_CTRL4,
|
||||||
|
ITDS_MASK_INT_DRDY, drdy_en);
|
||||||
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int itds_trigger_set(struct device *dev,
|
||||||
|
const struct sensor_trigger *trig,
|
||||||
|
sensor_trigger_handler_t handler)
|
||||||
|
{
|
||||||
|
if (trig->chan != SENSOR_CHAN_ACCEL_XYZ) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (trig->type) {
|
||||||
|
case SENSOR_TRIG_DATA_READY:
|
||||||
|
return itds_trigger_drdy_set(dev, trig->chan, handler);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void itds_work_handler(struct k_work *work)
|
||||||
|
{
|
||||||
|
struct itds_device_data *ddata =
|
||||||
|
CONTAINER_OF(work, struct itds_device_data, work);
|
||||||
|
struct device *dev = (struct device *)ddata->dev;
|
||||||
|
const struct itds_device_config *cfg = dev->config_info;
|
||||||
|
uint8_t status;
|
||||||
|
struct sensor_trigger drdy_trigger = {
|
||||||
|
.chan = SENSOR_CHAN_ACCEL_XYZ,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (i2c_reg_read_byte(ddata->i2c, cfg->i2c_addr, ITDS_REG_STATUS,
|
||||||
|
&status) < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status & ITDS_EVENT_DRDY) {
|
||||||
|
if (ddata->handler_drdy) {
|
||||||
|
drdy_trigger.type = SENSOR_TRIG_DATA_READY;
|
||||||
|
ddata->handler_drdy(dev, &drdy_trigger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void itds_gpio_callback(struct device *port,
|
||||||
|
struct gpio_callback *cb, uint32_t pin)
|
||||||
|
{
|
||||||
|
struct itds_device_data *ddata =
|
||||||
|
CONTAINER_OF(cb, struct itds_device_data, gpio_cb);
|
||||||
|
|
||||||
|
ARG_UNUSED(port);
|
||||||
|
ARG_UNUSED(pin);
|
||||||
|
|
||||||
|
k_work_submit(&ddata->work);
|
||||||
|
}
|
||||||
|
|
||||||
|
int itds_trigger_mode_init(struct device *dev)
|
||||||
|
{
|
||||||
|
struct itds_device_data *ddata = dev->driver_data;
|
||||||
|
const struct itds_device_config *cfg = dev->config_info;
|
||||||
|
|
||||||
|
ddata->gpio = device_get_binding(cfg->gpio_port);
|
||||||
|
if (!ddata->gpio) {
|
||||||
|
LOG_DBG("Gpio controller %s not found.", cfg->gpio_port);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ddata->work.handler = itds_work_handler;
|
||||||
|
ddata->dev = dev;
|
||||||
|
|
||||||
|
gpio_pin_configure(ddata->gpio, cfg->int_pin,
|
||||||
|
GPIO_INPUT | cfg->int_flags);
|
||||||
|
|
||||||
|
gpio_init_callback(&ddata->gpio_cb, itds_gpio_callback,
|
||||||
|
BIT(cfg->int_pin));
|
||||||
|
|
||||||
|
gpio_add_callback(ddata->gpio, &ddata->gpio_cb);
|
||||||
|
gpio_pin_interrupt_configure(ddata->gpio, cfg->int_pin,
|
||||||
|
GPIO_INT_EDGE_TO_ACTIVE);
|
||||||
|
|
||||||
|
/* enable global interrupt */
|
||||||
|
return i2c_reg_update_byte(ddata->i2c, cfg->i2c_addr, ITDS_REG_CTRL7,
|
||||||
|
ITDS_MASK_INT_EN, ITDS_MASK_INT_EN);
|
||||||
|
}
|
43
dts/bindings/sensor/we,wsen-itds.yaml
Normal file
43
dts/bindings/sensor/we,wsen-itds.yaml
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
# Copyright (c) 2020 Linumiz
|
||||||
|
|
||||||
|
description: WSEN-ITDS 3-axis accel sensor
|
||||||
|
|
||||||
|
compatible: "we,wsen-itds"
|
||||||
|
|
||||||
|
include: i2c-device.yaml
|
||||||
|
|
||||||
|
properties:
|
||||||
|
int-gpios:
|
||||||
|
type: phandle-array
|
||||||
|
required: false
|
||||||
|
description: |
|
||||||
|
This property specifies the connection for INT0, the driver maps
|
||||||
|
all interrupts to INT0 as default. The signal to output high when
|
||||||
|
data produced by the sensor.
|
||||||
|
|
||||||
|
odr:
|
||||||
|
type: string
|
||||||
|
required: false
|
||||||
|
default: "800"
|
||||||
|
description: Output data rate in Hz
|
||||||
|
enum:
|
||||||
|
- "1.6"
|
||||||
|
- "12.5"
|
||||||
|
- "25"
|
||||||
|
- "50"
|
||||||
|
- "100"
|
||||||
|
- "200"
|
||||||
|
- "400"
|
||||||
|
- "800"
|
||||||
|
- "1600"
|
||||||
|
|
||||||
|
op-mode:
|
||||||
|
type: string
|
||||||
|
required: false
|
||||||
|
default: "high-perf"
|
||||||
|
description: Operating mode of sensor
|
||||||
|
enum:
|
||||||
|
- "low-power"
|
||||||
|
- "normal"
|
||||||
|
- "high-perf"
|
|
@ -536,3 +536,10 @@ test_i2c_iis2dh: iis2dh@18 {
|
||||||
reg = <0x18>;
|
reg = <0x18>;
|
||||||
drdy-gpios = <&test_gpio 0 0>;
|
drdy-gpios = <&test_gpio 0 0>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
test_i2c_itds: itds@18 {
|
||||||
|
compatible = "we,wsen-itds";
|
||||||
|
label = "WSEN-ITDS";
|
||||||
|
reg = <0x18>;
|
||||||
|
int-gpios = <&test_gpio 0 0>;
|
||||||
|
};
|
||||||
|
|
|
@ -32,3 +32,4 @@ CONFIG_SX9500=y
|
||||||
CONFIG_SX9500_TRIGGER_OWN_THREAD=y
|
CONFIG_SX9500_TRIGGER_OWN_THREAD=y
|
||||||
CONFIG_TMP007=y
|
CONFIG_TMP007=y
|
||||||
CONFIG_TMP007_TRIGGER_OWN_THREAD=y
|
CONFIG_TMP007_TRIGGER_OWN_THREAD=y
|
||||||
|
CONFIG_ITDS=y
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue