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