diff --git a/drivers/sensor/lis2dh/lis2dh.h b/drivers/sensor/lis2dh/lis2dh.h index 72cc710ed9e..142b1330d78 100644 --- a/drivers/sensor/lis2dh/lis2dh.h +++ b/drivers/sensor/lis2dh/lis2dh.h @@ -29,11 +29,9 @@ #define LIS2DH_AUTOINCREMENT_ADDR BIT(7) #define LIS2DH_REG_CTRL0 0x1e -#define LIS2DH_SDO_PU_DISC_SHIFT 7 -#define LIS2DH_SDO_PU_DISC_MASK BIT(LIS2DH_SDO_PU_DISC_SHIFT) +#define LIS2DH_SDO_PU_DISC_MASK BIT(7) #define LIS2DH_REG_CTRL1 0x20 -#define LIS2DH_ACCEL_XYZ_SHIFT 0 #define LIS2DH_ACCEL_X_EN_BIT BIT(0) #define LIS2DH_ACCEL_Y_EN_BIT BIT(1) #define LIS2DH_ACCEL_Z_EN_BIT BIT(2) @@ -91,14 +89,15 @@ #define LIS2DH_HPIS2_EN_BIT BIT(1) #define LIS2DH_FDS_EN_BIT BIT(3) -#define LIS2DH_HPIS_EN_SHIFT 0 -#define LIS2DH_HPIS_EN_MASK BIT_MASK(2) << LIS2DH_HPIS_EN_SHIFT +#define LIS2DH_HPIS_EN_MASK BIT_MASK(2) #define LIS2DH_REG_CTRL3 0x22 -#define LIS2DH_EN_DRDY1_INT1_SHIFT 4 -#define LIS2DH_EN_DRDY1_INT1 BIT(LIS2DH_EN_DRDY1_INT1_SHIFT) +#define LIS2DH_EN_CLICK_INT1 BIT(7) +#define LIS2DH_EN_IA_INT1 BIT(6) +#define LIS2DH_EN_DRDY1_INT1 BIT(4) #define LIS2DH_REG_CTRL4 0x23 +#define LIS2DH_CTRL4_BDU_BIT BIT(7) #define LIS2DH_FS_SHIFT 4 #define LIS2DH_FS_MASK (BIT_MASK(2) << LIS2DH_FS_SHIFT) @@ -122,16 +121,12 @@ #endif #define LIS2DH_REG_CTRL5 0x24 -#define LIS2DH_LIR_INT2_SHIFT 1 -#define LIS2DH_LIR_INT1_SHIFT 3 -#define LIS2DH_EN_LIR_INT2 BIT(LIS2DH_LIR_INT2_SHIFT) -#define LIS2DH_EN_LIR_INT1 BIT(LIS2DH_LIR_INT1_SHIFT) +#define LIS2DH_EN_LIR_INT2 BIT(1) +#define LIS2DH_EN_LIR_INT1 BIT(3) #define LIS2DH_REG_CTRL6 0x25 -#define LIS2DH_EN_INT2_INT2_SHIFT 5 -#define LIS2DH_EN_INT2_INT2 BIT(LIS2DH_EN_INT2_INT2_SHIFT) -#define LIS2DH_EN_INT1_INT1_SHIFT 6 -#define LIS2DH_EN_INT1_INT1 BIT(LIS2DH_EN_INT1_INT1_SHIFT) +#define LIS2DH_EN_CLICK_INT2 BIT(7) +#define LIS2DH_EN_IA_INT2 BIT(5) #define LIS2DH_REG_REFERENCE 0x26 @@ -164,8 +159,8 @@ #define LIS2DH_REG_INT2_DUR 0x37 #define LIS2DH_INT_CFG_MODE_SHIFT 6 -#define LIS2DH_INT_CFG_AOI_CFG BIT(LIS2DH_INT_CFG_MODE_SHIFT + 1) -#define LIS2DH_INT_CFG_6D_CFG BIT(LIS2DH_INT_CFG_MODE_SHIFT) +#define LIS2DH_INT_CFG_AOI_CFG BIT(7) +#define LIS2DH_INT_CFG_6D_CFG BIT(6) #define LIS2DH_INT_CFG_ZHIE_ZUPE BIT(5) #define LIS2DH_INT_CFG_ZLIE_ZDOWNE BIT(4) #define LIS2DH_INT_CFG_YHIE_YUPE BIT(3) @@ -173,11 +168,26 @@ #define LIS2DH_INT_CFG_XHIE_XUPE BIT(1) #define LIS2DH_INT_CFG_XLIE_XDOWNE BIT(0) +#define LIS2DH_REG_CFG_CLICK 0x38 +#define LIS2DH_EN_CLICK_ZD BIT(5) +#define LIS2DH_EN_CLICK_ZS BIT(4) +#define LIS2DH_EN_CLICK_YD BIT(3) +#define LIS2DH_EN_CLICK_YS BIT(2) +#define LIS2DH_EN_CLICK_XD BIT(1) +#define LIS2DH_EN_CLICK_XS BIT(0) + +#define LIS2DH_REG_CLICK_SRC 0x39 +#define LIS2DH_CLICK_SRC_DCLICK BIT(5) +#define LIS2DH_CLICK_SRC_SCLICK BIT(4) + +#define LIS2DH_REG_CFG_CLICK_THS 0x3A +#define LIS2DH_CLICK_LIR BIT(7) + +#define LIS2DH_REG_TIME_LIMIT 0x3B + /* sample buffer size includes status register */ #define LIS2DH_BUF_SZ 7 -#define LIS2DH_CTRL4_BDU_BIT BIT(7) - union lis2dh_sample { uint8_t raw[LIS2DH_BUF_SZ]; struct { @@ -260,6 +270,8 @@ struct lis2dh_data { const struct sensor_trigger *trig_drdy; sensor_trigger_handler_t handler_anymotion; const struct sensor_trigger *trig_anymotion; + sensor_trigger_handler_t handler_tap; + const struct sensor_trigger *trig_tap; atomic_t trig_flags; enum sensor_channel chan_drdy; diff --git a/drivers/sensor/lis2dh/lis2dh_trigger.c b/drivers/sensor/lis2dh/lis2dh_trigger.c index 5b017ff0013..2b773b2aef8 100644 --- a/drivers/sensor/lis2dh/lis2dh_trigger.c +++ b/drivers/sensor/lis2dh/lis2dh_trigger.c @@ -127,9 +127,10 @@ static inline void setup_int2(const struct device *dev, : GPIO_INT_DISABLE); } -static int lis2dh_trigger_anym_set(const struct device *dev, - sensor_trigger_handler_t handler, - const struct sensor_trigger *trig) +/* common handler for any motion and tap triggers */ +static int lis2dh_trigger_anym_tap_set(const struct device *dev, + sensor_trigger_handler_t handler, + const struct sensor_trigger *trig) { const struct lis2dh_config *cfg = dev->config; struct lis2dh_data *lis2dh = dev->data; @@ -152,19 +153,34 @@ static int lis2dh_trigger_anym_set(const struct device *dev, } /* disable any movement interrupt events */ - status = lis2dh->hw_tf->write_reg( - dev, - cfg->hw.anym_on_int1 ? LIS2DH_REG_INT1_CFG : LIS2DH_REG_INT2_CFG, - 0); + status = lis2dh->hw_tf->write_reg(dev, + cfg->hw.anym_on_int1 ? + LIS2DH_REG_INT1_CFG : + LIS2DH_REG_INT2_CFG, + 0); + /* disable any click interrupt events */ + status = lis2dh->hw_tf->write_reg(dev, + LIS2DH_REG_CFG_CLICK, + 0); /* make sure any pending interrupt is cleared */ - status = lis2dh->hw_tf->read_reg( - dev, - cfg->hw.anym_on_int1 ? LIS2DH_REG_INT1_SRC : LIS2DH_REG_INT2_SRC, - ®_val); + status = lis2dh->hw_tf->read_reg(dev, + cfg->hw.anym_on_int1 ? + LIS2DH_REG_INT1_SRC : + LIS2DH_REG_INT2_SRC, + ®_val); + status = lis2dh->hw_tf->read_reg(dev, + LIS2DH_REG_CLICK_SRC, + ®_val); + + if (trig->type == SENSOR_TRIG_DELTA) { + lis2dh->handler_anymotion = handler; + lis2dh->trig_anymotion = trig; + } else if (trig->type == SENSOR_TRIG_TAP) { + lis2dh->handler_tap = handler; + lis2dh->trig_tap = trig; + } - lis2dh->handler_anymotion = handler; - lis2dh->trig_anymotion = trig; if ((handler == NULL) || (status < 0)) { return status; } @@ -181,17 +197,71 @@ static int lis2dh_trigger_anym_set(const struct device *dev, return 0; } +static int lis2dh_trigger_anym_set(const struct device *dev, + sensor_trigger_handler_t handler, + const struct sensor_trigger *trig) +{ + return lis2dh_trigger_anym_tap_set(dev, handler, trig); +} + +static int lis2dh_trigger_tap_set(const struct device *dev, + sensor_trigger_handler_t handler, + const struct sensor_trigger *trig) +{ + return lis2dh_trigger_anym_tap_set(dev, handler, trig); +} + static int lis2dh_start_trigger_int2(const struct device *dev) { struct lis2dh_data *lis2dh = dev->data; const struct lis2dh_config *cfg = dev->config; + int status = 0; + uint8_t reg = 0, mask = 0, val = 0; setup_int2(dev, true); - return lis2dh->hw_tf->write_reg( - dev, - cfg->hw.anym_on_int1 ? LIS2DH_REG_INT1_CFG : LIS2DH_REG_INT2_CFG, - (cfg->hw.anym_mode << LIS2DH_INT_CFG_MODE_SHIFT) | LIS2DH_ANYM_CFG); + bool has_anyt = (lis2dh->handler_tap != NULL); + bool has_anym = (lis2dh->handler_anymotion != NULL); + + /* configure any motion interrupt */ + reg = cfg->hw.anym_on_int1 ? LIS2DH_REG_INT1_CFG : LIS2DH_REG_INT2_CFG; + val = (cfg->hw.anym_mode << LIS2DH_INT_CFG_MODE_SHIFT) | LIS2DH_ANYM_CFG; + status = lis2dh->hw_tf->write_reg(dev, reg, val); + if (status < 0) { + LOG_ERR("Failed to configure any motion interrupt"); + return status; + } + + /* enable any motion detection on int line */ + reg = cfg->hw.anym_on_int1 ? LIS2DH_REG_CTRL3 : LIS2DH_REG_CTRL6; + mask = cfg->hw.anym_on_int1 ? LIS2DH_EN_IA_INT1 : LIS2DH_EN_IA_INT2; + val = has_anym ? mask : 0; + status = lis2dh->hw_tf->update_reg(dev, reg, mask, val); + if (status < 0) { + LOG_ERR("Failed to enable any motion detection on int line"); + return status; + } + + /* configure tap interrupt on all axes */ + reg = LIS2DH_REG_CFG_CLICK; + mask = LIS2DH_EN_CLICK_XS | LIS2DH_EN_CLICK_YS | LIS2DH_EN_CLICK_ZS; + val = has_anyt ? mask : 0; + status = lis2dh->hw_tf->update_reg(dev, reg, mask, val); + if (status < 0) { + LOG_ERR("Failed to configure tap interrupt"); + return status; + } + + /* set click detection on int line */ + reg = cfg->hw.anym_on_int1 ? LIS2DH_REG_CTRL3 : LIS2DH_REG_CTRL6; + mask = cfg->hw.anym_on_int1 ? LIS2DH_EN_CLICK_INT1 : LIS2DH_EN_CLICK_INT2; + val = has_anyt ? mask : 0; + status = lis2dh->hw_tf->update_reg(dev, reg, mask, val); + if (status < 0) { + LOG_ERR("Failed to enable click detection on int line"); + return status; + } + return 0; } int lis2dh_trigger_set(const struct device *dev, @@ -203,6 +273,8 @@ int lis2dh_trigger_set(const struct device *dev, return lis2dh_trigger_drdy_set(dev, trig->chan, handler, trig); } else if (trig->type == SENSOR_TRIG_DELTA) { return lis2dh_trigger_anym_set(dev, handler, trig); + } else if (trig->type == SENSOR_TRIG_TAP) { + return lis2dh_trigger_tap_set(dev, handler, trig); } return -ENOTSUP; @@ -243,11 +315,17 @@ int lis2dh_acc_slope_config(const struct device *dev, LOG_INF("int2_ths=0x%x range_g=%d ums2=%u", reg_val, range_g, slope_th_ums2 - 1); + /* Configure threshold for the any motion recognition */ status = lis2dh->hw_tf->write_reg(dev, cfg->hw.anym_on_int1 ? - LIS2DH_REG_INT1_THS : - LIS2DH_REG_INT2_THS, + LIS2DH_REG_INT1_THS : + LIS2DH_REG_INT2_THS, reg_val); + + /* Configure threshold for the Click recognition */ + status = lis2dh->hw_tf->write_reg(dev, + LIS2DH_REG_CFG_CLICK_THS, + LIS2DH_CLICK_LIR | reg_val); } else { /* SENSOR_ATTR_SLOPE_DUR */ /* * slope duration is measured in number of samples: @@ -259,10 +337,16 @@ int lis2dh_acc_slope_config(const struct device *dev, LOG_INF("int2_dur=0x%x", val->val1); + /* Configure time limit for the any motion recognition */ status = lis2dh->hw_tf->write_reg(dev, cfg->hw.anym_on_int1 ? - LIS2DH_REG_INT1_DUR : - LIS2DH_REG_INT2_DUR, + LIS2DH_REG_INT1_DUR : + LIS2DH_REG_INT2_DUR, + val->val1); + + /* Configure time limit for the Click recognition */ + status = lis2dh->hw_tf->write_reg(dev, + LIS2DH_REG_TIME_LIMIT, val->val1); } @@ -358,7 +442,6 @@ static void lis2dh_thread_cb(const struct device *dev) TRIGGED_INT1)) { if (likely(lis2dh->handler_drdy != NULL)) { lis2dh->handler_drdy(dev, lis2dh->trig_drdy); - } /* Reactivate level triggered interrupt if handler did not @@ -374,7 +457,7 @@ static void lis2dh_thread_cb(const struct device *dev) if (cfg->gpio_int.port && atomic_test_and_clear_bit(&lis2dh->trig_flags, TRIGGED_INT2)) { - uint8_t reg_val; + uint8_t reg_val = 0; if (cfg->hw.anym_latch) { /* clear interrupt to de-assert int line */ @@ -387,18 +470,34 @@ static void lis2dh_thread_cb(const struct device *dev) LOG_ERR("clearing interrupt 2 failed: %d", status); return; } + } + + if (likely(lis2dh->handler_anymotion != NULL) && + (reg_val >> LIS2DH_INT_CFG_MODE_SHIFT)) { + lis2dh->handler_anymotion(dev, lis2dh->trig_anymotion); LOG_DBG("@tick=%u int2_src=0x%x", k_cycle_get_32(), reg_val); } - if (likely(lis2dh->handler_anymotion != NULL)) { - lis2dh->handler_anymotion(dev, lis2dh->trig_anymotion); + /* read click interrupt */ + status = lis2dh->hw_tf->read_reg(dev, LIS2DH_REG_CLICK_SRC, + ®_val); + if (status < 0) { + LOG_ERR("clearing interrupt 2 failed: %d", status); + return; + } + + if (likely(lis2dh->handler_tap != NULL) && + (reg_val & LIS2DH_CLICK_SRC_SCLICK)) { + lis2dh->handler_tap(dev, lis2dh->trig_tap); + + LOG_DBG("@tick=%u click_src=0x%x", k_cycle_get_32(), reg_val); } /* Reactivate level triggered interrupt if handler did not * disable itself */ - if (lis2dh->handler_anymotion != NULL) { + if (lis2dh->handler_anymotion || lis2dh->handler_tap) { setup_int2(dev, true); } @@ -522,49 +621,45 @@ check_gpio_int: } LOG_INF("%s: int2 on %s.%02u", dev->name, - cfg->gpio_int.port->name, - cfg->gpio_int.pin); + cfg->gpio_int.port->name, + cfg->gpio_int.pin); /* disable interrupt in case of warm (re)boot */ - status = lis2dh->hw_tf->write_reg( - dev, - cfg->hw.anym_on_int1 ? LIS2DH_REG_INT1_CFG : LIS2DH_REG_INT2_CFG, - 0); + status = lis2dh->hw_tf->write_reg(dev, + cfg->hw.anym_on_int1 ? + LIS2DH_REG_INT1_CFG : + LIS2DH_REG_INT2_CFG, + 0); + if (status < 0) { + LOG_ERR("Interrupt disable reg write failed (%d)", status); + return status; + } + status = lis2dh->hw_tf->write_reg(dev, + LIS2DH_REG_CFG_CLICK, + 0); if (status < 0) { LOG_ERR("Interrupt disable reg write failed (%d)", status); return status; } (void)memset(raw, 0, sizeof(raw)); - status = lis2dh->hw_tf->write_data( - dev, - cfg->hw.anym_on_int1 ? LIS2DH_REG_INT1_THS : LIS2DH_REG_INT2_THS, - raw, sizeof(raw)); + status = lis2dh->hw_tf->write_data(dev, + cfg->hw.anym_on_int1 ? + LIS2DH_REG_INT1_THS : + LIS2DH_REG_INT2_THS, + raw, sizeof(raw)); if (status < 0) { LOG_ERR("Burst write to THS failed (%d)", status); return status; } - if (cfg->hw.anym_on_int1) { - /* enable interrupt 1 on int1 line */ - status = lis2dh->hw_tf->update_reg(dev, LIS2DH_REG_CTRL3, - LIS2DH_EN_INT1_INT1, - LIS2DH_EN_INT1_INT1); - if (cfg->hw.anym_latch) { - /* latch int1 line interrupt */ - status = lis2dh->hw_tf->write_reg(dev, LIS2DH_REG_CTRL5, - LIS2DH_EN_LIR_INT1); - } - } else { - /* enable interrupt 2 on int2 line */ - status = lis2dh->hw_tf->update_reg(dev, LIS2DH_REG_CTRL6, - LIS2DH_EN_INT2_INT2, - LIS2DH_EN_INT2_INT2); - if (cfg->hw.anym_latch) { - /* latch int2 line interrupt */ - status = lis2dh->hw_tf->write_reg(dev, LIS2DH_REG_CTRL5, - LIS2DH_EN_LIR_INT2); - } + if (cfg->hw.anym_latch) { + /* latch line interrupt */ + status = lis2dh->hw_tf->write_reg(dev, + LIS2DH_REG_CTRL5, + cfg->hw.anym_on_int1 ? + LIS2DH_EN_LIR_INT1 : + LIS2DH_EN_LIR_INT2); } if (status < 0) {