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