| .. SPDX-License-Identifier: GPL-2.0-only | |
| Virtual GPIO Consumer | |
| ===================== | |
| The virtual GPIO Consumer module allows users to instantiate virtual devices | |
| that request GPIOs and then control their behavior over debugfs. Virtual | |
| consumer devices can be instantiated from device-tree or over configfs. | |
| A virtual consumer uses the driver-facing GPIO APIs and allows to cover it with | |
| automated tests driven by user-space. The GPIOs are requested using | |
| ``gpiod_get_array()`` and so we support multiple GPIOs per connector ID. | |
| Creating GPIO consumers | |
| ----------------------- | |
| The gpio-consumer module registers a configfs subsystem called | |
| ``'gpio-virtuser'``. For details of the configfs filesystem, please refer to | |
| the configfs documentation. | |
| The user can create a hierarchy of configfs groups and items as well as modify | |
| values of exposed attributes. Once the consumer is instantiated, this hierarchy | |
| will be translated to appropriate device properties. The general structure is: | |
| **Group:** ``/config/gpio-virtuser`` | |
| This is the top directory of the gpio-consumer configfs tree. | |
| **Group:** ``/config/gpio-consumer/example-name`` | |
| **Attribute:** ``/config/gpio-consumer/example-name/live`` | |
| **Attribute:** ``/config/gpio-consumer/example-name/dev_name`` | |
| This is a directory representing a GPIO consumer device. | |
| The read-only ``dev_name`` attribute exposes the name of the device as it will | |
| appear in the system on the platform bus. This is useful for locating the | |
| associated debugfs directory under | |
| ``/sys/kernel/debug/gpio-virtuser/$dev_name``. | |
| The ``'live'`` attribute allows to trigger the actual creation of the device | |
| once it's fully configured. The accepted values are: ``'1'`` to enable the | |
| virtual device and ``'0'`` to disable and tear it down. | |
| Creating GPIO lookup tables | |
| --------------------------- | |
| Users can create a number of configfs groups under the device group: | |
| **Group:** ``/config/gpio-consumer/example-name/con_id`` | |
| The ``'con_id'`` directory represents a single GPIO lookup and its value maps | |
| to the ``'con_id'`` argument of the ``gpiod_get()`` function. For example: | |
| ``con_id`` == ``'reset'`` maps to the ``reset-gpios`` device property. | |
| Users can assign a number of GPIOs to each lookup. Each GPIO is a sub-directory | |
| with a user-defined name under the ``'con_id'`` group. | |
| **Attribute:** ``/config/gpio-consumer/example-name/con_id/0/key`` | |
| **Attribute:** ``/config/gpio-consumer/example-name/con_id/0/offset`` | |
| **Attribute:** ``/config/gpio-consumer/example-name/con_id/0/drive`` | |
| **Attribute:** ``/config/gpio-consumer/example-name/con_id/0/pull`` | |
| **Attribute:** ``/config/gpio-consumer/example-name/con_id/0/active_low`` | |
| **Attribute:** ``/config/gpio-consumer/example-name/con_id/0/transitory`` | |
| This is a group describing a single GPIO in the ``con_id-gpios`` property. | |
| For virtual consumers created using configfs we use machine lookup tables so | |
| this group can be considered as a mapping between the filesystem and the fields | |
| of a single entry in ``'struct gpiod_lookup'``. | |
| The ``'key'`` attribute represents either the name of the chip this GPIO | |
| belongs to or the GPIO line name. This depends on the value of the ``'offset'`` | |
| attribute: if its value is >= 0, then ``'key'`` represents the label of the | |
| chip to lookup while ``'offset'`` represents the offset of the line in that | |
| chip. If ``'offset'`` is < 0, then ``'key'`` represents the name of the line. | |
| The remaining attributes map to the ``'flags'`` field of the GPIO lookup | |
| struct. The first two take string values as arguments: | |
| **``'drive'``:** ``'push-pull'``, ``'open-drain'``, ``'open-source'`` | |
| **``'pull'``:** ``'pull-up'``, ``'pull-down'``, ``'pull-disabled'``, ``'as-is'`` | |
| ``'active_low'`` and ``'transitory'`` are boolean attributes. | |
| Activating GPIO consumers | |
| ------------------------- | |
| Once the configuration is complete, the ``'live'`` attribute must be set to 1 in | |
| order to instantiate the consumer. It can be set back to 0 to destroy the | |
| virtual device. The module will synchronously wait for the new simulated device | |
| to be successfully probed and if this doesn't happen, writing to ``'live'`` will | |
| result in an error. | |
| Device-tree | |
| ----------- | |
| Virtual GPIO consumers can also be defined in device-tree. The compatible string | |
| must be: ``"gpio-virtuser"`` with at least one property following the | |
| standardized GPIO pattern. | |
| An example device-tree code defining a virtual GPIO consumer: | |
| .. code-block :: none | |
| gpio-virt-consumer { | |
| compatible = "gpio-virtuser"; | |
| foo-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>, <&gpio1 2 0>; | |
| bar-gpios = <&gpio0 6 0>; | |
| }; | |
| Controlling virtual GPIO consumers | |
| ---------------------------------- | |
| Once active, the device will export debugfs attributes for controlling GPIO | |
| arrays as well as each requested GPIO line separately. Let's consider the | |
| following device property: ``foo-gpios = <&gpio0 0 0>, <&gpio0 4 0>;``. | |
| The following debugfs attribute groups will be created: | |
| **Group:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo/`` | |
| This is the group that will contain the attributes for the entire GPIO array. | |
| **Attribute:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo/values`` | |
| **Attribute:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo/values_atomic`` | |
| Both attributes allow to read and set arrays of GPIO values. User must pass | |
| exactly the number of values that the array contains in the form of a string | |
| containing zeroes and ones representing inactive and active GPIO states | |
| respectively. In this example: ``echo 11 > values``. | |
| The ``values_atomic`` attribute works the same as ``values`` but the kernel | |
| will execute the GPIO driver callbacks in interrupt context. | |
| **Group:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo:$index/`` | |
| This is a group that represents a single GPIO with ``$index`` being its offset | |
| in the array. | |
| **Attribute:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo:$index/consumer`` | |
| Allows to set and read the consumer label of the GPIO line. | |
| **Attribute:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo:$index/debounce`` | |
| Allows to set and read the debounce period of the GPIO line. | |
| **Attribute:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo:$index/direction`` | |
| **Attribute:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo:$index/direction_atomic`` | |
| These two attributes allow to set the direction of the GPIO line. They accept | |
| "input" and "output" as values. The atomic variant executes the driver callback | |
| in interrupt context. | |
| **Attribute:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo:$index/interrupts`` | |
| If the line is requested in input mode, writing ``1`` to this attribute will | |
| make the module listen for edge interrupts on the GPIO. Writing ``0`` disables | |
| the monitoring. Reading this attribute returns the current number of registered | |
| interrupts (both edges). | |
| **Attribute:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo:$index/value`` | |
| **Attribute:** ``/sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo:$index/value_atomic`` | |
| Both attributes allow to read and set values of individual requested GPIO lines. | |
| They accept the following values: ``1`` and ``0``. |