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:
parent
4195130214
commit
120691a155
9 changed files with 91 additions and 13 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue