xref: /linux/drivers/virtio/virtio_rtc_ptp.c (revision 8ca154e4910efff1b04e7750e007d75732c68323)
1*9a17125aSPeter Hilber // SPDX-License-Identifier: GPL-2.0-or-later
2*9a17125aSPeter Hilber /*
3*9a17125aSPeter Hilber  * Expose virtio_rtc clocks as PTP clocks.
4*9a17125aSPeter Hilber  *
5*9a17125aSPeter Hilber  * Copyright (C) 2022-2023 OpenSynergy GmbH
6*9a17125aSPeter Hilber  * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
7*9a17125aSPeter Hilber  *
8*9a17125aSPeter Hilber  * Derived from ptp_kvm_common.c, virtual PTP 1588 clock for use with KVM
9*9a17125aSPeter Hilber  * guests.
10*9a17125aSPeter Hilber  *
11*9a17125aSPeter Hilber  * Copyright (C) 2017 Red Hat Inc.
12*9a17125aSPeter Hilber  */
13*9a17125aSPeter Hilber 
14*9a17125aSPeter Hilber #include <linux/device.h>
15*9a17125aSPeter Hilber #include <linux/err.h>
16*9a17125aSPeter Hilber #include <linux/ptp_clock_kernel.h>
17*9a17125aSPeter Hilber 
18*9a17125aSPeter Hilber #include <uapi/linux/virtio_rtc.h>
19*9a17125aSPeter Hilber 
20*9a17125aSPeter Hilber #include "virtio_rtc_internal.h"
21*9a17125aSPeter Hilber 
22*9a17125aSPeter Hilber /**
23*9a17125aSPeter Hilber  * struct viortc_ptp_clock - PTP clock abstraction
24*9a17125aSPeter Hilber  * @ptp_clock: PTP clock handle for unregistering
25*9a17125aSPeter Hilber  * @viortc: virtio_rtc device data
26*9a17125aSPeter Hilber  * @ptp_info: PTP clock description
27*9a17125aSPeter Hilber  * @vio_clk_id: virtio_rtc clock id
28*9a17125aSPeter Hilber  * @have_cross: device supports crosststamp with available HW counter
29*9a17125aSPeter Hilber  */
30*9a17125aSPeter Hilber struct viortc_ptp_clock {
31*9a17125aSPeter Hilber 	struct ptp_clock *ptp_clock;
32*9a17125aSPeter Hilber 	struct viortc_dev *viortc;
33*9a17125aSPeter Hilber 	struct ptp_clock_info ptp_info;
34*9a17125aSPeter Hilber 	u16 vio_clk_id;
35*9a17125aSPeter Hilber 	bool have_cross;
36*9a17125aSPeter Hilber };
37*9a17125aSPeter Hilber 
38*9a17125aSPeter Hilber /**
39*9a17125aSPeter Hilber  * struct viortc_ptp_cross_ctx - context for get_device_system_crosststamp()
40*9a17125aSPeter Hilber  * @device_time: device clock reading
41*9a17125aSPeter Hilber  * @system_counterval: HW counter value at device_time
42*9a17125aSPeter Hilber  *
43*9a17125aSPeter Hilber  * Provides the already obtained crosststamp to get_device_system_crosststamp().
44*9a17125aSPeter Hilber  */
45*9a17125aSPeter Hilber struct viortc_ptp_cross_ctx {
46*9a17125aSPeter Hilber 	ktime_t device_time;
47*9a17125aSPeter Hilber 	struct system_counterval_t system_counterval;
48*9a17125aSPeter Hilber };
49*9a17125aSPeter Hilber 
50*9a17125aSPeter Hilber /* Weak function in case get_device_system_crosststamp() is not supported */
viortc_hw_xtstamp_params(u8 * hw_counter,enum clocksource_ids * cs_id)51*9a17125aSPeter Hilber int __weak viortc_hw_xtstamp_params(u8 *hw_counter, enum clocksource_ids *cs_id)
52*9a17125aSPeter Hilber {
53*9a17125aSPeter Hilber 	return -EOPNOTSUPP;
54*9a17125aSPeter Hilber }
55*9a17125aSPeter Hilber 
56*9a17125aSPeter Hilber /**
57*9a17125aSPeter Hilber  * viortc_ptp_get_time_fn() - callback for get_device_system_crosststamp()
58*9a17125aSPeter Hilber  * @device_time: device clock reading
59*9a17125aSPeter Hilber  * @system_counterval: HW counter value at device_time
60*9a17125aSPeter Hilber  * @ctx: context with already obtained crosststamp
61*9a17125aSPeter Hilber  *
62*9a17125aSPeter Hilber  * Return: zero (success).
63*9a17125aSPeter Hilber  */
viortc_ptp_get_time_fn(ktime_t * device_time,struct system_counterval_t * system_counterval,void * ctx)64*9a17125aSPeter Hilber static int viortc_ptp_get_time_fn(ktime_t *device_time,
65*9a17125aSPeter Hilber 				  struct system_counterval_t *system_counterval,
66*9a17125aSPeter Hilber 				  void *ctx)
67*9a17125aSPeter Hilber {
68*9a17125aSPeter Hilber 	struct viortc_ptp_cross_ctx *vio_ctx = ctx;
69*9a17125aSPeter Hilber 
70*9a17125aSPeter Hilber 	*device_time = vio_ctx->device_time;
71*9a17125aSPeter Hilber 	*system_counterval = vio_ctx->system_counterval;
72*9a17125aSPeter Hilber 
73*9a17125aSPeter Hilber 	return 0;
74*9a17125aSPeter Hilber }
75*9a17125aSPeter Hilber 
76*9a17125aSPeter Hilber /**
77*9a17125aSPeter Hilber  * viortc_ptp_do_xtstamp() - get crosststamp from device
78*9a17125aSPeter Hilber  * @vio_ptp: virtio_rtc PTP clock
79*9a17125aSPeter Hilber  * @hw_counter: virtio_rtc HW counter type
80*9a17125aSPeter Hilber  * @cs_id: clocksource id corresponding to hw_counter
81*9a17125aSPeter Hilber  * @ctx: context for get_device_system_crosststamp()
82*9a17125aSPeter Hilber  *
83*9a17125aSPeter Hilber  * Reads HW-specific crosststamp from device.
84*9a17125aSPeter Hilber  *
85*9a17125aSPeter Hilber  * Context: Process context.
86*9a17125aSPeter Hilber  * Return: Zero on success, negative error code otherwise.
87*9a17125aSPeter Hilber  */
viortc_ptp_do_xtstamp(struct viortc_ptp_clock * vio_ptp,u8 hw_counter,enum clocksource_ids cs_id,struct viortc_ptp_cross_ctx * ctx)88*9a17125aSPeter Hilber static int viortc_ptp_do_xtstamp(struct viortc_ptp_clock *vio_ptp,
89*9a17125aSPeter Hilber 				 u8 hw_counter, enum clocksource_ids cs_id,
90*9a17125aSPeter Hilber 				 struct viortc_ptp_cross_ctx *ctx)
91*9a17125aSPeter Hilber {
92*9a17125aSPeter Hilber 	u64 max_ns, ns;
93*9a17125aSPeter Hilber 	int ret;
94*9a17125aSPeter Hilber 
95*9a17125aSPeter Hilber 	ctx->system_counterval.cs_id = cs_id;
96*9a17125aSPeter Hilber 
97*9a17125aSPeter Hilber 	ret = viortc_read_cross(vio_ptp->viortc, vio_ptp->vio_clk_id,
98*9a17125aSPeter Hilber 				hw_counter, &ns,
99*9a17125aSPeter Hilber 				&ctx->system_counterval.cycles);
100*9a17125aSPeter Hilber 	if (ret)
101*9a17125aSPeter Hilber 		return ret;
102*9a17125aSPeter Hilber 
103*9a17125aSPeter Hilber 	max_ns = (u64)ktime_to_ns(KTIME_MAX);
104*9a17125aSPeter Hilber 	if (ns > max_ns)
105*9a17125aSPeter Hilber 		return -EINVAL;
106*9a17125aSPeter Hilber 
107*9a17125aSPeter Hilber 	ctx->device_time = ns_to_ktime(ns);
108*9a17125aSPeter Hilber 
109*9a17125aSPeter Hilber 	return 0;
110*9a17125aSPeter Hilber }
111*9a17125aSPeter Hilber 
112*9a17125aSPeter Hilber /*
113*9a17125aSPeter Hilber  * PTP clock operations
114*9a17125aSPeter Hilber  */
115*9a17125aSPeter Hilber 
116*9a17125aSPeter Hilber /**
117*9a17125aSPeter Hilber  * viortc_ptp_getcrosststamp() - PTP clock getcrosststamp op
118*9a17125aSPeter Hilber  * @ptp: PTP clock info
119*9a17125aSPeter Hilber  * @xtstamp: crosststamp
120*9a17125aSPeter Hilber  *
121*9a17125aSPeter Hilber  * Context: Process context.
122*9a17125aSPeter Hilber  * Return: Zero on success, negative error code otherwise.
123*9a17125aSPeter Hilber  */
viortc_ptp_getcrosststamp(struct ptp_clock_info * ptp,struct system_device_crosststamp * xtstamp)124*9a17125aSPeter Hilber static int viortc_ptp_getcrosststamp(struct ptp_clock_info *ptp,
125*9a17125aSPeter Hilber 				     struct system_device_crosststamp *xtstamp)
126*9a17125aSPeter Hilber {
127*9a17125aSPeter Hilber 	struct viortc_ptp_clock *vio_ptp =
128*9a17125aSPeter Hilber 		container_of(ptp, struct viortc_ptp_clock, ptp_info);
129*9a17125aSPeter Hilber 	struct system_time_snapshot history_begin;
130*9a17125aSPeter Hilber 	struct viortc_ptp_cross_ctx ctx;
131*9a17125aSPeter Hilber 	enum clocksource_ids cs_id;
132*9a17125aSPeter Hilber 	u8 hw_counter;
133*9a17125aSPeter Hilber 	int ret;
134*9a17125aSPeter Hilber 
135*9a17125aSPeter Hilber 	if (!vio_ptp->have_cross)
136*9a17125aSPeter Hilber 		return -EOPNOTSUPP;
137*9a17125aSPeter Hilber 
138*9a17125aSPeter Hilber 	ret = viortc_hw_xtstamp_params(&hw_counter, &cs_id);
139*9a17125aSPeter Hilber 	if (ret)
140*9a17125aSPeter Hilber 		return ret;
141*9a17125aSPeter Hilber 
142*9a17125aSPeter Hilber 	ktime_get_snapshot(&history_begin);
143*9a17125aSPeter Hilber 	if (history_begin.cs_id != cs_id)
144*9a17125aSPeter Hilber 		return -EOPNOTSUPP;
145*9a17125aSPeter Hilber 
146*9a17125aSPeter Hilber 	/*
147*9a17125aSPeter Hilber 	 * Getting the timestamp can take many milliseconds with a slow Virtio
148*9a17125aSPeter Hilber 	 * device. This is too long for viortc_ptp_get_time_fn() passed to
149*9a17125aSPeter Hilber 	 * get_device_system_crosststamp(), which has to usually return before
150*9a17125aSPeter Hilber 	 * the timekeeper seqcount increases (every tick or so).
151*9a17125aSPeter Hilber 	 *
152*9a17125aSPeter Hilber 	 * So, get the actual cross-timestamp first.
153*9a17125aSPeter Hilber 	 */
154*9a17125aSPeter Hilber 	ret = viortc_ptp_do_xtstamp(vio_ptp, hw_counter, cs_id, &ctx);
155*9a17125aSPeter Hilber 	if (ret)
156*9a17125aSPeter Hilber 		return ret;
157*9a17125aSPeter Hilber 
158*9a17125aSPeter Hilber 	ret = get_device_system_crosststamp(viortc_ptp_get_time_fn, &ctx,
159*9a17125aSPeter Hilber 					    &history_begin, xtstamp);
160*9a17125aSPeter Hilber 	if (ret)
161*9a17125aSPeter Hilber 		pr_debug("%s: get_device_system_crosststamp() returned %d\n",
162*9a17125aSPeter Hilber 			 __func__, ret);
163*9a17125aSPeter Hilber 
164*9a17125aSPeter Hilber 	return ret;
165*9a17125aSPeter Hilber }
166*9a17125aSPeter Hilber 
167*9a17125aSPeter Hilber /* viortc_ptp_adjfine() - unsupported PTP clock adjfine op */
viortc_ptp_adjfine(struct ptp_clock_info * ptp,long scaled_ppm)168*9a17125aSPeter Hilber static int viortc_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
169*9a17125aSPeter Hilber {
170*9a17125aSPeter Hilber 	return -EOPNOTSUPP;
171*9a17125aSPeter Hilber }
172*9a17125aSPeter Hilber 
173*9a17125aSPeter Hilber /* viortc_ptp_adjtime() - unsupported PTP clock adjtime op */
viortc_ptp_adjtime(struct ptp_clock_info * ptp,s64 delta)174*9a17125aSPeter Hilber static int viortc_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
175*9a17125aSPeter Hilber {
176*9a17125aSPeter Hilber 	return -EOPNOTSUPP;
177*9a17125aSPeter Hilber }
178*9a17125aSPeter Hilber 
179*9a17125aSPeter Hilber /* viortc_ptp_settime64() - unsupported PTP clock settime64 op */
viortc_ptp_settime64(struct ptp_clock_info * ptp,const struct timespec64 * ts)180*9a17125aSPeter Hilber static int viortc_ptp_settime64(struct ptp_clock_info *ptp,
181*9a17125aSPeter Hilber 				const struct timespec64 *ts)
182*9a17125aSPeter Hilber {
183*9a17125aSPeter Hilber 	return -EOPNOTSUPP;
184*9a17125aSPeter Hilber }
185*9a17125aSPeter Hilber 
186*9a17125aSPeter Hilber /*
187*9a17125aSPeter Hilber  * viortc_ptp_gettimex64() - PTP clock gettimex64 op
188*9a17125aSPeter Hilber  *
189*9a17125aSPeter Hilber  * Context: Process context.
190*9a17125aSPeter Hilber  */
viortc_ptp_gettimex64(struct ptp_clock_info * ptp,struct timespec64 * ts,struct ptp_system_timestamp * sts)191*9a17125aSPeter Hilber static int viortc_ptp_gettimex64(struct ptp_clock_info *ptp,
192*9a17125aSPeter Hilber 				 struct timespec64 *ts,
193*9a17125aSPeter Hilber 				 struct ptp_system_timestamp *sts)
194*9a17125aSPeter Hilber {
195*9a17125aSPeter Hilber 	struct viortc_ptp_clock *vio_ptp =
196*9a17125aSPeter Hilber 		container_of(ptp, struct viortc_ptp_clock, ptp_info);
197*9a17125aSPeter Hilber 	int ret;
198*9a17125aSPeter Hilber 	u64 ns;
199*9a17125aSPeter Hilber 
200*9a17125aSPeter Hilber 	ptp_read_system_prets(sts);
201*9a17125aSPeter Hilber 	ret = viortc_read(vio_ptp->viortc, vio_ptp->vio_clk_id, &ns);
202*9a17125aSPeter Hilber 	ptp_read_system_postts(sts);
203*9a17125aSPeter Hilber 
204*9a17125aSPeter Hilber 	if (ret)
205*9a17125aSPeter Hilber 		return ret;
206*9a17125aSPeter Hilber 
207*9a17125aSPeter Hilber 	if (ns > (u64)S64_MAX)
208*9a17125aSPeter Hilber 		return -EINVAL;
209*9a17125aSPeter Hilber 
210*9a17125aSPeter Hilber 	*ts = ns_to_timespec64((s64)ns);
211*9a17125aSPeter Hilber 
212*9a17125aSPeter Hilber 	return 0;
213*9a17125aSPeter Hilber }
214*9a17125aSPeter Hilber 
215*9a17125aSPeter Hilber /* viortc_ptp_enable() - unsupported PTP clock enable op */
viortc_ptp_enable(struct ptp_clock_info * ptp,struct ptp_clock_request * rq,int on)216*9a17125aSPeter Hilber static int viortc_ptp_enable(struct ptp_clock_info *ptp,
217*9a17125aSPeter Hilber 			     struct ptp_clock_request *rq, int on)
218*9a17125aSPeter Hilber {
219*9a17125aSPeter Hilber 	return -EOPNOTSUPP;
220*9a17125aSPeter Hilber }
221*9a17125aSPeter Hilber 
222*9a17125aSPeter Hilber /*
223*9a17125aSPeter Hilber  * viortc_ptp_info_template - ptp_clock_info template
224*9a17125aSPeter Hilber  *
225*9a17125aSPeter Hilber  * The .name member will be set for individual virtio_rtc PTP clocks.
226*9a17125aSPeter Hilber  *
227*9a17125aSPeter Hilber  * The .getcrosststamp member will be cleared for PTP clocks not supporting
228*9a17125aSPeter Hilber  * crosststamp.
229*9a17125aSPeter Hilber  */
230*9a17125aSPeter Hilber static const struct ptp_clock_info viortc_ptp_info_template = {
231*9a17125aSPeter Hilber 	.owner = THIS_MODULE,
232*9a17125aSPeter Hilber 	/* .name is set according to clock type */
233*9a17125aSPeter Hilber 	.adjfine = viortc_ptp_adjfine,
234*9a17125aSPeter Hilber 	.adjtime = viortc_ptp_adjtime,
235*9a17125aSPeter Hilber 	.gettimex64 = viortc_ptp_gettimex64,
236*9a17125aSPeter Hilber 	.settime64 = viortc_ptp_settime64,
237*9a17125aSPeter Hilber 	.enable = viortc_ptp_enable,
238*9a17125aSPeter Hilber 	.getcrosststamp = viortc_ptp_getcrosststamp,
239*9a17125aSPeter Hilber };
240*9a17125aSPeter Hilber 
241*9a17125aSPeter Hilber /**
242*9a17125aSPeter Hilber  * viortc_ptp_unregister() - PTP clock unregistering wrapper
243*9a17125aSPeter Hilber  * @vio_ptp: virtio_rtc PTP clock
244*9a17125aSPeter Hilber  * @parent_dev: parent device of PTP clock
245*9a17125aSPeter Hilber  *
246*9a17125aSPeter Hilber  * Return: Zero on success, negative error code otherwise.
247*9a17125aSPeter Hilber  */
viortc_ptp_unregister(struct viortc_ptp_clock * vio_ptp,struct device * parent_dev)248*9a17125aSPeter Hilber int viortc_ptp_unregister(struct viortc_ptp_clock *vio_ptp,
249*9a17125aSPeter Hilber 			  struct device *parent_dev)
250*9a17125aSPeter Hilber {
251*9a17125aSPeter Hilber 	int ret = ptp_clock_unregister(vio_ptp->ptp_clock);
252*9a17125aSPeter Hilber 
253*9a17125aSPeter Hilber 	if (!ret)
254*9a17125aSPeter Hilber 		devm_kfree(parent_dev, vio_ptp);
255*9a17125aSPeter Hilber 
256*9a17125aSPeter Hilber 	return ret;
257*9a17125aSPeter Hilber }
258*9a17125aSPeter Hilber 
259*9a17125aSPeter Hilber /**
260*9a17125aSPeter Hilber  * viortc_ptp_get_cross_cap() - get xtstamp support info from device
261*9a17125aSPeter Hilber  * @viortc: virtio_rtc device data
262*9a17125aSPeter Hilber  * @vio_ptp: virtio_rtc PTP clock abstraction
263*9a17125aSPeter Hilber  *
264*9a17125aSPeter Hilber  * Context: Process context.
265*9a17125aSPeter Hilber  * Return: Zero on success, negative error code otherwise.
266*9a17125aSPeter Hilber  */
viortc_ptp_get_cross_cap(struct viortc_dev * viortc,struct viortc_ptp_clock * vio_ptp)267*9a17125aSPeter Hilber static int viortc_ptp_get_cross_cap(struct viortc_dev *viortc,
268*9a17125aSPeter Hilber 				    struct viortc_ptp_clock *vio_ptp)
269*9a17125aSPeter Hilber {
270*9a17125aSPeter Hilber 	enum clocksource_ids cs_id;
271*9a17125aSPeter Hilber 	bool xtstamp_supported;
272*9a17125aSPeter Hilber 	u8 hw_counter;
273*9a17125aSPeter Hilber 	int ret;
274*9a17125aSPeter Hilber 
275*9a17125aSPeter Hilber 	ret = viortc_hw_xtstamp_params(&hw_counter, &cs_id);
276*9a17125aSPeter Hilber 	if (ret) {
277*9a17125aSPeter Hilber 		vio_ptp->have_cross = false;
278*9a17125aSPeter Hilber 		return 0;
279*9a17125aSPeter Hilber 	}
280*9a17125aSPeter Hilber 
281*9a17125aSPeter Hilber 	ret = viortc_cross_cap(viortc, vio_ptp->vio_clk_id, hw_counter,
282*9a17125aSPeter Hilber 			       &xtstamp_supported);
283*9a17125aSPeter Hilber 	if (ret)
284*9a17125aSPeter Hilber 		return ret;
285*9a17125aSPeter Hilber 
286*9a17125aSPeter Hilber 	vio_ptp->have_cross = xtstamp_supported;
287*9a17125aSPeter Hilber 
288*9a17125aSPeter Hilber 	return 0;
289*9a17125aSPeter Hilber }
290*9a17125aSPeter Hilber 
291*9a17125aSPeter Hilber /**
292*9a17125aSPeter Hilber  * viortc_ptp_register() - prepare and register PTP clock
293*9a17125aSPeter Hilber  * @viortc: virtio_rtc device data
294*9a17125aSPeter Hilber  * @parent_dev: parent device for PTP clock
295*9a17125aSPeter Hilber  * @vio_clk_id: id of virtio_rtc clock which backs PTP clock
296*9a17125aSPeter Hilber  * @ptp_clock_name: PTP clock name
297*9a17125aSPeter Hilber  *
298*9a17125aSPeter Hilber  * Context: Process context.
299*9a17125aSPeter Hilber  * Return: Pointer on success, ERR_PTR() otherwise; NULL if PTP clock support
300*9a17125aSPeter Hilber  *         not available.
301*9a17125aSPeter Hilber  */
viortc_ptp_register(struct viortc_dev * viortc,struct device * parent_dev,u16 vio_clk_id,const char * ptp_clock_name)302*9a17125aSPeter Hilber struct viortc_ptp_clock *viortc_ptp_register(struct viortc_dev *viortc,
303*9a17125aSPeter Hilber 					     struct device *parent_dev,
304*9a17125aSPeter Hilber 					     u16 vio_clk_id,
305*9a17125aSPeter Hilber 					     const char *ptp_clock_name)
306*9a17125aSPeter Hilber {
307*9a17125aSPeter Hilber 	struct viortc_ptp_clock *vio_ptp;
308*9a17125aSPeter Hilber 	struct ptp_clock *ptp_clock;
309*9a17125aSPeter Hilber 	ssize_t len;
310*9a17125aSPeter Hilber 	int ret;
311*9a17125aSPeter Hilber 
312*9a17125aSPeter Hilber 	vio_ptp = devm_kzalloc(parent_dev, sizeof(*vio_ptp), GFP_KERNEL);
313*9a17125aSPeter Hilber 	if (!vio_ptp)
314*9a17125aSPeter Hilber 		return ERR_PTR(-ENOMEM);
315*9a17125aSPeter Hilber 
316*9a17125aSPeter Hilber 	vio_ptp->viortc = viortc;
317*9a17125aSPeter Hilber 	vio_ptp->vio_clk_id = vio_clk_id;
318*9a17125aSPeter Hilber 	vio_ptp->ptp_info = viortc_ptp_info_template;
319*9a17125aSPeter Hilber 	len = strscpy(vio_ptp->ptp_info.name, ptp_clock_name,
320*9a17125aSPeter Hilber 		      sizeof(vio_ptp->ptp_info.name));
321*9a17125aSPeter Hilber 	if (len < 0) {
322*9a17125aSPeter Hilber 		ret = len;
323*9a17125aSPeter Hilber 		goto err_free_dev;
324*9a17125aSPeter Hilber 	}
325*9a17125aSPeter Hilber 
326*9a17125aSPeter Hilber 	ret = viortc_ptp_get_cross_cap(viortc, vio_ptp);
327*9a17125aSPeter Hilber 	if (ret)
328*9a17125aSPeter Hilber 		goto err_free_dev;
329*9a17125aSPeter Hilber 
330*9a17125aSPeter Hilber 	if (!vio_ptp->have_cross)
331*9a17125aSPeter Hilber 		vio_ptp->ptp_info.getcrosststamp = NULL;
332*9a17125aSPeter Hilber 
333*9a17125aSPeter Hilber 	ptp_clock = ptp_clock_register(&vio_ptp->ptp_info, parent_dev);
334*9a17125aSPeter Hilber 	if (IS_ERR(ptp_clock))
335*9a17125aSPeter Hilber 		goto err_on_register;
336*9a17125aSPeter Hilber 
337*9a17125aSPeter Hilber 	vio_ptp->ptp_clock = ptp_clock;
338*9a17125aSPeter Hilber 
339*9a17125aSPeter Hilber 	return vio_ptp;
340*9a17125aSPeter Hilber 
341*9a17125aSPeter Hilber err_on_register:
342*9a17125aSPeter Hilber 	ret = PTR_ERR(ptp_clock);
343*9a17125aSPeter Hilber 
344*9a17125aSPeter Hilber err_free_dev:
345*9a17125aSPeter Hilber 	devm_kfree(parent_dev, vio_ptp);
346*9a17125aSPeter Hilber 	return ERR_PTR(ret);
347*9a17125aSPeter Hilber }
348