From 727cd198d29376f355fa1283dfe9d5048d77f333 Mon Sep 17 00:00:00 2001
From: Ondrej Jirman <megi@xff.cz>
Date: Sat, 18 Feb 2023 00:38:44 +0100
Subject: [PATCH 373/480] usb: typec: tcpm: Fix PD devices/capabilities
 registration

Unregister caps before registering them. Store NULL to the struct
if registration fails, so that next attempt can succeed.

Fixes "sysfs: cannot create duplicate filename
'/devices/virtual/usb_power_delivery/pd1/source-capabilities'" error.

Signed-off-by: Ondrej Jirman <megi@xff.cz>
---
 drivers/usb/typec/tcpm/tcpm.c | 37 +++++++++++++++++++++++++++--------
 1 file changed, 29 insertions(+), 8 deletions(-)

diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index 01e1a2c066c7..9f2e376aafd6 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -3057,15 +3057,22 @@ static int tcpm_register_source_caps(struct tcpm_port *port)
 	struct usb_power_delivery_desc desc = { port->negotiated_rev };
 	struct usb_power_delivery_capabilities_desc caps = { };
 	struct usb_power_delivery_capabilities *cap;
+	struct usb_power_delivery *partner_pd;
+
+	if (!port->partner_pd) {
+		partner_pd = usb_power_delivery_register(NULL, &desc);
+		if (IS_ERR(partner_pd))
+			return PTR_ERR(partner_pd);
 
-	if (!port->partner_pd)
-		port->partner_pd = usb_power_delivery_register(NULL, &desc);
-	if (IS_ERR(port->partner_pd))
-		return PTR_ERR(port->partner_pd);
+		port->partner_pd = partner_pd;
+	}
 
 	memcpy(caps.pdo, port->source_caps, sizeof(u32) * port->nr_source_caps);
 	caps.role = TYPEC_SOURCE;
 
+	usb_power_delivery_unregister_capabilities(port->partner_source_caps);
+	port->partner_source_caps = NULL;
+
 	cap = usb_power_delivery_register_capabilities(port->partner_pd, &caps);
 	if (IS_ERR(cap))
 		return PTR_ERR(cap);
@@ -3080,15 +3087,22 @@ static int tcpm_register_sink_caps(struct tcpm_port *port)
 	struct usb_power_delivery_desc desc = { port->negotiated_rev };
 	struct usb_power_delivery_capabilities_desc caps = { };
 	struct usb_power_delivery_capabilities *cap;
+	struct usb_power_delivery *partner_pd;
+
+	if (!port->partner_pd) {
+		partner_pd = usb_power_delivery_register(NULL, &desc);
+		if (IS_ERR(partner_pd))
+			return PTR_ERR(partner_pd);
 
-	if (!port->partner_pd)
-		port->partner_pd = usb_power_delivery_register(NULL, &desc);
-	if (IS_ERR(port->partner_pd))
-		return PTR_ERR(port->partner_pd);
+		port->partner_pd = partner_pd;
+	}
 
 	memcpy(caps.pdo, port->sink_caps, sizeof(u32) * port->nr_sink_caps);
 	caps.role = TYPEC_SINK;
 
+	usb_power_delivery_unregister_capabilities(port->partner_sink_caps);
+	port->partner_sink_caps = NULL;
+
 	cap = usb_power_delivery_register_capabilities(port->partner_pd, &caps);
 	if (IS_ERR(cap))
 		return PTR_ERR(cap);
@@ -7098,10 +7112,17 @@ static int tcpm_port_register_pd(struct tcpm_port *port)
 		port->pds[i] = usb_power_delivery_register(port->dev, &desc);
 		if (IS_ERR(port->pds[i])) {
 			ret = PTR_ERR(port->pds[i]);
+			port->pds[i] = NULL;
 			goto err_unregister;
 		}
 		port->pd_list[i]->pd = port->pds[i];
 
+		usb_power_delivery_unregister_capabilities(port->pd_list[i]->source_cap);
+		port->pd_list[i]->source_cap = NULL;
+
+		usb_power_delivery_unregister_capabilities(port->pd_list[i]->sink_cap);
+		port->pd_list[i]->sink_cap = NULL;
+
 		if (port->pd_list[i]->source_desc.pdo[0]) {
 			cap = usb_power_delivery_register_capabilities(port->pds[i],
 								&port->pd_list[i]->source_desc);
-- 
2.49.0

