diff --git a/Documentation/ABI/testing/sysfs-ptp b/Documentation/ABI/testing/sysfs-ptp
index 9c317ac7c47a..9d9875e7c56a 100644
--- a/Documentation/ABI/testing/sysfs-ptp
+++ b/Documentation/ABI/testing/sysfs-ptp
@@ -81,6 +81,22 @@ Description:
 		switches the physical clock back to normal, adjustable
 		operation.
 
+What:		/sys/class/ptp/ptp<N>/dmtsc_en_flags
+Date:		August 2023
+Contact:	Xabier Marquiegui <reibax@gmail.com>
+Description:
+		This read/write file controls the de-multiplexing of 
+		external timestamp channel fifos. In write more, you
+		can de-multiplex by enabling a channel or re-multiplex
+		it by disabling it. Write mode can be done in channel mode
+		for single channel control "c 0 1" or mask mode for 
+		multi-channel "m 0x3 1". Syntax is:
+		<mode (m/c)> <value> <enable (0/1)>
+		In read mode you get the enable mask for all channels in 
+		hex.
+		See function dmtsc_en_flags_store on 
+		drivers/ptp/ptp_sysfs.c for more details.
+
 What:		/sys/class/ptp/ptp<N>/pins
 Date:		March 2014
 Contact:	Richard Cochran <richardcochran@gmail.com>
diff --git a/MAINTAINERS b/MAINTAINERS
index 4cc6bf79fdd8..8d9a24039d67 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17171,6 +17171,11 @@ S:	Maintained
 F:	drivers/ptp/ptp_vclock.c
 F:	net/ethtool/phc_vclocks.c
 
+PTP DEMUXED TS CHANEL FIFOS
+M: Xabier Marquiegui <reibax@gmail.com>
+S: Maintained
+F: drivers/ptp/ptp_demuxtschan.c
+
 PTRACE SUPPORT
 M:	Oleg Nesterov <oleg@redhat.com>
 S:	Maintained
diff --git a/drivers/ptp/Makefile b/drivers/ptp/Makefile
index 553f18bf3c83..6dbae0b9aa7c 100644
--- a/drivers/ptp/Makefile
+++ b/drivers/ptp/Makefile
@@ -3,7 +3,7 @@
 # Makefile for PTP 1588 clock support.
 #
 
-ptp-y					:= ptp_clock.o ptp_chardev.o ptp_sysfs.o ptp_vclock.o
+ptp-y					:= ptp_clock.o ptp_chardev.o ptp_sysfs.o ptp_vclock.o ptp_demuxtschan.o
 ptp_kvm-$(CONFIG_X86)			:= ptp_kvm_x86.o ptp_kvm_common.o
 ptp_kvm-$(CONFIG_HAVE_ARM_SMCCC)	:= ptp_kvm_arm.o ptp_kvm_common.o
 obj-$(CONFIG_PTP_1588_CLOCK)		+= ptp.o
diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c
index 362bf756e6b7..0c900042c389 100644
--- a/drivers/ptp/ptp_chardev.c
+++ b/drivers/ptp/ptp_chardev.c
@@ -441,8 +441,6 @@ __poll_t ptp_poll(struct posix_clock *pc, struct file *fp, poll_table *wait)
 	return queue_cnt(&ptp->tsevq) ? EPOLLIN : 0;
 }
 
-#define EXTTS_BUFSIZE (PTP_BUF_TIMESTAMPS * sizeof(struct ptp_extts_event))
-
 ssize_t ptp_read(struct posix_clock *pc,
 		 uint rdflags, char __user *buf, size_t cnt)
 {
diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c
index 80f74e38c2da..383508c269a2 100644
--- a/drivers/ptp/ptp_clock.c
+++ b/drivers/ptp/ptp_clock.c
@@ -172,6 +172,8 @@ static void ptp_clock_release(struct device *dev)
 
 	ptp_cleanup_pin_groups(ptp);
 	kfree(ptp->vclock_index);
+	mutex_destroy(&ptp->dmtsc_devs.dmtsc_devs_mux);
+	mutex_destroy(&ptp->dmtsc_sysfs_mux);
 	mutex_destroy(&ptp->tsevq_mux);
 	mutex_destroy(&ptp->pincfg_mux);
 	mutex_destroy(&ptp->n_vclocks_mux);
@@ -232,7 +234,13 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,
 	mutex_init(&ptp->tsevq_mux);
 	mutex_init(&ptp->pincfg_mux);
 	mutex_init(&ptp->n_vclocks_mux);
+	mutex_init(&ptp->dmtsc_sysfs_mux);
+	mutex_init(&ptp->dmtsc_devs.dmtsc_devs_mux);
 	init_waitqueue_head(&ptp->tsev_wq);
+	ptp->dmtsc_en_flags = 0x0;
+	ptp->dmtscevq = NULL;
+	ptp->dmtsc_devs.readers = 0;
+	ptp->dmtsc_devs.clean_request = false;
 
 	if (ptp->info->getcycles64 || ptp->info->getcyclesx64) {
 		ptp->has_cycles = true;
@@ -330,6 +338,8 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,
 	if (ptp->kworker)
 		kthread_destroy_worker(ptp->kworker);
 kworker_err:
+	mutex_destroy(&ptp->dmtsc_devs.dmtsc_devs_mux);
+	mutex_destroy(&ptp->dmtsc_sysfs_mux);
 	mutex_destroy(&ptp->tsevq_mux);
 	mutex_destroy(&ptp->pincfg_mux);
 	mutex_destroy(&ptp->n_vclocks_mux);
@@ -351,6 +361,8 @@ static int unregister_vclock(struct device *dev, void *data)
 
 int ptp_clock_unregister(struct ptp_clock *ptp)
 {
+	ptp_dmtsc_dev_uregister(ptp);
+
 	if (ptp_vclock_in_use(ptp)) {
 		device_for_each_child(&ptp->dev, NULL, unregister_vclock);
 	}
@@ -383,7 +395,15 @@ void ptp_clock_event(struct ptp_clock *ptp, struct ptp_clock_event *event)
 		break;
 
 	case PTP_CLOCK_EXTTS:
-		enqueue_external_timestamp(&ptp->tsevq, event);
+		/* If event index demuxed queue mask is enabled send to dedicated fifo */
+		if (ptp->dmtsc_en_flags & (0x1 << event->index)) {
+			enqueue_external_timestamp(&ptp->dmtscevq[event->index], event);
+		}
+		else
+		{
+			enqueue_external_timestamp(&ptp->tsevq, event);
+		}
+
 		wake_up_interruptible(&ptp->tsev_wq);
 		break;
 
diff --git a/drivers/ptp/ptp_demuxtschan.c b/drivers/ptp/ptp_demuxtschan.c
new file mode 100644
index 000000000000..516a1dabe8dd
--- /dev/null
+++ b/drivers/ptp/ptp_demuxtschan.c
@@ -0,0 +1,211 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * PTP exploded timestamp event queue driver
+ *
+ * Copyright 2023 Aingura IIoT
+ */
+
+#include <linux/slab.h>
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include "ptp_private.h"
+
+static int ptp_dmtsc_open(struct inode *inode, struct file *file)
+{
+    struct ptp_dmtsc_cdev_info *cdev = container_of(inode->i_cdev,
+                struct ptp_dmtsc_cdev_info, dmtsc_cdev);
+
+    file->private_data = cdev;
+
+    if (mutex_lock_interruptible(&cdev->pclock->dmtsc_devs.dmtsc_devs_mux))
+		return -ERESTARTSYS;
+    cdev->pclock->dmtsc_devs.readers++;
+    mutex_unlock(&cdev->pclock->dmtsc_devs.dmtsc_devs_mux);
+
+	return stream_open(inode, file);
+}
+
+int ptp_dmtsc_release (struct inode *inode, struct file *file)
+{
+    struct ptp_dmtsc_cdev_info *cdev = file->private_data;
+
+    if (mutex_lock_interruptible(&cdev->pclock->dmtsc_devs.dmtsc_devs_mux))
+		return -ERESTARTSYS;
+    cdev->pclock->dmtsc_devs.readers--;
+
+    if ((cdev->pclock->dmtsc_devs.readers == 0) &&
+        cdev->pclock->dmtsc_devs.clean_request) {
+            mutex_unlock(&cdev->pclock->dmtsc_devs.dmtsc_devs_mux);
+            ptp_dmtsc_dev_uregister(cdev->pclock);
+        }
+    mutex_unlock(&cdev->pclock->dmtsc_devs.dmtsc_devs_mux);
+    return 0;
+}
+
+ssize_t ptp_dmtsc_read(struct file *file, char __user *buf,
+		      size_t cnt, loff_t *offset)
+{
+    struct ptp_dmtsc_cdev_info *cdev = file->private_data;
+	struct timestamp_event_queue *queue = &cdev->pclock->dmtscevq[cdev->minor];
+    struct mutex *dmtsceq_mux = &cdev->pclock->dmtsc_devs.cdev_info[cdev->minor].dmtsceq_mux;
+	struct ptp_extts_event *event;
+	unsigned long flags;
+	size_t qcnt, i;
+	int result;
+
+	if (cnt % sizeof(struct ptp_extts_event) != 0)
+		return -EINVAL;
+
+	if (cnt > EXTTS_BUFSIZE)
+		cnt = EXTTS_BUFSIZE;
+
+	cnt = cnt / sizeof(struct ptp_extts_event);
+
+	if (mutex_lock_interruptible(dmtsceq_mux))
+		return -ERESTARTSYS;
+
+	if (wait_event_interruptible(cdev->pclock->tsev_wq,
+				     cdev->pclock->defunct || queue_cnt(queue))) {
+		mutex_unlock(dmtsceq_mux);
+		return -ERESTARTSYS;
+	}
+
+	if (cdev->pclock->defunct) {
+		mutex_unlock(dmtsceq_mux);
+		return -ENODEV;
+	}
+
+	event = kmalloc(EXTTS_BUFSIZE, GFP_KERNEL);
+	if (!event) {
+		mutex_unlock(dmtsceq_mux);
+		return -ENOMEM;
+	}
+
+	spin_lock_irqsave(&queue->lock, flags);
+
+	qcnt = queue_cnt(queue);
+
+	if (cnt > qcnt)
+		cnt = qcnt;
+
+	for (i = 0; i < cnt; i++) {
+		event[i] = queue->buf[queue->head];
+		queue->head = (queue->head + 1) % PTP_MAX_TIMESTAMPS;
+	}
+
+	spin_unlock_irqrestore(&queue->lock, flags);
+
+	cnt = cnt * sizeof(struct ptp_extts_event);
+
+	mutex_unlock(dmtsceq_mux);
+
+	result = cnt;
+	if (copy_to_user(buf, event, cnt))
+		result = -EFAULT;
+
+	kfree(event);
+	return result;
+}
+
+struct file_operations fops = {
+	.owner = THIS_MODULE,
+	.open = ptp_dmtsc_open,
+	.read = ptp_dmtsc_read,
+    .release = ptp_dmtsc_release
+};
+
+void ptp_dmtsc_cdev_clean(struct ptp_clock *ptp)
+{
+    int idx, major;
+    dev_t device;
+
+    major = MAJOR(ptp->dmtsc_devs.devid);
+    for (idx = 0; idx < ptp->info->n_ext_ts ; idx++) {
+        if (ptp->dmtsc_devs.cdev_info[idx].minor >= 0) {
+            device = MKDEV(major, idx);
+            device_destroy(ptp->dmtsc_devs.dmtsc_class, device);
+            cdev_del(&ptp->dmtsc_devs.cdev_info[idx].dmtsc_cdev);
+            ptp->dmtsc_devs.cdev_info[idx].minor = -1;
+        }
+    }
+    class_destroy(ptp->dmtsc_devs.dmtsc_class);
+    unregister_chrdev_region(ptp->dmtsc_devs.devid, ptp->info->n_ext_ts);
+    mutex_destroy(&ptp->dmtsc_devs.cdev_info[idx].dmtsceq_mux);
+}
+
+int ptp_dmtsc_dev_register(struct ptp_clock *ptp)
+{
+    int err, idx, major;
+    dev_t device;
+    struct device *dev;
+
+    // Create fifos for all channels. The mask will control which of them get fed
+    ptp->dmtscevq = kcalloc(ptp->info->n_ext_ts, sizeof(*ptp->dmtscevq), GFP_KERNEL);
+    if (!ptp->dmtscevq) {
+        err = -EFAULT;
+        goto err;
+    }
+    ptp->dmtsc_devs.cdev_info = kcalloc(ptp->info->n_ext_ts,
+        sizeof(*ptp->dmtsc_devs.cdev_info), GFP_KERNEL);
+    if (!ptp->dmtsc_devs.cdev_info) {
+        err = -ENODEV;
+        goto fifo_clean;
+    }
+    for (idx = 0; idx < ptp->info->n_ext_ts ; idx++) {
+        ptp->dmtsc_devs.cdev_info[idx].minor = -1;
+    }
+    // Create devices for all channels. The mask will control which of them get fed
+    err = alloc_chrdev_region(&ptp->dmtsc_devs.devid, 0, ptp->info->n_ext_ts, "ptptsevqch");
+    if (!err) {
+        major = MAJOR(ptp->dmtsc_devs.devid);
+        ptp->dmtsc_devs.dmtsc_class = class_create(THIS_MODULE, "ptptsevqch_class");
+        for (idx = 0; idx < ptp->info->n_ext_ts ; idx++) {
+            mutex_init(&ptp->dmtsc_devs.cdev_info[idx].dmtsceq_mux);
+            device = MKDEV(major, idx);
+            ptp->dmtsc_devs.cdev_info[idx].pclock = ptp;
+            cdev_init(&ptp->dmtsc_devs.cdev_info[idx].dmtsc_cdev, &fops);
+            err = cdev_add(&ptp->dmtsc_devs.cdev_info[idx].dmtsc_cdev, device, 1);
+            if (err) {
+                goto cdev_clean;
+            } else {
+                ptp->dmtsc_devs.cdev_info[idx].minor = idx;
+                dev = device_create(ptp->dmtsc_devs.dmtsc_class, &ptp->dev, device, NULL, "ptp%dch%d", ptp->index, idx);
+                if (IS_ERR(dev)) {
+                    err = PTR_ERR(dev);
+                    goto cdev_clean;
+                }
+            }
+        }
+    } else {
+        goto dev_clean;
+    }
+    return 0;
+
+cdev_clean:
+    ptp_dmtsc_cdev_clean(ptp);
+dev_clean:
+    kfree(ptp->dmtsc_devs.cdev_info);
+    ptp->dmtsc_devs.cdev_info = NULL;
+fifo_clean:
+    kfree(ptp->dmtscevq);
+    ptp->dmtscevq = NULL;
+err:
+    return err;
+}
+
+void ptp_dmtsc_dev_uregister(struct ptp_clock *ptp)
+{
+    if (mutex_lock_interruptible(&ptp->dmtsc_devs.dmtsc_devs_mux))
+		return;
+    if (ptp->dmtsc_devs.readers > 0) {
+        ptp->dmtsc_devs.clean_request = true;
+        mutex_unlock(&ptp->dmtsc_devs.dmtsc_devs_mux);
+        return;
+    }
+    mutex_unlock(&ptp->dmtsc_devs.dmtsc_devs_mux);
+    ptp_dmtsc_cdev_clean(ptp);
+    kfree(ptp->dmtsc_devs.cdev_info);
+    ptp->dmtsc_devs.cdev_info = NULL;
+    kfree(ptp->dmtscevq);
+    ptp->dmtscevq = NULL;
+}
\ No newline at end of file
diff --git a/drivers/ptp/ptp_private.h b/drivers/ptp/ptp_private.h
index 75f58fc468a7..9fc7b6ec6517 100644
--- a/drivers/ptp/ptp_private.h
+++ b/drivers/ptp/ptp_private.h
@@ -20,6 +20,8 @@
 #define PTP_BUF_TIMESTAMPS 30
 #define PTP_DEFAULT_MAX_VCLOCKS 20
 
+#define EXTTS_BUFSIZE (PTP_BUF_TIMESTAMPS * sizeof(struct ptp_extts_event))
+
 struct timestamp_event_queue {
 	struct ptp_extts_event buf[PTP_MAX_TIMESTAMPS];
 	int head;
@@ -27,6 +29,22 @@ struct timestamp_event_queue {
 	spinlock_t lock;
 };
 
+struct ptp_dmtsc_cdev_info {
+	struct cdev dmtsc_cdev; /* Demuxed event device chardev */
+	int minor; /* Demuxed event queue chardev device minor */
+	struct ptp_clock *pclock; /* Direct access to parent clock device */
+	struct mutex dmtsceq_mux; /* Protect access to demuxed event queue */
+};
+
+struct ptp_dmtsc_dev_info {
+	dev_t devid;
+	int readers; /* Amount of users with chardev open */
+	bool clean_request; /* Signal userspace open chardev preventing safe device removal */
+	struct mutex dmtsc_devs_mux; /* Protect access to device management */
+	struct class *dmtsc_class;
+	struct ptp_dmtsc_cdev_info *cdev_info;
+};
+
 struct ptp_clock {
 	struct posix_clock clock;
 	struct device dev;
@@ -36,6 +54,10 @@ struct ptp_clock {
 	struct pps_device *pps_source;
 	long dialed_frequency; /* remembers the frequency adjustment */
 	struct timestamp_event_queue tsevq; /* simple fifo for time stamps */
+	u32 dmtsc_en_flags; /* Demultiplexed timestamp channels enable flags */
+	struct mutex dmtsc_sysfs_mux; /* Demultiplexed timestamp channels sysfs mutex */
+	struct timestamp_event_queue *dmtscevq; /* Demultiplexed timestamp channel fifos */
+	struct ptp_dmtsc_dev_info dmtsc_devs; /* Demultiplexed timestamp channel access character devices */
 	struct mutex tsevq_mux; /* one process at a time reading the fifo */
 	struct mutex pincfg_mux; /* protect concurrent info->pin_config access */
 	wait_queue_head_t tsev_wq;
@@ -139,4 +161,7 @@ void ptp_cleanup_pin_groups(struct ptp_clock *ptp);
 
 struct ptp_vclock *ptp_vclock_register(struct ptp_clock *pclock);
 void ptp_vclock_unregister(struct ptp_vclock *vclock);
+
+int ptp_dmtsc_dev_register(struct ptp_clock *ptp);
+void ptp_dmtsc_dev_uregister(struct ptp_clock *ptp);
 #endif
diff --git a/drivers/ptp/ptp_sysfs.c b/drivers/ptp/ptp_sysfs.c
index 6e4d5456a885..fc85aa1d3d23 100644
--- a/drivers/ptp/ptp_sysfs.c
+++ b/drivers/ptp/ptp_sysfs.c
@@ -316,6 +316,117 @@ static ssize_t max_vclocks_store(struct device *dev,
 }
 static DEVICE_ATTR_RW(max_vclocks);
 
+static ssize_t dmtsc_en_flags_show(struct device *dev,
+			      struct device_attribute *attr, char *page)
+{
+	struct ptp_clock *ptp = dev_get_drvdata(dev);
+	ssize_t size;
+
+	size = snprintf(page, PAGE_SIZE - 1, "0x%X\n", ptp->dmtsc_en_flags);
+
+	return size;
+}
+
+static ssize_t dmtsc_en_flags_store(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	struct ptp_clock *ptp = dev_get_drvdata(dev);
+	int err = -EINVAL;
+	char mode, val[7];
+	int enable, channel, cnt;
+	u32 req_mask, new_mask;
+
+	/* Read mode, value and enable
+	    - mode: "m" - Channel mask mode
+		        "c" - Single channel mode
+		- value: channel mask in hex or channel number in decimal
+			lsb = channel 0
+		- enable: '1' - enable
+				  '0' - disable
+	*/
+	cnt = sscanf(buf, "%c %s %d", &mode, val, &enable);
+	if (cnt != 3)
+		return err;
+
+	if (mutex_lock_interruptible(&ptp->dmtsc_sysfs_mux))
+		return -ERESTARTSYS;
+
+	switch (mode) {
+		case 'm':
+			if (kstrtou32(val, 0, &req_mask))
+			{
+				dev_info(dev, "dmtscevq invalid arguments");
+				goto out;
+			}
+			break;
+		case 'c':
+			if (kstrtoint(val, 0, &channel)) {
+				dev_info(dev, "dmtscevq invalid channel number");
+				goto out;
+			}
+			if ((channel < 0) || (channel > 31))
+			{
+				dev_info(dev, "dmtscevq channel number out of range");
+				goto out;
+			}
+			req_mask = (0x1 << channel);
+			break;
+		default:
+			goto out;
+			break;
+	}
+
+	switch (enable) {
+		case 0:
+			new_mask = ptp->dmtsc_en_flags & ~req_mask;
+			break;
+		case 1:
+			new_mask = ptp->dmtsc_en_flags | req_mask;
+			break;
+		default:
+			dev_info(dev, "dmtscevq invalid enable value");
+			break;
+	}
+
+	if (new_mask == 0x0) {
+		// All queues disabled. Remove all character devices.
+		if (ptp->dmtscevq != NULL) {
+			ptp_dmtsc_dev_uregister(ptp);
+		} else {
+			if (ptp->dmtsc_en_flags != 0x0) {
+				dev_info(dev, "dmtscevq. Unexpected error: TSEVQ exploded buffers presumed unitialized. Skipping.");
+			}
+		}
+	} else {
+		// At least une queue enabled. Create all character devices.
+		// The mask will feed the selected character device and keep others inactive.
+		ptp->dmtsc_devs.readers = 0;
+		ptp->dmtsc_devs.clean_request = false;
+		if (ptp->dmtscevq == NULL) {
+			err = ptp_dmtsc_dev_register(ptp);
+			if (err != 0) {
+				dev_info(dev, "dmtscevq. Error while trying to register exploded queues");
+				goto out;
+			}
+		} else {
+			if (ptp->dmtsc_en_flags == 0x0) {
+				dev_info(dev, "dmtscevq. Unexpected error: TSEVQ exploded buffers already initialized, skipping initialization.");
+			}
+		}
+
+	}
+
+	ptp->dmtsc_en_flags = new_mask;
+
+	mutex_unlock(&ptp->dmtsc_sysfs_mux);
+	return count;
+out:
+	mutex_unlock(&ptp->dmtsc_sysfs_mux);
+	return err;
+}
+static DEVICE_ATTR_RW(dmtsc_en_flags);
+
 static struct attribute *ptp_attrs[] = {
 	&dev_attr_clock_name.attr,
 
@@ -333,6 +444,8 @@ static struct attribute *ptp_attrs[] = {
 	&dev_attr_pps_enable.attr,
 	&dev_attr_n_vclocks.attr,
 	&dev_attr_max_vclocks.attr,
+
+	&dev_attr_dmtsc_en_flags.attr,
 	NULL
 };
 
