162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci//
362306a36Sopenharmony_ci// Copyright (C) 2018 Integrated Device Technology, Inc
462306a36Sopenharmony_ci//
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#define pr_fmt(fmt) "IDT_82p33xxx: " fmt
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/firmware.h>
962306a36Sopenharmony_ci#include <linux/platform_device.h>
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <linux/ptp_clock_kernel.h>
1262306a36Sopenharmony_ci#include <linux/delay.h>
1362306a36Sopenharmony_ci#include <linux/jiffies.h>
1462306a36Sopenharmony_ci#include <linux/kernel.h>
1562306a36Sopenharmony_ci#include <linux/timekeeping.h>
1662306a36Sopenharmony_ci#include <linux/bitops.h>
1762306a36Sopenharmony_ci#include <linux/of.h>
1862306a36Sopenharmony_ci#include <linux/mfd/rsmu.h>
1962306a36Sopenharmony_ci#include <linux/mfd/idt82p33_reg.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include "ptp_private.h"
2262306a36Sopenharmony_ci#include "ptp_idt82p33.h"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ciMODULE_DESCRIPTION("Driver for IDT 82p33xxx clock devices");
2562306a36Sopenharmony_ciMODULE_AUTHOR("IDT support-1588 <IDT-support-1588@lm.renesas.com>");
2662306a36Sopenharmony_ciMODULE_VERSION("1.0");
2762306a36Sopenharmony_ciMODULE_LICENSE("GPL");
2862306a36Sopenharmony_ciMODULE_FIRMWARE(FW_FILENAME);
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define EXTTS_PERIOD_MS (95)
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/* Module Parameters */
3362306a36Sopenharmony_cistatic u32 phase_snap_threshold = SNAP_THRESHOLD_NS;
3462306a36Sopenharmony_cimodule_param(phase_snap_threshold, uint, 0);
3562306a36Sopenharmony_ciMODULE_PARM_DESC(phase_snap_threshold,
3662306a36Sopenharmony_ci"threshold (10000ns by default) below which adjtime would use double dco");
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic char *firmware;
3962306a36Sopenharmony_cimodule_param(firmware, charp, 0);
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistatic struct ptp_pin_desc pin_config[MAX_PHC_PLL][MAX_TRIG_CLK];
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic inline int idt82p33_read(struct idt82p33 *idt82p33, u16 regaddr,
4462306a36Sopenharmony_ci				u8 *buf, u16 count)
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci	return regmap_bulk_read(idt82p33->regmap, regaddr, buf, count);
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic inline int idt82p33_write(struct idt82p33 *idt82p33, u16 regaddr,
5062306a36Sopenharmony_ci				 u8 *buf, u16 count)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	return regmap_bulk_write(idt82p33->regmap, regaddr, buf, count);
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic void idt82p33_byte_array_to_timespec(struct timespec64 *ts,
5662306a36Sopenharmony_ci					    u8 buf[TOD_BYTE_COUNT])
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	time64_t sec;
5962306a36Sopenharmony_ci	s32 nsec;
6062306a36Sopenharmony_ci	u8 i;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	nsec = buf[3];
6362306a36Sopenharmony_ci	for (i = 0; i < 3; i++) {
6462306a36Sopenharmony_ci		nsec <<= 8;
6562306a36Sopenharmony_ci		nsec |= buf[2 - i];
6662306a36Sopenharmony_ci	}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	sec = buf[9];
6962306a36Sopenharmony_ci	for (i = 0; i < 5; i++) {
7062306a36Sopenharmony_ci		sec <<= 8;
7162306a36Sopenharmony_ci		sec |= buf[8 - i];
7262306a36Sopenharmony_ci	}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	ts->tv_sec = sec;
7562306a36Sopenharmony_ci	ts->tv_nsec = nsec;
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic void idt82p33_timespec_to_byte_array(struct timespec64 const *ts,
7962306a36Sopenharmony_ci					    u8 buf[TOD_BYTE_COUNT])
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	time64_t sec;
8262306a36Sopenharmony_ci	s32 nsec;
8362306a36Sopenharmony_ci	u8 i;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	nsec = ts->tv_nsec;
8662306a36Sopenharmony_ci	sec = ts->tv_sec;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
8962306a36Sopenharmony_ci		buf[i] = nsec & 0xff;
9062306a36Sopenharmony_ci		nsec >>= 8;
9162306a36Sopenharmony_ci	}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	for (i = 4; i < TOD_BYTE_COUNT; i++) {
9462306a36Sopenharmony_ci		buf[i] = sec & 0xff;
9562306a36Sopenharmony_ci		sec >>= 8;
9662306a36Sopenharmony_ci	}
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistatic int idt82p33_dpll_set_mode(struct idt82p33_channel *channel,
10062306a36Sopenharmony_ci				  enum pll_mode mode)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	struct idt82p33 *idt82p33 = channel->idt82p33;
10362306a36Sopenharmony_ci	u8 dpll_mode;
10462306a36Sopenharmony_ci	int err;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	if (channel->pll_mode == mode)
10762306a36Sopenharmony_ci		return 0;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	err = idt82p33_read(idt82p33, channel->dpll_mode_cnfg,
11062306a36Sopenharmony_ci			    &dpll_mode, sizeof(dpll_mode));
11162306a36Sopenharmony_ci	if (err)
11262306a36Sopenharmony_ci		return err;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	dpll_mode &= ~(PLL_MODE_MASK << PLL_MODE_SHIFT);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	dpll_mode |= (mode << PLL_MODE_SHIFT);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	err = idt82p33_write(idt82p33, channel->dpll_mode_cnfg,
11962306a36Sopenharmony_ci			     &dpll_mode, sizeof(dpll_mode));
12062306a36Sopenharmony_ci	if (err)
12162306a36Sopenharmony_ci		return err;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	channel->pll_mode = mode;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	return 0;
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic int idt82p33_set_tod_trigger(struct idt82p33_channel *channel,
12962306a36Sopenharmony_ci				    u8 trigger, bool write)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	struct idt82p33 *idt82p33 = channel->idt82p33;
13262306a36Sopenharmony_ci	int err;
13362306a36Sopenharmony_ci	u8 cfg;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	if (trigger > WR_TRIG_SEL_MAX)
13662306a36Sopenharmony_ci		return -EINVAL;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	err = idt82p33_read(idt82p33, channel->dpll_tod_trigger,
13962306a36Sopenharmony_ci			    &cfg, sizeof(cfg));
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	if (err)
14262306a36Sopenharmony_ci		return err;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	if (write == true)
14562306a36Sopenharmony_ci		trigger = (trigger << WRITE_TRIGGER_SHIFT) |
14662306a36Sopenharmony_ci			  (cfg & READ_TRIGGER_MASK);
14762306a36Sopenharmony_ci	else
14862306a36Sopenharmony_ci		trigger = (trigger << READ_TRIGGER_SHIFT) |
14962306a36Sopenharmony_ci			  (cfg & WRITE_TRIGGER_MASK);
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	return idt82p33_write(idt82p33, channel->dpll_tod_trigger,
15262306a36Sopenharmony_ci			      &trigger, sizeof(trigger));
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistatic int idt82p33_get_extts(struct idt82p33_channel *channel,
15662306a36Sopenharmony_ci			      struct timespec64 *ts)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	struct idt82p33 *idt82p33 = channel->idt82p33;
15962306a36Sopenharmony_ci	u8 buf[TOD_BYTE_COUNT];
16062306a36Sopenharmony_ci	int err;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	err = idt82p33_read(idt82p33, channel->dpll_tod_sts, buf, sizeof(buf));
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	if (err)
16562306a36Sopenharmony_ci		return err;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	/* Since trigger is not self clearing itself, we have to poll tod_sts */
16862306a36Sopenharmony_ci	if (memcmp(buf, channel->extts_tod_sts, TOD_BYTE_COUNT) == 0)
16962306a36Sopenharmony_ci		return -EAGAIN;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	memcpy(channel->extts_tod_sts, buf, TOD_BYTE_COUNT);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	idt82p33_byte_array_to_timespec(ts, buf);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	if (channel->discard_next_extts) {
17662306a36Sopenharmony_ci		channel->discard_next_extts = false;
17762306a36Sopenharmony_ci		return -EAGAIN;
17862306a36Sopenharmony_ci	}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	return 0;
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic int map_ref_to_tod_trig_sel(int ref, u8 *trigger)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	int err = 0;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	switch (ref) {
18862306a36Sopenharmony_ci	case 0:
18962306a36Sopenharmony_ci		*trigger = HW_TOD_TRIG_SEL_IN12;
19062306a36Sopenharmony_ci		break;
19162306a36Sopenharmony_ci	case 1:
19262306a36Sopenharmony_ci		*trigger = HW_TOD_TRIG_SEL_IN13;
19362306a36Sopenharmony_ci		break;
19462306a36Sopenharmony_ci	case 2:
19562306a36Sopenharmony_ci		*trigger = HW_TOD_TRIG_SEL_IN14;
19662306a36Sopenharmony_ci		break;
19762306a36Sopenharmony_ci	default:
19862306a36Sopenharmony_ci		err = -EINVAL;
19962306a36Sopenharmony_ci	}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	return err;
20262306a36Sopenharmony_ci}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_cistatic bool is_one_shot(u8 mask)
20562306a36Sopenharmony_ci{
20662306a36Sopenharmony_ci	/* Treat single bit PLL masks as continuous trigger */
20762306a36Sopenharmony_ci	if ((mask == 1) || (mask == 2))
20862306a36Sopenharmony_ci		return false;
20962306a36Sopenharmony_ci	else
21062306a36Sopenharmony_ci		return true;
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_cistatic int arm_tod_read_with_trigger(struct idt82p33_channel *channel, u8 trigger)
21462306a36Sopenharmony_ci{
21562306a36Sopenharmony_ci	struct idt82p33 *idt82p33 = channel->idt82p33;
21662306a36Sopenharmony_ci	u8 buf[TOD_BYTE_COUNT];
21762306a36Sopenharmony_ci	int err;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	/* Remember the current tod_sts before setting the trigger */
22062306a36Sopenharmony_ci	err = idt82p33_read(idt82p33, channel->dpll_tod_sts, buf, sizeof(buf));
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	if (err)
22362306a36Sopenharmony_ci		return err;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	memcpy(channel->extts_tod_sts, buf, TOD_BYTE_COUNT);
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	err = idt82p33_set_tod_trigger(channel, trigger, false);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	if (err)
23062306a36Sopenharmony_ci		dev_err(idt82p33->dev, "%s: err = %d", __func__, err);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	return err;
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cistatic int idt82p33_extts_enable(struct idt82p33_channel *channel,
23662306a36Sopenharmony_ci				 struct ptp_clock_request *rq, int on)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci	u8 index = rq->extts.index;
23962306a36Sopenharmony_ci	struct idt82p33 *idt82p33;
24062306a36Sopenharmony_ci	u8 mask = 1 << index;
24162306a36Sopenharmony_ci	int err = 0;
24262306a36Sopenharmony_ci	u8 old_mask;
24362306a36Sopenharmony_ci	u8 trigger;
24462306a36Sopenharmony_ci	int ref;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	idt82p33  = channel->idt82p33;
24762306a36Sopenharmony_ci	old_mask = idt82p33->extts_mask;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	/* Reject requests with unsupported flags */
25062306a36Sopenharmony_ci	if (rq->extts.flags & ~(PTP_ENABLE_FEATURE |
25162306a36Sopenharmony_ci				PTP_RISING_EDGE |
25262306a36Sopenharmony_ci				PTP_FALLING_EDGE |
25362306a36Sopenharmony_ci				PTP_STRICT_FLAGS))
25462306a36Sopenharmony_ci		return -EOPNOTSUPP;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	/* Reject requests to enable time stamping on falling edge */
25762306a36Sopenharmony_ci	if ((rq->extts.flags & PTP_ENABLE_FEATURE) &&
25862306a36Sopenharmony_ci	    (rq->extts.flags & PTP_FALLING_EDGE))
25962306a36Sopenharmony_ci		return -EOPNOTSUPP;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	if (index >= MAX_PHC_PLL)
26262306a36Sopenharmony_ci		return -EINVAL;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	if (on) {
26562306a36Sopenharmony_ci		/* Return if it was already enabled */
26662306a36Sopenharmony_ci		if (idt82p33->extts_mask & mask)
26762306a36Sopenharmony_ci			return 0;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci		/* Use the pin configured for the channel */
27062306a36Sopenharmony_ci		ref = ptp_find_pin(channel->ptp_clock, PTP_PF_EXTTS, channel->plln);
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci		if (ref < 0) {
27362306a36Sopenharmony_ci			dev_err(idt82p33->dev, "%s: No valid pin found for Pll%d!\n",
27462306a36Sopenharmony_ci				__func__, channel->plln);
27562306a36Sopenharmony_ci			return -EBUSY;
27662306a36Sopenharmony_ci		}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci		err = map_ref_to_tod_trig_sel(ref, &trigger);
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci		if (err) {
28162306a36Sopenharmony_ci			dev_err(idt82p33->dev,
28262306a36Sopenharmony_ci				"%s: Unsupported ref %d!\n", __func__, ref);
28362306a36Sopenharmony_ci			return err;
28462306a36Sopenharmony_ci		}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci		err = arm_tod_read_with_trigger(&idt82p33->channel[index], trigger);
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci		if (err == 0) {
28962306a36Sopenharmony_ci			idt82p33->extts_mask |= mask;
29062306a36Sopenharmony_ci			idt82p33->channel[index].tod_trigger = trigger;
29162306a36Sopenharmony_ci			idt82p33->event_channel[index] = channel;
29262306a36Sopenharmony_ci			idt82p33->extts_single_shot = is_one_shot(idt82p33->extts_mask);
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci			if (old_mask)
29562306a36Sopenharmony_ci				return 0;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci			schedule_delayed_work(&idt82p33->extts_work,
29862306a36Sopenharmony_ci					      msecs_to_jiffies(EXTTS_PERIOD_MS));
29962306a36Sopenharmony_ci		}
30062306a36Sopenharmony_ci	} else {
30162306a36Sopenharmony_ci		idt82p33->extts_mask &= ~mask;
30262306a36Sopenharmony_ci		idt82p33->extts_single_shot = is_one_shot(idt82p33->extts_mask);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci		if (idt82p33->extts_mask == 0)
30562306a36Sopenharmony_ci			cancel_delayed_work(&idt82p33->extts_work);
30662306a36Sopenharmony_ci	}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	return err;
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic int idt82p33_extts_check_channel(struct idt82p33 *idt82p33, u8 todn)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	struct idt82p33_channel *event_channel;
31462306a36Sopenharmony_ci	struct ptp_clock_event event;
31562306a36Sopenharmony_ci	struct timespec64 ts;
31662306a36Sopenharmony_ci	int err;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	err = idt82p33_get_extts(&idt82p33->channel[todn], &ts);
31962306a36Sopenharmony_ci	if (err == 0) {
32062306a36Sopenharmony_ci		event_channel = idt82p33->event_channel[todn];
32162306a36Sopenharmony_ci		event.type = PTP_CLOCK_EXTTS;
32262306a36Sopenharmony_ci		event.index = todn;
32362306a36Sopenharmony_ci		event.timestamp = timespec64_to_ns(&ts);
32462306a36Sopenharmony_ci		ptp_clock_event(event_channel->ptp_clock,
32562306a36Sopenharmony_ci				&event);
32662306a36Sopenharmony_ci	}
32762306a36Sopenharmony_ci	return err;
32862306a36Sopenharmony_ci}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_cistatic u8 idt82p33_extts_enable_mask(struct idt82p33_channel *channel,
33162306a36Sopenharmony_ci				     u8 extts_mask, bool enable)
33262306a36Sopenharmony_ci{
33362306a36Sopenharmony_ci	struct idt82p33 *idt82p33 = channel->idt82p33;
33462306a36Sopenharmony_ci	u8 trigger = channel->tod_trigger;
33562306a36Sopenharmony_ci	u8 mask;
33662306a36Sopenharmony_ci	int err;
33762306a36Sopenharmony_ci	int i;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	if (extts_mask == 0)
34062306a36Sopenharmony_ci		return 0;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	if (enable == false)
34362306a36Sopenharmony_ci		cancel_delayed_work_sync(&idt82p33->extts_work);
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	for (i = 0; i < MAX_PHC_PLL; i++) {
34662306a36Sopenharmony_ci		mask = 1 << i;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci		if ((extts_mask & mask) == 0)
34962306a36Sopenharmony_ci			continue;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci		if (enable) {
35262306a36Sopenharmony_ci			err = arm_tod_read_with_trigger(&idt82p33->channel[i], trigger);
35362306a36Sopenharmony_ci			if (err)
35462306a36Sopenharmony_ci				dev_err(idt82p33->dev,
35562306a36Sopenharmony_ci					"%s: Arm ToD read trigger failed, err = %d",
35662306a36Sopenharmony_ci					__func__, err);
35762306a36Sopenharmony_ci		} else {
35862306a36Sopenharmony_ci			err = idt82p33_extts_check_channel(idt82p33, i);
35962306a36Sopenharmony_ci			if (err == 0 && idt82p33->extts_single_shot)
36062306a36Sopenharmony_ci				/* trigger happened so we won't re-enable it */
36162306a36Sopenharmony_ci				extts_mask &= ~mask;
36262306a36Sopenharmony_ci		}
36362306a36Sopenharmony_ci	}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	if (enable)
36662306a36Sopenharmony_ci		schedule_delayed_work(&idt82p33->extts_work,
36762306a36Sopenharmony_ci				      msecs_to_jiffies(EXTTS_PERIOD_MS));
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	return extts_mask;
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic int _idt82p33_gettime(struct idt82p33_channel *channel,
37362306a36Sopenharmony_ci			     struct timespec64 *ts)
37462306a36Sopenharmony_ci{
37562306a36Sopenharmony_ci	struct idt82p33 *idt82p33 = channel->idt82p33;
37662306a36Sopenharmony_ci	u8 old_mask = idt82p33->extts_mask;
37762306a36Sopenharmony_ci	u8 buf[TOD_BYTE_COUNT];
37862306a36Sopenharmony_ci	u8 new_mask = 0;
37962306a36Sopenharmony_ci	int err;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	/* Disable extts */
38262306a36Sopenharmony_ci	if (old_mask)
38362306a36Sopenharmony_ci		new_mask = idt82p33_extts_enable_mask(channel, old_mask, false);
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	err = idt82p33_set_tod_trigger(channel, HW_TOD_RD_TRIG_SEL_LSB_TOD_STS,
38662306a36Sopenharmony_ci				       false);
38762306a36Sopenharmony_ci	if (err)
38862306a36Sopenharmony_ci		return err;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	channel->discard_next_extts = true;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	if (idt82p33->calculate_overhead_flag)
39362306a36Sopenharmony_ci		idt82p33->start_time = ktime_get_raw();
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	err = idt82p33_read(idt82p33, channel->dpll_tod_sts, buf, sizeof(buf));
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	if (err)
39862306a36Sopenharmony_ci		return err;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	/* Re-enable extts */
40162306a36Sopenharmony_ci	if (new_mask)
40262306a36Sopenharmony_ci		idt82p33_extts_enable_mask(channel, new_mask, true);
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	idt82p33_byte_array_to_timespec(ts, buf);
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	return 0;
40762306a36Sopenharmony_ci}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci/*
41062306a36Sopenharmony_ci *   TOD Trigger:
41162306a36Sopenharmony_ci *   Bits[7:4] Write 0x9, MSB write
41262306a36Sopenharmony_ci *   Bits[3:0] Read 0x9, LSB read
41362306a36Sopenharmony_ci */
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_cistatic int _idt82p33_settime(struct idt82p33_channel *channel,
41662306a36Sopenharmony_ci			     struct timespec64 const *ts)
41762306a36Sopenharmony_ci{
41862306a36Sopenharmony_ci	struct idt82p33 *idt82p33 = channel->idt82p33;
41962306a36Sopenharmony_ci	struct timespec64 local_ts = *ts;
42062306a36Sopenharmony_ci	char buf[TOD_BYTE_COUNT];
42162306a36Sopenharmony_ci	s64 dynamic_overhead_ns;
42262306a36Sopenharmony_ci	int err;
42362306a36Sopenharmony_ci	u8 i;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	err = idt82p33_set_tod_trigger(channel, HW_TOD_WR_TRIG_SEL_MSB_TOD_CNFG,
42662306a36Sopenharmony_ci				       true);
42762306a36Sopenharmony_ci	if (err)
42862306a36Sopenharmony_ci		return err;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	channel->discard_next_extts = true;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	if (idt82p33->calculate_overhead_flag) {
43362306a36Sopenharmony_ci		dynamic_overhead_ns = ktime_to_ns(ktime_get_raw())
43462306a36Sopenharmony_ci					- ktime_to_ns(idt82p33->start_time);
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci		timespec64_add_ns(&local_ts, dynamic_overhead_ns);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci		idt82p33->calculate_overhead_flag = 0;
43962306a36Sopenharmony_ci	}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	idt82p33_timespec_to_byte_array(&local_ts, buf);
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	/*
44462306a36Sopenharmony_ci	 * Store the new time value.
44562306a36Sopenharmony_ci	 */
44662306a36Sopenharmony_ci	for (i = 0; i < TOD_BYTE_COUNT; i++) {
44762306a36Sopenharmony_ci		err = idt82p33_write(idt82p33, channel->dpll_tod_cnfg + i,
44862306a36Sopenharmony_ci				     &buf[i], sizeof(buf[i]));
44962306a36Sopenharmony_ci		if (err)
45062306a36Sopenharmony_ci			return err;
45162306a36Sopenharmony_ci	}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	return err;
45462306a36Sopenharmony_ci}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_cistatic int _idt82p33_adjtime_immediate(struct idt82p33_channel *channel,
45762306a36Sopenharmony_ci				       s64 delta_ns)
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	struct idt82p33 *idt82p33 = channel->idt82p33;
46062306a36Sopenharmony_ci	struct timespec64 ts;
46162306a36Sopenharmony_ci	s64 now_ns;
46262306a36Sopenharmony_ci	int err;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	idt82p33->calculate_overhead_flag = 1;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	err = _idt82p33_gettime(channel, &ts);
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	if (err)
46962306a36Sopenharmony_ci		return err;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	now_ns = timespec64_to_ns(&ts);
47262306a36Sopenharmony_ci	now_ns += delta_ns + idt82p33->tod_write_overhead_ns;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	ts = ns_to_timespec64(now_ns);
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	err = _idt82p33_settime(channel, &ts);
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	return err;
47962306a36Sopenharmony_ci}
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_cistatic int _idt82p33_adjtime_internal_triggered(struct idt82p33_channel *channel,
48262306a36Sopenharmony_ci						s64 delta_ns)
48362306a36Sopenharmony_ci{
48462306a36Sopenharmony_ci	struct idt82p33 *idt82p33 = channel->idt82p33;
48562306a36Sopenharmony_ci	char buf[TOD_BYTE_COUNT];
48662306a36Sopenharmony_ci	struct timespec64 ts;
48762306a36Sopenharmony_ci	const u8 delay_ns = 32;
48862306a36Sopenharmony_ci	s32 remainder;
48962306a36Sopenharmony_ci	s64 ns;
49062306a36Sopenharmony_ci	int err;
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	err = _idt82p33_gettime(channel, &ts);
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	if (err)
49562306a36Sopenharmony_ci		return err;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	if (ts.tv_nsec > (NSEC_PER_SEC - 5 * NSEC_PER_MSEC)) {
49862306a36Sopenharmony_ci		/*  Too close to miss next trigger, so skip it */
49962306a36Sopenharmony_ci		mdelay(6);
50062306a36Sopenharmony_ci		ns = (ts.tv_sec + 2) * NSEC_PER_SEC + delta_ns + delay_ns;
50162306a36Sopenharmony_ci	} else
50262306a36Sopenharmony_ci		ns = (ts.tv_sec + 1) * NSEC_PER_SEC + delta_ns + delay_ns;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	ts = ns_to_timespec64(ns);
50562306a36Sopenharmony_ci	idt82p33_timespec_to_byte_array(&ts, buf);
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	/*
50862306a36Sopenharmony_ci	 * Store the new time value.
50962306a36Sopenharmony_ci	 */
51062306a36Sopenharmony_ci	err = idt82p33_write(idt82p33, channel->dpll_tod_cnfg, buf, sizeof(buf));
51162306a36Sopenharmony_ci	if (err)
51262306a36Sopenharmony_ci		return err;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	/* Schedule to implement the workaround in one second */
51562306a36Sopenharmony_ci	(void)div_s64_rem(delta_ns, NSEC_PER_SEC, &remainder);
51662306a36Sopenharmony_ci	if (remainder != 0)
51762306a36Sopenharmony_ci		schedule_delayed_work(&channel->adjtime_work, HZ);
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	return idt82p33_set_tod_trigger(channel, HW_TOD_TRIG_SEL_TOD_PPS, true);
52062306a36Sopenharmony_ci}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_cistatic void idt82p33_adjtime_workaround(struct work_struct *work)
52362306a36Sopenharmony_ci{
52462306a36Sopenharmony_ci	struct idt82p33_channel *channel = container_of(work,
52562306a36Sopenharmony_ci							struct idt82p33_channel,
52662306a36Sopenharmony_ci							adjtime_work.work);
52762306a36Sopenharmony_ci	struct idt82p33 *idt82p33 = channel->idt82p33;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	mutex_lock(idt82p33->lock);
53062306a36Sopenharmony_ci	/* Workaround for TOD-to-output alignment issue */
53162306a36Sopenharmony_ci	_idt82p33_adjtime_internal_triggered(channel, 0);
53262306a36Sopenharmony_ci	mutex_unlock(idt82p33->lock);
53362306a36Sopenharmony_ci}
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_cistatic int _idt82p33_adjfine(struct idt82p33_channel *channel, long scaled_ppm)
53662306a36Sopenharmony_ci{
53762306a36Sopenharmony_ci	struct idt82p33 *idt82p33 = channel->idt82p33;
53862306a36Sopenharmony_ci	unsigned char buf[5] = {0};
53962306a36Sopenharmony_ci	int err, i;
54062306a36Sopenharmony_ci	s64 fcw;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	/*
54362306a36Sopenharmony_ci	 * Frequency Control Word unit is: 1.6861512 * 10^-10 ppm
54462306a36Sopenharmony_ci	 *
54562306a36Sopenharmony_ci	 * adjfreq:
54662306a36Sopenharmony_ci	 *       ppb * 10^14
54762306a36Sopenharmony_ci	 * FCW = -----------
54862306a36Sopenharmony_ci	 *         16861512
54962306a36Sopenharmony_ci	 *
55062306a36Sopenharmony_ci	 * adjfine:
55162306a36Sopenharmony_ci	 *       scaled_ppm * 5^12 * 10^5
55262306a36Sopenharmony_ci	 * FCW = ------------------------
55362306a36Sopenharmony_ci	 *            16861512 * 2^4
55462306a36Sopenharmony_ci	 */
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	fcw = scaled_ppm * 762939453125ULL;
55762306a36Sopenharmony_ci	fcw = div_s64(fcw, 8430756LL);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	for (i = 0; i < 5; i++) {
56062306a36Sopenharmony_ci		buf[i] = fcw & 0xff;
56162306a36Sopenharmony_ci		fcw >>= 8;
56262306a36Sopenharmony_ci	}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	err = idt82p33_dpll_set_mode(channel, PLL_MODE_DCO);
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	if (err)
56762306a36Sopenharmony_ci		return err;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	err = idt82p33_write(idt82p33, channel->dpll_freq_cnfg,
57062306a36Sopenharmony_ci			     buf, sizeof(buf));
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	return err;
57362306a36Sopenharmony_ci}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci/* ppb = scaled_ppm * 125 / 2^13 */
57662306a36Sopenharmony_cistatic s32 idt82p33_ddco_scaled_ppm(long current_ppm, s32 ddco_ppb)
57762306a36Sopenharmony_ci{
57862306a36Sopenharmony_ci	s64 scaled_ppm = div_s64(((s64)ddco_ppb << 13), 125);
57962306a36Sopenharmony_ci	s64 max_scaled_ppm = div_s64(((s64)DCO_MAX_PPB << 13), 125);
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	current_ppm += scaled_ppm;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	if (current_ppm > max_scaled_ppm)
58462306a36Sopenharmony_ci		current_ppm = max_scaled_ppm;
58562306a36Sopenharmony_ci	else if (current_ppm < -max_scaled_ppm)
58662306a36Sopenharmony_ci		current_ppm = -max_scaled_ppm;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	return (s32)current_ppm;
58962306a36Sopenharmony_ci}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_cistatic int idt82p33_stop_ddco(struct idt82p33_channel *channel)
59262306a36Sopenharmony_ci{
59362306a36Sopenharmony_ci	int err;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	err = _idt82p33_adjfine(channel, channel->current_freq);
59662306a36Sopenharmony_ci	if (err)
59762306a36Sopenharmony_ci		return err;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	channel->ddco = false;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	return 0;
60262306a36Sopenharmony_ci}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_cistatic int idt82p33_start_ddco(struct idt82p33_channel *channel, s32 delta_ns)
60562306a36Sopenharmony_ci{
60662306a36Sopenharmony_ci	s32 current_ppm = channel->current_freq;
60762306a36Sopenharmony_ci	u32 duration_ms = MSEC_PER_SEC;
60862306a36Sopenharmony_ci	s32 ppb;
60962306a36Sopenharmony_ci	int err;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	/* If the ToD correction is less than 5 nanoseconds, then skip it.
61262306a36Sopenharmony_ci	 * The error introduced by the ToD adjustment procedure would be bigger
61362306a36Sopenharmony_ci	 * than the required ToD correction
61462306a36Sopenharmony_ci	 */
61562306a36Sopenharmony_ci	if (abs(delta_ns) < DDCO_THRESHOLD_NS)
61662306a36Sopenharmony_ci		return 0;
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	/* For most cases, keep ddco duration 1 second */
61962306a36Sopenharmony_ci	ppb = delta_ns;
62062306a36Sopenharmony_ci	while (abs(ppb) > DCO_MAX_PPB) {
62162306a36Sopenharmony_ci		duration_ms *= 2;
62262306a36Sopenharmony_ci		ppb /= 2;
62362306a36Sopenharmony_ci	}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	err = _idt82p33_adjfine(channel,
62662306a36Sopenharmony_ci				idt82p33_ddco_scaled_ppm(current_ppm, ppb));
62762306a36Sopenharmony_ci	if (err)
62862306a36Sopenharmony_ci		return err;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	/* schedule the worker to cancel ddco */
63162306a36Sopenharmony_ci	ptp_schedule_worker(channel->ptp_clock,
63262306a36Sopenharmony_ci			    msecs_to_jiffies(duration_ms) - 1);
63362306a36Sopenharmony_ci	channel->ddco = true;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	return 0;
63662306a36Sopenharmony_ci}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_cistatic int idt82p33_measure_one_byte_write_overhead(
63962306a36Sopenharmony_ci		struct idt82p33_channel *channel, s64 *overhead_ns)
64062306a36Sopenharmony_ci{
64162306a36Sopenharmony_ci	struct idt82p33 *idt82p33 = channel->idt82p33;
64262306a36Sopenharmony_ci	ktime_t start, stop;
64362306a36Sopenharmony_ci	u8 trigger = 0;
64462306a36Sopenharmony_ci	s64 total_ns;
64562306a36Sopenharmony_ci	int err;
64662306a36Sopenharmony_ci	u8 i;
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	total_ns = 0;
64962306a36Sopenharmony_ci	*overhead_ns = 0;
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	for (i = 0; i < MAX_MEASURMENT_COUNT; i++) {
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci		start = ktime_get_raw();
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci		err = idt82p33_write(idt82p33, channel->dpll_tod_trigger,
65662306a36Sopenharmony_ci				     &trigger, sizeof(trigger));
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci		stop = ktime_get_raw();
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci		if (err)
66162306a36Sopenharmony_ci			return err;
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci		total_ns += ktime_to_ns(stop) - ktime_to_ns(start);
66462306a36Sopenharmony_ci	}
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	*overhead_ns = div_s64(total_ns, MAX_MEASURMENT_COUNT);
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	return err;
66962306a36Sopenharmony_ci}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_cistatic int idt82p33_measure_one_byte_read_overhead(
67262306a36Sopenharmony_ci		struct idt82p33_channel *channel, s64 *overhead_ns)
67362306a36Sopenharmony_ci{
67462306a36Sopenharmony_ci	struct idt82p33 *idt82p33 = channel->idt82p33;
67562306a36Sopenharmony_ci	ktime_t start, stop;
67662306a36Sopenharmony_ci	u8 trigger = 0;
67762306a36Sopenharmony_ci	s64 total_ns;
67862306a36Sopenharmony_ci	int err;
67962306a36Sopenharmony_ci	u8 i;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	total_ns = 0;
68262306a36Sopenharmony_ci	*overhead_ns = 0;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	for (i = 0; i < MAX_MEASURMENT_COUNT; i++) {
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci		start = ktime_get_raw();
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci		err = idt82p33_read(idt82p33, channel->dpll_tod_trigger,
68962306a36Sopenharmony_ci				    &trigger, sizeof(trigger));
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci		stop = ktime_get_raw();
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci		if (err)
69462306a36Sopenharmony_ci			return err;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci		total_ns += ktime_to_ns(stop) - ktime_to_ns(start);
69762306a36Sopenharmony_ci	}
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	*overhead_ns = div_s64(total_ns, MAX_MEASURMENT_COUNT);
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	return err;
70262306a36Sopenharmony_ci}
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_cistatic int idt82p33_measure_tod_write_9_byte_overhead(
70562306a36Sopenharmony_ci		struct idt82p33_channel *channel)
70662306a36Sopenharmony_ci{
70762306a36Sopenharmony_ci	struct idt82p33 *idt82p33 = channel->idt82p33;
70862306a36Sopenharmony_ci	u8 buf[TOD_BYTE_COUNT];
70962306a36Sopenharmony_ci	ktime_t start, stop;
71062306a36Sopenharmony_ci	s64 total_ns;
71162306a36Sopenharmony_ci	int err = 0;
71262306a36Sopenharmony_ci	u8 i, j;
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	total_ns = 0;
71562306a36Sopenharmony_ci	idt82p33->tod_write_overhead_ns = 0;
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	for (i = 0; i < MAX_MEASURMENT_COUNT; i++) {
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci		start = ktime_get_raw();
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci		/* Need one less byte for applicable overhead */
72262306a36Sopenharmony_ci		for (j = 0; j < (TOD_BYTE_COUNT - 1); j++) {
72362306a36Sopenharmony_ci			err = idt82p33_write(idt82p33,
72462306a36Sopenharmony_ci					     channel->dpll_tod_cnfg + i,
72562306a36Sopenharmony_ci					     &buf[i], sizeof(buf[i]));
72662306a36Sopenharmony_ci			if (err)
72762306a36Sopenharmony_ci				return err;
72862306a36Sopenharmony_ci		}
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci		stop = ktime_get_raw();
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci		total_ns += ktime_to_ns(stop) - ktime_to_ns(start);
73362306a36Sopenharmony_ci	}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	idt82p33->tod_write_overhead_ns = div_s64(total_ns,
73662306a36Sopenharmony_ci						  MAX_MEASURMENT_COUNT);
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	return err;
73962306a36Sopenharmony_ci}
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_cistatic int idt82p33_measure_settime_gettime_gap_overhead(
74262306a36Sopenharmony_ci		struct idt82p33_channel *channel, s64 *overhead_ns)
74362306a36Sopenharmony_ci{
74462306a36Sopenharmony_ci	struct timespec64 ts1 = {0, 0};
74562306a36Sopenharmony_ci	struct timespec64 ts2;
74662306a36Sopenharmony_ci	int err;
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	*overhead_ns = 0;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	err = _idt82p33_settime(channel, &ts1);
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	if (err)
75362306a36Sopenharmony_ci		return err;
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	err = _idt82p33_gettime(channel, &ts2);
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	if (!err)
75862306a36Sopenharmony_ci		*overhead_ns = timespec64_to_ns(&ts2) - timespec64_to_ns(&ts1);
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	return err;
76162306a36Sopenharmony_ci}
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_cistatic int idt82p33_measure_tod_write_overhead(struct idt82p33_channel *channel)
76462306a36Sopenharmony_ci{
76562306a36Sopenharmony_ci	s64 trailing_overhead_ns, one_byte_write_ns, gap_ns, one_byte_read_ns;
76662306a36Sopenharmony_ci	struct idt82p33 *idt82p33 = channel->idt82p33;
76762306a36Sopenharmony_ci	int err;
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	idt82p33->tod_write_overhead_ns = 0;
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	err = idt82p33_measure_settime_gettime_gap_overhead(channel, &gap_ns);
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	if (err) {
77462306a36Sopenharmony_ci		dev_err(idt82p33->dev,
77562306a36Sopenharmony_ci			"Failed in %s with err %d!\n", __func__, err);
77662306a36Sopenharmony_ci		return err;
77762306a36Sopenharmony_ci	}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	err = idt82p33_measure_one_byte_write_overhead(channel,
78062306a36Sopenharmony_ci						       &one_byte_write_ns);
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	if (err)
78362306a36Sopenharmony_ci		return err;
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	err = idt82p33_measure_one_byte_read_overhead(channel,
78662306a36Sopenharmony_ci						      &one_byte_read_ns);
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	if (err)
78962306a36Sopenharmony_ci		return err;
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	err = idt82p33_measure_tod_write_9_byte_overhead(channel);
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	if (err)
79462306a36Sopenharmony_ci		return err;
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	trailing_overhead_ns = gap_ns - 2 * one_byte_write_ns
79762306a36Sopenharmony_ci			       - one_byte_read_ns;
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	idt82p33->tod_write_overhead_ns -= trailing_overhead_ns;
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	return err;
80262306a36Sopenharmony_ci}
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_cistatic int idt82p33_check_and_set_masks(struct idt82p33 *idt82p33,
80562306a36Sopenharmony_ci					u8 page,
80662306a36Sopenharmony_ci					u8 offset,
80762306a36Sopenharmony_ci					u8 val)
80862306a36Sopenharmony_ci{
80962306a36Sopenharmony_ci	int err = 0;
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	if (page == PLLMASK_ADDR_HI && offset == PLLMASK_ADDR_LO) {
81262306a36Sopenharmony_ci		if ((val & 0xfc) || !(val & 0x3)) {
81362306a36Sopenharmony_ci			dev_err(idt82p33->dev,
81462306a36Sopenharmony_ci				"Invalid PLL mask 0x%x\n", val);
81562306a36Sopenharmony_ci			err = -EINVAL;
81662306a36Sopenharmony_ci		} else {
81762306a36Sopenharmony_ci			idt82p33->pll_mask = val;
81862306a36Sopenharmony_ci		}
81962306a36Sopenharmony_ci	} else if (page == PLL0_OUTMASK_ADDR_HI &&
82062306a36Sopenharmony_ci		offset == PLL0_OUTMASK_ADDR_LO) {
82162306a36Sopenharmony_ci		idt82p33->channel[0].output_mask = val;
82262306a36Sopenharmony_ci	} else if (page == PLL1_OUTMASK_ADDR_HI &&
82362306a36Sopenharmony_ci		offset == PLL1_OUTMASK_ADDR_LO) {
82462306a36Sopenharmony_ci		idt82p33->channel[1].output_mask = val;
82562306a36Sopenharmony_ci	}
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	return err;
82862306a36Sopenharmony_ci}
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_cistatic void idt82p33_display_masks(struct idt82p33 *idt82p33)
83162306a36Sopenharmony_ci{
83262306a36Sopenharmony_ci	u8 mask, i;
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	dev_info(idt82p33->dev,
83562306a36Sopenharmony_ci		 "pllmask = 0x%02x\n", idt82p33->pll_mask);
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	for (i = 0; i < MAX_PHC_PLL; i++) {
83862306a36Sopenharmony_ci		mask = 1 << i;
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci		if (mask & idt82p33->pll_mask)
84162306a36Sopenharmony_ci			dev_info(idt82p33->dev,
84262306a36Sopenharmony_ci				 "PLL%d output_mask = 0x%04x\n",
84362306a36Sopenharmony_ci				 i, idt82p33->channel[i].output_mask);
84462306a36Sopenharmony_ci	}
84562306a36Sopenharmony_ci}
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_cistatic int idt82p33_sync_tod(struct idt82p33_channel *channel, bool enable)
84862306a36Sopenharmony_ci{
84962306a36Sopenharmony_ci	struct idt82p33 *idt82p33 = channel->idt82p33;
85062306a36Sopenharmony_ci	u8 sync_cnfg;
85162306a36Sopenharmony_ci	int err;
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	err = idt82p33_read(idt82p33, channel->dpll_sync_cnfg,
85462306a36Sopenharmony_ci			    &sync_cnfg, sizeof(sync_cnfg));
85562306a36Sopenharmony_ci	if (err)
85662306a36Sopenharmony_ci		return err;
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	sync_cnfg &= ~SYNC_TOD;
85962306a36Sopenharmony_ci	if (enable)
86062306a36Sopenharmony_ci		sync_cnfg |= SYNC_TOD;
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	return idt82p33_write(idt82p33, channel->dpll_sync_cnfg,
86362306a36Sopenharmony_ci			      &sync_cnfg, sizeof(sync_cnfg));
86462306a36Sopenharmony_ci}
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_cistatic long idt82p33_work_handler(struct ptp_clock_info *ptp)
86762306a36Sopenharmony_ci{
86862306a36Sopenharmony_ci	struct idt82p33_channel *channel =
86962306a36Sopenharmony_ci			container_of(ptp, struct idt82p33_channel, caps);
87062306a36Sopenharmony_ci	struct idt82p33 *idt82p33 = channel->idt82p33;
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	mutex_lock(idt82p33->lock);
87362306a36Sopenharmony_ci	(void)idt82p33_stop_ddco(channel);
87462306a36Sopenharmony_ci	mutex_unlock(idt82p33->lock);
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	/* Return a negative value here to not reschedule */
87762306a36Sopenharmony_ci	return -1;
87862306a36Sopenharmony_ci}
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_cistatic int idt82p33_output_enable(struct idt82p33_channel *channel,
88162306a36Sopenharmony_ci				  bool enable, unsigned int outn)
88262306a36Sopenharmony_ci{
88362306a36Sopenharmony_ci	struct idt82p33 *idt82p33 = channel->idt82p33;
88462306a36Sopenharmony_ci	int err;
88562306a36Sopenharmony_ci	u8 val;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	err = idt82p33_read(idt82p33, OUT_MUX_CNFG(outn), &val, sizeof(val));
88862306a36Sopenharmony_ci	if (err)
88962306a36Sopenharmony_ci		return err;
89062306a36Sopenharmony_ci	if (enable)
89162306a36Sopenharmony_ci		val &= ~SQUELCH_ENABLE;
89262306a36Sopenharmony_ci	else
89362306a36Sopenharmony_ci		val |= SQUELCH_ENABLE;
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	return idt82p33_write(idt82p33, OUT_MUX_CNFG(outn), &val, sizeof(val));
89662306a36Sopenharmony_ci}
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_cistatic int idt82p33_perout_enable(struct idt82p33_channel *channel,
89962306a36Sopenharmony_ci				  bool enable,
90062306a36Sopenharmony_ci				  struct ptp_perout_request *perout)
90162306a36Sopenharmony_ci{
90262306a36Sopenharmony_ci	/* Enable/disable individual output instead */
90362306a36Sopenharmony_ci	return idt82p33_output_enable(channel, enable, perout->index);
90462306a36Sopenharmony_ci}
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_cistatic int idt82p33_enable_tod(struct idt82p33_channel *channel)
90762306a36Sopenharmony_ci{
90862306a36Sopenharmony_ci	struct idt82p33 *idt82p33 = channel->idt82p33;
90962306a36Sopenharmony_ci	struct timespec64 ts = {0, 0};
91062306a36Sopenharmony_ci	int err;
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	err = idt82p33_measure_tod_write_overhead(channel);
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	if (err) {
91562306a36Sopenharmony_ci		dev_err(idt82p33->dev,
91662306a36Sopenharmony_ci			"Failed in %s with err %d!\n", __func__, err);
91762306a36Sopenharmony_ci		return err;
91862306a36Sopenharmony_ci	}
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	err = _idt82p33_settime(channel, &ts);
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	if (err)
92362306a36Sopenharmony_ci		return err;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	return idt82p33_sync_tod(channel, true);
92662306a36Sopenharmony_ci}
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_cistatic void idt82p33_ptp_clock_unregister_all(struct idt82p33 *idt82p33)
92962306a36Sopenharmony_ci{
93062306a36Sopenharmony_ci	struct idt82p33_channel *channel;
93162306a36Sopenharmony_ci	u8 i;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	for (i = 0; i < MAX_PHC_PLL; i++) {
93462306a36Sopenharmony_ci		channel = &idt82p33->channel[i];
93562306a36Sopenharmony_ci		cancel_delayed_work_sync(&channel->adjtime_work);
93662306a36Sopenharmony_ci		if (channel->ptp_clock)
93762306a36Sopenharmony_ci			ptp_clock_unregister(channel->ptp_clock);
93862306a36Sopenharmony_ci	}
93962306a36Sopenharmony_ci}
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_cistatic int idt82p33_enable(struct ptp_clock_info *ptp,
94462306a36Sopenharmony_ci			   struct ptp_clock_request *rq, int on)
94562306a36Sopenharmony_ci{
94662306a36Sopenharmony_ci	struct idt82p33_channel *channel =
94762306a36Sopenharmony_ci			container_of(ptp, struct idt82p33_channel, caps);
94862306a36Sopenharmony_ci	struct idt82p33 *idt82p33 = channel->idt82p33;
94962306a36Sopenharmony_ci	int err = -EOPNOTSUPP;
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	mutex_lock(idt82p33->lock);
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	switch (rq->type) {
95462306a36Sopenharmony_ci	case PTP_CLK_REQ_PEROUT:
95562306a36Sopenharmony_ci		if (!on)
95662306a36Sopenharmony_ci			err = idt82p33_perout_enable(channel, false,
95762306a36Sopenharmony_ci						     &rq->perout);
95862306a36Sopenharmony_ci		/* Only accept a 1-PPS aligned to the second. */
95962306a36Sopenharmony_ci		else if (rq->perout.start.nsec || rq->perout.period.sec != 1 ||
96062306a36Sopenharmony_ci			 rq->perout.period.nsec)
96162306a36Sopenharmony_ci			err = -ERANGE;
96262306a36Sopenharmony_ci		else
96362306a36Sopenharmony_ci			err = idt82p33_perout_enable(channel, true,
96462306a36Sopenharmony_ci						     &rq->perout);
96562306a36Sopenharmony_ci		break;
96662306a36Sopenharmony_ci	case PTP_CLK_REQ_EXTTS:
96762306a36Sopenharmony_ci		err = idt82p33_extts_enable(channel, rq, on);
96862306a36Sopenharmony_ci		break;
96962306a36Sopenharmony_ci	default:
97062306a36Sopenharmony_ci		break;
97162306a36Sopenharmony_ci	}
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	mutex_unlock(idt82p33->lock);
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	if (err)
97662306a36Sopenharmony_ci		dev_err(idt82p33->dev,
97762306a36Sopenharmony_ci			"Failed in %s with err %d!\n", __func__, err);
97862306a36Sopenharmony_ci	return err;
97962306a36Sopenharmony_ci}
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_cistatic s32 idt82p33_getmaxphase(__always_unused struct ptp_clock_info *ptp)
98262306a36Sopenharmony_ci{
98362306a36Sopenharmony_ci	return WRITE_PHASE_OFFSET_LIMIT;
98462306a36Sopenharmony_ci}
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_cistatic int idt82p33_adjwritephase(struct ptp_clock_info *ptp, s32 offset_ns)
98762306a36Sopenharmony_ci{
98862306a36Sopenharmony_ci	struct idt82p33_channel *channel =
98962306a36Sopenharmony_ci		container_of(ptp, struct idt82p33_channel, caps);
99062306a36Sopenharmony_ci	struct idt82p33 *idt82p33 = channel->idt82p33;
99162306a36Sopenharmony_ci	s64 offset_regval;
99262306a36Sopenharmony_ci	u8 val[4] = {0};
99362306a36Sopenharmony_ci	int err;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	/* Convert from phaseoffset_fs to register value */
99662306a36Sopenharmony_ci	offset_regval = div_s64((s64)(-offset_ns) * 1000000000ll,
99762306a36Sopenharmony_ci				IDT_T0DPLL_PHASE_RESOL);
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	val[0] = offset_regval & 0xFF;
100062306a36Sopenharmony_ci	val[1] = (offset_regval >> 8) & 0xFF;
100162306a36Sopenharmony_ci	val[2] = (offset_regval >> 16) & 0xFF;
100262306a36Sopenharmony_ci	val[3] = (offset_regval >> 24) & 0x1F;
100362306a36Sopenharmony_ci	val[3] |= PH_OFFSET_EN;
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	mutex_lock(idt82p33->lock);
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	err = idt82p33_dpll_set_mode(channel, PLL_MODE_WPH);
100862306a36Sopenharmony_ci	if (err) {
100962306a36Sopenharmony_ci		dev_err(idt82p33->dev,
101062306a36Sopenharmony_ci			"Failed in %s with err %d!\n", __func__, err);
101162306a36Sopenharmony_ci		goto out;
101262306a36Sopenharmony_ci	}
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	err = idt82p33_write(idt82p33, channel->dpll_phase_cnfg, val,
101562306a36Sopenharmony_ci			     sizeof(val));
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ciout:
101862306a36Sopenharmony_ci	mutex_unlock(idt82p33->lock);
101962306a36Sopenharmony_ci	return err;
102062306a36Sopenharmony_ci}
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_cistatic int idt82p33_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
102362306a36Sopenharmony_ci{
102462306a36Sopenharmony_ci	struct idt82p33_channel *channel =
102562306a36Sopenharmony_ci			container_of(ptp, struct idt82p33_channel, caps);
102662306a36Sopenharmony_ci	struct idt82p33 *idt82p33 = channel->idt82p33;
102762306a36Sopenharmony_ci	int err;
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	if (channel->ddco == true)
103062306a36Sopenharmony_ci		return 0;
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	if (scaled_ppm == channel->current_freq)
103362306a36Sopenharmony_ci		return 0;
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	mutex_lock(idt82p33->lock);
103662306a36Sopenharmony_ci	err = _idt82p33_adjfine(channel, scaled_ppm);
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	if (err == 0)
103962306a36Sopenharmony_ci		channel->current_freq = scaled_ppm;
104062306a36Sopenharmony_ci	mutex_unlock(idt82p33->lock);
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	if (err)
104362306a36Sopenharmony_ci		dev_err(idt82p33->dev,
104462306a36Sopenharmony_ci			"Failed in %s with err %d!\n", __func__, err);
104562306a36Sopenharmony_ci	return err;
104662306a36Sopenharmony_ci}
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_cistatic int idt82p33_adjtime(struct ptp_clock_info *ptp, s64 delta_ns)
104962306a36Sopenharmony_ci{
105062306a36Sopenharmony_ci	struct idt82p33_channel *channel =
105162306a36Sopenharmony_ci			container_of(ptp, struct idt82p33_channel, caps);
105262306a36Sopenharmony_ci	struct idt82p33 *idt82p33 = channel->idt82p33;
105362306a36Sopenharmony_ci	int err;
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	if (channel->ddco == true)
105662306a36Sopenharmony_ci		return -EBUSY;
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	mutex_lock(idt82p33->lock);
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	if (abs(delta_ns) < phase_snap_threshold) {
106162306a36Sopenharmony_ci		err = idt82p33_start_ddco(channel, delta_ns);
106262306a36Sopenharmony_ci		mutex_unlock(idt82p33->lock);
106362306a36Sopenharmony_ci		return err;
106462306a36Sopenharmony_ci	}
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	/* Use more accurate internal 1pps triggered write first */
106762306a36Sopenharmony_ci	err = _idt82p33_adjtime_internal_triggered(channel, delta_ns);
106862306a36Sopenharmony_ci	if (err && delta_ns > IMMEDIATE_SNAP_THRESHOLD_NS)
106962306a36Sopenharmony_ci		err = _idt82p33_adjtime_immediate(channel, delta_ns);
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	mutex_unlock(idt82p33->lock);
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	if (err)
107462306a36Sopenharmony_ci		dev_err(idt82p33->dev,
107562306a36Sopenharmony_ci			"Failed in %s with err %d!\n", __func__, err);
107662306a36Sopenharmony_ci	return err;
107762306a36Sopenharmony_ci}
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_cistatic int idt82p33_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
108062306a36Sopenharmony_ci{
108162306a36Sopenharmony_ci	struct idt82p33_channel *channel =
108262306a36Sopenharmony_ci			container_of(ptp, struct idt82p33_channel, caps);
108362306a36Sopenharmony_ci	struct idt82p33 *idt82p33 = channel->idt82p33;
108462306a36Sopenharmony_ci	int err;
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	mutex_lock(idt82p33->lock);
108762306a36Sopenharmony_ci	err = _idt82p33_gettime(channel, ts);
108862306a36Sopenharmony_ci	mutex_unlock(idt82p33->lock);
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	if (err)
109162306a36Sopenharmony_ci		dev_err(idt82p33->dev,
109262306a36Sopenharmony_ci			"Failed in %s with err %d!\n", __func__, err);
109362306a36Sopenharmony_ci	return err;
109462306a36Sopenharmony_ci}
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_cistatic int idt82p33_settime(struct ptp_clock_info *ptp,
109762306a36Sopenharmony_ci			    const struct timespec64 *ts)
109862306a36Sopenharmony_ci{
109962306a36Sopenharmony_ci	struct idt82p33_channel *channel =
110062306a36Sopenharmony_ci			container_of(ptp, struct idt82p33_channel, caps);
110162306a36Sopenharmony_ci	struct idt82p33 *idt82p33 = channel->idt82p33;
110262306a36Sopenharmony_ci	int err;
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci	mutex_lock(idt82p33->lock);
110562306a36Sopenharmony_ci	err = _idt82p33_settime(channel, ts);
110662306a36Sopenharmony_ci	mutex_unlock(idt82p33->lock);
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	if (err)
110962306a36Sopenharmony_ci		dev_err(idt82p33->dev,
111062306a36Sopenharmony_ci			"Failed in %s with err %d!\n", __func__, err);
111162306a36Sopenharmony_ci	return err;
111262306a36Sopenharmony_ci}
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_cistatic int idt82p33_channel_init(struct idt82p33 *idt82p33, u32 index)
111562306a36Sopenharmony_ci{
111662306a36Sopenharmony_ci	struct idt82p33_channel *channel = &idt82p33->channel[index];
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	switch (index) {
111962306a36Sopenharmony_ci	case 0:
112062306a36Sopenharmony_ci		channel->dpll_tod_cnfg = DPLL1_TOD_CNFG;
112162306a36Sopenharmony_ci		channel->dpll_tod_trigger = DPLL1_TOD_TRIGGER;
112262306a36Sopenharmony_ci		channel->dpll_tod_sts = DPLL1_TOD_STS;
112362306a36Sopenharmony_ci		channel->dpll_mode_cnfg = DPLL1_OPERATING_MODE_CNFG;
112462306a36Sopenharmony_ci		channel->dpll_freq_cnfg = DPLL1_HOLDOVER_FREQ_CNFG;
112562306a36Sopenharmony_ci		channel->dpll_phase_cnfg = DPLL1_PHASE_OFFSET_CNFG;
112662306a36Sopenharmony_ci		channel->dpll_sync_cnfg = DPLL1_SYNC_EDGE_CNFG;
112762306a36Sopenharmony_ci		channel->dpll_input_mode_cnfg = DPLL1_INPUT_MODE_CNFG;
112862306a36Sopenharmony_ci		break;
112962306a36Sopenharmony_ci	case 1:
113062306a36Sopenharmony_ci		channel->dpll_tod_cnfg = DPLL2_TOD_CNFG;
113162306a36Sopenharmony_ci		channel->dpll_tod_trigger = DPLL2_TOD_TRIGGER;
113262306a36Sopenharmony_ci		channel->dpll_tod_sts = DPLL2_TOD_STS;
113362306a36Sopenharmony_ci		channel->dpll_mode_cnfg = DPLL2_OPERATING_MODE_CNFG;
113462306a36Sopenharmony_ci		channel->dpll_freq_cnfg = DPLL2_HOLDOVER_FREQ_CNFG;
113562306a36Sopenharmony_ci		channel->dpll_phase_cnfg = DPLL2_PHASE_OFFSET_CNFG;
113662306a36Sopenharmony_ci		channel->dpll_sync_cnfg = DPLL2_SYNC_EDGE_CNFG;
113762306a36Sopenharmony_ci		channel->dpll_input_mode_cnfg = DPLL2_INPUT_MODE_CNFG;
113862306a36Sopenharmony_ci		break;
113962306a36Sopenharmony_ci	default:
114062306a36Sopenharmony_ci		return -EINVAL;
114162306a36Sopenharmony_ci	}
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	channel->plln = index;
114462306a36Sopenharmony_ci	channel->current_freq = 0;
114562306a36Sopenharmony_ci	channel->idt82p33 = idt82p33;
114662306a36Sopenharmony_ci	INIT_DELAYED_WORK(&channel->adjtime_work, idt82p33_adjtime_workaround);
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci	return 0;
114962306a36Sopenharmony_ci}
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_cistatic int idt82p33_verify_pin(struct ptp_clock_info *ptp, unsigned int pin,
115262306a36Sopenharmony_ci			       enum ptp_pin_function func, unsigned int chan)
115362306a36Sopenharmony_ci{
115462306a36Sopenharmony_ci	switch (func) {
115562306a36Sopenharmony_ci	case PTP_PF_NONE:
115662306a36Sopenharmony_ci	case PTP_PF_EXTTS:
115762306a36Sopenharmony_ci		break;
115862306a36Sopenharmony_ci	case PTP_PF_PEROUT:
115962306a36Sopenharmony_ci	case PTP_PF_PHYSYNC:
116062306a36Sopenharmony_ci		return -1;
116162306a36Sopenharmony_ci	}
116262306a36Sopenharmony_ci	return 0;
116362306a36Sopenharmony_ci}
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_cistatic void idt82p33_caps_init(u32 index, struct ptp_clock_info *caps,
116662306a36Sopenharmony_ci			       struct ptp_pin_desc *pin_cfg, u8 max_pins)
116762306a36Sopenharmony_ci{
116862306a36Sopenharmony_ci	struct ptp_pin_desc *ppd;
116962306a36Sopenharmony_ci	int i;
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	caps->owner = THIS_MODULE;
117262306a36Sopenharmony_ci	caps->max_adj = DCO_MAX_PPB;
117362306a36Sopenharmony_ci	caps->n_per_out = MAX_PER_OUT;
117462306a36Sopenharmony_ci	caps->n_ext_ts = MAX_PHC_PLL,
117562306a36Sopenharmony_ci	caps->n_pins = max_pins,
117662306a36Sopenharmony_ci	caps->adjphase = idt82p33_adjwritephase,
117762306a36Sopenharmony_ci	caps->getmaxphase = idt82p33_getmaxphase,
117862306a36Sopenharmony_ci	caps->adjfine = idt82p33_adjfine;
117962306a36Sopenharmony_ci	caps->adjtime = idt82p33_adjtime;
118062306a36Sopenharmony_ci	caps->gettime64 = idt82p33_gettime;
118162306a36Sopenharmony_ci	caps->settime64 = idt82p33_settime;
118262306a36Sopenharmony_ci	caps->enable = idt82p33_enable;
118362306a36Sopenharmony_ci	caps->verify = idt82p33_verify_pin;
118462306a36Sopenharmony_ci	caps->do_aux_work = idt82p33_work_handler;
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	snprintf(caps->name, sizeof(caps->name), "IDT 82P33 PLL%u", index);
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci	caps->pin_config = pin_cfg;
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	for (i = 0; i < max_pins; ++i) {
119162306a36Sopenharmony_ci		ppd = &pin_cfg[i];
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci		ppd->index = i;
119462306a36Sopenharmony_ci		ppd->func = PTP_PF_NONE;
119562306a36Sopenharmony_ci		ppd->chan = index;
119662306a36Sopenharmony_ci		snprintf(ppd->name, sizeof(ppd->name), "in%d", 12 + i);
119762306a36Sopenharmony_ci	}
119862306a36Sopenharmony_ci}
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_cistatic int idt82p33_enable_channel(struct idt82p33 *idt82p33, u32 index)
120162306a36Sopenharmony_ci{
120262306a36Sopenharmony_ci	struct idt82p33_channel *channel;
120362306a36Sopenharmony_ci	int err;
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	if (!(index < MAX_PHC_PLL))
120662306a36Sopenharmony_ci		return -EINVAL;
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci	channel = &idt82p33->channel[index];
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	err = idt82p33_channel_init(idt82p33, index);
121162306a36Sopenharmony_ci	if (err) {
121262306a36Sopenharmony_ci		dev_err(idt82p33->dev,
121362306a36Sopenharmony_ci			"Channel_init failed in %s with err %d!\n",
121462306a36Sopenharmony_ci			__func__, err);
121562306a36Sopenharmony_ci		return err;
121662306a36Sopenharmony_ci	}
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	idt82p33_caps_init(index, &channel->caps,
121962306a36Sopenharmony_ci			   pin_config[index], MAX_TRIG_CLK);
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci	channel->ptp_clock = ptp_clock_register(&channel->caps, NULL);
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	if (IS_ERR(channel->ptp_clock)) {
122462306a36Sopenharmony_ci		err = PTR_ERR(channel->ptp_clock);
122562306a36Sopenharmony_ci		channel->ptp_clock = NULL;
122662306a36Sopenharmony_ci		return err;
122762306a36Sopenharmony_ci	}
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	if (!channel->ptp_clock)
123062306a36Sopenharmony_ci		return -ENOTSUPP;
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	err = idt82p33_dpll_set_mode(channel, PLL_MODE_DCO);
123362306a36Sopenharmony_ci	if (err) {
123462306a36Sopenharmony_ci		dev_err(idt82p33->dev,
123562306a36Sopenharmony_ci			"Dpll_set_mode failed in %s with err %d!\n",
123662306a36Sopenharmony_ci			__func__, err);
123762306a36Sopenharmony_ci		return err;
123862306a36Sopenharmony_ci	}
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	err = idt82p33_enable_tod(channel);
124162306a36Sopenharmony_ci	if (err) {
124262306a36Sopenharmony_ci		dev_err(idt82p33->dev,
124362306a36Sopenharmony_ci			"Enable_tod failed in %s with err %d!\n",
124462306a36Sopenharmony_ci			__func__, err);
124562306a36Sopenharmony_ci		return err;
124662306a36Sopenharmony_ci	}
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	dev_info(idt82p33->dev, "PLL%d registered as ptp%d\n",
124962306a36Sopenharmony_ci		 index, channel->ptp_clock->index);
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	return 0;
125262306a36Sopenharmony_ci}
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_cistatic int idt82p33_reset(struct idt82p33 *idt82p33, bool cold)
125562306a36Sopenharmony_ci{
125662306a36Sopenharmony_ci	int err;
125762306a36Sopenharmony_ci	u8 cfg = SOFT_RESET_EN;
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	if (cold == true)
126062306a36Sopenharmony_ci		goto cold_reset;
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	err = idt82p33_read(idt82p33, REG_SOFT_RESET, &cfg, sizeof(cfg));
126362306a36Sopenharmony_ci	if (err) {
126462306a36Sopenharmony_ci		dev_err(idt82p33->dev,
126562306a36Sopenharmony_ci			"Soft reset failed with err %d!\n", err);
126662306a36Sopenharmony_ci		return err;
126762306a36Sopenharmony_ci	}
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	cfg |= SOFT_RESET_EN;
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_cicold_reset:
127262306a36Sopenharmony_ci	err = idt82p33_write(idt82p33, REG_SOFT_RESET, &cfg, sizeof(cfg));
127362306a36Sopenharmony_ci	if (err)
127462306a36Sopenharmony_ci		dev_err(idt82p33->dev,
127562306a36Sopenharmony_ci			"Cold reset failed with err %d!\n", err);
127662306a36Sopenharmony_ci	return err;
127762306a36Sopenharmony_ci}
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_cistatic int idt82p33_load_firmware(struct idt82p33 *idt82p33)
128062306a36Sopenharmony_ci{
128162306a36Sopenharmony_ci	char fname[128] = FW_FILENAME;
128262306a36Sopenharmony_ci	const struct firmware *fw;
128362306a36Sopenharmony_ci	struct idt82p33_fwrc *rec;
128462306a36Sopenharmony_ci	u8 loaddr, page, val;
128562306a36Sopenharmony_ci	int err;
128662306a36Sopenharmony_ci	s32 len;
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	if (firmware) /* module parameter */
128962306a36Sopenharmony_ci		snprintf(fname, sizeof(fname), "%s", firmware);
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	dev_info(idt82p33->dev, "requesting firmware '%s'\n", fname);
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	err = request_firmware(&fw, fname, idt82p33->dev);
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	if (err) {
129662306a36Sopenharmony_ci		dev_err(idt82p33->dev,
129762306a36Sopenharmony_ci			"Failed in %s with err %d!\n", __func__, err);
129862306a36Sopenharmony_ci		return err;
129962306a36Sopenharmony_ci	}
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	dev_dbg(idt82p33->dev, "firmware size %zu bytes\n", fw->size);
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	rec = (struct idt82p33_fwrc *) fw->data;
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	for (len = fw->size; len > 0; len -= sizeof(*rec)) {
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci		if (rec->reserved) {
130862306a36Sopenharmony_ci			dev_err(idt82p33->dev,
130962306a36Sopenharmony_ci				"bad firmware, reserved field non-zero\n");
131062306a36Sopenharmony_ci			err = -EINVAL;
131162306a36Sopenharmony_ci		} else {
131262306a36Sopenharmony_ci			val = rec->value;
131362306a36Sopenharmony_ci			loaddr = rec->loaddr;
131462306a36Sopenharmony_ci			page = rec->hiaddr;
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci			rec++;
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci			err = idt82p33_check_and_set_masks(idt82p33, page,
131962306a36Sopenharmony_ci							   loaddr, val);
132062306a36Sopenharmony_ci		}
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci		if (err == 0) {
132362306a36Sopenharmony_ci			/* Page size 128, last 4 bytes of page skipped */
132462306a36Sopenharmony_ci			if (loaddr > 0x7b)
132562306a36Sopenharmony_ci				continue;
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci			err = idt82p33_write(idt82p33, REG_ADDR(page, loaddr),
132862306a36Sopenharmony_ci					     &val, sizeof(val));
132962306a36Sopenharmony_ci		}
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci		if (err)
133262306a36Sopenharmony_ci			goto out;
133362306a36Sopenharmony_ci	}
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	idt82p33_display_masks(idt82p33);
133662306a36Sopenharmony_ciout:
133762306a36Sopenharmony_ci	release_firmware(fw);
133862306a36Sopenharmony_ci	return err;
133962306a36Sopenharmony_ci}
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_cistatic void idt82p33_extts_check(struct work_struct *work)
134262306a36Sopenharmony_ci{
134362306a36Sopenharmony_ci	struct idt82p33 *idt82p33 = container_of(work, struct idt82p33,
134462306a36Sopenharmony_ci						 extts_work.work);
134562306a36Sopenharmony_ci	struct idt82p33_channel *channel;
134662306a36Sopenharmony_ci	int err;
134762306a36Sopenharmony_ci	u8 mask;
134862306a36Sopenharmony_ci	int i;
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	if (idt82p33->extts_mask == 0)
135162306a36Sopenharmony_ci		return;
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	mutex_lock(idt82p33->lock);
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	for (i = 0; i < MAX_PHC_PLL; i++) {
135662306a36Sopenharmony_ci		mask = 1 << i;
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci		if ((idt82p33->extts_mask & mask) == 0)
135962306a36Sopenharmony_ci			continue;
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci		err = idt82p33_extts_check_channel(idt82p33, i);
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci		if (err == 0) {
136462306a36Sopenharmony_ci			/* trigger clears itself, so clear the mask */
136562306a36Sopenharmony_ci			if (idt82p33->extts_single_shot) {
136662306a36Sopenharmony_ci				idt82p33->extts_mask &= ~mask;
136762306a36Sopenharmony_ci			} else {
136862306a36Sopenharmony_ci				/* Re-arm */
136962306a36Sopenharmony_ci				channel = &idt82p33->channel[i];
137062306a36Sopenharmony_ci				arm_tod_read_with_trigger(channel, channel->tod_trigger);
137162306a36Sopenharmony_ci			}
137262306a36Sopenharmony_ci		}
137362306a36Sopenharmony_ci	}
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	if (idt82p33->extts_mask)
137662306a36Sopenharmony_ci		schedule_delayed_work(&idt82p33->extts_work,
137762306a36Sopenharmony_ci				      msecs_to_jiffies(EXTTS_PERIOD_MS));
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	mutex_unlock(idt82p33->lock);
138062306a36Sopenharmony_ci}
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_cistatic int idt82p33_probe(struct platform_device *pdev)
138362306a36Sopenharmony_ci{
138462306a36Sopenharmony_ci	struct rsmu_ddata *ddata = dev_get_drvdata(pdev->dev.parent);
138562306a36Sopenharmony_ci	struct idt82p33 *idt82p33;
138662306a36Sopenharmony_ci	int err;
138762306a36Sopenharmony_ci	u8 i;
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci	idt82p33 = devm_kzalloc(&pdev->dev,
139062306a36Sopenharmony_ci				sizeof(struct idt82p33), GFP_KERNEL);
139162306a36Sopenharmony_ci	if (!idt82p33)
139262306a36Sopenharmony_ci		return -ENOMEM;
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci	idt82p33->dev = &pdev->dev;
139562306a36Sopenharmony_ci	idt82p33->mfd = pdev->dev.parent;
139662306a36Sopenharmony_ci	idt82p33->lock = &ddata->lock;
139762306a36Sopenharmony_ci	idt82p33->regmap = ddata->regmap;
139862306a36Sopenharmony_ci	idt82p33->tod_write_overhead_ns = 0;
139962306a36Sopenharmony_ci	idt82p33->calculate_overhead_flag = 0;
140062306a36Sopenharmony_ci	idt82p33->pll_mask = DEFAULT_PLL_MASK;
140162306a36Sopenharmony_ci	idt82p33->channel[0].output_mask = DEFAULT_OUTPUT_MASK_PLL0;
140262306a36Sopenharmony_ci	idt82p33->channel[1].output_mask = DEFAULT_OUTPUT_MASK_PLL1;
140362306a36Sopenharmony_ci	idt82p33->extts_mask = 0;
140462306a36Sopenharmony_ci	INIT_DELAYED_WORK(&idt82p33->extts_work, idt82p33_extts_check);
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	mutex_lock(idt82p33->lock);
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci	/* cold reset before loading firmware */
140962306a36Sopenharmony_ci	idt82p33_reset(idt82p33, true);
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci	err = idt82p33_load_firmware(idt82p33);
141262306a36Sopenharmony_ci	if (err)
141362306a36Sopenharmony_ci		dev_warn(idt82p33->dev,
141462306a36Sopenharmony_ci			 "loading firmware failed with %d\n", err);
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci	/* soft reset after loading firmware */
141762306a36Sopenharmony_ci	idt82p33_reset(idt82p33, false);
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_ci	if (idt82p33->pll_mask) {
142062306a36Sopenharmony_ci		for (i = 0; i < MAX_PHC_PLL; i++) {
142162306a36Sopenharmony_ci			if (idt82p33->pll_mask & (1 << i))
142262306a36Sopenharmony_ci				err = idt82p33_enable_channel(idt82p33, i);
142362306a36Sopenharmony_ci			else
142462306a36Sopenharmony_ci				err = idt82p33_channel_init(idt82p33, i);
142562306a36Sopenharmony_ci			if (err) {
142662306a36Sopenharmony_ci				dev_err(idt82p33->dev,
142762306a36Sopenharmony_ci					"Failed in %s with err %d!\n",
142862306a36Sopenharmony_ci					__func__, err);
142962306a36Sopenharmony_ci				break;
143062306a36Sopenharmony_ci			}
143162306a36Sopenharmony_ci		}
143262306a36Sopenharmony_ci	} else {
143362306a36Sopenharmony_ci		dev_err(idt82p33->dev,
143462306a36Sopenharmony_ci			"no PLLs flagged as PHCs, nothing to do\n");
143562306a36Sopenharmony_ci		err = -ENODEV;
143662306a36Sopenharmony_ci	}
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_ci	mutex_unlock(idt82p33->lock);
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci	if (err) {
144162306a36Sopenharmony_ci		idt82p33_ptp_clock_unregister_all(idt82p33);
144262306a36Sopenharmony_ci		return err;
144362306a36Sopenharmony_ci	}
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ci	platform_set_drvdata(pdev, idt82p33);
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci	return 0;
144862306a36Sopenharmony_ci}
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_cistatic int idt82p33_remove(struct platform_device *pdev)
145162306a36Sopenharmony_ci{
145262306a36Sopenharmony_ci	struct idt82p33 *idt82p33 = platform_get_drvdata(pdev);
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci	cancel_delayed_work_sync(&idt82p33->extts_work);
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_ci	idt82p33_ptp_clock_unregister_all(idt82p33);
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci	return 0;
145962306a36Sopenharmony_ci}
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_cistatic struct platform_driver idt82p33_driver = {
146262306a36Sopenharmony_ci	.driver = {
146362306a36Sopenharmony_ci		.name = "82p33x1x-phc",
146462306a36Sopenharmony_ci	},
146562306a36Sopenharmony_ci	.probe = idt82p33_probe,
146662306a36Sopenharmony_ci	.remove	= idt82p33_remove,
146762306a36Sopenharmony_ci};
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_cimodule_platform_driver(idt82p33_driver);
1470