drivers: move gpio_keys from gpio to input
Port the gpio_keys_zephyr driver from the gpio subsystem with a dedicated API to the input subsystem reporting input events. Move the test as well, simplify the cases a bit since the API is simpler now. Signed-off-by: Fabio Baltieri <fabiobaltieri@google.com>
This commit is contained in:
parent
29ac5d4381
commit
2815f96440
19 changed files with 182 additions and 350 deletions
|
@ -18,4 +18,3 @@ API Reference
|
||||||
*************
|
*************
|
||||||
|
|
||||||
.. doxygengroup:: gpio_interface
|
.. doxygengroup:: gpio_interface
|
||||||
.. doxygengroup:: gpio_keys_interface
|
|
||||||
|
|
|
@ -38,6 +38,7 @@ add_subdirectory_ifdef(CONFIG_I2C i2c)
|
||||||
add_subdirectory_ifdef(CONFIG_I2S i2s)
|
add_subdirectory_ifdef(CONFIG_I2S i2s)
|
||||||
add_subdirectory_ifdef(CONFIG_I3C i3c)
|
add_subdirectory_ifdef(CONFIG_I3C i3c)
|
||||||
add_subdirectory_ifdef(CONFIG_IEEE802154 ieee802154)
|
add_subdirectory_ifdef(CONFIG_IEEE802154 ieee802154)
|
||||||
|
add_subdirectory_ifdef(CONFIG_INPUT input)
|
||||||
add_subdirectory_ifdef(CONFIG_IPM ipm)
|
add_subdirectory_ifdef(CONFIG_IPM ipm)
|
||||||
add_subdirectory_ifdef(CONFIG_KSCAN kscan)
|
add_subdirectory_ifdef(CONFIG_KSCAN kscan)
|
||||||
add_subdirectory_ifdef(CONFIG_LED led)
|
add_subdirectory_ifdef(CONFIG_LED led)
|
||||||
|
|
|
@ -36,6 +36,7 @@ source "drivers/i2c/Kconfig"
|
||||||
source "drivers/i2s/Kconfig"
|
source "drivers/i2s/Kconfig"
|
||||||
source "drivers/i3c/Kconfig"
|
source "drivers/i3c/Kconfig"
|
||||||
source "drivers/ieee802154/Kconfig"
|
source "drivers/ieee802154/Kconfig"
|
||||||
|
source "drivers/input/Kconfig"
|
||||||
source "drivers/interrupt_controller/Kconfig"
|
source "drivers/interrupt_controller/Kconfig"
|
||||||
source "drivers/interrupt_controller/Kconfig.shared_irq"
|
source "drivers/interrupt_controller/Kconfig.shared_irq"
|
||||||
source "drivers/ipm/Kconfig"
|
source "drivers/ipm/Kconfig"
|
||||||
|
|
|
@ -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.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_GPIO_RT1718S gpio_rt1718s_port.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_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)
|
zephyr_library_sources_ifdef(CONFIG_GPIO_HOGS gpio_hogs.c)
|
||||||
|
|
|
@ -181,6 +181,4 @@ source "drivers/gpio/Kconfig.numicro"
|
||||||
|
|
||||||
source "drivers/gpio/Kconfig.bd8lb600fs"
|
source "drivers/gpio/Kconfig.bd8lb600fs"
|
||||||
|
|
||||||
source "drivers/gpio/Kconfig.zephyr"
|
|
||||||
|
|
||||||
endif # GPIO
|
endif # GPIO
|
||||||
|
|
6
drivers/input/CMakeLists.txt
Normal file
6
drivers/input/CMakeLists.txt
Normal file
|
@ -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)
|
12
drivers/input/Kconfig
Normal file
12
drivers/input/Kconfig
Normal file
|
@ -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
|
|
@ -1,7 +1,7 @@
|
||||||
# Copyright (c) 2022 Google LLC
|
# Copyright (c) 2022 Google LLC
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
config GPIO_KEYS_ZEPHYR
|
config INPUT_GPIO_KEYS
|
||||||
bool "Zephyr GPIO Keys"
|
bool "Zephyr GPIO Keys"
|
||||||
default y
|
default y
|
||||||
depends on DT_HAS_ZEPHYR_GPIO_KEYS_ENABLED
|
depends on DT_HAS_ZEPHYR_GPIO_KEYS_ENABLED
|
|
@ -6,14 +6,20 @@
|
||||||
|
|
||||||
#include <zephyr/device.h>
|
#include <zephyr/device.h>
|
||||||
#include <zephyr/drivers/gpio.h>
|
#include <zephyr/drivers/gpio.h>
|
||||||
#include <zephyr/drivers/gpio_keys.h>
|
#include <zephyr/input/input.h>
|
||||||
#include <zephyr/kernel.h>
|
#include <zephyr/kernel.h>
|
||||||
#include <zephyr/logging/log.h>
|
#include <zephyr/logging/log.h>
|
||||||
|
|
||||||
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
|
#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 {
|
struct gpio_keys_pin_config {
|
||||||
/** GPIO specification from devicetree */
|
/** GPIO specification from devicetree */
|
||||||
struct gpio_dt_spec spec;
|
struct gpio_dt_spec spec;
|
||||||
|
@ -35,7 +41,6 @@ struct gpio_keys_pin_data {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct gpio_keys_data {
|
struct gpio_keys_data {
|
||||||
gpio_keys_callback_handler_t callback;
|
|
||||||
struct gpio_keys_pin_data *pin_data;
|
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,
|
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);
|
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) {
|
if (new_pressed != pin_data->cb_data.pin_state) {
|
||||||
pin_data->cb_data.pin_state = new_pressed;
|
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);
|
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;
|
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)
|
static int gpio_keys_init(const struct device *dev)
|
||||||
{
|
{
|
||||||
struct gpio_keys_data *data = dev->data;
|
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;
|
data->pin_data[i].dev = dev;
|
||||||
k_work_init_delayable(&data->pin_data[i].work, gpio_keys_change_deferred);
|
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;
|
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) \
|
#define GPIO_KEYS_CFG_DEF(node_id) \
|
||||||
{ \
|
{ \
|
||||||
.spec = GPIO_DT_SPEC_GET(node_id, gpios), \
|
.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, \
|
.pin_data = gpio_keys_pin_data_##i, \
|
||||||
}; \
|
}; \
|
||||||
DEVICE_DT_INST_DEFINE(i, &gpio_keys_init, NULL, &gpio_keys_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_config_##i, POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, \
|
||||||
&gpio_keys_zephyr_api);
|
NULL);
|
||||||
|
|
||||||
DT_INST_FOREACH_STATUS_OKAY(GPIO_KEYS_INIT)
|
DT_INST_FOREACH_STATUS_OKAY(GPIO_KEYS_INIT)
|
|
@ -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 <stdint.h>
|
|
||||||
#include <zephyr/drivers/gpio.h>
|
|
||||||
|
|
||||||
#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 <syscalls/gpio_keys.h>
|
|
||||||
|
|
||||||
#endif /* ZEPHYR_INCLUDE_DRIVERS_GPIO_KEYS_H_ */
|
|
|
@ -5,31 +5,5 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
&gpio0 {
|
&gpio0 {
|
||||||
ngpios = <3>;
|
ngpios = <2>;
|
||||||
};
|
|
||||||
|
|
||||||
/ {
|
|
||||||
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>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,121 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2022 Google LLC
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "zephyr/sys/util.h"
|
|
||||||
#include <zephyr/device.h>
|
|
||||||
#include <zephyr/drivers/gpio/gpio_emul.h>
|
|
||||||
#include <zephyr/kernel.h>
|
|
||||||
#include <zephyr/logging/log.h>
|
|
||||||
#include <zephyr/ztest.h>
|
|
||||||
|
|
||||||
#include <zephyr/drivers/gpio_keys.h>
|
|
||||||
|
|
||||||
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)) */
|
|
9
tests/drivers/input/gpio_keys/CMakeLists.txt
Normal file
9
tests/drivers/input/gpio_keys/CMakeLists.txt
Normal file
|
@ -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})
|
25
tests/drivers/input/gpio_keys/boards/native_posix.overlay
Normal file
25
tests/drivers/input/gpio_keys/boards/native_posix.overlay
Normal file
|
@ -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>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,6 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2023 Google LLC
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
#include "native_posix.overlay"
|
7
tests/drivers/input/gpio_keys/prj.conf
Normal file
7
tests/drivers/input/gpio_keys/prj.conf
Normal file
|
@ -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
|
84
tests/drivers/input/gpio_keys/src/main.c
Normal file
84
tests/drivers/input/gpio_keys/src/main.c
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 Google LLC
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "zephyr/sys/util.h"
|
||||||
|
#include <zephyr/device.h>
|
||||||
|
#include <zephyr/drivers/gpio/gpio_emul.h>
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
#include <zephyr/ztest.h>
|
||||||
|
#include <zephyr/input/input.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
8
tests/drivers/input/gpio_keys/testcase.yaml
Normal file
8
tests/drivers/input/gpio_keys/testcase.yaml
Normal file
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue