bool attached;
        bool connected;
        enum typec_port_type port_type;
+
+       /*
+        * Set to true when vbus is greater than VSAFE5V min.
+        * Set to false when vbus falls below vSinkDisconnect max threshold.
+        */
        bool vbus_present;
+
+       /*
+        * Set to true when vbus is less than VSAFE0V max.
+        * Set to false when vbus is greater than VSAFE0V max.
+        */
+       bool vbus_vsafe0v;
+
        bool vbus_never_low;
        bool vbus_source;
        bool vbus_charge;
                else if (tcpm_port_is_audio(port))
                        tcpm_set_state(port, AUDIO_ACC_ATTACHED,
                                       PD_T_CC_DEBOUNCE);
-               else if (tcpm_port_is_source(port))
+               else if (tcpm_port_is_source(port) && port->vbus_vsafe0v)
                        tcpm_set_state(port,
                                       tcpm_try_snk(port) ? SNK_TRY
                                                          : SRC_ATTACHED,
 {
        tcpm_log_force(port, "VBUS on");
        port->vbus_present = true;
+       /*
+        * When vbus_present is true i.e. Voltage at VBUS is greater than VSAFE5V implicitly
+        * states that vbus is not at VSAFE0V, hence clear the vbus_vsafe0v flag here.
+        */
+       port->vbus_vsafe0v = false;
+
        switch (port->state) {
        case SNK_TRANSITION_SINK_VBUS:
                port->explicit_contract = true;
        case SNK_HARD_RESET_SINK_OFF:
                tcpm_set_state(port, SNK_HARD_RESET_WAIT_VBUS, 0);
                break;
-       case SRC_HARD_RESET_VBUS_OFF:
-               /*
-                * After establishing the vSafe0V voltage condition on VBUS, the Source Shall wait
-                * tSrcRecover before re-applying VCONN and restoring VBUS to vSafe5V.
-                */
-               tcpm_set_state(port, SRC_HARD_RESET_VBUS_ON, PD_T_SRC_RECOVER);
-               break;
        case HARD_RESET_SEND:
                break;
-
        case SNK_TRY:
                /* Do nothing, waiting for timeout */
                break;
        }
 }
 
+static void _tcpm_pd_vbus_vsafe0v(struct tcpm_port *port)
+{
+       tcpm_log_force(port, "VBUS VSAFE0V");
+       port->vbus_vsafe0v = true;
+       switch (port->state) {
+       case SRC_HARD_RESET_VBUS_OFF:
+               /*
+                * After establishing the vSafe0V voltage condition on VBUS, the Source Shall wait
+                * tSrcRecover before re-applying VCONN and restoring VBUS to vSafe5V.
+                */
+               tcpm_set_state(port, SRC_HARD_RESET_VBUS_ON, PD_T_SRC_RECOVER);
+               break;
+       case SRC_ATTACH_WAIT:
+               if (tcpm_port_is_source(port))
+                       tcpm_set_state(port, tcpm_try_snk(port) ? SNK_TRY : SRC_ATTACHED,
+                                      PD_T_CC_DEBOUNCE);
+               break;
+       default:
+               break;
+       }
+}
+
 static void _tcpm_pd_hard_reset(struct tcpm_port *port)
 {
        tcpm_log_force(port, "Received hard reset");
                        bool vbus;
 
                        vbus = port->tcpc->get_vbus(port->tcpc);
-                       if (vbus)
+                       if (vbus) {
                                _tcpm_pd_vbus_on(port);
-                       else
+                       } else {
                                _tcpm_pd_vbus_off(port);
+                               /*
+                                * When TCPC does not support detecting vsafe0v voltage level,
+                                * treat vbus absent as vsafe0v. Else invoke is_vbus_vsafe0v
+                                * to see if vbus has discharge to VSAFE0V.
+                                */
+                               if (!port->tcpc->is_vbus_vsafe0v ||
+                                   port->tcpc->is_vbus_vsafe0v(port->tcpc))
+                                       _tcpm_pd_vbus_vsafe0v(port);
+                       }
                }
                if (events & TCPM_CC_EVENT) {
                        enum typec_cc_status cc1, cc2;
 
  *             will be turned on. requested_vbus_voltage is set to 0 when vbus
  *             is going to disappear knowingly i.e. during PR_SWAP and
  *             HARD_RESET etc.
+ * @is_vbus_vsafe0v:
+ *             Optional; TCPCI spec based TCPC implementations are expected to
+ *             detect VSAFE0V voltage level at vbus. When detection of VSAFE0V
+ *             is supported by TCPC, set this callback for TCPM to query
+ *             whether vbus is at VSAFE0V when needed.
+ *             Returns true when vbus is at VSAFE0V, false otherwise.
  */
 struct tcpc_dev {
        struct fwnode_handle *fwnode;
        int (*enable_auto_vbus_discharge)(struct tcpc_dev *dev, bool enable);
        int (*set_auto_vbus_discharge_threshold)(struct tcpc_dev *dev, enum typec_pwr_opmode mode,
                                                 bool pps_active, u32 requested_vbus_voltage);
+       bool (*is_vbus_vsafe0v)(struct tcpc_dev *dev);
 };
 
 struct tcpm_port;