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 /**
39d94ba80eSRichard Cochran  * struct ptp_clock_info - decribes 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  *
68d94ba80eSRichard Cochran  * @adjtime:  Shifts the time of the hardware clock.
69d94ba80eSRichard Cochran  *            parameter delta: Desired change in nanoseconds.
70d94ba80eSRichard Cochran  *
7192f17194SRichard Cochran  * @gettime64:  Reads the current time from the hardware clock.
72916444dfSMiroslav Lichvar  *              This method is deprecated.  New drivers should implement
73916444dfSMiroslav Lichvar  *              the @gettimex64 method instead.
7492f17194SRichard Cochran  *              parameter ts: Holds the result.
7592f17194SRichard Cochran  *
7636180087SMiroslav Lichvar  * @gettimex64:  Reads the current time from the hardware clock and optionally
7736180087SMiroslav Lichvar  *               also the system clock.
7836180087SMiroslav Lichvar  *               parameter ts: Holds the PHC timestamp.
7936180087SMiroslav Lichvar  *               parameter sts: If not NULL, it holds a pair of timestamps from
8036180087SMiroslav Lichvar  *               the system clock. The first reading is made right before
8136180087SMiroslav Lichvar  *               reading the lowest bits of the PHC timestamp and the second
8236180087SMiroslav Lichvar  *               reading immediately follows that.
8336180087SMiroslav Lichvar  *
84719f1aa4SChristopher S. Hall  * @getcrosststamp:  Reads the current time from the hardware clock and
85719f1aa4SChristopher S. Hall  *                   system clock simultaneously.
86719f1aa4SChristopher S. Hall  *                   parameter cts: Contains timestamp (device,system) pair,
87719f1aa4SChristopher S. Hall  *                   where system time is realtime and monotonic.
88719f1aa4SChristopher S. Hall  *
8992f17194SRichard Cochran  * @settime64:  Set the current time on the hardware clock.
90d94ba80eSRichard Cochran  *              parameter ts: Time value to set.
91d94ba80eSRichard Cochran  *
92d94ba80eSRichard Cochran  * @enable:   Request driver to enable or disable an ancillary feature.
93d94ba80eSRichard Cochran  *            parameter request: Desired resource to enable or disable.
94d94ba80eSRichard Cochran  *            parameter on: Caller passes one to enable or zero to disable.
95d94ba80eSRichard Cochran  *
966092315dSRichard Cochran  * @verify:   Confirm that a pin can perform a given function. The PTP
976092315dSRichard Cochran  *            Hardware Clock subsystem maintains the 'pin_config'
986092315dSRichard Cochran  *            array on behalf of the drivers, but the PHC subsystem
996092315dSRichard Cochran  *            assumes that every pin can perform every function. This
1006092315dSRichard Cochran  *            hook gives drivers a way of telling the core about
1016092315dSRichard Cochran  *            limitations on specific pins. This function must return
1026092315dSRichard Cochran  *            zero if the function can be assigned to this pin, and
1036092315dSRichard Cochran  *            nonzero otherwise.
1046092315dSRichard Cochran  *            parameter pin: index of the pin in question.
1056092315dSRichard Cochran  *            parameter func: the desired function to use.
1066092315dSRichard Cochran  *            parameter chan: the function channel index to use.
1076092315dSRichard Cochran  *
108d9535cb7SGrygorii Strashko  * @do_work:  Request driver to perform auxiliary (periodic) operations
109d9535cb7SGrygorii Strashko  *	      Driver should return delay of the next auxiliary work scheduling
110d9535cb7SGrygorii Strashko  *	      time (>=0) or negative value in case further scheduling
111d9535cb7SGrygorii Strashko  *	      is not required.
112d9535cb7SGrygorii Strashko  *
113d94ba80eSRichard Cochran  * Drivers should embed their ptp_clock_info within a private
114d94ba80eSRichard Cochran  * structure, obtaining a reference to it using container_of().
115d94ba80eSRichard Cochran  *
116d94ba80eSRichard Cochran  * The callbacks must all return zero on success, non-zero otherwise.
117d94ba80eSRichard Cochran  */
118d94ba80eSRichard Cochran 
119d94ba80eSRichard Cochran struct ptp_clock_info {
120d94ba80eSRichard Cochran 	struct module *owner;
121d94ba80eSRichard Cochran 	char name[16];
122d94ba80eSRichard Cochran 	s32 max_adj;
123d94ba80eSRichard Cochran 	int n_alarm;
124d94ba80eSRichard Cochran 	int n_ext_ts;
125d94ba80eSRichard Cochran 	int n_per_out;
1266092315dSRichard Cochran 	int n_pins;
127d94ba80eSRichard Cochran 	int pps;
1286092315dSRichard Cochran 	struct ptp_pin_desc *pin_config;
129d8d26354SRichard Cochran 	int (*adjfine)(struct ptp_clock_info *ptp, long scaled_ppm);
130d94ba80eSRichard Cochran 	int (*adjfreq)(struct ptp_clock_info *ptp, s32 delta);
131d94ba80eSRichard Cochran 	int (*adjtime)(struct ptp_clock_info *ptp, s64 delta);
13292f17194SRichard Cochran 	int (*gettime64)(struct ptp_clock_info *ptp, struct timespec64 *ts);
13336180087SMiroslav Lichvar 	int (*gettimex64)(struct ptp_clock_info *ptp, struct timespec64 *ts,
13436180087SMiroslav Lichvar 			  struct ptp_system_timestamp *sts);
135719f1aa4SChristopher S. Hall 	int (*getcrosststamp)(struct ptp_clock_info *ptp,
136719f1aa4SChristopher S. Hall 			      struct system_device_crosststamp *cts);
13792f17194SRichard Cochran 	int (*settime64)(struct ptp_clock_info *p, const struct timespec64 *ts);
138d94ba80eSRichard Cochran 	int (*enable)(struct ptp_clock_info *ptp,
139d94ba80eSRichard Cochran 		      struct ptp_clock_request *request, int on);
1406092315dSRichard Cochran 	int (*verify)(struct ptp_clock_info *ptp, unsigned int pin,
1416092315dSRichard Cochran 		      enum ptp_pin_function func, unsigned int chan);
142d9535cb7SGrygorii Strashko 	long (*do_aux_work)(struct ptp_clock_info *ptp);
143d94ba80eSRichard Cochran };
144d94ba80eSRichard Cochran 
145d94ba80eSRichard Cochran struct ptp_clock;
146d94ba80eSRichard Cochran 
147d94ba80eSRichard Cochran enum ptp_clock_events {
148d94ba80eSRichard Cochran 	PTP_CLOCK_ALARM,
149d94ba80eSRichard Cochran 	PTP_CLOCK_EXTTS,
150d94ba80eSRichard Cochran 	PTP_CLOCK_PPS,
151220a60a4SBen Hutchings 	PTP_CLOCK_PPSUSR,
152d94ba80eSRichard Cochran };
153d94ba80eSRichard Cochran 
154d94ba80eSRichard Cochran /**
155d94ba80eSRichard Cochran  * struct ptp_clock_event - decribes a PTP hardware clock event
156d94ba80eSRichard Cochran  *
157d94ba80eSRichard Cochran  * @type:  One of the ptp_clock_events enumeration values.
158d94ba80eSRichard Cochran  * @index: Identifies the source of the event.
159220a60a4SBen Hutchings  * @timestamp: When the event occurred (%PTP_CLOCK_EXTTS only).
160220a60a4SBen Hutchings  * @pps_times: When the event occurred (%PTP_CLOCK_PPSUSR only).
161d94ba80eSRichard Cochran  */
162d94ba80eSRichard Cochran 
163d94ba80eSRichard Cochran struct ptp_clock_event {
164d94ba80eSRichard Cochran 	int type;
165d94ba80eSRichard Cochran 	int index;
166220a60a4SBen Hutchings 	union {
167d94ba80eSRichard Cochran 		u64 timestamp;
168220a60a4SBen Hutchings 		struct pps_event_time pps_times;
169220a60a4SBen Hutchings 	};
170d94ba80eSRichard Cochran };
171d94ba80eSRichard Cochran 
172d1cbfd77SNicolas Pitre #if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
173d1cbfd77SNicolas Pitre 
174d1cbfd77SNicolas Pitre /**
175d1cbfd77SNicolas Pitre  * ptp_clock_register() - register a PTP hardware clock driver
176d1cbfd77SNicolas Pitre  *
177d1cbfd77SNicolas Pitre  * @info:   Structure describing the new clock.
178d1cbfd77SNicolas Pitre  * @parent: Pointer to the parent device of the new clock.
179d1cbfd77SNicolas Pitre  *
180d1cbfd77SNicolas Pitre  * Returns a valid pointer on success or PTR_ERR on failure.  If PHC
181d1cbfd77SNicolas Pitre  * support is missing at the configuration level, this function
182d1cbfd77SNicolas Pitre  * returns NULL, and drivers are expected to gracefully handle that
183d1cbfd77SNicolas Pitre  * case separately.
184d1cbfd77SNicolas Pitre  */
185d1cbfd77SNicolas Pitre 
186d1cbfd77SNicolas Pitre extern struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,
187d1cbfd77SNicolas Pitre 					    struct device *parent);
188d1cbfd77SNicolas Pitre 
189d1cbfd77SNicolas Pitre /**
190d1cbfd77SNicolas Pitre  * ptp_clock_unregister() - unregister a PTP hardware clock driver
191d1cbfd77SNicolas Pitre  *
192d1cbfd77SNicolas Pitre  * @ptp:  The clock to remove from service.
193d1cbfd77SNicolas Pitre  */
194d1cbfd77SNicolas Pitre 
195d1cbfd77SNicolas Pitre extern int ptp_clock_unregister(struct ptp_clock *ptp);
196d1cbfd77SNicolas Pitre 
197d94ba80eSRichard Cochran /**
198d94ba80eSRichard Cochran  * ptp_clock_event() - notify the PTP layer about an event
199d94ba80eSRichard Cochran  *
200d94ba80eSRichard Cochran  * @ptp:    The clock obtained from ptp_clock_register().
201d94ba80eSRichard Cochran  * @event:  Message structure describing the event.
202d94ba80eSRichard Cochran  */
203d94ba80eSRichard Cochran 
204d94ba80eSRichard Cochran extern void ptp_clock_event(struct ptp_clock *ptp,
205d94ba80eSRichard Cochran 			    struct ptp_clock_event *event);
206d94ba80eSRichard Cochran 
207995a9090SRichard Cochran /**
208995a9090SRichard Cochran  * ptp_clock_index() - obtain the device index of a PTP clock
209995a9090SRichard Cochran  *
210995a9090SRichard Cochran  * @ptp:    The clock obtained from ptp_clock_register().
211995a9090SRichard Cochran  */
212995a9090SRichard Cochran 
213995a9090SRichard Cochran extern int ptp_clock_index(struct ptp_clock *ptp);
214995a9090SRichard Cochran 
2156092315dSRichard Cochran /**
216*4368dadaSShalom Toledo  * scaled_ppm_to_ppb() - convert scaled ppm to ppb
217*4368dadaSShalom Toledo  *
218*4368dadaSShalom Toledo  * @ppm:    Parts per million, but with a 16 bit binary fractional field
219*4368dadaSShalom Toledo  */
220*4368dadaSShalom Toledo 
221*4368dadaSShalom Toledo extern s32 scaled_ppm_to_ppb(long ppm);
222*4368dadaSShalom Toledo 
223*4368dadaSShalom Toledo /**
2246092315dSRichard Cochran  * ptp_find_pin() - obtain the pin index of a given auxiliary function
2256092315dSRichard Cochran  *
2266092315dSRichard Cochran  * @ptp:    The clock obtained from ptp_clock_register().
2276092315dSRichard Cochran  * @func:   One of the ptp_pin_function enumerated values.
2286092315dSRichard Cochran  * @chan:   The particular functional channel to find.
2296092315dSRichard Cochran  * Return:  Pin index in the range of zero to ptp_clock_caps.n_pins - 1,
2306092315dSRichard Cochran  *          or -1 if the auxiliary function cannot be found.
2316092315dSRichard Cochran  */
2326092315dSRichard Cochran 
2336092315dSRichard Cochran int ptp_find_pin(struct ptp_clock *ptp,
2346092315dSRichard Cochran 		 enum ptp_pin_function func, unsigned int chan);
2356092315dSRichard Cochran 
236d9535cb7SGrygorii Strashko /**
237d9535cb7SGrygorii Strashko  * ptp_schedule_worker() - schedule ptp auxiliary work
238d9535cb7SGrygorii Strashko  *
239d9535cb7SGrygorii Strashko  * @ptp:    The clock obtained from ptp_clock_register().
240d9535cb7SGrygorii Strashko  * @delay:  number of jiffies to wait before queuing
241d9535cb7SGrygorii Strashko  *          See kthread_queue_delayed_work() for more info.
242d9535cb7SGrygorii Strashko  */
243d9535cb7SGrygorii Strashko 
244d9535cb7SGrygorii Strashko int ptp_schedule_worker(struct ptp_clock *ptp, unsigned long delay);
245d9535cb7SGrygorii Strashko 
246d1cbfd77SNicolas Pitre #else
247d1cbfd77SNicolas Pitre static inline struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,
248d1cbfd77SNicolas Pitre 						   struct device *parent)
249d1cbfd77SNicolas Pitre { return NULL; }
250d1cbfd77SNicolas Pitre static inline int ptp_clock_unregister(struct ptp_clock *ptp)
251d1cbfd77SNicolas Pitre { return 0; }
252d1cbfd77SNicolas Pitre static inline void ptp_clock_event(struct ptp_clock *ptp,
253d1cbfd77SNicolas Pitre 				   struct ptp_clock_event *event)
254d1cbfd77SNicolas Pitre { }
255d1cbfd77SNicolas Pitre static inline int ptp_clock_index(struct ptp_clock *ptp)
256d1cbfd77SNicolas Pitre { return -1; }
257d1cbfd77SNicolas Pitre static inline int ptp_find_pin(struct ptp_clock *ptp,
258d1cbfd77SNicolas Pitre 			       enum ptp_pin_function func, unsigned int chan)
259d1cbfd77SNicolas Pitre { return -1; }
260d9535cb7SGrygorii Strashko static inline int ptp_schedule_worker(struct ptp_clock *ptp,
261d9535cb7SGrygorii Strashko 				      unsigned long delay)
262d9535cb7SGrygorii Strashko { return -EOPNOTSUPP; }
263d9535cb7SGrygorii Strashko 
264d1cbfd77SNicolas Pitre #endif
265d1cbfd77SNicolas Pitre 
26636180087SMiroslav Lichvar static inline void ptp_read_system_prets(struct ptp_system_timestamp *sts)
26736180087SMiroslav Lichvar {
26836180087SMiroslav Lichvar 	if (sts)
26936180087SMiroslav Lichvar 		ktime_get_real_ts64(&sts->pre_ts);
27036180087SMiroslav Lichvar }
27136180087SMiroslav Lichvar 
27236180087SMiroslav Lichvar static inline void ptp_read_system_postts(struct ptp_system_timestamp *sts)
27336180087SMiroslav Lichvar {
27436180087SMiroslav Lichvar 	if (sts)
27536180087SMiroslav Lichvar 		ktime_get_real_ts64(&sts->post_ts);
27636180087SMiroslav Lichvar }
27736180087SMiroslav Lichvar 
278d94ba80eSRichard Cochran #endif
279