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 #define TEST_GPIO_MAX_SINGLE_ENDED_RISE_FALL_TIME_MS    100
13 #define TEST_POINT(n)   (n)
14 
pin_get_raw_and_verify(const struct device * port,unsigned int pin,int val_expected,int idx)15 static void pin_get_raw_and_verify(const struct device *port,
16 				   unsigned int pin,
17 				   int val_expected, int idx)
18 {
19 	int val_actual;
20 
21 	val_actual = gpio_pin_get_raw(port, pin);
22 	zassert_true(val_actual >= 0,
23 		     "Test point %d: failed to get pin value", idx);
24 	zassert_equal(val_expected, val_actual,
25 		      "Test point %d: invalid pin get value", idx);
26 }
27 
pin_set_raw_and_verify(const struct device * port,unsigned int pin,int val,int idx)28 static void pin_set_raw_and_verify(const struct device *port,
29 				   unsigned int pin,
30 				   int val, int idx)
31 {
32 	zassert_equal(gpio_pin_set_raw(port, pin, val), 0,
33 		      "Test point %d: failed to set pin value", idx);
34 	k_busy_wait(TEST_GPIO_MAX_RISE_FALL_TIME_US);
35 }
36 
37 /** @brief Verify gpio_pin_configure function in push pull mode.
38  *
39  * - Configure pin in in/out mode, verify that gpio_pin_set_raw /
40  *   gpio_pin_get_raw operations change pin state.
41  * - Verify that GPIO_OUTPUT_HIGH flag is initializing the pin to high.
42  * - Verify that GPIO_OUTPUT_LOW flag is initializing the pin to low.
43  * - Verify that configuring the pin as an output without initializing it
44  *   to high or low does not change pin state.
45  * - Verify that it is not possible to change value of a pin via
46  *   gpio_pin_set_raw function if pin is configured as an input.
47  */
ZTEST(gpio_api_1pin_conf,test_gpio_pin_configure_push_pull)48 ZTEST(gpio_api_1pin_conf, test_gpio_pin_configure_push_pull)
49 {
50 	const struct device *port;
51 	int ret;
52 
53 	port = DEVICE_DT_GET(TEST_NODE);
54 	zassert_true(device_is_ready(port), "GPIO dev is not ready");
55 
56 	TC_PRINT("Running test on port=%s, pin=%d\n", port->name, TEST_PIN);
57 
58 	ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT);
59 	zassert_equal(ret, 0, "Failed to configure the pin as an output");
60 
61 	pin_set_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(1));
62 	pin_set_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(1));
63 
64 	/* Configure pin in in/out mode, verify that gpio_pin_set_raw /
65 	 * gpio_pin_get_raw operations change pin state.
66 	 */
67 	ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT | GPIO_INPUT);
68 	if (ret == -ENOTSUP) {
69 		TC_PRINT("Simultaneous pin in/out mode is not supported.\n");
70 		ztest_test_skip();
71 		return;
72 	}
73 	zassert_equal(ret, 0, "Failed to configure the pin in in/out mode");
74 
75 	pin_set_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(2));
76 	pin_get_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(2));
77 
78 	pin_set_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(3));
79 	pin_get_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(3));
80 
81 	pin_set_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(4));
82 	pin_get_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(4));
83 
84 	/* Verify that GPIO_OUTPUT_HIGH flag is initializing the pin to high. */
85 	ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT_HIGH | GPIO_INPUT);
86 	zassert_equal(ret, 0,
87 		      "Failed to configure the pin in in/out mode and "
88 		      "initialize it to high");
89 
90 	pin_get_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(5));
91 
92 	/* Verify that configuring the pin as an output without initializing it
93 	 * to high or low does not change pin state.
94 	 */
95 	ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT | GPIO_INPUT);
96 	zassert_equal(ret, 0, "Failed to configure the pin in in/out mode");
97 
98 	pin_get_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(6));
99 
100 	/* Verify that GPIO_OUTPUT_LOW flag is initializing the pin to low. */
101 	ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT_LOW | GPIO_INPUT);
102 	zassert_equal(ret, 0,
103 		      "Failed to configure the pin in in/out mode and "
104 		      "initialize it to low");
105 
106 	pin_get_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(7));
107 
108 	/* Verify that configuring the pin as an output without initializing it
109 	 * to high or low does not change pin state.
110 	 */
111 	ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT | GPIO_INPUT);
112 	zassert_equal(ret, 0, "Failed to configure the pin in in/out mode");
113 
114 	pin_get_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(8));
115 
116 	/* Verify that it is not possible to change value of a pin via
117 	 * gpio_pin_set_raw function if pin is configured as an input.
118 	 */
119 	ret = gpio_pin_configure(port, TEST_PIN, GPIO_INPUT);
120 	zassert_equal(ret, 0, "Failed to configure the pin as an input");
121 	k_busy_wait(TEST_GPIO_MAX_RISE_FALL_TIME_US);
122 
123 	int pin_in_val;
124 
125 	pin_in_val = gpio_pin_get_raw(port, TEST_PIN);
126 	zassert_true(pin_in_val >= 0,
127 		     "Test point %d: failed to get pin value", TEST_POINT(9));
128 
129 	pin_set_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(10));
130 	pin_get_raw_and_verify(port, TEST_PIN, pin_in_val, TEST_POINT(10));
131 
132 	pin_set_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(11));
133 	pin_get_raw_and_verify(port, TEST_PIN, pin_in_val, TEST_POINT(11));
134 }
135 
136 /** @brief Verify gpio_pin_configure function in single ended mode.
137  *
138  * @note This test verifies single ended mode only partially. It should not be
139  *       used as a sign off test.
140  *
141  * - Verify that pin configured in Open Drain mode and initialized
142  *   to high results in pin high value if the same pin configured
143  *   as input is high. Drivers that do not support Open Drain flag
144  *   return ENOTSUP.
145  * - Setting pin configured in Open Drain mode to low results in
146  *   pin low value if the same pin configured as input is high.
147  * - Verify that pin configured in Open Source mode and
148  *   initialized to low results in pin high value if the same pin
149  *   configured as input is high. Drivers that do not support Open
150  *   Source flag return ENOTSUP.
151  * - Verify that pin configured in Open Source mode and
152  *   initialized to low results in pin low value if the same pin
153  *   configured as input is low. Drivers that do not support Open
154  *   Source flag return ENOTSUP.
155  * - Setting pin configured in Open Source mode to high results in
156  *   pin high value if the same pin configured as input is low.
157  * - Verify that pin configured in Open Drain mode and
158  *   initialized to high results in pin low value if the same pin
159  *   configured as input is low. Drivers that do not support Open
160  *   Drain flag return ENOTSUP.
161  */
ZTEST(gpio_api_1pin_conf,test_gpio_pin_configure_single_ended)162 ZTEST(gpio_api_1pin_conf, test_gpio_pin_configure_single_ended)
163 {
164 	const struct device *port;
165 	int pin_in_val;
166 	int pin_val;
167 	unsigned int cfg_flag;
168 	int ret;
169 
170 	port = DEVICE_DT_GET(TEST_NODE);
171 	zassert_true(device_is_ready(port), "GPIO dev is not ready");
172 
173 	TC_PRINT("Running test on port=%s, pin=%d\n", port->name, TEST_PIN);
174 
175 	/* If the LED is connected directly between the MCU pin and power or
176 	 * ground we can test only one of the Open Drain / Open Source modes.
177 	 * Guess pin level when the LED is off. If the pin is not connected
178 	 * directly to LED but instead the signal is routed to an input of
179 	 * another chip we could test both modes. However, there is no way to
180 	 * find it out so only one mode is tested.
181 	 */
182 	if ((TEST_PIN_DTS_FLAGS & GPIO_ACTIVE_LOW) != 0) {
183 		cfg_flag = GPIO_PULL_UP;
184 		pin_val = 1;
185 	} else {
186 		cfg_flag = GPIO_PULL_DOWN;
187 		pin_val = 0;
188 	}
189 
190 	/* Configure pin as an input with pull up/down and check input level. */
191 	ret = gpio_pin_configure(port, TEST_PIN, GPIO_INPUT | cfg_flag);
192 	if (ret == -ENOTSUP) {
193 		TC_PRINT("Pull Up / Pull Down pin bias is not supported\n");
194 		ztest_test_skip();
195 		return;
196 	}
197 	zassert_equal(ret, 0, "Failed to configure pin as an input");
198 
199 	k_sleep(K_MSEC(TEST_GPIO_MAX_SINGLE_ENDED_RISE_FALL_TIME_MS));
200 
201 	pin_in_val = gpio_pin_get_raw(port, TEST_PIN);
202 	zassert_true(pin_in_val >= 0, "Failed to get pin value");
203 
204 	if (pin_val != pin_in_val) {
205 		TC_PRINT("Board configuration does not allow to run the test\n");
206 		ztest_test_skip();
207 		return;
208 	}
209 
210 	if (pin_val == 1) {
211 		TC_PRINT("When configured as input test pin value is high\n");
212 		/* Verify that pin configured in Open Drain mode and initialized
213 		 * to high results in pin high value if the same pin configured
214 		 * as input is high. Drivers that do not support Open Drain flag
215 		 * return -ENOTSUP.
216 		 */
217 		ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT_HIGH |
218 				GPIO_OPEN_DRAIN | GPIO_INPUT | GPIO_PULL_UP);
219 		if (ret == -ENOTSUP) {
220 			TC_PRINT("Open Drain configuration or Pull Up pin "
221 				 "bias is not supported\n");
222 			ztest_test_skip();
223 			return;
224 		}
225 		zassert_equal(ret, 0,
226 			      "Failed to configure the pin in Open Drain mode");
227 
228 		pin_get_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(1));
229 
230 		/* Setting pin configured in Open Drain mode to low results in
231 		 * pin low value if the same pin configured as input is high.
232 		 */
233 		pin_set_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(2));
234 		pin_get_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(2));
235 
236 		/* Verify that pin configured in Open Source mode and
237 		 * initialized to low results in pin high value if the same pin
238 		 * configured as input is high. Drivers that do not support Open
239 		 * Source flag return -ENOTSUP.
240 		 */
241 		ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT_LOW |
242 				GPIO_OPEN_SOURCE | GPIO_INPUT | GPIO_PULL_UP);
243 		if (ret == -ENOTSUP) {
244 			TC_PRINT("Open Source configuration or Pull Up pin "
245 				 "bias is not supported\n");
246 			return;
247 		}
248 		zassert_equal(ret, 0,
249 			      "Failed to configure the pin in Open Source mode");
250 
251 		k_sleep(K_MSEC(TEST_GPIO_MAX_SINGLE_ENDED_RISE_FALL_TIME_MS));
252 
253 		pin_get_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(3));
254 
255 		pin_set_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(4));
256 		pin_get_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(4));
257 	} else {
258 		TC_PRINT("When configured as input test pin value is low\n");
259 		/* Verify that pin configured in Open Source mode and
260 		 * initialized to low results in pin low value if the same pin
261 		 * configured as input is low. Drivers that do not support Open
262 		 * Source flag return -ENOTSUP.
263 		 */
264 		ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT_LOW |
265 				GPIO_OPEN_SOURCE | GPIO_INPUT | GPIO_PULL_DOWN);
266 		if (ret == -ENOTSUP) {
267 			TC_PRINT("Open Source configuration or Pull Down pin "
268 				 "bias is not supported\n");
269 			ztest_test_skip();
270 			return;
271 		}
272 		zassert_equal(ret, 0,
273 			      "Failed to configure the pin in Open Source mode");
274 
275 		pin_get_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(5));
276 
277 		/* Setting pin configured in Open Source mode to high results in
278 		 * pin high value if the same pin configured as input is low.
279 		 */
280 		pin_set_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(6));
281 		pin_get_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(6));
282 
283 		/* Verify that pin configured in Open Drain mode and
284 		 * initialized to high results in pin low value if the same pin
285 		 * configured as input is low. Drivers that do not support Open
286 		 * Drain flag return -ENOTSUP.
287 		 */
288 		ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT_HIGH |
289 				GPIO_OPEN_DRAIN | GPIO_INPUT | GPIO_PULL_DOWN);
290 		if (ret == -ENOTSUP) {
291 			TC_PRINT("Open Drain configuration or Pull Down pin "
292 				 "bias is not supported\n");
293 			return;
294 		}
295 		zassert_equal(ret, 0,
296 			      "Failed to configure the pin in Open Drain mode");
297 
298 		k_sleep(K_MSEC(TEST_GPIO_MAX_SINGLE_ENDED_RISE_FALL_TIME_MS));
299 
300 		pin_get_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(7));
301 
302 		pin_set_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(8));
303 		pin_get_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(8));
304 	}
305 }
306 
307 ZTEST_SUITE(gpio_api_1pin_conf, NULL, NULL, NULL, NULL, NULL);
308