drivers: spi: Add xmc4xxx driver

Adds spi driver for xmc4xxx SoCs.

Signed-off-by: Andriy Gelman <andriy.gelman@gmail.com>
diff --git a/boards/arm/xmc45_relax_kit/doc/index.rst b/boards/arm/xmc45_relax_kit/doc/index.rst
index 59a37bc..ee107a6 100644
--- a/boards/arm/xmc45_relax_kit/doc/index.rst
+++ b/boards/arm/xmc45_relax_kit/doc/index.rst
@@ -43,6 +43,8 @@
 +-----------+------------+-----------------------+
 | UART      | on-chip    | serial port           |
 +-----------+------------+-----------------------+
+| SPI       | on-chip    | spi                   |
++-----------+------------+-----------------------+
 
 More details about the supported peripherals are available in `XMC4500 TRM`_
 Other hardware features are not currently supported by the Zephyr kernel.
diff --git a/drivers/spi/CMakeLists.txt b/drivers/spi/CMakeLists.txt
index 6c2f4df..54a2d5f 100644
--- a/drivers/spi/CMakeLists.txt
+++ b/drivers/spi/CMakeLists.txt
@@ -34,6 +34,7 @@
 zephyr_library_sources_ifdef(CONFIG_SPI_PL022		spi_pl022.c)
 zephyr_library_sources_ifdef(CONFIG_SPI_ANDES_ATCSPI200	spi_andes_atcspi200.c)
 zephyr_library_sources_ifdef(CONFIG_NXP_S32_SPI spi_nxp_s32.c)
+zephyr_library_sources_ifdef(CONFIG_SPI_XMC4XXX     spi_xmc4xxx.c)
 
 zephyr_library_sources_ifdef(CONFIG_SPI_ASYNC spi_signal.c)
 zephyr_library_sources_ifdef(CONFIG_USERSPACE		spi_handlers.c)
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index a1f46d0..df2fa6a 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -107,4 +107,6 @@
 
 source "drivers/spi/Kconfig.nxp_s32"
 
+source "drivers/spi/Kconfig.xmc4xxx"
+
 endif # SPI
diff --git a/drivers/spi/Kconfig.xmc4xxx b/drivers/spi/Kconfig.xmc4xxx
new file mode 100644
index 0000000..b34fc39
--- /dev/null
+++ b/drivers/spi/Kconfig.xmc4xxx
@@ -0,0 +1,20 @@
+# Copyright (c) 2022 Schlumberger
+# SPDX-License-Identifier: Apache-2.0
+
+menuconfig SPI_XMC4XXX
+	bool "XMC4XX SPI driver"
+	default y
+	depends on DT_HAS_INFINEON_XMC4XXX_SPI_ENABLED
+	select GPIO
+	help
+	  Enable XMC4XXX SPI driver.
+
+
+if SPI_XMC4XXX
+
+config SPI_XMC4XXX_INTERRUPT
+	bool "XMC4XXX SPI interrupt mode"
+	help
+	  Enables interrupt support for XMC4XXX SPI driver.
+
+endif # SPI_XMC4XXX
diff --git a/drivers/spi/spi_xmc4xxx.c b/drivers/spi/spi_xmc4xxx.c
new file mode 100644
index 0000000..fe03970
--- /dev/null
+++ b/drivers/spi/spi_xmc4xxx.c
@@ -0,0 +1,366 @@
+/*
+ * Copyright (c) 2022 Schlumberger
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#define DT_DRV_COMPAT infineon_xmc4xxx_spi
+
+#define LOG_LEVEL CONFIG_SPI_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(spi_xmc4xxx);
+
+#include "spi_context.h"
+
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/drivers/spi.h>
+
+#include <xmc_spi.h>
+#include <xmc_usic.h>
+
+struct spi_xmc4xxx_config {
+	XMC_USIC_CH_t *spi;
+	const struct pinctrl_dev_config *pcfg;
+	uint8_t miso_src;
+#if defined(CONFIG_SPI_XMC4XXX_INTERRUPT)
+	void (*irq_config_func)(const struct device *dev);
+#endif
+};
+
+struct spi_xmc4xxx_data {
+	struct spi_context ctx;
+};
+
+static void spi_xmc4xxx_shift_frames(const struct device *dev)
+{
+	struct spi_xmc4xxx_data *data = dev->data;
+	const struct spi_xmc4xxx_config *config = dev->config;
+	struct spi_context *ctx = &data->ctx;
+	uint8_t tx_data = 0;
+	uint8_t rx_data;
+	uint32_t status;
+
+	if (spi_context_tx_buf_on(ctx)) {
+		tx_data = ctx->tx_buf[0];
+	}
+
+	XMC_SPI_CH_ClearStatusFlag(config->spi,
+				   XMC_SPI_CH_STATUS_FLAG_TRANSMIT_SHIFT_INDICATION |
+				   XMC_SPI_CH_STATUS_FLAG_RECEIVE_INDICATION |
+				   XMC_SPI_CH_STATUS_FLAG_ALTERNATIVE_RECEIVE_INDICATION);
+
+	XMC_SPI_CH_Transmit(config->spi, tx_data, XMC_SPI_CH_MODE_STANDARD);
+
+	spi_context_update_tx(ctx, 1, 1);
+
+#if defined(CONFIG_SPI_XMC4XXX_INTERRUPT)
+	return;
+#endif
+
+	/* Wait to finish transmitting */
+	while (1) {
+		status = XMC_SPI_CH_GetStatusFlag(config->spi);
+		if (status & XMC_SPI_CH_STATUS_FLAG_TRANSMIT_SHIFT_INDICATION) {
+			break;
+		}
+	}
+
+	/* Wait to finish receiving */
+	while (1) {
+		status = XMC_SPI_CH_GetStatusFlag(config->spi);
+		if (status & (XMC_SPI_CH_STATUS_FLAG_RECEIVE_INDICATION |
+			      XMC_SPI_CH_STATUS_FLAG_ALTERNATIVE_RECEIVE_INDICATION)) {
+			break;
+		}
+	}
+
+	rx_data = XMC_SPI_CH_GetReceivedData(config->spi);
+
+	if (spi_context_rx_buf_on(ctx)) {
+		*ctx->rx_buf = rx_data;
+	}
+	spi_context_update_rx(ctx, 1, 1);
+}
+
+#if defined(CONFIG_SPI_XMC4XXX_INTERRUPT)
+static void spi_xmc4xxx_isr(const struct device *dev)
+{
+	struct spi_xmc4xxx_data *data = dev->data;
+	const struct spi_xmc4xxx_config *config = dev->config;
+	struct spi_context *ctx = &data->ctx;
+	uint8_t rx_data;
+
+	rx_data = XMC_SPI_CH_GetReceivedData(config->spi);
+
+	if (spi_context_rx_buf_on(ctx)) {
+		*ctx->rx_buf = rx_data;
+	}
+	spi_context_update_rx(ctx, 1, 1);
+
+	if (spi_context_tx_on(ctx) || spi_context_rx_on(ctx)) {
+		spi_xmc4xxx_shift_frames(dev);
+		return;
+	}
+
+	if (!(ctx->config->operation & SPI_HOLD_ON_CS)) {
+		spi_context_cs_control(ctx, false);
+	}
+
+	spi_context_complete(ctx, dev, 0);
+}
+#endif
+
+#define LOOPBACK_SRC 6
+static int spi_xmc4xxx_configure(const struct device *dev, const struct spi_config *spi_cfg)
+{
+	int ret;
+	struct spi_xmc4xxx_data *data = dev->data;
+	const struct spi_xmc4xxx_config *config = dev->config;
+	struct spi_context *ctx = &data->ctx;
+	uint16_t settings = spi_cfg->operation;
+	bool CPOL = SPI_MODE_GET(settings) & SPI_MODE_CPOL;
+	bool CPHA = SPI_MODE_GET(settings) & SPI_MODE_CPHA;
+	XMC_SPI_CH_CONFIG_t usic_cfg = {.baudrate = spi_cfg->frequency};
+	XMC_SPI_CH_BRG_SHIFT_CLOCK_PASSIVE_LEVEL_t clock_settings;
+
+	if (spi_context_configured(ctx, spi_cfg)) {
+		return 0;
+	}
+
+	ctx->config = spi_cfg;
+
+	if (spi_cfg->operation & SPI_HALF_DUPLEX) {
+		LOG_ERR("Half-duplex not supported");
+		return -ENOTSUP;
+	}
+
+	if (spi_cfg->operation & SPI_OP_MODE_SLAVE) {
+		LOG_ERR("Slave mode not supported");
+		return -ENOTSUP;
+	}
+
+	if (SPI_WORD_SIZE_GET(spi_cfg->operation) != 8) {
+		LOG_ERR("Only 8 bit word size is supported");
+		return -ENOTSUP;
+	}
+
+	ret = XMC_SPI_CH_Stop(config->spi);
+	if (ret != XMC_SPI_CH_STATUS_OK) {
+		return -EBUSY;
+	}
+	XMC_SPI_CH_Init(config->spi, &usic_cfg);
+	XMC_SPI_CH_Start(config->spi);
+
+	if (SPI_MODE_GET(settings) & SPI_MODE_LOOP) {
+		XMC_SPI_CH_SetInputSource(config->spi, XMC_SPI_CH_INPUT_DIN0, LOOPBACK_SRC);
+	} else {
+		XMC_SPI_CH_SetInputSource(config->spi, XMC_SPI_CH_INPUT_DIN0, config->miso_src);
+	}
+
+	if (!CPOL && !CPHA) {
+		clock_settings = XMC_SPI_CH_BRG_SHIFT_CLOCK_PASSIVE_LEVEL_0_DELAY_ENABLED;
+	} else if (!CPOL && CPHA) {
+		clock_settings = XMC_SPI_CH_BRG_SHIFT_CLOCK_PASSIVE_LEVEL_0_DELAY_DISABLED;
+	} else if (CPOL && !CPHA) {
+		clock_settings = XMC_SPI_CH_BRG_SHIFT_CLOCK_PASSIVE_LEVEL_1_DELAY_ENABLED;
+	} else if (CPOL && CPHA) {
+		clock_settings = XMC_SPI_CH_BRG_SHIFT_CLOCK_PASSIVE_LEVEL_1_DELAY_DISABLED;
+	}
+	XMC_SPI_CH_ConfigureShiftClockOutput(config->spi, clock_settings,
+					     XMC_SPI_CH_BRG_SHIFT_CLOCK_OUTPUT_SCLK);
+
+	if (settings & SPI_TRANSFER_LSB) {
+		XMC_SPI_CH_SetBitOrderLsbFirst(config->spi);
+	} else {
+		XMC_SPI_CH_SetBitOrderMsbFirst(config->spi);
+	}
+
+	XMC_SPI_CH_SetWordLength(config->spi, 8);
+
+	return 0;
+}
+
+static int spi_xmc4xxx_transceive(const struct device *dev, const struct spi_config *spi_cfg,
+				  const struct spi_buf_set *tx_bufs,
+				  const struct spi_buf_set *rx_bufs,
+				  bool asynchronous, spi_callback_t cb, void *userdata)
+{
+	struct spi_xmc4xxx_data *data = dev->data;
+	const struct spi_xmc4xxx_config *config = dev->config;
+	struct spi_context *ctx = &data->ctx;
+	uint32_t recv_status;
+	int ret;
+
+	if (!tx_bufs && !rx_bufs) {
+		return 0;
+	}
+
+#ifndef CONFIG_SPI_XMC4XXX_INTERRUPT
+	if (asynchronous) {
+		return -ENOTSUP;
+	}
+#endif
+
+	spi_context_lock(ctx, asynchronous, cb, userdata, spi_cfg);
+
+	ret = spi_xmc4xxx_configure(dev, spi_cfg);
+	if (ret) {
+		LOG_DBG("SPI config on device %s failed\n", dev->name);
+		spi_context_release(ctx, ret);
+		return ret;
+	}
+
+	/* flush out any received bytes */
+	recv_status = XMC_USIC_CH_GetReceiveBufferStatus(config->spi);
+	if (recv_status & USIC_CH_RBUFSR_RDV0_Msk) {
+		XMC_SPI_CH_GetReceivedData(config->spi);
+	}
+	if (recv_status & USIC_CH_RBUFSR_RDV1_Msk) {
+		XMC_SPI_CH_GetReceivedData(config->spi);
+	}
+
+	spi_context_buffers_setup(ctx, tx_bufs, rx_bufs, 1);
+
+	spi_context_cs_control(ctx, true);
+
+#if defined(CONFIG_SPI_XMC4XXX_INTERRUPT)
+	XMC_SPI_CH_EnableEvent(config->spi, XMC_SPI_CH_EVENT_STANDARD_RECEIVE |
+					    XMC_SPI_CH_EVENT_ALTERNATIVE_RECEIVE);
+	spi_xmc4xxx_shift_frames(dev);
+	ret = spi_context_wait_for_completion(ctx);
+	/* cs released in isr */
+#else
+	while (spi_context_tx_on(ctx) || spi_context_rx_on(ctx)) {
+		spi_xmc4xxx_shift_frames(dev);
+	}
+
+	if (!(spi_cfg->operation & SPI_HOLD_ON_CS)) {
+		spi_context_cs_control(ctx, false);
+	}
+#endif
+
+	spi_context_release(ctx, ret);
+
+	return ret;
+}
+
+#if defined(CONFIG_SPI_ASYNC)
+static int spi_xmc4xxx_transceive_async(const struct device *dev, const struct spi_config *spi_cfg,
+					const struct spi_buf_set *tx_bufs,
+					const struct spi_buf_set *rx_bufs,
+					spi_callback_t cb,
+					void *userdata)
+{
+	return spi_xmc4xxx_transceive(dev, spi_cfg, tx_bufs, rx_bufs, true, cb, userdata);
+}
+#endif
+
+static int spi_xmc4xxx_transceive_sync(const struct device *dev, const struct spi_config *spi_cfg,
+					const struct spi_buf_set *tx_bufs,
+					const struct spi_buf_set *rx_bufs)
+{
+	return spi_xmc4xxx_transceive(dev, spi_cfg, tx_bufs, rx_bufs, false, NULL, NULL);
+}
+
+static int spi_xmc4xxx_release(const struct device *dev, const struct spi_config *config)
+{
+	struct spi_xmc4xxx_data *data = dev->data;
+
+	if (!spi_context_configured(&data->ctx, config)) {
+		return -EINVAL;
+	}
+
+	spi_context_unlock_unconditionally(&data->ctx);
+	return 0;
+}
+
+static int spi_xmc4xxx_init(const struct device *dev)
+{
+	struct spi_xmc4xxx_data *data = dev->data;
+	const struct spi_xmc4xxx_config *config = dev->config;
+	int ret;
+
+	XMC_USIC_CH_Enable(config->spi);
+
+	spi_context_unlock_unconditionally(&data->ctx);
+
+#if defined(CONFIG_SPI_XMC4XXX_INTERRUPT)
+	config->irq_config_func(dev);
+#endif
+
+	ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
+	if (ret < 0) {
+		return ret;
+	}
+
+	XMC_SPI_CH_SetInputSource(config->spi, XMC_SPI_CH_INPUT_DIN0, config->miso_src);
+	spi_context_cs_configure_all(&data->ctx);
+
+	return 0;
+}
+
+static const struct spi_driver_api spi_xmc4xxx_driver_api = {
+	.transceive = spi_xmc4xxx_transceive_sync,
+#if defined(CONFIG_SPI_ASYNC)
+	.transceive_async = spi_xmc4xxx_transceive_async,
+#endif
+	.release = spi_xmc4xxx_release,
+};
+
+#if defined(CONFIG_SPI_XMC4XXX_INTERRUPT)
+
+#define USIC_IRQ_MIN  84
+#define IRQS_PER_USIC 6
+
+#define XMC4XXX_IRQ_HANDLER_INIT(index)                                                            \
+	static void spi_xmc4xxx_irq_setup_##index(const struct device *dev)                        \
+	{                                                                                          \
+		const struct spi_xmc4xxx_config *config = dev->config;                             \
+		uint8_t service_request;                                                           \
+		uint8_t irq_num;                                                                   \
+												   \
+		irq_num = DT_INST_IRQ_BY_NAME(index, rx, irq);                                     \
+		service_request = (irq_num - USIC_IRQ_MIN) % IRQS_PER_USIC;                        \
+												   \
+		XMC_SPI_CH_SelectInterruptNodePointer(                                             \
+			config->spi, XMC_SPI_CH_INTERRUPT_NODE_POINTER_RECEIVE, service_request);  \
+		XMC_SPI_CH_SelectInterruptNodePointer(                                             \
+			config->spi, XMC_SPI_CH_INTERRUPT_NODE_POINTER_ALTERNATE_RECEIVE,          \
+			service_request);                                                          \
+												   \
+		XMC_SPI_CH_EnableEvent(config->spi, XMC_SPI_CH_EVENT_STANDARD_RECEIVE |            \
+						    XMC_SPI_CH_EVENT_ALTERNATIVE_RECEIVE);         \
+												   \
+		IRQ_CONNECT(DT_INST_IRQ_BY_NAME(index, rx, irq),                                   \
+			    DT_INST_IRQ_BY_NAME(index, rx, priority), spi_xmc4xxx_isr,             \
+			    DEVICE_DT_INST_GET(index), 0);                                         \
+		irq_enable(DT_INST_IRQ_BY_NAME(index, rx, irq));                                   \
+	}
+
+#define XMC4XXX_IRQ_HANDLER_STRUCT_INIT(index) .irq_config_func = spi_xmc4xxx_irq_setup_##index,
+
+#else
+#define XMC4XXX_IRQ_HANDLER_INIT(index)
+#define XMC4XXX_IRQ_HANDLER_STRUCT_INIT(index)
+#endif
+
+#define XMC4XXX_INIT(index)                                                                        \
+	PINCTRL_DT_INST_DEFINE(index);                                                             \
+	XMC4XXX_IRQ_HANDLER_INIT(index)                                                            \
+	static struct spi_xmc4xxx_data xmc4xxx_data_##index = {                                    \
+		SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(index), ctx)                           \
+			SPI_CONTEXT_INIT_LOCK(xmc4xxx_data_##index, ctx),                          \
+		SPI_CONTEXT_INIT_SYNC(xmc4xxx_data_##index, ctx),                                  \
+	};                                                                                         \
+                                                                                                   \
+	static const struct spi_xmc4xxx_config xmc4xxx_config_##index = {                          \
+		.spi = (XMC_USIC_CH_t *)DT_INST_REG_ADDR(index),                                   \
+		.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(index),                                     \
+		.miso_src = DT_INST_ENUM_IDX(index, miso_src),                                     \
+		XMC4XXX_IRQ_HANDLER_STRUCT_INIT(index)};                                           \
+                                                                                                   \
+	DEVICE_DT_INST_DEFINE(index, &spi_xmc4xxx_init, NULL, &xmc4xxx_data_##index,               \
+			      &xmc4xxx_config_##index, POST_KERNEL,                                \
+			      CONFIG_SPI_INIT_PRIORITY, &spi_xmc4xxx_driver_api);
+
+DT_INST_FOREACH_STATUS_OKAY(XMC4XXX_INIT)
diff --git a/dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi b/dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi
index fc8c8be..9b9e0a9 100644
--- a/dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi
+++ b/dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi
@@ -86,4 +86,117 @@
 	/omit-if-no-ref/ uart_rx_p4_0_u2c1: uart_rx_p4_0_u2c1 {
 		pinmux = <XMC4XXX_PINMUX_SET(4, 0, 0)>;	/* USIC input src = DX0C */
 	};
+
+	/omit-if-no-ref/ spi_mosi_p0_1_u1c1: spi_mosi_p0_1_u1c1 {
+		pinmux = <XMC4XXX_PINMUX_SET(0, 1, 2)>;
+	};
+	/omit-if-no-ref/ spi_mosi_p0_5_u1c0: spi_mosi_p0_5_u1c0 {
+		pinmux = <XMC4XXX_PINMUX_SET(0, 5, 2)>;
+	};
+	/omit-if-no-ref/ spi_mosi_p1_5_u0c0: spi_mosi_p1_5_u0c0 {
+		pinmux = <XMC4XXX_PINMUX_SET(1, 5, 2)>;
+	};
+	/omit-if-no-ref/ spi_mosi_p1_7_u0c0: spi_mosi_p1_7_u0c0 {
+		pinmux = <XMC4XXX_PINMUX_SET(1, 7, 2)>;
+	};
+	/omit-if-no-ref/ spi_mosi_p2_5_u0c1: spi_mosi_p2_5_u0c1 {
+		pinmux = <XMC4XXX_PINMUX_SET(2, 5, 2)>;
+	};
+	/omit-if-no-ref/ spi_mosi_p2_14_u1c0: spi_mosi_p2_14_u1c0 {
+		pinmux = <XMC4XXX_PINMUX_SET(2, 14, 2)>;
+	};
+	/omit-if-no-ref/ spi_mosi_p3_5_u2c1: spi_mosi_p3_5_u2c1 {
+		pinmux = <XMC4XXX_PINMUX_SET(3, 5, 1)>;
+	};
+	/omit-if-no-ref/ spi_mosi_p3_5_u0c1: spi_mosi_p3_5_u0c1 {
+		pinmux = <XMC4XXX_PINMUX_SET(3, 5, 4)>;
+	};
+	/omit-if-no-ref/ spi_mosi_p5_0_u2c0: spi_mosi_p5_0_u2c0 {
+		pinmux = <XMC4XXX_PINMUX_SET(5, 0, 1)>;
+	};
+	/omit-if-no-ref/ spi_mosi_p5_1_u0c0: spi_mosi_p5_1_u0c0 {
+		pinmux = <XMC4XXX_PINMUX_SET(5, 1, 1)>;
+	};
+
+	/omit-if-no-ref/ spi_miso_p1_4_u0c0: spi_miso_p1_4_u0c0 {
+		pinmux = <XMC4XXX_PINMUX_SET(1, 4, 0)>;	/* USIC input src = DX0B */
+	};
+	/omit-if-no-ref/ spi_miso_p1_5_u0c0: spi_miso_p1_5_u0c0 {
+		pinmux = <XMC4XXX_PINMUX_SET(1, 5, 0)>;	/* USIC input src = DX0A */
+	};
+	/omit-if-no-ref/ spi_miso_p5_0_u0c0: spi_miso_p5_0_u0c0 {
+		pinmux = <XMC4XXX_PINMUX_SET(5, 0, 0)>;	/* USIC input src = DX0D */
+	};
+	/omit-if-no-ref/ spi_miso_p2_2_u0c1: spi_miso_p2_2_u0c1 {
+		pinmux = <XMC4XXX_PINMUX_SET(2, 2, 0)>;	/* USIC input src = DX0A */
+	};
+	/omit-if-no-ref/ spi_miso_p2_5_u0c1: spi_miso_p2_5_u0c1 {
+		pinmux = <XMC4XXX_PINMUX_SET(2, 5, 0)>;	/* USIC input src = DX0B */
+	};
+	/omit-if-no-ref/ spi_miso_p4_0_u0c1: spi_miso_p4_0_u0c1 {
+		pinmux = <XMC4XXX_PINMUX_SET(4, 0, 0)>;	/* USIC input src = DX0E */
+	};
+	/omit-if-no-ref/ spi_miso_p0_4_u1c0: spi_miso_p0_4_u1c0 {
+		pinmux = <XMC4XXX_PINMUX_SET(0, 4, 0)>;	/* USIC input src = DX0A */
+	};
+	/omit-if-no-ref/ spi_miso_p0_5_u1c0: spi_miso_p0_5_u1c0 {
+		pinmux = <XMC4XXX_PINMUX_SET(0, 5, 0)>;	/* USIC input src = DX0B */
+	};
+	/omit-if-no-ref/ spi_miso_p2_14_u1c0: spi_miso_p2_14_u1c0 {
+		pinmux = <XMC4XXX_PINMUX_SET(2, 14, 0)>;	/* USIC input src = DX0D */
+	};
+	/omit-if-no-ref/ spi_miso_p2_15_u1c0: spi_miso_p2_15_u1c0 {
+		pinmux = <XMC4XXX_PINMUX_SET(2, 15, 0)>;	/* USIC input src = DX0C */
+	};
+	/omit-if-no-ref/ spi_miso_p0_0_u1c1: spi_miso_p0_0_u1c1 {
+		pinmux = <XMC4XXX_PINMUX_SET(0, 0, 0)>;	/* USIC input src = DX0D */
+	};
+	/omit-if-no-ref/ spi_miso_p5_0_u2c0: spi_miso_p5_0_u2c0 {
+		pinmux = <XMC4XXX_PINMUX_SET(5, 0, 0)>;	/* USIC input src = DX0B */
+	};
+	/omit-if-no-ref/ spi_miso_p5_1_u2c0: spi_miso_p5_1_u2c0 {
+		pinmux = <XMC4XXX_PINMUX_SET(5, 1, 0)>;	/* USIC input src = DX0A */
+	};
+	/omit-if-no-ref/ spi_miso_p3_4_u2c1: spi_miso_p3_4_u2c1 {
+		pinmux = <XMC4XXX_PINMUX_SET(3, 4, 0)>;	/* USIC input src = DX0B */
+	};
+	/omit-if-no-ref/ spi_miso_p3_5_u2c1: spi_miso_p3_5_u2c1 {
+		pinmux = <XMC4XXX_PINMUX_SET(3, 5, 0)>;	/* USIC input src = DX0A */
+	};
+	/omit-if-no-ref/ spi_miso_p4_0_u2c1: spi_miso_p4_0_u2c1 {
+		pinmux = <XMC4XXX_PINMUX_SET(4, 0, 0)>;	/* USIC input src = DX0C */
+	};
+	/omit-if-no-ref/ spi_sclk_p0_8_u0c0: spi_sclk_p0_8_u0c0 {
+		pinmux = <XMC4XXX_PINMUX_SET(0, 8, 2)>;
+	};
+	/omit-if-no-ref/ spi_sclk_p0_10_u1c1: spi_sclk_p0_10_u1c1 {
+		pinmux = <XMC4XXX_PINMUX_SET(0, 10, 2)>;
+	};
+	/omit-if-no-ref/ spi_sclk_p0_11_u1c0: spi_sclk_p0_11_u1c0 {
+		pinmux = <XMC4XXX_PINMUX_SET(0, 11, 2)>;
+	};
+	/omit-if-no-ref/ spi_sclk_p1_1_u0c0: spi_sclk_p1_1_u0c0 {
+		pinmux = <XMC4XXX_PINMUX_SET(1, 1, 2)>;
+	};
+	/omit-if-no-ref/ spi_sclk_p1_6_u0c0: spi_sclk_p1_6_u0c0 {
+		pinmux = <XMC4XXX_PINMUX_SET(1, 6, 2)>;
+	};
+	/omit-if-no-ref/ spi_sclk_p1_10_u0c0: spi_sclk_p1_10_u0c0 {
+		pinmux = <XMC4XXX_PINMUX_SET(1, 10, 2)>;
+	};
+	/omit-if-no-ref/ spi_sclk_p2_4_u0c1: spi_sclk_p2_4_u0c1 {
+		pinmux = <XMC4XXX_PINMUX_SET(2, 4, 2)>;
+	};
+	/omit-if-no-ref/ spi_sclk_p3_0_u0c1: spi_sclk_p3_0_u0c1 {
+		pinmux = <XMC4XXX_PINMUX_SET(3, 0, 2)>;
+	};
+	/omit-if-no-ref/ spi_sclk_p3_6_u2c1: spi_sclk_p3_6_u2c1 {
+		pinmux = <XMC4XXX_PINMUX_SET(3, 6, 1)>;
+	};
+	/omit-if-no-ref/ spi_sclk_p3_6_u0c1: spi_sclk_p3_6_u0c1 {
+		pinmux = <XMC4XXX_PINMUX_SET(3, 6, 4)>;
+	};
+	/omit-if-no-ref/ spi_sclk_p5_2_u2c0: spi_sclk_p5_2_u2c0 {
+		pinmux = <XMC4XXX_PINMUX_SET(5, 2, 1)>;
+	};
 };
diff --git a/dts/bindings/spi/infineon,xmc4xxx-spi.yaml b/dts/bindings/spi/infineon,xmc4xxx-spi.yaml
new file mode 100644
index 0000000..d12a7ac
--- /dev/null
+++ b/dts/bindings/spi/infineon,xmc4xxx-spi.yaml
@@ -0,0 +1,43 @@
+# Copyright (c) 2022 Schlumberger
+# SPDX-License-Identifier: Apache-2.0
+
+description: INFINEON XMC4XXX SPI controller
+
+compatible: "infineon,xmc4xxx-spi"
+
+include: [spi-controller.yaml, pinctrl-device.yaml]
+
+properties:
+  reg:
+    required: true
+
+  miso-src:
+    description: |
+      Connects the SPI miso line (USIC DX0 input) to a specific GPIO pin.
+      The USIC DX0 input is a multiplexer which connects to different GPIO pins.
+      Refer to the XMC4XXX reference manual for the GPIO pin/mux mappings. DX0G
+      is the loopback input line.
+    type: string
+    required: true
+    enum:
+      - "DX0A"
+      - "DX0B"
+      - "DX0C"
+      - "DX0D"
+      - "DX0E"
+      - "DX0F"
+      - "DX0G"
+
+  interrupts:
+    description: |
+      IRQ number and priority to use for interrupt driven UART.
+      USIC0..2 have their own interrupt range as follows:
+      USIC0 = [84, 89]
+      USIC1 = [90, 95]
+      USIC2 = [96, 101]
+
+  pinctrl-0:
+    required: true
+
+  pinctrl-names:
+    required: true
diff --git a/modules/Kconfig.infineon b/modules/Kconfig.infineon
index 3b2f8b5..0268a8d 100644
--- a/modules/Kconfig.infineon
+++ b/modules/Kconfig.infineon
@@ -35,4 +35,9 @@
 	help
 	  Enable XMCLIB DMA
 
+config HAS_XMCLIB_SPI
+	bool
+	help
+	  Enable XMCLIB SPI
+
 endif # HAS_XMCLIB
diff --git a/soc/arm/infineon_xmc/4xxx/Kconfig.series b/soc/arm/infineon_xmc/4xxx/Kconfig.series
index 76facd3..4e130ba 100644
--- a/soc/arm/infineon_xmc/4xxx/Kconfig.series
+++ b/soc/arm/infineon_xmc/4xxx/Kconfig.series
@@ -17,5 +17,6 @@
 	select HAS_XMCLIB_ERU
 	select HAS_XMCLIB_VADC
 	select HAS_XMCLIB_DMA
+	select HAS_XMCLIB_SPI
 	help
 	  Enable support for XMC 4xxx MCU series