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