This document is a short note.
Linux can synchronize with GPS time thanks to a PPS signal. The implementation come from the NTP need to synchronize against a GPS (, ).
We will use the PPS serial line discipline in order to acquire the PPS signal. The DB9's pin that receive the PPS is the DCD (carrier detect, or pin number 1) .
The kernel can automatically handle the phase and/or frequency locking .
On the slave machine (the one that need to be synchronized), you have to check your kernel configuration :
General setup Timers subsystem Timer tick handling constant rate no dynticks Device drivers [*] PPS support [*] PPS kernel consumer support [M] Kernel timer client (Testing client, use for debug) [M] PPS line discipline [*] PTP clock support
PPS kernel consumer support (CONFIG_NTP_PPS) allow the kernel to handle PPS and reduce jitter compared to userspace handling. As it only works on non-"tickless" systems, you will need to check "constant rate no dynticks".
In order to test the PPS system, we nned the userspace tools (warning : this isn't the genuine tools, this branch implement the kernel consumer control)  :
git clone https://github.com/ago/pps-tools.git
You can follow the official linuxpps guide .
For the test driver :
For the serial line discipline test :
modprobe pps_ktimer ppstest /dev/pps0
modprobe pps_ldisc ldattach PPS /dev/ttyS0 ppsctl -a -h /dev/pps1
Attach the "line discipline" (see the ldattach implementation in  sys-utils/ldattach.c).
int tty_fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY);
Open a pps file descriptor.
#include <sys/ioctl.h> int ldisc = N_PPS; ioctl(tty_fd, TIOCSETD; &ldisc);
Bind the PPS to a "kernel consumer" (see the RFC of the PPS API , or in the code of timepps.h ).
int pps_fd = open("/dev/pps1", O_RDWR);
This code will enable the PPS monitoring by the kernel. Tell the kernel to lock phase and frequency on the PPS (see  or in the code of ppsctl.c ).
#include <linux/pps.h> struct pps_bind_args kc_bind_args; kc_bind_args.tsformat = PPS_TSFMT_TSPEC; kc_bind_args.consummer = PPS_KC_HARDPPS; kc_bind_args.edge = PPS_CAPTUREASSERT; ioctl(pps_fd, PPS_KC_BIND, &kc_bind_args);
If you need to adjust the clock, use the adjtimex syscall. The kernel documention contain an exemple with the ADJ_SETOFFSET mode  that isn't documented in the adjtimex manual (probably not standard).
#include <sys/timex.h> struct timex tx; tx.modes = ADJ_STATUS; tx.status |= (STA_PPSFREQ | STA_PPSTIME); adjtimex(&tx);
#include <sys/timex.h> #ifndef ADJ_SETOFFSET #define ADJ_SETOFFSET 0x0100 #endif struct timex tx; tx.modes = ADJ_SETOFFSET; tx.time.tv_sec = offset; tx.time.tv_usec = 0; adjtimex(&tx);