1 /*
2  * Copyright (c) 2019 Piotr Mienkowski
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 
8 #include <limits.h>
9 #include <zephyr/sys/util.h>
10 #include "test_gpio_api.h"
11 
12 struct gpio_callback gpio_cb;
13 static int cb_count;
14 static int cb_count_target;
15 
callback_edge(const struct device * port,struct gpio_callback * cb,gpio_port_pins_t pins)16 static void callback_edge(const struct device *port, struct gpio_callback *cb,
17 			  gpio_port_pins_t pins)
18 {
19 	zassert_equal(pins, BIT(TEST_PIN),
20 		     "Detected interrupt on an invalid pin");
21 	cb_count++;
22 }
23 
callback_level(const struct device * port,struct gpio_callback * cb,gpio_port_pins_t pins)24 static void callback_level(const struct device *port,
25 			   struct gpio_callback *cb,
26 			   gpio_port_pins_t pins)
27 {
28 	int ret;
29 
30 	zassert_equal(pins, BIT(TEST_PIN),
31 		     "Detected interrupt on an invalid pin");
32 
33 	cb_count++;
34 	if (cb_count % cb_count_target == 0) {
35 		ret = gpio_pin_interrupt_configure(port, TEST_PIN, GPIO_INT_DISABLE);
36 		zassert_equal(ret, 0,
37 				  "Failed to disable pin interrupt in the callback");
38 	}
39 }
40 
pin_set_and_verify(const struct device * port,unsigned int pin,int val,int idx)41 static void pin_set_and_verify(const struct device *port, unsigned int pin,
42 			       int val,
43 			       int idx)
44 {
45 	zassert_equal(gpio_pin_set(port, pin, val), 0,
46 		      "Test point %d: failed to set logical pin value", idx);
47 	k_busy_wait(TEST_GPIO_MAX_RISE_FALL_TIME_US);
48 }
49 
test_gpio_pin_interrupt_edge(unsigned int cfg_flags,unsigned int int_flags)50 void test_gpio_pin_interrupt_edge(unsigned int cfg_flags,
51 				  unsigned int int_flags)
52 {
53 	const struct device *port;
54 	int cb_count_expected;
55 	unsigned int cfg_out_flag;
56 	int ret;
57 
58 	port = DEVICE_DT_GET(TEST_NODE);
59 	zassert_true(device_is_ready(port), "GPIO dev is not ready");
60 
61 	TC_PRINT("Running test on port=%s, pin=%d\n", port->name, TEST_PIN);
62 
63 	ret = gpio_pin_configure(port, TEST_PIN, GPIO_INPUT | GPIO_OUTPUT);
64 	if (ret == -ENOTSUP) {
65 		TC_PRINT("Simultaneous pin in/out mode is not supported.\n");
66 		ztest_test_skip();
67 		return;
68 	}
69 	zassert_equal(ret, 0, "Failed to configure the pin");
70 
71 	if ((cfg_flags & GPIO_ACTIVE_LOW) != 0) {
72 		cfg_out_flag = GPIO_OUTPUT_HIGH;
73 	} else {
74 		cfg_out_flag = GPIO_OUTPUT_LOW;
75 	}
76 	ret = gpio_pin_configure(port, TEST_PIN, GPIO_INPUT | cfg_out_flag |
77 				 cfg_flags);
78 	zassert_equal(ret, 0, "Failed to configure the pin");
79 
80 	cb_count = 0;
81 	cb_count_expected = 0;
82 
83 	gpio_init_callback(&gpio_cb, callback_edge, BIT(TEST_PIN));
84 	ret = gpio_add_callback(port, &gpio_cb);
85 
86 	ret = gpio_pin_interrupt_configure(port, TEST_PIN, int_flags);
87 	if (ret == -ENOTSUP) {
88 		TC_PRINT("Pin interrupt is not supported.\n");
89 		ztest_test_skip();
90 		return;
91 	}
92 	zassert_equal(ret, 0, "Failed to configure pin interrupt");
93 
94 	for (int i = 0; i < 6; i++) {
95 		pin_set_and_verify(port, TEST_PIN, 1, i);
96 		if (int_flags & GPIO_INT_HIGH_1) {
97 			cb_count_expected++;
98 		}
99 		zassert_equal(cb_count, cb_count_expected,
100 			      "Test point %d: Pin interrupt triggered invalid "
101 			      "number of times on rising/to active edge", i);
102 
103 		pin_set_and_verify(port, TEST_PIN, 0, i);
104 		if (int_flags & GPIO_INT_LOW_0) {
105 			cb_count_expected++;
106 		}
107 		zassert_equal(cb_count, cb_count_expected,
108 			      "Test point %d: Pin interrupt triggered invalid "
109 			      "number of times on falling/to inactive edge", i);
110 	}
111 
112 	ret = gpio_pin_interrupt_configure(port, TEST_PIN, GPIO_INT_DISABLE);
113 	zassert_equal(ret, 0, "Failed to disable pin interrupt");
114 
115 	for (int i = 0; i < 6; i++) {
116 		pin_set_and_verify(port, TEST_PIN, 1, i);
117 		pin_set_and_verify(port, TEST_PIN, 0, i);
118 		zassert_equal(cb_count, cb_count_expected,
119 			      "Pin interrupt triggered when disabled");
120 	}
121 }
122 
test_gpio_pin_interrupt_level(unsigned int cfg_flags,unsigned int int_flags,unsigned int interrupt_calls)123 void test_gpio_pin_interrupt_level(unsigned int cfg_flags,
124 				   unsigned int int_flags, unsigned int interrupt_calls)
125 {
126 	const struct device *port;
127 	int cb_count_expected;
128 	unsigned int cfg_out_flag;
129 	int pin_out_val;
130 	int ret;
131 
132 	port = DEVICE_DT_GET(TEST_NODE);
133 	zassert_true(device_is_ready(port), "GPIO dev is not ready");
134 
135 	TC_PRINT("Running test on port=%s, pin=%d\n", port->name, TEST_PIN);
136 
137 	ret = gpio_pin_configure(port, TEST_PIN, GPIO_INPUT | GPIO_OUTPUT);
138 	if (ret == -ENOTSUP) {
139 		TC_PRINT("Simultaneous pin in/out mode is not supported.\n");
140 		ztest_test_skip();
141 		return;
142 	}
143 	zassert_equal(ret, 0, "Failed to configure the pin");
144 
145 	pin_out_val = ((int_flags & GPIO_INT_HIGH_1) != 0) ? 0 : 1;
146 
147 	if ((cfg_flags & GPIO_ACTIVE_LOW) != 0) {
148 		cfg_out_flag = (pin_out_val != 0) ? GPIO_OUTPUT_LOW :
149 						    GPIO_OUTPUT_HIGH;
150 	} else {
151 		cfg_out_flag = (pin_out_val != 0) ? GPIO_OUTPUT_HIGH :
152 						    GPIO_OUTPUT_LOW;
153 	}
154 
155 	ret = gpio_pin_configure(port, TEST_PIN, GPIO_INPUT | cfg_out_flag |
156 				 cfg_flags);
157 	zassert_equal(ret, 0, "Failed to configure the pin");
158 
159 	cb_count = 0;
160 	cb_count_expected = 0;
161 	cb_count_target = interrupt_calls;
162 
163 	gpio_init_callback(&gpio_cb, callback_level, BIT(TEST_PIN));
164 	ret = gpio_add_callback(port, &gpio_cb);
165 
166 	ret = gpio_pin_interrupt_configure(port, TEST_PIN, int_flags);
167 	if (ret == -ENOTSUP) {
168 		TC_PRINT("Pin interrupt is not supported.\n");
169 		ztest_test_skip();
170 		return;
171 	}
172 	zassert_equal(ret, 0, "Failed to configure pin interrupt");
173 
174 	zassert_equal(cb_count, cb_count_expected,
175 		      "Pin interrupt triggered on level %d", pin_out_val);
176 
177 	for (int i = 0; i < 6; i++) {
178 		pin_out_val = (pin_out_val != 0) ? 0 : 1;
179 		pin_set_and_verify(port, TEST_PIN, pin_out_val, i);
180 		cb_count_expected += interrupt_calls;
181 		zassert_equal(cb_count, cb_count_expected,
182 			      "Test point %d: Pin interrupt triggered invalid "
183 			      "number of times on level %d", i, pin_out_val);
184 
185 		pin_out_val = (pin_out_val != 0) ? 0 : 1;
186 		pin_set_and_verify(port, TEST_PIN, pin_out_val, i);
187 		zassert_equal(cb_count, cb_count_expected,
188 			      "Test point %d: Pin interrupt triggered invalid "
189 			      "number of times on level %d", i, pin_out_val);
190 
191 		/* Re-enable pin level interrupt */
192 		ret = gpio_pin_interrupt_configure(port, TEST_PIN, int_flags);
193 		zassert_equal(ret, 0,
194 			      "Failed to re-enable pin level interrupt");
195 	}
196 
197 	ret = gpio_pin_interrupt_configure(port, TEST_PIN, GPIO_INT_DISABLE);
198 	zassert_equal(ret, 0, "Failed to disable pin interrupt");
199 
200 	for (int i = 0; i < 6; i++) {
201 		pin_set_and_verify(port, TEST_PIN, 1, i);
202 		pin_set_and_verify(port, TEST_PIN, 0, i);
203 		zassert_equal(cb_count, cb_count_expected,
204 			      "Pin interrupt triggered when disabled");
205 	}
206 }
207 
208 /** @brief Verify GPIO_INT_EDGE_RISING flag. */
ZTEST(gpio_api_1pin_int,test_gpio_int_edge_rising)209 ZTEST(gpio_api_1pin_int, test_gpio_int_edge_rising)
210 {
211 	test_gpio_pin_interrupt_edge(0, GPIO_INT_EDGE_RISING);
212 }
213 
214 /** @brief Verify GPIO_INT_EDGE_FALLING flag. */
ZTEST(gpio_api_1pin_int,test_gpio_int_edge_falling)215 ZTEST(gpio_api_1pin_int, test_gpio_int_edge_falling)
216 {
217 	test_gpio_pin_interrupt_edge(0, GPIO_INT_EDGE_FALLING);
218 }
219 
220 /** @brief Verify GPIO_INT_EDGE_BOTH flag. */
ZTEST(gpio_api_1pin_int,test_gpio_int_edge_both)221 ZTEST(gpio_api_1pin_int, test_gpio_int_edge_both)
222 {
223 	test_gpio_pin_interrupt_edge(0, GPIO_INT_EDGE_BOTH);
224 }
225 
226 /** @brief Verify GPIO_INT_EDGE_TO_ACTIVE flag. */
ZTEST(gpio_api_1pin_int,test_gpio_int_edge_to_active)227 ZTEST(gpio_api_1pin_int, test_gpio_int_edge_to_active)
228 {
229 	TC_PRINT("Step 1: Configure pin as active high\n");
230 	test_gpio_pin_interrupt_edge(GPIO_ACTIVE_HIGH, GPIO_INT_EDGE_TO_ACTIVE);
231 	TC_PRINT("Step 2: Configure pin as active low\n");
232 	test_gpio_pin_interrupt_edge(GPIO_ACTIVE_LOW, GPIO_INT_EDGE_TO_ACTIVE);
233 }
234 
235 /** @brief Verify GPIO_INT_EDGE_TO_INACTIVE flag. */
ZTEST(gpio_api_1pin_int,test_gpio_int_edge_to_inactive)236 ZTEST(gpio_api_1pin_int, test_gpio_int_edge_to_inactive)
237 {
238 	TC_PRINT("Step 1: Configure pin as active high\n");
239 	test_gpio_pin_interrupt_edge(GPIO_ACTIVE_HIGH, GPIO_INT_EDGE_TO_INACTIVE);
240 	TC_PRINT("Step 2: Configure pin as active low\n");
241 	test_gpio_pin_interrupt_edge(GPIO_ACTIVE_LOW, GPIO_INT_EDGE_TO_INACTIVE);
242 }
243 
244 /** @brief Verify GPIO_INT_LEVEL_HIGH flag with 1 interrupt call */
ZTEST(gpio_api_1pin_int,test_gpio_int_level_high_interrupt_count_1)245 ZTEST(gpio_api_1pin_int, test_gpio_int_level_high_interrupt_count_1)
246 {
247 	test_gpio_pin_interrupt_level(0, GPIO_INT_LEVEL_HIGH, 1);
248 }
249 
250 /** @brief Verify GPIO_INT_LEVEL_HIGH flag with 5 interrupt call */
ZTEST(gpio_api_1pin_int,test_gpio_int_level_high_interrupt_count_5)251 ZTEST(gpio_api_1pin_int, test_gpio_int_level_high_interrupt_count_5)
252 {
253 	test_gpio_pin_interrupt_level(0, GPIO_INT_LEVEL_HIGH, 5);
254 }
255 
256 /** @brief Verify GPIO_INT_LEVEL_LOW flag with 1 interrupt call */
ZTEST(gpio_api_1pin_int,test_gpio_int_level_low_interrupt_count_1)257 ZTEST(gpio_api_1pin_int, test_gpio_int_level_low_interrupt_count_1)
258 {
259 	test_gpio_pin_interrupt_level(0, GPIO_INT_LEVEL_LOW, 1);
260 }
261 
262 /** @brief Verify GPIO_INT_LEVEL_LOW flag with 5 interrupt call */
ZTEST(gpio_api_1pin_int,test_gpio_int_level_low_interrupt_count_5)263 ZTEST(gpio_api_1pin_int, test_gpio_int_level_low_interrupt_count_5)
264 {
265 	test_gpio_pin_interrupt_level(0, GPIO_INT_LEVEL_LOW, 5);
266 }
267 
268 /** @brief Verify GPIO_INT_LEVEL_ACTIVE flag. */
ZTEST(gpio_api_1pin_int,test_gpio_int_level_active)269 ZTEST(gpio_api_1pin_int, test_gpio_int_level_active)
270 {
271 	TC_PRINT("Step 1: Configure pin as active high\n");
272 	test_gpio_pin_interrupt_level(GPIO_ACTIVE_HIGH, GPIO_INT_LEVEL_ACTIVE, 1);
273 	TC_PRINT("Step 2: Configure pin as active low\n");
274 	test_gpio_pin_interrupt_level(GPIO_ACTIVE_LOW, GPIO_INT_LEVEL_ACTIVE, 1);
275 }
276 
277 /** @brief Verify GPIO_INT_LEVEL_INACTIVE flag. */
ZTEST(gpio_api_1pin_int,test_gpio_int_level_inactive)278 ZTEST(gpio_api_1pin_int, test_gpio_int_level_inactive)
279 {
280 	TC_PRINT("Step 1: Configure pin as active high\n");
281 	test_gpio_pin_interrupt_level(GPIO_ACTIVE_HIGH, GPIO_INT_LEVEL_INACTIVE, 1);
282 	TC_PRINT("Step 2: Configure pin as active low\n");
283 	test_gpio_pin_interrupt_level(GPIO_ACTIVE_LOW, GPIO_INT_LEVEL_INACTIVE, 1);
284 }
285 
286 ZTEST_SUITE(gpio_api_1pin_int, NULL, NULL, NULL, NULL, NULL);
287