drivers: pinctrl: initial skeleton

Initial skeleton for pinctrl drivers. This patch includes common
infrastructure and API definitions for pinctrl drivers.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
This commit is contained in:
Gerard Marull-Paretas 2021-08-10 11:17:46 +02:00 committed by Kumar Gala
commit 4040df096f
7 changed files with 427 additions and 0 deletions

View file

@ -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)

View file

@ -123,4 +123,6 @@ source "drivers/bbram/Kconfig"
source "drivers/fpga/Kconfig"
source "drivers/pinctrl/Kconfig"
endmenu

View file

@ -0,0 +1,5 @@
# Copyright (c) 2021 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0
zephyr_library()
zephyr_library_sources(common.c)

24
drivers/pinctrl/Kconfig Normal file
View file

@ -0,0 +1,24 @@
# 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.
endif # PINCTRL

22
drivers/pinctrl/common.c Normal file
View file

@ -0,0 +1,22 @@
/*
* Copyright (c) 2021 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <drivers/pinctrl.h>
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;
}

View file

@ -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.

330
include/drivers/pinctrl.h Normal file
View file

@ -0,0 +1,330 @@
/*
* 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 <device.h>
#include <devicetree.h>
#include <devicetree/pinctrl.h>
#include <pinctrl_soc.h>
#include <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 */
/**
* @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 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) \
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) \
{ \
.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
/** @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 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 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.
*
* @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) \
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);
}
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif /* ZEPHYR_INCLUDE_DRIVERS_PINCTRL_H_ */