|  | /* | 
|  | * SPDX-License-Identifier: Apache-2.0 | 
|  | * | 
|  | * Copyright (c) 2024 Realtek Semiconductor Corporation, SIBG-SD7 | 
|  | * Author: Lin Yu-Cheng <lin_yu_cheng@realtek.com> | 
|  | */ | 
|  |  | 
|  | #define DT_DRV_COMPAT realtek_rts5912_gpio | 
|  |  | 
|  | #include <errno.h> | 
|  | #include <zephyr/device.h> | 
|  | #include <zephyr/kernel.h> | 
|  | #include <zephyr/drivers/gpio.h> | 
|  | #include <zephyr/irq.h> | 
|  | #include "zephyr/drivers/gpio/gpio_utils.h" | 
|  | #include <zephyr/logging/log.h> | 
|  | #include <zephyr/dt-bindings/gpio/realtek-gpio.h> | 
|  |  | 
|  | #include <reg/reg_gpio.h> | 
|  |  | 
|  | LOG_MODULE_REGISTER(gpio_rts5912, CONFIG_GPIO_LOG_LEVEL); | 
|  |  | 
|  | #define RTS5912_GPIOA_REG_BASE ((GPIO_Type *)(DT_REG_ADDR(DT_NODELABEL(gpioa)))) | 
|  |  | 
|  | struct gpio_rts5912_config { | 
|  | struct gpio_driver_config common; | 
|  | volatile uint32_t *reg_base; | 
|  | uint8_t num_pins; | 
|  | }; | 
|  |  | 
|  | struct gpio_rts5912_data { | 
|  | struct gpio_driver_data common; | 
|  | sys_slist_t callbacks; | 
|  | }; | 
|  |  | 
|  | static int pin_is_valid(const struct gpio_rts5912_config *config, gpio_pin_t pin) | 
|  | { | 
|  | if (pin >= config->num_pins) { | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int pin_output_high(const struct device *port, gpio_pin_t pin) | 
|  | { | 
|  | const struct gpio_rts5912_config *config = port->config; | 
|  | volatile uint32_t *gcr = &config->reg_base[pin]; | 
|  |  | 
|  | int err = pin_is_valid(config, pin); | 
|  |  | 
|  | if (err) { | 
|  | return err; | 
|  | } | 
|  |  | 
|  | if (*gcr & GPIO_GCR_OUTMD_Msk) { | 
|  | /* Switch I/O mode to input mode when configuration is open-drain with output high | 
|  | */ | 
|  | *gcr = (*gcr & ~GPIO_GCR_DIR_Msk) | GPIO_GCR_OUTCTRL_Msk; | 
|  | } else { | 
|  | *gcr |= GPIO_GCR_OUTCTRL_Msk | GPIO_GCR_DIR_Msk; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int pin_output_low(const struct device *port, gpio_pin_t pin) | 
|  | { | 
|  | const struct gpio_rts5912_config *config = port->config; | 
|  | volatile uint32_t *gcr = &config->reg_base[pin]; | 
|  |  | 
|  | int err = pin_is_valid(config, pin); | 
|  |  | 
|  | if (err) { | 
|  | return err; | 
|  | } | 
|  |  | 
|  | *gcr = (*gcr & ~GPIO_GCR_OUTCTRL_Msk) | GPIO_GCR_DIR_Msk; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int gpio_rts5912_configuration(const struct device *port, gpio_pin_t pin, gpio_flags_t flags) | 
|  | { | 
|  | const struct gpio_rts5912_config *config = port->config; | 
|  | volatile uint32_t *gcr = &config->reg_base[pin]; | 
|  | uint32_t cfg_val = *gcr; | 
|  |  | 
|  | int err = pin_is_valid(config, pin); | 
|  |  | 
|  | if (err) { | 
|  | return err; | 
|  | } | 
|  |  | 
|  | if (flags & GPIO_INPUT) { | 
|  | cfg_val &= ~GPIO_GCR_DIR_Msk; | 
|  | cfg_val &= ~GPIO_GCR_OUTCTRL_Msk; | 
|  | /* enable input detect */ | 
|  | cfg_val |= GPIO_GCR_INDETEN_Msk; | 
|  | } | 
|  |  | 
|  | if (flags & GPIO_DISCONNECTED) { | 
|  | cfg_val &= ~GPIO_GCR_DIR_Msk; | 
|  | cfg_val &= ~GPIO_GCR_OUTCTRL_Msk; | 
|  | /* disable input detect */ | 
|  | cfg_val &= ~GPIO_GCR_INDETEN_Msk; | 
|  | } | 
|  |  | 
|  | if (flags & GPIO_OPEN_DRAIN) { | 
|  | cfg_val |= GPIO_GCR_OUTMD_Msk; | 
|  | } else { | 
|  | cfg_val &= ~GPIO_GCR_OUTMD_Msk; | 
|  | } | 
|  |  | 
|  | switch (flags & (GPIO_PULL_UP | GPIO_PULL_DOWN)) { | 
|  | case GPIO_PULL_UP: | 
|  | cfg_val &= ~GPIO_GCR_PULLDWEN_Msk; | 
|  | cfg_val |= GPIO_GCR_PULLUPEN_Msk; | 
|  | break; | 
|  | case GPIO_PULL_DOWN: | 
|  | cfg_val &= ~GPIO_GCR_PULLUPEN_Msk; | 
|  | cfg_val |= GPIO_GCR_PULLDWEN_Msk; | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  |  | 
|  | switch (flags & RTS5912_GPIO_VOLTAGE_MASK) { | 
|  | case RTS5912_GPIO_VOLTAGE_1V8: | 
|  | cfg_val |= GPIO_GCR_INVOLMD_Msk; | 
|  | break; | 
|  | case RTS5912_GPIO_VOLTAGE_DEFAULT: | 
|  | case RTS5912_GPIO_VOLTAGE_3V3: | 
|  | cfg_val &= ~GPIO_GCR_INVOLMD_Msk; | 
|  | break; | 
|  | case RTS5912_GPIO_VOLTAGE_5V0: | 
|  | return -ENOTSUP; | 
|  | default: | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (flags & RTS5912_GPIO_OUTDRV) { | 
|  | cfg_val |= GPIO_GCR_OUTDRV_Msk; | 
|  | } else { | 
|  | cfg_val &= ~GPIO_GCR_OUTDRV_Msk; | 
|  | } | 
|  |  | 
|  | if (flags & RTS5912_GPIO_SLEWRATE) { | 
|  | cfg_val |= GPIO_GCR_SLEWRATE_Msk; | 
|  | } else { | 
|  | cfg_val &= ~GPIO_GCR_SLEWRATE_Msk; | 
|  | } | 
|  |  | 
|  | if (flags & RTS5912_GPIO_SCHEN) { | 
|  | cfg_val |= GPIO_GCR_SCHEN_Msk; | 
|  | } else { | 
|  | cfg_val &= ~GPIO_GCR_SCHEN_Msk; | 
|  | } | 
|  |  | 
|  | cfg_val &= ~GPIO_GCR_MFCTRL_Msk; | 
|  | switch (flags & RTS5912_GPIO_MFCTRL_MASK) { | 
|  | case RTS5912_GPIO_MFCTRL_0: | 
|  | cfg_val |= (0U << GPIO_GCR_MFCTRL_Pos); | 
|  | break; | 
|  | case RTS5912_GPIO_MFCTRL_1: | 
|  | cfg_val |= (1U << GPIO_GCR_MFCTRL_Pos); | 
|  | break; | 
|  | case RTS5912_GPIO_MFCTRL_2: | 
|  | cfg_val |= (2U << GPIO_GCR_MFCTRL_Pos); | 
|  | break; | 
|  | case RTS5912_GPIO_MFCTRL_3: | 
|  | cfg_val |= (3U << GPIO_GCR_MFCTRL_Pos); | 
|  | break; | 
|  | default: | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | *gcr = cfg_val; | 
|  |  | 
|  | if (flags & GPIO_OUTPUT) { | 
|  | if (flags & GPIO_OUTPUT_INIT_HIGH) { | 
|  | pin_output_high(port, pin); | 
|  | } else if (flags & GPIO_OUTPUT_INIT_LOW) { | 
|  | pin_output_low(port, pin); | 
|  | } | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | #ifdef CONFIG_GPIO_GET_CONFIG | 
|  | static int gpio_rts5912_get_configuration(const struct device *port, gpio_pin_t pin, | 
|  | gpio_flags_t *flags) | 
|  | { | 
|  | const struct gpio_rts5912_config *config = port->config; | 
|  | volatile uint32_t *gcr = &config->reg_base[pin]; | 
|  | gpio_flags_t cfg_flag = 0x0UL; | 
|  |  | 
|  | int err = pin_is_valid(config, pin); | 
|  |  | 
|  | if (err) { | 
|  | return err; | 
|  | } | 
|  |  | 
|  | if (*gcr & GPIO_GCR_OUTCTRL_Msk) { | 
|  | cfg_flag |= GPIO_OUTPUT | GPIO_OUTPUT_INIT_HIGH; | 
|  | } else { | 
|  | if (*gcr & GPIO_GCR_DIR_Msk) { | 
|  | cfg_flag |= GPIO_OUTPUT | GPIO_OUTPUT_INIT_LOW; | 
|  | } else { | 
|  | cfg_flag |= GPIO_INPUT; | 
|  | if (*gcr & GPIO_GCR_INVOLMD_Msk) { | 
|  | cfg_flag |= RTS5912_GPIO_VOLTAGE_1V8; | 
|  | } else { | 
|  | cfg_flag |= RTS5912_GPIO_VOLTAGE_3V3; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (*gcr & GPIO_GCR_OUTMD_Msk) { | 
|  | cfg_flag |= GPIO_OPEN_DRAIN; | 
|  | } | 
|  |  | 
|  | if (*gcr & GPIO_GCR_PULLUPEN_Msk) { | 
|  | cfg_flag |= GPIO_PULL_UP; | 
|  | } else if (*gcr & GPIO_GCR_PULLDWEN_Msk) { | 
|  | cfg_flag |= GPIO_PULL_DOWN; | 
|  | } | 
|  |  | 
|  | if (*gcr & GPIO_GCR_INDETEN_Msk) { | 
|  | cfg_flag |= RTS5912_GPIO_INDETEN; | 
|  | } else { | 
|  | cfg_flag &= ~RTS5912_GPIO_INDETEN; | 
|  | } | 
|  |  | 
|  | if (*gcr & GPIO_GCR_OUTDRV_Msk) { | 
|  | cfg_flag |= RTS5912_GPIO_OUTDRV; | 
|  | } else { | 
|  | cfg_flag &= ~RTS5912_GPIO_OUTDRV; | 
|  | } | 
|  |  | 
|  | if (*gcr & GPIO_GCR_SLEWRATE_Msk) { | 
|  | cfg_flag |= RTS5912_GPIO_SLEWRATE; | 
|  | } else { | 
|  | cfg_flag &= ~RTS5912_GPIO_SLEWRATE; | 
|  | } | 
|  |  | 
|  | if (*gcr & GPIO_GCR_SCHEN_Msk) { | 
|  | cfg_flag |= RTS5912_GPIO_SCHEN; | 
|  | } else { | 
|  | cfg_flag &= ~RTS5912_GPIO_SCHEN; | 
|  | } | 
|  |  | 
|  | switch ((*gcr & GPIO_GCR_MFCTRL_Msk) >> GPIO_GCR_MFCTRL_Pos) { | 
|  | case 0: | 
|  | cfg_flag |= RTS5912_GPIO_MFCTRL_0; | 
|  | break; | 
|  | case 1: | 
|  | cfg_flag |= RTS5912_GPIO_MFCTRL_1; | 
|  | break; | 
|  | case 2: | 
|  | cfg_flag |= RTS5912_GPIO_MFCTRL_2; | 
|  | break; | 
|  | case 3: | 
|  | cfg_flag |= RTS5912_GPIO_MFCTRL_3; | 
|  | break; | 
|  | default: | 
|  | cfg_flag |= RTS5912_GPIO_MFCTRL_0; | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (*gcr & GPIO_GCR_INTEN_Msk) { | 
|  | switch (*gcr & GPIO_GCR_INTCTRL_Msk) { | 
|  | case GPIO_GCR_INTCTRL_TRIG_EDGE_HIGH: | 
|  | cfg_flag |= GPIO_INT_EDGE_RISING; | 
|  | break; | 
|  | case GPIO_GCR_INTCTRL_TRIG_EDGE_LOW: | 
|  | cfg_flag |= GPIO_INT_EDGE_FALLING; | 
|  | break; | 
|  | case GPIO_GCR_INTCTRL_TRIG_EDGE_BOTH: | 
|  | cfg_flag |= GPIO_INT_EDGE_BOTH; | 
|  | break; | 
|  | case GPIO_GCR_INTCTRL_TRIG_LEVEL_LOW: | 
|  | cfg_flag |= GPIO_INT_LEVEL_LOW; | 
|  | break; | 
|  | case GPIO_GCR_INTCTRL_TRIG_LEVEL_HIGH: | 
|  | cfg_flag |= GPIO_INT_LEVEL_HIGH; | 
|  | break; | 
|  | default: | 
|  | cfg_flag |= GPIO_INT_LEVEL_LOW; | 
|  | break; | 
|  | } | 
|  | } else { | 
|  | cfg_flag |= GPIO_INT_DISABLE; | 
|  | } | 
|  |  | 
|  | *flags = cfg_flag; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | static int gpio_rts5912_port_get_raw(const struct device *port, gpio_port_value_t *value) | 
|  | { | 
|  | const struct gpio_rts5912_config *config = port->config; | 
|  | gpio_port_value_t ret_val = 0; | 
|  | uint16_t mask = 0x1U; | 
|  |  | 
|  | for (gpio_pin_t i = 0; i < config->num_pins; i++) { | 
|  | if (config->reg_base[i] & GPIO_GCR_PINSTS_Msk) { | 
|  | ret_val |= (gpio_port_value_t)mask; | 
|  | } | 
|  | mask <<= 1; | 
|  | } | 
|  |  | 
|  | *value = ret_val; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int gpio_rts5912_port_set_masked_raw(const struct device *port, gpio_port_pins_t mask, | 
|  | gpio_port_value_t value) | 
|  | { | 
|  | const struct gpio_rts5912_config *config = port->config; | 
|  | uint32_t pin; | 
|  |  | 
|  | mask &= 0x0000FFFF; | 
|  | for (; mask; mask &= ~BIT(pin)) { | 
|  | pin = find_lsb_set(mask) - 1; | 
|  | if (pin >= config->num_pins) { | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (value & BIT(pin)) { | 
|  | pin_output_high(port, pin); | 
|  | } else { | 
|  | pin_output_low(port, pin); | 
|  | } | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int gpio_rts5912_port_set_bits_raw(const struct device *port, gpio_port_pins_t pins) | 
|  | { | 
|  | const struct gpio_rts5912_config *config = port->config; | 
|  | volatile uint32_t *gcr = config->reg_base; | 
|  | uint32_t pin = 0; | 
|  |  | 
|  | pins &= 0x0000FFFF; | 
|  | gpio_port_pins_t sel_pin = 1; | 
|  |  | 
|  | for (; pins;) { | 
|  | if (pins & sel_pin) { | 
|  | pin_output_high(port, pin); | 
|  | } | 
|  | pins &= ~sel_pin; | 
|  | sel_pin <<= 1; | 
|  | gcr++; | 
|  | pin++; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int gpio_rts5912_port_clear_bits_raw(const struct device *port, gpio_port_pins_t pins) | 
|  | { | 
|  | const struct gpio_rts5912_config *config = port->config; | 
|  | volatile uint32_t *gcr = config->reg_base; | 
|  | uint32_t pin = 0; | 
|  |  | 
|  | pins &= 0x0000FFFF; | 
|  | gpio_port_pins_t sel_pin = 1; | 
|  |  | 
|  | for (; pins;) { | 
|  | if (pins & sel_pin) { | 
|  | pin_output_low(port, pin); | 
|  | } | 
|  | pins &= ~sel_pin; | 
|  | sel_pin <<= 1; | 
|  | gcr++; | 
|  | pin++; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int gpio_rts5912_port_toggle_bits(const struct device *port, gpio_port_pins_t pins) | 
|  | { | 
|  | const struct gpio_rts5912_config *config = port->config; | 
|  | volatile uint32_t *gcr = config->reg_base; | 
|  | uint32_t pin = 0; | 
|  |  | 
|  | pins &= 0x0000FFFF; | 
|  | gpio_port_pins_t sel_pin = 0x1UL; | 
|  |  | 
|  | for (; pins;) { | 
|  | if (pins & sel_pin) { | 
|  | if (*gcr & GPIO_GCR_OUTCTRL_Msk) { | 
|  | pin_output_low(port, pin); | 
|  | } else { | 
|  | pin_output_high(port, pin); | 
|  | } | 
|  | } | 
|  |  | 
|  | pins &= ~sel_pin; | 
|  | sel_pin <<= 1; | 
|  | gcr++; | 
|  | pin++; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int gpio_rts5912_get_pin_num(const struct gpio_dt_spec *gpio) | 
|  | { | 
|  | const struct device *dev = gpio->port; | 
|  | const struct gpio_rts5912_config *config = dev->config; | 
|  | uint32_t gcr = (uint32_t)config->reg_base; | 
|  |  | 
|  | return (gcr - (uint32_t)(RTS5912_GPIOA_REG_BASE)) / 4 + gpio->pin; | 
|  | } | 
|  |  | 
|  | volatile uint32_t *gpio_rts5912_get_port_address(const struct gpio_dt_spec *gpio) | 
|  | { | 
|  | const struct device *dev = gpio->port; | 
|  | const struct gpio_rts5912_config *config = dev->config; | 
|  | volatile uint32_t *gcr = config->reg_base; | 
|  |  | 
|  | return gcr; | 
|  | } | 
|  |  | 
|  | gpio_pin_t gpio_rts5912_get_intr_pin(volatile uint32_t *reg_base) | 
|  | { | 
|  | gpio_pin_t pin = 0U; | 
|  |  | 
|  | for (; pin < 16; pin++) { | 
|  | if (reg_base[pin] & GPIO_GCR_INTSTS_Msk) { | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | return pin; | 
|  | } | 
|  |  | 
|  | static void gpio_rts5912_isr(const void *arg) | 
|  | { | 
|  | const struct device *port = arg; | 
|  | const struct gpio_rts5912_config *config = port->config; | 
|  | struct gpio_rts5912_data *data = port->data; | 
|  | volatile uint32_t *gcr = config->reg_base; | 
|  | unsigned int key = irq_lock(); | 
|  | gpio_pin_t pin = gpio_rts5912_get_intr_pin(gcr); | 
|  |  | 
|  | if (gcr[pin] & GPIO_GCR_INTSTS_Msk) { | 
|  | gcr[pin] |= GPIO_GCR_INTSTS_Msk; | 
|  |  | 
|  | gpio_fire_callbacks(&data->callbacks, port, BIT(pin)); | 
|  | } | 
|  | irq_unlock(key); | 
|  | } | 
|  |  | 
|  | static int gpio_rts5912_intr_config(const struct device *port, gpio_pin_t pin, | 
|  | enum gpio_int_mode mode, enum gpio_int_trig trig) | 
|  | { | 
|  | const struct gpio_rts5912_config *config = port->config; | 
|  | volatile uint32_t *gcr = &config->reg_base[pin]; | 
|  | uint32_t cfg_val = *gcr; | 
|  | uint32_t pin_index = | 
|  | DT_IRQ_BY_IDX(DT_NODELABEL(gpioa), 0, irq) + | 
|  | ((uint32_t)(&config->reg_base[pin]) - (uint32_t)(RTS5912_GPIOA_REG_BASE)) / 4; | 
|  |  | 
|  | int err = pin_is_valid(config, pin); | 
|  |  | 
|  | if (err) { | 
|  | return err; | 
|  | } | 
|  |  | 
|  | switch (mode) { | 
|  | case GPIO_INT_MODE_DISABLED: | 
|  | cfg_val &= ~GPIO_GCR_INTEN_Msk; | 
|  | irq_disable(pin_index); | 
|  | *gcr = cfg_val; | 
|  | return 0; | 
|  | case GPIO_INT_MODE_LEVEL: | 
|  | switch (trig) { | 
|  | case GPIO_INT_TRIG_LOW: | 
|  | cfg_val &= ~GPIO_GCR_INTCTRL_Msk; | 
|  | cfg_val |= GPIO_GCR_INTCTRL_TRIG_LEVEL_LOW; | 
|  | break; | 
|  | case GPIO_INT_TRIG_HIGH: | 
|  | cfg_val &= ~GPIO_GCR_INTCTRL_Msk; | 
|  | cfg_val |= GPIO_GCR_INTCTRL_TRIG_LEVEL_HIGH; | 
|  | break; | 
|  | default: | 
|  | return -EINVAL; | 
|  | } | 
|  | break; | 
|  | case GPIO_INT_MODE_EDGE: | 
|  | switch (trig) { | 
|  | case GPIO_INT_TRIG_LOW: | 
|  | cfg_val &= ~GPIO_GCR_INTCTRL_Msk; | 
|  | cfg_val |= GPIO_GCR_INTCTRL_TRIG_EDGE_LOW; | 
|  | break; | 
|  | case GPIO_INT_TRIG_HIGH: | 
|  | cfg_val &= ~GPIO_GCR_INTCTRL_Msk; | 
|  | cfg_val |= GPIO_GCR_INTCTRL_TRIG_EDGE_HIGH; | 
|  | break; | 
|  | case GPIO_INT_TRIG_BOTH: | 
|  | cfg_val &= ~GPIO_GCR_INTCTRL_Msk; | 
|  | cfg_val |= GPIO_GCR_INTCTRL_TRIG_EDGE_BOTH; | 
|  | break; | 
|  | default: | 
|  | return -EINVAL; | 
|  | } | 
|  | break; | 
|  | default: | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | /* enable interrupt */ | 
|  | cfg_val |= GPIO_GCR_INTEN_Msk; | 
|  | /* set value to GPIO register */ | 
|  | *gcr = cfg_val; | 
|  |  | 
|  | irq_enable(pin_index); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int gpio_rts5912_manage_cb(const struct device *port, struct gpio_callback *cb, bool set) | 
|  | { | 
|  | struct gpio_rts5912_data *data = port->data; | 
|  |  | 
|  | return gpio_manage_callback(&data->callbacks, cb, set); | 
|  | } | 
|  |  | 
|  | static DEVICE_API(gpio, gpio_rts5912_driver_api) = { | 
|  | .pin_configure = gpio_rts5912_configuration, | 
|  | #ifdef CONFIG_GPIO_GET_CONFIG | 
|  | .pin_get_config = gpio_rts5912_get_configuration, | 
|  | #endif | 
|  | .port_get_raw = gpio_rts5912_port_get_raw, | 
|  | .port_set_masked_raw = gpio_rts5912_port_set_masked_raw, | 
|  | .port_set_bits_raw = gpio_rts5912_port_set_bits_raw, | 
|  | .port_clear_bits_raw = gpio_rts5912_port_clear_bits_raw, | 
|  | .port_toggle_bits = gpio_rts5912_port_toggle_bits, | 
|  | .pin_interrupt_configure = gpio_rts5912_intr_config, | 
|  | .manage_callback = gpio_rts5912_manage_cb, | 
|  | }; | 
|  |  | 
|  | #ifdef CONFIG_GEN_ISR_TABLES | 
|  | #define RTS5912_GPIO_DTNAMIC_IRQ(id)                                                               \ | 
|  | for (int i = 0; i < 16 && (DT_INST_IRQ_BY_IDX(id, 0, irq) + i) < 132; i++) {               \ | 
|  | irq_connect_dynamic((DT_INST_IRQ_BY_IDX(id, 0, irq) + i),                          \ | 
|  | DT_INST_IRQ(id, priority), gpio_rts5912_isr,                   \ | 
|  | DEVICE_DT_INST_GET(id), 0U);                                   \ | 
|  | } | 
|  | #else | 
|  | #define RTS5912_GPIO_DTNAMIC_IRQ(id)                                                               \ | 
|  | IRQ_CONNECT(DT_INST_IRQN(id), DT_INST_IRQ(id, priority), gpio_rts5912_isr,                 \ | 
|  | DEVICE_DT_INST_GET(id), 0U); | 
|  | #endif | 
|  |  | 
|  | #define GPIO_RTS5912_INIT(id)                                                                      \ | 
|  | static int gpio_rts5912_init_##id(const struct device *dev)                                \ | 
|  | {                                                                                          \ | 
|  | if (!(DT_INST_IRQ_HAS_CELL(id, irq))) {                                            \ | 
|  | return 0;                                                                  \ | 
|  | }                                                                                  \ | 
|  | \ | 
|  | RTS5912_GPIO_DTNAMIC_IRQ(id)                                                       \ | 
|  | \ | 
|  | return 0;                                                                          \ | 
|  | }                                                                                          \ | 
|  | \ | 
|  | static struct gpio_rts5912_data gpio_rts5912_data_##id;                                    \ | 
|  | \ | 
|  | static const struct gpio_rts5912_config gpio_rts5912_config_##id = {                       \ | 
|  | .common = {.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(id)},                  \ | 
|  | .reg_base = (volatile uint32_t *)DT_INST_REG_ADDR(id),                             \ | 
|  | .num_pins = DT_INST_PROP(id, ngpios),                                              \ | 
|  | };                                                                                         \ | 
|  | DEVICE_DT_INST_DEFINE(id, gpio_rts5912_init_##id, NULL, &gpio_rts5912_data_##id,           \ | 
|  | &gpio_rts5912_config_##id, PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY,  \ | 
|  | &gpio_rts5912_driver_api); | 
|  |  | 
|  | DT_INST_FOREACH_STATUS_OKAY(GPIO_RTS5912_INIT) |