1 /*
2  * Copyright (c) 2016 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_in,struct gpio_callback * gpio_cb,uint32_t pins)13 static void callback(const struct device *dev_in, struct gpio_callback *gpio_cb,
14 		     uint32_t pins)
15 {
16 	const struct device *const dev_out = DEVICE_DT_GET(DEV_OUT);
17 	const struct drv_data *dd = CONTAINER_OF(gpio_cb,
18 						 struct drv_data, gpio_cb);
19 
20 	/*= checkpoint: pins should be marked with correct pin number bit =*/
21 	zassert_equal(pins, BIT(PIN_IN),
22 		      "unexpected pins %x", pins);
23 	++cb_cnt;
24 	TC_PRINT("callback triggered: %d\n", cb_cnt);
25 	if ((cb_cnt == 1)
26 	    && (dd->mode == GPIO_INT_EDGE_BOTH)) {
27 		gpio_pin_toggle(dev_out, PIN_OUT);
28 	}
29 	if (cb_cnt >= MAX_INT_CNT) {
30 		gpio_pin_set(dev_out, PIN_OUT, 0);
31 		gpio_pin_interrupt_configure(dev_in, PIN_IN, GPIO_INT_DISABLE);
32 	}
33 }
34 
test_callback(int mode)35 static int test_callback(int mode)
36 {
37 	const struct device *const dev_in = DEVICE_DT_GET(DEV_IN);
38 	const struct device *const dev_out = DEVICE_DT_GET(DEV_OUT);
39 	struct drv_data *drv_data = &data;
40 
41 	gpio_pin_interrupt_configure(dev_in, PIN_IN, GPIO_INT_DISABLE);
42 	gpio_pin_interrupt_configure(dev_out, PIN_OUT, GPIO_INT_DISABLE);
43 
44 	/* 1. set PIN_OUT to logical initial state inactive */
45 	uint32_t out_flags = GPIO_OUTPUT_LOW | PIN_OUT_FLAGS;
46 
47 	if ((mode & GPIO_INT_LOW_0) != 0) {
48 		out_flags = GPIO_OUTPUT_HIGH | GPIO_ACTIVE_LOW;
49 	}
50 
51 	int rc = gpio_pin_configure(dev_out, PIN_OUT, out_flags);
52 
53 	if (rc != 0) {
54 		TC_ERROR("PIN_OUT config fail: %d", rc);
55 		return TC_FAIL;
56 	}
57 
58 	/* 2. configure PIN_IN callback and trigger condition */
59 	rc = gpio_pin_configure(dev_in, PIN_IN, (GPIO_INPUT | PIN_IN_FLAGS));
60 	if (rc != 0) {
61 		TC_ERROR("config PIN_IN fail: %d\n", rc);
62 		goto err_exit;
63 	}
64 
65 	drv_data->mode = mode;
66 	gpio_init_callback(&drv_data->gpio_cb, callback, BIT(PIN_IN));
67 	rc = gpio_add_callback(dev_in, &drv_data->gpio_cb);
68 	if (rc == -ENOTSUP) {
69 		TC_PRINT("interrupts not supported\n");
70 		return TC_PASS;
71 	} else if (rc != 0) {
72 		TC_ERROR("set PIN_IN callback fail: %d\n", rc);
73 		return TC_FAIL;
74 	}
75 
76 	/* 3. enable callback, trigger PIN_IN interrupt by operate PIN_OUT */
77 	cb_cnt = 0;
78 	rc = gpio_pin_interrupt_configure(dev_in, PIN_IN, mode);
79 	if (rc == -ENOTSUP) {
80 		TC_PRINT("Mode %x not supported\n", mode);
81 		goto pass_exit;
82 	} else if (rc != 0) {
83 		TC_ERROR("config PIN_IN interrupt fail: %d\n", rc);
84 		goto err_exit;
85 	}
86 	k_sleep(K_MSEC(100));
87 	gpio_pin_set(dev_out, PIN_OUT, 1);
88 	k_sleep(K_MSEC(1000));
89 	(void)gpio_pin_interrupt_configure(dev_in, PIN_IN, GPIO_INT_DISABLE);
90 
91 	/*= checkpoint: check callback is triggered =*/
92 	TC_PRINT("OUT init %x, IN cfg %x, cnt %d\n", out_flags, mode, cb_cnt);
93 	if (mode == GPIO_INT_EDGE_BOTH) {
94 		if (cb_cnt != 2) {
95 			TC_ERROR("double edge not detected\n");
96 			goto err_exit;
97 		}
98 		goto pass_exit;
99 	}
100 	if ((mode & GPIO_INT_EDGE) == GPIO_INT_EDGE) {
101 		if (cb_cnt != 1) {
102 			TC_ERROR("edge not trigger callback correctly\n");
103 			goto err_exit;
104 		}
105 		goto pass_exit;
106 	} else {
107 		if (cb_cnt != MAX_INT_CNT) {
108 			TC_ERROR("level not trigger callback correctly\n");
109 			goto err_exit;
110 		}
111 	}
112 
113 pass_exit:
114 	gpio_remove_callback(dev_in, &drv_data->gpio_cb);
115 	return TC_PASS;
116 
117 err_exit:
118 	gpio_remove_callback(dev_in, &drv_data->gpio_cb);
119 	return TC_FAIL;
120 }
121 
122 /* export test cases */
ZTEST(gpio_port_cb_vari,test_gpio_callback_variants)123 ZTEST(gpio_port_cb_vari, test_gpio_callback_variants)
124 {
125 	zassert_equal(test_callback(GPIO_INT_EDGE_FALLING), TC_PASS,
126 		      "falling edge failed");
127 	zassert_equal(test_callback(GPIO_INT_EDGE_RISING), TC_PASS,
128 		      "rising edge failed");
129 	zassert_equal(test_callback(GPIO_INT_EDGE_TO_ACTIVE), TC_PASS,
130 		      "edge active failed");
131 	zassert_equal(test_callback(GPIO_INT_EDGE_TO_INACTIVE), TC_PASS,
132 		      "edge inactive failed");
133 	zassert_equal(test_callback(GPIO_INT_LEVEL_HIGH), TC_PASS,
134 		      "level high failed");
135 	zassert_equal(test_callback(GPIO_INT_LEVEL_LOW), TC_PASS,
136 		      "level low failed");
137 	zassert_equal(test_callback(GPIO_INT_LEVEL_ACTIVE), TC_PASS,
138 		      "level active failed");
139 	zassert_equal(test_callback(GPIO_INT_LEVEL_INACTIVE), TC_PASS,
140 		      "level inactive failed");
141 	zassert_equal(test_callback(GPIO_INT_EDGE_BOTH), TC_PASS,
142 		      "edge both failed");
143 }
144