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 DT_DRV_COMPAT silabs_dbus_pinctrl
|
||||||
#define PIN_MASK 0xF0000UL
|
#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)
|
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++) {
|
for (uint8_t i = 0U; i < pin_cnt; i++) {
|
||||||
mem_addr_t enable_reg, route_reg;
|
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 */
|
/* Configure GPIO */
|
||||||
GPIO_PinModeSet(pins[i].port, pins[i].pin, pins[i].mode, pins[i].dout);
|
GPIO_PinModeSet(pins[i].port, pins[i].pin, pins[i].mode, pins[i].dout);
|
||||||
|
|
||||||
/* Configure DBUS */
|
/* 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));
|
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);
|
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);
|
sys_set_bit(enable_reg, pins[i].en_bit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -337,7 +337,8 @@
|
||||||
|
|
||||||
pinctrl: pin-controller@5003c440 {
|
pinctrl: pin-controller@5003c440 {
|
||||||
compatible = "silabs,dbus-pinctrl";
|
compatible = "silabs,dbus-pinctrl";
|
||||||
reg = <0x5003c440 0xbc0>;
|
reg = <0x5003c440 0xbc0>, <0x5003c320 0x40>;
|
||||||
|
reg-names = "dbus", "abus";
|
||||||
};
|
};
|
||||||
|
|
||||||
dma0: dma@40040000{
|
dma0: dma@40040000{
|
||||||
|
|
|
@ -315,7 +315,8 @@
|
||||||
|
|
||||||
pinctrl: pin-controller@5003c440 {
|
pinctrl: pin-controller@5003c440 {
|
||||||
compatible = "silabs,dbus-pinctrl";
|
compatible = "silabs,dbus-pinctrl";
|
||||||
reg = <0x5003c440 0xbc0>;
|
reg = <0x5003c440 0xbc0>, <0x5003c320 0x40>;
|
||||||
|
reg-names = "dbus", "abus";
|
||||||
};
|
};
|
||||||
|
|
||||||
se: semailbox@5c000000 {
|
se: semailbox@5c000000 {
|
||||||
|
|
|
@ -388,7 +388,8 @@
|
||||||
|
|
||||||
pinctrl: pin-controller@5003c440 {
|
pinctrl: pin-controller@5003c440 {
|
||||||
compatible = "silabs,dbus-pinctrl";
|
compatible = "silabs,dbus-pinctrl";
|
||||||
reg = <0x5003c440 0xbc0>;
|
reg = <0x5003c440 0xbc0>, <0x5003c320 0x40>;
|
||||||
|
reg-names = "dbus", "abus";
|
||||||
};
|
};
|
||||||
|
|
||||||
dma0: dma@40040000 {
|
dma0: dma@40040000 {
|
||||||
|
|
|
@ -418,7 +418,8 @@
|
||||||
|
|
||||||
pinctrl: pin-controller@5003c440 {
|
pinctrl: pin-controller@5003c440 {
|
||||||
compatible = "silabs,dbus-pinctrl";
|
compatible = "silabs,dbus-pinctrl";
|
||||||
reg = <0x5003c440 0xbc0>;
|
reg = <0x5003c440 0xbc0>, <0x5003c320 0x40>;
|
||||||
|
reg-names = "dbus", "abus";
|
||||||
};
|
};
|
||||||
|
|
||||||
dma0: dma@50040000{
|
dma0: dma@50040000{
|
||||||
|
|
|
@ -315,7 +315,8 @@
|
||||||
|
|
||||||
pinctrl: pin-controller@5003c440 {
|
pinctrl: pin-controller@5003c440 {
|
||||||
compatible = "silabs,dbus-pinctrl";
|
compatible = "silabs,dbus-pinctrl";
|
||||||
reg = <0x5003c440 0xbc0>;
|
reg = <0x5003c440 0xbc0>, <0x5003c320 0x40>;
|
||||||
|
reg-names = "dbus", "abus";
|
||||||
};
|
};
|
||||||
|
|
||||||
dma0: dma@40040000{
|
dma0: dma@40040000{
|
||||||
|
|
|
@ -6,7 +6,8 @@ description: |
|
||||||
pin function selection and pin properties. For example, you can use this
|
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
|
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)
|
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
|
The pinctrl settings are referenced in a device tree peripheral node. For
|
||||||
example when configuring a USART:
|
example when configuring a USART:
|
||||||
|
@ -81,6 +82,24 @@ description: |
|
||||||
Allowed in drive-push-pull and
|
Allowed in drive-push-pull and
|
||||||
drive-open-drain modes.
|
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"
|
compatible: "silabs,dbus-pinctrl"
|
||||||
|
|
||||||
include: base.yaml
|
include: base.yaml
|
||||||
|
@ -107,7 +126,6 @@ child-binding:
|
||||||
|
|
||||||
properties:
|
properties:
|
||||||
pins:
|
pins:
|
||||||
required: true
|
|
||||||
type: array
|
type: array
|
||||||
description: |
|
description: |
|
||||||
An array of pins sharing the same group properties. The pins should be
|
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
|
for this pin. May be used in drive-push-pull and drive-open-drain
|
||||||
modes.
|
modes.
|
||||||
type: boolean
|
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:
|
* 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
|
* 28..24: Route register offset in words from peripheral config (offset of <fun>ROUTE
|
||||||
* register in GPIO_<periph>ROUTE_TypeDef)
|
* register in GPIO_<periph>ROUTE_TypeDef)
|
||||||
* 23..19: Enable bit (offset into ROUTEEN register for given function)
|
* 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])
|
* register in GPIO_TypeDef minus offset of first route register [DBGROUTEPEN, 0x440])
|
||||||
* 7..4 : GPIO pin
|
* 7..4 : GPIO pin
|
||||||
* 3..0 : GPIO port
|
* 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
|
#define SILABS_PINCTRL_GPIO_PORT_MASK 0x0000000FUL
|
||||||
|
@ -29,6 +36,14 @@
|
||||||
#define SILABS_PINCTRL_EN_BIT_MASK 0x00F80000UL
|
#define SILABS_PINCTRL_EN_BIT_MASK 0x00F80000UL
|
||||||
#define SILABS_PINCTRL_ROUTE_MASK 0x1F000000UL
|
#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) \
|
#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_PORT_MASK, port) | \
|
||||||
FIELD_PREP(SILABS_PINCTRL_GPIO_PIN_MASK, pin) | \
|
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_EN_BIT_MASK, en_bit) | \
|
||||||
FIELD_PREP(SILABS_PINCTRL_ROUTE_MASK, route))
|
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_ */
|
#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_SILABS_PINCTRL_DBUS_H_ */
|
||||||
|
|
|
@ -73,14 +73,30 @@ typedef struct pinctrl_soc_pin {
|
||||||
.en_bit = \
|
.en_bit = \
|
||||||
(FIELD_GET(SILABS_PINCTRL_HAVE_EN_MASK, DT_PROP_BY_IDX(node, prop, idx)) \
|
(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)) \
|
? 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)), \
|
.route_offset = FIELD_GET(SILABS_PINCTRL_ROUTE_MASK, DT_PROP_BY_IDX(node, prop, idx)), \
|
||||||
.mode = Z_PINCTRL_SILABS_MODE_INIT(node), \
|
.mode = Z_PINCTRL_SILABS_MODE_INIT(node), \
|
||||||
.dout = Z_PINCTRL_SILABS_DOUT_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) \
|
#define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \
|
||||||
{DT_FOREACH_CHILD_VARGS(DT_PHANDLE(node_id, prop), DT_FOREACH_PROP_ELEM, pins, \
|
{DT_FOREACH_CHILD(DT_PHANDLE(node_id, prop), Z_PINCTRL_SILABS_DISPATCH)}
|
||||||
Z_PINCTRL_STATE_PIN_INIT)}
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue