diff --git a/MAINTAINERS b/MAINTAINERS
index 9944845ae9f5..7cd54c70aeed 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -741,7 +741,9 @@ M:	Christian Marangi <ansuelsmth@gmail.com>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:	Maintained
 F:	Documentation/devicetree/bindings/soc/airoha/airoha,an7581-scu-ssr.yaml
+F:	drivers/soc/airoha/airoha-scu-ssr.c
 F:	include/dt-bindings/soc/airoha,scu-ssr.h
+F:	include/linux/soc/airoha/airoha-scu-ssr.h
 
 AIROHA SPI SNFI DRIVER
 M:	Lorenzo Bianconi <lorenzo@kernel.org>
diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index 6a8daeb8c4b9..21bacefd2e06 100644
--- a/drivers/soc/Kconfig
+++ b/drivers/soc/Kconfig
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 menu "SOC (System On Chip) specific Drivers"
 
+source "drivers/soc/airoha/Kconfig"
 source "drivers/soc/amlogic/Kconfig"
 source "drivers/soc/apple/Kconfig"
 source "drivers/soc/aspeed/Kconfig"
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index 2037a8695cb2..2b4027837d60 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -3,6 +3,7 @@
 # Makefile for the Linux Kernel SOC specific device drivers.
 #
 
+obj-y				+= airoha/
 obj-y				+= apple/
 obj-y				+= aspeed/
 obj-$(CONFIG_ARCH_AT91)		+= atmel/
diff --git a/drivers/soc/airoha/Kconfig b/drivers/soc/airoha/Kconfig
new file mode 100644
index 000000000000..56c677f8238d
--- /dev/null
+++ b/drivers/soc/airoha/Kconfig
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config AIROHA_SCU_SSR
+	tristate "Airoha SCU SSR Driver"
+	depends on ARCH_AIROHA || COMPILE_TEST
+	depends on OF
+	help
+	  Say 'Y' here to add support for Airoha SCU SSR driver.
+
+	  Airoha SoC pheriperal (like USB/PCIe/Ethernet port) are
+	  selected by toggling specific bit. Serdes Port line
+	  are mutually exclusive such as selecting PCIe port 2
+	  disable support for USB port 2 3.0 mode.
+
+	  This driver is used to configure such bit and expose
+	  an API to read the current status from a user of such
+	  Serdes lines.
+
diff --git a/drivers/soc/airoha/Makefile b/drivers/soc/airoha/Makefile
new file mode 100644
index 000000000000..530825251ae9
--- /dev/null
+++ b/drivers/soc/airoha/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_AIROHA_SCU_SSR)		+= airoha-scu-ssr.o
diff --git a/drivers/soc/airoha/airoha-scu-ssr.c b/drivers/soc/airoha/airoha-scu-ssr.c
new file mode 100644
index 000000000000..29e17577e9a4
--- /dev/null
+++ b/drivers/soc/airoha/airoha-scu-ssr.c
@@ -0,0 +1,221 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Author: Christian Marangi <ansuelsmth@gmail.com>
+ */
+
+#include <dt-bindings/soc/airoha,scu-ssr.h>
+#include <linux/bitfield.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/soc/airoha/airoha-scu-ssr.h>
+
+#define AIROHA_SCU_PCIC			0x88
+#define   AIROHA_SCU_PCIE_2LANE_MODE	BIT(14)
+
+#define AIROHA_SCU_SSR3			0x94
+#define   AIROHA_SCU_SSUSB_HSGMII_SEL	BIT(29)
+
+#define AIROHA_SCU_SSTR			0x9c
+#define   AIROHA_SCU_PCIE_XSI0_SEL	GENMASK(14, 13)
+#define   AIROHA_SCU_PCIE_XSI0_SEL_PCIE	FIELD_PREP_CONST(AIROHA_SCU_PCIE_XSI0_SEL, 0x0)
+#define   AIROHA_SCU_PCIE_XSI1_SEL	GENMASK(12, 11)
+#define   AIROHA_SCU_PCIE_XSI1_SEL_PCIE	FIELD_PREP_CONST(AIROHA_SCU_PCIE_XSI0_SEL, 0x0)
+#define   AIROHA_SCU_USB_PCIE_SEL	BIT(3)
+
+#define AIROHA_SCU_MAX_SERDES_PORT	4
+
+struct airoha_scu_ssr_priv {
+	struct device *dev;
+	struct regmap *regmap;
+
+	unsigned int serdes_port[AIROHA_SCU_MAX_SERDES_PORT];
+};
+
+static const char * const airoha_scu_serdes_mode_to_str[] = {
+	[AIROHA_SCU_SERDES_MODE_PCIE0_X1] = "pcie0_x1",
+	[AIROHA_SCU_SERDES_MODE_PCIE0_X2] = "pcie0_x2",
+	[AIROHA_SCU_SERDES_MODE_PCIE1_X1] = "pcie1_x1",
+	[AIROHA_SCU_SERDES_MODE_PCIE2_X1] = "pcie2_x1",
+	[AIROHA_SCU_SERDES_MODE_USB3] = "usb3",
+	[AIROHA_SCU_SERDES_MODE_ETHERNET] = "ethernet",
+};
+
+static int airoha_scu_serdes_str_to_mode(const char *serdes_str)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(airoha_scu_serdes_mode_to_str); i++)
+		if (!strncmp(serdes_str, airoha_scu_serdes_mode_to_str[i],
+			     strlen(airoha_scu_serdes_mode_to_str[i])))
+			return i;
+
+	return -EINVAL;
+}
+
+static int airoha_scu_ssr_apply_modes(struct airoha_scu_ssr_priv *priv)
+{
+	int ret;
+
+	/*
+	 * This is a very bad scenario and needs to be correctly warned
+	 * as it cause PCIe malfunction.
+	 */
+	if ((priv->serdes_port[AIROHA_SCU_SERDES_WIFI1] == AIROHA_SCU_SERDES_MODE_PCIE0_X2 &&
+	     priv->serdes_port[AIROHA_SCU_SERDES_WIFI2] != AIROHA_SCU_SERDES_MODE_PCIE0_X2) ||
+	    (priv->serdes_port[AIROHA_SCU_SERDES_WIFI1] != AIROHA_SCU_SERDES_MODE_PCIE0_X2 &&
+	     priv->serdes_port[AIROHA_SCU_SERDES_WIFI2] == AIROHA_SCU_SERDES_MODE_PCIE0_X2)) {
+		WARN(true, "Wrong Serdes configuration for PCIe0 2 Line mode. Please check DT.\n");
+		return -EINVAL;
+	}
+
+	/* PCS driver takes care of setting the SCU bit for HSGMII or USXGMII */
+	if (priv->serdes_port[AIROHA_SCU_SERDES_WIFI1] == AIROHA_SCU_SERDES_MODE_PCIE0_X1 ||
+	    priv->serdes_port[AIROHA_SCU_SERDES_WIFI1] == AIROHA_SCU_SERDES_MODE_PCIE0_X2) {
+		ret = regmap_update_bits(priv->regmap, AIROHA_SCU_SSTR,
+					 AIROHA_SCU_PCIE_XSI0_SEL,
+					 AIROHA_SCU_PCIE_XSI0_SEL_PCIE);
+		if (ret)
+			return ret;
+	}
+
+	/* PCS driver takes care of setting the SCU bit for HSGMII or USXGMII */
+	if (priv->serdes_port[AIROHA_SCU_SERDES_WIFI2] == AIROHA_SCU_SERDES_MODE_PCIE1_X1 ||
+	    priv->serdes_port[AIROHA_SCU_SERDES_WIFI2] == AIROHA_SCU_SERDES_MODE_PCIE0_X2) {
+		ret = regmap_update_bits(priv->regmap, AIROHA_SCU_SSTR,
+					 AIROHA_SCU_PCIE_XSI1_SEL,
+					 AIROHA_SCU_PCIE_XSI1_SEL_PCIE);
+		if (ret)
+			return ret;
+	}
+
+	/* Toggle PCIe0 2 Line mode if enabled or not */
+	if (priv->serdes_port[AIROHA_SCU_SERDES_WIFI1] == AIROHA_SCU_SERDES_MODE_PCIE0_X2)
+		ret = regmap_set_bits(priv->regmap, AIROHA_SCU_PCIC,
+				      AIROHA_SCU_PCIE_2LANE_MODE);
+	else
+		ret = regmap_clear_bits(priv->regmap, AIROHA_SCU_PCIC,
+					AIROHA_SCU_PCIE_2LANE_MODE);
+	if (ret)
+		return ret;
+
+	if (priv->serdes_port[AIROHA_SCU_SERDES_USB1] == AIROHA_SCU_SERDES_MODE_ETHERNET)
+		ret = regmap_clear_bits(priv->regmap, AIROHA_SCU_SSR3,
+					AIROHA_SCU_SSUSB_HSGMII_SEL);
+	else
+		ret = regmap_set_bits(priv->regmap, AIROHA_SCU_SSR3,
+				      AIROHA_SCU_SSUSB_HSGMII_SEL);
+	if (ret)
+		return ret;
+
+	if (priv->serdes_port[AIROHA_SCU_SERDES_USB2] == AIROHA_SCU_SERDES_MODE_PCIE2_X1)
+		ret = regmap_clear_bits(priv->regmap, AIROHA_SCU_SSTR,
+					AIROHA_SCU_USB_PCIE_SEL);
+	else
+		ret = regmap_set_bits(priv->regmap, AIROHA_SCU_SSTR,
+				      AIROHA_SCU_USB_PCIE_SEL);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int airoha_scu_ssr_parse_mode(struct device *dev,
+				     struct airoha_scu_ssr_priv *priv,
+				     const char *property_name, unsigned int port,
+				     unsigned int default_mode)
+{
+	const struct airoha_scu_ssr_serdes_info *port_info;
+	const struct airoha_scu_ssr_data *pdata;
+	const char *serdes_mode;
+	int mode, i;
+
+	pdata = dev->platform_data;
+
+	if (of_property_read_string(dev->of_node, property_name,
+				    &serdes_mode)) {
+		priv->serdes_port[port] = default_mode;
+		return 0;
+	}
+
+	mode = airoha_scu_serdes_str_to_mode(serdes_mode);
+	if (mode) {
+		dev_err(dev, "invalid mode %s for %s\n", serdes_mode, property_name);
+		return mode;
+	}
+
+	port_info = &pdata->ports_info[port];
+	for (i = 0; i < port_info->num_modes; i++) {
+		if (port_info->possible_modes[i] == mode) {
+			priv->serdes_port[port] = mode;
+			return 0;
+		}
+	}
+
+	dev_err(dev, "mode %s not supported for %s", serdes_mode, property_name);
+	return -EINVAL;
+}
+
+static int airoha_scu_ssr_probe(struct platform_device *pdev)
+{
+	struct airoha_scu_ssr_priv *priv;
+	struct device *dev = &pdev->dev;
+	int ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->dev = dev;
+
+	/* Get regmap from MFD */
+	priv->regmap = dev_get_regmap(dev->parent, NULL);
+	if (!priv->regmap)
+		return -EINVAL;
+
+	ret = airoha_scu_ssr_parse_mode(dev, priv, "airoha,serdes-wifi1",
+					AIROHA_SCU_SERDES_WIFI1,
+					AIROHA_SCU_SERDES_MODE_PCIE0_X1);
+	if (ret)
+		return ret;
+
+	ret = airoha_scu_ssr_parse_mode(dev, priv, "airoha,serdes-wifi2",
+					AIROHA_SCU_SERDES_WIFI2,
+					AIROHA_SCU_SERDES_MODE_PCIE1_X1);
+	if (ret)
+		return ret;
+
+	ret = airoha_scu_ssr_parse_mode(dev, priv, "airoha,serdes-usb1",
+					AIROHA_SCU_SERDES_USB1,
+					AIROHA_SCU_SERDES_MODE_USB3);
+	if (ret)
+		return ret;
+
+	ret = airoha_scu_ssr_parse_mode(dev, priv, "airoha,serdes-usb2",
+					AIROHA_SCU_SERDES_USB2,
+					AIROHA_SCU_SERDES_MODE_USB3);
+	if (ret)
+		return ret;
+
+	ret = airoha_scu_ssr_apply_modes(priv);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, priv);
+
+	return 0;
+}
+
+static struct platform_driver airoha_scu_ssr_driver = {
+	.probe		= airoha_scu_ssr_probe,
+	.driver		= {
+		.name	= "airoha-scu-ssr",
+	},
+};
+
+module_platform_driver(airoha_scu_ssr_driver);
+
+MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Airoha SCU SSR/STR driver");
diff --git a/include/linux/soc/airoha/airoha-scu-ssr.h b/include/linux/soc/airoha/airoha-scu-ssr.h
new file mode 100644
index 000000000000..0224c0340b6d
--- /dev/null
+++ b/include/linux/soc/airoha/airoha-scu-ssr.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __AIROHA_SCU_SSR__
+#define __AIROHA_SCU_SSR__
+
+enum airoha_scu_serdes_modes {
+	AIROHA_SCU_SERDES_MODE_PCIE0_X1,
+	AIROHA_SCU_SERDES_MODE_PCIE0_X2,
+	AIROHA_SCU_SERDES_MODE_PCIE1_X1,
+	AIROHA_SCU_SERDES_MODE_PCIE2_X1,
+	AIROHA_SCU_SERDES_MODE_USB3,
+	AIROHA_SCU_SERDES_MODE_ETHERNET,
+};
+
+struct airoha_scu_ssr_serdes_info {
+	unsigned int *possible_modes;
+	unsigned int num_modes;
+};
+
+struct airoha_scu_ssr_data {
+	const struct airoha_scu_ssr_serdes_info *ports_info;
+};
+
+#endif
