You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
272 lines
8.9 KiB
272 lines
8.9 KiB
.. _gpio-kbd: |
|
|
|
GPIO Keyboard Matrix |
|
#################### |
|
|
|
The :dtcompatible:`gpio-kbd-matrix` driver supports a large variety of keyboard |
|
matrix hardware configurations and has numerous options to change its behavior. |
|
This is an overview of some common setups and how they can be supported by the |
|
driver. |
|
|
|
The conventional configuration for all of these is that the driver reads on the |
|
row GPIOs (inputs) and selects on the columns GPIOs (output). |
|
|
|
Base use case, no isolation diodes, interrupt capable GPIOs |
|
*********************************************************** |
|
|
|
This is the common configuration found on consumer keyboards with membrane |
|
switches and flexible circuit boards, no isolation diodes, requires ghosting |
|
detection (which is enabled by default). |
|
|
|
.. figure:: no-diodes.svg |
|
:align: center |
|
:width: 50% |
|
|
|
A 3x3 matrix, no diodes |
|
|
|
The system must support GPIO interrupts, and the interrupt can be enabled on all |
|
row GPIOs at the same time. |
|
|
|
.. code-block:: devicetree |
|
|
|
kbd-matrix { |
|
compatible = "gpio-kbd-matrix"; |
|
row-gpios = <&gpio0 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>, |
|
<&gpio0 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>, |
|
<&gpio0 2 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; |
|
col-gpios = <&gpio0 3 GPIO_ACTIVE_LOW>, |
|
<&gpio0 4 GPIO_ACTIVE_LOW>, |
|
<&gpio0 5 GPIO_ACTIVE_LOW>; |
|
}; |
|
|
|
In this configuration the matrix scanning library enters idle mode once all |
|
keys are released, and the keyboard matrix thread only wakes up when a key has |
|
been pressed. |
|
|
|
GPIOs for columns that are not currently selected are configured in high |
|
impedance mode. This means that the row state may need some time to settle to |
|
avoid misreading the key state from a column to the following one. The settle |
|
time can be tweaked by changing the ``settle-time-us`` property. |
|
|
|
Isolation diodes |
|
**************** |
|
|
|
If the matrix has isolation diodes for every key, then it's possible to: |
|
|
|
- disable ghosting detection, allowing any key combination to be detected |
|
- configuring the driver to drive unselected columns GPIO to inactive state |
|
rather than high impedance, this allows to reduce the settle time |
|
(potentially down to 0), and use the more efficient port wide GPIO read APIs |
|
(happens automatically if the GPIO pins are sequential) |
|
|
|
Matrixes with diodes going from rows to columns must use pull-ups on rows and |
|
active low columns. |
|
|
|
.. figure:: diodes-rc.svg |
|
:align: center |
|
:width: 50% |
|
|
|
A 3x3 matrix with row to column isolation diodes. |
|
|
|
.. code-block:: devicetree |
|
|
|
kbd-matrix { |
|
compatible = "gpio-kbd-matrix"; |
|
row-gpios = <&gpio0 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>, |
|
<&gpio0 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>, |
|
<&gpio0 2 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; |
|
col-gpios = <&gpio0 3 GPIO_ACTIVE_LOW>, |
|
<&gpio0 4 GPIO_ACTIVE_LOW>, |
|
<&gpio0 5 GPIO_ACTIVE_LOW>; |
|
col-drive-inactive; |
|
settle-time-us = <0>; |
|
no-ghostkey-check; |
|
}; |
|
|
|
Matrixes with diodes going from columns to rows must use pull-downs on rows and |
|
active high columns. |
|
|
|
.. figure:: diodes-cr.svg |
|
:align: center |
|
:width: 50% |
|
|
|
A 3x3 matrix with column to row isolation diodes. |
|
|
|
.. code-block:: devicetree |
|
|
|
kbd-matrix { |
|
compatible = "gpio-kbd-matrix"; |
|
row-gpios = <&gpio0 0 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>, |
|
<&gpio0 1 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>, |
|
<&gpio0 2 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>; |
|
col-gpios = <&gpio0 3 GPIO_ACTIVE_HIGH>, |
|
<&gpio0 4 GPIO_ACTIVE_HIGH>, |
|
<&gpio0 5 GPIO_ACTIVE_HIGH>; |
|
col-drive-inactive; |
|
settle-time-us = <0>; |
|
no-ghostkey-check; |
|
}; |
|
|
|
GPIO with no interrupt support |
|
****************************** |
|
|
|
Some GPIO controllers have limitations on GPIO interrupts, and may not support |
|
enabling interrupts on all row GPIOs at the same time. |
|
|
|
In this case, the driver can be configured to not use interrupt at all, and |
|
instead idle by selecting all columns and keep polling on the row GPIOs, which |
|
is a single GPIO API operation if the pins are sequential. |
|
|
|
This configuration can be enabled by setting the ``idle-mode`` property to |
|
``poll``: |
|
|
|
.. code-block:: devicetree |
|
|
|
kbd-matrix { |
|
compatible = "gpio-kbd-matrix"; |
|
... |
|
idle-mode = "poll"; |
|
}; |
|
|
|
GPIO multiplexer |
|
**************** |
|
|
|
In more extreme cases, such as if the columns are using a multiplexer and it's |
|
impossible to select all of them at the same time, the driver can be configured |
|
to scan continuously. |
|
|
|
This can be done by setting ``idle-mode`` to ``scan`` and ``poll-timeout-ms`` |
|
to ``0``. |
|
|
|
.. code-block:: devicetree |
|
|
|
kbd-matrix { |
|
compatible = "gpio-kbd-matrix"; |
|
... |
|
poll-timeout-ms = <0>; |
|
idle-mode = "scan"; |
|
}; |
|
|
|
Row and column GPIO selection |
|
***************************** |
|
|
|
If the row GPIOs are sequential and on the same gpio controller, the driver |
|
automatically switches API to read from the whole GPIO port rather than the |
|
individual pins. This is particularly useful if the GPIOs are not memory |
|
mapped, for example on an I2C or SPI port expander, as this significantly |
|
reduces the number of transactions on the corresponding bus. |
|
|
|
The same is true for column GPIOs, but only if the matrix is configured for |
|
``col-drive-inactive``, so that is only usable for matrixes with isolation |
|
diodes. |
|
|
|
16-bit row support |
|
****************** |
|
|
|
The driver uses an 8-bit datatype to store the row state by default, which |
|
limits the matrix row size to 8. This can be increased to 16 by enabling the |
|
:kconfig:option:`CONFIG_INPUT_KBD_MATRIX_16_BIT_ROW` option. |
|
|
|
Actual key mask configuration |
|
***************************** |
|
|
|
If the key matrix is not complete, a map of the keys that are actually |
|
populated can be specified using the ``actual-key-mask`` property. This allows |
|
the matrix state to be filtered to remove keys that are not present before |
|
ghosting detection, potentially allowing key combinations that would otherwise |
|
be blocked by it. |
|
|
|
For example for a 3x3 matrix missing a key: |
|
|
|
.. figure:: no-sw4.svg |
|
:align: center |
|
:width: 50% |
|
|
|
A 3x3 matrix missing a key. |
|
|
|
.. code-block:: devicetree |
|
|
|
kbd-matrix { |
|
compatible = "gpio-kbd-matrix"; |
|
... |
|
actual-key-mask = <0x07 0x05 0x07>; |
|
}; |
|
|
|
This would allow, for example, to detect pressing ``Sw1``, ``SW2`` and ``SW4`` |
|
at the same time without triggering anti ghosting. |
|
|
|
The actual key mask can be changed at runtime by enabling |
|
:kconfig:option:`CONFIG_INPUT_KBD_ACTUAL_KEY_MASK_DYNAMIC` and the using the |
|
:c:func:`input_kbd_matrix_actual_key_mask_set` API. |
|
|
|
Keymap configuration |
|
******************** |
|
|
|
Keyboard matrix devices report a series of x/y/touch events. These can be |
|
mapped to normal key events using the :dtcompatible:`input-keymap` driver. |
|
|
|
For example, the following would setup a ``keymap`` device that take the |
|
x/y/touch events as an input and generate corresponding key events as an |
|
output: |
|
|
|
.. code-block:: devicetree |
|
|
|
kbd { |
|
... |
|
keymap { |
|
compatible = "input-keymap"; |
|
keymap = < |
|
MATRIX_KEY(0, 0, INPUT_KEY_1) |
|
MATRIX_KEY(0, 1, INPUT_KEY_2) |
|
MATRIX_KEY(0, 2, INPUT_KEY_3) |
|
MATRIX_KEY(1, 0, INPUT_KEY_4) |
|
MATRIX_KEY(1, 1, INPUT_KEY_5) |
|
MATRIX_KEY(1, 2, INPUT_KEY_6) |
|
MATRIX_KEY(2, 0, INPUT_KEY_7) |
|
MATRIX_KEY(2, 1, INPUT_KEY_8) |
|
MATRIX_KEY(2, 2, INPUT_KEY_9) |
|
>; |
|
row-size = <3>; |
|
col-size = <3>; |
|
}; |
|
}; |
|
|
|
Keyboard matrix shell commands |
|
****************************** |
|
|
|
The shell command ``kbd_matrix_state_dump`` can be used to test the |
|
functionality of any keyboard matrix driver implemented using the keyboard |
|
matrix library. Once enabled it logs the state of the matrix every time it |
|
changes, and once disabled it prints an or-mask of any key that has been |
|
detected, which can be used to set the ``actual-key-mask`` property. |
|
|
|
The command can be enabled using the |
|
:kconfig:option:`CONFIG_INPUT_SHELL_KBD_MATRIX_STATE`. |
|
|
|
Example usage: |
|
|
|
.. code-block:: console |
|
|
|
uart:~$ device list |
|
devices: |
|
- kbd-matrix (READY) |
|
uart:~$ input kbd_matrix_state_dump kbd-matrix |
|
Keyboard state logging enabled for kbd-matrix |
|
[00:01:41.678,466] <inf> input: kbd-matrix state [01 -- -- --] (1) |
|
[00:01:41.784,912] <inf> input: kbd-matrix state [-- -- -- --] (0) |
|
... |
|
press more buttons |
|
... |
|
uart:~$ input kbd_matrix_state_dump off |
|
Keyboard state logging disabled |
|
[00:01:47.967,651] <inf> input: kbd-matrix key-mask [07 05 07 --] (8) |
|
|
|
Keyboard matrix library |
|
*********************** |
|
|
|
The GPIO keyboard matrix driver is based on a generic keyboard matrix library, |
|
which implements the core functionalities such as scanning delays, debouncing, |
|
idle mode etc. This can be reused to implement other keyboard matrix drivers, |
|
potentially application specific. |
|
|
|
.. doxygengroup:: input_kbd_matrix
|
|
|