| /* |
| * Copyright (c) 2023 Silicon Labs |
| * Copyright (c) 2024 Capgemini |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <zephyr/drivers/pinctrl.h> |
| |
| #include <soc_gpio.h> |
| |
| int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintptr_t reg) |
| { |
| USART_TypeDef *base = (USART_TypeDef *)reg; |
| uint8_t loc; |
| #ifdef CONFIG_SOC_FAMILY_SILABS_S1 |
| LEUART_TypeDef *lebase = (LEUART_TypeDef *)reg; |
| #else |
| |
| #if USART_COUNT > 1 |
| int usart_num = USART_NUM(base); |
| #else |
| int usart_num = 0; |
| (void)base; |
| #endif /*USART_COUNT > 1*/ |
| |
| #ifdef CONFIG_SPI_GECKO_EUSART |
| EUSART_TypeDef *ebase = (EUSART_TypeDef *)reg; |
| int eusart_num = EUSART_NUM(ebase); |
| #endif |
| |
| #endif |
| |
| #ifdef CONFIG_I2C_GECKO |
| I2C_TypeDef *i2c_base = (I2C_TypeDef *)reg; |
| #endif |
| |
| #ifdef CONFIG_UART_GECKO |
| struct soc_gpio_pin rxpin = {0, 0, 0, 0}; |
| struct soc_gpio_pin txpin = {0, 0, 0, 0}; |
| #endif /* CONFIG_UART_GECKO */ |
| |
| struct soc_gpio_pin pin_config = {0, 0, 0, 0}; |
| |
| for (uint8_t i = 0U; i < pin_cnt; i++) { |
| pin_config.port = GECKO_GET_PORT(pins[i]); |
| pin_config.pin = GECKO_GET_PIN(pins[i]); |
| loc = GECKO_GET_LOC(pins[i]); |
| |
| switch (GECKO_GET_FUN(pins[i])) { |
| #ifdef CONFIG_UART_GECKO |
| case GECKO_FUN_UART_RX: |
| rxpin.port = GECKO_GET_PORT(pins[i]); |
| rxpin.pin = GECKO_GET_PIN(pins[i]); |
| rxpin.mode = gpioModeInput; |
| rxpin.out = 1; |
| GPIO_PinModeSet(rxpin.port, rxpin.pin, rxpin.mode, |
| rxpin.out); |
| break; |
| |
| case GECKO_FUN_UART_TX: |
| txpin.port = GECKO_GET_PORT(pins[i]); |
| txpin.pin = GECKO_GET_PIN(pins[i]); |
| txpin.mode = gpioModePushPull; |
| txpin.out = 1; |
| GPIO_PinModeSet(txpin.port, txpin.pin, txpin.mode, |
| txpin.out); |
| break; |
| |
| #ifdef CONFIG_SOC_FAMILY_SILABS_S1 |
| case GECKO_FUN_UART_RTS: |
| pin_config.mode = gpioModePushPull; |
| pin_config.out = 1; |
| GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, |
| pin_config.out); |
| break; |
| |
| case GECKO_FUN_UART_CTS: |
| pin_config.mode = gpioModeInput; |
| pin_config.out = 1; |
| GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, |
| pin_config.out); |
| break; |
| |
| case GECKO_FUN_UART_RX_LOC: |
| base->ROUTEPEN |= USART_ROUTEPEN_RXPEN; |
| base->ROUTELOC0 &= ~_USART_ROUTELOC0_RXLOC_MASK; |
| base->ROUTELOC0 |= (loc << _USART_ROUTELOC0_RXLOC_SHIFT); |
| break; |
| |
| case GECKO_FUN_UART_TX_LOC: |
| base->ROUTEPEN |= USART_ROUTEPEN_TXPEN; |
| base->ROUTELOC0 &= ~_USART_ROUTELOC0_TXLOC_MASK; |
| base->ROUTELOC0 |= (loc << _USART_ROUTELOC0_TXLOC_SHIFT); |
| break; |
| |
| case GECKO_FUN_UART_RTS_LOC: |
| base->ROUTEPEN |= USART_ROUTEPEN_RTSPEN; |
| base->ROUTELOC1 &= ~_USART_ROUTELOC1_RTSLOC_MASK; |
| base->ROUTELOC1 |= (loc << _USART_ROUTELOC1_RTSLOC_SHIFT); |
| break; |
| |
| case GECKO_FUN_UART_CTS_LOC: |
| base->ROUTEPEN |= USART_ROUTEPEN_CTSPEN; |
| base->ROUTELOC1 &= ~_USART_ROUTELOC1_CTSLOC_MASK; |
| base->ROUTELOC1 |= (loc << _USART_ROUTELOC1_CTSLOC_SHIFT); |
| break; |
| |
| case GECKO_FUN_LEUART_RX_LOC: |
| lebase->ROUTEPEN |= LEUART_ROUTEPEN_RXPEN; |
| lebase->ROUTELOC0 &= ~_LEUART_ROUTELOC0_RXLOC_MASK; |
| lebase->ROUTELOC0 |= (loc << _LEUART_ROUTELOC0_RXLOC_SHIFT); |
| break; |
| |
| case GECKO_FUN_LEUART_TX_LOC: |
| lebase->ROUTEPEN |= LEUART_ROUTEPEN_TXPEN; |
| lebase->ROUTELOC0 &= ~_LEUART_ROUTELOC0_TXLOC_MASK; |
| lebase->ROUTELOC0 |= (loc << _LEUART_ROUTELOC0_TXLOC_SHIFT); |
| break; |
| #else /* CONFIG_SOC_FAMILY_SILABS_S1 */ |
| case GECKO_FUN_UART_LOC: |
| #ifdef CONFIG_SOC_GECKO_HAS_INDIVIDUAL_PIN_LOCATION |
| /* For SOCs with configurable pin_cfg locations (set in SOC Kconfig) */ |
| base->ROUTEPEN = USART_ROUTEPEN_RXPEN | USART_ROUTEPEN_TXPEN; |
| base->ROUTELOC0 = (loc << _USART_ROUTELOC0_TXLOC_SHIFT) | |
| (loc << _USART_ROUTELOC0_RXLOC_SHIFT); |
| base->ROUTELOC1 = _USART_ROUTELOC1_RESETVALUE; |
| #elif defined(USART_ROUTE_RXPEN) && defined(USART_ROUTE_TXPEN) |
| /* For olders SOCs with only one pin location */ |
| base->ROUTE = USART_ROUTE_RXPEN | USART_ROUTE_TXPEN | (loc << 8); |
| #elif defined(GPIO_USART_ROUTEEN_RXPEN) && defined(GPIO_USART_ROUTEEN_TXPEN) |
| GPIO->USARTROUTE[usart_num].ROUTEEN = |
| GPIO_USART_ROUTEEN_TXPEN | GPIO_USART_ROUTEEN_RXPEN; |
| GPIO->USARTROUTE[usart_num].TXROUTE = |
| (txpin.pin << _GPIO_USART_TXROUTE_PIN_SHIFT) | |
| (txpin.port << _GPIO_USART_TXROUTE_PORT_SHIFT); |
| GPIO->USARTROUTE[usart_num].RXROUTE = |
| (rxpin.pin << _GPIO_USART_RXROUTE_PIN_SHIFT) | |
| (rxpin.port << _GPIO_USART_RXROUTE_PORT_SHIFT); |
| #endif /* CONFIG_SOC_GECKO_HAS_INDIVIDUAL_PIN_LOCATION */ |
| |
| #ifdef UART_GECKO_HW_FLOW_CONTROL |
| /* Configure HW flow control (RTS, CTS) */ |
| if (config->hw_flowcontrol) { |
| GPIO_PinModeSet(config->pin_rts.port, |
| config->pin_rts.pin, |
| config->pin_rts.mode, |
| config->pin_rts.out); |
| GPIO_PinModeSet(config->pin_cts.port, |
| config->pin_cts.pin, |
| config->pin_cts.mode, |
| config->pin_cts.out); |
| #ifdef CONFIG_SOC_GECKO_HAS_INDIVIDUAL_PIN_LOCATION |
| config->base->ROUTEPEN = |
| USART_ROUTEPEN_RXPEN | USART_ROUTEPEN_TXPEN | |
| USART_ROUTEPEN_RTSPEN | USART_ROUTEPEN_CTSPEN; |
| |
| config->base->ROUTELOC1 = |
| (config->loc_rts << _USART_ROUTELOC1_RTSLOC_SHIFT) | |
| (config->loc_cts << _USART_ROUTELOC1_CTSLOC_SHIFT); |
| #elif defined(GPIO_USART_ROUTEEN_RTSPEN) && defined(GPIO_USART_ROUTEEN_CTSPEN) |
| GPIO->USARTROUTE[usart_num].ROUTEEN = |
| GPIO_USART_ROUTEEN_TXPEN | GPIO_USART_ROUTEEN_RXPEN | |
| GPIO_USART_ROUTEPEN_RTSPEN | GPIO_USART_ROUTEPEN_CTSPEN; |
| |
| GPIO->USARTROUTE[usart_num].RTSROUTE = |
| (config->pin_rts.pin << _GPIO_USART_RTSROUTE_PIN_SHIFT) | |
| (config->pin_rts.port << _GPIO_USART_RTSROUTE_PORT_SHIFT); |
| GPIO->USARTROUTE[usart_num].CTSROUTE = |
| (config->pin_cts.pin << _GPIO_USART_CTSROUTE_PIN_SHIFT) | |
| (config->pin_cts.port << _GPIO_USART_CTSROUTE_PORT_SHIFT); |
| #endif /* CONFIG_SOC_GECKO_HAS_INDIVIDUAL_PIN_LOCATION */ |
| } |
| #endif /* UART_GECKO_HW_FLOW_CONTROL */ |
| break; |
| #endif /* CONFIG_SOC_FAMILY_SILABS_S1 */ |
| #endif /* CONFIG_UART_GECKO */ |
| |
| #ifdef CONFIG_SPI_GECKO_EUSART |
| case GECKO_FUN_SPI_SCK: |
| pin_config.mode = gpioModePushPull; |
| pin_config.out = 1; |
| GPIO->EUSARTROUTE[eusart_num].SCLKROUTE = |
| (pin_config.port << _GPIO_EUSART_SCLKROUTE_PORT_SHIFT) | |
| (pin_config.pin << _GPIO_EUSART_SCLKROUTE_PIN_SHIFT); |
| GPIO->EUSARTROUTE[eusart_num].ROUTEEN |= GPIO_EUSART_ROUTEEN_SCLKPEN; |
| GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, |
| pin_config.out); |
| break; |
| |
| case GECKO_FUN_SPI_CSN: |
| pin_config.mode = gpioModePushPull; |
| pin_config.out = 1; |
| GPIO->EUSARTROUTE[eusart_num].CSROUTE = |
| (pin_config.port << _GPIO_EUSART_CSROUTE_PORT_SHIFT) | |
| (pin_config.pin << _GPIO_EUSART_CSROUTE_PIN_SHIFT); |
| GPIO->EUSARTROUTE[eusart_num].ROUTEEN |= GPIO_EUSART_ROUTEEN_CSPEN; |
| GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, |
| pin_config.out); |
| break; |
| |
| case GECKO_FUN_SPI_MOSI: |
| pin_config.mode = gpioModePushPull; |
| pin_config.out = 1; |
| GPIO->EUSARTROUTE[eusart_num].TXROUTE = |
| (pin_config.port << _GPIO_EUSART_TXROUTE_PORT_SHIFT) | |
| (pin_config.pin << _GPIO_EUSART_TXROUTE_PIN_SHIFT); |
| GPIO->EUSARTROUTE[eusart_num].ROUTEEN |= GPIO_EUSART_ROUTEEN_TXPEN; |
| GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, |
| pin_config.out); |
| break; |
| |
| case GECKO_FUN_SPI_MISO: |
| pin_config.mode = gpioModeInput; |
| pin_config.out = 1; |
| GPIO->EUSARTROUTE[eusart_num].RXROUTE = |
| (pin_config.port << _GPIO_EUSART_RXROUTE_PORT_SHIFT) | |
| (pin_config.pin << _GPIO_EUSART_RXROUTE_PIN_SHIFT); |
| GPIO->EUSARTROUTE[EUSART_NUM(EUSART1)].ROUTEEN |= GPIO_EUSART_ROUTEEN_RXPEN; |
| GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, |
| pin_config.out); |
| break; |
| #endif /*CONFIG_SPI_GECKO_EUSART*/ |
| |
| #ifdef CONFIG_SPI_GECKO_USART |
| #ifdef CONFIG_SOC_FAMILY_SILABS_S1 |
| case GECKO_FUN_SPIM_SCK: |
| pin_config.mode = gpioModePushPull; |
| pin_config.out = 1; |
| GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, |
| pin_config.out); |
| break; |
| |
| case GECKO_FUN_SPIM_MOSI: |
| pin_config.mode = gpioModePushPull; |
| pin_config.out = 1; |
| GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, |
| pin_config.out); |
| break; |
| |
| case GECKO_FUN_SPIM_MISO: |
| pin_config.mode = gpioModeInput; |
| pin_config.out = 1; |
| GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, |
| pin_config.out); |
| break; |
| |
| case GECKO_FUN_SPIM_CS: |
| pin_config.mode = gpioModePushPull; |
| pin_config.out = 1; |
| GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, |
| pin_config.out); |
| break; |
| |
| case GECKO_FUN_SPIS_SCK: |
| pin_config.mode = gpioModeInput; |
| pin_config.out = 1; |
| GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, |
| pin_config.out); |
| break; |
| |
| case GECKO_FUN_SPIS_MOSI: |
| pin_config.mode = gpioModeInput; |
| pin_config.out = 1; |
| GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, |
| pin_config.out); |
| break; |
| |
| case GECKO_FUN_SPIS_MISO: |
| pin_config.mode = gpioModePushPull; |
| pin_config.out = 1; |
| GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, |
| pin_config.out); |
| break; |
| |
| case GECKO_FUN_SPIS_CS: |
| pin_config.mode = gpioModeInput; |
| pin_config.out = 1; |
| GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, |
| pin_config.out); |
| break; |
| |
| case GECKO_FUN_SPI_SCK_LOC: |
| base->ROUTEPEN |= USART_ROUTEPEN_CLKPEN; |
| base->ROUTELOC0 &= ~_USART_ROUTELOC0_CLKLOC_MASK; |
| base->ROUTELOC0 |= (loc << _USART_ROUTELOC0_CLKLOC_SHIFT); |
| break; |
| |
| case GECKO_FUN_SPI_MOSI_LOC: |
| base->ROUTEPEN |= USART_ROUTEPEN_TXPEN; |
| base->ROUTELOC0 &= ~_USART_ROUTELOC0_TXLOC_MASK; |
| base->ROUTELOC0 |= (loc << _USART_ROUTELOC0_TXLOC_SHIFT); |
| break; |
| |
| case GECKO_FUN_SPI_MISO_LOC: |
| base->ROUTEPEN |= USART_ROUTEPEN_RXPEN; |
| base->ROUTELOC0 &= ~_USART_ROUTELOC0_RXLOC_MASK; |
| base->ROUTELOC0 |= (loc << _USART_ROUTELOC0_RXLOC_SHIFT); |
| break; |
| |
| case GECKO_FUN_SPI_CS_LOC: |
| base->ROUTEPEN |= USART_ROUTEPEN_CSPEN; |
| base->ROUTELOC0 &= ~_USART_ROUTELOC0_CSLOC_MASK; |
| base->ROUTELOC0 |= (loc << _USART_ROUTELOC0_CSLOC_SHIFT); |
| break; |
| |
| #else /* CONFIG_SOC_FAMILY_SILABS_S1 */ |
| case GECKO_FUN_SPI_SCK: |
| pin_config.mode = gpioModePushPull; |
| pin_config.out = 1; |
| GPIO->USARTROUTE[usart_num].ROUTEEN |= GPIO_USART_ROUTEEN_CLKPEN; |
| GPIO->USARTROUTE[usart_num].CLKROUTE = |
| (pin_config.pin << _GPIO_USART_CLKROUTE_PIN_SHIFT) | |
| (pin_config.port << _GPIO_USART_CLKROUTE_PORT_SHIFT); |
| GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, |
| pin_config.out); |
| break; |
| |
| case GECKO_FUN_SPI_MOSI: |
| pin_config.mode = gpioModePushPull; |
| pin_config.out = 1; |
| GPIO->USARTROUTE[usart_num].ROUTEEN |= GPIO_USART_ROUTEEN_TXPEN; |
| GPIO->USARTROUTE[usart_num].TXROUTE = |
| (pin_config.pin << _GPIO_USART_TXROUTE_PIN_SHIFT) | |
| (pin_config.port << _GPIO_USART_TXROUTE_PORT_SHIFT); |
| GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, |
| pin_config.out); |
| break; |
| |
| case GECKO_FUN_SPI_MISO: |
| pin_config.mode = gpioModeInput; |
| pin_config.out = 1; |
| GPIO->USARTROUTE[usart_num].ROUTEEN |= GPIO_USART_ROUTEEN_RXPEN; |
| GPIO->USARTROUTE[usart_num].RXROUTE = |
| (pin_config.pin << _GPIO_USART_RXROUTE_PIN_SHIFT) | |
| (pin_config.port << _GPIO_USART_RXROUTE_PORT_SHIFT); |
| GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, |
| pin_config.out); |
| break; |
| #endif /* CONFIG_SOC_FAMILY_SILABS_S1 */ |
| #endif /* CONFIG_SPI_GECKO_USART */ |
| |
| #ifdef CONFIG_I2C_GECKO |
| case GECKO_FUN_I2C_SDA: |
| pin_config.mode = gpioModeWiredAnd; |
| pin_config.out = 1; |
| GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, |
| pin_config.out); |
| |
| #if defined(GPIO_I2C_ROUTEEN_SDAPEN) |
| GPIO->I2CROUTE[I2C_NUM(i2c_base)].SDAROUTE = |
| (pin_config.pin << _GPIO_I2C_SDAROUTE_PIN_SHIFT) | |
| (pin_config.port << _GPIO_I2C_SDAROUTE_PORT_SHIFT); |
| GPIO->I2CROUTE[I2C_NUM(i2c_base)].ROUTEEN |= GPIO_I2C_ROUTEEN_SDAPEN; |
| #endif |
| break; |
| |
| case GECKO_FUN_I2C_SCL: |
| pin_config.mode = gpioModeWiredAnd; |
| pin_config.out = 1; |
| GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, |
| pin_config.out); |
| |
| #if defined(GPIO_I2C_ROUTEEN_SCLPEN) |
| GPIO->I2CROUTE[I2C_NUM(i2c_base)].SCLROUTE = |
| (pin_config.pin << _GPIO_I2C_SCLROUTE_PIN_SHIFT) | |
| (pin_config.port << _GPIO_I2C_SCLROUTE_PORT_SHIFT); |
| GPIO->I2CROUTE[I2C_NUM(i2c_base)].ROUTEEN |= GPIO_I2C_ROUTEEN_SCLPEN; |
| #endif |
| break; |
| |
| case GECKO_FUN_I2C_SDA_LOC: |
| #ifdef CONFIG_SOC_GECKO_HAS_INDIVIDUAL_PIN_LOCATION |
| i2c_base->ROUTEPEN |= I2C_ROUTEPEN_SDAPEN; |
| i2c_base->ROUTELOC0 &= ~_I2C_ROUTELOC0_SDALOC_MASK; |
| i2c_base->ROUTELOC0 |= (loc << _I2C_ROUTELOC0_SDALOC_SHIFT); |
| #elif defined(I2C_ROUTE_SDAPEN) |
| i2c_base->ROUTE = I2C_ROUTE_SDAPEN | I2C_ROUTE_SCLPEN | (loc << 8); |
| #endif |
| break; |
| |
| case GECKO_FUN_I2C_SCL_LOC: |
| #ifdef CONFIG_SOC_GECKO_HAS_INDIVIDUAL_PIN_LOCATION |
| i2c_base->ROUTEPEN |= I2C_ROUTEPEN_SCLPEN; |
| i2c_base->ROUTELOC0 &= ~_I2C_ROUTELOC0_SCLLOC_MASK; |
| i2c_base->ROUTELOC0 |= (loc << _I2C_ROUTELOC0_SCLLOC_SHIFT); |
| #elif defined(I2C_ROUTE_SCLPEN) |
| i2c_base->ROUTE = I2C_ROUTE_SDAPEN | I2C_ROUTE_SCLPEN | (loc << 8); |
| #endif |
| break; |
| |
| #endif /* CONFIG_I2C_GECKO */ |
| |
| default: |
| return -ENOTSUP; |
| } |
| } |
| |
| return 0; |
| } |