drivers: pinctrl: add support for dynamic pin control
Add support for dynamic pin control, that is, allow to change device pin configuration at runtime. Because no device de-initialization is available yet, this API has limited usage options, e.g. modify pin configuration at early boot stage (before device driver is initialized) Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
This commit is contained in:
parent
aecb0c74b5
commit
329f2453c5
|
@ -21,4 +21,12 @@ config PINCTRL_NON_STATIC
|
|||
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
|
||||
|
|
|
@ -20,3 +20,36 @@ int pinctrl_lookup_state(const struct pinctrl_dev_config *config, uint8_t id,
|
|||
|
||||
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 */
|
||||
|
|
|
@ -197,22 +197,29 @@ struct pinctrl_dev_config {
|
|||
#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 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.
|
||||
* 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 const struct pinctrl_dev_config \
|
||||
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__) */
|
||||
|
||||
|
@ -231,8 +238,9 @@ struct pinctrl_dev_config {
|
|||
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);
|
||||
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.
|
||||
|
@ -342,6 +350,101 @@ static inline int pinctrl_apply_state(const struct pinctrl_dev_config *config,
|
|||
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
|
||||
|
|
Loading…
Reference in New Issue