1 /*
2  * Copyright (c) 2022 Google Inc
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/drivers/gpio.h>
8 #include <zephyr/drivers/gpio/gpio_emul.h>
9 #include <zephyr/kernel.h>
10 #include <zephyr/ztest.h>
11 
12 static struct gpio_dt_spec irq_pin =
13 	GPIO_DT_SPEC_GET(DT_INST(0, test_gpio_enable_disable_interrupt), irq_gpios);
14 static struct gpio_callback cb_data;
15 static bool cb_called;
16 
callback(const struct device * dev,struct gpio_callback * gpio_cb,uint32_t pins)17 static void callback(const struct device *dev, struct gpio_callback *gpio_cb, uint32_t pins)
18 {
19 	cb_called = true;
20 }
21 
22 struct gpio_enable_disable_interrupt_fixture {
23 	const struct gpio_dt_spec *irq_spec;
24 };
25 
gpio_enable_disable_interrupt_setup(void)26 static void *gpio_enable_disable_interrupt_setup(void)
27 {
28 	static struct gpio_enable_disable_interrupt_fixture fixture;
29 
30 	fixture.irq_spec = &irq_pin;
31 
32 	return &fixture;
33 }
34 
gpio_enable_disable_interrupt_before(void * arg)35 static void gpio_enable_disable_interrupt_before(void *arg)
36 {
37 	struct gpio_enable_disable_interrupt_fixture *fixture =
38 		(struct gpio_enable_disable_interrupt_fixture *)arg;
39 
40 	zassert_true(gpio_is_ready_dt(fixture->irq_spec), "GPIO device is not ready");
41 
42 	zassert_ok(gpio_pin_configure_dt(fixture->irq_spec, GPIO_INPUT));
43 	zassert_ok(gpio_emul_input_set(fixture->irq_spec->port, fixture->irq_spec->pin, 0),
44 		   "failed to set value on input pin");
45 	cb_called = false;
46 
47 	zassert_ok(gpio_pin_interrupt_configure_dt(fixture->irq_spec, GPIO_INT_DISABLE));
48 	gpio_init_callback(&cb_data, callback, BIT(fixture->irq_spec->pin));
49 	zassert_ok(gpio_add_callback(fixture->irq_spec->port, &cb_data), "failed to add callback");
50 }
51 
gpio_enable_disable_interrupt_after(void * arg)52 static void gpio_enable_disable_interrupt_after(void *arg)
53 {
54 	struct gpio_enable_disable_interrupt_fixture *fixture =
55 		(struct gpio_enable_disable_interrupt_fixture *)arg;
56 
57 	zassert_ok(gpio_remove_callback(fixture->irq_spec->port, &cb_data),
58 		   "failed to remove callback");
59 }
60 
enable_interrupt(const struct gpio_dt_spec * irq_spec)61 static void enable_interrupt(const struct gpio_dt_spec *irq_spec)
62 {
63 	zassert_ok(gpio_pin_interrupt_configure_dt(irq_spec, GPIO_INT_MODE_ENABLE_ONLY),
64 		   "failed to only enable interrupt");
65 }
66 
disable_interrupt(const struct gpio_dt_spec * irq_spec)67 static void disable_interrupt(const struct gpio_dt_spec *irq_spec)
68 {
69 	zassert_ok(gpio_pin_interrupt_configure_dt(irq_spec, GPIO_INT_MODE_DISABLE_ONLY),
70 		   " failed to only disable interrupt");
71 }
72 
trigger_callback(const struct gpio_dt_spec * irq_spec)73 static void trigger_callback(const struct gpio_dt_spec *irq_spec)
74 {
75 	zassert_ok(gpio_emul_input_set(irq_spec->port, irq_spec->pin, 1),
76 		   "failed to set value on input pin");
77 	k_sleep(K_MSEC(100));
78 }
79 
ZTEST_F(gpio_enable_disable_interrupt,test_not_configured_as_interrupt)80 ZTEST_F(gpio_enable_disable_interrupt, test_not_configured_as_interrupt)
81 {
82 	enable_interrupt(fixture->irq_spec);
83 	trigger_callback(fixture->irq_spec);
84 	zassert_false(cb_called,
85 		      "callback should not be executed before configuring the interrupt");
86 }
87 
ZTEST_F(gpio_enable_disable_interrupt,test_initial_enable_then_disable)88 ZTEST_F(gpio_enable_disable_interrupt, test_initial_enable_then_disable)
89 {
90 	zassert_ok(gpio_pin_interrupt_configure_dt(fixture->irq_spec, GPIO_INT_EDGE_RISING),
91 		   "failed to set interrupt with edge rising");
92 	disable_interrupt(fixture->irq_spec);
93 	trigger_callback(fixture->irq_spec);
94 	zassert_false(cb_called, "callback should not be executed after disabling the interrupt");
95 }
96 
ZTEST_F(gpio_enable_disable_interrupt,test_disable_then_enable)97 ZTEST_F(gpio_enable_disable_interrupt, test_disable_then_enable)
98 {
99 	zassert_ok(gpio_pin_interrupt_configure_dt(fixture->irq_spec, GPIO_INT_EDGE_RISING),
100 		   "failed to set interrupt with edge rising");
101 	disable_interrupt(fixture->irq_spec);
102 	trigger_callback(fixture->irq_spec);
103 	enable_interrupt(fixture->irq_spec);
104 	zassert_true(cb_called, "callback should be executed after enabling the interrupt");
105 }
106 
107 ZTEST_SUITE(gpio_enable_disable_interrupt, NULL, gpio_enable_disable_interrupt_setup,
108 	    gpio_enable_disable_interrupt_before, gpio_enable_disable_interrupt_after, NULL);
109