drivers: gpio: Add support for RZ/N2L

Add GPIO driver for RZ/N2L

Signed-off-by: Quang Le <quang.le.eb@bp.renesas.com>
Signed-off-by: Nhut Nguyen <nhut.nguyen.kc@renesas.com>
diff --git a/drivers/gpio/gpio_renesas_rz.c b/drivers/gpio/gpio_renesas_rz.c
index 386bae1..8692a64 100644
--- a/drivers/gpio/gpio_renesas_rz.c
+++ b/drivers/gpio/gpio_renesas_rz.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024 Renesas Electronics Corporation
+ * Copyright (c) 2024-2025 Renesas Electronics Corporation
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -15,6 +15,10 @@
 #include <zephyr/drivers/gpio/gpio_utils.h>
 #include "gpio_renesas_rz.h"
 #include <zephyr/logging/log.h>
+#if defined(CONFIG_SOC_SERIES_RZN2L)
+#include "r_icu.h"
+#include <zephyr/drivers/interrupt_controller/intc_rz_ext_irq.h>
+#endif
 LOG_MODULE_REGISTER(rz_gpio, CONFIG_GPIO_LOG_LEVEL);
 
 #define LOG_DEV_ERR(dev, format, ...) LOG_ERR("%s:" #format, (dev)->name, ##__VA_ARGS__)
@@ -28,7 +32,12 @@
 	const ioport_cfg_t *fsp_cfg;
 	const ioport_api_t *fsp_api;
 	const struct device *int_dev;
-	uint8_t tint_num[GPIO_RZ_MAX_TINT_NUM];
+	uint8_t int_num[GPIO_RZ_MAX_INT_NUM];
+#if defined(CONFIG_SOC_SERIES_RZN2L)
+	const struct device *eirq_dev[GPIO_RZ_MAX_INT_NUM];
+
+	void (*cb_list[GPIO_RZ_MAX_INT_NUM])(void *arg);
+#endif
 };
 
 struct gpio_rz_data {
@@ -36,15 +45,18 @@
 	sys_slist_t cb;
 	ioport_instance_ctrl_t *fsp_ctrl;
 	struct k_spinlock lock;
+#if defined(CONFIG_SOC_SERIES_RZN2L)
+	uint8_t pin[GPIO_RZ_MAX_INT_NUM];
+#endif
 };
 
-struct gpio_rz_tint_isr_data {
+struct gpio_rz_isr_data {
 	const struct device *gpio_dev;
 	gpio_pin_t pin;
 };
 
-struct gpio_rz_tint_data {
-	struct gpio_rz_tint_isr_data tint_data[GPIO_RZ_MAX_TINT_NUM];
+struct gpio_rz_int_data {
+	struct gpio_rz_isr_data gpio_mapping[GPIO_RZ_MAX_INT_NUM];
 	uint32_t irq_set_edge;
 };
 
@@ -70,18 +82,12 @@
 {
 	bsp_io_port_t port = (port_pin >> 8U) & 0xFF;
 	gpio_pin_t pin = port_pin & 0xFF;
-	volatile uint8_t *p_p = GPIO_RZ_IOPORT_P_REG_BASE_GET;
-	volatile uint16_t *p_pm = GPIO_RZ_IOPORT_PM_REG_BASE_GET;
+	volatile uint8_t *p_p = GPIO_RZ_IOPORT_P_REG_GET(port, pin);
+	volatile uint16_t *p_pm = GPIO_RZ_IOPORT_PM_REG_GET(port, pin);
 
-	uint8_t adr_offset;
 	uint8_t p_value;
 	uint16_t pm_value;
 
-	adr_offset = (uint8_t)GPIO_RZ_REG_OFFSET(port, pin);
-
-	p_p = &p_p[adr_offset];
-	p_pm = &p_pm[adr_offset];
-
 	p_value = GPIO_RZ_P_VALUE_GET(*p_p, pin);
 	pm_value = GPIO_RZ_PM_VALUE_GET(*p_pm, pin);
 
@@ -108,7 +114,11 @@
 
 	if (!flags) {
 		/* Disconnect mode */
+#if defined(CONFIG_SOC_SERIES_RZN2L)
+		GPIO_RZ_PIN_DISCONNECT(config->fsp_port, pin);
+#elif defined(CONFIG_SOC_SERIES_RZG3S)
 		ioport_config_data = 0;
+#endif /* CONFIG_SOC_SERIES_* */
 	} else if (!(flags & GPIO_OPEN_DRAIN)) {
 		/* PM register */
 		ioport_config_data &= GPIO_RZ_PIN_CONFIGURE_INPUT_OUTPUT_RESET;
@@ -136,7 +146,7 @@
 		if (flags & GPIO_PULL_UP) {
 			ioport_config_data |= IOPORT_CFG_PULLUP_ENABLE;
 		} else if (flags & GPIO_PULL_DOWN) {
-			ioport_config_data |= IOPORT_CFG_PULLUP_ENABLE;
+			ioport_config_data |= IOPORT_CFG_PULLDOWN_ENABLE;
 		}
 
 		/* ISEL register */
@@ -147,10 +157,14 @@
 		}
 
 		/* Drive Ability register */
-		ioport_config_data |= GPIO_RZ_PIN_CONFIGURE_GET_DRIVE_ABILITY(flags);
-
+		ioport_config_data |= GPIO_RZ_PIN_CONFIGURE_GET(flags);
+#if defined(CONFIG_SOC_SERIES_RZG3S)
 		/* Filter register, see in renesas-rz-gpio-ioport.h */
 		ioport_config_data |= GPIO_RZ_PIN_CONFIGURE_GET_FILTER(flags);
+#elif defined(CONFIG_SOC_SERIES_RZN2L)
+		/* RSEL reg */
+		ioport_config_data |= IOPORT_CFG_REGION_NSAFETY;
+#endif /* CONFIG_SOC_SERIES_* */
 	} else {
 		return -ENOTSUP;
 	}
@@ -251,60 +265,92 @@
 	return 0;
 }
 
-#define GPIO_RZ_HAS_INTERRUPT DT_HAS_COMPAT_STATUS_OKAY(renesas_rz_gpio_int)
+#define GPIO_RZ_HAS_INTERRUPT                                                                      \
+	DT_HAS_COMPAT_STATUS_OKAY(renesas_rz_gpio_int) |                                           \
+		DT_HAS_COMPAT_STATUS_OKAY(renesas_rz_ext_irq)
 
 #if GPIO_RZ_HAS_INTERRUPT
-static int gpio_rz_int_disable(const struct device *dev, uint8_t tint_num)
+static int gpio_rz_int_disable(const struct device *dev, const struct device *gpio_dev,
+			       uint8_t int_num, gpio_pin_t pin)
 {
-	struct gpio_rz_tint_data *data = dev->data;
+#if defined(CONFIG_SOC_SERIES_RZG3S)
 	volatile uint32_t *tssr = &R_INTC_IM33->TSSR0;
 	volatile uint32_t *titsr = &R_INTC_IM33->TITSR0;
 	volatile uint32_t *tscr = &R_INTC_IM33->TSCR;
+	struct gpio_rz_int_data *data = dev->data;
 
 	/* Get register offset base on interrupt number. */
-	tssr = &tssr[tint_num / 4];
-	titsr = &titsr[tint_num / 16];
+	tssr = &tssr[int_num / 4];
+	titsr = &titsr[int_num / 16];
 
-	irq_disable(GPIO_RZ_TINT_IRQ_GET(tint_num));
+	irq_disable(GPIO_RZ_TINT_IRQ_GET(int_num));
 	/* Disable interrupt and clear interrupt source. */
-	*tssr &= ~(0xFF << GPIO_RZ_TSSR_OFFSET(tint_num));
+	*tssr &= ~(0xFF << GPIO_RZ_TSSR_OFFSET(int_num));
 	/* Reset interrupt dectect type to default. */
-	*titsr &= ~(0x3 << GPIO_RZ_TITSR_OFFSET(tint_num));
+	*titsr &= ~(0x3 << GPIO_RZ_TITSR_OFFSET(int_num));
 
 	/* Clear interrupt detection status. */
-	if (data->irq_set_edge & BIT(tint_num)) {
-		*tscr &= ~BIT(tint_num);
-		data->irq_set_edge &= ~BIT(tint_num);
+	if (data->irq_set_edge & BIT(int_num)) {
+		*tscr &= ~BIT(int_num);
+		data->irq_set_edge &= ~BIT(int_num);
 	}
-	data->tint_data[tint_num].gpio_dev = NULL;
-	data->tint_data[tint_num].pin = UINT8_MAX;
+
+	data->gpio_mapping[int_num].gpio_dev = NULL;
+	data->gpio_mapping[int_num].pin = UINT8_MAX;
+#elif defined(CONFIG_SOC_SERIES_RZN2L)
+	const struct gpio_rz_config *gpio_config = gpio_dev->config;
+	const struct device *eirq_dev = gpio_config->eirq_dev[pin];
+
+	if (device_is_ready(eirq_dev)) {
+		intc_rz_ext_irq_disable(eirq_dev);
+	}
+#endif /* CONFIG_SOC_SERIES_* */
 
 	return 0;
 }
 
 static int gpio_rz_int_enable(const struct device *int_dev, const struct device *gpio_dev,
-			      uint8_t tint_num, uint8_t irq_type, gpio_pin_t pin)
+			      uint8_t int_num, uint8_t irq_type, gpio_pin_t pin)
 {
-	struct gpio_rz_tint_data *int_data = int_dev->data;
+	if (irq_type == GPIO_RZ_INT_UNSUPPORTED) {
+		return -ENOTSUP;
+	}
+
 	const struct gpio_rz_config *gpio_config = gpio_dev->config;
+
+#if defined(CONFIG_SOC_SERIES_RZG3S)
 	volatile uint32_t *tssr = &R_INTC_IM33->TSSR0;
 	volatile uint32_t *titsr = &R_INTC_IM33->TITSR0;
+	struct gpio_rz_int_data *int_data = int_dev->data;
 
-	tssr = &tssr[tint_num / 4];
-	titsr = &titsr[tint_num / 16];
+	tssr = &tssr[int_num / 4];
+	titsr = &titsr[int_num / 16];
 	/* Select interrupt detect type. */
-	*titsr |= (irq_type << GPIO_RZ_TITSR_OFFSET(tint_num));
+	*titsr &= ~(3U << GPIO_RZ_TITSR_OFFSET(int_num));
+	*titsr |= (irq_type << GPIO_RZ_TITSR_OFFSET(int_num));
 	/* Select interrupt source base on port and pin number.*/
-	*tssr |= (GPIO_RZ_TSSR_VAL(gpio_config->port_num, pin)) << GPIO_RZ_TSSR_OFFSET(tint_num);
+	*tssr |= (GPIO_RZ_TSSR_VAL(gpio_config->port_num, pin)) << GPIO_RZ_TSSR_OFFSET(int_num);
 
-	if (irq_type == GPIO_RZ_TINT_EDGE_RISING || irq_type == GPIO_RZ_TINT_EDGE_FALLING) {
-		int_data->irq_set_edge |= BIT(tint_num);
+	if (irq_type == GPIO_RZ_INT_EDGE_RISING || irq_type == GPIO_RZ_INT_EDGE_FALLING) {
+		int_data->irq_set_edge |= BIT(int_num);
 		/* Clear interrupt status. */
-		R_INTC_IM33->TSCR &= ~BIT(tint_num);
+		R_INTC_IM33->TSCR &= ~BIT(int_num);
 	}
-	int_data->tint_data[tint_num].gpio_dev = gpio_dev;
-	int_data->tint_data[tint_num].pin = pin;
-	irq_enable(GPIO_RZ_TINT_IRQ_GET(tint_num));
+	irq_enable(GPIO_RZ_TINT_IRQ_GET(int_num));
+	int_data->gpio_mapping[int_num].gpio_dev = gpio_dev;
+	int_data->gpio_mapping[int_num].pin = pin;
+#elif defined(CONFIG_SOC_SERIES_RZN2L)
+	const struct device *eirq_dev = gpio_config->eirq_dev[pin];
+	struct gpio_rz_data *gpio_data = gpio_dev->data;
+
+	gpio_data->pin[int_num] = pin;
+	if (device_is_ready(eirq_dev)) {
+		intc_rz_ext_irq_set_type(eirq_dev, irq_type);
+		intc_rz_ext_irq_enable(eirq_dev);
+		intc_rz_ext_irq_set_callback(eirq_dev, gpio_config->cb_list[int_num],
+					     (void *)gpio_dev);
+	}
+#endif /* CONFIG_SOC_SERIES_* */
 
 	return 0;
 }
@@ -315,54 +361,56 @@
 	const struct gpio_rz_config *config = dev->config;
 	struct gpio_rz_data *data = dev->data;
 	bsp_io_port_pin_t port_pin = config->fsp_port | pin;
-	uint8_t tint_num = config->tint_num[pin];
+	uint8_t int_num = config->int_num[pin];
 	uint8_t irq_type = 0;
 	gpio_flags_t pre_flags = 0;
 	k_spinlock_key_t key;
+	int ret = 0;
 
-	if (tint_num >= GPIO_RZ_MAX_TINT_NUM) {
-		LOG_DEV_ERR(dev, "Invalid TINT interrupt:%d >= %d", tint_num, GPIO_RZ_MAX_TINT_NUM);
+	if (int_num >= GPIO_RZ_MAX_INT_NUM) {
+		LOG_DEV_ERR(dev, "Invalid interrupt:%d >= %d", int_num, GPIO_RZ_MAX_INT_NUM);
 	}
 
 	if (pin > config->ngpios) {
 		return -EINVAL;
 	}
 
-	if (trig == GPIO_INT_TRIG_BOTH) {
-		return -ENOTSUP;
-	}
-
 	key = k_spin_lock(&data->lock);
 
 	if (mode == GPIO_INT_MODE_DISABLED) {
 		gpio_rz_pin_config_get_raw(port_pin, &pre_flags);
 		pre_flags |= GPIO_INT_DISABLE;
 		gpio_rz_pin_configure(dev, pin, pre_flags);
-		gpio_rz_int_disable(config->int_dev, tint_num);
+		gpio_rz_int_disable(config->int_dev, dev, int_num, pin);
 		goto exit_unlock;
 	}
 
 	if (mode == GPIO_INT_MODE_EDGE) {
-		irq_type = GPIO_RZ_TINT_EDGE_RISING;
 		if (trig == GPIO_INT_TRIG_LOW) {
-			irq_type = GPIO_RZ_TINT_EDGE_FALLING;
+			irq_type = GPIO_RZ_INT_EDGE_FALLING;
+		} else if (trig == GPIO_INT_TRIG_HIGH) {
+			irq_type = GPIO_RZ_INT_EDGE_RISING;
+		} else if (trig == GPIO_INT_TRIG_BOTH) {
+			irq_type = GPIO_RZ_INT_BOTH_EDGE;
 		}
 	} else {
-		irq_type = GPIO_RZ_TINT_LEVEL_HIGH;
 		if (trig == GPIO_INT_TRIG_LOW) {
-			irq_type = GPIO_RZ_TINT_LEVEL_LOW;
+			irq_type = GPIO_RZ_INT_LEVEL_LOW;
+		} else if (trig == GPIO_INT_TRIG_HIGH) {
+			irq_type = GPIO_RZ_INT_LEVEL_HIGH;
 		}
 	}
 
-	/* Set register ISEL */
-	gpio_rz_pin_config_get_raw(port_pin, &pre_flags);
-	pre_flags |= GPIO_INT_ENABLE;
-	gpio_rz_pin_configure(dev, pin, pre_flags);
-	gpio_rz_int_enable(config->int_dev, dev, tint_num, irq_type, pin);
+	ret = gpio_rz_int_enable(config->int_dev, dev, int_num, irq_type, pin);
+	if (ret == 0) {
+		gpio_rz_pin_config_get_raw(port_pin, &pre_flags);
+		pre_flags |= GPIO_INT_ENABLE;
+		gpio_rz_pin_configure(dev, pin, pre_flags);
+	}
 
 exit_unlock:
 	k_spin_unlock(&data->lock, key);
-	return 0;
+	return ret;
 }
 
 static int gpio_rz_manage_callback(const struct device *dev, struct gpio_callback *callback,
@@ -373,41 +421,37 @@
 	return gpio_manage_callback(&data->cb, callback, set);
 }
 
-static void gpio_rz_isr(const struct device *dev, uint8_t pin)
+static void gpio_rz_isr(uint16_t irq, void *param)
 {
-	struct gpio_rz_data *data = dev->data;
-
-	gpio_fire_callbacks(&data->cb, dev, BIT(pin));
-}
-
-static void gpio_rz_tint_isr(uint16_t irq, const struct device *dev)
-{
-	struct gpio_rz_tint_data *data = dev->data;
+#if defined(CONFIG_SOC_SERIES_RZG3S)
+	const struct device *dev = param;
+	struct gpio_rz_int_data *int_data = dev->data;
 	volatile uint32_t *tscr = &R_INTC_IM33->TSCR;
-	uint8_t tint_num;
 
-	tint_num = irq - GPIO_RZ_TINT_IRQ_OFFSET;
-
-	if (!(*tscr & BIT(tint_num))) {
-		LOG_DEV_DBG(dev, "tint:%u spurious irq, status 0", tint_num);
+	if (!(*tscr & BIT(irq))) {
+		LOG_DEV_DBG(dev, "tint:%u spurious irq, status 0", irq);
 		return;
 	}
 
-	if (data->irq_set_edge & BIT(tint_num)) {
-		*tscr &= ~BIT(tint_num);
+	if (int_data->irq_set_edge & BIT(irq)) {
+		*tscr &= ~BIT(irq);
 	}
 
-	gpio_rz_isr(data->tint_data[tint_num].gpio_dev, data->tint_data[tint_num].pin);
+	uint8_t pin = int_data->gpio_mapping[irq].pin;
+	const struct device *gpio_dev = int_data->gpio_mapping[irq].gpio_dev;
+	struct gpio_rz_data *gpio_data = gpio_dev->data;
+
+	gpio_fire_callbacks(&gpio_data->cb, gpio_dev, BIT(pin));
+#elif defined(CONFIG_SOC_SERIES_RZN2L)
+	const struct device *gpio_dev = (const struct device *)param;
+	struct gpio_rz_data *gpio_data = gpio_dev->data;
+	uint8_t pin = gpio_data->pin[irq];
+
+	gpio_fire_callbacks(&gpio_data->cb, gpio_dev, BIT(pin));
+#endif /* CONFIG_SOC_SERIES_* */
 }
 
-static int gpio_rz_int_init(const struct device *dev)
-{
-	const struct gpio_rz_tint_config *config = dev->config;
-
-	config->gpio_int_init();
-	return 0;
-}
-#endif
+#endif /* GPIO_RZ_HAS_INTERRUPT */
 
 static DEVICE_API(gpio, gpio_rz_driver_api) = {
 	.pin_configure = gpio_rz_pin_configure,
@@ -426,18 +470,29 @@
 };
 
 /*Initialize GPIO interrupt device*/
-#define GPIO_RZ_TINT_ISR_DECLARE(irq_num, node_id)                                                 \
-	static void rz_gpio_isr_##irq_num(void *param)                                             \
+#define GPIO_RZ_ISR_DEFINE(irq_num, _)                                                             \
+	static void rz_gpio_isr##irq_num(void *param)                                              \
 	{                                                                                          \
-		gpio_rz_tint_isr(DT_IRQ_BY_IDX(node_id, irq_num, irq), param);                     \
+		gpio_rz_isr(irq_num, param);                                                       \
 	}
 
-#define GPIO_RZ_TINT_ISR_INIT(node_id, irq_num) LISTIFY(irq_num,                                   \
-							GPIO_RZ_TINT_ISR_DECLARE, (), node_id)
+#define GPIO_RZ_ALL_ISR_DEFINE(irq_num) LISTIFY(irq_num, GPIO_RZ_ISR_DEFINE, ())
+
+#if defined(CONFIG_SOC_SERIES_RZG3S)
+
+#define GPIO_RZ_INT_DEFINE(inst) .int_dev = DEVICE_DT_GET_OR_NULL(DT_INST(0, renesas_rz_gpio_int))
+
+static int gpio_rz_int_init(const struct device *dev)
+{
+	const struct gpio_rz_tint_config *config = dev->config;
+
+	config->gpio_int_init();
+	return 0;
+}
 
 #define GPIO_RZ_TINT_CONNECT(irq_num, node_id)                                                     \
 	IRQ_CONNECT(DT_IRQ_BY_IDX(node_id, irq_num, irq),                                          \
-		    DT_IRQ_BY_IDX(node_id, irq_num, priority), rz_gpio_isr_##irq_num,              \
+		    DT_IRQ_BY_IDX(node_id, irq_num, priority), rz_gpio_isr##irq_num,               \
 		    DEVICE_DT_GET(node_id), 0);
 
 #define GPIO_RZ_TINT_CONNECT_FUNC(node_id)                                                         \
@@ -449,18 +504,42 @@
 	}
 /* Initialize GPIO device*/
 #define GPIO_RZ_INT_INIT(node_id)                                                                  \
-	GPIO_RZ_TINT_ISR_INIT(node_id, DT_NUM_IRQS(node_id))                                       \
+	GPIO_RZ_ALL_ISR_DEFINE(DT_NUM_IRQS(node_id))                                               \
 	GPIO_RZ_TINT_CONNECT_FUNC(node_id)                                                         \
 	static const struct gpio_rz_tint_config rz_gpio_tint_cfg_##node_id = {                     \
 		.gpio_int_init = rz_gpio_tint_connect_func##node_id,                               \
 	};                                                                                         \
-	static struct gpio_rz_tint_data rz_gpio_tint_data_##node_id = {};                          \
+	static struct gpio_rz_int_data rz_gpio_tint_data_##node_id = {};                           \
 	DEVICE_DT_DEFINE(node_id, gpio_rz_int_init, NULL, &rz_gpio_tint_data_##node_id,            \
 			 &rz_gpio_tint_cfg_##node_id, POST_KERNEL,                                 \
 			 UTIL_DEC(CONFIG_GPIO_INIT_PRIORITY), NULL);
-
 DT_FOREACH_STATUS_OKAY(renesas_rz_gpio_int, GPIO_RZ_INT_INIT)
 
+#elif defined(CONFIG_SOC_SERIES_RZN2L) && GPIO_RZ_HAS_INTERRUPT
+
+GPIO_RZ_ALL_ISR_DEFINE(GPIO_RZ_MAX_INT_NUM)
+
+#define EIRQ_CB_GET(eirq_line, _) [eirq_line] = rz_gpio_isr##eirq_line
+
+#define EIRQ_DEV_LABEL_GET(inst, idx) CONCAT(irq, DT_INST_PROP_BY_IDX(inst, irqs, UTIL_INC(idx)))
+
+#define EIRQ_DEV_GET(idx, inst)                                                                    \
+	COND_CODE_1(DT_INST_PROP_HAS_IDX(inst, irqs, idx),                                         \
+		    ([DT_INST_PROP_BY_IDX(inst, irqs, idx)] =                                      \
+			     DEVICE_DT_GET_OR_NULL(DT_NODELABEL(EIRQ_DEV_LABEL_GET(inst, idx))),), \
+		    ())
+
+#define ALL_EIRQ_DEV_GET(inst)                                                                     \
+	FOR_EACH_FIXED_ARG(EIRQ_DEV_GET, (), inst,                                                 \
+			   LISTIFY(DT_INST_PROP_LEN_OR(inst, irqs, 0), VALUE_2X, (,)))
+
+#define GPIO_RZ_INT_DEFINE(inst)                                                                   \
+	.eirq_dev = {ALL_EIRQ_DEV_GET(inst)},                                                      \
+	.cb_list = {LISTIFY(GPIO_RZ_MAX_INT_NUM, EIRQ_CB_GET, (,))}
+#else
+#define GPIO_RZ_INT_DEFINE(inst)
+#endif /* CONFIG_SOC_SERIES_* */
+
 #define VALUE_2X(i, _) UTIL_X2(i)
 #define PIN_IRQ_GET(idx, inst)                                                                     \
 	COND_CODE_1(DT_INST_PROP_HAS_IDX(inst, irqs, idx),                                         \
@@ -489,9 +568,8 @@
 		.ngpios = (uint8_t)DT_INST_PROP(inst, ngpios),                                     \
 		.fsp_cfg = &g_ioport_##inst##_cfg,                                                 \
 		.fsp_api = &g_ioport_on_ioport,                                                    \
-		.int_dev = DEVICE_DT_GET_OR_NULL(DT_INST(0, renesas_rz_gpio_int)),                 \
-		.tint_num = {PIN_IRQS_GET(inst)},                                                  \
-	};                                                                                         \
+		.int_num = {PIN_IRQS_GET(inst)},                                                   \
+		GPIO_RZ_INT_DEFINE(inst)};                                                         \
 	static ioport_instance_ctrl_t g_ioport_##inst##_ctrl;                                      \
 	static struct gpio_rz_data gpio_rz_##inst##_data = {                                       \
 		.fsp_ctrl = &g_ioport_##inst##_ctrl,                                               \
diff --git a/drivers/gpio/gpio_renesas_rz.h b/drivers/gpio/gpio_renesas_rz.h
index 6980450..e3ab3b8 100644
--- a/drivers/gpio/gpio_renesas_rz.h
+++ b/drivers/gpio/gpio_renesas_rz.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024 Renesas Electronics Corporation
+ * Copyright (c) 2024-2025 Renesas Electronics Corporation
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -7,35 +7,40 @@
 #ifndef ZEPHYR_DRIVERS_GPIO_RENESAS_RZ_H_
 #define ZEPHYR_DRIVERS_GPIO_RENESAS_RZ_H_
 
-#include <zephyr/dt-bindings/gpio/renesas-rz-gpio.h>
 #include "r_ioport.h"
 
+#define GPIO_RZ_INT_UNSUPPORTED 0xF
+
+#if defined(CONFIG_SOC_SERIES_RZG3S)
+#include <zephyr/dt-bindings/gpio/renesas-rz-gpio.h>
+
 #define GPIO_RZ_IOPORT_P_REG_BASE_GET  (&R_GPIO->P_20)
 #define GPIO_RZ_IOPORT_PM_REG_BASE_GET (&R_GPIO->PM_20)
 
-#define GPIO_RZ_REG_OFFSET(port, pin) (port + (pin / 4))
+#define GPIO_RZ_IOPORT_P_REG_GET(port, pin)  (&GPIO_RZ_IOPORT_P_REG_BASE_GET[port + (pin / 4)])
+#define GPIO_RZ_IOPORT_PM_REG_GET(port, pin) (&GPIO_RZ_IOPORT_PM_REG_BASE_GET[port + (pin / 4)])
 
 #define GPIO_RZ_P_VALUE_GET(value, pin)  ((value >> pin) & 1U)
 #define GPIO_RZ_PM_VALUE_GET(value, pin) ((value >> (pin * 2)) & 3U)
 
 #define GPIO_RZ_MAX_PORT_NUM 19
-#define GPIO_RZ_MAX_TINT_NUM 32
+#define GPIO_RZ_MAX_INT_NUM  32
 
 #define GPIO_RZ_TINT_IRQ_OFFSET        429
 #define GPIO_RZ_TINT_IRQ_GET(tint_num) (tint_num + GPIO_RZ_TINT_IRQ_OFFSET)
 
-#define GPIO_RZ_TINT_EDGE_RISING  0x0
-#define GPIO_RZ_TINT_EDGE_FALLING 0x1
-#define GPIO_RZ_TINT_LEVEL_HIGH   0x2
-#define GPIO_RZ_TINT_LEVEL_LOW    0x3
+#define GPIO_RZ_INT_EDGE_RISING  0x0
+#define GPIO_RZ_INT_EDGE_FALLING 0x1
+#define GPIO_RZ_INT_LEVEL_HIGH   0x2
+#define GPIO_RZ_INT_LEVEL_LOW    0x3
+#define GPIO_RZ_INT_BOTH_EDGE    GPIO_RZ_INT_UNSUPPORTED
 
 #define GPIO_RZ_TSSR_VAL(port, pin) (0x80 | (gpio_rz_int[port] + pin))
 #define GPIO_RZ_TSSR_OFFSET(irq)    ((irq % 4) * 8)
 #define GPIO_RZ_TITSR_OFFSET(irq)   ((irq % 16) * 2)
 
 #define GPIO_RZ_PIN_CONFIGURE_GET_FILTER(flag) (((flags >> RZG3S_GPIO_FILTER_SHIFT) & 0x1F) << 19U)
-#define GPIO_RZ_PIN_CONFIGURE_GET_DRIVE_ABILITY(flag)                                              \
-	(((flag >> RZG3S_GPIO_IOLH_SHIFT) & 0x3) << 10U)
+#define GPIO_RZ_PIN_CONFIGURE_GET(flag)        (((flag >> RZG3S_GPIO_IOLH_SHIFT) & 0x3) << 10U)
 
 #define GPIO_RZ_PIN_CONFIGURE_INT_ENABLE         IOPORT_CFG_TINT_ENABLE
 #define GPIO_RZ_PIN_CONFIGURE_INT_DISABLE        (~(IOPORT_CFG_TINT_ENABLE))
@@ -43,4 +48,43 @@
 
 static const uint8_t gpio_rz_int[GPIO_RZ_MAX_PORT_NUM] = {0,  4,  9,  13, 17, 23, 28, 33, 38, 43,
 							  47, 52, 56, 58, 63, 66, 70, 72, 76};
+
+#elif defined(CONFIG_SOC_SERIES_RZN2L)
+#include <zephyr/dt-bindings/gpio/renesas-rztn-gpio.h>
+#define GPIO_RZ_IOPORT_P_REG_REGION_GET(p)  (R_BSP_IoRegionGet(p) == BSP_IO_REGION_NOT_SAFE ? 1 : 0)
+#define GPIO_RZ_IOPORT_PM_REG_REGION_GET(p) (R_BSP_IoRegionGet(p) == BSP_IO_REGION_NOT_SAFE ? 1 : 0)
+
+#define GPIO_RZ_IOPORT_P_REG_BASE_GET(port, pin)                                                   \
+	(GPIO_RZ_IOPORT_P_REG_REGION_GET((port << 8U) | pin) == 1 ? &R_PORT_NSR->P[port]           \
+								  : &R_PORT_SR->P[port])
+
+#define GPIO_RZ_IOPORT_PM_REG_BASE_GET(port, pin)                                                  \
+	(GPIO_RZ_IOPORT_PM_REG_REGION_GET((port << 8U) | pin) == 1 ? &R_PORT_NSR->PM[port]         \
+								   : &R_PORT_SR->PM[port])
+
+#define GPIO_RZ_IOPORT_P_REG_GET(port, pin)  (GPIO_RZ_IOPORT_P_REG_BASE_GET(port, pin))
+#define GPIO_RZ_IOPORT_PM_REG_GET(port, pin) (GPIO_RZ_IOPORT_PM_REG_BASE_GET(port, pin))
+
+#define GPIO_RZ_P_VALUE_GET(value, pin)  ((value >> pin) & 1U)
+#define GPIO_RZ_PM_VALUE_GET(value, pin) ((value >> (pin * 2)) & 3U)
+
+#define GPIO_RZ_PIN_DISCONNECT(port, pin)                                                          \
+	*GPIO_RZ_IOPORT_PM_REG_GET((port >> 8U), pin) &= ~(3U << (pin * 2))
+
+#define GPIO_RZ_MAX_INT_NUM 16
+
+#define GPIO_RZ_INT_EDGE_FALLING 0x0
+#define GPIO_RZ_INT_EDGE_RISING  0x1
+#define GPIO_RZ_INT_BOTH_EDGE    0x2
+#define GPIO_RZ_INT_LEVEL_LOW    0x3
+#define GPIO_RZ_INT_LEVEL_HIGH   GPIO_RZ_INT_UNSUPPORTED
+
+#define GPIO_RZ_PIN_CONFIGURE_GET(flag) (((flag >> RZTN_GPIO_DRCTL_SHIFT) & 0x33) << 8U)
+
+#define GPIO_RZ_PIN_CONFIGURE_INT_ENABLE         (1U << 3)
+#define GPIO_RZ_PIN_CONFIGURE_INT_DISABLE        (~(1U << 3))
+#define GPIO_RZ_PIN_CONFIGURE_INPUT_OUTPUT_RESET (~(0x3 << 2))
+
+#endif /* CONFIG_SOC_* */
+
 #endif /* ZEPHYR_DRIVERS_GPIO_RENESAS_RZ_H_ */
diff --git a/dts/arm/renesas/rz/rzn/r9a07g084.dtsi b/dts/arm/renesas/rz/rzn/r9a07g084.dtsi
index b7d6ba7..9133045 100644
--- a/dts/arm/renesas/rz/rzn/r9a07g084.dtsi
+++ b/dts/arm/renesas/rz/rzn/r9a07g084.dtsi
@@ -242,6 +242,243 @@
 		pinctrl: pinctrl@800a0000 {
 			compatible = "renesas,rzn-pinctrl";
 			reg = <0x800a0000 0x1000 0x81030c00 0x1000>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			gpio0: gpio@0 {
+				compatible = "renesas,rz-gpio";
+				gpio-controller;
+				#gpio-cells = <2>;
+				ngpios = <8>;
+				reg = <0x0>;
+				status = "disabled";
+			};
+
+			gpio1: gpio@100 {
+				compatible = "renesas,rz-gpio";
+				gpio-controller;
+				#gpio-cells= <2>;
+				ngpios = <8>;
+				reg = <0x0100>;
+				status = "disabled";
+			};
+
+			gpio2: gpio@200 {
+				compatible = "renesas,rz-gpio";
+				gpio-controller;
+				#gpio-cells= <2>;
+				ngpios = <8>;
+				reg = <0x0200>;
+				status = "disabled";
+			};
+
+			gpio3: gpio@300 {
+				compatible = "renesas,rz-gpio";
+				gpio-controller;
+				#gpio-cells= <2>;
+				ngpios = <8>;
+				gpio-reserved-ranges = <1 4>;
+				reg = <0x0300>;
+				status = "disabled";
+			};
+
+			gpio4: gpio@400 {
+				compatible = "renesas,rz-gpio";
+				gpio-controller;
+				#gpio-cells= <2>;
+				ngpios = <8>;
+				gpio-reserved-ranges = <2 2>;
+				reg = <0x0400>;
+				status = "disabled";
+			};
+
+			gpio5: gpio@500 {
+				compatible = "renesas,rz-gpio";
+				gpio-controller;
+				#gpio-cells= <2>;
+				ngpios = <8>;
+				reg = <0x0500>;
+				status = "disabled";
+			};
+
+			gpio6: gpio@600 {
+				compatible = "renesas,rz-gpio";
+				gpio-controller;
+				#gpio-cells= <2>;
+				ngpios = <8>;
+				reg = <0x0600>;
+				status = "disabled";
+			};
+
+			gpio7: gpio@700 {
+				compatible = "renesas,rz-gpio";
+				gpio-controller;
+				#gpio-cells= <2>;
+				ngpios = <5>;
+				reg = <0x0700>;
+				status = "disabled";
+			};
+
+			gpio8: gpio@800 {
+				compatible = "renesas,rz-gpio";
+				gpio-controller;
+				#gpio-cells= <2>;
+				ngpios = <8>;
+				gpio-reserved-ranges = <0 4>;
+				reg = <0x0800>;
+				status = "disabled";
+			};
+
+			gpio9: gpio@900 {
+				compatible = "renesas,rz-gpio";
+				gpio-controller;
+				#gpio-cells= <2>;
+				ngpios = <8>;
+				reg = <0x0900>;
+				status = "disabled";
+			};
+
+			gpio10: gpio@a00 {
+				compatible = "renesas,rz-gpio";
+				gpio-controller;
+				#gpio-cells= <2>;
+				ngpios = <5>;
+				reg = <0x0a00>;
+				status = "disabled";
+			};
+
+			gpio11: gpio@b00 {
+				compatible = "renesas,rz-gpio";
+				gpio-controller;
+				#gpio-cells= <2>;
+				ngpios = <0>;
+				reg = <0x0b00>;
+				status = "disabled";
+			};
+
+			gpio12: gpio@c00 {
+				compatible = "renesas,rz-gpio";
+				gpio-controller;
+				#gpio-cells= <2>;
+				ngpios = <5>;
+				gpio-reserved-ranges = <0 4>;
+				reg = <0x0c00>;
+				status = "disabled";
+			};
+
+			gpio13: gpio@d00 {
+				compatible = "renesas,rz-gpio";
+				gpio-controller;
+				#gpio-cells= <2>;
+				ngpios = <8>;
+				gpio-reserved-ranges = <0 2>;
+				reg = <0x0d00>;
+				status = "disabled";
+			};
+
+			gpio14: gpio@e00 {
+				compatible = "renesas,rz-gpio";
+				gpio-controller;
+				#gpio-cells= <2>;
+				ngpios = <8>;
+				reg = <0x0e00>;
+				status = "disabled";
+			};
+
+			gpio15: gpio@f00 {
+				compatible = "renesas,rz-gpio";
+				gpio-controller;
+				#gpio-cells= <2>;
+				ngpios = <8>;
+				reg = <0x0f00>;
+				status = "disabled";
+			};
+
+			gpio16: gpio@1000 {
+				compatible = "renesas,rz-gpio";
+				gpio-controller;
+				#gpio-cells= <2>;
+				ngpios = <8>;
+				gpio-reserved-ranges = <4 1>;
+				reg = <0x1000>;
+				status = "disabled";
+			};
+
+			gpio17: gpio@1100 {
+				compatible = "renesas,rz-gpio";
+				gpio-controller;
+				#gpio-cells= <2>;
+				ngpios = <8>;
+				gpio-reserved-ranges = <1 2>;
+				reg = <0x1100>;
+				status = "disabled";
+			};
+
+			gpio18: gpio@1200 {
+				compatible = "renesas,rz-gpio";
+				gpio-controller;
+				#gpio-cells= <2>;
+				ngpios = <7>;
+				reg = <0x1200>;
+				status = "disabled";
+			};
+
+			gpio19: gpio@1300 {
+				compatible = "renesas,rz-gpio";
+				gpio-controller;
+				#gpio-cells= <2>;
+				ngpios = <1>;
+				reg = <0x1300>;
+				status = "disabled";
+			};
+
+			gpio20: gpio@1400 {
+				compatible = "renesas,rz-gpio";
+				gpio-controller;
+				#gpio-cells= <2>;
+				ngpios = <5>;
+				gpio-reserved-ranges = <0 1>;
+				reg = <0x1400>;
+				status = "disabled";
+			};
+
+			gpio21: gpio@1500 {
+				compatible = "renesas,rz-gpio";
+				gpio-controller;
+				#gpio-cells= <2>;
+				ngpios = <8>;
+				gpio-reserved-ranges = <0 1>;
+				reg = <0x1500>;
+				status = "disabled";
+			};
+
+			gpio22: gpio@1600 {
+				compatible = "renesas,rz-gpio";
+				gpio-controller;
+				#gpio-cells= <2>;
+				ngpios = <4>;
+				reg = <0x1600>;
+				status = "disabled";
+			};
+
+			gpio23: gpio@1700 {
+				compatible = "renesas,rz-gpio";
+				gpio-controller;
+				#gpio-cells= <2>;
+				ngpios = <8>;
+				gpio-reserved-ranges = <0 7>;
+				reg = <0x1700>;
+				status = "disabled";
+			};
+
+			gpio24: gpio@1800 {
+				compatible = "renesas,rz-gpio";
+				gpio-controller;
+				#gpio-cells= <2>;
+				ngpios = <3>;
+				reg = <0x1800>;
+				status = "disabled";
+			};
 		};
 
 		sci0: sci0@80001000 {
diff --git a/include/zephyr/dt-bindings/gpio/renesas-rztn-gpio.h b/include/zephyr/dt-bindings/gpio/renesas-rztn-gpio.h
new file mode 100644
index 0000000..22d4d3e
--- /dev/null
+++ b/include/zephyr/dt-bindings/gpio/renesas-rztn-gpio.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2025 Renesas Electronics Corporation
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_GPIO_RENESAS_RZTN_GPIO_H_
+#define ZEPHYR_INCLUDE_DT_BINDINGS_GPIO_RENESAS_RZTN_GPIO_H_
+
+/*********************************RZTN*****************************************/
+
+/**
+ * @brief RZTN specific GPIO Flags
+ * The pin driving ability flags are encoded in the 8 upper bits of @ref gpio_dt_flags_t as
+ * follows:
+ * - Bit 9..8: Driving ability control
+ * - Bit 12: Schmitt trigger control
+ * - Bit 13: Slew rate control
+ * Example:
+ * Driving ability control: Middle
+ * Schmitt trigger control: Enabled
+ * Slew rate control: Slow
+ * gpio-consumer {
+ *	out-gpios = <&port8 2 (GPIO_PULL_UP | RZTN_GPIO_CFG_SET(1, 1, 0))>;
+ * };
+ */
+
+/* GPIO DRCTL register */
+#define RZTN_GPIO_DRCTL_SHIFT        8U
+#define RZTN_GPIO_SCHMITT_TRIG_SHIFT 4U
+#define RZTN_GPIO_SLEW_RATE_SHIFT    5U
+#define RZTN_GPIO_DRCTL_SET(drive_ability, schmitt_trig, slew_rate)                                \
+	(((drive_ability) | ((schmitt_trig) << RZTN_GPIO_SCHMITT_TRIG_SHIFT) |                     \
+	  ((slew_rate) << RZTN_GPIO_SLEW_RATE_SHIFT))                                              \
+	 << RZTN_GPIO_DRCTL_SHIFT)
+
+/*******************************************************************************/
+
+#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_GPIO_RENESAS_RZTN_GPIO_H_ */
diff --git a/tests/drivers/gpio/gpio_basic_api/boards/rzn2l_rsk.overlay b/tests/drivers/gpio/gpio_basic_api/boards/rzn2l_rsk.overlay
new file mode 100644
index 0000000..85624d2
--- /dev/null
+++ b/tests/drivers/gpio/gpio_basic_api/boards/rzn2l_rsk.overlay
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2025 Renesas Electronics Corporation
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/ {
+	resources {
+		compatible = "test-gpio-basic-api";
+		out-gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>;
+		in-gpios = <&gpio2 0 GPIO_ACTIVE_HIGH>;
+	};
+};
+
+&pinctrl {
+	input_test: input_test {
+		group1 {
+			pinmux = <RZN_PINMUX(PORT_02, 0, 0)>;
+			input-enable;
+		};
+	};
+};
+
+&irq4 {
+	trigger-type = "falling";
+	pinctrl-0 = <&input_test>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&gpio2 {
+	irqs = <0 4>;
+	status = "okay";
+};