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
> 

Attachment: signature.asc
Description: PGP signature

Reply via email to