Skip to content

Commit

Permalink
input: gpio_kbd_matrix: add direct access support
Browse files Browse the repository at this point in the history
When the matrix is connected to consecutive pins on the same port, it's
possible to read the whole row or set the whole column in a single
operation. For the column, this is only possible if the matrix is
configured for driving unselected column, as there's no API to configure
multiple pins at the same time at the moment.

This is more efficient than checking the pins individually, and it's
particularly useful if the row or columns are driven from a GPIO port
expander.

Add some code to detect the condition and enable it automatically as
long as the hw configuration supports it.

Signed-off-by: Fabio Baltieri <fabiobaltieri@google.com>
  • Loading branch information
fabiobaltieri committed Nov 22, 2023
1 parent 8ec1b54 commit 6cd7249
Showing 1 changed file with 53 additions and 0 deletions.
53 changes: 53 additions & 0 deletions drivers/input/input_gpio_kbd_matrix.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ struct gpio_kbd_matrix_config {
struct gpio_kbd_matrix_data {
struct input_kbd_matrix_common_data common;
uint32_t last_col_state;
bool direct_read;
bool direct_write;
};

INPUT_KBD_STRUCT_CHECK(struct gpio_kbd_matrix_config,
Expand All @@ -50,6 +52,19 @@ static void gpio_kbd_matrix_drive_column(const struct device *dev, int col)
state = BIT(col);
}

if (data->direct_write) {
const struct gpio_dt_spec *gpio0 = &cfg->col_gpio[0];
gpio_port_pins_t gpio_mask;
gpio_port_value_t gpio_val;

gpio_mask = BIT_MASK(common->col_size) << gpio0->pin;
gpio_val = state << gpio0->pin;

gpio_port_set_masked(gpio0->port, gpio_mask, gpio_val);

return;
}

for (int i = 0; i < common->col_size; i++) {
const struct gpio_dt_spec *gpio = &cfg->col_gpio[i];

Expand All @@ -71,8 +86,18 @@ static kbd_row_t 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;
struct gpio_kbd_matrix_data *data = dev->data;
int val = 0;

if (data->direct_read) {
const struct gpio_dt_spec *gpio0 = &cfg->row_gpio[0];
gpio_port_value_t gpio_val;

gpio_port_get(gpio0->port, &gpio_val);

return (gpio_val >> gpio0->pin) & BIT_MASK(common->row_size);
}

for (int i = 0; i < common->row_size; i++) {
const struct gpio_dt_spec *gpio = &cfg->row_gpio[i];

Expand Down Expand Up @@ -102,10 +127,27 @@ static void gpio_kbd_matrix_set_detect_mode(const struct device *dev, bool enabl
}
}

static bool gpio_kbd_matrix_is_gpio_coherent(
const struct gpio_dt_spec *gpio, int gpio_count)
{
const struct gpio_dt_spec *gpio0 = &gpio[0];

for (int i = 1; i < gpio_count; i++) {
if (gpio[i].port != gpio0->port ||
gpio[i].dt_flags != gpio0->dt_flags ||
gpio[i].pin != gpio0->pin + i) {
return false;
}
}

return true;
}

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;
struct gpio_kbd_matrix_data *data = dev->data;
int ret;
int i;

Expand Down Expand Up @@ -152,6 +194,17 @@ static int gpio_kbd_matrix_init(const struct device *dev)
}
}

data->direct_read = gpio_kbd_matrix_is_gpio_coherent(
cfg->row_gpio, common->row_size);

if (cfg->col_drive_inactive) {
data->direct_write = gpio_kbd_matrix_is_gpio_coherent(
cfg->col_gpio, common->col_size);
}

LOG_DBG("direct_read: %d direct_write: %d",
data->direct_read, data->direct_write);

gpio_kbd_matrix_set_detect_mode(dev, true);

return input_kbd_matrix_common_init(dev);
Expand Down

0 comments on commit 6cd7249

Please sign in to comment.