drivers: pinctrl: silabs: Add pinctrl driver for digital bus

Silicon Labs Series 2 and newer devices do alternate function
configuration fundamentally differently from Series 0 and 1. Pin routing
is done in a centralized fashion in the GPIO peripheral, as opposed to
having ROUTE registers in every peripheral. The concept of alternate
function location numbers also does not exist, functions are directly
assigned to GPIOs by their port and pin number.

This commit adds a new pinctrl driver for devices that use DBUS. It fully
makes use of pinctrl design principles as outlined in the Zephyr
documentation. The previous driver hard-codes pin properties such as filter
and pull-up/down in the driver itself, while the new driver leaves this up
to the user as configurable DeviceTree properties. The previous driver has
hard-coded support for UART, SPI and I2C, while the new driver has generic
support for all DBUS signals.

Signed-off-by: Aksel Skauge Mellbye <aksel.mellbye@silabs.com>
This commit is contained in:
Aksel Skauge Mellbye 2024-11-25 12:21:31 +01:00 committed by Anas Nashif
commit f3246cda17
11 changed files with 7835 additions and 1 deletions

View file

@ -15,7 +15,10 @@
#include <stdint.h>
#include <zephyr/devicetree.h>
#if CONFIG_SOC_FAMILY_SILABS_S1
#if CONFIG_PINCTRL_SILABS_DBUS
#include <zephyr/sys/util.h>
#include <zephyr/dt-bindings/pinctrl/silabs-pinctrl-dbus.h>
#elif CONFIG_SOC_FAMILY_SILABS_S1
#include <zephyr/dt-bindings/pinctrl/gecko-pinctrl-s1.h>
#else
#include <zephyr/dt-bindings/pinctrl/gecko-pinctrl.h>
@ -27,6 +30,60 @@ extern "C" {
/** @cond INTERNAL_HIDDEN */
#if CONFIG_PINCTRL_SILABS_DBUS
/** Type for Silabs pin using DBUS. */
typedef struct pinctrl_soc_pin {
uint16_t base_offset;
uint8_t port;
uint8_t pin;
uint8_t en_bit;
uint8_t route_offset;
uint8_t mode;
uint8_t dout;
} pinctrl_soc_pin_t;
#define Z_PINCTRL_SILABS_MODE_INIT(node) \
(DT_PROP(node, drive_push_pull) ? (4 + DT_PROP(node, silabs_alternate_port_control)) \
: DT_PROP(node, drive_open_source) ? (6 + DT_PROP(node, bias_pull_down)) \
: DT_PROP(node, drive_open_drain) \
? (8 + DT_PROP(node, silabs_input_filter) + 2 * DT_PROP(node, bias_pull_up) + \
4 * DT_PROP(node, silabs_alternate_port_control)) \
: DT_PROP(node, input_enable) \
? ((DT_PROP(node, bias_pull_down) || DT_PROP(node, bias_pull_up)) \
? (2 + DT_PROP(node, silabs_input_filter)) \
: 1) \
: 0)
#define Z_PINCTRL_SILABS_DOUT_INIT(node) \
(DT_PROP(node, drive_push_pull) ? DT_PROP(node, output_high) \
: DT_PROP(node, drive_open_drain) ? 1 \
: DT_PROP(node, input_enable) \
? ((DT_PROP(node, bias_pull_down) || DT_PROP(node, bias_pull_up)) \
? DT_PROP(node, bias_pull_up) \
: DT_PROP(node, silabs_input_filter)) \
: DT_PROP(node, input_disable) ? DT_PROP(node, bias_pull_up) \
: 0)
#define Z_PINCTRL_STATE_PIN_INIT(node, prop, idx) \
{.base_offset = \
FIELD_GET(SILABS_PINCTRL_PERIPH_BASE_MASK, DT_PROP_BY_IDX(node, prop, idx)), \
.port = FIELD_GET(SILABS_PINCTRL_GPIO_PORT_MASK, DT_PROP_BY_IDX(node, prop, idx)), \
.pin = FIELD_GET(SILABS_PINCTRL_GPIO_PIN_MASK, DT_PROP_BY_IDX(node, prop, idx)), \
.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), \
.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_PINS_INIT(node_id, prop) \
{DT_FOREACH_CHILD_VARGS(DT_PHANDLE(node_id, prop), DT_FOREACH_PROP_ELEM, pins, \
Z_PINCTRL_STATE_PIN_INIT)}
#else
/** Type for gecko pin. */
typedef uint32_t pinctrl_soc_pin_t;
@ -86,6 +143,8 @@ typedef uint32_t pinctrl_soc_pin_t;
*/
#define GECKO_GET_SPEED(pincfg) (((pincfg) >> GECKO_SPEED_POS) & GECKO_SPEED_MSK)
#endif /* CONFIG_PINCTRL_SILABS_DBUS */
/** @endcond */
#ifdef __cplusplus