input: add a gpio based keyboard matrix driver
Add a GPIO based keyboard matrix driver using the generic keyboard matrix code. Signed-off-by: Fabio Baltieri <fabiobaltieri@google.com>
This commit is contained in:
parent
be5cb7af7c
commit
256bc860cf
|
@ -7,6 +7,7 @@ zephyr_library_property(ALLOW_EMPTY TRUE)
|
|||
zephyr_library_sources_ifdef(CONFIG_INPUT_CAP1203 input_cap1203.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_INPUT_CST816S input_cst816s.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_INPUT_FT5336 input_ft5336.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_INPUT_GPIO_KBD_MATRIX input_gpio_kbd_matrix.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_INPUT_GPIO_KEYS input_gpio_keys.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_INPUT_GPIO_QDEC input_gpio_qdec.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_INPUT_GT911 input_gt911.c)
|
||||
|
|
|
@ -9,6 +9,7 @@ menu "Input drivers"
|
|||
source "drivers/input/Kconfig.cap1203"
|
||||
source "drivers/input/Kconfig.cst816s"
|
||||
source "drivers/input/Kconfig.ft5336"
|
||||
source "drivers/input/Kconfig.gpio_kbd_matrix"
|
||||
source "drivers/input/Kconfig.gpio_keys"
|
||||
source "drivers/input/Kconfig.gpio_qdec"
|
||||
source "drivers/input/Kconfig.gt911"
|
||||
|
|
10
drivers/input/Kconfig.gpio_kbd_matrix
Normal file
10
drivers/input/Kconfig.gpio_kbd_matrix
Normal file
|
@ -0,0 +1,10 @@
|
|||
# Copyright 2023 Google LLC
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config INPUT_GPIO_KBD_MATRIX
|
||||
bool "GPIO based keyboard matrix input driver"
|
||||
default y
|
||||
depends on DT_HAS_GPIO_KBD_MATRIX_ENABLED
|
||||
select INPUT_KBD_MATRIX
|
||||
help
|
||||
GPIO keyboard matrix input driver.
|
198
drivers/input/input_gpio_kbd_matrix.c
Normal file
198
drivers/input/input_gpio_kbd_matrix.c
Normal file
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* Copyright 2023 Google LLC
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT gpio_kbd_matrix
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/drivers/gpio.h>
|
||||
#include <zephyr/input/input_kbd_matrix.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(input_gpio_kbd_matrix, CONFIG_INPUT_LOG_LEVEL);
|
||||
|
||||
struct gpio_kbd_matrix_config {
|
||||
struct input_kbd_matrix_common_config common;
|
||||
const struct gpio_dt_spec *row_gpio;
|
||||
const struct gpio_dt_spec *col_gpio;
|
||||
struct gpio_callback *gpio_cb;
|
||||
gpio_callback_handler_t handler;
|
||||
};
|
||||
|
||||
struct gpio_kbd_matrix_data {
|
||||
struct input_kbd_matrix_common_data common;
|
||||
uint32_t last_col_state;
|
||||
};
|
||||
|
||||
INPUT_KBD_STRUCT_CHECK(struct gpio_kbd_matrix_config,
|
||||
struct gpio_kbd_matrix_data);
|
||||
|
||||
static void gpio_kbd_matrix_drive_column(const struct device *dev, int col)
|
||||
{
|
||||
const struct gpio_kbd_matrix_config *cfg = dev->config;
|
||||
const struct input_kbd_matrix_common_config *common = &cfg->common;
|
||||
struct gpio_kbd_matrix_data *data = dev->data;
|
||||
int state;
|
||||
|
||||
if (col == INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE) {
|
||||
state = 0;
|
||||
} else if (col == INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL) {
|
||||
state = BIT_MASK(common->col_size);
|
||||
} else {
|
||||
state = BIT(col);
|
||||
}
|
||||
|
||||
for (int i = 0; i < common->col_size; i++) {
|
||||
const struct gpio_dt_spec *gpio = &cfg->col_gpio[i];
|
||||
|
||||
if ((data->last_col_state ^ state) & BIT(i)) {
|
||||
if (state & BIT(i)) {
|
||||
gpio_pin_configure_dt(gpio, GPIO_OUTPUT_ACTIVE);
|
||||
} else {
|
||||
gpio_pin_configure_dt(gpio, GPIO_INPUT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data->last_col_state = state;
|
||||
}
|
||||
|
||||
static int gpio_kbd_matrix_read_row(const struct device *dev)
|
||||
{
|
||||
const struct gpio_kbd_matrix_config *cfg = dev->config;
|
||||
const struct input_kbd_matrix_common_config *common = &cfg->common;
|
||||
int val = 0;
|
||||
|
||||
for (int i = 0; i < common->row_size; i++) {
|
||||
const struct gpio_dt_spec *gpio = &cfg->row_gpio[i];
|
||||
|
||||
if (gpio_pin_get_dt(gpio)) {
|
||||
val |= BIT(i);
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void gpio_kbd_matrix_set_detect_mode(const struct device *dev, bool enabled)
|
||||
{
|
||||
const struct gpio_kbd_matrix_config *cfg = dev->config;
|
||||
const struct input_kbd_matrix_common_config *common = &cfg->common;
|
||||
unsigned int flags = enabled ? GPIO_INT_EDGE_BOTH : GPIO_INT_DISABLE;
|
||||
int ret;
|
||||
|
||||
for (int i = 0; i < common->row_size; i++) {
|
||||
const struct gpio_dt_spec *gpio = &cfg->row_gpio[i];
|
||||
|
||||
ret = gpio_pin_interrupt_configure_dt(gpio, flags);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Pin %d interrupt configuration failed: %d", i, ret);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int gpio_kbd_matrix_init(const struct device *dev)
|
||||
{
|
||||
const struct gpio_kbd_matrix_config *cfg = dev->config;
|
||||
const struct input_kbd_matrix_common_config *common = &cfg->common;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < common->col_size; i++) {
|
||||
const struct gpio_dt_spec *gpio = &cfg->col_gpio[i];
|
||||
|
||||
if (!gpio_is_ready_dt(gpio)) {
|
||||
LOG_ERR("%s is not ready", gpio->port->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = gpio_pin_configure_dt(gpio, GPIO_INPUT);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Pin %d configuration failed: %d", i, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < common->row_size; i++) {
|
||||
const struct gpio_dt_spec *gpio = &cfg->row_gpio[i];
|
||||
struct gpio_callback *gpio_cb = &cfg->gpio_cb[i];
|
||||
|
||||
if (!gpio_is_ready_dt(gpio)) {
|
||||
LOG_ERR("%s is not ready", gpio->port->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = gpio_pin_configure_dt(gpio, GPIO_INPUT);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Pin %d configuration failed: %d", i, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gpio_init_callback(gpio_cb, cfg->handler, BIT(gpio->pin));
|
||||
|
||||
ret = gpio_add_callback_dt(gpio, gpio_cb);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Could not set gpio callback");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
gpio_kbd_matrix_set_detect_mode(dev, true);
|
||||
|
||||
return input_kbd_matrix_common_init(dev);
|
||||
}
|
||||
|
||||
static const struct input_kbd_matrix_api gpio_kbd_matrix_api = {
|
||||
.drive_column = gpio_kbd_matrix_drive_column,
|
||||
.read_row = gpio_kbd_matrix_read_row,
|
||||
.set_detect_mode = gpio_kbd_matrix_set_detect_mode,
|
||||
};
|
||||
|
||||
#define INPUT_GPIO_KBD_MATRIX_INIT(n) \
|
||||
BUILD_ASSERT(DT_INST_PROP_LEN(n, col_gpios) <= 32, "invalid col-size"); \
|
||||
\
|
||||
INPUT_KBD_MATRIX_DT_INST_DEFINE_ROW_COL( \
|
||||
n, DT_INST_PROP_LEN(n, row_gpios), DT_INST_PROP_LEN(n, col_gpios)); \
|
||||
\
|
||||
static void gpio_kbd_matrix_cb_##n(const struct device *gpio_dev, \
|
||||
struct gpio_callback *cb, uint32_t pins) \
|
||||
{ \
|
||||
input_kbd_matrix_poll_start(DEVICE_DT_INST_GET(n)); \
|
||||
} \
|
||||
\
|
||||
static const struct gpio_dt_spec gpio_kbd_matrix_row_gpio_##n[DT_INST_PROP_LEN( \
|
||||
n, row_gpios)] = { \
|
||||
DT_INST_FOREACH_PROP_ELEM_SEP(n, row_gpios, GPIO_DT_SPEC_GET_BY_IDX, (,)) \
|
||||
}; \
|
||||
static const struct gpio_dt_spec gpio_kbd_matrix_col_gpio_##n[DT_INST_PROP_LEN( \
|
||||
n, col_gpios)] = { \
|
||||
DT_INST_FOREACH_PROP_ELEM_SEP(n, col_gpios, GPIO_DT_SPEC_GET_BY_IDX, (,)) \
|
||||
}; \
|
||||
static struct gpio_callback gpio_kbd_matrix_gpio_cb_##n[DT_INST_PROP_LEN(n, row_gpios)];\
|
||||
\
|
||||
static const struct gpio_kbd_matrix_config gpio_kbd_matrix_cfg_##n = { \
|
||||
.common = INPUT_KBD_MATRIX_DT_INST_COMMON_CONFIG_INIT_ROW_COL( \
|
||||
n, &gpio_kbd_matrix_api, \
|
||||
DT_INST_PROP_LEN(n, row_gpios), DT_INST_PROP_LEN(n, col_gpios)), \
|
||||
.row_gpio = gpio_kbd_matrix_row_gpio_##n, \
|
||||
.col_gpio = gpio_kbd_matrix_col_gpio_##n, \
|
||||
.gpio_cb = gpio_kbd_matrix_gpio_cb_##n, \
|
||||
.handler = gpio_kbd_matrix_cb_##n, \
|
||||
}; \
|
||||
\
|
||||
static struct gpio_kbd_matrix_data gpio_kbd_matrix_data_##n; \
|
||||
\
|
||||
DEVICE_DT_INST_DEFINE(n, gpio_kbd_matrix_init, NULL, \
|
||||
&gpio_kbd_matrix_data_##n, &gpio_kbd_matrix_cfg_##n, \
|
||||
POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, \
|
||||
NULL);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(INPUT_GPIO_KBD_MATRIX_INIT)
|
43
dts/bindings/input/gpio-kbd-matrix.yaml
Normal file
43
dts/bindings/input/gpio-kbd-matrix.yaml
Normal file
|
@ -0,0 +1,43 @@
|
|||
# Copyright 2023 Google LLC
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: |
|
||||
GPIO based keyboard matrix input device
|
||||
|
||||
Implement an input device for a GPIO based keyboard matrix.
|
||||
|
||||
Example configuration:
|
||||
|
||||
kbd-matrix {
|
||||
compatible = "gpio-kbd-matrix";
|
||||
row-gpios = <&gpio0 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>,
|
||||
<&gpio0 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
|
||||
col-gpios = <&gpio0 2 GPIO_ACTIVE_LOW>,
|
||||
<&gpio0 3 GPIO_ACTIVE_LOW>,
|
||||
<&gpio0 4 GPIO_ACTIVE_LOW>;
|
||||
no-ghostkey-check;
|
||||
};
|
||||
|
||||
compatible: "gpio-kbd-matrix"
|
||||
|
||||
include:
|
||||
- name: kbd-matrix-common.yaml
|
||||
property-blocklist:
|
||||
- row-size
|
||||
- col-size
|
||||
|
||||
properties:
|
||||
row-gpios:
|
||||
type: phandle-array
|
||||
required: true
|
||||
description: |
|
||||
GPIO for the keyboard matrix rows, up to 8 different GPIOs. All row GPIO
|
||||
pins must have interrupt support.
|
||||
|
||||
col-gpios:
|
||||
type: phandle-array
|
||||
required: true
|
||||
description: |
|
||||
GPIO for the keyboard matrix columns, supports up to 32 different GPIOs.
|
||||
The pins will be driven according to the GPIO_ACTIVE_HIGH or
|
||||
GPIO_ACTIVE_LOW flags when selected, high impedance when not selected.
|
|
@ -26,6 +26,15 @@
|
|||
};
|
||||
};
|
||||
|
||||
kbd-matrix {
|
||||
compatible = "gpio-kbd-matrix";
|
||||
row-gpios = <&test_gpio 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>,
|
||||
<&test_gpio 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
|
||||
col-gpios = <&test_gpio 2 GPIO_ACTIVE_LOW>,
|
||||
<&test_gpio 3 GPIO_ACTIVE_LOW>,
|
||||
<&test_gpio 4 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
||||
qdec-gpio {
|
||||
compatible = "gpio-qdec";
|
||||
gpios = <&test_gpio 0 0>, <&test_gpio 1 0>;
|
||||
|
|
Loading…
Reference in a new issue