drivers: sensors: lis2dh: Allow any movement on interrupt 1

Allow movement detection to be used on hardware
that only has one interrupt line connected.
Change hardware configuration to a bitmask.

Signed-off-by: Andrew Hedin <andrew.hedin@lairdconnect.com>
This commit is contained in:
Andrew Hedin 2021-09-27 16:37:20 -05:00 committed by Carles Cufí
commit c64783f29d
4 changed files with 120 additions and 56 deletions

View file

@ -352,14 +352,14 @@ int lis2dh_init(const struct device *dev)
} }
/* Fix LSM303AGR_ACCEL device scale values */ /* Fix LSM303AGR_ACCEL device scale values */
if (cfg->is_lsm303agr_dev) { if (cfg->hw.is_lsm303agr_dev) {
lis2dh_reg_val_to_scale[0] = ACCEL_SCALE(1563); lis2dh_reg_val_to_scale[0] = ACCEL_SCALE(1563);
lis2dh_reg_val_to_scale[1] = ACCEL_SCALE(3126); lis2dh_reg_val_to_scale[1] = ACCEL_SCALE(3126);
lis2dh_reg_val_to_scale[2] = ACCEL_SCALE(6252); lis2dh_reg_val_to_scale[2] = ACCEL_SCALE(6252);
lis2dh_reg_val_to_scale[3] = ACCEL_SCALE(18758); lis2dh_reg_val_to_scale[3] = ACCEL_SCALE(18758);
} }
if (cfg->disc_pull_up) { if (cfg->hw.disc_pull_up) {
status = lis2dh->hw_tf->update_reg(dev, LIS2DH_REG_CTRL0, status = lis2dh->hw_tf->update_reg(dev, LIS2DH_REG_CTRL0,
LIS2DH_SDO_PU_DISC_MASK, LIS2DH_SDO_PU_DISC_MASK,
LIS2DH_SDO_PU_DISC_MASK); LIS2DH_SDO_PU_DISC_MASK);
@ -455,6 +455,9 @@ int lis2dh_init(const struct device *dev)
#define DISC_PULL_UP(inst) \ #define DISC_PULL_UP(inst) \
DT_INST_PROP(inst, disconnect_sdo_sa0_pull_up) DT_INST_PROP(inst, disconnect_sdo_sa0_pull_up)
#define ANYM_ON_INT1(inst) \
DT_INST_PROP(inst, anym_on_int1)
#ifdef CONFIG_LIS2DH_TRIGGER #ifdef CONFIG_LIS2DH_TRIGGER
#define GPIO_DT_SPEC_INST_GET_BY_IDX_COND(id, prop, idx) \ #define GPIO_DT_SPEC_INST_GET_BY_IDX_COND(id, prop, idx) \
COND_CODE_1(DT_INST_PROP_HAS_IDX(id, prop, idx), \ COND_CODE_1(DT_INST_PROP_HAS_IDX(id, prop, idx), \
@ -463,9 +466,13 @@ int lis2dh_init(const struct device *dev)
#define LIS2DH_CFG_INT(inst) \ #define LIS2DH_CFG_INT(inst) \
.gpio_drdy = \ .gpio_drdy = \
GPIO_DT_SPEC_INST_GET_BY_IDX_COND(inst, irq_gpios, 0), \ COND_CODE_1(ANYM_ON_INT1(inst), \
({.port = NULL, .pin = 0, .dt_flags = 0}), \
(GPIO_DT_SPEC_INST_GET_BY_IDX_COND(inst, irq_gpios, 0))), \
.gpio_int = \ .gpio_int = \
GPIO_DT_SPEC_INST_GET_BY_IDX_COND(inst, irq_gpios, 1), COND_CODE_1(ANYM_ON_INT1(inst), \
(GPIO_DT_SPEC_INST_GET_BY_IDX_COND(inst, irq_gpios, 0)), \
(GPIO_DT_SPEC_INST_GET_BY_IDX_COND(inst, irq_gpios, 1))),
#else #else
#define LIS2DH_CFG_INT(inst) #define LIS2DH_CFG_INT(inst)
#endif /* CONFIG_LIS2DH_TRIGGER */ #endif /* CONFIG_LIS2DH_TRIGGER */
@ -504,8 +511,9 @@ int lis2dh_init(const struct device *dev)
SPI_MODE_CPOL | \ SPI_MODE_CPOL | \
SPI_MODE_CPHA, \ SPI_MODE_CPHA, \
0) }, \ 0) }, \
.is_lsm303agr_dev = IS_LSM303AGR_DEV(inst), \ .hw = { .is_lsm303agr_dev = IS_LSM303AGR_DEV(inst), \
.disc_pull_up = DISC_PULL_UP(inst), \ .disc_pull_up = DISC_PULL_UP(inst), \
.anym_on_int1 = ANYM_ON_INT1(inst), }, \
LIS2DH_CFG_TEMPERATURE(inst) \ LIS2DH_CFG_TEMPERATURE(inst) \
LIS2DH_CFG_INT(inst) \ LIS2DH_CFG_INT(inst) \
} }
@ -525,8 +533,9 @@ int lis2dh_init(const struct device *dev)
.bus_name = DT_INST_BUS_LABEL(inst), \ .bus_name = DT_INST_BUS_LABEL(inst), \
.bus_init = lis2dh_i2c_init, \ .bus_init = lis2dh_i2c_init, \
.bus_cfg = { .i2c_slv_addr = DT_INST_REG_ADDR(inst), }, \ .bus_cfg = { .i2c_slv_addr = DT_INST_REG_ADDR(inst), }, \
.is_lsm303agr_dev = IS_LSM303AGR_DEV(inst), \ .hw = { .is_lsm303agr_dev = IS_LSM303AGR_DEV(inst), \
.disc_pull_up = DISC_PULL_UP(inst), \ .disc_pull_up = DISC_PULL_UP(inst), \
.anym_on_int1 = ANYM_ON_INT1(inst), }, \
LIS2DH_CFG_TEMPERATURE(inst) \ LIS2DH_CFG_TEMPERATURE(inst) \
LIS2DH_CFG_INT(inst) \ LIS2DH_CFG_INT(inst) \
} }

View file

@ -117,11 +117,15 @@
#define LIS2DH_REG_CTRL5 0x24 #define LIS2DH_REG_CTRL5 0x24
#define LIS2DH_LIR_INT2_SHIFT 1 #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_INT2 BIT(LIS2DH_LIR_INT2_SHIFT)
#define LIS2DH_EN_LIR_INT1 BIT(LIS2DH_LIR_INT1_SHIFT)
#define LIS2DH_REG_CTRL6 0x25 #define LIS2DH_REG_CTRL6 0x25
#define LIS2DH_EN_INT2_INT2_SHIFT 5 #define LIS2DH_EN_INT2_INT2_SHIFT 5
#define LIS2DH_EN_INT2_INT2 BIT(LIS2DH_EN_INT2_INT2_SHIFT) #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_REG_REFERENCE 0x26 #define LIS2DH_REG_REFERENCE 0x26
@ -145,7 +149,14 @@
#define LIS2DH_REG_ACCEL_Z_MSB 0x2D #define LIS2DH_REG_ACCEL_Z_MSB 0x2D
#define LIS2DH_REG_INT1_CFG 0x30 #define LIS2DH_REG_INT1_CFG 0x30
#define LIS2DH_REG_INT1_SRC 0x31
#define LIS2DH_REG_INT1_THS 0x32
#define LIS2DH_REG_INT1_DUR 0x33
#define LIS2DH_REG_INT2_CFG 0x34 #define LIS2DH_REG_INT2_CFG 0x34
#define LIS2DH_REG_INT2_SRC 0x35
#define LIS2DH_REG_INT2_THS 0x36
#define LIS2DH_REG_INT2_DUR 0x37
#define LIS2DH_AOI_CFG BIT(7) #define LIS2DH_AOI_CFG BIT(7)
#define LIS2DH_INT_CFG_ZHIE_ZUPE BIT(5) #define LIS2DH_INT_CFG_ZHIE_ZUPE BIT(5)
#define LIS2DH_INT_CFG_ZLIE_ZDOWNE BIT(4) #define LIS2DH_INT_CFG_ZLIE_ZDOWNE BIT(4)
@ -154,12 +165,6 @@
#define LIS2DH_INT_CFG_XHIE_XUPE BIT(1) #define LIS2DH_INT_CFG_XHIE_XUPE BIT(1)
#define LIS2DH_INT_CFG_XLIE_XDOWNE BIT(0) #define LIS2DH_INT_CFG_XLIE_XDOWNE BIT(0)
#define LIS2DH_REG_INT2_SRC 0x35
#define LIS2DH_REG_INT2_THS 0x36
#define LIS2DH_REG_INT2_DUR 0x37
/* sample buffer size includes status register */ /* sample buffer size includes status register */
#define LIS2DH_BUF_SZ 7 #define LIS2DH_BUF_SZ 7
@ -198,8 +203,11 @@ struct lis2dh_config {
const struct gpio_dt_spec gpio_drdy; const struct gpio_dt_spec gpio_drdy;
const struct gpio_dt_spec gpio_int; const struct gpio_dt_spec gpio_int;
#endif /* CONFIG_LIS2DH_TRIGGER */ #endif /* CONFIG_LIS2DH_TRIGGER */
bool is_lsm303agr_dev; struct {
bool disc_pull_up; bool is_lsm303agr_dev : 1;
bool disc_pull_up : 1;
bool anym_on_int1 : 1;
} hw;
#ifdef CONFIG_LIS2DH_MEASURE_TEMPERATURE #ifdef CONFIG_LIS2DH_MEASURE_TEMPERATURE
const struct temperature temperature; const struct temperature temperature;
#endif #endif

View file

@ -143,11 +143,22 @@ static int lis2dh_trigger_anym_set(const struct device *dev,
/* cancel potentially pending trigger */ /* cancel potentially pending trigger */
atomic_clear_bit(&lis2dh->trig_flags, TRIGGED_INT2); atomic_clear_bit(&lis2dh->trig_flags, TRIGGED_INT2);
/* disable all interrupt 2 events */ if (cfg->hw.anym_on_int1) {
status = lis2dh->hw_tf->write_reg(dev, LIS2DH_REG_INT2_CFG, 0); status = lis2dh->hw_tf->update_reg(dev, LIS2DH_REG_CTRL3,
LIS2DH_EN_DRDY1_INT1, 0);
}
/* 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);
/* make sure any pending interrupt is cleared */ /* make sure any pending interrupt is cleared */
status = lis2dh->hw_tf->read_reg(dev, LIS2DH_REG_INT2_SRC, &reg_val); status = lis2dh->hw_tf->read_reg(
dev,
cfg->hw.anym_on_int1 ? LIS2DH_REG_INT1_SRC : LIS2DH_REG_INT2_SRC,
&reg_val);
lis2dh->handler_anymotion = handler; lis2dh->handler_anymotion = handler;
if ((handler == NULL) || (status < 0)) { if ((handler == NULL) || (status < 0)) {
@ -169,10 +180,13 @@ static int lis2dh_trigger_anym_set(const struct device *dev,
static int lis2dh_start_trigger_int2(const struct device *dev) static int lis2dh_start_trigger_int2(const struct device *dev)
{ {
struct lis2dh_data *lis2dh = dev->data; struct lis2dh_data *lis2dh = dev->data;
const struct lis2dh_config *cfg = dev->config;
setup_int2(dev, true); setup_int2(dev, true);
return lis2dh->hw_tf->write_reg(dev, LIS2DH_REG_INT2_CFG, return lis2dh->hw_tf->write_reg(
dev,
cfg->hw.anym_on_int1 ? LIS2DH_REG_INT1_CFG : LIS2DH_REG_INT2_CFG,
LIS2DH_ANYM_CFG); LIS2DH_ANYM_CFG);
} }
@ -195,6 +209,7 @@ int lis2dh_acc_slope_config(const struct device *dev,
const struct sensor_value *val) const struct sensor_value *val)
{ {
struct lis2dh_data *lis2dh = dev->data; struct lis2dh_data *lis2dh = dev->data;
const struct lis2dh_config *cfg = dev->config;
int status; int status;
if (attr == SENSOR_ATTR_SLOPE_TH) { if (attr == SENSOR_ATTR_SLOPE_TH) {
@ -224,7 +239,10 @@ int lis2dh_acc_slope_config(const struct device *dev,
LOG_INF("int2_ths=0x%x range_g=%d ums2=%u", reg_val, LOG_INF("int2_ths=0x%x range_g=%d ums2=%u", reg_val,
range_g, slope_th_ums2 - 1); range_g, slope_th_ums2 - 1);
status = lis2dh->hw_tf->write_reg(dev, LIS2DH_REG_INT2_THS, status = lis2dh->hw_tf->write_reg(dev,
cfg->hw.anym_on_int1 ?
LIS2DH_REG_INT1_THS :
LIS2DH_REG_INT2_THS,
reg_val); reg_val);
} else { /* SENSOR_ATTR_SLOPE_DUR */ } else { /* SENSOR_ATTR_SLOPE_DUR */
/* /*
@ -237,7 +255,10 @@ int lis2dh_acc_slope_config(const struct device *dev,
LOG_INF("int2_dur=0x%x", val->val1); LOG_INF("int2_dur=0x%x", val->val1);
status = lis2dh->hw_tf->write_reg(dev, LIS2DH_REG_INT2_DUR, status = lis2dh->hw_tf->write_reg(dev,
cfg->hw.anym_on_int1 ?
LIS2DH_REG_INT1_DUR :
LIS2DH_REG_INT2_DUR,
val->val1); val->val1);
} }
@ -344,8 +365,11 @@ static void lis2dh_thread_cb(const struct device *dev)
}; };
uint8_t reg_val; uint8_t reg_val;
/* clear interrupt 2 to de-assert int2 line */ /* clear interrupt to de-assert int line */
status = lis2dh->hw_tf->read_reg(dev, LIS2DH_REG_INT2_SRC, status = lis2dh->hw_tf->read_reg(dev,
cfg->hw.anym_on_int1 ?
LIS2DH_REG_INT1_SRC :
LIS2DH_REG_INT2_SRC,
&reg_val); &reg_val);
if (status < 0) { if (status < 0) {
LOG_ERR("clearing interrupt 2 failed: %d", status); LOG_ERR("clearing interrupt 2 failed: %d", status);
@ -397,6 +421,18 @@ int lis2dh_init_interrupt(const struct device *dev)
int status; int status;
uint8_t raw[2]; uint8_t raw[2];
lis2dh->dev = dev;
#if defined(CONFIG_LIS2DH_TRIGGER_OWN_THREAD)
k_sem_init(&lis2dh->gpio_sem, 0, K_SEM_MAX_LIMIT);
k_thread_create(&lis2dh->thread, lis2dh->thread_stack, CONFIG_LIS2DH_THREAD_STACK_SIZE,
(k_thread_entry_t)lis2dh_thread, lis2dh, NULL, NULL,
K_PRIO_COOP(CONFIG_LIS2DH_THREAD_PRIORITY), 0, K_NO_WAIT);
#elif defined(CONFIG_LIS2DH_TRIGGER_GLOBAL_THREAD)
lis2dh->work.handler = lis2dh_work_cb;
#endif
/* /*
* Setup INT1 (for DRDY) if defined in DT * Setup INT1 (for DRDY) if defined in DT
*/ */
@ -414,20 +450,6 @@ int lis2dh_init_interrupt(const struct device *dev)
goto check_gpio_int; goto check_gpio_int;
} }
lis2dh->dev = dev;
#if defined(CONFIG_LIS2DH_TRIGGER_OWN_THREAD)
k_sem_init(&lis2dh->gpio_sem, 0, K_SEM_MAX_LIMIT);
k_thread_create(&lis2dh->thread, lis2dh->thread_stack,
CONFIG_LIS2DH_THREAD_STACK_SIZE,
(k_thread_entry_t)lis2dh_thread, lis2dh, NULL, NULL,
K_PRIO_COOP(CONFIG_LIS2DH_THREAD_PRIORITY), 0,
K_NO_WAIT);
#elif defined(CONFIG_LIS2DH_TRIGGER_GLOBAL_THREAD)
lis2dh->work.handler = lis2dh_work_cb;
#endif
/* data ready int1 gpio configuration */ /* data ready int1 gpio configuration */
status = gpio_pin_configure_dt(&cfg->gpio_drdy, GPIO_INPUT); status = gpio_pin_configure_dt(&cfg->gpio_drdy, GPIO_INPUT);
if (status < 0) { if (status < 0) {
@ -452,7 +474,7 @@ int lis2dh_init_interrupt(const struct device *dev)
check_gpio_int: check_gpio_int:
/* /*
* Setup INT2 (for Any Motion) if defined in DT * Setup Interrupt (for Any Motion) if defined in DT
*/ */
/* setup any motion gpio interrupt */ /* setup any motion gpio interrupt */
@ -491,21 +513,36 @@ check_gpio_int:
cfg->gpio_int.port->name, cfg->gpio_int.port->name,
cfg->gpio_int.pin); cfg->gpio_int.pin);
/* disable interrupt 2 in case of warm (re)boot */ /* disable interrupt in case of warm (re)boot */
status = lis2dh->hw_tf->write_reg(dev, 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) { if (status < 0) {
LOG_ERR("Interrupt 2 disable reg write failed (%d)", status); LOG_ERR("Interrupt disable reg write failed (%d)", status);
return status; return status;
} }
(void)memset(raw, 0, sizeof(raw)); (void)memset(raw, 0, sizeof(raw));
status = lis2dh->hw_tf->write_data(dev, LIS2DH_REG_INT2_THS, status = lis2dh->hw_tf->write_data(
dev,
cfg->hw.anym_on_int1 ? LIS2DH_REG_INT1_THS : LIS2DH_REG_INT2_THS,
raw, sizeof(raw)); raw, sizeof(raw));
if (status < 0) { if (status < 0) {
LOG_ERR("Burst write to INT2 THS failed (%d)", status); LOG_ERR("Burst write to THS failed (%d)", status);
return 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);
/* 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 */ /* enable interrupt 2 on int2 line */
status = lis2dh->hw_tf->update_reg(dev, LIS2DH_REG_CTRL6, status = lis2dh->hw_tf->update_reg(dev, LIS2DH_REG_CTRL6,
LIS2DH_EN_INT2_INT2, LIS2DH_EN_INT2_INT2,
@ -514,8 +551,10 @@ check_gpio_int:
/* latch int2 line interrupt */ /* latch int2 line interrupt */
status = lis2dh->hw_tf->write_reg(dev, LIS2DH_REG_CTRL5, status = lis2dh->hw_tf->write_reg(dev, LIS2DH_REG_CTRL5,
LIS2DH_EN_LIR_INT2); LIS2DH_EN_LIR_INT2);
}
if (status < 0) { if (status < 0) {
LOG_ERR("INT2 latch enable reg write failed (%d)", status); LOG_ERR("latch enable reg write failed (%d)", status);
return status; return status;
} }

View file

@ -17,3 +17,11 @@ properties:
during device initialization (e.g. to save current during device initialization (e.g. to save current
leakage). Note that only subset of devices supported by this leakage). Note that only subset of devices supported by this
binding have SDO/SA0 pull-up (e.g. LIS2DH12, LIS3DH). binding have SDO/SA0 pull-up (e.g. LIS2DH12, LIS3DH).
anym-on-int1:
type: boolean
required: false
description: |
Indicates that the device driver should use interrupt 1
for any movement. This is for boards that only have one
interrupt line connected from the sensor to the processor.