driver/sensor: lis2dw12: single/double tap trigger implementation
Implementation for two new interrupt triggers: single tap and double tap. Add new Kconfig options to configure those triggers: trigger mode (single/single and double), latency/quiet/shock time, threshold levels, active axes. Signed-off-by: Michał Oleszczyk <oleszczyk.m@gmail.com>
This commit is contained in:
parent
58b46d7089
commit
e4ed17472f
4 changed files with 296 additions and 27 deletions
|
@ -68,6 +68,94 @@ config LIS2DW12_INT_PIN_2
|
|||
bool "int2"
|
||||
endchoice
|
||||
|
||||
menuconfig LIS2DW12_PULSE
|
||||
bool "Pulse detection"
|
||||
help
|
||||
Enable pulse (single/double tap) detection
|
||||
|
||||
if LIS2DW12_PULSE
|
||||
|
||||
choice
|
||||
prompt "Pulse interrupt source"
|
||||
default LIS2DW12_ONLY_SINGLE
|
||||
|
||||
config LIS2DW12_ONLY_SINGLE
|
||||
bool "single"
|
||||
|
||||
config LIS2DW12_SINGLE_DOUBLE
|
||||
bool "single/double"
|
||||
|
||||
endchoice
|
||||
|
||||
config LIS2DW12_PULSE_THSX
|
||||
hex "Pulse X-axis threshold"
|
||||
range 0 0x1F
|
||||
default 0x0E
|
||||
help
|
||||
Threshold to start the pulse-event detection procedure on the X-axis.
|
||||
Threshold values for each axis are unsigned 5-bit corresponding
|
||||
to an 2g acceleration full-scale range.
|
||||
|
||||
config LIS2DW12_PULSE_THSY
|
||||
hex "Pulse Y-axis threshold"
|
||||
range 0 0x1F
|
||||
default 0x0E
|
||||
help
|
||||
Threshold to start the pulse-event detection procedure on the Y-axis.
|
||||
Threshold values for each axis are unsigned 5-bit corresponding
|
||||
to an 2g acceleration full-scale range.
|
||||
|
||||
config LIS2DW12_PULSE_THSZ
|
||||
hex "Pulse Z-axis threshold"
|
||||
range 0 0x1F
|
||||
default 0x0E
|
||||
help
|
||||
Threshold to start the pulse-event detection procedure on the Z-axis.
|
||||
Threshold values for each axis are unsigned 5-bit corresponding
|
||||
to an 2g acceleration full-scale range.
|
||||
|
||||
config LIS2DW12_PULSE_X
|
||||
bool "Enable X axis for pulse"
|
||||
default y
|
||||
|
||||
config LIS2DW12_PULSE_Y
|
||||
bool "Enable Y axis for pulse"
|
||||
default y
|
||||
|
||||
config LIS2DW12_PULSE_Z
|
||||
bool "Enable Z axis for pulse"
|
||||
default y
|
||||
|
||||
config LIS2DW12_PULSE_SHOCK
|
||||
hex "Shock value"
|
||||
range 0 0x03
|
||||
default 0x00
|
||||
help
|
||||
Maximum duration of over-threshold event: 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.
|
||||
|
||||
config LIS2DW12_PULSE_LTNCY
|
||||
hex "Latency value"
|
||||
range 0 0x0F
|
||||
default 0x05
|
||||
help
|
||||
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.
|
||||
|
||||
config LIS2DW12_PULSE_QUIET
|
||||
hex "Quiet value"
|
||||
range 0 0x03
|
||||
default 0x00
|
||||
help
|
||||
Expected quiet time after a tap detection: 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.
|
||||
|
||||
endif # LIS2DW12_PULSE
|
||||
|
||||
endif # LIS2DW12_TRIGGER
|
||||
|
||||
choice
|
||||
|
|
|
@ -308,6 +308,64 @@ static int lis2dw12_init(struct device *dev)
|
|||
LOG_ERR("Failed to initialize interrupts");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LIS2DW12_PULSE
|
||||
if (lis2dw12_tap_mode_set(lis2dw12->ctx, cfg->pulse_trigger) < 0) {
|
||||
LOG_ERR("Failed to select pulse trigger mode");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (lis2dw12_tap_threshold_x_set(lis2dw12->ctx,
|
||||
cfg->pulse_ths[0]) < 0) {
|
||||
LOG_ERR("Failed to set tap X axis threshold");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (lis2dw12_tap_threshold_y_set(lis2dw12->ctx,
|
||||
cfg->pulse_ths[1]) < 0) {
|
||||
LOG_ERR("Failed to set tap Y axis threshold");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (lis2dw12_tap_threshold_z_set(lis2dw12->ctx,
|
||||
cfg->pulse_ths[2]) < 0) {
|
||||
LOG_ERR("Failed to set tap Z axis threshold");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (lis2dw12_tap_detection_on_x_set(lis2dw12->ctx,
|
||||
CONFIG_LIS2DW12_PULSE_X) < 0) {
|
||||
LOG_ERR("Failed to set tap detection on X axis");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (lis2dw12_tap_detection_on_y_set(lis2dw12->ctx,
|
||||
CONFIG_LIS2DW12_PULSE_Y) < 0) {
|
||||
LOG_ERR("Failed to set tap detection on Y axis");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (lis2dw12_tap_detection_on_z_set(lis2dw12->ctx,
|
||||
CONFIG_LIS2DW12_PULSE_Z) < 0) {
|
||||
LOG_ERR("Failed to set tap detection on Z axis");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (lis2dw12_tap_shock_set(lis2dw12->ctx, cfg->pulse_shock) < 0) {
|
||||
LOG_ERR("Failed to set tap shock duration");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (lis2dw12_tap_dur_set(lis2dw12->ctx, cfg->pulse_ltncy) < 0) {
|
||||
LOG_ERR("Failed to set tap latency");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (lis2dw12_tap_quiet_set(lis2dw12->ctx, cfg->pulse_quiet) < 0) {
|
||||
LOG_ERR("Failed to set tap quiet time");
|
||||
return -EIO;
|
||||
}
|
||||
#endif /* CONFIG_LIS2DW12_PULSE */
|
||||
#endif /* CONFIG_LIS2DW12_TRIGGER */
|
||||
|
||||
return 0;
|
||||
|
@ -325,6 +383,19 @@ const struct lis2dw12_device_config lis2dw12_cfg = {
|
|||
.int_pin = 2,
|
||||
#endif /* CONFIG_LIS2DW12_INT_PIN */
|
||||
|
||||
#ifdef CONFIG_LIS2DW12_PULSE
|
||||
#if defined(CONFIG_LIS2DW12_ONLY_SINGLE)
|
||||
.pulse_trigger = LIS2DW12_ONLY_SINGLE,
|
||||
#elif defined(CONFIG_LIS2DW12_SINGLE_DOUBLE)
|
||||
.pulse_trigger = LIS2DW12_BOTH_SINGLE_DOUBLE,
|
||||
#endif
|
||||
.pulse_ths[0] = CONFIG_LIS2DW12_PULSE_THSX,
|
||||
.pulse_ths[1] = CONFIG_LIS2DW12_PULSE_THSY,
|
||||
.pulse_ths[2] = CONFIG_LIS2DW12_PULSE_THSZ,
|
||||
.pulse_shock = CONFIG_LIS2DW12_PULSE_SHOCK,
|
||||
.pulse_ltncy = CONFIG_LIS2DW12_PULSE_LTNCY,
|
||||
.pulse_quiet = CONFIG_LIS2DW12_PULSE_QUIET,
|
||||
#endif /* CONFIG_LIS2DW12_PULSE */
|
||||
#endif /* CONFIG_LIS2DW12_TRIGGER */
|
||||
};
|
||||
|
||||
|
|
|
@ -88,6 +88,13 @@ struct lis2dw12_device_config {
|
|||
const char *int_gpio_port;
|
||||
u8_t int_gpio_pin;
|
||||
u8_t int_pin;
|
||||
#ifdef CONFIG_LIS2DW12_PULSE
|
||||
u8_t pulse_trigger;
|
||||
u8_t pulse_ths[3];
|
||||
u8_t pulse_shock;
|
||||
u8_t pulse_ltncy;
|
||||
u8_t pulse_quiet;
|
||||
#endif /* CONFIG_LIS2DW12_PULSE */
|
||||
#endif /* CONFIG_LIS2DW12_TRIGGER */
|
||||
};
|
||||
|
||||
|
@ -106,8 +113,11 @@ struct lis2dw12_data {
|
|||
#ifdef CONFIG_LIS2DW12_TRIGGER
|
||||
struct device *gpio;
|
||||
struct gpio_callback gpio_cb;
|
||||
sensor_trigger_handler_t handler_drdy;
|
||||
|
||||
sensor_trigger_handler_t drdy_handler;
|
||||
#ifdef CONFIG_LIS2DW12_PULSE
|
||||
sensor_trigger_handler_t tap_handler;
|
||||
sensor_trigger_handler_t double_tap_handler;
|
||||
#endif /* CONFIG_LIS2DW12_PULSE */
|
||||
#if defined(CONFIG_LIS2DW12_TRIGGER_OWN_THREAD)
|
||||
K_THREAD_STACK_MEMBER(thread_stack, CONFIG_LIS2DW12_THREAD_STACK_SIZE);
|
||||
struct k_thread thread;
|
||||
|
|
|
@ -21,26 +21,54 @@ LOG_MODULE_DECLARE(LIS2DW12);
|
|||
/**
|
||||
* lis2dw12_enable_int - enable selected int pin to generate interrupt
|
||||
*/
|
||||
static int lis2dw12_enable_int(struct device *dev, int enable)
|
||||
static int lis2dw12_enable_int(struct device *dev,
|
||||
enum sensor_trigger_type type, int enable)
|
||||
{
|
||||
const struct lis2dw12_device_config *cfg = dev->config->config_info;
|
||||
struct lis2dw12_data *lis2dw12 = dev->driver_data;
|
||||
lis2dw12_reg_t int_route;
|
||||
|
||||
/* set interrupt */
|
||||
if (cfg->int_pin == 1U) {
|
||||
/* set interrupt for pin INT1 */
|
||||
lis2dw12_pin_int1_route_get(lis2dw12->ctx,
|
||||
&int_route.ctrl4_int1_pad_ctrl);
|
||||
int_route.ctrl4_int1_pad_ctrl.int1_drdy = enable;
|
||||
return lis2dw12_pin_int1_route_set(lis2dw12->ctx,
|
||||
&int_route.ctrl4_int1_pad_ctrl);
|
||||
}
|
||||
&int_route.ctrl4_int1_pad_ctrl);
|
||||
|
||||
lis2dw12_pin_int2_route_get(lis2dw12->ctx,
|
||||
&int_route.ctrl5_int2_pad_ctrl);
|
||||
int_route.ctrl5_int2_pad_ctrl.int2_drdy = enable;
|
||||
return lis2dw12_pin_int2_route_set(lis2dw12->ctx,
|
||||
&int_route.ctrl5_int2_pad_ctrl);
|
||||
switch (type) {
|
||||
case SENSOR_TRIG_DATA_READY:
|
||||
int_route.ctrl4_int1_pad_ctrl.int1_drdy = enable;
|
||||
break;
|
||||
#ifdef CONFIG_LIS2DW12_PULSE
|
||||
case SENSOR_TRIG_TAP:
|
||||
int_route.ctrl4_int1_pad_ctrl.int1_single_tap = enable;
|
||||
break;
|
||||
case SENSOR_TRIG_DOUBLE_TAP:
|
||||
int_route.ctrl4_int1_pad_ctrl.int1_tap = enable;
|
||||
break;
|
||||
#endif /* CONFIG_LIS2DW12_PULSE */
|
||||
default:
|
||||
LOG_ERR("Unsupported trigger interrupt route");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return lis2dw12_pin_int1_route_set(lis2dw12->ctx,
|
||||
&int_route.ctrl4_int1_pad_ctrl);
|
||||
} else {
|
||||
/* set interrupt for pin INT2 */
|
||||
lis2dw12_pin_int2_route_get(lis2dw12->ctx,
|
||||
&int_route.ctrl5_int2_pad_ctrl);
|
||||
|
||||
switch (type) {
|
||||
case SENSOR_TRIG_DATA_READY:
|
||||
int_route.ctrl5_int2_pad_ctrl.int2_drdy = enable;
|
||||
break;
|
||||
default:
|
||||
LOG_ERR("Unsupported trigger interrupt route");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return lis2dw12_pin_int2_route_set(lis2dw12->ctx,
|
||||
&int_route.ctrl5_int2_pad_ctrl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -52,37 +80,109 @@ int lis2dw12_trigger_set(struct device *dev,
|
|||
{
|
||||
struct lis2dw12_data *lis2dw12 = dev->driver_data;
|
||||
axis3bit16_t raw;
|
||||
int state = (handler != NULL) ? PROPERTY_ENABLE : PROPERTY_DISABLE;
|
||||
|
||||
if (trig->chan == SENSOR_CHAN_ACCEL_XYZ) {
|
||||
lis2dw12->handler_drdy = handler;
|
||||
if (handler) {
|
||||
switch (trig->type) {
|
||||
case SENSOR_TRIG_DATA_READY:
|
||||
lis2dw12->drdy_handler = handler;
|
||||
if (state) {
|
||||
/* dummy read: re-trigger interrupt */
|
||||
lis2dw12_acceleration_raw_get(lis2dw12->ctx, raw.u8bit);
|
||||
return lis2dw12_enable_int(dev, PROPERTY_ENABLE);
|
||||
} else {
|
||||
return lis2dw12_enable_int(dev, PROPERTY_DISABLE);
|
||||
}
|
||||
return lis2dw12_enable_int(dev, SENSOR_TRIG_DATA_READY, state);
|
||||
break;
|
||||
#ifdef CONFIG_LIS2DW12_PULSE
|
||||
case SENSOR_TRIG_TAP:
|
||||
lis2dw12->tap_handler = handler;
|
||||
return lis2dw12_enable_int(dev, SENSOR_TRIG_TAP, state);
|
||||
break;
|
||||
case SENSOR_TRIG_DOUBLE_TAP:
|
||||
lis2dw12->double_tap_handler = handler;
|
||||
return lis2dw12_enable_int(dev, SENSOR_TRIG_DOUBLE_TAP, state);
|
||||
break;
|
||||
#endif /* CONFIG_LIS2DW12_PULSE */
|
||||
default:
|
||||
LOG_ERR("Unsupported sensor trigger");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
}
|
||||
|
||||
static int lis2dw12_handle_drdy_int(struct device *dev)
|
||||
{
|
||||
struct lis2dw12_data *data = dev->driver_data;
|
||||
|
||||
struct sensor_trigger drdy_trig = {
|
||||
.type = SENSOR_TRIG_DATA_READY,
|
||||
.chan = SENSOR_CHAN_ALL,
|
||||
};
|
||||
|
||||
if (data->drdy_handler) {
|
||||
data->drdy_handler(dev, &drdy_trig);
|
||||
}
|
||||
|
||||
return -ENOTSUP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LIS2DW12_PULSE
|
||||
static int lis2dw12_handle_single_tap_int(struct device *dev)
|
||||
{
|
||||
struct lis2dw12_data *data = dev->driver_data;
|
||||
sensor_trigger_handler_t handler = data->tap_handler;;
|
||||
|
||||
struct sensor_trigger pulse_trig = {
|
||||
.type = SENSOR_TRIG_TAP,
|
||||
.chan = SENSOR_CHAN_ALL,
|
||||
};
|
||||
|
||||
if (handler) {
|
||||
handler(dev, &pulse_trig);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lis2dw12_handle_double_tap_int(struct device *dev)
|
||||
{
|
||||
struct lis2dw12_data *data = dev->driver_data;
|
||||
sensor_trigger_handler_t handler = data->double_tap_handler;;
|
||||
|
||||
struct sensor_trigger pulse_trig = {
|
||||
.type = SENSOR_TRIG_DOUBLE_TAP,
|
||||
.chan = SENSOR_CHAN_ALL,
|
||||
};
|
||||
|
||||
if (handler) {
|
||||
handler(dev, &pulse_trig);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_LIS2DW12_PULSE */
|
||||
|
||||
/**
|
||||
* lis2dw12_handle_interrupt - handle the drdy event
|
||||
* read data and call handler if registered any
|
||||
*/
|
||||
static void lis2dw12_handle_interrupt(void *arg)
|
||||
{
|
||||
struct device *dev = arg;
|
||||
struct device *dev = (struct device *)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;
|
||||
lis2dw12_all_sources_t sources;
|
||||
|
||||
if (lis2dw12->handler_drdy != NULL) {
|
||||
lis2dw12->handler_drdy(dev, &drdy_trigger);
|
||||
lis2dw12_all_sources_get(lis2dw12->ctx, &sources);
|
||||
|
||||
if (sources.status_dup.drdy) {
|
||||
lis2dw12_handle_drdy_int(dev);
|
||||
}
|
||||
#ifdef CONFIG_LIS2DW12_PULSE
|
||||
if (sources.status_dup.single_tap) {
|
||||
lis2dw12_handle_single_tap_int(dev);
|
||||
}
|
||||
if (sources.status_dup.double_tap) {
|
||||
lis2dw12_handle_double_tap_int(dev);
|
||||
}
|
||||
#endif /* CONFIG_LIS2DW12_PULSE */
|
||||
|
||||
gpio_pin_enable_callback(lis2dw12->gpio, cfg->int_gpio_pin);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue