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_TEMP_KINETIS nxp_kinetis_temp)
|
||||
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_SENSOR_SHELL sensor_shell.c)
|
||||
|
|
|
@ -169,4 +169,6 @@ source "drivers/sensor/vl53l0x/Kconfig"
|
|||
|
||||
source "drivers/sensor/nxp_kinetis_temp/Kconfig"
|
||||
|
||||
source "drivers/sensor/wsen_itds/Kconfig"
|
||||
|
||||
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>;
|
||||
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_TMP007=y
|
||||
CONFIG_TMP007_TRIGGER_OWN_THREAD=y
|
||||
CONFIG_ITDS=y
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue