drivers: sensor: lis2dh: add tap interrupt
add interrupt for single tap on ST LIS2DH shared interrupt with any motion Signed-off-by: Mathias Storck <mathias.storck@gwa-hygiene.de>
This commit is contained in:
parent
b0b32c5701
commit
4431c4755c
2 changed files with 182 additions and 75 deletions
|
@ -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;
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue