Move all the generic code from the Nuvoton NPCX keyboard scanning driver into input_kbd_matrix.c. While doing that convert few configs into devicetree properties and tweak few other things to enable the generic code to support multiple instances. This is limited to 8 rows for now, and that's fine for all the current in-tree drivers, the limit could be removed down the road but this should be fine for now, added few generic build checks to make sure a driver does not go over the limit, as well and some more implementation specific checks. Signed-off-by: Fabio Baltieri <fabiobaltieri@google.com>
169 lines
5.4 KiB
C
169 lines
5.4 KiB
C
/*
|
|
* Copyright 2023 Google LLC
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr/device.h>
|
|
#include <zephyr/kernel.h>
|
|
#include <zephyr/sys/util.h>
|
|
#include <zephyr/sys_clock.h>
|
|
#include <zephyr/toolchain.h>
|
|
|
|
/** Special drive_column argument for not driving any column */
|
|
#define INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE -1
|
|
|
|
/** Special drive_column argument for driving all the columns */
|
|
#define INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL -2
|
|
|
|
/** Number of tracked scan cycles */
|
|
#define INPUT_KBD_MATRIX_SCAN_OCURRENCES 30U
|
|
|
|
/**
|
|
* @brief Keyboard matrix internal APIs.
|
|
*/
|
|
struct input_kbd_matrix_api {
|
|
void (*drive_column)(const struct device *dev, int col);
|
|
int (*read_row)(const struct device *dev);
|
|
void (*set_detect_mode)(const struct device *dev, bool enabled);
|
|
};
|
|
|
|
/**
|
|
* @brief Common keyboard matrix config.
|
|
*
|
|
* This structure **must** be placed first in the driver's config structure.
|
|
*/
|
|
struct input_kbd_matrix_common_config {
|
|
struct input_kbd_matrix_api api;
|
|
uint8_t row_size;
|
|
uint8_t col_size;
|
|
uint32_t poll_period_us;
|
|
uint32_t poll_timeout_ms;
|
|
uint32_t debounce_down_ms;
|
|
uint32_t debounce_up_ms;
|
|
uint32_t settle_time_us;
|
|
bool ghostkey_check;
|
|
|
|
/* extra data pointers */
|
|
uint8_t *matrix_stable_state;
|
|
uint8_t *matrix_unstable_state;
|
|
uint8_t *matrix_previous_state;
|
|
uint8_t *matrix_new_state;
|
|
uint8_t *scan_cycle_idx;
|
|
};
|
|
|
|
#define INPUT_KBD_MATRIX_DATA_NAME(node_id, name) \
|
|
_CONCAT(__input_kbd_matrix_, \
|
|
_CONCAT(name, DEVICE_DT_NAME_GET(node_id)))
|
|
|
|
/**
|
|
* @brief Defines the common keyboard matrix support data from devicetree.
|
|
*/
|
|
#define INPUT_KBD_MATRIX_DT_DEFINE(node_id) \
|
|
BUILD_ASSERT(IN_RANGE(DT_PROP(node_id, row_size), 1, 8), "invalid row-size"); \
|
|
BUILD_ASSERT(IN_RANGE(DT_PROP(node_id, col_size), 1, UINT8_MAX), "invalid col-size"); \
|
|
static uint8_t INPUT_KBD_MATRIX_DATA_NAME( \
|
|
node_id, stable_state)[DT_PROP(node_id, col_size)]; \
|
|
static uint8_t INPUT_KBD_MATRIX_DATA_NAME( \
|
|
node_id, unstable_state)[DT_PROP(node_id, col_size)]; \
|
|
static uint8_t INPUT_KBD_MATRIX_DATA_NAME( \
|
|
node_id, previous_state)[DT_PROP(node_id, col_size)]; \
|
|
static uint8_t INPUT_KBD_MATRIX_DATA_NAME( \
|
|
node_id, new_state)[DT_PROP(node_id, col_size)]; \
|
|
static uint8_t INPUT_KBD_MATRIX_DATA_NAME( \
|
|
node_id, scan_cycle_idx)[DT_PROP(node_id, row_size) * \
|
|
DT_PROP(node_id, col_size)];
|
|
|
|
/**
|
|
* @brief Defines the common keyboard matrix support data from devicetree instance.
|
|
*
|
|
* @param inst Instance.
|
|
*/
|
|
#define INPUT_KBD_MATRIX_DT_INST_DEFINE(inst) \
|
|
INPUT_KBD_MATRIX_DT_DEFINE(DT_DRV_INST(inst))
|
|
|
|
/**
|
|
* @brief Initialize common keyboard matrix config from devicetree.
|
|
*
|
|
* @param api Pointer to a :c:struct:`input_kbd_matrix_api` structure.
|
|
*/
|
|
#define INPUT_KBD_MATRIX_DT_COMMON_CONFIG_INIT(node_id, _api) \
|
|
{ \
|
|
.api = _api, \
|
|
.row_size = DT_PROP(node_id, row_size), \
|
|
.col_size = DT_PROP(node_id, col_size), \
|
|
.poll_period_us = DT_PROP(node_id, poll_period_ms) * USEC_PER_MSEC, \
|
|
.poll_timeout_ms = DT_PROP(node_id, poll_timeout_ms), \
|
|
.debounce_down_ms = DT_PROP(node_id, debounce_down_ms), \
|
|
.debounce_up_ms = DT_PROP(node_id, debounce_up_ms), \
|
|
.settle_time_us = DT_PROP(node_id, settle_time_us), \
|
|
.ghostkey_check = !DT_PROP(node_id, no_ghostkey_check), \
|
|
\
|
|
.matrix_stable_state = INPUT_KBD_MATRIX_DATA_NAME(node_id, stable_state), \
|
|
.matrix_unstable_state = INPUT_KBD_MATRIX_DATA_NAME(node_id, unstable_state), \
|
|
.matrix_previous_state = INPUT_KBD_MATRIX_DATA_NAME(node_id, previous_state), \
|
|
.matrix_new_state = INPUT_KBD_MATRIX_DATA_NAME(node_id, new_state), \
|
|
.scan_cycle_idx = INPUT_KBD_MATRIX_DATA_NAME(node_id, scan_cycle_idx), \
|
|
}
|
|
|
|
/**
|
|
* @brief Initialize common keyboard matrix config from devicetree instance.
|
|
*
|
|
* @param inst Instance.
|
|
* @param api Pointer to a :c:struct:`input_kbd_matrix_api` structure.
|
|
*/
|
|
#define INPUT_KBD_MATRIX_DT_INST_COMMON_CONFIG_INIT(inst, api) \
|
|
INPUT_KBD_MATRIX_DT_COMMON_CONFIG_INIT(DT_DRV_INST(inst), api)
|
|
|
|
/**
|
|
* @brief Common keyboard matrix data.
|
|
*
|
|
* This structure **must** be placed first in the driver's data structure.
|
|
*/
|
|
struct input_kbd_matrix_common_data {
|
|
/* Track previous cycles, used for debouncing. */
|
|
uint8_t scan_clk_cycle[INPUT_KBD_MATRIX_SCAN_OCURRENCES];
|
|
uint8_t scan_cycles_idx;
|
|
|
|
struct k_sem poll_lock;
|
|
|
|
struct k_thread thread;
|
|
|
|
K_KERNEL_STACK_MEMBER(thread_stack,
|
|
CONFIG_INPUT_KBD_MATRIX_THREAD_STACK_SIZE);
|
|
};
|
|
|
|
/**
|
|
* @brief Validate the offset of the common data structures.
|
|
*
|
|
* @param config Name of the config structure.
|
|
* @param data Name of the data structure.
|
|
*/
|
|
#define INPUT_KBD_STRUCT_CHECK(config, data) \
|
|
BUILD_ASSERT(offsetof(config, common) == 0, \
|
|
"struct input_kbd_matrix_common_config must be placed first"); \
|
|
BUILD_ASSERT(offsetof(data, common) == 0, \
|
|
"struct input_kbd_matrix_common_data must be placed first")
|
|
|
|
/**
|
|
* @brief Start scanning the keyboard matrix
|
|
*
|
|
* Starts the keyboard matrix scanning cycle, this should be called in reaction
|
|
* of a press event, after the device has been put in detect mode.
|
|
*
|
|
* @param dev Keyboard matrix device instance.
|
|
*/
|
|
void input_kbd_matrix_poll_start(const struct device *dev);
|
|
|
|
/**
|
|
* @brief Common function to initialize a keyboard matrix device at init time.
|
|
*
|
|
* This function must be called at the end of the device init function.
|
|
*
|
|
* @param dev Keyboard matrix device instance.
|
|
*
|
|
* @retval 0 If initialized successfully.
|
|
* @retval -errno Negative errno in case of failure.
|
|
*/
|
|
int input_kbd_matrix_common_init(const struct device *dev);
|