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