Add matrix polling logic to matrix GPIO driver.

This commit is contained in:
Jason Chestnut 2020-09-25 11:29:21 -04:00
parent 9668305621
commit b1dce208f8
2 changed files with 48 additions and 19 deletions

View file

@ -7,7 +7,7 @@ if ZMK_KSCAN_GPIO_DRIVER
config ZMK_KSCAN_MATRIX_POLLING config ZMK_KSCAN_MATRIX_POLLING
bool "Poll for key event triggers instead of using interrupts on matrix boards." bool "Poll for key event triggers instead of using interrupts on matrix boards."
default y default n
config ZMK_KSCAN_DIRECT_POLLING config ZMK_KSCAN_DIRECT_POLLING
bool "Poll for key event triggers instead of using interrupts on direct wired boards." bool "Poll for key event triggers instead of using interrupts on direct wired boards."

View file

@ -31,7 +31,8 @@ struct kscan_gpio_item_config {
#define _KSCAN_GPIO_ROW_CFG_INIT(idx, n) _KSCAN_GPIO_ITEM_CFG_INIT(n, row_gpios, idx) #define _KSCAN_GPIO_ROW_CFG_INIT(idx, n) _KSCAN_GPIO_ITEM_CFG_INIT(n, row_gpios, idx)
#define _KSCAN_GPIO_COL_CFG_INIT(idx, n) _KSCAN_GPIO_ITEM_CFG_INIT(n, col_gpios, idx) #define _KSCAN_GPIO_COL_CFG_INIT(idx, n) _KSCAN_GPIO_ITEM_CFG_INIT(n, col_gpios, idx)
static int kscan_gpio_config_interrupts(struct device **devices, COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING,
(static int kscan_gpio_config_interrupts(struct device **devices,
const struct kscan_gpio_item_config *configs, size_t len, const struct kscan_gpio_item_config *configs, size_t len,
gpio_flags_t flags) { gpio_flags_t flags) {
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
@ -47,7 +48,8 @@ static int kscan_gpio_config_interrupts(struct device **devices,
} }
return 0; return 0;
} }), ())
#define INST_MATRIX_ROWS(n) DT_INST_PROP_LEN(n, row_gpios) #define INST_MATRIX_ROWS(n) DT_INST_PROP_LEN(n, row_gpios)
#define INST_MATRIX_COLS(n) DT_INST_PROP_LEN(n, col_gpios) #define INST_MATRIX_COLS(n) DT_INST_PROP_LEN(n, col_gpios)
#define INST_OUTPUT_LEN(n) \ #define INST_OUTPUT_LEN(n) \
@ -69,6 +71,7 @@ static int kscan_gpio_config_interrupts(struct device **devices,
}; \ }; \
struct kscan_gpio_data_##n { \ struct kscan_gpio_data_##n { \
kscan_callback_t callback; \ kscan_callback_t callback; \
COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, (), (struct k_timer poll_timer;)) \
struct COND_CODE_0(DT_INST_PROP(n, debounce_period), (k_work), (k_delayed_work)) work; \ struct COND_CODE_0(DT_INST_PROP(n, debounce_period), (k_work), (k_delayed_work)) work; \
bool matrix_state[INST_MATRIX_ROWS(n)][INST_MATRIX_COLS(n)]; \ bool matrix_state[INST_MATRIX_ROWS(n)][INST_MATRIX_COLS(n)]; \
struct device *rows[INST_MATRIX_ROWS(n)]; \ struct device *rows[INST_MATRIX_ROWS(n)]; \
@ -96,16 +99,17 @@ static int kscan_gpio_config_interrupts(struct device **devices,
return ( \ return ( \
COND_CODE_0(DT_ENUM_IDX(DT_DRV_INST(n), diode_direction), (cfg->rows), (cfg->cols))); \ COND_CODE_0(DT_ENUM_IDX(DT_DRV_INST(n), diode_direction), (cfg->rows), (cfg->cols))); \
} \ } \
static int kscan_gpio_enable_interrupts_##n(struct device *dev) { \ COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, \
return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), \ (static int kscan_gpio_enable_interrupts_##n(struct device *dev) { \
return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), \
kscan_gpio_input_configs_##n(dev), INST_INPUT_LEN(n), \ kscan_gpio_input_configs_##n(dev), INST_INPUT_LEN(n), \
GPIO_INT_DEBOUNCE | GPIO_INT_EDGE_BOTH); \ GPIO_INT_DEBOUNCE | GPIO_INT_EDGE_BOTH); \
} \ } \
static int kscan_gpio_disable_interrupts_##n(struct device *dev) { \ static int kscan_gpio_disable_interrupts_##n(struct device *dev) { \
return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), \ return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), \
kscan_gpio_input_configs_##n(dev), INST_INPUT_LEN(n), \ kscan_gpio_input_configs_##n(dev), INST_INPUT_LEN(n), \
GPIO_INT_DISABLE); \ GPIO_INT_DISABLE); \
} \ }), ()) \
static void kscan_gpio_set_output_state_##n(struct device *dev, int value) { \ static void kscan_gpio_set_output_state_##n(struct device *dev, int value) { \
for (int i = 0; i < INST_OUTPUT_LEN(n); i++) { \ for (int i = 0; i < INST_OUTPUT_LEN(n); i++) { \
struct device *in_dev = kscan_gpio_output_devices_##n(dev)[i]; \ struct device *in_dev = kscan_gpio_output_devices_##n(dev)[i]; \
@ -128,7 +132,8 @@ static int kscan_gpio_config_interrupts(struct device **devices,
/* Disable our interrupts temporarily while we scan, to avoid */ \ /* Disable our interrupts temporarily while we scan, to avoid */ \
/* re-entry while we iterate columns and set them active one by one */ \ /* re-entry while we iterate columns and set them active one by one */ \
/* to get pressed state for each matrix cell. */ \ /* to get pressed state for each matrix cell. */ \
kscan_gpio_disable_interrupts_##n(dev); \ COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, \
(kscan_gpio_disable_interrupts_##n(dev);),()) \
kscan_gpio_set_output_state_##n(dev, 0); \ kscan_gpio_set_output_state_##n(dev, 0); \
for (int o = 0; o < INST_OUTPUT_LEN(n); o++) { \ for (int o = 0; o < INST_OUTPUT_LEN(n); o++) { \
struct device *out_dev = kscan_gpio_output_devices_##n(dev)[o]; \ struct device *out_dev = kscan_gpio_output_devices_##n(dev)[o]; \
@ -143,10 +148,11 @@ static int kscan_gpio_config_interrupts(struct device **devices,
} \ } \
gpio_pin_set(out_dev, out_cfg->pin, 0); \ gpio_pin_set(out_dev, out_cfg->pin, 0); \
} \ } \
/* Set all our outputs as active again, then re-enable interrupts, */ \ /* Set all our outputs as active again. */ \
/* so we can trigger interrupts again for future press/release */ \
kscan_gpio_set_output_state_##n(dev, 1); \ kscan_gpio_set_output_state_##n(dev, 1); \
kscan_gpio_enable_interrupts_##n(dev); \ /*Re-enable interrupts so that they can be triggered again for future press/release*/ \
COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, \
(kscan_gpio_enable_interrupts_##n(dev);), ()) \
for (int r = 0; r < INST_MATRIX_ROWS(n); r++) { \ for (int r = 0; r < INST_MATRIX_ROWS(n); r++) { \
for (int c = 0; c < INST_MATRIX_COLS(n); c++) { \ for (int c = 0; c < INST_MATRIX_COLS(n); c++) { \
bool pressed = read_state[r][c]; \ bool pressed = read_state[r][c]; \
@ -190,15 +196,34 @@ static int kscan_gpio_config_interrupts(struct device **devices,
return -EINVAL; \ return -EINVAL; \
} \ } \
data->callback = callback; \ data->callback = callback; \
LOG_DBG("Configured GPIO %d", n); \
return 0; \ return 0; \
}; \ }; \
static int kscan_gpio_enable_##n(struct device *dev) { \ static int kscan_gpio_enable_##n(struct device *dev) { \
int err = kscan_gpio_enable_interrupts_##n(dev); \ COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, \
if (err) { \ (int err = kscan_gpio_enable_interrupts_##n(dev); \
return err; \ if (err) { \
} \ return err; \
return kscan_gpio_read_##n(dev); \ } \
return kscan_gpio_read_##n(dev);), \
(struct kscan_gpio_data_##n *data = dev->driver_data; \
k_timer_start(&data->poll_timer, K_MSEC(10), K_MSEC(10)); \
return 0;)) \
}; \ }; \
static int kscan_gpio_disable_##n(struct device *dev) { \
COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, \
(return kscan_gpio_disable_interrupts_##n(dev);), \
(struct kscan_gpio_data_##n *data = dev->driver_data; \
k_timer_stop(&data->poll_timer); \
return 0;)) \
}; \
COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, (), \
(static void kscan_gpio_timer_handler(struct k_timer *timer) { \
struct kscan_gpio_data_##n *data = \
CONTAINER_OF(timer, struct kscan_gpio_data_##n, poll_timer); \
k_work_submit(&data->work.work); \
LOG_DBG("Submitted work in timer handler."); \
})) \
static int kscan_gpio_init_##n(struct device *dev) { \ static int kscan_gpio_init_##n(struct device *dev) { \
struct kscan_gpio_data_##n *data = dev->driver_data; \ struct kscan_gpio_data_##n *data = dev->driver_data; \
int err; \ int err; \
@ -214,6 +239,8 @@ static int kscan_gpio_config_interrupts(struct device **devices,
if (err) { \ if (err) { \
LOG_ERR("Unable to configure pin %d on %s for input", in_cfg->pin, in_cfg->label); \ LOG_ERR("Unable to configure pin %d on %s for input", in_cfg->pin, in_cfg->label); \
return err; \ return err; \
} else { \
LOG_DBG("Configured pin %d on %s for input", in_cfg->pin, in_cfg->label); \
} \ } \
irq_callbacks_##n[i].work = &data->work; \ irq_callbacks_##n[i].work = &data->work; \
gpio_init_callback(&irq_callbacks_##n[i].callback, \ gpio_init_callback(&irq_callbacks_##n[i].callback, \
@ -241,6 +268,8 @@ static int kscan_gpio_config_interrupts(struct device **devices,
} \ } \
} \ } \
data->dev = dev; \ data->dev = dev; \
COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, (), \
(k_timer_init(&data->poll_timer, kscan_gpio_timer_handler, NULL);)) \
(COND_CODE_0(DT_INST_PROP(n, debounce_period), (k_work_init), (k_delayed_work_init)))( \ (COND_CODE_0(DT_INST_PROP(n, debounce_period), (k_work_init), (k_delayed_work_init)))( \
&data->work, kscan_gpio_work_handler_##n); \ &data->work, kscan_gpio_work_handler_##n); \
return 0; \ return 0; \
@ -248,7 +277,7 @@ static int kscan_gpio_config_interrupts(struct device **devices,
static const struct kscan_driver_api gpio_driver_api_##n = { \ static const struct kscan_driver_api gpio_driver_api_##n = { \
.config = kscan_gpio_configure_##n, \ .config = kscan_gpio_configure_##n, \
.enable_callback = kscan_gpio_enable_##n, \ .enable_callback = kscan_gpio_enable_##n, \
.disable_callback = kscan_gpio_disable_interrupts_##n, \ .disable_callback = kscan_gpio_disable_##n, \
}; \ }; \
static const struct kscan_gpio_config_##n kscan_gpio_config_##n = { \ static const struct kscan_gpio_config_##n kscan_gpio_config_##n = { \
.rows = {UTIL_LISTIFY(INST_MATRIX_ROWS(n), _KSCAN_GPIO_ROW_CFG_INIT, n)}, \ .rows = {UTIL_LISTIFY(INST_MATRIX_ROWS(n), _KSCAN_GPIO_ROW_CFG_INIT, n)}, \