diff --git a/CODEOWNERS b/CODEOWNERS
index 4fd2ded37cdd9..3f67468ac864c 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -290,6 +290,7 @@
/drivers/modem/Kconfig.hl7800 @LairdCP/zephyr
/drivers/pcie/ @dcpleung @nashif @jhedberg
/drivers/peci/ @albertofloyd @franciscomunoz @scottwcpg
+/drivers/pinctrl/ @gmarull
/drivers/pinmux/*b91* @yurvyn
/drivers/pinmux/*hsdk* @iriszzw
/drivers/pinmux/*it8xxx2* @ite
diff --git a/doc/conf.py b/doc/conf.py
index 9110effe5034f..867d6466e9d0f 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -108,6 +108,8 @@
todo_include_todos = False
+numfig = True
+
rst_epilog = """
.. include:: /substitutions.txt
"""
diff --git a/doc/guides/index.rst b/doc/guides/index.rst
index 333110c67664e..e101f850981ae 100644
--- a/doc/guides/index.rst
+++ b/doc/guides/index.rst
@@ -17,6 +17,7 @@ User and Developer Guides
debug_tools/index
device_mgmt/index
dts/index
+ pinctrl/index
emulator/index.rst
modules.rst
diff --git a/doc/guides/pinctrl/images/hw-cent-control.odg b/doc/guides/pinctrl/images/hw-cent-control.odg
new file mode 100644
index 0000000000000..fd979500665c4
Binary files /dev/null and b/doc/guides/pinctrl/images/hw-cent-control.odg differ
diff --git a/doc/guides/pinctrl/images/hw-cent-control.svg b/doc/guides/pinctrl/images/hw-cent-control.svg
new file mode 100644
index 0000000000000..571e90f134192
--- /dev/null
+++ b/doc/guides/pinctrl/images/hw-cent-control.svg
@@ -0,0 +1,905 @@
+
+
+
\ No newline at end of file
diff --git a/doc/guides/pinctrl/images/hw-dist-control.odg b/doc/guides/pinctrl/images/hw-dist-control.odg
new file mode 100644
index 0000000000000..25b6c7ae0f122
Binary files /dev/null and b/doc/guides/pinctrl/images/hw-dist-control.odg differ
diff --git a/doc/guides/pinctrl/images/hw-dist-control.svg b/doc/guides/pinctrl/images/hw-dist-control.svg
new file mode 100644
index 0000000000000..0030d75fc9933
--- /dev/null
+++ b/doc/guides/pinctrl/images/hw-dist-control.svg
@@ -0,0 +1,1198 @@
+
+
+
\ No newline at end of file
diff --git a/doc/guides/pinctrl/index.rst b/doc/guides/pinctrl/index.rst
new file mode 100644
index 0000000000000..40e80235a65b0
--- /dev/null
+++ b/doc/guides/pinctrl/index.rst
@@ -0,0 +1,492 @@
+.. _pinctrl-guide:
+
+Pin Control
+###########
+
+This is a high-level guide to pin control. See :ref:`pinctrl_api` for API
+reference material.
+
+Introduction
+************
+
+The hardware blocks that control pin multiplexing and pin configuration
+parameters such as pin direction, pull-up/down resistors, etc. are named **pin
+controllers**. The pin controller's main users are SoC hardware peripherals,
+since the controller enables exposing peripheral signals, like for example,
+map ``I2C0`` ``SDA`` signal to pin ``PX0``. Not only that, but it usually allows
+configuring certain pin settings that are necessary for the correct functioning
+of a peripheral, for example, the slew-rate depending on the operating
+frequency. The available configuration options are vendor/SoC dependent and can
+range from simple pull-up/down options to more advanced settings such as
+debouncing, low-power modes, etc.
+
+The way pin control is implemented in hardware is vendor/SoC specific. It is
+common to find a *centralized* approach, that is, all pin configuration
+parameters are controlled by a single hardware block (typically named pinmux),
+including signal mapping. :numref:`pinctrl-hw-cent-control` illustrates this
+approach. ``PX0`` can be mapped to ``UART0_TX``, ``I2C0_SCK`` or ``SPI0_MOSI``
+depending on the ``AF`` control bits. Other configuration parameters such as
+pull-up/down are controlled in the same block via ``CONFIG`` bits. This model is
+used by several SoC families, such as many from NXP and STM32.
+
+.. _pinctrl-hw-cent-control:
+
+.. figure:: images/hw-cent-control.svg
+
+ Example of pin control centralized into a single per-pin block
+
+Other vendors/SoCs use a *distributed* approach. In such case, the pin mapping
+and configuration are controlled by multiple hardware blocks.
+:numref:`pinctrl-hw-dist-control` illustrates a distributed approach where pin
+mapping is controlled by peripherals, such as in Nordic nRF SoCs.
+
+.. _pinctrl-hw-dist-control:
+
+.. figure:: images/hw-dist-control.svg
+
+ Example pin control distributed between peripheral registers and per-pin block
+
+From a user perspective, there is no difference in pin controller usage
+regardless of the hardware implementation: a user will always apply a state.
+The only difference lies in the driver implementation. In general, implementing
+a pin controller driver for a hardware that uses a distributed approach requires
+more effort, since the driver needs to gather knowledge of peripheral dependent
+registers.
+
+Pin control vs. GPIO
+====================
+
+Some functionality covered by a pin controller driver overlaps with GPIO
+drivers. For example, pull-up/down resistors can usually be enabled by both the
+pin control driver and the GPIO driver. In Zephyr context, the pin control
+driver purpose is to perform peripheral signal multiplexing and configuration of
+other pin parameters required for the correct operation of that peripheral.
+Therefore, the main users of the pin control driver are SoC peripherals. In
+contrast, GPIO drivers are for general purpose control of a pin, that is, when
+its logic level is read or controlled manually.
+
+State model
+***********
+
+For a device driver to operate correctly, a certain pin configuration needs to
+be applied. Some device drivers require a static configuration, usually set up
+at initialization time. Others need to change the configuration at runtime
+depending on the operating conditions, for example, to enable a low-power mode
+when suspending the device. Such requirements are modeled using **states**, a
+concept that has been adapted from the one in the Linux kernel. Each device
+driver owns a set of states. Each state has a unique name and contains a full
+pin configuration set (see :numref:`pinctrl-states-model`). This effectively
+means that states are independent of each other, so they do not need to be
+applied in any specific order. Another advantage of the state model is that it
+isolates device drivers from pin configuration.
+
+.. _pinctrl-states-model:
+
+.. table:: Example pin configuration encoded using the states model
+ :align: center
+
+ +----+------------------+----+------------------+
+ | ``UART0`` peripheral |
+ +====+==================+====+==================+
+ | ``default`` state | ``sleep`` state |
+ +----+------------------+----+------------------+
+ | TX | - Pin: PA0 | TX | - Pin: PA0 |
+ | | - Pull: NONE | | - Pull: NONE |
+ | | - Low Power: NO | | - Low Power: YES |
+ +----+------------------+----+------------------+
+ | RX | - Pin: PA1 | RX | - Pin: PA1 |
+ | | - Pull: UP | | - Pull: NONE |
+ | | - Low Power: NO | | - Low Power: YES |
+ +----+------------------+----+------------------+
+
+Standard states
+===============
+
+The name assigned to pin control states or the number of them is up to the
+device driver requirements. In many cases a single state applied at
+initialization time will be sufficient, but in some other cases more will be
+required. In order to make things consistent, a naming convention has been
+established for the most common use cases. :numref:`pinctrl-states-standard`
+details the standardized states and its purpose.
+
+.. _pinctrl-states-standard:
+
+.. table:: Standardized state names
+ :align: center
+
+ +-------------+----------------------------------+-------------------------+
+ | State | Identifier | Purpose |
+ +-------------+----------------------------------+-------------------------+
+ | ``default`` | :c:macro:`PINCTRL_STATE_DEFAULT` | State of the pins when |
+ | | | the device is in |
+ | | | operational state |
+ +-------------+----------------------------------+-------------------------+
+ | ``sleep`` | :c:macro:`PINCTRL_STATE_SLEEP` | State of the pins when |
+ | | | the device is in low |
+ | | | power or sleep modes |
+ +-------------+----------------------------------+-------------------------+
+
+Note that other standard states could be introduced in the future.
+
+Custom states
+=============
+
+Some device drivers may require using custom states beyond the standard ones. To
+achieve that, the device driver needs to have in its scope definitions for the
+custom state identifiers named as ``PINCTRL_STATE_{STATE_NAME}``, where
+``{STATE_NAME}`` is the capitalized state name. For example, if ``mystate`` has
+to be supported, a definition named ``PINCTRL_STATE_MYSTATE`` needs to be
+in the driver's scope.
+
+.. note::
+ It is important that custom state identifiers start from
+ :c:macro:`PINCTRL_STATE_PRIV_START`
+
+If custom states need to be accessed from outside the driver, for example to
+perform dynamic pin control, custom identifiers should be placed in a header
+that is publicly accessible.
+
+Skipping states
+===============
+
+In most situations, the states defined in Devicetree will be the ones used in
+the compiled firmware. However, there are some cases where certain states will
+be conditionally used depending on a compilation flag. A typical case is the
+``sleep`` state. This state is only used in practice if
+:kconfig:`CONFIG_PM_DEVICE` is enabled. If a firmware variant without device
+power management is needed, one should in theory remove the ``sleep`` state from
+Devicetree to not waste ROM space storing such unused state.
+
+States can be skipped by the ``pinctrl`` Devicetree macros if a definition named
+``PINCTRL_SKIP_{STATE_NAME}`` expanding to ``1`` is present when pin control
+configuration is defined. In case of the ``sleep`` state, the ``pinctrl`` API
+already provides such definition conditional to the availability of device power
+management:
+
+.. code-block:: c
+
+ #ifndef CONFIG_PM_DEVICE
+ /** If device power management is not enabled, "sleep" state will be ignored. */
+ #define PINCTRL_SKIP_SLEEP 1
+ #endif
+
+Dynamic pin control
+*******************
+
+Dynamic pin control refers to the capability of changing pin configuration
+at runtime. This feature can be useful in situations where the same firmware
+needs to run onto slightly different boards, each having a peripheral routed at
+a different set of pins. This feature can be enabled by setting
+:kconfig:`CONFIG_PINCTRL_DYNAMIC`.
+
+.. note::
+
+ Dynamic pin control should only be used on devices that have not been
+ initialized. Changing pin configurations while a device is operating may
+ lead to unexpected behavior. Since Zephyr does not support device
+ de-initialization yet, this functionality should only be used during early
+ boot stages.
+
+One of the effects of enabling dynamic pin control is that
+:c:struct:`pinctrl_dev_config` will be stored in RAM instead of ROM (not states
+or pin configurations, though). The user can then use
+:c:func:`pinctrl_update_states` to update the states stored in
+:c:struct:`pinctrl_dev_config` with a new set. This effectively means that the
+device driver will apply the pin configurations stored in the updated states
+when it applies a state.
+
+Devicetree representation
+*************************
+
+Because Devicetree is meant to describe hardware, it is the natural choice when
+it comes to storing pin control configuration. In the following sections you
+will find an overview on how states and pin configurations are represented in
+Devicetree.
+
+States
+======
+
+Given a device, each of its pin control state is represented in Devicetree by
+``pinctrl-N`` properties, being ``N`` the state index starting from zero. The
+``pinctrl-names`` property is then used to assign a unique identifier for each
+state property by index, for example, ``pinctrl-names`` list entry 0 is the name
+for ``pinctrl-0``.
+
+.. code-block:: devicetree
+
+ periph0: periph@0 {
+ ...
+ /* state 0 ("default") */
+ pinctrl-0 = <...>;
+ ...
+ /* state N ("mystate") */
+ pinctrl-N = <...>;
+ /* names for state 0 up to state N */
+ pinctrl-names = "default", ..., "mystate";
+ ...
+ };
+
+Pin configuration
+=================
+
+There are multiple ways to represent the pin configurations in Devicetree.
+However, all end up encoding the same information: the pin multiplexing and the
+pin configuration parameters. For example, ``UART_RX`` is mapped to ``PX0`` and
+pull-up is enabled. The representation choice largely depends on each
+vendor/SoC, so the Devicetree binding files for the pin control drivers are the
+best place to look for details.
+
+A popular and versatile option is shown in the example below. One of the
+advantages of this choice is the grouping capability based on shared pin
+configuration. This allows to reduce the verbosity of the pin control
+definitions. Another advantage is that the pin configuration parameters for a
+particular state are enclosed in a single Devicetree node.
+
+.. code-block:: devicetree
+
+ /* board.dts */
+ #include "board-pinctrl.dtsi"
+
+ &periph0 {
+ pinctrl-0 = <&periph0_default>;
+ pinctrl-names = "default";
+ };
+
+.. code-block:: c
+
+ /* vnd-soc-pkgxx.h
+ * File with valid mappings for a specific package (may be autogenerated).
+ * This file is optional, but recommended.
+ */
+ ...
+ #define PERIPH0_SIGA_PX0 VNDSOC_PIN(X, 0, MUX0)
+ #define PERIPH0_SIGB_PY7 VNDSOC_PIN(Y, 7, MUX4)
+ #define PERIPH0_SIGC_PZ1 VNDSOC_PIN(Z, 1, MUX2)
+ ...
+
+.. code-block:: devicetree
+
+ /* board-pinctrl.dtsi */
+ #include
+
+ &pinctrl {
+ /* Node with pin configuration for default state */
+ periph0_default: periph0_default {
+ pins1 {
+ /* Mappings: PERIPH0_SIGA -> PX0, PERIPH0_SIGC -> PZ1 */
+ pinmux = , ;
+ /* Pins PX0 and PZ1 have pull-up enabled */
+ bias-pull-up;
+ };
+ ...
+ pinsN {
+ /* Mappings: PERIPH0_SIGB -> PY7 */
+ pinmux = ;
+ };
+ };
+ };
+
+Another popular model is based on having a node for each pin configuration and
+state. While this model may lead to shorter board pin control files, it also
+requires to have one node for each pin mapping and state, since in general,
+nodes can not be re-used for multiple states. This method is discouraged if
+autogeneration is not an option.
+
+.. code-block:: devicetree
+
+ /* board.dts */
+ #include "board-pinctrl.dtsi"
+
+ &periph0 {
+ pinctrl-0 = <&periph0_siga_px0_default &periph0_sigb_py7_default
+ &periph0_sigc_pz1_default>;
+ pinctrl-names = "default";
+ };
+
+.. code-block:: devicetree
+
+ /* vnd-soc-pkgxx.dtsi
+ * File with valid nodes for a specific package (may be autogenerated).
+ * This file is optional, but recommended.
+ */
+
+ /* Mapping for PERIPH0_SIGA -> PX0, to be used for default state */
+ periph0_siga_px0_default: periph0_siga_px0_default {
+ pinmux = ;
+ };
+
+ /* Mapping for PERIPH0_SIGB -> PY7, to be used for default state */
+ periph0_sigb_py7_default: periph0_sigb_py7_default {
+ pinmux = ;
+ };
+
+ /* Mapping for PERIPH0_SIGC -> PZ1, to be used for default state */
+ periph0_sigc_pz1_default: periph0_sigc_pz1_default {
+ pinmux = ;
+ };
+
+.. code-block:: devicetree
+
+ /* board-pinctrl.dts */
+ #include
+
+ /* Enable pull-up for PX0 (default state) */
+ &periph0_siga_px0_default {
+ bias-pull-up;
+ };
+
+ /* Enable pull-up for PZ1 (default state) */
+ &periph0_sigc_pz1_default {
+ bias-pull-up;
+ };
+
+.. note::
+
+ It is discouraged to add pin configuration defaults in pre-defined nodes.
+ In general, pin configurations depend on the board design or on the
+ peripheral working conditions, so the decision should be made by the board.
+ For example, enabling a pull-up by default may not always be desired because
+ the board already has one or because its value depends on the operating bus
+ speed. Another downside of defaults is that user may not be aware of them,
+ for example:
+
+ .. code-block:: devicetree
+
+ /* not evident that "periph0_siga_px0_default" also implies "bias-pull-up" */
+ periph0_siga_px0_default: periph0_siga_px0_default {
+ pinmux = ;
+ bias-pull-up;
+ };
+
+Implementation guidelines
+*************************
+
+Pin control drivers
+===================
+
+Pin control drivers need to implement a single function:
+:c:func:`pinctrl_configure_pins`. This function receives an array of pin
+configurations that need to be applied. Furthermore, if
+:kconfig:`CONFIG_PINCTRL_STORE_REG` is set, it also receives the associated
+device register address for the given pins. This information may be required by
+some drivers to perform device specific actions.
+
+The pin configuration is stored in an opaque type that is vendor/SoC dependent:
+``pinctrl_soc_pin_t``. This type needs to be defined in a header named
+``pinctrl_soc.h`` file that is in the Zephyr's include path. It can range from
+a simple integer value to a struct with multiple fields. ``pinctrl_soc.h`` also
+needs to define a macro named ``Z_PINCTRL_STATE_PINS_INIT`` that accepts two
+arguments: a node identifier and a property name (``pinctrl-N``). With this
+information the macro needs to define an initializer for all pin configurations
+contained within the ``pinctrl-N`` property of the given node.
+
+Regarding Devicetree pin configuration representation, vendors can decide which
+option is better for their devices. However, the following guidelines should be
+followed:
+
+- Use ``pinctrl-N`` (N=0, 1, ...) and ``pinctrl-names`` properties to define pin
+ control states. These properties are defined in
+ :file:`dts/bindings/pinctrl/pinctrl-device.yaml`.
+- Use standard pin configuration properties as defined in
+ :file:`dts/bindings/pinctrl/pincfg-node.yaml` or
+ :file:`dts/bindings/pinctrl/pincfg-node-group.yaml`.
+
+Representations not following these guidelines may be accepted if they are
+already used by the same vendor in other operating systems, e.g. Linux.
+
+Device drivers
+==============
+
+In this section you will find some tips on how a device driver should use the
+``pinctrl`` API to successfully configure the pins it needs.
+
+The device compatible needs to be modified in the corresponding binding so that
+the ``pinctrl-device.yaml`` is included. For example:
+
+.. code-block:: yaml
+
+ include: [base.yaml, pinctrl-device.yaml]
+
+This file is needed to add ``pinctrl-N`` and ``pinctrl-names`` properties to the
+device.
+
+From a device driver perspective there are two steps that need to be performed
+to be able to use the ``pinctrl`` API. First, the pin control configuration
+needs to be defined. This includes all states and pins.
+:c:macro:`PINCTRL_DT_DEFINE` or :c:macro:`PINCTRL_DT_INST_DEFINE` macros
+should be used for this purpose. Second, a reference to
+the device instance :c:struct:`pinctrl_dev_config` needs to be stored, since it
+is required to later use the API. This can be achieved using the
+:c:macro:`PINCTRL_DT_DEV_CONFIG_GET` and
+:c:macro:`PINCTRL_DT_INST_DEV_CONFIG_GET` macros.
+
+It is worth to note that the only relationship between a device and its
+associated pin control configuration is based on variable naming conventions.
+The way an instance of :c:struct:`pinctrl_dev_config` is named for a
+corresponding device instance allows to later obtain a reference to it given the
+device's Devicetree node identifier. This allows to minimize ROM usage, since
+only devices requiring pin control will own a reference to a pin control
+configuration.
+
+Once the driver has defined the pin control configuration and kept a reference
+to it, it is ready to use the API. The most common way to apply a state is by
+using :c:func:`pinctrl_apply_state`. It is also possible to use the lower level
+function :c:func:`pinctrl_apply_state_direct` to skip state lookup if it is
+cached in advance (e.g. at init time). Since state lookup time is expected to be
+fast, it is recommended to use :c:func:`pinctrl_apply_state`.
+
+The example below contains a complete example of a device driver that uses the
+``pinctrl`` API.
+
+.. code-block:: c
+
+ /* A driver for the "mydev" compatible device */
+ #define DT_DRV_COMPAT mydev
+
+ ...
+ #include
+ ...
+
+ struct mydev_config {
+ ...
+ /* Reference to mydev pinctrl configuration */
+ const struct pinctrl_dev_config *pcfg;
+ ...
+ };
+
+ ...
+
+ static int mydev_init(const struct device *dev)
+ {
+ const struct mydev_config *config = dev->config;
+ int ret;
+ ...
+ /* Select "default" state at initialization time */
+ ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
+ if (ret < 0) {
+ return ret;
+ }
+ ...
+ }
+
+ #define MYDEV_DEFINE(i) \
+ /* Define all pinctrl configuration for instance "i" */ \
+ PINCTRL_DT_INST_DEFINE(i) \
+ ... \
+ static const struct mydev_config mydev_config_##i = { \
+ ... \
+ /* Keep a ref. to the pinctrl configuration for instance "i" */ \
+ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(i), \
+ ... \
+ }; \
+ ... \
+ \
+ DEVICE_DT_INST_DEFINE(i, mydev_init, NULL, &mydev_data##i, \
+ &mydev_config##i, ...)
+
+ DT_INST_FOREACH_STATUS_OKAY(MYDEV_DEFINE)
+
+Other reference material
+************************
+
+- `Introduction to pin muxing and GPIO control under Linux `_
diff --git a/doc/reference/api/overview.rst b/doc/reference/api/overview.rst
index 231e56fea2158..2e61009da78ce 100644
--- a/doc/reference/api/overview.rst
+++ b/doc/reference/api/overview.rst
@@ -232,6 +232,11 @@ current :ref:`stability level `.
- 1.0
- 2.6
+ * - :ref: `pinctrl_api`
+ - Experimental
+ - 3.0
+ - 3.0
+
* - :ref:`pinmux_api`
- Stable
- 1.0
diff --git a/doc/reference/index.rst b/doc/reference/index.rst
index d77a8d2078222..28499be390848 100644
--- a/doc/reference/index.rst
+++ b/doc/reference/index.rst
@@ -27,6 +27,7 @@ API Reference
modbus/index.rst
networking/index.rst
peripherals/index.rst
+ pinctrl/index.rst
power_management/index.rst
random/index.rst
resource_management/index.rst
diff --git a/doc/reference/pinctrl/index.rst b/doc/reference/pinctrl/index.rst
new file mode 100644
index 0000000000000..cf2a5ab44c808
--- /dev/null
+++ b/doc/reference/pinctrl/index.rst
@@ -0,0 +1,11 @@
+.. _pinctrl_api:
+
+Pin Control
+###########
+
+.. doxygengroup:: pinctrl_interface
+
+Dynamic pin control
+*******************
+
+.. doxygengroup:: pinctrl_interface_dynamic
diff --git a/doc/zephyr.doxyfile.in b/doc/zephyr.doxyfile.in
index e8a2f993ba866..897ef50f9668d 100644
--- a/doc/zephyr.doxyfile.in
+++ b/doc/zephyr.doxyfile.in
@@ -2229,7 +2229,8 @@ INCLUDE_FILE_PATTERNS =
# recursively expanded use the := operator instead of the = operator.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-PREDEFINED = CONFIG_ARCH_HAS_CUSTOM_BUSY_WAIT \
+PREDEFINED = __DOXYGEN__ \
+ CONFIG_ARCH_HAS_CUSTOM_BUSY_WAIT \
CONFIG_ARCH_HAS_CUSTOM_SWAP_TO_MAIN \
CONFIG_BT_BREDR \
CONFIG_BT_MESH_MODEL_EXTENSIONS \
diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt
index ce280174dd2df..182060d7391ef 100644
--- a/drivers/CMakeLists.txt
+++ b/drivers/CMakeLists.txt
@@ -61,3 +61,4 @@ add_subdirectory_ifdef(CONFIG_CACHE_MANAGEMENT cache)
add_subdirectory_ifdef(CONFIG_SYSCON syscon)
add_subdirectory_ifdef(CONFIG_BBRAM bbram)
add_subdirectory_ifdef(CONFIG_FPGA fpga)
+add_subdirectory_ifdef(CONFIG_PINCTRL pinctrl)
diff --git a/drivers/Kconfig b/drivers/Kconfig
index e70c0c15e5332..c21e9a2929943 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -123,4 +123,6 @@ source "drivers/bbram/Kconfig"
source "drivers/fpga/Kconfig"
+source "drivers/pinctrl/Kconfig"
+
endmenu
diff --git a/drivers/pinctrl/CMakeLists.txt b/drivers/pinctrl/CMakeLists.txt
new file mode 100644
index 0000000000000..cd3eca95d8d74
--- /dev/null
+++ b/drivers/pinctrl/CMakeLists.txt
@@ -0,0 +1,5 @@
+# Copyright (c) 2021 Nordic Semiconductor ASA
+# SPDX-License-Identifier: Apache-2.0
+
+zephyr_library()
+zephyr_library_sources(common.c)
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
new file mode 100644
index 0000000000000..7e1a67175b84c
--- /dev/null
+++ b/drivers/pinctrl/Kconfig
@@ -0,0 +1,32 @@
+# Copyright (c) 2021 Nordic Semiconductor ASA
+# SPDX-License-Identifier: Apache-2.0
+
+menuconfig PINCTRL
+ bool "Enable pin controller drivers"
+
+if PINCTRL
+
+config PINCTRL_STORE_REG
+ bool
+ help
+ This option must be selected by drivers that require access to the device
+ register address. This can happen, for example, if certain pin control
+ actions are device dependent or require access to device specific
+ registers
+
+config PINCTRL_NON_STATIC
+ bool
+ help
+ This option can be selected if the pin control configuration defined by
+ a driver has to be accessed externally. This can happen, for example, when
+ dynamic pin control is enabled or in testing environments.
+
+config PINCTRL_DYNAMIC
+ bool "Enable dynamic configuration of pins"
+ select PINCTRL_NON_STATIC
+ help
+ When this option is enabled pin control configuration can be changed at
+ runtime. This can be useful, for example, to change the pins assigned to a
+ peripheral at early boot stages depending on a certain input.
+
+endif # PINCTRL
diff --git a/drivers/pinctrl/common.c b/drivers/pinctrl/common.c
new file mode 100644
index 0000000000000..d2d2652910273
--- /dev/null
+++ b/drivers/pinctrl/common.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2021 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include
+
+int pinctrl_lookup_state(const struct pinctrl_dev_config *config, uint8_t id,
+ const struct pinctrl_state **state)
+{
+ *state = &config->states[0];
+ while (*state <= &config->states[config->state_cnt - 1U]) {
+ if (id == (*state)->id) {
+ return 0;
+ }
+
+ (*state)++;
+ }
+
+ return -ENOENT;
+}
+
+#ifdef CONFIG_PINCTRL_DYNAMIC
+int pinctrl_update_states(struct pinctrl_dev_config *config,
+ const struct pinctrl_state *states,
+ uint8_t state_cnt)
+{
+ uint8_t equal = 0U;
+
+ /* check we are inserting same number of states */
+ if (config->state_cnt != state_cnt) {
+ return -EINVAL;
+ }
+
+ /* check we have the same states */
+ for (uint8_t i = 0U; i < state_cnt; i++) {
+ for (uint8_t j = 0U; j < config->state_cnt; j++) {
+ if (states[i].id == config->states[j].id) {
+ equal++;
+ break;
+ }
+ }
+ }
+
+ if (equal != state_cnt) {
+ return -EINVAL;
+ }
+
+ /* replace current states */
+ config->states = states;
+
+ return 0;
+}
+#endif /* CONFIG_PINCTRL_DYNAMIC */
diff --git a/dts/bindings/pinctrl/pincfg-node-group.yaml b/dts/bindings/pinctrl/pincfg-node-group.yaml
new file mode 100644
index 0000000000000..09ec77d307c13
--- /dev/null
+++ b/dts/bindings/pinctrl/pincfg-node-group.yaml
@@ -0,0 +1,165 @@
+# Copyright (c) 2020, Linaro Limited
+# SPDX-License-Identifier: Apache-2.0
+
+description: |
+ Generic pin configuration schema.
+
+ This file is equivalent to pincfg-node.yaml but inserts properties at a
+ grandchildren level, useful for group based representation.
+
+child-binding:
+ child-binding:
+ description: |
+ Many data items that are represented in a pin configuration node are
+ common and generic. Pin control bindings should use the properties
+ defined below where they are applicable; not all of these properties are
+ relevant or useful for all hardware or binding structures. Each
+ individual binding document should state which of these generic
+ properties, if any, are used, and the structure of the DT nodes that
+ contain these properties.
+
+ This is based on Linux, documentation:
+ https://www.kernel.org/doc/Documentation/devicetree/bindings/pinctrl/pincfg-node.yaml
+
+ properties:
+ bias-disable:
+ required: false
+ type: boolean
+ description: disable any pin bias
+
+ bias-high-impedance:
+ required: false
+ type: boolean
+ description: high impedance mode ("third-state", "floating")
+
+ bias-bus-hold:
+ required: false
+ type: boolean
+ description: latch weakly
+
+ bias-pull-up:
+ required: false
+ type: boolean
+ description: enable pull-up resistor
+
+ bias-pull-down:
+ required: false
+ type: boolean
+ description: enable pull-down resistor
+
+ bias-pull-pin-default:
+ required: false
+ type: boolean
+ description: use pin's default pull state
+
+ drive-push-pull:
+ required: false
+ type: boolean
+ description: drive actively high and low
+
+ drive-open-drain:
+ required: false
+ type: boolean
+ description: drive with open drain (hardware AND)
+
+ drive-open-source:
+ required: false
+ type: boolean
+ description: drive with open source (hardware OR)
+
+ drive-strength:
+ required: false
+ type: int
+ description: maximum sink or source current in mA
+
+ drive-strength-microamp:
+ required: false
+ type: int
+ description: maximum sink or source current in μA
+
+ input-enable:
+ required: false
+ type: boolean
+ description: |
+ enable input on pin (no effect on output, such as enabling an input
+ buffer)
+
+ input-disable:
+ required: false
+ type: boolean
+ description: |
+ disable input on pin (no effect on output, such as disabling an input
+ buffer)
+
+ input-schmitt-enable:
+ required: false
+ type: boolean
+ description: enable schmitt-trigger mode
+
+ input-schmitt-disable:
+ required: false
+ type: boolean
+ description: disable schmitt-trigger mode
+
+ input-debounce:
+ required: false
+ type: int
+ description: |
+ Takes the debounce time in μsec, as argument or 0 to disable debouncing
+
+ power-source:
+ required: false
+ type: int
+ description: select between different power supplies
+
+ low-power-enable:
+ required: false
+ type: boolean
+ description: enable low power mode
+
+ low-power-disable:
+ required: false
+ type: boolean
+ description: disable low power mode
+
+ output-disable:
+ required: false
+ type: boolean
+ description: disable output on a pin (such as disable an output buffer)
+
+ output-enable:
+ required: false
+ type: boolean
+ description: |
+ enable output on a pin without actively driving it (such as enabling
+ an output buffer)
+
+ output-low:
+ required: false
+ type: boolean
+ description: set the pin to output mode with low level
+
+ output-high:
+ required: false
+ type: boolean
+ description: set the pin to output mode with high level
+
+ sleep-hardware-state:
+ required: false
+ type: boolean
+ description: |
+ indicate this is sleep related state which will be programmed into
+ the registers for the sleep state
+
+ slew-rate:
+ required: false
+ type: int
+ description: set the slew rate
+
+ skew-delay:
+ required: false
+ type: int
+ description: |
+ This affects the expected clock skew on input pins and the delay
+ before latching a value to an output pin. Typically indicates how
+ many double-inverters are used to delay the signal.
diff --git a/dts/bindings/pinctrl/pinctrl-device.yaml b/dts/bindings/pinctrl/pinctrl-device.yaml
new file mode 100644
index 0000000000000..40679dbac6b88
--- /dev/null
+++ b/dts/bindings/pinctrl/pinctrl-device.yaml
@@ -0,0 +1,43 @@
+# Copyright (c) 2021 Nordic Semiconductor ASA
+# SPDX-License-Identifier: Apache-2.0
+
+description: |
+ This file needs to be included by devices that need to specify a set of pin
+ controller states. The maximum number of supported states is 5 (pinctrl-0 ...
+ pinctrl-4) but it can be incremented if required.
+
+ The bindings file for each pin controller driver implementation should provide
+ more information on what is the expected pin configuration format.
+
+properties:
+ pinctrl-0:
+ type: phandles
+ description: |
+ Pin configuration/s for the first state. Content is specific to the
+ selected pin controller driver implementation.
+
+ pinctrl-1:
+ type: phandles
+ description: |
+ Pin configuration/s for the second state. See pinctrl-0.
+
+ pinctrl-2:
+ type: phandles
+ description: |
+ Pin configuration/s for the third state. See pinctrl-0.
+
+ pinctrl-3:
+ type: phandles
+ description: |
+ Pin configuration/s for the fourth state. See pinctrl-0.
+
+ pinctrl-4:
+ type: phandles
+ description: |
+ Pin configuration/s for the fifth state. See pinctrl-0.
+
+ pinctrl-names:
+ type: string-array
+ description: |
+ Names for the provided states. The number of names needs to match the
+ number of states.
diff --git a/dts/bindings/test/vnd,pinctrl-device.yaml b/dts/bindings/test/vnd,pinctrl-device.yaml
new file mode 100644
index 0000000000000..3f8e18c88b184
--- /dev/null
+++ b/dts/bindings/test/vnd,pinctrl-device.yaml
@@ -0,0 +1,8 @@
+# Copyright (c) 2021 Nordic Semiconductor ASA
+# SPDX-License-Identifier: Apache-2.0
+
+description: Test device for pin controller.
+
+compatible: "vnd,pinctrl-device"
+
+include: [base.yaml, pinctrl-device.yaml]
diff --git a/dts/bindings/test/vnd,pinctrl-test.yaml b/dts/bindings/test/vnd,pinctrl-test.yaml
new file mode 100644
index 0000000000000..d0c74ac2361e0
--- /dev/null
+++ b/dts/bindings/test/vnd,pinctrl-test.yaml
@@ -0,0 +1,59 @@
+# Copyright (c) 2021 Nordic Semiconductor ASA
+# SPDX-License-Identifier: Apache-2.0
+
+description: |
+ Test pin controller.
+
+compatible: "vnd,pinctrl-test"
+
+include:
+ - name: base.yaml
+ - name: pincfg-node-group.yaml
+ child-binding:
+ child-binding:
+ property-allowlist:
+ - bias-pull-down
+ - bias-pull-up
+
+child-binding:
+ description: |
+ Test pin controller pin configuration nodes. Each node is composed by one or
+ more groups, each defining the configuration for a set of pins.
+
+ child-binding:
+ description: |
+ Test pin controller pin configuration group. Each group contains a list of
+ pins sharing the same set of properties. Example:
+
+ /* node representing default state for test_device0 */
+ test_device0_default: test_device0_default {
+ /* group 1 (name is arbitrary) */
+ pins1 {
+ /* configure pins 0 and 1 */
+ pins = <0>, <1>;
+ /* both pins 0 and 1 have pull-up enabled */
+ bias-pull-up;
+ };
+ ...
+ /* group N (name is arbitrary) */
+ pinsN {
+ /* configure pin M */
+ pins = ;
+ /* pin M has pull-down enabled */
+ bias-pull-down;
+ };
+ };
+
+ The list of supported standard properties:
+
+ - bias-pull-up: Enable pull-up resistor.
+ - bias-pull-down: Enable pull-down resistor.
+
+ properties:
+ pins:
+ required: true
+ type: array
+ description: |
+ An array of pins sharing the same group properties. Each entry is a
+ 32-bit integer that is just used to identify the entry for testing
+ purposes.
diff --git a/include/drivers/pinctrl.h b/include/drivers/pinctrl.h
new file mode 100644
index 0000000000000..b8a429c240ab3
--- /dev/null
+++ b/include/drivers/pinctrl.h
@@ -0,0 +1,456 @@
+/*
+ * Copyright (c) 2021 Nordic Semiconductor ASA
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/**
+ * @file
+ * Public APIs for pin control drivers
+ */
+
+#ifndef ZEPHYR_INCLUDE_DRIVERS_PINCTRL_H_
+#define ZEPHYR_INCLUDE_DRIVERS_PINCTRL_H_
+
+/**
+ * @brief Pin Controller Interface
+ * @defgroup pinctrl_interface Pin Controller Interface
+ * @ingroup io_interfaces
+ * @{
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @name Pin control states
+ * @anchor PINCTRL_STATES
+ * @{
+ */
+
+/** Default state (state used when the device is in operational state). */
+#define PINCTRL_STATE_DEFAULT 0U
+/** Sleep state (state used when the device is in low power mode). */
+#define PINCTRL_STATE_SLEEP 1U
+
+/** This and higher values refer to custom private states. */
+#define PINCTRL_STATE_PRIV_START 2U
+
+/** @} */
+
+/** Pin control state configuration. */
+struct pinctrl_state {
+ /** Pin configurations. */
+ const pinctrl_soc_pin_t *pins;
+ /** Number of pin configurations. */
+ uint8_t pin_cnt;
+ /** State identifier (see @ref PINCTRL_STATES). */
+ uint8_t id;
+};
+
+/** Pin controller configuration for a given device. */
+struct pinctrl_dev_config {
+#if defined(CONFIG_PINCTRL_STORE_REG) || defined(__DOXYGEN__)
+ /**
+ * Device address (only available if @kconfig{CONFIG_PINCTRL_STORE_REG}
+ * is enabled).
+ */
+ uintptr_t reg;
+#endif /* defined(CONFIG_PINCTRL_STORE_REG) || defined(__DOXYGEN__) */
+ /** List of state configurations. */
+ const struct pinctrl_state *states;
+ /** Number of state configurations. */
+ uint8_t state_cnt;
+};
+
+/** Utility macro to indicate no register is used. */
+#define PINCTRL_REG_NONE 0U
+
+/** @cond INTERNAL_HIDDEN */
+
+#ifndef CONFIG_PM_DEVICE
+/** If device power management is not enabled, "sleep" state will be ignored. */
+#define PINCTRL_SKIP_SLEEP 1
+#endif
+
+/**
+ * @brief Obtain the state identifier for the given node and state index.
+ *
+ * @param state_idx State index.
+ * @param node_id Node identifier.
+ */
+#define Z_PINCTRL_STATE_ID(state_idx, node_id) \
+ _CONCAT(PINCTRL_STATE_, \
+ DT_PINCTRL_IDX_TO_NAME_UPPER_TOKEN(node_id, state_idx))
+
+/**
+ * @brief Obtain the variable name storing pinctrl config for the given DT node
+ * identifier.
+ *
+ * @param node_id Node identifier.
+ */
+#define Z_PINCTRL_DEV_CONFIG_NAME(node_id) \
+ _CONCAT(__pinctrl_dev_config, DEVICE_DT_NAME_GET(node_id))
+
+/**
+ * @brief Obtain the variable name storing pinctrl states for the given DT node
+ * identifier.
+ *
+ * @param node_id Node identifier.
+ */
+#define Z_PINCTRL_STATES_NAME(node_id) \
+ _CONCAT(__pinctrl_states, DEVICE_DT_NAME_GET(node_id))
+
+/**
+ * @brief Obtain the variable name storing pinctrl pins for the given DT node
+ * identifier and state index.
+ *
+ * @param state_idx State index.
+ * @param node_id Node identifier.
+ */
+#define Z_PINCTRL_STATE_PINS_NAME(state_idx, node_id) \
+ _CONCAT(__pinctrl_state_pins_ ## state_idx, DEVICE_DT_NAME_GET(node_id))
+
+/**
+ * @brief Utility macro to check if given state has to be skipped.
+ *
+ * If a certain state has to be skipped, a macro named PINCTRL_SKIP_
+ * can be defined evaluating to 1. This can be useful, for example, to
+ * automatically ignore the sleep state if no device power management is
+ * enabled.
+ *
+ * @param state_idx State index.
+ * @param node_id Node identifier.
+ */
+#define Z_PINCTRL_SKIP_STATE(state_idx, node_id) \
+ _CONCAT(PINCTRL_SKIP_, \
+ DT_PINCTRL_IDX_TO_NAME_UPPER_TOKEN(node_id, state_idx))
+
+/**
+ * @brief Helper macro to define pins for a given pin control state.
+ *
+ * @param state_idx State index.
+ * @param node_id Node identifier.
+ */
+#define Z_PINCTRL_STATE_PINS_DEFINE(state_idx, node_id) \
+ COND_CODE_1(Z_PINCTRL_SKIP_STATE(state_idx, node_id), (), \
+ (static const pinctrl_soc_pin_t \
+ Z_PINCTRL_STATE_PINS_NAME(state_idx, node_id)[] = \
+ Z_PINCTRL_STATE_PINS_INIT(node_id, pinctrl_ ## state_idx);))
+
+/**
+ * @brief Helper macro to initialize a pin control state.
+ *
+ * @param state_idx State index.
+ * @param node_id Node identifier.
+ */
+#define Z_PINCTRL_STATE_INIT(state_idx, node_id) \
+ COND_CODE_1(Z_PINCTRL_SKIP_STATE(state_idx, node_id), (), \
+ ({ \
+ .id = Z_PINCTRL_STATE_ID(state_idx, node_id), \
+ .pins = Z_PINCTRL_STATE_PINS_NAME(state_idx, node_id), \
+ .pin_cnt = ARRAY_SIZE(Z_PINCTRL_STATE_PINS_NAME(state_idx, \
+ node_id)) \
+ },))
+
+/**
+ * @brief Define all the states for the given node identifier.
+ *
+ * @param node_id Node identifier.
+ */
+#define Z_PINCTRL_STATES_DEFINE(node_id) \
+ static const struct pinctrl_state \
+ Z_PINCTRL_STATES_NAME(node_id)[] = { \
+ UTIL_LISTIFY(DT_NUM_PINCTRL_STATES(node_id), \
+ Z_PINCTRL_STATE_INIT, node_id) \
+ };
+
+#ifdef CONFIG_PINCTRL_STORE_REG
+/**
+ * @brief Helper macro to initialize pin control config.
+ *
+ * @param node_id Node identifier.
+ */
+#define Z_PINCTRL_DEV_CONFIG_INIT(node_id) \
+ { \
+ .reg = DT_REG_ADDR(node_id), \
+ .states = Z_PINCTRL_STATES_NAME(node_id), \
+ .state_cnt = ARRAY_SIZE(Z_PINCTRL_STATES_NAME(node_id)), \
+ }
+#else
+#define Z_PINCTRL_DEV_CONFIG_INIT(node_id) \
+ { \
+ .states = Z_PINCTRL_STATES_NAME(node_id), \
+ .state_cnt = ARRAY_SIZE(Z_PINCTRL_STATES_NAME(node_id)), \
+ }
+#endif
+
+#ifdef CONFIG_PINCTRL_NON_STATIC
+#define Z_PINCTRL_DEV_CONFIG_STATIC
+#else
+#define Z_PINCTRL_DEV_CONFIG_STATIC static
+#endif
+
+#ifdef CONFIG_PINCTRL_DYNAMIC
+#define Z_PINCTRL_DEV_CONFIG_CONST
+#else
+#define Z_PINCTRL_DEV_CONFIG_CONST const
+#endif
+
+/** @endcond */
+
+#if defined(CONFIG_PINCTRL_NON_STATIC) || defined(__DOXYGEN__)
+/**
+ * @brief Declare pin control configuration for a given node identifier.
+ *
+ * This macro should be used by tests or applications using runtime pin control
+ * to declare the pin control configuration for a device.
+ * #PINCTRL_DT_DEV_CONFIG_GET can later be used to obtain a reference to such
+ * configuration.
+ *
+ * Only available if @kconfig{CONFIG_PINCTRL_NON_STATIC} is selected.
+ *
+ * @param node_id Node identifier.
+ */
+#define PINCTRL_DT_DEV_CONFIG_DECLARE(node_id) \
+ extern Z_PINCTRL_DEV_CONFIG_CONST struct pinctrl_dev_config \
+ Z_PINCTRL_DEV_CONFIG_NAME(node_id)
+#endif /* defined(CONFIG_PINCTRL_NON_STATIC) || defined(__DOXYGEN__) */
+
+/**
+ * @brief Define all pin control information for the given node identifier.
+ *
+ * This helper macro should be called together with device definition. It
+ * defines and initializes the pin control configuration for the device
+ * represented by node_id. Each pin control state (pinctrl-0, ..., pinctrl-N) is
+ * also defined and initialized. Note that states marked to be skipped will not
+ * be defined (refer to Z_PINCTRL_SKIP_STATE for more details).
+ *
+ * @param node_id Node identifier.
+ */
+#define PINCTRL_DT_DEFINE(node_id) \
+ UTIL_LISTIFY(DT_NUM_PINCTRL_STATES(node_id), \
+ Z_PINCTRL_STATE_PINS_DEFINE, node_id) \
+ Z_PINCTRL_STATES_DEFINE(node_id) \
+ Z_PINCTRL_DEV_CONFIG_CONST Z_PINCTRL_DEV_CONFIG_STATIC \
+ struct pinctrl_dev_config Z_PINCTRL_DEV_CONFIG_NAME(node_id) = \
+ Z_PINCTRL_DEV_CONFIG_INIT(node_id);
+
+/**
+ * @brief Define all pin control information for the given compatible index.
+ *
+ * @param inst Instance number.
+ *
+ * @see #PINCTRL_DT_DEFINE
+ */
+#define PINCTRL_DT_INST_DEFINE(inst) PINCTRL_DT_DEFINE(DT_DRV_INST(inst))
+
+/**
+ * @brief Obtain a reference to the pin control configuration given a node
+ * identifier.
+ *
+ * @param node_id Node identifier.
+ */
+#define PINCTRL_DT_DEV_CONFIG_GET(node_id) &Z_PINCTRL_DEV_CONFIG_NAME(node_id)
+
+/**
+ * @brief Obtain a reference to the pin control configuration given current
+ * compatible instance number.
+ *
+ * @param inst Instance number.
+ *
+ * @see #PINCTRL_DT_DEV_CONFIG_GET
+ */
+#define PINCTRL_DT_INST_DEV_CONFIG_GET(inst) \
+ PINCTRL_DT_DEV_CONFIG_GET(DT_DRV_INST(inst))
+
+/**
+ * @brief Find the state configuration for the given state id.
+ *
+ * @param config Pin controller configuration.
+ * @param id Pin controller state id (see @ref PINCTRL_STATES).
+ * @param state Found state.
+ *
+ * @retval 0 If state has been found.
+ * @retval -ENOENT If the state has not been found.
+ */
+int pinctrl_lookup_state(const struct pinctrl_dev_config *config, uint8_t id,
+ const struct pinctrl_state **state);
+
+/**
+ * @brief Configure a set of pins.
+ *
+ * This function will configure the necessary hardware blocks to make the
+ * configuration immediately effective.
+ *
+ * @warning This function must never be used to configure pins used by an
+ * instantiated device driver.
+ *
+ * @param pins List of pins to be configured.
+ * @param pin_cnt Number of pins.
+ * @param reg Device register (optional, use #PINCTRL_REG_NONE if not used).
+ *
+ * @retval 0 If succeeded
+ * @retval -errno Negative errno for other failures.
+ */
+int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt,
+ uintptr_t reg);
+
+/**
+ * @brief Apply a state directly from the provided state configuration.
+ *
+ * @param config Pin control configuration.
+ * @param state State.
+ *
+ * @retval 0 If succeeded
+ * @retval -errno Negative errno for other failures.
+ */
+static inline int pinctrl_apply_state_direct(
+ const struct pinctrl_dev_config *config,
+ const struct pinctrl_state *state)
+{
+ uintptr_t reg;
+
+#ifdef CONFIG_PINCTRL_STORE_REG
+ reg = config->reg;
+#else
+ reg = PINCTRL_REG_NONE;
+#endif
+
+ return pinctrl_configure_pins(state->pins, state->pin_cnt, reg);
+}
+
+/**
+ * @brief Apply a state from the given device configuration.
+ *
+ * @param config Pin control configuration.
+ * @param id Id of the state to be applied (see @ref PINCTRL_STATES).
+ *
+ * @retval 0 If succeeded.
+ * @retval -ENOENT If given state id does not exist.
+ * @retval -errno Negative errno for other failures.
+ */
+static inline int pinctrl_apply_state(const struct pinctrl_dev_config *config,
+ uint8_t id)
+{
+ int ret;
+ const struct pinctrl_state *state;
+
+ ret = pinctrl_lookup_state(config, id, &state);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return pinctrl_apply_state_direct(config, state);
+}
+
+#if defined(CONFIG_PINCTRL_DYNAMIC) || defined(__DOXYGEN__)
+/**
+ * @defgroup pinctrl_interface_dynamic Dynamic Pin Control
+ * @{
+ */
+
+/**
+ * @brief Helper macro to define the pins of a pin control state from
+ * Devicetree.
+ *
+ * The name of the defined state pins variable is the same used by @p prop. This
+ * macro is expected to be used in conjunction with #PINCTRL_DT_STATE_INIT.
+ *
+ * @param node_id Node identifier containing @p prop.
+ * @param prop Property within @p node_id containing state configuration.
+ *
+ * @see #PINCTRL_DT_STATE_INIT
+ */
+#define PINCTRL_DT_STATE_PINS_DEFINE(node_id, prop) \
+ static const pinctrl_soc_pin_t prop ## _pins[] = \
+ Z_PINCTRL_STATE_PINS_INIT(node_id, prop); \
+
+/**
+ * @brief Utility macro to initialize a pin control state.
+ *
+ * This macro should be used in conjunction with #PINCTRL_DT_STATE_PINS_DEFINE
+ * when using dynamic pin control to define an alternative state configuration
+ * stored in Devicetree.
+ *
+ * Example:
+ *
+ * @code{.devicetree}
+ * // board.dts
+ *
+ * /{
+ * zephyr,user {
+ * // uart0_alt_default node contains alternative pin config
+ * uart0_alt_default = <&uart0_alt_default>;
+ * };
+ * };
+ * @endcode
+ *
+ * @code{.c}
+ * // application
+ *
+ * PINCTRL_DT_STATE_PINS_DEFINE(DT_PATH(zephyr_user), uart0_alt_default);
+ *
+ * static const struct pinctrl_state uart0_alt[] = {
+ * PINCTRL_DT_STATE_INIT(uart0_alt_default, PINCTRL_STATE_DEFAULT)
+ * };
+ * @endcode
+ *
+ * @param prop Property name in Devicetree containing state configuration.
+ * @param state State represented by @p prop (see @ref PINCTRL_STATES).
+ *
+ * @see #PINCTRL_DT_STATE_PINS_DEFINE
+ */
+#define PINCTRL_DT_STATE_INIT(prop, state) \
+ { \
+ .id = state, \
+ .pins = prop ## _pins, \
+ .pin_cnt = ARRAY_SIZE(prop ## _pins) \
+ }
+
+/**
+ * @brief Update states with a new set.
+ *
+ * @note In order to guarantee device drivers correct operation the same states
+ * have to be provided. For example, if @c default and @c sleep are in the
+ * current list of states, it is expected that the new array of states also
+ * contains both.
+ *
+ * @param config Pin control configuration.
+ * @param states New states to be set.
+ * @param state_cnt Number of new states to be set.
+ *
+ * @retval -EINVAL If the new configuration does not contain the same states as
+ * the current active configuration.
+ * @retval -ENOSYS If the functionality is not available.
+ * @retval 0 On success.
+ */
+int pinctrl_update_states(struct pinctrl_dev_config *config,
+ const struct pinctrl_state *states,
+ uint8_t state_cnt);
+
+/** @} */
+#else
+static inline int pinctrl_update_states(
+ struct pinctrl_dev_config *config,
+ const struct pinctrl_state *states, uint8_t state_cnt)
+{
+ return -ENOSYS;
+}
+#endif /* defined(CONFIG_PINCTRL_DYNAMIC) || defined(__DOXYGEN__) */
+
+#ifdef __cplusplus
+}
+#endif
+
+/**
+ * @}
+ */
+
+#endif /* ZEPHYR_INCLUDE_DRIVERS_PINCTRL_H_ */
diff --git a/tests/drivers/pinctrl/api/CMakeLists.txt b/tests/drivers/pinctrl/api/CMakeLists.txt
new file mode 100644
index 0000000000000..1825c3dabc4c0
--- /dev/null
+++ b/tests/drivers/pinctrl/api/CMakeLists.txt
@@ -0,0 +1,12 @@
+# Copyright (c) 2021 Nordic Semiconductor ASA
+# SPDX-License-Identifier: Apache-2.0
+
+cmake_minimum_required(VERSION 3.20.0)
+find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
+
+project(pinctrl_api)
+
+zephyr_include_directories(src)
+zephyr_include_directories(../common)
+
+target_sources(app PRIVATE src/main.c src/pinctrl_test.c ../common/test_device.c)
diff --git a/tests/drivers/pinctrl/api/Kconfig b/tests/drivers/pinctrl/api/Kconfig
new file mode 100644
index 0000000000000..8102053cdb6f5
--- /dev/null
+++ b/tests/drivers/pinctrl/api/Kconfig
@@ -0,0 +1,13 @@
+# Copyright (c) 2021 Nordic Semiconductor ASA
+# SPDX-License-Identifier: Apache-2.0
+
+mainmenu "pinctrl API Test"
+
+source "Kconfig.zephyr"
+
+config PINCTRL_TEST_STORE_REG
+ bool "Store register address"
+ select PINCTRL_STORE_REG
+ help
+ This option should be selected by unit tests that want to store the
+ register address of devices.
diff --git a/tests/drivers/pinctrl/api/app.overlay b/tests/drivers/pinctrl/api/app.overlay
new file mode 100644
index 0000000000000..d406814b84086
--- /dev/null
+++ b/tests/drivers/pinctrl/api/app.overlay
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2021 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+ / {
+ pinctrl {
+ compatible = "vnd,pinctrl-test";
+
+ /* default state for device 0 */
+ test_device0_default: test_device0_default {
+ pins1 {
+ pins = <0>;
+ bias-pull-up;
+ };
+ pins2 {
+ pins = <1>;
+ bias-pull-down;
+ };
+ };
+
+ /* sleep state for device 0 */
+ test_device0_sleep: test_device0_sleep {
+ pins1 {
+ pins = <0>, <1>;
+ };
+ };
+
+ /* alternative default state for device 0 */
+ test_device0_alt_default: test_device0_alt_default {
+ pins1 {
+ pins = <2>;
+ bias-pull-down;
+ };
+ pins2 {
+ pins = <3>;
+ bias-pull-up;
+ };
+ };
+
+ /* alternative sleep state for device 0 */
+ test_device0_alt_sleep: test_device0_alt_sleep {
+ pins1 {
+ pins = <2>, <3>;
+ };
+ };
+
+ /* default state for device 1 */
+ test_device1_default: test_device1_default {
+ pins1 {
+ pins = <10>, <11>, <12>;
+ };
+ };
+
+ /* custom state "mystate" for device 1 */
+ test_device1_mystate: test_device1_mystate {
+ pins1 {
+ pins = <10>;
+ };
+ pins2 {
+ pins = <11>;
+ bias-pull-up;
+ };
+ pins3 {
+ pins = <12>;
+ bias-pull-down;
+ };
+ };
+ };
+
+ zephyr,user {
+ test_device0_alt_default = <&test_device0_alt_default>;
+ test_device0_alt_sleep = <&test_device0_alt_sleep>;
+ };
+
+ test_device0: test_device@0 {
+ compatible = "vnd,pinctrl-device";
+ reg = <0x0 0x1>;
+ pinctrl-0 = <&test_device0_default>;
+ pinctrl-1 = <&test_device0_sleep>;
+ pinctrl-names = "default", "sleep";
+ };
+
+ test_device1: test_device@1 {
+ compatible = "vnd,pinctrl-device";
+ reg = <0x1 0x1>;
+ pinctrl-0 = <&test_device1_default>;
+ pinctrl-1 = <&test_device1_mystate>;
+ pinctrl-names = "default", "mystate";
+ };
+};
diff --git a/tests/drivers/pinctrl/api/prj.conf b/tests/drivers/pinctrl/api/prj.conf
new file mode 100644
index 0000000000000..0ffb301538730
--- /dev/null
+++ b/tests/drivers/pinctrl/api/prj.conf
@@ -0,0 +1,7 @@
+# Copyright (c) 2021 Nordic Semiconductor ASA
+# SPDX-License-Identifier: Apache-2.0
+
+CONFIG_ZTEST=y
+CONFIG_ZTEST_MOCKING=y
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_DYNAMIC=y
diff --git a/tests/drivers/pinctrl/api/reg.conf b/tests/drivers/pinctrl/api/reg.conf
new file mode 100644
index 0000000000000..955bd02ea4082
--- /dev/null
+++ b/tests/drivers/pinctrl/api/reg.conf
@@ -0,0 +1,4 @@
+# Copyright (c) 2021 Nordic Semiconductor ASA
+# SPDX-License-Identifier: Apache-2.0
+
+CONFIG_PINCTRL_TEST_STORE_REG=y
diff --git a/tests/drivers/pinctrl/api/src/main.c b/tests/drivers/pinctrl/api/src/main.c
new file mode 100644
index 0000000000000..3f331b9f1a698
--- /dev/null
+++ b/tests/drivers/pinctrl/api/src/main.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2021 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include
+#include
+
+#include "test_device.h"
+
+/* test device 0 */
+#define TEST_DEVICE0 DT_NODELABEL(test_device0)
+PINCTRL_DT_DEV_CONFIG_DECLARE(TEST_DEVICE0);
+static struct pinctrl_dev_config *pcfg0 = PINCTRL_DT_DEV_CONFIG_GET(TEST_DEVICE0);
+
+/* test device 1 */
+#define TEST_DEVICE1 DT_NODELABEL(test_device1)
+PINCTRL_DT_DEV_CONFIG_DECLARE(TEST_DEVICE1);
+static struct pinctrl_dev_config *pcfg1 = PINCTRL_DT_DEV_CONFIG_GET(TEST_DEVICE1);
+
+/**
+ * @brief Test if configuration for device 0 has been stored as expected.
+ *
+ * Device 0 is also used to verify that certain states are skipped
+ * automatically, e.g. "sleep" if CONFIG_PM_DEVICE is not active.
+ *
+ * This test together with test_config_dev1 is used to verify that the whole
+ * set of macros used to define and initialize pin control config from
+ * Devicetree works as expected.
+ */
+static void test_config_dev0(void)
+{
+ const struct pinctrl_state *scfg;
+
+ zassert_equal(pcfg0->state_cnt, 1, NULL);
+#ifdef CONFIG_PINCTRL_STORE_REG
+ zassert_equal(pcfg0->reg, 0, NULL);
+#endif
+
+ scfg = &pcfg0->states[0];
+ zassert_equal(scfg->id, PINCTRL_STATE_DEFAULT, NULL);
+ zassert_equal(TEST_GET_PIN(scfg->pins[0]), 0, NULL);
+ zassert_equal(TEST_GET_PULL(scfg->pins[0]), TEST_PULL_UP, NULL);
+ zassert_equal(TEST_GET_PIN(scfg->pins[1]), 1, NULL);
+ zassert_equal(TEST_GET_PULL(scfg->pins[1]), TEST_PULL_DOWN, NULL);
+}
+
+/**
+ * @brief Test if configuration for device 1 has been stored as expected.
+ *
+ * Device 1 is also used to verify that custom states can be defined.
+ *
+ * @see test_config_dev0()
+ */
+static void test_config_dev1(void)
+{
+ const struct pinctrl_state *scfg;
+
+ zassert_equal(pcfg1->state_cnt, 2, NULL);
+#ifdef CONFIG_PINCTRL_STORE_REG
+ zassert_equal(pcfg1->reg, 1, NULL);
+#endif
+
+ scfg = &pcfg1->states[0];
+ zassert_equal(scfg->id, PINCTRL_STATE_DEFAULT, NULL);
+ zassert_equal(scfg->pin_cnt, 3, NULL);
+ zassert_equal(TEST_GET_PIN(scfg->pins[0]), 10, NULL);
+ zassert_equal(TEST_GET_PULL(scfg->pins[0]), TEST_PULL_DISABLE, NULL);
+ zassert_equal(TEST_GET_PIN(scfg->pins[1]), 11, NULL);
+ zassert_equal(TEST_GET_PULL(scfg->pins[1]), TEST_PULL_DISABLE, NULL);
+ zassert_equal(TEST_GET_PIN(scfg->pins[2]), 12, NULL);
+ zassert_equal(TEST_GET_PULL(scfg->pins[2]), TEST_PULL_DISABLE, NULL);
+
+ scfg = &pcfg1->states[1];
+ zassert_equal(scfg->id, PINCTRL_STATE_MYSTATE, NULL);
+ zassert_equal(scfg->pin_cnt, 3, NULL);
+ zassert_equal(TEST_GET_PIN(scfg->pins[0]), 10, NULL);
+ zassert_equal(TEST_GET_PULL(scfg->pins[0]), TEST_PULL_DISABLE, NULL);
+ zassert_equal(TEST_GET_PIN(scfg->pins[1]), 11, NULL);
+ zassert_equal(TEST_GET_PULL(scfg->pins[1]), TEST_PULL_UP, NULL);
+ zassert_equal(TEST_GET_PIN(scfg->pins[2]), 12, NULL);
+ zassert_equal(TEST_GET_PULL(scfg->pins[2]), TEST_PULL_DOWN, NULL);
+}
+
+/**
+ * @brief Test that pinctrl_lookup_state() works as expected
+ */
+static void test_lookup_state(void)
+{
+ int ret;
+ const struct pinctrl_state *scfg;
+
+ ret = pinctrl_lookup_state(pcfg0, PINCTRL_STATE_DEFAULT, &scfg);
+ zassert_equal(ret, 0, NULL);
+ zassert_equal_ptr(scfg, &pcfg0->states[0], NULL);
+
+ ret = pinctrl_lookup_state(pcfg0, PINCTRL_STATE_SLEEP, &scfg);
+ zassert_equal(ret, -ENOENT, NULL);
+}
+
+/**
+ * @brief Test that pinctrl_apply_state() works as expected.
+ */
+static void test_apply_state(void)
+{
+ int ret;
+
+ ztest_expect_data(pinctrl_configure_pins, pins, pcfg0->states[0].pins);
+ ztest_expect_value(pinctrl_configure_pins, pin_cnt,
+ pcfg0->states[0].pin_cnt);
+#ifdef CONFIG_PINCTRL_STORE_REG
+ ztest_expect_value(pinctrl_configure_pins, reg, 0);
+#else
+ ztest_expect_value(pinctrl_configure_pins, reg, PINCTRL_REG_NONE);
+#endif
+
+ ret = pinctrl_apply_state(pcfg0, PINCTRL_STATE_DEFAULT);
+ zassert_equal(ret, 0, NULL);
+}
+
+/** Test device 0 alternative pins for default state */
+PINCTRL_DT_STATE_PINS_DEFINE(DT_PATH(zephyr_user), test_device0_alt_default);
+/** Test device 0 alternative pins for sleep state */
+PINCTRL_DT_STATE_PINS_DEFINE(DT_PATH(zephyr_user), test_device0_alt_sleep);
+
+/** Test device 0 alternative states. */
+static const struct pinctrl_state test_device0_alt[] = {
+ PINCTRL_DT_STATE_INIT(test_device0_alt_default, PINCTRL_STATE_DEFAULT),
+};
+
+/** Test device 0 invalid alternative states. */
+static const struct pinctrl_state test_device0_alt_invalid[] = {
+ PINCTRL_DT_STATE_INIT(test_device0_alt_default, PINCTRL_STATE_DEFAULT),
+ /* sleep state is skipped (no CONFIG_PM_DEVICE), so it is invalid */
+ PINCTRL_DT_STATE_INIT(test_device0_alt_sleep, PINCTRL_STATE_SLEEP),
+};
+
+/**
+ * @brief This test checks if pinctrl_update_states() works as expected.
+ */
+static void test_update_states(void)
+{
+ int ret;
+ const struct pinctrl_state *scfg;
+
+ ret = pinctrl_update_states(pcfg0, test_device0_alt,
+ ARRAY_SIZE(test_device0_alt));
+ zassert_equal(ret, 0, NULL);
+
+ scfg = &pcfg0->states[0];
+ zassert_equal(TEST_GET_PIN(scfg->pins[0]), 2, NULL);
+ zassert_equal(TEST_GET_PULL(scfg->pins[0]), TEST_PULL_DOWN, NULL);
+ zassert_equal(TEST_GET_PIN(scfg->pins[1]), 3, NULL);
+ zassert_equal(TEST_GET_PULL(scfg->pins[1]), TEST_PULL_UP, NULL);
+
+ ret = pinctrl_update_states(pcfg0, test_device0_alt_invalid,
+ ARRAY_SIZE(test_device0_alt_invalid));
+ zassert_equal(ret, -EINVAL, NULL);
+}
+
+void test_main(void)
+{
+ ztest_test_suite(pinctrl_api,
+ ztest_unit_test(test_config_dev0),
+ ztest_unit_test(test_config_dev1),
+ ztest_unit_test(test_lookup_state),
+ ztest_unit_test(test_apply_state),
+ ztest_unit_test(test_update_states));
+ ztest_run_test_suite(pinctrl_api);
+}
diff --git a/tests/drivers/pinctrl/api/src/pinctrl_soc.h b/tests/drivers/pinctrl/api/src/pinctrl_soc.h
new file mode 100644
index 0000000000000..85195c2f3187a
--- /dev/null
+++ b/tests/drivers/pinctrl/api/src/pinctrl_soc.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2021 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/**
+ * @file
+ * Testing specific helpers for pinctrl driver.
+ */
+
+#ifndef ZEPHYR_TESTS_DRIVERS_PINCTRL_API_SRC_PINCTRL_SOC_H_
+#define ZEPHYR_TESTS_DRIVERS_PINCTRL_API_SRC_PINCTRL_SOC_H_
+
+#include
+#include
+
+/**
+ * @name Test pin configuration bit field positions and masks.
+ *
+ * Bits 31, 30: Pull config.
+ * Bits 29..0: Pin.
+ *
+ * @{
+ */
+
+/** Position of the pull field. */
+#define TEST_PULL_POS 30U
+/** Mask of the pull field. */
+#define TEST_PULL_MSK 0x3U
+/** Position of the pin field. */
+#define TEST_PIN_POS 0U
+/** Mask for the pin field. */
+#define TEST_PIN_MSK 0x3FFFFFFFU
+
+/** @} */
+
+/**
+ * @name Test pinctrl pull-up/down.
+ * @{
+ */
+
+/** Pull-up disabled. */
+#define TEST_PULL_DISABLE 0U
+/** Pull-down enabled. */
+#define TEST_PULL_DOWN 1U
+/** Pull-up enabled. */
+#define TEST_PULL_UP 2U
+
+/** @} */
+
+/**
+ * @brief Utility macro to obtain pin pull configuration.
+ *
+ * @param pincfg Pin configuration bit field.
+ */
+#define TEST_GET_PULL(pincfg) (((pincfg) >> TEST_PULL_POS) & TEST_PULL_MSK)
+
+/**
+ * @brief Utility macro to obtain port and pin combination.
+ *
+ * @param pincfg Pin configuration bit field.
+ */
+#define TEST_GET_PIN(pincfg) (((pincfg) >> TEST_PIN_POS) & TEST_PIN_MSK)
+
+/** @cond INTERNAL_HIDDEN */
+
+/** Test pin type */
+typedef uint32_t pinctrl_soc_pin_t;
+
+/**
+ * @brief Utility macro to initialize each pin.
+ *
+ * @param node_id Node identifier.
+ * @param prop Property name.
+ * @param idx Property entry index.
+ */
+#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) \
+ (((DT_PROP_BY_IDX(node_id, prop, idx) << TEST_PIN_POS) \
+ & TEST_PIN_MSK) | \
+ ((TEST_PULL_UP * DT_PROP(node_id, bias_pull_up)) \
+ << TEST_PULL_POS) | \
+ ((TEST_PULL_DOWN * DT_PROP(node_id, bias_pull_down)) \
+ << TEST_PULL_POS) \
+ ),
+
+/**
+ * @brief Utility macro to initialize state pins contained in a given property.
+ *
+ * @param node_id Node identifier.
+ * @param prop Property name describing state pins.
+ */
+#define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \
+ {DT_FOREACH_CHILD_VARGS(DT_PROP_BY_IDX(node_id, prop, 0), \
+ DT_FOREACH_PROP_ELEM, pins, \
+ Z_PINCTRL_STATE_PIN_INIT)}
+
+/** @endcond */
+
+#endif /* ZEPHYR_TESTS_DRIVERS_PINCTRL_API_SRC_PINCTRL_SOC_H_ */
diff --git a/tests/drivers/pinctrl/api/src/pinctrl_test.c b/tests/drivers/pinctrl/api/src/pinctrl_test.c
new file mode 100644
index 0000000000000..0dff842f27f94
--- /dev/null
+++ b/tests/drivers/pinctrl/api/src/pinctrl_test.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2021 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include
+#include
+
+/* pinctrl test driver implemented as a mock */
+
+int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt,
+ uintptr_t reg)
+{
+ ztest_check_expected_data(pins, pin_cnt * sizeof(*pins));
+ ztest_check_expected_value(pin_cnt);
+ ztest_check_expected_value(reg);
+
+ return 0;
+}
diff --git a/tests/drivers/pinctrl/api/testcase.yaml b/tests/drivers/pinctrl/api/testcase.yaml
new file mode 100644
index 0000000000000..f56eb6a56fa20
--- /dev/null
+++ b/tests/drivers/pinctrl/api/testcase.yaml
@@ -0,0 +1,11 @@
+# Copyright (c) 2021 Nordic Semiconductor ASA
+# SPDX-License-Identifier: Apache-2.0
+
+tests:
+ drivers.pinctrl.api:
+ tags: drivers pinctrl
+ platform_allow: native_posix native_posix_64
+ derivers.pinctrl.api_reg:
+ tags: drivers pinctrl
+ platform_allow: native_posix native_posix_64
+ extra_args: CONF_FILE="prj.conf;reg.conf"
diff --git a/tests/drivers/pinctrl/common/test_device.c b/tests/drivers/pinctrl/common/test_device.c
new file mode 100644
index 0000000000000..827e47577519b
--- /dev/null
+++ b/tests/drivers/pinctrl/common/test_device.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2021 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#define DT_DRV_COMPAT vnd_pinctrl_device
+
+#include "test_device.h"
+
+#include
+#include
+
+int test_device_init(const struct device *dev)
+{
+ ARG_UNUSED(dev);
+
+ return 0;
+}
+
+#define PINCTRL_DEVICE_INIT(inst) \
+ PINCTRL_DT_INST_DEFINE(inst) \
+ \
+ DEVICE_DT_INST_DEFINE(inst, test_device_init, NULL, NULL, NULL, \
+ POST_KERNEL, \
+ CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, NULL);
+
+DT_INST_FOREACH_STATUS_OKAY(PINCTRL_DEVICE_INIT)
diff --git a/tests/drivers/pinctrl/common/test_device.h b/tests/drivers/pinctrl/common/test_device.h
new file mode 100644
index 0000000000000..769465ce8c274
--- /dev/null
+++ b/tests/drivers/pinctrl/common/test_device.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2021 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef ZEPHYR_TESTS_DRIVERS_PINCTRL_COMMON_TEST_DEVICE_H_
+#define ZEPHYR_TESTS_DRIVERS_PINCTRL_COMMON_TEST_DEVICE_H_
+
+#include
+
+/** Custom pinctrl state "mystate". */
+#define PINCTRL_STATE_MYSTATE PINCTRL_STATE_PRIV_START
+
+#endif /* ZEPHYR_TESTS_DRIVERS_PINCTRL_COMMON_TEST_DEVICE_H_ */