1 /*
2  * Copyright (c) 2020 Friedt Professional Engineering Services, Inc
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/device.h>
8 #include <zephyr/drivers/gpio.h>
9 #include <zephyr/drivers/gpio/gpio_emul.h>
10 #include <zephyr/sys/util.h>
11 #include <zephyr/kernel.h>
12 
13 #include "test_gpio.h"
14 
15 /*
16  * When GPIO are emulated, this callback can be used to implement the
17  * "wiring". E.g. in this test application, PIN_OUT is connected to
18  * PIN_IN. When PIN_OUT is set high or low, PIN_IN must be set
19  * correspondingly, as if a wire were connecting the two.
20  */
21 static void gpio_emul_callback_handler(const struct device *port,
22 				      struct gpio_callback *cb,
23 				      gpio_port_pins_t pins);
24 
25 struct gpio_callback gpio_emul_callback = {
26 	.handler = gpio_emul_callback_handler,
27 	.pin_mask = BIT(PIN_IN) | BIT(PIN_OUT),
28 };
29 
gpio_emul_callback_handler(const struct device * port,struct gpio_callback * cb,gpio_port_pins_t pins)30 static void gpio_emul_callback_handler(const struct device *port,
31 				      struct gpio_callback *cb,
32 				      gpio_port_pins_t pins)
33 {
34 	int r;
35 	int val;
36 	uint32_t output_flags;
37 	uint32_t input_flags;
38 
39 	__ASSERT(pins & gpio_emul_callback.pin_mask, "invalid mask: %x", pins);
40 
41 	r = gpio_emul_flags_get(port, PIN_OUT, &output_flags);
42 	__ASSERT(r == 0, "gpio_emul_flags_get() failed: %d", r);
43 	r = gpio_emul_flags_get(port, PIN_IN, &input_flags);
44 	__ASSERT(r == 0, "gpio_emul_flags_get() failed: %d", r);
45 
46 	if ((output_flags & GPIO_OUTPUT) && (input_flags & GPIO_INPUT)) {
47 		r = gpio_emul_output_get(port, PIN_OUT);
48 		__ASSERT(r == 0 || r == 1, "gpio_emul_output_get() failed: %d", r);
49 		val = r;
50 		r = gpio_emul_input_set(port, PIN_IN, val);
51 		__ASSERT(r == 0, "gpio_emul_input_set() failed: %d", r);
52 
53 		return;
54 	}
55 
56 	if ((output_flags == GPIO_DISCONNECTED) && (input_flags & GPIO_INPUT)) {
57 		if (input_flags & GPIO_PULL_UP) {
58 			val = 1;
59 		} else {
60 			/* either GPIO_PULL_DOWN or no input */
61 			val = 0;
62 		}
63 
64 		r = gpio_emul_input_set(port, PIN_IN, val);
65 		__ASSERT(r == 0, "gpio_emul_input_set() failed: %d", r);
66 
67 		return;
68 	}
69 }
70