drivers: interrupt_controller: Add XMC4XXX ERU driver

In Infineon XMC4XXX SoCs, gpio interrupts are triggered via an
Event Request Unit (ERU) module. A subset of the gpios are
connected to the ERU. The ERU monitors edge triggers and creates
a SR.

This driver configures the ERU for a target port/pin combination
for rising/falling edge events. Note that the ERU module does
not generate SR based on the gpio level. Internally the ERU
tracks the *status* of an event. The status is set on a positive
edge and unset on a negative edge (or vice-versa depending on
the configuration). The value of the status is used to implement
a level triggered interrupt; The ISR checks the status flag and
calls the callback function if the status is set.

The ERU configurations for supported port/pin combinations are
stored in a devicetree file dts/arm/infineon/xmc4xxx_x_x-intc.dtsi.
The configurations are stored in the opaque array
uint16 port_line_mapping[].

Signed-off-by: Andriy Gelman <andriy.gelman@gmail.com>
diff --git a/boards/arm/xmc45_relax_kit/xmc45_relax_kit.dts b/boards/arm/xmc45_relax_kit/xmc45_relax_kit.dts
index 069740d..f338253 100644
--- a/boards/arm/xmc45_relax_kit/xmc45_relax_kit.dts
+++ b/boards/arm/xmc45_relax_kit/xmc45_relax_kit.dts
@@ -9,6 +9,7 @@
 /dts-v1/;
 
 #include <infineon/xmc4500_F100x1024.dtsi>
+#include <infineon/xmc4500_F100x1024-intc.dtsi>
 #include "xmc45_relax_kit-pinctrl.dtsi"
 
 / {
diff --git a/drivers/interrupt_controller/CMakeLists.txt b/drivers/interrupt_controller/CMakeLists.txt
index 5c09490..8c4fa09 100644
--- a/drivers/interrupt_controller/CMakeLists.txt
+++ b/drivers/interrupt_controller/CMakeLists.txt
@@ -31,6 +31,7 @@
 zephyr_library_sources_ifdef(CONFIG_VEXRISCV_LITEX_IRQ      intc_vexriscv_litex.c)
 zephyr_library_sources_ifdef(CONFIG_NUCLEI_ECLIC            intc_nuclei_eclic.c)
 zephyr_library_sources_ifdef(CONFIG_NXP_S32_EIRQ            intc_eirq_nxp_s32.c)
+zephyr_library_sources_ifdef(CONFIG_XMC4XXX_INTC            intc_xmc4xxx.c)
 
 if(CONFIG_INTEL_VTD_ICTL)
   zephyr_library_include_directories(${ZEPHYR_BASE}/arch/x86/include)
diff --git a/drivers/interrupt_controller/Kconfig b/drivers/interrupt_controller/Kconfig
index fd2bd20..d436bb8 100644
--- a/drivers/interrupt_controller/Kconfig
+++ b/drivers/interrupt_controller/Kconfig
@@ -83,4 +83,6 @@
 
 source "drivers/interrupt_controller/Kconfig.nxp_s32"
 
+source "drivers/interrupt_controller/Kconfig.xmc4xxx"
+
 endmenu
diff --git a/drivers/interrupt_controller/Kconfig.xmc4xxx b/drivers/interrupt_controller/Kconfig.xmc4xxx
new file mode 100644
index 0000000..e76b5c9
--- /dev/null
+++ b/drivers/interrupt_controller/Kconfig.xmc4xxx
@@ -0,0 +1,12 @@
+# XMC4XXX INTC configuration
+
+# Copyright (c) Schlumberger
+# SPDX-License-Identifier: Apache-2.0
+
+config XMC4XXX_INTC
+	bool "Interrupt Controller Driver for XMC4XXX series devices"
+	default y
+	depends on DT_HAS_INFINEON_XMC4XXX_INTC_ENABLED
+	help
+	  Enable interrupt controller driver for XMC4XXX series of devices. This is required for
+	  GPIO interrupt support.
diff --git a/drivers/interrupt_controller/intc_xmc4xxx.c b/drivers/interrupt_controller/intc_xmc4xxx.c
new file mode 100644
index 0000000..b5de41c
--- /dev/null
+++ b/drivers/interrupt_controller/intc_xmc4xxx.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2022 Schlumberger
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#define DT_DRV_COMPAT infineon_xmc4xxx_intc
+
+#include <zephyr/device.h>
+#include <zephyr/devicetree.h>
+#include <zephyr/drivers/gpio.h>
+#include <zephyr/dt-bindings/interrupt-controller/infineon-xmc4xxx-intc.h>
+#include <zephyr/irq.h>
+
+#include <xmc_eru.h>
+
+/* In Infineon XMC4XXX SoCs, gpio interrupts are triggered via an Event Request Unit (ERU) */
+/* module. A subset of the GPIOs are connected to the ERU. The ERU monitors edge triggers */
+/* and creates a SR. */
+
+/* This driver configures the ERU for a target port/pin combination for rising/falling */
+/* edge events. Note that the ERU module does not generate SR based on the gpio level. */
+/* Internally the ERU tracks the *status* of an event. The status is set on a positive edge and */
+/* unset on a negative edge (or vice-versa depending on the configuration). The value of */
+/* the status is used to implement a level triggered interrupt; The ISR checks the status */
+/* flag and calls the callback function if the status is set. */
+
+/* The ERU configurations for supported port/pin combinations are stored in a devicetree file */
+/* dts/arm/infineon/xmc4xxx_x_x-intc.dtsi. The configurations are stored in the opaque array */
+/* uint16 port_line_mapping[]. The bitfields for the opaque entries are defined in */
+/* dt-bindings/interrupt-controller/infineon-xmc4xxx-intc.h. */
+
+struct isr_cb {
+	/* if fn is NULL it implies the interrupt line has not been allocated */
+	void (*fn)(const struct device *dev, int pin);
+	void *data;
+	enum gpio_int_mode mode;
+	uint8_t port_id;
+	uint8_t pin;
+};
+
+#define MAX_ISR_NUM 8
+struct intc_xmc4xxx_data {
+	struct isr_cb cb[MAX_ISR_NUM];
+};
+
+#define NUM_ERUS 2
+struct intc_xmc4xxx_config {
+	XMC_ERU_t *eru_regs[NUM_ERUS];
+};
+
+static const uint16_t port_line_mapping[DT_INST_PROP_LEN(0, port_line_mapping)] =
+				DT_INST_PROP(0, port_line_mapping);
+
+int intc_xmc4xxx_gpio_enable_interrupt(int port_id, int pin, enum gpio_int_mode mode,
+				       enum gpio_int_trig trig,
+				       void (*fn)(const struct device *, int), void *user_data)
+{
+	const struct device *dev = DEVICE_DT_INST_GET(0);
+	struct intc_xmc4xxx_data *data = dev->data;
+	const struct intc_xmc4xxx_config *config = dev->config;
+	int ret = -ENOTSUP;
+
+	for (int i = 0; i < ARRAY_SIZE(port_line_mapping); i++) {
+		XMC_ERU_ETL_CONFIG_t etl_config = {0};
+		XMC_ERU_OGU_CONFIG_t isr_config = {0};
+		XMC_ERU_ETL_EDGE_DETECTION_t trig_xmc;
+		XMC_ERU_t *eru;
+		int port_map, pin_map, line, eru_src, eru_ch;
+		struct isr_cb *cb;
+
+		port_map = XMC4XXX_INTC_GET_PORT(port_line_mapping[i]);
+		pin_map  = XMC4XXX_INTC_GET_PIN(port_line_mapping[i]);
+
+		if (port_map != port_id || pin_map != pin) {
+			continue;
+		}
+
+		line = XMC4XXX_INTC_GET_LINE(port_line_mapping[i]);
+		cb = &data->cb[line];
+		if (cb->fn) {
+			/* It's already used. Continue search for available line */
+			/* with same port/pin */
+			ret = -EBUSY;
+			continue;
+		}
+
+		eru_src = XMC4XXX_INTC_GET_ERU_SRC(port_line_mapping[i]);
+		eru_ch  = line & 0x3;
+
+		if (trig == GPIO_INT_TRIG_HIGH) {
+			trig_xmc = XMC_ERU_ETL_EDGE_DETECTION_RISING;
+		} else if (trig == GPIO_INT_TRIG_LOW) {
+			trig_xmc = XMC_ERU_ETL_EDGE_DETECTION_FALLING;
+		} else if (trig == GPIO_INT_TRIG_BOTH) {
+			trig_xmc = XMC_ERU_ETL_EDGE_DETECTION_BOTH;
+		} else {
+			return -EINVAL;
+		}
+
+		cb->port_id = port_id;
+		cb->pin = pin;
+		cb->mode = mode;
+		cb->fn = fn;
+		cb->data = user_data;
+
+		/* setup the eru */
+		etl_config.edge_detection = trig_xmc;
+		etl_config.input_a = eru_src;
+		etl_config.input_b = eru_src;
+		etl_config.source = eru_src >> 2;
+		etl_config.status_flag_mode = XMC_ERU_ETL_STATUS_FLAG_MODE_HWCTRL;
+		etl_config.enable_output_trigger = 1;
+		etl_config.output_trigger_channel = eru_ch;
+
+		eru = config->eru_regs[line >> 2];
+
+		XMC_ERU_ETL_Init(eru, eru_ch, &etl_config);
+
+		isr_config.service_request = XMC_ERU_OGU_SERVICE_REQUEST_ON_TRIGGER;
+		XMC_ERU_OGU_Init(eru, eru_ch, &isr_config);
+
+		/* if the gpio level is already set then we must manually set the interrupt to */
+		/* pending */
+		if (mode == GPIO_INT_MODE_LEVEL) {
+			ret = gpio_pin_get_raw(user_data, pin);
+			if (ret < 0) {
+				return ret;
+			}
+#define NVIC_ISPR_BASE 0xe000e200u
+			if ((ret == 0 && trig == GPIO_INT_TRIG_LOW) ||
+			    (ret == 1 && trig == GPIO_INT_TRIG_HIGH)) {
+				eru->EXICON_b[eru_ch].FL = 1;
+				/* put interrupt into pending state */
+				*(uint32_t *)(NVIC_ISPR_BASE) |= BIT(line + 1);
+			}
+		}
+
+		return 0;
+	}
+	return ret;
+}
+
+int intc_xmc4xxx_gpio_disable_interrupt(int port_id, int pin)
+{
+	const struct device *dev = DEVICE_DT_INST_GET(0);
+	const struct intc_xmc4xxx_config *config = dev->config;
+	struct intc_xmc4xxx_data *data = dev->data;
+	int eru_ch;
+
+	for (int line = 0; line < ARRAY_SIZE(data->cb); line++) {
+		struct isr_cb *cb;
+
+		cb = &data->cb[line];
+		eru_ch = line & 0x3;
+		if (cb->fn && cb->port_id == port_id && cb->pin == pin) {
+			XMC_ERU_t *eru = config->eru_regs[line >> 2];
+
+			cb->fn = NULL;
+			/* disable the SR */
+			eru->EXICON_b[eru_ch].PE = 0;
+			/* unset the status flag */
+			eru->EXICON_b[eru_ch].FL = 0;
+			/* no need to clear other variables in cb*/
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+static void intc_xmc4xxx_isr(void *arg)
+{
+	int line = (int)arg;
+	const struct device *dev = DEVICE_DT_INST_GET(0);
+	struct intc_xmc4xxx_data *data = dev->data;
+	const struct intc_xmc4xxx_config *config = dev->config;
+	struct isr_cb *cb = &data->cb[line];
+	XMC_ERU_t *eru = config->eru_regs[line >> 2];
+	int eru_ch = line & 0x3;
+
+	/* The callback function may actually disable the interrupt and set cb->fn = NULL */
+	/* as is done in tests/drivers/gpio/gpio_api_1pin. Assume that the callback function */
+	/* will NOT disable the interrupt and then enable another port/pin */
+	/* in the same callback which could potentially set cb->fn again. */
+	while (cb->fn) {
+		cb->fn(cb->data, cb->pin);
+		/* for level triggered interrupts we have to manually check the status. */
+		if (cb->mode == GPIO_INT_MODE_LEVEL && eru->EXICON_b[eru_ch].FL == 1) {
+			continue;
+		}
+		/* break for edge triggered interrupts */
+		break;
+	}
+}
+
+#define INTC_IRQ_CONNECT_ENABLE(name, line_number)                                                \
+	COND_CODE_1(DT_INST_IRQ_HAS_NAME(0, name),                                                \
+	(IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, name, irq),                                           \
+		DT_INST_IRQ_BY_NAME(0, name, priority), intc_xmc4xxx_isr, (void *)line_number, 0); \
+		irq_enable(DT_INST_IRQ_BY_NAME(0, name, irq));), ())
+
+static int intc_xmc4xxx_init(const struct device *dev)
+{
+	/* connect irqs only if they defined by name in the dts */
+	INTC_IRQ_CONNECT_ENABLE(eru0sr0, 0);
+	INTC_IRQ_CONNECT_ENABLE(eru0sr1, 1);
+	INTC_IRQ_CONNECT_ENABLE(eru0sr2, 2);
+	INTC_IRQ_CONNECT_ENABLE(eru0sr3, 3);
+	INTC_IRQ_CONNECT_ENABLE(eru1sr0, 4);
+	INTC_IRQ_CONNECT_ENABLE(eru1sr1, 5);
+	INTC_IRQ_CONNECT_ENABLE(eru1sr2, 6);
+	INTC_IRQ_CONNECT_ENABLE(eru1sr3, 7);
+	return 0;
+}
+
+struct intc_xmc4xxx_data intc_xmc4xxx_data0;
+
+struct intc_xmc4xxx_config intc_xmc4xxx_config0 = {
+	.eru_regs = {
+		(XMC_ERU_t *)DT_INST_REG_ADDR_BY_NAME(0, eru0),
+		(XMC_ERU_t *)DT_INST_REG_ADDR_BY_NAME(0, eru1),
+	},
+};
+
+DEVICE_DT_INST_DEFINE(0, intc_xmc4xxx_init, NULL,
+		&intc_xmc4xxx_data0, &intc_xmc4xxx_config0, PRE_KERNEL_1,
+		CONFIG_INTC_INIT_PRIORITY, NULL);
diff --git a/dts/arm/infineon/xmc4500_F100x1024-intc.dtsi b/dts/arm/infineon/xmc4500_F100x1024-intc.dtsi
new file mode 100644
index 0000000..d70c845
--- /dev/null
+++ b/dts/arm/infineon/xmc4500_F100x1024-intc.dtsi
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2022 Schlumberger
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <zephyr/dt-bindings/interrupt-controller/infineon-xmc4xxx-intc.h>
+
+&intc {
+	port-line-mapping = <
+	XMC4XXX_INTC_SET_LINE_MAP(0, 1, 0, 0)     /* ERU0_ETL0_INPUTA_P0_1   XMC_ERU_ETL_INPUT_A0 */
+	XMC4XXX_INTC_SET_LINE_MAP(2, 5, 2, 0)     /* ERU0_ETL0_INPUTA_P2_5   XMC_ERU_ETL_INPUT_A2 */
+	XMC4XXX_INTC_SET_LINE_MAP(3, 2, 1, 0)     /* ERU0_ETL0_INPUTA_P3_2   XMC_ERU_ETL_INPUT_A1 */
+	XMC4XXX_INTC_SET_LINE_MAP(0, 0, 4, 0)     /* ERU0_ETL0_INPUTB_P0_0   XMC_ERU_ETL_INPUT_B0 */
+	XMC4XXX_INTC_SET_LINE_MAP(2, 0, 7, 0)     /* ERU0_ETL0_INPUTB_P2_0   XMC_ERU_ETL_INPUT_B3 */
+	XMC4XXX_INTC_SET_LINE_MAP(2, 4, 6, 0)     /* ERU0_ETL0_INPUTB_P2_4   XMC_ERU_ETL_INPUT_B2 */
+	XMC4XXX_INTC_SET_LINE_MAP(3, 1, 5, 0)     /* ERU0_ETL0_INPUTB_P3_1   XMC_ERU_ETL_INPUT_B1 */
+	XMC4XXX_INTC_SET_LINE_MAP(0, 10, 0, 1)    /* ERU0_ETL1_INPUTA_P0_10  XMC_ERU_ETL_INPUT_A0 */
+	XMC4XXX_INTC_SET_LINE_MAP(2, 3, 2, 1)     /* ERU0_ETL1_INPUTA_P2_3   XMC_ERU_ETL_INPUT_A2 */
+	XMC4XXX_INTC_SET_LINE_MAP(0, 9, 4, 1)     /* ERU0_ETL1_INPUTB_P0_9   XMC_ERU_ETL_INPUT_B0 */
+	XMC4XXX_INTC_SET_LINE_MAP(2, 2, 6, 1)     /* ERU0_ETL1_INPUTB_P2_2   XMC_ERU_ETL_INPUT_B2 */
+	XMC4XXX_INTC_SET_LINE_MAP(2, 6, 7, 1)     /* ERU0_ETL1_INPUTB_P2_6   XMC_ERU_ETL_INPUT_B3 */
+	XMC4XXX_INTC_SET_LINE_MAP(0, 8, 1, 2)     /* ERU0_ETL2_INPUTA_P0_8   XMC_ERU_ETL_INPUT_A1 */
+	XMC4XXX_INTC_SET_LINE_MAP(1, 5, 0, 2)     /* ERU0_ETL2_INPUTA_P1_5   XMC_ERU_ETL_INPUT_A0 */
+	XMC4XXX_INTC_SET_LINE_MAP(0, 12, 6, 2)    /* ERU0_ETL2_INPUTB_P0_12  XMC_ERU_ETL_INPUT_B2 */
+	XMC4XXX_INTC_SET_LINE_MAP(0, 4, 7, 2)     /* ERU0_ETL2_INPUTB_P0_4   XMC_ERU_ETL_INPUT_B3 */
+	XMC4XXX_INTC_SET_LINE_MAP(0, 7, 5, 2)     /* ERU0_ETL2_INPUTB_P0_7   XMC_ERU_ETL_INPUT_B1 */
+	XMC4XXX_INTC_SET_LINE_MAP(1, 4, 4, 2)     /* ERU0_ETL2_INPUTB_P1_4   XMC_ERU_ETL_INPUT_B0 */
+	XMC4XXX_INTC_SET_LINE_MAP(0, 11, 2, 3)    /* ERU0_ETL3_INPUTA_P0_11  XMC_ERU_ETL_INPUT_A2 */
+	XMC4XXX_INTC_SET_LINE_MAP(1, 1, 0, 3)     /* ERU0_ETL3_INPUTA_P1_1   XMC_ERU_ETL_INPUT_A0 */
+	XMC4XXX_INTC_SET_LINE_MAP(3, 6, 1, 3)     /* ERU0_ETL3_INPUTA_P3_6   XMC_ERU_ETL_INPUT_A1 */
+	XMC4XXX_INTC_SET_LINE_MAP(0, 2, 7, 3)     /* ERU0_ETL3_INPUTB_P0_2   XMC_ERU_ETL_INPUT_B3 */
+	XMC4XXX_INTC_SET_LINE_MAP(0, 6, 6, 3)     /* ERU0_ETL3_INPUTB_P0_6   XMC_ERU_ETL_INPUT_B2 */
+	XMC4XXX_INTC_SET_LINE_MAP(1, 0, 4, 3)     /* ERU0_ETL3_INPUTB_P1_0   XMC_ERU_ETL_INPUT_B0 */
+	XMC4XXX_INTC_SET_LINE_MAP(3, 5, 5, 3)     /* ERU0_ETL3_INPUTB_P3_5   XMC_ERU_ETL_INPUT_B1 */
+	XMC4XXX_INTC_SET_LINE_MAP(1, 5, 0, 4)     /* ERU1_ETL0_INPUTA_P1_5   XMC_ERU_ETL_INPUT_A0 */
+	XMC4XXX_INTC_SET_LINE_MAP(2, 1, 4, 4)     /* ERU1_ETL0_INPUTB_P2_1   XMC_ERU_ETL_INPUT_B0 */
+	XMC4XXX_INTC_SET_LINE_MAP(1, 15, 0, 5)    /* ERU1_ETL1_INPUTA_P1_15  XMC_ERU_ETL_INPUT_A0 */
+	XMC4XXX_INTC_SET_LINE_MAP(2, 7, 4, 5)     /* ERU1_ETL1_INPUTB_P2_7   XMC_ERU_ETL_INPUT_B0 */
+	XMC4XXX_INTC_SET_LINE_MAP(1, 3, 0, 6)     /* ERU1_ETL2_INPUTA_P1_3   XMC_ERU_ETL_INPUT_A0 */
+	XMC4XXX_INTC_SET_LINE_MAP(1, 2, 4, 6)     /* ERU1_ETL2_INPUTB_P1_2   XMC_ERU_ETL_INPUT_B0 */
+	XMC4XXX_INTC_SET_LINE_MAP(0, 5, 0, 7)     /* ERU1_ETL3_INPUTA_P0_5   XMC_ERU_ETL_INPUT_A0 */
+	XMC4XXX_INTC_SET_LINE_MAP(0, 3, 4, 7)     /* ERU1_ETL3_INPUTB_P0_3   XMC_ERU_ETL_INPUT_B0 */
+	>;
+};
diff --git a/dts/arm/infineon/xmc4xxx.dtsi b/dts/arm/infineon/xmc4xxx.dtsi
index 85628cd..cb7071b 100644
--- a/dts/arm/infineon/xmc4xxx.dtsi
+++ b/dts/arm/infineon/xmc4xxx.dtsi
@@ -51,6 +51,16 @@
 	};
 
 	soc {
+		intc: eru@40044000 {
+			compatible = "infineon,xmc4xxx-intc";
+			reg = <0x40044000 0xff>, <0x50004800 0xff>;
+			/* naming order is intentional. eru1 maps to a lower address than eru0 */
+			reg-names = "eru1", "eru0";
+			interrupts = <1 1>, <2 1>, <3 1>, <4 1>, <5 1>, <6 1>, <7 1>, <8 1>;
+			interrupt-names = "eru0sr0", "eru0sr1", "eru0sr2", "eru0sr3",
+					"eru1sr0", "eru1sr1", "eru1sr2", "eru1sr3";
+		};
+
 		pinctrl: pinctrl@48028000 {
 			compatible = "infineon,xmc4xxx-pinctrl";
 			#address-cells = <1>;
diff --git a/dts/bindings/interrupt-controller/infineon,xmc4xxx-intc.yaml b/dts/bindings/interrupt-controller/infineon,xmc4xxx-intc.yaml
new file mode 100644
index 0000000..cb09476
--- /dev/null
+++ b/dts/bindings/interrupt-controller/infineon,xmc4xxx-intc.yaml
@@ -0,0 +1,22 @@
+description: Infineon XMC4XXX series Interrupt Controller
+
+compatible: "infineon,xmc4xxx-intc"
+
+include: base.yaml
+
+properties:
+  reg:
+    required: true
+
+  port-line-mapping:
+    type: array
+    required: true
+    description: |
+      An array to store the Event Request Unit (ERU) configuration for a given port/pin
+      combintation. The array elements are opaque fields set using the macro
+      XMC4XXX_INTC_SET_LINE_MAP(port, pin, eru_src, line);
+      eru_src defines where the specific port/pin combination is connected in the ERU.
+      line defines the SR line that will be raised by the event.
+
+  interrupts:
+    required: true
diff --git a/include/zephyr/drivers/interrupt_controller/intc_xmc4xxx.h b/include/zephyr/drivers/interrupt_controller/intc_xmc4xxx.h
new file mode 100644
index 0000000..af6a865
--- /dev/null
+++ b/include/zephyr/drivers/interrupt_controller/intc_xmc4xxx.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2022 Schlumberger
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef ZEPHYR_DRIVERS_INTERRUPT_CONTROLLER_XMC4XXX_INTC_H_
+#define ZEPHYR_DRIVERS_INTERRUPT_CONTROLLER_XMC4XXX_INTC_H_
+
+/**
+ * @brief Enable interrupt for specific port_id and pin combination
+ *
+ * @param port_id Port index
+ * @param pin pin Pin the port
+ * @param mode Level or edge interrupt
+ * @param trig Trigger edge type (falling, rising or both)
+ * @param fn Callback function
+ * @param user_data Parameter to the interrupt callback
+ *
+ * @retval  0 On success
+ * @retval -ENOTSUP If the specific port_id/pin combination is not supported or
+ * not defined in the dts
+ * @retval -EBUSY  If the interrupt line is already used by a different port_id/pin
+ * @retval -EINVAL If the trigger combination is invalid
+ *
+ */
+
+int intc_xmc4xxx_gpio_enable_interrupt(int port_id, int pin, enum gpio_int_mode mode,
+		enum gpio_int_trig trig, void(*fn)(const struct device*, int), void *user_data);
+
+/**
+ * @brief Disable interrupt for specific port_id and pin combination
+ *
+ * @param port_id Port index
+ * @param pin pin Pin the port
+ * @retval 0 On susccess
+ * @retval -EINVAL If the specific port_id and pin combination has no interrupt
+ * enabled
+ */
+
+int intc_xmc4xxx_gpio_disable_interrupt(int port_id, int pin);
+
+#endif /* ZEPHYR_DRIVERS_INTERRUPT_CONTROLLER_XMC4XXX_INTC_H_ */
diff --git a/include/zephyr/dt-bindings/interrupt-controller/infineon-xmc4xxx-intc.h b/include/zephyr/dt-bindings/interrupt-controller/infineon-xmc4xxx-intc.h
new file mode 100644
index 0000000..d6ddc22
--- /dev/null
+++ b/include/zephyr/dt-bindings/interrupt-controller/infineon-xmc4xxx-intc.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2022 Schlumberger
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_INTERRUPT_CONTROLLER_INFINEON_XMC4XXX_INTC_H_
+#define ZEPHYR_INCLUDE_DT_BINDINGS_INTERRUPT_CONTROLLER_INFINEON_XMC4XXX_INTC_H_
+
+#define XMC4XXX_INTC_PORT_POS		0
+#define XMC4XXX_INTC_PORT_MASK		0xf
+
+#define XMC4XXX_INTC_PIN_POS		4
+#define XMC4XXX_INTC_PIN_MASK		0xf
+
+#define XMC4XXX_INTC_LINE_POS		8
+#define XMC4XXX_INTC_LINE_MASK		0x7
+
+#define XMC4XXX_INTC_ERU_SRC_POS	11
+#define XMC4XXX_INTC_ERU_SRC_MASK	0x7
+
+#define XMC4XXX_INTC_GET_PORT(mx)    ((mx >> XMC4XXX_INTC_PORT_POS) & XMC4XXX_INTC_PORT_MASK)
+#define XMC4XXX_INTC_GET_PIN(mx)     ((mx >> XMC4XXX_INTC_PIN_POS) & XMC4XXX_INTC_PIN_MASK)
+#define XMC4XXX_INTC_GET_LINE(mx)    ((mx >> XMC4XXX_INTC_LINE_POS) & XMC4XXX_INTC_LINE_MASK)
+#define XMC4XXX_INTC_GET_ERU_SRC(mx) ((mx >> XMC4XXX_INTC_ERU_SRC_POS) & XMC4XXX_INTC_ERU_SRC_MASK)
+
+#define XMC4XXX_INTC_SET_LINE_MAP(port, pin, eru_src, line)                                        \
+	((port) << XMC4XXX_INTC_PORT_POS | (pin) << XMC4XXX_INTC_PIN_POS |                         \
+	 (eru_src) << XMC4XXX_INTC_ERU_SRC_POS | (line) << XMC4XXX_INTC_LINE_POS)
+
+#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_INTERRUPT_CONTROLLER_INFINEON_XMC4XXX_INTC_H_ */
diff --git a/modules/Kconfig.infineon b/modules/Kconfig.infineon
index 1f8e2df..6180704 100644
--- a/modules/Kconfig.infineon
+++ b/modules/Kconfig.infineon
@@ -19,4 +19,10 @@
 	bool
 	help
 	  Enable XMCLIB Flash
+
+config HAS_XMCLIB_ERU
+	bool
+	help
+	  Enable XMCLIB Event Request Unit (ERU) for GPIO interrupt support
+
 endif # HAS_XMCLIB
diff --git a/soc/arm/infineon_xmc/4xxx/Kconfig.series b/soc/arm/infineon_xmc/4xxx/Kconfig.series
index 24c03b4..ce44c5e 100644
--- a/soc/arm/infineon_xmc/4xxx/Kconfig.series
+++ b/soc/arm/infineon_xmc/4xxx/Kconfig.series
@@ -14,5 +14,6 @@
 	select CPU_HAS_FPU
 	select HAS_XMCLIB_UART
 	select HAS_XMCLIB_FLASH
+	select HAS_XMCLIB_ERU
 	help
 	  Enable support for XMC 4xxx MCU series