diff --git a/boards/silabs/radio_boards/siwx917_rb4338a/siwx917_rb4338a.dts b/boards/silabs/radio_boards/siwx917_rb4338a/siwx917_rb4338a.dts index 8412c23..87b8160 100644 --- a/boards/silabs/radio_boards/siwx917_rb4338a/siwx917_rb4338a.dts +++ b/boards/silabs/radio_boards/siwx917_rb4338a/siwx917_rb4338a.dts @@ -6,6 +6,8 @@ /dts-v1/; #include +#include +#include / { model = "Silicon Labs BRD4338A (SiWG917 Radio Board)"; @@ -17,6 +19,36 @@ zephyr,console = &ulpuart0; zephyr,shell-uart = &ulpuart0; }; + + aliases { + led0 = &led0; + led1 = &led1; + sw0 = &button0; + sw1 = &button1; + }; + + leds { + compatible = "gpio-leds"; + led0: led_0 { + gpios = <&gpioulp 2 GPIO_ACTIVE_HIGH>; + }; + + led1: led_1 { + gpios = <&gpioa 10 GPIO_ACTIVE_HIGH>; + }; + }; + + buttons { + compatible = "gpio-keys"; + button0: button_0 { + gpios = <&gpiouulp 2 GPIO_ACTIVE_LOW>; + zephyr,code = ; + }; + button1: button_1 { + gpios = <&gpioa 11 GPIO_ACTIVE_LOW>; + zephyr,code = ; + }; + }; }; &ulpuart0 { diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index d7463ca..bb5dbee 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -1,4 +1,5 @@ # Copyright (c) 2024 Silicon Laboratories Inc. # SPDX-License-Identifier: Apache-2.0 +add_subdirectory(gpio) add_subdirectory(pinctrl) diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt new file mode 100644 index 0000000..4a42fab --- /dev/null +++ b/drivers/gpio/CMakeLists.txt @@ -0,0 +1,5 @@ +# Copyright (c) 2024 Silicon Laboratories Inc. +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library_sources_ifdef(CONFIG_GPIO_SILABS_SIWX917 gpio_silabs_siwx917.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_SILABS_SIWX917_UULP gpio_silabs_siwx917_uulp.c) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig new file mode 100644 index 0000000..72d8b7f --- /dev/null +++ b/drivers/gpio/Kconfig @@ -0,0 +1,8 @@ +# Copyright (c) 2024 Silicon Laboratories Inc. +# SPDX-License-Identifier: Apache-2.0 + +if GPIO + +rsource "Kconfig.siwx917" + +endif diff --git a/drivers/gpio/Kconfig.siwx917 b/drivers/gpio/Kconfig.siwx917 new file mode 100644 index 0000000..b78d02a --- /dev/null +++ b/drivers/gpio/Kconfig.siwx917 @@ -0,0 +1,16 @@ +# Copyright (c) 2024 Silicon Laboratories Inc. +# SPDX-License-Identifier: Apache-2.0 + +config GPIO_SILABS_SIWX917 + bool "Silabs SiWx917 GPIO driver" + default y + depends on DT_HAS_SILABS_SIWX917_GPIO_ENABLED + help + Enable the HP/ULP GPIO driver for the Silabs SiWx917 SoC series. + +config GPIO_SILABS_SIWX917_UULP + bool "Silabs SiWx917 UULP GPIO driver" + default y + depends on DT_HAS_SILABS_SIWX917_GPIO_UULP_ENABLED + help + Enable the UULP GPIO driver for the Silabs SiWx917 SoC series. diff --git a/drivers/gpio/gpio_silabs_siwx917.c b/drivers/gpio/gpio_silabs_siwx917.c new file mode 100644 index 0000000..b2d55ed --- /dev/null +++ b/drivers/gpio/gpio_silabs_siwx917.c @@ -0,0 +1,352 @@ +/* + * Copyright (c) 2024 Silicon Laboratories Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT silabs_siwx917_gpio_port + +#include "sl_si91x_driver_gpio.h" +#include "sl_status.h" + +#include +#include + +/* Zephyr GPIO header must be included after driver, due to symbol conflicts + * for GPIO_INPUT and GPIO_OUTPUT between preprocessor macros in the Zephyr + * API and struct member register definitions for the SiWx917 device. + */ +#include +#include + +/* Zephyr IRQ header must be included last, as it defines symbols that mess up + * structure definitions in the device headers. + * + * TODO: Something is terribly wrong with NVIC priority bits, it's either 4 or 6... + */ +#undef __NVIC_PRIO_BITS +#define __NVIC_PRIO_BITS 4 +#include + +#define HP_PORT_COUNT 4 +#define INVALID_PORT 8 +#define HP_INTERRUPT_COUNT 8 +#define ULP_INTERRUPT_COUNT 8 + +/* Types */ +struct gpio_siwx917_port_config { + /* gpio_driver_config needs to be first */ + struct gpio_driver_config common; + const struct device *parent; + int port; +}; + +struct gpio_siwx917_common_data { + /* a list of all ports */ + const struct device *ports[HP_PORT_COUNT]; + size_t count; + sl_gpio_t hp_interrupts[8]; + sl_gpio_t ulp_interrupts[8]; +}; + +struct gpio_siwx917_port_data { + /* gpio_driver_data needs to be first */ + struct gpio_driver_data common; + /* port ISR callback routine address */ + sys_slist_t callbacks; +}; + +/* Functions */ +static int gpio_siwx917_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) +{ + const struct gpio_siwx917_port_config *cfg = dev->config; + sl_si91x_gpio_pin_config_t pin_config; + + pin_config.port_pin = (sl_gpio_t){cfg->port, pin}; + if (flags & GPIO_OUTPUT) { + pin_config.direction = 0; + } else { + pin_config.direction = 1; + } + + sl_gpio_set_configuration(pin_config); + + /* TODO set gpio mode and other content from flags */ + + return 0; +} + +static int gpio_siwx917_port_get(const struct device *port, gpio_port_value_t *value) +{ + const struct gpio_siwx917_port_config *cfg = port->config; + + *value = sl_gpio_driver_get_port_input(cfg->port); + return 0; +} + +static int gpio_siwx917_port_set_masked(const struct device *port, gpio_port_pins_t mask, + gpio_port_value_t value) +{ + const struct gpio_siwx917_port_config *cfg = port->config; + sl_status_t status = sl_gpio_driver_set_port_output_value(cfg->port, value, mask); + + if (status != SL_STATUS_OK) { + return -ENODEV; + } + return 0; +} + +static int gpio_siwx917_port_set_bits(const struct device *port, gpio_port_pins_t pins) +{ + const struct gpio_siwx917_port_config *cfg = port->config; + sl_status_t status = sl_gpio_driver_set_port(cfg->port, pins); + + if (status != SL_STATUS_OK) { + return -ENODEV; + } + + return 0; +} + +static int gpio_siwx917_port_clear_bits(const struct device *port, gpio_port_pins_t pins) +{ + const struct gpio_siwx917_port_config *cfg = port->config; + sl_status_t status = sl_gpio_driver_clear_port(cfg->port, pins); + + if (status != SL_STATUS_OK) { + return -ENODEV; + } + + return 0; +} + +static int gpio_siwx917_port_toggle_bits(const struct device *port, gpio_port_pins_t pins) +{ + const struct gpio_siwx917_port_config *cfg = port->config; + sl_status_t status = sl_gpio_driver_toggle_port_output(cfg->port, pins); + + if (status != SL_STATUS_OK) { + return -ENODEV; + } + + return 0; +} + +static int gpio_siwx917_manage_callback(const struct device *port, struct gpio_callback *callback, + bool set) +{ + struct gpio_siwx917_port_data *data = port->data; + + return gpio_manage_callback(&data->callbacks, callback, set); +} + +static int gpio_siwx917_interrupt_configure(const struct device *port, gpio_pin_t pin, + enum gpio_int_mode mode, enum gpio_int_trig trig) +{ + const struct gpio_siwx917_port_config *config = port->config; + const struct device *parent = config->parent; + struct gpio_siwx917_common_data *data = parent->data; + uint32_t flags = 0; + + if (mode == GPIO_INT_MODE_DISABLED) { + if (config->port < HP_PORT_COUNT) { + for (size_t i = 0; i < HP_INTERRUPT_COUNT; i++) { + if (data->hp_interrupts[i].port == config->port && + data->hp_interrupts[i].pin == pin) { + data->hp_interrupts[i].port = INVALID_PORT; + sl_gpio_clear_interrupts(i); + sl_gpio_configure_interrupt(config->port, pin, i, flags); + return 0; + } + } + } else if (config->port == SL_GPIO_ULP_PORT) { + for (size_t i = 0; i < ULP_INTERRUPT_COUNT; i++) { + if (data->ulp_interrupts[i].port == config->port && + data->ulp_interrupts[i].pin == pin) { + data->ulp_interrupts[i].port = INVALID_PORT; + sl_si91x_gpio_clear_ulp_interrupt(i); + sl_si91x_gpio_configure_ulp_pin_interrupt(i, flags, pin); + return 0; + } + } + } + } else { + if (trig == GPIO_INT_TRIG_LOW) { + flags = (mode == GPIO_INT_MODE_LEVEL) ? SL_GPIO_INTERRUPT_LEVEL_LOW + : SL_GPIO_INTERRUPT_FALL_EDGE; + } else if (trig == GPIO_INT_TRIG_HIGH) { + flags = (mode == GPIO_INT_MODE_LEVEL) ? SL_GPIO_INTERRUPT_LEVEL_HIGH + : SL_GPIO_INTERRUPT_RISE_EDGE; + } else { + flags = SL_GPIO_INTERRUPT_RISE_FALL_EDGE; + } + + if (config->port < HP_PORT_COUNT) { + for (size_t i = 0; i < HP_INTERRUPT_COUNT; i++) { + if (data->hp_interrupts[i].port == INVALID_PORT) { + data->hp_interrupts[i].port = config->port; + data->hp_interrupts[i].pin = pin; + + sl_gpio_configure_interrupt(config->port, pin, i, flags); + return 0; + } + } + } else if (config->port == SL_GPIO_ULP_PORT) { + for (size_t i = 0; i < ULP_INTERRUPT_COUNT; i++) { + if (data->ulp_interrupts[i].port == INVALID_PORT) { + data->ulp_interrupts[i].port = config->port; + data->ulp_interrupts[i].pin = pin; + + sl_si91x_gpio_configure_ulp_pin_interrupt(i, flags, pin); + return 0; + } + } + } + } + /* No more available interrupts */ + return -EBUSY; +} + +static inline void gpio_siwx917_add_port(struct gpio_siwx917_common_data *data, + const struct device *dev) +{ + /* Register port as active */ + __ASSERT(dev, "No port device!"); + data->ports[data->count++] = dev; +} + +/* Handler for all HP interrupts */ +static void gpio_siwx917_hp_isr(const struct device *parent) +{ + struct gpio_siwx917_common_data *common = parent->data; + const struct device *port; + const struct gpio_siwx917_port_config *config; + struct gpio_siwx917_port_data *data; + uint32_t pending = sl_gpio_get_pending_interrupts(); + + for (size_t i = 0; i < HP_INTERRUPT_COUNT; i++) { + sl_gpio_port_t port_no = common->hp_interrupts[i].port; + + if ((pending & BIT(4 * i)) && (port_no != INVALID_PORT)) { + sl_gpio_driver_clear_interrupts(i); + port = common->ports[port_no]; + config = port->config; + data = port->data; + gpio_fire_callbacks(&data->callbacks, port, + BIT(common->hp_interrupts[i].pin)); + } + } +} + +static void gpio_siwx917_ulp_isr(const struct device *port) +{ + struct gpio_siwx917_port_data *data = port->data; + const struct gpio_siwx917_port_config *config = port->config; + const struct device *parent = config->parent; + struct gpio_siwx917_common_data *common = parent->data; + + for (int i = 0; i < ULP_INTERRUPT_COUNT; i++) { + if (sl_si91x_gpio_driver_get_ulp_interrupt_status(i)) { + sl_gpio_port_t port_no = common->ulp_interrupts[i].port; + + if (port_no != INVALID_PORT) { + sl_si91x_gpio_driver_clear_ulp_interrupt(i); + gpio_fire_callbacks(&data->callbacks, port, + BIT(common->ulp_interrupts[i].pin)); + } + } + } +} + +#define CONFIGURE_SHARED_IRQ(node_id, prop, idx) \ + IRQ_CONNECT(DT_IRQ_BY_IDX(node_id, idx, irq), DT_IRQ_BY_IDX(node_id, idx, priority), \ + gpio_siwx917_hp_isr, DEVICE_DT_GET(node_id), 0); \ + irq_enable(DT_IRQ_BY_IDX(node_id, idx, irq)); + +static int gpio_siwx917_init(const struct device *dev) +{ + struct gpio_siwx917_common_data *data = dev->data; + sl_status_t status; + + /* The init function of the high-level GPIO driver sl_gpio_driver_init(), is not used + * since we don't want to use the interrupt handlers and dispatch tables from the driver. + */ + + status = sl_si91x_gpio_driver_enable_clock((sl_si91x_gpio_select_clock_t)M4CLK_GPIO); + if (status != SL_STATUS_OK) { + return -ENODEV; + } + status = sl_si91x_gpio_driver_enable_clock((sl_si91x_gpio_select_clock_t)ULPCLK_GPIO); + if (status != SL_STATUS_OK) { + return -ENODEV; + } + + data->count = 0; + for (size_t i = 0; i < HP_INTERRUPT_COUNT; i++) { + data->hp_interrupts[i].port = INVALID_PORT; + } + + DT_FOREACH_PROP_ELEM(DT_NODELABEL(gpio), interrupt_names, CONFIGURE_SHARED_IRQ); + + return 0; +} + +static const struct gpio_driver_api gpio_siwx917_driver_api = { + .pin_configure = gpio_siwx917_pin_configure, +#ifdef CONFIG_GPIO_GET_CONFIG + .pin_get_config = NULL, +#endif + .port_get_raw = gpio_siwx917_port_get, + .port_set_masked_raw = gpio_siwx917_port_set_masked, + .port_set_bits_raw = gpio_siwx917_port_set_bits, + .port_clear_bits_raw = gpio_siwx917_port_clear_bits, + .port_toggle_bits = gpio_siwx917_port_toggle_bits, + .pin_interrupt_configure = gpio_siwx917_interrupt_configure, + .manage_callback = gpio_siwx917_manage_callback, + .get_pending_int = NULL, +#ifdef CONFIG_GPIO_GET_DIRECTION + .port_get_direction = NULL, +#endif +}; + +static const struct gpio_driver_api gpio_siwx917_common_driver_api = {}; + +static struct gpio_siwx917_common_data gpio_siwx917_data; + +DEVICE_DT_DEFINE(DT_INST(0, silabs_siwx917_gpio), gpio_siwx917_init, NULL, &gpio_siwx917_data, NULL, + PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, /* TODO: Separate common init priority? */ + &gpio_siwx917_common_driver_api); + +#define GPIO_PORT_INIT(idx) \ + static int gpio_siwx917_init_port_##idx##_(const struct device *dev); \ + static const struct gpio_siwx917_port_config gpio_siwx917_port_##idx##_config = { \ + .common = \ + { \ + .port_pin_mask = (gpio_port_pins_t)(-1), \ + }, \ + .parent = DEVICE_DT_GET(DT_NODELABEL(gpio)), \ + .port = DT_INST_REG_ADDR(idx), \ + }; \ + static struct gpio_siwx917_port_data gpio_siwx917_port_##idx##_data; \ + \ + DEVICE_DT_INST_DEFINE(idx, gpio_siwx917_init_port_##idx##_, NULL, \ + &gpio_siwx917_port_##idx##_data, &gpio_siwx917_port_##idx##_config, \ + PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, &gpio_siwx917_driver_api); \ + static int gpio_siwx917_init_port_##idx##_(const struct device *dev) \ + { \ + const struct gpio_siwx917_port_config *config = dev->config; \ + const struct device *parent = config->parent; \ + struct gpio_siwx917_common_data *data = parent->data; \ + COND_CODE_1( \ + DT_INST_IRQ_HAS_NAME(idx, ulp), \ + (for (size_t i = 0; i < ULP_INTERRUPT_COUNT; i++) { \ + data->ulp_interrupts[i].port = INVALID_PORT; \ + } IRQ_CONNECT(DT_INST_IRQ_BY_NAME(idx, ulp, irq), \ + DT_INST_IRQ_BY_NAME(idx, ulp, priority), \ + gpio_siwx917_ulp_isr, DEVICE_DT_GET(DT_DRV_INST(idx)), 0); \ + irq_enable(DT_INST_IRQ_BY_NAME(idx, ulp, irq));), \ + (gpio_siwx917_add_port(data, dev);)); \ + return 0; \ + } + +DT_INST_FOREACH_STATUS_OKAY(GPIO_PORT_INIT) diff --git a/drivers/gpio/gpio_silabs_siwx917_uulp.c b/drivers/gpio/gpio_silabs_siwx917_uulp.c new file mode 100644 index 0000000..b512789 --- /dev/null +++ b/drivers/gpio/gpio_silabs_siwx917_uulp.c @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2024 Silicon Laboratories Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT silabs_siwx917_gpio_uulp + +#include "sl_si91x_driver_gpio.h" +#include "sl_status.h" + +#include +#include + +/* Zephyr GPIO header must be included after driver, due to symbol conflicts + * for GPIO_INPUT and GPIO_OUTPUT between preprocessor macros in the Zephyr + * API and struct member register definitions for the SiWx917 device. + */ +#include +#include + +/* Zephyr IRQ header must be included last, as it defines symbols that mess up + * structure definitions in the device headers. + * + * TODO: Something is terribly wrong with NVIC priority bits, it's either 4 or 6... + */ +#undef __NVIC_PRIO_BITS +#define __NVIC_PRIO_BITS 4 +#include + +#define UULP_GPIO_COUNT 5 + +/* Types */ +struct gpio_siwx917_uulp_config { + /* gpio_driver_config needs to be first */ + struct gpio_driver_config common; +}; + +struct gpio_siwx917_uulp_data { + /* gpio_driver_data needs to be first */ + struct gpio_driver_data common; + /* port ISR callback routine address */ + sys_slist_t callbacks; +}; + +/* Functions */ +static int gpio_siwx917_uulp_pin_configure(const struct device *dev, gpio_pin_t pin, + gpio_flags_t flags) +{ + sl_si91x_gpio_pin_config_t pin_config; + + pin_config.port_pin = (sl_gpio_t){SL_GPIO_UULP_PORT, pin}; + if (flags & GPIO_OUTPUT) { + pin_config.direction = 0; + } else { + pin_config.direction = 1; + } + + sl_gpio_set_configuration(pin_config); + + /* TODO set gpio mode and other content from flags */ + + return 0; +} + +static int gpio_siwx917_uulp_port_get(const struct device *port, gpio_port_value_t *value) +{ + for (size_t i = 0; i < UULP_GPIO_COUNT; i++) { + WRITE_BIT(*value, i, sl_si91x_gpio_get_uulp_npss_pin(i)); + } + + return 0; +} + +static int gpio_siwx917_uulp_port_set_masked(const struct device *port, gpio_port_pins_t mask, + gpio_port_value_t value) +{ + for (size_t i = 0; i < UULP_GPIO_COUNT; i++) { + if (mask & BIT(i)) { + sl_si91x_gpio_set_uulp_npss_pin_value(i, FIELD_GET(value, BIT(i))); + } + } + + return 0; +} + +static int gpio_siwx917_uulp_port_set_bits(const struct device *port, gpio_port_pins_t pins) +{ + for (size_t i = 0; i < UULP_GPIO_COUNT; i++) { + if (FIELD_GET(pins, BIT(i))) { + sl_si91x_gpio_set_uulp_npss_pin_value(i, 1); + } + } + + return 0; +} + +static int gpio_siwx917_uulp_port_clear_bits(const struct device *port, gpio_port_pins_t pins) +{ + for (size_t i = 0; i < UULP_GPIO_COUNT; i++) { + if (FIELD_GET(pins, BIT(i))) { + sl_si91x_gpio_set_uulp_npss_pin_value(i, 0); + } + } + + return 0; +} + +static int gpio_siwx917_uulp_port_toggle_bits(const struct device *port, gpio_port_pins_t pins) +{ + for (size_t i = 0; i < UULP_GPIO_COUNT; i++) { + if (FIELD_GET(pins, BIT(i))) { + sl_si91x_gpio_toggle_uulp_npss_pin(i); + } + } + + return 0; +} + +static int gpio_siwx917_uulp_manage_callback(const struct device *port, + struct gpio_callback *callback, bool set) +{ + struct gpio_siwx917_uulp_data *data = port->data; + + return gpio_manage_callback(&data->callbacks, callback, set); +} + +static int gpio_siwx917_uulp_interrupt_configure(const struct device *port, gpio_pin_t pin, + enum gpio_int_mode mode, enum gpio_int_trig trig) +{ + uint32_t flags = 0; + + if (mode == GPIO_INT_MODE_DISABLED) { + sl_si91x_gpio_driver_clear_uulp_interrupt(pin); + sl_si91x_gpio_configure_uulp_interrupt(flags, pin); + } else { + if (trig == GPIO_INT_TRIG_LOW) { + flags = (mode == GPIO_INT_MODE_LEVEL) ? SL_GPIO_INTERRUPT_LEVEL_LOW + : SL_GPIO_INTERRUPT_FALL_EDGE; + } else if (trig == GPIO_INT_TRIG_HIGH) { + flags = (mode == GPIO_INT_MODE_LEVEL) ? SL_GPIO_INTERRUPT_LEVEL_HIGH + : SL_GPIO_INTERRUPT_RISE_EDGE; + } else { + flags = SL_GPIO_INTERRUPT_RISE_FALL_EDGE; + } + + sl_si91x_gpio_configure_uulp_interrupt(flags, pin); + } + return 0; +} + +static void gpio_siwx917_uulp_isr(const struct device *port) +{ + struct gpio_siwx917_uulp_data *data = port->data; + uint8_t pins = sl_si91x_gpio_get_uulp_interrupt_status(); + + sl_si91x_gpio_driver_clear_uulp_interrupt(pins); + + gpio_fire_callbacks(&data->callbacks, port, pins); +} + +static const struct gpio_driver_api gpio_siwx917_uulp_driver_api = { + .pin_configure = gpio_siwx917_uulp_pin_configure, +#ifdef CONFIG_GPIO_GET_CONFIG + .pin_get_config = NULL, +#endif + .port_get_raw = gpio_siwx917_uulp_port_get, + .port_set_masked_raw = gpio_siwx917_uulp_port_set_masked, + .port_set_bits_raw = gpio_siwx917_uulp_port_set_bits, + .port_clear_bits_raw = gpio_siwx917_uulp_port_clear_bits, + .port_toggle_bits = gpio_siwx917_uulp_port_toggle_bits, + .pin_interrupt_configure = gpio_siwx917_uulp_interrupt_configure, + .manage_callback = gpio_siwx917_uulp_manage_callback, + .get_pending_int = NULL, +#ifdef CONFIG_GPIO_GET_DIRECTION + .port_get_direction = NULL, +#endif +}; + +#define GPIO_PORT_INIT(idx) \ + static int gpio_siwx917_init_port_##idx##_(const struct device *dev); \ + static const struct gpio_siwx917_uulp_config gpio_siwx917_port_##idx##_config = { \ + .common = \ + { \ + .port_pin_mask = (gpio_port_pins_t)(-1), \ + }, \ + }; \ + static struct gpio_siwx917_uulp_data gpio_siwx917_port_##idx##_data; \ + \ + DEVICE_DT_INST_DEFINE(idx, gpio_siwx917_init_port_##idx##_, NULL, \ + &gpio_siwx917_port_##idx##_data, &gpio_siwx917_port_##idx##_config, \ + PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, \ + &gpio_siwx917_uulp_driver_api); \ + static int gpio_siwx917_init_port_##idx##_(const struct device *dev) \ + { \ + GPIO_NPSS_GPIO_CONFIG_REG = 0; \ + IRQ_CONNECT(DT_INST_IRQ(idx, irq), DT_INST_IRQ(idx, priority), \ + gpio_siwx917_uulp_isr, DEVICE_DT_GET(DT_DRV_INST(idx)), 0); \ + irq_enable(DT_INST_IRQ(idx, irq)); \ + return 0; \ + } + +DT_INST_FOREACH_STATUS_OKAY(GPIO_PORT_INIT) diff --git a/dts/arm/silabs/siwg917.dtsi b/dts/arm/silabs/siwg917.dtsi index 8ef7b76..f851508 100644 --- a/dts/arm/silabs/siwg917.dtsi +++ b/dts/arm/silabs/siwg917.dtsi @@ -59,6 +59,73 @@ current-speed = <115200>; status = "disabled"; }; + + gpio: gpio@46130000 { + compatible = "silabs,siwx917-gpio"; + reg = <0x46130000 0x1000>; + interrupts = <52 0>, <53 0>, <54 0>, <55 0>, + <56 0>, <57 0>, <58 0>, <59 0>; + interrupt-names = "PIN0", "PIN1", "PIN2", "PIN3", + "PIN4", "PIN5", "PIN6", "PIN7"; + + #address-cells = <1>; + #size-cells = <0>; + + gpioa: gpio@0 { + compatible = "silabs,siwx917-gpio-port"; + reg = <0>; + gpio-controller; + #gpio-cells = <2>; + status = "okay"; + }; + + gpiob: gpio@1 { + compatible = "silabs,siwx917-gpio-port"; + reg = <1>; + gpio-controller; + #gpio-cells = <2>; + status = "okay"; + }; + + gpioc: gpio@2 { + compatible = "silabs,siwx917-gpio-port"; + reg = <2>; + gpio-controller; + #gpio-cells = <2>; + status = "okay"; + }; + + gpiod: gpio@3 { + compatible = "silabs,siwx917-gpio-port"; + reg = <3>; + gpio-controller; + #gpio-cells = <2>; + status = "okay"; + }; + + gpioulp: gpio@4 { + compatible = "silabs,siwx917-gpio-port"; + reg = <4>; + interrupts = <18 0>; + interrupt-names = "ULP"; + + gpio-controller; + #gpio-cells = <2>; + status = "okay"; + }; + + gpiouulp: gpio@5 { + compatible = "silabs,siwx917-gpio-uulp"; + reg = <5>; + interrupts = <21 0>; + interrupt-names = "UULP"; + + gpio-controller; + #gpio-cells = <2>; + status = "okay"; + }; + + }; }; }; diff --git a/dts/bindings/gpio/silabs,siwx917-gpio-port.yaml b/dts/bindings/gpio/silabs,siwx917-gpio-port.yaml new file mode 100644 index 0000000..73fcd5f --- /dev/null +++ b/dts/bindings/gpio/silabs,siwx917-gpio-port.yaml @@ -0,0 +1,17 @@ +description: SiLabs SiWx917 GPIO port node + +compatible: "silabs,siwx917-gpio-port" + +include: [gpio-controller.yaml, base.yaml] + +properties: + + reg: + required: true + + "#gpio-cells": + const: 2 + +gpio-cells: + - pin + - flags diff --git a/dts/bindings/gpio/silabs,siwx917-gpio-uulp.yaml b/dts/bindings/gpio/silabs,siwx917-gpio-uulp.yaml new file mode 100644 index 0000000..de02739 --- /dev/null +++ b/dts/bindings/gpio/silabs,siwx917-gpio-uulp.yaml @@ -0,0 +1,17 @@ +description: SiLabs SiWx917 UULP GPIO port node + +compatible: "silabs,siwx917-gpio-uulp" + +include: [gpio-controller.yaml, base.yaml] + +properties: + + reg: + required: true + + "#gpio-cells": + const: 2 + +gpio-cells: + - pin + - flags diff --git a/dts/bindings/gpio/silabs,siwx917-gpio.yaml b/dts/bindings/gpio/silabs,siwx917-gpio.yaml new file mode 100644 index 0000000..8eb8765 --- /dev/null +++ b/dts/bindings/gpio/silabs,siwx917-gpio.yaml @@ -0,0 +1,12 @@ +description: SiLabs SiWx917 GPIO node + +compatible: "silabs,siwx917-gpio" + +include: base.yaml + +properties: + reg: + required: true + + interrupts: + required: true diff --git a/west.yml b/west.yml index 16752d7..ff84d1d 100644 --- a/west.yml +++ b/west.yml @@ -11,7 +11,7 @@ manifest: projects: - name: hal_silabs remote: silabs - revision: d3191b380c5a0975230881bcf21045e92189c263 + revision: pull/5/head path: modules/hal/silabs - name: zephyr remote: zephyrproject-rtos