xref: /linux/drivers/ptp/ptp_idt82p33.c (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
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>
9*013a3e7cSMin 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>
13*013a3e7cSMin Li #include <linux/jiffies.h>
1457a10d8cSMin Li #include <linux/kernel.h>
1557a10d8cSMin Li #include <linux/timekeeping.h>
1657a10d8cSMin Li #include <linux/bitops.h>
17*013a3e7cSMin Li #include <linux/of.h>
18*013a3e7cSMin Li #include <linux/mfd/rsmu.h>
19*013a3e7cSMin 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 
3057a10d8cSMin Li /* Module Parameters */
31d30e1c3dSYueHaibing static u32 phase_snap_threshold = SNAP_THRESHOLD_NS;
3257a10d8cSMin Li module_param(phase_snap_threshold, uint, 0);
3357a10d8cSMin Li MODULE_PARM_DESC(phase_snap_threshold,
34*013a3e7cSMin Li "threshold (10000ns by default) below which adjtime would use double dco");
35*013a3e7cSMin Li 
36*013a3e7cSMin Li static char *firmware;
37*013a3e7cSMin Li module_param(firmware, charp, 0);
38*013a3e7cSMin Li 
39*013a3e7cSMin Li static inline int idt82p33_read(struct idt82p33 *idt82p33, u16 regaddr,
40*013a3e7cSMin Li 				u8 *buf, u16 count)
41*013a3e7cSMin Li {
42*013a3e7cSMin Li 	return regmap_bulk_read(idt82p33->regmap, regaddr, buf, count);
43*013a3e7cSMin Li }
44*013a3e7cSMin Li 
45*013a3e7cSMin Li static inline int idt82p33_write(struct idt82p33 *idt82p33, u16 regaddr,
46*013a3e7cSMin Li 				 u8 *buf, u16 count)
47*013a3e7cSMin Li {
48*013a3e7cSMin Li 	return regmap_bulk_write(idt82p33->regmap, regaddr, buf, count);
49*013a3e7cSMin Li }
5057a10d8cSMin Li 
5157a10d8cSMin Li static void idt82p33_byte_array_to_timespec(struct timespec64 *ts,
5257a10d8cSMin Li 					    u8 buf[TOD_BYTE_COUNT])
5357a10d8cSMin Li {
5457a10d8cSMin Li 	time64_t sec;
5557a10d8cSMin Li 	s32 nsec;
5657a10d8cSMin Li 	u8 i;
5757a10d8cSMin Li 
5857a10d8cSMin Li 	nsec = buf[3];
5957a10d8cSMin Li 	for (i = 0; i < 3; i++) {
6057a10d8cSMin Li 		nsec <<= 8;
6157a10d8cSMin Li 		nsec |= buf[2 - i];
6257a10d8cSMin Li 	}
6357a10d8cSMin Li 
6457a10d8cSMin Li 	sec = buf[9];
6557a10d8cSMin Li 	for (i = 0; i < 5; i++) {
6657a10d8cSMin Li 		sec <<= 8;
6757a10d8cSMin Li 		sec |= buf[8 - i];
6857a10d8cSMin Li 	}
6957a10d8cSMin Li 
7057a10d8cSMin Li 	ts->tv_sec = sec;
7157a10d8cSMin Li 	ts->tv_nsec = nsec;
7257a10d8cSMin Li }
7357a10d8cSMin Li 
7457a10d8cSMin Li static void idt82p33_timespec_to_byte_array(struct timespec64 const *ts,
7557a10d8cSMin Li 					    u8 buf[TOD_BYTE_COUNT])
7657a10d8cSMin Li {
7757a10d8cSMin Li 	time64_t sec;
7857a10d8cSMin Li 	s32 nsec;
7957a10d8cSMin Li 	u8 i;
8057a10d8cSMin Li 
8157a10d8cSMin Li 	nsec = ts->tv_nsec;
8257a10d8cSMin Li 	sec = ts->tv_sec;
8357a10d8cSMin Li 
8457a10d8cSMin Li 	for (i = 0; i < 4; i++) {
8557a10d8cSMin Li 		buf[i] = nsec & 0xff;
8657a10d8cSMin Li 		nsec >>= 8;
8757a10d8cSMin Li 	}
8857a10d8cSMin Li 
8957a10d8cSMin Li 	for (i = 4; i < TOD_BYTE_COUNT; i++) {
9057a10d8cSMin Li 		buf[i] = sec & 0xff;
9157a10d8cSMin Li 		sec >>= 8;
9257a10d8cSMin Li 	}
9357a10d8cSMin Li }
9457a10d8cSMin Li 
9557a10d8cSMin Li static int idt82p33_dpll_set_mode(struct idt82p33_channel *channel,
9657a10d8cSMin Li 				  enum pll_mode mode)
9757a10d8cSMin Li {
9857a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
9957a10d8cSMin Li 	u8 dpll_mode;
10057a10d8cSMin Li 	int err;
10157a10d8cSMin Li 
10257a10d8cSMin Li 	if (channel->pll_mode == mode)
10357a10d8cSMin Li 		return 0;
10457a10d8cSMin Li 
10557a10d8cSMin Li 	err = idt82p33_read(idt82p33, channel->dpll_mode_cnfg,
10657a10d8cSMin Li 			    &dpll_mode, sizeof(dpll_mode));
10757a10d8cSMin Li 	if (err)
10857a10d8cSMin Li 		return err;
10957a10d8cSMin Li 
11057a10d8cSMin Li 	dpll_mode &= ~(PLL_MODE_MASK << PLL_MODE_SHIFT);
11157a10d8cSMin Li 
11257a10d8cSMin Li 	dpll_mode |= (mode << PLL_MODE_SHIFT);
11357a10d8cSMin Li 
11457a10d8cSMin Li 	err = idt82p33_write(idt82p33, channel->dpll_mode_cnfg,
11557a10d8cSMin Li 			     &dpll_mode, sizeof(dpll_mode));
11657a10d8cSMin Li 	if (err)
11757a10d8cSMin Li 		return err;
11857a10d8cSMin Li 
119*013a3e7cSMin Li 	channel->pll_mode = mode;
12057a10d8cSMin Li 
12157a10d8cSMin Li 	return 0;
12257a10d8cSMin Li }
12357a10d8cSMin Li 
12457a10d8cSMin Li static int _idt82p33_gettime(struct idt82p33_channel *channel,
12557a10d8cSMin Li 			     struct timespec64 *ts)
12657a10d8cSMin Li {
12757a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
12857a10d8cSMin Li 	u8 buf[TOD_BYTE_COUNT];
12957a10d8cSMin Li 	u8 trigger;
13057a10d8cSMin Li 	int err;
13157a10d8cSMin Li 
13257a10d8cSMin Li 	trigger = TOD_TRIGGER(HW_TOD_WR_TRIG_SEL_MSB_TOD_CNFG,
13357a10d8cSMin Li 			      HW_TOD_RD_TRIG_SEL_LSB_TOD_STS);
13457a10d8cSMin Li 
13557a10d8cSMin Li 
13657a10d8cSMin Li 	err = idt82p33_write(idt82p33, channel->dpll_tod_trigger,
13757a10d8cSMin Li 			     &trigger, sizeof(trigger));
13857a10d8cSMin Li 
13957a10d8cSMin Li 	if (err)
14057a10d8cSMin Li 		return err;
14157a10d8cSMin Li 
14257a10d8cSMin Li 	if (idt82p33->calculate_overhead_flag)
14357a10d8cSMin Li 		idt82p33->start_time = ktime_get_raw();
14457a10d8cSMin Li 
14557a10d8cSMin Li 	err = idt82p33_read(idt82p33, channel->dpll_tod_sts, buf, sizeof(buf));
14657a10d8cSMin Li 
14757a10d8cSMin Li 	if (err)
14857a10d8cSMin Li 		return err;
14957a10d8cSMin Li 
15057a10d8cSMin Li 	idt82p33_byte_array_to_timespec(ts, buf);
15157a10d8cSMin Li 
15257a10d8cSMin Li 	return 0;
15357a10d8cSMin Li }
15457a10d8cSMin Li 
15557a10d8cSMin Li /*
15657a10d8cSMin Li  *   TOD Trigger:
15757a10d8cSMin Li  *   Bits[7:4] Write 0x9, MSB write
15857a10d8cSMin Li  *   Bits[3:0] Read 0x9, LSB read
15957a10d8cSMin Li  */
16057a10d8cSMin Li 
16157a10d8cSMin Li static int _idt82p33_settime(struct idt82p33_channel *channel,
16257a10d8cSMin Li 			     struct timespec64 const *ts)
16357a10d8cSMin Li {
16457a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
16557a10d8cSMin Li 	struct timespec64 local_ts = *ts;
16657a10d8cSMin Li 	char buf[TOD_BYTE_COUNT];
16757a10d8cSMin Li 	s64 dynamic_overhead_ns;
16857a10d8cSMin Li 	unsigned char trigger;
16957a10d8cSMin Li 	int err;
17057a10d8cSMin Li 	u8 i;
17157a10d8cSMin Li 
17257a10d8cSMin Li 	trigger = TOD_TRIGGER(HW_TOD_WR_TRIG_SEL_MSB_TOD_CNFG,
17357a10d8cSMin Li 			      HW_TOD_RD_TRIG_SEL_LSB_TOD_STS);
17457a10d8cSMin Li 
17557a10d8cSMin Li 	err = idt82p33_write(idt82p33, channel->dpll_tod_trigger,
17657a10d8cSMin Li 			&trigger, sizeof(trigger));
17757a10d8cSMin Li 
17857a10d8cSMin Li 	if (err)
17957a10d8cSMin Li 		return err;
18057a10d8cSMin Li 
18157a10d8cSMin Li 	if (idt82p33->calculate_overhead_flag) {
18257a10d8cSMin Li 		dynamic_overhead_ns = ktime_to_ns(ktime_get_raw())
18357a10d8cSMin Li 					- ktime_to_ns(idt82p33->start_time);
18457a10d8cSMin Li 
18557a10d8cSMin Li 		timespec64_add_ns(&local_ts, dynamic_overhead_ns);
18657a10d8cSMin Li 
18757a10d8cSMin Li 		idt82p33->calculate_overhead_flag = 0;
18857a10d8cSMin Li 	}
18957a10d8cSMin Li 
19057a10d8cSMin Li 	idt82p33_timespec_to_byte_array(&local_ts, buf);
19157a10d8cSMin Li 
19257a10d8cSMin Li 	/*
19357a10d8cSMin Li 	 * Store the new time value.
19457a10d8cSMin Li 	 */
19557a10d8cSMin Li 	for (i = 0; i < TOD_BYTE_COUNT; i++) {
19657a10d8cSMin Li 		err = idt82p33_write(idt82p33, channel->dpll_tod_cnfg + i,
19757a10d8cSMin Li 				     &buf[i], sizeof(buf[i]));
19857a10d8cSMin Li 		if (err)
19957a10d8cSMin Li 			return err;
20057a10d8cSMin Li 	}
20157a10d8cSMin Li 
20257a10d8cSMin Li 	return err;
20357a10d8cSMin Li }
20457a10d8cSMin Li 
20557a10d8cSMin Li static int _idt82p33_adjtime(struct idt82p33_channel *channel, s64 delta_ns)
20657a10d8cSMin Li {
20757a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
20857a10d8cSMin Li 	struct timespec64 ts;
20957a10d8cSMin Li 	s64 now_ns;
21057a10d8cSMin Li 	int err;
21157a10d8cSMin Li 
21257a10d8cSMin Li 	idt82p33->calculate_overhead_flag = 1;
21357a10d8cSMin Li 
21457a10d8cSMin Li 	err = _idt82p33_gettime(channel, &ts);
21557a10d8cSMin Li 
21657a10d8cSMin Li 	if (err)
21757a10d8cSMin Li 		return err;
21857a10d8cSMin Li 
21957a10d8cSMin Li 	now_ns = timespec64_to_ns(&ts);
22057a10d8cSMin Li 	now_ns += delta_ns + idt82p33->tod_write_overhead_ns;
22157a10d8cSMin Li 
22257a10d8cSMin Li 	ts = ns_to_timespec64(now_ns);
22357a10d8cSMin Li 
22457a10d8cSMin Li 	err = _idt82p33_settime(channel, &ts);
22557a10d8cSMin Li 
22657a10d8cSMin Li 	return err;
22757a10d8cSMin Li }
22857a10d8cSMin Li 
22957a10d8cSMin Li static int _idt82p33_adjfine(struct idt82p33_channel *channel, long scaled_ppm)
23057a10d8cSMin Li {
23157a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
23257a10d8cSMin Li 	unsigned char buf[5] = {0};
23357a10d8cSMin Li 	int err, i;
23457a10d8cSMin Li 	s64 fcw;
23557a10d8cSMin Li 
23657a10d8cSMin Li 	if (scaled_ppm == channel->current_freq_ppb)
23757a10d8cSMin Li 		return 0;
23857a10d8cSMin Li 
23957a10d8cSMin Li 	/*
24057a10d8cSMin Li 	 * Frequency Control Word unit is: 1.68 * 10^-10 ppm
24157a10d8cSMin Li 	 *
24257a10d8cSMin Li 	 * adjfreq:
24357a10d8cSMin Li 	 *       ppb * 10^9
24457a10d8cSMin Li 	 * FCW = ----------
24557a10d8cSMin Li 	 *          168
24657a10d8cSMin Li 	 *
24757a10d8cSMin Li 	 * adjfine:
24857a10d8cSMin Li 	 *       scaled_ppm * 5^12
24957a10d8cSMin Li 	 * FCW = -------------
25057a10d8cSMin Li 	 *         168 * 2^4
25157a10d8cSMin Li 	 */
25257a10d8cSMin Li 
25357a10d8cSMin Li 	fcw = scaled_ppm * 244140625ULL;
2546c196f36SMin Li 	fcw = div_s64(fcw, 2688);
25557a10d8cSMin Li 
25657a10d8cSMin Li 	for (i = 0; i < 5; i++) {
25757a10d8cSMin Li 		buf[i] = fcw & 0xff;
25857a10d8cSMin Li 		fcw >>= 8;
25957a10d8cSMin Li 	}
26057a10d8cSMin Li 
26157a10d8cSMin Li 	err = idt82p33_dpll_set_mode(channel, PLL_MODE_DCO);
26257a10d8cSMin Li 
26357a10d8cSMin Li 	if (err)
26457a10d8cSMin Li 		return err;
26557a10d8cSMin Li 
26657a10d8cSMin Li 	err = idt82p33_write(idt82p33, channel->dpll_freq_cnfg,
26757a10d8cSMin Li 			     buf, sizeof(buf));
26857a10d8cSMin Li 
26957a10d8cSMin Li 	if (err == 0)
27057a10d8cSMin Li 		channel->current_freq_ppb = scaled_ppm;
27157a10d8cSMin Li 
27257a10d8cSMin Li 	return err;
27357a10d8cSMin Li }
27457a10d8cSMin Li 
27557a10d8cSMin Li static int idt82p33_measure_one_byte_write_overhead(
27657a10d8cSMin Li 		struct idt82p33_channel *channel, s64 *overhead_ns)
27757a10d8cSMin Li {
27857a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
27957a10d8cSMin Li 	ktime_t start, stop;
28057a10d8cSMin Li 	s64 total_ns;
28157a10d8cSMin Li 	u8 trigger;
28257a10d8cSMin Li 	int err;
28357a10d8cSMin Li 	u8 i;
28457a10d8cSMin Li 
28557a10d8cSMin Li 	total_ns = 0;
28657a10d8cSMin Li 	*overhead_ns = 0;
28757a10d8cSMin Li 	trigger = TOD_TRIGGER(HW_TOD_WR_TRIG_SEL_MSB_TOD_CNFG,
28857a10d8cSMin Li 			      HW_TOD_RD_TRIG_SEL_LSB_TOD_STS);
28957a10d8cSMin Li 
29057a10d8cSMin Li 	for (i = 0; i < MAX_MEASURMENT_COUNT; i++) {
29157a10d8cSMin Li 
29257a10d8cSMin Li 		start = ktime_get_raw();
29357a10d8cSMin Li 
29457a10d8cSMin Li 		err = idt82p33_write(idt82p33, channel->dpll_tod_trigger,
29557a10d8cSMin Li 				     &trigger, sizeof(trigger));
29657a10d8cSMin Li 
29757a10d8cSMin Li 		stop = ktime_get_raw();
29857a10d8cSMin Li 
29957a10d8cSMin Li 		if (err)
30057a10d8cSMin Li 			return err;
30157a10d8cSMin Li 
30257a10d8cSMin Li 		total_ns += ktime_to_ns(stop) - ktime_to_ns(start);
30357a10d8cSMin Li 	}
30457a10d8cSMin Li 
30557a10d8cSMin Li 	*overhead_ns = div_s64(total_ns, MAX_MEASURMENT_COUNT);
30657a10d8cSMin Li 
30757a10d8cSMin Li 	return err;
30857a10d8cSMin Li }
30957a10d8cSMin Li 
31057a10d8cSMin Li static int idt82p33_measure_tod_write_9_byte_overhead(
31157a10d8cSMin Li 			struct idt82p33_channel *channel)
31257a10d8cSMin Li {
31357a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
31457a10d8cSMin Li 	u8 buf[TOD_BYTE_COUNT];
31557a10d8cSMin Li 	ktime_t start, stop;
31657a10d8cSMin Li 	s64 total_ns;
31757a10d8cSMin Li 	int err = 0;
31857a10d8cSMin Li 	u8 i, j;
31957a10d8cSMin Li 
32057a10d8cSMin Li 	total_ns = 0;
32157a10d8cSMin Li 	idt82p33->tod_write_overhead_ns = 0;
32257a10d8cSMin Li 
32357a10d8cSMin Li 	for (i = 0; i < MAX_MEASURMENT_COUNT; i++) {
32457a10d8cSMin Li 
32557a10d8cSMin Li 		start = ktime_get_raw();
32657a10d8cSMin Li 
32757a10d8cSMin Li 		/* Need one less byte for applicable overhead */
32857a10d8cSMin Li 		for (j = 0; j < (TOD_BYTE_COUNT - 1); j++) {
32957a10d8cSMin Li 			err = idt82p33_write(idt82p33,
33057a10d8cSMin Li 					     channel->dpll_tod_cnfg + i,
33157a10d8cSMin Li 					     &buf[i], sizeof(buf[i]));
33257a10d8cSMin Li 			if (err)
33357a10d8cSMin Li 				return err;
33457a10d8cSMin Li 		}
33557a10d8cSMin Li 
33657a10d8cSMin Li 		stop = ktime_get_raw();
33757a10d8cSMin Li 
33857a10d8cSMin Li 		total_ns += ktime_to_ns(stop) - ktime_to_ns(start);
33957a10d8cSMin Li 	}
34057a10d8cSMin Li 
34157a10d8cSMin Li 	idt82p33->tod_write_overhead_ns = div_s64(total_ns,
34257a10d8cSMin Li 						  MAX_MEASURMENT_COUNT);
34357a10d8cSMin Li 
34457a10d8cSMin Li 	return err;
34557a10d8cSMin Li }
34657a10d8cSMin Li 
34757a10d8cSMin Li static int idt82p33_measure_settime_gettime_gap_overhead(
34857a10d8cSMin Li 		struct idt82p33_channel *channel, s64 *overhead_ns)
34957a10d8cSMin Li {
35057a10d8cSMin Li 	struct timespec64 ts1 = {0, 0};
35157a10d8cSMin Li 	struct timespec64 ts2;
35257a10d8cSMin Li 	int err;
35357a10d8cSMin Li 
35457a10d8cSMin Li 	*overhead_ns = 0;
35557a10d8cSMin Li 
35657a10d8cSMin Li 	err = _idt82p33_settime(channel, &ts1);
35757a10d8cSMin Li 
35857a10d8cSMin Li 	if (err)
35957a10d8cSMin Li 		return err;
36057a10d8cSMin Li 
36157a10d8cSMin Li 	err = _idt82p33_gettime(channel, &ts2);
36257a10d8cSMin Li 
36357a10d8cSMin Li 	if (!err)
36457a10d8cSMin Li 		*overhead_ns = timespec64_to_ns(&ts2) - timespec64_to_ns(&ts1);
36557a10d8cSMin Li 
36657a10d8cSMin Li 	return err;
36757a10d8cSMin Li }
36857a10d8cSMin Li 
36957a10d8cSMin Li static int idt82p33_measure_tod_write_overhead(struct idt82p33_channel *channel)
37057a10d8cSMin Li {
37157a10d8cSMin Li 	s64 trailing_overhead_ns, one_byte_write_ns, gap_ns;
37257a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
37357a10d8cSMin Li 	int err;
37457a10d8cSMin Li 
37557a10d8cSMin Li 	idt82p33->tod_write_overhead_ns = 0;
37657a10d8cSMin Li 
37757a10d8cSMin Li 	err = idt82p33_measure_settime_gettime_gap_overhead(channel, &gap_ns);
37857a10d8cSMin Li 
379e014ae39SMin Li 	if (err) {
380*013a3e7cSMin Li 		dev_err(idt82p33->dev,
381e014ae39SMin Li 			"Failed in %s with err %d!\n", __func__, err);
38257a10d8cSMin Li 		return err;
383e014ae39SMin Li 	}
38457a10d8cSMin Li 
38557a10d8cSMin Li 	err = idt82p33_measure_one_byte_write_overhead(channel,
38657a10d8cSMin Li 						       &one_byte_write_ns);
38757a10d8cSMin Li 
38857a10d8cSMin Li 	if (err)
38957a10d8cSMin Li 		return err;
39057a10d8cSMin Li 
39157a10d8cSMin Li 	err = idt82p33_measure_tod_write_9_byte_overhead(channel);
39257a10d8cSMin Li 
39357a10d8cSMin Li 	if (err)
39457a10d8cSMin Li 		return err;
39557a10d8cSMin Li 
39657a10d8cSMin Li 	trailing_overhead_ns = gap_ns - (2 * one_byte_write_ns);
39757a10d8cSMin Li 
39857a10d8cSMin Li 	idt82p33->tod_write_overhead_ns -= trailing_overhead_ns;
39957a10d8cSMin Li 
40057a10d8cSMin Li 	return err;
40157a10d8cSMin Li }
40257a10d8cSMin Li 
40357a10d8cSMin Li static int idt82p33_check_and_set_masks(struct idt82p33 *idt82p33,
40457a10d8cSMin Li 					u8 page,
40557a10d8cSMin Li 					u8 offset,
40657a10d8cSMin Li 					u8 val)
40757a10d8cSMin Li {
40857a10d8cSMin Li 	int err = 0;
40957a10d8cSMin Li 
41057a10d8cSMin Li 	if (page == PLLMASK_ADDR_HI && offset == PLLMASK_ADDR_LO) {
41157a10d8cSMin Li 		if ((val & 0xfc) || !(val & 0x3)) {
412*013a3e7cSMin Li 			dev_err(idt82p33->dev,
413*013a3e7cSMin Li 				"Invalid PLL mask 0x%x\n", val);
41457a10d8cSMin Li 			err = -EINVAL;
41557a10d8cSMin Li 		} else {
41657a10d8cSMin Li 			idt82p33->pll_mask = val;
41757a10d8cSMin Li 		}
41857a10d8cSMin Li 	} else if (page == PLL0_OUTMASK_ADDR_HI &&
41957a10d8cSMin Li 		offset == PLL0_OUTMASK_ADDR_LO) {
42057a10d8cSMin Li 		idt82p33->channel[0].output_mask = val;
42157a10d8cSMin Li 	} else if (page == PLL1_OUTMASK_ADDR_HI &&
42257a10d8cSMin Li 		offset == PLL1_OUTMASK_ADDR_LO) {
42357a10d8cSMin Li 		idt82p33->channel[1].output_mask = val;
42457a10d8cSMin Li 	}
42557a10d8cSMin Li 
42657a10d8cSMin Li 	return err;
42757a10d8cSMin Li }
42857a10d8cSMin Li 
42957a10d8cSMin Li static void idt82p33_display_masks(struct idt82p33 *idt82p33)
43057a10d8cSMin Li {
43157a10d8cSMin Li 	u8 mask, i;
43257a10d8cSMin Li 
433*013a3e7cSMin Li 	dev_info(idt82p33->dev,
43457a10d8cSMin Li 		 "pllmask = 0x%02x\n", idt82p33->pll_mask);
43557a10d8cSMin Li 
43657a10d8cSMin Li 	for (i = 0; i < MAX_PHC_PLL; i++) {
43757a10d8cSMin Li 		mask = 1 << i;
43857a10d8cSMin Li 
43957a10d8cSMin Li 		if (mask & idt82p33->pll_mask)
440*013a3e7cSMin Li 			dev_info(idt82p33->dev,
44157a10d8cSMin Li 				 "PLL%d output_mask = 0x%04x\n",
44257a10d8cSMin Li 				 i, idt82p33->channel[i].output_mask);
44357a10d8cSMin Li 	}
44457a10d8cSMin Li }
44557a10d8cSMin Li 
44657a10d8cSMin Li static int idt82p33_sync_tod(struct idt82p33_channel *channel, bool enable)
44757a10d8cSMin Li {
44857a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
44957a10d8cSMin Li 	u8 sync_cnfg;
45057a10d8cSMin Li 	int err;
45157a10d8cSMin Li 
45257a10d8cSMin Li 	err = idt82p33_read(idt82p33, channel->dpll_sync_cnfg,
45357a10d8cSMin Li 			    &sync_cnfg, sizeof(sync_cnfg));
45457a10d8cSMin Li 	if (err)
45557a10d8cSMin Li 		return err;
45657a10d8cSMin Li 
45757a10d8cSMin Li 	sync_cnfg &= ~SYNC_TOD;
45857a10d8cSMin Li 	if (enable)
45957a10d8cSMin Li 		sync_cnfg |= SYNC_TOD;
46057a10d8cSMin Li 
461e014ae39SMin Li 	return idt82p33_write(idt82p33, channel->dpll_sync_cnfg,
46257a10d8cSMin Li 			      &sync_cnfg, sizeof(sync_cnfg));
46357a10d8cSMin Li }
46457a10d8cSMin Li 
465e014ae39SMin Li static int idt82p33_output_enable(struct idt82p33_channel *channel,
466e014ae39SMin Li 				  bool enable, unsigned int outn)
46757a10d8cSMin Li {
46857a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
46957a10d8cSMin Li 	int err;
470e014ae39SMin Li 	u8 val;
471e014ae39SMin Li 
472e014ae39SMin Li 	err = idt82p33_read(idt82p33, OUT_MUX_CNFG(outn), &val, sizeof(val));
473e014ae39SMin Li 	if (err)
474e014ae39SMin Li 		return err;
475e014ae39SMin Li 	if (enable)
476e014ae39SMin Li 		val &= ~SQUELCH_ENABLE;
477e014ae39SMin Li 	else
478e014ae39SMin Li 		val |= SQUELCH_ENABLE;
479e014ae39SMin Li 
480e014ae39SMin Li 	return idt82p33_write(idt82p33, OUT_MUX_CNFG(outn), &val, sizeof(val));
481e014ae39SMin Li }
482e014ae39SMin Li 
483e014ae39SMin Li static int idt82p33_output_mask_enable(struct idt82p33_channel *channel,
484e014ae39SMin Li 				       bool enable)
485e014ae39SMin Li {
486e014ae39SMin Li 	u16 mask;
487e014ae39SMin Li 	int err;
488e014ae39SMin Li 	u8 outn;
48957a10d8cSMin Li 
49057a10d8cSMin Li 	mask = channel->output_mask;
49157a10d8cSMin Li 	outn = 0;
49257a10d8cSMin Li 
49357a10d8cSMin Li 	while (mask) {
49457a10d8cSMin Li 		if (mask & 0x1) {
495e014ae39SMin Li 			err = idt82p33_output_enable(channel, enable, outn);
49657a10d8cSMin Li 			if (err)
49757a10d8cSMin Li 				return err;
49857a10d8cSMin Li 		}
499e014ae39SMin Li 
50057a10d8cSMin Li 		mask >>= 0x1;
50157a10d8cSMin Li 		outn++;
50257a10d8cSMin Li 	}
50357a10d8cSMin Li 
50457a10d8cSMin Li 	return 0;
50557a10d8cSMin Li }
50657a10d8cSMin Li 
507e014ae39SMin Li static int idt82p33_perout_enable(struct idt82p33_channel *channel,
508e014ae39SMin Li 				  bool enable,
509e014ae39SMin Li 				  struct ptp_perout_request *perout)
510e014ae39SMin Li {
511e014ae39SMin Li 	unsigned int flags = perout->flags;
512e014ae39SMin Li 
513e014ae39SMin Li 	/* Enable/disable output based on output_mask */
514e014ae39SMin Li 	if (flags == PEROUT_ENABLE_OUTPUT_MASK)
515e014ae39SMin Li 		return idt82p33_output_mask_enable(channel, enable);
516e014ae39SMin Li 
517e014ae39SMin Li 	/* Enable/disable individual output instead */
518e014ae39SMin Li 	return idt82p33_output_enable(channel, enable, perout->index);
519e014ae39SMin Li }
520e014ae39SMin Li 
52157a10d8cSMin Li static int idt82p33_enable_tod(struct idt82p33_channel *channel)
52257a10d8cSMin Li {
52357a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
52457a10d8cSMin Li 	struct timespec64 ts = {0, 0};
52557a10d8cSMin Li 	int err;
52657a10d8cSMin Li 
52757a10d8cSMin Li 	err = idt82p33_measure_tod_write_overhead(channel);
52857a10d8cSMin Li 
529e014ae39SMin Li 	if (err) {
530*013a3e7cSMin Li 		dev_err(idt82p33->dev,
531e014ae39SMin Li 			"Failed in %s with err %d!\n", __func__, err);
53257a10d8cSMin Li 		return err;
533e014ae39SMin Li 	}
53457a10d8cSMin Li 
53557a10d8cSMin Li 	err = _idt82p33_settime(channel, &ts);
53657a10d8cSMin Li 
53757a10d8cSMin Li 	if (err)
53857a10d8cSMin Li 		return err;
53957a10d8cSMin Li 
54057a10d8cSMin Li 	return idt82p33_sync_tod(channel, true);
54157a10d8cSMin Li }
54257a10d8cSMin Li 
54357a10d8cSMin Li static void idt82p33_ptp_clock_unregister_all(struct idt82p33 *idt82p33)
54457a10d8cSMin Li {
54557a10d8cSMin Li 	struct idt82p33_channel *channel;
54657a10d8cSMin Li 	u8 i;
54757a10d8cSMin Li 
54857a10d8cSMin Li 	for (i = 0; i < MAX_PHC_PLL; i++) {
54957a10d8cSMin Li 
55057a10d8cSMin Li 		channel = &idt82p33->channel[i];
55157a10d8cSMin Li 
552e014ae39SMin Li 		if (channel->ptp_clock)
55357a10d8cSMin Li 			ptp_clock_unregister(channel->ptp_clock);
55457a10d8cSMin Li 	}
55557a10d8cSMin Li }
55657a10d8cSMin Li 
55757a10d8cSMin Li static int idt82p33_enable(struct ptp_clock_info *ptp,
55857a10d8cSMin Li 			   struct ptp_clock_request *rq, int on)
55957a10d8cSMin Li {
56057a10d8cSMin Li 	struct idt82p33_channel *channel =
56157a10d8cSMin Li 			container_of(ptp, struct idt82p33_channel, caps);
56257a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
563*013a3e7cSMin Li 	int err = -EOPNOTSUPP;
56457a10d8cSMin Li 
565*013a3e7cSMin Li 	mutex_lock(idt82p33->lock);
56657a10d8cSMin Li 
56757a10d8cSMin Li 	if (rq->type == PTP_CLK_REQ_PEROUT) {
56857a10d8cSMin Li 		if (!on)
569e014ae39SMin Li 			err = idt82p33_perout_enable(channel, false,
570e014ae39SMin Li 						     &rq->perout);
57157a10d8cSMin Li 		/* Only accept a 1-PPS aligned to the second. */
57257a10d8cSMin Li 		else if (rq->perout.start.nsec || rq->perout.period.sec != 1 ||
573*013a3e7cSMin Li 			 rq->perout.period.nsec)
57457a10d8cSMin Li 			err = -ERANGE;
575*013a3e7cSMin Li 		else
576e014ae39SMin Li 			err = idt82p33_perout_enable(channel, true,
577e014ae39SMin Li 						     &rq->perout);
57857a10d8cSMin Li 	}
57957a10d8cSMin Li 
580*013a3e7cSMin Li 	mutex_unlock(idt82p33->lock);
58157a10d8cSMin Li 
582*013a3e7cSMin Li 	if (err)
583*013a3e7cSMin Li 		dev_err(idt82p33->dev,
584*013a3e7cSMin Li 			"Failed in %s with err %d!\n", __func__, err);
58557a10d8cSMin Li 	return err;
58657a10d8cSMin Li }
58757a10d8cSMin Li 
588e014ae39SMin Li static int idt82p33_adjwritephase(struct ptp_clock_info *ptp, s32 offset_ns)
589e014ae39SMin Li {
590e014ae39SMin Li 	struct idt82p33_channel *channel =
591e014ae39SMin Li 		container_of(ptp, struct idt82p33_channel, caps);
592e014ae39SMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
593e014ae39SMin Li 	s64 offset_regval, offset_fs;
594e014ae39SMin Li 	u8 val[4] = {0};
595e014ae39SMin Li 	int err;
596e014ae39SMin Li 
597e014ae39SMin Li 	offset_fs = (s64)(-offset_ns) * 1000000;
598e014ae39SMin Li 
599e014ae39SMin Li 	if (offset_fs > WRITE_PHASE_OFFSET_LIMIT)
600e014ae39SMin Li 		offset_fs = WRITE_PHASE_OFFSET_LIMIT;
601e014ae39SMin Li 	else if (offset_fs < -WRITE_PHASE_OFFSET_LIMIT)
602e014ae39SMin Li 		offset_fs = -WRITE_PHASE_OFFSET_LIMIT;
603e014ae39SMin Li 
604e014ae39SMin Li 	/* Convert from phaseoffset_fs to register value */
605e014ae39SMin Li 	offset_regval = div_s64(offset_fs * 1000, IDT_T0DPLL_PHASE_RESOL);
606e014ae39SMin Li 
607e014ae39SMin Li 	val[0] = offset_regval & 0xFF;
608e014ae39SMin Li 	val[1] = (offset_regval >> 8) & 0xFF;
609e014ae39SMin Li 	val[2] = (offset_regval >> 16) & 0xFF;
610e014ae39SMin Li 	val[3] = (offset_regval >> 24) & 0x1F;
611e014ae39SMin Li 	val[3] |= PH_OFFSET_EN;
612e014ae39SMin Li 
613*013a3e7cSMin Li 	mutex_lock(idt82p33->lock);
614e014ae39SMin Li 
615e014ae39SMin Li 	err = idt82p33_dpll_set_mode(channel, PLL_MODE_WPH);
616e014ae39SMin Li 	if (err) {
617*013a3e7cSMin Li 		dev_err(idt82p33->dev,
618e014ae39SMin Li 			"Failed in %s with err %d!\n", __func__, err);
619e014ae39SMin Li 		goto out;
620e014ae39SMin Li 	}
621e014ae39SMin Li 
622e014ae39SMin Li 	err = idt82p33_write(idt82p33, channel->dpll_phase_cnfg, val,
623e014ae39SMin Li 			     sizeof(val));
624e014ae39SMin Li 
625e014ae39SMin Li out:
626*013a3e7cSMin Li 	mutex_unlock(idt82p33->lock);
627e014ae39SMin Li 	return err;
628e014ae39SMin Li }
629e014ae39SMin Li 
63057a10d8cSMin Li static int idt82p33_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
63157a10d8cSMin Li {
63257a10d8cSMin Li 	struct idt82p33_channel *channel =
63357a10d8cSMin Li 			container_of(ptp, struct idt82p33_channel, caps);
63457a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
63557a10d8cSMin Li 	int err;
63657a10d8cSMin Li 
637*013a3e7cSMin Li 	mutex_lock(idt82p33->lock);
63857a10d8cSMin Li 	err = _idt82p33_adjfine(channel, scaled_ppm);
639*013a3e7cSMin Li 	mutex_unlock(idt82p33->lock);
640e014ae39SMin Li 	if (err)
641*013a3e7cSMin Li 		dev_err(idt82p33->dev,
642e014ae39SMin Li 			"Failed in %s with err %d!\n", __func__, err);
64357a10d8cSMin Li 
64457a10d8cSMin Li 	return err;
64557a10d8cSMin Li }
64657a10d8cSMin Li 
64757a10d8cSMin Li static int idt82p33_adjtime(struct ptp_clock_info *ptp, s64 delta_ns)
64857a10d8cSMin Li {
64957a10d8cSMin Li 	struct idt82p33_channel *channel =
65057a10d8cSMin Li 			container_of(ptp, struct idt82p33_channel, caps);
65157a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
65257a10d8cSMin Li 	int err;
65357a10d8cSMin Li 
654*013a3e7cSMin Li 	mutex_lock(idt82p33->lock);
65557a10d8cSMin Li 
65657a10d8cSMin Li 	if (abs(delta_ns) < phase_snap_threshold) {
657*013a3e7cSMin Li 		mutex_unlock(idt82p33->lock);
65857a10d8cSMin Li 		return 0;
65957a10d8cSMin Li 	}
66057a10d8cSMin Li 
66157a10d8cSMin Li 	err = _idt82p33_adjtime(channel, delta_ns);
66257a10d8cSMin Li 
663*013a3e7cSMin Li 	mutex_unlock(idt82p33->lock);
66457a10d8cSMin Li 
665e014ae39SMin Li 	if (err)
666*013a3e7cSMin Li 		dev_err(idt82p33->dev,
667*013a3e7cSMin Li 			"Failed in %s with err %d!\n", __func__, err);
66857a10d8cSMin Li 	return err;
66957a10d8cSMin Li }
67057a10d8cSMin Li 
67157a10d8cSMin Li static int idt82p33_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
67257a10d8cSMin Li {
67357a10d8cSMin Li 	struct idt82p33_channel *channel =
67457a10d8cSMin Li 			container_of(ptp, struct idt82p33_channel, caps);
67557a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
67657a10d8cSMin Li 	int err;
67757a10d8cSMin Li 
678*013a3e7cSMin Li 	mutex_lock(idt82p33->lock);
67957a10d8cSMin Li 	err = _idt82p33_gettime(channel, ts);
680*013a3e7cSMin Li 	mutex_unlock(idt82p33->lock);
68157a10d8cSMin Li 
682*013a3e7cSMin Li 	if (err)
683*013a3e7cSMin Li 		dev_err(idt82p33->dev,
684*013a3e7cSMin Li 			"Failed in %s with err %d!\n", __func__, err);
68557a10d8cSMin Li 	return err;
68657a10d8cSMin Li }
68757a10d8cSMin Li 
68857a10d8cSMin Li static int idt82p33_settime(struct ptp_clock_info *ptp,
68957a10d8cSMin Li 			    const struct timespec64 *ts)
69057a10d8cSMin Li {
69157a10d8cSMin Li 	struct idt82p33_channel *channel =
69257a10d8cSMin Li 			container_of(ptp, struct idt82p33_channel, caps);
69357a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
69457a10d8cSMin Li 	int err;
69557a10d8cSMin Li 
696*013a3e7cSMin Li 	mutex_lock(idt82p33->lock);
69757a10d8cSMin Li 	err = _idt82p33_settime(channel, ts);
698*013a3e7cSMin Li 	mutex_unlock(idt82p33->lock);
69957a10d8cSMin Li 
700*013a3e7cSMin Li 	if (err)
701*013a3e7cSMin Li 		dev_err(idt82p33->dev,
702*013a3e7cSMin Li 			"Failed in %s with err %d!\n", __func__, err);
70357a10d8cSMin Li 	return err;
70457a10d8cSMin Li }
70557a10d8cSMin Li 
70657a10d8cSMin Li static int idt82p33_channel_init(struct idt82p33_channel *channel, int index)
70757a10d8cSMin Li {
70857a10d8cSMin Li 	switch (index) {
70957a10d8cSMin Li 	case 0:
71057a10d8cSMin Li 		channel->dpll_tod_cnfg = DPLL1_TOD_CNFG;
71157a10d8cSMin Li 		channel->dpll_tod_trigger = DPLL1_TOD_TRIGGER;
71257a10d8cSMin Li 		channel->dpll_tod_sts = DPLL1_TOD_STS;
71357a10d8cSMin Li 		channel->dpll_mode_cnfg = DPLL1_OPERATING_MODE_CNFG;
71457a10d8cSMin Li 		channel->dpll_freq_cnfg = DPLL1_HOLDOVER_FREQ_CNFG;
71557a10d8cSMin Li 		channel->dpll_phase_cnfg = DPLL1_PHASE_OFFSET_CNFG;
71657a10d8cSMin Li 		channel->dpll_sync_cnfg = DPLL1_SYNC_EDGE_CNFG;
71757a10d8cSMin Li 		channel->dpll_input_mode_cnfg = DPLL1_INPUT_MODE_CNFG;
71857a10d8cSMin Li 		break;
71957a10d8cSMin Li 	case 1:
72057a10d8cSMin Li 		channel->dpll_tod_cnfg = DPLL2_TOD_CNFG;
72157a10d8cSMin Li 		channel->dpll_tod_trigger = DPLL2_TOD_TRIGGER;
72257a10d8cSMin Li 		channel->dpll_tod_sts = DPLL2_TOD_STS;
72357a10d8cSMin Li 		channel->dpll_mode_cnfg = DPLL2_OPERATING_MODE_CNFG;
72457a10d8cSMin Li 		channel->dpll_freq_cnfg = DPLL2_HOLDOVER_FREQ_CNFG;
72557a10d8cSMin Li 		channel->dpll_phase_cnfg = DPLL2_PHASE_OFFSET_CNFG;
72657a10d8cSMin Li 		channel->dpll_sync_cnfg = DPLL2_SYNC_EDGE_CNFG;
72757a10d8cSMin Li 		channel->dpll_input_mode_cnfg = DPLL2_INPUT_MODE_CNFG;
72857a10d8cSMin Li 		break;
72957a10d8cSMin Li 	default:
73057a10d8cSMin Li 		return -EINVAL;
73157a10d8cSMin Li 	}
73257a10d8cSMin Li 
73357a10d8cSMin Li 	channel->current_freq_ppb = 0;
73457a10d8cSMin Li 
73557a10d8cSMin Li 	return 0;
73657a10d8cSMin Li }
73757a10d8cSMin Li 
73857a10d8cSMin Li static void idt82p33_caps_init(struct ptp_clock_info *caps)
73957a10d8cSMin Li {
74057a10d8cSMin Li 	caps->owner = THIS_MODULE;
741*013a3e7cSMin Li 	caps->max_adj = DCO_MAX_PPB;
742e014ae39SMin Li 	caps->n_per_out = 11;
743e014ae39SMin Li 	caps->adjphase = idt82p33_adjwritephase;
74457a10d8cSMin Li 	caps->adjfine = idt82p33_adjfine;
74557a10d8cSMin Li 	caps->adjtime = idt82p33_adjtime;
74657a10d8cSMin Li 	caps->gettime64 = idt82p33_gettime;
74757a10d8cSMin Li 	caps->settime64 = idt82p33_settime;
74857a10d8cSMin Li 	caps->enable = idt82p33_enable;
74957a10d8cSMin Li }
75057a10d8cSMin Li 
75157a10d8cSMin Li static int idt82p33_enable_channel(struct idt82p33 *idt82p33, u32 index)
75257a10d8cSMin Li {
75357a10d8cSMin Li 	struct idt82p33_channel *channel;
75457a10d8cSMin Li 	int err;
75557a10d8cSMin Li 
75657a10d8cSMin Li 	if (!(index < MAX_PHC_PLL))
75757a10d8cSMin Li 		return -EINVAL;
75857a10d8cSMin Li 
75957a10d8cSMin Li 	channel = &idt82p33->channel[index];
76057a10d8cSMin Li 
76157a10d8cSMin Li 	err = idt82p33_channel_init(channel, index);
762e014ae39SMin Li 	if (err) {
763*013a3e7cSMin Li 		dev_err(idt82p33->dev,
764e014ae39SMin Li 			"Channel_init failed in %s with err %d!\n",
765e014ae39SMin Li 			__func__, err);
76657a10d8cSMin Li 		return err;
767e014ae39SMin Li 	}
76857a10d8cSMin Li 
76957a10d8cSMin Li 	channel->idt82p33 = idt82p33;
77057a10d8cSMin Li 
77157a10d8cSMin Li 	idt82p33_caps_init(&channel->caps);
77257a10d8cSMin Li 	snprintf(channel->caps.name, sizeof(channel->caps.name),
77357a10d8cSMin Li 		 "IDT 82P33 PLL%u", index);
77457a10d8cSMin Li 
77557a10d8cSMin Li 	channel->ptp_clock = ptp_clock_register(&channel->caps, NULL);
77657a10d8cSMin Li 
77757a10d8cSMin Li 	if (IS_ERR(channel->ptp_clock)) {
77857a10d8cSMin Li 		err = PTR_ERR(channel->ptp_clock);
77957a10d8cSMin Li 		channel->ptp_clock = NULL;
78057a10d8cSMin Li 		return err;
78157a10d8cSMin Li 	}
78257a10d8cSMin Li 
78357a10d8cSMin Li 	if (!channel->ptp_clock)
78457a10d8cSMin Li 		return -ENOTSUPP;
78557a10d8cSMin Li 
786e014ae39SMin Li 	err = idt82p33_dpll_set_mode(channel, PLL_MODE_DCO);
787e014ae39SMin Li 	if (err) {
788*013a3e7cSMin Li 		dev_err(idt82p33->dev,
789e014ae39SMin Li 			"Dpll_set_mode failed in %s with err %d!\n",
790e014ae39SMin Li 			__func__, err);
791e014ae39SMin Li 		return err;
792e014ae39SMin Li 	}
793e014ae39SMin Li 
794e014ae39SMin Li 	err = idt82p33_enable_tod(channel);
795e014ae39SMin Li 	if (err) {
796*013a3e7cSMin Li 		dev_err(idt82p33->dev,
797e014ae39SMin Li 			"Enable_tod failed in %s with err %d!\n",
798e014ae39SMin Li 			__func__, err);
799e014ae39SMin Li 		return err;
800e014ae39SMin Li 	}
801e014ae39SMin Li 
802*013a3e7cSMin Li 	dev_info(idt82p33->dev, "PLL%d registered as ptp%d\n",
80357a10d8cSMin Li 		 index, channel->ptp_clock->index);
80457a10d8cSMin Li 
80557a10d8cSMin Li 	return 0;
80657a10d8cSMin Li }
80757a10d8cSMin Li 
80857a10d8cSMin Li static int idt82p33_load_firmware(struct idt82p33 *idt82p33)
80957a10d8cSMin Li {
81057a10d8cSMin Li 	const struct firmware *fw;
81157a10d8cSMin Li 	struct idt82p33_fwrc *rec;
81257a10d8cSMin Li 	u8 loaddr, page, val;
81357a10d8cSMin Li 	int err;
81457a10d8cSMin Li 	s32 len;
81557a10d8cSMin Li 
816*013a3e7cSMin Li 	dev_dbg(idt82p33->dev, "requesting firmware '%s'\n", FW_FILENAME);
81757a10d8cSMin Li 
818*013a3e7cSMin Li 	err = request_firmware(&fw, FW_FILENAME, idt82p33->dev);
81957a10d8cSMin Li 
820e014ae39SMin Li 	if (err) {
821*013a3e7cSMin Li 		dev_err(idt82p33->dev,
822e014ae39SMin Li 			"Failed in %s with err %d!\n", __func__, err);
82357a10d8cSMin Li 		return err;
824e014ae39SMin Li 	}
82557a10d8cSMin Li 
826*013a3e7cSMin Li 	dev_dbg(idt82p33->dev, "firmware size %zu bytes\n", fw->size);
82757a10d8cSMin Li 
82857a10d8cSMin Li 	rec = (struct idt82p33_fwrc *) fw->data;
82957a10d8cSMin Li 
83057a10d8cSMin Li 	for (len = fw->size; len > 0; len -= sizeof(*rec)) {
83157a10d8cSMin Li 
83257a10d8cSMin Li 		if (rec->reserved) {
833*013a3e7cSMin Li 			dev_err(idt82p33->dev,
83457a10d8cSMin Li 				"bad firmware, reserved field non-zero\n");
83557a10d8cSMin Li 			err = -EINVAL;
83657a10d8cSMin Li 		} else {
83757a10d8cSMin Li 			val = rec->value;
83857a10d8cSMin Li 			loaddr = rec->loaddr;
83957a10d8cSMin Li 			page = rec->hiaddr;
84057a10d8cSMin Li 
84157a10d8cSMin Li 			rec++;
84257a10d8cSMin Li 
84357a10d8cSMin Li 			err = idt82p33_check_and_set_masks(idt82p33, page,
84457a10d8cSMin Li 							   loaddr, val);
84557a10d8cSMin Li 		}
84657a10d8cSMin Li 
84757a10d8cSMin Li 		if (err == 0) {
84857a10d8cSMin Li 			/* Page size 128, last 4 bytes of page skipped */
849*013a3e7cSMin Li 			if (loaddr > 0x7b)
85057a10d8cSMin Li 				continue;
85157a10d8cSMin Li 
852*013a3e7cSMin Li 			err = idt82p33_write(idt82p33, REG_ADDR(page, loaddr),
85357a10d8cSMin Li 					     &val, sizeof(val));
85457a10d8cSMin Li 		}
85557a10d8cSMin Li 
85657a10d8cSMin Li 		if (err)
85757a10d8cSMin Li 			goto out;
85857a10d8cSMin Li 	}
85957a10d8cSMin Li 
86057a10d8cSMin Li 	idt82p33_display_masks(idt82p33);
86157a10d8cSMin Li out:
86257a10d8cSMin Li 	release_firmware(fw);
86357a10d8cSMin Li 	return err;
86457a10d8cSMin Li }
86557a10d8cSMin Li 
86657a10d8cSMin Li 
867*013a3e7cSMin Li static int idt82p33_probe(struct platform_device *pdev)
86857a10d8cSMin Li {
869*013a3e7cSMin Li 	struct rsmu_ddata *ddata = dev_get_drvdata(pdev->dev.parent);
87057a10d8cSMin Li 	struct idt82p33 *idt82p33;
87157a10d8cSMin Li 	int err;
87257a10d8cSMin Li 	u8 i;
87357a10d8cSMin Li 
874*013a3e7cSMin Li 	idt82p33 = devm_kzalloc(&pdev->dev,
87557a10d8cSMin Li 				sizeof(struct idt82p33), GFP_KERNEL);
87657a10d8cSMin Li 	if (!idt82p33)
87757a10d8cSMin Li 		return -ENOMEM;
87857a10d8cSMin Li 
879*013a3e7cSMin Li 	idt82p33->dev = &pdev->dev;
880*013a3e7cSMin Li 	idt82p33->mfd = pdev->dev.parent;
881*013a3e7cSMin Li 	idt82p33->lock = &ddata->lock;
882*013a3e7cSMin Li 	idt82p33->regmap = ddata->regmap;
88357a10d8cSMin Li 	idt82p33->tod_write_overhead_ns = 0;
88457a10d8cSMin Li 	idt82p33->calculate_overhead_flag = 0;
88557a10d8cSMin Li 	idt82p33->pll_mask = DEFAULT_PLL_MASK;
88657a10d8cSMin Li 	idt82p33->channel[0].output_mask = DEFAULT_OUTPUT_MASK_PLL0;
88757a10d8cSMin Li 	idt82p33->channel[1].output_mask = DEFAULT_OUTPUT_MASK_PLL1;
88857a10d8cSMin Li 
889*013a3e7cSMin Li 	mutex_lock(idt82p33->lock);
89057a10d8cSMin Li 
89157a10d8cSMin Li 	err = idt82p33_load_firmware(idt82p33);
89257a10d8cSMin Li 
89357a10d8cSMin Li 	if (err)
894*013a3e7cSMin Li 		dev_warn(idt82p33->dev,
89557a10d8cSMin Li 			 "loading firmware failed with %d\n", err);
89657a10d8cSMin Li 
89757a10d8cSMin Li 	if (idt82p33->pll_mask) {
89857a10d8cSMin Li 		for (i = 0; i < MAX_PHC_PLL; i++) {
89957a10d8cSMin Li 			if (idt82p33->pll_mask & (1 << i)) {
90057a10d8cSMin Li 				err = idt82p33_enable_channel(idt82p33, i);
901e014ae39SMin Li 				if (err) {
902*013a3e7cSMin Li 					dev_err(idt82p33->dev,
903e014ae39SMin Li 						"Failed in %s with err %d!\n",
904e014ae39SMin Li 						__func__, err);
90557a10d8cSMin Li 					break;
90657a10d8cSMin Li 				}
90757a10d8cSMin Li 			}
908e014ae39SMin Li 		}
90957a10d8cSMin Li 	} else {
910*013a3e7cSMin Li 		dev_err(idt82p33->dev,
91157a10d8cSMin Li 			"no PLLs flagged as PHCs, nothing to do\n");
91257a10d8cSMin Li 		err = -ENODEV;
91357a10d8cSMin Li 	}
91457a10d8cSMin Li 
915*013a3e7cSMin Li 	mutex_unlock(idt82p33->lock);
91657a10d8cSMin Li 
91757a10d8cSMin Li 	if (err) {
91857a10d8cSMin Li 		idt82p33_ptp_clock_unregister_all(idt82p33);
91957a10d8cSMin Li 		return err;
92057a10d8cSMin Li 	}
92157a10d8cSMin Li 
922*013a3e7cSMin Li 	platform_set_drvdata(pdev, idt82p33);
92357a10d8cSMin Li 
92457a10d8cSMin Li 	return 0;
92557a10d8cSMin Li }
92657a10d8cSMin Li 
927*013a3e7cSMin Li static int idt82p33_remove(struct platform_device *pdev)
92857a10d8cSMin Li {
929*013a3e7cSMin Li 	struct idt82p33 *idt82p33 = platform_get_drvdata(pdev);
93057a10d8cSMin Li 
93157a10d8cSMin Li 	idt82p33_ptp_clock_unregister_all(idt82p33);
93257a10d8cSMin Li 
93357a10d8cSMin Li 	return 0;
93457a10d8cSMin Li }
93557a10d8cSMin Li 
936*013a3e7cSMin Li static struct platform_driver idt82p33_driver = {
93757a10d8cSMin Li 	.driver = {
938*013a3e7cSMin Li 		.name = "82p33x1x-phc",
93957a10d8cSMin Li 	},
94057a10d8cSMin Li 	.probe = idt82p33_probe,
94157a10d8cSMin Li 	.remove	= idt82p33_remove,
94257a10d8cSMin Li };
94357a10d8cSMin Li 
944*013a3e7cSMin Li module_platform_driver(idt82p33_driver);
945