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 cb_data[2];
11 static int cb_cnt[2];
12 
callback_1(const struct device * dev,struct gpio_callback * gpio_cb,uint32_t pins)13 static void callback_1(const struct device *dev,
14 		       struct gpio_callback *gpio_cb, uint32_t pins)
15 {
16 	TC_PRINT("%s triggered: %d\n", __func__, ++cb_cnt[0]);
17 
18 }
19 
callback_2(const struct device * dev,struct gpio_callback * gpio_cb,uint32_t pins)20 static void callback_2(const struct device *dev,
21 		       struct gpio_callback *gpio_cb, uint32_t pins)
22 {
23 	TC_PRINT("%s triggered: %d\n", __func__, ++cb_cnt[1]);
24 }
25 
callback_remove_self(const struct device * dev,struct gpio_callback * gpio_cb,uint32_t pins)26 static void callback_remove_self(const struct device *dev,
27 				 struct gpio_callback *gpio_cb, uint32_t pins)
28 {
29 	struct drv_data *dd = CONTAINER_OF(gpio_cb, struct drv_data, gpio_cb);
30 
31 	TC_PRINT("%s triggered: %d\n", __func__, ++cb_cnt[1]);
32 	dd->aux = gpio_remove_callback(dev, gpio_cb);
33 }
34 
init_callback(const struct device * dev_in,const struct device * dev_out,gpio_callback_handler_t handler_1,gpio_callback_handler_t handler_2)35 static int init_callback(const struct device *dev_in, const struct device *dev_out,
36 			 gpio_callback_handler_t handler_1, gpio_callback_handler_t handler_2)
37 {
38 	int rc = gpio_pin_interrupt_configure(dev_in, PIN_IN, GPIO_INT_DISABLE);
39 
40 	if (rc == 0) {
41 		rc = gpio_pin_interrupt_configure(dev_out, PIN_OUT, GPIO_INT_DISABLE);
42 	}
43 	if (rc == 0) {
44 		/* 1. set PIN_OUT */
45 		rc = gpio_pin_configure(dev_out, PIN_OUT, (GPIO_OUTPUT_LOW | PIN_OUT_FLAGS));
46 	}
47 
48 	if (rc == 0) {
49 		/* 2. configure PIN_IN callback, but don't enable */
50 		rc = gpio_pin_configure(dev_in, PIN_IN, (GPIO_INPUT | PIN_IN_FLAGS));
51 	}
52 
53 	if (rc == 0) {
54 		gpio_init_callback(&cb_data[0].gpio_cb, handler_1, BIT(PIN_IN));
55 		rc = gpio_add_callback(dev_in, &cb_data[0].gpio_cb);
56 	}
57 
58 	if (rc == 0) {
59 		gpio_init_callback(&cb_data[1].gpio_cb, handler_2, BIT(PIN_IN));
60 		rc = gpio_add_callback(dev_in, &cb_data[1].gpio_cb);
61 	}
62 
63 	return rc;
64 }
65 
trigger_callback(const struct device * dev_in,const struct device * dev_out,int enable_cb)66 static void trigger_callback(const struct device *dev_in, const struct device *dev_out,
67 			     int enable_cb)
68 {
69 	int rc;
70 
71 	gpio_pin_set(dev_out, PIN_OUT, 0);
72 	k_sleep(K_MSEC(100));
73 
74 	cb_cnt[0] = 0;
75 	cb_cnt[1] = 0;
76 	if (enable_cb == 1) {
77 		rc = gpio_pin_interrupt_configure(dev_in, PIN_IN, GPIO_INT_EDGE_RISING);
78 	} else {
79 		rc = gpio_pin_interrupt_configure(dev_in, PIN_IN, GPIO_INT_DISABLE);
80 	}
81 	zassert_equal(rc, 0);
82 	k_sleep(K_MSEC(100));
83 	gpio_pin_set(dev_out, PIN_OUT, 1);
84 	k_sleep(K_MSEC(1000));
85 }
86 
test_callback_add_remove(void)87 static int test_callback_add_remove(void)
88 {
89 	const struct device *const dev_in = DEVICE_DT_GET(DEV_IN);
90 	const struct device *const dev_out = DEVICE_DT_GET(DEV_OUT);
91 
92 	/* SetUp: initialize environment */
93 	int rc = init_callback(dev_in, dev_out, callback_1, callback_2);
94 
95 	if (rc == -ENOTSUP) {
96 		TC_PRINT("%s not supported\n", __func__);
97 		return TC_PASS;
98 	}
99 	zassert_equal(rc, 0,
100 		      "init_callback failed");
101 
102 	/* 3. enable callback, trigger PIN_IN interrupt by operate PIN_OUT */
103 	trigger_callback(dev_in, dev_out, 1);
104 	/*= checkpoint: check callback is triggered =*/
105 	if (cb_cnt[0] != 1 || cb_cnt[1] != 1) {
106 		TC_ERROR("not trigger callback correctly\n");
107 		goto err_exit;
108 	}
109 
110 	/* 4. remove callback_1 */
111 	gpio_remove_callback(dev_in, &cb_data[0].gpio_cb);
112 	trigger_callback(dev_in, dev_out, 1);
113 
114 	/*= checkpoint: check callback is triggered =*/
115 	if (cb_cnt[0] != 0 || cb_cnt[1] != 1) {
116 		TC_ERROR("not trigger callback correctly\n");
117 		goto err_exit;
118 	}
119 
120 	/* 5. remove callback_2 */
121 	gpio_remove_callback(dev_in, &cb_data[1].gpio_cb);
122 	trigger_callback(dev_in, dev_out, 1);
123 	/*= checkpoint: check callback is triggered =*/
124 	if (cb_cnt[0] != 0 || cb_cnt[1] != 0) {
125 		TC_ERROR("not trigger callback correctly\n");
126 		goto err_exit;
127 	}
128 	return TC_PASS;
129 
130 err_exit:
131 	gpio_remove_callback(dev_in, &cb_data[0].gpio_cb);
132 	gpio_remove_callback(dev_in, &cb_data[1].gpio_cb);
133 	return TC_FAIL;
134 }
135 
test_callback_self_remove(void)136 static int test_callback_self_remove(void)
137 {
138 	int res = TC_FAIL;
139 	const struct device *const dev_in = DEVICE_DT_GET(DEV_IN);
140 	const struct device *const dev_out = DEVICE_DT_GET(DEV_OUT);
141 
142 	/* SetUp: initialize environment */
143 	int rc = init_callback(dev_in, dev_out, callback_1, callback_remove_self);
144 
145 	if (rc == -ENOTSUP) {
146 		TC_PRINT("%s not supported\n", __func__);
147 		return TC_PASS;
148 	}
149 	zassert_equal(rc, 0,
150 		      "init_callback failed");
151 
152 	gpio_pin_set(dev_out, PIN_OUT, 0);
153 	k_sleep(K_MSEC(100));
154 
155 	cb_data[0].aux = INT_MAX;
156 	cb_data[1].aux = INT_MAX;
157 
158 	/* 3. enable callback, trigger PIN_IN interrupt by operate PIN_OUT */
159 	trigger_callback(dev_in, dev_out, 1);
160 
161 	/*= checkpoint: check both callbacks are triggered =*/
162 	if (cb_cnt[0] != 1 || cb_cnt[1] != 1) {
163 		TC_ERROR("not trigger callback correctly\n");
164 		goto err_exit;
165 	}
166 
167 	/*= checkpoint: check remove executed is invoked =*/
168 	if (cb_data[0].aux != INT_MAX || cb_data[1].aux != 0) {
169 		TC_ERROR("not remove callback correctly\n");
170 		goto err_exit;
171 	}
172 
173 	/* 4 enable callback, trigger PIN_IN interrupt by operate PIN_OUT */
174 	trigger_callback(dev_in, dev_out, 1);
175 
176 	/*= checkpoint: check only remaining callback is triggered =*/
177 	if (cb_cnt[0] != 1 || cb_cnt[1] != 0) {
178 		TC_ERROR("not trigger remaining callback correctly\n");
179 		goto err_exit;
180 	}
181 
182 	res = TC_PASS;
183 
184 err_exit:
185 	gpio_remove_callback(dev_in, &cb_data[0].gpio_cb);
186 	gpio_remove_callback(dev_in, &cb_data[1].gpio_cb);
187 	return res;
188 }
189 
test_callback_enable_disable(void)190 static int test_callback_enable_disable(void)
191 {
192 	const struct device *const dev_in = DEVICE_DT_GET(DEV_IN);
193 	const struct device *const dev_out = DEVICE_DT_GET(DEV_OUT);
194 
195 	/* SetUp: initialize environment */
196 	int rc = init_callback(dev_in, dev_out, callback_1, callback_2);
197 
198 	if (rc == -ENOTSUP) {
199 		TC_PRINT("%s not supported\n", __func__);
200 		return TC_PASS;
201 	}
202 	zassert_equal(rc, 0,
203 		      "init_callback failed");
204 
205 	/* 3. enable callback, trigger PIN_IN interrupt by operate PIN_OUT */
206 	trigger_callback(dev_in, dev_out, 1);
207 	/*= checkpoint: check callback is triggered =*/
208 	if (cb_cnt[0] != 1 || cb_cnt[1] != 1) {
209 		TC_ERROR("not trigger callback correctly\n");
210 		goto err_exit;
211 	}
212 
213 	/* 4. disable callback */
214 	trigger_callback(dev_in, dev_out, 0);
215 	/*= checkpoint: check callback is triggered =*/
216 	if (cb_cnt[0] != 0 || cb_cnt[1] != 0) {
217 		TC_ERROR("not trigger callback correctly\n");
218 		goto err_exit;
219 	}
220 
221 	/* 5. enable callback again */
222 	trigger_callback(dev_in, dev_out, 1);
223 	/*= checkpoint: check callback is triggered =*/
224 	if (cb_cnt[0] != 1 || cb_cnt[1] != 1) {
225 		TC_ERROR("not trigger callback correctly\n");
226 		goto err_exit;
227 	}
228 	gpio_remove_callback(dev_in, &cb_data[0].gpio_cb);
229 	gpio_remove_callback(dev_in, &cb_data[1].gpio_cb);
230 	return TC_PASS;
231 
232 err_exit:
233 	gpio_remove_callback(dev_in, &cb_data[0].gpio_cb);
234 	gpio_remove_callback(dev_in, &cb_data[1].gpio_cb);
235 	return TC_FAIL;
236 }
237 
ZTEST(gpio_port_cb_mgmt,test_gpio_callback_add_remove)238 ZTEST(gpio_port_cb_mgmt, test_gpio_callback_add_remove)
239 {
240 	zassert_equal(test_callback_add_remove(), TC_PASS);
241 }
242 
ZTEST(gpio_port_cb_mgmt,test_gpio_callback_self_remove)243 ZTEST(gpio_port_cb_mgmt, test_gpio_callback_self_remove)
244 {
245 	zassert_equal(test_callback_self_remove(), TC_PASS);
246 }
247 
ZTEST(gpio_port_cb_mgmt,test_gpio_callback_enable_disable)248 ZTEST(gpio_port_cb_mgmt, test_gpio_callback_enable_disable)
249 {
250 	zassert_equal(test_callback_enable_disable(), TC_PASS);
251 }
252