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