mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v2 0/3] drm: bridge: anx7625: implement Type-C support
@ 2026-01-21 10:15 Dmitry Baryshkov
  2026-01-21 10:15 ` [PATCH v2 1/3] dt-bindings: drm/bridge: anx7625: describe Type-C connector Dmitry Baryshkov
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Dmitry Baryshkov @ 2026-01-21 10:15 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Xin Ji, Heikki Krogerus,
	Greg Kroah-Hartman
  Cc: dri-devel, devicetree, linux-usb, linux-arm-msm, linux-kernel

ANX7625 can be used to mux converted video stream with the USB signals
on a Type-C connector. Provide minimal Type-C support necessary for
ANX7625 to register the Type-C port device and properly respond to data
/ power role events from the Type-C partner.

Notes:
- I'm not 100% happy having Type-C code in the DRM subtree. Should I use
  AUX device and to move Type-C-related code to drivers/usb/typec?

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
Changes in v2:
- Reworked handling of status bits, removing code duplication.
- Enabled setting data role through the ANX7625 messages.
- Link to v1: https://lore.kernel.org/r/20251126-anx7625-typec-v1-0-22b30f846a88@oss.qualcomm.com

---
Dmitry Baryshkov (3):
      dt-bindings: drm/bridge: anx7625: describe Type-C connector
      drm: bridge: anx7625: implement minimal Type-C support
      drm: bridge: anx7625: implement message sending

 .../bindings/display/bridge/analogix,anx7625.yaml  |  98 ++++++++-
 drivers/gpu/drm/bridge/analogix/Kconfig            |   1 +
 drivers/gpu/drm/bridge/analogix/anx7625.c          | 223 ++++++++++++++++++++-
 drivers/gpu/drm/bridge/analogix/anx7625.h          |  34 +++-
 4 files changed, 345 insertions(+), 11 deletions(-)
---
base-commit: 873e63546ef0e4c612f57a097e4fbcd5b2f4abb6
change-id: 20251126-anx7625-typec-07d455f423da

Best regards,
-- 
With best wishes
Dmitry


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

* [PATCH v2 1/3] dt-bindings: drm/bridge: anx7625: describe Type-C connector
  2026-01-21 10:15 [PATCH v2 0/3] drm: bridge: anx7625: implement Type-C support Dmitry Baryshkov
@ 2026-01-21 10:15 ` Dmitry Baryshkov
  2026-01-21 16:23   ` Rob Herring (Arm)
  2026-01-21 10:15 ` [PATCH v2 2/3] drm: bridge: anx7625: implement minimal Type-C support Dmitry Baryshkov
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 7+ messages in thread
From: Dmitry Baryshkov @ 2026-01-21 10:15 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Xin Ji, Heikki Krogerus,
	Greg Kroah-Hartman
  Cc: dri-devel, devicetree, linux-usb, linux-arm-msm, linux-kernel

ANX7625 can be used to mux converted video stream with the USB signals
on a Type-C connector. Describe the optional connector subnode, make it
exclusive with the AUX bus and port@1 as it is impossible to have both
eDP panel and USB-C connector.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
 .../bindings/display/bridge/analogix,anx7625.yaml  | 98 +++++++++++++++++++++-
 1 file changed, 97 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml b/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml
index a1ed1004651b..6ad466952c02 100644
--- a/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml
+++ b/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml
@@ -85,6 +85,11 @@ properties:
   aux-bus:
     $ref: /schemas/display/dp-aux-bus.yaml#
 
+  connector:
+    type: object
+    $ref: /schemas/connector/usb-connector.yaml#
+    unevaluatedProperties: false
+
   ports:
     $ref: /schemas/graph.yaml#/properties/ports
 
@@ -117,7 +122,6 @@ properties:
 
     required:
       - port@0
-      - port@1
 
 required:
   - compatible
@@ -127,6 +131,28 @@ required:
   - vdd33-supply
   - ports
 
+allOf:
+  - if:
+      required:
+        - aux-bus
+        - connector
+    then:
+      false
+
+  - if:
+      required:
+        - connector
+    then:
+      properties:
+        ports:
+          properties:
+            port@1: false
+    else:
+      properties:
+        ports:
+          required:
+            - port@1
+
 additionalProperties: false
 
 examples:
@@ -185,3 +211,73 @@ examples:
             };
         };
     };
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        encoder@58 {
+            compatible = "analogix,anx7625";
+            reg = <0x58>;
+            enable-gpios = <&pio 45 GPIO_ACTIVE_HIGH>;
+            reset-gpios = <&pio 73 GPIO_ACTIVE_HIGH>;
+            vdd10-supply = <&pp1000_mipibrdg>;
+            vdd18-supply = <&pp1800_mipibrdg>;
+            vdd33-supply = <&pp3300_mipibrdg>;
+            analogix,audio-enable;
+            analogix,lane0-swing = /bits/ 8 <0x14 0x54 0x64 0x74>;
+            analogix,lane1-swing = /bits/ 8 <0x14 0x54 0x64 0x74>;
+
+            connector {
+                compatible = "usb-c-connector";
+                power-role = "dual";
+                data-role = "dual";
+                vbus-supply = <&vbus_reg>;
+
+                ports {
+                    #address-cells = <1>;
+                    #size-cells = <0>;
+
+                    port@0 {
+                        reg = <0>;
+
+                        endpoint {
+                            remote-endpoint = <&usb_hs>;
+                        };
+                    };
+
+                    port@1 {
+                        reg = <1>;
+
+                        endpoint {
+                            remote-endpoint = <&usb_ss>;
+                        };
+                    };
+
+                    port@2 {
+                        reg = <2>;
+
+                        endpoint {
+                            remote-endpoint = <&usb_sbu>;
+                        };
+                    };
+                };
+            };
+
+            ports {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                port@0 {
+                    reg = <0>;
+                    endpoint {
+                        remote-endpoint = <&mipi_dsi>;
+                        bus-type = <7>;
+                        data-lanes = <0 1 2 3>;
+                    };
+                };
+            };
+        };
+    };

-- 
2.47.3


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

* [PATCH v2 2/3] drm: bridge: anx7625: implement minimal Type-C support
  2026-01-21 10:15 [PATCH v2 0/3] drm: bridge: anx7625: implement Type-C support Dmitry Baryshkov
  2026-01-21 10:15 ` [PATCH v2 1/3] dt-bindings: drm/bridge: anx7625: describe Type-C connector Dmitry Baryshkov
@ 2026-01-21 10:15 ` Dmitry Baryshkov
  2026-01-21 10:15 ` [PATCH v2 3/3] drm: bridge: anx7625: implement message sending Dmitry Baryshkov
  2026-02-07 10:40 ` [PATCH v2 0/3] drm: bridge: anx7625: implement Type-C support Dmitry Baryshkov
  3 siblings, 0 replies; 7+ messages in thread
From: Dmitry Baryshkov @ 2026-01-21 10:15 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Xin Ji, Heikki Krogerus,
	Greg Kroah-Hartman
  Cc: dri-devel, devicetree, linux-usb, linux-arm-msm, linux-kernel

ANX7625 can be used as a USB-C controller, handling USB and DP data
streams. Provide minimal Type-C support necessary for ANX7625 to
register the Type-C port device and properly respond to data / power
role events from the Type-C partner.

While ANX7625 provides TCPCI interface, using it would circumvent the
on-chip running firmware. Analogix recommended using the higher-level
interface instead of TCPCI.

Reviewed-by: Xin Ji <xji@analogixsemi.com>
Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
 drivers/gpu/drm/bridge/analogix/Kconfig   |   1 +
 drivers/gpu/drm/bridge/analogix/anx7625.c | 155 ++++++++++++++++++++++++++++--
 drivers/gpu/drm/bridge/analogix/anx7625.h |  22 ++++-
 3 files changed, 168 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/Kconfig b/drivers/gpu/drm/bridge/analogix/Kconfig
index 4846b2e9be7c..f3448b0631fe 100644
--- a/drivers/gpu/drm/bridge/analogix/Kconfig
+++ b/drivers/gpu/drm/bridge/analogix/Kconfig
@@ -34,6 +34,7 @@ config DRM_ANALOGIX_ANX7625
 	tristate "Analogix Anx7625 MIPI to DP interface support"
 	depends on DRM
 	depends on OF
+	depends on TYPEC || !TYPEC
 	select DRM_DISPLAY_DP_HELPER
 	select DRM_DISPLAY_HDCP_HELPER
 	select DRM_DISPLAY_HELPER
diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c
index 4e49e4f28d55..8dc6e3b16968 100644
--- a/drivers/gpu/drm/bridge/analogix/anx7625.c
+++ b/drivers/gpu/drm/bridge/analogix/anx7625.c
@@ -3,6 +3,7 @@
  * Copyright(c) 2020, Analogix Semiconductor. All rights reserved.
  *
  */
+#include <linux/cleanup.h>
 #include <linux/gcd.h>
 #include <linux/gpio/consumer.h>
 #include <linux/i2c.h>
@@ -15,6 +16,9 @@
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <linux/types.h>
+#include <linux/usb.h>
+#include <linux/usb/pd.h>
+#include <linux/usb/role.h>
 #include <linux/workqueue.h>
 
 #include <linux/of_graph.h>
@@ -1325,7 +1329,7 @@ static int anx7625_read_hpd_gpio_config_status(struct anx7625_data *ctx)
 static void anx7625_disable_pd_protocol(struct anx7625_data *ctx)
 {
 	struct device *dev = ctx->dev;
-	int ret, val;
+	int ret;
 
 	/* Reset main ocm */
 	ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, 0x88, 0x40);
@@ -1339,6 +1343,11 @@ static void anx7625_disable_pd_protocol(struct anx7625_data *ctx)
 		DRM_DEV_DEBUG_DRIVER(dev, "disable PD feature fail.\n");
 	else
 		DRM_DEV_DEBUG_DRIVER(dev, "disable PD feature succeeded.\n");
+}
+
+static void anx7625_configure_hpd(struct anx7625_data *ctx)
+{
+	int val;
 
 	/*
 	 * Make sure the HPD GPIO already be configured after OCM release before
@@ -1369,7 +1378,9 @@ static int anx7625_ocm_loading_check(struct anx7625_data *ctx)
 	if ((ret & FLASH_LOAD_STA_CHK) != FLASH_LOAD_STA_CHK)
 		return -ENODEV;
 
-	anx7625_disable_pd_protocol(ctx);
+	if (!ctx->typec_port)
+		anx7625_disable_pd_protocol(ctx);
+	anx7625_configure_hpd(ctx);
 
 	DRM_DEV_DEBUG_DRIVER(dev, "Firmware ver %02x%02x,",
 			     anx7625_reg_read(ctx,
@@ -1472,6 +1483,107 @@ static void anx7625_start_dp_work(struct anx7625_data *ctx)
 	DRM_DEV_DEBUG_DRIVER(dev, "Secure OCM version=%02x\n", ret);
 }
 
+#if IS_REACHABLE(CONFIG_TYPEC)
+static void anx7625_typec_set_orientation(struct anx7625_data *ctx)
+{
+	u32 val = anx7625_reg_read(ctx, ctx->i2c.rx_p0_client, SYSTEM_STSTUS);
+
+	if (val & (CC1_RP | CC1_RD))
+		typec_set_orientation(ctx->typec_port, TYPEC_ORIENTATION_NORMAL);
+	else if (val & (CC2_RP | CC2_RD))
+		typec_set_orientation(ctx->typec_port, TYPEC_ORIENTATION_REVERSE);
+	else
+		typec_set_orientation(ctx->typec_port, TYPEC_ORIENTATION_NONE);
+}
+
+static void anx7625_typec_set_status(struct anx7625_data *ctx,
+				     unsigned int intr_status,
+				     unsigned int intr_vector)
+{
+	if (intr_vector & CC_STATUS)
+		anx7625_typec_set_orientation(ctx);
+	if (intr_vector & DATA_ROLE_STATUS) {
+		enum typec_data_role data_role = (intr_status & DATA_ROLE_STATUS) ?
+			TYPEC_HOST : TYPEC_DEVICE;
+		usb_role_switch_set_role(ctx->role_sw,
+					 (intr_status & DATA_ROLE_STATUS) ?
+					 USB_ROLE_HOST : USB_ROLE_DEVICE);
+		typec_set_data_role(ctx->typec_port, data_role);
+		ctx->typec_data_role = data_role;
+	}
+	if (intr_vector & VBUS_STATUS)
+		typec_set_pwr_role(ctx->typec_port,
+				   (intr_status & VBUS_STATUS) ?
+				   TYPEC_SOURCE : TYPEC_SINK);
+	if (intr_vector & VCONN_STATUS)
+		typec_set_vconn_role(ctx->typec_port,
+				     (intr_status & VCONN_STATUS) ?
+				     TYPEC_SOURCE : TYPEC_SINK);
+}
+
+static int anx7625_typec_register(struct anx7625_data *ctx)
+{
+	struct typec_capability typec_cap = { };
+	struct fwnode_handle *fwnode __free(fwnode_handle) =
+		device_get_named_child_node(ctx->dev, "connector");
+	u32 val;
+	int ret;
+
+	if (!fwnode)
+		return 0;
+
+	ret = typec_get_fw_cap(&typec_cap, fwnode);
+	if (ret < 0)
+		return ret;
+
+	typec_cap.revision = 0x0120;
+	typec_cap.pd_revision = 0x0300;
+	typec_cap.usb_capability = USB_CAPABILITY_USB2 | USB_CAPABILITY_USB3;
+	typec_cap.orientation_aware = true;
+
+	typec_cap.driver_data = ctx;
+
+	ctx->typec_port = typec_register_port(ctx->dev, &typec_cap);
+	if (IS_ERR(ctx->typec_port))
+		return PTR_ERR(ctx->typec_port);
+
+	ctx->role_sw = fwnode_usb_role_switch_get(fwnode);
+	if (IS_ERR(ctx->role_sw)) {
+		typec_unregister_port(ctx->typec_port);
+		return PTR_ERR(ctx->role_sw);
+	}
+
+	val = anx7625_reg_read(ctx, ctx->i2c.rx_p0_client, SYSTEM_STSTUS);
+
+	anx7625_typec_set_status(ctx, val,
+				 CC_STATUS | DATA_ROLE_STATUS |
+				 VBUS_STATUS | VCONN_STATUS);
+
+	return 0;
+}
+
+static void anx7625_typec_unregister(struct anx7625_data *ctx)
+{
+	usb_role_switch_put(ctx->role_sw);
+	typec_unregister_port(ctx->typec_port);
+}
+#else
+static void anx7625_typec_set_status(struct anx7625_data *ctx,
+				     unsigned int intr_status,
+				     unsigned int intr_vector)
+{
+}
+
+static int anx7625_typec_register(struct anx7625_data *ctx)
+{
+	return 0;
+}
+
+static void anx7625_typec_unregister(struct anx7625_data *ctx)
+{
+}
+#endif
+
 static int anx7625_read_hpd_status_p0(struct anx7625_data *ctx)
 {
 	return anx7625_reg_read(ctx, ctx->i2c.rx_p0_client, SYSTEM_STSTUS);
@@ -1566,7 +1678,7 @@ static void dp_hpd_change_handler(struct anx7625_data *ctx, bool on)
 	}
 }
 
-static int anx7625_hpd_change_detect(struct anx7625_data *ctx)
+static int anx7625_intr_status(struct anx7625_data *ctx)
 {
 	int intr_vector, status;
 	struct device *dev = ctx->dev;
@@ -1593,9 +1705,6 @@ static int anx7625_hpd_change_detect(struct anx7625_data *ctx)
 		return status;
 	}
 
-	if (!(intr_vector & HPD_STATUS_CHANGE))
-		return -ENOENT;
-
 	status = anx7625_reg_read(ctx, ctx->i2c.rx_p0_client,
 				  SYSTEM_STSTUS);
 	if (status < 0) {
@@ -1604,6 +1713,12 @@ static int anx7625_hpd_change_detect(struct anx7625_data *ctx)
 	}
 
 	DRM_DEV_DEBUG_DRIVER(dev, "0x7e:0x45=%x\n", status);
+
+	anx7625_typec_set_status(ctx, status, intr_vector);
+
+	if (!(intr_vector & HPD_STATUS))
+		return -ENOENT;
+
 	dp_hpd_change_handler(ctx, status & HPD_STATUS);
 
 	return 0;
@@ -1622,7 +1737,7 @@ static void anx7625_work_func(struct work_struct *work)
 		return;
 	}
 
-	event = anx7625_hpd_change_detect(ctx);
+	event = anx7625_intr_status(ctx);
 
 	mutex_unlock(&ctx->lock);
 
@@ -2741,11 +2856,29 @@ static int anx7625_i2c_probe(struct i2c_client *client)
 	}
 
 	if (!platform->pdata.low_power_mode) {
-		anx7625_disable_pd_protocol(platform);
+		struct fwnode_handle *fwnode;
+
+		fwnode = device_get_named_child_node(dev, "connector");
+		if (fwnode)
+			fwnode_handle_put(fwnode);
+		else
+			anx7625_disable_pd_protocol(platform);
+
+		anx7625_configure_hpd(platform);
+
 		pm_runtime_get_sync(dev);
 		_anx7625_hpd_polling(platform, 5000 * 100);
 	}
 
+	if (platform->pdata.intp_irq)
+		anx7625_reg_write(platform, platform->i2c.rx_p0_client,
+				  INTERFACE_CHANGE_INT_MASK, 0);
+
+	/* After getting runtime handle */
+	ret = anx7625_typec_register(platform);
+	if (ret)
+		goto pm_suspend;
+
 	/* Add work function */
 	if (platform->pdata.intp_irq) {
 		enable_irq(platform->pdata.intp_irq);
@@ -2759,6 +2892,10 @@ static int anx7625_i2c_probe(struct i2c_client *client)
 
 	return 0;
 
+pm_suspend:
+	if (!platform->pdata.low_power_mode)
+		pm_runtime_put_sync_suspend(&client->dev);
+
 free_wq:
 	if (platform->workqueue)
 		destroy_workqueue(platform->workqueue);
@@ -2774,6 +2911,8 @@ static void anx7625_i2c_remove(struct i2c_client *client)
 {
 	struct anx7625_data *platform = i2c_get_clientdata(client);
 
+	anx7625_typec_unregister(platform);
+
 	drm_bridge_remove(&platform->bridge);
 
 	if (platform->pdata.intp_irq)
diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.h b/drivers/gpu/drm/bridge/analogix/anx7625.h
index eb5580f1ab2f..a18561c213af 100644
--- a/drivers/gpu/drm/bridge/analogix/anx7625.h
+++ b/drivers/gpu/drm/bridge/analogix/anx7625.h
@@ -51,9 +51,21 @@
 #define INTR_RECEIVED_MSG BIT(5)
 
 #define SYSTEM_STSTUS 0x45
+#define INTERFACE_CHANGE_INT_MASK 0x43
 #define INTERFACE_CHANGE_INT 0x44
-#define HPD_STATUS_CHANGE 0x80
-#define HPD_STATUS 0x80
+#define VCONN_STATUS	BIT(2)
+#define VBUS_STATUS	BIT(3)
+#define CC_STATUS	BIT(4)
+#define DATA_ROLE_STATUS	BIT(5)
+#define HPD_STATUS	BIT(7)
+
+#define NEW_CC_STATUS 0x46
+#define CC1_RD                  BIT(0)
+#define CC1_RA                  BIT(1)
+#define CC1_RP			(BIT(2) | BIT(3))
+#define CC2_RD                  BIT(4)
+#define CC2_RA                  BIT(5)
+#define CC2_RP			(BIT(6) | BIT(7))
 
 /******** END of I2C Address 0x58 ********/
 
@@ -447,9 +459,15 @@ struct anx7625_i2c_client {
 	struct i2c_client *tcpc_client;
 };
 
+struct typec_port;
+struct usb_role_switch;
+
 struct anx7625_data {
 	struct anx7625_platform_data pdata;
 	struct platform_device *audio_pdev;
+	struct typec_port *typec_port;
+	struct usb_role_switch *role_sw;
+	int typec_data_role;
 	int hpd_status;
 	int hpd_high_cnt;
 	int dp_en;

-- 
2.47.3


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

* [PATCH v2 3/3] drm: bridge: anx7625: implement message sending
  2026-01-21 10:15 [PATCH v2 0/3] drm: bridge: anx7625: implement Type-C support Dmitry Baryshkov
  2026-01-21 10:15 ` [PATCH v2 1/3] dt-bindings: drm/bridge: anx7625: describe Type-C connector Dmitry Baryshkov
  2026-01-21 10:15 ` [PATCH v2 2/3] drm: bridge: anx7625: implement minimal Type-C support Dmitry Baryshkov
@ 2026-01-21 10:15 ` Dmitry Baryshkov
  2026-01-22  1:40   ` Xin Ji
  2026-02-07 10:40 ` [PATCH v2 0/3] drm: bridge: anx7625: implement Type-C support Dmitry Baryshkov
  3 siblings, 1 reply; 7+ messages in thread
From: Dmitry Baryshkov @ 2026-01-21 10:15 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Xin Ji, Heikki Krogerus,
	Greg Kroah-Hartman
  Cc: dri-devel, devicetree, linux-usb, linux-arm-msm, linux-kernel

Swapping the data role requires sending the message to the other USB-C
side. Implement sending these messages through the OCM. The code is
largely based on the anx7411.c USB-C driver.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
 drivers/gpu/drm/bridge/analogix/anx7625.c | 68 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/bridge/analogix/anx7625.h | 12 ++++++
 2 files changed, 80 insertions(+)

diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c
index 8dc6e3b16968..c43519097a45 100644
--- a/drivers/gpu/drm/bridge/analogix/anx7625.c
+++ b/drivers/gpu/drm/bridge/analogix/anx7625.c
@@ -1484,6 +1484,73 @@ static void anx7625_start_dp_work(struct anx7625_data *ctx)
 }
 
 #if IS_REACHABLE(CONFIG_TYPEC)
+static u8 anx7625_checksum(u8 *buf, u8 len)
+{
+	u8 ret = 0;
+	u8 i;
+
+	for (i = 0; i < len; i++)
+		ret += buf[i];
+
+	return ret;
+}
+
+static int anx7625_read_msg_ctrl_status(struct anx7625_data *ctx)
+{
+	return anx7625_reg_read(ctx, ctx->i2c.rx_p0_client, CMD_SEND_BUF);
+}
+
+static int anx7625_wait_msg_empty(struct anx7625_data *ctx)
+{
+	int val;
+
+	return readx_poll_timeout(anx7625_read_msg_ctrl_status, ctx,
+				  val, (val < 0) || (val == 0),
+				  2000, 2000 * 150);
+}
+
+static int anx7625_send_msg(struct anx7625_data *ctx, u8 type, u8 *buf, u8 size)
+{
+	struct fw_msg *msg = &ctx->send_msg;
+	u8 crc;
+	int ret;
+
+	size = min_t(u8, size, (u8)MAX_BUF_LEN);
+	memcpy(msg->buf, buf, size);
+	msg->msg_type = type;
+
+	/* msg len equals buffer length + msg_type */
+	msg->msg_len = size + 1;
+
+	crc = anx7625_checksum((u8 *)msg, size + HEADER_LEN);
+	msg->buf[size] = 0 - crc;
+
+	ret = anx7625_wait_msg_empty(ctx);
+	if (ret)
+		return ret;
+
+	ret = anx7625_reg_block_write(ctx, ctx->i2c.rx_p0_client,
+				      CMD_SEND_BUF + 1, size + HEADER_LEN,
+				      &msg->msg_type);
+	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, CMD_SEND_BUF,
+				 msg->msg_len);
+	return ret;
+}
+
+static int anx7625_typec_dr_set(struct typec_port *port, enum typec_data_role role)
+{
+	struct anx7625_data *ctx = typec_get_drvdata(port);
+
+	if (role == ctx->typec_data_role)
+		return 0;
+
+	return anx7625_send_msg(ctx, 0x11, NULL, 0);
+}
+
+static const struct typec_operations anx7625_typec_ops = {
+	.dr_set = anx7625_typec_dr_set,
+};
+
 static void anx7625_typec_set_orientation(struct anx7625_data *ctx)
 {
 	u32 val = anx7625_reg_read(ctx, ctx->i2c.rx_p0_client, SYSTEM_STSTUS);
@@ -1542,6 +1609,7 @@ static int anx7625_typec_register(struct anx7625_data *ctx)
 	typec_cap.orientation_aware = true;
 
 	typec_cap.driver_data = ctx;
+	typec_cap.ops = &anx7625_typec_ops;
 
 	ctx->typec_port = typec_register_port(ctx->dev, &typec_cap);
 	if (IS_ERR(ctx->typec_port))
diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.h b/drivers/gpu/drm/bridge/analogix/anx7625.h
index a18561c213af..957d234ec07c 100644
--- a/drivers/gpu/drm/bridge/analogix/anx7625.h
+++ b/drivers/gpu/drm/bridge/analogix/anx7625.h
@@ -67,6 +67,9 @@
 #define CC2_RA                  BIT(5)
 #define CC2_RP			(BIT(6) | BIT(7))
 
+#define CMD_SEND_BUF		0xC0
+#define CMD_RECV_BUF		0xE0
+
 /******** END of I2C Address 0x58 ********/
 
 /***************************************************************/
@@ -462,6 +465,14 @@ struct anx7625_i2c_client {
 struct typec_port;
 struct usb_role_switch;
 
+#define MAX_BUF_LEN	30
+struct fw_msg {
+	u8 msg_len;
+	u8 msg_type;
+	u8 buf[MAX_BUF_LEN];
+} __packed;
+#define HEADER_LEN		2
+
 struct anx7625_data {
 	struct anx7625_platform_data pdata;
 	struct platform_device *audio_pdev;
@@ -497,6 +508,7 @@ struct anx7625_data {
 	struct drm_connector *connector;
 	struct mipi_dsi_device *dsi;
 	struct drm_dp_aux aux;
+	struct fw_msg send_msg;
 };
 
 #endif  /* __ANX7625_H__ */

-- 
2.47.3


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

* Re: [PATCH v2 1/3] dt-bindings: drm/bridge: anx7625: describe Type-C connector
  2026-01-21 10:15 ` [PATCH v2 1/3] dt-bindings: drm/bridge: anx7625: describe Type-C connector Dmitry Baryshkov
@ 2026-01-21 16:23   ` Rob Herring (Arm)
  0 siblings, 0 replies; 7+ messages in thread
From: Rob Herring (Arm) @ 2026-01-21 16:23 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Greg Kroah-Hartman, Simona Vetter, Thomas Zimmermann,
	Krzysztof Kozlowski, Laurent Pinchart, Maxime Ripard,
	David Airlie, dri-devel, linux-kernel, Xin Ji, linux-usb,
	Conor Dooley, devicetree, linux-arm-msm, Neil Armstrong,
	Maarten Lankhorst, Jonas Karlman, Andrzej Hajda, Heikki Krogerus,
	Robert Foss, Jernej Skrabec


On Wed, 21 Jan 2026 12:15:45 +0200, Dmitry Baryshkov wrote:
> ANX7625 can be used to mux converted video stream with the USB signals
> on a Type-C connector. Describe the optional connector subnode, make it
> exclusive with the AUX bus and port@1 as it is impossible to have both
> eDP panel and USB-C connector.
> 
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
> ---
>  .../bindings/display/bridge/analogix,anx7625.yaml  | 98 +++++++++++++++++++++-
>  1 file changed, 97 insertions(+), 1 deletion(-)
> 

Reviewed-by: Rob Herring (Arm) <robh@kernel.org>


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

* RE: [PATCH v2 3/3] drm: bridge: anx7625: implement message sending
  2026-01-21 10:15 ` [PATCH v2 3/3] drm: bridge: anx7625: implement message sending Dmitry Baryshkov
@ 2026-01-22  1:40   ` Xin Ji
  0 siblings, 0 replies; 7+ messages in thread
From: Xin Ji @ 2026-01-22  1:40 UTC (permalink / raw)
  To: Dmitry Baryshkov, Andrzej Hajda, Neil Armstrong, Robert Foss,
	Laurent Pinchart, Jonas Karlman, Jernej Skrabec, David Airlie,
	Simona Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Heikki Krogerus, Greg Kroah-Hartman
  Cc: dri-devel, devicetree, linux-usb, linux-arm-msm, linux-kernel

Hi Dmity, thanks for the patch, it is OK for me.

Reviewed-by: Xin Ji <xji@analogixsemi.com>

> Swapping the data role requires sending the message to the other USB-C side.
> Implement sending these messages through the OCM. The code is largely
> based on the anx7411.c USB-C driver.
> 
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
> ---
>  drivers/gpu/drm/bridge/analogix/anx7625.c | 68
> +++++++++++++++++++++++++++++++
> drivers/gpu/drm/bridge/analogix/anx7625.h | 12 ++++++
>  2 files changed, 80 insertions(+)
> 
> diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c
> b/drivers/gpu/drm/bridge/analogix/anx7625.c
> index 8dc6e3b16968..c43519097a45 100644
> --- a/drivers/gpu/drm/bridge/analogix/anx7625.c
> +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c
> @@ -1484,6 +1484,73 @@ static void anx7625_start_dp_work(struct
> anx7625_data *ctx)  }
> 
>  #if IS_REACHABLE(CONFIG_TYPEC)
> +static u8 anx7625_checksum(u8 *buf, u8 len) {
> +	u8 ret = 0;
> +	u8 i;
> +
> +	for (i = 0; i < len; i++)
> +		ret += buf[i];
> +
> +	return ret;
> +}
> +
> +static int anx7625_read_msg_ctrl_status(struct anx7625_data *ctx) {
> +	return anx7625_reg_read(ctx, ctx->i2c.rx_p0_client,
> CMD_SEND_BUF); }
> +
> +static int anx7625_wait_msg_empty(struct anx7625_data *ctx) {
> +	int val;
> +
> +	return readx_poll_timeout(anx7625_read_msg_ctrl_status, ctx,
> +				  val, (val < 0) || (val == 0),
> +				  2000, 2000 * 150);
> +}
> +
> +static int anx7625_send_msg(struct anx7625_data *ctx, u8 type, u8 *buf,
> +u8 size) {
> +	struct fw_msg *msg = &ctx->send_msg;
> +	u8 crc;
> +	int ret;
> +
> +	size = min_t(u8, size, (u8)MAX_BUF_LEN);
> +	memcpy(msg->buf, buf, size);
> +	msg->msg_type = type;
> +
> +	/* msg len equals buffer length + msg_type */
> +	msg->msg_len = size + 1;
> +
> +	crc = anx7625_checksum((u8 *)msg, size + HEADER_LEN);
> +	msg->buf[size] = 0 - crc;
> +
> +	ret = anx7625_wait_msg_empty(ctx);
> +	if (ret)
> +		return ret;
> +
> +	ret = anx7625_reg_block_write(ctx, ctx->i2c.rx_p0_client,
> +				      CMD_SEND_BUF + 1, size + HEADER_LEN,
> +				      &msg->msg_type);
> +	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, CMD_SEND_BUF,
> +				 msg->msg_len);
> +	return ret;
> +}
> +
> +static int anx7625_typec_dr_set(struct typec_port *port, enum
> +typec_data_role role) {
> +	struct anx7625_data *ctx = typec_get_drvdata(port);
> +
> +	if (role == ctx->typec_data_role)
> +		return 0;
> +
> +	return anx7625_send_msg(ctx, 0x11, NULL, 0); }
> +
> +static const struct typec_operations anx7625_typec_ops = {
> +	.dr_set = anx7625_typec_dr_set,
> +};
> +
>  static void anx7625_typec_set_orientation(struct anx7625_data *ctx)  {
>  	u32 val = anx7625_reg_read(ctx, ctx->i2c.rx_p0_client,
> SYSTEM_STSTUS); @@ -1542,6 +1609,7 @@ static int
> anx7625_typec_register(struct anx7625_data *ctx)
>  	typec_cap.orientation_aware = true;
> 
>  	typec_cap.driver_data = ctx;
> +	typec_cap.ops = &anx7625_typec_ops;
> 
>  	ctx->typec_port = typec_register_port(ctx->dev, &typec_cap);
>  	if (IS_ERR(ctx->typec_port))
> diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.h
> b/drivers/gpu/drm/bridge/analogix/anx7625.h
> index a18561c213af..957d234ec07c 100644
> --- a/drivers/gpu/drm/bridge/analogix/anx7625.h
> +++ b/drivers/gpu/drm/bridge/analogix/anx7625.h
> @@ -67,6 +67,9 @@
>  #define CC2_RA                  BIT(5)
>  #define CC2_RP			(BIT(6) | BIT(7))
> 
> +#define CMD_SEND_BUF		0xC0
> +#define CMD_RECV_BUF		0xE0
> +
>  /******** END of I2C Address 0x58 ********/
> 
> 
> /***************************************************************
> /
> @@ -462,6 +465,14 @@ struct anx7625_i2c_client {  struct typec_port;  struct
> usb_role_switch;
> 
> +#define MAX_BUF_LEN	30
> +struct fw_msg {
> +	u8 msg_len;
> +	u8 msg_type;
> +	u8 buf[MAX_BUF_LEN];
> +} __packed;
> +#define HEADER_LEN		2
> +
>  struct anx7625_data {
>  	struct anx7625_platform_data pdata;
>  	struct platform_device *audio_pdev;
> @@ -497,6 +508,7 @@ struct anx7625_data {
>  	struct drm_connector *connector;
>  	struct mipi_dsi_device *dsi;
>  	struct drm_dp_aux aux;
> +	struct fw_msg send_msg;
>  };
> 
>  #endif  /* __ANX7625_H__ */
> 
> --
> 2.47.3


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

* Re: [PATCH v2 0/3] drm: bridge: anx7625: implement Type-C support
  2026-01-21 10:15 [PATCH v2 0/3] drm: bridge: anx7625: implement Type-C support Dmitry Baryshkov
                   ` (2 preceding siblings ...)
  2026-01-21 10:15 ` [PATCH v2 3/3] drm: bridge: anx7625: implement message sending Dmitry Baryshkov
@ 2026-02-07 10:40 ` Dmitry Baryshkov
  3 siblings, 0 replies; 7+ messages in thread
From: Dmitry Baryshkov @ 2026-02-07 10:40 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Xin Ji, Heikki Krogerus,
	Greg Kroah-Hartman, Dmitry Baryshkov
  Cc: dri-devel, devicetree, linux-usb, linux-arm-msm, linux-kernel

On Wed, 21 Jan 2026 12:15:44 +0200, Dmitry Baryshkov wrote:
> ANX7625 can be used to mux converted video stream with the USB signals
> on a Type-C connector. Provide minimal Type-C support necessary for
> ANX7625 to register the Type-C port device and properly respond to data
> / power role events from the Type-C partner.
> 
> Notes:
> - I'm not 100% happy having Type-C code in the DRM subtree. Should I use
>   AUX device and to move Type-C-related code to drivers/usb/typec?
> 
> [...]

Applied to drm-misc-next, thanks!

[1/3] dt-bindings: drm/bridge: anx7625: describe Type-C connector
      commit: 1d7532444a32b53ff7344dc52019bab5a4b5ed66
[2/3] drm: bridge: anx7625: implement minimal Type-C support
      commit: f81455b2d3327a5685623e7db4050dbbe5513bc3
[3/3] drm: bridge: anx7625: implement message sending
      commit: 8ad0f7d2e6fdfc4462a5b168ec64d73b7e952ab9

Best regards,
-- 
With best wishes
Dmitry



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

end of thread, other threads:[~2026-02-07 10:40 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-01-21 10:15 [PATCH v2 0/3] drm: bridge: anx7625: implement Type-C support Dmitry Baryshkov
2026-01-21 10:15 ` [PATCH v2 1/3] dt-bindings: drm/bridge: anx7625: describe Type-C connector Dmitry Baryshkov
2026-01-21 16:23   ` Rob Herring (Arm)
2026-01-21 10:15 ` [PATCH v2 2/3] drm: bridge: anx7625: implement minimal Type-C support Dmitry Baryshkov
2026-01-21 10:15 ` [PATCH v2 3/3] drm: bridge: anx7625: implement message sending Dmitry Baryshkov
2026-01-22  1:40   ` Xin Ji
2026-02-07 10:40 ` [PATCH v2 0/3] drm: bridge: anx7625: implement Type-C support Dmitry Baryshkov

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

all inboxes | Powered by JetHome®