diff --git a/drivers/sensor/lis2dw12/Kconfig b/drivers/sensor/lis2dw12/Kconfig index 74ad833efc133..47ee8ac608599 100644 --- a/drivers/sensor/lis2dw12/Kconfig +++ b/drivers/sensor/lis2dw12/Kconfig @@ -52,6 +52,11 @@ config LIS2DW12_THREAD_STACK_SIZE help Stack size of thread used by the driver to handle interrupts. +config LIS2DW12_TAP + bool "Single/Double Tap recognition" + help + Enable Single/Double Tap recognition + choice prompt "Sensor INT pin number" default LIS2DW12_INT_PIN_1 diff --git a/drivers/sensor/lis2dw12/lis2dw12.c b/drivers/sensor/lis2dw12/lis2dw12.c index ab16ffd8d222b..644e07a606577 100644 --- a/drivers/sensor/lis2dw12/lis2dw12.c +++ b/drivers/sensor/lis2dw12/lis2dw12.c @@ -50,6 +50,10 @@ static int lis2dw12_set_range(struct device *dev, u16_t range) lis2dw12->gain = LIS2DW12_FS_TO_GAIN(LIS2DW12_FS_TO_REG(range), shift_gain); +#ifdef CONFIG_LIS2DW12_TAP + lis2dw12->tap_ths = + LIS2DW12_FS_TO_TAP_THS(LIS2DW12_FS_TO_REG(range)); +#endif /* CONFIG_LIS2DW12_TAP */ } return err; @@ -63,6 +67,7 @@ static int lis2dw12_set_range(struct device *dev, u16_t range) static int lis2dw12_set_odr(struct device *dev, u16_t odr) { struct lis2dw12_data *lis2dw12 = dev->driver_data; + const struct lis2dw12_device_config *cfg = dev->config->config_info; /* check if power off */ if (odr == 0) { @@ -72,7 +77,8 @@ static int lis2dw12_set_odr(struct device *dev, u16_t odr) LIS2DW12_ODR_POWER_OFF_VAL); } - if (odr > LIS2DW12_MAX_ODR) { + if (odr > LIS2DW12_MAX_ODR || + (odr > 200 && cfg->pm != LIS2DW12_HIGH_PERF)) { LOG_ERR("ODR too high"); return -ENOTSUP; } @@ -194,7 +200,7 @@ static int lis2dw12_sample_fetch(struct device *dev, enum sensor_channel chan) return -EIO; } - if (!(tmp & LIS2DW12_STS_XLDA_UP)) { + if (!(tmp & LIS2DW12_STS_DRDY)) { return -EAGAIN; } @@ -335,6 +341,10 @@ static int lis2dw12_init(struct device *dev) cfg->pm == LIS2DW12_LOW_POWER_M1 ? LIS2DW12_SHFT_GAIN_NOLP1 : 0); +#ifdef CONFIG_LIS2DW12_TAP + lis2dw12->tap_ths = LIS2DW12_FS_TO_TAP_THS(LIS2DW12_ACC_FS); +#endif /* CONFIG_LIS2DW12_TAP */ + #ifdef CONFIG_LIS2DW12_TRIGGER if (lis2dw12_init_interrupt(dev) < 0) { LOG_ERR("Failed to initialize interrupts"); diff --git a/drivers/sensor/lis2dw12/lis2dw12.h b/drivers/sensor/lis2dw12/lis2dw12.h index ef327139e086c..3f4df6dc59c1d 100644 --- a/drivers/sensor/lis2dw12/lis2dw12.h +++ b/drivers/sensor/lis2dw12/lis2dw12.h @@ -94,13 +94,16 @@ enum lis2dh_odr { #define LIS2DW12_LIR_MASK BIT(4) #define LIS2DW12_CTRL4_ADDR 0x23 +#define LIS2DW12_INT1_STAP BIT(6) +#define LIS2DW12_INT1_DTAP BIT(3) #define LIS2DW12_INT1_DRDY BIT(0) #define LIS2DW12_CTRL5_ADDR 0x24 #define LIS2DW12_INT2_DRDY BIT(0) #define LIS2DW12_CTRL6_ADDR 0x25 -#define LIS2DW12_FS_MASK 0x30 +#define LIS2DW12_FS_MASK (BIT(5) | BIT(4)) +#define LIS2DW12_LOW_NOISE_MASK BIT(2) enum lis2dh_fs { LIS2DW12_FS_2G_VAL, @@ -126,7 +129,9 @@ enum lis2dh_fs { #define LIS2DW12_OUT_T_REG 0x26 #define LIS2DW12_STATUS_REG 0x27 -#define LIS2DW12_STS_XLDA_UP 0x01 +#define LIS2DW12_STS_DTAP BIT(4) +#define LIS2DW12_STS_STAP BIT(3) +#define LIS2DW12_STS_DRDY BIT(0) #define LIS2DW12_OUT_X_L_ADDR 0x28 @@ -145,6 +150,37 @@ enum lis2dh_fs { #define LIS2DW12_SHIFT_PM1 4 #define LIS2DW12_SHIFT_PMOTHER 2 +#define LIS2DW12_TAP_THS_X 0x30 +#define LIS2DW12_TAP_THS_Y 0x31 +#define LIS2DW12_TAP_THS_Z 0x32 +/* in TAP_THS_Y register */ +#define LIS2DW12_TAP_PRI_MASK (BIT(7) | BIT(6) | BIT(5)) +/* in TAP_THS_Z register */ +#define LIS2DW12_TAP_EN_MASK (BIT(7) | BIT(6) | BIT(5)) +/* in TAP_THS_X/Y/Z registers */ +#define LIS2DW12_TAP_THS_MASK (BIT(4) | BIT(3) | BIT(2) | \ + BIT(1) | BIT(0)) + +#define LIS2DW12_FS_2G_THS 9 +#define LIS2DW12_FS_TO_TAP_THS(_fs) (LIS2DW12_FS_2G_THS >> ((_fs))) + +#define LIS2DW12_INT_DUR 0x33 +#define LIS2DW12_LATENCY_MASK (BIT(7) | BIT(6) | \ + BIT(5) | BIT(4)) +#define LIS2DW12_LATENCY_SHIFT 4 +#define LIS2DW12_QUIET_MASK (BIT(3) | BIT(2)) +#define LIS2DW12_QUIET_SHIFT 2 +#define LIS2DW12_SHOCK_MASK (BIT(1) | BIT(0)) +#define LIS2DW12_SHOCK_SHIFT 0 + +#define LIS2DW12_WAKE_UP_THS 0x34 +#define LIS2DW12_DTAP_MASK BIT(7) + +#define LIS2DW12_TAP_SRC 0x39 + +#define LIS2DW12_CTRL7_ADDR 0x3F +#define LIS2DW12_INTS_ENABLED BIT(5) + /** * struct lis2dw12_device_config - lis2dw12 hw configuration * @bus_name: Pointer to bus master identifier. @@ -193,6 +229,7 @@ struct lis2dw12_data { struct device *gpio; struct gpio_callback gpio_cb; sensor_trigger_handler_t handler_drdy; + sensor_trigger_handler_t handler_tap; #if defined(CONFIG_LIS2DW12_TRIGGER_OWN_THREAD) K_THREAD_STACK_MEMBER(thread_stack, CONFIG_LIS2DW12_THREAD_STACK_SIZE); @@ -202,6 +239,11 @@ struct lis2dw12_data { struct k_work work; struct device *dev; #endif /* CONFIG_LIS2DW12_TRIGGER_GLOBAL_THREAD */ + +#ifdef CONFIG_LIS2DW12_TAP + u8_t tap_ths; +#endif /* CONFIG_LIS2DW12_TAP */ + #endif /* CONFIG_LIS2DW12_TRIGGER */ #if defined(DT_ST_LIS2DW12_0_CS_GPIO_CONTROLLER) struct spi_cs_control cs_ctrl; diff --git a/drivers/sensor/lis2dw12/lis2dw12_trigger.c b/drivers/sensor/lis2dw12/lis2dw12_trigger.c index 1bd8ac9166d99..4b0598dc9c6ed 100644 --- a/drivers/sensor/lis2dw12/lis2dw12_trigger.c +++ b/drivers/sensor/lis2dw12/lis2dw12_trigger.c @@ -19,9 +19,9 @@ LOG_MODULE_DECLARE(LIS2DW12); /** - * lis2dw12_enable_int - enable selected int pin to generate interrupt + * lis2dw12_enable_drdy - enable selected int pin to generate DRDY interrupt */ -static int lis2dw12_enable_int(struct device *dev, int enable) +static int lis2dw12_enable_drdy(struct device *dev, int enable) { const struct lis2dw12_device_config *cfg = dev->config->config_info; struct lis2dw12_data *lis2dw12 = dev->driver_data; @@ -39,6 +39,85 @@ static int lis2dw12_enable_int(struct device *dev, int enable) enable); } +#ifdef CONFIG_LIS2DW12_TAP +/* + * lis2dw12_enable_tap - enable single or double tap event + * (odr >= 400Hz) + */ +static int lis2dw12_enable_tap(struct device *dev, u8_t dtap, u8_t enable) +{ + u8_t tmp; + u8_t int_dur, tap_int; + struct lis2dw12_data *lis2dw12 = dev->driver_data; + + if (dtap) { + int_dur = 0x7f; /* latency = 7, shock = 3, quiet = 3 */ + tap_int = LIS2DW12_INT1_DTAP; + } else { + int_dur = 0x06; /* latency = 0, shock = 2, quiet = 1 */ + tap_int = LIS2DW12_INT1_STAP; + } + + /* enable LOW noise */ + if (lis2dw12->hw_tf->update_reg(lis2dw12, LIS2DW12_CTRL6_ADDR, + LIS2DW12_LOW_NOISE_MASK, 1)) { + LOG_ERR("enable low noise error"); + return -EIO; + } + + /* Set tap threshold for X axis. */ + if (lis2dw12->hw_tf->update_reg(lis2dw12, LIS2DW12_TAP_THS_X, + LIS2DW12_TAP_THS_MASK, + lis2dw12->tap_ths)) { + LOG_ERR("set x-threshold error"); + return -EIO; + } + + /* Set tap threshold for Y axis and TAP priority Z-Y-X. */ + tmp = (0xE0 | ((lis2dw12->tap_ths) & (LIS2DW12_TAP_THS_MASK))); + if (lis2dw12->hw_tf->write_reg(lis2dw12, LIS2DW12_TAP_THS_Y, tmp)) { + LOG_ERR("set y-threshold error"); + return -EIO; + } + + /* Set tap threshold for Z axis and tap detection on X, Y, Z-axis */ + tmp = (0xE0 | ((lis2dw12->tap_ths) & (LIS2DW12_TAP_THS_MASK))); + if (lis2dw12->hw_tf->write_reg(lis2dw12, LIS2DW12_TAP_THS_Z, tmp)) { + LOG_ERR("set z-threshold error"); + return -EIO; + } + + /* Set interrupt duration params (latency/quiet/shock time windows */ + if (lis2dw12->hw_tf->write_reg(lis2dw12, LIS2DW12_INT_DUR, int_dur)) { + LOG_ERR("set int duration error"); + return -EIO; + } + + /* Enable single-tap or double-tap event */ + if (lis2dw12->hw_tf->update_reg(lis2dw12, LIS2DW12_WAKE_UP_THS, + LIS2DW12_DTAP_MASK, dtap)) { + LOG_ERR("enable single/double tap event error"); + return -EIO; + } + + /* Enable single-tap or double-tap interrupt */ + if (lis2dw12->hw_tf->update_reg(lis2dw12, LIS2DW12_CTRL4_ADDR, + tap_int, enable)) { + LOG_ERR("enable single/double tap int error"); + return -EIO; + } + + /* Enable algo interrupts */ + if (lis2dw12->hw_tf->update_reg(lis2dw12, LIS2DW12_CTRL7_ADDR, + LIS2DW12_INTS_ENABLED, enable)) { + LOG_ERR("enable algo int error"); + return -EIO; + } + + return 0; +} +#endif /* CONFIG_LIS2DW12_TAP */ + /** * lis2dw12_trigger_set - link external trigger to event data ready */ @@ -49,18 +128,29 @@ int lis2dw12_trigger_set(struct device *dev, struct lis2dw12_data *lis2dw12 = dev->driver_data; u8_t raw[6]; - if (trig->chan == SENSOR_CHAN_ACCEL_XYZ) { + if (trig->type == SENSOR_TRIG_DATA_READY) { lis2dw12->handler_drdy = handler; if (handler) { /* dummy read: re-trigger interrupt */ lis2dw12->hw_tf->read_data(lis2dw12, LIS2DW12_OUT_X_L_ADDR, raw, sizeof(raw)); - return lis2dw12_enable_int(dev, LIS2DW12_EN_BIT); + return lis2dw12_enable_drdy(dev, LIS2DW12_EN_BIT); } else { - return lis2dw12_enable_int(dev, LIS2DW12_DIS_BIT); + return lis2dw12_enable_drdy(dev, LIS2DW12_DIS_BIT); } } +#ifdef CONFIG_LIS2DW12_TAP + else if (trig->type == SENSOR_TRIG_TAP) { + lis2dw12->handler_tap = handler; + + return lis2dw12_enable_tap(dev, 0, (handler) ? 1 : 0); + } else if (trig->type == SENSOR_TRIG_DOUBLE_TAP) { + lis2dw12->handler_tap = handler; + + return lis2dw12_enable_tap(dev, 1, (handler) ? 1 : 0); + } +#endif /* CONFIG_LIS2DW12_TAP */ return -ENOTSUP; } @@ -71,15 +161,36 @@ int lis2dw12_trigger_set(struct device *dev, */ static void lis2dw12_handle_interrupt(void *arg) { + u8_t status; struct device *dev = arg; struct lis2dw12_data *lis2dw12 = dev->driver_data; - struct sensor_trigger drdy_trigger = { - .type = SENSOR_TRIG_DATA_READY, - }; const struct lis2dw12_device_config *cfg = dev->config->config_info; + struct sensor_trigger trigger; + + if (lis2dw12->hw_tf->read_reg(lis2dw12, + LIS2DW12_STATUS_REG, + &status) < 0) { + LOG_ERR("status reading error"); + } + + if ((status & LIS2DW12_STS_DRDY) && + (lis2dw12->handler_drdy != NULL)) { + trigger.type = SENSOR_TRIG_DATA_READY; + lis2dw12->handler_drdy(dev, &trigger); + } + + if ((status & LIS2DW12_STS_STAP) && + (lis2dw12->handler_tap != NULL)) { + trigger.type = SENSOR_TRIG_TAP; + lis2dw12->hw_tf->read_reg(lis2dw12, LIS2DW12_TAP_SRC, &status); + lis2dw12->handler_tap(dev, &trigger); + } - if (lis2dw12->handler_drdy != NULL) { - lis2dw12->handler_drdy(dev, &drdy_trigger); + if ((status & LIS2DW12_STS_DTAP) && + (lis2dw12->handler_tap != NULL)) { + trigger.type = SENSOR_TRIG_DOUBLE_TAP; + lis2dw12->hw_tf->read_reg(lis2dw12, LIS2DW12_TAP_SRC, &status); + lis2dw12->handler_tap(dev, &trigger); } gpio_pin_enable_callback(lis2dw12->gpio, cfg->int_gpio_pin); @@ -172,9 +283,9 @@ int lis2dw12_init_interrupt(struct device *dev) return -EIO; } - /* enable interrupt on int1/int2 in pulse mode */ + /* enable interrupt on int1/int2 in lir mode */ if (lis2dw12->hw_tf->update_reg(lis2dw12, LIS2DW12_CTRL3_ADDR, - LIS2DW12_LIR_MASK, LIS2DW12_DIS_BIT)) { + LIS2DW12_LIR_MASK, 1)) { return -EIO; }