drivers: pinctrl: silabs: Add support for analog bus allocation

The GPIO peripheral on Silabs Series 2 devices is responsible for
allocating analog buses to analog peripherals. Enable support for
this in the pinctrl driver. Since these bus allocations are not
digital pins, introduce a new property silabs,analog-bus for this
purpose.

Signed-off-by: Aksel Skauge Mellbye <aksel.mellbye@silabs.com>
This commit is contained in:
Aksel Skauge Mellbye 2025-01-23 19:56:09 +01:00 committed by Benjamin Cabé
commit 120691a155
9 changed files with 91 additions and 13 deletions

View file

@ -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);
}
}

View file

@ -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{

View file

@ -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 {

View file

@ -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 {

View file

@ -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{

View file

@ -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{

View file

@ -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 = <ABUS_AEVEN0_IADC0>, <ABUS_AODD1_IADC0>;
}
};
};
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_<bus>_<peripheral> macros available from the
SoC DeviceTree files.

View file

@ -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 <fun>ROUTE
* register in GPIO_<periph>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_ */

View file

@ -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