diff --git a/drivers/sensor/st/lsm6dso/Kconfig b/drivers/sensor/st/lsm6dso/Kconfig index c0c1b7fd994..7d25ba57daf 100644 --- a/drivers/sensor/st/lsm6dso/Kconfig +++ b/drivers/sensor/st/lsm6dso/Kconfig @@ -60,6 +60,16 @@ config LSM6DSO_THREAD_STACK_SIZE help Stack size of thread used by the driver to handle interrupts. +config LSM6DSO_TILT + bool "Tilt detection" + help + Enable tilt detection + +config LSM6DSO_TAP + bool "Tap and Tap-Tap detection" + help + Enable tap (single/double) detection + endif # LSM6DSO_TRIGGER config LSM6DSO_ENABLE_TEMP diff --git a/drivers/sensor/st/lsm6dso/lsm6dso.c b/drivers/sensor/st/lsm6dso/lsm6dso.c index d3cdaf9dfd2..08c2fa03cd3 100644 --- a/drivers/sensor/st/lsm6dso/lsm6dso.c +++ b/drivers/sensor/st/lsm6dso/lsm6dso.c @@ -869,6 +869,17 @@ static int lsm6dso_init(const struct device *dev) * Instantiation macros used when a device is on a SPI bus. */ +#ifdef CONFIG_LSM6DSO_TAP +#define LSM6DSO_CONFIG_TAP(inst) \ + .tap_mode = DT_INST_PROP(inst, tap_mode), \ + .tap_threshold = DT_INST_PROP(inst, tap_threshold), \ + .tap_shock = DT_INST_PROP(inst, tap_shock), \ + .tap_latency = DT_INST_PROP(inst, tap_latency), \ + .tap_quiet = DT_INST_PROP(inst, tap_quiet), +#else +#define LSM6DSO_CONFIG_TAP(inst) +#endif /* CONFIG_LSM6DSO_TAP */ + #ifdef CONFIG_LSM6DSO_TRIGGER #define LSM6DSO_CFG_IRQ(inst) \ .trig_enabled = true, \ @@ -892,7 +903,8 @@ static int lsm6dso_init(const struct device *dev) .gyro_pm = DT_INST_PROP(inst, gyro_pm), \ .gyro_odr = DT_INST_PROP(inst, gyro_odr), \ .gyro_range = DT_INST_PROP(inst, gyro_range), \ - .drdy_pulsed = DT_INST_PROP(inst, drdy_pulsed), \ + .drdy_pulsed = DT_INST_PROP(inst, drdy_pulsed), \ + LSM6DSO_CONFIG_TAP(inst) \ COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, irq_gpios), \ (LSM6DSO_CFG_IRQ(inst)), ()) diff --git a/drivers/sensor/st/lsm6dso/lsm6dso.h b/drivers/sensor/st/lsm6dso/lsm6dso.h index a721f0244c1..98da0058234 100644 --- a/drivers/sensor/st/lsm6dso/lsm6dso.h +++ b/drivers/sensor/st/lsm6dso/lsm6dso.h @@ -63,6 +63,13 @@ struct lsm6dso_config { const struct gpio_dt_spec gpio_drdy; uint8_t int_pin; bool trig_enabled; +#ifdef CONFIG_LSM6DSO_TAP + uint8_t tap_mode; + uint8_t tap_threshold[3]; + uint8_t tap_shock; + uint8_t tap_latency; + uint8_t tap_quiet; +#endif /* CONFIG_LSM6DSO_TAP */ #endif /* CONFIG_LSM6DSO_TRIGGER */ }; @@ -106,6 +113,18 @@ struct lsm6dso_data { sensor_trigger_handler_t handler_drdy_temp; const struct sensor_trigger *trig_drdy_temp; +#ifdef CONFIG_LSM6DSO_TILT + sensor_trigger_handler_t handler_tilt; + const struct sensor_trigger *trig_tilt; +#endif /* CONFIG_LSM6DSO_TILT */ + +#ifdef CONFIG_LSM6DSO_TAP + sensor_trigger_handler_t handler_tap; + const struct sensor_trigger *trig_tap; + sensor_trigger_handler_t handler_double_tap; + const struct sensor_trigger *trig_double_tap; +#endif /* CONFIG_LSM6DSO_TAP */ + #if defined(CONFIG_LSM6DSO_TRIGGER_OWN_THREAD) K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_LSM6DSO_THREAD_STACK_SIZE); struct k_thread thread; diff --git a/drivers/sensor/st/lsm6dso/lsm6dso_trigger.c b/drivers/sensor/st/lsm6dso/lsm6dso_trigger.c index 7c7a3c13f93..9b928c62736 100644 --- a/drivers/sensor/st/lsm6dso/lsm6dso_trigger.c +++ b/drivers/sensor/st/lsm6dso/lsm6dso_trigger.c @@ -48,6 +48,193 @@ static int lsm6dso_enable_t_int(const struct device *dev, int enable) } #endif +#if defined(CONFIG_LSM6DSO_TILT) + +static int lsm6dso_enable_tilt_int(const struct device *dev, int enable) +{ + const struct lsm6dso_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + int ret = 0; + lsm6dso_emb_sens_t sens; + + sens.tilt = PROPERTY_ENABLE; + + ret += lsm6dso_embedded_sens_set(ctx, &sens); + if (ret < 0) { + LOG_ERR("Failed to enable tilt"); + return -EIO; + } + + if (cfg->int_pin == 1) { + + lsm6dso_pin_int1_route_t route; + + lsm6dso_pin_int1_route_get(ctx, &route); + route.tilt = enable; + + ret += lsm6dso_pin_int1_route_set(ctx, route); + if (ret < 0) { + LOG_ERR("Failed to set int1 route"); + return -EIO; + } + + } else { + + lsm6dso_pin_int2_route_t route; + + lsm6dso_pin_int2_route_get(ctx, NULL, &route); + route.tilt = enable; + + ret += lsm6dso_pin_int2_route_set(ctx, NULL, route); + if (ret < 0) { + LOG_ERR("Failed to set int2 route"); + return -EIO; + } + + } + + return 0; +} + +#endif + +#if defined(CONFIG_LSM6DSO_TAP) + +static int lsm6dso_enable_tap(const struct device *dev, int enable) +{ + const struct lsm6dso_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lsm6dso_odr_xl_t odr; + + if (lsm6dso_xl_data_rate_get(ctx, &odr) < 0) { + LOG_ERR("Unable to read accelerometer ODR"); + return -EIO; + } + + if (odr < LSM6DSO_XL_ODR_417Hz) { + LOG_WRN("Minimum recommended accelerometer ODR is 417Hz for tap mode"); + } + + LOG_INF("TAP: tap mode is %d", cfg->tap_mode); + if (lsm6dso_tap_mode_set(ctx, cfg->tap_mode) < 0) { + LOG_ERR("Failed to select tap trigger mode"); + return -EIO; + } + + LOG_INF("TAP: ths_x is %02x", cfg->tap_threshold[0]); + if (lsm6dso_tap_threshold_x_set(ctx, cfg->tap_threshold[0]) < 0) { + LOG_ERR("Failed to set tap X axis threshold"); + return -EIO; + } + + LOG_DBG("TAP: ths_y is %02x", cfg->tap_threshold[1]); + if (lsm6dso_tap_threshold_y_set(ctx, cfg->tap_threshold[1]) < 0) { + LOG_ERR("Failed to set tap Y axis threshold"); + return -EIO; + } + + LOG_DBG("TAP: ths_z is %02x", cfg->tap_threshold[2]); + if (lsm6dso_tap_threshold_z_set(ctx, cfg->tap_threshold[2]) < 0) { + LOG_ERR("Failed to set tap Z axis threshold"); + return -EIO; + } + + if (cfg->tap_threshold[0] > 0) { + LOG_DBG("TAP: tap_x enabled"); + if (lsm6dso_tap_detection_on_x_set(ctx, enable) < 0) { + LOG_ERR("Failed to set tap detection on X axis"); + return -EIO; + } + } + + if (cfg->tap_threshold[1] > 0) { + LOG_DBG("TAP: tap_y enabled"); + if (lsm6dso_tap_detection_on_y_set(ctx, enable) < 0) { + LOG_ERR("Failed to set tap detection on Y axis"); + return -EIO; + } + } + + if (cfg->tap_threshold[2] > 0) { + LOG_DBG("TAP: tap_z enabled"); + if (lsm6dso_tap_detection_on_z_set(ctx, enable) < 0) { + LOG_ERR("Failed to set tap detection on Z axis"); + return -EIO; + } + } + + LOG_DBG("TAP: shock is %02x", cfg->tap_shock); + if (lsm6dso_tap_shock_set(ctx, cfg->tap_shock) < 0) { + LOG_ERR("Failed to set tap shock duration"); + return -EIO; + } + + LOG_DBG("TAP: latency is %02x", cfg->tap_latency); + if (lsm6dso_tap_dur_set(ctx, cfg->tap_latency) < 0) { + LOG_ERR("Failed to set tap latency"); + return -EIO; + } + + /* Set tap quiet */ + LOG_DBG("TAP: quiet time is %02x", cfg->tap_quiet); + if (lsm6dso_tap_quiet_set(ctx, cfg->tap_quiet) < 0) { + LOG_ERR("Failed to set tap quiet time"); + return -EIO; + } + + return 0; +} + +static int lsm6dso_enable_single_tap_int(const struct device *dev, int enable) +{ + const struct lsm6dso_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + + if (cfg->int_pin == 1) { + + lsm6dso_pin_int1_route_t route; + + lsm6dso_pin_int1_route_get(ctx, &route); + route.single_tap = enable; + return lsm6dso_pin_int1_route_set(ctx, route); + + } else { + + lsm6dso_pin_int2_route_t route; + + lsm6dso_pin_int2_route_get(ctx, NULL, &route); + route.single_tap = enable; + return lsm6dso_pin_int2_route_set(ctx, NULL, route); + } + + return 0; +} + +static int lsm6dso_enable_double_tap_int(const struct device *dev, int enable) +{ + const struct lsm6dso_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + + if (cfg->int_pin == 1) { + + lsm6dso_pin_int1_route_t route; + + lsm6dso_pin_int1_route_get(ctx, &route); + route.double_tap = enable; + return lsm6dso_pin_int1_route_set(ctx, route); + + } else { + + lsm6dso_pin_int2_route_t route; + + lsm6dso_pin_int2_route_get(ctx, NULL, &route); + route.double_tap = enable; + return lsm6dso_pin_int2_route_set(ctx, NULL, route); + } +} + +#endif /* CONFIG_LSM6DSO_TAP */ + /** * lsm6dso_enable_xl_int - XL enable selected int pin to generate interrupt */ @@ -134,36 +321,86 @@ int lsm6dso_trigger_set(const struct device *dev, return -ENOTSUP; } - if (trig->chan == SENSOR_CHAN_ACCEL_XYZ) { - lsm6dso->handler_drdy_acc = handler; - lsm6dso->trig_drdy_acc = trig; - if (handler) { - return lsm6dso_enable_xl_int(dev, LSM6DSO_EN_BIT); - } else { - return lsm6dso_enable_xl_int(dev, LSM6DSO_DIS_BIT); + if (trig->type == SENSOR_TRIG_DATA_READY) { + + if (trig->chan == SENSOR_CHAN_ACCEL_XYZ) { + lsm6dso->handler_drdy_acc = handler; + lsm6dso->trig_drdy_acc = trig; + if (handler) { + return lsm6dso_enable_xl_int(dev, LSM6DSO_EN_BIT); + } else { + return lsm6dso_enable_xl_int(dev, LSM6DSO_DIS_BIT); + } + } else if (trig->chan == SENSOR_CHAN_GYRO_XYZ) { + lsm6dso->handler_drdy_gyr = handler; + lsm6dso->trig_drdy_gyr = trig; + if (handler) { + return lsm6dso_enable_g_int(dev, LSM6DSO_EN_BIT); + } else { + return lsm6dso_enable_g_int(dev, LSM6DSO_DIS_BIT); + } } - } else if (trig->chan == SENSOR_CHAN_GYRO_XYZ) { - lsm6dso->handler_drdy_gyr = handler; - lsm6dso->trig_drdy_gyr = trig; - if (handler) { - return lsm6dso_enable_g_int(dev, LSM6DSO_EN_BIT); - } else { - return lsm6dso_enable_g_int(dev, LSM6DSO_DIS_BIT); - } - } #if defined(CONFIG_LSM6DSO_ENABLE_TEMP) - else if (trig->chan == SENSOR_CHAN_DIE_TEMP) { - lsm6dso->handler_drdy_temp = handler; - lsm6dso->trig_drdy_temp = trig; - if (handler) { - return lsm6dso_enable_t_int(dev, LSM6DSO_EN_BIT); - } else { - return lsm6dso_enable_t_int(dev, LSM6DSO_DIS_BIT); + else if (trig->chan == SENSOR_CHAN_DIE_TEMP) { + lsm6dso->handler_drdy_temp = handler; + lsm6dso->trig_drdy_temp = trig; + if (handler) { + return lsm6dso_enable_t_int(dev, LSM6DSO_EN_BIT); + } else { + return lsm6dso_enable_t_int(dev, LSM6DSO_DIS_BIT); + } } +#endif + else { + + return -ENOTSUP; + + } + + } +#if defined(CONFIG_LSM6DSO_TILT) + else if (trig->type == SENSOR_TRIG_TILT) { + + lsm6dso->handler_tilt = handler; + lsm6dso->trig_tilt = trig; + if (handler) { + return lsm6dso_enable_tilt_int(dev, LSM6DSO_EN_BIT); + } else { + return lsm6dso_enable_tilt_int(dev, LSM6DSO_DIS_BIT); + } + } #endif +#if defined(CONFIG_LSM6DSO_TAP) + else if (trig->type == SENSOR_TRIG_TAP || trig->type == SENSOR_TRIG_DOUBLE_TAP) { + lsm6dso_enable_tap(dev, handler ? LSM6DSO_EN_BIT : LSM6DSO_DIS_BIT); + + /* Set interrupt */ + if (trig->type == SENSOR_TRIG_TAP) { + + lsm6dso->handler_tap = handler; + lsm6dso->trig_tap = trig; + if (handler) { + return lsm6dso_enable_single_tap_int(dev, LSM6DSO_EN_BIT); + } else { + return lsm6dso_enable_single_tap_int(dev, LSM6DSO_DIS_BIT); + } + + } else if (trig->type == SENSOR_TRIG_DOUBLE_TAP) { + + lsm6dso->handler_double_tap = handler; + lsm6dso->trig_double_tap = trig; + if (handler) { + return lsm6dso_enable_double_tap_int(dev, LSM6DSO_EN_BIT); + } else { + return lsm6dso_enable_double_tap_int(dev, LSM6DSO_DIS_BIT); + } + } + } +#endif /* CONFIG_LSM6DSO_TAP */ return -ENOTSUP; + } /** @@ -175,37 +412,63 @@ static void lsm6dso_handle_interrupt(const struct device *dev) struct lsm6dso_data *lsm6dso = dev->data; const struct lsm6dso_config *cfg = dev->config; stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; - lsm6dso_status_reg_t status; + lsm6dso_all_sources_t sources; + bool pending_status = false; while (1) { - if (lsm6dso_status_reg_get(ctx, &status) < 0) { - LOG_DBG("failed reading status reg"); + + if (lsm6dso_all_sources_get(ctx, &sources) < 0) { + LOG_ERR("failed reading all sources"); return; } - if ((status.xlda == 0) && (status.gda == 0) + if ((sources.drdy_xl && lsm6dso->handler_drdy_acc != NULL) || + (sources.drdy_g && lsm6dso->handler_drdy_gyr != NULL) #if defined(CONFIG_LSM6DSO_ENABLE_TEMP) - && (status.tda == 0) + || (sources.drdy_temp && lsm6dso->handler_drdy_temp != NULL) #endif - ) { - break; + ) { + pending_status = true; + } else { + pending_status = false; } - if ((status.xlda) && (lsm6dso->handler_drdy_acc != NULL)) { + if ((sources.drdy_xl) && (lsm6dso->handler_drdy_acc != NULL)) { lsm6dso->handler_drdy_acc(dev, lsm6dso->trig_drdy_acc); } - if ((status.gda) && (lsm6dso->handler_drdy_gyr != NULL)) { + if ((sources.drdy_g) && (lsm6dso->handler_drdy_gyr != NULL)) { lsm6dso->handler_drdy_gyr(dev, lsm6dso->trig_drdy_gyr); } #if defined(CONFIG_LSM6DSO_ENABLE_TEMP) - if ((status.tda) && (lsm6dso->handler_drdy_temp != NULL)) { + if ((sources.drdy_temp) && (lsm6dso->handler_drdy_temp != NULL)) { lsm6dso->handler_drdy_temp(dev, lsm6dso->trig_drdy_temp); } #endif + + if (!pending_status) { + break; + } + } +#if defined(CONFIG_LSM6DSO_TILT) + if (sources.tilt && (lsm6dso->handler_tilt != NULL)) { + lsm6dso->handler_tilt(dev, lsm6dso->trig_tilt); + } +#endif /* CONFIG_LSM6DSO_TILT */ +#if defined(CONFIG_LSM6DSO_TAP) + + if (sources.single_tap && lsm6dso->handler_tap != NULL) { + lsm6dso->handler_tap(dev, lsm6dso->trig_tap); + } + + if (sources.double_tap && lsm6dso->handler_double_tap != NULL) { + lsm6dso->handler_double_tap(dev, lsm6dso->trig_double_tap); + } +#endif /* CONFIG_LSM6DSO_TAP */ + gpio_pin_interrupt_configure_dt(&cfg->gpio_drdy, GPIO_INT_EDGE_TO_ACTIVE); } @@ -285,6 +548,7 @@ int lsm6dso_init_interrupt(const struct device *dev) return ret; } + gpio_init_callback(&lsm6dso->gpio_cb, lsm6dso_gpio_callback, BIT(cfg->gpio_drdy.pin)); diff --git a/dts/bindings/sensor/st,lsm6dso-common.yaml b/dts/bindings/sensor/st,lsm6dso-common.yaml index fe1c4d90ab1..700953c8c79 100644 --- a/dts/bindings/sensor/st,lsm6dso-common.yaml +++ b/dts/bindings/sensor/st,lsm6dso-common.yaml @@ -146,3 +146,67 @@ properties: description: | Selects the pulsed mode for data-ready interrupt when enabled, and the latched mode when disabled. + + # tap and tap-tap configuration section + # All default values are selected to match the power-up values. + # tap and tap-tap events can be generated on INT1 only. + + tap-mode: + type: int + default: 0 + description: | + Tap mode. Default is power-up configuration. + + - 0 # LSM6DSO_DT_SINGLE_TAP + - 1 # LSM6DSO_DT_SINGLE_DOUBLE_TAP + + enum: [0, 1] + + tap-threshold: + type: array + default: [0, 0, 0] + description: | + Tap X/Y/Z axes threshold. Default is power-up configuration. + (X/Y/Z values range from 0x00 to 0x1F) + + Thresholds to start the tap-event detection procedure on the X/Y/Z axes. + Threshold values for each axis are unsigned 5-bit corresponding + to a 2g acceleration full-scale range. A threshold value equal to zero + corresponds to disable the tap detection on that axis. + + For example, if you want to set the threshold for X to 12, for Z to 14 + and want to disable tap detection on Y, you should specify in Device Tree + + tap-threshold = <12>, <0>, <14> + + which is equivalent to X = 12 * 2g/32 = 750mg and Z = 14 * 2g/32 = 875mg. + + tap-shock: + type: int + default: 0x0 + description: | + Tap shock value. Default is power-up configuration. + (values range from 0x0 to 0x3) + This register represents the maximum time of an over-threshold signal + detection to be recognized as a tap event. Where 0 equals 4*1/ODR and + 1LSB = 8*1/ODR. + + tap-latency: + type: int + default: 0x0 + description: | + Tap latency. Default is power-up configuration. + (values range from 0x0 to 0xF) + When double-tap recognition is enabled, this register expresses the + maximum time between two successive detected taps to determine a + double-tap event. Where 0 equals 16*1/ODR and 1LSB = 32*1/ODR. + + tap-quiet: + type: int + default: 0x0 + description: | + Expected quiet time after a tap detection. Default is power-up configuration. + (values range from 0x0 to 0x3) + This register represents the time after the first detected tap in which + there must not be any overthreshold event. Where 0 equals 2*1/ODR + and 1LSB = 4*1/ODR. diff --git a/include/zephyr/drivers/sensor.h b/include/zephyr/drivers/sensor.h index 68f131e103d..eecfb4e985d 100644 --- a/include/zephyr/drivers/sensor.h +++ b/include/zephyr/drivers/sensor.h @@ -272,6 +272,10 @@ enum sensor_trigger_type { /** Trigger fires when the FIFO becomes full. */ SENSOR_TRIG_FIFO_FULL, + + /** Trigger fires when a tilt is detected. */ + SENSOR_TRIG_TILT, + /** * Number of all common sensor triggers. */ diff --git a/include/zephyr/dt-bindings/sensor/lsm6dso.h b/include/zephyr/dt-bindings/sensor/lsm6dso.h index 7d3775bae3d..9d46bf6c85a 100644 --- a/include/zephyr/dt-bindings/sensor/lsm6dso.h +++ b/include/zephyr/dt-bindings/sensor/lsm6dso.h @@ -42,4 +42,8 @@ #define LSM6DSO_DT_ODR_6667Hz 0xa #define LSM6DSO_DT_ODR_1Hz6 0xb +/* Tap mode */ +#define LSM6DSO_DT_SINGLE_TAP 0 +#define LSM6DSO_DT_SINGLE_DOUBLE_TAP 1 + #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_LSM6DSO_H_ */