1 /*
2  * Copyright (c) 2015 - 2020, Nordic Semiconductor ASA
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice, this
9  *    list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its
16  *    contributors may be used to endorse or promote products derived from this
17  *    software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <nrfx.h>
33 
34 #if NRFX_CHECK(NRFX_WDT_ENABLED)
35 
36 #if !(NRFX_CHECK(NRFX_WDT0_ENABLED) || NRFX_CHECK(NRFX_WDT1_ENABLED))
37 #error "No enabled WDT instances. Check <nrfx_config.h>."
38 #endif
39 
40 #include <nrfx_wdt.h>
41 
42 #define NRFX_LOG_MODULE WDT
43 #include <nrfx_log.h>
44 
45 // Control block - driver instance local data.
46 typedef struct
47 {
48     nrfx_drv_state_t         state;
49     uint8_t                  alloc_index;
50 #if !NRFX_CHECK(NRFX_WDT_CONFIG_NO_IRQ)
51     nrfx_wdt_event_handler_t wdt_event_handler;
52 #endif
53 } wdt_control_block_t;
54 
55 static wdt_control_block_t m_cb[NRFX_WDT_ENABLED_COUNT];
56 
nrfx_wdt_init(nrfx_wdt_t const * p_instance,nrfx_wdt_config_t const * p_config,nrfx_wdt_event_handler_t wdt_event_handler)57 nrfx_err_t nrfx_wdt_init(nrfx_wdt_t const *        p_instance,
58                          nrfx_wdt_config_t const * p_config,
59                          nrfx_wdt_event_handler_t  wdt_event_handler)
60 {
61     NRFX_ASSERT(p_config);
62     nrfx_err_t err_code;
63 
64     wdt_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
65 
66 #if NRFX_CHECK(NRFX_WDT_CONFIG_NO_IRQ)
67     (void)wdt_event_handler;
68 #else
69     p_cb->wdt_event_handler = wdt_event_handler;
70 #endif
71 
72     if (p_cb->state == NRFX_DRV_STATE_UNINITIALIZED)
73     {
74         p_cb->state = NRFX_DRV_STATE_INITIALIZED;
75     }
76     else
77     {
78         err_code = NRFX_ERROR_INVALID_STATE;
79         NRFX_LOG_WARNING("Function: %s, error code: %s.",
80                          __func__,
81                          NRFX_LOG_ERROR_STRING_GET(err_code));
82         return err_code;
83     }
84 
85     nrf_wdt_behaviour_set(p_instance->p_reg, p_config->behaviour);
86 
87     uint64_t ticks = (p_config->reload_value * 32768ULL) / 1000;
88     NRFX_ASSERT(ticks <= UINT32_MAX);
89 
90     nrf_wdt_reload_value_set(p_instance->p_reg, (uint32_t) ticks);
91 
92 #if !NRFX_CHECK(NRFX_WDT_CONFIG_NO_IRQ)
93     if (wdt_event_handler)
94     {
95         nrf_wdt_int_enable(p_instance->p_reg, NRF_WDT_INT_TIMEOUT_MASK);
96         NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_reg), p_config->interrupt_priority);
97         NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_reg));
98     }
99 #endif
100 
101     err_code = NRFX_SUCCESS;
102     NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
103     return err_code;
104 }
105 
106 
nrfx_wdt_enable(nrfx_wdt_t const * p_instance)107 void nrfx_wdt_enable(nrfx_wdt_t const * p_instance)
108 {
109     wdt_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
110     NRFX_ASSERT(p_cb->alloc_index != 0);
111     NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_INITIALIZED);
112     nrf_wdt_task_trigger(p_instance->p_reg, NRF_WDT_TASK_START);
113     p_cb->state = NRFX_DRV_STATE_POWERED_ON;
114     NRFX_LOG_INFO("Enabled.");
115 }
116 
117 
nrfx_wdt_feed(nrfx_wdt_t const * p_instance)118 void nrfx_wdt_feed(nrfx_wdt_t const * p_instance)
119 {
120     wdt_control_block_t const * p_cb = &m_cb[p_instance->drv_inst_idx];
121     NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_POWERED_ON);
122     for (uint8_t i = 0; i < p_cb->alloc_index; i++)
123     {
124         nrf_wdt_reload_request_set(p_instance->p_reg, (nrf_wdt_rr_register_t)(NRF_WDT_RR0 + i));
125     }
126 }
127 
nrfx_wdt_channel_alloc(nrfx_wdt_t const * p_instance,nrfx_wdt_channel_id * p_channel_id)128 nrfx_err_t nrfx_wdt_channel_alloc(nrfx_wdt_t const * p_instance, nrfx_wdt_channel_id * p_channel_id)
129 {
130     nrfx_err_t result;
131     wdt_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
132 
133     NRFX_ASSERT(p_channel_id);
134     NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_INITIALIZED);
135 
136     NRFX_CRITICAL_SECTION_ENTER();
137     if (p_cb->alloc_index < NRF_WDT_CHANNEL_NUMBER)
138     {
139         *p_channel_id = (nrfx_wdt_channel_id)(NRF_WDT_RR0 + p_cb->alloc_index);
140         p_cb->alloc_index++;
141         nrf_wdt_reload_request_enable(p_instance->p_reg, *p_channel_id);
142         result = NRFX_SUCCESS;
143     }
144     else
145     {
146         result = NRFX_ERROR_NO_MEM;
147     }
148     NRFX_CRITICAL_SECTION_EXIT();
149     NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(result));
150     return result;
151 }
152 
nrfx_wdt_channel_feed(nrfx_wdt_t const * p_instance,nrfx_wdt_channel_id channel_id)153 void nrfx_wdt_channel_feed(nrfx_wdt_t const * p_instance, nrfx_wdt_channel_id channel_id)
154 {
155     NRFX_ASSERT(m_cb[p_instance->drv_inst_idx].state == NRFX_DRV_STATE_POWERED_ON);
156     nrf_wdt_reload_request_set(p_instance->p_reg, channel_id);
157 }
158 
159 #if NRFX_CHECK(NRFX_WDT0_ENABLED) && !NRFX_CHECK(NRFX_WDT_CONFIG_NO_IRQ)
nrfx_wdt_0_irq_handler(void)160 void nrfx_wdt_0_irq_handler(void)
161 {
162     if (nrf_wdt_event_check(NRF_WDT0, NRF_WDT_EVENT_TIMEOUT))
163     {
164         m_cb[NRFX_WDT0_INST_IDX].wdt_event_handler();
165         nrf_wdt_event_clear(NRF_WDT0, NRF_WDT_EVENT_TIMEOUT);
166     }
167 }
168 #endif
169 
170 #if NRFX_CHECK(NRFX_WDT1_ENABLED) && !NRFX_CHECK(NRFX_WDT_CONFIG_NO_IRQ)
nrfx_wdt_1_irq_handler(void)171 void nrfx_wdt_1_irq_handler(void)
172 {
173     if (nrf_wdt_event_check(NRF_WDT1, NRF_WDT_EVENT_TIMEOUT))
174     {
175         m_cb[NRFX_WDT1_INST_IDX].wdt_event_handler();
176         nrf_wdt_event_clear(NRF_WDT1, NRF_WDT_EVENT_TIMEOUT);
177     }
178 }
179 #endif
180 
181 #endif // NRFX_CHECK(NRFX_WDT_ENABLED)
182