linux-usb.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] Enable USB type C support on SM8150
@ 2020-07-31  4:57 Wesley Cheng
  2020-07-31  4:57 ` [PATCH 1/3] arm64: boot: dts: qcom: sm8150: Add nodes for PMIC based typec detection Wesley Cheng
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Wesley Cheng @ 2020-07-31  4:57 UTC (permalink / raw)
  To: bjorn.andersson, kishon, vkoul, agross, balbi, gregkh, robh+dt
  Cc: devicetree, linux-kernel, linux-arm-msm, linux-usb, jackp, Wesley Cheng

This series adds support for setting of the orientation multiplexor within the
QMP PHY based on the detection output from the PM8150B.  It will also introduce
a role switch in DWC3 QCOM, which is used so that the DWC3 QCOM glue can receive
role switch change events, and set the vbus override accordingly.  This event
will then be propagated down to the DWC3 core driver, by the DWC3 QCOM getting a
handle to the DWC3 core's role switch.

Wesley Cheng (3):
  arm64: boot: dts: qcom: sm8150: Add nodes for PMIC based typec
    detection
  phy: qcom-qmp: Register as a typec switch for orientation detection
  usb: dwc3: dwc3-qcom: Find USB connector and register role switch

 arch/arm64/boot/dts/qcom/sm8150-mtp.dts |  37 ++++++++-
 drivers/phy/qualcomm/Kconfig            |  11 +++
 drivers/phy/qualcomm/phy-qcom-qmp.c     |  71 +++++++++++++++-
 drivers/usb/dwc3/dwc3-qcom.c            | 103 +++++++++++++++++++++++-
 4 files changed, 216 insertions(+), 6 deletions(-)

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* [PATCH 1/3] arm64: boot: dts: qcom: sm8150: Add nodes for PMIC based typec detection
  2020-07-31  4:57 [PATCH 0/3] Enable USB type C support on SM8150 Wesley Cheng
@ 2020-07-31  4:57 ` Wesley Cheng
  2020-07-31  4:57 ` [PATCH 2/3] phy: qcom-qmp: Register as a typec switch for orientation detection Wesley Cheng
  2020-07-31  4:57 ` [PATCH 3/3] usb: dwc3: dwc3-qcom: Find USB connector and register role switch Wesley Cheng
  2 siblings, 0 replies; 6+ messages in thread
From: Wesley Cheng @ 2020-07-31  4:57 UTC (permalink / raw)
  To: bjorn.andersson, kishon, vkoul, agross, balbi, gregkh, robh+dt
  Cc: devicetree, linux-kernel, linux-arm-msm, linux-usb, jackp, Wesley Cheng

Introduce required child nodes to enable the PMIC based USB type C driver.
This consits of connector and endpoint nodes to drivers, which manage the
type C mux and the USB role switch.

Signed-off-by: Wesley Cheng <wcheng@codeaurora.org>
---
 arch/arm64/boot/dts/qcom/sm8150-mtp.dts | 37 ++++++++++++++++++++++++-
 1 file changed, 36 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/qcom/sm8150-mtp.dts b/arch/arm64/boot/dts/qcom/sm8150-mtp.dts
index ba3b5b802954..c7d5aab69b56 100644
--- a/arch/arm64/boot/dts/qcom/sm8150-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sm8150-mtp.dts
@@ -413,6 +413,28 @@ &pm8150b_vbus {
 	status = "okay";
 };
 
+&pm8150b_typec {
+	status = "okay";
+	connector {
+		compatible = "usb-c-connector";
+		power-role = "dual";
+		data-role = "dual";
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			port@1 {
+				reg = <1>;
+				usb3_data_ss: endpoint@0 {
+					remote-endpoint = <&qmp_ss_mux>;
+				};
+				usb3_role: endpoint@1 {
+					remote-endpoint = <&dwc3_drd_switch>;
+				};
+			};
+		};
+	};
+};
+
 &usb_1_hsphy {
 	status = "okay";
 	vdda-pll-supply = <&vdd_usb_hs_core>;
@@ -424,12 +446,25 @@ &usb_1_qmpphy {
 	status = "okay";
 	vdda-phy-supply = <&vreg_l3c_1p2>;
 	vdda-pll-supply = <&vdda_usb_ss_dp_core_1>;
+	orientation-switch;
+	port {
+		qmp_ss_mux: endpoint@0 {
+			remote-endpoint = <&usb3_data_ss>;
+		};
+	};
 };
 
 &usb_1 {
 	status = "okay";
+	usb-role-switch;
+	port {
+		dwc3_drd_switch: endpoint@0 {
+			remote-endpoint = <&usb3_role>;
+		};
+	};
 };
 
 &usb_1_dwc3 {
-	dr_mode = "peripheral";
+	dr_mode = "otg";
+	usb-role-switch;
 };
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* [PATCH 2/3] phy: qcom-qmp: Register as a typec switch for orientation detection
  2020-07-31  4:57 [PATCH 0/3] Enable USB type C support on SM8150 Wesley Cheng
  2020-07-31  4:57 ` [PATCH 1/3] arm64: boot: dts: qcom: sm8150: Add nodes for PMIC based typec detection Wesley Cheng
@ 2020-07-31  4:57 ` Wesley Cheng
  2020-07-31  4:57 ` [PATCH 3/3] usb: dwc3: dwc3-qcom: Find USB connector and register role switch Wesley Cheng
  2 siblings, 0 replies; 6+ messages in thread
From: Wesley Cheng @ 2020-07-31  4:57 UTC (permalink / raw)
  To: bjorn.andersson, kishon, vkoul, agross, balbi, gregkh, robh+dt
  Cc: devicetree, linux-kernel, linux-arm-msm, linux-usb, jackp, Wesley Cheng

The lane select switch for USB typec orientation is within the USB QMP PHY.
the current device.  It could be connected through an endpoint, to an
independent device handling the typec detection, ie the QCOM SPMI typec
driver.

Signed-off-by: Wesley Cheng <wcheng@codeaurora.org>
---
 drivers/phy/qualcomm/Kconfig        | 11 +++++
 drivers/phy/qualcomm/phy-qcom-qmp.c | 70 +++++++++++++++++++++++++++--
 2 files changed, 78 insertions(+), 3 deletions(-)

diff --git a/drivers/phy/qualcomm/Kconfig b/drivers/phy/qualcomm/Kconfig
index 928db510b86c..43f46a1b3db1 100644
--- a/drivers/phy/qualcomm/Kconfig
+++ b/drivers/phy/qualcomm/Kconfig
@@ -48,6 +48,17 @@ config PHY_QCOM_QMP
 	  Enable this to support the QMP PHY transceiver that is used
 	  with controllers such as PCIe, UFS, and USB on Qualcomm chips.
 
+if PHY_QCOM_QMP
+config PHY_QCOM_QMP_TYPEC
+	bool "Enable QCOM QMP PHY Type C Switch Support"
+	depends on PHY_QCOM_QMP=y && TYPEC=y || PHY_QCOM_QMP=m && TYPEC
+	help
+	  Register a type C switch from the QMP PHY driver for type C
+	  orientation support.  This has dependencies with if the type C kernel
+	  configuration is enabled or not.  This support will not be present if
+	  USB type C is disabled.
+endif
+
 config PHY_QCOM_QUSB2
 	tristate "Qualcomm QUSB2 PHY Driver"
 	depends on OF && (ARCH_QCOM || COMPILE_TEST)
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c
index 562053ce9455..29d8a3570328 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -19,6 +19,7 @@
 #include <linux/regulator/consumer.h>
 #include <linux/reset.h>
 #include <linux/slab.h>
+#include <linux/usb/typec_mux.h>
 
 #include <dt-bindings/phy/phy.h>
 
@@ -66,6 +67,9 @@
 /* QPHY_V3_PCS_MISC_CLAMP_ENABLE register bits */
 #define CLAMP_EN				BIT(0) /* enables i/o clamp_n */
 
+#define SW_PORTSELECT_VAL			BIT(0)
+#define SW_PORTSELECT_MUX			BIT(1)
+
 #define PHY_INIT_COMPLETE_TIMEOUT		10000
 #define POWER_DOWN_DELAY_US_MIN			10
 #define POWER_DOWN_DELAY_US_MAX			11
@@ -1845,6 +1849,8 @@ struct qmp_phy {
  * @phy_initialized: indicate if PHY has been initialized
  * @mode: current PHY mode
  * @ufs_reset: optional UFS PHY reset handle
+ * @sw: typec switch for receiving orientation changes
+ * @orientation: carries current CC orientation
  */
 struct qcom_qmp {
 	struct device *dev;
@@ -1864,6 +1870,8 @@ struct qcom_qmp {
 	enum phy_mode mode;
 
 	struct reset_control *ufs_reset;
+	struct typec_switch *sw;
+	enum typec_orientation orientation;
 };
 
 static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
@@ -2485,6 +2493,7 @@ static int qcom_qmp_phy_com_init(struct qmp_phy *qphy)
 	void __iomem *pcs = qphy->pcs;
 	void __iomem *dp_com = qmp->dp_com;
 	int ret, i;
+	unsigned int val;
 
 	mutex_lock(&qmp->phy_mutex);
 	if (qmp->init_count++) {
@@ -2534,6 +2543,13 @@ static int qcom_qmp_phy_com_init(struct qmp_phy *qphy)
 		qphy_setbits(dp_com, QPHY_V3_DP_COM_PHY_MODE_CTRL,
 			     USB3_MODE | DP_MODE);
 
+		if (cfg->is_dual_lane_phy) {
+			val = SW_PORTSELECT_MUX;
+			if (qmp->orientation == TYPEC_ORIENTATION_REVERSE)
+				val |= SW_PORTSELECT_VAL;
+			qphy_setbits(dp_com, QPHY_V3_DP_COM_TYPEC_CTRL, val);
+		}
+
 		/* bring both QMP USB and QMP DP PHYs PCS block out of reset */
 		qphy_clrbits(dp_com, QPHY_V3_DP_COM_RESET_OVRD_CTRL,
 			     SW_DPPHY_RESET_MUX | SW_DPPHY_RESET |
@@ -2559,7 +2575,7 @@ static int qcom_qmp_phy_com_init(struct qmp_phy *qphy)
 
 	if (cfg->has_phy_com_ctrl) {
 		void __iomem *status;
-		unsigned int mask, val;
+		unsigned int mask;
 
 		qphy_clrbits(serdes, cfg->regs[QPHY_COM_SW_RESET], SW_RESET);
 		qphy_setbits(serdes, cfg->regs[QPHY_COM_START_CONTROL],
@@ -3242,6 +3258,47 @@ static const struct dev_pm_ops qcom_qmp_phy_pm_ops = {
 			   qcom_qmp_phy_runtime_resume, NULL)
 };
 
+#if IS_ENABLED(CONFIG_PHY_QCOM_QMP_TYPEC)
+static int qcom_qmp_phy_typec_switch_set(struct typec_switch *sw,
+					 enum typec_orientation orientation)
+{
+	struct qcom_qmp *qmp = typec_switch_get_drvdata(sw);
+	struct qmp_phy *qphy = qmp->phys[0];
+
+	qmp->orientation = orientation;
+	if (qmp->phy_initialized) {
+		qcom_qmp_phy_disable(qphy->phy);
+		qcom_qmp_phy_enable(qphy->phy);
+	}
+
+	return 0;
+}
+
+static int qcom_qmp_phy_typec_switch_register(struct qcom_qmp *qmp)
+{
+	struct typec_switch_desc sw_desc;
+	struct device *dev = qmp->dev;
+
+	if (qmp->cfg->is_dual_lane_phy) {
+		sw_desc.drvdata = qmp;
+		sw_desc.fwnode = dev->fwnode;
+		sw_desc.set = qcom_qmp_phy_typec_switch_set;
+		qmp->sw = typec_switch_register(dev, &sw_desc);
+		if (IS_ERR(qmp->sw)) {
+			dev_err(dev, "Error registering typec switch: %ld\n",
+				PTR_ERR(qmp->sw));
+		}
+	}
+
+	return 0;
+}
+#else
+static int qcom_qmp_phy_typec_switch_register(struct qcom_qmp *qmp)
+{
+	return 0;
+}
+#endif
+
 static int qcom_qmp_phy_probe(struct platform_device *pdev)
 {
 	struct qcom_qmp *qmp;
@@ -3250,7 +3307,7 @@ static int qcom_qmp_phy_probe(struct platform_device *pdev)
 	struct device_node *child;
 	struct phy_provider *phy_provider;
 	void __iomem *base;
-	int num, id;
+	int num = 0, id;
 	int ret;
 
 	qmp = devm_kzalloc(dev, sizeof(*qmp), GFP_KERNEL);
@@ -3302,7 +3359,11 @@ static int qcom_qmp_phy_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	num = of_get_available_child_count(dev->of_node);
+	qcom_qmp_phy_typec_switch_register(qmp);
+	for_each_available_child_of_node(dev->of_node, child) {
+		if (!strncmp("lanes", child->name, 5))
+			num++;
+	}
 	/* do we have a rogue child node ? */
 	if (num > qmp->cfg->nlanes)
 		return -EINVAL;
@@ -3322,6 +3383,9 @@ static int qcom_qmp_phy_probe(struct platform_device *pdev)
 
 	for_each_available_child_of_node(dev->of_node, child) {
 		/* Create per-lane phy */
+		if (strncmp("lanes", child->name, 5))
+			continue;
+
 		ret = qcom_qmp_phy_create(dev, child, id);
 		if (ret) {
 			dev_err(dev, "failed to create lane%d phy, %d\n",
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* [PATCH 3/3] usb: dwc3: dwc3-qcom: Find USB connector and register role switch
  2020-07-31  4:57 [PATCH 0/3] Enable USB type C support on SM8150 Wesley Cheng
  2020-07-31  4:57 ` [PATCH 1/3] arm64: boot: dts: qcom: sm8150: Add nodes for PMIC based typec detection Wesley Cheng
  2020-07-31  4:57 ` [PATCH 2/3] phy: qcom-qmp: Register as a typec switch for orientation detection Wesley Cheng
@ 2020-07-31  4:57 ` Wesley Cheng
  2020-08-10 12:13   ` Felipe Balbi
  2 siblings, 1 reply; 6+ messages in thread
From: Wesley Cheng @ 2020-07-31  4:57 UTC (permalink / raw)
  To: bjorn.andersson, kishon, vkoul, agross, balbi, gregkh, robh+dt
  Cc: devicetree, linux-kernel, linux-arm-msm, linux-usb, jackp, Wesley Cheng

If registering a USB typeC connector, the connector node may not be a child
of the DWC3 QCOM device.  Utilize devcon graph search to lookup if any
remote endpoints contain the connector.  If a connector is present, the
DWC3 QCOM will register a USB role switch to receive role change events, as
well as attain a reference to the DWC3 core role switch to pass the event
down.

Signed-off-by: Wesley Cheng <wcheng@codeaurora.org>
---
 drivers/usb/dwc3/dwc3-qcom.c | 103 ++++++++++++++++++++++++++++++++++-
 1 file changed, 101 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c
index e1e78e9824b1..fe1e8a4ab7d6 100644
--- a/drivers/usb/dwc3/dwc3-qcom.c
+++ b/drivers/usb/dwc3/dwc3-qcom.c
@@ -19,6 +19,8 @@
 #include <linux/usb/of.h>
 #include <linux/reset.h>
 #include <linux/iopoll.h>
+#include <linux/fwnode.h>
+#include <linux/usb/role.h>
 
 #include "core.h"
 
@@ -71,6 +73,9 @@ struct dwc3_qcom {
 	struct notifier_block	vbus_nb;
 	struct notifier_block	host_nb;
 
+	struct usb_role_switch *role_sw;
+	struct usb_role_switch *dwc3_drd_sw;
+
 	const struct dwc3_acpi_pdata *acpi_pdata;
 
 	enum usb_dr_mode	mode;
@@ -190,6 +195,73 @@ static int dwc3_qcom_register_extcon(struct dwc3_qcom *qcom)
 	return 0;
 }
 
+static int dwc3_qcom_usb_role_switch_set(struct usb_role_switch *sw,
+					 enum usb_role role)
+{
+	struct dwc3_qcom *qcom = usb_role_switch_get_drvdata(sw);
+	struct fwnode_handle *child;
+	bool enable = false;
+
+	if (!qcom->dwc3_drd_sw) {
+		child = device_get_next_child_node(qcom->dev, NULL);
+		if (child) {
+			qcom->dwc3_drd_sw = usb_role_switch_find_by_fwnode(child);
+			fwnode_handle_put(child);
+			if (IS_ERR(qcom->dwc3_drd_sw)) {
+				qcom->dwc3_drd_sw = NULL;
+				return 0;
+			}
+		}
+	}
+
+	usb_role_switch_set_role(qcom->dwc3_drd_sw, role);
+
+	if (role == USB_ROLE_DEVICE)
+		enable = true;
+	else
+		enable = false;
+
+	qcom->mode = (role == USB_ROLE_HOST) ? USB_DR_MODE_HOST :
+					       USB_DR_MODE_PERIPHERAL;
+	dwc3_qcom_vbus_overrride_enable(qcom, enable);
+	return 0;
+}
+
+static enum usb_role dwc3_qcom_usb_role_switch_get(struct usb_role_switch *sw)
+{
+	struct dwc3_qcom *qcom = usb_role_switch_get_drvdata(sw);
+	enum usb_role role;
+
+	switch (qcom->mode) {
+	case USB_DR_MODE_HOST:
+		role = USB_ROLE_HOST;
+		break;
+	case USB_DR_MODE_PERIPHERAL:
+		role = USB_ROLE_DEVICE;
+		break;
+	default:
+		role = USB_ROLE_DEVICE;
+		break;
+	}
+
+	return role;
+}
+
+static int dwc3_qcom_setup_role_switch(struct dwc3_qcom *qcom)
+{
+	struct usb_role_switch_desc dwc3_role_switch = {NULL};
+
+	dwc3_role_switch.fwnode = dev_fwnode(qcom->dev);
+	dwc3_role_switch.set = dwc3_qcom_usb_role_switch_set;
+	dwc3_role_switch.get = dwc3_qcom_usb_role_switch_get;
+	dwc3_role_switch.driver_data = qcom;
+	qcom->role_sw = usb_role_switch_register(qcom->dev, &dwc3_role_switch);
+	if (IS_ERR(qcom->role_sw))
+		return PTR_ERR(qcom->role_sw);
+
+	return 0;
+}
+
 static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom)
 {
 	if (qcom->hs_phy_irq) {
@@ -540,6 +612,25 @@ static int dwc3_qcom_of_register_core(struct platform_device *pdev)
 	return 0;
 }
 
+static void *dwc3_qcom_find_usb_connector_match(struct device_connection *con,
+						int ep, void *data)
+{
+	if (!fwnode_property_match_string(con->fwnode, "compatible",
+					  "gpio-usb-b-connector") ||
+	    !fwnode_property_match_string(con->fwnode, "compatible",
+					  "usb-c-connector"))
+		return con->fwnode;
+	return 0;
+}
+
+static bool dwc3_qcom_find_usb_connector(struct platform_device *pdev)
+{
+	struct fwnode_handle *fwnode = pdev->dev.fwnode;
+
+	return fwnode_connection_find_match(fwnode, "connector", NULL,
+					    dwc3_qcom_find_usb_connector_match);
+}
+
 static int dwc3_qcom_probe(struct platform_device *pdev)
 {
 	struct device_node	*np = pdev->dev.of_node;
@@ -644,8 +735,13 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
 	if (qcom->mode == USB_DR_MODE_PERIPHERAL)
 		dwc3_qcom_vbus_overrride_enable(qcom, true);
 
-	/* register extcon to override sw_vbus on Vbus change later */
-	ret = dwc3_qcom_register_extcon(qcom);
+	if (dwc3_qcom_find_usb_connector(pdev)) {
+		ret = dwc3_qcom_setup_role_switch(qcom);
+	} else {
+		/* register extcon to override sw_vbus on Vbus change later */
+		ret = dwc3_qcom_register_extcon(qcom);
+	}
+
 	if (ret)
 		goto depopulate;
 
@@ -679,6 +775,9 @@ static int dwc3_qcom_remove(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	int i;
 
+	usb_role_switch_unregister(qcom->role_sw);
+	usb_role_switch_put(qcom->dwc3_drd_sw);
+
 	of_platform_depopulate(dev);
 
 	for (i = qcom->num_clocks - 1; i >= 0; i--) {
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* Re: [PATCH 3/3] usb: dwc3: dwc3-qcom: Find USB connector and register role switch
  2020-07-31  4:57 ` [PATCH 3/3] usb: dwc3: dwc3-qcom: Find USB connector and register role switch Wesley Cheng
@ 2020-08-10 12:13   ` Felipe Balbi
  2020-08-10 20:51     ` Wesley Cheng
  0 siblings, 1 reply; 6+ messages in thread
From: Felipe Balbi @ 2020-08-10 12:13 UTC (permalink / raw)
  To: Wesley Cheng, bjorn.andersson, kishon, vkoul, agross, gregkh, robh+dt
  Cc: devicetree, linux-kernel, linux-arm-msm, linux-usb, jackp, Wesley Cheng

[-- Attachment #1: Type: text/plain, Size: 1151 bytes --]


Hi,

Wesley Cheng <wcheng@codeaurora.org> writes:
> @@ -190,6 +195,73 @@ static int dwc3_qcom_register_extcon(struct dwc3_qcom *qcom)
>  	return 0;
>  }
>  
> +static int dwc3_qcom_usb_role_switch_set(struct usb_role_switch *sw,
> +					 enum usb_role role)
> +{
> +	struct dwc3_qcom *qcom = usb_role_switch_get_drvdata(sw);
> +	struct fwnode_handle *child;
> +	bool enable = false;
> +
> +	if (!qcom->dwc3_drd_sw) {
> +		child = device_get_next_child_node(qcom->dev, NULL);
> +		if (child) {
> +			qcom->dwc3_drd_sw = usb_role_switch_find_by_fwnode(child);
> +			fwnode_handle_put(child);
> +			if (IS_ERR(qcom->dwc3_drd_sw)) {
> +				qcom->dwc3_drd_sw = NULL;
> +				return 0;
> +			}
> +		}
> +	}
> +
> +	usb_role_switch_set_role(qcom->dwc3_drd_sw, role);

why is this done at the glue layer instead of core.c?

> +	if (role == USB_ROLE_DEVICE)
> +		enable = true;
> +	else
> +		enable = false;
> +
> +	qcom->mode = (role == USB_ROLE_HOST) ? USB_DR_MODE_HOST :
> +					       USB_DR_MODE_PERIPHERAL;
> +	dwc3_qcom_vbus_overrride_enable(qcom, enable);

could you add a patch fixing this typo?

-- 
balbi

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

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

* Re: [PATCH 3/3] usb: dwc3: dwc3-qcom: Find USB connector and register role switch
  2020-08-10 12:13   ` Felipe Balbi
@ 2020-08-10 20:51     ` Wesley Cheng
  0 siblings, 0 replies; 6+ messages in thread
From: Wesley Cheng @ 2020-08-10 20:51 UTC (permalink / raw)
  To: Felipe Balbi, bjorn.andersson, kishon, vkoul, agross, gregkh, robh+dt
  Cc: devicetree, linux-kernel, linux-arm-msm, linux-usb, jackp



On 8/10/2020 5:13 AM, Felipe Balbi wrote:
> 
> Hi,
> 
> Wesley Cheng <wcheng@codeaurora.org> writes:
>> @@ -190,6 +195,73 @@ static int dwc3_qcom_register_extcon(struct dwc3_qcom *qcom)
>>  	return 0;
>>  }
>>  
>> +static int dwc3_qcom_usb_role_switch_set(struct usb_role_switch *sw,
>> +					 enum usb_role role)
>> +{
>> +	struct dwc3_qcom *qcom = usb_role_switch_get_drvdata(sw);
>> +	struct fwnode_handle *child;
>> +	bool enable = false;
>> +
>> +	if (!qcom->dwc3_drd_sw) {
>> +		child = device_get_next_child_node(qcom->dev, NULL);
>> +		if (child) {
>> +			qcom->dwc3_drd_sw = usb_role_switch_find_by_fwnode(child);
>> +			fwnode_handle_put(child);
>> +			if (IS_ERR(qcom->dwc3_drd_sw)) {
>> +				qcom->dwc3_drd_sw = NULL;
>> +				return 0;
>> +			}
>> +		}
>> +	}
>> +
>> +	usb_role_switch_set_role(qcom->dwc3_drd_sw, role);
> 
> why is this done at the glue layer instead of core.c?
> 
Hi Felipe,

Thanks for the feedback.  So the DWC3 DRD driver already registers a
role switch device for receiving external events.  However, the DWC3
glue (dwc3-qcom) needs to also know of the role changes, so that it can
set the override bits accordingly in the controller.  I've seen a few
implementations, ie using a notifier block to notify the glue of these
events, but that placed a dependency on the DWC3 core being available to
the DWC3 glue at probe time.  If the DWC3 core was not available at that
time, the dwc3-qcom driver will finish its probing routine, and since
the notifier was never registered, the role change events would not be
received.

By registering another role switch device in the DWC3 glue, this gives
us a place to attempt initializing a channel w/ the DWC3 core if it
wasn't ready during probe().  For example...

usb_conn_detect_cable(role=USB_ROLE_DEVICE)
-->usb_role_switch_set_role(sw=dwc3-qcom)
  -->dwc3_qcom_usb_role_switch_set()
    -- IF DWC3 core role switch available
	-->usb_role_switch_set_role(sw=drd)
    -- ELSE
	--> do nothing.

So basically, the goal is to just propagate the role change event down
to the DWC3 core, while breaking the dependency of it being available at
probe.
>> +	if (role == USB_ROLE_DEVICE)
>> +		enable = true;
>> +	else
>> +		enable = false;
>> +
>> +	qcom->mode = (role == USB_ROLE_HOST) ? USB_DR_MODE_HOST :
>> +					       USB_DR_MODE_PERIPHERAL;
>> +	dwc3_qcom_vbus_overrride_enable(qcom, enable);
> 
> could you add a patch fixing this typo?
> 
Sure, I'll submit a separate patch to remove that extra 'r'

Thanks
Wesley

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

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

end of thread, other threads:[~2020-08-10 20:51 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-31  4:57 [PATCH 0/3] Enable USB type C support on SM8150 Wesley Cheng
2020-07-31  4:57 ` [PATCH 1/3] arm64: boot: dts: qcom: sm8150: Add nodes for PMIC based typec detection Wesley Cheng
2020-07-31  4:57 ` [PATCH 2/3] phy: qcom-qmp: Register as a typec switch for orientation detection Wesley Cheng
2020-07-31  4:57 ` [PATCH 3/3] usb: dwc3: dwc3-qcom: Find USB connector and register role switch Wesley Cheng
2020-08-10 12:13   ` Felipe Balbi
2020-08-10 20:51     ` Wesley Cheng

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).