242 lines
7.8 KiB
C
242 lines
7.8 KiB
C
/*
|
|
* 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))
|
|
|
|
/**
|
|
* @brief Convert a devicetree GPIO phandle+specifier to GPIOTE instance number.
|
|
*
|
|
* Some of nRF SoCs may have more instances of GPIOTE.
|
|
* To handle this, we use the "gpiote-instance" property of the GPIO node.
|
|
*
|
|
* This macro converts a devicetree GPIO phandle array value
|
|
* "<&gpioX pin ...>" to a GPIOTE instance number.
|
|
*
|
|
* Examples:
|
|
*
|
|
* &gpiote0 {
|
|
* instance = <0>;
|
|
* };
|
|
*
|
|
* &gpiote20 {
|
|
* instance = <20>;
|
|
* };
|
|
*
|
|
* &gpio0 {
|
|
* gpiote-instance = <&gpiote0>;
|
|
* }
|
|
*
|
|
* &gpio1 {
|
|
* gpiote-instance = <&gpiote20>;
|
|
* }
|
|
*
|
|
* foo: my-node {
|
|
* tx-gpios = <&gpio0 4 ...>;
|
|
* rx-gpios = <&gpio0 5 ...>, <&gpio1 5 ...>;
|
|
* };
|
|
*
|
|
* NRF_DT_GPIOTE_INST_BY_IDX(DT_NODELABEL(foo), tx_gpios, 0) // = 0
|
|
* NRF_DT_GPIOTE_INST_BY_IDX(DT_NODELABEL(foo), rx_gpios, 1) // = 20
|
|
*/
|
|
#define NRF_DT_GPIOTE_INST_BY_IDX(node_id, prop, idx) \
|
|
DT_PROP(DT_PHANDLE(DT_GPIO_CTLR_BY_IDX(node_id, prop, idx), \
|
|
gpiote_instance), \
|
|
instance)
|
|
|
|
/**
|
|
* @brief Equivalent to NRF_DT_GPIOTE_INST_BY_IDX(node_id, prop, 0)
|
|
*/
|
|
#define NRF_DT_GPIOTE_INST(node_id, prop) \
|
|
NRF_DT_GPIOTE_INST_BY_IDX(node_id, prop, 0)
|
|
|
|
/**
|
|
* 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 */
|
|
|
|
/**
|
|
* Error out the build if CONFIG_PM_DEVICE=y and pinctrl-1 state (sleep) is not
|
|
* defined.
|
|
*
|
|
* @param node_id node identifier
|
|
*/
|
|
#define NRF_DT_CHECK_NODE_HAS_PINCTRL_SLEEP(node_id) \
|
|
BUILD_ASSERT(!IS_ENABLED(CONFIG_PM_DEVICE) || \
|
|
DT_PINCTRL_HAS_NAME(node_id, sleep), \
|
|
DT_NODE_PATH(node_id) " defined without sleep state")
|
|
|
|
#endif /* !_ASMLANGUAGE */
|
|
|
|
#endif
|