[PATCH 06/16] usb: typec: add FUSB340 SuperSpeed switch driver
From: Fabrice Gasnier
Date: Fri Aug 21 2026 - 12:27:49 EST
Add a platform driver for the ON Semiconductor FUSB340 SuperSpeed switch.
The driver uses enable-gpios and select-gpios to control the switch and
registers Type-C switch and mux providers for Type-C applications where a
reversible cable requires a switch.
Assisted-by: GitHub-Copilot:GPT-5.4-mini
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@xxxxxxxxxxx>
---
drivers/usb/typec/mux/Kconfig | 8 ++
drivers/usb/typec/mux/Makefile | 1 +
drivers/usb/typec/mux/fusb340.c | 169 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 178 insertions(+)
diff --git a/drivers/usb/typec/mux/Kconfig b/drivers/usb/typec/mux/Kconfig
index 6dd8f961b593..6a1da48a2a8f 100644
--- a/drivers/usb/typec/mux/Kconfig
+++ b/drivers/usb/typec/mux/Kconfig
@@ -12,6 +12,14 @@ config TYPEC_MUX_FSA4480
common USB Type-C connector.
If compiled as a module, the module will be named fsa4480.
+config TYPEC_MUX_FUSB340
+ tristate "ON Semi FUSB340 SuperSpeed switch driver"
+ help
+ Driver for the ON Semiconductor FUSB340 SuperSpeed switch, which
+ provides support for routing SuperSpeed pairs in Type-C applications
+ where a reversible cable requires a switch.
+ If compiled as a module, the module will be named fusb340.
+
config TYPEC_MUX_GPIO_SBU
tristate "Generic GPIO based SBU mux for USB Type-C applications"
help
diff --git a/drivers/usb/typec/mux/Makefile b/drivers/usb/typec/mux/Makefile
index b4f599eb5053..ef8d2b05ff7f 100644
--- a/drivers/usb/typec/mux/Makefile
+++ b/drivers/usb/typec/mux/Makefile
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_TYPEC_MUX_FSA4480) += fsa4480.o
+obj-$(CONFIG_TYPEC_MUX_FUSB340) += fusb340.o
obj-$(CONFIG_TYPEC_MUX_GPIO_SBU) += gpio-sbu-mux.o
obj-$(CONFIG_TYPEC_MUX_PI3USB30532) += pi3usb30532.o
obj-$(CONFIG_TYPEC_MUX_INTEL_PMC) += intel_pmc_mux.o
diff --git a/drivers/usb/typec/mux/fusb340.c b/drivers/usb/typec/mux/fusb340.c
new file mode 100644
index 000000000000..0f0e45743784
--- /dev/null
+++ b/drivers/usb/typec/mux/fusb340.c
@@ -0,0 +1,169 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ON Semiconductor FUSB340 SuperSpeed switch driver
+ *
+ * Copyright (C) 2026 STMicroelectronics
+ */
+
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/usb/typec_altmode.h>
+#include <linux/usb/typec_mux.h>
+
+struct fusb340 {
+ struct gpio_desc *enable_gpio;
+ struct gpio_desc *select_gpio;
+ struct mutex lock; /* serialize orientation and mode updates */
+ struct typec_switch_dev *sw;
+ struct typec_mux_dev *mux;
+ enum typec_orientation orientation;
+ unsigned long mode;
+};
+
+static void fusb340_update_locked(struct fusb340 *fusb)
+{
+ bool enable = fusb->mode == TYPEC_STATE_USB &&
+ fusb->orientation != TYPEC_ORIENTATION_NONE;
+ bool select = fusb->orientation == TYPEC_ORIENTATION_REVERSE;
+
+ gpiod_set_value_cansleep(fusb->enable_gpio, enable);
+ gpiod_set_value_cansleep(fusb->select_gpio, select);
+}
+
+static int fusb340_switch_set(struct typec_switch_dev *sw,
+ enum typec_orientation orientation)
+{
+ struct fusb340 *fusb = typec_switch_get_drvdata(sw);
+
+ mutex_lock(&fusb->lock);
+
+ if (fusb->orientation != orientation) {
+ fusb->orientation = orientation;
+ fusb340_update_locked(fusb);
+ }
+
+ mutex_unlock(&fusb->lock);
+
+ return 0;
+}
+
+static int fusb340_mux_set(struct typec_mux_dev *mux,
+ struct typec_mux_state *state)
+{
+ struct fusb340 *fusb = typec_mux_get_drvdata(mux);
+ int ret = 0;
+
+ mutex_lock(&fusb->lock);
+
+ if (state->mode != TYPEC_STATE_SAFE && state->mode != TYPEC_STATE_USB) {
+ ret = -EOPNOTSUPP;
+ goto out_unlock;
+ }
+
+ if (fusb->mode != state->mode) {
+ fusb->mode = state->mode;
+ fusb340_update_locked(fusb);
+ }
+
+out_unlock:
+ mutex_unlock(&fusb->lock);
+
+ return ret;
+}
+
+static int fusb340_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct typec_switch_desc sw_desc = { };
+ struct typec_mux_desc mux_desc = { };
+ struct fusb340 *fusb;
+ int ret;
+
+ fusb = devm_kzalloc(dev, sizeof(*fusb), GFP_KERNEL);
+ if (!fusb)
+ return -ENOMEM;
+
+ fusb->orientation = TYPEC_ORIENTATION_NONE;
+ fusb->mode = TYPEC_STATE_SAFE;
+
+ fusb->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
+ if (IS_ERR(fusb->enable_gpio))
+ return dev_err_probe(dev, PTR_ERR(fusb->enable_gpio),
+ "failed to get enable gpio\n");
+
+ fusb->select_gpio = devm_gpiod_get(dev, "select", GPIOD_OUT_LOW);
+ if (IS_ERR(fusb->select_gpio))
+ return dev_err_probe(dev, PTR_ERR(fusb->select_gpio),
+ "failed to get select gpio\n");
+
+ mutex_init(&fusb->lock);
+
+ sw_desc.drvdata = fusb;
+ sw_desc.fwnode = dev_fwnode(dev);
+ sw_desc.set = fusb340_switch_set;
+
+ fusb->sw = typec_switch_register(dev, &sw_desc);
+ if (IS_ERR(fusb->sw)) {
+ ret = dev_err_probe(dev, PTR_ERR(fusb->sw),
+ "failed to register typec switch\n");
+ goto err_mutex_destroy;
+ }
+
+ mux_desc.drvdata = fusb;
+ mux_desc.fwnode = dev_fwnode(dev);
+ mux_desc.set = fusb340_mux_set;
+
+ fusb->mux = typec_mux_register(dev, &mux_desc);
+ if (IS_ERR(fusb->mux)) {
+ ret = dev_err_probe(dev, PTR_ERR(fusb->mux),
+ "failed to register typec mux\n");
+ goto err_unregister_switch;
+ }
+
+ platform_set_drvdata(pdev, fusb);
+
+ return 0;
+
+err_unregister_switch:
+ typec_switch_unregister(fusb->sw);
+err_mutex_destroy:
+ mutex_destroy(&fusb->lock);
+ return ret;
+}
+
+static void fusb340_remove(struct platform_device *pdev)
+{
+ struct fusb340 *fusb = platform_get_drvdata(pdev);
+
+ gpiod_set_value_cansleep(fusb->enable_gpio, 0);
+ gpiod_set_value_cansleep(fusb->select_gpio, 0);
+
+ typec_mux_unregister(fusb->mux);
+ typec_switch_unregister(fusb->sw);
+ mutex_destroy(&fusb->lock);
+}
+
+static const struct of_device_id fusb340_of_match[] = {
+ { .compatible = "onnn,fusb340" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, fusb340_of_match);
+
+static struct platform_driver fusb340_driver = {
+ .probe = fusb340_probe,
+ .remove = fusb340_remove,
+ .driver = {
+ .name = "fusb340",
+ .of_match_table = fusb340_of_match,
+ },
+};
+module_platform_driver(fusb340_driver);
+
+MODULE_DESCRIPTION("ON Semiconductor FUSB340 SuperSpeed switch driver");
+MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@xxxxxxxxxxx>");
+MODULE_LICENSE("GPL");
--
2.43.0