* [PATCH 00/16] Add support for USB Type-C on STM32MP25
@ 2026-08-21 16:23 Fabrice Gasnier
2026-08-21 16:23 ` [PATCH 01/16] dt-bindings: usb: st,tcpp: Document TCPP USB-C PD protection chip Fabrice Gasnier
` (15 more replies)
0 siblings, 16 replies; 24+ messages in thread
From: Fabrice Gasnier @ 2026-08-21 16:23 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Christian Bruel, Fabrice Gasnier, Heikki Krogerus,
Alexandre Torgue, Philipp Zabel, Liam Girdwood, Mark Brown,
Srinivas Kandagatla, Marek Vasut, Vinod Koul, Neil Armstrong,
Pankaj Dev, Marek Vasut
Cc: linux-usb, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel, linux-phy, Thomas Bourgoin
Add support for the UCPD controller found in STM32MP23 and STM32MP25 platforms.
It is tigtly coupled with external TCPP02/03 I2C companion chip to interface
and to protect UCB-C DRP port.
Purpose is to propose a complete set of drivers and bindings to enable USB
Type-C support on STM32MP25 reference design boards, EVAL and DK, compared
to alternate UCPD series [1].
This is an on-going work on top of over series [2] and [3].
[1] https://lore.kernel.org/all/20260819163410.119755-1-marex@nabladev.com/
[2] https://lore.kernel.org/linux-phy/20260816213849.1044073-1-marex@nabladev.com/
[3] https://lore.kernel.org/linux-usb/20260817163101.6203-1-fabrice.gasnier@foss.st.com/
---
Christian Bruel (6):
dt-bindings: usb: st,tcpp: Document TCPP USB-C PD protection chip
usb: typec: tcpm: Add STM32 tcpp driver
dt-bindings: usb: st,stm32-ucpd: Document STM32 UCPD controller
usb: typec: tcpm: Add STM32 UCPD driver
arm64: dts: st: add i2c1 pinctrl entries for stm32mp25
arm64: dts: st: add tcpp pinctrl entries for stm32mp25
Fabrice Gasnier (10):
dt-bindings: usb: add FUSB340 switch binding
usb: typec: add FUSB340 SuperSpeed switch driver
dt-bindings: nvmem: st,stm32-romem: align patternProperties regex on nvmem-deprecated-cells.yaml
arm64: dts: st: Add ucpd node on stm32mp251
dt-bindings: usb: dwc3: stm32: refer to dwc3-common
dt-bindings: phy: stm32: adapt usb2phy as syscon child on stm32mp25
dt-bindings: arm: stm32mp2: allow child nodes since simple-mfd transition
arm64: dts: st: enable usb on stm32mp257f-ev1
arm64: dts: st: enable usb on stm32mp257f-dk
arm64: configs: enable usb and its dependencies used on stm32mp25
.../bindings/arm/stm32/st,stm32-syscon.yaml | 10 +
.../devicetree/bindings/nvmem/st,stm32-romem.yaml | 2 +-
.../devicetree/bindings/phy/st,stm32-usb2phy.yaml | 20 +-
.../devicetree/bindings/usb/onnn,fusb340.yaml | 73 ++
.../devicetree/bindings/usb/st,stm32-ucpd.yaml | 134 ++++
.../devicetree/bindings/usb/st,stm32mp25-dwc3.yaml | 3 +
Documentation/devicetree/bindings/usb/st,tcpp.yaml | 63 ++
arch/arm64/boot/dts/st/stm32mp25-pinctrl.dtsi | 27 +
arch/arm64/boot/dts/st/stm32mp251.dtsi | 51 ++
arch/arm64/boot/dts/st/stm32mp257f-dk.dts | 111 +++
arch/arm64/boot/dts/st/stm32mp257f-ev1.dts | 79 ++
arch/arm64/configs/defconfig | 6 +
drivers/usb/typec/mux/Kconfig | 8 +
drivers/usb/typec/mux/Makefile | 1 +
drivers/usb/typec/mux/fusb340.c | 169 +++++
drivers/usb/typec/tcpm/Kconfig | 22 +
drivers/usb/typec/tcpm/Makefile | 2 +
drivers/usb/typec/tcpm/st_tcpp.c | 418 +++++++++++
drivers/usb/typec/tcpm/st_tcpp.h | 21 +
drivers/usb/typec/tcpm/stm32_ucpd.c | 818 +++++++++++++++++++++
20 files changed, 2024 insertions(+), 14 deletions(-)
---
base-commit: a8eb98861eefbab7fc254c8014712471448b295c
change-id: 20260821-ucpd-host-fusb340-v7-2-rfc-836f0bac0543
Best regards,
--
Fabrice Gasnier <fabrice.gasnier@foss.st.com>
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH 01/16] dt-bindings: usb: st,tcpp: Document TCPP USB-C PD protection chip
2026-08-21 16:23 [PATCH 00/16] Add support for USB Type-C on STM32MP25 Fabrice Gasnier
@ 2026-08-21 16:23 ` Fabrice Gasnier
2026-08-21 16:23 ` [PATCH 02/16] usb: typec: tcpm: Add STM32 tcpp driver Fabrice Gasnier
` (14 subsequent siblings)
15 siblings, 0 replies; 24+ messages in thread
From: Fabrice Gasnier @ 2026-08-21 16:23 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Christian Bruel, Fabrice Gasnier, Heikki Krogerus,
Alexandre Torgue, Philipp Zabel, Liam Girdwood, Mark Brown,
Srinivas Kandagatla, Marek Vasut, Vinod Koul, Neil Armstrong,
Pankaj Dev, Marek Vasut
Cc: linux-usb, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel, linux-phy
From: Christian Bruel <christian.bruel@foss.st.com>
Add binding documentation for the STMicroelectronics TCPP Type-C port
controller. TCPP03 is a companion chip to interface and to protect
UCB-C DRP port. It has been developed to be used with STM32
family embedding the UCPD controller.
Signed-off-by: Christian Bruel <christian.bruel@foss.st.com>
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
Documentation/devicetree/bindings/usb/st,tcpp.yaml | 63 ++++++++++++++++++++++
1 file changed, 63 insertions(+)
diff --git a/Documentation/devicetree/bindings/usb/st,tcpp.yaml b/Documentation/devicetree/bindings/usb/st,tcpp.yaml
new file mode 100644
index 000000000000..3224969359c6
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/st,tcpp.yaml
@@ -0,0 +1,63 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/st,tcpp.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STMicroelectronics TCPP03 USB-C PD protection chip for DRP
+
+maintainers:
+ - Christian Bruel <christian.bruel@foss.st.com>
+ - Fabrice Gasnier <fabrice.gasnier@foss.st.com>
+
+description:
+ TCPP03 is a companion chip to interface and to protect USB-C DRP port.
+ It has been developed to be used with STM32 family embedding UCPD controller.
+ Access from I2C interface with 2 read registers SR1/SR2 and 1 CR register.
+
+properties:
+ compatible:
+ const: st,tcpp03
+
+ reg:
+ description: I2C address
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ enable-gpios:
+ description:
+ GPIO pin connected to the TCPP_EN signal of the UCPD
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+ #include <dt-bindings/gpio/gpio.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&i2c1_pins_a>;
+ pinctrl-1 = <&i2c1_sleep_pins_a>;
+ clock-frequency = <400000>;
+
+ typec@34 {
+ compatible = "st,tcpp03";
+ reg = <0x34>;
+ enable-gpios = <&gpiog 2 GPIO_ACTIVE_HIGH>;
+ interrupt-parent = <&gpiog>;
+ interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&tcpp_flgn_pins_a>;
+ };
+ };
--
2.43.0
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 02/16] usb: typec: tcpm: Add STM32 tcpp driver
2026-08-21 16:23 [PATCH 00/16] Add support for USB Type-C on STM32MP25 Fabrice Gasnier
2026-08-21 16:23 ` [PATCH 01/16] dt-bindings: usb: st,tcpp: Document TCPP USB-C PD protection chip Fabrice Gasnier
@ 2026-08-21 16:23 ` Fabrice Gasnier
2026-08-22 4:50 ` Marek Vasut
2026-08-21 16:23 ` [PATCH 03/16] dt-bindings: usb: st,stm32-ucpd: Document STM32 UCPD controller Fabrice Gasnier
` (13 subsequent siblings)
15 siblings, 1 reply; 24+ messages in thread
From: Fabrice Gasnier @ 2026-08-21 16:23 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Christian Bruel, Fabrice Gasnier, Heikki Krogerus,
Alexandre Torgue, Philipp Zabel, Liam Girdwood, Mark Brown,
Srinivas Kandagatla, Marek Vasut, Vinod Koul, Neil Armstrong,
Pankaj Dev, Marek Vasut
Cc: linux-usb, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel, linux-phy
From: Christian Bruel <christian.bruel@foss.st.com>
Add support for the STMicroelectronics TCPP02 and TCPP03 USB-C PD
protection for dual role power (DRP).
It can be used with the STM32 family embedding UCPD controller.
Purpose is to be used by the UCPD driver and tcpm framework to notify
Vbus changes. To control the provider gate, the TCPP must be put in
normal PM mode. In this mode, only failures may be reported by the IRQ
line. So add a delayed work, to poll for VBUS status bits via I2C.
Start to poll when necessary: upon attach / detach, or when switching
on / off provider or consumer gates.
Also provide HW protection (mainly ESD) and drive Vbus and Vconn.
Isolate CC lines while in low power (hibernate mode) so the main STM32
controller can be put in standby mode safely.
Signed-off-by: Christian Bruel <christian.bruel@foss.st.com>
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
drivers/usb/typec/tcpm/Kconfig | 10 +
drivers/usb/typec/tcpm/Makefile | 1 +
drivers/usb/typec/tcpm/st_tcpp.c | 418 +++++++++++++++++++++++++++++++++++++++
drivers/usb/typec/tcpm/st_tcpp.h | 21 ++
4 files changed, 450 insertions(+)
diff --git a/drivers/usb/typec/tcpm/Kconfig b/drivers/usb/typec/tcpm/Kconfig
index 00baa7503d45..c24d98200a57 100644
--- a/drivers/usb/typec/tcpm/Kconfig
+++ b/drivers/usb/typec/tcpm/Kconfig
@@ -65,6 +65,16 @@ config TYPEC_FUSB302
Type-C Port Controller Manager to provide USB PD and USB
Type-C functionalities.
+config TYPEC_ST_TCPP
+ tristate "STMicroelectronics TCCP USB-C Protection for UCPD DRP"
+ depends on I2C
+ help
+ Say Y or M here if your system has STM TCPP03 or TCPP02 Type-C
+ PD protection
+
+ If you choose to build this driver as a dynamically linked
+ module, the module will be called st_tcpp.ko.
+
config TYPEC_WCOVE
tristate "Intel WhiskeyCove PMIC USB Type-C PHY driver"
depends on ACPI
diff --git a/drivers/usb/typec/tcpm/Makefile b/drivers/usb/typec/tcpm/Makefile
index 7a8cad0c0bdb..0ee6ff598f75 100644
--- a/drivers/usb/typec/tcpm/Makefile
+++ b/drivers/usb/typec/tcpm/Makefile
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_TYPEC_TCPM) += tcpm.o
obj-$(CONFIG_TYPEC_FUSB302) += fusb302.o
+obj-$(CONFIG_TYPEC_ST_TCPP) += st_tcpp.o
obj-$(CONFIG_TYPEC_WCOVE) += typec_wcove.o
typec_wcove-y := wcove.o
obj-$(CONFIG_TYPEC_TCPCI) += tcpci.o
diff --git a/drivers/usb/typec/tcpm/st_tcpp.c b/drivers/usb/typec/tcpm/st_tcpp.c
new file mode 100644
index 000000000000..975d20a1ec71
--- /dev/null
+++ b/drivers/usb/typec/tcpm/st_tcpp.c
@@ -0,0 +1,418 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * STMicroelectronics USB-C PD protection TCPP02/03 driver
+ *
+ * Copyright (C) 2026 STMicroelectronics
+ */
+
+#include <linux/i2c.h>
+#include <linux/of_irq.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+#include <linux/usb/pd.h>
+#include <linux/usb/tcpm.h>
+#include "st_tcpp.h"
+
+struct st_tcpp {
+ struct device *dev;
+ struct regmap *regmap;
+ struct gpio_desc *enable_gpio;
+ struct workqueue_struct *wq;
+ struct delayed_work vbus_work;
+ unsigned long delay;
+ bool vbus;
+ tcpp_vbus_cb_t vbus_cb;
+ /* lock for sharing states with stm32_ucpd */
+ struct mutex lock;
+ void *vbus_cb_data;
+};
+
+#define TCPP_CR0 0
+#define TCPP_SR1 1
+#define TCPP_SR2 2
+
+/* writing register CR0 */
+#define TCPP_VCONN GENMASK(1, 0)
+#define TCPP_V1 BIT(0)
+#define TCPP_V2 BIT(1)
+#define TCPP_GD GENMASK(3, 2)
+#define TCPP_GDP BIT(2) /* Provider Gate */
+#define TCPP_GDP_OPEN 0
+#define TCPP_GDP_CLOSED 1
+#define TCPP_GDC BIT(3) /* Consumer Gate */
+#define TCPP_GDC_OPEN 1
+#define TCPP_GDC_CLOSED 0
+
+#define TCPP_PM GENMASK(5, 4)
+#define PM_HIBERNATE 0
+#define PM_NORMAL 1
+#define PM_LP 2
+#define TCPP_VBUSD BIT(6)
+
+/* reading register SR1 */
+#define TCPP_VBUS_OK BIT(5)
+
+#define VBUS_POLL_INTERVAL_MS 10
+
+int tcpp_register_vbus_notifier(struct device *dev, tcpp_vbus_cb_t cb, void *data)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct st_tcpp *tcpp = i2c_get_clientdata(client);
+
+ tcpp->vbus_cb = cb;
+ tcpp->vbus_cb_data = data;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tcpp_register_vbus_notifier);
+
+void tcpp_unregister_vbus_notifier(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct st_tcpp *tcpp = i2c_get_clientdata(client);
+
+ tcpp->vbus_cb = NULL;
+ tcpp->vbus_cb_data = NULL;
+}
+EXPORT_SYMBOL_GPL(tcpp_unregister_vbus_notifier);
+
+static int tcpp_update_cr0_bits(struct st_tcpp *tcpp, u32 msk, u32 val)
+{
+ u32 sr1;
+ int ret;
+
+ ret = regmap_read(tcpp->regmap, TCPP_SR1, &sr1);
+ if (ret)
+ dev_err(tcpp->dev, "%s: Unable to read SR1: %d\n", __func__, ret);
+
+ sr1 &= ~msk;
+ sr1 |= val;
+
+ ret = regmap_write(tcpp->regmap, TCPP_CR0, sr1);
+ if (ret)
+ dev_err(tcpp->dev, "%s: Unable to update CR0: %d\n", __func__, ret);
+
+ return ret;
+}
+
+static int tcpp_set_pm(struct st_tcpp *tcpp, int pm)
+{
+ dev_dbg(tcpp->dev, "%s: set %s mode\n", __func__,
+ pm == PM_NORMAL ? "NORMAL" :
+ pm == PM_LP ? "LP" :
+ pm == PM_HIBERNATE ? "HIBERNATE" : "NA");
+
+ return tcpp_update_cr0_bits(tcpp, TCPP_PM, FIELD_PREP(TCPP_PM, pm));
+}
+
+int tcpp_init(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct st_tcpp *tcpp = i2c_get_clientdata(client);
+ int ret;
+
+ mutex_lock(&tcpp->lock);
+ gpiod_set_value_cansleep(tcpp->enable_gpio, true);
+
+ ret = tcpp_set_pm(tcpp, PM_LP);
+ if (ret) {
+ gpiod_set_value_cansleep(tcpp->enable_gpio, false);
+ goto err;
+ }
+
+ enable_irq(client->irq);
+
+err:
+ mutex_unlock(&tcpp->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(tcpp_init);
+
+void tcpp_deinit(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct st_tcpp *tcpp = i2c_get_clientdata(client);
+
+ disable_irq(client->irq);
+ /* vbus_work may take the lock : cancel it without holding the mutex */
+ cancel_delayed_work_sync(&tcpp->vbus_work);
+
+ mutex_lock(&tcpp->lock);
+ tcpp_set_pm(tcpp, PM_HIBERNATE);
+ gpiod_set_value_cansleep(tcpp->enable_gpio, false);
+ tcpp->vbus = false;
+
+ mutex_unlock(&tcpp->lock);
+}
+EXPORT_SYMBOL(tcpp_deinit);
+
+int tcpp_get_vbus(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct st_tcpp *tcpp = i2c_get_clientdata(client);
+ u32 sr2;
+ int ret;
+
+ mutex_lock(&tcpp->lock);
+ ret = regmap_read(tcpp->regmap, TCPP_SR2, &sr2);
+ if (ret) {
+ dev_err(tcpp->dev, "Unable to get SR2: %d\n", ret);
+ goto err;
+ }
+
+ ret = !!(sr2 & TCPP_VBUS_OK);
+
+err:
+ mutex_unlock(&tcpp->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(tcpp_get_vbus);
+
+int tcpp_set_vbus(struct device *dev, bool on, bool charge)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct st_tcpp *tcpp = i2c_get_clientdata(client);
+ bool gdp, gdc;
+ int ret;
+
+ dev_dbg(dev, "provider: %s, consumer: %s\n", str_enable_disable(on),
+ str_enable_disable(charge));
+
+ if (on) {
+ /* Set to normal mode to allow provider gate control via i2c */
+ ret = tcpp_set_pm(tcpp, PM_NORMAL);
+ if (ret)
+ return ret;
+ }
+
+ gdp = on ? TCPP_GDP_CLOSED : TCPP_GDP_OPEN;
+ gdc = charge ? TCPP_GDC_CLOSED : TCPP_GDC_OPEN;
+
+ ret = tcpp_update_cr0_bits(tcpp, TCPP_GD,
+ FIELD_PREP(TCPP_GDP, gdp) | FIELD_PREP(TCPP_GDC, gdc));
+ if (ret)
+ return ret;
+
+ /* Already done (switched ON or OFF) */
+ if ((on || charge) == tcpp->vbus)
+ return 0;
+
+ /*
+ * Not getting IRQ on Vbus change in NORMAL mode (only failures).
+ * Need to check Vbus state change to notify the tcpm state machine,
+ * e.g. either vbus has been en(dis)abled as provider or consumer,
+ * and vbus is in the expected en(dis)abled state (read it by i2c).
+ */
+ if (on)
+ tcpp->delay = jiffies + msecs_to_jiffies(PD_T_SRC_TURN_ON);
+ else
+ tcpp->delay = jiffies + msecs_to_jiffies(PD_T_SAFE_0V);
+
+ mod_delayed_work(tcpp->wq, &tcpp->vbus_work, 0);
+
+ return 0;
+}
+EXPORT_SYMBOL(tcpp_set_vbus);
+
+int tcpp_set_vconn(struct device *dev, bool on, enum typec_cc_polarity polarity)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct st_tcpp *tcpp = i2c_get_clientdata(client);
+ u32 vconn = 0;
+ int ret;
+
+ if (on) {
+ /* Set to normal mode to allow Vconn control via i2c */
+ ret = tcpp_set_pm(tcpp, PM_NORMAL);
+ if (ret)
+ return ret;
+
+ if (polarity == TYPEC_POLARITY_CC1)
+ vconn = TCPP_V2;
+ else
+ vconn = TCPP_V1;
+ }
+
+ dev_dbg(dev, "%s: set vconn 0x%x\n", __func__, vconn);
+
+ return tcpp_update_cr0_bits(tcpp, TCPP_VCONN, vconn);
+}
+EXPORT_SYMBOL(tcpp_set_vconn);
+
+int tcpp_attach(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct st_tcpp *tcpp = i2c_get_clientdata(client);
+ int ret;
+
+ mutex_lock(&tcpp->lock);
+ ret = tcpp_set_pm(tcpp, PM_NORMAL);
+ mutex_unlock(&tcpp->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(tcpp_attach);
+
+int tcpp_detach(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct st_tcpp *tcpp = i2c_get_clientdata(client);
+ int ret;
+
+ mutex_lock(&tcpp->lock);
+ ret = tcpp_set_pm(tcpp, PM_LP);
+ mutex_unlock(&tcpp->lock);
+ if (ret)
+ return ret;
+
+ /* Already OFF ? No need to poll. */
+ if (!tcpp->vbus)
+ return 0;
+
+ /*
+ * Earlier in NORMAL mode, don't get IRQ on vbus change (only failures),
+ * Check Vbus upon detach, to notify Vbus off.
+ */
+ tcpp->delay = jiffies + msecs_to_jiffies(PD_T_SAFE_0V);
+ mod_delayed_work(tcpp->wq, &tcpp->vbus_work, 0);
+
+ return ret;
+}
+EXPORT_SYMBOL(tcpp_detach);
+
+static void tcpp_vbus_poll_work(struct work_struct *work)
+{
+ struct st_tcpp *tcpp = container_of(work, struct st_tcpp, vbus_work.work);
+ bool vbus_on = !!tcpp_get_vbus(tcpp->dev);
+
+ dev_dbg(tcpp->dev, "%s vbus: %s\n", __func__, str_on_off(vbus_on));
+
+ if (tcpp->vbus != vbus_on) {
+ mutex_lock(&tcpp->lock);
+ if (tcpp->vbus_cb)
+ tcpp->vbus_cb(tcpp->vbus_cb_data, vbus_on);
+ mutex_unlock(&tcpp->lock);
+ tcpp->vbus = vbus_on;
+ return;
+ }
+
+ if (time_is_after_jiffies(tcpp->delay))
+ mod_delayed_work(tcpp->wq, &tcpp->vbus_work,
+ msecs_to_jiffies(VBUS_POLL_INTERVAL_MS));
+}
+
+static irqreturn_t tcpp_irq_thread(int irq, void *data)
+{
+ struct st_tcpp *tcpp = data;
+
+ mod_delayed_work(tcpp->wq, &tcpp->vbus_work, 0);
+
+ return IRQ_HANDLED;
+}
+
+static const struct regmap_config tcpp_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+static int tcpp_i2c_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct st_tcpp *tcpp;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ return -ENODEV;
+
+ tcpp = devm_kzalloc(dev, sizeof(*tcpp), GFP_KERNEL);
+ if (!tcpp)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, tcpp);
+
+ tcpp->dev = dev;
+ tcpp->regmap = devm_regmap_init_i2c(client, &tcpp_regmap);
+
+ mutex_init(&tcpp->lock);
+
+ tcpp->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
+ if (IS_ERR(tcpp->enable_gpio))
+ return dev_err_probe(dev, PTR_ERR(tcpp->enable_gpio),
+ "Failed to request TCPP enable GPIO\n");
+
+ irq_set_status_flags(client->irq, IRQ_NOAUTOEN);
+ ret = devm_request_threaded_irq(dev, client->irq, NULL, tcpp_irq_thread,
+ IRQF_ONESHOT, "tcpp", tcpp);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to request IRQ\n");
+
+ tcpp->wq = alloc_ordered_workqueue(dev_name(tcpp->dev), 0);
+ if (!tcpp->wq)
+ return -ENOMEM;
+
+ INIT_DELAYED_WORK(&tcpp->vbus_work, tcpp_vbus_poll_work);
+
+ return 0;
+}
+
+static void tcpp_remove(struct i2c_client *client)
+{
+ struct st_tcpp *tcpp = i2c_get_clientdata(client);
+
+ cancel_delayed_work_sync(&tcpp->vbus_work);
+ destroy_workqueue(tcpp->wq);
+}
+
+static int tcpp_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct st_tcpp *tcpp = i2c_get_clientdata(client);
+
+ flush_workqueue(tcpp->wq);
+ disable_irq(client->irq);
+
+ return 0;
+}
+
+static int tcpp_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ enable_irq(client->irq);
+
+ return 0;
+}
+
+static const struct dev_pm_ops tcpp_pm_ops = {
+ SYSTEM_SLEEP_PM_OPS(tcpp_suspend, tcpp_resume)
+};
+
+static const struct i2c_device_id tcpp_id[] = {
+ { "tcpp", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, tcpp_id);
+
+static const struct of_device_id stm_tcpp_match_table[] = {
+ { .compatible = "st,tcpp03" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, stm_tcpp_match_table);
+
+static struct i2c_driver tcpp_driver = {
+ .driver = {
+ .name = "tcpp",
+ .pm = &tcpp_pm_ops,
+ .of_match_table = stm_tcpp_match_table,
+ },
+ .probe = tcpp_i2c_probe,
+ .remove = tcpp_remove,
+ .id_table = tcpp_id,
+};
+module_i2c_driver(tcpp_driver);
+
+MODULE_DESCRIPTION("TCPP02/03 USB Type-C PD protection driver");
+MODULE_AUTHOR("Christian Bruel <christian.bruel@foss.st.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/typec/tcpm/st_tcpp.h b/drivers/usb/typec/tcpm/st_tcpp.h
new file mode 100644
index 000000000000..9284410af581
--- /dev/null
+++ b/drivers/usb/typec/tcpm/st_tcpp.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2026 STMicroelectronics
+ */
+
+#ifndef __ST_TCPP_H__
+#define __ST_TCPP_H__
+
+typedef void (*tcpp_vbus_cb_t)(void *data, bool vbus_present);
+
+int tcpp_init(struct device *tcpp);
+void tcpp_deinit(struct device *tcpp);
+int tcpp_get_vbus(struct device *tcpp);
+int tcpp_set_vbus(struct device *tcpp, bool on, bool charge);
+int tcpp_set_vconn(struct device *dev, bool on, enum typec_cc_polarity polarity);
+int tcpp_attach(struct device *tcpp);
+int tcpp_detach(struct device *tcpp);
+int tcpp_register_vbus_notifier(struct device *dev, tcpp_vbus_cb_t cb, void *data);
+void tcpp_unregister_vbus_notifier(struct device *dev);
+
+#endif
--
2.43.0
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 03/16] dt-bindings: usb: st,stm32-ucpd: Document STM32 UCPD controller
2026-08-21 16:23 [PATCH 00/16] Add support for USB Type-C on STM32MP25 Fabrice Gasnier
2026-08-21 16:23 ` [PATCH 01/16] dt-bindings: usb: st,tcpp: Document TCPP USB-C PD protection chip Fabrice Gasnier
2026-08-21 16:23 ` [PATCH 02/16] usb: typec: tcpm: Add STM32 tcpp driver Fabrice Gasnier
@ 2026-08-21 16:23 ` Fabrice Gasnier
2026-08-21 16:23 ` [PATCH 04/16] usb: typec: tcpm: Add STM32 UCPD driver Fabrice Gasnier
` (12 subsequent siblings)
15 siblings, 0 replies; 24+ messages in thread
From: Fabrice Gasnier @ 2026-08-21 16:23 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Christian Bruel, Fabrice Gasnier, Heikki Krogerus,
Alexandre Torgue, Philipp Zabel, Liam Girdwood, Mark Brown,
Srinivas Kandagatla, Marek Vasut, Vinod Koul, Neil Armstrong,
Pankaj Dev, Marek Vasut
Cc: linux-usb, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel, linux-phy
From: Christian Bruel <christian.bruel@foss.st.com>
Add support for the UCPD controller found in STM32MP25 platforms.
Document the compatible "st,stm32-ucpd". This controller handles
USB Type-C CC line management and USB PD.
VBUS monitoring relies on external TCPP03 companion chip
Signed-off-by: Christian Bruel <christian.bruel@foss.st.com>
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
.../devicetree/bindings/usb/st,stm32-ucpd.yaml | 134 +++++++++++++++++++++
1 file changed, 134 insertions(+)
diff --git a/Documentation/devicetree/bindings/usb/st,stm32-ucpd.yaml b/Documentation/devicetree/bindings/usb/st,stm32-ucpd.yaml
new file mode 100644
index 000000000000..d9b8253654a7
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/st,stm32-ucpd.yaml
@@ -0,0 +1,134 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/st,stm32-ucpd.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STM32 UCPD (USB Type-C and Power Delivery)
+
+maintainers:
+ - Christian Bruel <christian.bruel@foss.st.com>
+ - Fabrice Gasnier <fabrice.gasnier@foss.st.com>
+
+description:
+ STMicroelectronics USB Type-C and Power Delivery Port Controller
+
+properties:
+ compatible:
+ const: st,stm32mp25-ucpd
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ interrupt-names:
+ const: ucpd
+
+ clocks:
+ items:
+ - description: APB Bus clock
+ - description: RCC kernel clock
+
+ clock-names:
+ items:
+ - const: apb
+ - const: ker
+
+ resets:
+ maxItems: 1
+
+ reset-names:
+ const: ucpd
+
+ nvmem-cells:
+ maxItems: 6
+ description: Phandles to the trim values provided by otp
+
+ nvmem-cell-names:
+ maxItems: 6
+
+ st,tcpp:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description:
+ phandle to Type-C Port Protection companion chip.
+ Refer to ./st,tcpp.yaml
+
+ access-controllers:
+ maxItems: 1
+
+ power-domains:
+ maxItems: 1
+
+ ucpd-supply:
+ description: phandle to the UCPD regulator supply.
+
+ vconn-cc1-gpios:
+ description: Vconn on CC1 gate enable GPIO.
+
+ vconn-cc2-gpios:
+ description: Vconn on CC2 gate enable GPIO.
+
+ vconn-supply:
+ description: phandle to the regulator supplying Vconn gates.
+
+ connector:
+ type: object
+ $ref: ../connector/usb-connector.yaml#
+ unevaluatedProperties: false
+ description: USB Type-C connector properties.
+
+required:
+ - clocks
+ - clock-names
+ - compatible
+ - connector
+ - interrupts
+ - interrupt-names
+ - resets
+ - reset-names
+ - reg
+ - st,tcpp
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/st,stm32mp25-rcc.h>
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/reset/st,stm32mp25-rcc.h>
+
+ typec@480a0000 {
+ compatible = "st,stm32mp25-ucpd";
+ reg = <0x480a0000 0x400>;
+ interrupts-extended = <&exti1 46 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "ucpd";
+ clocks = <&rcc CK_BUS_USBTC>, <&rcc CK_KER_USBTC>;
+ clock-names = "apb", "ker";
+ resets = <&rcc USBTC_R>;
+ reset-names = "ucpd";
+ access-controllers = <&rifsc 69>;
+ power-domains = <&d1_pd>;
+ ucpd-supply = <&scmi_vdd33ucpd>;
+ vconn-cc1-gpios = <&gpiof 5 GPIO_ACTIVE_HIGH>;
+ vconn-cc2-gpios = <&gpioc 3 GPIO_ACTIVE_HIGH>;
+ vconn-supply = <&vconn>;
+ st,tcpp = <&tcpp03>;
+
+ connector {
+ compatible = "usb-c-connector";
+ label = "USB-C";
+ power-role = "dual";
+ try-power-role = "sink";
+ data-role = "dual";
+ typec-power-opmode = "default";
+ pd-disable;
+ port {
+ endpoint {
+ remote-endpoint = <&dwc3_ep>;
+ };
+ };
+ };
+ };
--
2.43.0
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 04/16] usb: typec: tcpm: Add STM32 UCPD driver
2026-08-21 16:23 [PATCH 00/16] Add support for USB Type-C on STM32MP25 Fabrice Gasnier
` (2 preceding siblings ...)
2026-08-21 16:23 ` [PATCH 03/16] dt-bindings: usb: st,stm32-ucpd: Document STM32 UCPD controller Fabrice Gasnier
@ 2026-08-21 16:23 ` Fabrice Gasnier
2026-08-24 14:38 ` Philipp Zabel
2026-08-21 16:23 ` [PATCH 05/16] dt-bindings: usb: add FUSB340 switch binding Fabrice Gasnier
` (11 subsequent siblings)
15 siblings, 1 reply; 24+ messages in thread
From: Fabrice Gasnier @ 2026-08-21 16:23 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Christian Bruel, Fabrice Gasnier, Heikki Krogerus,
Alexandre Torgue, Philipp Zabel, Liam Girdwood, Mark Brown,
Srinivas Kandagatla, Marek Vasut, Vinod Koul, Neil Armstrong,
Pankaj Dev, Marek Vasut
Cc: linux-usb, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel, linux-phy
From: Christian Bruel <christian.bruel@foss.st.com>
Add support for the STM32 UCPD controller providing USB Type‑C
Configuration Channel (CC) management and USB Power Delivery (PD)
protocol handling.
The driver integrates with the TCPM (Type-C Port Manager) framework.
On this platform, VBUS monitoring is handled by an external TCPP03
Note the driver doesn't allow PD, so the role can only be set at
plug time.
The UCPD can be a wakeup source, in such a case, keep the hardware
enabled. Else, keep track of the vbus state as provider and as
consumer, to be restored after low power.
Signed-off-by: Christian Bruel <christian.bruel@foss.st.com>
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
drivers/usb/typec/tcpm/Kconfig | 12 +
drivers/usb/typec/tcpm/Makefile | 1 +
drivers/usb/typec/tcpm/stm32_ucpd.c | 818 ++++++++++++++++++++++++++++++++++++
3 files changed, 831 insertions(+)
diff --git a/drivers/usb/typec/tcpm/Kconfig b/drivers/usb/typec/tcpm/Kconfig
index c24d98200a57..371381d24ee2 100644
--- a/drivers/usb/typec/tcpm/Kconfig
+++ b/drivers/usb/typec/tcpm/Kconfig
@@ -75,6 +75,18 @@ config TYPEC_ST_TCPP
If you choose to build this driver as a dynamically linked
module, the module will be called st_tcpp.ko.
+config TYPEC_UCPD_STM32
+ tristate "USB-C UCPD Interface for STM32"
+ select TYPEC_ST_TCPP
+ help
+ This driver provides both USB PD and Type-C functionalities.
+ Only supports Type-C functionality in Peripheral mode.
+ Say Y or M here if your system has Type-C UCPD controller on
+ STM32 MP23/MP25 SoCs.
+
+ If you choose to build this driver as a dynamically linked
+ module, the module will be called stm32_ucpd.ko.
+
config TYPEC_WCOVE
tristate "Intel WhiskeyCove PMIC USB Type-C PHY driver"
depends on ACPI
diff --git a/drivers/usb/typec/tcpm/Makefile b/drivers/usb/typec/tcpm/Makefile
index 0ee6ff598f75..b1a6681622b0 100644
--- a/drivers/usb/typec/tcpm/Makefile
+++ b/drivers/usb/typec/tcpm/Makefile
@@ -2,6 +2,7 @@
obj-$(CONFIG_TYPEC_TCPM) += tcpm.o
obj-$(CONFIG_TYPEC_FUSB302) += fusb302.o
obj-$(CONFIG_TYPEC_ST_TCPP) += st_tcpp.o
+obj-$(CONFIG_TYPEC_UCPD_STM32) += stm32_ucpd.o
obj-$(CONFIG_TYPEC_WCOVE) += typec_wcove.o
typec_wcove-y := wcove.o
obj-$(CONFIG_TYPEC_TCPCI) += tcpci.o
diff --git a/drivers/usb/typec/tcpm/stm32_ucpd.c b/drivers/usb/typec/tcpm/stm32_ucpd.c
new file mode 100644
index 000000000000..b5c9dc417814
--- /dev/null
+++ b/drivers/usb/typec/tcpm/stm32_ucpd.c
@@ -0,0 +1,818 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * STMicroelectronics USB-C PD driver
+ *
+ * Copyright (C) 2026 STMicroelectronics
+ */
+
+#include <linux/clk.h>
+#include <linux/devm-helpers.h>
+#include <linux/i2c.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/usb/tcpm.h>
+#include "st_tcpp.h"
+
+#define UCPD_CFGR1 0
+#define UCPD_EN BIT(31)
+#define UCPD_RXORDSETEN GENMASK(28, 20)
+#define UCPD_PSC_UCPDCLK GENMASK(19, 17)
+#define UCPD_TRANSWIN GENMASK(15, 11)
+#define UCPD_IFRGAP GENMASK(10, 6)
+#define UCPD_HBITCLKDIV GENMASK(5, 0)
+
+#define UCPD_CFGR2 0x4
+#define UCPD_WUPEN BIT(3)
+
+#define UCPD_CFGR3 0x8
+#define TRIM_CC1_RD GENMASK(3, 0)
+#define TRIM_CC1_RP GENMASK(12, 9)
+#define TRIM_CC2_RD GENMASK(19, 16)
+#define TRIM_CC2_RP GENMASK(28, 25)
+
+#define UCPD_CR 0xc
+#define UCPD_PHYRXEN BIT(5)
+#define UCPD_ANASUBMODE GENMASK(8, 7)
+#define UCPD_ANAMODE BIT(9)
+#define UCPD_CCENABLE GENMASK(11, 10)
+#define UCPD_RDCH BIT(18)
+#define UCPD_CC1TCDIS BIT(20)
+#define UCPD_CC2TCDIS BIT(21)
+
+#define UCPD_IMR 0x10
+#define UCPD_TXISIE BIT(0)
+#define TXMSGDISCIE BIT(1)
+#define TXMSGSENTIE BIT(2)
+#define TXMSGABTIE BIT(3)
+#define HRSTDISCIE BIT(4)
+#define HRSTSENTIE BIT(5)
+#define TXUNDIE BIT(6)
+#define RXNEIE BIT(8)
+#define RXORDDETIE BIT(9)
+#define RXHRSTDETIE BIT(10)
+#define RXOVRIE BIT(11)
+#define RXMSGENDIE BIT(12)
+#define TYPECEVT1IE BIT(14)
+#define TYPECEVT2IE BIT(15)
+
+#define UCPD_SR 0x14
+#define TYPECEVT1 BIT(14)
+#define TYPECEVT2 BIT(15)
+#define TYPEC_VSTATE_CC1 GENMASK(17, 16)
+#define TYPEC_VSTATE_CC2 GENMASK(19, 18)
+
+#define UCPD_ICR 0x18
+#define TYPECEVT1CF BIT(14)
+#define TYPECEVT2CF BIT(15)
+
+struct stm32_ucpd {
+ void __iomem *base;
+ struct device *dev;
+ struct device *tcpp_dev;
+ struct tcpm_port *tcpm_port;
+ struct tcpc_dev tcpc_dev;
+ struct reset_control *reset;
+ struct clk_bulk_data *clks;
+ int num_clks;
+ struct regulator *vdd;
+ struct regulator *vconn;
+ int ucpd_irq;
+ int cc1_status;
+ int cc2_status;
+ enum typec_cc_status cc;
+ enum typec_cc_polarity polarity;
+ bool vbus_on;
+ bool charge_on;
+ bool vconn_on;
+ bool vconn_restore;
+ struct gpio_desc *vconn_cc1_gpio;
+ struct gpio_desc *vconn_cc2_gpio;
+ struct workqueue_struct *wq;
+ struct delayed_work cc_work;
+ struct {
+ u8 cc1_rd;
+ u8 cc2_rd;
+ u8 cc1_3a;
+ u8 cc2_3a;
+ u8 cc1_1a5;
+ u8 cc2_1a5;
+ } trim;
+};
+
+/*
+ * +-----------+---------------------+----------+----------+----------+-----------+----------+
+ * | ANAMODE | ANASUBMODE[1:0] | Notes | CCx=00 | CCx=01 | CCx=10 | CCx=11 |
+ * +-----------+---------------------+----------+----------+----------+-----------+----------+
+ * | 0: Source | 00: Disabled | Disabled | Disabled | N/A | N/A | N/A |
+ * | | 01: Default USB Rp | - | vRa[Def] | vRd[Def] | vOPEN[Def]| N/A |
+ * | | 10: 1.5A Rp | - | vRa[1.5] | vRd[1.5] | vOPEN[1.5]| N/A |
+ * | | 11: 3.0A Rp | - | vRa[3.0] | vRd[3.0] | vOPEN[3.0]| N/A |
+ * | 1: Sink | xx | - | vRa | vRd-USB | vRd-1.5 | vRd-3.0 |
+ * +-----------+---------------------+----------+----------+----------+-----------+----------+
+ */
+static enum typec_cc_status ucpd_ccrd_to_tcpm(struct stm32_ucpd *ucpd, u32 cc)
+{
+ u32 cr = readl(ucpd->base + UCPD_CR);
+ bool is_src = !FIELD_GET(UCPD_ANAMODE, cr);
+
+ if (is_src) {
+ switch (cc) {
+ case 0:
+ return TYPEC_CC_RA;
+ case 1:
+ return TYPEC_CC_RD;
+ case 2:
+ return TYPEC_CC_OPEN;
+ default:
+ dev_err(ucpd->dev, "cc mode %d\n", cc);
+ return TYPEC_CC_OPEN;
+ }
+ }
+
+ switch (cc) {
+ case 0:
+ return TYPEC_CC_OPEN;
+ case 1:
+ return TYPEC_CC_RP_DEF;
+ case 2:
+ return TYPEC_CC_RP_1_5;
+ case 3:
+ return TYPEC_CC_RP_3_0;
+ default:
+ dev_err(ucpd->dev, "cc mode %d\n", cc);
+ return TYPEC_CC_OPEN;
+ }
+}
+
+static void ucpd_cc_work(struct work_struct *work)
+{
+ struct stm32_ucpd *ucpd = container_of(work, struct stm32_ucpd, cc_work.work);
+ u32 sr = readl(ucpd->base + UCPD_SR);
+ enum typec_cc_status cc1, cc2;
+
+ cc1 = ucpd_ccrd_to_tcpm(ucpd, FIELD_GET(TYPEC_VSTATE_CC1, sr));
+ cc2 = ucpd_ccrd_to_tcpm(ucpd, FIELD_GET(TYPEC_VSTATE_CC2, sr));
+
+ if (cc1 != ucpd->cc1_status || cc2 != ucpd->cc2_status) {
+ ucpd->cc1_status = cc1;
+ ucpd->cc2_status = cc2;
+ tcpm_cc_change(ucpd->tcpm_port);
+ }
+}
+
+static void ucpd_set_trim(struct stm32_ucpd *ucpd)
+{
+ u32 val = FIELD_PREP(TRIM_CC1_RD, ucpd->trim.cc1_rd) |
+ FIELD_PREP(TRIM_CC2_RD, ucpd->trim.cc2_rd) |
+ FIELD_PREP(TRIM_CC1_RP, ucpd->trim.cc1_3a) |
+ FIELD_PREP(TRIM_CC2_RP, ucpd->trim.cc2_3a);
+
+ writel(val, ucpd->base + UCPD_CFGR3);
+}
+
+static int stm32_ucpd_init(struct tcpc_dev *dev)
+{
+ struct stm32_ucpd *ucpd = container_of(dev, struct stm32_ucpd, tcpc_dev);
+ u32 val;
+
+ ucpd_set_trim(ucpd);
+
+ val = readl(ucpd->base + UCPD_CFGR1);
+ val &= ~UCPD_EN;
+ writel(val, ucpd->base + UCPD_CFGR1);
+
+ val = TYPECEVT1IE | TYPECEVT2IE;
+ writel(val, ucpd->base + UCPD_IMR);
+
+ /* Enable wakeup when UCPD_EN = 0. It will be disabled if not needed upon suspend */
+ val = readl(ucpd->base + UCPD_CFGR2);
+ writel(val | UCPD_WUPEN, ucpd->base + UCPD_CFGR2);
+ enable_irq_wake(ucpd->ucpd_irq);
+
+ val = readl(ucpd->base + UCPD_CFGR1);
+ val |= UCPD_EN;
+ writel(val, ucpd->base + UCPD_CFGR1);
+
+ return tcpp_init(ucpd->tcpp_dev);
+}
+
+/*
+ * stm32_ucpd_deinit() should be called with IRQ disabled, to avoid undesired IRQ when
+ * disconnecting TCPP protection
+ */
+static void stm32_ucpd_deinit(struct tcpc_dev *dev)
+{
+ struct stm32_ucpd *ucpd = container_of(dev, struct stm32_ucpd, tcpc_dev);
+
+ /*
+ * Place the UCPD lines into a safe state: switch OFF vbus gates and isolate CC lines.
+ * It avoids a device that may be plugged into the Type-C port to pull-up the CC lines
+ * at 5v and damage them (this must be avoided in case our vdd supply gets turned off
+ * upon reboot/reset).
+ */
+ tcpp_deinit(ucpd->tcpp_dev);
+
+ /* Can now disable UCPD (clear UCPD_EN), other register bits will be reset */
+ writel(0, ucpd->base + UCPD_CFGR1);
+ disable_irq_wake(ucpd->ucpd_irq);
+}
+
+static int stm32_ucpd_get_vbus(struct tcpc_dev *dev)
+{
+ struct stm32_ucpd *ucpd = container_of(dev, struct stm32_ucpd, tcpc_dev);
+
+ return tcpp_get_vbus(ucpd->tcpp_dev);
+}
+
+static int stm32_ucpd_set_vbus(struct tcpc_dev *dev, bool on, bool charge)
+{
+ struct stm32_ucpd *ucpd = container_of(dev, struct stm32_ucpd, tcpc_dev);
+ int ret;
+
+ dev_dbg(ucpd->dev, "%s: %s %s\n", __func__, str_on_off(on), str_on_off(charge));
+
+ ret = tcpp_set_vbus(ucpd->tcpp_dev, on, charge);
+ if (!ret) {
+ ucpd->vbus_on = on;
+ ucpd->charge_on = charge;
+ }
+
+ return ret;
+}
+
+static u32 stm32_ucpd_to_anasubmode(enum typec_cc_status cc)
+{
+ switch (cc) {
+ case TYPEC_CC_RP_DEF:
+ return FIELD_PREP(UCPD_ANASUBMODE, 1);
+ case TYPEC_CC_RP_1_5:
+ return FIELD_PREP(UCPD_ANASUBMODE, 2);
+ case TYPEC_CC_RP_3_0:
+ return FIELD_PREP(UCPD_ANASUBMODE, 3);
+ default:
+ return 0;
+ }
+}
+
+static int stm32_ucpd_set_cc(struct tcpc_dev *dev, enum typec_cc_status cc)
+{
+ struct stm32_ucpd *ucpd = container_of(dev, struct stm32_ucpd, tcpc_dev);
+ u32 val;
+
+ switch (cc) {
+ case TYPEC_CC_OPEN:
+ val = readl(ucpd->base + UCPD_CR);
+ val = (val & ~UCPD_CCENABLE) | UCPD_ANAMODE;
+ break;
+ case TYPEC_CC_RD:
+ val = readl(ucpd->base + UCPD_CR);
+ val |= (UCPD_ANAMODE | UCPD_CCENABLE);
+ break;
+ case TYPEC_CC_RP_DEF:
+ case TYPEC_CC_RP_1_5:
+ case TYPEC_CC_RP_3_0:
+ val = readl(ucpd->base + UCPD_CR);
+ val &= ~(UCPD_ANAMODE | UCPD_ANASUBMODE);
+ val |= stm32_ucpd_to_anasubmode(cc) | UCPD_CCENABLE;
+ break;
+ default:
+ dev_err(ucpd->dev, "%s: Unsupported cc status %d\n", __func__, cc);
+
+ return -EOPNOTSUPP;
+ }
+
+ writel(val, ucpd->base + UCPD_CR);
+ ucpd->cc = cc;
+
+ return 0;
+}
+
+static int stm32_ucpd_get_cc(struct tcpc_dev *dev, enum typec_cc_status *cc1,
+ enum typec_cc_status *cc2)
+{
+ struct stm32_ucpd *ucpd = container_of(dev, struct stm32_ucpd, tcpc_dev);
+ u32 sr = readl(ucpd->base + UCPD_SR);
+
+ *cc1 = ucpd_ccrd_to_tcpm(ucpd, FIELD_GET(TYPEC_VSTATE_CC1, sr));
+ *cc2 = ucpd_ccrd_to_tcpm(ucpd, FIELD_GET(TYPEC_VSTATE_CC2, sr));
+
+ dev_dbg(ucpd->dev, "%s: cc1=0x%x cc2=0x%x\n", __func__, *cc1, *cc2);
+
+ return 0;
+}
+
+static int stm32_ucpd_set_polarity(struct tcpc_dev *dev, enum typec_cc_polarity polarity)
+{
+ struct stm32_ucpd *ucpd = container_of(dev, struct stm32_ucpd, tcpc_dev);
+
+ ucpd->polarity = polarity;
+ dev_dbg(ucpd->dev, "%s: polarity %d\n", __func__, polarity);
+
+ return 0;
+}
+
+static int stm32_ucpd_set_vconn_gpio(struct stm32_ucpd *ucpd, bool on)
+{
+ bool cc1_on = on && ucpd->polarity == TYPEC_POLARITY_CC2;
+ bool cc2_on = on && ucpd->polarity == TYPEC_POLARITY_CC1;
+ int ret;
+
+ /*
+ * Enable regulator before turning cc1/cc2 gate on. Check vconn_on, to
+ * ensure regulator enable / disable balance.
+ */
+ if (on && !ucpd->vconn_on && ucpd->vconn) {
+ ret = regulator_enable(ucpd->vconn);
+ if (ret) {
+ dev_err(ucpd->dev, "vconn enable failed %d\n", ret);
+ return ret;
+ }
+ }
+
+ if (ucpd->vconn_cc1_gpio) {
+ ret = gpiod_set_value_cansleep(ucpd->vconn_cc1_gpio, cc1_on);
+ if (ret) {
+ dev_err(ucpd->dev, "vconn-cc1 %s failed: %d\n", str_enable_disable(cc1_on),
+ ret);
+ goto undo_vconn;
+ }
+ dev_dbg(ucpd->dev, "vconn-cc1 %s\n", str_enabled_disabled(cc1_on));
+ }
+
+ if (ucpd->vconn_cc2_gpio) {
+ ret = gpiod_set_value_cansleep(ucpd->vconn_cc2_gpio, cc2_on);
+ if (ret) {
+ dev_err(ucpd->dev, "vconn-cc2 %s failed: %d\n", str_enable_disable(cc2_on),
+ ret);
+ goto undo_vconn;
+ }
+ dev_dbg(ucpd->dev, "vconn-cc2 %s\n", str_enabled_disabled(cc2_on));
+ }
+
+ /* Disable in the reverse order */
+ if (!on && ucpd->vconn_on && ucpd->vconn) {
+ ret = regulator_disable(ucpd->vconn);
+ if (ret) {
+ dev_err(ucpd->dev, "vconn disable failed %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+
+undo_vconn:
+ if (on && !ucpd->vconn_on && ucpd->vconn)
+ regulator_disable(ucpd->vconn);
+
+ return ret;
+}
+
+static int stm32_ucpd_set_vconn(struct tcpc_dev *dev, bool on)
+{
+ struct stm32_ucpd *ucpd = container_of(dev, struct stm32_ucpd, tcpc_dev);
+ int ret;
+
+ dev_dbg(ucpd->dev, "%s: %s\n", __func__, str_on_off(on));
+
+ if (!on) {
+ /* Disable optional gate for CC1/CC2 Vconn before tcpp */
+ ret = stm32_ucpd_set_vconn_gpio(ucpd, on);
+ if (ret)
+ return ret;
+ }
+
+ ret = tcpp_set_vconn(ucpd->tcpp_dev, on, ucpd->polarity);
+ if (ret) {
+ dev_err(ucpd->dev, "tcpp_set_vconn failed: %d\n", ret);
+ return ret;
+ }
+
+ if (on) {
+ /* Enable optional gate for CC1/CC2 Vconn after tcpp */
+ ret = stm32_ucpd_set_vconn_gpio(ucpd, on);
+ if (ret)
+ return ret;
+ }
+
+ ucpd->vconn_on = on;
+
+ return 0;
+}
+
+static int stm32_ucpd_set_pd_rx(struct tcpc_dev *dev, bool on)
+{
+ struct stm32_ucpd *ucpd = container_of(dev, struct stm32_ucpd, tcpc_dev);
+
+ dev_dbg(ucpd->dev, "%s power delivery reception\n", str_enable_disable(on));
+
+ if (on)
+ return -EOPNOTSUPP;
+ else
+ return 0;
+}
+
+static int stm32_ucpd_set_roles(struct tcpc_dev *dev, bool attached,
+ enum typec_role pwr, enum typec_data_role data)
+{
+ struct stm32_ucpd *ucpd = container_of(dev, struct stm32_ucpd, tcpc_dev);
+ int ret;
+
+ dev_dbg(ucpd->dev, "%s: Set role pwr %s data %s\n", __func__,
+ pwr == TYPEC_SINK ? "sink" : "source",
+ data == TYPEC_DEVICE ? "device" : "host");
+
+ if (attached) {
+ dev_dbg(ucpd->dev, "attached\n");
+ ret = tcpp_attach(ucpd->tcpp_dev);
+ } else {
+ dev_dbg(ucpd->dev, "detached\n");
+ ret = tcpp_detach(ucpd->tcpp_dev);
+ }
+
+ return ret;
+}
+
+static int stm32_ucpd_pd_transmit(struct tcpc_dev *dev, enum tcpm_transmit_type type,
+ const struct pd_message *msg, unsigned int negotiated_rev)
+{
+ struct stm32_ucpd *ucpd = container_of(dev, struct stm32_ucpd, tcpc_dev);
+
+ dev_dbg(ucpd->dev, "%s regociated %d\n", __func__, negotiated_rev);
+
+ return -EOPNOTSUPP;
+}
+
+static void init_tcpc_dev(struct tcpc_dev *tcpc_dev)
+{
+ tcpc_dev->init = stm32_ucpd_init;
+ tcpc_dev->get_vbus = stm32_ucpd_get_vbus;
+ tcpc_dev->set_cc = stm32_ucpd_set_cc;
+ tcpc_dev->get_cc = stm32_ucpd_get_cc;
+ tcpc_dev->set_polarity = stm32_ucpd_set_polarity;
+ tcpc_dev->set_vconn = stm32_ucpd_set_vconn;
+ tcpc_dev->set_vbus = stm32_ucpd_set_vbus;
+ tcpc_dev->set_pd_rx = stm32_ucpd_set_pd_rx;
+ tcpc_dev->set_roles = stm32_ucpd_set_roles;
+ tcpc_dev->pd_transmit = stm32_ucpd_pd_transmit;
+}
+
+static int stm32_ucpd_read_trim(struct device *dev, const char *name, u8 *val)
+{
+ struct nvmem_cell *cell;
+ size_t len;
+ void *buf;
+
+ cell = devm_nvmem_cell_get(dev, name);
+ if (IS_ERR(cell)) {
+ dev_err(dev, "cannot get cell %s\n", name);
+ return PTR_ERR(cell);
+ }
+
+ buf = nvmem_cell_read(cell, &len);
+ if (IS_ERR(buf)) {
+ dev_err(dev, "cannot read %s\n", name);
+ return PTR_ERR(buf);
+ }
+
+ *val = *(u8 *)buf;
+ kfree(buf);
+
+ return 0;
+}
+
+struct trim_desc {
+ const char *name;
+ u8 *value;
+};
+
+static int stm32_ucpd_get_trim_values(struct stm32_ucpd *ucpd)
+{
+ struct trim_desc desc[] = {
+ { "trim_1a5_cc1", &ucpd->trim.cc1_1a5 },
+ { "trim_3a_cc1", &ucpd->trim.cc1_3a },
+ { "trim_3a_cc2", &ucpd->trim.cc2_3a },
+ { "trim_1a5_cc2", &ucpd->trim.cc2_1a5 },
+ { "trim_rd_cc1", &ucpd->trim.cc1_rd },
+ { "trim_rd_cc2", &ucpd->trim.cc2_rd },
+ };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(desc); i++) {
+ int ret = stm32_ucpd_read_trim(ucpd->dev, desc[i].name, desc[i].value);
+
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static irqreturn_t ucpd_irq_handler(int irq, void *data)
+{
+ struct stm32_ucpd *ucpd = data;
+ enum typec_cc_status cc1 = ucpd->cc1_status;
+ enum typec_cc_status cc2 = ucpd->cc2_status;
+ u32 sr, handled = 0;
+
+ sr = readl(ucpd->base + UCPD_SR);
+
+ if (sr & TYPECEVT1) {
+ cc1 = ucpd_ccrd_to_tcpm(ucpd, FIELD_GET(TYPEC_VSTATE_CC1, sr));
+ handled |= TYPECEVT1CF;
+ }
+
+ if (sr & TYPECEVT2) {
+ cc2 = ucpd_ccrd_to_tcpm(ucpd, FIELD_GET(TYPEC_VSTATE_CC2, sr));
+ handled |= TYPECEVT2CF;
+ }
+
+ if (!handled) {
+ dev_err(ucpd->dev, "unexpected IRQ, SR %#x\n", sr);
+
+ return IRQ_NONE;
+ }
+
+ if (cc1 == ucpd->cc1_status && cc2 == ucpd->cc2_status)
+ goto irq_handled;
+
+ /*
+ * For the first transition from unattached (cached CC_OPEN),
+ * notify the TCPM framework and rely on its own attach debounce.
+ * Debounce subsequent CC changes locally.
+ */
+ if (ucpd->cc1_status != TYPEC_CC_OPEN || ucpd->cc2_status != TYPEC_CC_OPEN) {
+ mod_delayed_work(ucpd->wq, &ucpd->cc_work, msecs_to_jiffies(PD_T_PD_DEBOUNCE));
+ } else {
+ if (cc1 != TYPEC_CC_OPEN)
+ ucpd->cc1_status = cc1;
+ if (cc2 != TYPEC_CC_OPEN)
+ ucpd->cc2_status = cc2;
+ tcpm_cc_change(ucpd->tcpm_port);
+ }
+
+irq_handled:
+ writel(handled, ucpd->base + UCPD_ICR);
+
+ return IRQ_HANDLED;
+}
+
+static void ucpd_vbus_changed(void *data, bool vbus_present)
+{
+ struct stm32_ucpd *ucpd = data;
+
+ dev_dbg(ucpd->dev, "VBUS change: %d\n", vbus_present);
+
+ tcpm_vbus_change(ucpd->tcpm_port);
+}
+
+static int stm32_ucpd_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct i2c_client *tcpp_client;
+ struct device_node *tcpp_np;
+ struct stm32_ucpd *ucpd;
+ int ret;
+
+ ucpd = devm_kzalloc(dev, sizeof(*ucpd), GFP_KERNEL);
+ if (!ucpd)
+ return -ENOMEM;
+
+ ucpd->dev = dev;
+ platform_set_drvdata(pdev, ucpd);
+
+ ucpd->vdd = devm_regulator_get(&pdev->dev, "ucpd");
+ if (IS_ERR(ucpd->vdd))
+ return dev_err_probe(&pdev->dev, PTR_ERR(ucpd->vdd), "vdd get failed\n");
+
+ ucpd->vconn = devm_regulator_get_optional(&pdev->dev, "vconn");
+ if (IS_ERR(ucpd->vconn)) {
+ if (PTR_ERR(ucpd->vconn) != -ENODEV)
+ return dev_err_probe(&pdev->dev, PTR_ERR(ucpd->vconn),
+ "vconn get failed\n");
+ ucpd->vconn = NULL;
+ }
+
+ ucpd->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(ucpd->base))
+ return PTR_ERR(ucpd->base);
+
+ ucpd->num_clks = devm_clk_bulk_get_all(dev, &ucpd->clks);
+ if (ucpd->num_clks <= 0)
+ return ucpd->num_clks ? : -ENOENT;
+
+ ucpd->reset = devm_reset_control_get_exclusive(dev, "ucpd");
+ if (IS_ERR(ucpd->reset))
+ return dev_err_probe(dev, PTR_ERR(ucpd->reset), "Failed to get UCPD reset\n");
+
+ ret = stm32_ucpd_get_trim_values(ucpd);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get trim values\n");
+
+ ucpd->vconn_cc1_gpio = devm_gpiod_get_optional(dev, "vconn-cc1", GPIOD_OUT_LOW);
+ if (IS_ERR(ucpd->vconn_cc1_gpio))
+ return dev_err_probe(dev, PTR_ERR(ucpd->vconn_cc1_gpio), "vconn-cc1 get failed\n");
+
+ ucpd->vconn_cc2_gpio = devm_gpiod_get_optional(dev, "vconn-cc2", GPIOD_OUT_LOW);
+ if (IS_ERR(ucpd->vconn_cc2_gpio))
+ return dev_err_probe(dev, PTR_ERR(ucpd->vconn_cc2_gpio), "vconn-cc2 get failed\n");
+
+ ucpd->ucpd_irq = platform_get_irq_byname(pdev, "ucpd");
+ if (ucpd->ucpd_irq < 0)
+ return ucpd->ucpd_irq;
+
+ ucpd->tcpc_dev.fwnode = device_get_named_child_node(dev, "connector");
+ if (IS_ERR(ucpd->tcpc_dev.fwnode))
+ return dev_err_probe(dev, PTR_ERR(ucpd->tcpc_dev.fwnode), "connector not found");
+
+ tcpp_np = of_parse_phandle(dev->of_node, "st,tcpp", 0);
+ if (!tcpp_np)
+ return -EINVAL;
+
+ tcpp_client = of_find_i2c_device_by_node(tcpp_np);
+ of_node_put(tcpp_np);
+
+ /* tcpp driver must be probed so tcpp_init() can be called from tcpm_register_port() */
+ if (!tcpp_client || !tcpp_client->dev.driver)
+ return -EPROBE_DEFER;
+
+ ucpd->tcpp_dev = &tcpp_client->dev;
+
+ /* No irq until tcpm_port is ready */
+ irq_set_status_flags(ucpd->ucpd_irq, IRQ_NOAUTOEN);
+ ret = devm_request_threaded_irq(dev, ucpd->ucpd_irq, NULL, ucpd_irq_handler, IRQF_ONESHOT,
+ dev_name(dev), ucpd);
+ if (ret) {
+ dev_err_probe(dev, ret, "failed to get irq\n");
+ goto put_tcpp;
+ }
+
+ init_tcpc_dev(&ucpd->tcpc_dev);
+
+ ret = regulator_enable(ucpd->vdd);
+ if (ret) {
+ dev_err_probe(dev, ret, "failed to enable regulator\n");
+ goto put_tcpp;
+ }
+
+ ret = clk_bulk_prepare_enable(ucpd->num_clks, ucpd->clks);
+ if (ret) {
+ dev_err_probe(dev, ret, "failed to enable clocks\n");
+ goto disable_regulator;
+ }
+
+ ret = reset_control_deassert(ucpd->reset);
+ if (ret) {
+ dev_err_probe(dev, ret, "failed to deassert reset\n");
+ goto disable_clks;
+ }
+
+ ret = devm_pm_runtime_get_noresume(dev);
+ if (ret) {
+ dev_err_probe(dev, ret, "Failed to get runtime PM noresume\n");
+ goto disable_clks;
+ }
+
+ ret = devm_pm_runtime_set_active_enabled(dev);
+ if (ret < 0) {
+ dev_err_probe(dev, ret, "Failed to activate and enable runtime PM\n");
+ goto disable_clks;
+ }
+
+ ucpd->wq = create_singlethread_workqueue(dev_name(ucpd->dev));
+ if (!ucpd->wq) {
+ ret = -ENOMEM;
+ goto disable_clks;
+ }
+
+ INIT_DELAYED_WORK(&ucpd->cc_work, ucpd_cc_work);
+
+ ucpd->tcpm_port = tcpm_register_port(dev, &ucpd->tcpc_dev);
+ if (IS_ERR(ucpd->tcpm_port)) {
+ ret = dev_err_probe(dev, PTR_ERR(ucpd->tcpm_port), "failed to register tcpm\n");
+ goto destroy_wq;
+ }
+
+ tcpp_register_vbus_notifier(ucpd->tcpp_dev, ucpd_vbus_changed, ucpd);
+
+ device_set_wakeup_capable(dev, true);
+
+ enable_irq(ucpd->ucpd_irq);
+
+ return 0;
+
+destroy_wq:
+ destroy_workqueue(ucpd->wq);
+
+disable_clks:
+ clk_bulk_disable_unprepare(ucpd->num_clks, ucpd->clks);
+
+disable_regulator:
+ regulator_disable(ucpd->vdd);
+
+put_tcpp:
+ put_device(ucpd->tcpp_dev);
+
+ return ret;
+};
+
+static void stm32_ucpd_remove(struct platform_device *pdev)
+{
+ struct stm32_ucpd *ucpd = platform_get_drvdata(pdev);
+
+ disable_irq(ucpd->ucpd_irq);
+ cancel_delayed_work_sync(&ucpd->cc_work);
+ tcpp_unregister_vbus_notifier(ucpd->tcpp_dev);
+ tcpm_unregister_port(ucpd->tcpm_port);
+ stm32_ucpd_deinit(&ucpd->tcpc_dev);
+ destroy_workqueue(ucpd->wq);
+ clk_bulk_disable_unprepare(ucpd->num_clks, ucpd->clks);
+ regulator_disable(ucpd->vdd);
+ put_device(ucpd->tcpp_dev);
+};
+
+static void stm32_ucpd_shutdown(struct platform_device *pdev)
+{
+ struct stm32_ucpd *ucpd = platform_get_drvdata(pdev);
+
+ disable_irq(ucpd->ucpd_irq);
+ stm32_ucpd_set_vconn(&ucpd->tcpc_dev, false);
+ stm32_ucpd_deinit(&ucpd->tcpc_dev);
+}
+
+static int stm32_ucpd_suspend(struct device *dev)
+{
+ struct stm32_ucpd *ucpd = dev_get_drvdata(dev);
+
+ /* Already enabled for wakeup: just return */
+ if (device_may_wakeup(dev))
+ return 0;
+
+ disable_irq(ucpd->ucpd_irq);
+ cancel_delayed_work_sync(&ucpd->cc_work);
+ /* backup vconn_on flag */
+ ucpd->vconn_restore = ucpd->vconn_on;
+ stm32_ucpd_set_vconn(&ucpd->tcpc_dev, false);
+ stm32_ucpd_deinit(&ucpd->tcpc_dev);
+ clk_bulk_disable_unprepare(ucpd->num_clks, ucpd->clks);
+ regulator_disable(ucpd->vdd);
+
+ return 0;
+}
+
+static int stm32_ucpd_resume(struct device *dev)
+{
+ struct stm32_ucpd *ucpd = dev_get_drvdata(dev);
+ int ret;
+
+ /* Kept active: just return */
+ if (device_may_wakeup(dev))
+ return 0;
+
+ ret = regulator_enable(ucpd->vdd);
+ if (ret)
+ return ret;
+
+ ret = clk_bulk_prepare_enable(ucpd->num_clks, ucpd->clks);
+ if (ret) {
+ regulator_disable(ucpd->vdd);
+ return ret;
+ }
+
+ stm32_ucpd_init(&ucpd->tcpc_dev);
+ stm32_ucpd_set_cc(&ucpd->tcpc_dev, ucpd->cc);
+ stm32_ucpd_set_vconn(&ucpd->tcpc_dev, ucpd->vconn_restore);
+ tcpp_set_vbus(ucpd->tcpp_dev, ucpd->vbus_on, ucpd->charge_on);
+ enable_irq(ucpd->ucpd_irq);
+
+ return 0;
+}
+
+static const struct dev_pm_ops stm32_ucpd_pm_ops = {
+ SYSTEM_SLEEP_PM_OPS(stm32_ucpd_suspend, stm32_ucpd_resume)
+};
+
+static const struct of_device_id stm32_ucpd_of_match[] = {
+ { .compatible = "st,stm32mp25-ucpd" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, stm32_ucpd_of_match);
+
+static struct platform_driver stm32_ucpd_driver = {
+ .probe = stm32_ucpd_probe,
+ .remove = stm32_ucpd_remove,
+ .shutdown = stm32_ucpd_shutdown,
+ .driver = {
+ .name = "stm32-ucpd",
+ .pm = &stm32_ucpd_pm_ops,
+ .of_match_table = stm32_ucpd_of_match,
+ },
+};
+module_platform_driver(stm32_ucpd_driver);
+
+MODULE_DESCRIPTION("USB Type-C Power Delivery");
+MODULE_AUTHOR("Christian Bruel <christian.bruel@foss.st.com>");
+MODULE_LICENSE("GPL");
--
2.43.0
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 05/16] dt-bindings: usb: add FUSB340 switch binding
2026-08-21 16:23 [PATCH 00/16] Add support for USB Type-C on STM32MP25 Fabrice Gasnier
` (3 preceding siblings ...)
2026-08-21 16:23 ` [PATCH 04/16] usb: typec: tcpm: Add STM32 UCPD driver Fabrice Gasnier
@ 2026-08-21 16:23 ` Fabrice Gasnier
2026-08-22 4:49 ` Marek Vasut
2026-08-21 16:23 ` [PATCH 06/16] usb: typec: add FUSB340 SuperSpeed switch driver Fabrice Gasnier
` (10 subsequent siblings)
15 siblings, 1 reply; 24+ messages in thread
From: Fabrice Gasnier @ 2026-08-21 16:23 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Christian Bruel, Fabrice Gasnier, Heikki Krogerus,
Alexandre Torgue, Philipp Zabel, Liam Girdwood, Mark Brown,
Srinivas Kandagatla, Marek Vasut, Vinod Koul, Neil Armstrong,
Pankaj Dev, Marek Vasut
Cc: linux-usb, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel, linux-phy
Document the ON Semiconductor FUSB340 SuperSpeed switch as a USB switch
binding with enable-gpios and select-gpios controls. The switch can be used
in 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@foss.st.com>
---
.../devicetree/bindings/usb/onnn,fusb340.yaml | 73 ++++++++++++++++++++++
1 file changed, 73 insertions(+)
diff --git a/Documentation/devicetree/bindings/usb/onnn,fusb340.yaml b/Documentation/devicetree/bindings/usb/onnn,fusb340.yaml
new file mode 100644
index 000000000000..b1991bd465ad
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/onnn,fusb340.yaml
@@ -0,0 +1,73 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/onnn,fusb340.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ON Semiconductor FUSB340 SuperSpeed switch
+
+maintainers:
+ - Fabrice Gasnier <fabrice.gasnier@foss.st.com>
+
+description:
+ The FUSB340 is a 2:1 USB 3.1 SuperSpeed data switch with enable and select
+ GPIO control signals. The switch can be used in Type-C applications where a
+ reversible cable requires a switch.
+
+properties:
+ compatible:
+ const: onnn,fusb340
+
+ enable-gpios:
+ description: Switch enable GPIO
+
+ select-gpios:
+ description: Switch path select GPIO
+
+ mode-switch: true
+ orientation-switch: true
+
+required:
+ - compatible
+ - enable-gpios
+ - select-gpios
+ - mode-switch
+ - orientation-switch
+
+allOf:
+ - $ref: usb-switch.yaml#
+ - $ref: usb-switch-ports.yaml#
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ usb-switch {
+ compatible = "onnn,fusb340";
+ enable-gpios = <&gpioh 2 GPIO_ACTIVE_LOW>;
+ select-gpios = <&gpioh 3 GPIO_ACTIVE_HIGH>;
+ mode-switch;
+ orientation-switch;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ usb_con_ss: endpoint {
+ remote-endpoint = <&typec_con_ss>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ usb_phy_ss: endpoint {
+ remote-endpoint = <&usb_phy_ss>;
+ };
+ };
+ };
+ };
+...
--
2.43.0
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 06/16] usb: typec: add FUSB340 SuperSpeed switch driver
2026-08-21 16:23 [PATCH 00/16] Add support for USB Type-C on STM32MP25 Fabrice Gasnier
` (4 preceding siblings ...)
2026-08-21 16:23 ` [PATCH 05/16] dt-bindings: usb: add FUSB340 switch binding Fabrice Gasnier
@ 2026-08-21 16:23 ` Fabrice Gasnier
2026-08-21 16:23 ` [PATCH 07/16] dt-bindings: nvmem: st,stm32-romem: align patternProperties regex on nvmem-deprecated-cells.yaml Fabrice Gasnier
` (9 subsequent siblings)
15 siblings, 0 replies; 24+ messages in thread
From: Fabrice Gasnier @ 2026-08-21 16:23 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Christian Bruel, Fabrice Gasnier, Heikki Krogerus,
Alexandre Torgue, Philipp Zabel, Liam Girdwood, Mark Brown,
Srinivas Kandagatla, Marek Vasut, Vinod Koul, Neil Armstrong,
Pankaj Dev, Marek Vasut
Cc: linux-usb, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel, linux-phy
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@foss.st.com>
---
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@foss.st.com>");
+MODULE_LICENSE("GPL");
--
2.43.0
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 07/16] dt-bindings: nvmem: st,stm32-romem: align patternProperties regex on nvmem-deprecated-cells.yaml
2026-08-21 16:23 [PATCH 00/16] Add support for USB Type-C on STM32MP25 Fabrice Gasnier
` (5 preceding siblings ...)
2026-08-21 16:23 ` [PATCH 06/16] usb: typec: add FUSB340 SuperSpeed switch driver Fabrice Gasnier
@ 2026-08-21 16:23 ` Fabrice Gasnier
2026-08-21 16:23 ` [PATCH 08/16] arm64: dts: st: Add ucpd node on stm32mp251 Fabrice Gasnier
` (8 subsequent siblings)
15 siblings, 0 replies; 24+ messages in thread
From: Fabrice Gasnier @ 2026-08-21 16:23 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Christian Bruel, Fabrice Gasnier, Heikki Krogerus,
Alexandre Torgue, Philipp Zabel, Liam Girdwood, Mark Brown,
Srinivas Kandagatla, Marek Vasut, Vinod Koul, Neil Armstrong,
Pankaj Dev, Marek Vasut
Cc: linux-usb, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel, linux-phy, Thomas Bourgoin
Align the regex with the one used in nvmem-deprecated-cells.yaml
("@[0-9a-f]+(,[0-7])?$") so both patternProperties definitions apply
to the same set of node names.
The patternProperties key only matched node names of the form
"name@address" ("^.*@[0-9a-f]+$"). It did not match nodes using the
extra unit-address index used to disambiguate cells sharing the same
reg, e.g. "trim_rd_cc1@1e8,4", causing dtbs_check failures such as:
efuse@44000000 (st,stm32mp25-bsec): Unevaluated properties are not
allowed ('trim_rd_cc1@1e8,4', ...)
Signed-off-by: Thomas Bourgoin <thomas.bourgoin@foss.st.com>
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
Documentation/devicetree/bindings/nvmem/st,stm32-romem.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/nvmem/st,stm32-romem.yaml b/Documentation/devicetree/bindings/nvmem/st,stm32-romem.yaml
index ab4cdc4e3614..a9988b1d63f5 100644
--- a/Documentation/devicetree/bindings/nvmem/st,stm32-romem.yaml
+++ b/Documentation/devicetree/bindings/nvmem/st,stm32-romem.yaml
@@ -31,7 +31,7 @@ properties:
maxItems: 1
patternProperties:
- "@[0-9a-f]+$":
+ "@[0-9a-f]+(,[0-7])?$":
type: object
$ref: layouts/fixed-cell.yaml
unevaluatedProperties: false
--
2.43.0
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 08/16] arm64: dts: st: Add ucpd node on stm32mp251
2026-08-21 16:23 [PATCH 00/16] Add support for USB Type-C on STM32MP25 Fabrice Gasnier
` (6 preceding siblings ...)
2026-08-21 16:23 ` [PATCH 07/16] dt-bindings: nvmem: st,stm32-romem: align patternProperties regex on nvmem-deprecated-cells.yaml Fabrice Gasnier
@ 2026-08-21 16:23 ` Fabrice Gasnier
2026-08-22 5:00 ` Marek Vasut
2026-08-21 16:23 ` [PATCH 09/16] arm64: dts: st: add i2c1 pinctrl entries for stm32mp25 Fabrice Gasnier
` (7 subsequent siblings)
15 siblings, 1 reply; 24+ messages in thread
From: Fabrice Gasnier @ 2026-08-21 16:23 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Christian Bruel, Fabrice Gasnier, Heikki Krogerus,
Alexandre Torgue, Philipp Zabel, Liam Girdwood, Mark Brown,
Srinivas Kandagatla, Marek Vasut, Vinod Koul, Neil Armstrong,
Pankaj Dev, Marek Vasut
Cc: linux-usb, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel, linux-phy, Thomas Bourgoin
Describe UCPD bindings and nvmem cells to access trim values.
This provides the PD and CC USB-C cable signaling functions.
Co-developed-by: Christian Bruel <christian.bruel@foss.st.com>
Signed-off-by: Christian Bruel <christian.bruel@foss.st.com>
Co-developed-by: Thomas Bourgoin <thomas.bourgoin@foss.st.com>
Signed-off-by: Thomas Bourgoin <thomas.bourgoin@foss.st.com>
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
arch/arm64/boot/dts/st/stm32mp251.dtsi | 51 ++++++++++++++++++++++++++++++++++
1 file changed, 51 insertions(+)
diff --git a/arch/arm64/boot/dts/st/stm32mp251.dtsi b/arch/arm64/boot/dts/st/stm32mp251.dtsi
index 9dc7a05fce99..be54dd56713b 100644
--- a/arch/arm64/boot/dts/st/stm32mp251.dtsi
+++ b/arch/arm64/boot/dts/st/stm32mp251.dtsi
@@ -1637,6 +1637,27 @@ dcmipp: dcmipp@48030000 {
status = "disabled";
};
+ ucpd: typec@480a0000 {
+ compatible = "st,stm32mp25-ucpd";
+ reg = <0x480a0000 0x400>;
+ interrupts-extended = <&exti1 46 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "ucpd";
+ clocks = <&rcc CK_BUS_USBTC>, <&rcc CK_KER_USBTC>;
+ clock-names = "apb", "ker";
+ resets = <&rcc USBTC_R>;
+ reset-names = "ucpd";
+ nvmem-cells = <&ucpd_trim_rd_cc1 &ucpd_trim_rd_cc2
+ &ucpd_trim_3a_cc1 &ucpd_trim_3a_cc2
+ &ucpd_trim_1a5_cc1 &ucpd_trim_1a5_cc2>;
+ nvmem-cell-names = "trim_rd_cc1", "trim_rd_cc2",
+ "trim_3a_cc1", "trim_3a_cc2",
+ "trim_1a5_cc1", "trim_1a5_cc2";
+ ucpd-supply = <&scmi_vdd33ucpd>;
+ access-controllers = <&rifsc 69>;
+ power-domains = <&CLUSTER_PD>;
+ status = "disabled";
+ };
+
combophy: phy@480c0000 {
compatible = "st,stm32mp25-combophy";
reg = <0x480c0000 0x1000>;
@@ -1818,10 +1839,40 @@ part-number-otp@24 {
reg = <0x24 0x4>;
};
+ ucpd_trim_3a_cc1: trim_3a_cc1@1bd,1 {
+ reg = <0x1bd 0x1>;
+ bits = <1 4>;
+ };
+
+ ucpd_trim_3a_cc2: trim_3a_cc2@1bf,1 {
+ reg = <0x1bf 0x1>;
+ bits = <1 4>;
+ };
+
package-otp@1e8 {
reg = <0x1e8 0x1>;
bits = <0 3>;
};
+
+ ucpd_trim_rd_cc1: trim_rd_cc1@1e8,4 {
+ reg = <0x1e8 0x1>;
+ bits = <4 4>;
+ };
+
+ ucpd_trim_1a5_cc1: trim_1a5_cc1@1e9,0 {
+ reg = <0x1e9 0x1>;
+ bits = <0 4>;
+ };
+
+ ucpd_trim_rd_cc2: trim_rd_cc2@1e9,4 {
+ reg = <0x1e9 0x1>;
+ bits = <4 4>;
+ };
+
+ ucpd_trim_1a5_cc2: trim_1a5_cc2@1ea,0 {
+ reg = <0x1ea 0x1>;
+ bits = <0 4>;
+ };
};
hdp: pinctrl@44090000 {
--
2.43.0
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 09/16] arm64: dts: st: add i2c1 pinctrl entries for stm32mp25
2026-08-21 16:23 [PATCH 00/16] Add support for USB Type-C on STM32MP25 Fabrice Gasnier
` (7 preceding siblings ...)
2026-08-21 16:23 ` [PATCH 08/16] arm64: dts: st: Add ucpd node on stm32mp251 Fabrice Gasnier
@ 2026-08-21 16:23 ` Fabrice Gasnier
2026-08-21 16:23 ` [PATCH 10/16] arm64: dts: st: add tcpp " Fabrice Gasnier
` (6 subsequent siblings)
15 siblings, 0 replies; 24+ messages in thread
From: Fabrice Gasnier @ 2026-08-21 16:23 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Christian Bruel, Fabrice Gasnier, Heikki Krogerus,
Alexandre Torgue, Philipp Zabel, Liam Girdwood, Mark Brown,
Srinivas Kandagatla, Marek Vasut, Vinod Koul, Neil Armstrong,
Pankaj Dev, Marek Vasut
Cc: linux-usb, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel, linux-phy
From: Christian Bruel <christian.bruel@foss.st.com>
Add pinctrl entries related to TCPP03 I2C in stm32mp25-pinctrl.dtsi
Signed-off-by: Christian Bruel <christian.bruel@foss.st.com>
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
arch/arm64/boot/dts/st/stm32mp25-pinctrl.dtsi | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/arch/arm64/boot/dts/st/stm32mp25-pinctrl.dtsi b/arch/arm64/boot/dts/st/stm32mp25-pinctrl.dtsi
index 456ece7f8ebc..f97ce299d6aa 100644
--- a/arch/arm64/boot/dts/st/stm32mp25-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/st/stm32mp25-pinctrl.dtsi
@@ -203,6 +203,25 @@ pins {
};
};
+ /omit-if-no-ref/
+ i2c1_pins_a: i2c1-0 {
+ pins {
+ pinmux = <STM32_PINMUX('G', 13, AF9)>, /* I2C1_SCL */
+ <STM32_PINMUX('I', 1, AF9)>; /* I2C1_SDA */
+ bias-disable;
+ drive-open-drain;
+ slew-rate = <0>;
+ };
+ };
+
+ /omit-if-no-ref/
+ i2c1_sleep_pins_a: i2c1-sleep-0 {
+ pins {
+ pinmux = <STM32_PINMUX('G', 13, ANALOG)>, /* I2C1_SCL */
+ <STM32_PINMUX('I', 1, ANALOG)>; /* I2C1_SDA */
+ };
+ };
+
/omit-if-no-ref/
i2c2_pins_a: i2c2-0 {
pins {
--
2.43.0
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 10/16] arm64: dts: st: add tcpp pinctrl entries for stm32mp25
2026-08-21 16:23 [PATCH 00/16] Add support for USB Type-C on STM32MP25 Fabrice Gasnier
` (8 preceding siblings ...)
2026-08-21 16:23 ` [PATCH 09/16] arm64: dts: st: add i2c1 pinctrl entries for stm32mp25 Fabrice Gasnier
@ 2026-08-21 16:23 ` Fabrice Gasnier
2026-08-21 16:23 ` [PATCH 11/16] dt-bindings: usb: dwc3: stm32: refer to dwc3-common Fabrice Gasnier
` (5 subsequent siblings)
15 siblings, 0 replies; 24+ messages in thread
From: Fabrice Gasnier @ 2026-08-21 16:23 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Christian Bruel, Fabrice Gasnier, Heikki Krogerus,
Alexandre Torgue, Philipp Zabel, Liam Girdwood, Mark Brown,
Srinivas Kandagatla, Marek Vasut, Vinod Koul, Neil Armstrong,
Pankaj Dev, Marek Vasut
Cc: linux-usb, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel, linux-phy
From: Christian Bruel <christian.bruel@foss.st.com>
Add pinctrl entries related to TCPP03 GPIO in stm32mp25-pinctrl.dtsi
Signed-off-by: Christian Bruel <christian.bruel@foss.st.com>
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
arch/arm64/boot/dts/st/stm32mp25-pinctrl.dtsi | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/arm64/boot/dts/st/stm32mp25-pinctrl.dtsi b/arch/arm64/boot/dts/st/stm32mp25-pinctrl.dtsi
index f97ce299d6aa..85d94973bc4a 100644
--- a/arch/arm64/boot/dts/st/stm32mp25-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/st/stm32mp25-pinctrl.dtsi
@@ -474,6 +474,14 @@ pins1 {
};
};
+ /omit-if-no-ref/
+ tcpp_flgn_pins_a: tcpp-flgn-0 {
+ pins {
+ pinmux = <STM32_PINMUX('G', 1, GPIO)>;
+ bias-pull-up;
+ };
+ };
+
/omit-if-no-ref/
tim10_counter_pins_a: tim10-counter-0 {
pins {
--
2.43.0
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 11/16] dt-bindings: usb: dwc3: stm32: refer to dwc3-common
2026-08-21 16:23 [PATCH 00/16] Add support for USB Type-C on STM32MP25 Fabrice Gasnier
` (9 preceding siblings ...)
2026-08-21 16:23 ` [PATCH 10/16] arm64: dts: st: add tcpp " Fabrice Gasnier
@ 2026-08-21 16:23 ` Fabrice Gasnier
2026-08-21 16:23 ` [PATCH 12/16] dt-bindings: phy: stm32: adapt usb2phy as syscon child on stm32mp25 Fabrice Gasnier
` (4 subsequent siblings)
15 siblings, 0 replies; 24+ messages in thread
From: Fabrice Gasnier @ 2026-08-21 16:23 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Christian Bruel, Fabrice Gasnier, Heikki Krogerus,
Alexandre Torgue, Philipp Zabel, Liam Girdwood, Mark Brown,
Srinivas Kandagatla, Marek Vasut, Vinod Koul, Neil Armstrong,
Pankaj Dev, Marek Vasut
Cc: linux-usb, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel, linux-phy
Add reference to the dwc3-common bindings, used on stm32mp25.
This is a temporary update, as it depends on Marek's series [1]. This
should be dropped in later series revision.
It's a precursor to validate further DT addition on USB and Type-C, with
usb-role-switch properties.
[1] https://lore.kernel.org/linux-phy/20260816213849.1044073-6-marex@nabladev.com/
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
Documentation/devicetree/bindings/usb/st,stm32mp25-dwc3.yaml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/Documentation/devicetree/bindings/usb/st,stm32mp25-dwc3.yaml b/Documentation/devicetree/bindings/usb/st,stm32mp25-dwc3.yaml
index e377efef4350..161c5c287925 100644
--- a/Documentation/devicetree/bindings/usb/st,stm32mp25-dwc3.yaml
+++ b/Documentation/devicetree/bindings/usb/st,stm32mp25-dwc3.yaml
@@ -14,6 +14,9 @@ maintainers:
- Fabrice Gasnier <fabrice.gasnier@foss.st.com>
- Marek Vasut <marex@nabladev.com>
+allOf:
+ - $ref: snps,dwc3-common.yaml#
+
properties:
compatible:
const: st,stm32mp25-dwc3
--
2.43.0
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 12/16] dt-bindings: phy: stm32: adapt usb2phy as syscon child on stm32mp25
2026-08-21 16:23 [PATCH 00/16] Add support for USB Type-C on STM32MP25 Fabrice Gasnier
` (10 preceding siblings ...)
2026-08-21 16:23 ` [PATCH 11/16] dt-bindings: usb: dwc3: stm32: refer to dwc3-common Fabrice Gasnier
@ 2026-08-21 16:23 ` Fabrice Gasnier
2026-08-21 16:23 ` [PATCH 13/16] dt-bindings: arm: stm32mp2: allow child nodes since simple-mfd transition Fabrice Gasnier
` (3 subsequent siblings)
15 siblings, 0 replies; 24+ messages in thread
From: Fabrice Gasnier @ 2026-08-21 16:23 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Christian Bruel, Fabrice Gasnier, Heikki Krogerus,
Alexandre Torgue, Philipp Zabel, Liam Girdwood, Mark Brown,
Srinivas Kandagatla, Marek Vasut, Vinod Koul, Neil Armstrong,
Pankaj Dev, Marek Vasut
Cc: linux-usb, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel, linux-phy
Adapt stm32-usb2phy since transition to syscon child node on stm32mp25.
This is a temporary update, as it depends on Marek's series [1]. This
should be dropped in later series revision.
It's a precursor to validate further DT addition on USB and Type-C.
Allow usb2phy to be a child node with reg and unit address.
It replaces the st,syscfg phandle.
Also adapt the example, e.g. stm32mp25-usb2phy1 address, clock and reset.
[1] https://lore.kernel.org/linux-phy/20260816213849.1044073-2-marex@nabladev.com/
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
.../devicetree/bindings/phy/st,stm32-usb2phy.yaml | 20 +++++++-------------
1 file changed, 7 insertions(+), 13 deletions(-)
diff --git a/Documentation/devicetree/bindings/phy/st,stm32-usb2phy.yaml b/Documentation/devicetree/bindings/phy/st,stm32-usb2phy.yaml
index ab6c943af9a2..3e8f57a46db3 100644
--- a/Documentation/devicetree/bindings/phy/st,stm32-usb2phy.yaml
+++ b/Documentation/devicetree/bindings/phy/st,stm32-usb2phy.yaml
@@ -23,6 +23,8 @@ properties:
- st,stm32mp25-usb2phy1
- st,stm32mp25-usb2phy2
+ reg: true
+
"#phy-cells":
const: 0
@@ -35,24 +37,16 @@ properties:
vdd33-supply:
description: Phandle to regulator providing 3V3 power supply to the USB2 HS PHY
- st,syscfg:
- $ref: /schemas/types.yaml#/definitions/phandle-array
- description: Phandle to system configuration controller.
- items:
- - items:
- - description: phandle to syscfg
- - description: USB2PHY control offset within syscfg
-
"#clock-cells":
const: 1
required:
- compatible
+ - reg
- "#clock-cells"
- "#phy-cells"
- clocks
- resets
- - st,syscfg
- vdd33-supply
additionalProperties: false
@@ -62,12 +56,12 @@ examples:
#include <dt-bindings/clock/st,stm32mp25-rcc.h>
#include <dt-bindings/reset/st,stm32mp25-rcc.h>
- usb2_phy2: usb-phy {
+ usb2_phy2: phy@2400 {
compatible = "st,stm32mp25-usb2phy1";
+ reg = <0x2400 0x24>;
#clock-cells = <1>;
#phy-cells = <0>;
- clocks = <&rcc CK_KER_USB2PHY2>;
- resets = <&rcc USB2PHY2_R>;
- st,syscfg = <&syscfg 0x2800>;
+ clocks = <&rcc CK_KER_USB2PHY1>;
+ resets = <&rcc USB2PHY1_R>;
vdd33-supply = <&vdd33usb>;
};
--
2.43.0
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 13/16] dt-bindings: arm: stm32mp2: allow child nodes since simple-mfd transition
2026-08-21 16:23 [PATCH 00/16] Add support for USB Type-C on STM32MP25 Fabrice Gasnier
` (11 preceding siblings ...)
2026-08-21 16:23 ` [PATCH 12/16] dt-bindings: phy: stm32: adapt usb2phy as syscon child on stm32mp25 Fabrice Gasnier
@ 2026-08-21 16:23 ` Fabrice Gasnier
2026-08-21 16:23 ` [PATCH 14/16] arm64: dts: st: enable usb on stm32mp257f-ev1 Fabrice Gasnier
` (2 subsequent siblings)
15 siblings, 0 replies; 24+ messages in thread
From: Fabrice Gasnier @ 2026-08-21 16:23 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Christian Bruel, Fabrice Gasnier, Heikki Krogerus,
Alexandre Torgue, Philipp Zabel, Liam Girdwood, Mark Brown,
Srinivas Kandagatla, Marek Vasut, Vinod Koul, Neil Armstrong,
Pankaj Dev, Marek Vasut
Cc: linux-usb, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel, linux-phy
Adapt stm32-syscon on stm32mp2, since transition to simple-mfd, to support
usb2phy child nodes, that has a unit address.
This is a temporary update, as it depends on Marek's series [1]. This
should be dropped in later series revision.
It's a precursor to validate further DT addition on USB and Type-C.
[1] https://lore.kernel.org/linux-phy/20260816213849.1044073-8-marex@nabladev.com/
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
.../devicetree/bindings/arm/stm32/st,stm32-syscon.yaml | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/Documentation/devicetree/bindings/arm/stm32/st,stm32-syscon.yaml b/Documentation/devicetree/bindings/arm/stm32/st,stm32-syscon.yaml
index ef640443dd23..964e1a5a43a3 100644
--- a/Documentation/devicetree/bindings/arm/stm32/st,stm32-syscon.yaml
+++ b/Documentation/devicetree/bindings/arm/stm32/st,stm32-syscon.yaml
@@ -40,6 +40,16 @@ properties:
"#clock-cells":
const: 0
+ "#address-cells":
+ const: 1
+
+ "#size-cells":
+ const: 1
+
+patternProperties:
+ "@[0-9a-f]+$":
+ type: object
+
required:
- compatible
- reg
--
2.43.0
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 14/16] arm64: dts: st: enable usb on stm32mp257f-ev1
2026-08-21 16:23 [PATCH 00/16] Add support for USB Type-C on STM32MP25 Fabrice Gasnier
` (12 preceding siblings ...)
2026-08-21 16:23 ` [PATCH 13/16] dt-bindings: arm: stm32mp2: allow child nodes since simple-mfd transition Fabrice Gasnier
@ 2026-08-21 16:23 ` Fabrice Gasnier
2026-08-21 16:23 ` [PATCH 15/16] arm64: dts: st: enable usb on stm32mp257f-dk Fabrice Gasnier
2026-08-21 16:23 ` [PATCH 16/16] arm64: configs: enable usb and its dependencies used on stm32mp25 Fabrice Gasnier
15 siblings, 0 replies; 24+ messages in thread
From: Fabrice Gasnier @ 2026-08-21 16:23 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Christian Bruel, Fabrice Gasnier, Heikki Krogerus,
Alexandre Torgue, Philipp Zabel, Liam Girdwood, Mark Brown,
Srinivas Kandagatla, Marek Vasut, Vinod Koul, Neil Armstrong,
Pankaj Dev, Marek Vasut
Cc: linux-usb, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel, linux-phy
STM32MP257F-EV1 board uses two USB controllers:
- USB Host port, with external onboard HUB providing to connectors
- USB Dual role Type-C port
Both are capable of to operate in High-Speed mode.
The Type-C port management is done through integrated UCPD controller
and external TCPP03 I2C protection chip on I2C1.
Signed-off-by: Christian Bruel <christian.bruel@foss.st.com>
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
arch/arm64/boot/dts/st/stm32mp257f-ev1.dts | 79 ++++++++++++++++++++++++++++++
1 file changed, 79 insertions(+)
diff --git a/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts b/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts
index 14e033f365e3..6c2bfbf77aac 100644
--- a/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts
+++ b/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts
@@ -253,6 +253,28 @@ phy0_eth2: ethernet-phy@1 {
};
};
+&i2c1 {
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&i2c1_pins_a>;
+ pinctrl-1 = <&i2c1_sleep_pins_a>;
+ clock-frequency = <400000>;
+ status = "okay";
+ /* spare dmas for other usage */
+ /delete-property/dmas;
+ /delete-property/dma-names;
+
+ tcpp: typec@34 {
+ compatible = "st,tcpp03";
+ reg = <0x34>;
+ enable-gpios = <&gpiog 2 GPIO_ACTIVE_HIGH>;
+ interrupt-parent = <&gpiog>;
+ interrupts = <1 IRQ_TYPE_EDGE_BOTH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&tcpp_flgn_pins_a>;
+ status = "okay";
+ };
+};
+
&i2c2 {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&i2c2_pins_a>;
@@ -516,6 +538,27 @@ timer@11 {
};
};
+&ucpd {
+ st,tcpp = <&tcpp>;
+ status = "okay";
+
+ connector {
+ compatible = "usb-c-connector";
+ label = "USB-C";
+ data-role = "dual";
+ power-role = "dual";
+ try-power-role = "sink";
+ typec-power-opmode = "1.5A";
+ pd-disable;
+ self-powered;
+ port {
+ typec_ep: endpoint {
+ remote-endpoint = <&dwc3_ep>;
+ };
+ };
+ };
+};
+
&usart2 {
pinctrl-names = "default", "idle", "sleep";
pinctrl-0 = <&usart2_pins_a>;
@@ -534,3 +577,39 @@ &usart6 {
uart-has-rtscts;
status = "disabled";
};
+
+&usb2_phy1 {
+ vdd33-supply = <&scmi_vdd3v3_usb>;
+ status = "okay";
+};
+
+&usb2_phy2 {
+ vdd33-supply = <&scmi_vdd3v3_usb>;
+ status = "okay";
+};
+
+&usb3dr {
+ maximum-speed = "high-speed";
+ phys = <&usb2_phy2>;
+ phy-names = "usb2-phy";
+ usb-role-switch;
+ status = "okay";
+ port {
+ dwc3_ep: endpoint {
+ remote-endpoint = <&typec_ep>;
+ };
+ };
+};
+
+&usbh_ehci {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "okay";
+ /* onboard HUB */
+ hub@1 {
+ compatible = "usb424,2514";
+ reg = <1>;
+ vdd-supply = <&scmi_v3v3>;
+ vdda-supply = <&scmi_v3v3>;
+ };
+};
--
2.43.0
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 15/16] arm64: dts: st: enable usb on stm32mp257f-dk
2026-08-21 16:23 [PATCH 00/16] Add support for USB Type-C on STM32MP25 Fabrice Gasnier
` (13 preceding siblings ...)
2026-08-21 16:23 ` [PATCH 14/16] arm64: dts: st: enable usb on stm32mp257f-ev1 Fabrice Gasnier
@ 2026-08-21 16:23 ` Fabrice Gasnier
2026-08-21 16:23 ` [PATCH 16/16] arm64: configs: enable usb and its dependencies used on stm32mp25 Fabrice Gasnier
15 siblings, 0 replies; 24+ messages in thread
From: Fabrice Gasnier @ 2026-08-21 16:23 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Christian Bruel, Fabrice Gasnier, Heikki Krogerus,
Alexandre Torgue, Philipp Zabel, Liam Girdwood, Mark Brown,
Srinivas Kandagatla, Marek Vasut, Vinod Koul, Neil Armstrong,
Pankaj Dev, Marek Vasut
Cc: linux-usb, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel, linux-phy
STM32MP257F-DK board uses two USB controllers:
- USB 2.0 High-Speed Host, with external onboard HUB providing two
connectors.
- USB 3.0 Super-Speed dual role Type-C port
The Type-C port management is done through integrated UCPD controller
and external TCPP03 I2C protection chip on I2C1. FUSB340 SuperSpeed
switch is used to reverse Super-Speed lines, depending on the
orientation.
Signed-off-by: Christian Bruel <christian.bruel@foss.st.com>
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
arch/arm64/boot/dts/st/stm32mp257f-dk.dts | 111 ++++++++++++++++++++++++++++++
1 file changed, 111 insertions(+)
diff --git a/arch/arm64/boot/dts/st/stm32mp257f-dk.dts b/arch/arm64/boot/dts/st/stm32mp257f-dk.dts
index 8daf3dfd5133..fdb21c4c48b9 100644
--- a/arch/arm64/boot/dts/st/stm32mp257f-dk.dts
+++ b/arch/arm64/boot/dts/st/stm32mp257f-dk.dts
@@ -27,6 +27,20 @@ chosen {
stdout-path = "serial0:115200n8";
};
+ fusb340: usb-switch {
+ compatible = "onnn,fusb340";
+ enable-gpios = <&gpioh 2 GPIO_ACTIVE_LOW>;
+ select-gpios = <&gpioh 3 GPIO_ACTIVE_HIGH>;
+ mode-switch;
+ orientation-switch;
+
+ port {
+ fusb340_con_ss: endpoint {
+ remote-endpoint = <&typec_ss>;
+ };
+ };
+ };
+
gpio-keys {
compatible = "gpio-keys";
@@ -138,6 +152,11 @@ &arm_wdt {
status = "okay";
};
+&combophy {
+ st,ssc-on;
+ status = "okay";
+};
+
ðernet1 {
pinctrl-0 = <ð1_rgmii_pins_b>;
pinctrl-1 = <ð1_rgmii_sleep_pins_b>;
@@ -160,6 +179,28 @@ phy1_eth1: ethernet-phy@1 {
};
};
+&i2c1 {
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&i2c1_pins_a>;
+ pinctrl-1 = <&i2c1_sleep_pins_a>;
+ clock-frequency = <400000>;
+ status = "okay";
+ /* spare dmas for other usage */
+ /delete-property/dmas;
+ /delete-property/dma-names;
+
+ tcpp: typec@34 {
+ compatible = "st,tcpp03";
+ reg = <0x34>;
+ enable-gpios = <&gpioa 3 GPIO_ACTIVE_HIGH>;
+ interrupt-parent = <&gpiog>;
+ interrupts = <1 IRQ_TYPE_EDGE_BOTH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&tcpp_flgn_pins_a>;
+ status = "okay";
+ };
+};
+
&i2c2 {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&i2c2_pins_b>;
@@ -279,6 +320,44 @@ &sdmmc1 {
status = "okay";
};
+&ucpd {
+ vconn-cc1-gpios = <&gpiof 5 GPIO_ACTIVE_HIGH>;
+ vconn-cc2-gpios = <&gpioc 3 GPIO_ACTIVE_HIGH>;
+ vconn-supply = <&scmi_v5v_vconn>;
+ st,tcpp = <&tcpp>;
+ status = "okay";
+
+ connector {
+ compatible = "usb-c-connector";
+ label = "USB-C";
+ data-role = "dual";
+ power-role = "dual";
+ try-power-role = "sink";
+ typec-power-opmode = "1.5A";
+ pd-disable;
+ self-powered;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ typec_ep: endpoint {
+ remote-endpoint = <&dwc3_ep>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ typec_ss: endpoint {
+ remote-endpoint = <&fusb340_con_ss>;
+ };
+ };
+ };
+ };
+};
+
&usart2 {
pinctrl-names = "default", "idle", "sleep";
pinctrl-0 = <&usart2_pins_a>;
@@ -288,3 +367,35 @@ &usart2 {
/delete-property/dma-names;
status = "okay";
};
+
+&usb2_phy1 {
+ vdd33-supply = <&scmi_vdd3v3_usb>;
+ status = "okay";
+};
+
+&usb2_phy2 {
+ vdd33-supply = <&scmi_vdd3v3_usb>;
+ status = "okay";
+};
+
+&usb3dr {
+ usb-role-switch;
+ status = "okay";
+ port {
+ dwc3_ep: endpoint {
+ remote-endpoint = <&typec_ep>;
+ };
+ };
+};
+
+&usbh_ehci {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "okay";
+ /* onboard HUB */
+ hub@1 {
+ compatible = "usb424,2422";
+ reg = <1>;
+ vdd-supply = <&scmi_v3v3>;
+ };
+};
--
2.43.0
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 16/16] arm64: configs: enable usb and its dependencies used on stm32mp25
2026-08-21 16:23 [PATCH 00/16] Add support for USB Type-C on STM32MP25 Fabrice Gasnier
` (14 preceding siblings ...)
2026-08-21 16:23 ` [PATCH 15/16] arm64: dts: st: enable usb on stm32mp257f-dk Fabrice Gasnier
@ 2026-08-21 16:23 ` Fabrice Gasnier
2026-08-22 7:28 ` Krzysztof Kozlowski
15 siblings, 1 reply; 24+ messages in thread
From: Fabrice Gasnier @ 2026-08-21 16:23 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Christian Bruel, Fabrice Gasnier, Heikki Krogerus,
Alexandre Torgue, Philipp Zabel, Liam Girdwood, Mark Brown,
Srinivas Kandagatla, Marek Vasut, Vinod Koul, Neil Armstrong,
Pankaj Dev, Marek Vasut
Cc: linux-usb, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel, linux-phy
Enable USB drivers used on stm32mp25 reference design boards.
In addition to the USB HighSpeed and SuperSpeed PHY drivers,
enable the USB Type-C related drivers used on those boards e.g. UCPD,
external TCPP i2c protection chip and FUSB340 SuperSpeed mux.
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
---
arch/arm64/configs/defconfig | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 654a102cb5bc..b9aceadf31ad 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -633,6 +633,7 @@ CONFIG_I2C_RK3X=y
CONFIG_I2C_RZV2M=m
CONFIG_I2C_S3C2410=y
CONFIG_I2C_SH_MOBILE=y
+CONFIG_I2C_STM32F7=m
CONFIG_I2C_TEGRA=y
CONFIG_I2C_UNIPHIER_F=y
CONFIG_I2C_XILINX=m
@@ -1251,6 +1252,7 @@ CONFIG_TYPEC_RT1711H=m
CONFIG_TYPEC_MT6360=m
CONFIG_TYPEC_TCPCI_MAXIM=m
CONFIG_TYPEC_FUSB302=m
+CONFIG_TYPEC_UCPD_STM32=m
CONFIG_TYPEC_QCOM_PMIC=m
CONFIG_TYPEC_UCSI=m
CONFIG_UCSI_CCG=m
@@ -1258,6 +1260,7 @@ CONFIG_UCSI_PMIC_GLINK=m
CONFIG_TYPEC_TPS6598X=m
CONFIG_TYPEC_HD3SS3220=m
CONFIG_TYPEC_MUX_FSA4480=m
+CONFIG_TYPEC_MUX_FUSB340=m
CONFIG_TYPEC_MUX_GPIO_SBU=m
CONFIG_TYPEC_MUX_IT5205=m
CONFIG_TYPEC_MUX_NB7VPQ904M=m
@@ -1795,6 +1798,8 @@ CONFIG_PHY_ROCKCHIP_USBDP=m
CONFIG_PHY_SAMSUNG_UFS=y
CONFIG_PHY_UNIPHIER_USB2=y
CONFIG_PHY_UNIPHIER_USB3=y
+CONFIG_PHY_STM32_COMBOPHY=m
+CONFIG_PHY_STM32_USB2PHY=y
CONFIG_PHY_TEGRA_XUSB=y
CONFIG_PHY_AM654_SERDES=m
CONFIG_PHY_J721E_WIZ=m
@@ -1831,6 +1836,7 @@ CONFIG_NVMEM_ROCKCHIP_EFUSE=y
CONFIG_NVMEM_ROCKCHIP_OTP=y
CONFIG_NVMEM_SNVS_LPGPR=y
CONFIG_NVMEM_SPMI_SDAM=m
+CONFIG_NVMEM_STM32_ROMEM=m
CONFIG_NVMEM_SUNXI_SID=y
CONFIG_NVMEM_UNIPHIER_EFUSE=y
CONFIG_NVMEM_ZYNQMP=m
--
2.43.0
^ permalink raw reply related [flat|nested] 24+ messages in thread
* Re: [PATCH 05/16] dt-bindings: usb: add FUSB340 switch binding
2026-08-21 16:23 ` [PATCH 05/16] dt-bindings: usb: add FUSB340 switch binding Fabrice Gasnier
@ 2026-08-22 4:49 ` Marek Vasut
2026-08-25 13:09 ` Fabrice Gasnier
0 siblings, 1 reply; 24+ messages in thread
From: Marek Vasut @ 2026-08-22 4:49 UTC (permalink / raw)
To: Fabrice Gasnier, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Christian Bruel,
Heikki Krogerus, Alexandre Torgue, Philipp Zabel, Liam Girdwood,
Mark Brown, Srinivas Kandagatla, Vinod Koul, Neil Armstrong,
Pankaj Dev
Cc: linux-usb, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel, linux-phy
On 8/21/26 6:23 PM, Fabrice Gasnier wrote:
> Document the ON Semiconductor FUSB340 SuperSpeed switch as a USB switch
> binding with enable-gpios and select-gpios controls. The switch can be used
> in Type-C applications where a reversible cable requires a switch.
>
> Assisted-by: GitHub-Copilot:GPT-5.4-mini
Use gpio-sbu-mux , there is no need to add more AI generated duplicate
drivers.
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 02/16] usb: typec: tcpm: Add STM32 tcpp driver
2026-08-21 16:23 ` [PATCH 02/16] usb: typec: tcpm: Add STM32 tcpp driver Fabrice Gasnier
@ 2026-08-22 4:50 ` Marek Vasut
0 siblings, 0 replies; 24+ messages in thread
From: Marek Vasut @ 2026-08-22 4:50 UTC (permalink / raw)
To: Fabrice Gasnier, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Christian Bruel,
Heikki Krogerus, Alexandre Torgue, Philipp Zabel, Liam Girdwood,
Mark Brown, Srinivas Kandagatla, Vinod Koul, Neil Armstrong,
Pankaj Dev
Cc: linux-usb, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel, linux-phy
On 8/21/26 6:23 PM, Fabrice Gasnier wrote:
> From: Christian Bruel <christian.bruel@foss.st.com>
>
> Add support for the STMicroelectronics TCPP02 and TCPP03 USB-C PD
> protection for dual role power (DRP).
> It can be used with the STM32 family embedding UCPD controller.
[...]
> +++ b/drivers/usb/typec/tcpm/st_tcpp.h
> @@ -0,0 +1,21 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (C) 2026 STMicroelectronics
> + */
> +
> +#ifndef __ST_TCPP_H__
> +#define __ST_TCPP_H__
> +
> +typedef void (*tcpp_vbus_cb_t)(void *data, bool vbus_present);
> +
> +int tcpp_init(struct device *tcpp);
> +void tcpp_deinit(struct device *tcpp);
> +int tcpp_get_vbus(struct device *tcpp);
> +int tcpp_set_vbus(struct device *tcpp, bool on, bool charge);
> +int tcpp_set_vconn(struct device *dev, bool on, enum typec_cc_polarity polarity);
> +int tcpp_attach(struct device *tcpp);
> +int tcpp_detach(struct device *tcpp);
> +int tcpp_register_vbus_notifier(struct device *dev, tcpp_vbus_cb_t cb, void *data);
> +void tcpp_unregister_vbus_notifier(struct device *dev);
Model the TCPP as four GPIOs and you won't need any of this
horribleness. Have a look at the UCPD driver I posted two days ago,
"[PATCH 2/4] usb: typec: ucpd: Add ST UCPD driver", it operates TCPP
exactly that way.
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 08/16] arm64: dts: st: Add ucpd node on stm32mp251
2026-08-21 16:23 ` [PATCH 08/16] arm64: dts: st: Add ucpd node on stm32mp251 Fabrice Gasnier
@ 2026-08-22 5:00 ` Marek Vasut
2026-08-26 13:19 ` Fabrice Gasnier
0 siblings, 1 reply; 24+ messages in thread
From: Marek Vasut @ 2026-08-22 5:00 UTC (permalink / raw)
To: Fabrice Gasnier, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Christian Bruel,
Heikki Krogerus, Alexandre Torgue, Philipp Zabel, Liam Girdwood,
Mark Brown, Srinivas Kandagatla, Vinod Koul, Neil Armstrong,
Pankaj Dev
Cc: linux-usb, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel, linux-phy, Thomas Bourgoin
On 8/21/26 6:23 PM, Fabrice Gasnier wrote:
> Describe UCPD bindings and nvmem cells to access trim values.
> This provides the PD and CC USB-C cable signaling functions.
>
> Co-developed-by: Christian Bruel <christian.bruel@foss.st.com>
> Signed-off-by: Christian Bruel <christian.bruel@foss.st.com>
> Co-developed-by: Thomas Bourgoin <thomas.bourgoin@foss.st.com>
> Signed-off-by: Thomas Bourgoin <thomas.bourgoin@foss.st.com>
> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
> ---
> arch/arm64/boot/dts/st/stm32mp251.dtsi | 51 ++++++++++++++++++++++++++++++++++
> 1 file changed, 51 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/st/stm32mp251.dtsi b/arch/arm64/boot/dts/st/stm32mp251.dtsi
> index 9dc7a05fce99..be54dd56713b 100644
> --- a/arch/arm64/boot/dts/st/stm32mp251.dtsi
[...]
> @@ -1818,10 +1839,40 @@ part-number-otp@24 {
> reg = <0x24 0x4>;
> };
>
> + ucpd_trim_3a_cc1: trim_3a_cc1@1bd,1 {
> + reg = <0x1bd 0x1>;
> + bits = <1 4>;
> + };
> +
> + ucpd_trim_3a_cc2: trim_3a_cc2@1bf,1 {
> + reg = <0x1bf 0x1>;
> + bits = <1 4>;
> + };
These two fuse fields ^ do not seem to match STM32MP25xx documentation ?
RM0457 Rev 5
Table 876. UCPD software trim data
Page 5013
Non-volatile memory location
Name Address Bits
3A0_CC1[3:0] 0x5400 01E8 11:8
3A0_CC2[3:0] 0x5400 01E8 11:8
^^^^^^^ ^^^^ ^^^^
> package-otp@1e8 {
> reg = <0x1e8 0x1>;
> bits = <0 3>;
> };
[...]
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 16/16] arm64: configs: enable usb and its dependencies used on stm32mp25
2026-08-21 16:23 ` [PATCH 16/16] arm64: configs: enable usb and its dependencies used on stm32mp25 Fabrice Gasnier
@ 2026-08-22 7:28 ` Krzysztof Kozlowski
0 siblings, 0 replies; 24+ messages in thread
From: Krzysztof Kozlowski @ 2026-08-22 7:28 UTC (permalink / raw)
To: Fabrice Gasnier, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Christian Bruel,
Heikki Krogerus, Alexandre Torgue, Philipp Zabel, Liam Girdwood,
Mark Brown, Srinivas Kandagatla, Marek Vasut, Vinod Koul,
Neil Armstrong, Pankaj Dev
Cc: linux-usb, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel, linux-phy
On 21/08/2026 18:23, Fabrice Gasnier wrote:
> Enable USB drivers used on stm32mp25 reference design boards.
> In addition to the USB HighSpeed and SuperSpeed PHY drivers,
> enable the USB Type-C related drivers used on those boards e.g. UCPD,
> external TCPP i2c protection chip and FUSB340 SuperSpeed mux.
>
> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
> ---
> arch/arm64/configs/defconfig | 6 ++++++
> 1 file changed, 6 insertions(+)
Subject prefix is imprecise - you update one config, not configs. Look
at git history how this should be named - arm64: defconfig:
Also, you completely missed company name - it's not your private config
- and actual name of upstream boards using it.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 04/16] usb: typec: tcpm: Add STM32 UCPD driver
2026-08-21 16:23 ` [PATCH 04/16] usb: typec: tcpm: Add STM32 UCPD driver Fabrice Gasnier
@ 2026-08-24 14:38 ` Philipp Zabel
0 siblings, 0 replies; 24+ messages in thread
From: Philipp Zabel @ 2026-08-24 14:38 UTC (permalink / raw)
To: Fabrice Gasnier, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Christian Bruel,
Heikki Krogerus, Alexandre Torgue, Liam Girdwood, Mark Brown,
Srinivas Kandagatla, Marek Vasut, Vinod Koul, Neil Armstrong,
Pankaj Dev
Cc: linux-usb, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel, linux-phy
On Fr, 2026-08-21 at 18:23 +0200, Fabrice Gasnier wrote:
> From: Christian Bruel <christian.bruel@foss.st.com>
>
> Add support for the STM32 UCPD controller providing USB Type‑C
> Configuration Channel (CC) management and USB Power Delivery (PD)
> protocol handling.
>
> The driver integrates with the TCPM (Type-C Port Manager) framework.
> On this platform, VBUS monitoring is handled by an external TCPP03
>
> Note the driver doesn't allow PD, so the role can only be set at
> plug time.
>
> The UCPD can be a wakeup source, in such a case, keep the hardware
> enabled. Else, keep track of the vbus state as provider and as
> consumer, to be restored after low power.
>
> Signed-off-by: Christian Bruel <christian.bruel@foss.st.com>
> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
> ---
> drivers/usb/typec/tcpm/Kconfig | 12 +
> drivers/usb/typec/tcpm/Makefile | 1 +
> drivers/usb/typec/tcpm/stm32_ucpd.c | 818 ++++++++++++++++++++++++++++++++++++
> 3 files changed, 831 insertions(+)
>
[...]
> diff --git a/drivers/usb/typec/tcpm/stm32_ucpd.c b/drivers/usb/typec/tcpm/stm32_ucpd.c
> new file mode 100644
> index 000000000000..b5c9dc417814
> --- /dev/null
> +++ b/drivers/usb/typec/tcpm/stm32_ucpd.c
> @@ -0,0 +1,818 @@
[...]
> +static int stm32_ucpd_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct i2c_client *tcpp_client;
> + struct device_node *tcpp_np;
> + struct stm32_ucpd *ucpd;
> + int ret;
> +
> + ucpd = devm_kzalloc(dev, sizeof(*ucpd), GFP_KERNEL);
> + if (!ucpd)
> + return -ENOMEM;
> +
> + ucpd->dev = dev;
> + platform_set_drvdata(pdev, ucpd);
> +
> + ucpd->vdd = devm_regulator_get(&pdev->dev, "ucpd");
> + if (IS_ERR(ucpd->vdd))
> + return dev_err_probe(&pdev->dev, PTR_ERR(ucpd->vdd), "vdd get failed\n");
> +
> + ucpd->vconn = devm_regulator_get_optional(&pdev->dev, "vconn");
> + if (IS_ERR(ucpd->vconn)) {
> + if (PTR_ERR(ucpd->vconn) != -ENODEV)
> + return dev_err_probe(&pdev->dev, PTR_ERR(ucpd->vconn),
> + "vconn get failed\n");
> + ucpd->vconn = NULL;
> + }
> +
> + ucpd->base = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(ucpd->base))
> + return PTR_ERR(ucpd->base);
> +
> + ucpd->num_clks = devm_clk_bulk_get_all(dev, &ucpd->clks);
> + if (ucpd->num_clks <= 0)
> + return ucpd->num_clks ? : -ENOENT;
> +
> + ucpd->reset = devm_reset_control_get_exclusive(dev, "ucpd");
> + if (IS_ERR(ucpd->reset))
> + return dev_err_probe(dev, PTR_ERR(ucpd->reset), "Failed to get UCPD reset\n");
> +
> + ret = stm32_ucpd_get_trim_values(ucpd);
> + if (ret)
> + return dev_err_probe(dev, ret, "Failed to get trim values\n");
> +
> + ucpd->vconn_cc1_gpio = devm_gpiod_get_optional(dev, "vconn-cc1", GPIOD_OUT_LOW);
> + if (IS_ERR(ucpd->vconn_cc1_gpio))
> + return dev_err_probe(dev, PTR_ERR(ucpd->vconn_cc1_gpio), "vconn-cc1 get failed\n");
> +
> + ucpd->vconn_cc2_gpio = devm_gpiod_get_optional(dev, "vconn-cc2", GPIOD_OUT_LOW);
> + if (IS_ERR(ucpd->vconn_cc2_gpio))
> + return dev_err_probe(dev, PTR_ERR(ucpd->vconn_cc2_gpio), "vconn-cc2 get failed\n");
> +
> + ucpd->ucpd_irq = platform_get_irq_byname(pdev, "ucpd");
> + if (ucpd->ucpd_irq < 0)
> + return ucpd->ucpd_irq;
> +
> + ucpd->tcpc_dev.fwnode = device_get_named_child_node(dev, "connector");
> + if (IS_ERR(ucpd->tcpc_dev.fwnode))
> + return dev_err_probe(dev, PTR_ERR(ucpd->tcpc_dev.fwnode), "connector not found");
> +
> + tcpp_np = of_parse_phandle(dev->of_node, "st,tcpp", 0);
> + if (!tcpp_np)
> + return -EINVAL;
> +
> + tcpp_client = of_find_i2c_device_by_node(tcpp_np);
> + of_node_put(tcpp_np);
> +
> + /* tcpp driver must be probed so tcpp_init() can be called from tcpm_register_port() */
> + if (!tcpp_client || !tcpp_client->dev.driver)
> + return -EPROBE_DEFER;
> +
> + ucpd->tcpp_dev = &tcpp_client->dev;
> +
> + /* No irq until tcpm_port is ready */
> + irq_set_status_flags(ucpd->ucpd_irq, IRQ_NOAUTOEN);
> + ret = devm_request_threaded_irq(dev, ucpd->ucpd_irq, NULL, ucpd_irq_handler, IRQF_ONESHOT,
> + dev_name(dev), ucpd);
> + if (ret) {
> + dev_err_probe(dev, ret, "failed to get irq\n");
> + goto put_tcpp;
> + }
> +
> + init_tcpc_dev(&ucpd->tcpc_dev);
> +
> + ret = regulator_enable(ucpd->vdd);
> + if (ret) {
> + dev_err_probe(dev, ret, "failed to enable regulator\n");
> + goto put_tcpp;
> + }
> +
> + ret = clk_bulk_prepare_enable(ucpd->num_clks, ucpd->clks);
> + if (ret) {
> + dev_err_probe(dev, ret, "failed to enable clocks\n");
> + goto disable_regulator;
> + }
> +
> + ret = reset_control_deassert(ucpd->reset);
No reset_control_assert() in the error path and in stm32_ucpd_remove()?
regards
Philipp
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 05/16] dt-bindings: usb: add FUSB340 switch binding
2026-08-22 4:49 ` Marek Vasut
@ 2026-08-25 13:09 ` Fabrice Gasnier
0 siblings, 0 replies; 24+ messages in thread
From: Fabrice Gasnier @ 2026-08-25 13:09 UTC (permalink / raw)
To: Marek Vasut, Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Christian Bruel, Heikki Krogerus, Alexandre Torgue,
Philipp Zabel, Liam Girdwood, Mark Brown, Srinivas Kandagatla,
Vinod Koul, Neil Armstrong, Pankaj Dev
Cc: linux-usb, devicetree, linux-kernel, linux-stm32,
linux-arm-kernel, linux-phy
On 8/22/26 06:49, Marek Vasut wrote:
> On 8/21/26 6:23 PM, Fabrice Gasnier wrote:
>> Document the ON Semiconductor FUSB340 SuperSpeed switch as a USB switch
>> binding with enable-gpios and select-gpios controls. The switch can be
>> used
>> in Type-C applications where a reversible cable requires a switch.
>>
>> Assisted-by: GitHub-Copilot:GPT-5.4-mini
>
> Use gpio-sbu-mux , there is no need to add more AI generated duplicate
> drivers.
Hello Marek,
Ack. I just need an additional enable part for orientation-switch only
in gpio-sbu-mux.
I've split into a separate series:
https://lore.kernel.org/linux-usb/20260825-usb-fusb340-v1-v1-0-2191179b0661@foss.st.com/T/#t
Thanks for reviewing,
Fabrice
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 08/16] arm64: dts: st: Add ucpd node on stm32mp251
2026-08-22 5:00 ` Marek Vasut
@ 2026-08-26 13:19 ` Fabrice Gasnier
0 siblings, 0 replies; 24+ messages in thread
From: Fabrice Gasnier @ 2026-08-26 13:19 UTC (permalink / raw)
To: Marek Vasut
Cc: Greg Kroah-Hartman, Christian Bruel, linux-usb, devicetree,
linux-kernel, linux-stm32, Conor Dooley, Krzysztof Kozlowski,
linux-arm-kernel, Neil Armstrong, Vinod Koul, Liam Girdwood,
Heikki Krogerus, linux-phy, Thomas Bourgoin, Mark Brown,
Philipp Zabel, Rob Herring, Alexandre Torgue, Srinivas Kandagatla,
Pankaj Dev
On 8/22/26 07:00, Marek Vasut wrote:
> On 8/21/26 6:23 PM, Fabrice Gasnier wrote:
>> Describe UCPD bindings and nvmem cells to access trim values.
>> This provides the PD and CC USB-C cable signaling functions.
>>
>> Co-developed-by: Christian Bruel <christian.bruel@foss.st.com>
>> Signed-off-by: Christian Bruel <christian.bruel@foss.st.com>
>> Co-developed-by: Thomas Bourgoin <thomas.bourgoin@foss.st.com>
>> Signed-off-by: Thomas Bourgoin <thomas.bourgoin@foss.st.com>
>> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
>> ---
>> arch/arm64/boot/dts/st/stm32mp251.dtsi | 51 ++++++++++++++++++++++++
>> ++++++++++
>> 1 file changed, 51 insertions(+)
>>
>> diff --git a/arch/arm64/boot/dts/st/stm32mp251.dtsi b/arch/arm64/boot/
>> dts/st/stm32mp251.dtsi
>> index 9dc7a05fce99..be54dd56713b 100644
>> --- a/arch/arm64/boot/dts/st/stm32mp251.dtsi
>
> [...]
>
>> @@ -1818,10 +1839,40 @@ part-number-otp@24 {
>> reg = <0x24 0x4>;
>> };
>> + ucpd_trim_3a_cc1: trim_3a_cc1@1bd,1 {
>> + reg = <0x1bd 0x1>;
>> + bits = <1 4>;
>> + };
>> +
>> + ucpd_trim_3a_cc2: trim_3a_cc2@1bf,1 {
>> + reg = <0x1bf 0x1>;
>> + bits = <1 4>;
>> + };
>
> These two fuse fields ^ do not seem to match STM32MP25xx documentation ?
>
> RM0457 Rev 5
> Table 876. UCPD software trim data
> Page 5013
>
> Non-volatile memory location
> Name Address Bits
> 3A0_CC1[3:0] 0x5400 01E8 11:8
> 3A0_CC2[3:0] 0x5400 01E8 11:8
> ^^^^^^^ ^^^^ ^^^^
>
Hi Marek,
Yes, I've raised it internally (ST) so the documentation gets clarified.
Please look at "OTP mapping" section instead, Table 34.
e.g. OTP111
word/bits |
9 to 12 | USBTC_VIREF1_3A0[3:0] | USB Type C CC1 ref current trim (±6%)
in 3 A mode
25 to 28 | USBTC_VIREF2_3A0[3:0] | USB Type C CC2 ref current trim (±6%)
in 3 A mode
and OTP122
4 to 7 | USBTC_CCRPD1[3:0] | USB Type C CC1 5.1Kohm pull down trim
(±10%)
8 to 11 | USBTC_VIREF1_1A5[3:0] | USB Type C CC1 ref current trim (±6%)
in 1.5 A mode
12 to 15 | USBTC_CCRPD2[3:0] | USB Type C CC2 pull down trim (5.1 K
±10%)
16 to 19 | USBTC_VIREF2_1A5[3:0] | USB Type C CC2 ref current trim (±6%)
in 1.5 A mode
BR,
Fabrice
>> package-otp@1e8 {
>> reg = <0x1e8 0x1>;
>> bits = <0 3>;
>> };
> [...]
^ permalink raw reply [flat|nested] 24+ messages in thread
end of thread, other threads:[~2026-08-26 13:20 UTC | newest]
Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-21 16:23 [PATCH 00/16] Add support for USB Type-C on STM32MP25 Fabrice Gasnier
2026-08-21 16:23 ` [PATCH 01/16] dt-bindings: usb: st,tcpp: Document TCPP USB-C PD protection chip Fabrice Gasnier
2026-08-21 16:23 ` [PATCH 02/16] usb: typec: tcpm: Add STM32 tcpp driver Fabrice Gasnier
2026-08-22 4:50 ` Marek Vasut
2026-08-21 16:23 ` [PATCH 03/16] dt-bindings: usb: st,stm32-ucpd: Document STM32 UCPD controller Fabrice Gasnier
2026-08-21 16:23 ` [PATCH 04/16] usb: typec: tcpm: Add STM32 UCPD driver Fabrice Gasnier
2026-08-24 14:38 ` Philipp Zabel
2026-08-21 16:23 ` [PATCH 05/16] dt-bindings: usb: add FUSB340 switch binding Fabrice Gasnier
2026-08-22 4:49 ` Marek Vasut
2026-08-25 13:09 ` Fabrice Gasnier
2026-08-21 16:23 ` [PATCH 06/16] usb: typec: add FUSB340 SuperSpeed switch driver Fabrice Gasnier
2026-08-21 16:23 ` [PATCH 07/16] dt-bindings: nvmem: st,stm32-romem: align patternProperties regex on nvmem-deprecated-cells.yaml Fabrice Gasnier
2026-08-21 16:23 ` [PATCH 08/16] arm64: dts: st: Add ucpd node on stm32mp251 Fabrice Gasnier
2026-08-22 5:00 ` Marek Vasut
2026-08-26 13:19 ` Fabrice Gasnier
2026-08-21 16:23 ` [PATCH 09/16] arm64: dts: st: add i2c1 pinctrl entries for stm32mp25 Fabrice Gasnier
2026-08-21 16:23 ` [PATCH 10/16] arm64: dts: st: add tcpp " Fabrice Gasnier
2026-08-21 16:23 ` [PATCH 11/16] dt-bindings: usb: dwc3: stm32: refer to dwc3-common Fabrice Gasnier
2026-08-21 16:23 ` [PATCH 12/16] dt-bindings: phy: stm32: adapt usb2phy as syscon child on stm32mp25 Fabrice Gasnier
2026-08-21 16:23 ` [PATCH 13/16] dt-bindings: arm: stm32mp2: allow child nodes since simple-mfd transition Fabrice Gasnier
2026-08-21 16:23 ` [PATCH 14/16] arm64: dts: st: enable usb on stm32mp257f-ev1 Fabrice Gasnier
2026-08-21 16:23 ` [PATCH 15/16] arm64: dts: st: enable usb on stm32mp257f-dk Fabrice Gasnier
2026-08-21 16:23 ` [PATCH 16/16] arm64: configs: enable usb and its dependencies used on stm32mp25 Fabrice Gasnier
2026-08-22 7:28 ` Krzysztof Kozlowski
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox