1 /*
2  * Copyright (c) 2015 - 2023, Nordic Semiconductor ASA
3  *
4  * Modifications to the GPIO 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 of the functions below is taken from the NRFx HAL with minor
10  * modifications, specially:
11  * 	nrf_gpio_cfg()
12  * 	nrf_gpio_reconfigure()
13  * 	nrf_gpio_port_pin_output_set()
14  * 	nrf_gpio_port_pin_input_set()
15  * 	nrf_gpio_pin_dir_set()
16  * 	nrf_gpio_pin_toggle()
17  * 	nrf_gpio_port_detect_latch_set()
18  * 	nrf_gpio_pin_latch_clear()
19  * 	nrf_gpio_latches_read_and_clear()
20  * For that code, the original license applies:
21  *
22  * SPDX-License-Identifier: BSD-3-Clause
23  *
24  * Redistribution and use in source and binary forms, with or without
25  * modification, are permitted provided that the following conditions are met:
26  *
27  * 1. Redistributions of source code must retain the above copyright notice, this
28  *    list of conditions and the following disclaimer.
29  *
30  * 2. Redistributions in binary form must reproduce the above copyright
31  *    notice, this list of conditions and the following disclaimer in the
32  *    documentation and/or other materials provided with the distribution.
33  *
34  * 3. Neither the name of the copyright holder nor the names of its
35  *    contributors may be used to endorse or promote products derived from this
36  *    software without specific prior written permission.
37  *
38  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
39  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
42  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
43  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
44  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
45  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
46  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
47  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
48  * POSSIBILITY OF SUCH DAMAGE.
49  */
50 
51 #include <stdint.h>
52 #include "NRF_GPIO.h"
53 #include "hal/nrf_gpio.h"
54 #include "bs_tracing.h"
55 
gpio_number_from_ptr(NRF_GPIO_Type const * p_reg)56 static int gpio_number_from_ptr(NRF_GPIO_Type const * p_reg){
57 	int i = ( (int)p_reg - (int)&NRF_GPIO_regs[0] ) / sizeof(NRF_GPIO_Type);
58 	return i;
59 }
60 
61 extern NRF_GPIO_Type * nrf_gpio_pin_port_decode(uint32_t * p_pin);
62 
nrf_gpio_cfg(uint32_t pin_number,nrf_gpio_pin_dir_t dir,nrf_gpio_pin_input_t input,nrf_gpio_pin_pull_t pull,nrf_gpio_pin_drive_t drive,nrf_gpio_pin_sense_t sense)63 void nrf_gpio_cfg(
64     uint32_t             pin_number,
65     nrf_gpio_pin_dir_t   dir,
66     nrf_gpio_pin_input_t input,
67     nrf_gpio_pin_pull_t  pull,
68     nrf_gpio_pin_drive_t drive,
69     nrf_gpio_pin_sense_t sense)
70 {
71     NRF_GPIO_Type * reg = nrf_gpio_pin_port_decode(&pin_number);
72     uint32_t cnf = reg->PIN_CNF[pin_number];
73 
74     uint32_t to_update = GPIO_PIN_CNF_DIR_Msk    |
75                          GPIO_PIN_CNF_INPUT_Msk  |
76                          GPIO_PIN_CNF_PULL_Msk   |
77 #if defined(GPIO_PIN_CNF_DRIVE_Msk)
78                          GPIO_PIN_CNF_DRIVE_Msk  |
79 #else
80                          GPIO_PIN_CNF_DRIVE0_Msk |
81                          GPIO_PIN_CNF_DRIVE1_Msk |
82 #endif
83                          GPIO_PIN_CNF_SENSE_Msk;
84 
85     /* Clear fields that will be updated. */
86     cnf &= ~to_update;
87     cnf |= ((uint32_t)dir << GPIO_PIN_CNF_DIR_Pos)      |
88            ((uint32_t)input << GPIO_PIN_CNF_INPUT_Pos)  |
89            ((uint32_t)pull << GPIO_PIN_CNF_PULL_Pos)    |
90 #if defined(GPIO_PIN_CNF_DRIVE_Pos)
91            ((uint32_t)drive << GPIO_PIN_CNF_DRIVE_Pos)  |
92 #else
93            ((uint32_t)drive << GPIO_PIN_CNF_DRIVE0_Pos) |
94 #endif
95            ((uint32_t)sense << GPIO_PIN_CNF_SENSE_Pos);
96 
97     reg->PIN_CNF[pin_number] = cnf;
98 
99     nrf_gpio_regw_sideeffects_PIN_CNF(gpio_number_from_ptr(reg), pin_number);
100 }
101 
nrf_gpio_reconfigure(uint32_t pin_number,const nrf_gpio_pin_dir_t * p_dir,const nrf_gpio_pin_input_t * p_input,const nrf_gpio_pin_pull_t * p_pull,const nrf_gpio_pin_drive_t * p_drive,const nrf_gpio_pin_sense_t * p_sense)102 void nrf_gpio_reconfigure(uint32_t                     pin_number,
103                           const nrf_gpio_pin_dir_t *   p_dir,
104                           const nrf_gpio_pin_input_t * p_input,
105                           const nrf_gpio_pin_pull_t *  p_pull,
106                           const nrf_gpio_pin_drive_t * p_drive,
107                           const nrf_gpio_pin_sense_t * p_sense)
108 {
109     NRF_GPIO_Type * reg = nrf_gpio_pin_port_decode(&pin_number);
110     uint32_t cnf = reg->PIN_CNF[pin_number];
111     uint32_t to_update = (p_dir   ? GPIO_PIN_CNF_DIR_Msk                                : 0) |
112                          (p_input ? GPIO_PIN_CNF_INPUT_Msk                              : 0) |
113                          (p_pull  ? GPIO_PIN_CNF_PULL_Msk                               : 0) |
114 #if defined(GPIO_PIN_CNF_DRIVE_Msk)
115                          (p_drive ? GPIO_PIN_CNF_DRIVE_Msk                              : 0) |
116 #else
117                          (p_drive ? (GPIO_PIN_CNF_DRIVE0_Msk | GPIO_PIN_CNF_DRIVE1_Msk) : 0) |
118 #endif
119                          (p_sense ? GPIO_PIN_CNF_SENSE_Msk                              : 0);
120 
121     /* Clear fields that will be updated. */
122     cnf &= ~to_update;
123     cnf |= ((uint32_t)(p_dir   ? *p_dir   : 0) << GPIO_PIN_CNF_DIR_Pos)    |
124            ((uint32_t)(p_input ? *p_input : 0) << GPIO_PIN_CNF_INPUT_Pos)  |
125            ((uint32_t)(p_pull  ? *p_pull  : 0) << GPIO_PIN_CNF_PULL_Pos)   |
126 #if defined(GPIO_PIN_CNF_DRIVE_Pos)
127            ((uint32_t)(p_drive ? *p_drive : 0) << GPIO_PIN_CNF_DRIVE_Pos)  |
128 #else
129            ((uint32_t)(p_drive ? *p_drive : 0) << GPIO_PIN_CNF_DRIVE0_Pos) |
130 #endif
131            ((uint32_t)(p_sense ? *p_sense : 0)<< GPIO_PIN_CNF_SENSE_Pos);
132 
133     reg->PIN_CNF[pin_number] = cnf;
134 
135     nrf_gpio_regw_sideeffects_PIN_CNF(gpio_number_from_ptr(reg), pin_number);
136 }
137 
138 
nrf_gpio_port_pin_output_set(NRF_GPIO_Type * p_reg,uint32_t pin_number)139 void nrf_gpio_port_pin_output_set(NRF_GPIO_Type * p_reg, uint32_t pin_number)
140 {
141     uint32_t cnf = ((uint32_t)NRF_GPIO_PIN_DIR_OUTPUT << GPIO_PIN_CNF_DIR_Pos) |
142            ((uint32_t)NRF_GPIO_PIN_INPUT_DISCONNECT << GPIO_PIN_CNF_INPUT_Pos) |
143            ((uint32_t)NRF_GPIO_PIN_NOPULL << GPIO_PIN_CNF_PULL_Pos)            |
144 #if defined(GPIO_PIN_CNF_DRIVE_Pos)
145            ((uint32_t)NRF_GPIO_PIN_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)             |
146 #else
147            ((uint32_t)NRF_GPIO_PIN_S0S1 << GPIO_PIN_CNF_DRIVE0_Pos)            |
148 #endif
149            ((uint32_t)NRF_GPIO_PIN_NOSENSE << GPIO_PIN_CNF_SENSE_Pos);
150     p_reg->PIN_CNF[pin_number] = cnf;
151     nrf_gpio_regw_sideeffects_PIN_CNF(gpio_number_from_ptr(p_reg), pin_number);
152 }
153 
nrf_gpio_port_pin_input_set(NRF_GPIO_Type * p_reg,uint32_t pin_number,nrf_gpio_pin_pull_t pull_config)154 void nrf_gpio_port_pin_input_set(NRF_GPIO_Type *     p_reg,
155                                                    uint32_t            pin_number,
156                                                    nrf_gpio_pin_pull_t pull_config)
157 {
158     uint32_t cnf = ((uint32_t)NRF_GPIO_PIN_DIR_INPUT << GPIO_PIN_CNF_DIR_Pos) |
159            ((uint32_t)NRF_GPIO_PIN_INPUT_CONNECT << GPIO_PIN_CNF_INPUT_Pos)   |
160            ((uint32_t)pull_config << GPIO_PIN_CNF_PULL_Pos)                   |
161 #if defined(GPIO_PIN_CNF_DRIVE_Pos)
162            ((uint32_t)NRF_GPIO_PIN_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)            |
163 #else
164            ((uint32_t)NRF_GPIO_PIN_S0S1 << GPIO_PIN_CNF_DRIVE0_Pos)           |
165 #endif
166            ((uint32_t)NRF_GPIO_PIN_NOSENSE << GPIO_PIN_CNF_SENSE_Pos);
167     p_reg->PIN_CNF[pin_number] = cnf;
168     nrf_gpio_regw_sideeffects_PIN_CNF(gpio_number_from_ptr(p_reg), pin_number);
169 }
170 
nrf_gpio_pin_dir_set(uint32_t pin_number,nrf_gpio_pin_dir_t direction)171 void nrf_gpio_pin_dir_set(uint32_t pin_number, nrf_gpio_pin_dir_t direction)
172 {
173     if (direction == NRF_GPIO_PIN_DIR_INPUT)
174     {
175         nrf_gpio_cfg(
176             pin_number,
177             NRF_GPIO_PIN_DIR_INPUT,
178             NRF_GPIO_PIN_INPUT_CONNECT,
179             NRF_GPIO_PIN_NOPULL,
180             NRF_GPIO_PIN_S0S1,
181             NRF_GPIO_PIN_NOSENSE);
182     }
183     else
184     {
185         NRF_GPIO_Type * reg = nrf_gpio_pin_port_decode(&pin_number);
186         reg->DIRSET = (1UL << pin_number);
187 
188         nrf_gpio_regw_sideeffects_DIRSET(gpio_number_from_ptr(reg));
189     }
190 }
191 
nrf_gpio_pin_toggle(uint32_t pin_number)192 void nrf_gpio_pin_toggle(uint32_t pin_number)
193 {
194     NRF_GPIO_Type * reg        = nrf_gpio_pin_port_decode(&pin_number);
195     unsigned int port = gpio_number_from_ptr(reg);
196 
197     uint32_t        pins_state = reg->OUT;
198 
199     reg->OUTSET = (~pins_state & (1UL << pin_number));
200     nrf_gpio_regw_sideeffects_OUTSET(port);
201     reg->OUTCLR = (pins_state & (1UL << pin_number));
202     nrf_gpio_regw_sideeffects_OUTCLR(port);
203 }
204 
205 
nrf_gpio_port_dir_output_set(NRF_GPIO_Type * p_reg,uint32_t out_mask)206 void nrf_gpio_port_dir_output_set(NRF_GPIO_Type * p_reg, uint32_t out_mask)
207 {
208     p_reg->DIRSET = out_mask;
209     nrf_gpio_regw_sideeffects_DIRSET(gpio_number_from_ptr(p_reg));
210 }
211 
212 
nrf_gpio_port_dir_input_set(NRF_GPIO_Type * p_reg,uint32_t in_mask)213 void nrf_gpio_port_dir_input_set(NRF_GPIO_Type * p_reg, uint32_t in_mask)
214 {
215     p_reg->DIRCLR = in_mask;
216     nrf_gpio_regw_sideeffects_DIRCLR(gpio_number_from_ptr(p_reg));
217 }
218 
nrf_gpio_port_dir_write(NRF_GPIO_Type * p_reg,uint32_t value)219 void nrf_gpio_port_dir_write(NRF_GPIO_Type * p_reg, uint32_t value)
220 {
221     p_reg->DIR = value;
222     nrf_gpio_regw_sideeffects_DIR(gpio_number_from_ptr(p_reg));
223 }
224 
nrf_gpio_port_out_write(NRF_GPIO_Type * p_reg,uint32_t value)225 void nrf_gpio_port_out_write(NRF_GPIO_Type * p_reg, uint32_t value)
226 {
227     p_reg->OUT = value;
228     nrf_gpio_regw_sideeffects_OUT(gpio_number_from_ptr(p_reg));
229 }
230 
nrf_gpio_port_out_set(NRF_GPIO_Type * p_reg,uint32_t set_mask)231 void nrf_gpio_port_out_set(NRF_GPIO_Type * p_reg, uint32_t set_mask)
232 {
233     p_reg->OUTSET = set_mask;
234     nrf_gpio_regw_sideeffects_OUTSET(gpio_number_from_ptr(p_reg));
235 }
236 
237 
nrf_gpio_port_out_clear(NRF_GPIO_Type * p_reg,uint32_t clr_mask)238 void nrf_gpio_port_out_clear(NRF_GPIO_Type * p_reg, uint32_t clr_mask)
239 {
240     p_reg->OUTCLR = clr_mask;
241     nrf_gpio_regw_sideeffects_OUTCLR(gpio_number_from_ptr(p_reg));
242 }
243 
nrf_gpio_port_detect_latch_set(NRF_GPIO_Type * p_reg,bool enable)244 void nrf_gpio_port_detect_latch_set(NRF_GPIO_Type * p_reg, bool enable)
245 {
246     p_reg->DETECTMODE = (enable ? GPIO_DETECTMODE_DETECTMODE_LDETECT :
247                                   GPIO_DETECTMODE_DETECTMODE_Default);
248     nrf_gpio_regw_sideeffects_DETECTMODE(gpio_number_from_ptr(p_reg));
249 }
250 
nrf_gpio_latches_read_and_clear(uint32_t start_port,uint32_t length,uint32_t * p_masks)251 void nrf_gpio_latches_read_and_clear(uint32_t   start_port,
252                                      uint32_t   length,
253                                      uint32_t * p_masks)
254 {
255     NRF_GPIO_Type * gpio_regs[GPIO_COUNT] = GPIO_REG_LIST;
256     uint32_t        i;
257 
258     for (i = start_port; i < (start_port + length); i++)
259     {
260         *p_masks = gpio_regs[i]->LATCH;
261 
262         // The LATCH register is cleared by writing a '1' to the bit that shall be cleared.
263         gpio_regs[i]->LATCH = *p_masks;
264         nrf_gpio_regw_sideeffects_LATCH(gpio_number_from_ptr(gpio_regs[i]));
265 
266         p_masks++;
267     }
268 }
269 
nrf_gpio_pin_latch_clear(uint32_t pin_number)270 void nrf_gpio_pin_latch_clear(uint32_t pin_number)
271 {
272     NRF_GPIO_Type * reg = nrf_gpio_pin_port_decode(&pin_number);
273 
274     reg->LATCH = (1 << pin_number);
275     nrf_gpio_regw_sideeffects_LATCH(gpio_number_from_ptr(reg));
276 }
277