diff --git a/drivers/hte/Kconfig b/drivers/hte/Kconfig
index f7b01fcc7190..c4d335c41254 100644
--- a/drivers/hte/Kconfig
+++ b/drivers/hte/Kconfig
@@ -31,4 +31,11 @@ config HTE_TEGRA194
 	  systems-on-chip. The driver supports 352 LIC IRQs and 39 AON GPIOs
 	  lines for timestamping in realtime.
 
+config HTE_TEGRA194_IRQ_TEST
+        tristate "NVIDIA Tegra194 HTE LIC IRQ Test"
+        depends on HTE_TEGRA194
+        help
+          The NVIDIA Tegra194 GTE IRQ test driver demonstrates HTE subsystem
+	  usage for the LIC IRQ hardware timestamp.
+
 endif
diff --git a/drivers/hte/Makefile b/drivers/hte/Makefile
index 52f978cfc913..b1cde6bc939b 100644
--- a/drivers/hte/Makefile
+++ b/drivers/hte/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_HTE)		+= hte.o
-obj-$(CONFIG_HTE_TEGRA194)	+= hte-tegra194.o
\ No newline at end of file
+obj-$(CONFIG_HTE_TEGRA194)	+= hte-tegra194.o
+obj-$(CONFIG_HTE_TEGRA194_IRQ_TEST) += hte-tegra194-irq-test.o
\ No newline at end of file
diff --git a/drivers/hte/hte-tegra194-irq-test.c b/drivers/hte/hte-tegra194-irq-test.c
new file mode 100644
index 000000000000..c51eaeb3d1ea
--- /dev/null
+++ b/drivers/hte/hte-tegra194-irq-test.c
@@ -0,0 +1,400 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2021 NVIDIA Corporation
+ *
+ * Author: Dipen Patel <dipenp@nvidia.com>
+ */
+
+#include <linux/version.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
+#include <linux/hte.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+
+/*
+ * Tegra194 On chip HTE (hardware timestamping engine) also known as GTE
+ * (generic timestamping engine) can monitor LIC (Legacy interrupt controller)
+ * IRQ lines for the event and timestamp accordingly in realtime. Follow
+ * technical reference manual for the IRQ numbers and descriptions.
+ *
+ * This sample HTE IRQ test driver demonstrating HTE API usage by enabling
+ * lic irq line in HTE to monitor and timestamp.
+ */
+
+/*
+ * Used to increase line buffer length to this power in case of the dropped
+ * timestamps.
+ */
+static unsigned int len_pow = 2;
+module_param(len_pow, uint, 0660);
+
+static struct tegra_hte_test {
+	size_t buf_len;
+	bool update_buf_len;
+	struct hte_ts_desc *desc;
+	struct work_struct ev_work;
+	struct kobject *kobj;
+	struct device *pdev;
+} hte;
+
+static void hte_callback(enum hte_notify n)
+{
+	if (n == HTE_TS_AVAIL) {
+		hte.update_buf_len = false;
+	} else if (n == HTE_TS_DROPPED) {
+		dev_info(hte.pdev, "Timestamp dropped\n");
+		hte.update_buf_len = true;
+	} else {
+		dev_dbg(hte.pdev, "Wrong notify value (%d)\n", n);
+		return;
+	}
+	schedule_work(&hte.ev_work);
+}
+
+static void tegra_hte_irq_get_ts(void)
+{
+	int ret, i;
+	size_t avail;
+	struct hte_ts_data *el;
+
+	avail = hte_available_ts(hte.desc);
+
+	/*
+	 * Workqueue only got scheduled from the hte_callback, it is highly
+	 * unlikely that there is no timestamp to retrieve.
+	 */
+	if (unlikely(!avail)) {
+		dev_dbg(hte.pdev, "timestamp not available\n");
+		goto error;
+	}
+
+	el = kzalloc(avail * sizeof(*el), GFP_KERNEL);
+	if (!el) {
+		dev_dbg(hte.pdev, "Can not allocate %lu bytes memory\n",
+			avail * sizeof(*el));
+		/*
+		 * We have two options here:
+		 * 1. Release the line as system is running low memory.
+		 * 2. Run an loop to retrieve an element till its drained.
+		 *
+		 * We will use 1st option.
+		 */
+		goto error;
+	}
+
+	ret = hte_retrieve_ts_ns_wait(hte.desc, el, avail);
+	if (ret < 0) {
+		dev_dbg(hte.pdev,
+			"Something went wrong retrieving timestamp data\n");
+		kfree(el);
+		goto error;
+	}
+
+	for (i = 0; i < avail; i++) {
+		dev_info(hte.pdev, "IRQ HW timestamp(%llu): %llu, edge: %s\n",
+			 el[i].seq, el[i].tsc,
+			 (el[i].dir == 1) ? "rising" : "falling");
+	}
+
+	kfree(el);
+
+	return;
+
+error:
+	hte_release_ts(hte.desc);
+}
+
+static void hte_ts_work(struct work_struct *data)
+{
+	size_t temp;
+	int ret;
+	(void) data;
+
+	if (hte.update_buf_len) {
+		ret = hte_disable_ts(hte.desc);
+		if (ret) {
+			dev_err(hte.pdev, "Not able to disable line\n");
+			goto error;
+		}
+
+		temp = hte.buf_len * len_pow;
+		ret = hte_set_buf_len(hte.desc, temp);
+		if (ret) {
+			dev_err(hte.pdev, "Not able to set new buf len (%lu)\n",
+				temp);
+			goto error;
+		}
+
+		hte.buf_len = hte_get_buf_len(hte.desc);
+		if (unlikely(hte.buf_len != temp)) {
+			dev_err(hte.pdev, "New length is (%lu) != (%lu)\n",
+				hte.buf_len, temp);
+			goto error;
+		}
+
+		dev_dbg(hte.pdev, "New buffer length (%lu)\n", hte.buf_len);
+		hte.update_buf_len = false;
+		ret = hte_enable_ts(hte.desc);
+		if (ret) {
+			dev_err(hte.pdev, "failed to enable line\n");
+			goto error;
+		}
+
+		return;
+	}
+
+	tegra_hte_irq_get_ts();
+
+	return;
+
+error:
+	hte_release_ts(hte.desc);
+}
+
+/*
+ * Sysfs attribute to request/release HTE IRQ line.
+ */
+static ssize_t store_en_dis(struct kobject *kobj,
+			    struct kobj_attribute *attr,
+			    const char *buf, size_t count)
+{
+	int ret = count;
+	unsigned long val = 0;
+	struct hte_clk_info ci;
+
+	if (kstrtoul(buf, 10, &val) < 0) {
+		ret = -EINVAL;
+		goto error;
+	}
+
+	if (val == 1) {
+		if (hte.desc) {
+			ret = -EEXIST;
+			goto error;
+		}
+
+		hte.desc = devm_of_hte_request_ts(hte.pdev, "hte-lic",
+						  hte_callback);
+		if (IS_ERR(hte.desc)) {
+			ret = PTR_ERR(hte.desc);
+			hte.desc = NULL;
+			goto error;
+		}
+
+		hte_get_clk_src_info(hte.desc, &ci);
+		dev_info(hte.pdev, "clk rate:%llu, clk type: %d\n",
+			 ci.hz, ci.type);
+
+		hte.buf_len = hte_get_buf_len(hte.desc);
+		if (hte.buf_len < 0) {
+			ret = hte.buf_len;
+			hte_release_ts(hte.desc);
+			hte.desc = NULL;
+			goto error;
+		}
+	} else if (val == 0) {
+		if (!hte.desc) {
+			ret = -EINVAL;
+			goto error;
+		}
+		/*
+		 * Ideally, you never need to call this API, simply removing
+		 * this module should be enough, it is being called here just
+		 * for demonstration.
+		 */
+		ret = devm_hte_release_ts(hte.pdev, hte.desc);
+		if (ret)
+			goto error;
+
+		hte.desc = NULL;
+	}
+
+	ret = count;
+
+error:
+	return ret;
+}
+
+struct kobj_attribute en_dis_attr =
+		__ATTR(en_dis, 0220, NULL, store_en_dis);
+
+/*
+ * Sysfs attribute to set/get watermark.
+ */
+static ssize_t store_watermark(struct kobject *kobj,
+			       struct kobj_attribute *attr,
+			       const char *buf, size_t count)
+{
+	int ret = count;
+	size_t val = 0;
+
+	if (kstrtoul(buf, 10, &val) < 0) {
+		ret = -EINVAL;
+		goto error;
+	}
+
+	if (hte.desc) {
+		ret = hte_set_buf_watermark(hte.desc, val);
+		if (ret < 0)
+			goto error;
+	} else {
+		ret = -EINVAL;
+		goto error;
+	}
+
+	ret = count;
+
+error:
+	return ret;
+}
+
+static ssize_t show_watermark(struct kobject *kobj,
+			      struct kobj_attribute *attr,
+			      char *buf)
+{
+	size_t ret;
+
+	if (hte.desc) {
+		ret = hte_get_buf_watermark(hte.desc);
+		if (!ret)
+			goto error;
+	} else {
+		goto error;
+	}
+
+	return scnprintf(buf, PAGE_SIZE, "%lu\n", ret);
+
+error:
+	return -EINVAL;
+}
+
+struct kobj_attribute watermark_attr =
+		__ATTR(watermark, 0660, show_watermark, store_watermark);
+
+/*
+ * Sysfs attribute to set/get buffer.
+ */
+static ssize_t store_buf_len(struct kobject *kobj,
+			     struct kobj_attribute *attr,
+			     const char *buf, size_t count)
+{
+	int ret = count;
+	size_t val = 0;
+
+	if (kstrtoul(buf, 10, &val) < 0) {
+		ret = -EINVAL;
+		goto error;
+	}
+
+	if (hte.desc) {
+		ret = hte_set_buf_len(hte.desc, val);
+		if (ret < 0)
+			goto error;
+	} else {
+		ret = -EINVAL;
+		goto error;
+	}
+
+	ret = count;
+
+error:
+	return ret;
+}
+
+static ssize_t show_buf_len(struct kobject *kobj,
+			    struct kobj_attribute *attr,
+			    char *buf)
+{
+	size_t ret;
+
+	if (hte.desc) {
+		ret = hte_get_buf_len(hte.desc);
+		if (!ret)
+			goto error;
+	} else {
+		goto error;
+	}
+
+	return scnprintf(buf, PAGE_SIZE, "%lu\n", ret);
+
+error:
+	return -EINVAL;
+}
+
+struct kobj_attribute buf_len_attr =
+		__ATTR(buf_len, 0660, show_buf_len, store_buf_len);
+
+static struct attribute *attrs[] = {
+	&en_dis_attr.attr,
+	&watermark_attr.attr,
+	&buf_len_attr.attr,
+	NULL,
+};
+
+static struct attribute_group tegra_hte_test_attr_group = {
+	.attrs = attrs,
+};
+
+static int tegra_hte_test_sysfs_create(void)
+{
+	int ret;
+
+	/* Creates /sys/kernel/tegra_hte_irq_test */
+	hte.kobj = kobject_create_and_add("tegra_hte_irq_test", kernel_kobj);
+	if (!hte.kobj)
+		return -ENOMEM;
+
+	ret = sysfs_create_group(hte.kobj, &tegra_hte_test_attr_group);
+	if (ret)
+		kobject_put(hte.kobj);
+	return ret;
+}
+
+static const struct of_device_id tegra_hte_irq_test_of_match[] = {
+	{ .compatible = "nvidia,tegra194-hte-irq-test"},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, tegra_hte_irq_test_of_match);
+
+static int tegra_hte_test_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	dev_set_drvdata(&pdev->dev, &hte);
+	hte.pdev = &pdev->dev;
+
+	ret = tegra_hte_test_sysfs_create();
+	if (ret != 0) {
+		dev_err(hte.pdev, "sysfs creation failed\n");
+		return -ENXIO;
+	}
+
+	INIT_WORK(&hte.ev_work, hte_ts_work);
+
+	return 0;
+}
+
+static int tegra_hte_test_remove(struct platform_device *pdev)
+{
+	cancel_work_sync(&hte.ev_work);
+	kobject_put(hte.kobj);
+
+	return 0;
+}
+
+static struct platform_driver tegra_hte_irq_test_driver = {
+	.probe = tegra_hte_test_probe,
+	.remove = tegra_hte_test_remove,
+	.driver = {
+		.name = "tegra_hte_irq_test",
+		.of_match_table = tegra_hte_irq_test_of_match,
+	},
+};
+module_platform_driver(tegra_hte_irq_test_driver);
+
+MODULE_AUTHOR("Dipen Patel <dipenp@nvidia.com>");
+MODULE_LICENSE("GPL v2");
