diff --git a/ethtool.8.in b/ethtool.8.in
index 9e272f7056a8c9122b122ade745f3bc601c13c27..7188e6ab5005cd0221ae0d2c6a0ec6a1566181fc 100644
--- a/ethtool.8.in
+++ b/ethtool.8.in
@@ -342,6 +342,10 @@ ethtool \- query or control network driver and hardware settings
 .HP
 .B ethtool \-T|\-\-show\-time\-stamping
 .I devname
+.RB [ index
+.IR N
+.BI qualifier
+.IR precise|approx ]
 .HP
 .B ethtool \-x|\-\-show\-rxfh\-indir|\-\-show\-rxfh
 .I devname
@@ -1233,7 +1237,17 @@ Sets the dump flag for the device.
 .TP
 .B \-T \-\-show\-time\-stamping
 Show the device's time stamping capabilities and associated PTP
-hardware clock.
+hardware clock. Show the capabilities of the currently selected time
+stamping if no \fBindex\fR and \fBqualifier\fR is provided.
+.RS 4
+.TP
+.BI index \ N
+Index of the ptp hardware clock
+.TP
+.BI qualifier \ precise | approx
+Qualifier of the ptp hardware clock. Mainly "precise" the default one is
+for IEEE 1588 quality and "approx" is for NICs DMA point.
+.RE
 .TP
 .B \-x \-\-show\-rxfh\-indir \-\-show\-rxfh
 Retrieves the receive flow hash indirection table and/or RSS hash key.
diff --git a/ethtool.c b/ethtool.c
index a1393bc14b7b1a473853965fd3557b51efabc3c6..cd3434021857e8c441325e321378323481fd98e0 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -5974,7 +5974,8 @@ static const struct option args[] = {
 		.opts	= "-T|--show-time-stamping",
 		.func	= do_tsinfo,
 		.nlfunc	= nl_tsinfo,
-		.help	= "Show time stamping capabilities"
+		.help	= "Show time stamping capabilities",
+		.xhelp	= "		[ index N qualifier precise|approx ]\n"
 	},
 	{
 		.opts	= "-x|--show-rxfh-indir|--show-rxfh",
diff --git a/netlink/tsinfo.c b/netlink/tsinfo.c
index 4df41415dc478415fa5e991b31c4feb91b0cb5e4..c12070fc877b68d925d845caee6fe8a126e19882 100644
--- a/netlink/tsinfo.c
+++ b/netlink/tsinfo.c
@@ -13,9 +13,44 @@
 #include "../common.h"
 #include "netlink.h"
 #include "bitset.h"
+#include "parser.h"
 
 /* TSINFO_GET */
 
+static const char *tsinfo_hwprov_qualifier_names(u32 val)
+{
+	switch (val) {
+	case HWTSTAMP_PROVIDER_QUALIFIER_PRECISE:
+		return "Precise (IEEE 1588 quality)";
+	case HWTSTAMP_PROVIDER_QUALIFIER_APPROX:
+		return "Approximate";
+	default:
+		return "unsupported";
+	}
+}
+
+static int tsinfo_show_hwprov(const struct nlattr *nest)
+{
+	const struct nlattr *tb[ETHTOOL_A_TS_HWTSTAMP_PROVIDER_MAX + 1] = {};
+	DECLARE_ATTR_TB_INFO(tb);
+	u32 val;
+	int ret;
+
+	ret = mnl_attr_parse_nested(nest, attr_cb, &tb_info);
+	if (ret < 0)
+		return ret;
+
+	val = mnl_attr_get_u32(tb[ETHTOOL_A_TS_HWTSTAMP_PROVIDER_INDEX]);
+	print_uint(PRINT_ANY, "hwtstamp-provider-index",
+		   "Hardware timestamp provider index: %u\n", val);
+	val = mnl_attr_get_u32(tb[ETHTOOL_A_TS_HWTSTAMP_PROVIDER_QUALIFIER]);
+	print_string(PRINT_ANY, "hwtstamp-provider-qualifier",
+		     "Hardware timestamp provider qualifier: %s\n",
+		     tsinfo_hwprov_qualifier_names(val));
+
+	return 0;
+}
+
 static int tsinfo_show_stats(const struct nlattr *nest)
 {
 	const struct nlattr *tb[ETHTOOL_A_TS_STAT_MAX + 1] = {};
@@ -135,12 +170,19 @@ int tsinfo_reply_cb(const struct nlmsghdr *nlhdr, void *data)
 	if (ret < 0)
 		return err_ret;
 
-	printf("PTP Hardware Clock: ");
-	if (tb[ETHTOOL_A_TSINFO_PHC_INDEX])
+	if (tb[ETHTOOL_A_TSINFO_HWTSTAMP_PROVIDER]) {
+		ret = tsinfo_show_hwprov(tb[ETHTOOL_A_TSINFO_HWTSTAMP_PROVIDER]);
+		if (ret < 0)
+			return err_ret;
+
+	} else if (tb[ETHTOOL_A_TSINFO_PHC_INDEX]) {
+		printf("PTP Hardware Clock: ");
 		printf("%d\n",
 		       mnl_attr_get_u32(tb[ETHTOOL_A_TSINFO_PHC_INDEX]));
-	else
+	} else {
+		printf("PTP Hardware Clock: ");
 		printf("none\n");
+	}
 
 	ret = tsinfo_dump_list(nlctx, tb[ETHTOOL_A_TSINFO_TX_TYPES],
 			       "Hardware Transmit Timestamp Modes", " none",
@@ -163,6 +205,46 @@ int tsinfo_reply_cb(const struct nlmsghdr *nlhdr, void *data)
 	return MNL_CB_OK;
 }
 
+static int tsinfo_qualifier_parser(struct nl_context *nlctx,
+				   uint16_t type __maybe_unused,
+				   const void *data __maybe_unused,
+				   struct nl_msg_buff *msgbuff __maybe_unused,
+				   void *dest __maybe_unused)
+{
+	const char *arg = *nlctx->argp;
+	u32 val;
+
+	nlctx->argp++;
+	nlctx->argc--;
+
+	if (!strncmp(arg, "precise", sizeof("precise")))
+		val = HWTSTAMP_PROVIDER_QUALIFIER_PRECISE;
+	else if (!strncmp(arg, "approx", sizeof("approx")))
+		val = HWTSTAMP_PROVIDER_QUALIFIER_APPROX;
+	else
+		return -EINVAL;
+
+	return (type && ethnla_put_u32(msgbuff, type, val)) ? -EMSGSIZE : 0;
+}
+
+static const struct param_parser tsinfo_params[] = {
+	{
+		.arg		= "index",
+		.type		= ETHTOOL_A_TS_HWTSTAMP_PROVIDER_INDEX,
+		.group		= ETHTOOL_A_TSINFO_HWTSTAMP_PROVIDER,
+		.handler	= nl_parse_direct_u32,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "qualifier",
+		.type		= ETHTOOL_A_TS_HWTSTAMP_PROVIDER_QUALIFIER,
+		.group		= ETHTOOL_A_TSINFO_HWTSTAMP_PROVIDER,
+		.handler	= tsinfo_qualifier_parser,
+		.min_argc	= 1,
+	},
+	{}
+};
+
 int nl_tsinfo(struct cmd_context *ctx)
 {
 	struct nl_context *nlctx = ctx->nlctx;
@@ -172,16 +254,21 @@ int nl_tsinfo(struct cmd_context *ctx)
 
 	if (netlink_cmd_check(ctx, ETHTOOL_MSG_TSINFO_GET, true))
 		return -EOPNOTSUPP;
-	if (ctx->argc > 0) {
-		fprintf(stderr, "ethtool: unexpected parameter '%s'\n",
-			*ctx->argp);
-		return 1;
-	}
 
 	flags = get_stats_flag(nlctx, ETHTOOL_MSG_TSINFO_GET, ETHTOOL_A_TSINFO_HEADER);
 	ret = nlsock_prep_get_request(nlsk, ETHTOOL_MSG_TSINFO_GET,
 				      ETHTOOL_A_TSINFO_HEADER, flags);
 	if (ret < 0)
 		return ret;
+
+	nlctx->cmd = "-T";
+	nlctx->argp = ctx->argp;
+	nlctx->argc = ctx->argc;
+	nlctx->devname = ctx->devname;
+
+	ret = nl_parser(nlctx, tsinfo_params, NULL, PARSER_GROUP_NEST, NULL);
+	if (ret < 0)
+		return ret;
+
 	return nlsock_send_get_request(nlsk, tsinfo_reply_cb);
 }
