1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * PTP 1588 clock support - User space test program
5 * Copyright (C) 2010 OMICRON electronics GmbH
8 #define __SANE_USERSPACE_TYPES__ /* For PPC64, to get LL64 types */
17 #include <sys/ioctl.h>
21 #include <sys/timex.h>
22 #include <sys/types.h>
26 #include <linux/ptp_clock.h>
28 #define DEVICE "/dev/ptp0"
31 #define ADJ_SETOFFSET 0x0100
35 #define CLOCK_INVALID -1
38 #define NSEC_PER_SEC 1000000000LL
40 /* clock_adjtime is not available in GLIBC < 2.14 */
41 #if !__GLIBC_PREREQ(2, 14)
42 #include <sys/syscall.h>
43 static int clock_adjtime(clockid_t id
, struct timex
*tx
)
45 return syscall(__NR_clock_adjtime
, id
, tx
);
49 static void show_flag_test(int rq_index
, unsigned int flags
, int err
)
51 printf("PTP_EXTTS_REQUEST%c flags 0x%08x : (%d) %s\n",
52 rq_index
? '1' + rq_index
: ' ',
53 flags
, err
, strerror(errno
));
54 /* sigh, uClibc ... */
58 static void do_flag_test(int fd
, unsigned int index
)
60 struct ptp_extts_request extts_request
;
61 unsigned long request
[2] = {
65 unsigned int enable_flags
[5] = {
67 PTP_ENABLE_FEATURE
| PTP_RISING_EDGE
,
68 PTP_ENABLE_FEATURE
| PTP_FALLING_EDGE
,
69 PTP_ENABLE_FEATURE
| PTP_RISING_EDGE
| PTP_FALLING_EDGE
,
70 PTP_ENABLE_FEATURE
| (PTP_EXTTS_VALID_FLAGS
+ 1),
74 memset(&extts_request
, 0, sizeof(extts_request
));
75 extts_request
.index
= index
;
77 for (i
= 0; i
< 2; i
++) {
78 for (j
= 0; j
< 5; j
++) {
79 extts_request
.flags
= enable_flags
[j
];
80 err
= ioctl(fd
, request
[i
], &extts_request
);
81 show_flag_test(i
, extts_request
.flags
, err
);
83 extts_request
.flags
= 0;
84 err
= ioctl(fd
, request
[i
], &extts_request
);
89 static clockid_t
get_clockid(int fd
)
92 return (((unsigned int) ~fd
) << 3) | CLOCKFD
;
95 static long ppb_to_scaled_ppm(int ppb
)
98 * The 'freq' field in the 'struct timex' is in parts per
99 * million, but with a 16 bit binary fractional field.
100 * Instead of calculating either one of
102 * scaled_ppm = (ppb / 1000) << 16 [1]
103 * scaled_ppm = (ppb << 16) / 1000 [2]
105 * we simply use double precision math, in order to avoid the
106 * truncation in [1] and the possible overflow in [2].
108 return (long) (ppb
* 65.536);
111 static int64_t pctns(struct ptp_clock_time
*t
)
113 return t
->sec
* NSEC_PER_SEC
+ t
->nsec
;
116 static void usage(char *progname
)
119 "usage: %s [options]\n"
120 " -c query the ptp clock's capabilities\n"
121 " -d name device to open\n"
122 " -e val read 'val' external time stamp events\n"
123 " -f val adjust the ptp clock frequency by 'val' ppb\n"
124 " -F chan Enable single channel mask and keep device open for debugfs verification.\n"
125 " -g get the ptp clock time\n"
126 " -h prints this message\n"
127 " -i val index for event/trigger\n"
128 " -k val measure the time offset between system and phc clock\n"
129 " for 'val' times (Maximum 25)\n"
130 " -l list the current pin configuration\n"
131 " -L pin,val configure pin index 'pin' with function 'val'\n"
132 " the channel index is taken from the '-i' option\n"
133 " 'val' specifies the auxiliary function:\n"
135 " 1 - external time stamp\n"
136 " 2 - periodic output\n"
137 " -n val shift the ptp clock time by 'val' nanoseconds\n"
138 " -o val phase offset (in nanoseconds) to be provided to the PHC servo\n"
139 " -p val enable output with a period of 'val' nanoseconds\n"
140 " -H val set output phase to 'val' nanoseconds (requires -p)\n"
141 " -w val set output pulse width to 'val' nanoseconds (requires -p)\n"
142 " -P val enable or disable (val=1|0) the system clock PPS\n"
143 " -s set the ptp clock time from the system time\n"
144 " -S set the system time from the ptp clock time\n"
145 " -t val shift the ptp clock time by 'val' seconds\n"
146 " -T val set the ptp clock time to 'val' seconds\n"
147 " -x val get an extended ptp clock time with the desired number of samples (up to %d)\n"
148 " -X get a ptp clock cross timestamp\n"
149 " -y val pre/post tstamp timebase to use {realtime|monotonic|monotonic-raw}\n"
150 " -z test combinations of rising/falling external time stamp flags\n",
151 progname
, PTP_MAX_SAMPLES
);
154 int main(int argc
, char *argv
[])
156 struct ptp_clock_caps caps
;
157 struct ptp_extts_event event
;
158 struct ptp_extts_request extts_request
;
159 struct ptp_perout_request perout_request
;
160 struct ptp_pin_desc desc
;
163 struct ptp_clock_time
*pct
;
164 struct ptp_sys_offset
*sysoff
;
165 struct ptp_sys_offset_extended
*soe
;
166 struct ptp_sys_offset_precise
*xts
;
172 char *device
= DEVICE
;
174 int adjfreq
= 0x7fffffff;
178 int capabilities
= 0;
188 int pin_index
= -1, pin_func
;
193 clockid_t ext_clockid
= CLOCK_REALTIME
;
196 int64_t interval
, offset
;
197 int64_t perout_phase
= -1;
198 int64_t pulsewidth
= -1;
201 progname
= strrchr(argv
[0], '/');
202 progname
= progname
? 1+progname
: argv
[0];
203 while (EOF
!= (c
= getopt(argc
, argv
, "cd:e:f:F:ghH:i:k:lL:n:o:p:P:sSt:T:w:x:Xy:z"))) {
212 extts
= atoi(optarg
);
215 adjfreq
= atoi(optarg
);
218 channel
= atoi(optarg
);
224 perout_phase
= atoll(optarg
);
227 index
= atoi(optarg
);
231 n_samples
= atoi(optarg
);
237 cnt
= sscanf(optarg
, "%d,%d", &pin_index
, &pin_func
);
244 adjns
= atoi(optarg
);
247 adjphase
= atoi(optarg
);
250 perout
= atoll(optarg
);
262 adjtime
= atoi(optarg
);
266 seconds
= atoi(optarg
);
269 pulsewidth
= atoi(optarg
);
272 getextended
= atoi(optarg
);
273 if (getextended
< 1 || getextended
> PTP_MAX_SAMPLES
) {
275 "number of extended timestamp samples must be between 1 and %d; was asked for %d\n",
276 PTP_MAX_SAMPLES
, getextended
);
284 if (!strcasecmp(optarg
, "realtime"))
285 ext_clockid
= CLOCK_REALTIME
;
286 else if (!strcasecmp(optarg
, "monotonic"))
287 ext_clockid
= CLOCK_MONOTONIC
;
288 else if (!strcasecmp(optarg
, "monotonic-raw"))
289 ext_clockid
= CLOCK_MONOTONIC_RAW
;
292 "type needs to be realtime, monotonic or monotonic-raw; was given %s\n",
311 fd
= open(device
, O_RDWR
);
313 fprintf(stderr
, "opening %s: %s\n", device
, strerror(errno
));
317 clkid
= get_clockid(fd
);
318 if (CLOCK_INVALID
== clkid
) {
319 fprintf(stderr
, "failed to read clock id\n");
324 if (ioctl(fd
, PTP_CLOCK_GETCAPS
, &caps
)) {
325 perror("PTP_CLOCK_GETCAPS");
327 printf("capabilities:\n"
328 " %d maximum frequency adjustment (ppb)\n"
329 " %d programmable alarms\n"
330 " %d external time stamp channels\n"
331 " %d programmable periodic signals\n"
332 " %d pulse per second\n"
333 " %d programmable pins\n"
334 " %d cross timestamping\n"
336 " %d maximum phase adjustment (ns)\n",
343 caps
.cross_timestamping
,
349 if (0x7fffffff != adjfreq
) {
350 memset(&tx
, 0, sizeof(tx
));
351 tx
.modes
= ADJ_FREQUENCY
;
352 tx
.freq
= ppb_to_scaled_ppm(adjfreq
);
353 if (clock_adjtime(clkid
, &tx
)) {
354 perror("clock_adjtime");
356 puts("frequency adjustment okay");
360 if (adjtime
|| adjns
) {
361 memset(&tx
, 0, sizeof(tx
));
362 tx
.modes
= ADJ_SETOFFSET
| ADJ_NANO
;
363 tx
.time
.tv_sec
= adjtime
;
364 tx
.time
.tv_usec
= adjns
;
365 while (tx
.time
.tv_usec
< 0) {
367 tx
.time
.tv_usec
+= NSEC_PER_SEC
;
370 if (clock_adjtime(clkid
, &tx
) < 0) {
371 perror("clock_adjtime");
373 puts("time shift okay");
378 memset(&tx
, 0, sizeof(tx
));
379 tx
.modes
= ADJ_OFFSET
| ADJ_NANO
;
380 tx
.offset
= adjphase
;
382 if (clock_adjtime(clkid
, &tx
) < 0) {
383 perror("clock_adjtime");
385 puts("phase adjustment okay");
390 if (clock_gettime(clkid
, &ts
)) {
391 perror("clock_gettime");
393 printf("clock time: %ld.%09ld or %s",
394 ts
.tv_sec
, ts
.tv_nsec
, ctime(&ts
.tv_sec
));
399 clock_gettime(CLOCK_REALTIME
, &ts
);
400 if (clock_settime(clkid
, &ts
)) {
401 perror("clock_settime");
403 puts("set time okay");
408 clock_gettime(clkid
, &ts
);
409 if (clock_settime(CLOCK_REALTIME
, &ts
)) {
410 perror("clock_settime");
412 puts("set time okay");
419 if (clock_settime(clkid
, &ts
)) {
420 perror("clock_settime");
422 puts("set time okay");
426 if (pin_index
>= 0) {
427 memset(&desc
, 0, sizeof(desc
));
428 desc
.index
= pin_index
;
429 desc
.func
= pin_func
;
431 if (ioctl(fd
, PTP_PIN_SETFUNC
, &desc
)) {
432 perror("PTP_PIN_SETFUNC");
434 puts("set pin function okay");
439 memset(&extts_request
, 0, sizeof(extts_request
));
440 extts_request
.index
= index
;
441 extts_request
.flags
= PTP_ENABLE_FEATURE
;
442 if (ioctl(fd
, PTP_EXTTS_REQUEST
, &extts_request
)) {
443 perror("PTP_EXTTS_REQUEST");
446 puts("external time stamp request okay");
448 for (; extts
; extts
--) {
449 cnt
= read(fd
, &event
, sizeof(event
));
450 if (cnt
!= sizeof(event
)) {
454 printf("event index %u at %lld.%09u\n", event
.index
,
455 event
.t
.sec
, event
.t
.nsec
);
458 /* Disable the feature again. */
459 extts_request
.flags
= 0;
460 if (ioctl(fd
, PTP_EXTTS_REQUEST
, &extts_request
)) {
461 perror("PTP_EXTTS_REQUEST");
466 do_flag_test(fd
, index
);
471 if (ioctl(fd
, PTP_CLOCK_GETCAPS
, &caps
)) {
472 perror("PTP_CLOCK_GETCAPS");
474 n_pins
= caps
.n_pins
;
476 for (i
= 0; i
< n_pins
; i
++) {
478 if (ioctl(fd
, PTP_PIN_GETFUNC
, &desc
)) {
479 perror("PTP_PIN_GETFUNC");
482 printf("name %s index %u func %u chan %u\n",
483 desc
.name
, desc
.index
, desc
.func
, desc
.chan
);
487 if (pulsewidth
>= 0 && perout
< 0) {
488 puts("-w can only be specified together with -p");
492 if (perout_phase
>= 0 && perout
< 0) {
493 puts("-H can only be specified together with -p");
498 if (clock_gettime(clkid
, &ts
)) {
499 perror("clock_gettime");
502 memset(&perout_request
, 0, sizeof(perout_request
));
503 perout_request
.index
= index
;
504 perout_request
.period
.sec
= perout
/ NSEC_PER_SEC
;
505 perout_request
.period
.nsec
= perout
% NSEC_PER_SEC
;
506 perout_request
.flags
= 0;
507 if (pulsewidth
>= 0) {
508 perout_request
.flags
|= PTP_PEROUT_DUTY_CYCLE
;
509 perout_request
.on
.sec
= pulsewidth
/ NSEC_PER_SEC
;
510 perout_request
.on
.nsec
= pulsewidth
% NSEC_PER_SEC
;
512 if (perout_phase
>= 0) {
513 perout_request
.flags
|= PTP_PEROUT_PHASE
;
514 perout_request
.phase
.sec
= perout_phase
/ NSEC_PER_SEC
;
515 perout_request
.phase
.nsec
= perout_phase
% NSEC_PER_SEC
;
517 perout_request
.start
.sec
= ts
.tv_sec
+ 2;
518 perout_request
.start
.nsec
= 0;
521 if (ioctl(fd
, PTP_PEROUT_REQUEST2
, &perout_request
)) {
522 perror("PTP_PEROUT_REQUEST");
524 puts("periodic output request okay");
529 int enable
= pps
? 1 : 0;
530 if (ioctl(fd
, PTP_ENABLE_PPS
, enable
)) {
531 perror("PTP_ENABLE_PPS");
533 puts("pps for system time request okay");
538 if (n_samples
<= 0 || n_samples
> 25) {
539 puts("n_samples should be between 1 and 25");
544 sysoff
= calloc(1, sizeof(*sysoff
));
549 sysoff
->n_samples
= n_samples
;
551 if (ioctl(fd
, PTP_SYS_OFFSET
, sysoff
))
552 perror("PTP_SYS_OFFSET");
554 puts("system and phc clock time offset request okay");
556 pct
= &sysoff
->ts
[0];
557 for (i
= 0; i
< sysoff
->n_samples
; i
++) {
559 tp
= pctns(pct
+2*i
+1);
560 t2
= pctns(pct
+2*i
+2);
562 offset
= (t2
+ t1
) / 2 - tp
;
564 printf("system time: %lld.%09u\n",
565 (pct
+2*i
)->sec
, (pct
+2*i
)->nsec
);
566 printf("phc time: %lld.%09u\n",
567 (pct
+2*i
+1)->sec
, (pct
+2*i
+1)->nsec
);
568 printf("system time: %lld.%09u\n",
569 (pct
+2*i
+2)->sec
, (pct
+2*i
+2)->nsec
);
570 printf("system/phc clock time offset is %" PRId64
" ns\n"
571 "system clock time delay is %" PRId64
" ns\n",
579 soe
= calloc(1, sizeof(*soe
));
585 soe
->n_samples
= getextended
;
586 soe
->clockid
= ext_clockid
;
588 if (ioctl(fd
, PTP_SYS_OFFSET_EXTENDED
, soe
)) {
589 perror("PTP_SYS_OFFSET_EXTENDED");
591 printf("extended timestamp request returned %d samples\n",
594 for (i
= 0; i
< getextended
; i
++) {
595 switch (ext_clockid
) {
597 printf("sample #%2d: real time before: %lld.%09u\n",
598 i
, soe
->ts
[i
][0].sec
,
601 case CLOCK_MONOTONIC
:
602 printf("sample #%2d: monotonic time before: %lld.%09u\n",
603 i
, soe
->ts
[i
][0].sec
,
606 case CLOCK_MONOTONIC_RAW
:
607 printf("sample #%2d: monotonic-raw time before: %lld.%09u\n",
608 i
, soe
->ts
[i
][0].sec
,
614 printf(" phc time: %lld.%09u\n",
615 soe
->ts
[i
][1].sec
, soe
->ts
[i
][1].nsec
);
616 switch (ext_clockid
) {
618 printf(" real time after: %lld.%09u\n",
622 case CLOCK_MONOTONIC
:
623 printf(" monotonic time after: %lld.%09u\n",
627 case CLOCK_MONOTONIC_RAW
:
628 printf(" monotonic-raw time after: %lld.%09u\n",
642 xts
= calloc(1, sizeof(*xts
));
648 if (ioctl(fd
, PTP_SYS_OFFSET_PRECISE
, xts
)) {
649 perror("PTP_SYS_OFFSET_PRECISE");
651 puts("system and phc crosstimestamping request okay");
653 printf("device time: %lld.%09u\n",
654 xts
->device
.sec
, xts
->device
.nsec
);
655 printf("system time: %lld.%09u\n",
656 xts
->sys_realtime
.sec
, xts
->sys_realtime
.nsec
);
657 printf("monoraw time: %lld.%09u\n",
658 xts
->sys_monoraw
.sec
, xts
->sys_monoraw
.nsec
);
665 if (ioctl(fd
, PTP_MASK_CLEAR_ALL
)) {
666 perror("PTP_MASK_CLEAR_ALL");
667 } else if (ioctl(fd
, PTP_MASK_EN_SINGLE
, (unsigned int *)&channel
)) {
668 perror("PTP_MASK_EN_SINGLE");
670 printf("Channel %d exclusively enabled. Check on debugfs.\n", channel
);
671 printf("Press any key to continue\n.");