drivers: dma: dma_intel_lpss: Added intel LPSS DMA interface

Added intel LPSS DMA interface using dw common to support
usage of internal DMA in LPSS UART, SPI and I2C for
transfer and receive operations.

Signed-off-by: Anisetti Avinash Krishna <anisetti.avinash.krishna@intel.com>
diff --git a/drivers/dma/CMakeLists.txt b/drivers/dma/CMakeLists.txt
index d73d0a8..8b91184 100644
--- a/drivers/dma/CMakeLists.txt
+++ b/drivers/dma/CMakeLists.txt
@@ -23,6 +23,7 @@
 zephyr_library_sources_ifdef(CONFIG_DMA_INTEL_ADSP_HDA_LINK_IN dma_intel_adsp_hda_link_in.c)
 zephyr_library_sources_ifdef(CONFIG_DMA_INTEL_ADSP_HDA_LINK_OUT dma_intel_adsp_hda_link_out.c)
 zephyr_library_sources_ifdef(CONFIG_DMA_INTEL_ADSP_GPDMA	dma_intel_adsp_gpdma.c dma_dw_common.c)
+zephyr_library_sources_ifdef(CONFIG_DMA_INTEL_LPSS      dma_intel_lpss.c dma_dw_common.c)
 zephyr_library_sources_ifdef(CONFIG_DMA_GD32		dma_gd32.c)
 zephyr_library_sources_ifdef(CONFIG_DMA_ESP32		dma_esp32_gdma.c)
 zephyr_library_sources_ifdef(CONFIG_DMA_MCHP_XEC	dma_mchp_xec.c)
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index ad0df00..d88d2bb 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -58,4 +58,5 @@
 
 source "drivers/dma/Kconfig.rpi_pico"
 
+source "drivers/dma/Kconfig.intel_lpss"
 endif # DMA
diff --git a/drivers/dma/Kconfig.dw_common b/drivers/dma/Kconfig.dw_common
index c522b7c..8b81d4a 100644
--- a/drivers/dma/Kconfig.dw_common
+++ b/drivers/dma/Kconfig.dw_common
@@ -38,3 +38,9 @@
 	help
 	  Some instances of the DesignWare DMAC require a mask applied to source/destination
 	  addresses to signifiy the memory space the address is in.
+
+config DMA_DW_CHANNEL_COUNT
+	int "dw max channel count"
+	default 8
+	help
+	  Channel count for designware DMA instances.
diff --git a/drivers/dma/Kconfig.intel_lpss b/drivers/dma/Kconfig.intel_lpss
new file mode 100644
index 0000000..d475c74
--- /dev/null
+++ b/drivers/dma/Kconfig.intel_lpss
@@ -0,0 +1,17 @@
+# LPSS DMA configuration options
+
+# Copyright (c) 2023 Intel Corporation
+# SPDX-License-Identifier: Apache-2.0
+
+config DMA_INTEL_LPSS
+	bool "INTEL LPSS DMA driver"
+	default n
+	depends on DT_HAS_INTEL_LPSS_ENABLED
+	help
+	  INTEL LPSS DMA driver.
+
+if DMA_INTEL_LPSS
+
+source "drivers/dma/Kconfig.dw_common"
+
+endif # DMA_INTEL_LPSS
diff --git a/drivers/dma/dma_dw_common.c b/drivers/dma/dma_dw_common.c
index dd389f9..e321065 100644
--- a/drivers/dma/dma_dw_common.c
+++ b/drivers/dma/dma_dw_common.c
@@ -132,7 +132,7 @@
 	uint32_t msize = 3;/* default msize, 8 bytes */
 	int ret = 0;
 
-	if (channel >= DW_MAX_CHAN) {
+	if (channel >= DW_CHAN_COUNT) {
 		LOG_ERR("%s: invalid dma channel %d", __func__, channel);
 		ret = -EINVAL;
 		goto out;
@@ -444,7 +444,7 @@
 	int ret = 0;
 
 	/* validate channel */
-	if (channel >= DW_MAX_CHAN) {
+	if (channel >= DW_CHAN_COUNT) {
 		ret = -EINVAL;
 		goto out;
 	}
@@ -492,10 +492,10 @@
 
 	/* channel needs to start from scratch, so write SAR and DAR */
 #ifdef CONFIG_DMA_64BIT
-	dw_write(dev_cfg->base, DW_SAR(channel), (uint32_t)(lli->sar & BIT_MASK(32)));
-	dw_write(dev_cfg->base, DW_SAR_HI(channel), (uint32_t)(lli->sar >> 32));
-	dw_write(dev_cfg->base, DW_DAR(channel), (uint32_t)(lli->dar & BIT_MASK(32)));
-	dw_write(dev_cfg->base, DW_DAR_HI(channel), (uint32_t)(lli->dar >> 32));
+	dw_write(dev_cfg->base, DW_SAR(channel), (uint32_t)(lli->sar & DW_ADDR_MASK_32));
+	dw_write(dev_cfg->base, DW_SAR_HI(channel), (uint32_t)(lli->sar >> DW_ADDR_RIGHT_SHIFT));
+	dw_write(dev_cfg->base, DW_DAR(channel), (uint32_t)(lli->dar & DW_ADDR_MASK_32));
+	dw_write(dev_cfg->base, DW_DAR_HI(channel), (uint32_t)(lli->dar >> DW_ADDR_RIGHT_SHIFT));
 #else
 	dw_write(dev_cfg->base, DW_SAR(channel), lli->sar);
 	dw_write(dev_cfg->base, DW_DAR(channel), lli->dar);
@@ -548,7 +548,7 @@
 	struct dw_dma_chan_data *chan_data = &dev_data->chan[channel];
 	int ret = 0;
 
-	if (channel >= DW_MAX_CHAN) {
+	if (channel >= DW_CHAN_COUNT) {
 		ret = -EINVAL;
 		goto out;
 	}
@@ -617,7 +617,7 @@
 	int ret = 0;
 
 	/* Validate channel index */
-	if (channel >= DW_MAX_CHAN) {
+	if (channel >= DW_CHAN_COUNT) {
 		ret = -EINVAL;
 		goto out;
 	}
@@ -649,7 +649,7 @@
 	int ret = 0;
 
 	/* Validate channel index */
-	if (channel >= DW_MAX_CHAN) {
+	if (channel >= DW_CHAN_COUNT) {
 		ret = -EINVAL;
 		goto out;
 	}
@@ -704,7 +704,7 @@
 
 	LOG_DBG("%s: dma %s", __func__, dev->name);
 
-	for (i = 0; i <  DW_MAX_CHAN; i++) {
+	for (i = 0; i <  DW_CHAN_COUNT; i++) {
 		dw_read(dev_cfg->base, DW_DMA_CHAN_EN);
 	}
 
diff --git a/drivers/dma/dma_dw_common.h b/drivers/dma/dma_dw_common.h
index 56d7068..5d61911 100644
--- a/drivers/dma/dma_dw_common.h
+++ b/drivers/dma/dma_dw_common.h
@@ -21,8 +21,11 @@
 	(((x) & ((1ULL << ((b_hi) - (b_lo) + 1ULL)) - 1ULL)) << (b_lo))
 
 #define DW_MAX_CHAN		8
+#define DW_CHAN_COUNT		CONFIG_DMA_DW_CHANNEL_COUNT
 #define DW_CH_SIZE		0x58
 #define DW_CHAN_OFFSET(chan)	(DW_CH_SIZE * chan)
+#define DW_ADDR_MASK_32		BIT_MASK(32)
+#define DW_ADDR_RIGHT_SHIFT	32
 
 #define DW_SAR(chan)	\
 	(0x0000 + DW_CHAN_OFFSET(chan))
@@ -176,7 +179,7 @@
 };
 
 struct dw_drv_plat_data {
-	struct dw_chan_arbit_data chan[DW_MAX_CHAN];
+	struct dw_chan_arbit_data chan[DW_CHAN_COUNT];
 };
 
 /* DMA descriptor used by HW */
@@ -187,6 +190,7 @@
 #else
 	uint32_t sar;
 	uint32_t dar;
+#endif
 	uint32_t llp;
 	uint32_t ctrl_lo;
 	uint32_t ctrl_hi;
@@ -242,10 +246,10 @@
 struct dw_dma_dev_data {
 	struct dma_context dma_ctx;
 	struct dw_drv_plat_data *channel_data;
-	struct dw_dma_chan_data chan[DW_MAX_CHAN];
-	struct dw_lli lli_pool[DW_MAX_CHAN][CONFIG_DMA_DW_LLI_POOL_SIZE] __aligned(64);
+	struct dw_dma_chan_data chan[DW_CHAN_COUNT];
+	struct dw_lli lli_pool[DW_CHAN_COUNT][CONFIG_DMA_DW_LLI_POOL_SIZE] __aligned(64);
 
-	ATOMIC_DEFINE(channels_atomic, DW_MAX_CHAN);
+	ATOMIC_DEFINE(channels_atomic, DW_CHAN_COUNT);
 };
 
 /* Device constant configuration parameters */
diff --git a/drivers/dma/dma_intel_lpss.c b/drivers/dma/dma_intel_lpss.c
new file mode 100644
index 0000000..c1ae176
--- /dev/null
+++ b/drivers/dma/dma_intel_lpss.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2023 Intel Corporation.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#define DT_DRV_COMPAT intel_lpss
+
+#include <errno.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <zephyr/kernel.h>
+#include <zephyr/device.h>
+#include <zephyr/init.h>
+#include <zephyr/drivers/dma.h>
+#include <zephyr/drivers/dma/dma_intel_lpss.h>
+#include "dma_dw_common.h"
+#include <soc.h>
+
+#include <zephyr/logging/log.h>
+#include <zephyr/irq.h>
+LOG_MODULE_REGISTER(dma_intel_lpss, CONFIG_DMA_LOG_LEVEL);
+
+struct dma_intel_lpss_cfg {
+	struct dw_dma_dev_cfg dw_cfg;
+	const struct device *parent;
+};
+
+static int dma_intel_lpss_init(const struct device *dev)
+{
+	struct dma_intel_lpss_cfg *dev_cfg = (struct dma_intel_lpss_cfg *)dev->config;
+	uint32_t base;
+	int ret;
+
+	if (!device_is_ready(dev_cfg->parent)) {
+		LOG_ERR("LPSS DMA parent not ready");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	base = DEVICE_MMIO_GET(dev_cfg->parent) + DMA_INTEL_LPSS_OFFSET;
+	dev_cfg->dw_cfg.base = base;
+
+	ret = dw_dma_setup(dev);
+
+	if (ret != 0) {
+		LOG_ERR("failed to initialize LPSS DMA %s", dev->name);
+		goto out;
+	}
+	ret = 0;
+out:
+	return ret;
+}
+
+void dma_intel_lpss_isr(const struct device *dev)
+{
+	dw_dma_isr(dev);
+}
+
+static const struct dma_driver_api dma_intel_lpss_driver_api = {
+	.config = dw_dma_config,
+	.start = dw_dma_start,
+	.stop = dw_dma_stop,
+};
+
+#define DMA_INTEL_LPSS_INIT(n)						\
+									\
+	static struct dw_drv_plat_data dma_intel_lpss##n = {		\
+		.chan[0] = {						\
+			.class  = 6,					\
+			.weight = 0,					\
+		},							\
+		.chan[1] = {						\
+			.class  = 6,					\
+			.weight = 0,					\
+		},							\
+	};								\
+									\
+									\
+	static struct dma_intel_lpss_cfg dma_intel_lpss##n##_config = {	\
+		.dw_cfg = {						\
+			.base = 0,					\
+		},							\
+		.parent = DEVICE_DT_GET(DT_INST_PARENT(n)),		\
+	};								\
+									\
+	static struct dw_dma_dev_data dma_intel_lpss##n##_data = {	\
+		.channel_data = &dma_intel_lpss##n,			\
+	};								\
+									\
+	DEVICE_DT_INST_DEFINE(n,					\
+			    &dma_intel_lpss_init,			\
+			    NULL,					\
+			    &dma_intel_lpss##n##_data,			\
+			    &dma_intel_lpss##n##_config, POST_KERNEL,	\
+			    DMA_INTEL_LPSS_INIT_PRIORITY,		\
+			    &dma_intel_lpss_driver_api);		\
+
+DT_INST_FOREACH_STATUS_OKAY(DMA_INTEL_LPSS_INIT)
diff --git a/dts/bindings/dma/intel,lpss.yaml b/dts/bindings/dma/intel,lpss.yaml
new file mode 100644
index 0000000..d9fc4a6
--- /dev/null
+++ b/dts/bindings/dma/intel,lpss.yaml
@@ -0,0 +1,15 @@
+# Copyright (c) 2019 Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: Apache-2.0
+
+description: LPSS DMA Controller node
+
+compatible: "intel,lpss"
+
+include: dma-controller.yaml
+
+properties:
+  "#dma-cells":
+    const: 1
+
+dma-cells:
+  - channel
diff --git a/include/zephyr/drivers/dma/dma_intel_lpss.h b/include/zephyr/drivers/dma/dma_intel_lpss.h
new file mode 100644
index 0000000..c3cf3be
--- /dev/null
+++ b/include/zephyr/drivers/dma/dma_intel_lpss.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2023 Intel Corporation.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef ZEPHYR_INCLUDE_DRIVERS_DMA_INTEL_LPSS_H_
+#define ZEPHYR_INCLUDE_DRIVERS_DMA_INTEL_LPSS_H_
+
+#define DMA_INTEL_LPSS_INIT_PRIORITY	80
+#define DMA_INTEL_LPSS_OFFSET		0x800
+#define DMA_INTEL_LPSS_REMAP_LOW	0x240
+#define DMA_INTEL_LPSS_REMAP_HI		0x244
+#define DMA_INTEL_LPSS_TX_CHAN		0
+#define DMA_INTEL_LPSS_RX_CHAN		1
+#define DMA_INTEL_LPSS_ADDR_RIGHT_SHIFT	32
+
+void dma_intel_lpss_isr(const struct device *dev);
+
+#endif /* ZEPHYR_INCLUDE_DRIVERS_DMA_INTEL_LPSS_H_ */