[PATCH RFC 2/2] usb: typec: qcom: Add support for shared USBIN VBUS detection

Alexander Koskovich posted 2 patches 1 month ago
[PATCH RFC 2/2] usb: typec: qcom: Add support for shared USBIN VBUS detection
Posted by Alexander Koskovich 1 month ago
On devices with multiple USB-C ports whose VBUS lines are wired to a
single shared USBIN input on the PM8150B PMIC (e.g. ASUS ROG Phone 3), the
Type-C port controller cannot distinguish which port is providing VBUS.

In practice this shows up as being unable to use the affected Type-C port
while the other port is connected to a device providing VBUS such as a PC
or charger.

Add support for an optional vbus-detect-gpios property that allows the
Type-C port controller to read VBUS state from a per-port GPIO instead of
the shared USBIN input. When present, the driver also bypasses VSAFE0V
checks and switches DRP toggling to TRY_SRC to avoid false source
detection caused by VBUS present on USBIN from another port.

Signed-off-by: Alexander Koskovich <akoskovich@pm.me>
---
 drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.c | 46 +++++++++++++++++++++-
 1 file changed, 44 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.c b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.c
index 8051eaa46991..c338e26651b0 100644
--- a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.c
+++ b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.c
@@ -5,6 +5,7 @@
 
 #include <linux/delay.h>
 #include <linux/err.h>
+#include <linux/gpio/consumer.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/mod_devicetable.h>
@@ -176,6 +177,8 @@ struct pmic_typec_port {
 	bool				vbus_enabled;
 	struct mutex			vbus_lock;		/* VBUS state serialization */
 
+	struct gpio_desc		*vbus_detect_gpio;
+
 	int				cc;
 	bool				debouncing_cc;
 	struct delayed_work		cc_debounce_dwork;
@@ -277,7 +280,12 @@ static int qcom_pmic_typec_port_vbus_detect(struct pmic_typec_port *pmic_typec_p
 {
 	struct device *dev = pmic_typec_port->dev;
 	unsigned int misc;
-	int ret;
+	int ret, vbus;
+
+	if (pmic_typec_port->vbus_detect_gpio) {
+		vbus = gpiod_get_value_cansleep(pmic_typec_port->vbus_detect_gpio);
+		return vbus;
+	}
 
 	ret = regmap_read(pmic_typec_port->regmap,
 			  pmic_typec_port->base + TYPEC_MISC_STATUS_REG,
@@ -307,6 +315,13 @@ static int qcom_pmic_typec_port_vbus_toggle(struct pmic_typec_port *pmic_typec_p
 		if (ret)
 			return ret;
 
+		/*
+		 * On devices with multiple ports sharing USBIN, VBUS from another
+		 * port prevents VSAFE0V from being reached.
+		 */
+		if (pmic_typec_port->vbus_detect_gpio)
+			return 0;
+
 		val = TYPEC_SM_VBUS_VSAFE0V;
 	}
 
@@ -589,7 +604,14 @@ static int qcom_pmic_typec_port_start_toggling(struct tcpc_dev *tcpc,
 		mode = EN_SNK_ONLY;
 		break;
 	case TYPEC_PORT_DRP:
-		mode = EN_TRY_SNK;
+		/*
+		 * VBUS from another port makes EN_TRY_SNK falsely detect
+		 * a source. Start as Rp to reliably find sinks.
+		 */
+		if (pmic_typec_port->vbus_detect_gpio)
+			mode = EN_TRY_SRC;
+		else
+			mode = EN_TRY_SNK;
 		break;
 	}
 
@@ -677,6 +699,20 @@ static int qcom_pmic_typec_port_start(struct pmic_typec *tcpm,
 	if (ret)
 		goto done;
 
+	/*
+	 * On devices with multiple USB-C ports sharing USBIN, bypass
+	 * VSAFE0V so SRC attachment can complete despite VBUS being
+	 * present on USBIN from another port.
+	 */
+	if (pmic_typec_port->vbus_detect_gpio) {
+		ret = regmap_update_bits(pmic_typec_port->regmap,
+					 pmic_typec_port->base + TYPEC_EXIT_STATE_CFG_REG,
+					 BYPASS_VSAFE0V_DURING_ROLE_SWAP,
+					 BYPASS_VSAFE0V_DURING_ROLE_SWAP);
+		if (ret)
+			goto done;
+	}
+
 	pmic_typec_port->tcpm_port = tcpm_port;
 
 	for (i = 0; i < pmic_typec_port->nr_irqs; i++)
@@ -724,6 +760,12 @@ int qcom_pmic_typec_port_probe(struct platform_device *pdev,
 	if (IS_ERR(pmic_typec_port->vdd_vbus))
 		return PTR_ERR(pmic_typec_port->vdd_vbus);
 
+	pmic_typec_port->vbus_detect_gpio = devm_gpiod_get_optional(dev, "vbus-detect",
+								 GPIOD_IN);
+	if (IS_ERR(pmic_typec_port->vbus_detect_gpio))
+		return dev_err_probe(dev, PTR_ERR(pmic_typec_port->vbus_detect_gpio),
+				     "failed to get vbus-detect GPIO\n");
+
 	pmic_typec_port->dev = dev;
 	pmic_typec_port->base = base;
 	pmic_typec_port->regmap = regmap;

-- 
2.53.0
Re: [PATCH RFC 2/2] usb: typec: qcom: Add support for shared USBIN VBUS detection
Posted by Bryan O'Donoghue 4 weeks ago
On 08/03/2026 23:20, Alexander Koskovich wrote:
> +	if (IS_ERR(pmic_typec_port->vbus_detect_gpio))
> +		return dev_err_probe(dev, PTR_ERR(pmic_typec_port->vbus_detect_gpio),
> +				     "failed to get vbus-detect GPIO\n");
> +

I'd prefer if this was bracketed since it is over more than one line.

Reviewed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

---
bod
Re: [PATCH RFC 2/2] usb: typec: qcom: Add support for shared USBIN VBUS detection
Posted by Alexander Koskovich 4 weeks ago
On Wednesday, March 11th, 2026 at 7:06 PM, Bryan O'Donoghue <bryan.odonoghue@linaro.org> wrote:

> On 08/03/2026 23:20, Alexander Koskovich wrote:
> > +	if (IS_ERR(pmic_typec_port->vbus_detect_gpio))
> > +		return dev_err_probe(dev, PTR_ERR(pmic_typec_port->vbus_detect_gpio),
> > +				     "failed to get vbus-detect GPIO\n");
> > +
> 
> I'd prefer if this was bracketed since it is over more than one line.
> 
> Reviewed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

Uploaded v2 but didn't carry your Reviewed-By since there's a fair bit of diff, can you look at v2 and check if all looks good?

> 
> ---
> bod
> 
> 

Thanks,
Alex
Re: [PATCH RFC 2/2] usb: typec: qcom: Add support for shared USBIN VBUS detection
Posted by Konrad Dybcio 4 weeks, 1 day ago
On 3/9/26 12:20 AM, Alexander Koskovich wrote:
> On devices with multiple USB-C ports whose VBUS lines are wired to a
> single shared USBIN input on the PM8150B PMIC (e.g. ASUS ROG Phone 3), the
> Type-C port controller cannot distinguish which port is providing VBUS.
> 
> In practice this shows up as being unable to use the affected Type-C port
> while the other port is connected to a device providing VBUS such as a PC
> or charger.
> 
> Add support for an optional vbus-detect-gpios property that allows the
> Type-C port controller to read VBUS state from a per-port GPIO instead of
> the shared USBIN input. When present, the driver also bypasses VSAFE0V
> checks and switches DRP toggling to TRY_SRC to avoid false source
> detection caused by VBUS present on USBIN from another port.
> 
> Signed-off-by: Alexander Koskovich <akoskovich@pm.me>
> ---

[...]

> +	if (pmic_typec_port->vbus_detect_gpio) {
> +		vbus = gpiod_get_value_cansleep(pmic_typec_port->vbus_detect_gpio);
> +		return vbus;

"return gpiod_..."

[...]

> +	/*
> +	 * On devices with multiple USB-C ports sharing USBIN, bypass
> +	 * VSAFE0V so SRC attachment can complete despite VBUS being
> +	 * present on USBIN from another port.
> +	 */
> +	if (pmic_typec_port->vbus_detect_gpio) {
> +		ret = regmap_update_bits(pmic_typec_port->regmap,
> +					 pmic_typec_port->base + TYPEC_EXIT_STATE_CFG_REG,
> +					 BYPASS_VSAFE0V_DURING_ROLE_SWAP,
> +					 BYPASS_VSAFE0V_DURING_ROLE_SWAP);

regmap_set_bits()



> +		if (ret)
> +			goto done;
> +	}
> +
>  	pmic_typec_port->tcpm_port = tcpm_port;
>  
>  	for (i = 0; i < pmic_typec_port->nr_irqs; i++)
> @@ -724,6 +760,12 @@ int qcom_pmic_typec_port_probe(struct platform_device *pdev,
>  	if (IS_ERR(pmic_typec_port->vdd_vbus))
>  		return PTR_ERR(pmic_typec_port->vdd_vbus);
>  
> +	pmic_typec_port->vbus_detect_gpio = devm_gpiod_get_optional(dev, "vbus-detect",
> +								 GPIOD_IN);

I thought the intent here was to have 2 GPIOs, one per port - could
you please shed some light on this?

Konrad
Re: [PATCH RFC 2/2] usb: typec: qcom: Add support for shared USBIN VBUS detection
Posted by Alexander Koskovich 4 weeks ago
On Wednesday, March 11th, 2026 at 9:02 AM, Konrad Dybcio <konrad.dybcio@oss.qualcomm.com> wrote:

> 
> I thought the intent here was to have 2 GPIOs, one per port - could
> you please shed some light on this?

For the ROG 3 there is a pm8150b_typec and an rt1715, the pm8150b_typec is the
only one that needs this workaround as the rt1715 has it's own CC detection
mechanism that doesn't get confused by the shared VBUS.

Although there is a GPIO to detect VBUS on the bottom port as well, I just
found that I only needed the one for pm8150b_typec atm. 

> 
> Konrad
> 

Thanks,
Alex
Re: [PATCH RFC 2/2] usb: typec: qcom: Add support for shared USBIN VBUS detection
Posted by Bryan O'Donoghue 4 weeks ago
On 11/03/2026 13:01, Konrad Dybcio wrote:
>> +	pmic_typec_port->vbus_detect_gpio = devm_gpiod_get_optional(dev, "vbus-detect",
>> +								 GPIOD_IN);
> I thought the intent here was to have 2 GPIOs, one per port - could
> you please shed some light on this?

You should have two instances of the driver. One for each port so one 
GPIO detect in-lieu of VBUS per port.

So for this board we would expect to see

- pmic@2::pm8150b_typec: typec@1500
- pmic@3::pm8150b_typec: typec@1500

and a VBUS GPIO associated with each type-c connector.

---
bod