drivers: watchdog: nrfx: add synchronization after stop

In order to ensure that watchdog channels are freed in proper
driver state, synchronization in form of simple loop needs
to be added after stopping. In no irq variant, it is already done
on nrfx level. NRFY function can be replaced by NRFX one in
the future.

Signed-off-by: Michał Stasiak <michal.stasiak@nordicsemi.no>
This commit is contained in:
Michał Stasiak 2025-01-10 08:12:44 +01:00 committed by Benjamin Cabé
parent c96f236a1b
commit b578ffa49a

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
#include <zephyr/kernel.h>
#include <zephyr/sys/math_extras.h> #include <zephyr/sys/math_extras.h>
#include <nrfx_wdt.h> #include <nrfx_wdt.h>
#include <zephyr/drivers/watchdog.h> #include <zephyr/drivers/watchdog.h>
@ -13,11 +14,18 @@
#include <zephyr/irq.h> #include <zephyr/irq.h>
LOG_MODULE_REGISTER(wdt_nrfx); LOG_MODULE_REGISTER(wdt_nrfx);
#if !CONFIG_WDT_NRFX_NO_IRQ && NRF_WDT_HAS_STOP
#define WDT_NRFX_SYNC_STOP 1
#endif
struct wdt_nrfx_data { struct wdt_nrfx_data {
wdt_callback_t m_callbacks[NRF_WDT_CHANNEL_NUMBER]; wdt_callback_t m_callbacks[NRF_WDT_CHANNEL_NUMBER];
uint32_t m_timeout; uint32_t m_timeout;
uint8_t m_allocated_channels; uint8_t m_allocated_channels;
bool enabled; bool enabled;
#if defined(WDT_NRFX_SYNC_STOP)
struct k_sem sync_stop;
#endif
}; };
struct wdt_nrfx_config { struct wdt_nrfx_config {
@ -73,6 +81,10 @@ static int wdt_nrf_disable(const struct device *dev)
return -EFAULT; return -EFAULT;
} }
#if defined(WDT_NRFX_SYNC_STOP)
k_sem_take(&data->sync_stop, K_FOREVER);
#endif
nrfx_wdt_channels_free(&config->wdt); nrfx_wdt_channels_free(&config->wdt);
for (channel_id = 0; channel_id < data->m_allocated_channels; channel_id++) { for (channel_id = 0; channel_id < data->m_allocated_channels; channel_id++) {
@ -170,11 +182,17 @@ static DEVICE_API(wdt, wdt_nrfx_driver_api) = {
static void wdt_event_handler(const struct device *dev, nrf_wdt_event_t event_type, static void wdt_event_handler(const struct device *dev, nrf_wdt_event_t event_type,
uint32_t requests, void *p_context) uint32_t requests, void *p_context)
{ {
(void)event_type;
(void)p_context;
struct wdt_nrfx_data *data = dev->data; struct wdt_nrfx_data *data = dev->data;
#if defined(WDT_NRFX_SYNC_STOP)
if (event_type == NRF_WDT_EVENT_STOPPED) {
k_sem_give(&data->sync_stop);
}
#else
(void)event_type;
#endif
(void)p_context;
while (requests) { while (requests) {
uint8_t i = u32_count_trailing_zeros(requests); uint8_t i = u32_count_trailing_zeros(requests);
@ -217,7 +235,11 @@ static void wdt_event_handler(const struct device *dev, nrf_wdt_event_t event_ty
} \ } \
return 0; \ return 0; \
} \ } \
static struct wdt_nrfx_data wdt_##idx##_data; \ static struct wdt_nrfx_data wdt_##idx##_data = { \
IF_ENABLED(WDT_NRFX_SYNC_STOP, \
(.sync_stop = Z_SEM_INITIALIZER( \
wdt_##idx##_data.sync_stop, 0, 1),)) \
}; \
static const struct wdt_nrfx_config wdt_##idx##z_config = { \ static const struct wdt_nrfx_config wdt_##idx##z_config = { \
.wdt = NRFX_WDT_INSTANCE(idx), \ .wdt = NRFX_WDT_INSTANCE(idx), \
}; \ }; \