blob: be89bdba15ed7d24725596f8f0da2591911d1de3 [file] [log] [blame]
/*
* Copyright (c) 2022 Google Inc
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/gpio/gpio_emul.h>
#include <zephyr/kernel.h>
#include <zephyr/ztest.h>
static struct gpio_dt_spec irq_pin =
GPIO_DT_SPEC_GET(DT_INST(0, test_gpio_enable_disable_interrupt), irq_gpios);
static struct gpio_callback cb_data;
static bool cb_called;
static void callback(const struct device *dev, struct gpio_callback *gpio_cb, uint32_t pins)
{
cb_called = true;
}
struct gpio_enable_disable_interrupt_fixture {
const struct gpio_dt_spec *irq_spec;
};
static void *gpio_enable_disable_interrupt_setup(void)
{
static struct gpio_enable_disable_interrupt_fixture fixture;
fixture.irq_spec = &irq_pin;
return &fixture;
}
static void gpio_enable_disable_interrupt_before(void *arg)
{
struct gpio_enable_disable_interrupt_fixture *fixture =
(struct gpio_enable_disable_interrupt_fixture *)arg;
zassert_true(gpio_is_ready_dt(fixture->irq_spec), "GPIO device is not ready");
zassert_ok(gpio_pin_configure_dt(fixture->irq_spec, GPIO_INPUT));
zassert_ok(gpio_emul_input_set(fixture->irq_spec->port, fixture->irq_spec->pin, 0),
"failed to set value on input pin");
cb_called = false;
zassert_ok(gpio_pin_interrupt_configure_dt(fixture->irq_spec, GPIO_INT_DISABLE));
gpio_init_callback(&cb_data, callback, BIT(fixture->irq_spec->pin));
zassert_ok(gpio_add_callback(fixture->irq_spec->port, &cb_data), "failed to add callback");
}
static void gpio_enable_disable_interrupt_after(void *arg)
{
struct gpio_enable_disable_interrupt_fixture *fixture =
(struct gpio_enable_disable_interrupt_fixture *)arg;
zassert_ok(gpio_remove_callback(fixture->irq_spec->port, &cb_data),
"failed to remove callback");
}
static void enable_interrupt(const struct gpio_dt_spec *irq_spec)
{
zassert_ok(gpio_pin_interrupt_configure_dt(irq_spec, GPIO_INT_MODE_ENABLE_ONLY),
"failed to only enable interrupt");
}
static void disable_interrupt(const struct gpio_dt_spec *irq_spec)
{
zassert_ok(gpio_pin_interrupt_configure_dt(irq_spec, GPIO_INT_MODE_DISABLE_ONLY),
" failed to only disable interrupt");
}
static void trigger_callback(const struct gpio_dt_spec *irq_spec)
{
zassert_ok(gpio_emul_input_set(irq_spec->port, irq_spec->pin, 1),
"failed to set value on input pin");
k_sleep(K_MSEC(100));
}
ZTEST_F(gpio_enable_disable_interrupt, test_not_configured_as_interrupt)
{
enable_interrupt(fixture->irq_spec);
trigger_callback(fixture->irq_spec);
zassert_false(cb_called,
"callback should not be executed before configuring the interrupt");
}
ZTEST_F(gpio_enable_disable_interrupt, test_initial_enable_then_disable)
{
zassert_ok(gpio_pin_interrupt_configure_dt(fixture->irq_spec, GPIO_INT_EDGE_RISING),
"failed to set interrupt with edge rising");
disable_interrupt(fixture->irq_spec);
trigger_callback(fixture->irq_spec);
zassert_false(cb_called, "callback should not be executed after disabling the interrupt");
}
ZTEST_F(gpio_enable_disable_interrupt, test_disable_then_enable)
{
zassert_ok(gpio_pin_interrupt_configure_dt(fixture->irq_spec, GPIO_INT_EDGE_RISING),
"failed to set interrupt with edge rising");
disable_interrupt(fixture->irq_spec);
trigger_callback(fixture->irq_spec);
enable_interrupt(fixture->irq_spec);
zassert_true(cb_called, "callback should be executed after enabling the interrupt");
}
ZTEST_SUITE(gpio_enable_disable_interrupt, NULL, gpio_enable_disable_interrupt_setup,
gpio_enable_disable_interrupt_before, gpio_enable_disable_interrupt_after, NULL);