From 7cf4eff731410a8a26b27835324de1465fa3bb94 Mon Sep 17 00:00:00 2001 From: Andy Sinclair Date: Wed, 11 Oct 2023 13:42:30 +0100 Subject: [PATCH] drivers: mfd: npm1300: Fixed race condition in event callback If an event occurs between the status registers being read and the event being cleared, the interrupt line will remain active. As the interrupt is edge triggered, all future interrupts will being ignored. This problem will also occur if an I2C transation fails in the callback. The state of the interrupt pin is now checked at the end of the callback, and a retry is attempted if the interrupt has not been cleared. Signed-off-by: Andy Sinclair --- drivers/mfd/mfd_npm1300.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/mfd/mfd_npm1300.c b/drivers/mfd/mfd_npm1300.c index c100b7e915a..678d3572a24 100644 --- a/drivers/mfd/mfd_npm1300.c +++ b/drivers/mfd/mfd_npm1300.c @@ -79,12 +79,14 @@ static void gpio_callback(const struct device *dev, struct gpio_callback *cb, ui static void work_callback(struct k_work *work) { struct mfd_npm1300_data *data = CONTAINER_OF(work, struct mfd_npm1300_data, work); + const struct mfd_npm1300_config *config = data->dev->config; uint8_t buf[MAIN_SIZE]; int ret; /* Read all MAIN registers into temporary buffer */ ret = mfd_npm1300_reg_read_burst(data->dev, MAIN_BASE, 0U, buf, sizeof(buf)); if (ret < 0) { + k_work_submit(&data->work); return; } @@ -97,10 +99,16 @@ static void work_callback(struct k_work *work) ret = mfd_npm1300_reg_write(data->dev, MAIN_BASE, offset, event_reg[i].mask); if (ret < 0) { + k_work_submit(&data->work); return; } } } + + /* Resubmit handler to queue if interrupt is still active */ + if (gpio_pin_get_dt(&config->host_int_gpios) != 0) { + k_work_submit(&data->work); + } } static int mfd_npm1300_init(const struct device *dev)