xref: /OK3568_Linux_fs/kernel/drivers/ptp/ptp_clockmatrix.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * PTP hardware clock driver for the IDT ClockMatrix(TM) family of timing and
4*4882a593Smuzhiyun  * synchronization devices.
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Copyright (C) 2019 Integrated Device Technology, Inc., a Renesas Company.
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun #include <linux/firmware.h>
9*4882a593Smuzhiyun #include <linux/i2c.h>
10*4882a593Smuzhiyun #include <linux/module.h>
11*4882a593Smuzhiyun #include <linux/ptp_clock_kernel.h>
12*4882a593Smuzhiyun #include <linux/delay.h>
13*4882a593Smuzhiyun #include <linux/jiffies.h>
14*4882a593Smuzhiyun #include <linux/kernel.h>
15*4882a593Smuzhiyun #include <linux/timekeeping.h>
16*4882a593Smuzhiyun #include <linux/string.h>
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #include "ptp_private.h"
19*4882a593Smuzhiyun #include "ptp_clockmatrix.h"
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun MODULE_DESCRIPTION("Driver for IDT ClockMatrix(TM) family");
22*4882a593Smuzhiyun MODULE_AUTHOR("Richard Cochran <richardcochran@gmail.com>");
23*4882a593Smuzhiyun MODULE_AUTHOR("IDT support-1588 <IDT-support-1588@lm.renesas.com>");
24*4882a593Smuzhiyun MODULE_VERSION("1.0");
25*4882a593Smuzhiyun MODULE_LICENSE("GPL");
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun /*
28*4882a593Smuzhiyun  * The name of the firmware file to be loaded
29*4882a593Smuzhiyun  * over-rides any automatic selection
30*4882a593Smuzhiyun  */
31*4882a593Smuzhiyun static char *firmware;
32*4882a593Smuzhiyun module_param(firmware, charp, 0);
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun #define SETTIME_CORRECTION (0)
35*4882a593Smuzhiyun 
set_write_phase_ready(struct ptp_clock_info * ptp)36*4882a593Smuzhiyun static long set_write_phase_ready(struct ptp_clock_info *ptp)
37*4882a593Smuzhiyun {
38*4882a593Smuzhiyun 	struct idtcm_channel *channel =
39*4882a593Smuzhiyun 		container_of(ptp, struct idtcm_channel, caps);
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun 	channel->write_phase_ready = 1;
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun 	return 0;
44*4882a593Smuzhiyun }
45*4882a593Smuzhiyun 
char_array_to_timespec(u8 * buf,u8 count,struct timespec64 * ts)46*4882a593Smuzhiyun static int char_array_to_timespec(u8 *buf,
47*4882a593Smuzhiyun 				  u8 count,
48*4882a593Smuzhiyun 				  struct timespec64 *ts)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun 	u8 i;
51*4882a593Smuzhiyun 	u64 nsec;
52*4882a593Smuzhiyun 	time64_t sec;
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	if (count < TOD_BYTE_COUNT)
55*4882a593Smuzhiyun 		return 1;
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 	/* Sub-nanoseconds are in buf[0]. */
58*4882a593Smuzhiyun 	nsec = buf[4];
59*4882a593Smuzhiyun 	for (i = 0; i < 3; i++) {
60*4882a593Smuzhiyun 		nsec <<= 8;
61*4882a593Smuzhiyun 		nsec |= buf[3 - i];
62*4882a593Smuzhiyun 	}
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun 	sec = buf[10];
65*4882a593Smuzhiyun 	for (i = 0; i < 5; i++) {
66*4882a593Smuzhiyun 		sec <<= 8;
67*4882a593Smuzhiyun 		sec |= buf[9 - i];
68*4882a593Smuzhiyun 	}
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	ts->tv_sec = sec;
71*4882a593Smuzhiyun 	ts->tv_nsec = nsec;
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	return 0;
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun 
timespec_to_char_array(struct timespec64 const * ts,u8 * buf,u8 count)76*4882a593Smuzhiyun static int timespec_to_char_array(struct timespec64 const *ts,
77*4882a593Smuzhiyun 				  u8 *buf,
78*4882a593Smuzhiyun 				  u8 count)
79*4882a593Smuzhiyun {
80*4882a593Smuzhiyun 	u8 i;
81*4882a593Smuzhiyun 	s32 nsec;
82*4882a593Smuzhiyun 	time64_t sec;
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	if (count < TOD_BYTE_COUNT)
85*4882a593Smuzhiyun 		return 1;
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	nsec = ts->tv_nsec;
88*4882a593Smuzhiyun 	sec = ts->tv_sec;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	/* Sub-nanoseconds are in buf[0]. */
91*4882a593Smuzhiyun 	buf[0] = 0;
92*4882a593Smuzhiyun 	for (i = 1; i < 5; i++) {
93*4882a593Smuzhiyun 		buf[i] = nsec & 0xff;
94*4882a593Smuzhiyun 		nsec >>= 8;
95*4882a593Smuzhiyun 	}
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	for (i = 5; i < TOD_BYTE_COUNT; i++) {
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 		buf[i] = sec & 0xff;
100*4882a593Smuzhiyun 		sec >>= 8;
101*4882a593Smuzhiyun 	}
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	return 0;
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun 
idtcm_strverscmp(const char * version1,const char * version2)106*4882a593Smuzhiyun static int idtcm_strverscmp(const char *version1, const char *version2)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun 	u8 ver1[3], ver2[3];
109*4882a593Smuzhiyun 	int i;
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	if (sscanf(version1, "%hhu.%hhu.%hhu",
112*4882a593Smuzhiyun 		   &ver1[0], &ver1[1], &ver1[2]) != 3)
113*4882a593Smuzhiyun 		return -1;
114*4882a593Smuzhiyun 	if (sscanf(version2, "%hhu.%hhu.%hhu",
115*4882a593Smuzhiyun 		   &ver2[0], &ver2[1], &ver2[2]) != 3)
116*4882a593Smuzhiyun 		return -1;
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	for (i = 0; i < 3; i++) {
119*4882a593Smuzhiyun 		if (ver1[i] > ver2[i])
120*4882a593Smuzhiyun 			return 1;
121*4882a593Smuzhiyun 		if (ver1[i] < ver2[i])
122*4882a593Smuzhiyun 			return -1;
123*4882a593Smuzhiyun 	}
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	return 0;
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun 
idtcm_xfer_read(struct idtcm * idtcm,u8 regaddr,u8 * buf,u16 count)128*4882a593Smuzhiyun static int idtcm_xfer_read(struct idtcm *idtcm,
129*4882a593Smuzhiyun 			   u8 regaddr,
130*4882a593Smuzhiyun 			   u8 *buf,
131*4882a593Smuzhiyun 			   u16 count)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun 	struct i2c_client *client = idtcm->client;
134*4882a593Smuzhiyun 	struct i2c_msg msg[2];
135*4882a593Smuzhiyun 	int cnt;
136*4882a593Smuzhiyun 	char *fmt = "i2c_transfer failed at %d in %s, at addr: %04X!\n";
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	msg[0].addr = client->addr;
139*4882a593Smuzhiyun 	msg[0].flags = 0;
140*4882a593Smuzhiyun 	msg[0].len = 1;
141*4882a593Smuzhiyun 	msg[0].buf = &regaddr;
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	msg[1].addr = client->addr;
144*4882a593Smuzhiyun 	msg[1].flags = I2C_M_RD;
145*4882a593Smuzhiyun 	msg[1].len = count;
146*4882a593Smuzhiyun 	msg[1].buf = buf;
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	cnt = i2c_transfer(client->adapter, msg, 2);
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	if (cnt < 0) {
151*4882a593Smuzhiyun 		dev_err(&client->dev,
152*4882a593Smuzhiyun 			fmt,
153*4882a593Smuzhiyun 			__LINE__,
154*4882a593Smuzhiyun 			__func__,
155*4882a593Smuzhiyun 			regaddr);
156*4882a593Smuzhiyun 		return cnt;
157*4882a593Smuzhiyun 	} else if (cnt != 2) {
158*4882a593Smuzhiyun 		dev_err(&client->dev,
159*4882a593Smuzhiyun 			"i2c_transfer sent only %d of %d messages\n", cnt, 2);
160*4882a593Smuzhiyun 		return -EIO;
161*4882a593Smuzhiyun 	}
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	return 0;
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun 
idtcm_xfer_write(struct idtcm * idtcm,u8 regaddr,u8 * buf,u16 count)166*4882a593Smuzhiyun static int idtcm_xfer_write(struct idtcm *idtcm,
167*4882a593Smuzhiyun 			    u8 regaddr,
168*4882a593Smuzhiyun 			    u8 *buf,
169*4882a593Smuzhiyun 			    u16 count)
170*4882a593Smuzhiyun {
171*4882a593Smuzhiyun 	struct i2c_client *client = idtcm->client;
172*4882a593Smuzhiyun 	/* we add 1 byte for device register */
173*4882a593Smuzhiyun 	u8 msg[IDTCM_MAX_WRITE_COUNT + 1];
174*4882a593Smuzhiyun 	int cnt;
175*4882a593Smuzhiyun 	char *fmt = "i2c_master_send failed at %d in %s, at addr: %04X!\n";
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	if (count > IDTCM_MAX_WRITE_COUNT)
178*4882a593Smuzhiyun 		return -EINVAL;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	msg[0] = regaddr;
181*4882a593Smuzhiyun 	memcpy(&msg[1], buf, count);
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	cnt = i2c_master_send(client, msg, count + 1);
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	if (cnt < 0) {
186*4882a593Smuzhiyun 		dev_err(&client->dev,
187*4882a593Smuzhiyun 			fmt,
188*4882a593Smuzhiyun 			__LINE__,
189*4882a593Smuzhiyun 			__func__,
190*4882a593Smuzhiyun 			regaddr);
191*4882a593Smuzhiyun 		return cnt;
192*4882a593Smuzhiyun 	}
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	return 0;
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun 
idtcm_page_offset(struct idtcm * idtcm,u8 val)197*4882a593Smuzhiyun static int idtcm_page_offset(struct idtcm *idtcm, u8 val)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun 	u8 buf[4];
200*4882a593Smuzhiyun 	int err;
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	if (idtcm->page_offset == val)
203*4882a593Smuzhiyun 		return 0;
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	buf[0] = 0x0;
206*4882a593Smuzhiyun 	buf[1] = val;
207*4882a593Smuzhiyun 	buf[2] = 0x10;
208*4882a593Smuzhiyun 	buf[3] = 0x20;
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	err = idtcm_xfer_write(idtcm, PAGE_ADDR, buf, sizeof(buf));
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	if (err) {
213*4882a593Smuzhiyun 		idtcm->page_offset = 0xff;
214*4882a593Smuzhiyun 		dev_err(&idtcm->client->dev, "failed to set page offset\n");
215*4882a593Smuzhiyun 	} else {
216*4882a593Smuzhiyun 		idtcm->page_offset = val;
217*4882a593Smuzhiyun 	}
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	return err;
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun 
_idtcm_rdwr(struct idtcm * idtcm,u16 regaddr,u8 * buf,u16 count,bool write)222*4882a593Smuzhiyun static int _idtcm_rdwr(struct idtcm *idtcm,
223*4882a593Smuzhiyun 		       u16 regaddr,
224*4882a593Smuzhiyun 		       u8 *buf,
225*4882a593Smuzhiyun 		       u16 count,
226*4882a593Smuzhiyun 		       bool write)
227*4882a593Smuzhiyun {
228*4882a593Smuzhiyun 	u8 hi;
229*4882a593Smuzhiyun 	u8 lo;
230*4882a593Smuzhiyun 	int err;
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	hi = (regaddr >> 8) & 0xff;
233*4882a593Smuzhiyun 	lo = regaddr & 0xff;
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	err = idtcm_page_offset(idtcm, hi);
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	if (err)
238*4882a593Smuzhiyun 		return err;
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	if (write)
241*4882a593Smuzhiyun 		return idtcm_xfer_write(idtcm, lo, buf, count);
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	return idtcm_xfer_read(idtcm, lo, buf, count);
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun 
idtcm_read(struct idtcm * idtcm,u16 module,u16 regaddr,u8 * buf,u16 count)246*4882a593Smuzhiyun static int idtcm_read(struct idtcm *idtcm,
247*4882a593Smuzhiyun 		      u16 module,
248*4882a593Smuzhiyun 		      u16 regaddr,
249*4882a593Smuzhiyun 		      u8 *buf,
250*4882a593Smuzhiyun 		      u16 count)
251*4882a593Smuzhiyun {
252*4882a593Smuzhiyun 	return _idtcm_rdwr(idtcm, module + regaddr, buf, count, false);
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun 
idtcm_write(struct idtcm * idtcm,u16 module,u16 regaddr,u8 * buf,u16 count)255*4882a593Smuzhiyun static int idtcm_write(struct idtcm *idtcm,
256*4882a593Smuzhiyun 		       u16 module,
257*4882a593Smuzhiyun 		       u16 regaddr,
258*4882a593Smuzhiyun 		       u8 *buf,
259*4882a593Smuzhiyun 		       u16 count)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun 	return _idtcm_rdwr(idtcm, module + regaddr, buf, count, true);
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun 
_idtcm_gettime(struct idtcm_channel * channel,struct timespec64 * ts)264*4882a593Smuzhiyun static int _idtcm_gettime(struct idtcm_channel *channel,
265*4882a593Smuzhiyun 			  struct timespec64 *ts)
266*4882a593Smuzhiyun {
267*4882a593Smuzhiyun 	struct idtcm *idtcm = channel->idtcm;
268*4882a593Smuzhiyun 	u8 buf[TOD_BYTE_COUNT];
269*4882a593Smuzhiyun 	u8 timeout = 10;
270*4882a593Smuzhiyun 	u8 trigger;
271*4882a593Smuzhiyun 	int err;
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	err = idtcm_read(idtcm, channel->tod_read_primary,
274*4882a593Smuzhiyun 			 TOD_READ_PRIMARY_CMD, &trigger, sizeof(trigger));
275*4882a593Smuzhiyun 	if (err)
276*4882a593Smuzhiyun 		return err;
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	trigger &= ~(TOD_READ_TRIGGER_MASK << TOD_READ_TRIGGER_SHIFT);
279*4882a593Smuzhiyun 	trigger |= (1 << TOD_READ_TRIGGER_SHIFT);
280*4882a593Smuzhiyun 	trigger &= ~TOD_READ_TRIGGER_MODE; /* single shot */
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	err = idtcm_write(idtcm, channel->tod_read_primary,
283*4882a593Smuzhiyun 			  TOD_READ_PRIMARY_CMD, &trigger, sizeof(trigger));
284*4882a593Smuzhiyun 	if (err)
285*4882a593Smuzhiyun 		return err;
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 	/* wait trigger to be 0 */
288*4882a593Smuzhiyun 	while (trigger & TOD_READ_TRIGGER_MASK) {
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 		if (idtcm->calculate_overhead_flag)
291*4882a593Smuzhiyun 			idtcm->start_time = ktime_get_raw();
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 		err = idtcm_read(idtcm, channel->tod_read_primary,
294*4882a593Smuzhiyun 				 TOD_READ_PRIMARY_CMD, &trigger,
295*4882a593Smuzhiyun 				 sizeof(trigger));
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 		if (err)
298*4882a593Smuzhiyun 			return err;
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 		if (--timeout == 0)
301*4882a593Smuzhiyun 			return -EIO;
302*4882a593Smuzhiyun 	}
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	err = idtcm_read(idtcm, channel->tod_read_primary,
305*4882a593Smuzhiyun 			 TOD_READ_PRIMARY, buf, sizeof(buf));
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	if (err)
308*4882a593Smuzhiyun 		return err;
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	err = char_array_to_timespec(buf, sizeof(buf), ts);
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	return err;
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun 
_sync_pll_output(struct idtcm * idtcm,u8 pll,u8 sync_src,u8 qn,u8 qn_plus_1)315*4882a593Smuzhiyun static int _sync_pll_output(struct idtcm *idtcm,
316*4882a593Smuzhiyun 			    u8 pll,
317*4882a593Smuzhiyun 			    u8 sync_src,
318*4882a593Smuzhiyun 			    u8 qn,
319*4882a593Smuzhiyun 			    u8 qn_plus_1)
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun 	int err;
322*4882a593Smuzhiyun 	u8 val;
323*4882a593Smuzhiyun 	u16 sync_ctrl0;
324*4882a593Smuzhiyun 	u16 sync_ctrl1;
325*4882a593Smuzhiyun 	u8 temp;
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	if ((qn == 0) && (qn_plus_1 == 0))
328*4882a593Smuzhiyun 		return 0;
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	switch (pll) {
331*4882a593Smuzhiyun 	case 0:
332*4882a593Smuzhiyun 		sync_ctrl0 = HW_Q0_Q1_CH_SYNC_CTRL_0;
333*4882a593Smuzhiyun 		sync_ctrl1 = HW_Q0_Q1_CH_SYNC_CTRL_1;
334*4882a593Smuzhiyun 		break;
335*4882a593Smuzhiyun 	case 1:
336*4882a593Smuzhiyun 		sync_ctrl0 = HW_Q2_Q3_CH_SYNC_CTRL_0;
337*4882a593Smuzhiyun 		sync_ctrl1 = HW_Q2_Q3_CH_SYNC_CTRL_1;
338*4882a593Smuzhiyun 		break;
339*4882a593Smuzhiyun 	case 2:
340*4882a593Smuzhiyun 		sync_ctrl0 = HW_Q4_Q5_CH_SYNC_CTRL_0;
341*4882a593Smuzhiyun 		sync_ctrl1 = HW_Q4_Q5_CH_SYNC_CTRL_1;
342*4882a593Smuzhiyun 		break;
343*4882a593Smuzhiyun 	case 3:
344*4882a593Smuzhiyun 		sync_ctrl0 = HW_Q6_Q7_CH_SYNC_CTRL_0;
345*4882a593Smuzhiyun 		sync_ctrl1 = HW_Q6_Q7_CH_SYNC_CTRL_1;
346*4882a593Smuzhiyun 		break;
347*4882a593Smuzhiyun 	case 4:
348*4882a593Smuzhiyun 		sync_ctrl0 = HW_Q8_CH_SYNC_CTRL_0;
349*4882a593Smuzhiyun 		sync_ctrl1 = HW_Q8_CH_SYNC_CTRL_1;
350*4882a593Smuzhiyun 		break;
351*4882a593Smuzhiyun 	case 5:
352*4882a593Smuzhiyun 		sync_ctrl0 = HW_Q9_CH_SYNC_CTRL_0;
353*4882a593Smuzhiyun 		sync_ctrl1 = HW_Q9_CH_SYNC_CTRL_1;
354*4882a593Smuzhiyun 		break;
355*4882a593Smuzhiyun 	case 6:
356*4882a593Smuzhiyun 		sync_ctrl0 = HW_Q10_CH_SYNC_CTRL_0;
357*4882a593Smuzhiyun 		sync_ctrl1 = HW_Q10_CH_SYNC_CTRL_1;
358*4882a593Smuzhiyun 		break;
359*4882a593Smuzhiyun 	case 7:
360*4882a593Smuzhiyun 		sync_ctrl0 = HW_Q11_CH_SYNC_CTRL_0;
361*4882a593Smuzhiyun 		sync_ctrl1 = HW_Q11_CH_SYNC_CTRL_1;
362*4882a593Smuzhiyun 		break;
363*4882a593Smuzhiyun 	default:
364*4882a593Smuzhiyun 		return -EINVAL;
365*4882a593Smuzhiyun 	}
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	val = SYNCTRL1_MASTER_SYNC_RST;
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 	/* Place master sync in reset */
370*4882a593Smuzhiyun 	err = idtcm_write(idtcm, 0, sync_ctrl1, &val, sizeof(val));
371*4882a593Smuzhiyun 	if (err)
372*4882a593Smuzhiyun 		return err;
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	err = idtcm_write(idtcm, 0, sync_ctrl0, &sync_src, sizeof(sync_src));
375*4882a593Smuzhiyun 	if (err)
376*4882a593Smuzhiyun 		return err;
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	/* Set sync trigger mask */
379*4882a593Smuzhiyun 	val |= SYNCTRL1_FBDIV_FRAME_SYNC_TRIG | SYNCTRL1_FBDIV_SYNC_TRIG;
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	if (qn)
382*4882a593Smuzhiyun 		val |= SYNCTRL1_Q0_DIV_SYNC_TRIG;
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	if (qn_plus_1)
385*4882a593Smuzhiyun 		val |= SYNCTRL1_Q1_DIV_SYNC_TRIG;
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	err = idtcm_write(idtcm, 0, sync_ctrl1, &val, sizeof(val));
388*4882a593Smuzhiyun 	if (err)
389*4882a593Smuzhiyun 		return err;
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun 	/* PLL5 can have OUT8 as second additional output. */
392*4882a593Smuzhiyun 	if ((pll == 5) && (qn_plus_1 != 0)) {
393*4882a593Smuzhiyun 		err = idtcm_read(idtcm, 0, HW_Q8_CTRL_SPARE,
394*4882a593Smuzhiyun 				 &temp, sizeof(temp));
395*4882a593Smuzhiyun 		if (err)
396*4882a593Smuzhiyun 			return err;
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 		temp &= ~(Q9_TO_Q8_SYNC_TRIG);
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 		err = idtcm_write(idtcm, 0, HW_Q8_CTRL_SPARE,
401*4882a593Smuzhiyun 				  &temp, sizeof(temp));
402*4882a593Smuzhiyun 		if (err)
403*4882a593Smuzhiyun 			return err;
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 		temp |= Q9_TO_Q8_SYNC_TRIG;
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 		err = idtcm_write(idtcm, 0, HW_Q8_CTRL_SPARE,
408*4882a593Smuzhiyun 				  &temp, sizeof(temp));
409*4882a593Smuzhiyun 		if (err)
410*4882a593Smuzhiyun 			return err;
411*4882a593Smuzhiyun 	}
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun 	/* PLL6 can have OUT11 as second additional output. */
414*4882a593Smuzhiyun 	if ((pll == 6) && (qn_plus_1 != 0)) {
415*4882a593Smuzhiyun 		err = idtcm_read(idtcm, 0, HW_Q11_CTRL_SPARE,
416*4882a593Smuzhiyun 				 &temp, sizeof(temp));
417*4882a593Smuzhiyun 		if (err)
418*4882a593Smuzhiyun 			return err;
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 		temp &= ~(Q10_TO_Q11_SYNC_TRIG);
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 		err = idtcm_write(idtcm, 0, HW_Q11_CTRL_SPARE,
423*4882a593Smuzhiyun 				  &temp, sizeof(temp));
424*4882a593Smuzhiyun 		if (err)
425*4882a593Smuzhiyun 			return err;
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 		temp |= Q10_TO_Q11_SYNC_TRIG;
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 		err = idtcm_write(idtcm, 0, HW_Q11_CTRL_SPARE,
430*4882a593Smuzhiyun 				  &temp, sizeof(temp));
431*4882a593Smuzhiyun 		if (err)
432*4882a593Smuzhiyun 			return err;
433*4882a593Smuzhiyun 	}
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 	/* Place master sync out of reset */
436*4882a593Smuzhiyun 	val &= ~(SYNCTRL1_MASTER_SYNC_RST);
437*4882a593Smuzhiyun 	err = idtcm_write(idtcm, 0, sync_ctrl1, &val, sizeof(val));
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 	return err;
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun 
sync_source_dpll_tod_pps(u16 tod_addr,u8 * sync_src)442*4882a593Smuzhiyun static int sync_source_dpll_tod_pps(u16 tod_addr, u8 *sync_src)
443*4882a593Smuzhiyun {
444*4882a593Smuzhiyun 	int err = 0;
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	switch (tod_addr) {
447*4882a593Smuzhiyun 	case TOD_0:
448*4882a593Smuzhiyun 		*sync_src = SYNC_SOURCE_DPLL0_TOD_PPS;
449*4882a593Smuzhiyun 		break;
450*4882a593Smuzhiyun 	case TOD_1:
451*4882a593Smuzhiyun 		*sync_src = SYNC_SOURCE_DPLL1_TOD_PPS;
452*4882a593Smuzhiyun 		break;
453*4882a593Smuzhiyun 	case TOD_2:
454*4882a593Smuzhiyun 		*sync_src = SYNC_SOURCE_DPLL2_TOD_PPS;
455*4882a593Smuzhiyun 		break;
456*4882a593Smuzhiyun 	case TOD_3:
457*4882a593Smuzhiyun 		*sync_src = SYNC_SOURCE_DPLL3_TOD_PPS;
458*4882a593Smuzhiyun 		break;
459*4882a593Smuzhiyun 	default:
460*4882a593Smuzhiyun 		err = -EINVAL;
461*4882a593Smuzhiyun 	}
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 	return err;
464*4882a593Smuzhiyun }
465*4882a593Smuzhiyun 
idtcm_sync_pps_output(struct idtcm_channel * channel)466*4882a593Smuzhiyun static int idtcm_sync_pps_output(struct idtcm_channel *channel)
467*4882a593Smuzhiyun {
468*4882a593Smuzhiyun 	struct idtcm *idtcm = channel->idtcm;
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun 	u8 pll;
471*4882a593Smuzhiyun 	u8 sync_src;
472*4882a593Smuzhiyun 	u8 qn;
473*4882a593Smuzhiyun 	u8 qn_plus_1;
474*4882a593Smuzhiyun 	int err = 0;
475*4882a593Smuzhiyun 	u8 out8_mux = 0;
476*4882a593Smuzhiyun 	u8 out11_mux = 0;
477*4882a593Smuzhiyun 	u8 temp;
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 	u16 output_mask = channel->output_mask;
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun 	err = sync_source_dpll_tod_pps(channel->tod_n, &sync_src);
482*4882a593Smuzhiyun 	if (err)
483*4882a593Smuzhiyun 		return err;
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun 	err = idtcm_read(idtcm, 0, HW_Q8_CTRL_SPARE,
486*4882a593Smuzhiyun 			 &temp, sizeof(temp));
487*4882a593Smuzhiyun 	if (err)
488*4882a593Smuzhiyun 		return err;
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun 	if ((temp & Q9_TO_Q8_FANOUT_AND_CLOCK_SYNC_ENABLE_MASK) ==
491*4882a593Smuzhiyun 	    Q9_TO_Q8_FANOUT_AND_CLOCK_SYNC_ENABLE_MASK)
492*4882a593Smuzhiyun 		out8_mux = 1;
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 	err = idtcm_read(idtcm, 0, HW_Q11_CTRL_SPARE,
495*4882a593Smuzhiyun 			 &temp, sizeof(temp));
496*4882a593Smuzhiyun 	if (err)
497*4882a593Smuzhiyun 		return err;
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 	if ((temp & Q10_TO_Q11_FANOUT_AND_CLOCK_SYNC_ENABLE_MASK) ==
500*4882a593Smuzhiyun 	    Q10_TO_Q11_FANOUT_AND_CLOCK_SYNC_ENABLE_MASK)
501*4882a593Smuzhiyun 		out11_mux = 1;
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 	for (pll = 0; pll < 8; pll++) {
504*4882a593Smuzhiyun 		qn = 0;
505*4882a593Smuzhiyun 		qn_plus_1 = 0;
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 		if (pll < 4) {
508*4882a593Smuzhiyun 			/* First 4 pll has 2 outputs */
509*4882a593Smuzhiyun 			qn = output_mask & 0x1;
510*4882a593Smuzhiyun 			output_mask = output_mask >> 1;
511*4882a593Smuzhiyun 			qn_plus_1 = output_mask & 0x1;
512*4882a593Smuzhiyun 			output_mask = output_mask >> 1;
513*4882a593Smuzhiyun 		} else if (pll == 4) {
514*4882a593Smuzhiyun 			if (out8_mux == 0) {
515*4882a593Smuzhiyun 				qn = output_mask & 0x1;
516*4882a593Smuzhiyun 				output_mask = output_mask >> 1;
517*4882a593Smuzhiyun 			}
518*4882a593Smuzhiyun 		} else if (pll == 5) {
519*4882a593Smuzhiyun 			if (out8_mux) {
520*4882a593Smuzhiyun 				qn_plus_1 = output_mask & 0x1;
521*4882a593Smuzhiyun 				output_mask = output_mask >> 1;
522*4882a593Smuzhiyun 			}
523*4882a593Smuzhiyun 			qn = output_mask & 0x1;
524*4882a593Smuzhiyun 			output_mask = output_mask >> 1;
525*4882a593Smuzhiyun 		} else if (pll == 6) {
526*4882a593Smuzhiyun 			qn = output_mask & 0x1;
527*4882a593Smuzhiyun 			output_mask = output_mask >> 1;
528*4882a593Smuzhiyun 			if (out11_mux) {
529*4882a593Smuzhiyun 				qn_plus_1 = output_mask & 0x1;
530*4882a593Smuzhiyun 				output_mask = output_mask >> 1;
531*4882a593Smuzhiyun 			}
532*4882a593Smuzhiyun 		} else if (pll == 7) {
533*4882a593Smuzhiyun 			if (out11_mux == 0) {
534*4882a593Smuzhiyun 				qn = output_mask & 0x1;
535*4882a593Smuzhiyun 				output_mask = output_mask >> 1;
536*4882a593Smuzhiyun 			}
537*4882a593Smuzhiyun 		}
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 		if ((qn != 0) || (qn_plus_1 != 0))
540*4882a593Smuzhiyun 			err = _sync_pll_output(idtcm, pll, sync_src, qn,
541*4882a593Smuzhiyun 					       qn_plus_1);
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 		if (err)
544*4882a593Smuzhiyun 			return err;
545*4882a593Smuzhiyun 	}
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun 	return err;
548*4882a593Smuzhiyun }
549*4882a593Smuzhiyun 
_idtcm_set_dpll_hw_tod(struct idtcm_channel * channel,struct timespec64 const * ts,enum hw_tod_write_trig_sel wr_trig)550*4882a593Smuzhiyun static int _idtcm_set_dpll_hw_tod(struct idtcm_channel *channel,
551*4882a593Smuzhiyun 			       struct timespec64 const *ts,
552*4882a593Smuzhiyun 			       enum hw_tod_write_trig_sel wr_trig)
553*4882a593Smuzhiyun {
554*4882a593Smuzhiyun 	struct idtcm *idtcm = channel->idtcm;
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun 	u8 buf[TOD_BYTE_COUNT];
557*4882a593Smuzhiyun 	u8 cmd;
558*4882a593Smuzhiyun 	int err;
559*4882a593Smuzhiyun 	struct timespec64 local_ts = *ts;
560*4882a593Smuzhiyun 	s64 total_overhead_ns;
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun 	/* Configure HW TOD write trigger. */
563*4882a593Smuzhiyun 	err = idtcm_read(idtcm, channel->hw_dpll_n, HW_DPLL_TOD_CTRL_1,
564*4882a593Smuzhiyun 			 &cmd, sizeof(cmd));
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun 	if (err)
567*4882a593Smuzhiyun 		return err;
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 	cmd &= ~(0x0f);
570*4882a593Smuzhiyun 	cmd |= wr_trig | 0x08;
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun 	err = idtcm_write(idtcm, channel->hw_dpll_n, HW_DPLL_TOD_CTRL_1,
573*4882a593Smuzhiyun 			  &cmd, sizeof(cmd));
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 	if (err)
576*4882a593Smuzhiyun 		return err;
577*4882a593Smuzhiyun 
578*4882a593Smuzhiyun 	if (wr_trig  != HW_TOD_WR_TRIG_SEL_MSB) {
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun 		err = timespec_to_char_array(&local_ts, buf, sizeof(buf));
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun 		if (err)
583*4882a593Smuzhiyun 			return err;
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun 		err = idtcm_write(idtcm, channel->hw_dpll_n,
586*4882a593Smuzhiyun 				  HW_DPLL_TOD_OVR__0, buf, sizeof(buf));
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun 		if (err)
589*4882a593Smuzhiyun 			return err;
590*4882a593Smuzhiyun 	}
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun 	/* ARM HW TOD write trigger. */
593*4882a593Smuzhiyun 	cmd &= ~(0x08);
594*4882a593Smuzhiyun 
595*4882a593Smuzhiyun 	err = idtcm_write(idtcm, channel->hw_dpll_n, HW_DPLL_TOD_CTRL_1,
596*4882a593Smuzhiyun 			  &cmd, sizeof(cmd));
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun 	if (wr_trig == HW_TOD_WR_TRIG_SEL_MSB) {
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 		if (idtcm->calculate_overhead_flag) {
601*4882a593Smuzhiyun 			/* Assumption: I2C @ 400KHz */
602*4882a593Smuzhiyun 			total_overhead_ns =  ktime_to_ns(ktime_get_raw()
603*4882a593Smuzhiyun 							 - idtcm->start_time)
604*4882a593Smuzhiyun 					     + idtcm->tod_write_overhead_ns
605*4882a593Smuzhiyun 					     + SETTIME_CORRECTION;
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun 			timespec64_add_ns(&local_ts, total_overhead_ns);
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun 			idtcm->calculate_overhead_flag = 0;
610*4882a593Smuzhiyun 		}
611*4882a593Smuzhiyun 
612*4882a593Smuzhiyun 		err = timespec_to_char_array(&local_ts, buf, sizeof(buf));
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun 		if (err)
615*4882a593Smuzhiyun 			return err;
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun 		err = idtcm_write(idtcm, channel->hw_dpll_n,
618*4882a593Smuzhiyun 				  HW_DPLL_TOD_OVR__0, buf, sizeof(buf));
619*4882a593Smuzhiyun 	}
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun 	return err;
622*4882a593Smuzhiyun }
623*4882a593Smuzhiyun 
_idtcm_set_dpll_scsr_tod(struct idtcm_channel * channel,struct timespec64 const * ts,enum scsr_tod_write_trig_sel wr_trig,enum scsr_tod_write_type_sel wr_type)624*4882a593Smuzhiyun static int _idtcm_set_dpll_scsr_tod(struct idtcm_channel *channel,
625*4882a593Smuzhiyun 				    struct timespec64 const *ts,
626*4882a593Smuzhiyun 				    enum scsr_tod_write_trig_sel wr_trig,
627*4882a593Smuzhiyun 				    enum scsr_tod_write_type_sel wr_type)
628*4882a593Smuzhiyun {
629*4882a593Smuzhiyun 	struct idtcm *idtcm = channel->idtcm;
630*4882a593Smuzhiyun 	unsigned char buf[TOD_BYTE_COUNT], cmd;
631*4882a593Smuzhiyun 	struct timespec64 local_ts = *ts;
632*4882a593Smuzhiyun 	int err, count = 0;
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 	timespec64_add_ns(&local_ts, SETTIME_CORRECTION);
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun 	err = timespec_to_char_array(&local_ts, buf, sizeof(buf));
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun 	if (err)
639*4882a593Smuzhiyun 		return err;
640*4882a593Smuzhiyun 
641*4882a593Smuzhiyun 	err = idtcm_write(idtcm, channel->tod_write, TOD_WRITE,
642*4882a593Smuzhiyun 			  buf, sizeof(buf));
643*4882a593Smuzhiyun 	if (err)
644*4882a593Smuzhiyun 		return err;
645*4882a593Smuzhiyun 
646*4882a593Smuzhiyun 	/* Trigger the write operation. */
647*4882a593Smuzhiyun 	err = idtcm_read(idtcm, channel->tod_write, TOD_WRITE_CMD,
648*4882a593Smuzhiyun 			 &cmd, sizeof(cmd));
649*4882a593Smuzhiyun 	if (err)
650*4882a593Smuzhiyun 		return err;
651*4882a593Smuzhiyun 
652*4882a593Smuzhiyun 	cmd &= ~(TOD_WRITE_SELECTION_MASK << TOD_WRITE_SELECTION_SHIFT);
653*4882a593Smuzhiyun 	cmd &= ~(TOD_WRITE_TYPE_MASK << TOD_WRITE_TYPE_SHIFT);
654*4882a593Smuzhiyun 	cmd |= (wr_trig << TOD_WRITE_SELECTION_SHIFT);
655*4882a593Smuzhiyun 	cmd |= (wr_type << TOD_WRITE_TYPE_SHIFT);
656*4882a593Smuzhiyun 
657*4882a593Smuzhiyun 	err = idtcm_write(idtcm, channel->tod_write, TOD_WRITE_CMD,
658*4882a593Smuzhiyun 			   &cmd, sizeof(cmd));
659*4882a593Smuzhiyun 	if (err)
660*4882a593Smuzhiyun 		return err;
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	/* Wait for the operation to complete. */
663*4882a593Smuzhiyun 	while (1) {
664*4882a593Smuzhiyun 		/* pps trigger takes up to 1 sec to complete */
665*4882a593Smuzhiyun 		if (wr_trig == SCSR_TOD_WR_TRIG_SEL_TODPPS)
666*4882a593Smuzhiyun 			msleep(50);
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun 		err = idtcm_read(idtcm, channel->tod_write, TOD_WRITE_CMD,
669*4882a593Smuzhiyun 				 &cmd, sizeof(cmd));
670*4882a593Smuzhiyun 		if (err)
671*4882a593Smuzhiyun 			return err;
672*4882a593Smuzhiyun 
673*4882a593Smuzhiyun 		if (cmd == 0)
674*4882a593Smuzhiyun 			break;
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun 		if (++count > 20) {
677*4882a593Smuzhiyun 			dev_err(&idtcm->client->dev,
678*4882a593Smuzhiyun 				"Timed out waiting for the write counter\n");
679*4882a593Smuzhiyun 			return -EIO;
680*4882a593Smuzhiyun 		}
681*4882a593Smuzhiyun 	}
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun 	return 0;
684*4882a593Smuzhiyun }
685*4882a593Smuzhiyun 
_idtcm_settime(struct idtcm_channel * channel,struct timespec64 const * ts,enum hw_tod_write_trig_sel wr_trig)686*4882a593Smuzhiyun static int _idtcm_settime(struct idtcm_channel *channel,
687*4882a593Smuzhiyun 			  struct timespec64 const *ts,
688*4882a593Smuzhiyun 			  enum hw_tod_write_trig_sel wr_trig)
689*4882a593Smuzhiyun {
690*4882a593Smuzhiyun 	struct idtcm *idtcm = channel->idtcm;
691*4882a593Smuzhiyun 	int err;
692*4882a593Smuzhiyun 	int i;
693*4882a593Smuzhiyun 	u8 trig_sel;
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 	err = _idtcm_set_dpll_hw_tod(channel, ts, wr_trig);
696*4882a593Smuzhiyun 
697*4882a593Smuzhiyun 	if (err)
698*4882a593Smuzhiyun 		return err;
699*4882a593Smuzhiyun 
700*4882a593Smuzhiyun 	/* Wait for the operation to complete. */
701*4882a593Smuzhiyun 	for (i = 0; i < 10000; i++) {
702*4882a593Smuzhiyun 		err = idtcm_read(idtcm, channel->hw_dpll_n,
703*4882a593Smuzhiyun 				 HW_DPLL_TOD_CTRL_1, &trig_sel,
704*4882a593Smuzhiyun 				 sizeof(trig_sel));
705*4882a593Smuzhiyun 
706*4882a593Smuzhiyun 		if (err)
707*4882a593Smuzhiyun 			return err;
708*4882a593Smuzhiyun 
709*4882a593Smuzhiyun 		if (trig_sel == 0x4a)
710*4882a593Smuzhiyun 			break;
711*4882a593Smuzhiyun 
712*4882a593Smuzhiyun 		err = 1;
713*4882a593Smuzhiyun 	}
714*4882a593Smuzhiyun 
715*4882a593Smuzhiyun 	if (err) {
716*4882a593Smuzhiyun 		dev_err(&idtcm->client->dev,
717*4882a593Smuzhiyun 			"Failed at line %d in func %s!\n",
718*4882a593Smuzhiyun 			__LINE__,
719*4882a593Smuzhiyun 			__func__);
720*4882a593Smuzhiyun 		return err;
721*4882a593Smuzhiyun 	}
722*4882a593Smuzhiyun 
723*4882a593Smuzhiyun 	return idtcm_sync_pps_output(channel);
724*4882a593Smuzhiyun }
725*4882a593Smuzhiyun 
_idtcm_settime_v487(struct idtcm_channel * channel,struct timespec64 const * ts,enum scsr_tod_write_type_sel wr_type)726*4882a593Smuzhiyun static int _idtcm_settime_v487(struct idtcm_channel *channel,
727*4882a593Smuzhiyun 			       struct timespec64 const *ts,
728*4882a593Smuzhiyun 			       enum scsr_tod_write_type_sel wr_type)
729*4882a593Smuzhiyun {
730*4882a593Smuzhiyun 	return _idtcm_set_dpll_scsr_tod(channel, ts,
731*4882a593Smuzhiyun 					SCSR_TOD_WR_TRIG_SEL_IMMEDIATE,
732*4882a593Smuzhiyun 					wr_type);
733*4882a593Smuzhiyun }
734*4882a593Smuzhiyun 
idtcm_set_phase_pull_in_offset(struct idtcm_channel * channel,s32 offset_ns)735*4882a593Smuzhiyun static int idtcm_set_phase_pull_in_offset(struct idtcm_channel *channel,
736*4882a593Smuzhiyun 					  s32 offset_ns)
737*4882a593Smuzhiyun {
738*4882a593Smuzhiyun 	int err;
739*4882a593Smuzhiyun 	int i;
740*4882a593Smuzhiyun 	struct idtcm *idtcm = channel->idtcm;
741*4882a593Smuzhiyun 
742*4882a593Smuzhiyun 	u8 buf[4];
743*4882a593Smuzhiyun 
744*4882a593Smuzhiyun 	for (i = 0; i < 4; i++) {
745*4882a593Smuzhiyun 		buf[i] = 0xff & (offset_ns);
746*4882a593Smuzhiyun 		offset_ns >>= 8;
747*4882a593Smuzhiyun 	}
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun 	err = idtcm_write(idtcm, channel->dpll_phase_pull_in, PULL_IN_OFFSET,
750*4882a593Smuzhiyun 			  buf, sizeof(buf));
751*4882a593Smuzhiyun 
752*4882a593Smuzhiyun 	return err;
753*4882a593Smuzhiyun }
754*4882a593Smuzhiyun 
idtcm_set_phase_pull_in_slope_limit(struct idtcm_channel * channel,u32 max_ffo_ppb)755*4882a593Smuzhiyun static int idtcm_set_phase_pull_in_slope_limit(struct idtcm_channel *channel,
756*4882a593Smuzhiyun 					       u32 max_ffo_ppb)
757*4882a593Smuzhiyun {
758*4882a593Smuzhiyun 	int err;
759*4882a593Smuzhiyun 	u8 i;
760*4882a593Smuzhiyun 	struct idtcm *idtcm = channel->idtcm;
761*4882a593Smuzhiyun 
762*4882a593Smuzhiyun 	u8 buf[3];
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun 	if (max_ffo_ppb & 0xff000000)
765*4882a593Smuzhiyun 		max_ffo_ppb = 0;
766*4882a593Smuzhiyun 
767*4882a593Smuzhiyun 	for (i = 0; i < 3; i++) {
768*4882a593Smuzhiyun 		buf[i] = 0xff & (max_ffo_ppb);
769*4882a593Smuzhiyun 		max_ffo_ppb >>= 8;
770*4882a593Smuzhiyun 	}
771*4882a593Smuzhiyun 
772*4882a593Smuzhiyun 	err = idtcm_write(idtcm, channel->dpll_phase_pull_in,
773*4882a593Smuzhiyun 			  PULL_IN_SLOPE_LIMIT, buf, sizeof(buf));
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun 	return err;
776*4882a593Smuzhiyun }
777*4882a593Smuzhiyun 
idtcm_start_phase_pull_in(struct idtcm_channel * channel)778*4882a593Smuzhiyun static int idtcm_start_phase_pull_in(struct idtcm_channel *channel)
779*4882a593Smuzhiyun {
780*4882a593Smuzhiyun 	int err;
781*4882a593Smuzhiyun 	struct idtcm *idtcm = channel->idtcm;
782*4882a593Smuzhiyun 
783*4882a593Smuzhiyun 	u8 buf;
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun 	err = idtcm_read(idtcm, channel->dpll_phase_pull_in, PULL_IN_CTRL,
786*4882a593Smuzhiyun 			 &buf, sizeof(buf));
787*4882a593Smuzhiyun 
788*4882a593Smuzhiyun 	if (err)
789*4882a593Smuzhiyun 		return err;
790*4882a593Smuzhiyun 
791*4882a593Smuzhiyun 	if (buf == 0) {
792*4882a593Smuzhiyun 		buf = 0x01;
793*4882a593Smuzhiyun 		err = idtcm_write(idtcm, channel->dpll_phase_pull_in,
794*4882a593Smuzhiyun 				  PULL_IN_CTRL, &buf, sizeof(buf));
795*4882a593Smuzhiyun 	} else {
796*4882a593Smuzhiyun 		err = -EBUSY;
797*4882a593Smuzhiyun 	}
798*4882a593Smuzhiyun 
799*4882a593Smuzhiyun 	return err;
800*4882a593Smuzhiyun }
801*4882a593Smuzhiyun 
idtcm_do_phase_pull_in(struct idtcm_channel * channel,s32 offset_ns,u32 max_ffo_ppb)802*4882a593Smuzhiyun static int idtcm_do_phase_pull_in(struct idtcm_channel *channel,
803*4882a593Smuzhiyun 				  s32 offset_ns,
804*4882a593Smuzhiyun 				  u32 max_ffo_ppb)
805*4882a593Smuzhiyun {
806*4882a593Smuzhiyun 	int err;
807*4882a593Smuzhiyun 
808*4882a593Smuzhiyun 	err = idtcm_set_phase_pull_in_offset(channel, -offset_ns);
809*4882a593Smuzhiyun 
810*4882a593Smuzhiyun 	if (err)
811*4882a593Smuzhiyun 		return err;
812*4882a593Smuzhiyun 
813*4882a593Smuzhiyun 	err = idtcm_set_phase_pull_in_slope_limit(channel, max_ffo_ppb);
814*4882a593Smuzhiyun 
815*4882a593Smuzhiyun 	if (err)
816*4882a593Smuzhiyun 		return err;
817*4882a593Smuzhiyun 
818*4882a593Smuzhiyun 	err = idtcm_start_phase_pull_in(channel);
819*4882a593Smuzhiyun 
820*4882a593Smuzhiyun 	return err;
821*4882a593Smuzhiyun }
822*4882a593Smuzhiyun 
set_tod_write_overhead(struct idtcm_channel * channel)823*4882a593Smuzhiyun static int set_tod_write_overhead(struct idtcm_channel *channel)
824*4882a593Smuzhiyun {
825*4882a593Smuzhiyun 	struct idtcm *idtcm = channel->idtcm;
826*4882a593Smuzhiyun 	s64 current_ns = 0;
827*4882a593Smuzhiyun 	s64 lowest_ns = 0;
828*4882a593Smuzhiyun 	int err;
829*4882a593Smuzhiyun 	u8 i;
830*4882a593Smuzhiyun 
831*4882a593Smuzhiyun 	ktime_t start;
832*4882a593Smuzhiyun 	ktime_t stop;
833*4882a593Smuzhiyun 
834*4882a593Smuzhiyun 	char buf[TOD_BYTE_COUNT] = {0};
835*4882a593Smuzhiyun 
836*4882a593Smuzhiyun 	/* Set page offset */
837*4882a593Smuzhiyun 	idtcm_write(idtcm, channel->hw_dpll_n, HW_DPLL_TOD_OVR__0,
838*4882a593Smuzhiyun 		    buf, sizeof(buf));
839*4882a593Smuzhiyun 
840*4882a593Smuzhiyun 	for (i = 0; i < TOD_WRITE_OVERHEAD_COUNT_MAX; i++) {
841*4882a593Smuzhiyun 
842*4882a593Smuzhiyun 		start = ktime_get_raw();
843*4882a593Smuzhiyun 
844*4882a593Smuzhiyun 		err = idtcm_write(idtcm, channel->hw_dpll_n,
845*4882a593Smuzhiyun 				  HW_DPLL_TOD_OVR__0, buf, sizeof(buf));
846*4882a593Smuzhiyun 
847*4882a593Smuzhiyun 		if (err)
848*4882a593Smuzhiyun 			return err;
849*4882a593Smuzhiyun 
850*4882a593Smuzhiyun 		stop = ktime_get_raw();
851*4882a593Smuzhiyun 
852*4882a593Smuzhiyun 		current_ns = ktime_to_ns(stop - start);
853*4882a593Smuzhiyun 
854*4882a593Smuzhiyun 		if (i == 0) {
855*4882a593Smuzhiyun 			lowest_ns = current_ns;
856*4882a593Smuzhiyun 		} else {
857*4882a593Smuzhiyun 			if (current_ns < lowest_ns)
858*4882a593Smuzhiyun 				lowest_ns = current_ns;
859*4882a593Smuzhiyun 		}
860*4882a593Smuzhiyun 	}
861*4882a593Smuzhiyun 
862*4882a593Smuzhiyun 	idtcm->tod_write_overhead_ns = lowest_ns;
863*4882a593Smuzhiyun 
864*4882a593Smuzhiyun 	return err;
865*4882a593Smuzhiyun }
866*4882a593Smuzhiyun 
_idtcm_adjtime(struct idtcm_channel * channel,s64 delta)867*4882a593Smuzhiyun static int _idtcm_adjtime(struct idtcm_channel *channel, s64 delta)
868*4882a593Smuzhiyun {
869*4882a593Smuzhiyun 	int err;
870*4882a593Smuzhiyun 	struct idtcm *idtcm = channel->idtcm;
871*4882a593Smuzhiyun 	struct timespec64 ts;
872*4882a593Smuzhiyun 	s64 now;
873*4882a593Smuzhiyun 
874*4882a593Smuzhiyun 	if (abs(delta) < PHASE_PULL_IN_THRESHOLD_NS) {
875*4882a593Smuzhiyun 		err = idtcm_do_phase_pull_in(channel, delta, 0);
876*4882a593Smuzhiyun 	} else {
877*4882a593Smuzhiyun 		idtcm->calculate_overhead_flag = 1;
878*4882a593Smuzhiyun 
879*4882a593Smuzhiyun 		err = set_tod_write_overhead(channel);
880*4882a593Smuzhiyun 
881*4882a593Smuzhiyun 		if (err)
882*4882a593Smuzhiyun 			return err;
883*4882a593Smuzhiyun 
884*4882a593Smuzhiyun 		err = _idtcm_gettime(channel, &ts);
885*4882a593Smuzhiyun 
886*4882a593Smuzhiyun 		if (err)
887*4882a593Smuzhiyun 			return err;
888*4882a593Smuzhiyun 
889*4882a593Smuzhiyun 		now = timespec64_to_ns(&ts);
890*4882a593Smuzhiyun 		now += delta;
891*4882a593Smuzhiyun 
892*4882a593Smuzhiyun 		ts = ns_to_timespec64(now);
893*4882a593Smuzhiyun 
894*4882a593Smuzhiyun 		err = _idtcm_settime(channel, &ts, HW_TOD_WR_TRIG_SEL_MSB);
895*4882a593Smuzhiyun 	}
896*4882a593Smuzhiyun 
897*4882a593Smuzhiyun 	return err;
898*4882a593Smuzhiyun }
899*4882a593Smuzhiyun 
idtcm_state_machine_reset(struct idtcm * idtcm)900*4882a593Smuzhiyun static int idtcm_state_machine_reset(struct idtcm *idtcm)
901*4882a593Smuzhiyun {
902*4882a593Smuzhiyun 	int err;
903*4882a593Smuzhiyun 	u8 byte = SM_RESET_CMD;
904*4882a593Smuzhiyun 
905*4882a593Smuzhiyun 	err = idtcm_write(idtcm, RESET_CTRL, SM_RESET, &byte, sizeof(byte));
906*4882a593Smuzhiyun 
907*4882a593Smuzhiyun 	if (!err)
908*4882a593Smuzhiyun 		msleep_interruptible(POST_SM_RESET_DELAY_MS);
909*4882a593Smuzhiyun 
910*4882a593Smuzhiyun 	return err;
911*4882a593Smuzhiyun }
912*4882a593Smuzhiyun 
idtcm_read_hw_rev_id(struct idtcm * idtcm,u8 * hw_rev_id)913*4882a593Smuzhiyun static int idtcm_read_hw_rev_id(struct idtcm *idtcm, u8 *hw_rev_id)
914*4882a593Smuzhiyun {
915*4882a593Smuzhiyun 	return idtcm_read(idtcm, HW_REVISION, REV_ID, hw_rev_id, sizeof(u8));
916*4882a593Smuzhiyun }
917*4882a593Smuzhiyun 
idtcm_read_product_id(struct idtcm * idtcm,u16 * product_id)918*4882a593Smuzhiyun static int idtcm_read_product_id(struct idtcm *idtcm, u16 *product_id)
919*4882a593Smuzhiyun {
920*4882a593Smuzhiyun 	int err;
921*4882a593Smuzhiyun 	u8 buf[2] = {0};
922*4882a593Smuzhiyun 
923*4882a593Smuzhiyun 	err = idtcm_read(idtcm, GENERAL_STATUS, PRODUCT_ID, buf, sizeof(buf));
924*4882a593Smuzhiyun 
925*4882a593Smuzhiyun 	*product_id = (buf[1] << 8) | buf[0];
926*4882a593Smuzhiyun 
927*4882a593Smuzhiyun 	return err;
928*4882a593Smuzhiyun }
929*4882a593Smuzhiyun 
idtcm_read_major_release(struct idtcm * idtcm,u8 * major)930*4882a593Smuzhiyun static int idtcm_read_major_release(struct idtcm *idtcm, u8 *major)
931*4882a593Smuzhiyun {
932*4882a593Smuzhiyun 	int err;
933*4882a593Smuzhiyun 	u8 buf = 0;
934*4882a593Smuzhiyun 
935*4882a593Smuzhiyun 	err = idtcm_read(idtcm, GENERAL_STATUS, MAJ_REL, &buf, sizeof(buf));
936*4882a593Smuzhiyun 
937*4882a593Smuzhiyun 	*major = buf >> 1;
938*4882a593Smuzhiyun 
939*4882a593Smuzhiyun 	return err;
940*4882a593Smuzhiyun }
941*4882a593Smuzhiyun 
idtcm_read_minor_release(struct idtcm * idtcm,u8 * minor)942*4882a593Smuzhiyun static int idtcm_read_minor_release(struct idtcm *idtcm, u8 *minor)
943*4882a593Smuzhiyun {
944*4882a593Smuzhiyun 	return idtcm_read(idtcm, GENERAL_STATUS, MIN_REL, minor, sizeof(u8));
945*4882a593Smuzhiyun }
946*4882a593Smuzhiyun 
idtcm_read_hotfix_release(struct idtcm * idtcm,u8 * hotfix)947*4882a593Smuzhiyun static int idtcm_read_hotfix_release(struct idtcm *idtcm, u8 *hotfix)
948*4882a593Smuzhiyun {
949*4882a593Smuzhiyun 	return idtcm_read(idtcm,
950*4882a593Smuzhiyun 			  GENERAL_STATUS,
951*4882a593Smuzhiyun 			  HOTFIX_REL,
952*4882a593Smuzhiyun 			  hotfix,
953*4882a593Smuzhiyun 			  sizeof(u8));
954*4882a593Smuzhiyun }
955*4882a593Smuzhiyun 
idtcm_read_otp_scsr_config_select(struct idtcm * idtcm,u8 * config_select)956*4882a593Smuzhiyun static int idtcm_read_otp_scsr_config_select(struct idtcm *idtcm,
957*4882a593Smuzhiyun 					     u8 *config_select)
958*4882a593Smuzhiyun {
959*4882a593Smuzhiyun 	return idtcm_read(idtcm, GENERAL_STATUS, OTP_SCSR_CONFIG_SELECT,
960*4882a593Smuzhiyun 			  config_select, sizeof(u8));
961*4882a593Smuzhiyun }
962*4882a593Smuzhiyun 
set_pll_output_mask(struct idtcm * idtcm,u16 addr,u8 val)963*4882a593Smuzhiyun static int set_pll_output_mask(struct idtcm *idtcm, u16 addr, u8 val)
964*4882a593Smuzhiyun {
965*4882a593Smuzhiyun 	int err = 0;
966*4882a593Smuzhiyun 
967*4882a593Smuzhiyun 	switch (addr) {
968*4882a593Smuzhiyun 	case TOD0_OUT_ALIGN_MASK_ADDR:
969*4882a593Smuzhiyun 		SET_U16_LSB(idtcm->channel[0].output_mask, val);
970*4882a593Smuzhiyun 		break;
971*4882a593Smuzhiyun 	case TOD0_OUT_ALIGN_MASK_ADDR + 1:
972*4882a593Smuzhiyun 		SET_U16_MSB(idtcm->channel[0].output_mask, val);
973*4882a593Smuzhiyun 		break;
974*4882a593Smuzhiyun 	case TOD1_OUT_ALIGN_MASK_ADDR:
975*4882a593Smuzhiyun 		SET_U16_LSB(idtcm->channel[1].output_mask, val);
976*4882a593Smuzhiyun 		break;
977*4882a593Smuzhiyun 	case TOD1_OUT_ALIGN_MASK_ADDR + 1:
978*4882a593Smuzhiyun 		SET_U16_MSB(idtcm->channel[1].output_mask, val);
979*4882a593Smuzhiyun 		break;
980*4882a593Smuzhiyun 	case TOD2_OUT_ALIGN_MASK_ADDR:
981*4882a593Smuzhiyun 		SET_U16_LSB(idtcm->channel[2].output_mask, val);
982*4882a593Smuzhiyun 		break;
983*4882a593Smuzhiyun 	case TOD2_OUT_ALIGN_MASK_ADDR + 1:
984*4882a593Smuzhiyun 		SET_U16_MSB(idtcm->channel[2].output_mask, val);
985*4882a593Smuzhiyun 		break;
986*4882a593Smuzhiyun 	case TOD3_OUT_ALIGN_MASK_ADDR:
987*4882a593Smuzhiyun 		SET_U16_LSB(idtcm->channel[3].output_mask, val);
988*4882a593Smuzhiyun 		break;
989*4882a593Smuzhiyun 	case TOD3_OUT_ALIGN_MASK_ADDR + 1:
990*4882a593Smuzhiyun 		SET_U16_MSB(idtcm->channel[3].output_mask, val);
991*4882a593Smuzhiyun 		break;
992*4882a593Smuzhiyun 	default:
993*4882a593Smuzhiyun 		err = -EFAULT; /* Bad address */;
994*4882a593Smuzhiyun 		break;
995*4882a593Smuzhiyun 	}
996*4882a593Smuzhiyun 
997*4882a593Smuzhiyun 	return err;
998*4882a593Smuzhiyun }
999*4882a593Smuzhiyun 
set_tod_ptp_pll(struct idtcm * idtcm,u8 index,u8 pll)1000*4882a593Smuzhiyun static int set_tod_ptp_pll(struct idtcm *idtcm, u8 index, u8 pll)
1001*4882a593Smuzhiyun {
1002*4882a593Smuzhiyun 	if (index >= MAX_TOD) {
1003*4882a593Smuzhiyun 		dev_err(&idtcm->client->dev, "ToD%d not supported\n", index);
1004*4882a593Smuzhiyun 		return -EINVAL;
1005*4882a593Smuzhiyun 	}
1006*4882a593Smuzhiyun 
1007*4882a593Smuzhiyun 	if (pll >= MAX_PLL) {
1008*4882a593Smuzhiyun 		dev_err(&idtcm->client->dev, "Pll%d not supported\n", pll);
1009*4882a593Smuzhiyun 		return -EINVAL;
1010*4882a593Smuzhiyun 	}
1011*4882a593Smuzhiyun 
1012*4882a593Smuzhiyun 	idtcm->channel[index].pll = pll;
1013*4882a593Smuzhiyun 
1014*4882a593Smuzhiyun 	return 0;
1015*4882a593Smuzhiyun }
1016*4882a593Smuzhiyun 
check_and_set_masks(struct idtcm * idtcm,u16 regaddr,u8 val)1017*4882a593Smuzhiyun static int check_and_set_masks(struct idtcm *idtcm,
1018*4882a593Smuzhiyun 			       u16 regaddr,
1019*4882a593Smuzhiyun 			       u8 val)
1020*4882a593Smuzhiyun {
1021*4882a593Smuzhiyun 	int err = 0;
1022*4882a593Smuzhiyun 
1023*4882a593Smuzhiyun 	switch (regaddr) {
1024*4882a593Smuzhiyun 	case TOD_MASK_ADDR:
1025*4882a593Smuzhiyun 		if ((val & 0xf0) || !(val & 0x0f)) {
1026*4882a593Smuzhiyun 			dev_err(&idtcm->client->dev,
1027*4882a593Smuzhiyun 				"Invalid TOD mask 0x%hhx\n", val);
1028*4882a593Smuzhiyun 			err = -EINVAL;
1029*4882a593Smuzhiyun 		} else {
1030*4882a593Smuzhiyun 			idtcm->tod_mask = val;
1031*4882a593Smuzhiyun 		}
1032*4882a593Smuzhiyun 		break;
1033*4882a593Smuzhiyun 	case TOD0_PTP_PLL_ADDR:
1034*4882a593Smuzhiyun 		err = set_tod_ptp_pll(idtcm, 0, val);
1035*4882a593Smuzhiyun 		break;
1036*4882a593Smuzhiyun 	case TOD1_PTP_PLL_ADDR:
1037*4882a593Smuzhiyun 		err = set_tod_ptp_pll(idtcm, 1, val);
1038*4882a593Smuzhiyun 		break;
1039*4882a593Smuzhiyun 	case TOD2_PTP_PLL_ADDR:
1040*4882a593Smuzhiyun 		err = set_tod_ptp_pll(idtcm, 2, val);
1041*4882a593Smuzhiyun 		break;
1042*4882a593Smuzhiyun 	case TOD3_PTP_PLL_ADDR:
1043*4882a593Smuzhiyun 		err = set_tod_ptp_pll(idtcm, 3, val);
1044*4882a593Smuzhiyun 		break;
1045*4882a593Smuzhiyun 	default:
1046*4882a593Smuzhiyun 		err = set_pll_output_mask(idtcm, regaddr, val);
1047*4882a593Smuzhiyun 		break;
1048*4882a593Smuzhiyun 	}
1049*4882a593Smuzhiyun 
1050*4882a593Smuzhiyun 	return err;
1051*4882a593Smuzhiyun }
1052*4882a593Smuzhiyun 
display_pll_and_masks(struct idtcm * idtcm)1053*4882a593Smuzhiyun static void display_pll_and_masks(struct idtcm *idtcm)
1054*4882a593Smuzhiyun {
1055*4882a593Smuzhiyun 	u8 i;
1056*4882a593Smuzhiyun 	u8 mask;
1057*4882a593Smuzhiyun 
1058*4882a593Smuzhiyun 	dev_dbg(&idtcm->client->dev, "tod_mask = 0x%02x\n", idtcm->tod_mask);
1059*4882a593Smuzhiyun 
1060*4882a593Smuzhiyun 	for (i = 0; i < MAX_TOD; i++) {
1061*4882a593Smuzhiyun 		mask = 1 << i;
1062*4882a593Smuzhiyun 
1063*4882a593Smuzhiyun 		if (mask & idtcm->tod_mask)
1064*4882a593Smuzhiyun 			dev_dbg(&idtcm->client->dev,
1065*4882a593Smuzhiyun 				"TOD%d pll = %d    output_mask = 0x%04x\n",
1066*4882a593Smuzhiyun 				i, idtcm->channel[i].pll,
1067*4882a593Smuzhiyun 				idtcm->channel[i].output_mask);
1068*4882a593Smuzhiyun 	}
1069*4882a593Smuzhiyun }
1070*4882a593Smuzhiyun 
idtcm_load_firmware(struct idtcm * idtcm,struct device * dev)1071*4882a593Smuzhiyun static int idtcm_load_firmware(struct idtcm *idtcm,
1072*4882a593Smuzhiyun 			       struct device *dev)
1073*4882a593Smuzhiyun {
1074*4882a593Smuzhiyun 	char fname[128] = FW_FILENAME;
1075*4882a593Smuzhiyun 	const struct firmware *fw;
1076*4882a593Smuzhiyun 	struct idtcm_fwrc *rec;
1077*4882a593Smuzhiyun 	u32 regaddr;
1078*4882a593Smuzhiyun 	int err;
1079*4882a593Smuzhiyun 	s32 len;
1080*4882a593Smuzhiyun 	u8 val;
1081*4882a593Smuzhiyun 	u8 loaddr;
1082*4882a593Smuzhiyun 
1083*4882a593Smuzhiyun 	if (firmware) /* module parameter */
1084*4882a593Smuzhiyun 		snprintf(fname, sizeof(fname), "%s", firmware);
1085*4882a593Smuzhiyun 
1086*4882a593Smuzhiyun 	dev_dbg(&idtcm->client->dev, "requesting firmware '%s'\n", fname);
1087*4882a593Smuzhiyun 
1088*4882a593Smuzhiyun 	err = request_firmware(&fw, fname, dev);
1089*4882a593Smuzhiyun 
1090*4882a593Smuzhiyun 	if (err) {
1091*4882a593Smuzhiyun 		dev_err(&idtcm->client->dev,
1092*4882a593Smuzhiyun 			"Failed at line %d in func %s!\n",
1093*4882a593Smuzhiyun 			__LINE__,
1094*4882a593Smuzhiyun 			__func__);
1095*4882a593Smuzhiyun 		return err;
1096*4882a593Smuzhiyun 	}
1097*4882a593Smuzhiyun 
1098*4882a593Smuzhiyun 	dev_dbg(&idtcm->client->dev, "firmware size %zu bytes\n", fw->size);
1099*4882a593Smuzhiyun 
1100*4882a593Smuzhiyun 	rec = (struct idtcm_fwrc *) fw->data;
1101*4882a593Smuzhiyun 
1102*4882a593Smuzhiyun 	if (fw->size > 0)
1103*4882a593Smuzhiyun 		idtcm_state_machine_reset(idtcm);
1104*4882a593Smuzhiyun 
1105*4882a593Smuzhiyun 	for (len = fw->size; len > 0; len -= sizeof(*rec)) {
1106*4882a593Smuzhiyun 
1107*4882a593Smuzhiyun 		if (rec->reserved) {
1108*4882a593Smuzhiyun 			dev_err(&idtcm->client->dev,
1109*4882a593Smuzhiyun 				"bad firmware, reserved field non-zero\n");
1110*4882a593Smuzhiyun 			err = -EINVAL;
1111*4882a593Smuzhiyun 		} else {
1112*4882a593Smuzhiyun 			regaddr = rec->hiaddr << 8;
1113*4882a593Smuzhiyun 			regaddr |= rec->loaddr;
1114*4882a593Smuzhiyun 
1115*4882a593Smuzhiyun 			val = rec->value;
1116*4882a593Smuzhiyun 			loaddr = rec->loaddr;
1117*4882a593Smuzhiyun 
1118*4882a593Smuzhiyun 			rec++;
1119*4882a593Smuzhiyun 
1120*4882a593Smuzhiyun 			err = check_and_set_masks(idtcm, regaddr, val);
1121*4882a593Smuzhiyun 		}
1122*4882a593Smuzhiyun 
1123*4882a593Smuzhiyun 		if (err != -EINVAL) {
1124*4882a593Smuzhiyun 			err = 0;
1125*4882a593Smuzhiyun 
1126*4882a593Smuzhiyun 			/* Top (status registers) and bottom are read-only */
1127*4882a593Smuzhiyun 			if ((regaddr < GPIO_USER_CONTROL)
1128*4882a593Smuzhiyun 			    || (regaddr >= SCRATCH))
1129*4882a593Smuzhiyun 				continue;
1130*4882a593Smuzhiyun 
1131*4882a593Smuzhiyun 			/* Page size 128, last 4 bytes of page skipped */
1132*4882a593Smuzhiyun 			if (((loaddr > 0x7b) && (loaddr <= 0x7f))
1133*4882a593Smuzhiyun 			     || loaddr > 0xfb)
1134*4882a593Smuzhiyun 				continue;
1135*4882a593Smuzhiyun 
1136*4882a593Smuzhiyun 			err = idtcm_write(idtcm, regaddr, 0, &val, sizeof(val));
1137*4882a593Smuzhiyun 		}
1138*4882a593Smuzhiyun 
1139*4882a593Smuzhiyun 		if (err)
1140*4882a593Smuzhiyun 			goto out;
1141*4882a593Smuzhiyun 	}
1142*4882a593Smuzhiyun 
1143*4882a593Smuzhiyun 	display_pll_and_masks(idtcm);
1144*4882a593Smuzhiyun 
1145*4882a593Smuzhiyun out:
1146*4882a593Smuzhiyun 	release_firmware(fw);
1147*4882a593Smuzhiyun 	return err;
1148*4882a593Smuzhiyun }
1149*4882a593Smuzhiyun 
idtcm_output_enable(struct idtcm_channel * channel,bool enable,unsigned int outn)1150*4882a593Smuzhiyun static int idtcm_output_enable(struct idtcm_channel *channel,
1151*4882a593Smuzhiyun 			       bool enable, unsigned int outn)
1152*4882a593Smuzhiyun {
1153*4882a593Smuzhiyun 	struct idtcm *idtcm = channel->idtcm;
1154*4882a593Smuzhiyun 	int err;
1155*4882a593Smuzhiyun 	u8 val;
1156*4882a593Smuzhiyun 
1157*4882a593Smuzhiyun 	err = idtcm_read(idtcm, OUTPUT_MODULE_FROM_INDEX(outn),
1158*4882a593Smuzhiyun 			 OUT_CTRL_1, &val, sizeof(val));
1159*4882a593Smuzhiyun 
1160*4882a593Smuzhiyun 	if (err)
1161*4882a593Smuzhiyun 		return err;
1162*4882a593Smuzhiyun 
1163*4882a593Smuzhiyun 	if (enable)
1164*4882a593Smuzhiyun 		val |= SQUELCH_DISABLE;
1165*4882a593Smuzhiyun 	else
1166*4882a593Smuzhiyun 		val &= ~SQUELCH_DISABLE;
1167*4882a593Smuzhiyun 
1168*4882a593Smuzhiyun 	return idtcm_write(idtcm, OUTPUT_MODULE_FROM_INDEX(outn),
1169*4882a593Smuzhiyun 			   OUT_CTRL_1, &val, sizeof(val));
1170*4882a593Smuzhiyun }
1171*4882a593Smuzhiyun 
idtcm_output_mask_enable(struct idtcm_channel * channel,bool enable)1172*4882a593Smuzhiyun static int idtcm_output_mask_enable(struct idtcm_channel *channel,
1173*4882a593Smuzhiyun 				    bool enable)
1174*4882a593Smuzhiyun {
1175*4882a593Smuzhiyun 	u16 mask;
1176*4882a593Smuzhiyun 	int err;
1177*4882a593Smuzhiyun 	u8 outn;
1178*4882a593Smuzhiyun 
1179*4882a593Smuzhiyun 	mask = channel->output_mask;
1180*4882a593Smuzhiyun 	outn = 0;
1181*4882a593Smuzhiyun 
1182*4882a593Smuzhiyun 	while (mask) {
1183*4882a593Smuzhiyun 
1184*4882a593Smuzhiyun 		if (mask & 0x1) {
1185*4882a593Smuzhiyun 
1186*4882a593Smuzhiyun 			err = idtcm_output_enable(channel, enable, outn);
1187*4882a593Smuzhiyun 
1188*4882a593Smuzhiyun 			if (err)
1189*4882a593Smuzhiyun 				return err;
1190*4882a593Smuzhiyun 		}
1191*4882a593Smuzhiyun 
1192*4882a593Smuzhiyun 		mask >>= 0x1;
1193*4882a593Smuzhiyun 		outn++;
1194*4882a593Smuzhiyun 	}
1195*4882a593Smuzhiyun 
1196*4882a593Smuzhiyun 	return 0;
1197*4882a593Smuzhiyun }
1198*4882a593Smuzhiyun 
idtcm_perout_enable(struct idtcm_channel * channel,bool enable,struct ptp_perout_request * perout)1199*4882a593Smuzhiyun static int idtcm_perout_enable(struct idtcm_channel *channel,
1200*4882a593Smuzhiyun 			       bool enable,
1201*4882a593Smuzhiyun 			       struct ptp_perout_request *perout)
1202*4882a593Smuzhiyun {
1203*4882a593Smuzhiyun 	unsigned int flags = perout->flags;
1204*4882a593Smuzhiyun 
1205*4882a593Smuzhiyun 	if (flags == PEROUT_ENABLE_OUTPUT_MASK)
1206*4882a593Smuzhiyun 		return idtcm_output_mask_enable(channel, enable);
1207*4882a593Smuzhiyun 
1208*4882a593Smuzhiyun 	/* Enable/disable individual output instead */
1209*4882a593Smuzhiyun 	return idtcm_output_enable(channel, enable, perout->index);
1210*4882a593Smuzhiyun }
1211*4882a593Smuzhiyun 
idtcm_set_pll_mode(struct idtcm_channel * channel,enum pll_mode pll_mode)1212*4882a593Smuzhiyun static int idtcm_set_pll_mode(struct idtcm_channel *channel,
1213*4882a593Smuzhiyun 			      enum pll_mode pll_mode)
1214*4882a593Smuzhiyun {
1215*4882a593Smuzhiyun 	struct idtcm *idtcm = channel->idtcm;
1216*4882a593Smuzhiyun 	int err;
1217*4882a593Smuzhiyun 	u8 dpll_mode;
1218*4882a593Smuzhiyun 
1219*4882a593Smuzhiyun 	err = idtcm_read(idtcm, channel->dpll_n, DPLL_MODE,
1220*4882a593Smuzhiyun 			 &dpll_mode, sizeof(dpll_mode));
1221*4882a593Smuzhiyun 	if (err)
1222*4882a593Smuzhiyun 		return err;
1223*4882a593Smuzhiyun 
1224*4882a593Smuzhiyun 	dpll_mode &= ~(PLL_MODE_MASK << PLL_MODE_SHIFT);
1225*4882a593Smuzhiyun 
1226*4882a593Smuzhiyun 	dpll_mode |= (pll_mode << PLL_MODE_SHIFT);
1227*4882a593Smuzhiyun 
1228*4882a593Smuzhiyun 	channel->pll_mode = pll_mode;
1229*4882a593Smuzhiyun 
1230*4882a593Smuzhiyun 	err = idtcm_write(idtcm, channel->dpll_n, DPLL_MODE,
1231*4882a593Smuzhiyun 			  &dpll_mode, sizeof(dpll_mode));
1232*4882a593Smuzhiyun 	if (err)
1233*4882a593Smuzhiyun 		return err;
1234*4882a593Smuzhiyun 
1235*4882a593Smuzhiyun 	return 0;
1236*4882a593Smuzhiyun }
1237*4882a593Smuzhiyun 
1238*4882a593Smuzhiyun /* PTP Hardware Clock interface */
1239*4882a593Smuzhiyun 
1240*4882a593Smuzhiyun /**
1241*4882a593Smuzhiyun  * @brief Maximum absolute value for write phase offset in picoseconds
1242*4882a593Smuzhiyun  *
1243*4882a593Smuzhiyun  * Destination signed register is 32-bit register in resolution of 50ps
1244*4882a593Smuzhiyun  *
1245*4882a593Smuzhiyun  * 0x7fffffff * 50 =  2147483647 * 50 = 107374182350
1246*4882a593Smuzhiyun  */
_idtcm_adjphase(struct idtcm_channel * channel,s32 delta_ns)1247*4882a593Smuzhiyun static int _idtcm_adjphase(struct idtcm_channel *channel, s32 delta_ns)
1248*4882a593Smuzhiyun {
1249*4882a593Smuzhiyun 	struct idtcm *idtcm = channel->idtcm;
1250*4882a593Smuzhiyun 
1251*4882a593Smuzhiyun 	int err;
1252*4882a593Smuzhiyun 	u8 i;
1253*4882a593Smuzhiyun 	u8 buf[4] = {0};
1254*4882a593Smuzhiyun 	s32 phase_50ps;
1255*4882a593Smuzhiyun 	s64 offset_ps;
1256*4882a593Smuzhiyun 
1257*4882a593Smuzhiyun 	if (channel->pll_mode != PLL_MODE_WRITE_PHASE) {
1258*4882a593Smuzhiyun 
1259*4882a593Smuzhiyun 		err = idtcm_set_pll_mode(channel, PLL_MODE_WRITE_PHASE);
1260*4882a593Smuzhiyun 
1261*4882a593Smuzhiyun 		if (err)
1262*4882a593Smuzhiyun 			return err;
1263*4882a593Smuzhiyun 
1264*4882a593Smuzhiyun 		channel->write_phase_ready = 0;
1265*4882a593Smuzhiyun 
1266*4882a593Smuzhiyun 		ptp_schedule_worker(channel->ptp_clock,
1267*4882a593Smuzhiyun 				    msecs_to_jiffies(WR_PHASE_SETUP_MS));
1268*4882a593Smuzhiyun 	}
1269*4882a593Smuzhiyun 
1270*4882a593Smuzhiyun 	if (!channel->write_phase_ready)
1271*4882a593Smuzhiyun 		delta_ns = 0;
1272*4882a593Smuzhiyun 
1273*4882a593Smuzhiyun 	offset_ps = (s64)delta_ns * 1000;
1274*4882a593Smuzhiyun 
1275*4882a593Smuzhiyun 	/*
1276*4882a593Smuzhiyun 	 * Check for 32-bit signed max * 50:
1277*4882a593Smuzhiyun 	 *
1278*4882a593Smuzhiyun 	 * 0x7fffffff * 50 =  2147483647 * 50 = 107374182350
1279*4882a593Smuzhiyun 	 */
1280*4882a593Smuzhiyun 	if (offset_ps > MAX_ABS_WRITE_PHASE_PICOSECONDS)
1281*4882a593Smuzhiyun 		offset_ps = MAX_ABS_WRITE_PHASE_PICOSECONDS;
1282*4882a593Smuzhiyun 	else if (offset_ps < -MAX_ABS_WRITE_PHASE_PICOSECONDS)
1283*4882a593Smuzhiyun 		offset_ps = -MAX_ABS_WRITE_PHASE_PICOSECONDS;
1284*4882a593Smuzhiyun 
1285*4882a593Smuzhiyun 	phase_50ps = DIV_ROUND_CLOSEST(div64_s64(offset_ps, 50), 1);
1286*4882a593Smuzhiyun 
1287*4882a593Smuzhiyun 	for (i = 0; i < 4; i++) {
1288*4882a593Smuzhiyun 		buf[i] = phase_50ps & 0xff;
1289*4882a593Smuzhiyun 		phase_50ps >>= 8;
1290*4882a593Smuzhiyun 	}
1291*4882a593Smuzhiyun 
1292*4882a593Smuzhiyun 	err = idtcm_write(idtcm, channel->dpll_phase, DPLL_WR_PHASE,
1293*4882a593Smuzhiyun 			  buf, sizeof(buf));
1294*4882a593Smuzhiyun 
1295*4882a593Smuzhiyun 	return err;
1296*4882a593Smuzhiyun }
1297*4882a593Smuzhiyun 
_idtcm_adjfine(struct idtcm_channel * channel,long scaled_ppm)1298*4882a593Smuzhiyun static int _idtcm_adjfine(struct idtcm_channel *channel, long scaled_ppm)
1299*4882a593Smuzhiyun {
1300*4882a593Smuzhiyun 	struct idtcm *idtcm = channel->idtcm;
1301*4882a593Smuzhiyun 	u8 i;
1302*4882a593Smuzhiyun 	bool neg_adj = 0;
1303*4882a593Smuzhiyun 	int err;
1304*4882a593Smuzhiyun 	u8 buf[6] = {0};
1305*4882a593Smuzhiyun 	s64 fcw;
1306*4882a593Smuzhiyun 
1307*4882a593Smuzhiyun 	if (channel->pll_mode  != PLL_MODE_WRITE_FREQUENCY) {
1308*4882a593Smuzhiyun 		err = idtcm_set_pll_mode(channel, PLL_MODE_WRITE_FREQUENCY);
1309*4882a593Smuzhiyun 		if (err)
1310*4882a593Smuzhiyun 			return err;
1311*4882a593Smuzhiyun 	}
1312*4882a593Smuzhiyun 
1313*4882a593Smuzhiyun 	/*
1314*4882a593Smuzhiyun 	 * Frequency Control Word unit is: 1.11 * 10^-10 ppm
1315*4882a593Smuzhiyun 	 *
1316*4882a593Smuzhiyun 	 * adjfreq:
1317*4882a593Smuzhiyun 	 *       ppb * 10^9
1318*4882a593Smuzhiyun 	 * FCW = ----------
1319*4882a593Smuzhiyun 	 *          111
1320*4882a593Smuzhiyun 	 *
1321*4882a593Smuzhiyun 	 * adjfine:
1322*4882a593Smuzhiyun 	 *       ppm_16 * 5^12
1323*4882a593Smuzhiyun 	 * FCW = -------------
1324*4882a593Smuzhiyun 	 *         111 * 2^4
1325*4882a593Smuzhiyun 	 */
1326*4882a593Smuzhiyun 	if (scaled_ppm < 0) {
1327*4882a593Smuzhiyun 		neg_adj = 1;
1328*4882a593Smuzhiyun 		scaled_ppm = -scaled_ppm;
1329*4882a593Smuzhiyun 	}
1330*4882a593Smuzhiyun 
1331*4882a593Smuzhiyun 	/* 2 ^ -53 = 1.1102230246251565404236316680908e-16 */
1332*4882a593Smuzhiyun 	fcw = scaled_ppm * 244140625ULL;
1333*4882a593Smuzhiyun 
1334*4882a593Smuzhiyun 	fcw = div_u64(fcw, 1776);
1335*4882a593Smuzhiyun 
1336*4882a593Smuzhiyun 	if (neg_adj)
1337*4882a593Smuzhiyun 		fcw = -fcw;
1338*4882a593Smuzhiyun 
1339*4882a593Smuzhiyun 	for (i = 0; i < 6; i++) {
1340*4882a593Smuzhiyun 		buf[i] = fcw & 0xff;
1341*4882a593Smuzhiyun 		fcw >>= 8;
1342*4882a593Smuzhiyun 	}
1343*4882a593Smuzhiyun 
1344*4882a593Smuzhiyun 	err = idtcm_write(idtcm, channel->dpll_freq, DPLL_WR_FREQ,
1345*4882a593Smuzhiyun 			  buf, sizeof(buf));
1346*4882a593Smuzhiyun 
1347*4882a593Smuzhiyun 	return err;
1348*4882a593Smuzhiyun }
1349*4882a593Smuzhiyun 
idtcm_gettime(struct ptp_clock_info * ptp,struct timespec64 * ts)1350*4882a593Smuzhiyun static int idtcm_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
1351*4882a593Smuzhiyun {
1352*4882a593Smuzhiyun 	struct idtcm_channel *channel =
1353*4882a593Smuzhiyun 		container_of(ptp, struct idtcm_channel, caps);
1354*4882a593Smuzhiyun 	struct idtcm *idtcm = channel->idtcm;
1355*4882a593Smuzhiyun 	int err;
1356*4882a593Smuzhiyun 
1357*4882a593Smuzhiyun 	mutex_lock(&idtcm->reg_lock);
1358*4882a593Smuzhiyun 
1359*4882a593Smuzhiyun 	err = _idtcm_gettime(channel, ts);
1360*4882a593Smuzhiyun 
1361*4882a593Smuzhiyun 	if (err)
1362*4882a593Smuzhiyun 		dev_err(&idtcm->client->dev,
1363*4882a593Smuzhiyun 			"Failed at line %d in func %s!\n",
1364*4882a593Smuzhiyun 			__LINE__,
1365*4882a593Smuzhiyun 			__func__);
1366*4882a593Smuzhiyun 
1367*4882a593Smuzhiyun 	mutex_unlock(&idtcm->reg_lock);
1368*4882a593Smuzhiyun 
1369*4882a593Smuzhiyun 	return err;
1370*4882a593Smuzhiyun }
1371*4882a593Smuzhiyun 
idtcm_settime(struct ptp_clock_info * ptp,const struct timespec64 * ts)1372*4882a593Smuzhiyun static int idtcm_settime(struct ptp_clock_info *ptp,
1373*4882a593Smuzhiyun 			 const struct timespec64 *ts)
1374*4882a593Smuzhiyun {
1375*4882a593Smuzhiyun 	struct idtcm_channel *channel =
1376*4882a593Smuzhiyun 		container_of(ptp, struct idtcm_channel, caps);
1377*4882a593Smuzhiyun 	struct idtcm *idtcm = channel->idtcm;
1378*4882a593Smuzhiyun 	int err;
1379*4882a593Smuzhiyun 
1380*4882a593Smuzhiyun 	mutex_lock(&idtcm->reg_lock);
1381*4882a593Smuzhiyun 
1382*4882a593Smuzhiyun 	err = _idtcm_settime(channel, ts, HW_TOD_WR_TRIG_SEL_MSB);
1383*4882a593Smuzhiyun 
1384*4882a593Smuzhiyun 	if (err)
1385*4882a593Smuzhiyun 		dev_err(&idtcm->client->dev,
1386*4882a593Smuzhiyun 			"Failed at line %d in func %s!\n",
1387*4882a593Smuzhiyun 			__LINE__,
1388*4882a593Smuzhiyun 			__func__);
1389*4882a593Smuzhiyun 
1390*4882a593Smuzhiyun 	mutex_unlock(&idtcm->reg_lock);
1391*4882a593Smuzhiyun 
1392*4882a593Smuzhiyun 	return err;
1393*4882a593Smuzhiyun }
1394*4882a593Smuzhiyun 
idtcm_settime_v487(struct ptp_clock_info * ptp,const struct timespec64 * ts)1395*4882a593Smuzhiyun static int idtcm_settime_v487(struct ptp_clock_info *ptp,
1396*4882a593Smuzhiyun 			 const struct timespec64 *ts)
1397*4882a593Smuzhiyun {
1398*4882a593Smuzhiyun 	struct idtcm_channel *channel =
1399*4882a593Smuzhiyun 		container_of(ptp, struct idtcm_channel, caps);
1400*4882a593Smuzhiyun 	struct idtcm *idtcm = channel->idtcm;
1401*4882a593Smuzhiyun 	int err;
1402*4882a593Smuzhiyun 
1403*4882a593Smuzhiyun 	mutex_lock(&idtcm->reg_lock);
1404*4882a593Smuzhiyun 
1405*4882a593Smuzhiyun 	err = _idtcm_settime_v487(channel, ts, SCSR_TOD_WR_TYPE_SEL_ABSOLUTE);
1406*4882a593Smuzhiyun 
1407*4882a593Smuzhiyun 	if (err)
1408*4882a593Smuzhiyun 		dev_err(&idtcm->client->dev,
1409*4882a593Smuzhiyun 			"Failed at line %d in func %s!\n",
1410*4882a593Smuzhiyun 			__LINE__,
1411*4882a593Smuzhiyun 			__func__);
1412*4882a593Smuzhiyun 
1413*4882a593Smuzhiyun 	mutex_unlock(&idtcm->reg_lock);
1414*4882a593Smuzhiyun 
1415*4882a593Smuzhiyun 	return err;
1416*4882a593Smuzhiyun }
1417*4882a593Smuzhiyun 
idtcm_adjtime(struct ptp_clock_info * ptp,s64 delta)1418*4882a593Smuzhiyun static int idtcm_adjtime(struct ptp_clock_info *ptp, s64 delta)
1419*4882a593Smuzhiyun {
1420*4882a593Smuzhiyun 	struct idtcm_channel *channel =
1421*4882a593Smuzhiyun 		container_of(ptp, struct idtcm_channel, caps);
1422*4882a593Smuzhiyun 	struct idtcm *idtcm = channel->idtcm;
1423*4882a593Smuzhiyun 	int err;
1424*4882a593Smuzhiyun 
1425*4882a593Smuzhiyun 	mutex_lock(&idtcm->reg_lock);
1426*4882a593Smuzhiyun 
1427*4882a593Smuzhiyun 	err = _idtcm_adjtime(channel, delta);
1428*4882a593Smuzhiyun 
1429*4882a593Smuzhiyun 	if (err)
1430*4882a593Smuzhiyun 		dev_err(&idtcm->client->dev,
1431*4882a593Smuzhiyun 			"Failed at line %d in func %s!\n",
1432*4882a593Smuzhiyun 			__LINE__,
1433*4882a593Smuzhiyun 			__func__);
1434*4882a593Smuzhiyun 
1435*4882a593Smuzhiyun 	mutex_unlock(&idtcm->reg_lock);
1436*4882a593Smuzhiyun 
1437*4882a593Smuzhiyun 	return err;
1438*4882a593Smuzhiyun }
1439*4882a593Smuzhiyun 
idtcm_adjtime_v487(struct ptp_clock_info * ptp,s64 delta)1440*4882a593Smuzhiyun static int idtcm_adjtime_v487(struct ptp_clock_info *ptp, s64 delta)
1441*4882a593Smuzhiyun {
1442*4882a593Smuzhiyun 	struct idtcm_channel *channel =
1443*4882a593Smuzhiyun 		container_of(ptp, struct idtcm_channel, caps);
1444*4882a593Smuzhiyun 	struct idtcm *idtcm = channel->idtcm;
1445*4882a593Smuzhiyun 	struct timespec64 ts;
1446*4882a593Smuzhiyun 	enum scsr_tod_write_type_sel type;
1447*4882a593Smuzhiyun 	int err;
1448*4882a593Smuzhiyun 
1449*4882a593Smuzhiyun 	if (abs(delta) < PHASE_PULL_IN_THRESHOLD_NS_V487) {
1450*4882a593Smuzhiyun 		err = idtcm_do_phase_pull_in(channel, delta, 0);
1451*4882a593Smuzhiyun 		if (err)
1452*4882a593Smuzhiyun 			dev_err(&idtcm->client->dev,
1453*4882a593Smuzhiyun 				"Failed at line %d in func %s!\n",
1454*4882a593Smuzhiyun 				__LINE__,
1455*4882a593Smuzhiyun 				__func__);
1456*4882a593Smuzhiyun 		return err;
1457*4882a593Smuzhiyun 	}
1458*4882a593Smuzhiyun 
1459*4882a593Smuzhiyun 	if (delta >= 0) {
1460*4882a593Smuzhiyun 		ts = ns_to_timespec64(delta);
1461*4882a593Smuzhiyun 		type = SCSR_TOD_WR_TYPE_SEL_DELTA_PLUS;
1462*4882a593Smuzhiyun 	} else {
1463*4882a593Smuzhiyun 		ts = ns_to_timespec64(-delta);
1464*4882a593Smuzhiyun 		type = SCSR_TOD_WR_TYPE_SEL_DELTA_MINUS;
1465*4882a593Smuzhiyun 	}
1466*4882a593Smuzhiyun 
1467*4882a593Smuzhiyun 	mutex_lock(&idtcm->reg_lock);
1468*4882a593Smuzhiyun 
1469*4882a593Smuzhiyun 	err = _idtcm_settime_v487(channel, &ts, type);
1470*4882a593Smuzhiyun 
1471*4882a593Smuzhiyun 	if (err)
1472*4882a593Smuzhiyun 		dev_err(&idtcm->client->dev,
1473*4882a593Smuzhiyun 			"Failed at line %d in func %s!\n",
1474*4882a593Smuzhiyun 			__LINE__,
1475*4882a593Smuzhiyun 			__func__);
1476*4882a593Smuzhiyun 
1477*4882a593Smuzhiyun 	mutex_unlock(&idtcm->reg_lock);
1478*4882a593Smuzhiyun 
1479*4882a593Smuzhiyun 	return err;
1480*4882a593Smuzhiyun }
1481*4882a593Smuzhiyun 
idtcm_adjphase(struct ptp_clock_info * ptp,s32 delta)1482*4882a593Smuzhiyun static int idtcm_adjphase(struct ptp_clock_info *ptp, s32 delta)
1483*4882a593Smuzhiyun {
1484*4882a593Smuzhiyun 	struct idtcm_channel *channel =
1485*4882a593Smuzhiyun 		container_of(ptp, struct idtcm_channel, caps);
1486*4882a593Smuzhiyun 
1487*4882a593Smuzhiyun 	struct idtcm *idtcm = channel->idtcm;
1488*4882a593Smuzhiyun 
1489*4882a593Smuzhiyun 	int err;
1490*4882a593Smuzhiyun 
1491*4882a593Smuzhiyun 	mutex_lock(&idtcm->reg_lock);
1492*4882a593Smuzhiyun 
1493*4882a593Smuzhiyun 	err = _idtcm_adjphase(channel, delta);
1494*4882a593Smuzhiyun 
1495*4882a593Smuzhiyun 	if (err)
1496*4882a593Smuzhiyun 		dev_err(&idtcm->client->dev,
1497*4882a593Smuzhiyun 			"Failed at line %d in func %s!\n",
1498*4882a593Smuzhiyun 			__LINE__,
1499*4882a593Smuzhiyun 			__func__);
1500*4882a593Smuzhiyun 
1501*4882a593Smuzhiyun 	mutex_unlock(&idtcm->reg_lock);
1502*4882a593Smuzhiyun 
1503*4882a593Smuzhiyun 	return err;
1504*4882a593Smuzhiyun }
1505*4882a593Smuzhiyun 
idtcm_adjfine(struct ptp_clock_info * ptp,long scaled_ppm)1506*4882a593Smuzhiyun static int idtcm_adjfine(struct ptp_clock_info *ptp,  long scaled_ppm)
1507*4882a593Smuzhiyun {
1508*4882a593Smuzhiyun 	struct idtcm_channel *channel =
1509*4882a593Smuzhiyun 		container_of(ptp, struct idtcm_channel, caps);
1510*4882a593Smuzhiyun 
1511*4882a593Smuzhiyun 	struct idtcm *idtcm = channel->idtcm;
1512*4882a593Smuzhiyun 
1513*4882a593Smuzhiyun 	int err;
1514*4882a593Smuzhiyun 
1515*4882a593Smuzhiyun 	mutex_lock(&idtcm->reg_lock);
1516*4882a593Smuzhiyun 
1517*4882a593Smuzhiyun 	err = _idtcm_adjfine(channel, scaled_ppm);
1518*4882a593Smuzhiyun 
1519*4882a593Smuzhiyun 	if (err)
1520*4882a593Smuzhiyun 		dev_err(&idtcm->client->dev,
1521*4882a593Smuzhiyun 			"Failed at line %d in func %s!\n",
1522*4882a593Smuzhiyun 			__LINE__,
1523*4882a593Smuzhiyun 			__func__);
1524*4882a593Smuzhiyun 
1525*4882a593Smuzhiyun 	mutex_unlock(&idtcm->reg_lock);
1526*4882a593Smuzhiyun 
1527*4882a593Smuzhiyun 	return err;
1528*4882a593Smuzhiyun }
1529*4882a593Smuzhiyun 
idtcm_enable(struct ptp_clock_info * ptp,struct ptp_clock_request * rq,int on)1530*4882a593Smuzhiyun static int idtcm_enable(struct ptp_clock_info *ptp,
1531*4882a593Smuzhiyun 			struct ptp_clock_request *rq, int on)
1532*4882a593Smuzhiyun {
1533*4882a593Smuzhiyun 	int err;
1534*4882a593Smuzhiyun 
1535*4882a593Smuzhiyun 	struct idtcm_channel *channel =
1536*4882a593Smuzhiyun 		container_of(ptp, struct idtcm_channel, caps);
1537*4882a593Smuzhiyun 
1538*4882a593Smuzhiyun 	switch (rq->type) {
1539*4882a593Smuzhiyun 	case PTP_CLK_REQ_PEROUT:
1540*4882a593Smuzhiyun 		if (!on) {
1541*4882a593Smuzhiyun 			err = idtcm_perout_enable(channel, false, &rq->perout);
1542*4882a593Smuzhiyun 			if (err)
1543*4882a593Smuzhiyun 				dev_err(&channel->idtcm->client->dev,
1544*4882a593Smuzhiyun 					"Failed at line %d in func %s!\n",
1545*4882a593Smuzhiyun 					__LINE__,
1546*4882a593Smuzhiyun 					__func__);
1547*4882a593Smuzhiyun 			return err;
1548*4882a593Smuzhiyun 		}
1549*4882a593Smuzhiyun 
1550*4882a593Smuzhiyun 		/* Only accept a 1-PPS aligned to the second. */
1551*4882a593Smuzhiyun 		if (rq->perout.start.nsec || rq->perout.period.sec != 1 ||
1552*4882a593Smuzhiyun 		    rq->perout.period.nsec)
1553*4882a593Smuzhiyun 			return -ERANGE;
1554*4882a593Smuzhiyun 
1555*4882a593Smuzhiyun 		err = idtcm_perout_enable(channel, true, &rq->perout);
1556*4882a593Smuzhiyun 		if (err)
1557*4882a593Smuzhiyun 			dev_err(&channel->idtcm->client->dev,
1558*4882a593Smuzhiyun 				"Failed at line %d in func %s!\n",
1559*4882a593Smuzhiyun 				__LINE__,
1560*4882a593Smuzhiyun 				__func__);
1561*4882a593Smuzhiyun 		return err;
1562*4882a593Smuzhiyun 	default:
1563*4882a593Smuzhiyun 		break;
1564*4882a593Smuzhiyun 	}
1565*4882a593Smuzhiyun 
1566*4882a593Smuzhiyun 	return -EOPNOTSUPP;
1567*4882a593Smuzhiyun }
1568*4882a593Smuzhiyun 
_enable_pll_tod_sync(struct idtcm * idtcm,u8 pll,u8 sync_src,u8 qn,u8 qn_plus_1)1569*4882a593Smuzhiyun static int _enable_pll_tod_sync(struct idtcm *idtcm,
1570*4882a593Smuzhiyun 				u8 pll,
1571*4882a593Smuzhiyun 				u8 sync_src,
1572*4882a593Smuzhiyun 				u8 qn,
1573*4882a593Smuzhiyun 				u8 qn_plus_1)
1574*4882a593Smuzhiyun {
1575*4882a593Smuzhiyun 	int err;
1576*4882a593Smuzhiyun 	u8 val;
1577*4882a593Smuzhiyun 	u16 dpll;
1578*4882a593Smuzhiyun 	u16 out0 = 0, out1 = 0;
1579*4882a593Smuzhiyun 
1580*4882a593Smuzhiyun 	if ((qn == 0) && (qn_plus_1 == 0))
1581*4882a593Smuzhiyun 		return 0;
1582*4882a593Smuzhiyun 
1583*4882a593Smuzhiyun 	switch (pll) {
1584*4882a593Smuzhiyun 	case 0:
1585*4882a593Smuzhiyun 		dpll = DPLL_0;
1586*4882a593Smuzhiyun 		if (qn)
1587*4882a593Smuzhiyun 			out0 = OUTPUT_0;
1588*4882a593Smuzhiyun 		if (qn_plus_1)
1589*4882a593Smuzhiyun 			out1 = OUTPUT_1;
1590*4882a593Smuzhiyun 		break;
1591*4882a593Smuzhiyun 	case 1:
1592*4882a593Smuzhiyun 		dpll = DPLL_1;
1593*4882a593Smuzhiyun 		if (qn)
1594*4882a593Smuzhiyun 			out0 = OUTPUT_2;
1595*4882a593Smuzhiyun 		if (qn_plus_1)
1596*4882a593Smuzhiyun 			out1 = OUTPUT_3;
1597*4882a593Smuzhiyun 		break;
1598*4882a593Smuzhiyun 	case 2:
1599*4882a593Smuzhiyun 		dpll = DPLL_2;
1600*4882a593Smuzhiyun 		if (qn)
1601*4882a593Smuzhiyun 			out0 = OUTPUT_4;
1602*4882a593Smuzhiyun 		if (qn_plus_1)
1603*4882a593Smuzhiyun 			out1 = OUTPUT_5;
1604*4882a593Smuzhiyun 		break;
1605*4882a593Smuzhiyun 	case 3:
1606*4882a593Smuzhiyun 		dpll = DPLL_3;
1607*4882a593Smuzhiyun 		if (qn)
1608*4882a593Smuzhiyun 			out0 = OUTPUT_6;
1609*4882a593Smuzhiyun 		if (qn_plus_1)
1610*4882a593Smuzhiyun 			out1 = OUTPUT_7;
1611*4882a593Smuzhiyun 		break;
1612*4882a593Smuzhiyun 	case 4:
1613*4882a593Smuzhiyun 		dpll = DPLL_4;
1614*4882a593Smuzhiyun 		if (qn)
1615*4882a593Smuzhiyun 			out0 = OUTPUT_8;
1616*4882a593Smuzhiyun 		break;
1617*4882a593Smuzhiyun 	case 5:
1618*4882a593Smuzhiyun 		dpll = DPLL_5;
1619*4882a593Smuzhiyun 		if (qn)
1620*4882a593Smuzhiyun 			out0 = OUTPUT_9;
1621*4882a593Smuzhiyun 		if (qn_plus_1)
1622*4882a593Smuzhiyun 			out1 = OUTPUT_8;
1623*4882a593Smuzhiyun 		break;
1624*4882a593Smuzhiyun 	case 6:
1625*4882a593Smuzhiyun 		dpll = DPLL_6;
1626*4882a593Smuzhiyun 		if (qn)
1627*4882a593Smuzhiyun 			out0 = OUTPUT_10;
1628*4882a593Smuzhiyun 		if (qn_plus_1)
1629*4882a593Smuzhiyun 			out1 = OUTPUT_11;
1630*4882a593Smuzhiyun 		break;
1631*4882a593Smuzhiyun 	case 7:
1632*4882a593Smuzhiyun 		dpll = DPLL_7;
1633*4882a593Smuzhiyun 		if (qn)
1634*4882a593Smuzhiyun 			out0 = OUTPUT_11;
1635*4882a593Smuzhiyun 		break;
1636*4882a593Smuzhiyun 	default:
1637*4882a593Smuzhiyun 		return -EINVAL;
1638*4882a593Smuzhiyun 	}
1639*4882a593Smuzhiyun 
1640*4882a593Smuzhiyun 	/*
1641*4882a593Smuzhiyun 	 * Enable OUTPUT OUT_SYNC.
1642*4882a593Smuzhiyun 	 */
1643*4882a593Smuzhiyun 	if (out0) {
1644*4882a593Smuzhiyun 		err = idtcm_read(idtcm, out0, OUT_CTRL_1, &val, sizeof(val));
1645*4882a593Smuzhiyun 
1646*4882a593Smuzhiyun 		if (err)
1647*4882a593Smuzhiyun 			return err;
1648*4882a593Smuzhiyun 
1649*4882a593Smuzhiyun 		val &= ~OUT_SYNC_DISABLE;
1650*4882a593Smuzhiyun 
1651*4882a593Smuzhiyun 		err = idtcm_write(idtcm, out0, OUT_CTRL_1, &val, sizeof(val));
1652*4882a593Smuzhiyun 
1653*4882a593Smuzhiyun 		if (err)
1654*4882a593Smuzhiyun 			return err;
1655*4882a593Smuzhiyun 	}
1656*4882a593Smuzhiyun 
1657*4882a593Smuzhiyun 	if (out1) {
1658*4882a593Smuzhiyun 		err = idtcm_read(idtcm, out1, OUT_CTRL_1, &val, sizeof(val));
1659*4882a593Smuzhiyun 
1660*4882a593Smuzhiyun 		if (err)
1661*4882a593Smuzhiyun 			return err;
1662*4882a593Smuzhiyun 
1663*4882a593Smuzhiyun 		val &= ~OUT_SYNC_DISABLE;
1664*4882a593Smuzhiyun 
1665*4882a593Smuzhiyun 		err = idtcm_write(idtcm, out1, OUT_CTRL_1, &val, sizeof(val));
1666*4882a593Smuzhiyun 
1667*4882a593Smuzhiyun 		if (err)
1668*4882a593Smuzhiyun 			return err;
1669*4882a593Smuzhiyun 	}
1670*4882a593Smuzhiyun 
1671*4882a593Smuzhiyun 	/* enable dpll sync tod pps, must be set before dpll_mode */
1672*4882a593Smuzhiyun 	err = idtcm_read(idtcm, dpll, DPLL_TOD_SYNC_CFG, &val, sizeof(val));
1673*4882a593Smuzhiyun 	if (err)
1674*4882a593Smuzhiyun 		return err;
1675*4882a593Smuzhiyun 
1676*4882a593Smuzhiyun 	val &= ~(TOD_SYNC_SOURCE_MASK << TOD_SYNC_SOURCE_SHIFT);
1677*4882a593Smuzhiyun 	val |= (sync_src << TOD_SYNC_SOURCE_SHIFT);
1678*4882a593Smuzhiyun 	val |= TOD_SYNC_EN;
1679*4882a593Smuzhiyun 
1680*4882a593Smuzhiyun 	return idtcm_write(idtcm, dpll, DPLL_TOD_SYNC_CFG, &val, sizeof(val));
1681*4882a593Smuzhiyun }
1682*4882a593Smuzhiyun 
idtcm_enable_tod_sync(struct idtcm_channel * channel)1683*4882a593Smuzhiyun static int idtcm_enable_tod_sync(struct idtcm_channel *channel)
1684*4882a593Smuzhiyun {
1685*4882a593Smuzhiyun 	struct idtcm *idtcm = channel->idtcm;
1686*4882a593Smuzhiyun 
1687*4882a593Smuzhiyun 	u8 pll;
1688*4882a593Smuzhiyun 	u8 sync_src;
1689*4882a593Smuzhiyun 	u8 qn;
1690*4882a593Smuzhiyun 	u8 qn_plus_1;
1691*4882a593Smuzhiyun 	u8 cfg;
1692*4882a593Smuzhiyun 	int err = 0;
1693*4882a593Smuzhiyun 	u16 output_mask = channel->output_mask;
1694*4882a593Smuzhiyun 	u8 out8_mux = 0;
1695*4882a593Smuzhiyun 	u8 out11_mux = 0;
1696*4882a593Smuzhiyun 	u8 temp;
1697*4882a593Smuzhiyun 
1698*4882a593Smuzhiyun 	/*
1699*4882a593Smuzhiyun 	 * set tod_out_sync_enable to 0.
1700*4882a593Smuzhiyun 	 */
1701*4882a593Smuzhiyun 	err = idtcm_read(idtcm, channel->tod_n, TOD_CFG, &cfg, sizeof(cfg));
1702*4882a593Smuzhiyun 	if (err)
1703*4882a593Smuzhiyun 		return err;
1704*4882a593Smuzhiyun 
1705*4882a593Smuzhiyun 	cfg &= ~TOD_OUT_SYNC_ENABLE;
1706*4882a593Smuzhiyun 
1707*4882a593Smuzhiyun 	err = idtcm_write(idtcm, channel->tod_n, TOD_CFG, &cfg, sizeof(cfg));
1708*4882a593Smuzhiyun 	if (err)
1709*4882a593Smuzhiyun 		return err;
1710*4882a593Smuzhiyun 
1711*4882a593Smuzhiyun 	switch (channel->tod_n) {
1712*4882a593Smuzhiyun 	case TOD_0:
1713*4882a593Smuzhiyun 		sync_src = 0;
1714*4882a593Smuzhiyun 		break;
1715*4882a593Smuzhiyun 	case TOD_1:
1716*4882a593Smuzhiyun 		sync_src = 1;
1717*4882a593Smuzhiyun 		break;
1718*4882a593Smuzhiyun 	case TOD_2:
1719*4882a593Smuzhiyun 		sync_src = 2;
1720*4882a593Smuzhiyun 		break;
1721*4882a593Smuzhiyun 	case TOD_3:
1722*4882a593Smuzhiyun 		sync_src = 3;
1723*4882a593Smuzhiyun 		break;
1724*4882a593Smuzhiyun 	default:
1725*4882a593Smuzhiyun 		return -EINVAL;
1726*4882a593Smuzhiyun 	}
1727*4882a593Smuzhiyun 
1728*4882a593Smuzhiyun 	err = idtcm_read(idtcm, 0, HW_Q8_CTRL_SPARE,
1729*4882a593Smuzhiyun 			 &temp, sizeof(temp));
1730*4882a593Smuzhiyun 	if (err)
1731*4882a593Smuzhiyun 		return err;
1732*4882a593Smuzhiyun 
1733*4882a593Smuzhiyun 	if ((temp & Q9_TO_Q8_FANOUT_AND_CLOCK_SYNC_ENABLE_MASK) ==
1734*4882a593Smuzhiyun 	    Q9_TO_Q8_FANOUT_AND_CLOCK_SYNC_ENABLE_MASK)
1735*4882a593Smuzhiyun 		out8_mux = 1;
1736*4882a593Smuzhiyun 
1737*4882a593Smuzhiyun 	err = idtcm_read(idtcm, 0, HW_Q11_CTRL_SPARE,
1738*4882a593Smuzhiyun 			 &temp, sizeof(temp));
1739*4882a593Smuzhiyun 	if (err)
1740*4882a593Smuzhiyun 		return err;
1741*4882a593Smuzhiyun 
1742*4882a593Smuzhiyun 	if ((temp & Q10_TO_Q11_FANOUT_AND_CLOCK_SYNC_ENABLE_MASK) ==
1743*4882a593Smuzhiyun 	    Q10_TO_Q11_FANOUT_AND_CLOCK_SYNC_ENABLE_MASK)
1744*4882a593Smuzhiyun 		out11_mux = 1;
1745*4882a593Smuzhiyun 
1746*4882a593Smuzhiyun 	for (pll = 0; pll < 8; pll++) {
1747*4882a593Smuzhiyun 		qn = 0;
1748*4882a593Smuzhiyun 		qn_plus_1 = 0;
1749*4882a593Smuzhiyun 
1750*4882a593Smuzhiyun 		if (pll < 4) {
1751*4882a593Smuzhiyun 			/* First 4 pll has 2 outputs */
1752*4882a593Smuzhiyun 			qn = output_mask & 0x1;
1753*4882a593Smuzhiyun 			output_mask = output_mask >> 1;
1754*4882a593Smuzhiyun 			qn_plus_1 = output_mask & 0x1;
1755*4882a593Smuzhiyun 			output_mask = output_mask >> 1;
1756*4882a593Smuzhiyun 		} else if (pll == 4) {
1757*4882a593Smuzhiyun 			if (out8_mux == 0) {
1758*4882a593Smuzhiyun 				qn = output_mask & 0x1;
1759*4882a593Smuzhiyun 				output_mask = output_mask >> 1;
1760*4882a593Smuzhiyun 			}
1761*4882a593Smuzhiyun 		} else if (pll == 5) {
1762*4882a593Smuzhiyun 			if (out8_mux) {
1763*4882a593Smuzhiyun 				qn_plus_1 = output_mask & 0x1;
1764*4882a593Smuzhiyun 				output_mask = output_mask >> 1;
1765*4882a593Smuzhiyun 			}
1766*4882a593Smuzhiyun 			qn = output_mask & 0x1;
1767*4882a593Smuzhiyun 			output_mask = output_mask >> 1;
1768*4882a593Smuzhiyun 		} else if (pll == 6) {
1769*4882a593Smuzhiyun 			qn = output_mask & 0x1;
1770*4882a593Smuzhiyun 			output_mask = output_mask >> 1;
1771*4882a593Smuzhiyun 			if (out11_mux) {
1772*4882a593Smuzhiyun 				qn_plus_1 = output_mask & 0x1;
1773*4882a593Smuzhiyun 				output_mask = output_mask >> 1;
1774*4882a593Smuzhiyun 			}
1775*4882a593Smuzhiyun 		} else if (pll == 7) {
1776*4882a593Smuzhiyun 			if (out11_mux == 0) {
1777*4882a593Smuzhiyun 				qn = output_mask & 0x1;
1778*4882a593Smuzhiyun 				output_mask = output_mask >> 1;
1779*4882a593Smuzhiyun 			}
1780*4882a593Smuzhiyun 		}
1781*4882a593Smuzhiyun 
1782*4882a593Smuzhiyun 		if ((qn != 0) || (qn_plus_1 != 0))
1783*4882a593Smuzhiyun 			err = _enable_pll_tod_sync(idtcm, pll, sync_src, qn,
1784*4882a593Smuzhiyun 					       qn_plus_1);
1785*4882a593Smuzhiyun 
1786*4882a593Smuzhiyun 		if (err)
1787*4882a593Smuzhiyun 			return err;
1788*4882a593Smuzhiyun 	}
1789*4882a593Smuzhiyun 
1790*4882a593Smuzhiyun 	return err;
1791*4882a593Smuzhiyun }
1792*4882a593Smuzhiyun 
idtcm_enable_tod(struct idtcm_channel * channel)1793*4882a593Smuzhiyun static int idtcm_enable_tod(struct idtcm_channel *channel)
1794*4882a593Smuzhiyun {
1795*4882a593Smuzhiyun 	struct idtcm *idtcm = channel->idtcm;
1796*4882a593Smuzhiyun 	struct timespec64 ts = {0, 0};
1797*4882a593Smuzhiyun 	u8 cfg;
1798*4882a593Smuzhiyun 	int err;
1799*4882a593Smuzhiyun 
1800*4882a593Smuzhiyun 	/*
1801*4882a593Smuzhiyun 	 * Start the TOD clock ticking.
1802*4882a593Smuzhiyun 	 */
1803*4882a593Smuzhiyun 	err = idtcm_read(idtcm, channel->tod_n, TOD_CFG, &cfg, sizeof(cfg));
1804*4882a593Smuzhiyun 	if (err)
1805*4882a593Smuzhiyun 		return err;
1806*4882a593Smuzhiyun 
1807*4882a593Smuzhiyun 	cfg |= TOD_ENABLE;
1808*4882a593Smuzhiyun 
1809*4882a593Smuzhiyun 	err = idtcm_write(idtcm, channel->tod_n, TOD_CFG, &cfg, sizeof(cfg));
1810*4882a593Smuzhiyun 	if (err)
1811*4882a593Smuzhiyun 		return err;
1812*4882a593Smuzhiyun 
1813*4882a593Smuzhiyun 	return _idtcm_settime(channel, &ts, HW_TOD_WR_TRIG_SEL_MSB);
1814*4882a593Smuzhiyun }
1815*4882a593Smuzhiyun 
idtcm_display_version_info(struct idtcm * idtcm)1816*4882a593Smuzhiyun static void idtcm_display_version_info(struct idtcm *idtcm)
1817*4882a593Smuzhiyun {
1818*4882a593Smuzhiyun 	u8 major;
1819*4882a593Smuzhiyun 	u8 minor;
1820*4882a593Smuzhiyun 	u8 hotfix;
1821*4882a593Smuzhiyun 	u16 product_id;
1822*4882a593Smuzhiyun 	u8 hw_rev_id;
1823*4882a593Smuzhiyun 	u8 config_select;
1824*4882a593Smuzhiyun 	char *fmt = "%d.%d.%d, Id: 0x%04x  HW Rev: %d  OTP Config Select: %d\n";
1825*4882a593Smuzhiyun 
1826*4882a593Smuzhiyun 	idtcm_read_major_release(idtcm, &major);
1827*4882a593Smuzhiyun 	idtcm_read_minor_release(idtcm, &minor);
1828*4882a593Smuzhiyun 	idtcm_read_hotfix_release(idtcm, &hotfix);
1829*4882a593Smuzhiyun 
1830*4882a593Smuzhiyun 	idtcm_read_product_id(idtcm, &product_id);
1831*4882a593Smuzhiyun 	idtcm_read_hw_rev_id(idtcm, &hw_rev_id);
1832*4882a593Smuzhiyun 
1833*4882a593Smuzhiyun 	idtcm_read_otp_scsr_config_select(idtcm, &config_select);
1834*4882a593Smuzhiyun 
1835*4882a593Smuzhiyun 	snprintf(idtcm->version, sizeof(idtcm->version), "%u.%u.%u",
1836*4882a593Smuzhiyun 		 major, minor, hotfix);
1837*4882a593Smuzhiyun 
1838*4882a593Smuzhiyun 	dev_info(&idtcm->client->dev, fmt, major, minor, hotfix,
1839*4882a593Smuzhiyun 		 product_id, hw_rev_id, config_select);
1840*4882a593Smuzhiyun }
1841*4882a593Smuzhiyun 
1842*4882a593Smuzhiyun static const struct ptp_clock_info idtcm_caps_v487 = {
1843*4882a593Smuzhiyun 	.owner		= THIS_MODULE,
1844*4882a593Smuzhiyun 	.max_adj	= 244000,
1845*4882a593Smuzhiyun 	.n_per_out	= 12,
1846*4882a593Smuzhiyun 	.adjphase	= &idtcm_adjphase,
1847*4882a593Smuzhiyun 	.adjfine	= &idtcm_adjfine,
1848*4882a593Smuzhiyun 	.adjtime	= &idtcm_adjtime_v487,
1849*4882a593Smuzhiyun 	.gettime64	= &idtcm_gettime,
1850*4882a593Smuzhiyun 	.settime64	= &idtcm_settime_v487,
1851*4882a593Smuzhiyun 	.enable		= &idtcm_enable,
1852*4882a593Smuzhiyun 	.do_aux_work	= &set_write_phase_ready,
1853*4882a593Smuzhiyun };
1854*4882a593Smuzhiyun 
1855*4882a593Smuzhiyun static const struct ptp_clock_info idtcm_caps = {
1856*4882a593Smuzhiyun 	.owner		= THIS_MODULE,
1857*4882a593Smuzhiyun 	.max_adj	= 244000,
1858*4882a593Smuzhiyun 	.n_per_out	= 12,
1859*4882a593Smuzhiyun 	.adjphase	= &idtcm_adjphase,
1860*4882a593Smuzhiyun 	.adjfine	= &idtcm_adjfine,
1861*4882a593Smuzhiyun 	.adjtime	= &idtcm_adjtime,
1862*4882a593Smuzhiyun 	.gettime64	= &idtcm_gettime,
1863*4882a593Smuzhiyun 	.settime64	= &idtcm_settime,
1864*4882a593Smuzhiyun 	.enable		= &idtcm_enable,
1865*4882a593Smuzhiyun 	.do_aux_work	= &set_write_phase_ready,
1866*4882a593Smuzhiyun };
1867*4882a593Smuzhiyun 
configure_channel_pll(struct idtcm_channel * channel)1868*4882a593Smuzhiyun static int configure_channel_pll(struct idtcm_channel *channel)
1869*4882a593Smuzhiyun {
1870*4882a593Smuzhiyun 	int err = 0;
1871*4882a593Smuzhiyun 
1872*4882a593Smuzhiyun 	switch (channel->pll) {
1873*4882a593Smuzhiyun 	case 0:
1874*4882a593Smuzhiyun 		channel->dpll_freq = DPLL_FREQ_0;
1875*4882a593Smuzhiyun 		channel->dpll_n = DPLL_0;
1876*4882a593Smuzhiyun 		channel->hw_dpll_n = HW_DPLL_0;
1877*4882a593Smuzhiyun 		channel->dpll_phase = DPLL_PHASE_0;
1878*4882a593Smuzhiyun 		channel->dpll_ctrl_n = DPLL_CTRL_0;
1879*4882a593Smuzhiyun 		channel->dpll_phase_pull_in = DPLL_PHASE_PULL_IN_0;
1880*4882a593Smuzhiyun 		break;
1881*4882a593Smuzhiyun 	case 1:
1882*4882a593Smuzhiyun 		channel->dpll_freq = DPLL_FREQ_1;
1883*4882a593Smuzhiyun 		channel->dpll_n = DPLL_1;
1884*4882a593Smuzhiyun 		channel->hw_dpll_n = HW_DPLL_1;
1885*4882a593Smuzhiyun 		channel->dpll_phase = DPLL_PHASE_1;
1886*4882a593Smuzhiyun 		channel->dpll_ctrl_n = DPLL_CTRL_1;
1887*4882a593Smuzhiyun 		channel->dpll_phase_pull_in = DPLL_PHASE_PULL_IN_1;
1888*4882a593Smuzhiyun 		break;
1889*4882a593Smuzhiyun 	case 2:
1890*4882a593Smuzhiyun 		channel->dpll_freq = DPLL_FREQ_2;
1891*4882a593Smuzhiyun 		channel->dpll_n = DPLL_2;
1892*4882a593Smuzhiyun 		channel->hw_dpll_n = HW_DPLL_2;
1893*4882a593Smuzhiyun 		channel->dpll_phase = DPLL_PHASE_2;
1894*4882a593Smuzhiyun 		channel->dpll_ctrl_n = DPLL_CTRL_2;
1895*4882a593Smuzhiyun 		channel->dpll_phase_pull_in = DPLL_PHASE_PULL_IN_2;
1896*4882a593Smuzhiyun 		break;
1897*4882a593Smuzhiyun 	case 3:
1898*4882a593Smuzhiyun 		channel->dpll_freq = DPLL_FREQ_3;
1899*4882a593Smuzhiyun 		channel->dpll_n = DPLL_3;
1900*4882a593Smuzhiyun 		channel->hw_dpll_n = HW_DPLL_3;
1901*4882a593Smuzhiyun 		channel->dpll_phase = DPLL_PHASE_3;
1902*4882a593Smuzhiyun 		channel->dpll_ctrl_n = DPLL_CTRL_3;
1903*4882a593Smuzhiyun 		channel->dpll_phase_pull_in = DPLL_PHASE_PULL_IN_3;
1904*4882a593Smuzhiyun 		break;
1905*4882a593Smuzhiyun 	case 4:
1906*4882a593Smuzhiyun 		channel->dpll_freq = DPLL_FREQ_4;
1907*4882a593Smuzhiyun 		channel->dpll_n = DPLL_4;
1908*4882a593Smuzhiyun 		channel->hw_dpll_n = HW_DPLL_4;
1909*4882a593Smuzhiyun 		channel->dpll_phase = DPLL_PHASE_4;
1910*4882a593Smuzhiyun 		channel->dpll_ctrl_n = DPLL_CTRL_4;
1911*4882a593Smuzhiyun 		channel->dpll_phase_pull_in = DPLL_PHASE_PULL_IN_4;
1912*4882a593Smuzhiyun 		break;
1913*4882a593Smuzhiyun 	case 5:
1914*4882a593Smuzhiyun 		channel->dpll_freq = DPLL_FREQ_5;
1915*4882a593Smuzhiyun 		channel->dpll_n = DPLL_5;
1916*4882a593Smuzhiyun 		channel->hw_dpll_n = HW_DPLL_5;
1917*4882a593Smuzhiyun 		channel->dpll_phase = DPLL_PHASE_5;
1918*4882a593Smuzhiyun 		channel->dpll_ctrl_n = DPLL_CTRL_5;
1919*4882a593Smuzhiyun 		channel->dpll_phase_pull_in = DPLL_PHASE_PULL_IN_5;
1920*4882a593Smuzhiyun 		break;
1921*4882a593Smuzhiyun 	case 6:
1922*4882a593Smuzhiyun 		channel->dpll_freq = DPLL_FREQ_6;
1923*4882a593Smuzhiyun 		channel->dpll_n = DPLL_6;
1924*4882a593Smuzhiyun 		channel->hw_dpll_n = HW_DPLL_6;
1925*4882a593Smuzhiyun 		channel->dpll_phase = DPLL_PHASE_6;
1926*4882a593Smuzhiyun 		channel->dpll_ctrl_n = DPLL_CTRL_6;
1927*4882a593Smuzhiyun 		channel->dpll_phase_pull_in = DPLL_PHASE_PULL_IN_6;
1928*4882a593Smuzhiyun 		break;
1929*4882a593Smuzhiyun 	case 7:
1930*4882a593Smuzhiyun 		channel->dpll_freq = DPLL_FREQ_7;
1931*4882a593Smuzhiyun 		channel->dpll_n = DPLL_7;
1932*4882a593Smuzhiyun 		channel->hw_dpll_n = HW_DPLL_7;
1933*4882a593Smuzhiyun 		channel->dpll_phase = DPLL_PHASE_7;
1934*4882a593Smuzhiyun 		channel->dpll_ctrl_n = DPLL_CTRL_7;
1935*4882a593Smuzhiyun 		channel->dpll_phase_pull_in = DPLL_PHASE_PULL_IN_7;
1936*4882a593Smuzhiyun 		break;
1937*4882a593Smuzhiyun 	default:
1938*4882a593Smuzhiyun 		err = -EINVAL;
1939*4882a593Smuzhiyun 	}
1940*4882a593Smuzhiyun 
1941*4882a593Smuzhiyun 	return err;
1942*4882a593Smuzhiyun }
1943*4882a593Smuzhiyun 
idtcm_enable_channel(struct idtcm * idtcm,u32 index)1944*4882a593Smuzhiyun static int idtcm_enable_channel(struct idtcm *idtcm, u32 index)
1945*4882a593Smuzhiyun {
1946*4882a593Smuzhiyun 	struct idtcm_channel *channel;
1947*4882a593Smuzhiyun 	int err;
1948*4882a593Smuzhiyun 
1949*4882a593Smuzhiyun 	if (!(index < MAX_TOD))
1950*4882a593Smuzhiyun 		return -EINVAL;
1951*4882a593Smuzhiyun 
1952*4882a593Smuzhiyun 	channel = &idtcm->channel[index];
1953*4882a593Smuzhiyun 
1954*4882a593Smuzhiyun 	/* Set pll addresses */
1955*4882a593Smuzhiyun 	err = configure_channel_pll(channel);
1956*4882a593Smuzhiyun 	if (err)
1957*4882a593Smuzhiyun 		return err;
1958*4882a593Smuzhiyun 
1959*4882a593Smuzhiyun 	/* Set tod addresses */
1960*4882a593Smuzhiyun 	switch (index) {
1961*4882a593Smuzhiyun 	case 0:
1962*4882a593Smuzhiyun 		channel->tod_read_primary = TOD_READ_PRIMARY_0;
1963*4882a593Smuzhiyun 		channel->tod_write = TOD_WRITE_0;
1964*4882a593Smuzhiyun 		channel->tod_n = TOD_0;
1965*4882a593Smuzhiyun 		break;
1966*4882a593Smuzhiyun 	case 1:
1967*4882a593Smuzhiyun 		channel->tod_read_primary = TOD_READ_PRIMARY_1;
1968*4882a593Smuzhiyun 		channel->tod_write = TOD_WRITE_1;
1969*4882a593Smuzhiyun 		channel->tod_n = TOD_1;
1970*4882a593Smuzhiyun 		break;
1971*4882a593Smuzhiyun 	case 2:
1972*4882a593Smuzhiyun 		channel->tod_read_primary = TOD_READ_PRIMARY_2;
1973*4882a593Smuzhiyun 		channel->tod_write = TOD_WRITE_2;
1974*4882a593Smuzhiyun 		channel->tod_n = TOD_2;
1975*4882a593Smuzhiyun 		break;
1976*4882a593Smuzhiyun 	case 3:
1977*4882a593Smuzhiyun 		channel->tod_read_primary = TOD_READ_PRIMARY_3;
1978*4882a593Smuzhiyun 		channel->tod_write = TOD_WRITE_3;
1979*4882a593Smuzhiyun 		channel->tod_n = TOD_3;
1980*4882a593Smuzhiyun 		break;
1981*4882a593Smuzhiyun 	default:
1982*4882a593Smuzhiyun 		return -EINVAL;
1983*4882a593Smuzhiyun 	}
1984*4882a593Smuzhiyun 
1985*4882a593Smuzhiyun 	channel->idtcm = idtcm;
1986*4882a593Smuzhiyun 
1987*4882a593Smuzhiyun 	if (idtcm_strverscmp(idtcm->version, "4.8.7") >= 0)
1988*4882a593Smuzhiyun 		channel->caps = idtcm_caps_v487;
1989*4882a593Smuzhiyun 	else
1990*4882a593Smuzhiyun 		channel->caps = idtcm_caps;
1991*4882a593Smuzhiyun 
1992*4882a593Smuzhiyun 	snprintf(channel->caps.name, sizeof(channel->caps.name),
1993*4882a593Smuzhiyun 		 "IDT CM TOD%u", index);
1994*4882a593Smuzhiyun 
1995*4882a593Smuzhiyun 	if (idtcm_strverscmp(idtcm->version, "4.8.7") >= 0) {
1996*4882a593Smuzhiyun 		err = idtcm_enable_tod_sync(channel);
1997*4882a593Smuzhiyun 		if (err) {
1998*4882a593Smuzhiyun 			dev_err(&idtcm->client->dev,
1999*4882a593Smuzhiyun 				"Failed at line %d in func %s!\n",
2000*4882a593Smuzhiyun 				__LINE__,
2001*4882a593Smuzhiyun 				__func__);
2002*4882a593Smuzhiyun 			return err;
2003*4882a593Smuzhiyun 		}
2004*4882a593Smuzhiyun 	}
2005*4882a593Smuzhiyun 
2006*4882a593Smuzhiyun 	err = idtcm_set_pll_mode(channel, PLL_MODE_WRITE_FREQUENCY);
2007*4882a593Smuzhiyun 	if (err) {
2008*4882a593Smuzhiyun 		dev_err(&idtcm->client->dev,
2009*4882a593Smuzhiyun 			"Failed at line %d in func %s!\n",
2010*4882a593Smuzhiyun 			__LINE__,
2011*4882a593Smuzhiyun 			__func__);
2012*4882a593Smuzhiyun 		return err;
2013*4882a593Smuzhiyun 	}
2014*4882a593Smuzhiyun 
2015*4882a593Smuzhiyun 	err = idtcm_enable_tod(channel);
2016*4882a593Smuzhiyun 	if (err) {
2017*4882a593Smuzhiyun 		dev_err(&idtcm->client->dev,
2018*4882a593Smuzhiyun 			"Failed at line %d in func %s!\n",
2019*4882a593Smuzhiyun 			__LINE__,
2020*4882a593Smuzhiyun 			__func__);
2021*4882a593Smuzhiyun 		return err;
2022*4882a593Smuzhiyun 	}
2023*4882a593Smuzhiyun 
2024*4882a593Smuzhiyun 	channel->ptp_clock = ptp_clock_register(&channel->caps, NULL);
2025*4882a593Smuzhiyun 
2026*4882a593Smuzhiyun 	if (IS_ERR(channel->ptp_clock)) {
2027*4882a593Smuzhiyun 		err = PTR_ERR(channel->ptp_clock);
2028*4882a593Smuzhiyun 		channel->ptp_clock = NULL;
2029*4882a593Smuzhiyun 		return err;
2030*4882a593Smuzhiyun 	}
2031*4882a593Smuzhiyun 
2032*4882a593Smuzhiyun 	if (!channel->ptp_clock)
2033*4882a593Smuzhiyun 		return -ENOTSUPP;
2034*4882a593Smuzhiyun 
2035*4882a593Smuzhiyun 	channel->write_phase_ready = 0;
2036*4882a593Smuzhiyun 
2037*4882a593Smuzhiyun 	dev_info(&idtcm->client->dev, "PLL%d registered as ptp%d\n",
2038*4882a593Smuzhiyun 		 index, channel->ptp_clock->index);
2039*4882a593Smuzhiyun 
2040*4882a593Smuzhiyun 	return 0;
2041*4882a593Smuzhiyun }
2042*4882a593Smuzhiyun 
ptp_clock_unregister_all(struct idtcm * idtcm)2043*4882a593Smuzhiyun static void ptp_clock_unregister_all(struct idtcm *idtcm)
2044*4882a593Smuzhiyun {
2045*4882a593Smuzhiyun 	u8 i;
2046*4882a593Smuzhiyun 	struct idtcm_channel *channel;
2047*4882a593Smuzhiyun 
2048*4882a593Smuzhiyun 	for (i = 0; i < MAX_TOD; i++) {
2049*4882a593Smuzhiyun 
2050*4882a593Smuzhiyun 		channel = &idtcm->channel[i];
2051*4882a593Smuzhiyun 
2052*4882a593Smuzhiyun 		if (channel->ptp_clock)
2053*4882a593Smuzhiyun 			ptp_clock_unregister(channel->ptp_clock);
2054*4882a593Smuzhiyun 	}
2055*4882a593Smuzhiyun }
2056*4882a593Smuzhiyun 
set_default_masks(struct idtcm * idtcm)2057*4882a593Smuzhiyun static void set_default_masks(struct idtcm *idtcm)
2058*4882a593Smuzhiyun {
2059*4882a593Smuzhiyun 	idtcm->tod_mask = DEFAULT_TOD_MASK;
2060*4882a593Smuzhiyun 
2061*4882a593Smuzhiyun 	idtcm->channel[0].pll = DEFAULT_TOD0_PTP_PLL;
2062*4882a593Smuzhiyun 	idtcm->channel[1].pll = DEFAULT_TOD1_PTP_PLL;
2063*4882a593Smuzhiyun 	idtcm->channel[2].pll = DEFAULT_TOD2_PTP_PLL;
2064*4882a593Smuzhiyun 	idtcm->channel[3].pll = DEFAULT_TOD3_PTP_PLL;
2065*4882a593Smuzhiyun 
2066*4882a593Smuzhiyun 	idtcm->channel[0].output_mask = DEFAULT_OUTPUT_MASK_PLL0;
2067*4882a593Smuzhiyun 	idtcm->channel[1].output_mask = DEFAULT_OUTPUT_MASK_PLL1;
2068*4882a593Smuzhiyun 	idtcm->channel[2].output_mask = DEFAULT_OUTPUT_MASK_PLL2;
2069*4882a593Smuzhiyun 	idtcm->channel[3].output_mask = DEFAULT_OUTPUT_MASK_PLL3;
2070*4882a593Smuzhiyun }
2071*4882a593Smuzhiyun 
idtcm_probe(struct i2c_client * client,const struct i2c_device_id * id)2072*4882a593Smuzhiyun static int idtcm_probe(struct i2c_client *client,
2073*4882a593Smuzhiyun 		       const struct i2c_device_id *id)
2074*4882a593Smuzhiyun {
2075*4882a593Smuzhiyun 	struct idtcm *idtcm;
2076*4882a593Smuzhiyun 	int err;
2077*4882a593Smuzhiyun 	u8 i;
2078*4882a593Smuzhiyun 	char *fmt = "Failed at %d in line %s with channel output %d!\n";
2079*4882a593Smuzhiyun 
2080*4882a593Smuzhiyun 	/* Unused for now */
2081*4882a593Smuzhiyun 	(void)id;
2082*4882a593Smuzhiyun 
2083*4882a593Smuzhiyun 	idtcm = devm_kzalloc(&client->dev, sizeof(struct idtcm), GFP_KERNEL);
2084*4882a593Smuzhiyun 
2085*4882a593Smuzhiyun 	if (!idtcm)
2086*4882a593Smuzhiyun 		return -ENOMEM;
2087*4882a593Smuzhiyun 
2088*4882a593Smuzhiyun 	idtcm->client = client;
2089*4882a593Smuzhiyun 	idtcm->page_offset = 0xff;
2090*4882a593Smuzhiyun 	idtcm->calculate_overhead_flag = 0;
2091*4882a593Smuzhiyun 
2092*4882a593Smuzhiyun 	set_default_masks(idtcm);
2093*4882a593Smuzhiyun 
2094*4882a593Smuzhiyun 	mutex_init(&idtcm->reg_lock);
2095*4882a593Smuzhiyun 	mutex_lock(&idtcm->reg_lock);
2096*4882a593Smuzhiyun 
2097*4882a593Smuzhiyun 	idtcm_display_version_info(idtcm);
2098*4882a593Smuzhiyun 
2099*4882a593Smuzhiyun 	err = idtcm_load_firmware(idtcm, &client->dev);
2100*4882a593Smuzhiyun 
2101*4882a593Smuzhiyun 	if (err)
2102*4882a593Smuzhiyun 		dev_warn(&idtcm->client->dev,
2103*4882a593Smuzhiyun 			 "loading firmware failed with %d\n", err);
2104*4882a593Smuzhiyun 
2105*4882a593Smuzhiyun 	if (idtcm->tod_mask) {
2106*4882a593Smuzhiyun 		for (i = 0; i < MAX_TOD; i++) {
2107*4882a593Smuzhiyun 			if (idtcm->tod_mask & (1 << i)) {
2108*4882a593Smuzhiyun 				err = idtcm_enable_channel(idtcm, i);
2109*4882a593Smuzhiyun 				if (err) {
2110*4882a593Smuzhiyun 					dev_err(&idtcm->client->dev,
2111*4882a593Smuzhiyun 						fmt,
2112*4882a593Smuzhiyun 						__LINE__,
2113*4882a593Smuzhiyun 						__func__,
2114*4882a593Smuzhiyun 						i);
2115*4882a593Smuzhiyun 					break;
2116*4882a593Smuzhiyun 				}
2117*4882a593Smuzhiyun 			}
2118*4882a593Smuzhiyun 		}
2119*4882a593Smuzhiyun 	} else {
2120*4882a593Smuzhiyun 		dev_err(&idtcm->client->dev,
2121*4882a593Smuzhiyun 			"no PLLs flagged as PHCs, nothing to do\n");
2122*4882a593Smuzhiyun 		err = -ENODEV;
2123*4882a593Smuzhiyun 	}
2124*4882a593Smuzhiyun 
2125*4882a593Smuzhiyun 	mutex_unlock(&idtcm->reg_lock);
2126*4882a593Smuzhiyun 
2127*4882a593Smuzhiyun 	if (err) {
2128*4882a593Smuzhiyun 		ptp_clock_unregister_all(idtcm);
2129*4882a593Smuzhiyun 		return err;
2130*4882a593Smuzhiyun 	}
2131*4882a593Smuzhiyun 
2132*4882a593Smuzhiyun 	i2c_set_clientdata(client, idtcm);
2133*4882a593Smuzhiyun 
2134*4882a593Smuzhiyun 	return 0;
2135*4882a593Smuzhiyun }
2136*4882a593Smuzhiyun 
idtcm_remove(struct i2c_client * client)2137*4882a593Smuzhiyun static int idtcm_remove(struct i2c_client *client)
2138*4882a593Smuzhiyun {
2139*4882a593Smuzhiyun 	struct idtcm *idtcm = i2c_get_clientdata(client);
2140*4882a593Smuzhiyun 
2141*4882a593Smuzhiyun 	ptp_clock_unregister_all(idtcm);
2142*4882a593Smuzhiyun 
2143*4882a593Smuzhiyun 	mutex_destroy(&idtcm->reg_lock);
2144*4882a593Smuzhiyun 
2145*4882a593Smuzhiyun 	return 0;
2146*4882a593Smuzhiyun }
2147*4882a593Smuzhiyun 
2148*4882a593Smuzhiyun #ifdef CONFIG_OF
2149*4882a593Smuzhiyun static const struct of_device_id idtcm_dt_id[] = {
2150*4882a593Smuzhiyun 	{ .compatible = "idt,8a34000" },
2151*4882a593Smuzhiyun 	{ .compatible = "idt,8a34001" },
2152*4882a593Smuzhiyun 	{ .compatible = "idt,8a34002" },
2153*4882a593Smuzhiyun 	{ .compatible = "idt,8a34003" },
2154*4882a593Smuzhiyun 	{ .compatible = "idt,8a34004" },
2155*4882a593Smuzhiyun 	{ .compatible = "idt,8a34005" },
2156*4882a593Smuzhiyun 	{ .compatible = "idt,8a34006" },
2157*4882a593Smuzhiyun 	{ .compatible = "idt,8a34007" },
2158*4882a593Smuzhiyun 	{ .compatible = "idt,8a34008" },
2159*4882a593Smuzhiyun 	{ .compatible = "idt,8a34009" },
2160*4882a593Smuzhiyun 	{ .compatible = "idt,8a34010" },
2161*4882a593Smuzhiyun 	{ .compatible = "idt,8a34011" },
2162*4882a593Smuzhiyun 	{ .compatible = "idt,8a34012" },
2163*4882a593Smuzhiyun 	{ .compatible = "idt,8a34013" },
2164*4882a593Smuzhiyun 	{ .compatible = "idt,8a34014" },
2165*4882a593Smuzhiyun 	{ .compatible = "idt,8a34015" },
2166*4882a593Smuzhiyun 	{ .compatible = "idt,8a34016" },
2167*4882a593Smuzhiyun 	{ .compatible = "idt,8a34017" },
2168*4882a593Smuzhiyun 	{ .compatible = "idt,8a34018" },
2169*4882a593Smuzhiyun 	{ .compatible = "idt,8a34019" },
2170*4882a593Smuzhiyun 	{ .compatible = "idt,8a34040" },
2171*4882a593Smuzhiyun 	{ .compatible = "idt,8a34041" },
2172*4882a593Smuzhiyun 	{ .compatible = "idt,8a34042" },
2173*4882a593Smuzhiyun 	{ .compatible = "idt,8a34043" },
2174*4882a593Smuzhiyun 	{ .compatible = "idt,8a34044" },
2175*4882a593Smuzhiyun 	{ .compatible = "idt,8a34045" },
2176*4882a593Smuzhiyun 	{ .compatible = "idt,8a34046" },
2177*4882a593Smuzhiyun 	{ .compatible = "idt,8a34047" },
2178*4882a593Smuzhiyun 	{ .compatible = "idt,8a34048" },
2179*4882a593Smuzhiyun 	{ .compatible = "idt,8a34049" },
2180*4882a593Smuzhiyun 	{},
2181*4882a593Smuzhiyun };
2182*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, idtcm_dt_id);
2183*4882a593Smuzhiyun #endif
2184*4882a593Smuzhiyun 
2185*4882a593Smuzhiyun static const struct i2c_device_id idtcm_i2c_id[] = {
2186*4882a593Smuzhiyun 	{ "8a34000" },
2187*4882a593Smuzhiyun 	{ "8a34001" },
2188*4882a593Smuzhiyun 	{ "8a34002" },
2189*4882a593Smuzhiyun 	{ "8a34003" },
2190*4882a593Smuzhiyun 	{ "8a34004" },
2191*4882a593Smuzhiyun 	{ "8a34005" },
2192*4882a593Smuzhiyun 	{ "8a34006" },
2193*4882a593Smuzhiyun 	{ "8a34007" },
2194*4882a593Smuzhiyun 	{ "8a34008" },
2195*4882a593Smuzhiyun 	{ "8a34009" },
2196*4882a593Smuzhiyun 	{ "8a34010" },
2197*4882a593Smuzhiyun 	{ "8a34011" },
2198*4882a593Smuzhiyun 	{ "8a34012" },
2199*4882a593Smuzhiyun 	{ "8a34013" },
2200*4882a593Smuzhiyun 	{ "8a34014" },
2201*4882a593Smuzhiyun 	{ "8a34015" },
2202*4882a593Smuzhiyun 	{ "8a34016" },
2203*4882a593Smuzhiyun 	{ "8a34017" },
2204*4882a593Smuzhiyun 	{ "8a34018" },
2205*4882a593Smuzhiyun 	{ "8a34019" },
2206*4882a593Smuzhiyun 	{ "8a34040" },
2207*4882a593Smuzhiyun 	{ "8a34041" },
2208*4882a593Smuzhiyun 	{ "8a34042" },
2209*4882a593Smuzhiyun 	{ "8a34043" },
2210*4882a593Smuzhiyun 	{ "8a34044" },
2211*4882a593Smuzhiyun 	{ "8a34045" },
2212*4882a593Smuzhiyun 	{ "8a34046" },
2213*4882a593Smuzhiyun 	{ "8a34047" },
2214*4882a593Smuzhiyun 	{ "8a34048" },
2215*4882a593Smuzhiyun 	{ "8a34049" },
2216*4882a593Smuzhiyun 	{},
2217*4882a593Smuzhiyun };
2218*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, idtcm_i2c_id);
2219*4882a593Smuzhiyun 
2220*4882a593Smuzhiyun static struct i2c_driver idtcm_driver = {
2221*4882a593Smuzhiyun 	.driver = {
2222*4882a593Smuzhiyun 		.of_match_table	= of_match_ptr(idtcm_dt_id),
2223*4882a593Smuzhiyun 		.name		= "idtcm",
2224*4882a593Smuzhiyun 	},
2225*4882a593Smuzhiyun 	.probe		= idtcm_probe,
2226*4882a593Smuzhiyun 	.remove		= idtcm_remove,
2227*4882a593Smuzhiyun 	.id_table	= idtcm_i2c_id,
2228*4882a593Smuzhiyun };
2229*4882a593Smuzhiyun 
2230*4882a593Smuzhiyun module_i2c_driver(idtcm_driver);
2231