From 6f4cf5c73c18098ad352f9b40b7c6330a4b1adbc Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Thu, 7 Mar 2024 15:33:34 -0600 Subject: [PATCH] drivers: pinctrl: Add RW pinctrl driver Add pinctrl driver for NXP RW6XX chip. Signed-off-by: Declan Snyder Co-authored-by: Daniel DeGrasse --- drivers/pinctrl/CMakeLists.txt | 1 + drivers/pinctrl/Kconfig | 1 + drivers/pinctrl/Kconfig.rw | 9 + drivers/pinctrl/pinctrl_rw_iomux.c | 174 ++++++++++++++++++ .../pinctrl/nxp,rw-iomux-pinctrl.yaml | 69 +++++++ 5 files changed, 254 insertions(+) create mode 100644 drivers/pinctrl/Kconfig.rw create mode 100644 drivers/pinctrl/pinctrl_rw_iomux.c create mode 100644 dts/bindings/pinctrl/nxp,rw-iomux-pinctrl.yaml diff --git a/drivers/pinctrl/CMakeLists.txt b/drivers/pinctrl/CMakeLists.txt index 5a292054c08..4eb87c69909 100644 --- a/drivers/pinctrl/CMakeLists.txt +++ b/drivers/pinctrl/CMakeLists.txt @@ -34,6 +34,7 @@ zephyr_library_sources_ifdef(CONFIG_PINCTRL_EMSDP pinctrl_emsdp.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_TI_CC32XX pinctrl_ti_cc32xx.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_NUMAKER pinctrl_numaker.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_QUICKLOGIC_EOS_S3 pinctrl_eos_s3.c) +zephyr_library_sources_ifdef(CONFIG_PINCTRL_RW pinctrl_rw_iomux.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_IMX_SCU pinctrl_imx_scu.c) add_subdirectory(renesas) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 2ef117cabbe..cc2c8800a5d 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -62,6 +62,7 @@ source "drivers/pinctrl/Kconfig.emsdp" source "drivers/pinctrl/Kconfig.ti_cc32xx" source "drivers/pinctrl/Kconfig.numaker" source "drivers/pinctrl/Kconfig.eos_s3" +source "drivers/pinctrl/Kconfig.rw" source "drivers/pinctrl/Kconfig.zynqmp" rsource "renesas/Kconfig" diff --git a/drivers/pinctrl/Kconfig.rw b/drivers/pinctrl/Kconfig.rw new file mode 100644 index 00000000000..77d293f7b58 --- /dev/null +++ b/drivers/pinctrl/Kconfig.rw @@ -0,0 +1,9 @@ +# Copyright 2022 NXP +# SPDX-License-Identifier: Apache-2.0 + +config PINCTRL_RW + bool "Pin controller driver for NXP RW MCUs" + default y + depends on DT_HAS_NXP_RW_IOMUX_PINCTRL_ENABLED + help + Enable pin controller driver for NXP RW61x series MCUs diff --git a/drivers/pinctrl/pinctrl_rw_iomux.c b/drivers/pinctrl/pinctrl_rw_iomux.c new file mode 100644 index 00000000000..b3b586cac05 --- /dev/null +++ b/drivers/pinctrl/pinctrl_rw_iomux.c @@ -0,0 +1,174 @@ +/* + * Copyright 2022 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +static MCI_IO_MUX_Type *mci_iomux = + (MCI_IO_MUX_Type *)DT_REG_ADDR(DT_NODELABEL(pinctrl)); + +static SOCCIU_Type *soc_ctrl = + (SOCCIU_Type *)DT_REG_ADDR(DT_NODELABEL(soc_ctrl)); +static AON_SOC_CIU_Type *aon_soc_ciu = + (AON_SOC_CIU_Type *)DT_REG_ADDR(DT_NODELABEL(aon_soc_ctrl)); + +/* + * GPIO mux option definitions. Stored as a static array, because + * these mux options are needed to clear pin mux settings to + * a known good state before selecting a new alternate function. + */ +static uint64_t gpio_muxes[] = {IOMUX_GPIO_OPS}; + +/* + * Helper function to handle setting pin properties, + * such as pin bias and slew rate + */ +static void configure_pin_props(uint32_t pin_mux, uint8_t gpio_idx) +{ + uint32_t mask, set; + volatile uint32_t *pull_reg = &soc_ctrl->PAD_PU_PD_EN0; + volatile uint32_t *slew_reg = &soc_ctrl->SR_CONFIG0; + volatile uint32_t *sleep_force_en = &soc_ctrl->PAD_SLP_EN0; + volatile uint32_t *sleep_force_val = &soc_ctrl->PAD_SLP_VAL0; + + /* GPIO 22-27 use always on configuration registers */ + if (gpio_idx > 21 && gpio_idx < 28) { + pull_reg = (&aon_soc_ciu->PAD_PU_PD_EN1 - 1); + slew_reg = (&aon_soc_ciu->SR_CONFIG1 - 1); + sleep_force_en = &aon_soc_ciu->PAD_SLP_EN0; + sleep_force_val = &aon_soc_ciu->PAD_SLP_VAL0; + } + /* Calculate register offset for pull and slew regs. + * Use bit shifting as opposed to division + */ + pull_reg += (gpio_idx >> 4); + slew_reg += (gpio_idx >> 4); + sleep_force_en += (gpio_idx >> 5); + sleep_force_val += (gpio_idx >> 5); + /* Set pull-up/pull-down */ + /* Use mask and bitshift here as opposed to modulo and multiplication. + * equivalent to ((gpio_idx % 16) * 2) + */ + mask = 0x3 << ((gpio_idx & 0xF) << 1); + set = IOMUX_PAD_GET_PULL(pin_mux) << ((gpio_idx & 0xF) << 1); + *pull_reg = (*pull_reg & ~mask) | set; + + /* Set slew rate */ + set = IOMUX_PAD_GET_SLEW(pin_mux) << ((gpio_idx & 0xF) << 1); + *slew_reg = (*slew_reg & ~mask) | set; + + /* Set sleep force enable bit */ + mask = (0x1 << (gpio_idx & 0x1F)); + set = (IOMUX_PAD_GET_SLEEP_FORCE_EN(pin_mux) << (gpio_idx & 0x1F)); + *sleep_force_en = (*sleep_force_en & ~mask) | set; + set = (IOMUX_PAD_GET_SLEEP_FORCE_VAL(pin_mux) << (gpio_idx & 0x1F)); + *sleep_force_val = (*sleep_force_val & ~mask) | set; +} + +static void select_gpio_mode(uint8_t gpio_idx) +{ + uint64_t gpio_setting = gpio_muxes[gpio_idx]; + volatile uint32_t *flexcomm_reg = &mci_iomux->FC0; + + /* Clear flexcomm settings */ + flexcomm_reg += IOMUX_GET_FLEXCOMM_CLR_IDX(gpio_setting); + *flexcomm_reg &= ~IOMUX_GET_FLEXCOMM_CLR_MASK(gpio_setting); + /* Clear fsel settings */ + mci_iomux->FSEL &= ~IOMUX_GET_FSEL_CLR_MASK(gpio_setting); + /* Clear CTimer in/out, if required */ + if (IOMUX_GET_SCTIMER_IN_CLR_ENABLE(gpio_setting)) { + mci_iomux->C_TIMER_IN &= + ~(0x1 << IOMUX_GET_CTIMER_CLR_OFFSET(gpio_setting)); + mci_iomux->C_TIMER_OUT &= + ~(0x1 << IOMUX_GET_CTIMER_CLR_OFFSET(gpio_setting)); + } + /* Clear SCTimer in/out, if required */ + if (IOMUX_GET_SCTIMER_IN_CLR_ENABLE(gpio_setting)) { + mci_iomux->SC_TIMER &= + ~(0x1 << IOMUX_GET_SCTIMER_IN_CLR_OFFSET(gpio_setting)); + } + if (IOMUX_GET_SCTIMER_OUT_CLR_ENABLE(gpio_setting)) { + mci_iomux->SC_TIMER &= + ~(0x1 << (IOMUX_GET_SCTIMER_OUT_CLR_OFFSET(gpio_setting) + 16)); + } + /* Clear security gpio enable */ + mci_iomux->S_GPIO &= ~(0x1 << (gpio_idx - 32)); +} + + +int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, + uintptr_t reg) +{ + volatile uint32_t *flexcomm_reg; + volatile uint32_t *iomux_en_reg; + + for (uint8_t i = 0; i < pin_cnt; i++) { + flexcomm_reg = &mci_iomux->FC0; + iomux_en_reg = &soc_ctrl->MCI_IOMUX_EN0; + uint32_t pin_mux = pins[i]; + uint8_t gpio_idx = IOMUX_GET_GPIO_IDX(pin_mux); + uint8_t type = IOMUX_GET_TYPE(pin_mux); + /* + * Before selecting an alternate function, we must clear any + * conflicting pin configuration. We do this by resetting the + * pin to a gpio configuration, then selecting the alternate + * function. + */ + select_gpio_mode(gpio_idx); + switch (type) { + case IOMUX_FLEXCOMM: + flexcomm_reg += IOMUX_GET_FLEXCOMM_IDX(pin_mux); + *flexcomm_reg |= + (0x1 << IOMUX_GET_FLEXCOMM_BIT(pin_mux)); + break; + case IOMUX_FSEL: + mci_iomux->FSEL |= + (0x1 << IOMUX_GET_FSEL_BIT(pin_mux)); + break; + case IOMUX_CTIMER_IN: + mci_iomux->C_TIMER_IN |= + (0x1 << IOMUX_GET_CTIMER_BIT(pin_mux)); + break; + case IOMUX_CTIMER_OUT: + mci_iomux->C_TIMER_OUT |= + (0x1 << IOMUX_GET_CTIMER_BIT(pin_mux)); + break; + case IOMUX_SCTIMER_IN: + mci_iomux->SC_TIMER |= + (0x1 << IOMUX_GET_SCTIMER_BIT(pin_mux)); + break; + case IOMUX_SCTIMER_OUT: + mci_iomux->SC_TIMER |= + (0x1 << (IOMUX_GET_SCTIMER_BIT(pin_mux) + 16)); + break; + case IOMUX_SGPIO: + mci_iomux->S_GPIO |= (0x1 << (gpio_idx - 32)); + break; + case IOMUX_GPIO: + if (gpio_idx > 32) { + mci_iomux->GPIO_GRP1 |= (0x1 << (gpio_idx - 32)); + } else { + mci_iomux->GPIO_GRP0 |= (0x1 << gpio_idx); + } + break; + case IOMUX_AON: + /* No selection bits should be set */ + break; + default: + /* Unsupported type passed */ + return -ENOTSUP; + } + configure_pin_props(pin_mux, gpio_idx); + /* Now, enable pin controller access to this pin */ + if (gpio_idx > 21 && gpio_idx < 28) { + /* GPIO 22-27 use always on soc controller */ + iomux_en_reg = &aon_soc_ciu->MCI_IOMUX_EN0; + } + iomux_en_reg += (gpio_idx >> 5); + *iomux_en_reg |= (0x1 << (gpio_idx & 0x1F)); + } + return 0; +} diff --git a/dts/bindings/pinctrl/nxp,rw-iomux-pinctrl.yaml b/dts/bindings/pinctrl/nxp,rw-iomux-pinctrl.yaml new file mode 100644 index 00000000000..3264c405040 --- /dev/null +++ b/dts/bindings/pinctrl/nxp,rw-iomux-pinctrl.yaml @@ -0,0 +1,69 @@ +# Copyright 2022, NXP +# SPDX-License-Identifier: Apache-2.0 + +description: | + RW61x pin control node. This node defines pin configurations in pin + groups, and has the 'pinctrl' node identifier in the SOC's devicetree. Each + group within the pin configuration defines a peripheral's pin configuration. + Each numbered subgroup represents pins with shared configuration for that + peripheral. The 'pinmux' property of each group selects the pins to be + configured with these properties. For example, here is a configuration + for FLEXCOMM0 pins: + + pinmux_flexcomm0_usart: pinmux_flexcomm0_usart { + group0 { + pinmux = , + ; + slew-rate = "normal"; + }; + }; + + If only the required properties are supplied, the pin will be configured + as normal drive strength and no pull. This corresponds to the following + pin settings: + PAD_PU_PD_ENx = (0x0 << pin_index) + SR_CONFIGx = (0x2 << pin_index) + + Note + + Note the inherited pinctrl properties defined below have the following effects: + bias-pull-up: PAD_PU_PD_ENx= (0x1 << pin_index) + bias-pull-down: PAD_PU_PD_ENx= (0x10 << pin_index) + +compatible: "nxp,rw-iomux-pinctrl" + +include: + - name: base.yaml + +child-binding: + description: iMX RW IOMUX pin controller pin group + child-binding: + description: | + iMX RW IOMUX pin controller pin configuration node + include: + - name: pincfg-node.yaml + property-allowlist: + - bias-pull-up + - bias-pull-down + properties: + pinmux: + required: true + type: array + description: | + Pin mux selection for this group. See the SOC level pinctrl header + file in NXP's HAL for a defined list of these options. + slew-rate: + required: true + type: string + enum: + - "slow" + - "normal" + - "fast" + - "ultra" + description: | + Pin output slew rate. Sets the GPIOxx_SR field in the SR_CONFIGx + register. + 0 - slow slew rate + 1 - normal slew rate + 2 - fast slew rate + 3 - fastest slew rate (ultra)