174ba9207SThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-or-later */
2d94ba80eSRichard Cochran /*
3d94ba80eSRichard Cochran  * PTP 1588 clock support
4d94ba80eSRichard Cochran  *
5d94ba80eSRichard Cochran  * Copyright (C) 2010 OMICRON electronics GmbH
6d94ba80eSRichard Cochran  */
7d94ba80eSRichard Cochran 
8d94ba80eSRichard Cochran #ifndef _PTP_CLOCK_KERNEL_H_
9d94ba80eSRichard Cochran #define _PTP_CLOCK_KERNEL_H_
10d94ba80eSRichard Cochran 
111ef76158SRichard Cochran #include <linux/device.h>
12220a60a4SBen Hutchings #include <linux/pps_kernel.h>
13d94ba80eSRichard Cochran #include <linux/ptp_clock.h>
14d94ba80eSRichard Cochran 
15d94ba80eSRichard Cochran 
16d94ba80eSRichard Cochran struct ptp_clock_request {
17d94ba80eSRichard Cochran 	enum {
18d94ba80eSRichard Cochran 		PTP_CLK_REQ_EXTTS,
19d94ba80eSRichard Cochran 		PTP_CLK_REQ_PEROUT,
20d94ba80eSRichard Cochran 		PTP_CLK_REQ_PPS,
21d94ba80eSRichard Cochran 	} type;
22d94ba80eSRichard Cochran 	union {
23d94ba80eSRichard Cochran 		struct ptp_extts_request extts;
24d94ba80eSRichard Cochran 		struct ptp_perout_request perout;
25d94ba80eSRichard Cochran 	};
26d94ba80eSRichard Cochran };
27d94ba80eSRichard Cochran 
28719f1aa4SChristopher S. Hall struct system_device_crosststamp;
2936180087SMiroslav Lichvar 
3036180087SMiroslav Lichvar /**
3136180087SMiroslav Lichvar  * struct ptp_system_timestamp - system time corresponding to a PHC timestamp
3236180087SMiroslav Lichvar  */
3336180087SMiroslav Lichvar struct ptp_system_timestamp {
3436180087SMiroslav Lichvar 	struct timespec64 pre_ts;
3536180087SMiroslav Lichvar 	struct timespec64 post_ts;
3636180087SMiroslav Lichvar };
3736180087SMiroslav Lichvar 
38d94ba80eSRichard Cochran /**
39*184ecc9eSVincent Cheng  * struct ptp_clock_info - describes a PTP hardware clock
40d94ba80eSRichard Cochran  *
41d94ba80eSRichard Cochran  * @owner:     The clock driver should set to THIS_MODULE.
42de465846SRichard Cochran  * @name:      A short "friendly name" to identify the clock and to
43de465846SRichard Cochran  *             help distinguish PHY based devices from MAC based ones.
44de465846SRichard Cochran  *             The string is not meant to be a unique id.
45d94ba80eSRichard Cochran  * @max_adj:   The maximum possible frequency adjustment, in parts per billon.
46d94ba80eSRichard Cochran  * @n_alarm:   The number of programmable alarms.
47d94ba80eSRichard Cochran  * @n_ext_ts:  The number of external time stamp channels.
48d94ba80eSRichard Cochran  * @n_per_out: The number of programmable periodic signals.
496092315dSRichard Cochran  * @n_pins:    The number of programmable pins.
50d94ba80eSRichard Cochran  * @pps:       Indicates whether the clock supports a PPS callback.
516092315dSRichard Cochran  * @pin_config: Array of length 'n_pins'. If the number of
526092315dSRichard Cochran  *              programmable pins is nonzero, then drivers must
536092315dSRichard Cochran  *              allocate and initialize this array.
54d94ba80eSRichard Cochran  *
55d94ba80eSRichard Cochran  * clock operations
56d94ba80eSRichard Cochran  *
57d8d26354SRichard Cochran  * @adjfine:  Adjusts the frequency of the hardware clock.
58d8d26354SRichard Cochran  *            parameter scaled_ppm: Desired frequency offset from
59d8d26354SRichard Cochran  *            nominal frequency in parts per million, but with a
60d8d26354SRichard Cochran  *            16 bit binary fractional field.
61d8d26354SRichard Cochran  *
62d94ba80eSRichard Cochran  * @adjfreq:  Adjusts the frequency of the hardware clock.
63d8d26354SRichard Cochran  *            This method is deprecated.  New drivers should implement
64d8d26354SRichard Cochran  *            the @adjfine method instead.
6587f4d7c1SJacob Keller  *            parameter delta: Desired frequency offset from nominal frequency
6687f4d7c1SJacob Keller  *            in parts per billion
67d94ba80eSRichard Cochran  *
68*184ecc9eSVincent Cheng  * @adjphase:  Adjusts the phase offset of the hardware clock.
69*184ecc9eSVincent Cheng  *             parameter delta: Desired change in nanoseconds.
70*184ecc9eSVincent Cheng  *
71d94ba80eSRichard Cochran  * @adjtime:  Shifts the time of the hardware clock.
72d94ba80eSRichard Cochran  *            parameter delta: Desired change in nanoseconds.
73d94ba80eSRichard Cochran  *
7492f17194SRichard Cochran  * @gettime64:  Reads the current time from the hardware clock.
75916444dfSMiroslav Lichvar  *              This method is deprecated.  New drivers should implement
76916444dfSMiroslav Lichvar  *              the @gettimex64 method instead.
7792f17194SRichard Cochran  *              parameter ts: Holds the result.
7892f17194SRichard Cochran  *
7936180087SMiroslav Lichvar  * @gettimex64:  Reads the current time from the hardware clock and optionally
8036180087SMiroslav Lichvar  *               also the system clock.
8136180087SMiroslav Lichvar  *               parameter ts: Holds the PHC timestamp.
8236180087SMiroslav Lichvar  *               parameter sts: If not NULL, it holds a pair of timestamps from
8336180087SMiroslav Lichvar  *               the system clock. The first reading is made right before
8436180087SMiroslav Lichvar  *               reading the lowest bits of the PHC timestamp and the second
8536180087SMiroslav Lichvar  *               reading immediately follows that.
8636180087SMiroslav Lichvar  *
87719f1aa4SChristopher S. Hall  * @getcrosststamp:  Reads the current time from the hardware clock and
88719f1aa4SChristopher S. Hall  *                   system clock simultaneously.
89719f1aa4SChristopher S. Hall  *                   parameter cts: Contains timestamp (device,system) pair,
90719f1aa4SChristopher S. Hall  *                   where system time is realtime and monotonic.
91719f1aa4SChristopher S. Hall  *
9292f17194SRichard Cochran  * @settime64:  Set the current time on the hardware clock.
93d94ba80eSRichard Cochran  *              parameter ts: Time value to set.
94d94ba80eSRichard Cochran  *
95d94ba80eSRichard Cochran  * @enable:   Request driver to enable or disable an ancillary feature.
96d94ba80eSRichard Cochran  *            parameter request: Desired resource to enable or disable.
97d94ba80eSRichard Cochran  *            parameter on: Caller passes one to enable or zero to disable.
98d94ba80eSRichard Cochran  *
996092315dSRichard Cochran  * @verify:   Confirm that a pin can perform a given function. The PTP
1006092315dSRichard Cochran  *            Hardware Clock subsystem maintains the 'pin_config'
1016092315dSRichard Cochran  *            array on behalf of the drivers, but the PHC subsystem
1026092315dSRichard Cochran  *            assumes that every pin can perform every function. This
1036092315dSRichard Cochran  *            hook gives drivers a way of telling the core about
1046092315dSRichard Cochran  *            limitations on specific pins. This function must return
1056092315dSRichard Cochran  *            zero if the function can be assigned to this pin, and
1066092315dSRichard Cochran  *            nonzero otherwise.
1076092315dSRichard Cochran  *            parameter pin: index of the pin in question.
1086092315dSRichard Cochran  *            parameter func: the desired function to use.
1096092315dSRichard Cochran  *            parameter chan: the function channel index to use.
1106092315dSRichard Cochran  *
111d9535cb7SGrygorii Strashko  * @do_work:  Request driver to perform auxiliary (periodic) operations
112d9535cb7SGrygorii Strashko  *	      Driver should return delay of the next auxiliary work scheduling
113d9535cb7SGrygorii Strashko  *	      time (>=0) or negative value in case further scheduling
114d9535cb7SGrygorii Strashko  *	      is not required.
115d9535cb7SGrygorii Strashko  *
116d94ba80eSRichard Cochran  * Drivers should embed their ptp_clock_info within a private
117d94ba80eSRichard Cochran  * structure, obtaining a reference to it using container_of().
118d94ba80eSRichard Cochran  *
119d94ba80eSRichard Cochran  * The callbacks must all return zero on success, non-zero otherwise.
120d94ba80eSRichard Cochran  */
121d94ba80eSRichard Cochran 
122d94ba80eSRichard Cochran struct ptp_clock_info {
123d94ba80eSRichard Cochran 	struct module *owner;
124d94ba80eSRichard Cochran 	char name[16];
125d94ba80eSRichard Cochran 	s32 max_adj;
126d94ba80eSRichard Cochran 	int n_alarm;
127d94ba80eSRichard Cochran 	int n_ext_ts;
128d94ba80eSRichard Cochran 	int n_per_out;
1296092315dSRichard Cochran 	int n_pins;
130d94ba80eSRichard Cochran 	int pps;
1316092315dSRichard Cochran 	struct ptp_pin_desc *pin_config;
132d8d26354SRichard Cochran 	int (*adjfine)(struct ptp_clock_info *ptp, long scaled_ppm);
133d94ba80eSRichard Cochran 	int (*adjfreq)(struct ptp_clock_info *ptp, s32 delta);
134*184ecc9eSVincent Cheng 	int (*adjphase)(struct ptp_clock_info *ptp, s32 phase);
135d94ba80eSRichard Cochran 	int (*adjtime)(struct ptp_clock_info *ptp, s64 delta);
13692f17194SRichard Cochran 	int (*gettime64)(struct ptp_clock_info *ptp, struct timespec64 *ts);
13736180087SMiroslav Lichvar 	int (*gettimex64)(struct ptp_clock_info *ptp, struct timespec64 *ts,
13836180087SMiroslav Lichvar 			  struct ptp_system_timestamp *sts);
139719f1aa4SChristopher S. Hall 	int (*getcrosststamp)(struct ptp_clock_info *ptp,
140719f1aa4SChristopher S. Hall 			      struct system_device_crosststamp *cts);
14192f17194SRichard Cochran 	int (*settime64)(struct ptp_clock_info *p, const struct timespec64 *ts);
142d94ba80eSRichard Cochran 	int (*enable)(struct ptp_clock_info *ptp,
143d94ba80eSRichard Cochran 		      struct ptp_clock_request *request, int on);
1446092315dSRichard Cochran 	int (*verify)(struct ptp_clock_info *ptp, unsigned int pin,
1456092315dSRichard Cochran 		      enum ptp_pin_function func, unsigned int chan);
146d9535cb7SGrygorii Strashko 	long (*do_aux_work)(struct ptp_clock_info *ptp);
147d94ba80eSRichard Cochran };
148d94ba80eSRichard Cochran 
149d94ba80eSRichard Cochran struct ptp_clock;
150d94ba80eSRichard Cochran 
151d94ba80eSRichard Cochran enum ptp_clock_events {
152d94ba80eSRichard Cochran 	PTP_CLOCK_ALARM,
153d94ba80eSRichard Cochran 	PTP_CLOCK_EXTTS,
154d94ba80eSRichard Cochran 	PTP_CLOCK_PPS,
155220a60a4SBen Hutchings 	PTP_CLOCK_PPSUSR,
156d94ba80eSRichard Cochran };
157d94ba80eSRichard Cochran 
158d94ba80eSRichard Cochran /**
159d94ba80eSRichard Cochran  * struct ptp_clock_event - decribes a PTP hardware clock event
160d94ba80eSRichard Cochran  *
161d94ba80eSRichard Cochran  * @type:  One of the ptp_clock_events enumeration values.
162d94ba80eSRichard Cochran  * @index: Identifies the source of the event.
163220a60a4SBen Hutchings  * @timestamp: When the event occurred (%PTP_CLOCK_EXTTS only).
164220a60a4SBen Hutchings  * @pps_times: When the event occurred (%PTP_CLOCK_PPSUSR only).
165d94ba80eSRichard Cochran  */
166d94ba80eSRichard Cochran 
167d94ba80eSRichard Cochran struct ptp_clock_event {
168d94ba80eSRichard Cochran 	int type;
169d94ba80eSRichard Cochran 	int index;
170220a60a4SBen Hutchings 	union {
171d94ba80eSRichard Cochran 		u64 timestamp;
172220a60a4SBen Hutchings 		struct pps_event_time pps_times;
173220a60a4SBen Hutchings 	};
174d94ba80eSRichard Cochran };
175d94ba80eSRichard Cochran 
176d1cbfd77SNicolas Pitre #if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
177d1cbfd77SNicolas Pitre 
178d1cbfd77SNicolas Pitre /**
179d1cbfd77SNicolas Pitre  * ptp_clock_register() - register a PTP hardware clock driver
180d1cbfd77SNicolas Pitre  *
181d1cbfd77SNicolas Pitre  * @info:   Structure describing the new clock.
182d1cbfd77SNicolas Pitre  * @parent: Pointer to the parent device of the new clock.
183d1cbfd77SNicolas Pitre  *
184d1cbfd77SNicolas Pitre  * Returns a valid pointer on success or PTR_ERR on failure.  If PHC
185d1cbfd77SNicolas Pitre  * support is missing at the configuration level, this function
186d1cbfd77SNicolas Pitre  * returns NULL, and drivers are expected to gracefully handle that
187d1cbfd77SNicolas Pitre  * case separately.
188d1cbfd77SNicolas Pitre  */
189d1cbfd77SNicolas Pitre 
190d1cbfd77SNicolas Pitre extern struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,
191d1cbfd77SNicolas Pitre 					    struct device *parent);
192d1cbfd77SNicolas Pitre 
193d1cbfd77SNicolas Pitre /**
194d1cbfd77SNicolas Pitre  * ptp_clock_unregister() - unregister a PTP hardware clock driver
195d1cbfd77SNicolas Pitre  *
196d1cbfd77SNicolas Pitre  * @ptp:  The clock to remove from service.
197d1cbfd77SNicolas Pitre  */
198d1cbfd77SNicolas Pitre 
199d1cbfd77SNicolas Pitre extern int ptp_clock_unregister(struct ptp_clock *ptp);
200d1cbfd77SNicolas Pitre 
201d94ba80eSRichard Cochran /**
202d94ba80eSRichard Cochran  * ptp_clock_event() - notify the PTP layer about an event
203d94ba80eSRichard Cochran  *
204d94ba80eSRichard Cochran  * @ptp:    The clock obtained from ptp_clock_register().
205d94ba80eSRichard Cochran  * @event:  Message structure describing the event.
206d94ba80eSRichard Cochran  */
207d94ba80eSRichard Cochran 
208d94ba80eSRichard Cochran extern void ptp_clock_event(struct ptp_clock *ptp,
209d94ba80eSRichard Cochran 			    struct ptp_clock_event *event);
210d94ba80eSRichard Cochran 
211995a9090SRichard Cochran /**
212995a9090SRichard Cochran  * ptp_clock_index() - obtain the device index of a PTP clock
213995a9090SRichard Cochran  *
214995a9090SRichard Cochran  * @ptp:    The clock obtained from ptp_clock_register().
215995a9090SRichard Cochran  */
216995a9090SRichard Cochran 
217995a9090SRichard Cochran extern int ptp_clock_index(struct ptp_clock *ptp);
218995a9090SRichard Cochran 
2196092315dSRichard Cochran /**
2204368dadaSShalom Toledo  * scaled_ppm_to_ppb() - convert scaled ppm to ppb
2214368dadaSShalom Toledo  *
2224368dadaSShalom Toledo  * @ppm:    Parts per million, but with a 16 bit binary fractional field
2234368dadaSShalom Toledo  */
2244368dadaSShalom Toledo 
2254368dadaSShalom Toledo extern s32 scaled_ppm_to_ppb(long ppm);
2264368dadaSShalom Toledo 
2274368dadaSShalom Toledo /**
2286092315dSRichard Cochran  * ptp_find_pin() - obtain the pin index of a given auxiliary function
2296092315dSRichard Cochran  *
23062582a7eSRichard Cochran  * The caller must hold ptp_clock::pincfg_mux.  Drivers do not have
23162582a7eSRichard Cochran  * access to that mutex as ptp_clock is an opaque type.  However, the
23262582a7eSRichard Cochran  * core code acquires the mutex before invoking the driver's
23362582a7eSRichard Cochran  * ptp_clock_info::enable() callback, and so drivers may call this
23462582a7eSRichard Cochran  * function from that context.
23562582a7eSRichard Cochran  *
2366092315dSRichard Cochran  * @ptp:    The clock obtained from ptp_clock_register().
2376092315dSRichard Cochran  * @func:   One of the ptp_pin_function enumerated values.
2386092315dSRichard Cochran  * @chan:   The particular functional channel to find.
2396092315dSRichard Cochran  * Return:  Pin index in the range of zero to ptp_clock_caps.n_pins - 1,
2406092315dSRichard Cochran  *          or -1 if the auxiliary function cannot be found.
2416092315dSRichard Cochran  */
2426092315dSRichard Cochran 
2436092315dSRichard Cochran int ptp_find_pin(struct ptp_clock *ptp,
2446092315dSRichard Cochran 		 enum ptp_pin_function func, unsigned int chan);
2456092315dSRichard Cochran 
246d9535cb7SGrygorii Strashko /**
24762582a7eSRichard Cochran  * ptp_find_pin_unlocked() - wrapper for ptp_find_pin()
24862582a7eSRichard Cochran  *
24962582a7eSRichard Cochran  * This function acquires the ptp_clock::pincfg_mux mutex before
25062582a7eSRichard Cochran  * invoking ptp_find_pin().  Instead of using this function, drivers
25162582a7eSRichard Cochran  * should most likely call ptp_find_pin() directly from their
25262582a7eSRichard Cochran  * ptp_clock_info::enable() method.
25362582a7eSRichard Cochran  *
25462582a7eSRichard Cochran  */
25562582a7eSRichard Cochran 
25662582a7eSRichard Cochran int ptp_find_pin_unlocked(struct ptp_clock *ptp,
25762582a7eSRichard Cochran 			  enum ptp_pin_function func, unsigned int chan);
25862582a7eSRichard Cochran 
25962582a7eSRichard Cochran /**
260d9535cb7SGrygorii Strashko  * ptp_schedule_worker() - schedule ptp auxiliary work
261d9535cb7SGrygorii Strashko  *
262d9535cb7SGrygorii Strashko  * @ptp:    The clock obtained from ptp_clock_register().
263d9535cb7SGrygorii Strashko  * @delay:  number of jiffies to wait before queuing
264d9535cb7SGrygorii Strashko  *          See kthread_queue_delayed_work() for more info.
265d9535cb7SGrygorii Strashko  */
266d9535cb7SGrygorii Strashko 
267d9535cb7SGrygorii Strashko int ptp_schedule_worker(struct ptp_clock *ptp, unsigned long delay);
268d9535cb7SGrygorii Strashko 
269544fed47SVladimir Oltean /**
270544fed47SVladimir Oltean  * ptp_cancel_worker_sync() - cancel ptp auxiliary clock
271544fed47SVladimir Oltean  *
272544fed47SVladimir Oltean  * @ptp:     The clock obtained from ptp_clock_register().
273544fed47SVladimir Oltean  */
274544fed47SVladimir Oltean void ptp_cancel_worker_sync(struct ptp_clock *ptp);
275544fed47SVladimir Oltean 
276d1cbfd77SNicolas Pitre #else
277d1cbfd77SNicolas Pitre static inline struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,
278d1cbfd77SNicolas Pitre 						   struct device *parent)
279d1cbfd77SNicolas Pitre { return NULL; }
280d1cbfd77SNicolas Pitre static inline int ptp_clock_unregister(struct ptp_clock *ptp)
281d1cbfd77SNicolas Pitre { return 0; }
282d1cbfd77SNicolas Pitre static inline void ptp_clock_event(struct ptp_clock *ptp,
283d1cbfd77SNicolas Pitre 				   struct ptp_clock_event *event)
284d1cbfd77SNicolas Pitre { }
285d1cbfd77SNicolas Pitre static inline int ptp_clock_index(struct ptp_clock *ptp)
286d1cbfd77SNicolas Pitre { return -1; }
287d1cbfd77SNicolas Pitre static inline int ptp_find_pin(struct ptp_clock *ptp,
288d1cbfd77SNicolas Pitre 			       enum ptp_pin_function func, unsigned int chan)
289d1cbfd77SNicolas Pitre { return -1; }
290d9535cb7SGrygorii Strashko static inline int ptp_schedule_worker(struct ptp_clock *ptp,
291d9535cb7SGrygorii Strashko 				      unsigned long delay)
292d9535cb7SGrygorii Strashko { return -EOPNOTSUPP; }
293544fed47SVladimir Oltean static inline void ptp_cancel_worker_sync(struct ptp_clock *ptp)
294544fed47SVladimir Oltean { }
295d9535cb7SGrygorii Strashko 
296d1cbfd77SNicolas Pitre #endif
297d1cbfd77SNicolas Pitre 
29836180087SMiroslav Lichvar static inline void ptp_read_system_prets(struct ptp_system_timestamp *sts)
29936180087SMiroslav Lichvar {
30036180087SMiroslav Lichvar 	if (sts)
30136180087SMiroslav Lichvar 		ktime_get_real_ts64(&sts->pre_ts);
30236180087SMiroslav Lichvar }
30336180087SMiroslav Lichvar 
30436180087SMiroslav Lichvar static inline void ptp_read_system_postts(struct ptp_system_timestamp *sts)
30536180087SMiroslav Lichvar {
30636180087SMiroslav Lichvar 	if (sts)
30736180087SMiroslav Lichvar 		ktime_get_real_ts64(&sts->post_ts);
30836180087SMiroslav Lichvar }
30936180087SMiroslav Lichvar 
310d94ba80eSRichard Cochran #endif
311