drivers/sensor: lis2dw12: add threshold interrupt support

Add optional threshold interrupt support.
Implemented using SENSOR_TRIG_THRESHOLD sensor trigger type.
The features can be optionally enabled through Kconfig,
or disabled for smaller code size.

Signed-off-by: Maxime Vincent <maxime@veemax.be>
This commit is contained in:
Maxime Vincent 2022-03-19 11:08:21 +01:00 committed by Anas Nashif
commit bf1334bafb
4 changed files with 154 additions and 0 deletions

View file

@ -11,6 +11,7 @@
#define DT_DRV_COMPAT st_lis2dw12
#include <init.h>
#include <stdlib.h>
#include <sys/__assert.h>
#include <sys/byteorder.h>
#include <logging/log.h>
@ -157,11 +158,102 @@ static int lis2dw12_config(const struct device *dev, enum sensor_channel chan,
return -ENOTSUP;
}
static inline int32_t sensor_ms2_to_mg(const struct sensor_value *ms2)
{
int64_t nano_ms2 = (ms2->val1 * 1000000LL + ms2->val2) * 1000LL;
if (nano_ms2 > 0) {
return (nano_ms2 + SENSOR_G / 2) / SENSOR_G;
} else {
return (nano_ms2 - SENSOR_G / 2) / SENSOR_G;
}
}
#if CONFIG_LIS2DW12_THRESHOLD
/* Converts a lis2dw12_fs_t range to its value in milli-g
* Range can be 2/4/8/16G
*/
#define FS_RANGE_TO_MG(fs_range) ((2U << fs_range) * 1000U)
/* Converts a range in mg to the lsb value for the WK_THS register
* For the reg value: 1 LSB = 1/64 of FS
* Range can be 2/4/8/16G
*/
#define MG_TO_WK_THS_LSB(range_mg) (range_mg / 64)
/* Calculates the WK_THS reg value
* from the threshold in mg and the lsb value in mg
* with correct integer rounding
*/
#define THRESHOLD_MG_TO_WK_THS_REG(thr_mg, lsb_mg) \
((thr_mg + (lsb_mg / 2)) / lsb_mg)
static int lis2dw12_attr_set_thresh(const struct device *dev,
enum sensor_channel chan,
enum sensor_attribute attr,
const struct sensor_value *val)
{
uint8_t reg;
size_t ret;
int lsb_mg;
const struct lis2dw12_device_config *cfg = dev->config;
stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
LOG_DBG("%s on channel %d", __func__, chan);
/* can only be set for all directions at once */
if (chan != SENSOR_CHAN_ACCEL_XYZ) {
return -EINVAL;
}
/* Configure wakeup threshold threshold. */
lis2dw12_fs_t range;
int err = lis2dw12_full_scale_get(ctx, &range);
if (err) {
return err;
}
uint32_t thr_mg = abs(sensor_ms2_to_mg(val));
/* Check maximum value: depends on current FS value */
if (thr_mg >= FS_RANGE_TO_MG(range)) {
return -EINVAL;
}
/* The threshold is applied to both positive and negative data:
* for a wake-up interrupt generation at least one of the three axes must be
* bigger than the threshold.
*/
lsb_mg = MG_TO_WK_THS_LSB(FS_RANGE_TO_MG(range));
reg = THRESHOLD_MG_TO_WK_THS_REG(thr_mg, lsb_mg);
LOG_DBG("Threshold %d mg -> fs: %u mg -> reg = %d LSBs",
thr_mg, FS_RANGE_TO_MG(range), reg);
ret = 0;
return lis2dw12_wkup_threshold_set(ctx, reg);
}
#endif
static int lis2dw12_attr_set(const struct device *dev,
enum sensor_channel chan,
enum sensor_attribute attr,
const struct sensor_value *val)
{
#if CONFIG_LIS2DW12_THRESHOLD
switch (attr) {
case SENSOR_ATTR_UPPER_THRESH:
case SENSOR_ATTR_LOWER_THRESH:
return lis2dw12_attr_set_thresh(dev, chan, attr, val);
default:
/* Do nothing */
break;
}
#endif
switch (chan) {
case SENSOR_CHAN_ACCEL_X:
case SENSOR_CHAN_ACCEL_Y: