1 /*
2  * Copyright (c) 2019 - 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_EGU_ENABLED)
35 
36 #if !(NRFX_CHECK(NRFX_EGU0_ENABLED) || \
37       NRFX_CHECK(NRFX_EGU1_ENABLED) || \
38       NRFX_CHECK(NRFX_EGU2_ENABLED) || \
39       NRFX_CHECK(NRFX_EGU3_ENABLED) || \
40       NRFX_CHECK(NRFX_EGU4_ENABLED) || \
41       NRFX_CHECK(NRFX_EGU5_ENABLED))
42 #error "No enabled EGU instances. Check <nrfx_config.h>."
43 #endif
44 
45 #if NRFX_CHECK(NRFX_EGU0_ENABLED) && ((1 << 0) & NRFX_EGUS_USED)
46     #error "EGU instance 0 is reserved for use outside of nrfx."
47 #endif
48 #if NRFX_CHECK(NRFX_EGU1_ENABLED) && ((1 << 1) & NRFX_EGUS_USED)
49     #error "EGU instance 1 is reserved for use outside of nrfx."
50 #endif
51 #if NRFX_CHECK(NRFX_EGU2_ENABLED) && ((1 << 2) & NRFX_EGUS_USED)
52     #error "EGU instance 2 is reserved for use outside of nrfx."
53 #endif
54 #if NRFX_CHECK(NRFX_EGU3_ENABLED) && ((1 << 3) & NRFX_EGUS_USED)
55     #error "EGU instance 3 is reserved for use outside of nrfx."
56 #endif
57 #if NRFX_CHECK(NRFX_EGU4_ENABLED) && ((1 << 4) & NRFX_EGUS_USED)
58     #error "EGU instance 4 is reserved for use outside of nrfx."
59 #endif
60 #if NRFX_CHECK(NRFX_EGU5_ENABLED) && ((1 << 5) & NRFX_EGUS_USED)
61     #error "EGU instance 5 is reserved for use outside of nrfx."
62 #endif
63 
64 #include <nrfx_egu.h>
65 
66 typedef struct
67 {
68     nrfx_egu_event_handler_t handler;
69     void *                   p_context;
70     nrfx_drv_state_t         state;
71 } egu_control_block_t;
72 
73 static egu_control_block_t m_cb[NRFX_EGU_ENABLED_COUNT];
74 
egu_event_mask_get_and_clear(NRF_EGU_Type * p_reg,uint32_t int_mask)75 static uint32_t egu_event_mask_get_and_clear(NRF_EGU_Type * p_reg, uint32_t int_mask)
76 {
77     uint32_t event_mask = 0;
78     while (int_mask)
79     {
80         uint8_t event_idx = __CLZ(__RBIT(int_mask));
81         int_mask &= ~(1uL << event_idx);
82 
83         nrf_egu_event_t event = nrf_egu_triggered_event_get(event_idx);
84         if (nrf_egu_event_check(p_reg, event))
85         {
86             nrf_egu_event_clear(p_reg, event);
87             event_mask |= (1uL << event_idx);
88         }
89     }
90     return event_mask;
91 }
92 
nrfx_egu_init(nrfx_egu_t const * p_instance,uint8_t interrupt_priority,nrfx_egu_event_handler_t event_handler,void * p_context)93 nrfx_err_t nrfx_egu_init(nrfx_egu_t const *       p_instance,
94                          uint8_t                  interrupt_priority,
95                          nrfx_egu_event_handler_t event_handler,
96                          void *                   p_context)
97 {
98     NRFX_ASSERT(p_instance);
99 
100     egu_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
101 
102     if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
103     {
104         return NRFX_ERROR_INVALID_STATE;
105     }
106 
107     p_cb->state     = NRFX_DRV_STATE_INITIALIZED;
108     p_cb->p_context = p_context;
109     p_cb->handler   = event_handler;
110     if (event_handler)
111     {
112         NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_reg));
113         NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_reg), interrupt_priority);
114     }
115 
116     return NRFX_SUCCESS;
117 }
118 
nrfx_egu_int_enable(nrfx_egu_t const * p_instance,uint32_t mask)119 void nrfx_egu_int_enable(nrfx_egu_t const * p_instance, uint32_t mask)
120 {
121     NRFX_ASSERT(p_instance);
122     NRFX_ASSERT(m_cb[p_instance->drv_inst_idx].state == NRFX_DRV_STATE_INITIALIZED);
123     NRFX_ASSERT(m_cb[p_instance->drv_inst_idx].handler);
124 
125     (void)egu_event_mask_get_and_clear(p_instance->p_reg, mask);
126     nrf_egu_int_enable(p_instance->p_reg, mask);
127 }
128 
nrfx_egu_int_disable(nrfx_egu_t const * p_instance,uint32_t mask)129 void nrfx_egu_int_disable(nrfx_egu_t const * p_instance, uint32_t mask)
130 {
131     NRFX_ASSERT(p_instance);
132     NRFX_ASSERT(m_cb[p_instance->drv_inst_idx].state == NRFX_DRV_STATE_INITIALIZED);
133 
134     nrf_egu_int_disable(p_instance->p_reg, mask);
135 }
136 
nrfx_egu_trigger(nrfx_egu_t const * p_instance,uint8_t event_idx)137 void nrfx_egu_trigger(nrfx_egu_t const * p_instance, uint8_t event_idx)
138 {
139     NRFX_ASSERT(p_instance);
140     NRFX_ASSERT(m_cb[p_instance->drv_inst_idx].state == NRFX_DRV_STATE_INITIALIZED);
141     NRFX_ASSERT(event_idx < nrf_egu_channel_count(p_instance->p_reg));
142 
143     nrf_egu_task_trigger(p_instance->p_reg, nrf_egu_trigger_task_get(event_idx));
144 }
145 
nrfx_egu_uninit(nrfx_egu_t const * p_instance)146 void nrfx_egu_uninit(nrfx_egu_t const * p_instance)
147 {
148     NRFX_ASSERT(p_instance);
149 
150     egu_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
151 
152     nrf_egu_int_disable(p_instance->p_reg, ~0uL);
153     NRFX_IRQ_DISABLE(nrfx_get_irq_number(p_instance->p_reg));
154 
155     p_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
156 }
157 
egu_irq_handler(NRF_EGU_Type * p_reg,egu_control_block_t * p_cb)158 static void egu_irq_handler(NRF_EGU_Type * p_reg, egu_control_block_t * p_cb)
159 {
160     uint32_t int_mask = nrf_egu_int_enable_check(p_reg, ~0uL);
161 
162     /* Check (and clear) only the events that are set to generate interrupts.
163        Leave the other ones untouched. */
164     uint32_t event_mask = egu_event_mask_get_and_clear(p_reg, int_mask);
165     while (event_mask)
166     {
167         uint8_t event_idx = __CLZ(__RBIT(event_mask));
168         event_mask &= ~(1uL << event_idx);
169         p_cb->handler(event_idx, p_cb->p_context);
170     }
171 }
172 
173 #if NRFX_CHECK(NRFX_EGU0_ENABLED)
nrfx_egu_0_irq_handler(void)174 void nrfx_egu_0_irq_handler(void)
175 {
176     egu_irq_handler(NRF_EGU0, &m_cb[NRFX_EGU0_INST_IDX]);
177 }
178 #endif
179 
180 #if NRFX_CHECK(NRFX_EGU1_ENABLED)
nrfx_egu_1_irq_handler(void)181 void nrfx_egu_1_irq_handler(void)
182 {
183     egu_irq_handler(NRF_EGU1, &m_cb[NRFX_EGU1_INST_IDX]);
184 }
185 #endif
186 
187 #if NRFX_CHECK(NRFX_EGU2_ENABLED)
nrfx_egu_2_irq_handler(void)188 void nrfx_egu_2_irq_handler(void)
189 {
190     egu_irq_handler(NRF_EGU2, &m_cb[NRFX_EGU2_INST_IDX]);
191 }
192 #endif
193 
194 #if NRFX_CHECK(NRFX_EGU3_ENABLED)
nrfx_egu_3_irq_handler(void)195 void nrfx_egu_3_irq_handler(void)
196 {
197     egu_irq_handler(NRF_EGU3, &m_cb[NRFX_EGU3_INST_IDX]);
198 }
199 #endif
200 
201 #if NRFX_CHECK(NRFX_EGU4_ENABLED)
nrfx_egu_4_irq_handler(void)202 void nrfx_egu_4_irq_handler(void)
203 {
204     egu_irq_handler(NRF_EGU4, &m_cb[NRFX_EGU4_INST_IDX]);
205 }
206 #endif
207 
208 #if NRFX_CHECK(NRFX_EGU5_ENABLED)
nrfx_egu_5_irq_handler(void)209 void nrfx_egu_5_irq_handler(void)
210 {
211     egu_irq_handler(NRF_EGU5, &m_cb[NRFX_EGU5_INST_IDX]);
212 }
213 #endif
214 
215 #endif // NRFX_CHECK(NRFX_EGU_ENABLED)
216