1 /*
2  * Copyright (c) 2023 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /*
8  * GPIO - General purpose input/output
9  * https://infocenter.nordicsemi.com/topic/ps_nrf52833/gpio.html?cp=5_1_0_5_7
10  *
11  * This model has the following limitations:
12  *  * Note a.1:
13  *    PIN_CNF.PULL is ignored. If a pin input is disconnected and not driven externally it will
14  *    just remain at zero/low.
15  *  * Note a.2:
16  *    PIN_CNF.DRIVE / drive strength is ignored
17  *    It is not possible to connect two outputs together building a logical AND or OR
18  *  * Note a.3:
19  *    Reading OUTCLR & DIRCLR reads always 0
20  *  * Note a.4: There is no modeling of system idle/off, and as such a DETECT raising edge from the
21  *    GPIO will not cause the system to exit those states.
22  *
23  * This model has the following approximations:
24  *  * Note b.1:
25  *    If a DIR bit is cleared for a pin which was being driven as a high output,
26  *    that pin will be lowered immediately (like if it was driven low)
27  *  * Note b.2:
28  *    All drives are instantaneous.
29  *  * Note b.3:
30  *    During pin reconfigurations, there can be spurious transitions in the pins outputs
31  *    which may not correspond to how the real HW would behave
32  *  * In real HW, after a write to LATCH, the DETECT event output to the GPIOTE is kept low for
33  *    a few clocks, before being raised again (if it needs to), in the model the new pulse/raise
34  *    is sent instantaneously to the GPIOTE
35  */
36 
37 #include <stdint.h>
38 #include <stdbool.h>
39 #include <string.h>
40 #include "NHW_common_types.h"
41 #include "NHW_config.h"
42 #include "NHW_common_types.h"
43 #include "NHW_config.h"
44 #include "NHW_peri_types.h"
45 #include "NRF_GPIO.h"
46 #include "NRF_GPIOTE.h"
47 #include "bs_tracing.h"
48 #include "nsi_tasks.h"
49 
50 NRF_GPIO_Type NRF_GPIO_regs[NRF_GPIOS];
51 
52 /* Number of pins per port: */
53 static int GPIO_n_ports_pins[NRF_GPIOS] = NRF_GPIO_PORTS_PINS;
54 
55 static uint32_t IO_level[NRF_GPIOS]; /* Actual level in the pin */
56 static uint32_t DETECT[NRF_GPIOS];   /* Sense output / unlatched/non-sticky detect */
57 static uint32_t LDETECT[NRF_GPIOS];  /* Latched sense output */
58 static bool DETECT_signal[NRF_GPIOS]; /* Individual detect signal to the GPIOTE */
59 
60 static uint32_t INPUT_mask[NRF_GPIOS]; /* As a 32bit mask, PIN_CNF[*].INPUT (0: enabled; 1: disabled)*/
61 static uint32_t SENSE_mask[NRF_GPIOS]; /* As a 32bit mask, PIN_CNF[*].SENSE.en (1: enabled; 0: disabled)*/
62 static uint32_t SENSE_inv[NRF_GPIOS];  /* As a 32bit mask, PIN_CNF[*].SENSE.inv (1: inverted;0: not inverted) */
63 
64 /*
65  * Is the output driven by another peripheral (1) or the GPIO directly (0).
66  * Note that we don't keep track of who "owns" a pin, only that somebody else does
67  */
68 static uint32_t out_override[NRF_GPIOS];
69 /* Out value provided by other peripherals */
70 static uint32_t external_OUT[NRF_GPIOS];
71 
72 /* Is the pin input controlled by a peripheral(1) or the GPIO(0) */
73 static uint32_t input_override[NRF_GPIOS];
74 /* If input_override, is the peripheral configuring the input buffer as connected (1) or disconnected (0) */
75 static uint32_t input_override_connected[NRF_GPIOS];
76 
77 /* Is "dir" controlled by a peripheral(1) or the GPIO(0) */
78 static uint32_t dir_override[NRF_GPIOS];
79 /* If dir_override is set, is the peripheral configuring the output as connected (1) or disconnected (0) */
80 static uint32_t dir_override_set[NRF_GPIOS];
81 
82 /* Callbacks for peripherals to be informed of input changes */
83 static nrf_gpio_input_callback_t per_intoggle_callbacks[NRF_GPIOS][NRF_GPIO_MAX_PINS_PER_PORT];
84 static nrf_gpio_input_callback_t test_intoggle_callback;
85 
86 /*
87  * Initialize the GPIOs model
88  */
nrf_gpio_init(void)89 static void nrf_gpio_init(void) {
90 	memset(NRF_GPIO_regs, 0, sizeof(NRF_GPIO_regs));
91 
92 	for (int p = 0; p < NRF_GPIOS; p ++) {
93 		for (int n = 0; n < GPIO_n_ports_pins[p]; n++) {
94 			NRF_GPIO_regs[p].PIN_CNF[n] = 0x2; /* Disconnected out of reset */
95 		}
96 		INPUT_mask[p] = UINT32_MAX; /* All disconnected out of reset */
97 	}
98 
99 	nrf_gpio_backend_init();
100 }
101 
102 NSI_TASK(nrf_gpio_init, HW_INIT, 100);
103 
nrf_gpio_get_number_pins_in_port(int port)104 unsigned int nrf_gpio_get_number_pins_in_port(int port) {
105 	return GPIO_n_ports_pins[port];
106 }
107 
108 static void nrf_gpio_eval_outputs(unsigned int port);
109 static void nrf_gpio_eval_inputs(unsigned int port);
110 void nrf_gpio_eval_input(unsigned int port, unsigned int n, bool value);
111 
112 /*
113  * Register a test callback to be called whenever a pin IN register changes
114  */
nrf_gpio_test_register_in_callback(nrf_gpio_input_callback_t fptr)115 void nrf_gpio_test_register_in_callback(nrf_gpio_input_callback_t fptr) {
116 	test_intoggle_callback = fptr;
117 }
118 
119 /*
120  * Change a pin input value
121  *
122  * Note: The pin must not be currently driven by the SOC, or you will get an error
123  *
124  * Inputs:
125  *  * port: Which GPIO port
126  *  * n: which pin in that GPIO port
127  *  * value: true: high, false: low
128  */
nrf_gpio_test_change_pin_level(unsigned int port,unsigned int n,bool value)129 void nrf_gpio_test_change_pin_level(unsigned int port, unsigned int n, bool value) {
130 	nrf_gpio_eval_input(port, n, value);
131 }
132 
133 /*
134  * Get a pin level
135  *
136  * Inputs:
137  *  * port: Which GPIO port
138  *  * n: which pin in that GPIO port
139  * Return: true (high), false (low)
140  */
nrf_gpio_get_pin_level(unsigned int port,unsigned int n)141 bool nrf_gpio_get_pin_level(unsigned int port, unsigned int n) {
142 	return (IO_level[port] >> n) & 0x1;
143 }
144 
145 #define CHECK_PIN_EXISTS(port, n, dir) \
146 	if (port >= NRF_GPIOS || n >= GPIO_n_ports_pins[port]) { \
147 		bs_trace_error_time_line("%s: Error, attempted to toggle "dir" for nonexistent " \
148 					"GPIO port %i, pin %i\n", \
149 					__func__, port, n); \
150 	}
151 
get_enabled_inputs(unsigned int port)152 static inline uint32_t get_enabled_inputs(unsigned int port){
153 	return (~input_override[port] & ~INPUT_mask[port])
154 		| (input_override[port] & input_override_connected[port]);
155 }
156 
get_dir(unsigned int port)157 static inline uint32_t get_dir(unsigned int port){
158 	return (~dir_override[port] & NRF_GPIO_regs[port].DIR)
159 		| (dir_override[port] & dir_override_set[port]);
160 }
161 
162 /*
163  * Function with which another peripheral can claim configuration control of a pin.
164  *
165  * Inputs:
166  *	* port: Which GPIO port
167  *	* n : which pin in that GPIO port
168  *	* override_output:
169  *		* -1 : Don't change
170  *		*  0 : Leave for GPIO control (GPIO OUT register sets the output value)
171  *		*  1 : Take external control of pin output value (peripheral sets the output value
172  *		       with nrf_gpio_peri_change_output() )
173  *	* override_input:
174  *		* -1 : Don't change
175  *		*  0 : Leave input to be controlled by the GPIO module
176  *		*  2 : Take external control of input, and disconnect
177  *		*  3 : Take external control of input, and connect
178  *	* override_dir:
179  *		* -1 : Don't change
180  *		*  0 : Leave DIR to be controlled by the GPIO module
181  *		*  2 : Take external control of DIR, and disconnect
182  *		*  3 : Take external control of DIR, and connect
183  *      * fptr: Function to be called whenever that input toggles (if enabled).
184  *              Set to NULL if not needed.
185  *      * new_level:
186  *              * -1: Don't change
187  *              *  0: low
188  *              *  1: high
189  */
nrf_gpio_peri_pin_control(unsigned int port,unsigned int n,int override_output,int override_input,int override_dir,nrf_gpio_input_callback_t fptr,int new_level)190 void nrf_gpio_peri_pin_control(unsigned int port, unsigned int n,
191 			      int override_output, int override_input, int override_dir,
192 			      nrf_gpio_input_callback_t fptr, int new_level) {
193 
194 	if (port >= NRF_GPIOS || n >= GPIO_n_ports_pins[port]) { /* LCOV_EXCL_BR_LINE */
195 		bs_trace_error_time_line("Programming error\n"); /* LCOV_EXCL_LINE */
196 	}
197 
198 	uint32_t mask = 1<<n;
199 	bool need_output_eval = false;
200 	bool need_input_eval = false;
201 
202 	if (override_output >= 0) {
203 		out_override[port] &= ~mask;
204 		out_override[port] |= (uint32_t)(override_output?1:0) << n;
205 		need_output_eval = true;
206 	}
207 	if (override_input >= 0) {
208 		input_override[port] &= ~mask;
209 		input_override[port] |= (uint32_t)(override_input?1:0) << n;
210 
211 		input_override_connected[port] &= ~mask;
212 		input_override_connected[port] |= (uint32_t)(override_input==3?1:0) << n;
213 
214 		need_input_eval = true;
215 	}
216 	if (override_dir >= 0) {
217 		dir_override[port] &= ~mask;
218 		dir_override[port] |= (uint32_t)(override_dir?1:0) << n;
219 
220 		dir_override_set[port] &= ~mask;
221 		dir_override_set[port] |= (uint32_t)(override_dir==3?1:0) << n;
222 
223 		need_output_eval = true;
224 	}
225 	per_intoggle_callbacks[port][n] = fptr;
226 	if (new_level >= 0) {
227 		external_OUT[port] &= ~((uint32_t)1 << n);
228 		external_OUT[port] |= (uint32_t)(new_level?1:0) << n;
229 		need_output_eval = true;
230 	}
231 
232 	if (need_output_eval) {
233 		nrf_gpio_eval_outputs(port);
234 	}
235 	if (need_input_eval) {
236 		nrf_gpio_eval_inputs(port);
237 	}
238 }
239 
240 /*
241  * A peripheral wants to toggle a GPIO output to a new value <value>.
242  * Note: The value may be the same as it was, in which case nothing will happen.
243  *
244  * Inputs:
245  *  * port is the GPIO port
246  *  * n is the pin number inside that GPIO port (0..31)
247  *  * value is the new output value high (true) or low (false)
248  */
nrf_gpio_peri_change_output(unsigned int port,unsigned int n,bool value)249 void nrf_gpio_peri_change_output(unsigned int port, unsigned int n, bool value)
250 {
251 	CHECK_PIN_EXISTS(port, n, "output"); /* LCOV_EXCL_BR_LINE */
252 
253 	if (((out_override[port] >> n) & 0x1) != 1) { /* LCOV_EXCL_START */
254 		bs_trace_error_time_line("%s: Programming error, a peripheral is trying to toggle "
255 					"a GPIO output it does not own, GPIO port %i, pin %i\n",
256 					__func__, port, n);
257 	}
258 
259 	if (((get_dir(port) >> n) & 0x1) != 1) {
260 		bs_trace_warning_time_line("%s: A peripheral is trying to toggle "
261 					   "a GPIO output but the output is disabled, "
262 					   "GPIO port %i, pin %i\n",
263 					   __func__, port, n);
264 	} /* LCOV_EXCL_STOP */
265 
266 	external_OUT[port] &= ~((uint32_t)1 << n);
267 	external_OUT[port] |= (uint32_t)value << n;
268 	nrf_gpio_eval_outputs(port);
269 }
270 
nrf_gpio_update_detect_signal(unsigned int port)271 static void nrf_gpio_update_detect_signal(unsigned int port) {
272 	if (NRF_GPIO_regs[port].DETECTMODE == 0){ //gpio.detect signal from not latched detect
273 		DETECT_signal[port] = (DETECT[port] != 0);
274 	} else {//gpio.detect signal from latched detect
275 		DETECT_signal[port] = (LDETECT[port] != 0);
276 	}
277 }
278 
279 /*
280  * Evaluate sense output (after a change of input or configuration)
281  */
nrf_gpio_eval_sense(unsigned int port)282 static void nrf_gpio_eval_sense(unsigned int port){
283 	/* Note SENSE_dir inverts the output */
284 	DETECT[port] = (NRF_GPIO_regs[port].IN ^ SENSE_inv[port]) & SENSE_mask[port];
285 	LDETECT[port] |= DETECT[port];
286 	NRF_GPIO_regs[port].LATCH = LDETECT[port];
287 
288 	bool old_DETECT_signal = DETECT_signal[port];
289 
290 	nrf_gpio_update_detect_signal(port);
291 
292 	if ((DETECT_signal[port] == true) && (old_DETECT_signal==false)) {
293 		nrf_gpiote_port_event_raise(port);
294 	}
295 }
296 
297 /*
298  * Return the level of the DETECT output signal for a GPIO instance
299  *
300  * input: port: The GPIO instance number
301  */
nrf_gpio_get_detect_level(unsigned int port)302 bool nrf_gpio_get_detect_level(unsigned int port){
303 	return DETECT_signal[port];
304 }
305 
306 /*
307  * The input has changed and the driver is connected,
308  * notify as necessary
309  */
nrf_gpio_input_change_sideeffects(unsigned int port,unsigned int n)310 static void nrf_gpio_input_change_sideeffects(unsigned int port,unsigned int n)
311 {
312 	if (per_intoggle_callbacks[port][n] != NULL) {
313 		per_intoggle_callbacks[port][n](port, n, (NRF_GPIO_regs[port].IN >> n) & 0x1);
314 	}
315 	if (test_intoggle_callback != NULL) {
316 		test_intoggle_callback(port, n, (NRF_GPIO_regs[port].IN >> n) & 0x1);
317 	}
318 }
319 
320 /*
321  * Get the level of the IN signal for GPIO <port> pin <n>
322  */
nrf_gpio_get_IN(unsigned int port,unsigned int n)323 bool nrf_gpio_get_IN(unsigned int port, unsigned int n) {
324 	return (NRF_GPIO_regs[port].IN >> n) & 0x1;
325 }
326 
327 /*
328  * An input pin has toggled or the input configuration has changed,
329  * propagate it
330  */
nrf_gpio_eval_inputs(unsigned int port)331 static void nrf_gpio_eval_inputs(unsigned int port)
332 {
333 	uint32_t new_IN = IO_level[port] & get_enabled_inputs(port);
334 
335 	uint32_t diff = new_IN ^ NRF_GPIO_regs[port].IN;
336 
337 	NRF_GPIO_regs[port].IN = new_IN;
338 
339 	for (int n = __builtin_ffs(diff) - 1; n >= 0; n = __builtin_ffs(diff) - 1) {
340 		nrf_gpio_input_change_sideeffects(port, n);
341 		diff &= ~(1 << n);
342 	}
343 
344 	nrf_gpio_eval_sense(port);
345 }
346 
347 /*
348  * An input *may* be changing to a new value <value>.
349  * Note: The value may be the same as it was, in which case nothing will happen.
350  *
351  * This function is meant to be called from something which drives the input
352  * **externally**
353  *
354  * Inputs:
355  *  * port is the GPIO port
356  *  * n is the pin number inside that GPIO port (0..31)
357  *  * value: is the input high (true) or low (false)
358  */
nrf_gpio_eval_input(unsigned int port,unsigned int n,bool value)359 void nrf_gpio_eval_input(unsigned int port, unsigned int n, bool value)
360 {
361 	CHECK_PIN_EXISTS(port, n, "input"); /* LCOV_EXCL_BR_LINE */
362 
363 	uint32_t dir = get_dir(port);
364 
365 	if ((dir >> n) & 0x1) { /* LCOV_EXCL_START */
366 		bs_trace_warning_time_line("%s: Attempted to drive externally a pin which is "
367 					   "currently being driven by the SOC. It will be ignored."
368 					   "GPIO port %i, pin %i\n",
369 					   __func__, port, n);
370 		return;
371 	}			/* LCOV_EXCL_STOP */
372 
373 	int diff = ((IO_level[port] >> n) & 0x1) ^ (uint32_t)value;
374 
375 	if (diff == 0) {
376 		/* No toggle */
377 		return;
378 	}
379 
380 	IO_level[port] ^= (uint32_t)1 << n;
381 
382 	nrf_gpio_eval_inputs(port);
383 }
384 
385 /*
386  * The output is being changed, propagate it as necessary and/or record it.
387  */
nrf_gpio_output_change_sideeffects(unsigned int port,unsigned int n,bool value)388 static void nrf_gpio_output_change_sideeffects(unsigned int port,unsigned  int n, bool value)
389 {
390 	nrf_gpio_backend_write_output_change(port, n, value);
391 	nrf_gpio_backend_short_propagate(port, n, value);
392 }
393 
394 /*
395  * Reevaluate outputs after a configuration or OUT/external_OUT change
396  */
nrf_gpio_eval_outputs(unsigned int port)397 static void nrf_gpio_eval_outputs(unsigned int port)
398 {
399 	/* Actual level in the pin, but only of the bits driven by output: */
400 	static uint32_t O_level[NRF_GPIOS];
401 
402 	uint32_t dir = get_dir(port); /* Which pins are driven by output */
403 
404 	uint32_t out = (~out_override[port] & NRF_GPIO_regs[port].OUT)
405 			| (out_override[port] & external_OUT[port]);
406 
407 	uint32_t new_output = dir & out;
408 
409 	uint32_t diff = new_output ^ O_level[port];
410 
411 	if (diff == 0) {
412 		return;
413 	}
414 
415 	O_level[port] = new_output;
416 
417 	IO_level[port] &= ~dir;
418 	IO_level[port] |= O_level[port];
419 
420 	for (int n = __builtin_ffs(diff) - 1; n >= 0; n = __builtin_ffs(diff) - 1) {
421 		nrf_gpio_output_change_sideeffects(port, n, (new_output >> n) & 0x1);
422 		diff &= ~(1 << n);
423 	}
424 
425 	/* Inputs may be connected to pins driven by outputs, let's check */
426 	nrf_gpio_eval_inputs(port);
427 }
428 
429 
430 /*
431  * Register write side-effecting functions:
432  */
433 
nrf_gpio_regw_sideeffects_OUT(unsigned int port)434 void nrf_gpio_regw_sideeffects_OUT(unsigned int port) {
435 	nrf_gpio_eval_outputs(port);
436 }
437 
nrf_gpio_regw_sideeffects_OUTSET(unsigned int port)438 void nrf_gpio_regw_sideeffects_OUTSET(unsigned int port) {
439 	if (NRF_GPIO_regs[port].OUTSET) {
440 		NRF_GPIO_regs[port].OUT |= NRF_GPIO_regs[port].OUTSET;
441 		nrf_gpio_eval_outputs(port);
442 	}
443 	NRF_GPIO_regs[port].OUTSET = NRF_GPIO_regs[port].OUT;
444 }
445 
nrf_gpio_regw_sideeffects_OUTCLR(unsigned int port)446 void nrf_gpio_regw_sideeffects_OUTCLR(unsigned int port) {
447 	if (NRF_GPIO_regs[port].OUTCLR) {
448 		NRF_GPIO_regs[port].OUT &= ~NRF_GPIO_regs[port].OUTCLR;
449 		NRF_GPIO_regs[port].OUTCLR = 0;
450 		nrf_gpio_eval_outputs(port);
451 	}
452 }
453 
nrf_gpio_regw_sideeffects_DIR(unsigned int port)454 void nrf_gpio_regw_sideeffects_DIR(unsigned int port) {
455 	/* Mirror change into PIN_CNF[*].DIR */
456 	for (int n = 0; n < GPIO_n_ports_pins[port]; n++ ) {
457 		NRF_GPIO_regs[port].PIN_CNF[n] &= ~GPIO_PIN_CNF_DIR_Msk;
458 		NRF_GPIO_regs[port].PIN_CNF[n] |= (NRF_GPIO_regs[port].DIR >> n) & 0x1;
459 	}
460 
461 	nrf_gpio_eval_outputs(port);
462 }
463 
nrf_gpio_regw_sideeffects_DIRSET(unsigned int port)464 void nrf_gpio_regw_sideeffects_DIRSET(unsigned int port) {
465 	if (NRF_GPIO_regs[port].DIRSET) {
466 		NRF_GPIO_regs[port].DIR |= NRF_GPIO_regs[port].DIRSET;
467 		nrf_gpio_regw_sideeffects_DIR(port);
468 	}
469 	NRF_GPIO_regs[port].DIRSET = NRF_GPIO_regs[port].DIR;
470 }
471 
nrf_gpio_regw_sideeffects_DIRCLR(unsigned int port)472 void nrf_gpio_regw_sideeffects_DIRCLR(unsigned int port) {
473 	if (NRF_GPIO_regs[port].DIRCLR) {
474 		NRF_GPIO_regs[port].DIR &= ~NRF_GPIO_regs[port].DIRCLR;
475 		NRF_GPIO_regs[port].DIRCLR = 0;
476 		nrf_gpio_regw_sideeffects_DIR(port);
477 	}
478 }
479 
nrf_gpio_regw_sideeffects_LATCH(unsigned int port)480 void nrf_gpio_regw_sideeffects_LATCH(unsigned int port) {
481 
482 	/* LATCH contains what SW wrote: */
483 	uint32_t sw_input = NRF_GPIO_regs[port].LATCH;
484 
485 	/* Whatever bits SW set to 1, it is trying to clear: */
486 	LDETECT[port] &= ~sw_input;
487 
488 	/* But where the sense output is high, the bits are kept high: */
489 	LDETECT[port] |= DETECT[port];
490 
491 	NRF_GPIO_regs[port].LATCH = LDETECT[port];
492 
493 	nrf_gpio_update_detect_signal(port);
494 
495 	/*
496 	 * Note the text from the spec:
497 	 *   If one or more bits in the LATCH register are '1' after the CPU has
498 	 *   performed a clear operation on the LATCH registers, a rising edge will be generated
499 	 *   on the LDETECT signal.
500 	 * "the CPU has performed a clear operation" == after writing LATCH with any bit to 1
501 	 */
502 	if (sw_input != 0 && LDETECT[port] != 0 && NRF_GPIO_regs[port].DETECTMODE == 1) {
503 		nrf_gpiote_port_event_raise(port);
504 	}
505 }
506 
nrf_gpio_regw_sideeffects_DETECTMODE(unsigned int port)507 void nrf_gpio_regw_sideeffects_DETECTMODE(unsigned int port) {
508 	nrf_gpio_eval_sense(port);
509 }
510 
nrf_gpio_regw_sideeffects_PIN_CNF(unsigned int port,unsigned int n)511 void nrf_gpio_regw_sideeffects_PIN_CNF(unsigned int port,unsigned  int n) {
512 
513 	bool need_output_eval = false;
514 	bool need_input_eval = false;
515 	bool need_sense_eval = false;
516 
517 	int dir = NRF_GPIO_regs[port].PIN_CNF[n] & GPIO_PIN_CNF_DIR_Msk;
518 
519 	if (dir != ((NRF_GPIO_regs[port].DIR >> n) & 0x1)) {
520 		NRF_GPIO_regs[port].DIR ^= 1 << n;
521 		need_output_eval = true;
522 	}
523 
524 	/* Note: DRIVE and PULL are not yet used in this model
525 	int pull = (NRF_GPIO_regs[port].PIN_CNF[n] & GPIO_PIN_CNF_PULL_Msk)
526 					>> GPIO_PIN_CNF_PULL_Pos;
527 
528 	int drive = (NRF_GPIO_regs[port].PIN_CNF[n] & GPIO_PIN_CNF_DRIVE_Msk)
529 					>> GPIO_PIN_CNF_DRIVE_Pos;
530 	*/
531 
532 	int input = (NRF_GPIO_regs[port].PIN_CNF[n] & GPIO_PIN_CNF_INPUT_Msk)
533 			>> GPIO_PIN_CNF_INPUT_Pos;
534 	if (input != ((INPUT_mask[port] >> n) & 0x1)) {
535 		INPUT_mask[port] ^= 1 << n;
536 		need_input_eval = true;
537 	}
538 
539 	int sense = (NRF_GPIO_regs[port].PIN_CNF[n] & GPIO_PIN_CNF_SENSE_Msk)
540 			>> GPIO_PIN_CNF_SENSE_Pos;
541 	if (((sense >> 1) & 0x1) != ((SENSE_mask[port] >> n) & 0x1)) {
542 		SENSE_mask[port] ^= 1 << n;
543 		need_sense_eval = true;
544 	}
545 	if ((sense & 0x1) != ((SENSE_inv[port] >> n) & 0x1)) {
546 		SENSE_inv[port] ^= 1 << n;
547 		need_sense_eval = true;
548 	}
549 
550 	if (need_output_eval) {
551 		nrf_gpio_eval_outputs(port);
552 	}
553 	if (need_input_eval) {
554 		nrf_gpio_eval_inputs(port);
555 	}
556 	if (need_sense_eval) {
557 		nrf_gpio_eval_sense(port);
558 	}
559 }
560