drivers/timers/ptp: support ptp clock driver model

This patch introduces the foundational PTP (Precision Time Protocol) clock
driver framework for NuttX, enabling precise time synchronization support
based on IEEE 1588 standard.

Key changes include:

1. New PTP clock driver infrastructure:
   - Added drivers/timers/ptp_clock.c implementing upper-half driver
   - Created include/nuttx/timers/ptp_clock.h with PTP clock interfaces
   - Implemented upper/lower half driver architecture for hardware abstraction

2. Core functionality:
   - Clock time get/set operations (gettime, settime)
   - Frequency adjustment support (adjtime, adjfine)
   - Phase adjustment capabilities
   - System-device cross-timestamping for precise synchronization

3. IOCTL commands:
   - PTP_CLOCK_SETTIME/GETTIME for time manipulation
   - PTP_CLOCK_GETRES for resolution queries
   - PTP_CLOCK_ADJTIME for time adjustment
   - PTP_CLOCK_GETCAPS for capability queries
   - PTP_SYS_OFFSET* for system offset measurements

4. Supporting structures:
   - struct ptp_lowerhalf_s: lower-half driver interface
   - struct ptp_clock_caps: clock capabilities descriptor
   - struct ptp_sys_offset: system time offset measurement
   - Added timex structures in include/sys/timex.h for ADJ_* operations

5. Build system integration:
   - Added CONFIG_PTP_CLOCK Kconfig option
   - Updated CMakeLists.txt and Make.defs
   - Added PTPCLK debug macros in include/debug.h

This framework provides the base for PTP clock implementations, allowing
hardware-specific drivers to register and provide precise time services
through a standardized interface.

Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
This commit is contained in:
dongjiuzhu1
2025-03-22 15:09:48 +08:00
committed by Alan C. Assis
parent 7298977894
commit 31eb339356
10 changed files with 1019 additions and 1 deletions
+35
View File
@@ -2366,6 +2366,41 @@ config DEBUG_PCI_INFO
endif # DEBUG_PCI
config DEBUG_PTP
bool "PTP Debug Features"
default n
depends on PTP_CLOCK
---help---
Enable PTP driver debug features.
Support for this debug option is architecture-specific and may not
be available for some MCUs.
if DEBUG_PTP
config DEBUG_PTP_ERROR
bool "PTP Error Output"
default n
depends on DEBUG_ERROR
---help---
Enable PTP driver error output to SYSLOG.
config DEBUG_PTP_WARN
bool "PTP Warnings Output"
default n
depends on DEBUG_WARN
---help---
Enable PTP driver warning output to SYSLOG.
config DEBUG_PTP_INFO
bool "PTP Informational Output"
default n
depends on DEBUG_INFO
---help---
Enable PTP driver informational output to SYSLOG.
endif # DEBUG_PTP
config DEBUG_RPMSG
bool "RPMSG Debug Features"
default n
+4
View File
@@ -90,4 +90,8 @@ if(CONFIG_GOLDFISH_TIMER)
list(APPEND SRCS goldfish_timer.c)
endif()
if(CONFIG_PTP_CLOCK)
list(APPEND SRCS ptp_clock.c)
endif()
target_sources(drivers PRIVATE ${SRCS})
+16
View File
@@ -549,4 +549,20 @@ config GOLDFISH_TIMER
emulator. It is used to provide a virtual timer to the guest OS.
See: https://android.googlesource.com/platform/external/qemu/+/master/docs/GOLDFISH-VIRTUAL-HARDWARE.TXT
config PTP_CLOCK
bool "PTP clock driver"
default n
---help---
The IEEE 1588 standard defines a method to precisely
synchronize distributed clocks over Ethernet networks. The
standard defines a Precision Time Protocol (PTP), which can
be used to achieve synchronization within a few dozen
microseconds. In addition, with the help of special hardware
time stamping units, it can be possible to achieve
synchronization to within a few hundred nanoseconds.
This driver adds support for PTP clocks as character
devices. If you want to use a PTP clock, then you should
also enable at least one clock driver as well.
endmenu # Timer Driver Support
+4
View File
@@ -124,6 +124,10 @@ ifeq ($(CONFIG_GOLDFISH_TIMER),y)
TMRVPATH = :timers
endif
ifeq ($(CONFIG_PTP_CLOCK),y)
CSRCS += ptp_clock.c
endif
# Include timer build support (if any were selected)
DEPPATH += $(TMRDEPPATH)
+476
View File
@@ -0,0 +1,476 @@
/****************************************************************************
* drivers/timers/ptp_clock.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <sys/types.h>
#include <stdio.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/kmalloc.h>
#include <nuttx/mutex.h>
#include <nuttx/timers/ptp_clock.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Types
****************************************************************************/
/* This structure describes the state of the upper half driver */
struct ptp_upperhalf_s
{
FAR struct ptp_lowerhalf_s *lower; /* The handle of lower half driver */
mutex_t lock; /* Manages exclusive access to file operations */
long max_adj; /* The maximum frequency adjustment */
long adj_freq; /* remembers the frequency adjustment */
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static ssize_t ptp_clock_read(FAR struct file *filep, FAR char *buffer,
size_t buflen);
static int ptp_clock_ioctl(FAR struct file *filep, int cmd,
unsigned long arg);
/****************************************************************************
* Private Data
****************************************************************************/
static const struct file_operations g_ptp_clock_file_ops =
{
NULL, /* open */
NULL, /* close */
ptp_clock_read, /* read */
NULL, /* write */
NULL, /* seek */
ptp_clock_ioctl, /* ioctl */
};
/****************************************************************************
* Private Functions
****************************************************************************/
static ssize_t ptp_clock_read(FAR struct file *filep, FAR char *buffer,
size_t buflen)
{
return 0;
}
static inline long ptp_clock_scaled_ppm_to_ppb(long ppm)
{
/* The 'freq' field in the 'struct timex' is in parts per
* million, but with a 16 bit binary fractional field.
*
* We want to calculate
*
* ppb = scaled_ppm * 1000 / 2^16
*
* which simplifies to
*
* ppb = scaled_ppm * 125 / 2^13
*/
int64_t ppb = 1 + ppm;
ppb *= 125;
ppb >>= 13;
return (long)ppb;
}
static int ptp_clock_adjtime(FAR struct ptp_lowerhalf_s *lower,
FAR struct timex *tx)
{
FAR struct ptp_upperhalf_s *upper = lower->upper;
int ret = -ENOTSUP;
if (tx->modes & ADJ_SETOFFSET)
{
struct timespec ts;
int64_t delta;
ts.tv_sec = tx->time.tv_sec;
ts.tv_nsec = tx->time.tv_usec;
if (!(tx->modes & ADJ_NANO))
{
ts.tv_nsec *= 1000;
}
if ((unsigned long)ts.tv_nsec >= NSEC_PER_SEC)
{
return -EINVAL;
}
delta = ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec;
ret = lower->ops->adjtime(lower, delta);
}
else if ((tx->modes & ADJ_FREQUENCY) && lower->ops->adjfine != NULL)
{
long ppb = ptp_clock_scaled_ppm_to_ppb(tx->freq);
if (ppb > upper->max_adj || ppb < -upper->max_adj)
{
return -ERANGE;
}
ret = lower->ops->adjfine(lower, tx->freq);
upper->adj_freq = tx->freq;
}
else if ((tx->modes & ADJ_OFFSET) &&
lower->ops->adjphase != NULL)
{
int32_t offset = tx->offset;
if (!(tx->modes & ADJ_NANO))
{
offset *= NSEC_PER_USEC;
}
ret = lower->ops->adjphase(lower, offset);
}
else if (tx->modes == 0)
{
tx->freq = upper->adj_freq;
ret = 0;
}
return ret;
}
static int ptp_clock_ioctl(FAR struct file *filep, int cmd,
unsigned long arg)
{
FAR struct ptp_upperhalf_s *upper = filep->f_inode->i_private;
FAR struct ptp_lowerhalf_s *lower = upper->lower;
int ret = -ENOTTY;
int i;
nxmutex_lock(&upper->lock);
switch (cmd)
{
case PTP_CLOCK_SETTIME:
{
ret = -ENOTSUP;
if (lower->ops->settime)
{
ret = lower->ops->settime(lower,
(FAR const struct timespec *)(uintptr_t)arg);
}
}
break;
case PTP_CLOCK_GETTIME:
{
ret = -ENOTSUP;
if (lower->ops->gettime)
{
ret = lower->ops->gettime(lower,
(FAR struct timespec *)(uintptr_t)arg, NULL);
}
}
break;
case PTP_CLOCK_GETRES:
{
ret = -ENOTSUP;
if (lower->ops->getres)
{
ret = lower->ops->getres(lower,
(FAR struct timespec *)(uintptr_t)arg);
}
}
break;
case PTP_CLOCK_ADJTIME:
{
ret = ptp_clock_adjtime(lower, (FAR struct timex *)(uintptr_t)arg);
}
break;
case PTP_CLOCK_GETCAPS:
case PTP_CLOCK_GETCAPS2:
{
FAR struct ptp_clock_caps *caps = (FAR struct ptp_clock_caps *)
(uintptr_t)arg;
memset(caps, 0, sizeof(*caps));
caps->max_adj = upper->max_adj;
caps->cross_timestamping = lower->ops->getcrosststamp != NULL;
caps->adjust_phase = lower->ops->adjphase != NULL;
ret = OK;
}
break;
case PTP_SYS_OFFSET_PRECISE:
case PTP_SYS_OFFSET_PRECISE2:
{
FAR struct ptp_sys_offset_precise *preoff =
(FAR struct ptp_sys_offset_precise *)(uintptr_t)arg;
struct system_device_crosststamp xtstamp;
if (!lower->ops->getcrosststamp)
{
ret = -ENOTSUP;
break;
}
ret = lower->ops->getcrosststamp(lower, &xtstamp);
if (ret != 0)
{
break;
}
memset(preoff, 0, sizeof(*preoff));
preoff->device.sec = xtstamp.device.tv_sec;
preoff->device.nsec = xtstamp.device.tv_nsec;
preoff->sys_realtime.sec = xtstamp.realtime.tv_sec;
preoff->sys_realtime.nsec = xtstamp.realtime.tv_nsec;
preoff->sys_monoraw.sec = xtstamp.monoraw.tv_sec;
preoff->sys_monoraw.nsec = xtstamp.monoraw.tv_nsec;
}
break;
case PTP_SYS_OFFSET_EXTENDED:
case PTP_SYS_OFFSET_EXTENDED2:
{
FAR struct ptp_sys_offset_extended *extoff =
(FAR struct ptp_sys_offset_extended *)(uintptr_t)arg;
struct ptp_system_timestamp sts;
struct timespec ts;
if (!lower->ops->gettime)
{
ret = -ENOTSUP;
break;
}
if (extoff->n_samples > PTP_MAX_SAMPLES ||
extoff->rsv[0] || extoff->rsv[1] || extoff->rsv[2])
{
ret = -EINVAL;
break;
}
for (i = 0; i < extoff->n_samples; i++)
{
ret = lower->ops->gettime(lower, &ts, &sts);
if (ret < 0)
{
break;
}
extoff->ts[i][0].sec = sts.pre_ts.tv_sec;
extoff->ts[i][0].nsec = sts.pre_ts.tv_nsec;
extoff->ts[i][1].sec = ts.tv_sec;
extoff->ts[i][1].nsec = ts.tv_nsec;
extoff->ts[i][2].sec = sts.post_ts.tv_sec;
extoff->ts[i][2].nsec = sts.post_ts.tv_nsec;
}
}
break;
case PTP_SYS_OFFSET:
case PTP_SYS_OFFSET2:
{
FAR struct ptp_sys_offset *sysoff =
(FAR struct ptp_sys_offset *)(uintptr_t)arg;
FAR struct ptp_clock_time *pct;
struct timespec ts;
if (lower->ops->gettime == NULL)
{
ret = -ENOTSUP;
break;
}
if (sysoff->n_samples > PTP_MAX_SAMPLES)
{
ret = -EINVAL;
break;
}
pct = &sysoff->ts[0];
for (i = 0; i < sysoff->n_samples; i++)
{
nxclock_gettime(CLOCK_REALTIME, &ts);
pct->sec = ts.tv_sec;
pct->nsec = ts.tv_nsec;
pct++;
ret = lower->ops->gettime(lower, &ts, NULL);
if (ret < 0)
{
break;
}
pct->sec = ts.tv_sec;
pct->nsec = ts.tv_nsec;
pct++;
}
nxclock_gettime(CLOCK_REALTIME, &ts);
pct->sec = ts.tv_sec;
pct->nsec = ts.tv_nsec;
}
break;
default:
break;
}
nxmutex_unlock(&upper->lock);
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ptp_clockid_to_filep
*
* Description:
* Convert clockid to struct filep.
*
****************************************************************************/
int ptp_clockid_to_filep(clockid_t clock_id, FAR struct file **filep)
{
FAR const struct file_operations *ops;
int ret;
if ((clock_id & CLOCK_MASK) != CLOCK_FD)
{
return -EINVAL;
}
ret = clock_id >> CLOCK_SHIFT;
if (ret >= 0)
{
ret = fs_getfilep(ret, filep);
}
if (ret < 0)
{
return ret;
}
ops = (*filep)->f_inode->u.i_ops;
if (ops != &g_ptp_clock_file_ops)
{
fs_putfilep(*filep);
return -EINVAL;
}
return 0;
}
/****************************************************************************
* Name: ptp_clock_register
*
* Description:
* This function binds an instance of a "lower half" ptp driver with the
* "upper half" ptp device and registers that device so that can be used
* by application code.
*
* Input Parameters:
* lower - A pointer to an instance of lower half ptp driver. This
* instance is bound to the ptp driver and must persists as long
* as the driver persists.
* mxa_adj - The maximum frequency adjustment in parts per billion.
* devno - The user specifies number of device. ex: /dev/ptpX.
*
* Returned Value:
* OK if the driver was successfully register; A negated errno value is
* returned on any failure.
*
****************************************************************************/
int ptp_clock_register(FAR struct ptp_lowerhalf_s *lower, int32_t max_adj,
int devno)
{
FAR struct ptp_upperhalf_s *upper;
char path[16];
int ret;
DEBUGASSERT(lower != NULL);
/* Allocate the upper-half data structure */
upper = kmm_zalloc(sizeof(struct ptp_upperhalf_s));
if (!upper)
{
ptperr("ERROR: Allocation failed\n");
return -ENOMEM;
}
upper->lower = lower;
upper->max_adj = max_adj;
lower->upper = upper;
nxmutex_init(&upper->lock);
snprintf(path, sizeof(path), "/dev/ptp%d", devno);
ptpinfo("Registering %s\n", path);
ret = register_driver(path, &g_ptp_clock_file_ops, 0666, upper);
if (ret < 0)
{
nxmutex_destroy(&upper->lock);
kmm_free(upper);
}
return ret;
}
/****************************************************************************
* Name: ptp_clock_unregister
*
* Description:
* This function unregister character node and release all resource about
* upper half driver.
*
* Input Parameters:
* lower - A pointer to an instance of lower half ptp driver. This
* instance is bound to the ptp driver and must persists as long
* as the driver persists.
* devno - The user specifies which device of this type, from 0.
****************************************************************************/
void ptp_clock_unregister(FAR struct ptp_lowerhalf_s *lower, int devno)
{
FAR struct ptp_upperhalf_s *upper = lower->upper;
if (upper != NULL)
{
char path[16];
snprintf(path, sizeof(path), "/dev/ptp%d", devno);
unregister_driver(path);
nxmutex_destroy(&upper->lock);
kmm_free(upper);
}
}
+18
View File
@@ -1031,6 +1031,24 @@
# define csinfo _none
#endif
#ifdef CONFIG_DEBUG_PTP_ERROR
# define ptperr _err
#else
# define ptperr _none
#endif
#ifdef CONFIG_DEBUG_PTP_WARN
# define ptpwarn _warn
#else
# define ptpwarn _none
#endif
#ifdef CONFIG_DEBUG_PTP_INFO
# define ptpinfo _info
#else
# define ptpinfo _none
#endif
/* Buffer dumping macros do not depend on varargs */
#ifdef CONFIG_DEBUG_ERROR
+5 -1
View File
@@ -91,11 +91,15 @@
* CLOCK_PROCESS_CPUTIME_ID - 2
* CLOCK_THREAD_CPUTIME_ID - 3
* CLOCK_BOOTTIME - 4
* bit 3~32: the pid or tid value
* CLOCK_FD - 5
*
* if the clockid value exceeds CLOCK_MASK, it indicates a dynamic clockid.
* bit 3~32: the fd, pid or tid value
*
* The CLOCK_MASK are using to extract the clock_type from the clockid_t
*/
#define CLOCK_FD 5
#define CLOCK_MASK 7
#define CLOCK_SHIFT 3
+8
View File
@@ -112,6 +112,7 @@
#define _I2SOCBASE (0x4400) /* I2S driver ioctl commands */
#define _1WIREBASE (0x4500) /* 1WIRE ioctl commands */
#define _EEPIOCBASE (0x4600) /* EEPROM driver ioctl commands */
#define _PTPBASE (0x4700) /* PTP ioctl commands */
#define _WLIOCBASE (0x8b00) /* Wireless modules ioctl network commands */
/* boardctl() commands share the same number space */
@@ -799,6 +800,13 @@
#define _EEPIOCVALID(c) (_IOC_TYPE(c)==_EEPIOCBASE)
#define _EEPIOC(nr) _IOC(_EEPIOCBASE,nr)
/* PTP driver ioctl definitions *********************************************/
/* see nuttx/include/ptp_clock.h */
#define _PTPIOCVALID(c) (_IOC_TYPE(c)==_PTPBASE)
#define _PTPIOC(nr) _IOC(_PTPBASE,nr)
/****************************************************************************
* Public Type Definitions
****************************************************************************/
+355
View File
@@ -0,0 +1,355 @@
/****************************************************************************
* include/nuttx/timers/ptp_clock.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __INCLUDE_NUTTX_TIMERS_PTP_CLOCK_H
#define __INCLUDE_NUTTX_TIMERS_PTP_CLOCK_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <sys/types.h>
#include <sys/timex.h>
#include <nuttx/clock.h>
#include <nuttx/fs/ioctl.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define PTP_CLOCK_SETTIME _PTPIOC(0x1)
#define PTP_CLOCK_GETTIME _PTPIOC(0x2)
#define PTP_CLOCK_GETRES _PTPIOC(0x3)
#define PTP_CLOCK_ADJTIME _PTPIOC(0x4)
#define PTP_CLOCK_GETCAPS _PTPIOC(0x5)
#define PTP_SYS_OFFSET _PTPIOC(0x6)
#define PTP_SYS_OFFSET_PRECISE _PTPIOC(0x7)
#define PTP_SYS_OFFSET_EXTENDED _PTPIOC(0x8)
#define PTP_CLOCK_GETCAPS2 _PTPIOC(0x9)
#define PTP_SYS_OFFSET2 _PTPIOC(0xa)
#define PTP_SYS_OFFSET_PRECISE2 _PTPIOC(0xb)
#define PTP_SYS_OFFSET_EXTENDED2 _PTPIOC(0xc)
/* Maximum allowed offset measurement samples. */
#define PTP_MAX_SAMPLES 25
/****************************************************************************
* Inline Functions
****************************************************************************/
/****************************************************************************
* Public Types
****************************************************************************/
/* struct system_device_crosststamp - system/device cross-timestamp
* (synchronized capture)
*/
struct system_device_crosststamp
{
struct timespec device; /* Device time */
struct timespec realtime; /* Realtime simultaneous with device time */
struct timespec monoraw; /* Monotonic raw simultaneous with device time */
};
/* struct ptp_clock_time - represents a time value
*
* The sign of the seconds field applies to the whole value. The
* nanoseconds field is always unsigned. The reserved field is
* included for sub-nanosecond resolution, should the demand for
* this ever appear.
*/
struct ptp_clock_time
{
int64_t sec;
uint32_t nsec;
uint32_t reserved;
};
struct ptp_clock_caps
{
int max_adj; /* Maximum frequency adjustment in parts per billion. */
int cross_timestamping; /* Whether the clock supports precise system-device cross timestamps */
int adjust_phase; /* Whether the clock supports phase adjustment */
};
struct ptp_sys_offset
{
unsigned int n_samples; /* Desired number of measurements. */
unsigned int rsv[3]; /* Reserved for future use. */
/* Array of interleaved system/phc time stamps. The kernel
* will provide 2*n_samples + 1 time stamps, with the last
* one as a system time stamp.
*/
struct ptp_clock_time ts[2 * PTP_MAX_SAMPLES + 1];
};
struct ptp_sys_offset_extended
{
unsigned int n_samples; /* Desired number of measurements. */
unsigned int rsv[3]; /* Reserved for future use. */
/* Array of [system, phc, system] time stamps. The kernel will provide
* 3*n_samples time stamps.
*/
struct ptp_clock_time ts[PTP_MAX_SAMPLES][3];
};
struct ptp_sys_offset_precise
{
struct ptp_clock_time device;
struct ptp_clock_time sys_realtime;
struct ptp_clock_time sys_monoraw;
unsigned int rsv[4];
};
/* struct ptp_system_timestamp - system time corresponding to a
* PHC timestamp.
*/
struct ptp_system_timestamp
{
struct timespec pre_ts;
struct timespec post_ts;
};
struct ptp_lowerhalf_s;
struct ptp_ops_s
{
/**************************************************************************
* Name: adjfine
*
* Description:
* Adjusts the frequency of the hardware clock.
*
* Input Parameters:
* lower - The instance of lower half ptp driver
* scaled_ppm - Desired frequency offset from nominal frequency in parts
* per million, but with a 16 bit binary fractional field.
*
* Returned Value:
* Zero (OK) or positive on success; a negated errno value on failure.
*
**************************************************************************/
CODE int (*adjfine)(FAR struct ptp_lowerhalf_s *lower, long scaled_ppm);
/**************************************************************************
* Name: adjphase
*
* Description:
* Adjusts the phase offset of the hardware clock.
*
* Input Parameters:
* lower - The instance of lower half ptp driver.
* phase - Desired change in nanoseconds.
*
* Returned Value:
* Zero (OK) or positive on success; a negated errno value on failure.
*
**************************************************************************/
CODE int (*adjphase)(FAR struct ptp_lowerhalf_s *lower, int32_t phase);
/**************************************************************************
* Name: adjtime
*
* Description:
* Shifts the time of the hardware clock.
*
* Input Parameters:
* lower - The instance of lower half ptp driver.
* delta - Desired change in nanoseconds.
*
* Returned Value:
* Zero (OK) or positive on success; a negated errno value on failure.
*
**************************************************************************/
CODE int (*adjtime)(FAR struct ptp_lowerhalf_s *lower, int64_t delta);
/**************************************************************************
* Name: gettime
*
* Description:
* Reads the current time from the hardware clock and optionally also
* also the system clock. The first reading is made right before reading
* the lowest bits of the PHC timestamp and the second reading
* immediately follows that.
*
* Input Parameters:
* lower - The instance of lower half ptp driver.
* ts - Holds the PHC timestamp.
* sts - If not NULL, it holds a pair of timestamps from the
* system clock.
*
* Returned Value:
* Zero (OK) or positive on success; a negated errno value on failure.
*
**************************************************************************/
CODE int (*gettime)(FAR struct ptp_lowerhalf_s *lower,
FAR struct timespec *ts,
FAR struct ptp_system_timestamp *sts);
/**************************************************************************
* Name: getcrosststamp
*
* Description:
* Reads the current time from the hardware clock and system clock
* simultaneously.
*
* Input Parameters:
* lower - The instance of lower half ptp driver.
* cts - Contains timestamp (device,system) pair, where system time is
* realtime and monotonic.
*
* Returned Value:
* Zero (OK) or positive on success; a negated errno value on failure.
*
**************************************************************************/
CODE int (*getcrosststamp)(FAR struct ptp_lowerhalf_s *lower,
FAR struct system_device_crosststamp *cts);
/**************************************************************************
* Name: settime
*
* Description:
* Set the current time on the hardware clock.
*
* Input Parameters:
* lower - The instance of lower half ptp driver
* ts - Time value to set.
*
* Returned Value:
* Zero (OK) or positive on success; a negated errno value on failure.
*
**************************************************************************/
CODE int (*settime)(FAR struct ptp_lowerhalf_s *lower,
FAR const struct timespec *ts);
/**************************************************************************
* Name: getres
*
* Description:
* Finds the resolution (precision) of the specified clock, and, if res
* is non-NULL, stores it in the struct timespec pointed to by res.
*
* Input Parameters:
* pc - The instance of lower half ptp driver.
* res - Holds the resolution.
*
* Returned Value:
* Zero (OK) or positive on success; a negated errno value on failure.
*
**************************************************************************/
CODE int (*getres)(FAR struct ptp_lowerhalf_s *lower,
FAR struct timespec *res);
};
/* The ptp lower half driver interface, describes a PTP hardware
* clock driver.
*/
struct ptp_lowerhalf_s
{
FAR const struct ptp_ops_s *ops; /* Lower half driver operations. */
FAR void *upper; /* The upper handle */
};
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Name: ptp_clockid_to_filep
*
* Description:
* Convert clockid to struct filep.
*
****************************************************************************/
int ptp_clockid_to_filep(clockid_t clock_id, FAR struct file **filep);
/****************************************************************************
* Name: ptp_clock_register
*
* Description:
* This function binds an instance of a "lower half" ptp driver with the
* "upper half" ptp device and registers that device so that can be used
* by application code.
*
* Input Parameters:
* lower - A pointer to an instance of lower half ptp driver. This
* instance is bound to the ptp driver and must persists as long
* as the driver persists.
* mxa_adj - The maximum frequency adjustment in parts per billion.
* devno - The user specifies number of device. ex: /dev/ptpX.
*
* Returned Value:
* OK if the driver was successfully register; A negated errno value is
* returned on any failure.
*
****************************************************************************/
int ptp_clock_register(FAR struct ptp_lowerhalf_s *lower, int32_t max_adj,
int devno);
/****************************************************************************
* Name: ptp_clock_unregister
*
* Description:
* This function unregisters character node and releases all resource from
* upper half driver. This API corresponds to the ptp_register.
*
* Input Parameters:
* dev - A pointer to an instance of lower half ptp driver. This
* instance is bound to the ptp driver and must persists as long
* as the driver persists.
* devno - The user specifies which device of this type, from 0.
****************************************************************************/
void ptp_clock_unregister(FAR struct ptp_lowerhalf_s *dev, int devno);
#undef EXTERN
#if defined(__cplusplus)
}
#endif
#endif /* __INCLUDE_NUTTX_TIMERS_PTP_CLOCK_H */
+98
View File
@@ -0,0 +1,98 @@
/****************************************************************************
* include/sys/timex.h
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __INCLUDE_SYS_TIMEX_H
#define __INCLUDE_SYS_TIMEX_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <sys/time.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Mode codes (timex.mode) */
#define ADJ_OFFSET 0x0001 /* time offset */
#define ADJ_FREQUENCY 0x0002 /* frequency offset */
#define ADJ_MAXERROR 0x0004 /* maximum time error */
#define ADJ_ESTERROR 0x0008 /* estimated time error */
#define ADJ_STATUS 0x0010 /* clock status */
#define ADJ_TIMECONST 0x0020 /* pll time constant */
#define ADJ_TAI 0x0080 /* set TAI offset */
#define ADJ_SETOFFSET 0x0100 /* add 'time' to current time */
#define ADJ_MICRO 0x1000 /* select microsecond resolution */
#define ADJ_NANO 0x2000 /* select nanosecond resolution */
#define ADJ_TICK 0x4000 /* tick value */
#define ADJ_OFFSET_SINGLESHOT 0x8001 /* old-fashioned adjtime */
#define ADJ_OFFSET_SS_READ 0xa001 /* read-only adjtime */
/****************************************************************************
* Public Types
****************************************************************************/
struct timex
{
unsigned int modes; /* mode selector */
long offset; /* time offset (usec) */
long freq; /* frequency offset (scaled ppm) */
long maxerror; /* maximum error (usec) */
long esterror; /* estimated error (usec) */
int status; /* clock command/status */
long constant; /* pll time constant */
long precision; /* clock precision (usec) (read only) */
long tolerance; /* clock frequency tolerance (ppm) (read only) */
struct timeval time; /* (read only, except for ADJ_SETOFFSET) */
long tick; /* (modified) usecs between clock ticks */
long ppsfreq; /* pps frequency (scaled ppm) (ro) */
long jitter; /* pps jitter (us) (ro) */
int shift; /* interval duration (s) (shift) (ro) */
long stabil; /* pps stability (scaled ppm) (ro) */
long jitcnt; /* jitter limit exceeded (ro) */
long calcnt; /* calibration intervals (ro) */
long errcnt; /* calibration errors (ro) */
long stbcnt; /* stability limit exceeded (ro) */
int tai; /* TAI offset (ro) */
};
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
#undef EXTERN
#if defined(__cplusplus)
}
#endif
#endif /* __INCLUDE_SYS_TIMEX_H */