Re: [PATCH v2 05/10] usb: tcpm: add setup_host_mode/device_mode/disable_src_vbus APIs

Sebastian Reichel <[email protected]>
Newsgroups gmane.comp.boot-loaders.u-boot.general,gmane.comp.boot-loaders.u-boot
Message-ID <ano-_jXlvnruhCny@venus>
Hi,

On Sun, Jun 21, 2026 at 10:06:41AM +0800, Peng Fan (OSS) wrote:
> From: Peng Fan <[email protected]>
> 
> Add lightweight Type-C mode setup functions that bypass the TCPM state
> machine and call TCPCI driver ops directly:
> 
> - tcpm_setup_host_mode(): set CC=Rp, detect device, set polarity,
>   source VBUS
> - tcpm_setup_device_mode(): set CC=Rd, detect host, set polarity
> - tcpm_disable_src_vbus(): stop sourcing VBUS
> 
> These are used by board_usb_init/cleanup to configure the Type-C port
> for USB host or device mode without running the full PD state machine.
> 
> Signed-off-by: Peng Fan <[email protected]>
> ---

I don't see a user for these functions in this series, so maybe the
patch can just be dropped?

Generally it seems sensible to change the name to something like

 * tcpm_force_host_mode()
 * tcpm_force_device_mode()
 * tcpm_force_disable_vbus()

Also I think these functions deserve a comment header describing
when and why these functions should be used or not used. Avoiding
the state machine risks hard reset from the remote side, if proper
PD is being used later on.

Greetings,

-- Sebastian

>  drivers/usb/tcpm/tcpm-uclass.c | 87 ++++++++++++++++++++++++++++++++++++++++++
>  include/usb/tcpm.h             |  4 ++
>  2 files changed, 91 insertions(+)
> 
> diff --git a/drivers/usb/tcpm/tcpm-uclass.c b/drivers/usb/tcpm/tcpm-uclass.c
> index d4fe260e0db..e0f7ce62a79 100644
> --- a/drivers/usb/tcpm/tcpm-uclass.c
> +++ b/drivers/usb/tcpm/tcpm-uclass.c
> @@ -8,6 +8,7 @@
>  #include <dm/device.h>
>  #include <dm/device_compat.h>
>  #include <dm/uclass.h>
> +#include <linux/delay.h>
>  #include <linux/err.h>
>  #include <usb/tcpm.h>
>  #include "tcpm-internal.h"
> @@ -140,6 +141,92 @@ static int tcpm_post_bind(struct udevice *dev)
>  	return 0;
>  }
>  
> +int tcpm_setup_host_mode(struct udevice *dev, enum typec_cc_polarity *polarity)
> +{
> +	const struct dm_tcpm_ops *ops = dev_get_driver_ops(dev);
> +	enum typec_cc_status cc1, cc2;
> +	int ret;
> +
> +	ops->set_vbus(dev, false, false);
> +
> +	ops->set_cc(dev, TYPEC_CC_RP_DEF);
> +
> +	mdelay(100);
> +
> +	ret = ops->get_cc(dev, &cc1, &cc2);
> +	if (ret) {
> +		dev_err(dev, "Failed to get cc for host mode: %d\n", ret);
> +		return ret;
> +	}
> +
> +	if (cc1 == TYPEC_CC_RD) {
> +		*polarity = TYPEC_POLARITY_CC1;
> +	} else if (cc2 == TYPEC_CC_RD) {
> +		*polarity = TYPEC_POLARITY_CC2;
> +	} else {
> +		dev_err(dev, "no device detected (cc1=%d cc2=%d)\n", cc1, cc2);
> +		return -ENODEV;
> +	}
> +
> +	ret = ops->set_polarity(dev, *polarity);
> +	if (ret)
> +		return ret;
> +
> +	ops->set_vbus(dev, true, false);
> +	mdelay(300);
> +
> +	return 0;
> +}
> +
> +int tcpm_setup_device_mode(struct udevice *dev, enum typec_cc_polarity *polarity)
> +{
> +	const struct dm_tcpm_ops *ops = dev_get_driver_ops(dev);
> +	enum typec_cc_status cc1, cc2;
> +	int ret, retry;
> +
> +	ops->set_vbus(dev, false, false);
> +
> +	ops->set_cc(dev, TYPEC_CC_RD);
> +
> +	if (ops->start_toggling)
> +		ops->start_toggling(dev, TYPEC_PORT_SNK, TYPEC_CC_RD);
> +
> +	for (retry = 0; retry < 20; retry++) {
> +		mdelay(100);
> +
> +		ret = ops->get_cc(dev, &cc1, &cc2);
> +		if (ret) {
> +			dev_err(dev, "Failed to get cc for device mode: %d\n", ret);
> +			return ret;
> +		}
> +
> +		if (cc1 != TYPEC_CC_OPEN || cc2 != TYPEC_CC_OPEN)
> +			break;
> +	}
> +
> +	if (cc1 != TYPEC_CC_OPEN && cc2 == TYPEC_CC_OPEN) {
> +		*polarity = TYPEC_POLARITY_CC1;
> +	} else if (cc1 == TYPEC_CC_OPEN && cc2 != TYPEC_CC_OPEN) {
> +		*polarity = TYPEC_POLARITY_CC2;
> +	} else {
> +		dev_err(dev, "no host detected (cc1=%d cc2=%d)\n", cc1, cc2);
> +		return -ENODEV;
> +	}
> +
> +	ret = ops->set_polarity(dev, *polarity);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +int tcpm_disable_src_vbus(struct udevice *dev)
> +{
> +	const struct dm_tcpm_ops *ops = dev_get_driver_ops(dev);
> +
> +	return ops->set_vbus(dev, false, false);
> +}
> +
>  UCLASS_DRIVER(tcpm) = {
>  	.id		= UCLASS_TCPM,
>  	.name		= "tcpm",
> diff --git a/include/usb/tcpm.h b/include/usb/tcpm.h
> index 10f0515fe12..caa67a5639d 100644
> --- a/include/usb/tcpm.h
> +++ b/include/usb/tcpm.h
> @@ -96,4 +96,8 @@ enum typec_data_role tcpm_get_data_role(struct udevice *dev);
>  bool tcpm_is_connected(struct udevice *dev);
>  const char *tcpm_get_state(struct udevice *dev);
>  
> +int tcpm_setup_host_mode(struct udevice *dev, enum typec_cc_polarity *polarity);
> +int tcpm_setup_device_mode(struct udevice *dev, enum typec_cc_polarity *polarity);
> +int tcpm_disable_src_vbus(struct udevice *dev);
> +
>  #endif /* __LINUX_USB_TCPM_H */
> 
> -- 
> 2.51.0
>
signature.asc (application/pgp-signature, 833 B)
-----BEGIN PGP SIGNATURE-----

iQIzBAABCgAdFiEE72YNB0Y/i3JqeVQT2O7X88g7+poFAmp6QkIACgkQ2O7X88g7
+poSSA//aolmS5FsD9yjwyiL++x7MfId4MxKrXTqFrR30EPvckgqmbWekix6vOQc
Nw6c/jbAUhyU4f3zLlU1gH8TR8iDvQfkk7JiWXYCgKd1weIMcRaN6U5ABtPQr/do
G9zl1kbyhz0DotM2I0uByRP5QSlqPHPSyWZJc+CWkqbnP6YZSxJIwi97SIKZ7nqJ
zi9qHyKFwoqJ12PcIiwDhcSTytmKWauWU7OAfDQBntWMj9DWu3Vb7A3lTdVPbqY5
h4+AfwqS5UeDdwrQigrYc+KlTzpcLKq/rwaGpTV3qOTS8QaahOnKGVimUpXadfoE
UdlxsO+hpWgpOzm8QBPVW4xOmheCWqttfKF+jBLD3c4EvPVWML9FQqlM9njJ+Se6
vwRelpWJmnHM1foII0N2yHF4gkmHLt6H06mv7eNGLXXzWlK34hZpTqOWcT0wHdhB
MC6mnsvYwCLqdTn13v1+b2FwXKYN8xT7x0MTeWZAXzmkFok0jE4ZtjiQWKw9qoSH
eh3ghXntRXULtqfGOfR3PsUCvKaOQf5lQnLTBccjxbtYFj6bfCrU1HtDpgs15yd+
tHY1SqTvCS94kizkLQR6l3JNBUH4xs681kkyQ/A/35O6GRV3nfn4d1hMeG+F141w
+BMCmlGrEbGnwUQBFuLJNJK1FR97y15MpCWEYnNkoS41u+a/oag=
=rXmG
-----END PGP SIGNATURE-----
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.