xref: /openbmc/linux/drivers/ptp/ptp_idt82p33.c (revision ad3cc776)
157a10d8cSMin Li // SPDX-License-Identifier: GPL-2.0
257a10d8cSMin Li //
357a10d8cSMin Li // Copyright (C) 2018 Integrated Device Technology, Inc
457a10d8cSMin Li //
557a10d8cSMin Li 
657a10d8cSMin Li #define pr_fmt(fmt) "IDT_82p33xxx: " fmt
757a10d8cSMin Li 
857a10d8cSMin Li #include <linux/firmware.h>
9013a3e7cSMin Li #include <linux/platform_device.h>
1057a10d8cSMin Li #include <linux/module.h>
1157a10d8cSMin Li #include <linux/ptp_clock_kernel.h>
1257a10d8cSMin Li #include <linux/delay.h>
13013a3e7cSMin Li #include <linux/jiffies.h>
1457a10d8cSMin Li #include <linux/kernel.h>
1557a10d8cSMin Li #include <linux/timekeeping.h>
1657a10d8cSMin Li #include <linux/bitops.h>
17013a3e7cSMin Li #include <linux/of.h>
18013a3e7cSMin Li #include <linux/mfd/rsmu.h>
19013a3e7cSMin Li #include <linux/mfd/idt82p33_reg.h>
2057a10d8cSMin Li 
2157a10d8cSMin Li #include "ptp_private.h"
2257a10d8cSMin Li #include "ptp_idt82p33.h"
2357a10d8cSMin Li 
2457a10d8cSMin Li MODULE_DESCRIPTION("Driver for IDT 82p33xxx clock devices");
2557a10d8cSMin Li MODULE_AUTHOR("IDT support-1588 <IDT-support-1588@lm.renesas.com>");
2657a10d8cSMin Li MODULE_VERSION("1.0");
2757a10d8cSMin Li MODULE_LICENSE("GPL");
28e014ae39SMin Li MODULE_FIRMWARE(FW_FILENAME);
2957a10d8cSMin Li 
30*ad3cc776SMin Li #define EXTTS_PERIOD_MS (95)
31*ad3cc776SMin Li 
3257a10d8cSMin Li /* Module Parameters */
33d30e1c3dSYueHaibing static u32 phase_snap_threshold = SNAP_THRESHOLD_NS;
3457a10d8cSMin Li module_param(phase_snap_threshold, uint, 0);
3557a10d8cSMin Li MODULE_PARM_DESC(phase_snap_threshold,
36013a3e7cSMin Li "threshold (10000ns by default) below which adjtime would use double dco");
37013a3e7cSMin Li 
38013a3e7cSMin Li static char *firmware;
39013a3e7cSMin Li module_param(firmware, charp, 0);
40013a3e7cSMin Li 
41*ad3cc776SMin Li static struct ptp_pin_desc pin_config[MAX_PHC_PLL][MAX_TRIG_CLK];
42*ad3cc776SMin Li 
43013a3e7cSMin Li static inline int idt82p33_read(struct idt82p33 *idt82p33, u16 regaddr,
44013a3e7cSMin Li 				u8 *buf, u16 count)
45013a3e7cSMin Li {
46013a3e7cSMin Li 	return regmap_bulk_read(idt82p33->regmap, regaddr, buf, count);
47013a3e7cSMin Li }
48013a3e7cSMin Li 
49013a3e7cSMin Li static inline int idt82p33_write(struct idt82p33 *idt82p33, u16 regaddr,
50013a3e7cSMin Li 				 u8 *buf, u16 count)
51013a3e7cSMin Li {
52013a3e7cSMin Li 	return regmap_bulk_write(idt82p33->regmap, regaddr, buf, count);
53013a3e7cSMin Li }
5457a10d8cSMin Li 
5557a10d8cSMin Li static void idt82p33_byte_array_to_timespec(struct timespec64 *ts,
5657a10d8cSMin Li 					    u8 buf[TOD_BYTE_COUNT])
5757a10d8cSMin Li {
5857a10d8cSMin Li 	time64_t sec;
5957a10d8cSMin Li 	s32 nsec;
6057a10d8cSMin Li 	u8 i;
6157a10d8cSMin Li 
6257a10d8cSMin Li 	nsec = buf[3];
6357a10d8cSMin Li 	for (i = 0; i < 3; i++) {
6457a10d8cSMin Li 		nsec <<= 8;
6557a10d8cSMin Li 		nsec |= buf[2 - i];
6657a10d8cSMin Li 	}
6757a10d8cSMin Li 
6857a10d8cSMin Li 	sec = buf[9];
6957a10d8cSMin Li 	for (i = 0; i < 5; i++) {
7057a10d8cSMin Li 		sec <<= 8;
7157a10d8cSMin Li 		sec |= buf[8 - i];
7257a10d8cSMin Li 	}
7357a10d8cSMin Li 
7457a10d8cSMin Li 	ts->tv_sec = sec;
7557a10d8cSMin Li 	ts->tv_nsec = nsec;
7657a10d8cSMin Li }
7757a10d8cSMin Li 
7857a10d8cSMin Li static void idt82p33_timespec_to_byte_array(struct timespec64 const *ts,
7957a10d8cSMin Li 					    u8 buf[TOD_BYTE_COUNT])
8057a10d8cSMin Li {
8157a10d8cSMin Li 	time64_t sec;
8257a10d8cSMin Li 	s32 nsec;
8357a10d8cSMin Li 	u8 i;
8457a10d8cSMin Li 
8557a10d8cSMin Li 	nsec = ts->tv_nsec;
8657a10d8cSMin Li 	sec = ts->tv_sec;
8757a10d8cSMin Li 
8857a10d8cSMin Li 	for (i = 0; i < 4; i++) {
8957a10d8cSMin Li 		buf[i] = nsec & 0xff;
9057a10d8cSMin Li 		nsec >>= 8;
9157a10d8cSMin Li 	}
9257a10d8cSMin Li 
9357a10d8cSMin Li 	for (i = 4; i < TOD_BYTE_COUNT; i++) {
9457a10d8cSMin Li 		buf[i] = sec & 0xff;
9557a10d8cSMin Li 		sec >>= 8;
9657a10d8cSMin Li 	}
9757a10d8cSMin Li }
9857a10d8cSMin Li 
9957a10d8cSMin Li static int idt82p33_dpll_set_mode(struct idt82p33_channel *channel,
10057a10d8cSMin Li 				  enum pll_mode mode)
10157a10d8cSMin Li {
10257a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
10357a10d8cSMin Li 	u8 dpll_mode;
10457a10d8cSMin Li 	int err;
10557a10d8cSMin Li 
10657a10d8cSMin Li 	if (channel->pll_mode == mode)
10757a10d8cSMin Li 		return 0;
10857a10d8cSMin Li 
10957a10d8cSMin Li 	err = idt82p33_read(idt82p33, channel->dpll_mode_cnfg,
11057a10d8cSMin Li 			    &dpll_mode, sizeof(dpll_mode));
11157a10d8cSMin Li 	if (err)
11257a10d8cSMin Li 		return err;
11357a10d8cSMin Li 
11457a10d8cSMin Li 	dpll_mode &= ~(PLL_MODE_MASK << PLL_MODE_SHIFT);
11557a10d8cSMin Li 
11657a10d8cSMin Li 	dpll_mode |= (mode << PLL_MODE_SHIFT);
11757a10d8cSMin Li 
11857a10d8cSMin Li 	err = idt82p33_write(idt82p33, channel->dpll_mode_cnfg,
11957a10d8cSMin Li 			     &dpll_mode, sizeof(dpll_mode));
12057a10d8cSMin Li 	if (err)
12157a10d8cSMin Li 		return err;
12257a10d8cSMin Li 
123013a3e7cSMin Li 	channel->pll_mode = mode;
12457a10d8cSMin Li 
12557a10d8cSMin Li 	return 0;
12657a10d8cSMin Li }
12757a10d8cSMin Li 
128*ad3cc776SMin Li static int idt82p33_set_tod_trigger(struct idt82p33_channel *channel,
129*ad3cc776SMin Li 				    u8 trigger, bool write)
130*ad3cc776SMin Li {
131*ad3cc776SMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
132*ad3cc776SMin Li 	int err;
133*ad3cc776SMin Li 	u8 cfg;
134*ad3cc776SMin Li 
135*ad3cc776SMin Li 	if (trigger > WR_TRIG_SEL_MAX)
136*ad3cc776SMin Li 		return -EINVAL;
137*ad3cc776SMin Li 
138*ad3cc776SMin Li 	err = idt82p33_read(idt82p33, channel->dpll_tod_trigger,
139*ad3cc776SMin Li 			    &cfg, sizeof(cfg));
140*ad3cc776SMin Li 
141*ad3cc776SMin Li 	if (err)
142*ad3cc776SMin Li 		return err;
143*ad3cc776SMin Li 
144*ad3cc776SMin Li 	if (write == true)
145*ad3cc776SMin Li 		trigger = (trigger << WRITE_TRIGGER_SHIFT) |
146*ad3cc776SMin Li 			  (cfg & READ_TRIGGER_MASK);
147*ad3cc776SMin Li 	else
148*ad3cc776SMin Li 		trigger = (trigger << READ_TRIGGER_SHIFT) |
149*ad3cc776SMin Li 			  (cfg & WRITE_TRIGGER_MASK);
150*ad3cc776SMin Li 
151*ad3cc776SMin Li 	return idt82p33_write(idt82p33, channel->dpll_tod_trigger,
152*ad3cc776SMin Li 			      &trigger, sizeof(trigger));
153*ad3cc776SMin Li }
154*ad3cc776SMin Li 
155*ad3cc776SMin Li static int idt82p33_get_extts(struct idt82p33_channel *channel,
15657a10d8cSMin Li 			      struct timespec64 *ts)
15757a10d8cSMin Li {
15857a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
15957a10d8cSMin Li 	u8 buf[TOD_BYTE_COUNT];
16057a10d8cSMin Li 	int err;
16157a10d8cSMin Li 
162*ad3cc776SMin Li 	err = idt82p33_read(idt82p33, channel->dpll_tod_sts, buf, sizeof(buf));
16357a10d8cSMin Li 
16457a10d8cSMin Li 	if (err)
16557a10d8cSMin Li 		return err;
16657a10d8cSMin Li 
167*ad3cc776SMin Li 	/* Since trigger is not self clearing itself, we have to poll tod_sts */
168*ad3cc776SMin Li 	if (memcmp(buf, channel->extts_tod_sts, TOD_BYTE_COUNT) == 0)
169*ad3cc776SMin Li 		return -EAGAIN;
170*ad3cc776SMin Li 
171*ad3cc776SMin Li 	memcpy(channel->extts_tod_sts, buf, TOD_BYTE_COUNT);
172*ad3cc776SMin Li 
173*ad3cc776SMin Li 	idt82p33_byte_array_to_timespec(ts, buf);
174*ad3cc776SMin Li 
175*ad3cc776SMin Li 	if (channel->discard_next_extts) {
176*ad3cc776SMin Li 		channel->discard_next_extts = false;
177*ad3cc776SMin Li 		return -EAGAIN;
178*ad3cc776SMin Li 	}
179*ad3cc776SMin Li 
180*ad3cc776SMin Li 	return 0;
181*ad3cc776SMin Li }
182*ad3cc776SMin Li 
183*ad3cc776SMin Li static int map_ref_to_tod_trig_sel(int ref, u8 *trigger)
184*ad3cc776SMin Li {
185*ad3cc776SMin Li 	int err = 0;
186*ad3cc776SMin Li 
187*ad3cc776SMin Li 	switch (ref) {
188*ad3cc776SMin Li 	case 0:
189*ad3cc776SMin Li 		*trigger = HW_TOD_TRIG_SEL_IN12;
190*ad3cc776SMin Li 		break;
191*ad3cc776SMin Li 	case 1:
192*ad3cc776SMin Li 		*trigger = HW_TOD_TRIG_SEL_IN13;
193*ad3cc776SMin Li 		break;
194*ad3cc776SMin Li 	case 2:
195*ad3cc776SMin Li 		*trigger = HW_TOD_TRIG_SEL_IN14;
196*ad3cc776SMin Li 		break;
197*ad3cc776SMin Li 	default:
198*ad3cc776SMin Li 		err = -EINVAL;
199*ad3cc776SMin Li 	}
200*ad3cc776SMin Li 
201*ad3cc776SMin Li 	return err;
202*ad3cc776SMin Li }
203*ad3cc776SMin Li 
204*ad3cc776SMin Li static bool is_one_shot(u8 mask)
205*ad3cc776SMin Li {
206*ad3cc776SMin Li 	/* Treat single bit PLL masks as continuous trigger */
207*ad3cc776SMin Li 	if ((mask == 1) || (mask == 2))
208*ad3cc776SMin Li 		return false;
209*ad3cc776SMin Li 	else
210*ad3cc776SMin Li 		return true;
211*ad3cc776SMin Li }
212*ad3cc776SMin Li 
213*ad3cc776SMin Li static int arm_tod_read_with_trigger(struct idt82p33_channel *channel, u8 trigger)
214*ad3cc776SMin Li {
215*ad3cc776SMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
216*ad3cc776SMin Li 	u8 buf[TOD_BYTE_COUNT];
217*ad3cc776SMin Li 	int err;
218*ad3cc776SMin Li 
219*ad3cc776SMin Li 	/* Remember the current tod_sts before setting the trigger */
220*ad3cc776SMin Li 	err = idt82p33_read(idt82p33, channel->dpll_tod_sts, buf, sizeof(buf));
221*ad3cc776SMin Li 
222*ad3cc776SMin Li 	if (err)
223*ad3cc776SMin Li 		return err;
224*ad3cc776SMin Li 
225*ad3cc776SMin Li 	memcpy(channel->extts_tod_sts, buf, TOD_BYTE_COUNT);
226*ad3cc776SMin Li 
227*ad3cc776SMin Li 	err = idt82p33_set_tod_trigger(channel, trigger, false);
228*ad3cc776SMin Li 
229*ad3cc776SMin Li 	if (err)
230*ad3cc776SMin Li 		dev_err(idt82p33->dev, "%s: err = %d", __func__, err);
231*ad3cc776SMin Li 
232*ad3cc776SMin Li 	return err;
233*ad3cc776SMin Li }
234*ad3cc776SMin Li 
235*ad3cc776SMin Li static int idt82p33_extts_enable(struct idt82p33_channel *channel,
236*ad3cc776SMin Li 				 struct ptp_clock_request *rq, int on)
237*ad3cc776SMin Li {
238*ad3cc776SMin Li 	u8 index = rq->extts.index;
239*ad3cc776SMin Li 	struct idt82p33 *idt82p33;
240*ad3cc776SMin Li 	u8 mask = 1 << index;
241*ad3cc776SMin Li 	int err = 0;
242*ad3cc776SMin Li 	u8 old_mask;
243*ad3cc776SMin Li 	u8 trigger;
244*ad3cc776SMin Li 	int ref;
245*ad3cc776SMin Li 
246*ad3cc776SMin Li 	idt82p33  = channel->idt82p33;
247*ad3cc776SMin Li 	old_mask = idt82p33->extts_mask;
248*ad3cc776SMin Li 
249*ad3cc776SMin Li 	/* Reject requests with unsupported flags */
250*ad3cc776SMin Li 	if (rq->extts.flags & ~(PTP_ENABLE_FEATURE |
251*ad3cc776SMin Li 				PTP_RISING_EDGE |
252*ad3cc776SMin Li 				PTP_FALLING_EDGE |
253*ad3cc776SMin Li 				PTP_STRICT_FLAGS))
254*ad3cc776SMin Li 		return -EOPNOTSUPP;
255*ad3cc776SMin Li 
256*ad3cc776SMin Li 	/* Reject requests to enable time stamping on falling edge */
257*ad3cc776SMin Li 	if ((rq->extts.flags & PTP_ENABLE_FEATURE) &&
258*ad3cc776SMin Li 	    (rq->extts.flags & PTP_FALLING_EDGE))
259*ad3cc776SMin Li 		return -EOPNOTSUPP;
260*ad3cc776SMin Li 
261*ad3cc776SMin Li 	if (index >= MAX_PHC_PLL)
262*ad3cc776SMin Li 		return -EINVAL;
263*ad3cc776SMin Li 
264*ad3cc776SMin Li 	if (on) {
265*ad3cc776SMin Li 		/* Return if it was already enabled */
266*ad3cc776SMin Li 		if (idt82p33->extts_mask & mask)
267*ad3cc776SMin Li 			return 0;
268*ad3cc776SMin Li 
269*ad3cc776SMin Li 		/* Use the pin configured for the channel */
270*ad3cc776SMin Li 		ref = ptp_find_pin(channel->ptp_clock, PTP_PF_EXTTS, channel->plln);
271*ad3cc776SMin Li 
272*ad3cc776SMin Li 		if (ref < 0) {
273*ad3cc776SMin Li 			dev_err(idt82p33->dev, "%s: No valid pin found for Pll%d!\n",
274*ad3cc776SMin Li 				__func__, channel->plln);
275*ad3cc776SMin Li 			return -EBUSY;
276*ad3cc776SMin Li 		}
277*ad3cc776SMin Li 
278*ad3cc776SMin Li 		err = map_ref_to_tod_trig_sel(ref, &trigger);
279*ad3cc776SMin Li 
280*ad3cc776SMin Li 		if (err) {
281*ad3cc776SMin Li 			dev_err(idt82p33->dev,
282*ad3cc776SMin Li 				"%s: Unsupported ref %d!\n", __func__, ref);
283*ad3cc776SMin Li 			return err;
284*ad3cc776SMin Li 		}
285*ad3cc776SMin Li 
286*ad3cc776SMin Li 		err = arm_tod_read_with_trigger(&idt82p33->channel[index], trigger);
287*ad3cc776SMin Li 
288*ad3cc776SMin Li 		if (err == 0) {
289*ad3cc776SMin Li 			idt82p33->extts_mask |= mask;
290*ad3cc776SMin Li 			idt82p33->channel[index].tod_trigger = trigger;
291*ad3cc776SMin Li 			idt82p33->event_channel[index] = channel;
292*ad3cc776SMin Li 			idt82p33->extts_single_shot = is_one_shot(idt82p33->extts_mask);
293*ad3cc776SMin Li 
294*ad3cc776SMin Li 			if (old_mask)
295*ad3cc776SMin Li 				return 0;
296*ad3cc776SMin Li 
297*ad3cc776SMin Li 			schedule_delayed_work(&idt82p33->extts_work,
298*ad3cc776SMin Li 					      msecs_to_jiffies(EXTTS_PERIOD_MS));
299*ad3cc776SMin Li 		}
300*ad3cc776SMin Li 	} else {
301*ad3cc776SMin Li 		idt82p33->extts_mask &= ~mask;
302*ad3cc776SMin Li 		idt82p33->extts_single_shot = is_one_shot(idt82p33->extts_mask);
303*ad3cc776SMin Li 
304*ad3cc776SMin Li 		if (idt82p33->extts_mask == 0)
305*ad3cc776SMin Li 			cancel_delayed_work(&idt82p33->extts_work);
306*ad3cc776SMin Li 	}
307*ad3cc776SMin Li 
308*ad3cc776SMin Li 	return err;
309*ad3cc776SMin Li }
310*ad3cc776SMin Li 
311*ad3cc776SMin Li static int idt82p33_extts_check_channel(struct idt82p33 *idt82p33, u8 todn)
312*ad3cc776SMin Li {
313*ad3cc776SMin Li 	struct idt82p33_channel *event_channel;
314*ad3cc776SMin Li 	struct ptp_clock_event event;
315*ad3cc776SMin Li 	struct timespec64 ts;
316*ad3cc776SMin Li 	int err;
317*ad3cc776SMin Li 
318*ad3cc776SMin Li 	err = idt82p33_get_extts(&idt82p33->channel[todn], &ts);
319*ad3cc776SMin Li 	if (err == 0) {
320*ad3cc776SMin Li 		event_channel = idt82p33->event_channel[todn];
321*ad3cc776SMin Li 		event.type = PTP_CLOCK_EXTTS;
322*ad3cc776SMin Li 		event.index = todn;
323*ad3cc776SMin Li 		event.timestamp = timespec64_to_ns(&ts);
324*ad3cc776SMin Li 		ptp_clock_event(event_channel->ptp_clock,
325*ad3cc776SMin Li 				&event);
326*ad3cc776SMin Li 	}
327*ad3cc776SMin Li 	return err;
328*ad3cc776SMin Li }
329*ad3cc776SMin Li 
330*ad3cc776SMin Li static u8 idt82p33_extts_enable_mask(struct idt82p33_channel *channel,
331*ad3cc776SMin Li 				     u8 extts_mask, bool enable)
332*ad3cc776SMin Li {
333*ad3cc776SMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
334*ad3cc776SMin Li 	u8 trigger = channel->tod_trigger;
335*ad3cc776SMin Li 	u8 mask;
336*ad3cc776SMin Li 	int err;
337*ad3cc776SMin Li 	int i;
338*ad3cc776SMin Li 
339*ad3cc776SMin Li 	if (extts_mask == 0)
340*ad3cc776SMin Li 		return 0;
341*ad3cc776SMin Li 
342*ad3cc776SMin Li 	if (enable == false)
343*ad3cc776SMin Li 		cancel_delayed_work_sync(&idt82p33->extts_work);
344*ad3cc776SMin Li 
345*ad3cc776SMin Li 	for (i = 0; i < MAX_PHC_PLL; i++) {
346*ad3cc776SMin Li 		mask = 1 << i;
347*ad3cc776SMin Li 
348*ad3cc776SMin Li 		if ((extts_mask & mask) == 0)
349*ad3cc776SMin Li 			continue;
350*ad3cc776SMin Li 
351*ad3cc776SMin Li 		if (enable) {
352*ad3cc776SMin Li 			err = arm_tod_read_with_trigger(&idt82p33->channel[i], trigger);
353*ad3cc776SMin Li 			if (err)
354*ad3cc776SMin Li 				dev_err(idt82p33->dev,
355*ad3cc776SMin Li 					"%s: Arm ToD read trigger failed, err = %d",
356*ad3cc776SMin Li 					__func__, err);
357*ad3cc776SMin Li 		} else {
358*ad3cc776SMin Li 			err = idt82p33_extts_check_channel(idt82p33, i);
359*ad3cc776SMin Li 			if (err == 0 && idt82p33->extts_single_shot)
360*ad3cc776SMin Li 				/* trigger happened so we won't re-enable it */
361*ad3cc776SMin Li 				extts_mask &= ~mask;
362*ad3cc776SMin Li 		}
363*ad3cc776SMin Li 	}
364*ad3cc776SMin Li 
365*ad3cc776SMin Li 	if (enable)
366*ad3cc776SMin Li 		schedule_delayed_work(&idt82p33->extts_work,
367*ad3cc776SMin Li 				      msecs_to_jiffies(EXTTS_PERIOD_MS));
368*ad3cc776SMin Li 
369*ad3cc776SMin Li 	return extts_mask;
370*ad3cc776SMin Li }
371*ad3cc776SMin Li 
372*ad3cc776SMin Li static int _idt82p33_gettime(struct idt82p33_channel *channel,
373*ad3cc776SMin Li 			     struct timespec64 *ts)
374*ad3cc776SMin Li {
375*ad3cc776SMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
376*ad3cc776SMin Li 	u8 old_mask = idt82p33->extts_mask;
377*ad3cc776SMin Li 	u8 buf[TOD_BYTE_COUNT];
378*ad3cc776SMin Li 	u8 new_mask = 0;
379*ad3cc776SMin Li 	int err;
380*ad3cc776SMin Li 
381*ad3cc776SMin Li 	/* Disable extts */
382*ad3cc776SMin Li 	if (old_mask)
383*ad3cc776SMin Li 		new_mask = idt82p33_extts_enable_mask(channel, old_mask, false);
384*ad3cc776SMin Li 
385*ad3cc776SMin Li 	err = idt82p33_set_tod_trigger(channel, HW_TOD_RD_TRIG_SEL_LSB_TOD_STS,
386*ad3cc776SMin Li 				       false);
387*ad3cc776SMin Li 	if (err)
388*ad3cc776SMin Li 		return err;
389*ad3cc776SMin Li 
390*ad3cc776SMin Li 	channel->discard_next_extts = true;
391*ad3cc776SMin Li 
39257a10d8cSMin Li 	if (idt82p33->calculate_overhead_flag)
39357a10d8cSMin Li 		idt82p33->start_time = ktime_get_raw();
39457a10d8cSMin Li 
39557a10d8cSMin Li 	err = idt82p33_read(idt82p33, channel->dpll_tod_sts, buf, sizeof(buf));
39657a10d8cSMin Li 
39757a10d8cSMin Li 	if (err)
39857a10d8cSMin Li 		return err;
39957a10d8cSMin Li 
400*ad3cc776SMin Li 	/* Re-enable extts */
401*ad3cc776SMin Li 	if (new_mask)
402*ad3cc776SMin Li 		idt82p33_extts_enable_mask(channel, new_mask, true);
403*ad3cc776SMin Li 
40457a10d8cSMin Li 	idt82p33_byte_array_to_timespec(ts, buf);
40557a10d8cSMin Li 
40657a10d8cSMin Li 	return 0;
40757a10d8cSMin Li }
40857a10d8cSMin Li 
40957a10d8cSMin Li /*
41057a10d8cSMin Li  *   TOD Trigger:
41157a10d8cSMin Li  *   Bits[7:4] Write 0x9, MSB write
41257a10d8cSMin Li  *   Bits[3:0] Read 0x9, LSB read
41357a10d8cSMin Li  */
41457a10d8cSMin Li 
41557a10d8cSMin Li static int _idt82p33_settime(struct idt82p33_channel *channel,
41657a10d8cSMin Li 			     struct timespec64 const *ts)
41757a10d8cSMin Li {
41857a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
41957a10d8cSMin Li 	struct timespec64 local_ts = *ts;
42057a10d8cSMin Li 	char buf[TOD_BYTE_COUNT];
42157a10d8cSMin Li 	s64 dynamic_overhead_ns;
42257a10d8cSMin Li 	int err;
42357a10d8cSMin Li 	u8 i;
42457a10d8cSMin Li 
425*ad3cc776SMin Li 	err = idt82p33_set_tod_trigger(channel, HW_TOD_WR_TRIG_SEL_MSB_TOD_CNFG,
426*ad3cc776SMin Li 				       true);
42757a10d8cSMin Li 	if (err)
42857a10d8cSMin Li 		return err;
42957a10d8cSMin Li 
430*ad3cc776SMin Li 	channel->discard_next_extts = true;
431*ad3cc776SMin Li 
43257a10d8cSMin Li 	if (idt82p33->calculate_overhead_flag) {
43357a10d8cSMin Li 		dynamic_overhead_ns = ktime_to_ns(ktime_get_raw())
43457a10d8cSMin Li 					- ktime_to_ns(idt82p33->start_time);
43557a10d8cSMin Li 
43657a10d8cSMin Li 		timespec64_add_ns(&local_ts, dynamic_overhead_ns);
43757a10d8cSMin Li 
43857a10d8cSMin Li 		idt82p33->calculate_overhead_flag = 0;
43957a10d8cSMin Li 	}
44057a10d8cSMin Li 
44157a10d8cSMin Li 	idt82p33_timespec_to_byte_array(&local_ts, buf);
44257a10d8cSMin Li 
44357a10d8cSMin Li 	/*
44457a10d8cSMin Li 	 * Store the new time value.
44557a10d8cSMin Li 	 */
44657a10d8cSMin Li 	for (i = 0; i < TOD_BYTE_COUNT; i++) {
44757a10d8cSMin Li 		err = idt82p33_write(idt82p33, channel->dpll_tod_cnfg + i,
44857a10d8cSMin Li 				     &buf[i], sizeof(buf[i]));
44957a10d8cSMin Li 		if (err)
45057a10d8cSMin Li 			return err;
45157a10d8cSMin Li 	}
45257a10d8cSMin Li 
45357a10d8cSMin Li 	return err;
45457a10d8cSMin Li }
45557a10d8cSMin Li 
456*ad3cc776SMin Li static int _idt82p33_adjtime_immediate(struct idt82p33_channel *channel,
457*ad3cc776SMin Li 				       s64 delta_ns)
45857a10d8cSMin Li {
45957a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
46057a10d8cSMin Li 	struct timespec64 ts;
46157a10d8cSMin Li 	s64 now_ns;
46257a10d8cSMin Li 	int err;
46357a10d8cSMin Li 
46457a10d8cSMin Li 	idt82p33->calculate_overhead_flag = 1;
46557a10d8cSMin Li 
46657a10d8cSMin Li 	err = _idt82p33_gettime(channel, &ts);
46757a10d8cSMin Li 
46857a10d8cSMin Li 	if (err)
46957a10d8cSMin Li 		return err;
47057a10d8cSMin Li 
47157a10d8cSMin Li 	now_ns = timespec64_to_ns(&ts);
47257a10d8cSMin Li 	now_ns += delta_ns + idt82p33->tod_write_overhead_ns;
47357a10d8cSMin Li 
47457a10d8cSMin Li 	ts = ns_to_timespec64(now_ns);
47557a10d8cSMin Li 
47657a10d8cSMin Li 	err = _idt82p33_settime(channel, &ts);
47757a10d8cSMin Li 
47857a10d8cSMin Li 	return err;
47957a10d8cSMin Li }
48057a10d8cSMin Li 
481*ad3cc776SMin Li static int _idt82p33_adjtime_internal_triggered(struct idt82p33_channel *channel,
482*ad3cc776SMin Li 						s64 delta_ns)
483*ad3cc776SMin Li {
484*ad3cc776SMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
485*ad3cc776SMin Li 	char buf[TOD_BYTE_COUNT];
486*ad3cc776SMin Li 	struct timespec64 ts;
487*ad3cc776SMin Li 	const u8 delay_ns = 32;
488*ad3cc776SMin Li 	s32 remainder;
489*ad3cc776SMin Li 	s64 ns;
490*ad3cc776SMin Li 	int err;
491*ad3cc776SMin Li 
492*ad3cc776SMin Li 	err = _idt82p33_gettime(channel, &ts);
493*ad3cc776SMin Li 
494*ad3cc776SMin Li 	if (err)
495*ad3cc776SMin Li 		return err;
496*ad3cc776SMin Li 
497*ad3cc776SMin Li 	if (ts.tv_nsec > (NSEC_PER_SEC - 5 * NSEC_PER_MSEC)) {
498*ad3cc776SMin Li 		/*  Too close to miss next trigger, so skip it */
499*ad3cc776SMin Li 		mdelay(6);
500*ad3cc776SMin Li 		ns = (ts.tv_sec + 2) * NSEC_PER_SEC + delta_ns + delay_ns;
501*ad3cc776SMin Li 	} else
502*ad3cc776SMin Li 		ns = (ts.tv_sec + 1) * NSEC_PER_SEC + delta_ns + delay_ns;
503*ad3cc776SMin Li 
504*ad3cc776SMin Li 	ts = ns_to_timespec64(ns);
505*ad3cc776SMin Li 	idt82p33_timespec_to_byte_array(&ts, buf);
506*ad3cc776SMin Li 
507*ad3cc776SMin Li 	/*
508*ad3cc776SMin Li 	 * Store the new time value.
509*ad3cc776SMin Li 	 */
510*ad3cc776SMin Li 	err = idt82p33_write(idt82p33, channel->dpll_tod_cnfg, buf, sizeof(buf));
511*ad3cc776SMin Li 	if (err)
512*ad3cc776SMin Li 		return err;
513*ad3cc776SMin Li 
514*ad3cc776SMin Li 	/* Schedule to implement the workaround in one second */
515*ad3cc776SMin Li 	(void)div_s64_rem(delta_ns, NSEC_PER_SEC, &remainder);
516*ad3cc776SMin Li 	if (remainder != 0)
517*ad3cc776SMin Li 		schedule_delayed_work(&channel->adjtime_work, HZ);
518*ad3cc776SMin Li 
519*ad3cc776SMin Li 	return idt82p33_set_tod_trigger(channel, HW_TOD_TRIG_SEL_TOD_PPS, true);
520*ad3cc776SMin Li }
521*ad3cc776SMin Li 
522*ad3cc776SMin Li static void idt82p33_adjtime_workaround(struct work_struct *work)
523*ad3cc776SMin Li {
524*ad3cc776SMin Li 	struct idt82p33_channel *channel = container_of(work,
525*ad3cc776SMin Li 							struct idt82p33_channel,
526*ad3cc776SMin Li 							adjtime_work.work);
527*ad3cc776SMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
528*ad3cc776SMin Li 
529*ad3cc776SMin Li 	mutex_lock(idt82p33->lock);
530*ad3cc776SMin Li 	/* Workaround for TOD-to-output alignment issue */
531*ad3cc776SMin Li 	_idt82p33_adjtime_internal_triggered(channel, 0);
532*ad3cc776SMin Li 	mutex_unlock(idt82p33->lock);
533*ad3cc776SMin Li }
534*ad3cc776SMin Li 
53557a10d8cSMin Li static int _idt82p33_adjfine(struct idt82p33_channel *channel, long scaled_ppm)
53657a10d8cSMin Li {
53757a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
53857a10d8cSMin Li 	unsigned char buf[5] = {0};
53957a10d8cSMin Li 	int err, i;
54057a10d8cSMin Li 	s64 fcw;
54157a10d8cSMin Li 
54257a10d8cSMin Li 	/*
543*ad3cc776SMin Li 	 * Frequency Control Word unit is: 1.6861512 * 10^-10 ppm
54457a10d8cSMin Li 	 *
54557a10d8cSMin Li 	 * adjfreq:
546*ad3cc776SMin Li 	 *       ppb * 10^14
547*ad3cc776SMin Li 	 * FCW = -----------
548*ad3cc776SMin Li 	 *         16861512
54957a10d8cSMin Li 	 *
55057a10d8cSMin Li 	 * adjfine:
551*ad3cc776SMin Li 	 *       scaled_ppm * 5^12 * 10^5
552*ad3cc776SMin Li 	 * FCW = ------------------------
553*ad3cc776SMin Li 	 *            16861512 * 2^4
55457a10d8cSMin Li 	 */
55557a10d8cSMin Li 
556*ad3cc776SMin Li 	fcw = scaled_ppm * 762939453125ULL;
557*ad3cc776SMin Li 	fcw = div_s64(fcw, 8430756LL);
55857a10d8cSMin Li 
55957a10d8cSMin Li 	for (i = 0; i < 5; i++) {
56057a10d8cSMin Li 		buf[i] = fcw & 0xff;
56157a10d8cSMin Li 		fcw >>= 8;
56257a10d8cSMin Li 	}
56357a10d8cSMin Li 
56457a10d8cSMin Li 	err = idt82p33_dpll_set_mode(channel, PLL_MODE_DCO);
56557a10d8cSMin Li 
56657a10d8cSMin Li 	if (err)
56757a10d8cSMin Li 		return err;
56857a10d8cSMin Li 
56957a10d8cSMin Li 	err = idt82p33_write(idt82p33, channel->dpll_freq_cnfg,
57057a10d8cSMin Li 			     buf, sizeof(buf));
57157a10d8cSMin Li 
57257a10d8cSMin Li 	return err;
57357a10d8cSMin Li }
57457a10d8cSMin Li 
575*ad3cc776SMin Li /* ppb = scaled_ppm * 125 / 2^13 */
576*ad3cc776SMin Li static s32 idt82p33_ddco_scaled_ppm(long current_ppm, s32 ddco_ppb)
577*ad3cc776SMin Li {
578*ad3cc776SMin Li 	s64 scaled_ppm = div_s64(((s64)ddco_ppb << 13), 125);
579*ad3cc776SMin Li 	s64 max_scaled_ppm = div_s64(((s64)DCO_MAX_PPB << 13), 125);
580*ad3cc776SMin Li 
581*ad3cc776SMin Li 	current_ppm += scaled_ppm;
582*ad3cc776SMin Li 
583*ad3cc776SMin Li 	if (current_ppm > max_scaled_ppm)
584*ad3cc776SMin Li 		current_ppm = max_scaled_ppm;
585*ad3cc776SMin Li 	else if (current_ppm < -max_scaled_ppm)
586*ad3cc776SMin Li 		current_ppm = -max_scaled_ppm;
587*ad3cc776SMin Li 
588*ad3cc776SMin Li 	return (s32)current_ppm;
589*ad3cc776SMin Li }
590*ad3cc776SMin Li 
591*ad3cc776SMin Li static int idt82p33_stop_ddco(struct idt82p33_channel *channel)
592*ad3cc776SMin Li {
593*ad3cc776SMin Li 	int err;
594*ad3cc776SMin Li 
595*ad3cc776SMin Li 	err = _idt82p33_adjfine(channel, channel->current_freq);
596*ad3cc776SMin Li 	if (err)
597*ad3cc776SMin Li 		return err;
598*ad3cc776SMin Li 
599*ad3cc776SMin Li 	channel->ddco = false;
600*ad3cc776SMin Li 
601*ad3cc776SMin Li 	return 0;
602*ad3cc776SMin Li }
603*ad3cc776SMin Li 
604*ad3cc776SMin Li static int idt82p33_start_ddco(struct idt82p33_channel *channel, s32 delta_ns)
605*ad3cc776SMin Li {
606*ad3cc776SMin Li 	s32 current_ppm = channel->current_freq;
607*ad3cc776SMin Li 	u32 duration_ms = MSEC_PER_SEC;
608*ad3cc776SMin Li 	s32 ppb;
609*ad3cc776SMin Li 	int err;
610*ad3cc776SMin Li 
611*ad3cc776SMin Li 	/* If the ToD correction is less than 5 nanoseconds, then skip it.
612*ad3cc776SMin Li 	 * The error introduced by the ToD adjustment procedure would be bigger
613*ad3cc776SMin Li 	 * than the required ToD correction
614*ad3cc776SMin Li 	 */
615*ad3cc776SMin Li 	if (abs(delta_ns) < DDCO_THRESHOLD_NS)
616*ad3cc776SMin Li 		return 0;
617*ad3cc776SMin Li 
618*ad3cc776SMin Li 	/* For most cases, keep ddco duration 1 second */
619*ad3cc776SMin Li 	ppb = delta_ns;
620*ad3cc776SMin Li 	while (abs(ppb) > DCO_MAX_PPB) {
621*ad3cc776SMin Li 		duration_ms *= 2;
622*ad3cc776SMin Li 		ppb /= 2;
623*ad3cc776SMin Li 	}
624*ad3cc776SMin Li 
625*ad3cc776SMin Li 	err = _idt82p33_adjfine(channel,
626*ad3cc776SMin Li 				idt82p33_ddco_scaled_ppm(current_ppm, ppb));
627*ad3cc776SMin Li 	if (err)
628*ad3cc776SMin Li 		return err;
629*ad3cc776SMin Li 
630*ad3cc776SMin Li 	/* schedule the worker to cancel ddco */
631*ad3cc776SMin Li 	ptp_schedule_worker(channel->ptp_clock,
632*ad3cc776SMin Li 			    msecs_to_jiffies(duration_ms) - 1);
633*ad3cc776SMin Li 	channel->ddco = true;
634*ad3cc776SMin Li 
635*ad3cc776SMin Li 	return 0;
636*ad3cc776SMin Li }
637*ad3cc776SMin Li 
63857a10d8cSMin Li static int idt82p33_measure_one_byte_write_overhead(
63957a10d8cSMin Li 		struct idt82p33_channel *channel, s64 *overhead_ns)
64057a10d8cSMin Li {
64157a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
64257a10d8cSMin Li 	ktime_t start, stop;
643*ad3cc776SMin Li 	u8 trigger = 0;
64457a10d8cSMin Li 	s64 total_ns;
64557a10d8cSMin Li 	int err;
64657a10d8cSMin Li 	u8 i;
64757a10d8cSMin Li 
64857a10d8cSMin Li 	total_ns = 0;
64957a10d8cSMin Li 	*overhead_ns = 0;
65057a10d8cSMin Li 
65157a10d8cSMin Li 	for (i = 0; i < MAX_MEASURMENT_COUNT; i++) {
65257a10d8cSMin Li 
65357a10d8cSMin Li 		start = ktime_get_raw();
65457a10d8cSMin Li 
65557a10d8cSMin Li 		err = idt82p33_write(idt82p33, channel->dpll_tod_trigger,
65657a10d8cSMin Li 				     &trigger, sizeof(trigger));
65757a10d8cSMin Li 
65857a10d8cSMin Li 		stop = ktime_get_raw();
65957a10d8cSMin Li 
66057a10d8cSMin Li 		if (err)
66157a10d8cSMin Li 			return err;
66257a10d8cSMin Li 
66357a10d8cSMin Li 		total_ns += ktime_to_ns(stop) - ktime_to_ns(start);
66457a10d8cSMin Li 	}
66557a10d8cSMin Li 
66657a10d8cSMin Li 	*overhead_ns = div_s64(total_ns, MAX_MEASURMENT_COUNT);
66757a10d8cSMin Li 
66857a10d8cSMin Li 	return err;
66957a10d8cSMin Li }
67057a10d8cSMin Li 
671*ad3cc776SMin Li static int idt82p33_measure_one_byte_read_overhead(
672*ad3cc776SMin Li 		struct idt82p33_channel *channel, s64 *overhead_ns)
673*ad3cc776SMin Li {
674*ad3cc776SMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
675*ad3cc776SMin Li 	ktime_t start, stop;
676*ad3cc776SMin Li 	u8 trigger = 0;
677*ad3cc776SMin Li 	s64 total_ns;
678*ad3cc776SMin Li 	int err;
679*ad3cc776SMin Li 	u8 i;
680*ad3cc776SMin Li 
681*ad3cc776SMin Li 	total_ns = 0;
682*ad3cc776SMin Li 	*overhead_ns = 0;
683*ad3cc776SMin Li 
684*ad3cc776SMin Li 	for (i = 0; i < MAX_MEASURMENT_COUNT; i++) {
685*ad3cc776SMin Li 
686*ad3cc776SMin Li 		start = ktime_get_raw();
687*ad3cc776SMin Li 
688*ad3cc776SMin Li 		err = idt82p33_read(idt82p33, channel->dpll_tod_trigger,
689*ad3cc776SMin Li 				    &trigger, sizeof(trigger));
690*ad3cc776SMin Li 
691*ad3cc776SMin Li 		stop = ktime_get_raw();
692*ad3cc776SMin Li 
693*ad3cc776SMin Li 		if (err)
694*ad3cc776SMin Li 			return err;
695*ad3cc776SMin Li 
696*ad3cc776SMin Li 		total_ns += ktime_to_ns(stop) - ktime_to_ns(start);
697*ad3cc776SMin Li 	}
698*ad3cc776SMin Li 
699*ad3cc776SMin Li 	*overhead_ns = div_s64(total_ns, MAX_MEASURMENT_COUNT);
700*ad3cc776SMin Li 
701*ad3cc776SMin Li 	return err;
702*ad3cc776SMin Li }
703*ad3cc776SMin Li 
70457a10d8cSMin Li static int idt82p33_measure_tod_write_9_byte_overhead(
70557a10d8cSMin Li 		struct idt82p33_channel *channel)
70657a10d8cSMin Li {
70757a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
70857a10d8cSMin Li 	u8 buf[TOD_BYTE_COUNT];
70957a10d8cSMin Li 	ktime_t start, stop;
71057a10d8cSMin Li 	s64 total_ns;
71157a10d8cSMin Li 	int err = 0;
71257a10d8cSMin Li 	u8 i, j;
71357a10d8cSMin Li 
71457a10d8cSMin Li 	total_ns = 0;
71557a10d8cSMin Li 	idt82p33->tod_write_overhead_ns = 0;
71657a10d8cSMin Li 
71757a10d8cSMin Li 	for (i = 0; i < MAX_MEASURMENT_COUNT; i++) {
71857a10d8cSMin Li 
71957a10d8cSMin Li 		start = ktime_get_raw();
72057a10d8cSMin Li 
72157a10d8cSMin Li 		/* Need one less byte for applicable overhead */
72257a10d8cSMin Li 		for (j = 0; j < (TOD_BYTE_COUNT - 1); j++) {
72357a10d8cSMin Li 			err = idt82p33_write(idt82p33,
72457a10d8cSMin Li 					     channel->dpll_tod_cnfg + i,
72557a10d8cSMin Li 					     &buf[i], sizeof(buf[i]));
72657a10d8cSMin Li 			if (err)
72757a10d8cSMin Li 				return err;
72857a10d8cSMin Li 		}
72957a10d8cSMin Li 
73057a10d8cSMin Li 		stop = ktime_get_raw();
73157a10d8cSMin Li 
73257a10d8cSMin Li 		total_ns += ktime_to_ns(stop) - ktime_to_ns(start);
73357a10d8cSMin Li 	}
73457a10d8cSMin Li 
73557a10d8cSMin Li 	idt82p33->tod_write_overhead_ns = div_s64(total_ns,
73657a10d8cSMin Li 						  MAX_MEASURMENT_COUNT);
73757a10d8cSMin Li 
73857a10d8cSMin Li 	return err;
73957a10d8cSMin Li }
74057a10d8cSMin Li 
74157a10d8cSMin Li static int idt82p33_measure_settime_gettime_gap_overhead(
74257a10d8cSMin Li 		struct idt82p33_channel *channel, s64 *overhead_ns)
74357a10d8cSMin Li {
74457a10d8cSMin Li 	struct timespec64 ts1 = {0, 0};
74557a10d8cSMin Li 	struct timespec64 ts2;
74657a10d8cSMin Li 	int err;
74757a10d8cSMin Li 
74857a10d8cSMin Li 	*overhead_ns = 0;
74957a10d8cSMin Li 
75057a10d8cSMin Li 	err = _idt82p33_settime(channel, &ts1);
75157a10d8cSMin Li 
75257a10d8cSMin Li 	if (err)
75357a10d8cSMin Li 		return err;
75457a10d8cSMin Li 
75557a10d8cSMin Li 	err = _idt82p33_gettime(channel, &ts2);
75657a10d8cSMin Li 
75757a10d8cSMin Li 	if (!err)
75857a10d8cSMin Li 		*overhead_ns = timespec64_to_ns(&ts2) - timespec64_to_ns(&ts1);
75957a10d8cSMin Li 
76057a10d8cSMin Li 	return err;
76157a10d8cSMin Li }
76257a10d8cSMin Li 
76357a10d8cSMin Li static int idt82p33_measure_tod_write_overhead(struct idt82p33_channel *channel)
76457a10d8cSMin Li {
765*ad3cc776SMin Li 	s64 trailing_overhead_ns, one_byte_write_ns, gap_ns, one_byte_read_ns;
76657a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
76757a10d8cSMin Li 	int err;
76857a10d8cSMin Li 
76957a10d8cSMin Li 	idt82p33->tod_write_overhead_ns = 0;
77057a10d8cSMin Li 
77157a10d8cSMin Li 	err = idt82p33_measure_settime_gettime_gap_overhead(channel, &gap_ns);
77257a10d8cSMin Li 
773e014ae39SMin Li 	if (err) {
774013a3e7cSMin Li 		dev_err(idt82p33->dev,
775e014ae39SMin Li 			"Failed in %s with err %d!\n", __func__, err);
77657a10d8cSMin Li 		return err;
777e014ae39SMin Li 	}
77857a10d8cSMin Li 
77957a10d8cSMin Li 	err = idt82p33_measure_one_byte_write_overhead(channel,
78057a10d8cSMin Li 						       &one_byte_write_ns);
78157a10d8cSMin Li 
78257a10d8cSMin Li 	if (err)
78357a10d8cSMin Li 		return err;
78457a10d8cSMin Li 
785*ad3cc776SMin Li 	err = idt82p33_measure_one_byte_read_overhead(channel,
786*ad3cc776SMin Li 						      &one_byte_read_ns);
787*ad3cc776SMin Li 
788*ad3cc776SMin Li 	if (err)
789*ad3cc776SMin Li 		return err;
790*ad3cc776SMin Li 
79157a10d8cSMin Li 	err = idt82p33_measure_tod_write_9_byte_overhead(channel);
79257a10d8cSMin Li 
79357a10d8cSMin Li 	if (err)
79457a10d8cSMin Li 		return err;
79557a10d8cSMin Li 
796*ad3cc776SMin Li 	trailing_overhead_ns = gap_ns - 2 * one_byte_write_ns
797*ad3cc776SMin Li 			       - one_byte_read_ns;
79857a10d8cSMin Li 
79957a10d8cSMin Li 	idt82p33->tod_write_overhead_ns -= trailing_overhead_ns;
80057a10d8cSMin Li 
80157a10d8cSMin Li 	return err;
80257a10d8cSMin Li }
80357a10d8cSMin Li 
80457a10d8cSMin Li static int idt82p33_check_and_set_masks(struct idt82p33 *idt82p33,
80557a10d8cSMin Li 					u8 page,
80657a10d8cSMin Li 					u8 offset,
80757a10d8cSMin Li 					u8 val)
80857a10d8cSMin Li {
80957a10d8cSMin Li 	int err = 0;
81057a10d8cSMin Li 
81157a10d8cSMin Li 	if (page == PLLMASK_ADDR_HI && offset == PLLMASK_ADDR_LO) {
81257a10d8cSMin Li 		if ((val & 0xfc) || !(val & 0x3)) {
813013a3e7cSMin Li 			dev_err(idt82p33->dev,
814013a3e7cSMin Li 				"Invalid PLL mask 0x%x\n", val);
81557a10d8cSMin Li 			err = -EINVAL;
81657a10d8cSMin Li 		} else {
81757a10d8cSMin Li 			idt82p33->pll_mask = val;
81857a10d8cSMin Li 		}
81957a10d8cSMin Li 	} else if (page == PLL0_OUTMASK_ADDR_HI &&
82057a10d8cSMin Li 		offset == PLL0_OUTMASK_ADDR_LO) {
82157a10d8cSMin Li 		idt82p33->channel[0].output_mask = val;
82257a10d8cSMin Li 	} else if (page == PLL1_OUTMASK_ADDR_HI &&
82357a10d8cSMin Li 		offset == PLL1_OUTMASK_ADDR_LO) {
82457a10d8cSMin Li 		idt82p33->channel[1].output_mask = val;
82557a10d8cSMin Li 	}
82657a10d8cSMin Li 
82757a10d8cSMin Li 	return err;
82857a10d8cSMin Li }
82957a10d8cSMin Li 
83057a10d8cSMin Li static void idt82p33_display_masks(struct idt82p33 *idt82p33)
83157a10d8cSMin Li {
83257a10d8cSMin Li 	u8 mask, i;
83357a10d8cSMin Li 
834013a3e7cSMin Li 	dev_info(idt82p33->dev,
83557a10d8cSMin Li 		 "pllmask = 0x%02x\n", idt82p33->pll_mask);
83657a10d8cSMin Li 
83757a10d8cSMin Li 	for (i = 0; i < MAX_PHC_PLL; i++) {
83857a10d8cSMin Li 		mask = 1 << i;
83957a10d8cSMin Li 
84057a10d8cSMin Li 		if (mask & idt82p33->pll_mask)
841013a3e7cSMin Li 			dev_info(idt82p33->dev,
84257a10d8cSMin Li 				 "PLL%d output_mask = 0x%04x\n",
84357a10d8cSMin Li 				 i, idt82p33->channel[i].output_mask);
84457a10d8cSMin Li 	}
84557a10d8cSMin Li }
84657a10d8cSMin Li 
84757a10d8cSMin Li static int idt82p33_sync_tod(struct idt82p33_channel *channel, bool enable)
84857a10d8cSMin Li {
84957a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
85057a10d8cSMin Li 	u8 sync_cnfg;
85157a10d8cSMin Li 	int err;
85257a10d8cSMin Li 
85357a10d8cSMin Li 	err = idt82p33_read(idt82p33, channel->dpll_sync_cnfg,
85457a10d8cSMin Li 			    &sync_cnfg, sizeof(sync_cnfg));
85557a10d8cSMin Li 	if (err)
85657a10d8cSMin Li 		return err;
85757a10d8cSMin Li 
85857a10d8cSMin Li 	sync_cnfg &= ~SYNC_TOD;
85957a10d8cSMin Li 	if (enable)
86057a10d8cSMin Li 		sync_cnfg |= SYNC_TOD;
86157a10d8cSMin Li 
862e014ae39SMin Li 	return idt82p33_write(idt82p33, channel->dpll_sync_cnfg,
86357a10d8cSMin Li 			      &sync_cnfg, sizeof(sync_cnfg));
86457a10d8cSMin Li }
86557a10d8cSMin Li 
866*ad3cc776SMin Li static long idt82p33_work_handler(struct ptp_clock_info *ptp)
867*ad3cc776SMin Li {
868*ad3cc776SMin Li 	struct idt82p33_channel *channel =
869*ad3cc776SMin Li 			container_of(ptp, struct idt82p33_channel, caps);
870*ad3cc776SMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
871*ad3cc776SMin Li 
872*ad3cc776SMin Li 	mutex_lock(idt82p33->lock);
873*ad3cc776SMin Li 	(void)idt82p33_stop_ddco(channel);
874*ad3cc776SMin Li 	mutex_unlock(idt82p33->lock);
875*ad3cc776SMin Li 
876*ad3cc776SMin Li 	/* Return a negative value here to not reschedule */
877*ad3cc776SMin Li 	return -1;
878*ad3cc776SMin Li }
879*ad3cc776SMin Li 
880e014ae39SMin Li static int idt82p33_output_enable(struct idt82p33_channel *channel,
881e014ae39SMin Li 				  bool enable, unsigned int outn)
88257a10d8cSMin Li {
88357a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
88457a10d8cSMin Li 	int err;
885e014ae39SMin Li 	u8 val;
886e014ae39SMin Li 
887e014ae39SMin Li 	err = idt82p33_read(idt82p33, OUT_MUX_CNFG(outn), &val, sizeof(val));
888e014ae39SMin Li 	if (err)
889e014ae39SMin Li 		return err;
890e014ae39SMin Li 	if (enable)
891e014ae39SMin Li 		val &= ~SQUELCH_ENABLE;
892e014ae39SMin Li 	else
893e014ae39SMin Li 		val |= SQUELCH_ENABLE;
894e014ae39SMin Li 
895e014ae39SMin Li 	return idt82p33_write(idt82p33, OUT_MUX_CNFG(outn), &val, sizeof(val));
896e014ae39SMin Li }
897e014ae39SMin Li 
898e014ae39SMin Li static int idt82p33_output_mask_enable(struct idt82p33_channel *channel,
899e014ae39SMin Li 				       bool enable)
900e014ae39SMin Li {
901e014ae39SMin Li 	u16 mask;
902e014ae39SMin Li 	int err;
903e014ae39SMin Li 	u8 outn;
90457a10d8cSMin Li 
90557a10d8cSMin Li 	mask = channel->output_mask;
90657a10d8cSMin Li 	outn = 0;
90757a10d8cSMin Li 
90857a10d8cSMin Li 	while (mask) {
90957a10d8cSMin Li 		if (mask & 0x1) {
910e014ae39SMin Li 			err = idt82p33_output_enable(channel, enable, outn);
91157a10d8cSMin Li 			if (err)
91257a10d8cSMin Li 				return err;
91357a10d8cSMin Li 		}
914e014ae39SMin Li 
91557a10d8cSMin Li 		mask >>= 0x1;
91657a10d8cSMin Li 		outn++;
91757a10d8cSMin Li 	}
91857a10d8cSMin Li 
91957a10d8cSMin Li 	return 0;
92057a10d8cSMin Li }
92157a10d8cSMin Li 
922e014ae39SMin Li static int idt82p33_perout_enable(struct idt82p33_channel *channel,
923e014ae39SMin Li 				  bool enable,
924e014ae39SMin Li 				  struct ptp_perout_request *perout)
925e014ae39SMin Li {
926e014ae39SMin Li 	unsigned int flags = perout->flags;
927e014ae39SMin Li 
928e014ae39SMin Li 	/* Enable/disable output based on output_mask */
929e014ae39SMin Li 	if (flags == PEROUT_ENABLE_OUTPUT_MASK)
930e014ae39SMin Li 		return idt82p33_output_mask_enable(channel, enable);
931e014ae39SMin Li 
932e014ae39SMin Li 	/* Enable/disable individual output instead */
933e014ae39SMin Li 	return idt82p33_output_enable(channel, enable, perout->index);
934e014ae39SMin Li }
935e014ae39SMin Li 
93657a10d8cSMin Li static int idt82p33_enable_tod(struct idt82p33_channel *channel)
93757a10d8cSMin Li {
93857a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
93957a10d8cSMin Li 	struct timespec64 ts = {0, 0};
94057a10d8cSMin Li 	int err;
94157a10d8cSMin Li 
942*ad3cc776SMin Li 	/* STEELAI-366 - Temporary workaround for ts2phc compatibility */
943*ad3cc776SMin Li 	if (0)
944*ad3cc776SMin Li 		err = idt82p33_output_mask_enable(channel, false);
945*ad3cc776SMin Li 
94657a10d8cSMin Li 	err = idt82p33_measure_tod_write_overhead(channel);
94757a10d8cSMin Li 
948e014ae39SMin Li 	if (err) {
949013a3e7cSMin Li 		dev_err(idt82p33->dev,
950e014ae39SMin Li 			"Failed in %s with err %d!\n", __func__, err);
95157a10d8cSMin Li 		return err;
952e014ae39SMin Li 	}
95357a10d8cSMin Li 
95457a10d8cSMin Li 	err = _idt82p33_settime(channel, &ts);
95557a10d8cSMin Li 
95657a10d8cSMin Li 	if (err)
95757a10d8cSMin Li 		return err;
95857a10d8cSMin Li 
95957a10d8cSMin Li 	return idt82p33_sync_tod(channel, true);
96057a10d8cSMin Li }
96157a10d8cSMin Li 
96257a10d8cSMin Li static void idt82p33_ptp_clock_unregister_all(struct idt82p33 *idt82p33)
96357a10d8cSMin Li {
96457a10d8cSMin Li 	struct idt82p33_channel *channel;
96557a10d8cSMin Li 	u8 i;
96657a10d8cSMin Li 
96757a10d8cSMin Li 	for (i = 0; i < MAX_PHC_PLL; i++) {
96857a10d8cSMin Li 		channel = &idt82p33->channel[i];
969*ad3cc776SMin Li 		cancel_delayed_work_sync(&channel->adjtime_work);
970e014ae39SMin Li 		if (channel->ptp_clock)
97157a10d8cSMin Li 			ptp_clock_unregister(channel->ptp_clock);
97257a10d8cSMin Li 	}
97357a10d8cSMin Li }
97457a10d8cSMin Li 
975*ad3cc776SMin Li 
976*ad3cc776SMin Li 
97757a10d8cSMin Li static int idt82p33_enable(struct ptp_clock_info *ptp,
97857a10d8cSMin Li 			   struct ptp_clock_request *rq, int on)
97957a10d8cSMin Li {
98057a10d8cSMin Li 	struct idt82p33_channel *channel =
98157a10d8cSMin Li 			container_of(ptp, struct idt82p33_channel, caps);
98257a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
983013a3e7cSMin Li 	int err = -EOPNOTSUPP;
98457a10d8cSMin Li 
985013a3e7cSMin Li 	mutex_lock(idt82p33->lock);
98657a10d8cSMin Li 
987*ad3cc776SMin Li 	switch (rq->type) {
988*ad3cc776SMin Li 	case PTP_CLK_REQ_PEROUT:
98957a10d8cSMin Li 		if (!on)
990e014ae39SMin Li 			err = idt82p33_perout_enable(channel, false,
991e014ae39SMin Li 						     &rq->perout);
99257a10d8cSMin Li 		/* Only accept a 1-PPS aligned to the second. */
99357a10d8cSMin Li 		else if (rq->perout.start.nsec || rq->perout.period.sec != 1 ||
994013a3e7cSMin Li 			 rq->perout.period.nsec)
99557a10d8cSMin Li 			err = -ERANGE;
996013a3e7cSMin Li 		else
997e014ae39SMin Li 			err = idt82p33_perout_enable(channel, true,
998e014ae39SMin Li 						     &rq->perout);
999*ad3cc776SMin Li 		break;
1000*ad3cc776SMin Li 	case PTP_CLK_REQ_EXTTS:
1001*ad3cc776SMin Li 		err = idt82p33_extts_enable(channel, rq, on);
1002*ad3cc776SMin Li 		break;
1003*ad3cc776SMin Li 	default:
1004*ad3cc776SMin Li 		break;
100557a10d8cSMin Li 	}
100657a10d8cSMin Li 
1007013a3e7cSMin Li 	mutex_unlock(idt82p33->lock);
100857a10d8cSMin Li 
1009013a3e7cSMin Li 	if (err)
1010013a3e7cSMin Li 		dev_err(idt82p33->dev,
1011013a3e7cSMin Li 			"Failed in %s with err %d!\n", __func__, err);
101257a10d8cSMin Li 	return err;
101357a10d8cSMin Li }
101457a10d8cSMin Li 
1015e014ae39SMin Li static int idt82p33_adjwritephase(struct ptp_clock_info *ptp, s32 offset_ns)
1016e014ae39SMin Li {
1017e014ae39SMin Li 	struct idt82p33_channel *channel =
1018e014ae39SMin Li 		container_of(ptp, struct idt82p33_channel, caps);
1019e014ae39SMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
1020e014ae39SMin Li 	s64 offset_regval, offset_fs;
1021e014ae39SMin Li 	u8 val[4] = {0};
1022e014ae39SMin Li 	int err;
1023e014ae39SMin Li 
1024e014ae39SMin Li 	offset_fs = (s64)(-offset_ns) * 1000000;
1025e014ae39SMin Li 
1026e014ae39SMin Li 	if (offset_fs > WRITE_PHASE_OFFSET_LIMIT)
1027e014ae39SMin Li 		offset_fs = WRITE_PHASE_OFFSET_LIMIT;
1028e014ae39SMin Li 	else if (offset_fs < -WRITE_PHASE_OFFSET_LIMIT)
1029e014ae39SMin Li 		offset_fs = -WRITE_PHASE_OFFSET_LIMIT;
1030e014ae39SMin Li 
1031e014ae39SMin Li 	/* Convert from phaseoffset_fs to register value */
1032e014ae39SMin Li 	offset_regval = div_s64(offset_fs * 1000, IDT_T0DPLL_PHASE_RESOL);
1033e014ae39SMin Li 
1034e014ae39SMin Li 	val[0] = offset_regval & 0xFF;
1035e014ae39SMin Li 	val[1] = (offset_regval >> 8) & 0xFF;
1036e014ae39SMin Li 	val[2] = (offset_regval >> 16) & 0xFF;
1037e014ae39SMin Li 	val[3] = (offset_regval >> 24) & 0x1F;
1038e014ae39SMin Li 	val[3] |= PH_OFFSET_EN;
1039e014ae39SMin Li 
1040013a3e7cSMin Li 	mutex_lock(idt82p33->lock);
1041e014ae39SMin Li 
1042e014ae39SMin Li 	err = idt82p33_dpll_set_mode(channel, PLL_MODE_WPH);
1043e014ae39SMin Li 	if (err) {
1044013a3e7cSMin Li 		dev_err(idt82p33->dev,
1045e014ae39SMin Li 			"Failed in %s with err %d!\n", __func__, err);
1046e014ae39SMin Li 		goto out;
1047e014ae39SMin Li 	}
1048e014ae39SMin Li 
1049e014ae39SMin Li 	err = idt82p33_write(idt82p33, channel->dpll_phase_cnfg, val,
1050e014ae39SMin Li 			     sizeof(val));
1051e014ae39SMin Li 
1052e014ae39SMin Li out:
1053013a3e7cSMin Li 	mutex_unlock(idt82p33->lock);
1054e014ae39SMin Li 	return err;
1055e014ae39SMin Li }
1056e014ae39SMin Li 
105757a10d8cSMin Li static int idt82p33_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
105857a10d8cSMin Li {
105957a10d8cSMin Li 	struct idt82p33_channel *channel =
106057a10d8cSMin Li 			container_of(ptp, struct idt82p33_channel, caps);
106157a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
106257a10d8cSMin Li 	int err;
106357a10d8cSMin Li 
1064*ad3cc776SMin Li 	if (channel->ddco == true)
1065*ad3cc776SMin Li 		return 0;
1066*ad3cc776SMin Li 
1067*ad3cc776SMin Li 	if (scaled_ppm == channel->current_freq)
1068*ad3cc776SMin Li 		return 0;
1069*ad3cc776SMin Li 
1070013a3e7cSMin Li 	mutex_lock(idt82p33->lock);
107157a10d8cSMin Li 	err = _idt82p33_adjfine(channel, scaled_ppm);
1072*ad3cc776SMin Li 
1073*ad3cc776SMin Li 	if (err == 0)
1074*ad3cc776SMin Li 		channel->current_freq = scaled_ppm;
1075013a3e7cSMin Li 	mutex_unlock(idt82p33->lock);
1076*ad3cc776SMin Li 
1077e014ae39SMin Li 	if (err)
1078013a3e7cSMin Li 		dev_err(idt82p33->dev,
1079e014ae39SMin Li 			"Failed in %s with err %d!\n", __func__, err);
108057a10d8cSMin Li 	return err;
108157a10d8cSMin Li }
108257a10d8cSMin Li 
108357a10d8cSMin Li static int idt82p33_adjtime(struct ptp_clock_info *ptp, s64 delta_ns)
108457a10d8cSMin Li {
108557a10d8cSMin Li 	struct idt82p33_channel *channel =
108657a10d8cSMin Li 			container_of(ptp, struct idt82p33_channel, caps);
108757a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
108857a10d8cSMin Li 	int err;
108957a10d8cSMin Li 
1090*ad3cc776SMin Li 	if (channel->ddco == true)
1091*ad3cc776SMin Li 		return -EBUSY;
1092*ad3cc776SMin Li 
1093013a3e7cSMin Li 	mutex_lock(idt82p33->lock);
109457a10d8cSMin Li 
109557a10d8cSMin Li 	if (abs(delta_ns) < phase_snap_threshold) {
1096*ad3cc776SMin Li 		err = idt82p33_start_ddco(channel, delta_ns);
1097013a3e7cSMin Li 		mutex_unlock(idt82p33->lock);
1098*ad3cc776SMin Li 		return err;
109957a10d8cSMin Li 	}
110057a10d8cSMin Li 
1101*ad3cc776SMin Li 	/* Use more accurate internal 1pps triggered write first */
1102*ad3cc776SMin Li 	err = _idt82p33_adjtime_internal_triggered(channel, delta_ns);
1103*ad3cc776SMin Li 	if (err && delta_ns > IMMEDIATE_SNAP_THRESHOLD_NS)
1104*ad3cc776SMin Li 		err = _idt82p33_adjtime_immediate(channel, delta_ns);
110557a10d8cSMin Li 
1106013a3e7cSMin Li 	mutex_unlock(idt82p33->lock);
110757a10d8cSMin Li 
1108e014ae39SMin Li 	if (err)
1109013a3e7cSMin Li 		dev_err(idt82p33->dev,
1110013a3e7cSMin Li 			"Failed in %s with err %d!\n", __func__, err);
111157a10d8cSMin Li 	return err;
111257a10d8cSMin Li }
111357a10d8cSMin Li 
111457a10d8cSMin Li static int idt82p33_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
111557a10d8cSMin Li {
111657a10d8cSMin Li 	struct idt82p33_channel *channel =
111757a10d8cSMin Li 			container_of(ptp, struct idt82p33_channel, caps);
111857a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
111957a10d8cSMin Li 	int err;
112057a10d8cSMin Li 
1121013a3e7cSMin Li 	mutex_lock(idt82p33->lock);
112257a10d8cSMin Li 	err = _idt82p33_gettime(channel, ts);
1123013a3e7cSMin Li 	mutex_unlock(idt82p33->lock);
112457a10d8cSMin Li 
1125013a3e7cSMin Li 	if (err)
1126013a3e7cSMin Li 		dev_err(idt82p33->dev,
1127013a3e7cSMin Li 			"Failed in %s with err %d!\n", __func__, err);
112857a10d8cSMin Li 	return err;
112957a10d8cSMin Li }
113057a10d8cSMin Li 
113157a10d8cSMin Li static int idt82p33_settime(struct ptp_clock_info *ptp,
113257a10d8cSMin Li 			    const struct timespec64 *ts)
113357a10d8cSMin Li {
113457a10d8cSMin Li 	struct idt82p33_channel *channel =
113557a10d8cSMin Li 			container_of(ptp, struct idt82p33_channel, caps);
113657a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
113757a10d8cSMin Li 	int err;
113857a10d8cSMin Li 
1139013a3e7cSMin Li 	mutex_lock(idt82p33->lock);
114057a10d8cSMin Li 	err = _idt82p33_settime(channel, ts);
1141013a3e7cSMin Li 	mutex_unlock(idt82p33->lock);
114257a10d8cSMin Li 
1143013a3e7cSMin Li 	if (err)
1144013a3e7cSMin Li 		dev_err(idt82p33->dev,
1145013a3e7cSMin Li 			"Failed in %s with err %d!\n", __func__, err);
114657a10d8cSMin Li 	return err;
114757a10d8cSMin Li }
114857a10d8cSMin Li 
1149*ad3cc776SMin Li static int idt82p33_channel_init(struct idt82p33 *idt82p33, u32 index)
115057a10d8cSMin Li {
1151*ad3cc776SMin Li 	struct idt82p33_channel *channel = &idt82p33->channel[index];
1152*ad3cc776SMin Li 
115357a10d8cSMin Li 	switch (index) {
115457a10d8cSMin Li 	case 0:
115557a10d8cSMin Li 		channel->dpll_tod_cnfg = DPLL1_TOD_CNFG;
115657a10d8cSMin Li 		channel->dpll_tod_trigger = DPLL1_TOD_TRIGGER;
115757a10d8cSMin Li 		channel->dpll_tod_sts = DPLL1_TOD_STS;
115857a10d8cSMin Li 		channel->dpll_mode_cnfg = DPLL1_OPERATING_MODE_CNFG;
115957a10d8cSMin Li 		channel->dpll_freq_cnfg = DPLL1_HOLDOVER_FREQ_CNFG;
116057a10d8cSMin Li 		channel->dpll_phase_cnfg = DPLL1_PHASE_OFFSET_CNFG;
116157a10d8cSMin Li 		channel->dpll_sync_cnfg = DPLL1_SYNC_EDGE_CNFG;
116257a10d8cSMin Li 		channel->dpll_input_mode_cnfg = DPLL1_INPUT_MODE_CNFG;
116357a10d8cSMin Li 		break;
116457a10d8cSMin Li 	case 1:
116557a10d8cSMin Li 		channel->dpll_tod_cnfg = DPLL2_TOD_CNFG;
116657a10d8cSMin Li 		channel->dpll_tod_trigger = DPLL2_TOD_TRIGGER;
116757a10d8cSMin Li 		channel->dpll_tod_sts = DPLL2_TOD_STS;
116857a10d8cSMin Li 		channel->dpll_mode_cnfg = DPLL2_OPERATING_MODE_CNFG;
116957a10d8cSMin Li 		channel->dpll_freq_cnfg = DPLL2_HOLDOVER_FREQ_CNFG;
117057a10d8cSMin Li 		channel->dpll_phase_cnfg = DPLL2_PHASE_OFFSET_CNFG;
117157a10d8cSMin Li 		channel->dpll_sync_cnfg = DPLL2_SYNC_EDGE_CNFG;
117257a10d8cSMin Li 		channel->dpll_input_mode_cnfg = DPLL2_INPUT_MODE_CNFG;
117357a10d8cSMin Li 		break;
117457a10d8cSMin Li 	default:
117557a10d8cSMin Li 		return -EINVAL;
117657a10d8cSMin Li 	}
117757a10d8cSMin Li 
1178*ad3cc776SMin Li 	channel->plln = index;
1179*ad3cc776SMin Li 	channel->current_freq = 0;
1180*ad3cc776SMin Li 	channel->idt82p33 = idt82p33;
1181*ad3cc776SMin Li 	INIT_DELAYED_WORK(&channel->adjtime_work, idt82p33_adjtime_workaround);
118257a10d8cSMin Li 
118357a10d8cSMin Li 	return 0;
118457a10d8cSMin Li }
118557a10d8cSMin Li 
1186*ad3cc776SMin Li static int idt82p33_verify_pin(struct ptp_clock_info *ptp, unsigned int pin,
1187*ad3cc776SMin Li 			       enum ptp_pin_function func, unsigned int chan)
118857a10d8cSMin Li {
1189*ad3cc776SMin Li 	switch (func) {
1190*ad3cc776SMin Li 	case PTP_PF_NONE:
1191*ad3cc776SMin Li 	case PTP_PF_EXTTS:
1192*ad3cc776SMin Li 		break;
1193*ad3cc776SMin Li 	case PTP_PF_PEROUT:
1194*ad3cc776SMin Li 	case PTP_PF_PHYSYNC:
1195*ad3cc776SMin Li 		return -1;
1196*ad3cc776SMin Li 	}
1197*ad3cc776SMin Li 	return 0;
1198*ad3cc776SMin Li }
1199*ad3cc776SMin Li 
1200*ad3cc776SMin Li static void idt82p33_caps_init(u32 index, struct ptp_clock_info *caps,
1201*ad3cc776SMin Li 			       struct ptp_pin_desc *pin_cfg, u8 max_pins)
1202*ad3cc776SMin Li {
1203*ad3cc776SMin Li 	struct ptp_pin_desc *ppd;
1204*ad3cc776SMin Li 	int i;
1205*ad3cc776SMin Li 
120657a10d8cSMin Li 	caps->owner = THIS_MODULE;
1207013a3e7cSMin Li 	caps->max_adj = DCO_MAX_PPB;
1208*ad3cc776SMin Li 	caps->n_per_out = MAX_PER_OUT;
1209*ad3cc776SMin Li 	caps->n_ext_ts = MAX_PHC_PLL,
1210*ad3cc776SMin Li 	caps->n_pins = max_pins,
1211*ad3cc776SMin Li 	caps->adjphase = idt82p33_adjwritephase,
121257a10d8cSMin Li 	caps->adjfine = idt82p33_adjfine;
121357a10d8cSMin Li 	caps->adjtime = idt82p33_adjtime;
121457a10d8cSMin Li 	caps->gettime64 = idt82p33_gettime;
121557a10d8cSMin Li 	caps->settime64 = idt82p33_settime;
121657a10d8cSMin Li 	caps->enable = idt82p33_enable;
1217*ad3cc776SMin Li 	caps->verify = idt82p33_verify_pin;
1218*ad3cc776SMin Li 	caps->do_aux_work = idt82p33_work_handler;
1219*ad3cc776SMin Li 
1220*ad3cc776SMin Li 	snprintf(caps->name, sizeof(caps->name), "IDT 82P33 PLL%u", index);
1221*ad3cc776SMin Li 
1222*ad3cc776SMin Li 	caps->pin_config = pin_cfg;
1223*ad3cc776SMin Li 
1224*ad3cc776SMin Li 	for (i = 0; i < max_pins; ++i) {
1225*ad3cc776SMin Li 		ppd = &pin_cfg[i];
1226*ad3cc776SMin Li 
1227*ad3cc776SMin Li 		ppd->index = i;
1228*ad3cc776SMin Li 		ppd->func = PTP_PF_NONE;
1229*ad3cc776SMin Li 		ppd->chan = index;
1230*ad3cc776SMin Li 		snprintf(ppd->name, sizeof(ppd->name), "in%d", 12 + i);
1231*ad3cc776SMin Li 	}
123257a10d8cSMin Li }
123357a10d8cSMin Li 
123457a10d8cSMin Li static int idt82p33_enable_channel(struct idt82p33 *idt82p33, u32 index)
123557a10d8cSMin Li {
123657a10d8cSMin Li 	struct idt82p33_channel *channel;
123757a10d8cSMin Li 	int err;
123857a10d8cSMin Li 
123957a10d8cSMin Li 	if (!(index < MAX_PHC_PLL))
124057a10d8cSMin Li 		return -EINVAL;
124157a10d8cSMin Li 
124257a10d8cSMin Li 	channel = &idt82p33->channel[index];
124357a10d8cSMin Li 
1244*ad3cc776SMin Li 	err = idt82p33_channel_init(idt82p33, index);
1245e014ae39SMin Li 	if (err) {
1246013a3e7cSMin Li 		dev_err(idt82p33->dev,
1247e014ae39SMin Li 			"Channel_init failed in %s with err %d!\n",
1248e014ae39SMin Li 			__func__, err);
124957a10d8cSMin Li 		return err;
1250e014ae39SMin Li 	}
125157a10d8cSMin Li 
1252*ad3cc776SMin Li 	idt82p33_caps_init(index, &channel->caps,
1253*ad3cc776SMin Li 			   pin_config[index], MAX_TRIG_CLK);
125457a10d8cSMin Li 
125557a10d8cSMin Li 	channel->ptp_clock = ptp_clock_register(&channel->caps, NULL);
125657a10d8cSMin Li 
125757a10d8cSMin Li 	if (IS_ERR(channel->ptp_clock)) {
125857a10d8cSMin Li 		err = PTR_ERR(channel->ptp_clock);
125957a10d8cSMin Li 		channel->ptp_clock = NULL;
126057a10d8cSMin Li 		return err;
126157a10d8cSMin Li 	}
126257a10d8cSMin Li 
126357a10d8cSMin Li 	if (!channel->ptp_clock)
126457a10d8cSMin Li 		return -ENOTSUPP;
126557a10d8cSMin Li 
1266e014ae39SMin Li 	err = idt82p33_dpll_set_mode(channel, PLL_MODE_DCO);
1267e014ae39SMin Li 	if (err) {
1268013a3e7cSMin Li 		dev_err(idt82p33->dev,
1269e014ae39SMin Li 			"Dpll_set_mode failed in %s with err %d!\n",
1270e014ae39SMin Li 			__func__, err);
1271e014ae39SMin Li 		return err;
1272e014ae39SMin Li 	}
1273e014ae39SMin Li 
1274e014ae39SMin Li 	err = idt82p33_enable_tod(channel);
1275e014ae39SMin Li 	if (err) {
1276013a3e7cSMin Li 		dev_err(idt82p33->dev,
1277e014ae39SMin Li 			"Enable_tod failed in %s with err %d!\n",
1278e014ae39SMin Li 			__func__, err);
1279e014ae39SMin Li 		return err;
1280e014ae39SMin Li 	}
1281e014ae39SMin Li 
1282013a3e7cSMin Li 	dev_info(idt82p33->dev, "PLL%d registered as ptp%d\n",
128357a10d8cSMin Li 		 index, channel->ptp_clock->index);
128457a10d8cSMin Li 
128557a10d8cSMin Li 	return 0;
128657a10d8cSMin Li }
128757a10d8cSMin Li 
1288*ad3cc776SMin Li static int idt82p33_reset(struct idt82p33 *idt82p33, bool cold)
1289*ad3cc776SMin Li {
1290*ad3cc776SMin Li 	int err;
1291*ad3cc776SMin Li 	u8 cfg = SOFT_RESET_EN;
1292*ad3cc776SMin Li 
1293*ad3cc776SMin Li 	if (cold == true)
1294*ad3cc776SMin Li 		goto cold_reset;
1295*ad3cc776SMin Li 
1296*ad3cc776SMin Li 	err = idt82p33_read(idt82p33, REG_SOFT_RESET, &cfg, sizeof(cfg));
1297*ad3cc776SMin Li 	if (err) {
1298*ad3cc776SMin Li 		dev_err(idt82p33->dev,
1299*ad3cc776SMin Li 			"Soft reset failed with err %d!\n", err);
1300*ad3cc776SMin Li 		return err;
1301*ad3cc776SMin Li 	}
1302*ad3cc776SMin Li 
1303*ad3cc776SMin Li 	cfg |= SOFT_RESET_EN;
1304*ad3cc776SMin Li 
1305*ad3cc776SMin Li cold_reset:
1306*ad3cc776SMin Li 	err = idt82p33_write(idt82p33, REG_SOFT_RESET, &cfg, sizeof(cfg));
1307*ad3cc776SMin Li 	if (err)
1308*ad3cc776SMin Li 		dev_err(idt82p33->dev,
1309*ad3cc776SMin Li 			"Cold reset failed with err %d!\n", err);
1310*ad3cc776SMin Li 	return err;
1311*ad3cc776SMin Li }
1312*ad3cc776SMin Li 
131357a10d8cSMin Li static int idt82p33_load_firmware(struct idt82p33 *idt82p33)
131457a10d8cSMin Li {
1315*ad3cc776SMin Li 	char fname[128] = FW_FILENAME;
131657a10d8cSMin Li 	const struct firmware *fw;
131757a10d8cSMin Li 	struct idt82p33_fwrc *rec;
131857a10d8cSMin Li 	u8 loaddr, page, val;
131957a10d8cSMin Li 	int err;
132057a10d8cSMin Li 	s32 len;
132157a10d8cSMin Li 
1322*ad3cc776SMin Li 	if (firmware) /* module parameter */
1323*ad3cc776SMin Li 		snprintf(fname, sizeof(fname), "%s", firmware);
132457a10d8cSMin Li 
1325*ad3cc776SMin Li 	dev_info(idt82p33->dev, "requesting firmware '%s'\n", fname);
1326*ad3cc776SMin Li 
1327*ad3cc776SMin Li 	err = request_firmware(&fw, fname, idt82p33->dev);
132857a10d8cSMin Li 
1329e014ae39SMin Li 	if (err) {
1330013a3e7cSMin Li 		dev_err(idt82p33->dev,
1331e014ae39SMin Li 			"Failed in %s with err %d!\n", __func__, err);
133257a10d8cSMin Li 		return err;
1333e014ae39SMin Li 	}
133457a10d8cSMin Li 
1335013a3e7cSMin Li 	dev_dbg(idt82p33->dev, "firmware size %zu bytes\n", fw->size);
133657a10d8cSMin Li 
133757a10d8cSMin Li 	rec = (struct idt82p33_fwrc *) fw->data;
133857a10d8cSMin Li 
133957a10d8cSMin Li 	for (len = fw->size; len > 0; len -= sizeof(*rec)) {
134057a10d8cSMin Li 
134157a10d8cSMin Li 		if (rec->reserved) {
1342013a3e7cSMin Li 			dev_err(idt82p33->dev,
134357a10d8cSMin Li 				"bad firmware, reserved field non-zero\n");
134457a10d8cSMin Li 			err = -EINVAL;
134557a10d8cSMin Li 		} else {
134657a10d8cSMin Li 			val = rec->value;
134757a10d8cSMin Li 			loaddr = rec->loaddr;
134857a10d8cSMin Li 			page = rec->hiaddr;
134957a10d8cSMin Li 
135057a10d8cSMin Li 			rec++;
135157a10d8cSMin Li 
135257a10d8cSMin Li 			err = idt82p33_check_and_set_masks(idt82p33, page,
135357a10d8cSMin Li 							   loaddr, val);
135457a10d8cSMin Li 		}
135557a10d8cSMin Li 
135657a10d8cSMin Li 		if (err == 0) {
135757a10d8cSMin Li 			/* Page size 128, last 4 bytes of page skipped */
1358013a3e7cSMin Li 			if (loaddr > 0x7b)
135957a10d8cSMin Li 				continue;
136057a10d8cSMin Li 
1361013a3e7cSMin Li 			err = idt82p33_write(idt82p33, REG_ADDR(page, loaddr),
136257a10d8cSMin Li 					     &val, sizeof(val));
136357a10d8cSMin Li 		}
136457a10d8cSMin Li 
136557a10d8cSMin Li 		if (err)
136657a10d8cSMin Li 			goto out;
136757a10d8cSMin Li 	}
136857a10d8cSMin Li 
136957a10d8cSMin Li 	idt82p33_display_masks(idt82p33);
137057a10d8cSMin Li out:
137157a10d8cSMin Li 	release_firmware(fw);
137257a10d8cSMin Li 	return err;
137357a10d8cSMin Li }
137457a10d8cSMin Li 
1375*ad3cc776SMin Li static void idt82p33_extts_check(struct work_struct *work)
1376*ad3cc776SMin Li {
1377*ad3cc776SMin Li 	struct idt82p33 *idt82p33 = container_of(work, struct idt82p33,
1378*ad3cc776SMin Li 						 extts_work.work);
1379*ad3cc776SMin Li 	struct idt82p33_channel *channel;
1380*ad3cc776SMin Li 	int err;
1381*ad3cc776SMin Li 	u8 mask;
1382*ad3cc776SMin Li 	int i;
1383*ad3cc776SMin Li 
1384*ad3cc776SMin Li 	if (idt82p33->extts_mask == 0)
1385*ad3cc776SMin Li 		return;
1386*ad3cc776SMin Li 
1387*ad3cc776SMin Li 	mutex_lock(idt82p33->lock);
1388*ad3cc776SMin Li 
1389*ad3cc776SMin Li 	for (i = 0; i < MAX_PHC_PLL; i++) {
1390*ad3cc776SMin Li 		mask = 1 << i;
1391*ad3cc776SMin Li 
1392*ad3cc776SMin Li 		if ((idt82p33->extts_mask & mask) == 0)
1393*ad3cc776SMin Li 			continue;
1394*ad3cc776SMin Li 
1395*ad3cc776SMin Li 		err = idt82p33_extts_check_channel(idt82p33, i);
1396*ad3cc776SMin Li 
1397*ad3cc776SMin Li 		if (err == 0) {
1398*ad3cc776SMin Li 			/* trigger clears itself, so clear the mask */
1399*ad3cc776SMin Li 			if (idt82p33->extts_single_shot) {
1400*ad3cc776SMin Li 				idt82p33->extts_mask &= ~mask;
1401*ad3cc776SMin Li 			} else {
1402*ad3cc776SMin Li 				/* Re-arm */
1403*ad3cc776SMin Li 				channel = &idt82p33->channel[i];
1404*ad3cc776SMin Li 				arm_tod_read_with_trigger(channel, channel->tod_trigger);
1405*ad3cc776SMin Li 			}
1406*ad3cc776SMin Li 		}
1407*ad3cc776SMin Li 	}
1408*ad3cc776SMin Li 
1409*ad3cc776SMin Li 	if (idt82p33->extts_mask)
1410*ad3cc776SMin Li 		schedule_delayed_work(&idt82p33->extts_work,
1411*ad3cc776SMin Li 				      msecs_to_jiffies(EXTTS_PERIOD_MS));
1412*ad3cc776SMin Li 
1413*ad3cc776SMin Li 	mutex_unlock(idt82p33->lock);
1414*ad3cc776SMin Li }
141557a10d8cSMin Li 
1416013a3e7cSMin Li static int idt82p33_probe(struct platform_device *pdev)
141757a10d8cSMin Li {
1418013a3e7cSMin Li 	struct rsmu_ddata *ddata = dev_get_drvdata(pdev->dev.parent);
141957a10d8cSMin Li 	struct idt82p33 *idt82p33;
142057a10d8cSMin Li 	int err;
142157a10d8cSMin Li 	u8 i;
142257a10d8cSMin Li 
1423013a3e7cSMin Li 	idt82p33 = devm_kzalloc(&pdev->dev,
142457a10d8cSMin Li 				sizeof(struct idt82p33), GFP_KERNEL);
142557a10d8cSMin Li 	if (!idt82p33)
142657a10d8cSMin Li 		return -ENOMEM;
142757a10d8cSMin Li 
1428013a3e7cSMin Li 	idt82p33->dev = &pdev->dev;
1429013a3e7cSMin Li 	idt82p33->mfd = pdev->dev.parent;
1430013a3e7cSMin Li 	idt82p33->lock = &ddata->lock;
1431013a3e7cSMin Li 	idt82p33->regmap = ddata->regmap;
143257a10d8cSMin Li 	idt82p33->tod_write_overhead_ns = 0;
143357a10d8cSMin Li 	idt82p33->calculate_overhead_flag = 0;
143457a10d8cSMin Li 	idt82p33->pll_mask = DEFAULT_PLL_MASK;
143557a10d8cSMin Li 	idt82p33->channel[0].output_mask = DEFAULT_OUTPUT_MASK_PLL0;
143657a10d8cSMin Li 	idt82p33->channel[1].output_mask = DEFAULT_OUTPUT_MASK_PLL1;
1437*ad3cc776SMin Li 	idt82p33->extts_mask = 0;
1438*ad3cc776SMin Li 	INIT_DELAYED_WORK(&idt82p33->extts_work, idt82p33_extts_check);
143957a10d8cSMin Li 
1440013a3e7cSMin Li 	mutex_lock(idt82p33->lock);
144157a10d8cSMin Li 
1442*ad3cc776SMin Li 	/* cold reset before loading firmware */
1443*ad3cc776SMin Li 	idt82p33_reset(idt82p33, true);
144457a10d8cSMin Li 
1445*ad3cc776SMin Li 	err = idt82p33_load_firmware(idt82p33);
144657a10d8cSMin Li 	if (err)
1447013a3e7cSMin Li 		dev_warn(idt82p33->dev,
144857a10d8cSMin Li 			 "loading firmware failed with %d\n", err);
144957a10d8cSMin Li 
1450*ad3cc776SMin Li 	/* soft reset after loading firmware */
1451*ad3cc776SMin Li 	idt82p33_reset(idt82p33, false);
1452*ad3cc776SMin Li 
145357a10d8cSMin Li 	if (idt82p33->pll_mask) {
145457a10d8cSMin Li 		for (i = 0; i < MAX_PHC_PLL; i++) {
1455*ad3cc776SMin Li 			if (idt82p33->pll_mask & (1 << i))
145657a10d8cSMin Li 				err = idt82p33_enable_channel(idt82p33, i);
1457*ad3cc776SMin Li 			else
1458*ad3cc776SMin Li 				err = idt82p33_channel_init(idt82p33, i);
1459e014ae39SMin Li 			if (err) {
1460013a3e7cSMin Li 				dev_err(idt82p33->dev,
1461e014ae39SMin Li 					"Failed in %s with err %d!\n",
1462e014ae39SMin Li 					__func__, err);
146357a10d8cSMin Li 				break;
146457a10d8cSMin Li 			}
146557a10d8cSMin Li 		}
146657a10d8cSMin Li 	} else {
1467013a3e7cSMin Li 		dev_err(idt82p33->dev,
146857a10d8cSMin Li 			"no PLLs flagged as PHCs, nothing to do\n");
146957a10d8cSMin Li 		err = -ENODEV;
147057a10d8cSMin Li 	}
147157a10d8cSMin Li 
1472013a3e7cSMin Li 	mutex_unlock(idt82p33->lock);
147357a10d8cSMin Li 
147457a10d8cSMin Li 	if (err) {
147557a10d8cSMin Li 		idt82p33_ptp_clock_unregister_all(idt82p33);
147657a10d8cSMin Li 		return err;
147757a10d8cSMin Li 	}
147857a10d8cSMin Li 
1479013a3e7cSMin Li 	platform_set_drvdata(pdev, idt82p33);
148057a10d8cSMin Li 
148157a10d8cSMin Li 	return 0;
148257a10d8cSMin Li }
148357a10d8cSMin Li 
1484013a3e7cSMin Li static int idt82p33_remove(struct platform_device *pdev)
148557a10d8cSMin Li {
1486013a3e7cSMin Li 	struct idt82p33 *idt82p33 = platform_get_drvdata(pdev);
148757a10d8cSMin Li 
1488*ad3cc776SMin Li 	cancel_delayed_work_sync(&idt82p33->extts_work);
1489*ad3cc776SMin Li 
149057a10d8cSMin Li 	idt82p33_ptp_clock_unregister_all(idt82p33);
149157a10d8cSMin Li 
149257a10d8cSMin Li 	return 0;
149357a10d8cSMin Li }
149457a10d8cSMin Li 
1495013a3e7cSMin Li static struct platform_driver idt82p33_driver = {
149657a10d8cSMin Li 	.driver = {
1497013a3e7cSMin Li 		.name = "82p33x1x-phc",
149857a10d8cSMin Li 	},
149957a10d8cSMin Li 	.probe = idt82p33_probe,
150057a10d8cSMin Li 	.remove	= idt82p33_remove,
150157a10d8cSMin Li };
150257a10d8cSMin Li 
1503013a3e7cSMin Li module_platform_driver(idt82p33_driver);
1504