1 /*
2  * Copyright (c) 2015 - 2023, Nordic Semiconductor ASA
3  *
4  * Modifications to the GPIOTE HAL to use with simulation models
5  *
6  * Code which is not copied from the nRFx HAL is licensed as:
7  * SPDX-License-Identifier: Apache-2.0
8  *
9  * Most of the code below is taken from the NRFx HAL with minor
10  * modifications. For that code, the original license applies:
11  *
12  * SPDX-License-Identifier: BSD-3-Clause
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions are met:
16  *
17  * 1. Redistributions of source code must retain the above copyright notice, this
18  *    list of conditions and the following disclaimer.
19  *
20  * 2. Redistributions in binary form must reproduce the above copyright
21  *    notice, this list of conditions and the following disclaimer in the
22  *    documentation and/or other materials provided with the distribution.
23  *
24  * 3. Neither the name of the copyright holder nor the names of its
25  *    contributors may be used to endorse or promote products derived from this
26  *    software without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
29  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
32  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38  * POSSIBILITY OF SUCH DAMAGE.
39  */
40 
41 #include <stdint.h>
42 #include "NHW_config.h"
43 #include "NRF_GPIOTE.h"
44 #include "hal/nrf_gpiote.h"
45 #include "bs_tracing.h"
46 
gpiote_number_from_ptr(NRF_GPIOTE_Type const * p_reg)47 static int gpiote_number_from_ptr(NRF_GPIOTE_Type const * p_reg){
48   int i = ( (int)p_reg - (int)&NRF_GPIOTE_regs[0] ) / sizeof(NRF_GPIOTE_Type);
49   return i;
50 }
51 
nrf_gpiote_task_trigger(NRF_GPIOTE_Type * p_reg,nrf_gpiote_task_t task)52 void nrf_gpiote_task_trigger(NRF_GPIOTE_Type * p_reg, nrf_gpiote_task_t task)
53 {
54   uint32_t *reg = (uint32_t *)((uintptr_t)p_reg + task);
55   *(volatile uint32_t *)reg = 0x1UL;
56 
57   uint inst = gpiote_number_from_ptr(p_reg);
58 
59   if ((reg >= &NRF_GPIOTE_regs[inst].TASKS_OUT[0])
60       && (reg<= &NRF_GPIOTE_regs[inst].TASKS_OUT[NHW_GPIOTE_MAX_CHANNELS])) {
61     nrf_gpiote_regw_sideeffects_TASKS_OUT(inst, reg - &NRF_GPIOTE_regs[inst].TASKS_OUT[0]);
62   } else if ((reg >= &NRF_GPIOTE_regs[inst].TASKS_SET[0])
63              && (reg<= &NRF_GPIOTE_regs[inst].TASKS_SET[NHW_GPIOTE_MAX_CHANNELS])) {
64     nrf_gpiote_regw_sideeffects_TASKS_SET(inst, reg - &NRF_GPIOTE_regs[inst].TASKS_SET[0]);
65   } else if ((reg >= &NRF_GPIOTE_regs[inst].TASKS_CLR[0])
66              && (reg<= &NRF_GPIOTE_regs[inst].TASKS_CLR[NHW_GPIOTE_MAX_CHANNELS])) {
67     nrf_gpiote_regw_sideeffects_TASKS_CLR(inst, reg - &NRF_GPIOTE_regs[inst].TASKS_CLR[0]);
68   } else {
69     bs_trace_error_time_line("%s: Unknown GPIOTE tasks %i\n",task); /* LCOV_EXCL_LINE */
70   }
71 }
72 
nrf_gpiote_event_clear(NRF_GPIOTE_Type * p_reg,nrf_gpiote_event_t event)73 void nrf_gpiote_event_clear(NRF_GPIOTE_Type * p_reg, nrf_gpiote_event_t event)
74 {
75   uint32_t *reg = (uint32_t *)((uintptr_t)p_reg + event);
76   *(volatile uint32_t *)reg = 0;
77 
78   uint inst = gpiote_number_from_ptr(p_reg);
79 
80   if ((reg >= &NRF_GPIOTE_regs[inst].EVENTS_IN[0])
81       && (reg <= &NRF_GPIOTE_regs[inst].EVENTS_IN[NHW_GPIOTE_MAX_CHANNELS])) {
82     nrf_gpiote_regw_sideeffects_EVENTS_IN(inst, reg - &NRF_GPIOTE_regs[inst].EVENTS_IN[0]);
83 #if !NHW_GPIOTE_IS_54
84   } else if (reg == &NRF_GPIOTE_regs[inst].EVENTS_PORT) {
85     nrf_gpiote_regw_sideeffects_EVENTS_PORT(inst);
86 #else
87   } else if ((reg == &NRF_GPIOTE_regs[inst].EVENTS_PORT[0].NONSECURE)
88              || (reg == &NRF_GPIOTE_regs[inst].EVENTS_PORT[0].SECURE)) {
89     nrf_gpiote_regw_sideeffects_EVENTS_PORT(inst);
90 #endif
91   } else {
92     bs_trace_error_time_line("%s: Unknown GPIOTE event %i\n",event); /* LCOV_EXCL_LINE */
93   }
94 }
95 
96 #if defined(GPIOTE_IRQ_GROUP)
97 #define DEFAULT_IRQ_LINE NRF_GPIOTE_IRQ_GROUP
98 #else
99 #define DEFAULT_IRQ_LINE 0
100 #endif
101 
nrf_gpiote_int_enable(NRF_GPIOTE_Type * p_reg,uint32_t mask)102 void nrf_gpiote_int_enable(NRF_GPIOTE_Type * p_reg, uint32_t mask)
103 {
104     uint inst = gpiote_number_from_ptr(p_reg);
105     p_reg->NRFX_CONCAT_2(INTENSET, NRF_GPIOTE_IRQ_GROUP) = mask;
106     nrf_gpiote_regw_sideeffects_INTENSET(inst, DEFAULT_IRQ_LINE);
107 
108 }
109 
nrf_gpiote_int_disable(NRF_GPIOTE_Type * p_reg,uint32_t mask)110 void nrf_gpiote_int_disable(NRF_GPIOTE_Type * p_reg, uint32_t mask)
111 {
112     uint inst = gpiote_number_from_ptr(p_reg);
113     p_reg->NRFX_CONCAT_2(INTENCLR, NRF_GPIOTE_IRQ_GROUP) = mask;
114     nrf_gpiote_regw_sideeffects_INTENCLR(inst, DEFAULT_IRQ_LINE);
115 }
116 
nrf_gpiote_event_enable(NRF_GPIOTE_Type * p_reg,uint32_t idx)117 void nrf_gpiote_event_enable(NRF_GPIOTE_Type * p_reg, uint32_t idx)
118 {
119    uint inst = gpiote_number_from_ptr(p_reg);
120    p_reg->CONFIG[idx] |= GPIOTE_CONFIG_MODE_Event;
121    nrf_gpiote_regw_sideeffects_CONFIG(inst, idx);
122 }
123 
nrf_gpiote_event_disable(NRF_GPIOTE_Type * p_reg,uint32_t idx)124 void nrf_gpiote_event_disable(NRF_GPIOTE_Type * p_reg, uint32_t idx)
125 {
126    uint inst = gpiote_number_from_ptr(p_reg);
127    p_reg->CONFIG[idx] &= ~GPIOTE_CONFIG_MODE_Msk;
128    nrf_gpiote_regw_sideeffects_CONFIG(inst, idx);
129 }
130 
131 #if NRF_GPIOTE_HAS_INT_GROUPS
nrf_gpiote_int_group_enable(NRF_GPIOTE_Type * p_reg,uint8_t group_idx,uint32_t mask)132 void nrf_gpiote_int_group_enable(NRF_GPIOTE_Type * p_reg,
133                                  uint8_t           group_idx,
134                                  uint32_t          mask)
135 {
136     switch (group_idx)
137     {
138         case 0:
139             p_reg->INTENSET0 = mask;
140             break;
141         case 1:
142             p_reg->INTENSET1 = mask;
143             break;
144 #if defined(GPIOTE_INTENSET2_IN0_Msk)
145         case 2:
146             p_reg->INTENSET2 = mask;
147             break;
148 #endif
149 #if defined(GPIOTE_INTENSET3_IN0_Msk)
150         case 3:
151             p_reg->INTENSET3 = mask;
152             break;
153 #endif
154 #if defined(GPIOTE_INTENSET4_IN0_Msk)
155         case 4:
156             p_reg->INTENSET4 = mask;
157             break;
158 #endif
159 #if defined(GPIOTE_INTENSET5_IN0_Msk)
160         case 5:
161             p_reg->INTENSET5 = mask;
162             break;
163 #endif
164 #if defined(GPIOTE_INTENSET6_IN0_Msk)
165         case 6:
166             p_reg->INTENSET6 = mask;
167             break;
168 #endif
169        default:
170             NRFX_ASSERT(false);
171             break;
172     }
173     uint inst = gpiote_number_from_ptr(p_reg);
174     nrf_gpiote_regw_sideeffects_INTENSET(inst, group_idx);
175 }
176 
nrf_gpiote_int_group_disable(NRF_GPIOTE_Type * p_reg,uint8_t group_idx,uint32_t mask)177 void nrf_gpiote_int_group_disable(NRF_GPIOTE_Type * p_reg,
178                                   uint8_t           group_idx,
179                                   uint32_t          mask)
180 {
181     switch (group_idx)
182     {
183         case 0:
184             p_reg->INTENCLR0 = mask;
185             break;
186         case 1:
187             p_reg->INTENCLR1 = mask;
188             break;
189 #if defined(GPIOTE_INTENCLR2_IN0_Msk)
190         case 2:
191             p_reg->INTENCLR2 = mask;
192             break;
193 #endif
194 #if defined(GPIOTE_INTENCLR3_IN0_Msk)
195         case 3:
196             p_reg->INTENCLR3 = mask;
197             break;
198 #endif
199 #if defined(GPIOTE_INTENCLR4_IN0_Msk)
200         case 4:
201             p_reg->INTENCLR4 = mask;
202             break;
203 #endif
204 #if defined(GPIOTE_INTENCLR5_IN0_Msk)
205         case 5:
206             p_reg->INTENCLR5 = mask;
207             break;
208 #endif
209 #if defined(GPIOTE_INTENCLR6_IN0_Msk)
210         case 6:
211             p_reg->INTENCLR6 = mask;
212             break;
213 #endif
214         default:
215             NRFX_ASSERT(false);
216             break;
217     }
218     uint inst = gpiote_number_from_ptr(p_reg);
219     nrf_gpiote_regw_sideeffects_INTENCLR(inst, group_idx);
220 }
221 #endif
222 
nrf_gpiote_event_configure(NRF_GPIOTE_Type * p_reg,uint32_t idx,uint32_t pin,nrf_gpiote_polarity_t polarity)223 void nrf_gpiote_event_configure(NRF_GPIOTE_Type *     p_reg,
224                                 uint32_t              idx,
225                                 uint32_t              pin,
226                                 nrf_gpiote_polarity_t polarity)
227 {
228   uint inst = gpiote_number_from_ptr(p_reg);
229   p_reg->CONFIG[idx] &= ~(GPIOTE_CONFIG_PORT_PIN_Msk | GPIOTE_CONFIG_POLARITY_Msk);
230   p_reg->CONFIG[idx] |= ((pin << GPIOTE_CONFIG_PSEL_Pos) & GPIOTE_CONFIG_PORT_PIN_Msk) |
231                         ((polarity << GPIOTE_CONFIG_POLARITY_Pos) & GPIOTE_CONFIG_POLARITY_Msk);
232   nrf_gpiote_regw_sideeffects_CONFIG(inst, idx);
233 }
234 
nrf_gpiote_task_enable(NRF_GPIOTE_Type * p_reg,uint32_t idx)235 void nrf_gpiote_task_enable(NRF_GPIOTE_Type * p_reg, uint32_t idx)
236 {
237     uint inst = gpiote_number_from_ptr(p_reg);
238     uint32_t final_config = p_reg->CONFIG[idx] | GPIOTE_CONFIG_MODE_Task;
239     p_reg->CONFIG[idx] = final_config;
240     nrf_gpiote_regw_sideeffects_CONFIG(inst, idx);
241 }
242 
nrf_gpiote_task_disable(NRF_GPIOTE_Type * p_reg,uint32_t idx)243 void nrf_gpiote_task_disable(NRF_GPIOTE_Type * p_reg, uint32_t idx)
244 {
245     uint inst = gpiote_number_from_ptr(p_reg);
246     p_reg->CONFIG[idx] &= ~GPIOTE_CONFIG_MODE_Msk;
247     nrf_gpiote_regw_sideeffects_CONFIG(inst, idx);
248 }
249 
nrf_gpiote_task_configure(NRF_GPIOTE_Type * p_reg,uint32_t idx,uint32_t pin,nrf_gpiote_polarity_t polarity,nrf_gpiote_outinit_t init_val)250 void nrf_gpiote_task_configure(NRF_GPIOTE_Type *     p_reg,
251                                uint32_t              idx,
252                                uint32_t              pin,
253                                nrf_gpiote_polarity_t polarity,
254                                nrf_gpiote_outinit_t  init_val)
255 {
256   uint inst = gpiote_number_from_ptr(p_reg);
257   p_reg->CONFIG[idx] &= ~(GPIOTE_CONFIG_PORT_PIN_Msk |
258                           GPIOTE_CONFIG_POLARITY_Msk |
259                           GPIOTE_CONFIG_OUTINIT_Msk);
260 
261   p_reg->CONFIG[idx] |= ((pin << GPIOTE_CONFIG_PSEL_Pos) & GPIOTE_CONFIG_PORT_PIN_Msk) |
262                         ((polarity << GPIOTE_CONFIG_POLARITY_Pos) & GPIOTE_CONFIG_POLARITY_Msk) |
263                         ((init_val << GPIOTE_CONFIG_OUTINIT_Pos) & GPIOTE_CONFIG_OUTINIT_Msk);
264 
265   nrf_gpiote_regw_sideeffects_CONFIG(inst, idx);
266 }
267 
nrf_gpiote_task_force(NRF_GPIOTE_Type * p_reg,uint32_t idx,nrf_gpiote_outinit_t init_val)268 void nrf_gpiote_task_force(NRF_GPIOTE_Type *    p_reg,
269                            uint32_t             idx,
270                            nrf_gpiote_outinit_t init_val)
271 {
272     uint inst = gpiote_number_from_ptr(p_reg);
273     p_reg->CONFIG[idx] = (p_reg->CONFIG[idx] & ~GPIOTE_CONFIG_OUTINIT_Msk) |
274                          ((init_val << GPIOTE_CONFIG_OUTINIT_Pos) & GPIOTE_CONFIG_OUTINIT_Msk);
275     nrf_gpiote_regw_sideeffects_CONFIG(inst, idx);
276 }
277 
nrf_gpiote_te_default(NRF_GPIOTE_Type * p_reg,uint32_t idx)278 void nrf_gpiote_te_default(NRF_GPIOTE_Type * p_reg, uint32_t idx)
279 {
280     uint inst = gpiote_number_from_ptr(p_reg);
281     p_reg->CONFIG[idx] = 0;
282 #if !defined(NRF51_SERIES) && !defined(NRF52_SERIES)
283     p_reg->CONFIG[idx] = 0;
284 #endif
285     nrf_gpiote_regw_sideeffects_CONFIG(inst, idx);
286 }
287 
288 #if defined(DPPI_PRESENT)
nrf_gpiote_subscribe_common(NRF_GPIOTE_Type * p_reg,nrf_gpiote_task_t task)289 static void nrf_gpiote_subscribe_common(NRF_GPIOTE_Type * p_reg,
290                                         nrf_gpiote_task_t task)
291 {
292   uint inst = gpiote_number_from_ptr(p_reg);
293   int task_nbr;
294 
295   if ((task >= NRF_GPIOTE_TASK_OUT_0) && (task < NRF_GPIOTE_TASK_SET_0)) {
296     task_nbr = (task - NRF_GPIOTE_TASK_OUT_0)/sizeof(uint32_t);
297     nhw_gpiote_regw_sideeffects_SUBSCRIBE_OUT(inst, task_nbr);
298   } else if ((task >= NRF_GPIOTE_TASK_SET_0) && (task < NRF_GPIOTE_TASK_CLR_0)) {
299     task_nbr = (task - NRF_GPIOTE_TASK_SET_0)/sizeof(uint32_t);
300     nhw_gpiote_regw_sideeffects_SUBSCRIBE_SET(inst, task_nbr );
301   } else if (task >= NRF_GPIOTE_TASK_CLR_0) {
302     task_nbr = (task - NRF_GPIOTE_TASK_CLR_0)/sizeof(uint32_t);
303     nhw_gpiote_regw_sideeffects_SUBSCRIBE_CLR(inst, task_nbr);
304   } else {
305     bs_trace_error_line_time("Attempted to subscribe to a not-supported task in the nrf_timer (%i)\n",
306                              task);
307   }
308 }
309 
nrf_gpiote_subscribe_set(NRF_GPIOTE_Type * p_reg,nrf_gpiote_task_t task,uint8_t channel)310 void nrf_gpiote_subscribe_set(NRF_GPIOTE_Type * p_reg,
311                               nrf_gpiote_task_t task,
312                               uint8_t           channel)
313 {
314     *((volatile uint32_t *) ((uint8_t *) p_reg + (uint32_t) task + 0x80uL)) =
315             ((uint32_t)channel | NRF_SUBSCRIBE_PUBLISH_ENABLE);
316     nrf_gpiote_subscribe_common(p_reg, task);
317 }
318 
nrf_gpiote_subscribe_clear(NRF_GPIOTE_Type * p_reg,nrf_gpiote_task_t task)319 void nrf_gpiote_subscribe_clear(NRF_GPIOTE_Type * p_reg, nrf_gpiote_task_t task)
320 {
321     *((volatile uint32_t *) ((uint8_t *) p_reg + (uint32_t) task + 0x80uL)) = 0;
322     nrf_gpiote_subscribe_common(p_reg, task);
323 }
324 #endif // defined(DPPI_PRESENT)
325