mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 0/4] usb: typec: STUSB160x support
@ 2026-04-20  9:02 Sascha Hauer
  2026-04-20  9:02 ` [PATCH 1/4] usb: otg: Add function to set dr_mode Sascha Hauer
                   ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: Sascha Hauer @ 2026-04-20  9:02 UTC (permalink / raw)
  To: BAREBOX; +Cc: Claude Sonnet 4.6

This adds a driver for the STUSB160x typec controller. Also added is
support for setting the USB data role according to the setting the
typec controller is in. This way we don't have to set otg.mode manually
anymore for devices which have a typec controller.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
Sascha Hauer (4):
      usb: otg: Add function to set dr_mode
      usb: typec: wire USB role changes to OTG device
      usb: typec: add typec_find_port_power_role() and typec_find_pwr_opmode()
      USB: typec: Add STUSB160x driver

 drivers/usb/otg/otgdev.c      |  20 ++
 drivers/usb/typec/Kconfig     |   9 +
 drivers/usb/typec/Makefile    |   1 +
 drivers/usb/typec/class.c     |  88 +++++++
 drivers/usb/typec/stusb160x.c | 572 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/usb/typec.h     |  16 ++
 include/linux/usb/usb.h       |   1 +
 7 files changed, 707 insertions(+)
---
base-commit: 7f4d6a825f65861c43771e713ac3ce509dc9e49b
change-id: 20260420-usb-typec-stusb160x-afc4b3b889a5

Best regards,
-- 
Sascha Hauer <s.hauer@pengutronix.de>




^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/4] usb: otg: Add function to set dr_mode
  2026-04-20  9:02 [PATCH 0/4] usb: typec: STUSB160x support Sascha Hauer
@ 2026-04-20  9:02 ` Sascha Hauer
  2026-04-20 10:42   ` Ahmad Fatoum
  2026-04-20  9:02 ` [PATCH 2/4] usb: typec: wire USB role changes to OTG device Sascha Hauer
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 10+ messages in thread
From: Sascha Hauer @ 2026-04-20  9:02 UTC (permalink / raw)
  To: BAREBOX

So far we can only set the dr_mode on the command line. Add a function
for it.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/usb/otg/otgdev.c | 20 ++++++++++++++++++++
 include/linux/usb/usb.h  |  1 +
 2 files changed, 21 insertions(+)

diff --git a/drivers/usb/otg/otgdev.c b/drivers/usb/otg/otgdev.c
index 5a86263430..50d8105be3 100644
--- a/drivers/usb/otg/otgdev.c
+++ b/drivers/usb/otg/otgdev.c
@@ -74,6 +74,26 @@ int otg_device_get_mode(struct device *dev)
 	return otg->cur_mode;
 }
 
+int otg_device_set_dr_mode(struct device *dev, enum usb_dr_mode mode)
+{
+	struct otg_mode *otg;
+	int ret;
+
+	if (dev->bus != &otg_bus_type)
+		return -ENODEV;
+
+	otg = dev->priv;
+
+	ret = otg->set_mode_callback(otg->ctx, mode);
+	if (ret)
+		return ret;
+
+	otg->cur_mode = mode;
+	otg->var_mode = mode;
+
+	return 0;
+}
+
 int usb_register_otg_device(struct device *parent,
 			    int (*set_mode)(void *ctx, enum usb_dr_mode mode), void *ctx)
 {
diff --git a/include/linux/usb/usb.h b/include/linux/usb/usb.h
index c25f3d73c3..6aa9e55cc9 100644
--- a/include/linux/usb/usb.h
+++ b/include/linux/usb/usb.h
@@ -477,6 +477,7 @@ int usb_register_otg_device(struct device *parent,
 			    int (*set_mode)(void *ctx, enum usb_dr_mode mode), void *ctx);
 
 int otg_device_get_mode(struct device *dev);
+int otg_device_set_dr_mode(struct device *dev, enum usb_dr_mode mode);
 
 extern struct bus_type otg_bus_type;
 

-- 
2.47.3




^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 2/4] usb: typec: wire USB role changes to OTG device
  2026-04-20  9:02 [PATCH 0/4] usb: typec: STUSB160x support Sascha Hauer
  2026-04-20  9:02 ` [PATCH 1/4] usb: otg: Add function to set dr_mode Sascha Hauer
@ 2026-04-20  9:02 ` Sascha Hauer
  2026-04-20 11:08   ` Ahmad Fatoum
  2026-04-20  9:02 ` [PATCH 3/4] usb: typec: add typec_find_port_power_role() and typec_find_pwr_opmode() Sascha Hauer
  2026-04-20  9:02 ` [PATCH 4/4] USB: typec: Add STUSB160x driver Sascha Hauer
  3 siblings, 1 reply; 10+ messages in thread
From: Sascha Hauer @ 2026-04-20  9:02 UTC (permalink / raw)
  To: BAREBOX; +Cc: Claude Sonnet 4.6

When a Type-C controller reports a USB role change via typec_set_role(),
find the associated OTG device via the OF graph and set its dr_mode
accordingly.

Since the Type-C controller may probe before the OTG device registers,
a late_initcall sweeps all known ports and applies any role that was not
yet forwarded.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/usb/typec/class.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)

diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
index e03eaccbb9..b88e1c1e46 100644
--- a/drivers/usb/typec/class.c
+++ b/drivers/usb/typec/class.c
@@ -8,10 +8,15 @@
 
 #include <module.h>
 #include <driver.h>
+#include <init.h>
 #include <linux/kernel.h>
+#include <linux/list.h>
 #include <linux/usb/role.h>
 #include <linux/usb/typec.h>
 #include <linux/usb/typec_altmode.h>
+#include <linux/usb/usb.h>
+#include <linux/device/bus.h>
+#include <of_graph.h>
 #include <param.h>
 
 enum typec_param_accessory {
@@ -22,12 +27,16 @@ enum typec_param_accessory {
 
 struct typec_port {
 	struct device dev;
+	struct list_head list;
 	const struct typec_operations *ops;
 	int pwr_role;		/* enum typec_role */
 	int usb_role;		/* enum usb_role role */
 	int accessory;		/* enum typec_param_accessory */
+	bool otg_role_applied;
 };
 
+static LIST_HEAD(typec_port_list);
+
 /**
  * typec_set_pwr_role - Report power role change
  * @port: The USB Type-C Port where the role was changed
@@ -68,6 +77,41 @@ int typec_set_mode(struct typec_port *port, int mode)
 }
 EXPORT_SYMBOL_GPL(typec_set_mode);
 
+static bool typec_apply_otg_role(struct typec_port *port)
+{
+	struct device_node *connector = port->dev.of_node;
+	struct device_node *ep, *remote;
+	struct device *dev;
+	enum usb_dr_mode dr_mode;
+	bool applied = false;
+
+	if (!IS_ENABLED(CONFIG_USB_OTGDEV) || !connector)
+		return false;
+
+	if (port->usb_role == USB_ROLE_HOST)
+		dr_mode = USB_DR_MODE_HOST;
+	else if (port->usb_role == USB_ROLE_DEVICE)
+		dr_mode = USB_DR_MODE_PERIPHERAL;
+	else
+		return false;
+
+	for_each_endpoint_of_node(connector, ep) {
+		remote = of_graph_get_remote_port_parent(ep);
+		if (!remote)
+			continue;
+
+		bus_for_each_device(&otg_bus_type, dev) {
+			if (dev->parent && dev->parent->of_node == remote) {
+				otg_device_set_dr_mode(dev, dr_mode);
+				applied = true;
+				break;
+			}
+		}
+	}
+
+	return applied;
+}
+
 /**
  * typec_set_role - Set USB role for a Type-C connector
  * @port: USB Type-C connector
@@ -79,10 +123,24 @@ EXPORT_SYMBOL_GPL(typec_set_mode);
 int typec_set_role(struct typec_port *port, enum usb_role role)
 {
 	port->usb_role = role;
+	port->otg_role_applied = typec_apply_otg_role(port);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(typec_set_role);
 
+static int typec_apply_otg_roles(void)
+{
+	struct typec_port *port;
+
+	list_for_each_entry(port, &typec_port_list, list) {
+		if (!port->otg_role_applied)
+			port->otg_role_applied = typec_apply_otg_role(port);
+	}
+
+	return 0;
+}
+late_initcall(typec_apply_otg_roles);
+
 /**
  * typec_get_drvdata - Return private driver data pointer
  * @port: USB Type-C port
@@ -165,6 +223,8 @@ struct typec_port *typec_register_port(struct device *parent,
 	if (dev->of_node)
 		dev->of_node->dev = dev;
 
+	list_add_tail(&port->list, &typec_port_list);
+
 	dev_add_param_enum(dev, "usb_role", param_set_readonly, typec_param_update,
 			   &port->usb_role, usb_role_names,
 			   ARRAY_SIZE(usb_role_names), port);

-- 
2.47.3




^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 3/4] usb: typec: add typec_find_port_power_role() and typec_find_pwr_opmode()
  2026-04-20  9:02 [PATCH 0/4] usb: typec: STUSB160x support Sascha Hauer
  2026-04-20  9:02 ` [PATCH 1/4] usb: otg: Add function to set dr_mode Sascha Hauer
  2026-04-20  9:02 ` [PATCH 2/4] usb: typec: wire USB role changes to OTG device Sascha Hauer
@ 2026-04-20  9:02 ` Sascha Hauer
  2026-04-20  9:02 ` [PATCH 4/4] USB: typec: Add STUSB160x driver Sascha Hauer
  3 siblings, 0 replies; 10+ messages in thread
From: Sascha Hauer @ 2026-04-20  9:02 UTC (permalink / raw)
  To: BAREBOX; +Cc: Claude Sonnet 4.6

Add helpers to parse 'power-role' and 'typec-power-opmode' DT strings
into their respective enum values, mirroring the Linux typec framework.

Move enum typec_port_type and enum typec_pwr_opmode from driver-local
definitions into the typec framework header where they belong.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/usb/typec/class.c | 28 ++++++++++++++++++++++++++++
 include/linux/usb/typec.h | 16 ++++++++++++++++
 2 files changed, 44 insertions(+)

diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
index b88e1c1e46..363c5b8cbb 100644
--- a/drivers/usb/typec/class.c
+++ b/drivers/usb/typec/class.c
@@ -11,6 +11,7 @@
 #include <init.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
+#include <linux/string.h>
 #include <linux/usb/role.h>
 #include <linux/usb/typec.h>
 #include <linux/usb/typec_altmode.h>
@@ -151,6 +152,33 @@ void *typec_get_drvdata(struct typec_port *port)
 }
 EXPORT_SYMBOL_GPL(typec_get_drvdata);
 
+static const char * const typec_port_power_roles[] = {
+	[TYPEC_PORT_SRC] = "source",
+	[TYPEC_PORT_SNK] = "sink",
+	[TYPEC_PORT_DRP] = "dual",
+};
+
+static const char * const typec_pwr_opmodes[] = {
+	[TYPEC_PWR_MODE_USB]  = "default",
+	[TYPEC_PWR_MODE_1_5A] = "1.5A",
+	[TYPEC_PWR_MODE_3_0A] = "3.0A",
+	[TYPEC_PWR_MODE_PD]   = "usb_power_delivery",
+};
+
+int typec_find_port_power_role(const char *name)
+{
+	return match_string(typec_port_power_roles,
+			    ARRAY_SIZE(typec_port_power_roles), name);
+}
+EXPORT_SYMBOL_GPL(typec_find_port_power_role);
+
+int typec_find_pwr_opmode(const char *name)
+{
+	return match_string(typec_pwr_opmodes,
+			    ARRAY_SIZE(typec_pwr_opmodes), name);
+}
+EXPORT_SYMBOL_GPL(typec_find_pwr_opmode);
+
 static int typec_register_port_dev(struct typec_port *port, const char *name, int id)
 {
 	port->dev.id = id;
diff --git a/include/linux/usb/typec.h b/include/linux/usb/typec.h
index 315dee95e4..a8fa314d9e 100644
--- a/include/linux/usb/typec.h
+++ b/include/linux/usb/typec.h
@@ -8,6 +8,19 @@
 
 struct typec_port;
 
+enum typec_port_type {
+	TYPEC_PORT_SRC,
+	TYPEC_PORT_SNK,
+	TYPEC_PORT_DRP,
+};
+
+enum typec_pwr_opmode {
+	TYPEC_PWR_MODE_USB,
+	TYPEC_PWR_MODE_1_5A,
+	TYPEC_PWR_MODE_3_0A,
+	TYPEC_PWR_MODE_PD,
+};
+
 struct device;
 struct device_node;
 
@@ -51,4 +64,7 @@ int typec_set_role(struct typec_port *port, enum usb_role role);
 
 void *typec_get_drvdata(struct typec_port *port);
 
+int typec_find_port_power_role(const char *name);
+int typec_find_pwr_opmode(const char *name);
+
 #endif /* __LINUX_USB_TYPEC_H */

-- 
2.47.3




^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 4/4] USB: typec: Add STUSB160x driver
  2026-04-20  9:02 [PATCH 0/4] usb: typec: STUSB160x support Sascha Hauer
                   ` (2 preceding siblings ...)
  2026-04-20  9:02 ` [PATCH 3/4] usb: typec: add typec_find_port_power_role() and typec_find_pwr_opmode() Sascha Hauer
@ 2026-04-20  9:02 ` Sascha Hauer
  2026-04-20 11:14   ` Ahmad Fatoum
  3 siblings, 1 reply; 10+ messages in thread
From: Sascha Hauer @ 2026-04-20  9:02 UTC (permalink / raw)
  To: BAREBOX

This adds the STUSB160x driver from Linux. The feature set has been
reduced to what barebox provides.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/usb/typec/Kconfig     |   9 +
 drivers/usb/typec/Makefile    |   1 +
 drivers/usb/typec/stusb160x.c | 572 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 582 insertions(+)

diff --git a/drivers/usb/typec/Kconfig b/drivers/usb/typec/Kconfig
index 3b32a4e05a..22aacd73f6 100644
--- a/drivers/usb/typec/Kconfig
+++ b/drivers/usb/typec/Kconfig
@@ -12,3 +12,12 @@ config TYPEC_TUSB320
 	select TYPEC
 	help
 	  Say Y or here if your system has a TI TUSB320 Type-C port controller.
+
+config TYPEC_STUSB160X
+	tristate "STMicroelectronics STUSB160x Type-C controller driver"
+	depends on I2C
+	select REGMAP_I2C
+	select TYPEC
+	help
+	  Say Y or M here if your system has STMicroelectronics STUSB160x
+	  Type-C port controller.
\ No newline at end of file
diff --git a/drivers/usb/typec/Makefile b/drivers/usb/typec/Makefile
index 456b94afbf..b8c1e438b0 100644
--- a/drivers/usb/typec/Makefile
+++ b/drivers/usb/typec/Makefile
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_TYPEC)		+= class.o
 obj-$(CONFIG_TYPEC_TUSB320)	+= tusb320.o
+obj-$(CONFIG_TYPEC_STUSB160X)	+= stusb160x.o
\ No newline at end of file
diff --git a/drivers/usb/typec/stusb160x.c b/drivers/usb/typec/stusb160x.c
new file mode 100644
index 0000000000..ae7264af7e
--- /dev/null
+++ b/drivers/usb/typec/stusb160x.c
@@ -0,0 +1,572 @@
+// SPDX-License-Identifier: GPL-2.0
+// SPDX-Comment: Origin-URL: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/usb/typec/stusb160x.c?id=82375469755662b9910a22da14027cbef2bca666/*
+ * STMicroelectronics STUSB160x Type-C controller family driver
+ *
+ * Copyright (C) 2020, STMicroelectronics
+ * Author(s): Amelie Delaunay <amelie.delaunay@st.com>
+ */
+
+#include <linux/bitfield.h>
+#include <i2c/i2c.h>
+#include <init.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/printk.h>
+#include <linux/bitops.h>
+#include <regulator.h>
+#include <linux/regmap.h>
+#include <linux/usb/typec.h>
+#include <of.h>
+
+#define STUSB160X_ALERT_STATUS			0x0B /* RC */
+#define STUSB160X_ALERT_STATUS_MASK_CTRL	0x0C /* RW */
+#define STUSB160X_CC_CONNECTION_STATUS_TRANS	0x0D /* RC */
+#define STUSB160X_CC_CONNECTION_STATUS		0x0E /* RO */
+#define STUSB160X_MONITORING_STATUS_TRANS	0x0F /* RC */
+#define STUSB160X_MONITORING_STATUS		0x10 /* RO */
+#define STUSB160X_CC_OPERATION_STATUS		0x11 /* RO */
+#define STUSB160X_HW_FAULT_STATUS_TRANS		0x12 /* RC */
+#define STUSB160X_HW_FAULT_STATUS		0x13 /* RO */
+#define STUSB160X_CC_CAPABILITY_CTRL		0x18 /* RW */
+#define STUSB160X_CC_VCONN_SWITCH_CTRL		0x1E /* RW */
+#define STUSB160X_VCONN_MONITORING_CTRL		0x20 /* RW */
+#define STUSB160X_VBUS_MONITORING_RANGE_CTRL	0x22 /* RW */
+#define STUSB160X_RESET_CTRL			0x23 /* RW */
+#define STUSB160X_VBUS_DISCHARGE_TIME_CTRL	0x25 /* RW */
+#define STUSB160X_VBUS_DISCHARGE_STATUS		0x26 /* RO */
+#define STUSB160X_VBUS_ENABLE_STATUS		0x27 /* RO */
+#define STUSB160X_CC_POWER_MODE_CTRL		0x28 /* RW */
+#define STUSB160X_VBUS_MONITORING_CTRL		0x2E /* RW */
+#define STUSB1600_REG_MAX			0x2F /* RO - Reserved */
+
+/* STUSB160X_ALERT_STATUS/STUSB160X_ALERT_STATUS_MASK_CTRL bitfields */
+#define STUSB160X_HW_FAULT			BIT(4)
+#define STUSB160X_MONITORING			BIT(5)
+#define STUSB160X_CC_CONNECTION			BIT(6)
+#define STUSB160X_ALL_ALERTS			GENMASK(6, 4)
+
+/* STUSB160X_CC_CONNECTION_STATUS_TRANS bitfields */
+#define STUSB160X_CC_ATTACH_TRANS		BIT(0)
+
+/* STUSB160X_CC_CONNECTION_STATUS bitfields */
+#define STUSB160X_CC_ATTACH			BIT(0)
+#define STUSB160X_CC_VCONN_SUPPLY		BIT(1)
+#define STUSB160X_CC_POWER_ROLE(s)		(!!((s) & BIT(3)))
+#define STUSB160X_CC_ATTACHED_MODE		GENMASK(7, 5)
+
+/* STUSB160X_MONITORING_STATUS_TRANS bitfields */
+#define STUSB160X_VCONN_PRESENCE_TRANS		BIT(0)
+#define STUSB160X_VBUS_PRESENCE_TRANS		BIT(1)
+#define STUSB160X_VBUS_VSAFE0V_TRANS		BIT(2)
+#define STUSB160X_VBUS_VALID_TRANS		BIT(3)
+
+/* STUSB160X_MONITORING_STATUS bitfields */
+#define STUSB160X_VCONN_PRESENCE		BIT(0)
+#define STUSB160X_VBUS_PRESENCE			BIT(1)
+#define STUSB160X_VBUS_VSAFE0V			BIT(2)
+#define STUSB160X_VBUS_VALID			BIT(3)
+
+/* STUSB160X_CC_OPERATION_STATUS bitfields */
+#define STUSB160X_TYPEC_FSM_STATE		GENMASK(4, 0)
+#define STUSB160X_SINK_POWER_STATE		GENMASK(6, 5)
+#define STUSB160X_CC_ATTACHED			BIT(7)
+
+/* STUSB160X_HW_FAULT_STATUS_TRANS bitfields */
+#define STUSB160X_VCONN_SW_OVP_FAULT_TRANS	BIT(0)
+#define STUSB160X_VCONN_SW_OCP_FAULT_TRANS	BIT(1)
+#define STUSB160X_VCONN_SW_RVP_FAULT_TRANS	BIT(2)
+#define STUSB160X_VPU_VALID_TRANS		BIT(4)
+#define STUSB160X_VPU_OVP_FAULT_TRANS		BIT(5)
+#define STUSB160X_THERMAL_FAULT			BIT(7)
+
+/* STUSB160X_HW_FAULT_STATUS bitfields */
+#define STUSB160X_VCONN_SW_OVP_FAULT_CC2	BIT(0)
+#define STUSB160X_VCONN_SW_OVP_FAULT_CC1	BIT(1)
+#define STUSB160X_VCONN_SW_OCP_FAULT_CC2	BIT(2)
+#define STUSB160X_VCONN_SW_OCP_FAULT_CC1	BIT(3)
+#define STUSB160X_VCONN_SW_RVP_FAULT_CC2	BIT(4)
+#define STUSB160X_VCONN_SW_RVP_FAULT_CC1	BIT(5)
+#define STUSB160X_VPU_VALID			BIT(6)
+#define STUSB160X_VPU_OVP_FAULT			BIT(7)
+
+/* STUSB160X_CC_CAPABILITY_CTRL bitfields */
+#define STUSB160X_CC_VCONN_SUPPLY_EN		BIT(0)
+#define STUSB160X_CC_VCONN_DISCHARGE_EN		BIT(4)
+#define STUSB160X_CC_CURRENT_ADVERTISED		GENMASK(7, 6)
+
+/* STUSB160X_VCONN_SWITCH_CTRL bitfields */
+#define STUSB160X_CC_VCONN_SWITCH_ILIM		GENMASK(3, 0)
+
+/* STUSB160X_VCONN_MONITORING_CTRL bitfields */
+#define STUSB160X_VCONN_UVLO_THRESHOLD		BIT(6)
+#define STUSB160X_VCONN_MONITORING_EN		BIT(7)
+
+/* STUSB160X_VBUS_MONITORING_RANGE_CTRL bitfields */
+#define STUSB160X_SHIFT_LOW_VBUS_LIMIT		GENMASK(3, 0)
+#define STUSB160X_SHIFT_HIGH_VBUS_LIMIT		GENMASK(7, 4)
+
+/* STUSB160X_RESET_CTRL bitfields */
+#define STUSB160X_SW_RESET_EN			BIT(0)
+
+/* STUSB160X_VBUS_DISCHARGE_TIME_CTRL bitfields */
+#define STUSBXX02_VBUS_DISCHARGE_TIME_TO_PDO	GENMASK(3, 0)
+#define STUSB160X_VBUS_DISCHARGE_TIME_TO_0V	GENMASK(7, 4)
+
+/* STUSB160X_VBUS_DISCHARGE_STATUS bitfields */
+#define STUSB160X_VBUS_DISCHARGE_EN		BIT(7)
+
+/* STUSB160X_VBUS_ENABLE_STATUS bitfields */
+#define STUSB160X_VBUS_SOURCE_EN		BIT(0)
+#define STUSB160X_VBUS_SINK_EN			BIT(1)
+
+/* STUSB160X_CC_POWER_MODE_CTRL bitfields */
+#define STUSB160X_CC_POWER_MODE			GENMASK(2, 0)
+
+/* STUSB160X_VBUS_MONITORING_CTRL bitfields */
+#define STUSB160X_VDD_UVLO_DISABLE		BIT(0)
+#define STUSB160X_VBUS_VSAFE0V_THRESHOLD	GENMASK(2, 1)
+#define STUSB160X_VBUS_RANGE_DISABLE		BIT(4)
+#define STUSB160X_VDD_OVLO_DISABLE		BIT(6)
+
+enum stusb160x_pwr_mode {
+	SOURCE_WITH_ACCESSORY,
+	SINK_WITH_ACCESSORY,
+	SINK_WITHOUT_ACCESSORY,
+	DUAL_WITH_ACCESSORY,
+	DUAL_WITH_ACCESSORY_AND_TRY_SRC,
+	DUAL_WITH_ACCESSORY_AND_TRY_SNK,
+};
+
+enum stusb160x_attached_mode {
+	NO_DEVICE_ATTACHED,
+	SINK_ATTACHED,
+	SOURCE_ATTACHED,
+	DEBUG_ACCESSORY_ATTACHED,
+	AUDIO_ACCESSORY_ATTACHED,
+};
+
+enum typec_data_role {
+	TYPEC_DEVICE,
+	TYPEC_HOST,
+};
+
+struct stusb160x {
+	struct device		*dev;
+	struct regmap		*regmap;
+	struct regulator	*vdd_supply;
+	struct regulator	*vsys_supply;
+	struct regulator	*vconn_supply;
+	struct regulator	*main_supply;
+
+	struct typec_port	*port;
+	struct typec_capability capability;
+
+	enum typec_port_type	port_type;
+	enum typec_pwr_opmode	pwr_opmode;
+	bool			vbus_on;
+};
+
+static const struct regmap_config stusb1600_regmap_config = {
+	.reg_bits	= 8,
+	.reg_stride	= 1,
+	.val_bits	= 8,
+	.max_register	= STUSB1600_REG_MAX,
+};
+
+static bool stusb160x_get_vconn(struct stusb160x *chip)
+{
+	u32 val;
+	int ret;
+
+	ret = regmap_read(chip->regmap, STUSB160X_CC_CAPABILITY_CTRL, &val);
+	if (ret) {
+		dev_err(chip->dev, "Unable to get Vconn status: %d\n", ret);
+		return false;
+	}
+
+	return !!FIELD_GET(STUSB160X_CC_VCONN_SUPPLY_EN, val);
+}
+
+static int stusb160x_set_vconn(struct stusb160x *chip, bool on)
+{
+	int ret;
+
+	/* Manage VCONN input supply */
+	if (chip->vconn_supply) {
+		if (on) {
+			ret = regulator_enable(chip->vconn_supply);
+			if (ret) {
+				dev_err(chip->dev,
+					"failed to enable vconn supply: %d\n",
+					ret);
+				return ret;
+			}
+		} else {
+			regulator_disable(chip->vconn_supply);
+		}
+	}
+
+	/* Manage VCONN monitoring and power path */
+	ret = regmap_update_bits(chip->regmap, STUSB160X_VCONN_MONITORING_CTRL,
+				 STUSB160X_VCONN_MONITORING_EN,
+				 on ? STUSB160X_VCONN_MONITORING_EN : 0);
+	if (ret)
+		goto vconn_reg_disable;
+
+	return 0;
+
+vconn_reg_disable:
+	if (chip->vconn_supply && on)
+		regulator_disable(chip->vconn_supply);
+
+	return ret;
+}
+
+static int stusb160x_get_connector_caps(struct stusb160x *chip,
+					struct device_node *connector)
+{
+	const char *str;
+	int ret;
+
+	ret = of_property_read_string(connector, "power-role", &str);
+	if (!ret) {
+		ret = typec_find_port_power_role(str);
+		if (ret < 0) {
+			dev_err(chip->dev, "unknown power-role: %s\n", str);
+			return ret;
+		}
+		chip->port_type = ret;
+	}
+
+	/* Skip source power opmode config for sink-only ports */
+	if (chip->port_type == TYPEC_PORT_SNK)
+		return 0;
+
+	ret = of_property_read_string(connector, "typec-power-opmode", &str);
+	if (!ret) {
+		ret = typec_find_pwr_opmode(str);
+		/* Power delivery not supported */
+		if (ret < 0 || ret == TYPEC_PWR_MODE_PD) {
+			dev_err(chip->dev, "unknown typec-power-opmode: %s\n", str);
+			return -EINVAL;
+		}
+		chip->pwr_opmode = ret;
+	}
+
+	return 0;
+}
+
+static void stusb160x_set_data_role(struct stusb160x *chip,
+				    enum typec_data_role data_role,
+				    bool attached)
+{
+	enum usb_role usb_role = USB_ROLE_NONE;
+
+	if (attached) {
+		if (data_role == TYPEC_HOST)
+			usb_role = USB_ROLE_HOST;
+		else
+			usb_role = USB_ROLE_DEVICE;
+	}
+
+	typec_set_role(chip->port, usb_role);
+}
+
+static int stusb160x_attach(struct stusb160x *chip, u32 status)
+{
+	int ret;
+
+	if ((STUSB160X_CC_POWER_ROLE(status) == TYPEC_SOURCE) &&
+	    chip->vdd_supply) {
+		ret = regulator_enable(chip->vdd_supply);
+		if (ret) {
+			dev_err(chip->dev,
+				"Failed to enable Vbus supply: %d\n", ret);
+			return ret;
+		}
+		chip->vbus_on = true;
+	}
+
+	typec_set_pwr_role(chip->port, STUSB160X_CC_POWER_ROLE(status));
+	stusb160x_set_data_role(chip, STUSB160X_CC_POWER_ROLE(status), true);
+
+	return 0;
+}
+
+static void stusb160x_detach(struct stusb160x *chip, u32 status)
+{
+	typec_set_pwr_role(chip->port, STUSB160X_CC_POWER_ROLE(status));
+	stusb160x_set_data_role(chip, STUSB160X_CC_POWER_ROLE(status), false);
+
+	if (chip->vbus_on) {
+		regulator_disable(chip->vdd_supply);
+		chip->vbus_on = false;
+	}
+}
+
+static irqreturn_t stusb160x_irq_handler(struct typec_port *port)
+{
+	struct stusb160x *chip = typec_get_drvdata(port);
+	u32 pending, trans, status;
+	int ret;
+
+	ret = regmap_read(chip->regmap, STUSB160X_ALERT_STATUS, &pending);
+	if (ret)
+		goto err;
+
+	if (pending & STUSB160X_CC_CONNECTION) {
+		ret = regmap_read(chip->regmap,
+				  STUSB160X_CC_CONNECTION_STATUS_TRANS, &trans);
+		if (ret)
+			goto err;
+		ret = regmap_read(chip->regmap,
+				  STUSB160X_CC_CONNECTION_STATUS, &status);
+		if (ret)
+			goto err;
+
+		if (trans & STUSB160X_CC_ATTACH_TRANS) {
+			if (status & STUSB160X_CC_ATTACH) {
+				ret = stusb160x_attach(chip, status);
+				if (ret)
+					goto err;
+			} else {
+				stusb160x_detach(chip, status);
+			}
+		}
+	}
+err:
+	return IRQ_HANDLED;
+}
+
+static int stusb160x_irq_init(struct stusb160x *chip)
+{
+	u32 status;
+	int ret;
+
+	ret = regmap_read(chip->regmap,
+			  STUSB160X_CC_CONNECTION_STATUS, &status);
+	if (ret)
+		return ret;
+
+	if (status & STUSB160X_CC_ATTACH) {
+		ret = stusb160x_attach(chip, status);
+		if (ret)
+			dev_err(chip->dev, "attach failed: %d\n", ret);
+	}
+
+	/* Unmask CC_CONNECTION events */
+	ret = regmap_write_bits(chip->regmap, STUSB160X_ALERT_STATUS_MASK_CTRL,
+				STUSB160X_CC_CONNECTION, 0);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int stusb160x_chip_init(struct stusb160x *chip)
+{
+	u32 val;
+	int ret;
+
+	/* Change the default Type-C power mode */
+	if (chip->port_type == TYPEC_PORT_SRC)
+		ret = regmap_update_bits(chip->regmap,
+					 STUSB160X_CC_POWER_MODE_CTRL,
+					 STUSB160X_CC_POWER_MODE,
+					 SOURCE_WITH_ACCESSORY);
+	else if (chip->port_type == TYPEC_PORT_SNK)
+		ret = regmap_update_bits(chip->regmap,
+					 STUSB160X_CC_POWER_MODE_CTRL,
+					 STUSB160X_CC_POWER_MODE,
+					 SINK_WITH_ACCESSORY);
+	else /* (chip->port_type == TYPEC_PORT_DRP) */
+		ret = regmap_update_bits(chip->regmap,
+					 STUSB160X_CC_POWER_MODE_CTRL,
+					 STUSB160X_CC_POWER_MODE,
+					 DUAL_WITH_ACCESSORY);
+	if (ret)
+		return ret;
+
+	if (chip->port_type == TYPEC_PORT_SNK)
+		goto skip_src;
+
+	/* Change the default Type-C Source power operation mode capability */
+	ret = regmap_update_bits(chip->regmap, STUSB160X_CC_CAPABILITY_CTRL,
+				 STUSB160X_CC_CURRENT_ADVERTISED,
+				 FIELD_PREP(STUSB160X_CC_CURRENT_ADVERTISED,
+					    chip->pwr_opmode));
+	if (ret)
+		return ret;
+
+	/* Manage Type-C Source Vconn supply */
+	if (stusb160x_get_vconn(chip)) {
+		ret = stusb160x_set_vconn(chip, true);
+		if (ret)
+			return ret;
+	}
+
+skip_src:
+	/* Mask all events interrupts - to be unmasked with interrupt support */
+	ret = regmap_update_bits(chip->regmap, STUSB160X_ALERT_STATUS_MASK_CTRL,
+				 STUSB160X_ALL_ALERTS, STUSB160X_ALL_ALERTS);
+	if (ret)
+		return ret;
+
+	/* Read status at least once to clear any stale interrupts */
+	regmap_read(chip->regmap, STUSB160X_ALERT_STATUS, &val);
+	regmap_read(chip->regmap, STUSB160X_CC_CONNECTION_STATUS_TRANS, &val);
+	regmap_read(chip->regmap, STUSB160X_MONITORING_STATUS_TRANS, &val);
+	regmap_read(chip->regmap, STUSB160X_HW_FAULT_STATUS_TRANS, &val);
+
+	return 0;
+}
+
+static const struct typec_operations stusb160x_typec_ops = {
+	.poll	= stusb160x_irq_handler,
+};
+
+static const struct of_device_id stusb160x_of_match[] = {
+	{ .compatible = "st,stusb1600", .data = &stusb1600_regmap_config},
+	{},
+};
+MODULE_DEVICE_TABLE(of, stusb160x_of_match);
+
+static int stusb160x_probe(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	const struct regmap_config *regmap_config;
+	struct stusb160x *chip;
+	struct device_node *node;
+	int ret;
+
+	chip = devm_kzalloc(&client->dev, sizeof(struct stusb160x), GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, chip);
+
+	regmap_config = device_get_match_data(dev);
+
+	chip->regmap = regmap_init_i2c(client, regmap_config);
+	if (IS_ERR(chip->regmap)) {
+		ret = PTR_ERR(chip->regmap);
+		dev_err(&client->dev,
+			"Failed to allocate register map:%d\n", ret);
+		return ret;
+	}
+
+	chip->dev = &client->dev;
+
+	chip->vsys_supply = regulator_get_optional(chip->dev, "vsys");
+	if (IS_ERR(chip->vsys_supply)) {
+		ret = PTR_ERR(chip->vsys_supply);
+		if (ret != -ENODEV)
+			return ret;
+		chip->vsys_supply = NULL;
+	}
+
+	chip->vdd_supply = regulator_get_optional(chip->dev, "vdd");
+	if (IS_ERR(chip->vdd_supply)) {
+		ret = PTR_ERR(chip->vdd_supply);
+		if (ret != -ENODEV)
+			return ret;
+		chip->vdd_supply = NULL;
+	}
+
+	chip->vconn_supply = regulator_get_optional(chip->dev, "vconn");
+	if (IS_ERR(chip->vconn_supply)) {
+		ret = PTR_ERR(chip->vconn_supply);
+		if (ret != -ENODEV)
+			return ret;
+		chip->vconn_supply = NULL;
+	}
+
+	node = of_get_child_by_name(client->dev.of_node, "connector");
+	if (!node)
+		return -ENODEV;
+
+	/*
+	 * When both VDD and VSYS power supplies are present, the low power
+	 * supply VSYS is selected when VSYS voltage is above 3.1 V.
+	 * Otherwise VDD is selected.
+	 */
+	if (chip->vdd_supply &&
+	    (!chip->vsys_supply ||
+	     (regulator_get_voltage(chip->vsys_supply) <= 3100000)))
+		chip->main_supply = chip->vdd_supply;
+	else
+		chip->main_supply = chip->vsys_supply;
+
+	if (chip->main_supply) {
+		ret = regulator_enable(chip->main_supply);
+		if (ret) {
+			dev_err(chip->dev,
+				"Failed to enable main supply: %d\n", ret);
+			goto fwnode_put;
+		}
+	}
+
+	ret = stusb160x_get_connector_caps(chip, node);
+	if (ret)
+		goto main_reg_disable;
+
+	ret = stusb160x_chip_init(chip);
+	if (ret) {
+		dev_err(chip->dev, "Failed to init port: %d\n", ret);
+		goto main_reg_disable;
+	}
+
+	chip->capability.driver_data = chip;
+	chip->capability.ops = &stusb160x_typec_ops;
+	chip->capability.of_node = node;
+
+	chip->port = typec_register_port(chip->dev, &chip->capability);
+	if (IS_ERR(chip->port)) {
+		ret = PTR_ERR(chip->port);
+		goto all_reg_disable;
+	}
+
+	stusb160x_irq_init(chip);
+
+	/*
+	 * If Source or Dual power role, need to enable VDD supply
+	 * providing Vbus if present. In case of interrupt support,
+	 * VDD supply will be dynamically managed upon attach/detach
+	 * interrupt.
+	 */
+	if (chip->port_type != TYPEC_PORT_SNK && chip->vdd_supply) {
+		ret = regulator_enable(chip->vdd_supply);
+		if (ret) {
+			dev_err(chip->dev,
+				"Failed to enable VDD supply: %d\n",
+				ret);
+			goto all_reg_disable;
+		}
+		chip->vbus_on = true;
+	}
+
+	regmap_register_cdev(chip->regmap, NULL);
+
+	return 0;
+
+all_reg_disable:
+	if (stusb160x_get_vconn(chip))
+		stusb160x_set_vconn(chip, false);
+main_reg_disable:
+	if (chip->main_supply)
+		regulator_disable(chip->main_supply);
+fwnode_put:
+
+	return ret;
+}
+
+static struct driver stusb160x_driver = {
+	.name		= "typec-stusb160x",
+	.of_match_table = stusb160x_of_match,
+	.probe		= stusb160x_probe,
+};
+device_i2c_driver(stusb160x_driver);
+
+MODULE_AUTHOR("Amelie Delaunay <amelie.delaunay@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics STUSB160x Type-C controller driver");
+MODULE_LICENSE("GPL v2");

-- 
2.47.3




^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/4] usb: otg: Add function to set dr_mode
  2026-04-20  9:02 ` [PATCH 1/4] usb: otg: Add function to set dr_mode Sascha Hauer
@ 2026-04-20 10:42   ` Ahmad Fatoum
  0 siblings, 0 replies; 10+ messages in thread
From: Ahmad Fatoum @ 2026-04-20 10:42 UTC (permalink / raw)
  To: Sascha Hauer, BAREBOX

Hi,

On 4/20/26 11:02 AM, Sascha Hauer wrote:
> So far we can only set the dr_mode on the command line. Add a function
> for it.
> 
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>  drivers/usb/otg/otgdev.c | 20 ++++++++++++++++++++
>  include/linux/usb/usb.h  |  1 +
>  2 files changed, 21 insertions(+)
> 
> diff --git a/drivers/usb/otg/otgdev.c b/drivers/usb/otg/otgdev.c
> index 5a86263430..50d8105be3 100644
> --- a/drivers/usb/otg/otgdev.c
> +++ b/drivers/usb/otg/otgdev.c
> @@ -74,6 +74,26 @@ int otg_device_get_mode(struct device *dev)
>  	return otg->cur_mode;
>  }
>  
> +int otg_device_set_dr_mode(struct device *dev, enum usb_dr_mode mode)
> +{
> +	struct otg_mode *otg;
> +	int ret;
> +
> +	if (dev->bus != &otg_bus_type)
> +		return -ENODEV;
> +
> +	otg = dev->priv;
> +
> +	ret = otg->set_mode_callback(otg->ctx, mode);
> +	if (ret)
> +		return ret;

This doesn't guard against switching from peripheral to host and back
unlike the param version, which only allows switching away from otg.

I think the existing logic should be moved into this function and
otg_set_mode changed to a wrapper around it.

> +
> +	otg->cur_mode = mode;
> +	otg->var_mode = mode;
> +
> +	return 0;
> +}
> +
>  int usb_register_otg_device(struct device *parent,
>  			    int (*set_mode)(void *ctx, enum usb_dr_mode mode), void *ctx)
>  {
> diff --git a/include/linux/usb/usb.h b/include/linux/usb/usb.h
> index c25f3d73c3..6aa9e55cc9 100644
> --- a/include/linux/usb/usb.h
> +++ b/include/linux/usb/usb.h
> @@ -477,6 +477,7 @@ int usb_register_otg_device(struct device *parent,
>  			    int (*set_mode)(void *ctx, enum usb_dr_mode mode), void *ctx);
>  
>  int otg_device_get_mode(struct device *dev);
> +int otg_device_set_dr_mode(struct device *dev, enum usb_dr_mode mode);
>  
>  extern struct bus_type otg_bus_type;
>  
> 

-- 
Pengutronix e.K.                  |                             |
Steuerwalder Str. 21              | http://www.pengutronix.de/  |
31137 Hildesheim, Germany         | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686  | Fax:   +49-5121-206917-5555 |




^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/4] usb: typec: wire USB role changes to OTG device
  2026-04-20  9:02 ` [PATCH 2/4] usb: typec: wire USB role changes to OTG device Sascha Hauer
@ 2026-04-20 11:08   ` Ahmad Fatoum
  2026-04-20 12:02     ` Sascha Hauer
  0 siblings, 1 reply; 10+ messages in thread
From: Ahmad Fatoum @ 2026-04-20 11:08 UTC (permalink / raw)
  To: Sascha Hauer, BAREBOX; +Cc: Claude Sonnet 4.6

Hi,

On 4/20/26 11:02 AM, Sascha Hauer wrote:
> When a Type-C controller reports a USB role change via typec_set_role(),
> find the associated OTG device via the OF graph and set its dr_mode
> accordingly.
> 
> Since the Type-C controller may probe before the OTG device registers,
> a late_initcall sweeps all known ports and applies any role that was not
> yet forwarded.
> 
> Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>  drivers/usb/typec/class.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 60 insertions(+)
> 
> diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
> index e03eaccbb9..b88e1c1e46 100644
> --- a/drivers/usb/typec/class.c
> +++ b/drivers/usb/typec/class.c
> @@ -8,10 +8,15 @@
>  
>  #include <module.h>
>  #include <driver.h>
> +#include <init.h>
>  #include <linux/kernel.h>
> +#include <linux/list.h>
>  #include <linux/usb/role.h>
>  #include <linux/usb/typec.h>
>  #include <linux/usb/typec_altmode.h>
> +#include <linux/usb/usb.h>
> +#include <linux/device/bus.h>
> +#include <of_graph.h>
>  #include <param.h>
>  
>  enum typec_param_accessory {
> @@ -22,12 +27,16 @@ enum typec_param_accessory {
>  
>  struct typec_port {
>  	struct device dev;
> +	struct list_head list;
>  	const struct typec_operations *ops;
>  	int pwr_role;		/* enum typec_role */
>  	int usb_role;		/* enum usb_role role */
>  	int accessory;		/* enum typec_param_accessory */
> +	bool otg_role_applied;
>  };
>  
> +static LIST_HEAD(typec_port_list);
> +
>  /**
>   * typec_set_pwr_role - Report power role change
>   * @port: The USB Type-C Port where the role was changed
> @@ -68,6 +77,41 @@ int typec_set_mode(struct typec_port *port, int mode)
>  }
>  EXPORT_SYMBOL_GPL(typec_set_mode);
>  
> +static bool typec_apply_otg_role(struct typec_port *port)
> +{
> +	struct device_node *connector = port->dev.of_node;
> +	struct device_node *ep, *remote;
> +	struct device *dev;
> +	enum usb_dr_mode dr_mode;
> +	bool applied = false;
> +
> +	if (!IS_ENABLED(CONFIG_USB_OTGDEV) || !connector)
> +		return false;
> +
> +	if (port->usb_role == USB_ROLE_HOST)
> +		dr_mode = USB_DR_MODE_HOST;
> +	else if (port->usb_role == USB_ROLE_DEVICE)
> +		dr_mode = USB_DR_MODE_PERIPHERAL;
> +	else
> +		return false;
> +
> +	for_each_endpoint_of_node(connector, ep) {
> +		remote = of_graph_get_remote_port_parent(ep);
> +		if (!remote)
> +			continue;
> +
> +		bus_for_each_device(&otg_bus_type, dev) {
> +			if (dev->parent && dev->parent->of_node == remote) {

I believe board code could've set the mode before we come here.

Also, I think there must be a way to opt out of this.

Let's assume you load barebox via USB on a Type C port. You may not be
able to yank the cable away fast enough before barebox does the one-way
otg -> peripheral transition.

> +				otg_device_set_dr_mode(dev, dr_mode);
> +				applied = true;
> +				break;
> +			}
> +		}
> +	}
> +
> +	return applied;
> +}
> +
>  /**
>   * typec_set_role - Set USB role for a Type-C connector
>   * @port: USB Type-C connector
> @@ -79,10 +123,24 @@ EXPORT_SYMBOL_GPL(typec_set_mode);
>  int typec_set_role(struct typec_port *port, enum usb_role role)
>  {
>  	port->usb_role = role;
> +	port->otg_role_applied = typec_apply_otg_role(port);
>  	return 0;
>  }
>  EXPORT_SYMBOL_GPL(typec_set_role);
>  
> +static int typec_apply_otg_roles(void)
> +{
> +	struct typec_port *port;
> +
> +	list_for_each_entry(port, &typec_port_list, list) {
> +		if (!port->otg_role_applied)
> +			port->otg_role_applied = typec_apply_otg_role(port);
> +	}
> +
> +	return 0;
> +}
> +late_initcall(typec_apply_otg_roles);

Does postenvironment not make more sense, so the environment can
override this?

> +
>  /**
>   * typec_get_drvdata - Return private driver data pointer
>   * @port: USB Type-C port
> @@ -165,6 +223,8 @@ struct typec_port *typec_register_port(struct device *parent,
>  	if (dev->of_node)
>  		dev->of_node->dev = dev;
>  
> +	list_add_tail(&port->list, &typec_port_list);
> +
>  	dev_add_param_enum(dev, "usb_role", param_set_readonly, typec_param_update,
>  			   &port->usb_role, usb_role_names,
>  			   ARRAY_SIZE(usb_role_names), port);
> 

-- 
Pengutronix e.K.                  |                             |
Steuerwalder Str. 21              | http://www.pengutronix.de/  |
31137 Hildesheim, Germany         | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686  | Fax:   +49-5121-206917-5555 |




^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 4/4] USB: typec: Add STUSB160x driver
  2026-04-20  9:02 ` [PATCH 4/4] USB: typec: Add STUSB160x driver Sascha Hauer
@ 2026-04-20 11:14   ` Ahmad Fatoum
  2026-04-20 11:30     ` Sascha Hauer
  0 siblings, 1 reply; 10+ messages in thread
From: Ahmad Fatoum @ 2026-04-20 11:14 UTC (permalink / raw)
  To: Sascha Hauer, BAREBOX

Hi,

On 4/20/26 11:02 AM, Sascha Hauer wrote:
> --- /dev/null
> +++ b/drivers/usb/typec/stusb160x.c
> @@ -0,0 +1,572 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// SPDX-Comment: Origin-URL: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/usb/typec/stusb160x.c?id=82375469755662b9910a22da14027cbef2bca666/*

Invalid link. You may want to remove /* at the end.

> +	node = of_get_child_by_name(client->dev.of_node, "connector");
> +	if (!node)
> +		return -ENODEV;

Add extra error message here or return another error code that's not
silently swallowed up?


Cheers,
Ahmad

-- 
Pengutronix e.K.                  |                             |
Steuerwalder Str. 21              | http://www.pengutronix.de/  |
31137 Hildesheim, Germany         | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686  | Fax:   +49-5121-206917-5555 |




^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 4/4] USB: typec: Add STUSB160x driver
  2026-04-20 11:14   ` Ahmad Fatoum
@ 2026-04-20 11:30     ` Sascha Hauer
  0 siblings, 0 replies; 10+ messages in thread
From: Sascha Hauer @ 2026-04-20 11:30 UTC (permalink / raw)
  To: Ahmad Fatoum; +Cc: BAREBOX

On Mon, Apr 20, 2026 at 01:14:51PM +0200, Ahmad Fatoum wrote:
> Hi,
> 
> On 4/20/26 11:02 AM, Sascha Hauer wrote:
> > --- /dev/null
> > +++ b/drivers/usb/typec/stusb160x.c
> > @@ -0,0 +1,572 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +// SPDX-Comment: Origin-URL: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/usb/typec/stusb160x.c?id=82375469755662b9910a22da14027cbef2bca666/*
> 
> Invalid link. You may want to remove /* at the end.

Missing newline, /* should go to the next line.

> 
> > +	node = of_get_child_by_name(client->dev.of_node, "connector");
> > +	if (!node)
> > +		return -ENODEV;
> 
> Add extra error message here or return another error code that's not
> silently swallowed up?

Yes.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/4] usb: typec: wire USB role changes to OTG device
  2026-04-20 11:08   ` Ahmad Fatoum
@ 2026-04-20 12:02     ` Sascha Hauer
  0 siblings, 0 replies; 10+ messages in thread
From: Sascha Hauer @ 2026-04-20 12:02 UTC (permalink / raw)
  To: Ahmad Fatoum; +Cc: BAREBOX, Claude Sonnet 4.6

On Mon, Apr 20, 2026 at 01:08:41PM +0200, Ahmad Fatoum wrote:
> > +static bool typec_apply_otg_role(struct typec_port *port)
> > +{
> > +	struct device_node *connector = port->dev.of_node;
> > +	struct device_node *ep, *remote;
> > +	struct device *dev;
> > +	enum usb_dr_mode dr_mode;
> > +	bool applied = false;
> > +
> > +	if (!IS_ENABLED(CONFIG_USB_OTGDEV) || !connector)
> > +		return false;
> > +
> > +	if (port->usb_role == USB_ROLE_HOST)
> > +		dr_mode = USB_DR_MODE_HOST;
> > +	else if (port->usb_role == USB_ROLE_DEVICE)
> > +		dr_mode = USB_DR_MODE_PERIPHERAL;
> > +	else
> > +		return false;
> > +
> > +	for_each_endpoint_of_node(connector, ep) {
> > +		remote = of_graph_get_remote_port_parent(ep);
> > +		if (!remote)
> > +			continue;
> > +
> > +		bus_for_each_device(&otg_bus_type, dev) {
> > +			if (dev->parent && dev->parent->of_node == remote) {
> 
> I believe board code could've set the mode before we come here.
> 
> Also, I think there must be a way to opt out of this.
> 
> Let's assume you load barebox via USB on a Type C port. You may not be
> able to yank the cable away fast enough before barebox does the one-way
> otg -> peripheral transition.

Should have sent this as RFC, because these are the questions I had as
well. Ideally the otg->host or otg->device transition shouldn't be
oneway, but that might open a can of worms.

> > +late_initcall(typec_apply_otg_roles);
> 
> Does postenvironment not make more sense, so the environment can
> override this?

Sounds good, but then you don't have a chance anymore to do something
with the device from board code.

Ok, so we need something to opt in/out from that mechanism and also
something for board code to call the role transition earlier when
needed.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2026-04-20 12:02 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-04-20  9:02 [PATCH 0/4] usb: typec: STUSB160x support Sascha Hauer
2026-04-20  9:02 ` [PATCH 1/4] usb: otg: Add function to set dr_mode Sascha Hauer
2026-04-20 10:42   ` Ahmad Fatoum
2026-04-20  9:02 ` [PATCH 2/4] usb: typec: wire USB role changes to OTG device Sascha Hauer
2026-04-20 11:08   ` Ahmad Fatoum
2026-04-20 12:02     ` Sascha Hauer
2026-04-20  9:02 ` [PATCH 3/4] usb: typec: add typec_find_port_power_role() and typec_find_pwr_opmode() Sascha Hauer
2026-04-20  9:02 ` [PATCH 4/4] USB: typec: Add STUSB160x driver Sascha Hauer
2026-04-20 11:14   ` Ahmad Fatoum
2026-04-20 11:30     ` Sascha Hauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox