From 6d10b44bc1a24c5d0decb58c2707a57f328c1a6c Mon Sep 17 00:00:00 2001 From: "Daniel P. Carvalho" Date: Thu, 17 Sep 2026 17:50:44 -0300 Subject: [PATCH] netutils/ptpd: phase-lock hardware clock via POSIX clock_adjtime. When state->clockid is configured to a hardware PTP clock device (e.g., /dev/ptp0) instead of CLOCK_REALTIME, ptp_adjtime() previously passed only the measured frequency drift (-ppb) to clock_adjtime(), ignoring the residual phase offset (delta_ns / adjustment_ns). As a result, while the hardware counter tracked frequency, its phase was never pulled into alignment with the master clock. Convert delta_ns (which combines frequency drift and current phase error clamped to max_adjust_ns) to ppb over CONFIG_CLOCK_ADJTIME_PERIOD_MS, acting as a proportional-integral (PI) phase servo. This drives the hardware clock to phase lock with the master via POSIX clock_adjtime() using ADJ_FREQUENCY without requiring proprietary ioctl calls. Assisted-by: Claude:claude-sonnet-5 Assisted-by: Gemini:gemini-3.8-flash-medium Signed-off-by: Daniel P. Carvalho --- netutils/ptpd/ptpd.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/netutils/ptpd/ptpd.c b/netutils/ptpd/ptpd.c index 23b2180d5..e8d08c5d3 100644 --- a/netutils/ptpd/ptpd.c +++ b/netutils/ptpd/ptpd.c @@ -30,9 +30,10 @@ #include #include -#include #include #include +#include +#include #include #include @@ -441,9 +442,31 @@ static int ptp_adjtime(FAR struct ptp_state_s *state, int64_t delta_ns, else { struct timex buf; + int64_t hw_ppb; + const int64_t slew_limit_ppb = + CONFIG_CLOCK_ADJTIME_SLEWLIMIT_PPM * 1000; + + /* delta_ns passed here is adjustment_ns, which already + * combines frequency drift and current phase error clamped + * to max_adjust_ns. Converting it to ppb over + * CONFIG_CLOCK_ADJTIME_PERIOD_MS produces the rate needed to + * pull the hardware counter into phase lock. + */ + + hw_ppb = delta_ns * MSEC_PER_SEC / + CONFIG_CLOCK_ADJTIME_PERIOD_MS; + + if (hw_ppb > slew_limit_ppb) + { + hw_ppb = slew_limit_ppb; + } + else if (hw_ppb < -slew_limit_ppb) + { + hw_ppb = -slew_limit_ppb; + } memset(&buf, 0, sizeof(buf)); - buf.freq = (long)(-ppb * 65536 / 1000); + buf.freq = hw_ppb * 65536 / 1000; buf.modes = ADJ_FREQUENCY; return clock_adjtime(state->clockid, &buf);