diff --git a/arch/xtensa/src/common/espressif/esp_irq.c b/arch/xtensa/src/common/espressif/esp_irq.c index 403bfe99a83..b5c525ebef4 100644 --- a/arch/xtensa/src/common/espressif/esp_irq.c +++ b/arch/xtensa/src/common/espressif/esp_irq.c @@ -42,6 +42,7 @@ #include "xtensa.h" +#include "esp_gpio.h" #include "esp_irq.h" #include "esp_intr_alloc.h" @@ -596,6 +597,21 @@ void up_enable_irq(int irq) if (intr_handle == IRQ_UNMAPPED) { + /* Not a real interrupt-matrix source -- esp_gpio_irq() registers + * per-pin GPIO IRQs through gpio_isr_handler_add() instead, so + * esp_get_handle() never finds them here. Try it as a GPIO pin. + */ + +#ifdef CONFIG_ESPRESSIF_GPIO_IRQ + int pin = ESP_IRQ2PIN(irq); + + if (pin >= 0 && pin < SOC_GPIO_PIN_COUNT && ESP_PIN2IRQ(pin) == irq) + { + esp_gpioirqenable(pin); + return; + } +#endif + irqwarn("IRQ %d not mapped to handle\n", irq); return; } @@ -636,6 +652,17 @@ void up_disable_irq(int irq) intr_handle = esp_get_handle(this_cpu(), irq); if (intr_handle == IRQ_UNMAPPED) { + /* See the matching comment in up_enable_irq(). */ + +#ifdef CONFIG_ESPRESSIF_GPIO_IRQ + int pin = ESP_IRQ2PIN(irq); + + if (pin >= 0 && pin < SOC_GPIO_PIN_COUNT && ESP_PIN2IRQ(pin) == irq) + { + esp_gpioirqdisable(pin); + } +#endif + return; } diff --git a/drivers/sensors/lsm6ds3trc_uorb.c b/drivers/sensors/lsm6ds3trc_uorb.c index 86f2b78f0eb..93703e8231e 100644 --- a/drivers/sensors/lsm6ds3trc_uorb.c +++ b/drivers/sensors/lsm6ds3trc_uorb.c @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -202,6 +203,8 @@ struct lsm6ds3trc_dev_s bool interrupt_mode; /* True if using the INT pin instead of * kthread polling */ enum lsm6ds3trc_int_e int_pin; /* Shared INT pin (interrupt mode only) */ + int irq; /* IRQ number for int_pin, saved by the + * ISR so the worker can re-enable it */ struct work_s work; /* Shared interrupt work queue * structure -- one burst read serves * both sub-sensors */ @@ -834,9 +837,8 @@ static int accel_thread(int argc, char **argv) * ****************************************************************************/ -static void lsm6ds3trc_fifo_worker(FAR void *arg) +static void lsm6ds3trc_fifo_worker_body(FAR struct lsm6ds3trc_dev_s *dev) { - FAR struct lsm6ds3trc_dev_s *dev = arg; uint8_t status[2]; int16_t raw[FIFO_MAX_WORDS]; int16_t raw_temp; @@ -980,6 +982,24 @@ static void lsm6ds3trc_fifo_worker(FAR void *arg) } } +/**************************************************************************** + * Name: lsm6ds3trc_fifo_worker + * + * Description: + * work_queue() entry point. Re-enables the IRQ lsm6ds3trc_interrupt() + * disabled, after the FIFO has actually been drained -- see the comment + * on lsm6ds3trc_interrupt() for why the order matters. + * + ****************************************************************************/ + +static void lsm6ds3trc_fifo_worker(FAR void *arg) +{ + FAR struct lsm6ds3trc_dev_s *dev = arg; + + lsm6ds3trc_fifo_worker_body(dev); + up_enable_irq(dev->irq); +} + #else /**************************************************************************** * Name: lsm6ds3trc_worker @@ -993,9 +1013,8 @@ static void lsm6ds3trc_fifo_worker(FAR void *arg) * ****************************************************************************/ -static void lsm6ds3trc_worker(FAR void *arg) +static void lsm6ds3trc_worker_body(FAR struct lsm6ds3trc_dev_s *dev) { - FAR struct lsm6ds3trc_dev_s *dev = arg; int16_t raw[7]; /* temp, gx, gy, gz, ax, ay, az */ struct sensor_gyro gyro_data; struct sensor_accel accel_data; @@ -1043,6 +1062,24 @@ static void lsm6ds3trc_worker(FAR void *arg) sizeof(accel_data)); } } + +/**************************************************************************** + * Name: lsm6ds3trc_worker + * + * Description: + * work_queue() entry point. Re-enables the IRQ lsm6ds3trc_interrupt() + * disabled, after the measurement has actually been drained -- see the + * comment on lsm6ds3trc_interrupt() for why the order matters. + * + ****************************************************************************/ + +static void lsm6ds3trc_worker(FAR void *arg) +{ + FAR struct lsm6ds3trc_dev_s *dev = arg; + + lsm6ds3trc_worker_body(dev); + up_enable_irq(dev->irq); +} #endif /**************************************************************************** @@ -1053,6 +1090,13 @@ static void lsm6ds3trc_worker(FAR void *arg) * became ready -- the I2C read cannot run in interrupt context, so it's * deferred to lsm6ds3trc_worker()/lsm6ds3trc_fifo_worker() on HPWORK. * + * The IRQ is disabled here and only re-enabled once the worker has + * drained the condition that raised it: if a PM wake source ever leaves + * this pin level-triggered instead of edge-triggered (or the line is + * simply slow to fall), leaving the IRQ enabled would re-fire it + * continuously and starve every task, including the worker that would + * otherwise clear it. + * ****************************************************************************/ static int lsm6ds3trc_interrupt(int irq, FAR void *context, FAR void *arg) @@ -1064,6 +1108,9 @@ static int lsm6ds3trc_interrupt(int irq, FAR void *context, FAR void *arg) DEBUGASSERT(arg != NULL); + dev->irq = irq; + up_disable_irq(irq); + dev->timestamp = sensor_get_timestamp(); #ifdef CONFIG_SENSORS_LSM6DS3TRC_FIFO