drivers/input/keyboard/matrix_keypad.c

Source file repositories/reference/linux-study-clean/drivers/input/keyboard/matrix_keypad.c

File Facts

System
Linux kernel
Corpus path
drivers/input/keyboard/matrix_keypad.c
Extension
.c
Size
12360 bytes
Lines
492
Domain
Driver Families
Bucket
drivers/input
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct matrix_keypad {
	struct input_dev *input_dev;
	unsigned int row_shift;

	unsigned int col_scan_delay_us;
	unsigned int all_cols_on_delay_us;
	/* key debounce interval in milli-second */
	unsigned int debounce_ms;
	bool drive_inactive_cols;

	struct gpio_desc *row_gpios[MATRIX_MAX_ROWS];
	unsigned int num_row_gpios;

	struct gpio_desc *col_gpios[MATRIX_MAX_ROWS];
	unsigned int num_col_gpios;

	unsigned int row_irqs[MATRIX_MAX_ROWS];
	DECLARE_BITMAP(wakeup_enabled_irqs, MATRIX_MAX_ROWS);

	uint32_t last_key_state[MATRIX_MAX_COLS];
	struct delayed_work work;
	spinlock_t lock;
	bool scan_pending;
	bool stopped;
};

/*
 * NOTE: If drive_inactive_cols is false, then the GPIO has to be put into
 * HiZ when de-activated to cause minmal side effect when scanning other
 * columns. In that case it is configured here to be input, otherwise it is
 * driven with the inactive value.
 */
static void __activate_col(struct matrix_keypad *keypad, int col, bool on)
{
	if (on) {
		gpiod_direction_output(keypad->col_gpios[col], 1);
	} else {
		gpiod_set_value_cansleep(keypad->col_gpios[col], 0);
		if (!keypad->drive_inactive_cols)
			gpiod_direction_input(keypad->col_gpios[col]);
	}
}

static void activate_col(struct matrix_keypad *keypad, int col, bool on)
{
	__activate_col(keypad, col, on);

	if (on && keypad->col_scan_delay_us)
		fsleep(keypad->col_scan_delay_us);
}

static void activate_all_cols(struct matrix_keypad *keypad, bool on)
{
	int col;

	for (col = 0; col < keypad->num_col_gpios; col++)
		__activate_col(keypad, col, on);

	if (on && keypad->all_cols_on_delay_us)
		fsleep(keypad->all_cols_on_delay_us);
}

static bool row_asserted(struct matrix_keypad *keypad, int row)
{
	return gpiod_get_value_cansleep(keypad->row_gpios[row]);
}

static void enable_row_irqs(struct matrix_keypad *keypad)
{
	int i;

	for (i = 0; i < keypad->num_row_gpios; i++)
		enable_irq(keypad->row_irqs[i]);
}

static void disable_row_irqs(struct matrix_keypad *keypad)
{
	int i;

	for (i = 0; i < keypad->num_row_gpios; i++)
		disable_irq_nosync(keypad->row_irqs[i]);
}

static uint32_t read_row_state(struct matrix_keypad *keypad)
{
	int row;
	u32 row_state = 0;

	for (row = 0; row < keypad->num_row_gpios; row++)
		row_state |= row_asserted(keypad, row) ? BIT(row) : 0;

Annotation

Implementation Notes