diff --git a/doc/hardware/peripherals/gpio.rst b/doc/hardware/peripherals/gpio.rst index 33b1c4e1e36..9a07809b87d 100644 --- a/doc/hardware/peripherals/gpio.rst +++ b/doc/hardware/peripherals/gpio.rst @@ -18,4 +18,3 @@ API Reference ************* .. doxygengroup:: gpio_interface -.. doxygengroup:: gpio_keys_interface diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index af5bccc8da6..63af95cedd8 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -38,6 +38,7 @@ add_subdirectory_ifdef(CONFIG_I2C i2c) add_subdirectory_ifdef(CONFIG_I2S i2s) add_subdirectory_ifdef(CONFIG_I3C i3c) add_subdirectory_ifdef(CONFIG_IEEE802154 ieee802154) +add_subdirectory_ifdef(CONFIG_INPUT input) add_subdirectory_ifdef(CONFIG_IPM ipm) add_subdirectory_ifdef(CONFIG_KSCAN kscan) add_subdirectory_ifdef(CONFIG_LED led) diff --git a/drivers/Kconfig b/drivers/Kconfig index ef3059e16cc..d4259816ade 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -36,6 +36,7 @@ source "drivers/i2c/Kconfig" source "drivers/i2s/Kconfig" source "drivers/i3c/Kconfig" source "drivers/ieee802154/Kconfig" +source "drivers/input/Kconfig" source "drivers/interrupt_controller/Kconfig" source "drivers/interrupt_controller/Kconfig.shared_irq" source "drivers/ipm/Kconfig" diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index ec6761667c9..cf52114b73e 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -73,5 +73,4 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_NPM6001 gpio_npm6001.c) zephyr_library_sources_ifdef(CONFIG_GPIO_RT1718S gpio_rt1718s.c) zephyr_library_sources_ifdef(CONFIG_GPIO_RT1718S gpio_rt1718s_port.c) zephyr_library_sources_ifdef(CONFIG_GPIO_NUMICRO gpio_numicro.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_KEYS_ZEPHYR gpio_keys_zephyr.c) zephyr_library_sources_ifdef(CONFIG_GPIO_HOGS gpio_hogs.c) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 68256a7e9c9..3e6d21ef6c8 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -181,6 +181,4 @@ source "drivers/gpio/Kconfig.numicro" source "drivers/gpio/Kconfig.bd8lb600fs" -source "drivers/gpio/Kconfig.zephyr" - endif # GPIO diff --git a/drivers/input/CMakeLists.txt b/drivers/input/CMakeLists.txt new file mode 100644 index 00000000000..ed266734163 --- /dev/null +++ b/drivers/input/CMakeLists.txt @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() +zephyr_library_property(ALLOW_EMPTY TRUE) + +zephyr_library_sources_ifdef(CONFIG_INPUT_GPIO_KEYS input_gpio_keys.c) diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig new file mode 100644 index 00000000000..f62fd27fac2 --- /dev/null +++ b/drivers/input/Kconfig @@ -0,0 +1,12 @@ +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +if INPUT + +menu "Input Drivers" + +source "drivers/input/Kconfig.gpio_keys" + +endmenu # Input Drivers + +endif # INPUT diff --git a/drivers/gpio/Kconfig.zephyr b/drivers/input/Kconfig.gpio_keys similarity index 89% rename from drivers/gpio/Kconfig.zephyr rename to drivers/input/Kconfig.gpio_keys index 0e584a6d66f..9da697edb53 100644 --- a/drivers/gpio/Kconfig.zephyr +++ b/drivers/input/Kconfig.gpio_keys @@ -1,7 +1,7 @@ # Copyright (c) 2022 Google LLC # SPDX-License-Identifier: Apache-2.0 -config GPIO_KEYS_ZEPHYR +config INPUT_GPIO_KEYS bool "Zephyr GPIO Keys" default y depends on DT_HAS_ZEPHYR_GPIO_KEYS_ENABLED diff --git a/drivers/gpio/gpio_keys_zephyr.c b/drivers/input/input_gpio_keys.c similarity index 64% rename from drivers/gpio/gpio_keys_zephyr.c rename to drivers/input/input_gpio_keys.c index 6a9ce6274f2..13ef2b9187a 100644 --- a/drivers/gpio/gpio_keys_zephyr.c +++ b/drivers/input/input_gpio_keys.c @@ -6,14 +6,20 @@ #include #include -#include +#include #include #include -LOG_MODULE_REGISTER(zephyr_gpio_keys, CONFIG_GPIO_LOG_LEVEL); +LOG_MODULE_REGISTER(zephyr_gpio_keys, CONFIG_INPUT_LOG_LEVEL); #define DT_DRV_COMPAT zephyr_gpio_keys +struct gpio_keys_callback { + struct gpio_callback gpio_cb; + uint32_t zephyr_code; + int8_t pin_state; +}; + struct gpio_keys_pin_config { /** GPIO specification from devicetree */ struct gpio_dt_spec spec; @@ -35,7 +41,6 @@ struct gpio_keys_pin_data { }; struct gpio_keys_data { - gpio_keys_callback_handler_t callback; struct gpio_keys_pin_data *pin_data; }; @@ -56,12 +61,12 @@ static void gpio_keys_change_deferred(struct k_work *work) LOG_DBG("gpio_change_deferred %s pin_state=%d, new_pressed=%d, key_index=%d", dev->name, pin_data->cb_data.pin_state, new_pressed, key_index); - /* If gpio changed, invoke callback */ + /* If gpio changed, report the event */ if (new_pressed != pin_data->cb_data.pin_state) { pin_data->cb_data.pin_state = new_pressed; - LOG_DBG("Calling callback %s %d, code=%d", dev->name, new_pressed, + LOG_DBG("Report event %s %d, code=%d", dev->name, new_pressed, pin_cfg->zephyr_code); - data->callback(dev, &pin_data->cb_data, BIT(pin_cfg->spec.pin)); + input_report_key(dev, pin_cfg->zephyr_code, new_pressed, true, K_FOREVER); } } @@ -108,85 +113,6 @@ static int gpio_keys_interrupt_configure(const struct gpio_dt_spec *gpio_spec, return retval; } -static int gpio_keys_zephyr_enable_interrupt(const struct device *dev, - gpio_keys_callback_handler_t gpio_keys_cb) -{ - int retval = -ENODEV; - const struct gpio_keys_config *cfg = dev->config; - struct gpio_keys_data *data = dev->data; - - data->callback = gpio_keys_cb; - for (int i = 0; i < cfg->num_keys; i++) { - retval = gpio_keys_interrupt_configure(&cfg->pin_cfg[i].spec, - &data->pin_data[i].cb_data, - cfg->pin_cfg[i].zephyr_code); - } - - return retval; -} - -static int gpio_keys_zephyr_disable_interrupt(const struct device *dev) -{ - int retval = -ENODEV; - const struct gpio_keys_config *cfg = dev->config; - struct gpio_keys_data *data = dev->data; - const struct gpio_dt_spec *gpio_spec; - - for (int i = 0; i < cfg->num_keys; i++) { - gpio_spec = &cfg->pin_cfg[i].spec; - retval = z_impl_gpio_pin_interrupt_configure(gpio_spec->port, gpio_spec->pin, - GPIO_INT_MODE_DISABLED); - if (data->pin_data[i].cb_data.gpio_cb.handler) { - retval = gpio_remove_callback(gpio_spec->port, - &data->pin_data[i].cb_data.gpio_cb); - memset(&data->pin_data[i].cb_data, 0, sizeof(struct gpio_keys_callback)); - } - LOG_DBG("disable interrupt [0x%p, %d], rv=%d", gpio_spec->port, gpio_spec->pin, - retval); - } - - return retval; -} - -static int gpio_keys_get_gpio_port_logical(const struct device *gpio_dev, gpio_port_value_t *value) -{ - const struct gpio_driver_data *const data = gpio_dev->data; - - int ret = z_impl_gpio_port_get_raw(gpio_dev, value); - - if (ret == 0) { - *value ^= data->invert; - } - - return ret; -} - -static int gpio_keys_zephyr_get_pin(const struct device *dev, uint32_t idx) -{ - const struct gpio_keys_config *cfg = dev->config; - const struct gpio_dt_spec *gpio_spec = &cfg->pin_cfg[idx].spec; - const struct device *gpio_dev = gpio_spec->port; - const struct gpio_driver_config __maybe_unused *gpio_cfg = gpio_dev->config; - int ret; - gpio_port_value_t value; - - __ASSERT((gpio_cfg->port_pin_mask & (gpio_port_pins_t)BIT(gpio_spec->pin)) != 0U, - "Unsupported pin"); - - ret = gpio_keys_get_gpio_port_logical(gpio_dev, &value); - - if (ret == 0) { - ret = (value & (gpio_port_pins_t)BIT(gpio_spec->pin)) != 0 ? 1 : 0; - } - - if (ret < 0) { - LOG_ERR("Cannot read %s, ret=%d", dev->name, ret); - ret = 0; - } - - return ret; -} - static int gpio_keys_init(const struct device *dev) { struct gpio_keys_data *data = dev->data; @@ -209,17 +135,19 @@ static int gpio_keys_init(const struct device *dev) data->pin_data[i].dev = dev; k_work_init_delayable(&data->pin_data[i].work, gpio_keys_change_deferred); + + ret = gpio_keys_interrupt_configure(&cfg->pin_cfg[i].spec, + &data->pin_data[i].cb_data, + cfg->pin_cfg[i].zephyr_code); + if (ret != 0) { + LOG_ERR("Pin %d interrupt configuration failed: %d", i, ret); + return ret; + } } return 0; } -static const struct gpio_keys_api gpio_keys_zephyr_api = { - .enable_interrupt = gpio_keys_zephyr_enable_interrupt, - .disable_interrupt = gpio_keys_zephyr_disable_interrupt, - .get_pin = gpio_keys_zephyr_get_pin, -}; - #define GPIO_KEYS_CFG_DEF(node_id) \ { \ .spec = GPIO_DT_SPEC_GET(node_id, gpios), \ @@ -240,7 +168,7 @@ static const struct gpio_keys_api gpio_keys_zephyr_api = { .pin_data = gpio_keys_pin_data_##i, \ }; \ DEVICE_DT_INST_DEFINE(i, &gpio_keys_init, NULL, &gpio_keys_data_##i, \ - &gpio_keys_config_##i, POST_KERNEL, CONFIG_GPIO_INIT_PRIORITY, \ - &gpio_keys_zephyr_api); + &gpio_keys_config_##i, POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, \ + NULL); DT_INST_FOREACH_STATUS_OKAY(GPIO_KEYS_INIT) diff --git a/dts/bindings/gpio/zephyr,gpio-keys.yaml b/dts/bindings/input/zephyr,gpio-keys.yaml similarity index 100% rename from dts/bindings/gpio/zephyr,gpio-keys.yaml rename to dts/bindings/input/zephyr,gpio-keys.yaml diff --git a/include/zephyr/drivers/gpio_keys.h b/include/zephyr/drivers/gpio_keys.h deleted file mode 100644 index 18a4faf7e03..00000000000 --- a/include/zephyr/drivers/gpio_keys.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2022 Google LLC - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_INCLUDE_DRIVERS_GPIO_KEYS_H_ -#define ZEPHYR_INCLUDE_DRIVERS_GPIO_KEYS_H_ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct gpio_keys_callback { - struct gpio_callback gpio_cb; - uint32_t zephyr_code; - int8_t pin_state; -}; - -typedef void (*gpio_keys_callback_handler_t)(const struct device *port, - struct gpio_keys_callback *cb, gpio_port_pins_t pins); -/** - * @brief GPIO Keys Driver APIs - * @defgroup gpio_keys_interface GPIO KeysDriver APIs - * @ingroup io_interfaces - * @{ - */ - -__subsystem struct gpio_keys_api { - int (*enable_interrupt)(const struct device *dev, gpio_keys_callback_handler_t cb); - int (*disable_interrupt)(const struct device *dev); - int (*get_pin)(const struct device *dev, uint32_t idx); -}; - -/** - * @brief Enable interrupt - * - * @param dev Pointer to device structure for the driver instance. - * @param cb Function callback to be invoked after GPIO key has been debounced - * - * @return 0 If successful - */ -__syscall int gpio_keys_enable_interrupt(const struct device *dev, gpio_keys_callback_handler_t cb); - -static inline int z_impl_gpio_keys_enable_interrupt(const struct device *dev, - gpio_keys_callback_handler_t cb) -{ - struct gpio_keys_api *api; - - api = (struct gpio_keys_api *)dev->api; - return api->enable_interrupt(dev, cb); -} - -/** - * @brief Disable interrupt - * - * @param dev Pointer to device structure for the driver instance. - * - * @return 0 If successful - */ -__syscall int gpio_keys_disable_interrupt(const struct device *dev); - -static inline int z_impl_gpio_keys_disable_interrupt(const struct device *dev) -{ - struct gpio_keys_api *api; - - api = (struct gpio_keys_api *)dev->api; - return api->disable_interrupt(dev); -} - -/** - * @brief Get the logical level of GPIO Key - * - * @param dev Pointer to device structure for the driver instance. - * @param idx GPIO Key index in device tree - * - * @retval 0 If successful. - * @retval -EIO I/O error when accessing an external GPIO chip. - * @retval -EWOULDBLOCK if operation would block. - */ -__syscall int gpio_keys_get_pin(const struct device *dev, uint32_t idx); - -static inline int z_impl_gpio_keys_get_pin(const struct device *dev, uint32_t idx) -{ - struct gpio_keys_api *api; - - api = (struct gpio_keys_api *)dev->api; - return api->get_pin(dev, idx); -} - -/** - * @} - */ - -#ifdef __cplusplus -} -#endif - -#include - -#endif /* ZEPHYR_INCLUDE_DRIVERS_GPIO_KEYS_H_ */ diff --git a/tests/drivers/gpio/gpio_api_1pin/boards/native_posix.overlay b/tests/drivers/gpio/gpio_api_1pin/boards/native_posix.overlay index cb99d269466..ed09218f14e 100644 --- a/tests/drivers/gpio/gpio_api_1pin/boards/native_posix.overlay +++ b/tests/drivers/gpio/gpio_api_1pin/boards/native_posix.overlay @@ -5,31 +5,5 @@ */ &gpio0 { - ngpios = <3>; -}; - -/ { - gpio-keys0 { - compatible = "zephyr,gpio-keys"; - debounce-interval-ms = <30>; - - voldown_button: button_0 { - gpios = <&gpio0 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; - zephyr,code = <10>; - }; - volup_button: button_1 { - gpios = <&gpio0 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; - zephyr,code = <11>; - }; - }; - - gpio-keys1 { - compatible = "zephyr,gpio-keys"; - debounce-interval-ms = <100>; - - power_button: button_2 { - gpios = <&gpio0 2 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; - zephyr,code = <20>; - }; - }; + ngpios = <2>; }; diff --git a/tests/drivers/gpio/gpio_api_1pin/src/test_gpio_keys.c b/tests/drivers/gpio/gpio_api_1pin/src/test_gpio_keys.c deleted file mode 100644 index 45b33867662..00000000000 --- a/tests/drivers/gpio/gpio_api_1pin/src/test_gpio_keys.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2022 Google LLC - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "zephyr/sys/util.h" -#include -#include -#include -#include -#include - -#include - -LOG_MODULE_REGISTER(gpio_keys_test, LOG_LEVEL_DBG); - -#if DT_NODE_EXISTS(DT_NODELABEL(voldown_button)) - -const struct device *test_gpio_keys_dev = DEVICE_DT_GET(DT_PARENT(DT_NODELABEL(voldown_button))); -#define BUTTON_0_IDX DT_NODE_CHILD_IDX(DT_NODELABEL(voldown_button)) -#define BUTTON_1_IDX DT_NODE_CHILD_IDX(DT_NODELABEL(volup_button)) - -struct gpio_keys_pin_config { - /** GPIO specification from devicetree */ - struct gpio_dt_spec spec; - /** Zephyr code from devicetree */ - uint32_t zephyr_code; -}; -struct gpio_keys_config { - /** Debounce interval in milliseconds from devicetree */ - uint32_t debounce_interval_ms; - const int num_keys; - const struct gpio_keys_pin_config *pin_cfg; -}; - -/** - * @brief Test Suite: Verifies gpio_keys_config functionality. - */ -ZTEST_SUITE(gpio_keys, NULL, NULL, NULL, NULL, NULL); - -/** - * @brief TestPurpose: Verify gpio_keys_config pressed raw. - * - */ -ZTEST(gpio_keys, test_gpio_keys_pressed) -{ - const struct gpio_keys_config *config = test_gpio_keys_dev->config; - const struct gpio_keys_pin_config *pin_cfg = &config->pin_cfg[BUTTON_0_IDX]; - const struct gpio_dt_spec *spec = &pin_cfg->spec; - - zassert_ok(gpio_pin_configure(spec->port, spec->pin, GPIO_INPUT)); - - zassert_ok(gpio_emul_input_set(spec->port, spec->pin, 1)); - zassert_equal(1, gpio_keys_get_pin(test_gpio_keys_dev, BUTTON_0_IDX)); - - zassert_ok(gpio_emul_input_set(spec->port, spec->pin, 0)); - zassert_equal(0, gpio_keys_get_pin(test_gpio_keys_dev, BUTTON_0_IDX)); -} - -/** - * @brief TestPurpose: Verify button interrupt. - * - */ -uint32_t gpio_keys_interrupt_called; -void test_gpio_keys_cb_handler(const struct device *dev, struct gpio_keys_callback *cbdata, - uint32_t pins) -{ - LOG_DBG("GPIO_KEY %s pressed, pins=%d, zephyr_code=%u, pin_state=%d", dev->name, pins, - cbdata->zephyr_code, cbdata->pin_state); - gpio_keys_interrupt_called = cbdata->zephyr_code; -} - -ZTEST(gpio_keys, test_gpio_keys_interrupt) -{ - int button_idx[] = {BUTTON_0_IDX, BUTTON_1_IDX}; - int num_gpio_keys = ARRAY_SIZE(button_idx); - const struct gpio_keys_config *config = test_gpio_keys_dev->config; - const struct gpio_keys_pin_config *pin_cfg; - const struct gpio_dt_spec *spec; - - for (int i = 0; i < num_gpio_keys; i++) { - pin_cfg = &config->pin_cfg[button_idx[i]]; - spec = &pin_cfg->spec; - - LOG_DBG("GPIO_KEY config=[0x%p, %d]", config->debounce_interval_ms, - pin_cfg->zephyr_code); - LOG_DBG("GPIO_KEY spec=[0x%p, %d]", spec->port, spec->pin); - - zassert_ok(gpio_pin_configure(spec->port, spec->pin, GPIO_INPUT)); - zassert_ok(gpio_keys_disable_interrupt(test_gpio_keys_dev), NULL); - k_sleep(K_MSEC(500)); - - /* Check interrupts are disabled */ - gpio_keys_interrupt_called = 0; - zassert_ok(gpio_emul_input_set(spec->port, spec->pin, 0)); - k_sleep(K_MSEC(1000)); - zassert_ok(gpio_emul_input_set(spec->port, spec->pin, 1)); - k_sleep(K_MSEC(1000)); - zassert_equal(gpio_keys_interrupt_called, 0); - - zassert_ok( - gpio_keys_enable_interrupt(test_gpio_keys_dev, test_gpio_keys_cb_handler), - NULL); - zassert_ok(gpio_emul_input_set(spec->port, spec->pin, 0)); - k_sleep(K_MSEC(1000)); - - gpio_keys_interrupt_called = 0; - zassert_ok(gpio_emul_input_set(spec->port, spec->pin, 1)); - - /* Check interrupt doesn't prematurely fires */ - k_sleep(K_MSEC(config->debounce_interval_ms / 2)); - zassert_equal(gpio_keys_interrupt_called, 0); - - /* Check interrupt fires after debounce interval */ - k_sleep(K_MSEC(config->debounce_interval_ms)); - zassert_equal(gpio_keys_interrupt_called, pin_cfg->zephyr_code); - } -} - -#endif /* DT_NODE_EXISTS(DT_NODELABEL(voldown_button)) */ diff --git a/tests/drivers/input/gpio_keys/CMakeLists.txt b/tests/drivers/input/gpio_keys/CMakeLists.txt new file mode 100644 index 00000000000..96e819c83ba --- /dev/null +++ b/tests/drivers/input/gpio_keys/CMakeLists.txt @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +project(gpio_keys) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/drivers/input/gpio_keys/boards/native_posix.overlay b/tests/drivers/input/gpio_keys/boards/native_posix.overlay new file mode 100644 index 00000000000..c878e8c5016 --- /dev/null +++ b/tests/drivers/input/gpio_keys/boards/native_posix.overlay @@ -0,0 +1,25 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&gpio0 { + ngpios = <2>; +}; + +/ { + buttons: gpio-keys0 { + compatible = "zephyr,gpio-keys"; + debounce-interval-ms = <30>; + + voldown_button: button_0 { + gpios = <&gpio0 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + zephyr,code = <10>; + }; + volup_button: button_1 { + gpios = <&gpio0 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + zephyr,code = <11>; + }; + }; +}; diff --git a/tests/drivers/input/gpio_keys/boards/native_posix_64.overlay b/tests/drivers/input/gpio_keys/boards/native_posix_64.overlay new file mode 100644 index 00000000000..166e6f02e82 --- /dev/null +++ b/tests/drivers/input/gpio_keys/boards/native_posix_64.overlay @@ -0,0 +1,6 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "native_posix.overlay" diff --git a/tests/drivers/input/gpio_keys/prj.conf b/tests/drivers/input/gpio_keys/prj.conf new file mode 100644 index 00000000000..0da3a38cadf --- /dev/null +++ b/tests/drivers/input/gpio_keys/prj.conf @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_ZTEST=y +CONFIG_ZTEST_NEW_API=y +CONFIG_GPIO=y +CONFIG_INPUT=y +CONFIG_INPUT_MODE_SYNCHRONOUS=y diff --git a/tests/drivers/input/gpio_keys/src/main.c b/tests/drivers/input/gpio_keys/src/main.c new file mode 100644 index 00000000000..09d78c3dc6b --- /dev/null +++ b/tests/drivers/input/gpio_keys/src/main.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2022 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "zephyr/sys/util.h" +#include +#include +#include +#include +#include + +static const struct device *const test_gpio_keys_dev = DEVICE_DT_GET(DT_NODELABEL(buttons)); +#define BUTTON_0_IDX DT_NODE_CHILD_IDX(DT_NODELABEL(voldown_button)) + +struct gpio_keys_pin_config { + /** GPIO specification from devicetree */ + struct gpio_dt_spec spec; + /** Zephyr code from devicetree */ + uint32_t zephyr_code; +}; +struct gpio_keys_config { + /** Debounce interval in milliseconds from devicetree */ + uint32_t debounce_interval_ms; + const int num_keys; + const struct gpio_keys_pin_config *pin_cfg; +}; + +/** + * @brief Test Suite: Verifies gpio_keys_config functionality. + */ +ZTEST_SUITE(gpio_keys, NULL, NULL, NULL, NULL, NULL); + +static int event_count; +static uint16_t last_code; +static bool last_val; +static void test_gpio_keys_cb_handler(struct input_event *evt) +{ + TC_PRINT("GPIO_KEY %s pressed, zephyr_code=%u, value=%d\n", + evt->dev->name, evt->code, evt->value); + event_count++; + last_code = evt->code; + last_val = evt->value; +} +INPUT_LISTENER_CB_DEFINE(test_gpio_keys_dev, test_gpio_keys_cb_handler); + +/** + * @brief TestPurpose: Verify gpio_keys_config pressed raw. + * + */ +ZTEST(gpio_keys, test_gpio_keys_pressed) +{ + const struct gpio_keys_config *config = test_gpio_keys_dev->config; + const struct gpio_keys_pin_config *pin_cfg = &config->pin_cfg[BUTTON_0_IDX]; + const struct gpio_dt_spec *spec = &pin_cfg->spec; + + last_code = 0; + last_val = false; + + zassert_ok(gpio_emul_input_set(spec->port, spec->pin, 0)); + + /* Check interrupt doesn't prematurely fires */ + k_sleep(K_MSEC(config->debounce_interval_ms / 2)); + zassert_equal(event_count, 0); + + /* Check interrupt fires after debounce interval */ + k_sleep(K_MSEC(config->debounce_interval_ms)); + zassert_equal(event_count, 1); + zassert_equal(last_code, pin_cfg->zephyr_code); + zassert_equal(last_val, true); + + zassert_ok(gpio_emul_input_set(spec->port, spec->pin, 1)); + + /* Check interrupt doesn't prematurely fires */ + k_sleep(K_MSEC(config->debounce_interval_ms / 2)); + zassert_equal(event_count, 1); + + /* Check interrupt fires after debounce interval */ + k_sleep(K_MSEC(config->debounce_interval_ms)); + zassert_equal(event_count, 2); + zassert_equal(last_code, pin_cfg->zephyr_code); + zassert_equal(last_val, false); +} diff --git a/tests/drivers/input/gpio_keys/testcase.yaml b/tests/drivers/input/gpio_keys/testcase.yaml new file mode 100644 index 00000000000..476e2436163 --- /dev/null +++ b/tests/drivers/input/gpio_keys/testcase.yaml @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +tests: + drivers.input.gpio_keys: + tags: drivers input + platform_allow: native_posix native_posix_64 + integration_platforms: + - native_posix