1.. _pinctrl-guide:
2
3Pin Control
4###########
5
6This is a high-level guide to pin control. See :ref:`pinctrl_api` for API
7reference material.
8
9Introduction
10************
11
12The hardware blocks that control pin multiplexing and pin configuration
13parameters such as pin direction, pull-up/down resistors, etc. are named **pin
14controllers**. The pin controller's main users are SoC hardware peripherals,
15since the controller enables exposing peripheral signals, like for example,
16map ``I2C0`` ``SDA`` signal to pin ``PX0``. Not only that, but it usually allows
17configuring certain pin settings that are necessary for the correct functioning
18of a peripheral, for example, the slew-rate depending on the operating
19frequency. The available configuration options are vendor/SoC dependent and can
20range from simple pull-up/down options to more advanced settings such as
21debouncing, low-power modes, etc.
22
23The way pin control is implemented in hardware is vendor/SoC specific. It is
24common to find a *centralized* approach, that is, all pin configuration
25parameters are controlled by a single hardware block (typically named pinmux),
26including signal mapping. The figure below illustrates this
27approach. ``PX0`` can be mapped to ``UART0_TX``, ``I2C0_SCK`` or ``SPI0_MOSI``
28depending on the ``AF`` control bits. Other configuration parameters such as
29pull-up/down are controlled in the same block via ``CONFIG`` bits. This model is
30used by several SoC families, such as many from NXP and STM32.
31
32.. figure:: images/hw-cent-control.svg
33
34    Example of pin control centralized into a single per-pin block
35
36Other vendors/SoCs use a *distributed* approach. In such case, the pin mapping
37and configuration are controlled by multiple hardware blocks.
38The figure below illustrates a distributed approach where pin
39mapping is controlled by peripherals, such as in Nordic nRF SoCs.
40
41.. figure:: images/hw-dist-control.svg
42
43    Example pin control distributed between peripheral registers and per-pin block
44
45From a user perspective, there is no difference in pin controller usage
46regardless of the hardware implementation: a user will always apply a state.
47The only difference lies in the driver implementation. In general, implementing
48a pin controller driver for a hardware that uses a distributed approach requires
49more effort, since the driver needs to gather knowledge of peripheral dependent
50registers.
51
52Pin control vs. GPIO
53====================
54
55Some functionality covered by a pin controller driver overlaps with GPIO
56drivers. For example, pull-up/down resistors can usually be enabled by both the
57pin control driver and the GPIO driver. In Zephyr context, the pin control
58driver purpose is to perform peripheral signal multiplexing and configuration of
59other pin parameters required for the correct operation of that peripheral.
60Therefore, the main users of the pin control driver are SoC peripherals. In
61contrast, GPIO drivers are for general purpose control of a pin, that is, when
62its logic level is read or controlled manually.
63
64State model
65***********
66
67For a device driver to operate correctly, a certain pin configuration needs to
68be applied. Some device drivers require a static configuration, usually set up
69at initialization time. Others need to change the configuration at runtime
70depending on the operating conditions, for example, to enable a low-power mode
71when suspending the device. Such requirements are modeled using **states**, a
72concept that has been adapted from the one in the Linux kernel. Each device
73driver owns a set of states. Each state has a unique name and contains a full
74pin configuration set (see the figure below). This effectively
75means that states are independent of each other, so they do not need to be
76applied in any specific order. Another advantage of the state model is that it
77isolates device drivers from pin configuration.
78
79.. table:: Example pin configuration encoded using the states model
80    :align: center
81
82    +----+------------------+----+------------------+
83    | ``UART0`` peripheral                          |
84    +====+==================+====+==================+
85    | ``default`` state     | ``sleep`` state       |
86    +----+------------------+----+------------------+
87    | TX | - Pin: PA0       | TX | - Pin: PA0       |
88    |    | - Pull: NONE     |    | - Pull: NONE     |
89    |    | - Low Power: NO  |    | - Low Power: YES |
90    +----+------------------+----+------------------+
91    | RX | - Pin: PA1       | RX | - Pin: PA1       |
92    |    | - Pull: UP       |    | - Pull: NONE     |
93    |    | - Low Power: NO  |    | - Low Power: YES |
94    +----+------------------+----+------------------+
95
96Standard states
97===============
98
99The name assigned to pin control states or the number of them is up to the
100device driver requirements. In many cases a single state applied at
101initialization time will be sufficient, but in some other cases more will be
102required. In order to make things consistent, a naming convention has been
103established for the most common use cases. The figure below
104details the standardized states and its purpose.
105
106.. table:: Standardized state names
107    :align: center
108
109    +-------------+----------------------------------+-------------------------+
110    | State       | Identifier                       | Purpose                 |
111    +-------------+----------------------------------+-------------------------+
112    | ``default`` | :c:macro:`PINCTRL_STATE_DEFAULT` | State of the pins when  |
113    |             |                                  | the device is in        |
114    |             |                                  | operational state       |
115    +-------------+----------------------------------+-------------------------+
116    | ``sleep``   | :c:macro:`PINCTRL_STATE_SLEEP`   | State of the pins when  |
117    |             |                                  | the device is in low    |
118    |             |                                  | power or sleep modes    |
119    +-------------+----------------------------------+-------------------------+
120
121Note that other standard states could be introduced in the future.
122
123Custom states
124=============
125
126Some device drivers may require using custom states beyond the standard ones. To
127achieve that, the device driver needs to have in its scope definitions for the
128custom state identifiers named as ``PINCTRL_STATE_{STATE_NAME}``, where
129``{STATE_NAME}`` is the capitalized state name. For example, if ``mystate`` has
130to be supported, a definition named ``PINCTRL_STATE_MYSTATE`` needs to be
131in the driver's scope.
132
133.. note::
134    It is important that custom state identifiers start from
135    :c:macro:`PINCTRL_STATE_PRIV_START`
136
137If custom states need to be accessed from outside the driver, for example to
138perform dynamic pin control, custom identifiers should be placed in a header
139that is publicly accessible.
140
141Skipping states
142===============
143
144In most situations, the states defined in Devicetree will be the ones used in
145the compiled firmware. However, there are some cases where certain states will
146be conditionally used depending on a compilation flag. A typical case is the
147``sleep`` state. This state is only used in practice if
148:kconfig:option:`CONFIG_PM` or :kconfig:option:`CONFIG_PM_DEVICE` is enabled.
149If a firmware variant without these power management configurations is needed,
150one should in theory remove the ``sleep`` state from Devicetree to not waste ROM
151space storing such unused state.
152
153States can be skipped by the ``pinctrl`` Devicetree macros if a definition named
154``PINCTRL_SKIP_{STATE_NAME}`` expanding to ``1`` is present when pin control
155configuration is defined. In case of the ``sleep`` state, the ``pinctrl`` API
156already provides such definition conditional to the availability of device power
157management:
158
159.. code-block:: c
160
161    #if !defined(CONFIG_PM) && !defined(CONFIG_PM_DEVICE)
162    /** Out of power management configurations, ignore "sleep" state. */
163    #define PINCTRL_SKIP_SLEEP 1
164    #endif
165
166Dynamic pin control
167*******************
168
169Dynamic pin control refers to the capability of changing pin configuration
170at runtime. This feature can be useful in situations where the same firmware
171needs to run onto slightly different boards, each having a peripheral routed at
172a different set of pins. This feature can be enabled by setting
173:kconfig:option:`CONFIG_PINCTRL_DYNAMIC`.
174
175.. note::
176
177    Dynamic pin control should only be used on devices that have not been
178    initialized. Changing pin configurations while a device is operating may
179    lead to unexpected behavior. Since Zephyr does not support device
180    de-initialization yet, this functionality should only be used during early
181    boot stages.
182
183One of the effects of enabling dynamic pin control is that
184:c:struct:`pinctrl_dev_config` will be stored in RAM instead of ROM (not states
185or pin configurations, though). The user can then use
186:c:func:`pinctrl_update_states` to update the states stored in
187:c:struct:`pinctrl_dev_config` with a new set. This effectively means that the
188device driver will apply the pin configurations stored in the updated states
189when it applies a state.
190
191Devicetree representation
192*************************
193
194Because Devicetree is meant to describe hardware, it is the natural choice when
195it comes to storing pin control configuration. In the following sections you
196will find an overview on how states and pin configurations are represented in
197Devicetree.
198
199States
200======
201
202Given a device, each of its pin control state is represented in Devicetree by
203``pinctrl-N`` properties, being ``N`` the state index starting from zero. The
204``pinctrl-names`` property is then used to assign a unique identifier for each
205state property by index, for example, ``pinctrl-names`` list entry 0 is the name
206for ``pinctrl-0``.
207
208.. code-block:: devicetree
209
210    periph0: periph@0 {
211        ...
212        /* state 0 ("default") */
213        pinctrl-0 = <...>;
214        ...
215        /* state N ("mystate") */
216        pinctrl-N = <...>;
217        /* names for state 0 up to state N */
218        pinctrl-names = "default", ..., "mystate";
219        ...
220    };
221
222Pin configuration
223=================
224
225There are multiple ways to represent the pin configurations in Devicetree.
226However, all end up encoding the same information: the pin multiplexing and the
227pin configuration parameters. For example, ``UART_RX`` is mapped to ``PX0`` and
228pull-up is enabled. The representation choice largely depends on each
229vendor/SoC, so the Devicetree binding files for the pin control drivers are the
230best place to look for details.
231
232A popular and versatile option is shown in the example below. One of the
233advantages of this choice is the grouping capability based on shared pin
234configuration. This allows to reduce the verbosity of the pin control
235definitions. Another advantage is that the pin configuration parameters for a
236particular state are enclosed in a single Devicetree node.
237
238.. code-block:: devicetree
239
240    /* board.dts */
241    #include "board-pinctrl.dtsi"
242
243    &periph0 {
244        pinctrl-0 = <&periph0_default>;
245        pinctrl-names = "default";
246    };
247
248.. code-block:: c
249
250    /* vnd-soc-pkgxx.h
251     * File with valid mappings for a specific package (may be autogenerated).
252     * This file is optional, but recommended.
253     */
254    ...
255    #define PERIPH0_SIGA_PX0 VNDSOC_PIN(X, 0, MUX0)
256    #define PERIPH0_SIGB_PY7 VNDSOC_PIN(Y, 7, MUX4)
257    #define PERIPH0_SIGC_PZ1 VNDSOC_PIN(Z, 1, MUX2)
258    ...
259
260.. code-block:: devicetree
261
262    /* board-pinctrl.dtsi */
263    #include <vnd-soc-pkgxx.h>
264
265    &pinctrl {
266        /* Node with pin configuration for default state */
267        periph0_default: periph0_default {
268            group1 {
269                /* Mappings: PERIPH0_SIGA -> PX0, PERIPH0_SIGC -> PZ1 */
270                pinmux = <PERIPH0_SIGA_PX0>, <PERIPH0_SIGC_PZ1>;
271                /* Pins PX0 and PZ1 have pull-up enabled */
272                bias-pull-up;
273            };
274            ...
275            groupN {
276                /* Mappings: PERIPH0_SIGB -> PY7 */
277                pinmux = <PERIPH0_SIGB_PY7>;
278            };
279        };
280    };
281
282Another popular model is based on having a node for each pin configuration and
283state. While this model may lead to shorter board pin control files, it also
284requires to have one node for each pin mapping and state, since in general,
285nodes can not be re-used for multiple states. This method is discouraged if
286autogeneration is not an option.
287
288.. note::
289
290   Because all Devicetree information is parsed into a C header, it is important
291   to make sure its size is kept to a minimum. For this reason it is important
292   to prefix pre-generated nodes with ``/omit-if-no-ref/``. This prefix makes
293   sure that the node is discarded when not used.
294
295.. code-block:: devicetree
296
297    /* board.dts */
298    #include "board-pinctrl.dtsi"
299
300    &periph0 {
301        pinctrl-0 = <&periph0_siga_px0_default &periph0_sigb_py7_default
302                     &periph0_sigc_pz1_default>;
303        pinctrl-names = "default";
304    };
305
306.. code-block:: devicetree
307
308    /* vnd-soc-pkgxx.dtsi
309     * File with valid nodes for a specific package (may be autogenerated).
310     * This file is optional, but recommended.
311     */
312
313    &pinctrl {
314        /* Mapping for PERIPH0_SIGA -> PX0, to be used for default state */
315        /omit-if-no-ref/ periph0_siga_px0_default: periph0_siga_px0_default {
316            pinmux = <VNDSOC_PIN(X, 0, MUX0)>;
317        };
318
319        /* Mapping for PERIPH0_SIGB -> PY7, to be used for default state */
320        /omit-if-no-ref/ periph0_sigb_py7_default: periph0_sigb_py7_default {
321            pinmux = <VNDSOC_PIN(Y, 7, MUX4)>;
322        };
323
324        /* Mapping for PERIPH0_SIGC -> PZ1, to be used for default state */
325        /omit-if-no-ref/ periph0_sigc_pz1_default: periph0_sigc_pz1_default {
326            pinmux = <VNDSOC_PIN(Z, 1, MUX2)>;
327        };
328    };
329
330.. code-block:: devicetree
331
332    /* board-pinctrl.dts */
333    #include <vnd-soc-pkgxx.dtsi>
334
335    /* Enable pull-up for PX0 (default state) */
336    &periph0_siga_px0_default {
337        bias-pull-up;
338    };
339
340    /* Enable pull-up for PZ1 (default state) */
341    &periph0_sigc_pz1_default {
342        bias-pull-up;
343    };
344
345.. note::
346
347    It is discouraged to add pin configuration defaults in pre-defined nodes.
348    In general, pin configurations depend on the board design or on the
349    peripheral working conditions, so the decision should be made by the board.
350    For example, enabling a pull-up by default may not always be desired because
351    the board already has one or because its value depends on the operating bus
352    speed. Another downside of defaults is that user may not be aware of them,
353    for example:
354
355    .. code-block:: devicetree
356
357        /* not evident that "periph0_siga_px0_default" also implies "bias-pull-up" */
358        /omit-if-no-ref/ periph0_siga_px0_default: periph0_siga_px0_default {
359            pinmux = <VNDSOC_PIN(X, 0, MUX0)>;
360            bias-pull-up;
361        };
362
363Implementation guidelines
364*************************
365
366Pin control drivers
367===================
368
369Pin control drivers need to implement a single function:
370:c:func:`pinctrl_configure_pins`. This function receives an array of pin
371configurations that need to be applied. Furthermore, if
372:kconfig:option:`CONFIG_PINCTRL_STORE_REG` is set, it also receives the associated
373device register address for the given pins. This information may be required by
374some drivers to perform device specific actions.
375
376The pin configuration is stored in an opaque type that is vendor/SoC dependent:
377``pinctrl_soc_pin_t``. This type needs to be defined in a header named
378``pinctrl_soc.h`` file that is in the Zephyr's include path. It can range from
379a simple integer value to a struct with multiple fields. ``pinctrl_soc.h`` also
380needs to define a macro named ``Z_PINCTRL_STATE_PINS_INIT`` that accepts two
381arguments: a node identifier and a property name (``pinctrl-N``). With this
382information the macro needs to define an initializer for all pin configurations
383contained within the ``pinctrl-N`` property of the given node.
384
385Regarding Devicetree pin configuration representation, vendors can decide which
386option is better for their devices. However, the following guidelines should be
387followed:
388
389- Use ``pinctrl-N`` (N=0, 1, ...) and ``pinctrl-names`` properties to define pin
390  control states. These properties are defined in
391  :file:`dts/bindings/pinctrl/pinctrl-device.yaml`.
392- Use standard pin configuration properties as defined in
393  :file:`dts/bindings/pinctrl/pincfg-node.yaml`.
394
395Representations not following these guidelines may be accepted if they are
396already used by the same vendor in other operating systems, e.g. Linux.
397
398Device drivers
399==============
400
401In this section you will find some tips on how a device driver should use the
402``pinctrl`` API to successfully configure the pins it needs.
403
404The device compatible needs to be modified in the corresponding binding so that
405the ``pinctrl-device.yaml`` is included. For example:
406
407.. code-block:: yaml
408
409    include: [base.yaml, pinctrl-device.yaml]
410
411This file is needed to add ``pinctrl-N`` and ``pinctrl-names`` properties to the
412device.
413
414From a device driver perspective there are two steps that need to be performed
415to be able to use the ``pinctrl`` API. First, the pin control configuration
416needs to be defined. This includes all states and pins.
417:c:macro:`PINCTRL_DT_DEFINE` or :c:macro:`PINCTRL_DT_INST_DEFINE` macros
418should be used for this purpose. Second, a reference to
419the device instance :c:struct:`pinctrl_dev_config` needs to be stored, since it
420is required to later use the API. This can be achieved using the
421:c:macro:`PINCTRL_DT_DEV_CONFIG_GET` and
422:c:macro:`PINCTRL_DT_INST_DEV_CONFIG_GET` macros.
423
424It is worth to note that the only relationship between a device and its
425associated pin control configuration is based on variable naming conventions.
426The way an instance of :c:struct:`pinctrl_dev_config` is named for a
427corresponding device instance allows to later obtain a reference to it given the
428device's Devicetree node identifier. This allows to minimize ROM usage, since
429only devices requiring pin control will own a reference to a pin control
430configuration.
431
432Once the driver has defined the pin control configuration and kept a reference
433to it, it is ready to use the API. The most common way to apply a state is by
434using :c:func:`pinctrl_apply_state`. It is also possible to use the lower level
435function :c:func:`pinctrl_apply_state_direct` to skip state lookup if it is
436cached in advance (e.g. at init time). Since state lookup time is expected to be
437fast, it is recommended to use :c:func:`pinctrl_apply_state`.
438
439The example below contains a complete example of a device driver that uses the
440``pinctrl`` API.
441
442.. code-block:: c
443
444    /* A driver for the "mydev" compatible device */
445    #define DT_DRV_COMPAT mydev
446
447    ...
448    #include <zephyr/drivers/pinctrl.h>
449    ...
450
451    struct mydev_config {
452        ...
453        /* Reference to mydev pinctrl configuration */
454        const struct pinctrl_dev_config *pcfg;
455        ...
456    };
457
458    ...
459
460    static int mydev_init(const struct device *dev)
461    {
462        const struct mydev_config *config = dev->config;
463        int ret;
464        ...
465        /* Select "default" state at initialization time */
466        ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
467        if (ret < 0) {
468            return ret;
469        }
470        ...
471    }
472
473    #define MYDEV_DEFINE(i)                                                    \
474        /* Define all pinctrl configuration for instance "i" */                \
475        PINCTRL_DT_INST_DEFINE(i);                                             \
476        ...                                                                    \
477        static const struct mydev_config mydev_config_##i = {                  \
478            ...                                                                \
479            /* Keep a ref. to the pinctrl configuration for instance "i" */    \
480            .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(i),                         \
481            ...                                                                \
482        };                                                                     \
483        ...                                                                    \
484                                                                               \
485        DEVICE_DT_INST_DEFINE(i, mydev_init, NULL, &mydev_data##i,             \
486                              &mydev_config##i, ...);
487
488    DT_INST_FOREACH_STATUS_OKAY(MYDEV_DEFINE)
489
490.. _pinctrl_api:
491
492Pin Control API
493****************
494
495.. doxygengroup:: pinctrl_interface
496
497Dynamic pin control
498====================
499
500.. doxygengroup:: pinctrl_interface_dynamic
501
502
503Other reference material
504************************
505
506- `Introduction to pin muxing and GPIO control under Linux <https://elinux.org/images/a/a7/ELC-2021_Introduction_to_pin_muxing_and_GPIO_control_under_Linux.pdf>`_
507