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 	gpio_pin_set(dev_out, PIN_OUT, 0);
70 	k_sleep(K_MSEC(100));
71 
72 	cb_cnt[0] = 0;
73 	cb_cnt[1] = 0;
74 	if (enable_cb == 1) {
75 		gpio_pin_interrupt_configure(dev_in, PIN_IN, GPIO_INT_EDGE_RISING);
76 	} else {
77 		gpio_pin_interrupt_configure(dev_in, PIN_IN, GPIO_INT_DISABLE);
78 	}
79 	k_sleep(K_MSEC(100));
80 	gpio_pin_set(dev_out, PIN_OUT, 1);
81 	k_sleep(K_MSEC(1000));
82 }
83 
test_callback_add_remove(void)84 static int test_callback_add_remove(void)
85 {
86 	const struct device *const dev_in = DEVICE_DT_GET(DEV_IN);
87 	const struct device *const dev_out = DEVICE_DT_GET(DEV_OUT);
88 
89 	/* SetUp: initialize environment */
90 	int rc = init_callback(dev_in, dev_out, callback_1, callback_2);
91 
92 	if (rc == -ENOTSUP) {
93 		TC_PRINT("%s not supported\n", __func__);
94 		return TC_PASS;
95 	}
96 	zassert_equal(rc, 0,
97 		      "init_callback failed");
98 
99 	/* 3. enable callback, trigger PIN_IN interrupt by operate PIN_OUT */
100 	trigger_callback(dev_in, dev_out, 1);
101 	/*= checkpoint: check callback is triggered =*/
102 	if (cb_cnt[0] != 1 || cb_cnt[1] != 1) {
103 		TC_ERROR("not trigger callback correctly\n");
104 		goto err_exit;
105 	}
106 
107 	/* 4. remove callback_1 */
108 	gpio_remove_callback(dev_in, &cb_data[0].gpio_cb);
109 	trigger_callback(dev_in, dev_out, 1);
110 
111 	/*= checkpoint: check callback is triggered =*/
112 	if (cb_cnt[0] != 0 || cb_cnt[1] != 1) {
113 		TC_ERROR("not trigger callback correctly\n");
114 		goto err_exit;
115 	}
116 
117 	/* 5. remove callback_2 */
118 	gpio_remove_callback(dev_in, &cb_data[1].gpio_cb);
119 	trigger_callback(dev_in, dev_out, 1);
120 	/*= checkpoint: check callback is triggered =*/
121 	if (cb_cnt[0] != 0 || cb_cnt[1] != 0) {
122 		TC_ERROR("not trigger callback correctly\n");
123 		goto err_exit;
124 	}
125 	return TC_PASS;
126 
127 err_exit:
128 	gpio_remove_callback(dev_in, &cb_data[0].gpio_cb);
129 	gpio_remove_callback(dev_in, &cb_data[1].gpio_cb);
130 	return TC_FAIL;
131 }
132 
test_callback_self_remove(void)133 static int test_callback_self_remove(void)
134 {
135 	int res = TC_FAIL;
136 	const struct device *const dev_in = DEVICE_DT_GET(DEV_IN);
137 	const struct device *const dev_out = DEVICE_DT_GET(DEV_OUT);
138 
139 	/* SetUp: initialize environment */
140 	int rc = init_callback(dev_in, dev_out, callback_1, callback_remove_self);
141 
142 	if (rc == -ENOTSUP) {
143 		TC_PRINT("%s not supported\n", __func__);
144 		return TC_PASS;
145 	}
146 	zassert_equal(rc, 0,
147 		      "init_callback failed");
148 
149 	gpio_pin_set(dev_out, PIN_OUT, 0);
150 	k_sleep(K_MSEC(100));
151 
152 	cb_data[0].aux = INT_MAX;
153 	cb_data[1].aux = INT_MAX;
154 
155 	/* 3. enable callback, trigger PIN_IN interrupt by operate PIN_OUT */
156 	trigger_callback(dev_in, dev_out, 1);
157 
158 	/*= checkpoint: check both callbacks are triggered =*/
159 	if (cb_cnt[0] != 1 || cb_cnt[1] != 1) {
160 		TC_ERROR("not trigger callback correctly\n");
161 		goto err_exit;
162 	}
163 
164 	/*= checkpoint: check remove executed is invoked =*/
165 	if (cb_data[0].aux != INT_MAX || cb_data[1].aux != 0) {
166 		TC_ERROR("not remove callback correctly\n");
167 		goto err_exit;
168 	}
169 
170 	/* 4 enable callback, trigger PIN_IN interrupt by operate PIN_OUT */
171 	trigger_callback(dev_in, dev_out, 1);
172 
173 	/*= checkpoint: check only remaining callback is triggered =*/
174 	if (cb_cnt[0] != 1 || cb_cnt[1] != 0) {
175 		TC_ERROR("not trigger remaining callback correctly\n");
176 		goto err_exit;
177 	}
178 
179 	res = TC_PASS;
180 
181 err_exit:
182 	gpio_remove_callback(dev_in, &cb_data[0].gpio_cb);
183 	gpio_remove_callback(dev_in, &cb_data[1].gpio_cb);
184 	return res;
185 }
186 
test_callback_enable_disable(void)187 static int test_callback_enable_disable(void)
188 {
189 	const struct device *const dev_in = DEVICE_DT_GET(DEV_IN);
190 	const struct device *const dev_out = DEVICE_DT_GET(DEV_OUT);
191 
192 	/* SetUp: initialize environment */
193 	int rc = init_callback(dev_in, dev_out, callback_1, callback_2);
194 
195 	if (rc == -ENOTSUP) {
196 		TC_PRINT("%s not supported\n", __func__);
197 		return TC_PASS;
198 	}
199 	zassert_equal(rc, 0,
200 		      "init_callback failed");
201 
202 	/* 3. enable callback, trigger PIN_IN interrupt by operate PIN_OUT */
203 	trigger_callback(dev_in, dev_out, 1);
204 	/*= checkpoint: check callback is triggered =*/
205 	if (cb_cnt[0] != 1 || cb_cnt[1] != 1) {
206 		TC_ERROR("not trigger callback correctly\n");
207 		goto err_exit;
208 	}
209 
210 	/* 4. disable callback */
211 	trigger_callback(dev_in, dev_out, 0);
212 	/*= checkpoint: check callback is triggered =*/
213 	if (cb_cnt[0] != 0 || cb_cnt[1] != 0) {
214 		TC_ERROR("not trigger callback correctly\n");
215 		goto err_exit;
216 	}
217 
218 	/* 5. enable callback again */
219 	trigger_callback(dev_in, dev_out, 1);
220 	/*= checkpoint: check callback is triggered =*/
221 	if (cb_cnt[0] != 1 || cb_cnt[1] != 1) {
222 		TC_ERROR("not trigger callback correctly\n");
223 		goto err_exit;
224 	}
225 	gpio_remove_callback(dev_in, &cb_data[0].gpio_cb);
226 	gpio_remove_callback(dev_in, &cb_data[1].gpio_cb);
227 	return TC_PASS;
228 
229 err_exit:
230 	gpio_remove_callback(dev_in, &cb_data[0].gpio_cb);
231 	gpio_remove_callback(dev_in, &cb_data[1].gpio_cb);
232 	return TC_FAIL;
233 }
234 
ZTEST(gpio_port_cb_mgmt,test_gpio_callback_add_remove)235 ZTEST(gpio_port_cb_mgmt, test_gpio_callback_add_remove)
236 {
237 	zassert_equal(test_callback_add_remove(), TC_PASS,
238 		     NULL);
239 }
240 
ZTEST(gpio_port_cb_mgmt,test_gpio_callback_self_remove)241 ZTEST(gpio_port_cb_mgmt, test_gpio_callback_self_remove)
242 {
243 	zassert_equal(test_callback_self_remove(), TC_PASS,
244 		     NULL);
245 }
246 
ZTEST(gpio_port_cb_mgmt,test_gpio_callback_enable_disable)247 ZTEST(gpio_port_cb_mgmt, test_gpio_callback_enable_disable)
248 {
249 	zassert_equal(test_callback_enable_disable(), TC_PASS,
250 		     NULL);
251 }
252