diff --git a/drivers/net/wireless/sprd/Kconfig b/drivers/net/wireless/sprd/Kconfig
index 000000000000..b68db761a460
--- /dev/null
+++ b/drivers/net/wireless/sprd/Kconfig
@@ -0,0 +1,21 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# config kernel for the Unisoc Wi-Fi driver
+
+config SPRD_WLAN
+	tristate "Unisoc Wireless LAN Support"
+	depends on CFG80211
+	help
+	  This is a driver of IEEE80211 WLAN for the Unisoc WiFi chipsets.
+	  This driver works on Marlin3 chip, which is the 3rd WiFi chipsets
+	  of the Unisoc.
+	  When compiled as a module, it will be called sprdwl_ng.
+
+config SPRD_WLAN_MARLIN3
+	bool "MARLIN3"
+
+	help
+	  Select this to support the Unisoc SC2355 branch, which includes
+	  SDIO and PCIe interfaces to translate data and works on Marlin3
+	  chips. SDIO interface and PCIe interface correspond to different
+	  code logic for different customer projects.
+
+endchoice
diff --git a/drivers/net/wireless/sprd/Makefile b/drivers/net/wireless/sprd/Makefile
index 000000000000..a1eae0b4e302
--- /dev/null
+++ b/drivers/net/wireless/sprd/Makefile
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# Makefile for the Unisoc Wi-Fi driver
+
+#####module name ###
+obj-m += sprdwl_ng.o
+
+#######add .o file#####
+sprdwl_ng-objs += core_sc2355.o
+
+modules:
+	$(MAKE) ARCH=$(ARCH) -C $(KDIR) M=$(CURDIR) $@
+clean:
+	$(MAKE) ARCH=$(ARCH) -C $(KDIR) M=$(CURDIR) $@
+kernelrelease:
+	$(MAKE) ARCH=$(ARCH) -C $(KDIR) $@
diff --git a/drivers/net/wireless/sprd/core_sc2355.c b/drivers/net/wireless/sprd/core_sc2355.c
index 000000000000..27e1c5346b4e
--- /dev/null
+++ b/drivers/net/wireless/sprd/core_sc2355.c
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Wi-Fi driver of the Unisoc for Marlin3 chip:
+// register a Wi-Fi driver of IEEE802.11 WLAN for the Unisoc
+//
+// Copyright(C) 2018 Unisoc,Inc
+
+#include <linux/etherdevice.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/utsname.h>
+#include "core_sc2355.h"
+#include "interface.h"
+#include "wireless.h"
+
+static int sprdwl_ini_download_status(void)
+{
+	return 0;
+}
+
+static void sprdwl_force_exit(void *spdev)
+{
+	struct sprdwl_intf *intf = (struct sprdwl_intf *)spdev;
+
+	intf->exit = 1;
+}
+
+static int sprdwl_is_exit(void *spdev)
+{
+	struct sprdwl_intf *intf = (struct sprdwl_intf *)spdev;
+
+	return intf->exit;
+}
+
+static struct sprdwl_if_ops sprdwl_core_ops = {
+	.force_exit = sprdwl_force_exit,
+	.is_exit = sprdwl_is_exit,
+	.ini_download_status = sprdwl_ini_download_status
+};
+
+static int sprdwl_probe(struct platform_device *pdev)
+{
+	struct sprdwl_intf *intf;
+	struct sprdwl_priv *priv;
+	int ret;
+	u8 i;
+
+	intf = kzalloc(sizeof(*intf), GFP_ATOMIC);
+	if (!intf) {
+		ret = -ENOMEM;
+		dev_err(sprdwl_dev, "sc2355 sprd-wlan:%s alloc intf fail: %d\n", __func__, ret);
+		goto out;
+	}
+
+	platform_set_drvdata(pdev, intf);
+	intf->pdev = pdev;
+	sprdwl_dev = &pdev->dev;
+
+	for (i = 0; i < MAX_LUT_NUM; i++)
+		intf->peer_entry[i].ctx_id = 0xff;
+
+	priv = sprdwl_core_create(SPRDWL_HW_SC2355_SDIO,
+				  &sprdwl_core_ops);
+	if (!priv) {
+		dev_err(sprdwl_dev, "sc2355 sprd-wlan:%s core create fail\n", __func__);
+		ret = -ENXIO;
+		goto err;
+	}
+
+	ret = sprdwl_core_init(&pdev->dev, priv);
+	if (ret)
+		goto err;
+
+	return ret;
+
+err:
+	kfree(intf);
+out:
+	return ret;
+}
+
+static int sprdwl_remove(struct platform_device *pdev)
+{
+	struct sprdwl_intf *intf = platform_get_drvdata(pdev);
+	struct sprdwl_priv *priv = intf->priv;
+
+	sprdwl_core_deinit(priv);
+	sprdwl_core_free(priv);
+	kfree(intf);
+
+	return 0;
+}
+
+static const struct of_device_id sprdwl_of_match[] = {
+	{.compatible = "sprd,sc2355-wifi",},
+	{}
+};
+MODULE_DEVICE_TABLE(of, sprdwl_of_match);
+
+static struct platform_driver sprdwl_driver = {
+	.probe = sprdwl_probe,
+	.remove = sprdwl_remove,
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = "sc2355",
+		.of_match_table = sprdwl_of_match
+	}
+};
+
+module_platform_driver(sprdwl_driver);
+
+MODULE_DESCRIPTION("Unisoc Wireless LAN Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/sprd/core_sc2355.h b/drivers/net/wireless/sprd/core_sc2355.h
index 000000000000..7ff1292dbef0
--- /dev/null
+++ b/drivers/net/wireless/sprd/core_sc2355.h
@@ -0,0 +1,115 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+//
+// Wi-Fi driver of the Unisoc for the Marlin3 chip:
+// register a Wi-Fi driver of IEEE802.11 WLAN for the Unisoc
+//
+// Copyright(C) 2018 Unisoc,Inc
+
+#define SPRDWL_NORMAL_MEM	0
+#define SPRDWL_DEFRAG_MEM	1
+
+#define SPRDWL_TX_CMD_TIMEOUT	3000
+#define SPRDWL_TX_DATA_TIMEOUT	4000
+
+#define SPRDWL_TX_MSG_CMD_NUM	128
+#define SPRDWL_TX_MSG_SPECIAL_DATA_NUM	256
+#define SPRDWL_TX_QOS_POOL_SIZE	20000
+#define SPRDWL_TX_DATA_START_NUM	(SPRDWL_TX_QOS_POOL_SIZE - 3)
+#define SPRDWL_RX_MSG_NUM	20000
+
+#define SPRDWL_MAX_CMD_TXLEN	1596
+#define SPRDWL_MAX_CMD_RXLEN	1092
+#define SPRDWL_MAX_DATA_TXLEN	1672
+#define SPRDWL_MAX_DATA_RXLEN	1676
+
+#define MAX_LUT_NUM	32
+
+/* struct tx_address: the tx mac address of da and sa
+ * @da: destination address
+ * @sa: source address
+ */
+struct tx_address {
+	u8 da[ETH_ALEN];
+	u8 sa[ETH_ALEN];
+};
+
+/* struct rx_address: the rx mac address of da and sa
+ * @sa: source address
+ * @da: destination address
+ */
+struct rx_address {
+	u8 sa[ETH_ALEN];
+	u8 da[ETH_ALEN];
+};
+
+/* struct sprdwl_peer_entry: the information of peer connectted
+ * @rx: rx mac address
+ * @tx: tx mac address
+ * @lut_index: lookup table index of current peer
+ * @ctx_id: wifi context index of stap mode
+ * @ht_enable: indicate current peer high thoughput enabled
+ * @vht_enable: indicate current peer very high thoughput enabled
+ * @ip_acquired: indicate current peer ip address acquired
+ * @ba_tx_done_map: indicate current peer tx ba session enabled
+ * @vowifi_enabled: indicate current peer vowifi scenario enabled
+ */
+struct sprdwl_peer_entry {
+	union {
+		struct rx_address rx;
+		struct tx_address tx;
+	};
+
+	u8 lut_index;
+	u8 ctx_id;
+	u8 cipher_type;
+	u8 pending_num;
+	u8 ht_enable;
+	u8 vht_enable;
+	u8 ip_acquired;
+	unsigned long ba_tx_done_map;
+	u8 vowifi_enabled;
+};
+
+/* struct sprdwl_priv: the information of priv definition
+ */
+struct sprdwl_priv;
+
+/* struct sprdwl_intf: the information of interface
+ * @pdev: platform device
+ * @priv: wifi private struct
+ * @exit: indicate driver exit
+ * @tx_mode: value of tx mode
+ * @rx_mode: value of rx mode
+ * @hw_intf: the hardware interface type
+ * @sprdwl_tx: pointer to tx information struct
+ * @sprdwl_rx: pointer to rx information struct
+ * @peer_entry: the information of peer connectted
+ * @skb_da: destination address of this interface
+ * @hif_offset: data offset of the hardware interface
+ * @rx_cmd_port: cmd port for rx
+ * @rx_data_port: data port for rx
+ * @tx_cmd_port: cmd port for tx
+ * @tx_data_port: data port for tx
+ * @cp_asserted: indicate cp2 asserted
+ */
+struct sprdwl_intf {
+	struct platform_device *pdev;
+	struct sprdwl_priv *priv;
+	int exit;
+	int flag;
+	int tx_mode;
+	int rx_mode;
+	void *hw_intf;
+	void *sprdwl_tx;
+	void *sprdwl_rx;
+	struct sprdwl_peer_entry peer_entry[MAX_LUT_NUM];
+	unsigned char *skb_da;
+	int hif_offset;
+	unsigned char rx_cmd_port;
+	unsigned char rx_data_port;
+	unsigned char tx_cmd_port;
+	unsigned char tx_data_port;
+	u8 cp_asserted;
+};
+
+struct device *sprdwl_dev;
diff --git a/drivers/net/wireless/sprd/interface.h b/drivers/net/wireless/sprd/interface.h
index 000000000000..3ef1351f8d59
--- /dev/null
+++ b/drivers/net/wireless/sprd/interface.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+//
+// Wi-Fi driver of the Unisoc for Marlin3 chip:
+// interface operations
+//
+// Copyright(C) 2018 Unisoc,Inc
+
+#ifndef __SPRDWL_INTF_H__
+#define __SPRDWL_INTF_H__
+
+#include "message.h"
+#include "wireless.h"
+
+/* struct sprdwl_if_ops: interface operations
+ * @get_msg_buf: get a free message buffer from list
+ * @free_msg_buf: free the message buffer to use again
+ * @tx: transmit message buffer to tx thread
+ * @force_exit: force remove driver
+ * @is_exit: indicate driver exit or not
+ * @ini_download_status: indicate ini downloaded or not
+ */
+struct sprdwl_if_ops {
+	struct sprdwl_msg_buf *(*get_msg_buf)(void *sdev,
+					      enum sprdwl_head_type type,
+					      enum sprdwl_mode mode,
+					      u8 ctx_id);
+	void (*free_msg_buf)(void *sdev, struct sprdwl_msg_buf *msg);
+	int (*tx)(void *spdev, struct sprdwl_msg_buf *msg);
+	void (*force_exit)(void *spdev);
+	int (*is_exit)(void *spdev);
+	int (*ini_download_status)(void);
+};
+#endif
diff --git a/drivers/net/wireless/sprd/message.h b/drivers/net/wireless/sprd/message.h
index 000000000000..841ceb626483
--- /dev/null
+++ b/drivers/net/wireless/sprd/message.h
@@ -0,0 +1,95 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+//
+// Wi-Fi driver of the Unisoc for Marlin3 chip:
+// management the message buffer
+//
+// Copyright(C) 2018 Unisoc,Inc.
+
+#ifndef __SPRDWL_MSG_H__
+#define __SPRDWL_MSG_H__
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+enum sprdwl_mode {
+	SPRDWL_MODE_NONE,
+	SPRDWL_MODE_STATION,
+	SPRDWL_MODE_AP,
+
+	SPRDWL_MODE_P2P_DEVICE = 4,
+	SPRDWL_MODE_P2P_CLIENT,
+	SPRDWL_MODE_P2P_GO,
+
+	SPRDWL_MODE_IBSS,
+
+	SPRDWL_MODE_MAX
+};
+
+enum sm_state {
+	SPRDWL_UNKNOWN = 0,
+	SPRDWL_SCANNING,
+	SPRDWL_SCAN_ABORTING,
+	SPRDWL_DISCONNECTING,
+	SPRDWL_DISCONNECTED,
+	SPRDWL_CONNECTING,
+	SPRDWL_CONNECTED
+};
+
+enum sprdwl_head_type {
+	SPRDWL_TYPE_CMD,
+	SPRDWL_TYPE_EVENT,
+	SPRDWL_TYPE_DATA,
+	SPRDWL_TYPE_DATA_SPECIAL
+};
+
+/* struct sprdwl_msg_list: the list for management of command/data
+ * @freelist: list of data to be free
+ * @busylist: list of data in used
+ * @cmd_to_free: list of cmd to be free
+ * @maxnum: max number of list
+ * @ref: reference number of list
+ * @flow: data flow contrl
+ */
+struct sprdwl_msg_list {
+	struct list_head freelist;
+	struct list_head busylist;
+	struct list_head cmd_to_free;
+	int maxnum;
+	atomic_t ref;
+	atomic_t flow;
+};
+
+/* struct sprdwl_msg_buf: to manage socket buffer
+ * @list: list head of this skb belong to
+ * @skb: socket buffer
+ * @data: data of socket buffer
+ * @tran_data: data to be transferred
+ * @type: type of this buffer
+ * @mode: indicate which mode this skb data belong to
+ * @len: socket buffer length
+ * @timeout: value of data time out in list
+ * @fifo_id: identity of fifo
+ * @msglist: indicate which list the socket buffer assign to
+ * @buffer_type: type of this socket buffer
+ * @data_list: type of this socket buffer
+ * @xmit_msg_list: list to manage transmit data list
+ * @msg_type: indicate type of this buffer
+ */
+struct sprdwl_msg_buf {
+	struct list_head list;
+	struct sk_buff *skb;
+	void *data;
+	void *tran_data;
+	u8 type;
+	u8 mode;
+	u16 len;
+	unsigned long timeout;
+	unsigned int fifo_id;
+	struct sprdwl_msg_list *msglist;
+	unsigned char buffer_type;
+	struct peer_list *data_list;
+	struct sprdwl_xmit_msg_list *xmit_msg_list;
+	unsigned char msg_type;
+};
+#endif
diff --git a/drivers/net/wireless/sprd/wireless.h b/drivers/net/wireless/sprd/wireless.h
index 000000000000..152a5c231a7b
--- /dev/null
+++ b/drivers/net/wireless/sprd/wireless.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+//
+// Wi-Fi driver of the Unisoc for Marlin3 chip:
+// Unisoc's private data structure
+//
+// Copyright(C) 2018 Unisoc,Inc.
+
+#ifndef __SPRDWL_H__
+#define __SPRDWL_H__
+
+#include <net/cfg80211.h>
+#include <linux/inetdevice.h>
+#include <linux/spinlock.h>
+#include <linux/wireless.h>
+#include "interface.h"
+
+/* struct sprdwl_vif: describe the wifi virtual interface
+ * @ndev: net device
+ * @wdev: wireless device
+ * @priv: sprdwl private structure
+ * @mode: Wi-Fi working mode
+ * @vif_node: node for virtual interface list
+ * @ref: reference of virtual interface
+ * @ctx_id: wifi context index of stap mode
+ */
+struct sprdwl_vif {
+	struct net_device *ndev;
+	struct wireless_dev wdev;
+	struct sprdwl_priv *priv;
+	enum sprdwl_mode mode;
+	struct list_head vif_node;
+	int ref;
+	u8 ctx_id;
+};
+
+enum sprdwl_hw_type {
+	SPRDWL_HW_SDIO,
+	SPRDWL_HW_SIPC,
+	SPRDWL_HW_SDIO_BA,
+	SPRDWL_HW_SC2355_SDIO,
+	SPRDWL_HW_SC2355_PCIE
+};
+
+/* struct sprdwl_priv: describe the unisoc private structure
+ * @wiphy: wiphy of net device
+ * @vif_list: list of virtual interface
+ * @hw_priv: hardware private structure
+ * @hw_type: hardware type
+ * @ hw_offset: hardware data offset
+ * @if_ops: interface operations
+ */
+struct sprdwl_priv {
+	struct wiphy *wiphy;
+	struct list_head vif_list;
+	void *hw_priv;
+	enum sprdwl_hw_type hw_type;
+	int hw_offset;
+	struct sprdwl_if_ops *if_ops;
+};
+
+extern struct device *sprdwl_dev;
+
+struct sprdwl_priv *sprdwl_core_create(enum sprdwl_hw_type type,
+				       struct sprdwl_if_ops *ops);
+void sprdwl_core_free(struct sprdwl_priv *priv);
+int sprdwl_core_init(struct device *dev, struct sprdwl_priv *priv);
+int sprdwl_core_deinit(struct sprdwl_priv *priv);
+#endif
+
