zephyr/drivers/pinctrl/pinctrl_silabs_dbus.c
Aksel Skauge Mellbye 23c5144f9c drivers: pinctrl: silabs: Fix pin deallocation from digital bus
Fix the scenario where a pinctrl node intends to deallocate a pin
from a peripheral. If the GPIO mode is disabled the DBUS route
should be cleared, not set. This allows reuse of a pin for other
purposes when a driver is suspended and the pinctrl sleep state is
applied, as GPIOs are typically disabled in the sleep state.

Signed-off-by: Aksel Skauge Mellbye <aksel.mellbye@silabs.com>
2025-02-18 18:39:50 +01:00

53 lines
1.4 KiB
C

/*
* Copyright (c) 2024 Silicon Laboratories Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/drivers/pinctrl.h>
#include <zephyr/arch/cpu.h>
#include <em_gpio.h>
#define DT_DRV_COMPAT silabs_dbus_pinctrl
#define PIN_MASK 0xF0000UL
#define ABUS_MASK(i) GENMASK(((i) * 8) + 3, (i) * 8)
int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintptr_t reg)
{
ARG_UNUSED(reg);
for (uint8_t i = 0U; i < pin_cnt; i++) {
mem_addr_t enable_reg, route_reg;
/* Configure ABUS */
if (pins[i].en_bit == SILABS_PINCTRL_ANALOG) {
enable_reg = DT_INST_REG_ADDR_BY_NAME(0, abus) +
(pins[i].base_offset * sizeof(mem_addr_t));
sys_write32(FIELD_PREP(ABUS_MASK(pins[i].mode), pins[i].route_offset),
enable_reg);
continue;
}
/* Configure GPIO */
GPIO_PinModeSet(pins[i].port, pins[i].pin, pins[i].mode, pins[i].dout);
/* Configure DBUS */
enable_reg = DT_INST_REG_ADDR_BY_NAME(0, dbus) +
(pins[i].base_offset * sizeof(mem_addr_t));
route_reg = enable_reg + (pins[i].route_offset * sizeof(mem_addr_t));
sys_write32(pins[i].port | FIELD_PREP(PIN_MASK, pins[i].pin), route_reg);
if (pins[i].en_bit != SILABS_PINCTRL_UNUSED) {
if (pins[i].mode == gpioModeDisabled) {
sys_clear_bit(enable_reg, pins[i].en_bit);
} else {
sys_set_bit(enable_reg, pins[i].en_bit);
}
}
}
return 0;
}