xref: /linux/drivers/ptp/ptp_idt82p33.c (revision d30e1c3db96467f1f444d84023c2c37821202aeb)
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>
957a10d8cSMin Li #include <linux/i2c.h>
1057a10d8cSMin Li #include <linux/module.h>
1157a10d8cSMin Li #include <linux/ptp_clock_kernel.h>
1257a10d8cSMin Li #include <linux/delay.h>
1357a10d8cSMin Li #include <linux/kernel.h>
1457a10d8cSMin Li #include <linux/timekeeping.h>
1557a10d8cSMin Li #include <linux/bitops.h>
1657a10d8cSMin Li 
1757a10d8cSMin Li #include "ptp_private.h"
1857a10d8cSMin Li #include "ptp_idt82p33.h"
1957a10d8cSMin Li 
2057a10d8cSMin Li MODULE_DESCRIPTION("Driver for IDT 82p33xxx clock devices");
2157a10d8cSMin Li MODULE_AUTHOR("IDT support-1588 <IDT-support-1588@lm.renesas.com>");
2257a10d8cSMin Li MODULE_VERSION("1.0");
2357a10d8cSMin Li MODULE_LICENSE("GPL");
2457a10d8cSMin Li 
2557a10d8cSMin Li /* Module Parameters */
26*d30e1c3dSYueHaibing static u32 sync_tod_timeout = SYNC_TOD_TIMEOUT_SEC;
2757a10d8cSMin Li module_param(sync_tod_timeout, uint, 0);
2857a10d8cSMin Li MODULE_PARM_DESC(sync_tod_timeout,
2957a10d8cSMin Li "duration in second to keep SYNC_TOD on (set to 0 to keep it always on)");
3057a10d8cSMin Li 
31*d30e1c3dSYueHaibing 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,
3457a10d8cSMin Li "threshold (150000ns by default) below which adjtime would ignore");
3557a10d8cSMin Li 
3657a10d8cSMin Li static void idt82p33_byte_array_to_timespec(struct timespec64 *ts,
3757a10d8cSMin Li 					    u8 buf[TOD_BYTE_COUNT])
3857a10d8cSMin Li {
3957a10d8cSMin Li 	time64_t sec;
4057a10d8cSMin Li 	s32 nsec;
4157a10d8cSMin Li 	u8 i;
4257a10d8cSMin Li 
4357a10d8cSMin Li 	nsec = buf[3];
4457a10d8cSMin Li 	for (i = 0; i < 3; i++) {
4557a10d8cSMin Li 		nsec <<= 8;
4657a10d8cSMin Li 		nsec |= buf[2 - i];
4757a10d8cSMin Li 	}
4857a10d8cSMin Li 
4957a10d8cSMin Li 	sec = buf[9];
5057a10d8cSMin Li 	for (i = 0; i < 5; i++) {
5157a10d8cSMin Li 		sec <<= 8;
5257a10d8cSMin Li 		sec |= buf[8 - i];
5357a10d8cSMin Li 	}
5457a10d8cSMin Li 
5557a10d8cSMin Li 	ts->tv_sec = sec;
5657a10d8cSMin Li 	ts->tv_nsec = nsec;
5757a10d8cSMin Li }
5857a10d8cSMin Li 
5957a10d8cSMin Li static void idt82p33_timespec_to_byte_array(struct timespec64 const *ts,
6057a10d8cSMin Li 					    u8 buf[TOD_BYTE_COUNT])
6157a10d8cSMin Li {
6257a10d8cSMin Li 	time64_t sec;
6357a10d8cSMin Li 	s32 nsec;
6457a10d8cSMin Li 	u8 i;
6557a10d8cSMin Li 
6657a10d8cSMin Li 	nsec = ts->tv_nsec;
6757a10d8cSMin Li 	sec = ts->tv_sec;
6857a10d8cSMin Li 
6957a10d8cSMin Li 	for (i = 0; i < 4; i++) {
7057a10d8cSMin Li 		buf[i] = nsec & 0xff;
7157a10d8cSMin Li 		nsec >>= 8;
7257a10d8cSMin Li 	}
7357a10d8cSMin Li 
7457a10d8cSMin Li 	for (i = 4; i < TOD_BYTE_COUNT; i++) {
7557a10d8cSMin Li 		buf[i] = sec & 0xff;
7657a10d8cSMin Li 		sec >>= 8;
7757a10d8cSMin Li 	}
7857a10d8cSMin Li }
7957a10d8cSMin Li 
8057a10d8cSMin Li static int idt82p33_xfer(struct idt82p33 *idt82p33,
8157a10d8cSMin Li 			 unsigned char regaddr,
8257a10d8cSMin Li 			 unsigned char *buf,
8357a10d8cSMin Li 			 unsigned int count,
8457a10d8cSMin Li 			 int write)
8557a10d8cSMin Li {
8657a10d8cSMin Li 	struct i2c_client *client = idt82p33->client;
8757a10d8cSMin Li 	struct i2c_msg msg[2];
8857a10d8cSMin Li 	int cnt;
8957a10d8cSMin Li 
9057a10d8cSMin Li 	msg[0].addr = client->addr;
9157a10d8cSMin Li 	msg[0].flags = 0;
9257a10d8cSMin Li 	msg[0].len = 1;
9357a10d8cSMin Li 	msg[0].buf = &regaddr;
9457a10d8cSMin Li 
9557a10d8cSMin Li 	msg[1].addr = client->addr;
9657a10d8cSMin Li 	msg[1].flags = write ? 0 : I2C_M_RD;
9757a10d8cSMin Li 	msg[1].len = count;
9857a10d8cSMin Li 	msg[1].buf = buf;
9957a10d8cSMin Li 
10057a10d8cSMin Li 	cnt = i2c_transfer(client->adapter, msg, 2);
10157a10d8cSMin Li 	if (cnt < 0) {
10257a10d8cSMin Li 		dev_err(&client->dev, "i2c_transfer returned %d\n", cnt);
10357a10d8cSMin Li 		return cnt;
10457a10d8cSMin Li 	} else if (cnt != 2) {
10557a10d8cSMin Li 		dev_err(&client->dev,
10657a10d8cSMin Li 			"i2c_transfer sent only %d of %d messages\n", cnt, 2);
10757a10d8cSMin Li 		return -EIO;
10857a10d8cSMin Li 	}
10957a10d8cSMin Li 	return 0;
11057a10d8cSMin Li }
11157a10d8cSMin Li 
11257a10d8cSMin Li static int idt82p33_page_offset(struct idt82p33 *idt82p33, unsigned char val)
11357a10d8cSMin Li {
11457a10d8cSMin Li 	int err;
11557a10d8cSMin Li 
11657a10d8cSMin Li 	if (idt82p33->page_offset == val)
11757a10d8cSMin Li 		return 0;
11857a10d8cSMin Li 
11957a10d8cSMin Li 	err = idt82p33_xfer(idt82p33, PAGE_ADDR, &val, sizeof(val), 1);
12057a10d8cSMin Li 	if (err)
12157a10d8cSMin Li 		dev_err(&idt82p33->client->dev,
12257a10d8cSMin Li 			"failed to set page offset %d\n", val);
12357a10d8cSMin Li 	else
12457a10d8cSMin Li 		idt82p33->page_offset = val;
12557a10d8cSMin Li 
12657a10d8cSMin Li 	return err;
12757a10d8cSMin Li }
12857a10d8cSMin Li 
12957a10d8cSMin Li static int idt82p33_rdwr(struct idt82p33 *idt82p33, unsigned int regaddr,
13057a10d8cSMin Li 			 unsigned char *buf, unsigned int count, bool write)
13157a10d8cSMin Li {
13257a10d8cSMin Li 	u8 offset, page;
13357a10d8cSMin Li 	int err;
13457a10d8cSMin Li 
13557a10d8cSMin Li 	page = _PAGE(regaddr);
13657a10d8cSMin Li 	offset = _OFFSET(regaddr);
13757a10d8cSMin Li 
13857a10d8cSMin Li 	err = idt82p33_page_offset(idt82p33, page);
13957a10d8cSMin Li 	if (err)
14057a10d8cSMin Li 		goto out;
14157a10d8cSMin Li 
14257a10d8cSMin Li 	err = idt82p33_xfer(idt82p33, offset, buf, count, write);
14357a10d8cSMin Li out:
14457a10d8cSMin Li 	return err;
14557a10d8cSMin Li }
14657a10d8cSMin Li 
14757a10d8cSMin Li static int idt82p33_read(struct idt82p33 *idt82p33, unsigned int regaddr,
14857a10d8cSMin Li 			unsigned char *buf, unsigned int count)
14957a10d8cSMin Li {
15057a10d8cSMin Li 	return idt82p33_rdwr(idt82p33, regaddr, buf, count, false);
15157a10d8cSMin Li }
15257a10d8cSMin Li 
15357a10d8cSMin Li static int idt82p33_write(struct idt82p33 *idt82p33, unsigned int regaddr,
15457a10d8cSMin Li 			unsigned char *buf, unsigned int count)
15557a10d8cSMin Li {
15657a10d8cSMin Li 	return idt82p33_rdwr(idt82p33, regaddr, buf, count, true);
15757a10d8cSMin Li }
15857a10d8cSMin Li 
15957a10d8cSMin Li static int idt82p33_dpll_set_mode(struct idt82p33_channel *channel,
16057a10d8cSMin Li 				  enum pll_mode mode)
16157a10d8cSMin Li {
16257a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
16357a10d8cSMin Li 	u8 dpll_mode;
16457a10d8cSMin Li 	int err;
16557a10d8cSMin Li 
16657a10d8cSMin Li 	if (channel->pll_mode == mode)
16757a10d8cSMin Li 		return 0;
16857a10d8cSMin Li 
16957a10d8cSMin Li 	err = idt82p33_read(idt82p33, channel->dpll_mode_cnfg,
17057a10d8cSMin Li 			    &dpll_mode, sizeof(dpll_mode));
17157a10d8cSMin Li 	if (err)
17257a10d8cSMin Li 		return err;
17357a10d8cSMin Li 
17457a10d8cSMin Li 	dpll_mode &= ~(PLL_MODE_MASK << PLL_MODE_SHIFT);
17557a10d8cSMin Li 
17657a10d8cSMin Li 	dpll_mode |= (mode << PLL_MODE_SHIFT);
17757a10d8cSMin Li 
17857a10d8cSMin Li 	err = idt82p33_write(idt82p33, channel->dpll_mode_cnfg,
17957a10d8cSMin Li 			     &dpll_mode, sizeof(dpll_mode));
18057a10d8cSMin Li 	if (err)
18157a10d8cSMin Li 		return err;
18257a10d8cSMin Li 
18357a10d8cSMin Li 	channel->pll_mode = dpll_mode;
18457a10d8cSMin Li 
18557a10d8cSMin Li 	return 0;
18657a10d8cSMin Li }
18757a10d8cSMin Li 
18857a10d8cSMin Li static int _idt82p33_gettime(struct idt82p33_channel *channel,
18957a10d8cSMin Li 			     struct timespec64 *ts)
19057a10d8cSMin Li {
19157a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
19257a10d8cSMin Li 	u8 buf[TOD_BYTE_COUNT];
19357a10d8cSMin Li 	u8 trigger;
19457a10d8cSMin Li 	int err;
19557a10d8cSMin Li 
19657a10d8cSMin Li 	trigger = TOD_TRIGGER(HW_TOD_WR_TRIG_SEL_MSB_TOD_CNFG,
19757a10d8cSMin Li 			      HW_TOD_RD_TRIG_SEL_LSB_TOD_STS);
19857a10d8cSMin Li 
19957a10d8cSMin Li 
20057a10d8cSMin Li 	err = idt82p33_write(idt82p33, channel->dpll_tod_trigger,
20157a10d8cSMin Li 			     &trigger, sizeof(trigger));
20257a10d8cSMin Li 
20357a10d8cSMin Li 	if (err)
20457a10d8cSMin Li 		return err;
20557a10d8cSMin Li 
20657a10d8cSMin Li 	if (idt82p33->calculate_overhead_flag)
20757a10d8cSMin Li 		idt82p33->start_time = ktime_get_raw();
20857a10d8cSMin Li 
20957a10d8cSMin Li 	err = idt82p33_read(idt82p33, channel->dpll_tod_sts, buf, sizeof(buf));
21057a10d8cSMin Li 
21157a10d8cSMin Li 	if (err)
21257a10d8cSMin Li 		return err;
21357a10d8cSMin Li 
21457a10d8cSMin Li 	idt82p33_byte_array_to_timespec(ts, buf);
21557a10d8cSMin Li 
21657a10d8cSMin Li 	return 0;
21757a10d8cSMin Li }
21857a10d8cSMin Li 
21957a10d8cSMin Li /*
22057a10d8cSMin Li  *   TOD Trigger:
22157a10d8cSMin Li  *   Bits[7:4] Write 0x9, MSB write
22257a10d8cSMin Li  *   Bits[3:0] Read 0x9, LSB read
22357a10d8cSMin Li  */
22457a10d8cSMin Li 
22557a10d8cSMin Li static int _idt82p33_settime(struct idt82p33_channel *channel,
22657a10d8cSMin Li 			     struct timespec64 const *ts)
22757a10d8cSMin Li {
22857a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
22957a10d8cSMin Li 	struct timespec64 local_ts = *ts;
23057a10d8cSMin Li 	char buf[TOD_BYTE_COUNT];
23157a10d8cSMin Li 	s64 dynamic_overhead_ns;
23257a10d8cSMin Li 	unsigned char trigger;
23357a10d8cSMin Li 	int err;
23457a10d8cSMin Li 	u8 i;
23557a10d8cSMin Li 
23657a10d8cSMin Li 	trigger = TOD_TRIGGER(HW_TOD_WR_TRIG_SEL_MSB_TOD_CNFG,
23757a10d8cSMin Li 			      HW_TOD_RD_TRIG_SEL_LSB_TOD_STS);
23857a10d8cSMin Li 
23957a10d8cSMin Li 	err = idt82p33_write(idt82p33, channel->dpll_tod_trigger,
24057a10d8cSMin Li 			&trigger, sizeof(trigger));
24157a10d8cSMin Li 
24257a10d8cSMin Li 	if (err)
24357a10d8cSMin Li 		return err;
24457a10d8cSMin Li 
24557a10d8cSMin Li 	if (idt82p33->calculate_overhead_flag) {
24657a10d8cSMin Li 		dynamic_overhead_ns = ktime_to_ns(ktime_get_raw())
24757a10d8cSMin Li 					- ktime_to_ns(idt82p33->start_time);
24857a10d8cSMin Li 
24957a10d8cSMin Li 		timespec64_add_ns(&local_ts, dynamic_overhead_ns);
25057a10d8cSMin Li 
25157a10d8cSMin Li 		idt82p33->calculate_overhead_flag = 0;
25257a10d8cSMin Li 	}
25357a10d8cSMin Li 
25457a10d8cSMin Li 	idt82p33_timespec_to_byte_array(&local_ts, buf);
25557a10d8cSMin Li 
25657a10d8cSMin Li 	/*
25757a10d8cSMin Li 	 * Store the new time value.
25857a10d8cSMin Li 	 */
25957a10d8cSMin Li 	for (i = 0; i < TOD_BYTE_COUNT; i++) {
26057a10d8cSMin Li 		err = idt82p33_write(idt82p33, channel->dpll_tod_cnfg + i,
26157a10d8cSMin Li 				     &buf[i], sizeof(buf[i]));
26257a10d8cSMin Li 		if (err)
26357a10d8cSMin Li 			return err;
26457a10d8cSMin Li 	}
26557a10d8cSMin Li 
26657a10d8cSMin Li 	return err;
26757a10d8cSMin Li }
26857a10d8cSMin Li 
26957a10d8cSMin Li static int _idt82p33_adjtime(struct idt82p33_channel *channel, s64 delta_ns)
27057a10d8cSMin Li {
27157a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
27257a10d8cSMin Li 	struct timespec64 ts;
27357a10d8cSMin Li 	s64 now_ns;
27457a10d8cSMin Li 	int err;
27557a10d8cSMin Li 
27657a10d8cSMin Li 	idt82p33->calculate_overhead_flag = 1;
27757a10d8cSMin Li 
27857a10d8cSMin Li 	err = _idt82p33_gettime(channel, &ts);
27957a10d8cSMin Li 
28057a10d8cSMin Li 	if (err)
28157a10d8cSMin Li 		return err;
28257a10d8cSMin Li 
28357a10d8cSMin Li 	now_ns = timespec64_to_ns(&ts);
28457a10d8cSMin Li 	now_ns += delta_ns + idt82p33->tod_write_overhead_ns;
28557a10d8cSMin Li 
28657a10d8cSMin Li 	ts = ns_to_timespec64(now_ns);
28757a10d8cSMin Li 
28857a10d8cSMin Li 	err = _idt82p33_settime(channel, &ts);
28957a10d8cSMin Li 
29057a10d8cSMin Li 	return err;
29157a10d8cSMin Li }
29257a10d8cSMin Li 
29357a10d8cSMin Li static int _idt82p33_adjfine(struct idt82p33_channel *channel, long scaled_ppm)
29457a10d8cSMin Li {
29557a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
29657a10d8cSMin Li 	unsigned char buf[5] = {0};
29757a10d8cSMin Li 	int neg_adj = 0;
29857a10d8cSMin Li 	int err, i;
29957a10d8cSMin Li 	s64 fcw;
30057a10d8cSMin Li 
30157a10d8cSMin Li 	if (scaled_ppm == channel->current_freq_ppb)
30257a10d8cSMin Li 		return 0;
30357a10d8cSMin Li 
30457a10d8cSMin Li 	/*
30557a10d8cSMin Li 	 * Frequency Control Word unit is: 1.68 * 10^-10 ppm
30657a10d8cSMin Li 	 *
30757a10d8cSMin Li 	 * adjfreq:
30857a10d8cSMin Li 	 *       ppb * 10^9
30957a10d8cSMin Li 	 * FCW = ----------
31057a10d8cSMin Li 	 *          168
31157a10d8cSMin Li 	 *
31257a10d8cSMin Li 	 * adjfine:
31357a10d8cSMin Li 	 *       scaled_ppm * 5^12
31457a10d8cSMin Li 	 * FCW = -------------
31557a10d8cSMin Li 	 *         168 * 2^4
31657a10d8cSMin Li 	 */
31757a10d8cSMin Li 	if (scaled_ppm < 0) {
31857a10d8cSMin Li 		neg_adj = 1;
31957a10d8cSMin Li 		scaled_ppm = -scaled_ppm;
32057a10d8cSMin Li 	}
32157a10d8cSMin Li 
32257a10d8cSMin Li 	fcw = scaled_ppm * 244140625ULL;
32357a10d8cSMin Li 	fcw = div_u64(fcw, 2688);
32457a10d8cSMin Li 
32557a10d8cSMin Li 	if (neg_adj)
32657a10d8cSMin Li 		fcw = -fcw;
32757a10d8cSMin Li 
32857a10d8cSMin Li 	for (i = 0; i < 5; i++) {
32957a10d8cSMin Li 		buf[i] = fcw & 0xff;
33057a10d8cSMin Li 		fcw >>= 8;
33157a10d8cSMin Li 	}
33257a10d8cSMin Li 
33357a10d8cSMin Li 	err = idt82p33_dpll_set_mode(channel, PLL_MODE_DCO);
33457a10d8cSMin Li 
33557a10d8cSMin Li 	if (err)
33657a10d8cSMin Li 		return err;
33757a10d8cSMin Li 
33857a10d8cSMin Li 	err = idt82p33_write(idt82p33, channel->dpll_freq_cnfg,
33957a10d8cSMin Li 			     buf, sizeof(buf));
34057a10d8cSMin Li 
34157a10d8cSMin Li 	if (err == 0)
34257a10d8cSMin Li 		channel->current_freq_ppb = scaled_ppm;
34357a10d8cSMin Li 
34457a10d8cSMin Li 	return err;
34557a10d8cSMin Li }
34657a10d8cSMin Li 
34757a10d8cSMin Li static int idt82p33_measure_one_byte_write_overhead(
34857a10d8cSMin Li 		struct idt82p33_channel *channel, s64 *overhead_ns)
34957a10d8cSMin Li {
35057a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
35157a10d8cSMin Li 	ktime_t start, stop;
35257a10d8cSMin Li 	s64 total_ns;
35357a10d8cSMin Li 	u8 trigger;
35457a10d8cSMin Li 	int err;
35557a10d8cSMin Li 	u8 i;
35657a10d8cSMin Li 
35757a10d8cSMin Li 	total_ns = 0;
35857a10d8cSMin Li 	*overhead_ns = 0;
35957a10d8cSMin Li 	trigger = TOD_TRIGGER(HW_TOD_WR_TRIG_SEL_MSB_TOD_CNFG,
36057a10d8cSMin Li 			      HW_TOD_RD_TRIG_SEL_LSB_TOD_STS);
36157a10d8cSMin Li 
36257a10d8cSMin Li 	for (i = 0; i < MAX_MEASURMENT_COUNT; i++) {
36357a10d8cSMin Li 
36457a10d8cSMin Li 		start = ktime_get_raw();
36557a10d8cSMin Li 
36657a10d8cSMin Li 		err = idt82p33_write(idt82p33, channel->dpll_tod_trigger,
36757a10d8cSMin Li 				     &trigger, sizeof(trigger));
36857a10d8cSMin Li 
36957a10d8cSMin Li 		stop = ktime_get_raw();
37057a10d8cSMin Li 
37157a10d8cSMin Li 		if (err)
37257a10d8cSMin Li 			return err;
37357a10d8cSMin Li 
37457a10d8cSMin Li 		total_ns += ktime_to_ns(stop) - ktime_to_ns(start);
37557a10d8cSMin Li 	}
37657a10d8cSMin Li 
37757a10d8cSMin Li 	*overhead_ns = div_s64(total_ns, MAX_MEASURMENT_COUNT);
37857a10d8cSMin Li 
37957a10d8cSMin Li 	return err;
38057a10d8cSMin Li }
38157a10d8cSMin Li 
38257a10d8cSMin Li static int idt82p33_measure_tod_write_9_byte_overhead(
38357a10d8cSMin Li 			struct idt82p33_channel *channel)
38457a10d8cSMin Li {
38557a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
38657a10d8cSMin Li 	u8 buf[TOD_BYTE_COUNT];
38757a10d8cSMin Li 	ktime_t start, stop;
38857a10d8cSMin Li 	s64 total_ns;
38957a10d8cSMin Li 	int err = 0;
39057a10d8cSMin Li 	u8 i, j;
39157a10d8cSMin Li 
39257a10d8cSMin Li 	total_ns = 0;
39357a10d8cSMin Li 	idt82p33->tod_write_overhead_ns = 0;
39457a10d8cSMin Li 
39557a10d8cSMin Li 	for (i = 0; i < MAX_MEASURMENT_COUNT; i++) {
39657a10d8cSMin Li 
39757a10d8cSMin Li 		start = ktime_get_raw();
39857a10d8cSMin Li 
39957a10d8cSMin Li 		/* Need one less byte for applicable overhead */
40057a10d8cSMin Li 		for (j = 0; j < (TOD_BYTE_COUNT - 1); j++) {
40157a10d8cSMin Li 			err = idt82p33_write(idt82p33,
40257a10d8cSMin Li 					     channel->dpll_tod_cnfg + i,
40357a10d8cSMin Li 					     &buf[i], sizeof(buf[i]));
40457a10d8cSMin Li 			if (err)
40557a10d8cSMin Li 				return err;
40657a10d8cSMin Li 		}
40757a10d8cSMin Li 
40857a10d8cSMin Li 		stop = ktime_get_raw();
40957a10d8cSMin Li 
41057a10d8cSMin Li 		total_ns += ktime_to_ns(stop) - ktime_to_ns(start);
41157a10d8cSMin Li 	}
41257a10d8cSMin Li 
41357a10d8cSMin Li 	idt82p33->tod_write_overhead_ns = div_s64(total_ns,
41457a10d8cSMin Li 						  MAX_MEASURMENT_COUNT);
41557a10d8cSMin Li 
41657a10d8cSMin Li 	return err;
41757a10d8cSMin Li }
41857a10d8cSMin Li 
41957a10d8cSMin Li static int idt82p33_measure_settime_gettime_gap_overhead(
42057a10d8cSMin Li 		struct idt82p33_channel *channel, s64 *overhead_ns)
42157a10d8cSMin Li {
42257a10d8cSMin Li 	struct timespec64 ts1 = {0, 0};
42357a10d8cSMin Li 	struct timespec64 ts2;
42457a10d8cSMin Li 	int err;
42557a10d8cSMin Li 
42657a10d8cSMin Li 	*overhead_ns = 0;
42757a10d8cSMin Li 
42857a10d8cSMin Li 	err = _idt82p33_settime(channel, &ts1);
42957a10d8cSMin Li 
43057a10d8cSMin Li 	if (err)
43157a10d8cSMin Li 		return err;
43257a10d8cSMin Li 
43357a10d8cSMin Li 	err = _idt82p33_gettime(channel, &ts2);
43457a10d8cSMin Li 
43557a10d8cSMin Li 	if (!err)
43657a10d8cSMin Li 		*overhead_ns = timespec64_to_ns(&ts2) - timespec64_to_ns(&ts1);
43757a10d8cSMin Li 
43857a10d8cSMin Li 	return err;
43957a10d8cSMin Li }
44057a10d8cSMin Li 
44157a10d8cSMin Li static int idt82p33_measure_tod_write_overhead(struct idt82p33_channel *channel)
44257a10d8cSMin Li {
44357a10d8cSMin Li 	s64 trailing_overhead_ns, one_byte_write_ns, gap_ns;
44457a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
44557a10d8cSMin Li 	int err;
44657a10d8cSMin Li 
44757a10d8cSMin Li 	idt82p33->tod_write_overhead_ns = 0;
44857a10d8cSMin Li 
44957a10d8cSMin Li 	err = idt82p33_measure_settime_gettime_gap_overhead(channel, &gap_ns);
45057a10d8cSMin Li 
45157a10d8cSMin Li 	if (err)
45257a10d8cSMin Li 		return err;
45357a10d8cSMin Li 
45457a10d8cSMin Li 	err = idt82p33_measure_one_byte_write_overhead(channel,
45557a10d8cSMin Li 						       &one_byte_write_ns);
45657a10d8cSMin Li 
45757a10d8cSMin Li 	if (err)
45857a10d8cSMin Li 		return err;
45957a10d8cSMin Li 
46057a10d8cSMin Li 	err = idt82p33_measure_tod_write_9_byte_overhead(channel);
46157a10d8cSMin Li 
46257a10d8cSMin Li 	if (err)
46357a10d8cSMin Li 		return err;
46457a10d8cSMin Li 
46557a10d8cSMin Li 	trailing_overhead_ns = gap_ns - (2 * one_byte_write_ns);
46657a10d8cSMin Li 
46757a10d8cSMin Li 	idt82p33->tod_write_overhead_ns -= trailing_overhead_ns;
46857a10d8cSMin Li 
46957a10d8cSMin Li 	return err;
47057a10d8cSMin Li }
47157a10d8cSMin Li 
47257a10d8cSMin Li static int idt82p33_check_and_set_masks(struct idt82p33 *idt82p33,
47357a10d8cSMin Li 					u8 page,
47457a10d8cSMin Li 					u8 offset,
47557a10d8cSMin Li 					u8 val)
47657a10d8cSMin Li {
47757a10d8cSMin Li 	int err = 0;
47857a10d8cSMin Li 
47957a10d8cSMin Li 	if (page == PLLMASK_ADDR_HI && offset == PLLMASK_ADDR_LO) {
48057a10d8cSMin Li 		if ((val & 0xfc) || !(val & 0x3)) {
48157a10d8cSMin Li 			dev_err(&idt82p33->client->dev,
48257a10d8cSMin Li 				"Invalid PLL mask 0x%hhx\n", val);
48357a10d8cSMin Li 			err = -EINVAL;
48457a10d8cSMin Li 		} else {
48557a10d8cSMin Li 			idt82p33->pll_mask = val;
48657a10d8cSMin Li 		}
48757a10d8cSMin Li 	} else if (page == PLL0_OUTMASK_ADDR_HI &&
48857a10d8cSMin Li 		offset == PLL0_OUTMASK_ADDR_LO) {
48957a10d8cSMin Li 		idt82p33->channel[0].output_mask = val;
49057a10d8cSMin Li 	} else if (page == PLL1_OUTMASK_ADDR_HI &&
49157a10d8cSMin Li 		offset == PLL1_OUTMASK_ADDR_LO) {
49257a10d8cSMin Li 		idt82p33->channel[1].output_mask = val;
49357a10d8cSMin Li 	}
49457a10d8cSMin Li 
49557a10d8cSMin Li 	return err;
49657a10d8cSMin Li }
49757a10d8cSMin Li 
49857a10d8cSMin Li static void idt82p33_display_masks(struct idt82p33 *idt82p33)
49957a10d8cSMin Li {
50057a10d8cSMin Li 	u8 mask, i;
50157a10d8cSMin Li 
50257a10d8cSMin Li 	dev_info(&idt82p33->client->dev,
50357a10d8cSMin Li 		 "pllmask = 0x%02x\n", idt82p33->pll_mask);
50457a10d8cSMin Li 
50557a10d8cSMin Li 	for (i = 0; i < MAX_PHC_PLL; i++) {
50657a10d8cSMin Li 		mask = 1 << i;
50757a10d8cSMin Li 
50857a10d8cSMin Li 		if (mask & idt82p33->pll_mask)
50957a10d8cSMin Li 			dev_info(&idt82p33->client->dev,
51057a10d8cSMin Li 				 "PLL%d output_mask = 0x%04x\n",
51157a10d8cSMin Li 				 i, idt82p33->channel[i].output_mask);
51257a10d8cSMin Li 	}
51357a10d8cSMin Li }
51457a10d8cSMin Li 
51557a10d8cSMin Li static int idt82p33_sync_tod(struct idt82p33_channel *channel, bool enable)
51657a10d8cSMin Li {
51757a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
51857a10d8cSMin Li 	u8 sync_cnfg;
51957a10d8cSMin Li 	int err;
52057a10d8cSMin Li 
52157a10d8cSMin Li 	if (enable == channel->sync_tod_on) {
52257a10d8cSMin Li 		if (enable && sync_tod_timeout) {
52357a10d8cSMin Li 			mod_delayed_work(system_wq, &channel->sync_tod_work,
52457a10d8cSMin Li 					 sync_tod_timeout * HZ);
52557a10d8cSMin Li 		}
52657a10d8cSMin Li 		return 0;
52757a10d8cSMin Li 	}
52857a10d8cSMin Li 
52957a10d8cSMin Li 	err = idt82p33_read(idt82p33, channel->dpll_sync_cnfg,
53057a10d8cSMin Li 			    &sync_cnfg, sizeof(sync_cnfg));
53157a10d8cSMin Li 	if (err)
53257a10d8cSMin Li 		return err;
53357a10d8cSMin Li 
53457a10d8cSMin Li 	sync_cnfg &= ~SYNC_TOD;
53557a10d8cSMin Li 
53657a10d8cSMin Li 	if (enable)
53757a10d8cSMin Li 		sync_cnfg |= SYNC_TOD;
53857a10d8cSMin Li 
53957a10d8cSMin Li 	err = idt82p33_write(idt82p33, channel->dpll_sync_cnfg,
54057a10d8cSMin Li 			     &sync_cnfg, sizeof(sync_cnfg));
54157a10d8cSMin Li 	if (err)
54257a10d8cSMin Li 		return err;
54357a10d8cSMin Li 
54457a10d8cSMin Li 	channel->sync_tod_on = enable;
54557a10d8cSMin Li 
54657a10d8cSMin Li 	if (enable && sync_tod_timeout) {
54757a10d8cSMin Li 		mod_delayed_work(system_wq, &channel->sync_tod_work,
54857a10d8cSMin Li 				 sync_tod_timeout * HZ);
54957a10d8cSMin Li 	}
55057a10d8cSMin Li 
55157a10d8cSMin Li 	return 0;
55257a10d8cSMin Li }
55357a10d8cSMin Li 
55457a10d8cSMin Li static void idt82p33_sync_tod_work_handler(struct work_struct *work)
55557a10d8cSMin Li {
55657a10d8cSMin Li 	struct idt82p33_channel *channel =
55757a10d8cSMin Li 		container_of(work, struct idt82p33_channel, sync_tod_work.work);
55857a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
55957a10d8cSMin Li 
56057a10d8cSMin Li 	mutex_lock(&idt82p33->reg_lock);
56157a10d8cSMin Li 
56257a10d8cSMin Li 	(void)idt82p33_sync_tod(channel, false);
56357a10d8cSMin Li 
56457a10d8cSMin Li 	mutex_unlock(&idt82p33->reg_lock);
56557a10d8cSMin Li }
56657a10d8cSMin Li 
56757a10d8cSMin Li static int idt82p33_pps_enable(struct idt82p33_channel *channel, bool enable)
56857a10d8cSMin Li {
56957a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
57057a10d8cSMin Li 	u8 mask, outn, val;
57157a10d8cSMin Li 	int err;
57257a10d8cSMin Li 
57357a10d8cSMin Li 	mask = channel->output_mask;
57457a10d8cSMin Li 	outn = 0;
57557a10d8cSMin Li 
57657a10d8cSMin Li 	while (mask) {
57757a10d8cSMin Li 		if (mask & 0x1) {
57857a10d8cSMin Li 			err = idt82p33_read(idt82p33, OUT_MUX_CNFG(outn),
57957a10d8cSMin Li 					    &val, sizeof(val));
58057a10d8cSMin Li 			if (err)
58157a10d8cSMin Li 				return err;
58257a10d8cSMin Li 
58357a10d8cSMin Li 			if (enable)
58457a10d8cSMin Li 				val &= ~SQUELCH_ENABLE;
58557a10d8cSMin Li 			else
58657a10d8cSMin Li 				val |= SQUELCH_ENABLE;
58757a10d8cSMin Li 
58857a10d8cSMin Li 			err = idt82p33_write(idt82p33, OUT_MUX_CNFG(outn),
58957a10d8cSMin Li 					     &val, sizeof(val));
59057a10d8cSMin Li 
59157a10d8cSMin Li 			if (err)
59257a10d8cSMin Li 				return err;
59357a10d8cSMin Li 		}
59457a10d8cSMin Li 		mask >>= 0x1;
59557a10d8cSMin Li 		outn++;
59657a10d8cSMin Li 	}
59757a10d8cSMin Li 
59857a10d8cSMin Li 	return 0;
59957a10d8cSMin Li }
60057a10d8cSMin Li 
60157a10d8cSMin Li static int idt82p33_enable_tod(struct idt82p33_channel *channel)
60257a10d8cSMin Li {
60357a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
60457a10d8cSMin Li 	struct timespec64 ts = {0, 0};
60557a10d8cSMin Li 	int err;
60657a10d8cSMin Li 	u8 val;
60757a10d8cSMin Li 
60857a10d8cSMin Li 	val = 0;
60957a10d8cSMin Li 	err = idt82p33_write(idt82p33, channel->dpll_input_mode_cnfg,
61057a10d8cSMin Li 			     &val, sizeof(val));
61157a10d8cSMin Li 	if (err)
61257a10d8cSMin Li 		return err;
61357a10d8cSMin Li 
61457a10d8cSMin Li 	err = idt82p33_pps_enable(channel, false);
61557a10d8cSMin Li 
61657a10d8cSMin Li 	if (err)
61757a10d8cSMin Li 		return err;
61857a10d8cSMin Li 
61957a10d8cSMin Li 	err = idt82p33_measure_tod_write_overhead(channel);
62057a10d8cSMin Li 
62157a10d8cSMin Li 	if (err)
62257a10d8cSMin Li 		return err;
62357a10d8cSMin Li 
62457a10d8cSMin Li 	err = _idt82p33_settime(channel, &ts);
62557a10d8cSMin Li 
62657a10d8cSMin Li 	if (err)
62757a10d8cSMin Li 		return err;
62857a10d8cSMin Li 
62957a10d8cSMin Li 	return idt82p33_sync_tod(channel, true);
63057a10d8cSMin Li }
63157a10d8cSMin Li 
63257a10d8cSMin Li static void idt82p33_ptp_clock_unregister_all(struct idt82p33 *idt82p33)
63357a10d8cSMin Li {
63457a10d8cSMin Li 	struct idt82p33_channel *channel;
63557a10d8cSMin Li 	u8 i;
63657a10d8cSMin Li 
63757a10d8cSMin Li 	for (i = 0; i < MAX_PHC_PLL; i++) {
63857a10d8cSMin Li 
63957a10d8cSMin Li 		channel = &idt82p33->channel[i];
64057a10d8cSMin Li 
64157a10d8cSMin Li 		if (channel->ptp_clock) {
64257a10d8cSMin Li 			ptp_clock_unregister(channel->ptp_clock);
64357a10d8cSMin Li 			cancel_delayed_work_sync(&channel->sync_tod_work);
64457a10d8cSMin Li 		}
64557a10d8cSMin Li 	}
64657a10d8cSMin Li }
64757a10d8cSMin Li 
64857a10d8cSMin Li static int idt82p33_enable(struct ptp_clock_info *ptp,
64957a10d8cSMin Li 			 struct ptp_clock_request *rq, int on)
65057a10d8cSMin Li {
65157a10d8cSMin Li 	struct idt82p33_channel *channel =
65257a10d8cSMin Li 			container_of(ptp, struct idt82p33_channel, caps);
65357a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
65457a10d8cSMin Li 	int err;
65557a10d8cSMin Li 
65657a10d8cSMin Li 	err = -EOPNOTSUPP;
65757a10d8cSMin Li 
65857a10d8cSMin Li 	mutex_lock(&idt82p33->reg_lock);
65957a10d8cSMin Li 
66057a10d8cSMin Li 	if (rq->type == PTP_CLK_REQ_PEROUT) {
66157a10d8cSMin Li 		if (!on)
66257a10d8cSMin Li 			err = idt82p33_pps_enable(channel, false);
66357a10d8cSMin Li 
66457a10d8cSMin Li 		/* Only accept a 1-PPS aligned to the second. */
66557a10d8cSMin Li 		else if (rq->perout.start.nsec || rq->perout.period.sec != 1 ||
66657a10d8cSMin Li 		    rq->perout.period.nsec) {
66757a10d8cSMin Li 			err = -ERANGE;
66857a10d8cSMin Li 		} else
66957a10d8cSMin Li 			err = idt82p33_pps_enable(channel, true);
67057a10d8cSMin Li 	}
67157a10d8cSMin Li 
67257a10d8cSMin Li 	mutex_unlock(&idt82p33->reg_lock);
67357a10d8cSMin Li 
67457a10d8cSMin Li 	return err;
67557a10d8cSMin Li }
67657a10d8cSMin Li 
67757a10d8cSMin Li static int idt82p33_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
67857a10d8cSMin Li {
67957a10d8cSMin Li 	struct idt82p33_channel *channel =
68057a10d8cSMin Li 			container_of(ptp, struct idt82p33_channel, caps);
68157a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
68257a10d8cSMin Li 	int err;
68357a10d8cSMin Li 
68457a10d8cSMin Li 	mutex_lock(&idt82p33->reg_lock);
68557a10d8cSMin Li 	err = _idt82p33_adjfine(channel, scaled_ppm);
68657a10d8cSMin Li 	mutex_unlock(&idt82p33->reg_lock);
68757a10d8cSMin Li 
68857a10d8cSMin Li 	return err;
68957a10d8cSMin Li }
69057a10d8cSMin Li 
69157a10d8cSMin Li static int idt82p33_adjtime(struct ptp_clock_info *ptp, s64 delta_ns)
69257a10d8cSMin Li {
69357a10d8cSMin Li 	struct idt82p33_channel *channel =
69457a10d8cSMin Li 			container_of(ptp, struct idt82p33_channel, caps);
69557a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
69657a10d8cSMin Li 	int err;
69757a10d8cSMin Li 
69857a10d8cSMin Li 	mutex_lock(&idt82p33->reg_lock);
69957a10d8cSMin Li 
70057a10d8cSMin Li 	if (abs(delta_ns) < phase_snap_threshold) {
70157a10d8cSMin Li 		mutex_unlock(&idt82p33->reg_lock);
70257a10d8cSMin Li 		return 0;
70357a10d8cSMin Li 	}
70457a10d8cSMin Li 
70557a10d8cSMin Li 	err = _idt82p33_adjtime(channel, delta_ns);
70657a10d8cSMin Li 
70757a10d8cSMin Li 	if (err) {
70857a10d8cSMin Li 		mutex_unlock(&idt82p33->reg_lock);
70957a10d8cSMin Li 		return err;
71057a10d8cSMin Li 	}
71157a10d8cSMin Li 
71257a10d8cSMin Li 	err = idt82p33_sync_tod(channel, true);
71357a10d8cSMin Li 
71457a10d8cSMin Li 	mutex_unlock(&idt82p33->reg_lock);
71557a10d8cSMin Li 
71657a10d8cSMin Li 	return err;
71757a10d8cSMin Li }
71857a10d8cSMin Li 
71957a10d8cSMin Li static int idt82p33_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
72057a10d8cSMin Li {
72157a10d8cSMin Li 	struct idt82p33_channel *channel =
72257a10d8cSMin Li 			container_of(ptp, struct idt82p33_channel, caps);
72357a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
72457a10d8cSMin Li 	int err;
72557a10d8cSMin Li 
72657a10d8cSMin Li 	mutex_lock(&idt82p33->reg_lock);
72757a10d8cSMin Li 	err = _idt82p33_gettime(channel, ts);
72857a10d8cSMin Li 	mutex_unlock(&idt82p33->reg_lock);
72957a10d8cSMin Li 
73057a10d8cSMin Li 	return err;
73157a10d8cSMin Li }
73257a10d8cSMin Li 
73357a10d8cSMin Li static int idt82p33_settime(struct ptp_clock_info *ptp,
73457a10d8cSMin Li 			const struct timespec64 *ts)
73557a10d8cSMin Li {
73657a10d8cSMin Li 	struct idt82p33_channel *channel =
73757a10d8cSMin Li 			container_of(ptp, struct idt82p33_channel, caps);
73857a10d8cSMin Li 	struct idt82p33 *idt82p33 = channel->idt82p33;
73957a10d8cSMin Li 	int err;
74057a10d8cSMin Li 
74157a10d8cSMin Li 	mutex_lock(&idt82p33->reg_lock);
74257a10d8cSMin Li 	err = _idt82p33_settime(channel, ts);
74357a10d8cSMin Li 	mutex_unlock(&idt82p33->reg_lock);
74457a10d8cSMin Li 
74557a10d8cSMin Li 	return err;
74657a10d8cSMin Li }
74757a10d8cSMin Li 
74857a10d8cSMin Li static int idt82p33_channel_init(struct idt82p33_channel *channel, int index)
74957a10d8cSMin Li {
75057a10d8cSMin Li 	switch (index) {
75157a10d8cSMin Li 	case 0:
75257a10d8cSMin Li 		channel->dpll_tod_cnfg = DPLL1_TOD_CNFG;
75357a10d8cSMin Li 		channel->dpll_tod_trigger = DPLL1_TOD_TRIGGER;
75457a10d8cSMin Li 		channel->dpll_tod_sts = DPLL1_TOD_STS;
75557a10d8cSMin Li 		channel->dpll_mode_cnfg = DPLL1_OPERATING_MODE_CNFG;
75657a10d8cSMin Li 		channel->dpll_freq_cnfg = DPLL1_HOLDOVER_FREQ_CNFG;
75757a10d8cSMin Li 		channel->dpll_phase_cnfg = DPLL1_PHASE_OFFSET_CNFG;
75857a10d8cSMin Li 		channel->dpll_sync_cnfg = DPLL1_SYNC_EDGE_CNFG;
75957a10d8cSMin Li 		channel->dpll_input_mode_cnfg = DPLL1_INPUT_MODE_CNFG;
76057a10d8cSMin Li 		break;
76157a10d8cSMin Li 	case 1:
76257a10d8cSMin Li 		channel->dpll_tod_cnfg = DPLL2_TOD_CNFG;
76357a10d8cSMin Li 		channel->dpll_tod_trigger = DPLL2_TOD_TRIGGER;
76457a10d8cSMin Li 		channel->dpll_tod_sts = DPLL2_TOD_STS;
76557a10d8cSMin Li 		channel->dpll_mode_cnfg = DPLL2_OPERATING_MODE_CNFG;
76657a10d8cSMin Li 		channel->dpll_freq_cnfg = DPLL2_HOLDOVER_FREQ_CNFG;
76757a10d8cSMin Li 		channel->dpll_phase_cnfg = DPLL2_PHASE_OFFSET_CNFG;
76857a10d8cSMin Li 		channel->dpll_sync_cnfg = DPLL2_SYNC_EDGE_CNFG;
76957a10d8cSMin Li 		channel->dpll_input_mode_cnfg = DPLL2_INPUT_MODE_CNFG;
77057a10d8cSMin Li 		break;
77157a10d8cSMin Li 	default:
77257a10d8cSMin Li 		return -EINVAL;
77357a10d8cSMin Li 	}
77457a10d8cSMin Li 
77557a10d8cSMin Li 	INIT_DELAYED_WORK(&channel->sync_tod_work,
77657a10d8cSMin Li 			  idt82p33_sync_tod_work_handler);
77757a10d8cSMin Li 	channel->sync_tod_on = false;
77857a10d8cSMin Li 	channel->current_freq_ppb = 0;
77957a10d8cSMin Li 
78057a10d8cSMin Li 	return 0;
78157a10d8cSMin Li }
78257a10d8cSMin Li 
78357a10d8cSMin Li static void idt82p33_caps_init(struct ptp_clock_info *caps)
78457a10d8cSMin Li {
78557a10d8cSMin Li 	caps->owner = THIS_MODULE;
78657a10d8cSMin Li 	caps->max_adj = 92000;
78757a10d8cSMin Li 	caps->adjfine = idt82p33_adjfine;
78857a10d8cSMin Li 	caps->adjtime = idt82p33_adjtime;
78957a10d8cSMin Li 	caps->gettime64 = idt82p33_gettime;
79057a10d8cSMin Li 	caps->settime64 = idt82p33_settime;
79157a10d8cSMin Li 	caps->enable = idt82p33_enable;
79257a10d8cSMin Li }
79357a10d8cSMin Li 
79457a10d8cSMin Li static int idt82p33_enable_channel(struct idt82p33 *idt82p33, u32 index)
79557a10d8cSMin Li {
79657a10d8cSMin Li 	struct idt82p33_channel *channel;
79757a10d8cSMin Li 	int err;
79857a10d8cSMin Li 
79957a10d8cSMin Li 	if (!(index < MAX_PHC_PLL))
80057a10d8cSMin Li 		return -EINVAL;
80157a10d8cSMin Li 
80257a10d8cSMin Li 	channel = &idt82p33->channel[index];
80357a10d8cSMin Li 
80457a10d8cSMin Li 	err = idt82p33_channel_init(channel, index);
80557a10d8cSMin Li 	if (err)
80657a10d8cSMin Li 		return err;
80757a10d8cSMin Li 
80857a10d8cSMin Li 	channel->idt82p33 = idt82p33;
80957a10d8cSMin Li 
81057a10d8cSMin Li 	idt82p33_caps_init(&channel->caps);
81157a10d8cSMin Li 	snprintf(channel->caps.name, sizeof(channel->caps.name),
81257a10d8cSMin Li 		 "IDT 82P33 PLL%u", index);
81357a10d8cSMin Li 	channel->caps.n_per_out = hweight8(channel->output_mask);
81457a10d8cSMin Li 
81557a10d8cSMin Li 	err = idt82p33_dpll_set_mode(channel, PLL_MODE_DCO);
81657a10d8cSMin Li 	if (err)
81757a10d8cSMin Li 		return err;
81857a10d8cSMin Li 
81957a10d8cSMin Li 	err = idt82p33_enable_tod(channel);
82057a10d8cSMin Li 	if (err)
82157a10d8cSMin Li 		return err;
82257a10d8cSMin Li 
82357a10d8cSMin Li 	channel->ptp_clock = ptp_clock_register(&channel->caps, NULL);
82457a10d8cSMin Li 
82557a10d8cSMin Li 	if (IS_ERR(channel->ptp_clock)) {
82657a10d8cSMin Li 		err = PTR_ERR(channel->ptp_clock);
82757a10d8cSMin Li 		channel->ptp_clock = NULL;
82857a10d8cSMin Li 		return err;
82957a10d8cSMin Li 	}
83057a10d8cSMin Li 
83157a10d8cSMin Li 	if (!channel->ptp_clock)
83257a10d8cSMin Li 		return -ENOTSUPP;
83357a10d8cSMin Li 
83457a10d8cSMin Li 	dev_info(&idt82p33->client->dev, "PLL%d registered as ptp%d\n",
83557a10d8cSMin Li 		 index, channel->ptp_clock->index);
83657a10d8cSMin Li 
83757a10d8cSMin Li 	return 0;
83857a10d8cSMin Li }
83957a10d8cSMin Li 
84057a10d8cSMin Li static int idt82p33_load_firmware(struct idt82p33 *idt82p33)
84157a10d8cSMin Li {
84257a10d8cSMin Li 	const struct firmware *fw;
84357a10d8cSMin Li 	struct idt82p33_fwrc *rec;
84457a10d8cSMin Li 	u8 loaddr, page, val;
84557a10d8cSMin Li 	int err;
84657a10d8cSMin Li 	s32 len;
84757a10d8cSMin Li 
84857a10d8cSMin Li 	dev_dbg(&idt82p33->client->dev,
84957a10d8cSMin Li 		"requesting firmware '%s'\n", FW_FILENAME);
85057a10d8cSMin Li 
85157a10d8cSMin Li 	err = request_firmware(&fw, FW_FILENAME, &idt82p33->client->dev);
85257a10d8cSMin Li 
85357a10d8cSMin Li 	if (err)
85457a10d8cSMin Li 		return err;
85557a10d8cSMin Li 
85657a10d8cSMin Li 	dev_dbg(&idt82p33->client->dev, "firmware size %zu bytes\n", fw->size);
85757a10d8cSMin Li 
85857a10d8cSMin Li 	rec = (struct idt82p33_fwrc *) fw->data;
85957a10d8cSMin Li 
86057a10d8cSMin Li 	for (len = fw->size; len > 0; len -= sizeof(*rec)) {
86157a10d8cSMin Li 
86257a10d8cSMin Li 		if (rec->reserved) {
86357a10d8cSMin Li 			dev_err(&idt82p33->client->dev,
86457a10d8cSMin Li 				"bad firmware, reserved field non-zero\n");
86557a10d8cSMin Li 			err = -EINVAL;
86657a10d8cSMin Li 		} else {
86757a10d8cSMin Li 			val = rec->value;
86857a10d8cSMin Li 			loaddr = rec->loaddr;
86957a10d8cSMin Li 			page = rec->hiaddr;
87057a10d8cSMin Li 
87157a10d8cSMin Li 			rec++;
87257a10d8cSMin Li 
87357a10d8cSMin Li 			err = idt82p33_check_and_set_masks(idt82p33, page,
87457a10d8cSMin Li 							   loaddr, val);
87557a10d8cSMin Li 		}
87657a10d8cSMin Li 
87757a10d8cSMin Li 		if (err == 0) {
87857a10d8cSMin Li 			/* maximum 8 pages  */
87957a10d8cSMin Li 			if (page >= PAGE_NUM)
88057a10d8cSMin Li 				continue;
88157a10d8cSMin Li 
88257a10d8cSMin Li 			/* Page size 128, last 4 bytes of page skipped */
88357a10d8cSMin Li 			if (((loaddr > 0x7b) && (loaddr <= 0x7f))
88457a10d8cSMin Li 			     || ((loaddr > 0xfb) && (loaddr <= 0xff)))
88557a10d8cSMin Li 				continue;
88657a10d8cSMin Li 
88757a10d8cSMin Li 			err = idt82p33_write(idt82p33, _ADDR(page, loaddr),
88857a10d8cSMin Li 					     &val, sizeof(val));
88957a10d8cSMin Li 		}
89057a10d8cSMin Li 
89157a10d8cSMin Li 		if (err)
89257a10d8cSMin Li 			goto out;
89357a10d8cSMin Li 	}
89457a10d8cSMin Li 
89557a10d8cSMin Li 	idt82p33_display_masks(idt82p33);
89657a10d8cSMin Li out:
89757a10d8cSMin Li 	release_firmware(fw);
89857a10d8cSMin Li 	return err;
89957a10d8cSMin Li }
90057a10d8cSMin Li 
90157a10d8cSMin Li 
90257a10d8cSMin Li static int idt82p33_probe(struct i2c_client *client,
90357a10d8cSMin Li 			  const struct i2c_device_id *id)
90457a10d8cSMin Li {
90557a10d8cSMin Li 	struct idt82p33 *idt82p33;
90657a10d8cSMin Li 	int err;
90757a10d8cSMin Li 	u8 i;
90857a10d8cSMin Li 
90957a10d8cSMin Li 	(void)id;
91057a10d8cSMin Li 
91157a10d8cSMin Li 	idt82p33 = devm_kzalloc(&client->dev,
91257a10d8cSMin Li 				sizeof(struct idt82p33), GFP_KERNEL);
91357a10d8cSMin Li 	if (!idt82p33)
91457a10d8cSMin Li 		return -ENOMEM;
91557a10d8cSMin Li 
91657a10d8cSMin Li 	mutex_init(&idt82p33->reg_lock);
91757a10d8cSMin Li 
91857a10d8cSMin Li 	idt82p33->client = client;
91957a10d8cSMin Li 	idt82p33->page_offset = 0xff;
92057a10d8cSMin Li 	idt82p33->tod_write_overhead_ns = 0;
92157a10d8cSMin Li 	idt82p33->calculate_overhead_flag = 0;
92257a10d8cSMin Li 	idt82p33->pll_mask = DEFAULT_PLL_MASK;
92357a10d8cSMin Li 	idt82p33->channel[0].output_mask = DEFAULT_OUTPUT_MASK_PLL0;
92457a10d8cSMin Li 	idt82p33->channel[1].output_mask = DEFAULT_OUTPUT_MASK_PLL1;
92557a10d8cSMin Li 
92657a10d8cSMin Li 	mutex_lock(&idt82p33->reg_lock);
92757a10d8cSMin Li 
92857a10d8cSMin Li 	err = idt82p33_load_firmware(idt82p33);
92957a10d8cSMin Li 
93057a10d8cSMin Li 	if (err)
93157a10d8cSMin Li 		dev_warn(&idt82p33->client->dev,
93257a10d8cSMin Li 			 "loading firmware failed with %d\n", err);
93357a10d8cSMin Li 
93457a10d8cSMin Li 	if (idt82p33->pll_mask) {
93557a10d8cSMin Li 		for (i = 0; i < MAX_PHC_PLL; i++) {
93657a10d8cSMin Li 			if (idt82p33->pll_mask & (1 << i)) {
93757a10d8cSMin Li 				err = idt82p33_enable_channel(idt82p33, i);
93857a10d8cSMin Li 				if (err)
93957a10d8cSMin Li 					break;
94057a10d8cSMin Li 			}
94157a10d8cSMin Li 		}
94257a10d8cSMin Li 	} else {
94357a10d8cSMin Li 		dev_err(&idt82p33->client->dev,
94457a10d8cSMin Li 			"no PLLs flagged as PHCs, nothing to do\n");
94557a10d8cSMin Li 		err = -ENODEV;
94657a10d8cSMin Li 	}
94757a10d8cSMin Li 
94857a10d8cSMin Li 	mutex_unlock(&idt82p33->reg_lock);
94957a10d8cSMin Li 
95057a10d8cSMin Li 	if (err) {
95157a10d8cSMin Li 		idt82p33_ptp_clock_unregister_all(idt82p33);
95257a10d8cSMin Li 		return err;
95357a10d8cSMin Li 	}
95457a10d8cSMin Li 
95557a10d8cSMin Li 	i2c_set_clientdata(client, idt82p33);
95657a10d8cSMin Li 
95757a10d8cSMin Li 	return 0;
95857a10d8cSMin Li }
95957a10d8cSMin Li 
96057a10d8cSMin Li static int idt82p33_remove(struct i2c_client *client)
96157a10d8cSMin Li {
96257a10d8cSMin Li 	struct idt82p33 *idt82p33 = i2c_get_clientdata(client);
96357a10d8cSMin Li 
96457a10d8cSMin Li 	idt82p33_ptp_clock_unregister_all(idt82p33);
96557a10d8cSMin Li 	mutex_destroy(&idt82p33->reg_lock);
96657a10d8cSMin Li 
96757a10d8cSMin Li 	return 0;
96857a10d8cSMin Li }
96957a10d8cSMin Li 
97057a10d8cSMin Li #ifdef CONFIG_OF
97157a10d8cSMin Li static const struct of_device_id idt82p33_dt_id[] = {
97257a10d8cSMin Li 	{ .compatible = "idt,82p33810" },
97357a10d8cSMin Li 	{ .compatible = "idt,82p33813" },
97457a10d8cSMin Li 	{ .compatible = "idt,82p33814" },
97557a10d8cSMin Li 	{ .compatible = "idt,82p33831" },
97657a10d8cSMin Li 	{ .compatible = "idt,82p33910" },
97757a10d8cSMin Li 	{ .compatible = "idt,82p33913" },
97857a10d8cSMin Li 	{ .compatible = "idt,82p33914" },
97957a10d8cSMin Li 	{ .compatible = "idt,82p33931" },
98057a10d8cSMin Li 	{},
98157a10d8cSMin Li };
98257a10d8cSMin Li MODULE_DEVICE_TABLE(of, idt82p33_dt_id);
98357a10d8cSMin Li #endif
98457a10d8cSMin Li 
98557a10d8cSMin Li static const struct i2c_device_id idt82p33_i2c_id[] = {
98657a10d8cSMin Li 	{ "idt82p33810", },
98757a10d8cSMin Li 	{ "idt82p33813", },
98857a10d8cSMin Li 	{ "idt82p33814", },
98957a10d8cSMin Li 	{ "idt82p33831", },
99057a10d8cSMin Li 	{ "idt82p33910", },
99157a10d8cSMin Li 	{ "idt82p33913", },
99257a10d8cSMin Li 	{ "idt82p33914", },
99357a10d8cSMin Li 	{ "idt82p33931", },
99457a10d8cSMin Li 	{},
99557a10d8cSMin Li };
99657a10d8cSMin Li MODULE_DEVICE_TABLE(i2c, idt82p33_i2c_id);
99757a10d8cSMin Li 
99857a10d8cSMin Li static struct i2c_driver idt82p33_driver = {
99957a10d8cSMin Li 	.driver = {
100057a10d8cSMin Li 		.of_match_table	= of_match_ptr(idt82p33_dt_id),
100157a10d8cSMin Li 		.name		= "idt82p33",
100257a10d8cSMin Li 	},
100357a10d8cSMin Li 	.probe		= idt82p33_probe,
100457a10d8cSMin Li 	.remove		= idt82p33_remove,
100557a10d8cSMin Li 	.id_table	= idt82p33_i2c_id,
100657a10d8cSMin Li };
100757a10d8cSMin Li 
100857a10d8cSMin Li module_i2c_driver(idt82p33_driver);
1009