blob: 77f28ecb9128f931cf858664aa003abbce4d982d [file] [log] [blame]
/*
* Copyright (c) 2020 Nordic Semiconductor ASA
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file Common soc.h include for Nordic nRF5 SoCs.
*/
#ifndef _ZEPHYR_SOC_ARM_NORDIC_NRF_SOC_NRF_COMMON_H_
#define _ZEPHYR_SOC_ARM_NORDIC_NRF_SOC_NRF_COMMON_H_
#ifndef _ASMLANGUAGE
#include <nrfx.h>
#include <zephyr/devicetree.h>
#include <zephyr/toolchain.h>
/**
* @brief Get a PSEL value out of a foo-gpios or foo-pin devicetree property
*
* Many Nordic bindings have 'foo-pin' properties to specify a pin
* configuration as a PSEL value directly instead of using a 'foo-gpios'
* <&gpioX Y flags> style controller phandle + GPIO specifier.
*
* It would be better to use 'foo-gpios' properties instead. This type
* of property is more in line with the recommended DT encoding for GPIOs.
*
* To allow for a smooth migration from 'foo-pin' to 'foo-gpios', this
* helper macro can be used to get a PSEL value out of the devicetree
* using whichever one of 'foo-gpios' or 'foo-pin' is in the DTS.
*
* Note that you can also use:
*
* - NRF_DT_PSEL_CHECK_*() to check the property configuration at build time
* - NRF_DT_GPIOS_TO_PSEL() if you only have a 'foo-gpios'
*
* @param node_id node identifier
* @param psel_prop lowercase-and-underscores old-style 'foo-pin' property
* @param gpios_prop new-style 'foo-gpios' property
* @param default_val the value returned if neither is set
* @return PSEL register value taken from psel_prop or gpios_prop, whichever
* is present in the DTS. If gpios_prop is present, it is converted
* to a PSEL register value first.
*/
#define NRF_DT_PSEL(node_id, psel_prop, gpios_prop, default_val) \
COND_CODE_1(DT_NODE_HAS_PROP(node_id, psel_prop), \
(DT_PROP(node_id, psel_prop)), \
(COND_CODE_1( \
DT_NODE_HAS_PROP(node_id, gpios_prop), \
(NRF_DT_GPIOS_TO_PSEL(node_id, \
gpios_prop)), \
(default_val))))
/**
* Error out the build if the devicetree node with identifier
* 'node_id' has both a legacy psel-style property and a gpios
* property.
*
* Otherwise, do nothing.
*
* @param node_id node identifier
* @param psel_prop lowercase-and-underscores PSEL style property
* @param psel_prop_name human-readable string name of psel_prop
* @param gpios_prop lowercase-and-underscores foo-gpios style property
* @param gpio_prop_name human-readable string name of gpios_prop
*/
#define NRF_DT_PSEL_CHECK_NOT_BOTH(node_id, psel_prop, psel_prop_name, \
gpios_prop, gpios_prop_name) \
BUILD_ASSERT( \
!(DT_NODE_HAS_PROP(node_id, psel_prop) && \
DT_NODE_HAS_PROP(node_id, gpios_prop)), \
"Devicetree node " DT_NODE_PATH(node_id) \
" has both of the " psel_prop_name \
" and " gpios_prop_name \
" properties set; you must remove one. " \
"Note: you can use /delete-property/ to delete properties.")
/**
* Like NRF_DT_PSEL_CHECK_NOT_BOTH, but instead checks that exactly one
* of the properties is set.
*/
#define NRF_DT_PSEL_CHECK_EXACTLY_ONE(node_id, \
psel_prop, psel_prop_name, \
gpios_prop, gpios_prop_name) \
BUILD_ASSERT( \
(DT_NODE_HAS_PROP(node_id, psel_prop) ^ \
DT_NODE_HAS_PROP(node_id, gpios_prop)), \
"Devicetree node " DT_NODE_PATH(node_id) \
" must have exactly one of the " psel_prop_name \
" and " gpios_prop_name \
" properties set. " \
"Note: you can use /delete-property/ to delete properties.")
/**
* @brief Convert a devicetree GPIO phandle+specifier to PSEL value
*
* Various peripherals in nRF SoCs have pin select registers, which
* usually have PSEL in their names. The low bits of these registers
* generally look like this in the register map description:
*
* Bit number 5 4 3 2 1 0
* ID B A A A A A
*
* ID Field Value Description
* A PIN [0..31] Pin number
* B PORT [0..1] Port number
*
* Examples:
*
* - pin P0.4 has "PSEL value" 4 (B=0 and A=4)
* - pin P1.5 has "PSEL value" 37 (B=1 and A=5)
*
* This macro converts a devicetree GPIO phandle array value
* "<&gpioX pin ...>" to a "PSEL value".
*
* Note: in Nordic SoC devicetrees, "gpio0" means P0, and "gpio1"
* means P1. This is encoded in the "port" property of each GPIO node.
*
* Examples:
*
* foo: my-node {
* tx-gpios = <&gpio0 4 ...>;
* rx-gpios = <&gpio0 5 ...>, <&gpio1 5 ...>;
* };
*
* NRF_DT_GPIOS_TO_PSEL_BY_IDX(DT_NODELABEL(foo), tx_gpios, 0) // 0 + 4 = 4
* NRF_DT_GPIOS_TO_PSEL_BY_IDX(DT_NODELABEL(foo), rx_gpios, 1) // 32 + 5 = 37
*/
#define NRF_DT_GPIOS_TO_PSEL_BY_IDX(node_id, prop, idx) \
((DT_PROP_BY_PHANDLE_IDX(node_id, prop, idx, port) << 5) | \
(DT_GPIO_PIN_BY_IDX(node_id, prop, idx) & 0x1F))
/**
* @brief Equivalent to NRF_DT_GPIOS_TO_PSEL_BY_IDX(node_id, prop, 0)
*/
#define NRF_DT_GPIOS_TO_PSEL(node_id, prop) \
NRF_DT_GPIOS_TO_PSEL_BY_IDX(node_id, prop, 0)
/**
* If the node has the property, expands to
* NRF_DT_GPIOS_TO_PSEL(node_id, prop). The default_value argument is
* not expanded in this case.
*
* Otherwise, expands to default_value.
*/
#define NRF_DT_GPIOS_TO_PSEL_OR(node_id, prop, default_value) \
COND_CODE_1(DT_NODE_HAS_PROP(node_id, prop), \
(NRF_DT_GPIOS_TO_PSEL(node_id, prop)), \
(default_value))
/**
* Error out the build if 'prop' is set on node 'node_id' and
* DT_GPIO_CTLR(node_id, prop) is not an SoC GPIO controller,
* i.e. a node with compatible "nordic,nrf-gpio".
*
* Otherwise, do nothing.
*
* @param node_id node identifier
* @param prop lowercase-and-underscores PSEL style property
* @param prop_name human-readable string name for 'prop'
*/
#define NRF_DT_CHECK_GPIO_CTLR_IS_SOC(node_id, prop, prop_name) \
COND_CODE_1(DT_NODE_HAS_PROP(node_id, prop), \
(BUILD_ASSERT(DT_NODE_HAS_COMPAT( \
DT_GPIO_CTLR(node_id, prop), \
nordic_nrf_gpio), \
"Devicetree node " \
DT_NODE_PATH(node_id) \
" property " prop_name \
" must refer to a GPIO controller " \
"with compatible nordic,nrf-gpio; " \
"got " \
DT_NODE_PATH(DT_GPIO_CTLR(node_id, \
prop)) \
", which does not have this " \
"compatible")), \
(BUILD_ASSERT(1, \
"NRF_DT_CHECK_GPIO_CTLR_IS_SOC: OK")))
/* Note: allow a trailing ";" either way */
/**
* @brief Helper macro for NRF_DT_CHECK_PIN_ASSIGNMENTS
*
* This macro is needed only because the order of parameters taken by
* DT_NODE_HAS_PROP is different than that required for a macro to be
* invoked by FOR_EACH_FIXED_ARG.
*
* @param prop lowercase-and-underscores property name
* @param node_id node identifier
* @return 1 if the node has the property, 0 otherwise.
*/
#define NRF_DT_CHECK_NODE_HAS_PROP(prop, node_id) \
DT_NODE_HAS_PROP(node_id, prop)
/**
* Error out the build if PINCTRL is enabled and:
* - the specified node does not have the required pinctrl properties defined
* (pinctrl-0 always, pinctrl-1 when PM_DEVICE is enabled and the caller
* supports sleep state)
* or
* - it has any of the specified legacy pin properties defined (which would
* be ignored in this case, so presumably the resulting configuration would
* not be as expected)
* or if PINCTRL is not enabled and:
* - the specified node does not have at least one of the specified legacy
* pin properties defined
* or
* - it has any pinctrl states defined (which would be ignored in this case).
*
* @param node_id node identifier
* @param sleep_supported indicates whether the caller supports sleep state
* (so pinctrl-1 should be checked)
* @param ... list of lowercase-and-underscores legacy pin properties to be
* checked
*/
#define NRF_DT_CHECK_PIN_ASSIGNMENTS(node_id, sleep_supported, ...) \
BUILD_ASSERT((IS_ENABLED(CONFIG_PINCTRL) && \
DT_PINCTRL_HAS_IDX(node_id, 0) && \
(DT_PINCTRL_HAS_IDX(node_id, 1) || \
!sleep_supported || \
!IS_ENABLED(CONFIG_PM_DEVICE))) \
|| \
(!IS_ENABLED(CONFIG_PINCTRL) && \
(FOR_EACH_FIXED_ARG(NRF_DT_CHECK_NODE_HAS_PROP, \
(||), node_id, __VA_ARGS__))),\
DT_NODE_PATH(node_id) \
" defined without required pin configuration"); \
BUILD_ASSERT(!IS_ENABLED(CONFIG_PINCTRL) || \
!(FOR_EACH_FIXED_ARG(NRF_DT_CHECK_NODE_HAS_PROP, \
(||), node_id, __VA_ARGS__)), \
DT_NODE_PATH(node_id) " has legacy *-pin properties" \
" defined although PINCTRL is enabled"); \
BUILD_ASSERT(IS_ENABLED(CONFIG_PINCTRL) || \
!DT_NUM_PINCTRL_STATES(node_id), \
DT_NODE_PATH(node_id) " has pinctrl states defined" \
" although PINCTRL is not enabled")
#endif /* !_ASMLANGUAGE */
#endif