1 /*
2  * Copyright (c) 2023 Intel Corporation
3  * Copyright 2024 NXP
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include "test_gpio.h"
9 
10 static struct drv_data data;
11 static int cb_cnt;
12 
callback(const struct device * dev,struct gpio_callback * gpio_cb,uint32_t pins)13 static void callback(const struct device *dev,
14 		     struct gpio_callback *gpio_cb, uint32_t pins)
15 {
16 	/*= checkpoint: pins should be marked with correct pin number bit =*/
17 	zassert_equal(pins, BIT(PIN_IN),
18 		      "unexpected pins %x", pins);
19 
20 	++cb_cnt;
21 }
22 
ZTEST(after_flash_gpio_config_trigger,test_gpio_config_twice_trigger)23 ZTEST(after_flash_gpio_config_trigger, test_gpio_config_twice_trigger)
24 {
25 	const struct device *const dev_in = DEVICE_DT_GET(DEV_IN);
26 	const struct device *const dev_out = DEVICE_DT_GET(DEV_OUT);
27 	struct drv_data *drv_data = &data;
28 	int ret;
29 
30 	cb_cnt = 0;
31 
32 	ret = gpio_pin_configure(dev_out, PIN_OUT, GPIO_DISCONNECTED);
33 	if (ret == -ENOTSUP) {
34 		TC_PRINT("NOTE: cannot configure pin as disconnected; trying as input\n");
35 		ret = gpio_pin_configure(dev_out, PIN_OUT, GPIO_INPUT | GPIO_PULL_UP);
36 	}
37 	zassert_ok(ret, "config PIN_OUT failed");
38 
39 	/* 1. Configure PIN_IN callback */
40 	ret = gpio_pin_configure(dev_in, PIN_IN, GPIO_INPUT);
41 	zassert_ok(ret, "config PIN_IN failed");
42 
43 	gpio_init_callback(&drv_data->gpio_cb, callback, BIT(PIN_IN));
44 	ret = gpio_add_callback(dev_in, &drv_data->gpio_cb);
45 	zassert_ok(ret, "add callback failed");
46 
47 	/* 2. Enable PIN callback as both edges */
48 	ret = gpio_pin_interrupt_configure(dev_in, PIN_IN, GPIO_INT_EDGE_BOTH);
49 	if (ret == -ENOTSUP) {
50 		TC_PRINT("Both edge GPIO interrupt not supported.\n");
51 		gpio_remove_callback(dev_in, &drv_data->gpio_cb);
52 	} else {
53 		zassert_ok(ret, "enable callback failed");
54 	}
55 
56 	/* 3. Configure PIN_OUT as open drain, internal pull-up (may trigger
57 	 * callback)
58 	 */
59 	ret = gpio_pin_configure(dev_out, PIN_OUT, GPIO_OUTPUT | GPIO_OPEN_DRAIN | GPIO_PULL_UP);
60 	if (ret == -ENOTSUP) {
61 		TC_PRINT("Open drain not supported.\n");
62 		gpio_remove_callback(dev_in, &drv_data->gpio_cb);
63 		ztest_test_skip();
64 		return;
65 	}
66 	zassert_ok(ret, "config PIN_OUT failed");
67 
68 	/* 4. Configure PIN_OUT again (should not trigger callback)  */
69 	ret = gpio_pin_configure(dev_out, PIN_OUT, GPIO_OUTPUT | GPIO_OPEN_DRAIN | GPIO_PULL_UP);
70 	zassert_ok(ret, "config PIN_OUT twice failed");
71 
72 	/* 5. Wait a bit and ensure that interrupt happened at most once */
73 	k_sleep(K_MSEC(10));
74 	zassert_between_inclusive(cb_cnt, 0, 1, "Got %d interrupts", cb_cnt);
75 
76 	ret = gpio_pin_interrupt_configure(dev_in, PIN_IN, GPIO_INT_DISABLE);
77 	if (ret == -ENOTSUP) {
78 		TC_PRINT("GPIO_INT_DISABLE not supported.\n");
79 	} else {
80 		zassert_ok(ret, "interrupt disabling failed");
81 	}
82 
83 	gpio_remove_callback(dev_in, &drv_data->gpio_cb);
84 }
85 
ZTEST(after_flash_gpio_config_trigger,test_gpio_config_trigger)86 ZTEST(after_flash_gpio_config_trigger, test_gpio_config_trigger)
87 {
88 	const struct device *const dev_in = DEVICE_DT_GET(DEV_IN);
89 	const struct device *const dev_out = DEVICE_DT_GET(DEV_OUT);
90 	struct drv_data *drv_data = &data;
91 	int ret;
92 
93 	cb_cnt = 0;
94 
95 	ret = gpio_pin_configure(dev_out, PIN_OUT, GPIO_DISCONNECTED);
96 	if (ret == -ENOTSUP) {
97 		TC_PRINT("NOTE: cannot configure pin as disconnected; trying as input\n");
98 		ret = gpio_pin_configure(dev_out, PIN_OUT, GPIO_INPUT | GPIO_PULL_UP);
99 	}
100 	zassert_ok(ret, "config PIN_OUT failed");
101 
102 	/* 1. Configure PIN_IN callback */
103 	ret = gpio_pin_configure(dev_in, PIN_IN, GPIO_INPUT);
104 	zassert_ok(ret, "config PIN_IN failed");
105 
106 	gpio_init_callback(&drv_data->gpio_cb, callback, BIT(PIN_IN));
107 	ret = gpio_add_callback(dev_in, &drv_data->gpio_cb);
108 	zassert_ok(ret, "add callback failed");
109 
110 	/* 2. Enable PIN callback as both edges */
111 	ret = gpio_pin_interrupt_configure(dev_in, PIN_IN, GPIO_INT_EDGE_BOTH);
112 	if (ret == -ENOTSUP) {
113 		TC_PRINT("Both edge GPIO interrupt not supported.\n");
114 		gpio_remove_callback(dev_in, &drv_data->gpio_cb);
115 	} else {
116 		zassert_ok(ret, "enable callback failed");
117 	}
118 
119 	/* 3. Configure PIN_OUT as open drain, internal pull-up (may trigger
120 	 * callback)
121 	 */
122 	ret = gpio_pin_configure(dev_out, PIN_OUT, GPIO_OUTPUT | GPIO_OPEN_DRAIN | GPIO_PULL_UP);
123 	if (ret == -ENOTSUP) {
124 		TC_PRINT("Open drain not supported.\n");
125 		gpio_remove_callback(dev_in, &drv_data->gpio_cb);
126 		ztest_test_skip();
127 		return;
128 	}
129 	zassert_ok(ret, "config PIN_OUT failed");
130 
131 	/* 4. Wait a bit and ensure that interrupt happened at most once */
132 	k_sleep(K_MSEC(10));
133 	zassert_between_inclusive(cb_cnt, 0, 1, "Got %d interrupts", cb_cnt);
134 
135 	ret = gpio_pin_interrupt_configure(dev_in, PIN_IN, GPIO_INT_DISABLE);
136 	if (ret == -ENOTSUP) {
137 		TC_PRINT("GPIO_INT_DISABLE not supported.\n");
138 	} else {
139 		zassert_ok(ret, "interrupt disabling failed");
140 	}
141 
142 	gpio_remove_callback(dev_in, &drv_data->gpio_cb);
143 }
144