| /* |
| * 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 |
| * @since 3.0 |
| * @version 0.1.0 |
| * @ingroup io_interfaces |
| * @{ |
| */ |
| |
| #include <errno.h> |
| |
| #include <zephyr/device.h> |
| #include <zephyr/devicetree.h> |
| #include <zephyr/devicetree/pinctrl.h> |
| #include <pinctrl_soc.h> |
| #include <zephyr/sys/util.h> |
| |
| #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 */ |
| |
| #if !defined(CONFIG_PM) && !defined(CONFIG_PM_DEVICE) |
| /** Out of power management configurations, ignore "sleep" state. */ |
| #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_<STATE> |
| * 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)[] = { \ |
| 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) \ |
| LISTIFY(DT_NUM_PINCTRL_STATES(node_id), \ |
| Z_PINCTRL_STATE_PINS_DEFINE, (;), node_id); \ |
| Z_PINCTRL_STATES_DEFINE(node_id) \ |
| Z_PINCTRL_DEV_CONFIG_STATIC Z_PINCTRL_DEV_CONFIG_CONST \ |
| 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 |
| ARG_UNUSED(config); |
| 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) |
| { |
| ARG_UNUSED(config); |
| ARG_UNUSED(states); |
| ARG_UNUSED(state_cnt); |
| return -ENOSYS; |
| } |
| #endif /* defined(CONFIG_PINCTRL_DYNAMIC) || defined(__DOXYGEN__) */ |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| /** |
| * @} |
| */ |
| |
| #endif /* ZEPHYR_INCLUDE_DRIVERS_PINCTRL_H_ */ |