xref: /linux/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
11595ecceSKrishnanand Prabhu // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
21595ecceSKrishnanand Prabhu /*
31595ecceSKrishnanand Prabhu  * Copyright (C) 2021 - 2023 Intel Corporation
41595ecceSKrishnanand Prabhu  */
51595ecceSKrishnanand Prabhu 
61595ecceSKrishnanand Prabhu #include "mvm.h"
71595ecceSKrishnanand Prabhu #include "iwl-debug.h"
81595ecceSKrishnanand Prabhu #include <linux/timekeeping.h>
9a2f49f7dSAvraham Stern #include <linux/math64.h>
101595ecceSKrishnanand Prabhu 
111595ecceSKrishnanand Prabhu #define IWL_PTP_GP2_WRAP	0x100000000ULL
121595ecceSKrishnanand Prabhu #define IWL_PTP_WRAP_TIME	(3600 * HZ)
131595ecceSKrishnanand Prabhu 
14a2f49f7dSAvraham Stern /* The scaled_ppm parameter is ppm (parts per million) with a 16-bit fractional
15a2f49f7dSAvraham Stern  * part, which means that a value of 1 in one of those fields actually means
16a2f49f7dSAvraham Stern  * 2^-16 ppm, and 2^16=65536 is 1 ppm.
17a2f49f7dSAvraham Stern  */
18a2f49f7dSAvraham Stern #define SCALE_FACTOR	65536000000ULL
19a2f49f7dSAvraham Stern #define IWL_PTP_WRAP_THRESHOLD_USEC	(5000)
20a2f49f7dSAvraham Stern 
21e8610339SAvraham Stern #define IWL_PTP_GET_CROSS_TS_NUM	5
22e8610339SAvraham Stern 
iwl_mvm_ptp_update_new_read(struct iwl_mvm * mvm,u32 gp2)231595ecceSKrishnanand Prabhu static void iwl_mvm_ptp_update_new_read(struct iwl_mvm *mvm, u32 gp2)
241595ecceSKrishnanand Prabhu {
25a2f49f7dSAvraham Stern 	/* If the difference is above the threshold, assume it's a wraparound.
26a2f49f7dSAvraham Stern 	 * Otherwise assume it's an old read and ignore it.
27a2f49f7dSAvraham Stern 	 */
28a2f49f7dSAvraham Stern 	if (gp2 < mvm->ptp_data.last_gp2 &&
29a2f49f7dSAvraham Stern 	    mvm->ptp_data.last_gp2 - gp2 < IWL_PTP_WRAP_THRESHOLD_USEC) {
30a2f49f7dSAvraham Stern 		IWL_DEBUG_INFO(mvm,
31a2f49f7dSAvraham Stern 			       "PTP: ignore old read (gp2=%u, last_gp2=%u)\n",
32a2f49f7dSAvraham Stern 			       gp2, mvm->ptp_data.last_gp2);
33a2f49f7dSAvraham Stern 		return;
34a2f49f7dSAvraham Stern 	}
35a2f49f7dSAvraham Stern 
361595ecceSKrishnanand Prabhu 	if (gp2 < mvm->ptp_data.last_gp2) {
371595ecceSKrishnanand Prabhu 		mvm->ptp_data.wrap_counter++;
381595ecceSKrishnanand Prabhu 		IWL_DEBUG_INFO(mvm,
391595ecceSKrishnanand Prabhu 			       "PTP: wraparound detected (new counter=%u)\n",
401595ecceSKrishnanand Prabhu 			       mvm->ptp_data.wrap_counter);
411595ecceSKrishnanand Prabhu 	}
421595ecceSKrishnanand Prabhu 
431595ecceSKrishnanand Prabhu 	mvm->ptp_data.last_gp2 = gp2;
441595ecceSKrishnanand Prabhu 	schedule_delayed_work(&mvm->ptp_data.dwork, IWL_PTP_WRAP_TIME);
451595ecceSKrishnanand Prabhu }
461595ecceSKrishnanand Prabhu 
iwl_mvm_ptp_get_adj_time(struct iwl_mvm * mvm,u64 base_time_ns)47a2f49f7dSAvraham Stern u64 iwl_mvm_ptp_get_adj_time(struct iwl_mvm *mvm, u64 base_time_ns)
48a2f49f7dSAvraham Stern {
49a2f49f7dSAvraham Stern 	struct ptp_data *data = &mvm->ptp_data;
50a2f49f7dSAvraham Stern 	u64 last_gp2_ns = mvm->ptp_data.scale_update_gp2 * NSEC_PER_USEC;
51a2f49f7dSAvraham Stern 	u64 res;
52a2f49f7dSAvraham Stern 	u64 diff;
53a2f49f7dSAvraham Stern 
54a2f49f7dSAvraham Stern 	iwl_mvm_ptp_update_new_read(mvm,
55a2f49f7dSAvraham Stern 				    div64_u64(base_time_ns, NSEC_PER_USEC));
56a2f49f7dSAvraham Stern 
57a2f49f7dSAvraham Stern 	IWL_DEBUG_INFO(mvm, "base_time_ns=%llu, wrap_counter=%u\n",
58a2f49f7dSAvraham Stern 		       (unsigned long long)base_time_ns, data->wrap_counter);
59a2f49f7dSAvraham Stern 
60a2f49f7dSAvraham Stern 	base_time_ns = base_time_ns +
61a2f49f7dSAvraham Stern 		(data->wrap_counter * IWL_PTP_GP2_WRAP * NSEC_PER_USEC);
62a2f49f7dSAvraham Stern 
63a2f49f7dSAvraham Stern 	/* It is possible that a GP2 timestamp was received from fw before the
64a2f49f7dSAvraham Stern 	 * last scale update. Since we don't know how to scale - ignore it.
65a2f49f7dSAvraham Stern 	 */
66a2f49f7dSAvraham Stern 	if (base_time_ns < last_gp2_ns) {
67a2f49f7dSAvraham Stern 		IWL_DEBUG_INFO(mvm, "Time before scale update - ignore\n");
68a2f49f7dSAvraham Stern 		return 0;
69a2f49f7dSAvraham Stern 	}
70a2f49f7dSAvraham Stern 
71a2f49f7dSAvraham Stern 	diff = base_time_ns - last_gp2_ns;
72a2f49f7dSAvraham Stern 	IWL_DEBUG_INFO(mvm, "diff ns=%llu\n", (unsigned long long)diff);
73a2f49f7dSAvraham Stern 
74a2f49f7dSAvraham Stern 	diff = mul_u64_u64_div_u64(diff, data->scaled_freq,
75a2f49f7dSAvraham Stern 				   SCALE_FACTOR);
76a2f49f7dSAvraham Stern 	IWL_DEBUG_INFO(mvm, "scaled diff ns=%llu\n", (unsigned long long)diff);
77a2f49f7dSAvraham Stern 
78a2f49f7dSAvraham Stern 	res = data->scale_update_adj_time_ns + data->delta + diff;
79a2f49f7dSAvraham Stern 
80a2f49f7dSAvraham Stern 	IWL_DEBUG_INFO(mvm, "base=%llu delta=%lld adj=%llu\n",
81a2f49f7dSAvraham Stern 		       (unsigned long long)base_time_ns, (long long)data->delta,
82a2f49f7dSAvraham Stern 		       (unsigned long long)res);
83a2f49f7dSAvraham Stern 	return res;
84a2f49f7dSAvraham Stern }
85a2f49f7dSAvraham Stern 
861595ecceSKrishnanand Prabhu static int
iwl_mvm_get_crosstimestamp_fw(struct iwl_mvm * mvm,u32 * gp2,u64 * sys_time)8721fb8da6SAvraham Stern iwl_mvm_get_crosstimestamp_fw(struct iwl_mvm *mvm, u32 *gp2, u64 *sys_time)
8821fb8da6SAvraham Stern {
8921fb8da6SAvraham Stern 	struct iwl_synced_time_cmd synced_time_cmd = {
9021fb8da6SAvraham Stern 		.operation = cpu_to_le32(IWL_SYNCED_TIME_OPERATION_READ_BOTH)
9121fb8da6SAvraham Stern 	};
9221fb8da6SAvraham Stern 	struct iwl_host_cmd cmd = {
9321fb8da6SAvraham Stern 		.id = WIDE_ID(DATA_PATH_GROUP, WNM_PLATFORM_PTM_REQUEST_CMD),
9421fb8da6SAvraham Stern 		.flags = CMD_WANT_SKB,
9521fb8da6SAvraham Stern 		.data[0] = &synced_time_cmd,
9621fb8da6SAvraham Stern 		.len[0] = sizeof(synced_time_cmd),
9721fb8da6SAvraham Stern 	};
9821fb8da6SAvraham Stern 	struct iwl_synced_time_rsp *resp;
9921fb8da6SAvraham Stern 	struct iwl_rx_packet *pkt;
10021fb8da6SAvraham Stern 	int ret;
10121fb8da6SAvraham Stern 	u64 gp2_10ns;
10221fb8da6SAvraham Stern 
10321fb8da6SAvraham Stern 	ret = iwl_mvm_send_cmd(mvm, &cmd);
10421fb8da6SAvraham Stern 	if (ret)
10521fb8da6SAvraham Stern 		return ret;
10621fb8da6SAvraham Stern 
10721fb8da6SAvraham Stern 	pkt = cmd.resp_pkt;
10821fb8da6SAvraham Stern 
10921fb8da6SAvraham Stern 	if (iwl_rx_packet_payload_len(pkt) != sizeof(*resp)) {
11021fb8da6SAvraham Stern 		IWL_ERR(mvm, "PTP: Invalid command response\n");
11121fb8da6SAvraham Stern 		iwl_free_resp(&cmd);
11221fb8da6SAvraham Stern 		return -EIO;
11321fb8da6SAvraham Stern 	}
11421fb8da6SAvraham Stern 
11521fb8da6SAvraham Stern 	resp = (void *)pkt->data;
11621fb8da6SAvraham Stern 
11721fb8da6SAvraham Stern 	gp2_10ns = (u64)le32_to_cpu(resp->gp2_timestamp_hi) << 32 |
11821fb8da6SAvraham Stern 		le32_to_cpu(resp->gp2_timestamp_lo);
119*6cf882d9SNathan Chancellor 	*gp2 = div_u64(gp2_10ns, 100);
12021fb8da6SAvraham Stern 
12121fb8da6SAvraham Stern 	*sys_time = (u64)le32_to_cpu(resp->platform_timestamp_hi) << 32 |
12221fb8da6SAvraham Stern 		le32_to_cpu(resp->platform_timestamp_lo);
12321fb8da6SAvraham Stern 
12421fb8da6SAvraham Stern 	return ret;
12521fb8da6SAvraham Stern }
12621fb8da6SAvraham Stern 
iwl_mvm_phc_get_crosstimestamp_loop(struct iwl_mvm * mvm,ktime_t * sys_time,u32 * gp2)127e8610339SAvraham Stern static void iwl_mvm_phc_get_crosstimestamp_loop(struct iwl_mvm *mvm,
128e8610339SAvraham Stern 						ktime_t *sys_time, u32 *gp2)
129e8610339SAvraham Stern {
130e8610339SAvraham Stern 	u64 diff = 0, new_diff;
131e8610339SAvraham Stern 	u64 tmp_sys_time;
132e8610339SAvraham Stern 	u32 tmp_gp2;
133e8610339SAvraham Stern 	int i;
134e8610339SAvraham Stern 
135e8610339SAvraham Stern 	for (i = 0; i < IWL_PTP_GET_CROSS_TS_NUM; i++) {
136e8610339SAvraham Stern 		iwl_mvm_get_sync_time(mvm, CLOCK_REALTIME, &tmp_gp2, NULL,
137e8610339SAvraham Stern 				      &tmp_sys_time);
138e8610339SAvraham Stern 		new_diff = tmp_sys_time - ((u64)tmp_gp2 * NSEC_PER_USEC);
139e8610339SAvraham Stern 		if (!diff || new_diff < diff) {
140e8610339SAvraham Stern 			*sys_time = tmp_sys_time;
141e8610339SAvraham Stern 			*gp2 = tmp_gp2;
142e8610339SAvraham Stern 			diff = new_diff;
143e8610339SAvraham Stern 			IWL_DEBUG_INFO(mvm, "PTP: new times: gp2=%u sys=%lld\n",
144e8610339SAvraham Stern 				       *gp2, *sys_time);
145e8610339SAvraham Stern 		}
146e8610339SAvraham Stern 	}
147e8610339SAvraham Stern }
148e8610339SAvraham Stern 
14921fb8da6SAvraham Stern static int
iwl_mvm_phc_get_crosstimestamp(struct ptp_clock_info * ptp,struct system_device_crosststamp * xtstamp)1501595ecceSKrishnanand Prabhu iwl_mvm_phc_get_crosstimestamp(struct ptp_clock_info *ptp,
1511595ecceSKrishnanand Prabhu 			       struct system_device_crosststamp *xtstamp)
1521595ecceSKrishnanand Prabhu {
1531595ecceSKrishnanand Prabhu 	struct iwl_mvm *mvm = container_of(ptp, struct iwl_mvm,
1541595ecceSKrishnanand Prabhu 					   ptp_data.ptp_clock_info);
15521fb8da6SAvraham Stern 	int ret = 0;
1561595ecceSKrishnanand Prabhu 	/* Raw value read from GP2 register in usec */
1571595ecceSKrishnanand Prabhu 	u32 gp2;
1581595ecceSKrishnanand Prabhu 	/* GP2 value in ns*/
1591595ecceSKrishnanand Prabhu 	s64 gp2_ns;
1601595ecceSKrishnanand Prabhu 	/* System (wall) time */
1611595ecceSKrishnanand Prabhu 	ktime_t sys_time;
1621595ecceSKrishnanand Prabhu 
1631595ecceSKrishnanand Prabhu 	memset(xtstamp, 0, sizeof(struct system_device_crosststamp));
1641595ecceSKrishnanand Prabhu 
1651595ecceSKrishnanand Prabhu 	if (!mvm->ptp_data.ptp_clock) {
1661595ecceSKrishnanand Prabhu 		IWL_ERR(mvm, "No PHC clock registered\n");
1671595ecceSKrishnanand Prabhu 		return -ENODEV;
1681595ecceSKrishnanand Prabhu 	}
1691595ecceSKrishnanand Prabhu 
17021fb8da6SAvraham Stern 	mutex_lock(&mvm->mutex);
17121fb8da6SAvraham Stern 	if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SYNCED_TIME)) {
17221fb8da6SAvraham Stern 		ret = iwl_mvm_get_crosstimestamp_fw(mvm, &gp2, &sys_time);
17321fb8da6SAvraham Stern 
17421fb8da6SAvraham Stern 		if (ret)
17521fb8da6SAvraham Stern 			goto out;
17621fb8da6SAvraham Stern 	} else {
177e8610339SAvraham Stern 		iwl_mvm_phc_get_crosstimestamp_loop(mvm, &sys_time, &gp2);
17821fb8da6SAvraham Stern 	}
1791595ecceSKrishnanand Prabhu 
180a2f49f7dSAvraham Stern 	gp2_ns = iwl_mvm_ptp_get_adj_time(mvm, (u64)gp2 * NSEC_PER_USEC);
1811595ecceSKrishnanand Prabhu 
1821595ecceSKrishnanand Prabhu 	IWL_INFO(mvm, "Got Sync Time: GP2:%u, last_GP2: %u, GP2_ns: %lld, sys_time: %lld\n",
1831595ecceSKrishnanand Prabhu 		 gp2, mvm->ptp_data.last_gp2, gp2_ns, (s64)sys_time);
1841595ecceSKrishnanand Prabhu 
1851595ecceSKrishnanand Prabhu 	/* System monotonic raw time is not used */
1861595ecceSKrishnanand Prabhu 	xtstamp->device = (ktime_t)gp2_ns;
1871595ecceSKrishnanand Prabhu 	xtstamp->sys_realtime = sys_time;
1881595ecceSKrishnanand Prabhu 
18921fb8da6SAvraham Stern out:
19021fb8da6SAvraham Stern 	mutex_unlock(&mvm->mutex);
19121fb8da6SAvraham Stern 	return ret;
1921595ecceSKrishnanand Prabhu }
1931595ecceSKrishnanand Prabhu 
iwl_mvm_ptp_work(struct work_struct * wk)1941595ecceSKrishnanand Prabhu static void iwl_mvm_ptp_work(struct work_struct *wk)
1951595ecceSKrishnanand Prabhu {
1961595ecceSKrishnanand Prabhu 	struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm,
1971595ecceSKrishnanand Prabhu 					   ptp_data.dwork.work);
1981595ecceSKrishnanand Prabhu 	u32 gp2;
1991595ecceSKrishnanand Prabhu 
2001595ecceSKrishnanand Prabhu 	mutex_lock(&mvm->mutex);
2011595ecceSKrishnanand Prabhu 	gp2 = iwl_mvm_get_systime(mvm);
2021595ecceSKrishnanand Prabhu 	iwl_mvm_ptp_update_new_read(mvm, gp2);
2031595ecceSKrishnanand Prabhu 	mutex_unlock(&mvm->mutex);
2041595ecceSKrishnanand Prabhu }
2051595ecceSKrishnanand Prabhu 
iwl_mvm_ptp_gettime(struct ptp_clock_info * ptp,struct timespec64 * ts)206a2f49f7dSAvraham Stern static int iwl_mvm_ptp_gettime(struct ptp_clock_info *ptp,
207a2f49f7dSAvraham Stern 			       struct timespec64 *ts)
208a2f49f7dSAvraham Stern {
209a2f49f7dSAvraham Stern 	struct iwl_mvm *mvm = container_of(ptp, struct iwl_mvm,
210a2f49f7dSAvraham Stern 					   ptp_data.ptp_clock_info);
211a2f49f7dSAvraham Stern 	u64 gp2;
212a2f49f7dSAvraham Stern 	u64 ns;
213a2f49f7dSAvraham Stern 
214a2f49f7dSAvraham Stern 	mutex_lock(&mvm->mutex);
215a2f49f7dSAvraham Stern 	gp2 = iwl_mvm_get_systime(mvm);
216a2f49f7dSAvraham Stern 	ns = iwl_mvm_ptp_get_adj_time(mvm, gp2 * NSEC_PER_USEC);
217a2f49f7dSAvraham Stern 	mutex_unlock(&mvm->mutex);
218a2f49f7dSAvraham Stern 
219a2f49f7dSAvraham Stern 	*ts = ns_to_timespec64(ns);
220a2f49f7dSAvraham Stern 	return 0;
221a2f49f7dSAvraham Stern }
222a2f49f7dSAvraham Stern 
iwl_mvm_ptp_adjtime(struct ptp_clock_info * ptp,s64 delta)223a2f49f7dSAvraham Stern static int iwl_mvm_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
224a2f49f7dSAvraham Stern {
225a2f49f7dSAvraham Stern 	struct iwl_mvm *mvm = container_of(ptp, struct iwl_mvm,
226a2f49f7dSAvraham Stern 					   ptp_data.ptp_clock_info);
227a2f49f7dSAvraham Stern 	struct ptp_data *data = container_of(ptp, struct ptp_data,
228a2f49f7dSAvraham Stern 					     ptp_clock_info);
229a2f49f7dSAvraham Stern 
230a2f49f7dSAvraham Stern 	mutex_lock(&mvm->mutex);
231a2f49f7dSAvraham Stern 	data->delta += delta;
232a2f49f7dSAvraham Stern 	IWL_DEBUG_INFO(mvm, "delta=%lld, new delta=%lld\n", (long long)delta,
233a2f49f7dSAvraham Stern 		       (long long)data->delta);
234a2f49f7dSAvraham Stern 	mutex_unlock(&mvm->mutex);
235a2f49f7dSAvraham Stern 	return 0;
236a2f49f7dSAvraham Stern }
237a2f49f7dSAvraham Stern 
iwl_mvm_ptp_adjfine(struct ptp_clock_info * ptp,long scaled_ppm)238a2f49f7dSAvraham Stern static int iwl_mvm_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
239a2f49f7dSAvraham Stern {
240a2f49f7dSAvraham Stern 	struct iwl_mvm *mvm = container_of(ptp, struct iwl_mvm,
241a2f49f7dSAvraham Stern 					   ptp_data.ptp_clock_info);
242a2f49f7dSAvraham Stern 	struct ptp_data *data = &mvm->ptp_data;
243a2f49f7dSAvraham Stern 	u32 gp2;
244a2f49f7dSAvraham Stern 
245a2f49f7dSAvraham Stern 	mutex_lock(&mvm->mutex);
246a2f49f7dSAvraham Stern 
247a2f49f7dSAvraham Stern 	/* Must call _iwl_mvm_ptp_get_adj_time() before updating
248a2f49f7dSAvraham Stern 	 * data->scale_update_gp2 or data->scaled_freq since
249a2f49f7dSAvraham Stern 	 * scale_update_adj_time_ns should reflect the previous scaled_freq.
250a2f49f7dSAvraham Stern 	 */
251a2f49f7dSAvraham Stern 	gp2 = iwl_mvm_get_systime(mvm);
252a2f49f7dSAvraham Stern 	data->scale_update_adj_time_ns =
253a2f49f7dSAvraham Stern 		iwl_mvm_ptp_get_adj_time(mvm, gp2 * NSEC_PER_USEC);
254a2f49f7dSAvraham Stern 	data->scale_update_gp2 = gp2;
255a2f49f7dSAvraham Stern 	data->wrap_counter = 0;
256a2f49f7dSAvraham Stern 	data->delta = 0;
257a2f49f7dSAvraham Stern 
258a2f49f7dSAvraham Stern 	data->scaled_freq = SCALE_FACTOR + scaled_ppm;
259a2f49f7dSAvraham Stern 	IWL_DEBUG_INFO(mvm, "adjfine: scaled_ppm=%ld new=%llu\n",
260a2f49f7dSAvraham Stern 		       scaled_ppm, (unsigned long long)data->scaled_freq);
261a2f49f7dSAvraham Stern 
262a2f49f7dSAvraham Stern 	mutex_unlock(&mvm->mutex);
263a2f49f7dSAvraham Stern 	return 0;
264a2f49f7dSAvraham Stern }
265a2f49f7dSAvraham Stern 
2661595ecceSKrishnanand Prabhu /* iwl_mvm_ptp_init - initialize PTP for devices which support it.
2671595ecceSKrishnanand Prabhu  * @mvm: internal mvm structure, see &struct iwl_mvm.
2681595ecceSKrishnanand Prabhu  *
2691595ecceSKrishnanand Prabhu  * Performs the required steps for enabling PTP support.
2701595ecceSKrishnanand Prabhu  */
iwl_mvm_ptp_init(struct iwl_mvm * mvm)2711595ecceSKrishnanand Prabhu void iwl_mvm_ptp_init(struct iwl_mvm *mvm)
2721595ecceSKrishnanand Prabhu {
2731595ecceSKrishnanand Prabhu 	/* Warn if the interface already has a ptp_clock defined */
2741595ecceSKrishnanand Prabhu 	if (WARN_ON(mvm->ptp_data.ptp_clock))
2751595ecceSKrishnanand Prabhu 		return;
2761595ecceSKrishnanand Prabhu 
2771595ecceSKrishnanand Prabhu 	mvm->ptp_data.ptp_clock_info.owner = THIS_MODULE;
2781595ecceSKrishnanand Prabhu 	mvm->ptp_data.ptp_clock_info.max_adj = 0x7fffffff;
2791595ecceSKrishnanand Prabhu 	mvm->ptp_data.ptp_clock_info.getcrosststamp =
2801595ecceSKrishnanand Prabhu 					iwl_mvm_phc_get_crosstimestamp;
281a2f49f7dSAvraham Stern 	mvm->ptp_data.ptp_clock_info.adjfine = iwl_mvm_ptp_adjfine;
282a2f49f7dSAvraham Stern 	mvm->ptp_data.ptp_clock_info.adjtime = iwl_mvm_ptp_adjtime;
283a2f49f7dSAvraham Stern 	mvm->ptp_data.ptp_clock_info.gettime64 = iwl_mvm_ptp_gettime;
284a2f49f7dSAvraham Stern 	mvm->ptp_data.scaled_freq = SCALE_FACTOR;
2851595ecceSKrishnanand Prabhu 
2861595ecceSKrishnanand Prabhu 	/* Give a short 'friendly name' to identify the PHC clock */
2871595ecceSKrishnanand Prabhu 	snprintf(mvm->ptp_data.ptp_clock_info.name,
2881595ecceSKrishnanand Prabhu 		 sizeof(mvm->ptp_data.ptp_clock_info.name),
2891595ecceSKrishnanand Prabhu 		 "%s", "iwlwifi-PTP");
2901595ecceSKrishnanand Prabhu 
2911595ecceSKrishnanand Prabhu 	INIT_DELAYED_WORK(&mvm->ptp_data.dwork, iwl_mvm_ptp_work);
2921595ecceSKrishnanand Prabhu 
2931595ecceSKrishnanand Prabhu 	mvm->ptp_data.ptp_clock =
2941595ecceSKrishnanand Prabhu 		ptp_clock_register(&mvm->ptp_data.ptp_clock_info, mvm->dev);
2951595ecceSKrishnanand Prabhu 
2961595ecceSKrishnanand Prabhu 	if (IS_ERR(mvm->ptp_data.ptp_clock)) {
2971595ecceSKrishnanand Prabhu 		IWL_ERR(mvm, "Failed to register PHC clock (%ld)\n",
2981595ecceSKrishnanand Prabhu 			PTR_ERR(mvm->ptp_data.ptp_clock));
2991595ecceSKrishnanand Prabhu 		mvm->ptp_data.ptp_clock = NULL;
3001595ecceSKrishnanand Prabhu 	} else if (mvm->ptp_data.ptp_clock) {
3011595ecceSKrishnanand Prabhu 		IWL_INFO(mvm, "Registered PHC clock: %s, with index: %d\n",
3021595ecceSKrishnanand Prabhu 			 mvm->ptp_data.ptp_clock_info.name,
3031595ecceSKrishnanand Prabhu 			 ptp_clock_index(mvm->ptp_data.ptp_clock));
3041595ecceSKrishnanand Prabhu 	}
3051595ecceSKrishnanand Prabhu }
3061595ecceSKrishnanand Prabhu 
3071595ecceSKrishnanand Prabhu /* iwl_mvm_ptp_remove - disable PTP device.
3081595ecceSKrishnanand Prabhu  * @mvm: internal mvm structure, see &struct iwl_mvm.
3091595ecceSKrishnanand Prabhu  *
3101595ecceSKrishnanand Prabhu  * Disable PTP support.
3111595ecceSKrishnanand Prabhu  */
iwl_mvm_ptp_remove(struct iwl_mvm * mvm)3121595ecceSKrishnanand Prabhu void iwl_mvm_ptp_remove(struct iwl_mvm *mvm)
3131595ecceSKrishnanand Prabhu {
3141595ecceSKrishnanand Prabhu 	if (mvm->ptp_data.ptp_clock) {
3151595ecceSKrishnanand Prabhu 		IWL_INFO(mvm, "Unregistering PHC clock: %s, with index: %d\n",
3161595ecceSKrishnanand Prabhu 			 mvm->ptp_data.ptp_clock_info.name,
3171595ecceSKrishnanand Prabhu 			 ptp_clock_index(mvm->ptp_data.ptp_clock));
3181595ecceSKrishnanand Prabhu 
3191595ecceSKrishnanand Prabhu 		ptp_clock_unregister(mvm->ptp_data.ptp_clock);
3201595ecceSKrishnanand Prabhu 		mvm->ptp_data.ptp_clock = NULL;
3211595ecceSKrishnanand Prabhu 		memset(&mvm->ptp_data.ptp_clock_info, 0,
3221595ecceSKrishnanand Prabhu 		       sizeof(mvm->ptp_data.ptp_clock_info));
3231595ecceSKrishnanand Prabhu 		mvm->ptp_data.last_gp2 = 0;
3241595ecceSKrishnanand Prabhu 		cancel_delayed_work_sync(&mvm->ptp_data.dwork);
3251595ecceSKrishnanand Prabhu 	}
3261595ecceSKrishnanand Prabhu }
327