diff --git a/drivers/watchdog/Kconfig.nrfx b/drivers/watchdog/Kconfig.nrfx index 1633282d9e2..43ea65bbe9e 100644 --- a/drivers/watchdog/Kconfig.nrfx +++ b/drivers/watchdog/Kconfig.nrfx @@ -10,3 +10,16 @@ config WDT_NRFX select NRFX_WDT help Enable support for nrfx WDT driver for nRF MCU series. + +config NRFX_WDT0 + bool "Enable WDT0 instance" + depends on HAS_HW_NRF_WDT || HAS_HW_NRF_WDT0 + default y + help + Enable support for nrfx WDT instance 0. + +config NRFX_WDT1 + bool "Enable WDT1 instance" + depends on HAS_HW_NRF_WDT1 + help + Enable support for nrfx WDT instance 1. diff --git a/drivers/watchdog/wdt_nrfx.c b/drivers/watchdog/wdt_nrfx.c index 4709801c507..23770df9542 100644 --- a/drivers/watchdog/wdt_nrfx.c +++ b/drivers/watchdog/wdt_nrfx.c @@ -11,30 +11,32 @@ #include LOG_MODULE_REGISTER(wdt_nrfx); -DEVICE_DECLARE(wdt_nrfx); +struct wdt_nrfx_data { + wdt_callback_t m_callbacks[NRF_WDT_CHANNEL_NUMBER]; + u32_t m_timeout; + u8_t m_allocated_channels; +}; -/* Each activated and not reloaded channel can generate watchdog interrupt. - * Array m_callbacks provides storing callbacks for each channel. - */ -static wdt_callback_t m_callbacks[NRF_WDT_CHANNEL_NUMBER]; +struct wdt_nrfx_config { + nrfx_wdt_t wdt; + nrfx_wdt_config_t config; +}; -/* The m_allocated_channels variable stores number of currently allocated - * and activated watchdog channels. - */ -static u8_t m_allocated_channels; +static inline struct wdt_nrfx_data *get_dev_data(struct device *dev) +{ + return dev->driver_data; +} + +static inline const struct wdt_nrfx_config *get_dev_config(struct device *dev) +{ + return dev->config->config_info; +} -/* The m_timeout variable stores watchdog timeout value in millisecond units. - * It is used to check whether installing watchdog provide the same timeout - * value in the window configuration. - */ -static u32_t m_timeout; static int wdt_nrf_setup(struct device *dev, u8_t options) { nrf_wdt_behaviour_t behaviour; - ARG_UNUSED(dev); - /* Activate all available options. Run in all cases. */ behaviour = NRF_WDT_BEHAVIOUR_RUN_SLEEP_HALT; @@ -48,14 +50,16 @@ static int wdt_nrf_setup(struct device *dev, u8_t options) behaviour &= ~NRF_WDT_BEHAVIOUR_RUN_HALT; } - nrf_wdt_behaviour_set(behaviour); + nrf_wdt_behaviour_set(get_dev_config(dev)->wdt.p_reg, behaviour); /* The watchdog timer is driven by the LFCLK clock running at 32768 Hz. * The timeout value given in milliseconds needs to be converted here * to watchdog ticks.*/ nrf_wdt_reload_value_set( - (uint32_t)(((uint64_t)m_timeout * 32768U) / 1000)); + get_dev_config(dev)->wdt.p_reg, + (uint32_t)(((uint64_t)get_dev_data(dev)->m_timeout * 32768U) + / 1000)); - nrfx_wdt_enable(); + nrfx_wdt_enable(&get_dev_config(dev)->wdt); return 0; } @@ -73,8 +77,6 @@ static int wdt_nrf_install_timeout(struct device *dev, nrfx_err_t err_code; nrfx_wdt_channel_id channel_id; - ARG_UNUSED(dev); - if (cfg->flags != WDT_FLAG_RESET_SOC) { return -ENOTSUP; } @@ -83,7 +85,7 @@ static int wdt_nrf_install_timeout(struct device *dev, return -EINVAL; } - if (m_allocated_channels == 0U) { + if (get_dev_data(dev)->m_allocated_channels == 0U) { /* According to relevant Product Specifications, watchdogs * in all nRF chips can use reload values (determining * the timeout) from range 0xF-0xFFFFFFFF given in 32768 Hz @@ -95,81 +97,102 @@ static int wdt_nrf_install_timeout(struct device *dev, } /* Save timeout value from first registered watchdog channel. */ - m_timeout = cfg->window.max; - } else if (cfg->window.max != m_timeout) { + get_dev_data(dev)->m_timeout = cfg->window.max; + } else if (cfg->window.max != get_dev_data(dev)->m_timeout) { return -EINVAL; } - err_code = nrfx_wdt_channel_alloc(&channel_id); + err_code = nrfx_wdt_channel_alloc(&get_dev_config(dev)->wdt, + &channel_id); if (err_code == NRFX_ERROR_NO_MEM) { return -ENOMEM; } if (cfg->callback != NULL) { - m_callbacks[channel_id] = cfg->callback; + get_dev_data(dev)->m_callbacks[channel_id] = cfg->callback; } - m_allocated_channels++; + get_dev_data(dev)->m_allocated_channels++; return channel_id; } static int wdt_nrf_feed(struct device *dev, int channel_id) { - ARG_UNUSED(dev); - if (channel_id > m_allocated_channels) { + if (channel_id > get_dev_data(dev)->m_allocated_channels) { return -EINVAL; } - nrfx_wdt_channel_feed((nrfx_wdt_channel_id)channel_id); + nrfx_wdt_channel_feed(&get_dev_config(dev)->wdt, + (nrfx_wdt_channel_id)channel_id); return 0; } -static const struct wdt_driver_api wdt_nrf_api = { +static const struct wdt_driver_api wdt_nrfx_driver_api = { .setup = wdt_nrf_setup, .disable = wdt_nrf_disable, .install_timeout = wdt_nrf_install_timeout, .feed = wdt_nrf_feed, }; -static void wdt_event_handler(void) +static void wdt_event_handler(struct device *dev) { int i; - for (i = 0; i < m_allocated_channels ; ++i) { - if (nrf_wdt_request_status((nrf_wdt_rr_register_t)i)) { - if (m_callbacks[i]) { - m_callbacks[i](DEVICE_GET(wdt_nrfx), i); + for (i = 0; i < get_dev_data(dev)->m_allocated_channels; ++i) { + if (nrf_wdt_request_status(get_dev_config(dev)->wdt.p_reg, + (nrf_wdt_rr_register_t)i)) { + if (get_dev_data(dev)->m_callbacks[i]) { + get_dev_data(dev)->m_callbacks[i](dev, i); } } } } -static int init_wdt(struct device *dev) -{ - nrfx_err_t err_code; - /* Set default values. They will be overwritten by setup function. */ - const nrfx_wdt_config_t config = { - .behaviour = NRF_WDT_BEHAVIOUR_RUN_SLEEP_HALT, - .reload_value = 2000 - }; +#define WDT_NRFX_WDT_DEVICE(idx) \ + DEVICE_DECLARE(wdt_##idx); \ + static void wdt_##idx##_event_handler(void) \ + { \ + wdt_event_handler(DEVICE_GET(wdt_##idx)); \ + } \ + static int wdt_##idx##_init(struct device *dev) \ + { \ + nrfx_err_t err_code; \ + IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_WDT##idx), \ + DT_NORDIC_NRF_WATCHDOG_WDT_##idx##_IRQ_0_PRIORITY, \ + nrfx_isr, nrfx_wdt_##idx##_irq_handler, 0); \ + err_code = nrfx_wdt_init(&get_dev_config(dev)->wdt, \ + &get_dev_config(dev)->config, \ + wdt_##idx##_event_handler); \ + if (err_code != NRFX_SUCCESS) { \ + return -EBUSY; \ + } \ + return 0; \ + } \ + static struct wdt_nrfx_data wdt_##idx##_data = { \ + .m_timeout = 0, \ + .m_allocated_channels = 0, \ + }; \ + static const struct wdt_nrfx_config wdt_##idx##z_config = { \ + .wdt = NRFX_WDT_INSTANCE(idx), \ + .config = { \ + .behaviour = NRF_WDT_BEHAVIOUR_RUN_SLEEP_HALT, \ + .reload_value = 2000, \ + } \ + }; \ + DEVICE_DEFINE(wdt_##idx, DT_NORDIC_NRF_WATCHDOG_WDT_##idx##_LABEL, \ + wdt_##idx##_init, \ + NULL, \ + &wdt_##idx##_data, \ + &wdt_##idx##z_config, \ + PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ + &wdt_nrfx_driver_api) - ARG_UNUSED(dev); +#ifdef CONFIG_NRFX_WDT0 +WDT_NRFX_WDT_DEVICE(0); +#endif - err_code = nrfx_wdt_init(&config, wdt_event_handler); - if (err_code != NRFX_SUCCESS) { - return -EBUSY; - } - - IRQ_CONNECT(DT_NORDIC_NRF_WATCHDOG_WDT_0_IRQ_0, - DT_NORDIC_NRF_WATCHDOG_WDT_0_IRQ_0_PRIORITY, - nrfx_isr, nrfx_wdt_irq_handler, 0); - irq_enable(DT_NORDIC_NRF_WATCHDOG_WDT_0_IRQ_0); - - return 0; -} - -DEVICE_AND_API_INIT(wdt_nrf, DT_NORDIC_NRF_WATCHDOG_WDT_0_LABEL, init_wdt, - NULL, NULL, PRE_KERNEL_1, - CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &wdt_nrf_api); +#ifdef CONFIG_NRFX_WDT1 +WDT_NRFX_WDT_DEVICE(1); +#endif