diff mbox series

[net-next,v5,9/9] net: dsa: microchip: ksz9477: add periodic output support

Message ID 20201203102117.8995-10-ceggers@arri.de (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series net: dsa: microchip: PTP support for KSZ956x | expand

Checks

Context Check Description
netdev/cover_letter success Link
netdev/fixes_present success Link
netdev/patch_count success Link
netdev/tree_selection success Clearly marked for net-next
netdev/subject_prefix success Link
netdev/source_inline success Was 0 now: 0
netdev/verify_signedoff success Link
netdev/module_param success Was 0 now: 0
netdev/build_32bit success Errors and warnings before: 0 this patch: 0
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/verify_fixes success Link
netdev/checkpatch warning WARNING: line length of 81 exceeds 80 columns WARNING: line length of 85 exceeds 80 columns WARNING: line length of 90 exceeds 80 columns WARNING: line length of 95 exceeds 80 columns
netdev/build_allmodconfig_warn success Errors and warnings before: 0 this patch: 0
netdev/header_inline success Link
netdev/stable success Stable not CCed

Commit Message

Christian Eggers Dec. 3, 2020, 10:21 a.m. UTC
The KSZ9563 has a Trigger Output Unit (TOU) which can be used to
generate periodic signals.

The pulse length can be altered via a device attribute.

Tested on a Microchip KSZ9563 switch.

Signed-off-by: Christian Eggers <ceggers@arri.de>
---
Changes in v4:
--------------
- 80 chars per line
- reverse christmas tree
- Set default pulse width for perout pulse to 50% (max. 125ms)
- reject unsupported flags for perout_request

On Saturday, 21 November 2020, 00:48:08 CET, Vladimir Oltean wrote:
> On Wed, Nov 18, 2020 at 09:30:13PM +0100, Christian Eggers wrote:

> >  static int ksz9477_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
> > @@ -241,6 +256,15 @@ static int ksz9477_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
> >  	case KSZ_PTP_TOU_IDLE:
> >  		break;
> >  
> > +	case KSZ_PTP_TOU_PEROUT:
> > +		dev_info(dev->dev, "Restarting periodic output signal\n");
> 
> Isn't this a bit too verbose, or is there something for the user to be
> concerned about?
In my setup this message appears only once after ptp4l has been started. Shall
I remove it?

> Watch out for 80 characters, please!
A few long line are left (for instance ksz9477_ptp_enable_perout). Please let
me know how I shall wrap them.

> > +	if (perout_request->flags & PTP_PEROUT_DUTY_CYCLE) {
> > +		u64 value = perout_request->on.sec * NSEC_PER_SEC +
> > +			    perout_request->on.nsec;
> > +
> > +		ret = ksz9477_ptp_tou_pulse_verify(value);
> > +		if (ret)
> > +			return ret;
> > +
> > +		dev->ptp_perout_pulse_width_ns = value;
> > +	}
> 
> It is not guaranteed that user space will set this flag. Shouldn't you
> assign a default value for the pulse width? I don't know, half the
> period should be a good default.
Yes I should. The hardware support a maximum "duty cycle" of a little bit
more than 125 ms. As PPS signals often have a 125 ms high period, I use this
duration as the maximum.

> > +	/* Check error flag:
> > +	 * - the ACTIVE flag is NOT cleared an error!
> > +	 */
> > +	ret = ksz_read32(dev, REG_PTP_TRIG_STATUS__4, &gpio_stat0);
> > +	if (ret)
> > +		return ret;
> > +
> > +	if (gpio_stat0 & (1 << (0 + TRIG_ERROR_S))) {
> 
> What is the role of this "0 +" term here?
> 
> > +		dev_err(dev->dev, "%s: Trigger unit0 error!\n", __func__);
This is the index of the used trigger unit.

 drivers/net/dsa/microchip/ksz9477_ptp.c | 357 +++++++++++++++++++++++-
 drivers/net/dsa/microchip/ksz9477_ptp.h |   4 +
 drivers/net/dsa/microchip/ksz_common.h  |  10 +
 3 files changed, 369 insertions(+), 2 deletions(-)

Comments

Richard Cochran Dec. 3, 2020, 2:12 p.m. UTC | #1
On Thu, Dec 03, 2020 at 11:21:17AM +0100, Christian Eggers wrote:
> The KSZ9563 has a Trigger Output Unit (TOU) which can be used to
> generate periodic signals.
> 
> The pulse length can be altered via a device attribute.

Device tree is the wrong place for that.

Aren't you using PTP_PEROUT_DUTY_CYCLE anyhow?

Thanks,
Richard
Christian Eggers Dec. 3, 2020, 3:36 p.m. UTC | #2
On Thursday, 3 December 2020, 15:12:55 CET, Richard Cochran wrote:
> On Thu, Dec 03, 2020 at 11:21:17AM +0100, Christian Eggers wrote:
> > The KSZ9563 has a Trigger Output Unit (TOU) which can be used to
> > generate periodic signals.
> > 
> > The pulse length can be altered via a device attribute.
> 
> Device tree is the wrong place for that.
I meant a device specfic sysfs attribute.
/sys/class/ptp/ptp2/device/pulse

But this is not true anymore, as I moved the sysfs attribute to a later 
patch (not submitted yet).

> Aren't you using PTP_PEROUT_DUTY_CYCLE anyhow?
I also use PTP_PEROUT_DUTY_CYCLE. But this cannot be set via a shell
script. The existing "period" sysfs attribute doesn't allow to set
the pulse length, so I added a device specific attribute for this.

Should ptp_sysfs be extended with a "pulse" attribute with calls
enable() with only PTP_PEROUT_DUTY_CYCLE set?

> 
> Thanks,
> Richard
> 
> 
regards
Christian
Vladimir Oltean Dec. 3, 2020, 3:52 p.m. UTC | #3
On Thu, 3 Dec 2020 at 17:36, Christian Eggers <ceggers@arri.de> wrote:
> Should ptp_sysfs be extended with a "pulse" attribute with calls
> enable() with only PTP_PEROUT_DUTY_CYCLE set?

Use tools/testing/selftests/ptp/testptp.
Christian Eggers Dec. 3, 2020, 4:20 p.m. UTC | #4
On Thursday, 3 December 2020, 16:52:46 CET, Vladimir Oltean wrote:
> On Thu, 3 Dec 2020 at 17:36, Christian Eggers <ceggers@arri.de> wrote:
> > Should ptp_sysfs be extended with a "pulse" attribute with calls
> > enable() with only PTP_PEROUT_DUTY_CYCLE set?
> 
> Use tools/testing/selftests/ptp/testptp.

Thanks for the hint. Last time I looked at it (5.4), it used to have
no "pulse" feature (as the ioctl() interface).

Maybe I should also add support for PTP_PEROUT_PHASE to the KSZ driver.

regards
Christian
Richard Cochran Dec. 4, 2020, 12:45 a.m. UTC | #5
On Thu, Dec 03, 2020 at 04:36:26PM +0100, Christian Eggers wrote:
> Should ptp_sysfs be extended with a "pulse" attribute with calls
> enable() with only PTP_PEROUT_DUTY_CYCLE set?

Yes, that would make sense.  It would bring sysfs back to feature
parity with the ioctls.

Thanks,
Richard
Vladimir Oltean Dec. 4, 2020, 1 a.m. UTC | #6
On Thu, Dec 03, 2020 at 04:45:56PM -0800, Richard Cochran wrote:
> On Thu, Dec 03, 2020 at 04:36:26PM +0100, Christian Eggers wrote:
> > Should ptp_sysfs be extended with a "pulse" attribute with calls
> > enable() with only PTP_PEROUT_DUTY_CYCLE set?
>
> Yes, that would make sense.  It would bring sysfs back to feature
> parity with the ioctls.

Which is a good thing?

Anyway, Christian, if you do decide to do that, here's some context why
I didn't do it when I added the additional knobs for periodic output:
https://www.mail-archive.com/linuxptp-devel@lists.sourceforge.net/msg04150.html
Richard Cochran Dec. 4, 2020, 1:18 a.m. UTC | #7
On Fri, Dec 04, 2020 at 03:00:50AM +0200, Vladimir Oltean wrote:
> On Thu, Dec 03, 2020 at 04:45:56PM -0800, Richard Cochran wrote:
> > Yes, that would make sense.  It would bring sysfs back to feature
> > parity with the ioctls.
> 
> Which is a good thing?

Yes, of course it is.  I'm sorry I didn't insist on it in the first place!
 
> Anyway, Christian, if you do decide to do that, here's some context why
> I didn't do it when I added the additional knobs for periodic output:
> https://www.mail-archive.com/linuxptp-devel@lists.sourceforge.net/msg04150.html

I think Christian is proposing a different sysfs file, not a flag in
the existing ones.  That makes sense to me.

Thanks,
Richard
diff mbox series

Patch

diff --git a/drivers/net/dsa/microchip/ksz9477_ptp.c b/drivers/net/dsa/microchip/ksz9477_ptp.c
index e68c9fc8e679..c3a0275e444a 100644
--- a/drivers/net/dsa/microchip/ksz9477_ptp.c
+++ b/drivers/net/dsa/microchip/ksz9477_ptp.c
@@ -19,6 +19,140 @@ 
 #define KSZ_PTP_INC_NS 40  /* HW clock is incremented every 40 ns (by 40) */
 #define KSZ_PTP_SUBNS_BITS 32  /* Number of bits in sub-nanoseconds counter */
 
+/* Shared register access routines (Trigger Output Unit) */
+
+static int ksz9477_ptp_tou_reset(struct ksz_device *dev, unsigned int unit)
+{
+	u32 ctrl_stat, data;
+	int ret;
+
+	/* Reset trigger unit (clears TRIGGER_EN, but not GPIOSTATx) */
+	ret = ksz_read32(dev, REG_PTP_CTRL_STAT__4, &ctrl_stat);
+	if (ret)
+		return ret;
+
+	ctrl_stat |= TRIG_RESET;
+
+	ret = ksz_write32(dev, REG_PTP_CTRL_STAT__4, ctrl_stat);
+	if (ret)
+		return ret;
+
+	/* Clear DONE */
+	data = 1 << (unit + TRIG_DONE_S);
+	ret = ksz_write32(dev, REG_PTP_TRIG_STATUS__4, data);
+	if (ret)
+		return ret;
+
+	/* Clear IRQ */
+	data = 1 << (unit + TRIG_INT_S);
+	ret = ksz_write32(dev, REG_PTP_INT_STATUS__4, data);
+	if (ret)
+		return ret;
+
+	/* Clear reset and set GPIO direction */
+	ctrl_stat &= ~TRIG_ENABLE;  /* clear cached bit :-) */
+	ctrl_stat &= ~TRIG_RESET;
+
+	ret = ksz_write32(dev, REG_PTP_CTRL_STAT__4, ctrl_stat);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int ksz9477_ptp_tou_cycle_width_set(struct ksz_device *dev, u32 width_ns)
+{
+	int ret;
+
+	ret = ksz_write32(dev, REG_TRIG_CYCLE_WIDTH, width_ns);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int ksz9477_ptp_tou_cycle_count_set(struct ksz_device *dev, u16 count)
+{
+	u32 data;
+	int ret;
+
+	ret = ksz_read32(dev, REG_TRIG_CYCLE_CNT, &data);
+	if (ret)
+		return ret;
+
+	data &= ~(TRIG_CYCLE_CNT_M << TRIG_CYCLE_CNT_S);
+	data |= (count & TRIG_CYCLE_CNT_M) << TRIG_CYCLE_CNT_S;
+
+	ret = ksz_write32(dev, REG_TRIG_CYCLE_CNT, data);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int ksz9477_ptp_tou_pulse_verify(u64 pulse_ns)
+{
+	u32 data;
+
+	if (pulse_ns & 0x3)
+		return -EINVAL;
+
+	data = (pulse_ns / 8);
+	if (data != (data & TRIG_PULSE_WIDTH_M))
+		return -ERANGE;
+
+	return 0;
+}
+
+static int ksz9477_ptp_tou_pulse_set(struct ksz_device *dev, u32 pulse_ns)
+{
+	u32 data;
+
+	data = (pulse_ns / 8);
+
+	return ksz_write32(dev, REG_TRIG_PULSE_WIDTH__4, data);
+}
+
+static int ksz9477_ptp_tou_target_time_set(struct ksz_device *dev, struct timespec64 const *ts)
+{
+	int ret;
+
+	/* Hardware has only 32 bit */
+	if ((ts->tv_sec & 0xffffffff) != ts->tv_sec)
+		return -EINVAL;
+
+	ret = ksz_write32(dev, REG_TRIG_TARGET_NANOSEC, ts->tv_nsec);
+	if (ret)
+		return ret;
+
+	ret = ksz_write32(dev, REG_TRIG_TARGET_SEC, ts->tv_sec);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int ksz9477_ptp_tou_start(struct ksz_device *dev, u32 *ctrl_stat_)
+{
+	u32 ctrl_stat;
+	int ret;
+
+	ret = ksz_read32(dev, REG_PTP_CTRL_STAT__4, &ctrl_stat);
+	if (ret)
+		return ret;
+
+	ctrl_stat |= TRIG_ENABLE;
+
+	ret = ksz_write32(dev, REG_PTP_CTRL_STAT__4, ctrl_stat);
+	if (ret)
+		return ret;
+
+	if (ctrl_stat_)
+		*ctrl_stat_ = ctrl_stat;
+
+	return 0;
+}
+
 /* Posix clock support */
 
 static int ksz9477_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
@@ -76,6 +210,8 @@  static int ksz9477_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
 	return ret;
 }
 
+static int ksz9477_ptp_restart_perout(struct ksz_device *dev);
+
 static int ksz9477_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
 {
 	struct ksz_device *dev = container_of(ptp, struct ksz_device, ptp_caps);
@@ -115,6 +251,20 @@  static int ksz9477_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
 	if (ret)
 		goto error_return;
 
+	switch (dev->ptp_tou_mode) {
+	case KSZ_PTP_TOU_IDLE:
+		break;
+
+	case KSZ_PTP_TOU_PEROUT:
+		dev_info(dev->dev, "Restarting periodic output signal\n");
+
+		ret = ksz9477_ptp_restart_perout(dev);
+		if (ret)
+			goto error_return;
+
+		break;
+	}
+
 	spin_lock_bh(&ptp_shared->ptp_clock_lock);
 	ptp_shared->ptp_clock_time = timespec64_add(ptp_shared->ptp_clock_time,
 						    delta64);
@@ -218,6 +368,20 @@  static int ksz9477_ptp_settime(struct ptp_clock_info *ptp,
 	if (ret)
 		goto error_return;
 
+	switch (dev->ptp_tou_mode) {
+	case KSZ_PTP_TOU_IDLE:
+		break;
+
+	case KSZ_PTP_TOU_PEROUT:
+		dev_info(dev->dev, "Restarting periodic output signal\n");
+
+		ret = ksz9477_ptp_restart_perout(dev);
+		if (ret)
+			goto error_return;
+
+		break;
+	}
+
 	spin_lock_bh(&ptp_shared->ptp_clock_lock);
 	ptp_shared->ptp_clock_time = *ts;
 	spin_unlock_bh(&ptp_shared->ptp_clock_lock);
@@ -227,10 +391,199 @@  static int ksz9477_ptp_settime(struct ptp_clock_info *ptp,
 	return ret;
 }
 
+static int ksz9477_ptp_configure_perout(struct ksz_device *dev,
+					u32 cycle_width_ns, u16 cycle_count,
+					u32 pulse_width_ns,
+					struct timespec64 const *target_time)
+{
+	u32 trig_ctrl;
+	int ret;
+
+	/* Enable notify, set rising edge, set periodic pattern */
+	trig_ctrl = TRIG_NOTIFY | (TRIG_POS_PERIOD << TRIG_PATTERN_S);
+	ret = ksz_write32(dev, REG_TRIG_CTRL__4, trig_ctrl);
+	if (ret)
+		return ret;
+
+	ret = ksz9477_ptp_tou_cycle_width_set(dev, cycle_width_ns);
+	if (ret)
+		return ret;
+
+	ksz9477_ptp_tou_cycle_count_set(dev,  cycle_count);
+	if (ret)
+		return ret;
+
+	ret = ksz9477_ptp_tou_pulse_set(dev, pulse_width_ns);
+	if (ret)
+		return ret;
+
+	ret = ksz9477_ptp_tou_target_time_set(dev, target_time);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+#define KSZ9477_PEROUT_VALID_FLAGS ( \
+	PTP_PEROUT_DUTY_CYCLE \
+)
+
+static int ksz9477_ptp_enable_perout(struct ksz_device *dev,
+				     struct ptp_perout_request const *perout_request,
+				     int on)
+{
+	u64 cycle_width_ns;
+	u64 pulse_width_ns;
+	u32 gpio_stat0;
+	int ret;
+
+	if (perout_request->flags & ~KSZ9477_PEROUT_VALID_FLAGS)
+		return -EINVAL;
+
+	if (dev->ptp_tou_mode != KSZ_PTP_TOU_PEROUT &&
+	    dev->ptp_tou_mode != KSZ_PTP_TOU_IDLE)
+		return -EBUSY;
+
+	ret = ksz9477_ptp_tou_reset(dev, 0);
+	if (ret)
+		return ret;
+
+	if (!on) {
+		dev->ptp_tou_mode = KSZ_PTP_TOU_IDLE;
+		return 0;  /* success */
+	}
+
+	dev->ptp_perout_target_time_first.tv_sec  = perout_request->start.sec;
+	dev->ptp_perout_target_time_first.tv_nsec = perout_request->start.nsec;
+
+	dev->ptp_perout_period.tv_sec = perout_request->period.sec;
+	dev->ptp_perout_period.tv_nsec = perout_request->period.nsec;
+
+	cycle_width_ns = timespec64_to_ns(&dev->ptp_perout_period);
+	if ((cycle_width_ns & GENMASK(31, 0)) != cycle_width_ns)
+		return -EINVAL;
+
+	if (perout_request->flags & PTP_PEROUT_DUTY_CYCLE)
+		pulse_width_ns = perout_request->on.sec * NSEC_PER_SEC +
+				 perout_request->on.nsec;
+
+	else
+		/* Use a duty cycle of 50%. Maximum pulse width supported by the
+		 * hardware is a little bit more than 125 ms.
+		 */
+		pulse_width_ns = min_t(u64,
+				       (perout_request->period.sec * NSEC_PER_SEC
+					+ perout_request->period.nsec) / 2
+				       / 8 * 8,
+				       125000000LL);
+
+	ret = ksz9477_ptp_tou_pulse_verify(pulse_width_ns);
+	if (ret)
+		return ret;
+
+	dev->ptp_perout_pulse_width_ns = pulse_width_ns;
+
+	ret = ksz9477_ptp_configure_perout(dev, cycle_width_ns,
+					   dev->ptp_perout_cycle_count,
+					   dev->ptp_perout_pulse_width_ns,
+					   &dev->ptp_perout_target_time_first);
+	if (ret)
+		return ret;
+
+	/* Activate trigger unit */
+	ret = ksz9477_ptp_tou_start(dev, NULL);
+	if (ret)
+		return ret;
+
+	/* Check error flag:
+	 * - the ACTIVE flag is NOT cleared an error!
+	 */
+	ret = ksz_read32(dev, REG_PTP_TRIG_STATUS__4, &gpio_stat0);
+	if (ret)
+		return ret;
+
+	if (gpio_stat0 & (1 << (0 + TRIG_ERROR_S))) {
+		dev_err(dev->dev, "%s: Trigger unit0 error!\n", __func__);
+		ret = -EIO;
+		/* Unit will be reset on next access */
+		return ret;
+	}
+
+	dev->ptp_tou_mode = KSZ_PTP_TOU_PEROUT;
+	return 0;
+}
+
+static int ksz9477_ptp_restart_perout(struct ksz_device *dev)
+{
+	s64 now_ns, first_ns, period_ns, next_ns;
+	struct timespec64 now;
+	unsigned int count;
+	int ret;
+
+	ret = _ksz9477_ptp_gettime(dev, &now);
+	if (ret)
+		return ret;
+
+	now_ns = timespec64_to_ns(&now);
+	first_ns = timespec64_to_ns(&dev->ptp_perout_target_time_first);
+
+	/* Calculate next perout event based on start time and period */
+	period_ns = timespec64_to_ns(&dev->ptp_perout_period);
+
+	if (first_ns < now_ns) {
+		count = div_u64(now_ns - first_ns, period_ns);
+		next_ns = first_ns + count * period_ns;
+	} else {
+		next_ns = first_ns;
+	}
+
+	/* Ensure 100 ms guard time prior next event */
+	while (next_ns < now_ns + 100000000)
+		next_ns += period_ns;
+
+	/* Restart periodic output signal */
+	{
+		struct timespec64 next = ns_to_timespec64(next_ns);
+		struct ptp_perout_request perout_request = {
+			.start = {
+				.sec  = next.tv_sec,
+				.nsec = next.tv_nsec
+			},
+			.period = {
+				.sec  = dev->ptp_perout_period.tv_sec,
+				.nsec = dev->ptp_perout_period.tv_nsec
+			},
+			.index = 0,
+			.flags = 0,  /* keep current values */
+		};
+		ret = ksz9477_ptp_enable_perout(dev, &perout_request, 1);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
 static int ksz9477_ptp_enable(struct ptp_clock_info *ptp,
 			      struct ptp_clock_request *req, int on)
 {
-	return -EOPNOTSUPP;
+	struct ksz_device *dev = container_of(ptp, struct ksz_device, ptp_caps);
+	int ret;
+
+	switch (req->type) {
+	case PTP_CLK_REQ_PEROUT: {
+		struct ptp_perout_request const *perout_request = &req->perout;
+
+		mutex_lock(&dev->ptp_mutex);
+		ret = ksz9477_ptp_enable_perout(dev, perout_request, on);
+		mutex_unlock(&dev->ptp_mutex);
+		return ret;
+	}
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
 }
 
 static long ksz9477_ptp_do_aux_work(struct ptp_clock_info *ptp)
@@ -592,7 +945,7 @@  int ksz9477_ptp_init(struct ksz_device *dev)
 	dev->ptp_caps.max_adj     = 6249999;
 	dev->ptp_caps.n_alarm     = 0;
 	dev->ptp_caps.n_ext_ts    = 0;  /* currently not implemented */
-	dev->ptp_caps.n_per_out   = 0;
+	dev->ptp_caps.n_per_out   = 1;
 	dev->ptp_caps.pps         = 0;
 	dev->ptp_caps.adjfine     = ksz9477_ptp_adjfine;
 	dev->ptp_caps.adjtime     = ksz9477_ptp_adjtime;
diff --git a/drivers/net/dsa/microchip/ksz9477_ptp.h b/drivers/net/dsa/microchip/ksz9477_ptp.h
index 2f7c4fa0753a..4d20decf0ad7 100644
--- a/drivers/net/dsa/microchip/ksz9477_ptp.h
+++ b/drivers/net/dsa/microchip/ksz9477_ptp.h
@@ -20,6 +20,7 @@ 
 int ksz9477_ptp_init(struct ksz_device *dev);
 void ksz9477_ptp_deinit(struct ksz_device *dev);
 
+irqreturn_t ksz9477_ptp_interrupt(struct ksz_device *dev);
 irqreturn_t ksz9477_ptp_port_interrupt(struct ksz_device *dev, int port);
 
 int ksz9477_ptp_get_ts_info(struct dsa_switch *ds, int port,
@@ -36,6 +37,9 @@  bool ksz9477_ptp_port_txtstamp(struct dsa_switch *ds, int port,
 static inline int ksz9477_ptp_init(struct ksz_device *dev) { return 0; }
 static inline void ksz9477_ptp_deinit(struct ksz_device *dev) {}
 
+static inline irqreturn_t ksz9477_ptp_interrupt(struct ksz_device *dev)
+{ return IRQ_NONE; }
+
 static inline irqreturn_t ksz9477_ptp_port_interrupt(struct ksz_device *dev,
 						     int port)
 { return IRQ_NONE; }
diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h
index 18bae8c0de9a..626f56570c0b 100644
--- a/drivers/net/dsa/microchip/ksz_common.h
+++ b/drivers/net/dsa/microchip/ksz_common.h
@@ -52,6 +52,11 @@  struct ksz_port {
 #endif
 };
 
+enum ksz_ptp_tou_mode {
+	KSZ_PTP_TOU_IDLE,
+	KSZ_PTP_TOU_PEROUT,
+};
+
 struct ksz_device {
 	struct dsa_switch *ds;
 	struct ksz_platform_data *pdata;
@@ -107,6 +112,11 @@  struct ksz_device {
 	struct hwtstamp_config tstamp_config;
 	struct mutex ptp_mutex;		/* protects PTP related hardware */
 	struct ksz_device_ptp_shared ptp_shared;
+	enum ksz_ptp_tou_mode ptp_tou_mode;
+	struct timespec64 ptp_perout_target_time_first;  /* start of first perout pulse */
+	struct timespec64 ptp_perout_period;
+	u32 ptp_perout_pulse_width_ns;
+	u16 ptp_perout_cycle_count;
 #endif
 };