diff --git a/drivers/pinctrl/pinctrl_silabs_dbus.c b/drivers/pinctrl/pinctrl_silabs_dbus.c index be918847b16..488c1090162 100644 --- a/drivers/pinctrl/pinctrl_silabs_dbus.c +++ b/drivers/pinctrl/pinctrl_silabs_dbus.c @@ -11,6 +11,7 @@ #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) { @@ -19,16 +20,26 @@ int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintp 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(0) + (pins[i].base_offset * sizeof(mem_addr_t)); + 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 != 0xFFU) { + if (pins[i].en_bit != SILABS_PINCTRL_UNUSED) { sys_set_bit(enable_reg, pins[i].en_bit); } } diff --git a/dts/arm/silabs/efr32bg2x.dtsi b/dts/arm/silabs/efr32bg2x.dtsi index a1fd10e39be..89c841406a1 100644 --- a/dts/arm/silabs/efr32bg2x.dtsi +++ b/dts/arm/silabs/efr32bg2x.dtsi @@ -337,7 +337,8 @@ pinctrl: pin-controller@5003c440 { compatible = "silabs,dbus-pinctrl"; - reg = <0x5003c440 0xbc0>; + reg = <0x5003c440 0xbc0>, <0x5003c320 0x40>; + reg-names = "dbus", "abus"; }; dma0: dma@40040000{ diff --git a/dts/arm/silabs/efr32mg21.dtsi b/dts/arm/silabs/efr32mg21.dtsi index 0dea70eaf9c..ed0b86efcab 100644 --- a/dts/arm/silabs/efr32mg21.dtsi +++ b/dts/arm/silabs/efr32mg21.dtsi @@ -315,7 +315,8 @@ pinctrl: pin-controller@5003c440 { compatible = "silabs,dbus-pinctrl"; - reg = <0x5003c440 0xbc0>; + reg = <0x5003c440 0xbc0>, <0x5003c320 0x40>; + reg-names = "dbus", "abus"; }; se: semailbox@5c000000 { diff --git a/dts/arm/silabs/efr32mg24.dtsi b/dts/arm/silabs/efr32mg24.dtsi index e3af156b4bb..59929b17446 100644 --- a/dts/arm/silabs/efr32mg24.dtsi +++ b/dts/arm/silabs/efr32mg24.dtsi @@ -388,7 +388,8 @@ pinctrl: pin-controller@5003c440 { compatible = "silabs,dbus-pinctrl"; - reg = <0x5003c440 0xbc0>; + reg = <0x5003c440 0xbc0>, <0x5003c320 0x40>; + reg-names = "dbus", "abus"; }; dma0: dma@40040000 { diff --git a/dts/arm/silabs/efr32xg23.dtsi b/dts/arm/silabs/efr32xg23.dtsi index 849fbbc10d6..ce2124246ef 100644 --- a/dts/arm/silabs/efr32xg23.dtsi +++ b/dts/arm/silabs/efr32xg23.dtsi @@ -418,7 +418,8 @@ pinctrl: pin-controller@5003c440 { compatible = "silabs,dbus-pinctrl"; - reg = <0x5003c440 0xbc0>; + reg = <0x5003c440 0xbc0>, <0x5003c320 0x40>; + reg-names = "dbus", "abus"; }; dma0: dma@50040000{ diff --git a/dts/arm/silabs/xg29/xg29.dtsi b/dts/arm/silabs/xg29/xg29.dtsi index 8ed57db8729..6a9321ed544 100644 --- a/dts/arm/silabs/xg29/xg29.dtsi +++ b/dts/arm/silabs/xg29/xg29.dtsi @@ -315,7 +315,8 @@ pinctrl: pin-controller@5003c440 { compatible = "silabs,dbus-pinctrl"; - reg = <0x5003c440 0xbc0>; + reg = <0x5003c440 0xbc0>, <0x5003c320 0x40>; + reg-names = "dbus", "abus"; }; dma0: dma@40040000{ diff --git a/dts/bindings/pinctrl/silabs,dbus-pinctrl.yaml b/dts/bindings/pinctrl/silabs,dbus-pinctrl.yaml index 410edd4cf5e..d0229c72a33 100644 --- a/dts/bindings/pinctrl/silabs,dbus-pinctrl.yaml +++ b/dts/bindings/pinctrl/silabs,dbus-pinctrl.yaml @@ -6,7 +6,8 @@ description: | pin function selection and pin properties. For example, you can use this node to route USART0 RX to pin PA1 and enable the pull-up resistor on the pin. This pin controller is used for devices that use DBUS (Digital Bus) - for alternate function configuration, including Series 2 devices. + for alternate function configuration, including Series 2 devices. It is + also capable of ABUS (Analog Bus) allocation. The pinctrl settings are referenced in a device tree peripheral node. For example when configuring a USART: @@ -81,6 +82,24 @@ description: | Allowed in drive-push-pull and drive-open-drain modes. + ABUS allocation is performed using the 'silabs,analog-bus' property. This + property takes an array of buses to allocate. Example: + + &pinctrl { + iadc0_default: iadc0_default { + group0 { + /* Allocate even bus 0 and odd bus 1 from GPIO port A for ADC use */ + silabs,analog-bus = , ; + } + }; + }; + + A given group may contain a mix of analog bus allocations and digital pin + selections. Digital pin properties only apply to digital pins. Analog input + selection is not done through the pin controller, this is done in the devicetree + node for the respective peripheral using properties such as 'zephyr,input-positive' + for ADC. + compatible: "silabs,dbus-pinctrl" include: base.yaml @@ -107,7 +126,6 @@ child-binding: properties: pins: - required: true type: array description: | An array of pins sharing the same group properties. The pins should be @@ -126,3 +144,10 @@ child-binding: for this pin. May be used in drive-push-pull and drive-open-drain modes. type: boolean + + silabs,analog-bus: + type: array + description: | + Assign one or more analog buses to the given GPIO port. The bus should + be defined using the ABUS__ macros available from the + SoC DeviceTree files. diff --git a/include/zephyr/dt-bindings/pinctrl/silabs-pinctrl-dbus.h b/include/zephyr/dt-bindings/pinctrl/silabs-pinctrl-dbus.h index 9ad02a5cd0f..e42879a91c3 100644 --- a/include/zephyr/dt-bindings/pinctrl/silabs-pinctrl-dbus.h +++ b/include/zephyr/dt-bindings/pinctrl/silabs-pinctrl-dbus.h @@ -11,7 +11,9 @@ /* * Silabs Series 2 DBUS configuration is encoded in a 32-bit bitfield organized as follows: * - * 31..29: Reserved + * 31 : Whether the configuration represents an analog pin + * If digital (bit 31 == 0): + * 30..29: Reserved * 28..24: Route register offset in words from peripheral config (offset of ROUTE * register in GPIO_ROUTE_TypeDef) * 23..19: Enable bit (offset into ROUTEEN register for given function) @@ -20,6 +22,11 @@ * register in GPIO_TypeDef minus offset of first route register [DBGROUTEPEN, 0x440]) * 7..4 : GPIO pin * 3..0 : GPIO port + * If analog (bit 31 == 1): + * 15..14: Bus selection (A, B, CD) + * 13..12: Bus selection (EVEN0, EVEN1, ODD0, ODD1) + * 11..8 : Peripheral selection (bit in GPIO_nBUSALLOC bitfield) + * 7 ..0 : Reserved */ #define SILABS_PINCTRL_GPIO_PORT_MASK 0x0000000FUL @@ -29,6 +36,14 @@ #define SILABS_PINCTRL_EN_BIT_MASK 0x00F80000UL #define SILABS_PINCTRL_ROUTE_MASK 0x1F000000UL +#define SILABS_PINCTRL_ANALOG_MASK 0x80000000UL +#define SILABS_PINCTRL_ABUS_BUS_MASK 0x0000C000UL +#define SILABS_PINCTRL_ABUS_PARITY_MASK 0x00003000UL +#define SILABS_PINCTRL_ABUS_PERIPH_MASK 0x00000F00UL + +#define SILABS_PINCTRL_UNUSED 0xFF +#define SILABS_PINCTRL_ANALOG 0xAA + #define SILABS_DBUS(port, pin, periph_base, en_present, en_bit, route) \ (FIELD_PREP(SILABS_PINCTRL_GPIO_PORT_MASK, port) | \ FIELD_PREP(SILABS_PINCTRL_GPIO_PIN_MASK, pin) | \ @@ -37,4 +52,10 @@ FIELD_PREP(SILABS_PINCTRL_EN_BIT_MASK, en_bit) | \ FIELD_PREP(SILABS_PINCTRL_ROUTE_MASK, route)) +#define SILABS_ABUS(bus, parity, peripheral) \ + (FIELD_PREP(SILABS_PINCTRL_ANALOG_MASK, 1) | \ + FIELD_PREP(SILABS_PINCTRL_ABUS_BUS_MASK, bus) | \ + FIELD_PREP(SILABS_PINCTRL_ABUS_PARITY_MASK, parity) | \ + FIELD_PREP(SILABS_PINCTRL_ABUS_PERIPH_MASK, peripheral)) + #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_SILABS_PINCTRL_DBUS_H_ */ diff --git a/soc/silabs/common/pinctrl_soc.h b/soc/silabs/common/pinctrl_soc.h index 82592eafcf5..9b4d27c9a54 100644 --- a/soc/silabs/common/pinctrl_soc.h +++ b/soc/silabs/common/pinctrl_soc.h @@ -73,14 +73,30 @@ typedef struct pinctrl_soc_pin { .en_bit = \ (FIELD_GET(SILABS_PINCTRL_HAVE_EN_MASK, DT_PROP_BY_IDX(node, prop, idx)) \ ? FIELD_GET(SILABS_PINCTRL_EN_BIT_MASK, DT_PROP_BY_IDX(node, prop, idx)) \ - : 0xFF), \ + : SILABS_PINCTRL_UNUSED), \ .route_offset = FIELD_GET(SILABS_PINCTRL_ROUTE_MASK, DT_PROP_BY_IDX(node, prop, idx)), \ .mode = Z_PINCTRL_SILABS_MODE_INIT(node), \ .dout = Z_PINCTRL_SILABS_DOUT_INIT(node)}, +#define Z_PINCTRL_STATE_ABUS_INIT(node, prop, idx) \ + { \ + .base_offset = \ + FIELD_GET(SILABS_PINCTRL_ABUS_BUS_MASK, DT_PROP_BY_IDX(node, prop, idx)), \ + .route_offset = FIELD_GET(SILABS_PINCTRL_ABUS_PERIPH_MASK, \ + DT_PROP_BY_IDX(node, prop, idx)), \ + .en_bit = SILABS_PINCTRL_ANALOG, \ + .mode = FIELD_GET(SILABS_PINCTRL_ABUS_PARITY_MASK, \ + DT_PROP_BY_IDX(node, prop, idx)), \ + }, + +#define Z_PINCTRL_SILABS_DISPATCH(group) \ + IF_ENABLED(DT_NODE_HAS_PROP(group, pins), \ + (DT_FOREACH_PROP_ELEM(group, pins, Z_PINCTRL_STATE_PIN_INIT))) \ + IF_ENABLED(DT_NODE_HAS_PROP(group, silabs_analog_bus), \ + (DT_FOREACH_PROP_ELEM(group, silabs_analog_bus, Z_PINCTRL_STATE_ABUS_INIT))) + #define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \ - {DT_FOREACH_CHILD_VARGS(DT_PHANDLE(node_id, prop), DT_FOREACH_PROP_ELEM, pins, \ - Z_PINCTRL_STATE_PIN_INIT)} + {DT_FOREACH_CHILD(DT_PHANDLE(node_id, prop), Z_PINCTRL_SILABS_DISPATCH)} #else