e977a8d623
For certain peripheral signal lines in nRF54H20, it is required to set the clockpin bitfield for pins assigned to them, otherwise the peripheral may not work properly, for example, there will be no output from UART. Signed-off-by: Andrzej Głąbek <andrzej.glabek@nordicsemi.no>
390 lines
11 KiB
C
390 lines
11 KiB
C
/*
|
|
* Copyright (c) 2021 Nordic Semiconductor ASA
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr/drivers/pinctrl.h>
|
|
|
|
#include <hal/nrf_gpio.h>
|
|
|
|
BUILD_ASSERT(((NRF_PULL_NONE == NRF_GPIO_PIN_NOPULL) &&
|
|
(NRF_PULL_DOWN == NRF_GPIO_PIN_PULLDOWN) &&
|
|
(NRF_PULL_UP == NRF_GPIO_PIN_PULLUP)),
|
|
"nRF pinctrl pull settings do not match HAL values");
|
|
|
|
#if defined(GPIO_PIN_CNF_DRIVE_E0E1) || defined(GPIO_PIN_CNF_DRIVE0_E0)
|
|
#define NRF_DRIVE_COUNT (NRF_DRIVE_E0E1 + 1)
|
|
#else
|
|
#define NRF_DRIVE_COUNT (NRF_DRIVE_H0D1 + 1)
|
|
#endif
|
|
static const nrf_gpio_pin_drive_t drive_modes[NRF_DRIVE_COUNT] = {
|
|
[NRF_DRIVE_S0S1] = NRF_GPIO_PIN_S0S1,
|
|
[NRF_DRIVE_H0S1] = NRF_GPIO_PIN_H0S1,
|
|
[NRF_DRIVE_S0H1] = NRF_GPIO_PIN_S0H1,
|
|
[NRF_DRIVE_H0H1] = NRF_GPIO_PIN_H0H1,
|
|
[NRF_DRIVE_D0S1] = NRF_GPIO_PIN_D0S1,
|
|
[NRF_DRIVE_D0H1] = NRF_GPIO_PIN_D0H1,
|
|
[NRF_DRIVE_S0D1] = NRF_GPIO_PIN_S0D1,
|
|
[NRF_DRIVE_H0D1] = NRF_GPIO_PIN_H0D1,
|
|
#if defined(GPIO_PIN_CNF_DRIVE_E0E1) || defined(GPIO_PIN_CNF_DRIVE0_E0)
|
|
[NRF_DRIVE_E0E1] = NRF_GPIO_PIN_E0E1,
|
|
#endif
|
|
};
|
|
|
|
/* value to indicate pin level doesn't need initialization */
|
|
#define NO_WRITE UINT32_MAX
|
|
|
|
#define PSEL_DISCONNECTED 0xFFFFFFFFUL
|
|
|
|
#if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_uart)
|
|
#define NRF_PSEL_UART(reg, line) ((NRF_UART_Type *)reg)->PSEL##line
|
|
#elif DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_uarte)
|
|
#include <hal/nrf_uarte.h>
|
|
#define NRF_PSEL_UART(reg, line) ((NRF_UARTE_Type *)reg)->PSEL.line
|
|
#endif
|
|
|
|
#if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_spi)
|
|
#define NRF_PSEL_SPIM(reg, line) ((NRF_SPI_Type *)reg)->PSEL##line
|
|
#elif DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_spim)
|
|
#include <hal/nrf_spim.h>
|
|
#define NRF_PSEL_SPIM(reg, line) ((NRF_SPIM_Type *)reg)->PSEL.line
|
|
#endif
|
|
|
|
#if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_spis)
|
|
#include <hal/nrf_spis.h>
|
|
#if defined(NRF51)
|
|
#define NRF_PSEL_SPIS(reg, line) ((NRF_SPIS_Type *)reg)->PSEL##line
|
|
#else
|
|
#define NRF_PSEL_SPIS(reg, line) ((NRF_SPIS_Type *)reg)->PSEL.line
|
|
#endif
|
|
#endif /* DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_spis) */
|
|
|
|
#if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_twi)
|
|
#if !defined(TWI_PSEL_SCL_CONNECT_Pos)
|
|
#define NRF_PSEL_TWIM(reg, line) ((NRF_TWI_Type *)reg)->PSEL##line
|
|
#else
|
|
#define NRF_PSEL_TWIM(reg, line) ((NRF_TWI_Type *)reg)->PSEL.line
|
|
#endif
|
|
#elif DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_twim)
|
|
#include <hal/nrf_twim.h>
|
|
#define NRF_PSEL_TWIM(reg, line) ((NRF_TWIM_Type *)reg)->PSEL.line
|
|
#endif
|
|
|
|
#if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_i2s)
|
|
#define NRF_PSEL_I2S(reg, line) ((NRF_I2S_Type *)reg)->PSEL.line
|
|
#endif
|
|
|
|
#if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_pdm)
|
|
#define NRF_PSEL_PDM(reg, line) ((NRF_PDM_Type *)reg)->PSEL.line
|
|
#endif
|
|
|
|
#if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_pwm)
|
|
#define NRF_PSEL_PWM(reg, line) ((NRF_PWM_Type *)reg)->PSEL.line
|
|
#endif
|
|
|
|
#if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_qdec)
|
|
#define NRF_PSEL_QDEC(reg, line) ((NRF_QDEC_Type *)reg)->PSEL.line
|
|
#endif
|
|
|
|
#if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_qspi)
|
|
#define NRF_PSEL_QSPI(reg, line) ((NRF_QSPI_Type *)reg)->PSEL.line
|
|
#endif
|
|
|
|
int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt,
|
|
uintptr_t reg)
|
|
{
|
|
for (uint8_t i = 0U; i < pin_cnt; i++) {
|
|
nrf_gpio_pin_drive_t drive;
|
|
uint8_t drive_idx = NRF_GET_DRIVE(pins[i]);
|
|
uint32_t psel = NRF_GET_PIN(pins[i]);
|
|
uint32_t write = NO_WRITE;
|
|
nrf_gpio_pin_dir_t dir;
|
|
nrf_gpio_pin_input_t input;
|
|
#if NRF_GPIO_HAS_CLOCKPIN
|
|
bool clockpin = false;
|
|
#endif
|
|
|
|
if (drive_idx < ARRAY_SIZE(drive_modes)) {
|
|
drive = drive_modes[drive_idx];
|
|
} else {
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (psel == NRF_PIN_DISCONNECTED) {
|
|
psel = PSEL_DISCONNECTED;
|
|
}
|
|
|
|
switch (NRF_GET_FUN(pins[i])) {
|
|
#if defined(NRF_PSEL_UART)
|
|
case NRF_FUN_UART_TX:
|
|
NRF_PSEL_UART(reg, TXD) = psel;
|
|
write = 1U;
|
|
dir = NRF_GPIO_PIN_DIR_OUTPUT;
|
|
input = NRF_GPIO_PIN_INPUT_DISCONNECT;
|
|
#if NRF_GPIO_HAS_CLOCKPIN && defined(NRF_UARTE_CLOCKPIN_TXD_NEEDED)
|
|
clockpin = true;
|
|
#endif
|
|
break;
|
|
case NRF_FUN_UART_RX:
|
|
NRF_PSEL_UART(reg, RXD) = psel;
|
|
dir = NRF_GPIO_PIN_DIR_INPUT;
|
|
input = NRF_GPIO_PIN_INPUT_CONNECT;
|
|
break;
|
|
case NRF_FUN_UART_RTS:
|
|
NRF_PSEL_UART(reg, RTS) = psel;
|
|
write = 1U;
|
|
dir = NRF_GPIO_PIN_DIR_OUTPUT;
|
|
input = NRF_GPIO_PIN_INPUT_DISCONNECT;
|
|
#if NRF_GPIO_HAS_CLOCKPIN && defined(NRF_UARTE_CLOCKPIN_RTS_NEEDED)
|
|
clockpin = true;
|
|
#endif
|
|
break;
|
|
case NRF_FUN_UART_CTS:
|
|
NRF_PSEL_UART(reg, CTS) = psel;
|
|
dir = NRF_GPIO_PIN_DIR_INPUT;
|
|
input = NRF_GPIO_PIN_INPUT_CONNECT;
|
|
break;
|
|
#endif /* defined(NRF_PSEL_UART) */
|
|
#if defined(NRF_PSEL_SPIM)
|
|
case NRF_FUN_SPIM_SCK:
|
|
NRF_PSEL_SPIM(reg, SCK) = psel;
|
|
write = 0U;
|
|
dir = NRF_GPIO_PIN_DIR_OUTPUT;
|
|
input = NRF_GPIO_PIN_INPUT_CONNECT;
|
|
#if NRF_GPIO_HAS_CLOCKPIN && defined(NRF_SPIM_CLOCKPIN_SCK_NEEDED)
|
|
clockpin = true;
|
|
#endif
|
|
break;
|
|
case NRF_FUN_SPIM_MOSI:
|
|
NRF_PSEL_SPIM(reg, MOSI) = psel;
|
|
write = 0U;
|
|
dir = NRF_GPIO_PIN_DIR_OUTPUT;
|
|
input = NRF_GPIO_PIN_INPUT_DISCONNECT;
|
|
#if NRF_GPIO_HAS_CLOCKPIN && defined(NRF_SPIM_CLOCKPIN_MOSI_NEEDED)
|
|
clockpin = true;
|
|
#endif
|
|
break;
|
|
case NRF_FUN_SPIM_MISO:
|
|
NRF_PSEL_SPIM(reg, MISO) = psel;
|
|
dir = NRF_GPIO_PIN_DIR_INPUT;
|
|
input = NRF_GPIO_PIN_INPUT_CONNECT;
|
|
break;
|
|
#endif /* defined(NRF_PSEL_SPIM) */
|
|
#if defined(NRF_PSEL_SPIS)
|
|
case NRF_FUN_SPIS_SCK:
|
|
NRF_PSEL_SPIS(reg, SCK) = psel;
|
|
dir = NRF_GPIO_PIN_DIR_INPUT;
|
|
input = NRF_GPIO_PIN_INPUT_CONNECT;
|
|
#if NRF_GPIO_HAS_CLOCKPIN && defined(NRF_SPIS_CLOCKPIN_SCK_NEEDED)
|
|
clockpin = true;
|
|
#endif
|
|
break;
|
|
case NRF_FUN_SPIS_MOSI:
|
|
NRF_PSEL_SPIS(reg, MOSI) = psel;
|
|
dir = NRF_GPIO_PIN_DIR_INPUT;
|
|
input = NRF_GPIO_PIN_INPUT_CONNECT;
|
|
break;
|
|
case NRF_FUN_SPIS_MISO:
|
|
NRF_PSEL_SPIS(reg, MISO) = psel;
|
|
dir = NRF_GPIO_PIN_DIR_INPUT;
|
|
input = NRF_GPIO_PIN_INPUT_DISCONNECT;
|
|
#if NRF_GPIO_HAS_CLOCKPIN && defined(NRF_SPIS_CLOCKPIN_MISO_NEEDED)
|
|
clockpin = true;
|
|
#endif
|
|
break;
|
|
case NRF_FUN_SPIS_CSN:
|
|
NRF_PSEL_SPIS(reg, CSN) = psel;
|
|
dir = NRF_GPIO_PIN_DIR_INPUT;
|
|
input = NRF_GPIO_PIN_INPUT_CONNECT;
|
|
break;
|
|
#endif /* defined(NRF_PSEL_SPIS) */
|
|
#if defined(NRF_PSEL_TWIM)
|
|
case NRF_FUN_TWIM_SCL:
|
|
NRF_PSEL_TWIM(reg, SCL) = psel;
|
|
if (drive == NRF_GPIO_PIN_S0S1) {
|
|
/* Override the default drive setting with one
|
|
* suitable for TWI/TWIM peripherals (S0D1).
|
|
* This drive cannot be used always so that
|
|
* users are able to select e.g. H0D1 or E0E1
|
|
* in devicetree.
|
|
*/
|
|
drive = NRF_GPIO_PIN_S0D1;
|
|
}
|
|
dir = NRF_GPIO_PIN_DIR_INPUT;
|
|
input = NRF_GPIO_PIN_INPUT_CONNECT;
|
|
#if NRF_GPIO_HAS_CLOCKPIN && defined(NRF_TWIM_CLOCKPIN_SCL_NEEDED)
|
|
clockpin = true;
|
|
#endif
|
|
break;
|
|
case NRF_FUN_TWIM_SDA:
|
|
NRF_PSEL_TWIM(reg, SDA) = psel;
|
|
if (drive == NRF_GPIO_PIN_S0S1) {
|
|
drive = NRF_GPIO_PIN_S0D1;
|
|
}
|
|
dir = NRF_GPIO_PIN_DIR_INPUT;
|
|
input = NRF_GPIO_PIN_INPUT_CONNECT;
|
|
#if NRF_GPIO_HAS_CLOCKPIN && defined(NRF_TWIM_CLOCKPIN_SDA_NEEDED)
|
|
clockpin = true;
|
|
#endif
|
|
break;
|
|
#endif /* defined(NRF_PSEL_TWIM) */
|
|
#if defined(NRF_PSEL_I2S)
|
|
case NRF_FUN_I2S_SCK_M:
|
|
NRF_PSEL_I2S(reg, SCK) = psel;
|
|
write = 0U;
|
|
dir = NRF_GPIO_PIN_DIR_OUTPUT;
|
|
input = NRF_GPIO_PIN_INPUT_DISCONNECT;
|
|
break;
|
|
case NRF_FUN_I2S_SCK_S:
|
|
NRF_PSEL_I2S(reg, SCK) = psel;
|
|
dir = NRF_GPIO_PIN_DIR_INPUT;
|
|
input = NRF_GPIO_PIN_INPUT_CONNECT;
|
|
break;
|
|
case NRF_FUN_I2S_LRCK_M:
|
|
NRF_PSEL_I2S(reg, LRCK) = psel;
|
|
write = 0U;
|
|
dir = NRF_GPIO_PIN_DIR_OUTPUT;
|
|
input = NRF_GPIO_PIN_INPUT_DISCONNECT;
|
|
break;
|
|
case NRF_FUN_I2S_LRCK_S:
|
|
NRF_PSEL_I2S(reg, LRCK) = psel;
|
|
dir = NRF_GPIO_PIN_DIR_INPUT;
|
|
input = NRF_GPIO_PIN_INPUT_CONNECT;
|
|
break;
|
|
case NRF_FUN_I2S_SDIN:
|
|
NRF_PSEL_I2S(reg, SDIN) = psel;
|
|
dir = NRF_GPIO_PIN_DIR_INPUT;
|
|
input = NRF_GPIO_PIN_INPUT_CONNECT;
|
|
break;
|
|
case NRF_FUN_I2S_SDOUT:
|
|
NRF_PSEL_I2S(reg, SDOUT) = psel;
|
|
write = 0U;
|
|
dir = NRF_GPIO_PIN_DIR_OUTPUT;
|
|
input = NRF_GPIO_PIN_INPUT_DISCONNECT;
|
|
break;
|
|
case NRF_FUN_I2S_MCK:
|
|
NRF_PSEL_I2S(reg, MCK) = psel;
|
|
write = 0U;
|
|
dir = NRF_GPIO_PIN_DIR_OUTPUT;
|
|
input = NRF_GPIO_PIN_INPUT_DISCONNECT;
|
|
break;
|
|
#endif /* defined(NRF_PSEL_I2S) */
|
|
#if defined(NRF_PSEL_PDM)
|
|
case NRF_FUN_PDM_CLK:
|
|
NRF_PSEL_PDM(reg, CLK) = psel;
|
|
write = 0U;
|
|
dir = NRF_GPIO_PIN_DIR_OUTPUT;
|
|
input = NRF_GPIO_PIN_INPUT_DISCONNECT;
|
|
break;
|
|
case NRF_FUN_PDM_DIN:
|
|
NRF_PSEL_PDM(reg, DIN) = psel;
|
|
dir = NRF_GPIO_PIN_DIR_INPUT;
|
|
input = NRF_GPIO_PIN_INPUT_CONNECT;
|
|
break;
|
|
#endif /* defined(NRF_PSEL_PDM) */
|
|
#if defined(NRF_PSEL_PWM)
|
|
case NRF_FUN_PWM_OUT0:
|
|
NRF_PSEL_PWM(reg, OUT[0]) = psel;
|
|
write = NRF_GET_INVERT(pins[i]);
|
|
dir = NRF_GPIO_PIN_DIR_OUTPUT;
|
|
input = NRF_GPIO_PIN_INPUT_DISCONNECT;
|
|
break;
|
|
case NRF_FUN_PWM_OUT1:
|
|
NRF_PSEL_PWM(reg, OUT[1]) = psel;
|
|
write = NRF_GET_INVERT(pins[i]);
|
|
dir = NRF_GPIO_PIN_DIR_OUTPUT;
|
|
input = NRF_GPIO_PIN_INPUT_DISCONNECT;
|
|
break;
|
|
case NRF_FUN_PWM_OUT2:
|
|
NRF_PSEL_PWM(reg, OUT[2]) = psel;
|
|
write = NRF_GET_INVERT(pins[i]);
|
|
dir = NRF_GPIO_PIN_DIR_OUTPUT;
|
|
input = NRF_GPIO_PIN_INPUT_DISCONNECT;
|
|
break;
|
|
case NRF_FUN_PWM_OUT3:
|
|
NRF_PSEL_PWM(reg, OUT[3]) = psel;
|
|
write = NRF_GET_INVERT(pins[i]);
|
|
dir = NRF_GPIO_PIN_DIR_OUTPUT;
|
|
input = NRF_GPIO_PIN_INPUT_DISCONNECT;
|
|
break;
|
|
#endif /* defined(NRF_PSEL_PWM) */
|
|
#if defined(NRF_PSEL_QDEC)
|
|
case NRF_FUN_QDEC_A:
|
|
NRF_PSEL_QDEC(reg, A) = psel;
|
|
dir = NRF_GPIO_PIN_DIR_INPUT;
|
|
input = NRF_GPIO_PIN_INPUT_CONNECT;
|
|
break;
|
|
case NRF_FUN_QDEC_B:
|
|
NRF_PSEL_QDEC(reg, B) = psel;
|
|
dir = NRF_GPIO_PIN_DIR_INPUT;
|
|
input = NRF_GPIO_PIN_INPUT_CONNECT;
|
|
break;
|
|
case NRF_FUN_QDEC_LED:
|
|
NRF_PSEL_QDEC(reg, LED) = psel;
|
|
dir = NRF_GPIO_PIN_DIR_INPUT;
|
|
input = NRF_GPIO_PIN_INPUT_CONNECT;
|
|
break;
|
|
#endif /* defined(NRF_PSEL_QDEC) */
|
|
#if defined(NRF_PSEL_QSPI)
|
|
case NRF_FUN_QSPI_SCK:
|
|
NRF_PSEL_QSPI(reg, SCK) = psel;
|
|
dir = NRF_GPIO_PIN_DIR_INPUT;
|
|
input = NRF_GPIO_PIN_INPUT_DISCONNECT;
|
|
break;
|
|
case NRF_FUN_QSPI_CSN:
|
|
NRF_PSEL_QSPI(reg, CSN) = psel;
|
|
write = 1U;
|
|
dir = NRF_GPIO_PIN_DIR_OUTPUT;
|
|
input = NRF_GPIO_PIN_INPUT_DISCONNECT;
|
|
break;
|
|
case NRF_FUN_QSPI_IO0:
|
|
NRF_PSEL_QSPI(reg, IO0) = psel;
|
|
dir = NRF_GPIO_PIN_DIR_INPUT;
|
|
input = NRF_GPIO_PIN_INPUT_DISCONNECT;
|
|
break;
|
|
case NRF_FUN_QSPI_IO1:
|
|
NRF_PSEL_QSPI(reg, IO1) = psel;
|
|
dir = NRF_GPIO_PIN_DIR_INPUT;
|
|
input = NRF_GPIO_PIN_INPUT_DISCONNECT;
|
|
break;
|
|
case NRF_FUN_QSPI_IO2:
|
|
NRF_PSEL_QSPI(reg, IO2) = psel;
|
|
dir = NRF_GPIO_PIN_DIR_INPUT;
|
|
input = NRF_GPIO_PIN_INPUT_DISCONNECT;
|
|
break;
|
|
case NRF_FUN_QSPI_IO3:
|
|
NRF_PSEL_QSPI(reg, IO3) = psel;
|
|
dir = NRF_GPIO_PIN_DIR_INPUT;
|
|
input = NRF_GPIO_PIN_INPUT_DISCONNECT;
|
|
break;
|
|
#endif /* defined(NRF_PSEL_QSPI) */
|
|
default:
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
/* configure GPIO properties */
|
|
if (psel != PSEL_DISCONNECTED) {
|
|
uint32_t pin = psel;
|
|
|
|
if (write != NO_WRITE) {
|
|
nrf_gpio_pin_write(pin, write);
|
|
}
|
|
|
|
/* force input and disconnected buffer for low power */
|
|
if (NRF_GET_LP(pins[i]) == NRF_LP_ENABLE) {
|
|
dir = NRF_GPIO_PIN_DIR_INPUT;
|
|
input = NRF_GPIO_PIN_INPUT_DISCONNECT;
|
|
}
|
|
|
|
nrf_gpio_cfg(pin, dir, input, NRF_GET_PULL(pins[i]),
|
|
drive, NRF_GPIO_PIN_NOSENSE);
|
|
#if NRF_GPIO_HAS_CLOCKPIN
|
|
nrf_gpio_pin_clock_set(pin, clockpin);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|