blob: eec0a74d5fa6edc5834080de0c688a539e4de0db [file] [log] [blame]
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * PTP hardware clock driver for the IDT ClockMatrix(TM) family of timing and
4 * synchronization devices.
5 *
6 * Copyright (C) 2019 Integrated Device Technology, Inc., a Renesas Company.
7 */
8#include <linux/firmware.h>
9#include <linux/i2c.h>
10#include <linux/module.h>
11#include <linux/ptp_clock_kernel.h>
12#include <linux/delay.h>
Vincent Cheng425d2b12020-05-01 23:35:38 -040013#include <linux/jiffies.h>
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -040014#include <linux/kernel.h>
15#include <linux/timekeeping.h>
Min Li7ea5fda2020-07-28 16:00:30 -040016#include <linux/string.h>
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -040017
18#include "ptp_private.h"
19#include "ptp_clockmatrix.h"
20
21MODULE_DESCRIPTION("Driver for IDT ClockMatrix(TM) family");
22MODULE_AUTHOR("Richard Cochran <richardcochran@gmail.com>");
23MODULE_AUTHOR("IDT support-1588 <IDT-support-1588@lm.renesas.com>");
24MODULE_VERSION("1.0");
25MODULE_LICENSE("GPL");
26
Min Li7ea5fda2020-07-28 16:00:30 -040027/*
28 * The name of the firmware file to be loaded
29 * over-rides any automatic selection
30 */
31static char *firmware;
32module_param(firmware, charp, 0);
33
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -040034#define SETTIME_CORRECTION (0)
35
Min Li251f4fe2020-12-08 10:41:54 -050036static int contains_full_configuration(const struct firmware *fw)
37{
38 s32 full_count = FULL_FW_CFG_BYTES - FULL_FW_CFG_SKIPPED_BYTES;
39 struct idtcm_fwrc *rec = (struct idtcm_fwrc *)fw->data;
40 s32 count = 0;
41 u16 regaddr;
42 u8 loaddr;
43 s32 len;
44
45 /* If the firmware contains 'full configuration' SM_RESET can be used
46 * to ensure proper configuration.
47 *
48 * Full configuration is defined as the number of programmable
49 * bytes within the configuration range minus page offset addr range.
50 */
51 for (len = fw->size; len > 0; len -= sizeof(*rec)) {
52 regaddr = rec->hiaddr << 8;
53 regaddr |= rec->loaddr;
54
55 loaddr = rec->loaddr;
56
57 rec++;
58
59 /* Top (status registers) and bottom are read-only */
60 if (regaddr < GPIO_USER_CONTROL || regaddr >= SCRATCH)
61 continue;
62
63 /* Page size 128, last 4 bytes of page skipped */
64 if ((loaddr > 0x7b && loaddr <= 0x7f) || loaddr > 0xfb)
65 continue;
66
67 count++;
68 }
69
70 return (count >= full_count);
71}
72
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -040073static int char_array_to_timespec(u8 *buf,
74 u8 count,
75 struct timespec64 *ts)
76{
77 u8 i;
78 u64 nsec;
79 time64_t sec;
80
81 if (count < TOD_BYTE_COUNT)
82 return 1;
83
84 /* Sub-nanoseconds are in buf[0]. */
85 nsec = buf[4];
86 for (i = 0; i < 3; i++) {
87 nsec <<= 8;
88 nsec |= buf[3 - i];
89 }
90
91 sec = buf[10];
92 for (i = 0; i < 5; i++) {
93 sec <<= 8;
94 sec |= buf[9 - i];
95 }
96
97 ts->tv_sec = sec;
98 ts->tv_nsec = nsec;
99
100 return 0;
101}
102
103static int timespec_to_char_array(struct timespec64 const *ts,
104 u8 *buf,
105 u8 count)
106{
107 u8 i;
108 s32 nsec;
109 time64_t sec;
110
111 if (count < TOD_BYTE_COUNT)
112 return 1;
113
114 nsec = ts->tv_nsec;
115 sec = ts->tv_sec;
116
117 /* Sub-nanoseconds are in buf[0]. */
118 buf[0] = 0;
119 for (i = 1; i < 5; i++) {
120 buf[i] = nsec & 0xff;
121 nsec >>= 8;
122 }
123
124 for (i = 5; i < TOD_BYTE_COUNT; i++) {
125
126 buf[i] = sec & 0xff;
127 sec >>= 8;
128 }
129
130 return 0;
131}
132
Min Li3cb2e6d2020-11-24 21:58:35 -0500133static int idtcm_strverscmp(const char *version1, const char *version2)
Min Li7ea5fda2020-07-28 16:00:30 -0400134{
Min Li3cb2e6d2020-11-24 21:58:35 -0500135 u8 ver1[3], ver2[3];
136 int i;
Min Li7ea5fda2020-07-28 16:00:30 -0400137
Min Li3cb2e6d2020-11-24 21:58:35 -0500138 if (sscanf(version1, "%hhu.%hhu.%hhu",
139 &ver1[0], &ver1[1], &ver1[2]) != 3)
140 return -1;
141 if (sscanf(version2, "%hhu.%hhu.%hhu",
142 &ver2[0], &ver2[1], &ver2[2]) != 3)
143 return -1;
144
145 for (i = 0; i < 3; i++) {
146 if (ver1[i] > ver2[i])
147 return 1;
148 if (ver1[i] < ver2[i])
Min Li7ea5fda2020-07-28 16:00:30 -0400149 return -1;
Min Li7ea5fda2020-07-28 16:00:30 -0400150 }
Min Li3cb2e6d2020-11-24 21:58:35 -0500151
152 return 0;
Min Li7ea5fda2020-07-28 16:00:30 -0400153}
154
Min Li957ff422020-08-18 10:41:22 -0400155static int idtcm_xfer_read(struct idtcm *idtcm,
156 u8 regaddr,
157 u8 *buf,
158 u16 count)
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400159{
160 struct i2c_client *client = idtcm->client;
161 struct i2c_msg msg[2];
162 int cnt;
163
164 msg[0].addr = client->addr;
165 msg[0].flags = 0;
166 msg[0].len = 1;
167 msg[0].buf = &regaddr;
168
169 msg[1].addr = client->addr;
Min Li957ff422020-08-18 10:41:22 -0400170 msg[1].flags = I2C_M_RD;
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400171 msg[1].len = count;
172 msg[1].buf = buf;
173
174 cnt = i2c_transfer(client->adapter, msg, 2);
175
176 if (cnt < 0) {
Min Li7ea5fda2020-07-28 16:00:30 -0400177 dev_err(&client->dev,
Vincent Cheng1c49d3e2021-02-17 00:42:15 -0500178 "i2c_transfer failed at %d in %s, at addr: %04x!",
179 __LINE__, __func__, regaddr);
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400180 return cnt;
181 } else if (cnt != 2) {
182 dev_err(&client->dev,
Vincent Cheng1c49d3e2021-02-17 00:42:15 -0500183 "i2c_transfer sent only %d of %d messages", cnt, 2);
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400184 return -EIO;
185 }
186
187 return 0;
188}
189
Min Li957ff422020-08-18 10:41:22 -0400190static int idtcm_xfer_write(struct idtcm *idtcm,
191 u8 regaddr,
192 u8 *buf,
193 u16 count)
194{
195 struct i2c_client *client = idtcm->client;
196 /* we add 1 byte for device register */
197 u8 msg[IDTCM_MAX_WRITE_COUNT + 1];
198 int cnt;
Min Li957ff422020-08-18 10:41:22 -0400199
200 if (count > IDTCM_MAX_WRITE_COUNT)
201 return -EINVAL;
202
203 msg[0] = regaddr;
204 memcpy(&msg[1], buf, count);
205
206 cnt = i2c_master_send(client, msg, count + 1);
207
208 if (cnt < 0) {
209 dev_err(&client->dev,
Vincent Cheng1c49d3e2021-02-17 00:42:15 -0500210 "i2c_master_send failed at %d in %s, at addr: %04x!",
211 __LINE__, __func__, regaddr);
Min Li957ff422020-08-18 10:41:22 -0400212 return cnt;
213 }
214
215 return 0;
216}
217
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400218static int idtcm_page_offset(struct idtcm *idtcm, u8 val)
219{
220 u8 buf[4];
221 int err;
222
223 if (idtcm->page_offset == val)
224 return 0;
225
226 buf[0] = 0x0;
227 buf[1] = val;
228 buf[2] = 0x10;
229 buf[3] = 0x20;
230
Min Li957ff422020-08-18 10:41:22 -0400231 err = idtcm_xfer_write(idtcm, PAGE_ADDR, buf, sizeof(buf));
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400232
Min Li7ea5fda2020-07-28 16:00:30 -0400233 if (err) {
234 idtcm->page_offset = 0xff;
Vincent Cheng1c49d3e2021-02-17 00:42:15 -0500235 dev_err(&idtcm->client->dev, "failed to set page offset");
Min Li7ea5fda2020-07-28 16:00:30 -0400236 } else {
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400237 idtcm->page_offset = val;
Min Li7ea5fda2020-07-28 16:00:30 -0400238 }
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400239
240 return err;
241}
242
243static int _idtcm_rdwr(struct idtcm *idtcm,
244 u16 regaddr,
245 u8 *buf,
246 u16 count,
247 bool write)
248{
249 u8 hi;
250 u8 lo;
251 int err;
252
253 hi = (regaddr >> 8) & 0xff;
254 lo = regaddr & 0xff;
255
256 err = idtcm_page_offset(idtcm, hi);
257
258 if (err)
Min Li957ff422020-08-18 10:41:22 -0400259 return err;
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400260
Min Li957ff422020-08-18 10:41:22 -0400261 if (write)
262 return idtcm_xfer_write(idtcm, lo, buf, count);
263
264 return idtcm_xfer_read(idtcm, lo, buf, count);
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400265}
266
267static int idtcm_read(struct idtcm *idtcm,
268 u16 module,
269 u16 regaddr,
270 u8 *buf,
271 u16 count)
272{
273 return _idtcm_rdwr(idtcm, module + regaddr, buf, count, false);
274}
275
276static int idtcm_write(struct idtcm *idtcm,
277 u16 module,
278 u16 regaddr,
279 u8 *buf,
280 u16 count)
281{
282 return _idtcm_rdwr(idtcm, module + regaddr, buf, count, true);
283}
284
Min Li251f4fe2020-12-08 10:41:54 -0500285static int clear_boot_status(struct idtcm *idtcm)
286{
287 int err;
288 u8 buf[4] = {0};
289
290 err = idtcm_write(idtcm, GENERAL_STATUS, BOOT_STATUS, buf, sizeof(buf));
291
292 return err;
293}
294
295static int read_boot_status(struct idtcm *idtcm, u32 *status)
296{
297 int err;
298 u8 buf[4] = {0};
299
300 err = idtcm_read(idtcm, GENERAL_STATUS, BOOT_STATUS, buf, sizeof(buf));
301
302 *status = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
303
304 return err;
305}
306
307static int wait_for_boot_status_ready(struct idtcm *idtcm)
308{
309 u32 status = 0;
310 u8 i = 30; /* 30 * 100ms = 3s */
311 int err;
312
313 do {
314 err = read_boot_status(idtcm, &status);
315
316 if (err)
317 return err;
318
319 if (status == 0xA0)
320 return 0;
321
322 msleep(100);
323 i--;
324
325 } while (i);
326
Vincent Cheng1c49d3e2021-02-17 00:42:15 -0500327 dev_warn(&idtcm->client->dev, "%s timed out", __func__);
Min Li251f4fe2020-12-08 10:41:54 -0500328
329 return -EBUSY;
330}
331
Vincent Cheng797d3182021-02-17 00:42:12 -0500332static int read_sys_apll_status(struct idtcm *idtcm, u8 *status)
333{
334 return idtcm_read(idtcm, STATUS, DPLL_SYS_APLL_STATUS, status,
335 sizeof(u8));
336}
337
338static int read_sys_dpll_status(struct idtcm *idtcm, u8 *status)
339{
340 return idtcm_read(idtcm, STATUS, DPLL_SYS_STATUS, status, sizeof(u8));
341}
342
343static int wait_for_sys_apll_dpll_lock(struct idtcm *idtcm)
344{
345 unsigned long timeout = jiffies + msecs_to_jiffies(LOCK_TIMEOUT_MS);
346 u8 apll = 0;
347 u8 dpll = 0;
348 int err;
349
350 do {
351 err = read_sys_apll_status(idtcm, &apll);
352 if (err)
353 return err;
354
355 err = read_sys_dpll_status(idtcm, &dpll);
356 if (err)
357 return err;
358
359 apll &= SYS_APLL_LOSS_LOCK_LIVE_MASK;
360 dpll &= DPLL_SYS_STATE_MASK;
361
362 if (apll == SYS_APLL_LOSS_LOCK_LIVE_LOCKED &&
363 dpll == DPLL_STATE_LOCKED) {
364 return 0;
365 } else if (dpll == DPLL_STATE_FREERUN ||
366 dpll == DPLL_STATE_HOLDOVER ||
367 dpll == DPLL_STATE_OPEN_LOOP) {
368 dev_warn(&idtcm->client->dev,
369 "No wait state: DPLL_SYS_STATE %d", dpll);
370 return -EPERM;
371 }
372
373 msleep(LOCK_POLL_INTERVAL_MS);
374 } while (time_is_after_jiffies(timeout));
375
376 dev_warn(&idtcm->client->dev,
377 "%d ms lock timeout: SYS APLL Loss Lock %d SYS DPLL state %d",
378 LOCK_TIMEOUT_MS, apll, dpll);
379
380 return -ETIME;
381}
382
383static void wait_for_chip_ready(struct idtcm *idtcm)
384{
385 if (wait_for_boot_status_ready(idtcm))
386 dev_warn(&idtcm->client->dev, "BOOT_STATUS != 0xA0");
387
388 if (wait_for_sys_apll_dpll_lock(idtcm))
389 dev_warn(&idtcm->client->dev,
390 "Continuing while SYS APLL/DPLL is not locked");
391}
392
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400393static int _idtcm_gettime(struct idtcm_channel *channel,
394 struct timespec64 *ts)
395{
396 struct idtcm *idtcm = channel->idtcm;
397 u8 buf[TOD_BYTE_COUNT];
Min Li7ea5fda2020-07-28 16:00:30 -0400398 u8 timeout = 10;
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400399 u8 trigger;
400 int err;
401
402 err = idtcm_read(idtcm, channel->tod_read_primary,
403 TOD_READ_PRIMARY_CMD, &trigger, sizeof(trigger));
404 if (err)
405 return err;
406
407 trigger &= ~(TOD_READ_TRIGGER_MASK << TOD_READ_TRIGGER_SHIFT);
408 trigger |= (1 << TOD_READ_TRIGGER_SHIFT);
Min Li7ea5fda2020-07-28 16:00:30 -0400409 trigger &= ~TOD_READ_TRIGGER_MODE; /* single shot */
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400410
411 err = idtcm_write(idtcm, channel->tod_read_primary,
412 TOD_READ_PRIMARY_CMD, &trigger, sizeof(trigger));
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400413 if (err)
414 return err;
415
Min Li7ea5fda2020-07-28 16:00:30 -0400416 /* wait trigger to be 0 */
417 while (trigger & TOD_READ_TRIGGER_MASK) {
418
419 if (idtcm->calculate_overhead_flag)
420 idtcm->start_time = ktime_get_raw();
421
422 err = idtcm_read(idtcm, channel->tod_read_primary,
423 TOD_READ_PRIMARY_CMD, &trigger,
424 sizeof(trigger));
425
426 if (err)
427 return err;
428
429 if (--timeout == 0)
430 return -EIO;
431 }
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400432
433 err = idtcm_read(idtcm, channel->tod_read_primary,
434 TOD_READ_PRIMARY, buf, sizeof(buf));
435
436 if (err)
437 return err;
438
439 err = char_array_to_timespec(buf, sizeof(buf), ts);
440
441 return err;
442}
443
444static int _sync_pll_output(struct idtcm *idtcm,
445 u8 pll,
446 u8 sync_src,
447 u8 qn,
448 u8 qn_plus_1)
449{
450 int err;
451 u8 val;
452 u16 sync_ctrl0;
453 u16 sync_ctrl1;
Min Li7ea5fda2020-07-28 16:00:30 -0400454 u8 temp;
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400455
456 if ((qn == 0) && (qn_plus_1 == 0))
457 return 0;
458
459 switch (pll) {
460 case 0:
461 sync_ctrl0 = HW_Q0_Q1_CH_SYNC_CTRL_0;
462 sync_ctrl1 = HW_Q0_Q1_CH_SYNC_CTRL_1;
463 break;
464 case 1:
465 sync_ctrl0 = HW_Q2_Q3_CH_SYNC_CTRL_0;
466 sync_ctrl1 = HW_Q2_Q3_CH_SYNC_CTRL_1;
467 break;
468 case 2:
469 sync_ctrl0 = HW_Q4_Q5_CH_SYNC_CTRL_0;
470 sync_ctrl1 = HW_Q4_Q5_CH_SYNC_CTRL_1;
471 break;
472 case 3:
473 sync_ctrl0 = HW_Q6_Q7_CH_SYNC_CTRL_0;
474 sync_ctrl1 = HW_Q6_Q7_CH_SYNC_CTRL_1;
475 break;
476 case 4:
477 sync_ctrl0 = HW_Q8_CH_SYNC_CTRL_0;
478 sync_ctrl1 = HW_Q8_CH_SYNC_CTRL_1;
479 break;
480 case 5:
481 sync_ctrl0 = HW_Q9_CH_SYNC_CTRL_0;
482 sync_ctrl1 = HW_Q9_CH_SYNC_CTRL_1;
483 break;
484 case 6:
485 sync_ctrl0 = HW_Q10_CH_SYNC_CTRL_0;
486 sync_ctrl1 = HW_Q10_CH_SYNC_CTRL_1;
487 break;
488 case 7:
489 sync_ctrl0 = HW_Q11_CH_SYNC_CTRL_0;
490 sync_ctrl1 = HW_Q11_CH_SYNC_CTRL_1;
491 break;
492 default:
493 return -EINVAL;
494 }
495
496 val = SYNCTRL1_MASTER_SYNC_RST;
497
498 /* Place master sync in reset */
499 err = idtcm_write(idtcm, 0, sync_ctrl1, &val, sizeof(val));
500 if (err)
501 return err;
502
503 err = idtcm_write(idtcm, 0, sync_ctrl0, &sync_src, sizeof(sync_src));
504 if (err)
505 return err;
506
507 /* Set sync trigger mask */
508 val |= SYNCTRL1_FBDIV_FRAME_SYNC_TRIG | SYNCTRL1_FBDIV_SYNC_TRIG;
509
510 if (qn)
511 val |= SYNCTRL1_Q0_DIV_SYNC_TRIG;
512
513 if (qn_plus_1)
514 val |= SYNCTRL1_Q1_DIV_SYNC_TRIG;
515
516 err = idtcm_write(idtcm, 0, sync_ctrl1, &val, sizeof(val));
517 if (err)
518 return err;
519
Min Li7ea5fda2020-07-28 16:00:30 -0400520 /* PLL5 can have OUT8 as second additional output. */
521 if ((pll == 5) && (qn_plus_1 != 0)) {
522 err = idtcm_read(idtcm, 0, HW_Q8_CTRL_SPARE,
523 &temp, sizeof(temp));
524 if (err)
525 return err;
526
527 temp &= ~(Q9_TO_Q8_SYNC_TRIG);
528
529 err = idtcm_write(idtcm, 0, HW_Q8_CTRL_SPARE,
530 &temp, sizeof(temp));
531 if (err)
532 return err;
533
534 temp |= Q9_TO_Q8_SYNC_TRIG;
535
536 err = idtcm_write(idtcm, 0, HW_Q8_CTRL_SPARE,
537 &temp, sizeof(temp));
538 if (err)
539 return err;
540 }
541
542 /* PLL6 can have OUT11 as second additional output. */
543 if ((pll == 6) && (qn_plus_1 != 0)) {
544 err = idtcm_read(idtcm, 0, HW_Q11_CTRL_SPARE,
545 &temp, sizeof(temp));
546 if (err)
547 return err;
548
549 temp &= ~(Q10_TO_Q11_SYNC_TRIG);
550
551 err = idtcm_write(idtcm, 0, HW_Q11_CTRL_SPARE,
552 &temp, sizeof(temp));
553 if (err)
554 return err;
555
556 temp |= Q10_TO_Q11_SYNC_TRIG;
557
558 err = idtcm_write(idtcm, 0, HW_Q11_CTRL_SPARE,
559 &temp, sizeof(temp));
560 if (err)
561 return err;
562 }
563
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400564 /* Place master sync out of reset */
565 val &= ~(SYNCTRL1_MASTER_SYNC_RST);
566 err = idtcm_write(idtcm, 0, sync_ctrl1, &val, sizeof(val));
567
568 return err;
569}
570
Min Li7ea5fda2020-07-28 16:00:30 -0400571static int sync_source_dpll_tod_pps(u16 tod_addr, u8 *sync_src)
572{
573 int err = 0;
574
575 switch (tod_addr) {
576 case TOD_0:
577 *sync_src = SYNC_SOURCE_DPLL0_TOD_PPS;
578 break;
579 case TOD_1:
580 *sync_src = SYNC_SOURCE_DPLL1_TOD_PPS;
581 break;
582 case TOD_2:
583 *sync_src = SYNC_SOURCE_DPLL2_TOD_PPS;
584 break;
585 case TOD_3:
586 *sync_src = SYNC_SOURCE_DPLL3_TOD_PPS;
587 break;
588 default:
589 err = -EINVAL;
590 }
591
592 return err;
593}
594
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400595static int idtcm_sync_pps_output(struct idtcm_channel *channel)
596{
597 struct idtcm *idtcm = channel->idtcm;
598
599 u8 pll;
600 u8 sync_src;
601 u8 qn;
602 u8 qn_plus_1;
603 int err = 0;
Min Li7ea5fda2020-07-28 16:00:30 -0400604 u8 out8_mux = 0;
605 u8 out11_mux = 0;
606 u8 temp;
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400607
608 u16 output_mask = channel->output_mask;
609
Min Li7ea5fda2020-07-28 16:00:30 -0400610 err = sync_source_dpll_tod_pps(channel->tod_n, &sync_src);
611 if (err)
612 return err;
613
614 err = idtcm_read(idtcm, 0, HW_Q8_CTRL_SPARE,
615 &temp, sizeof(temp));
616 if (err)
617 return err;
618
619 if ((temp & Q9_TO_Q8_FANOUT_AND_CLOCK_SYNC_ENABLE_MASK) ==
620 Q9_TO_Q8_FANOUT_AND_CLOCK_SYNC_ENABLE_MASK)
621 out8_mux = 1;
622
623 err = idtcm_read(idtcm, 0, HW_Q11_CTRL_SPARE,
624 &temp, sizeof(temp));
625 if (err)
626 return err;
627
628 if ((temp & Q10_TO_Q11_FANOUT_AND_CLOCK_SYNC_ENABLE_MASK) ==
629 Q10_TO_Q11_FANOUT_AND_CLOCK_SYNC_ENABLE_MASK)
630 out11_mux = 1;
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400631
632 for (pll = 0; pll < 8; pll++) {
Min Li7ea5fda2020-07-28 16:00:30 -0400633 qn = 0;
634 qn_plus_1 = 0;
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400635
636 if (pll < 4) {
637 /* First 4 pll has 2 outputs */
Min Li7ea5fda2020-07-28 16:00:30 -0400638 qn = output_mask & 0x1;
639 output_mask = output_mask >> 1;
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400640 qn_plus_1 = output_mask & 0x1;
641 output_mask = output_mask >> 1;
Min Li7ea5fda2020-07-28 16:00:30 -0400642 } else if (pll == 4) {
643 if (out8_mux == 0) {
644 qn = output_mask & 0x1;
645 output_mask = output_mask >> 1;
646 }
647 } else if (pll == 5) {
648 if (out8_mux) {
649 qn_plus_1 = output_mask & 0x1;
650 output_mask = output_mask >> 1;
651 }
652 qn = output_mask & 0x1;
653 output_mask = output_mask >> 1;
654 } else if (pll == 6) {
655 qn = output_mask & 0x1;
656 output_mask = output_mask >> 1;
657 if (out11_mux) {
658 qn_plus_1 = output_mask & 0x1;
659 output_mask = output_mask >> 1;
660 }
661 } else if (pll == 7) {
662 if (out11_mux == 0) {
663 qn = output_mask & 0x1;
664 output_mask = output_mask >> 1;
665 }
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400666 }
667
668 if ((qn != 0) || (qn_plus_1 != 0))
669 err = _sync_pll_output(idtcm, pll, sync_src, qn,
670 qn_plus_1);
671
672 if (err)
673 return err;
674 }
675
676 return err;
677}
678
Min Li7ea5fda2020-07-28 16:00:30 -0400679static int _idtcm_set_dpll_hw_tod(struct idtcm_channel *channel,
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400680 struct timespec64 const *ts,
681 enum hw_tod_write_trig_sel wr_trig)
682{
683 struct idtcm *idtcm = channel->idtcm;
684
685 u8 buf[TOD_BYTE_COUNT];
686 u8 cmd;
687 int err;
688 struct timespec64 local_ts = *ts;
689 s64 total_overhead_ns;
690
691 /* Configure HW TOD write trigger. */
692 err = idtcm_read(idtcm, channel->hw_dpll_n, HW_DPLL_TOD_CTRL_1,
693 &cmd, sizeof(cmd));
694
695 if (err)
696 return err;
697
698 cmd &= ~(0x0f);
699 cmd |= wr_trig | 0x08;
700
701 err = idtcm_write(idtcm, channel->hw_dpll_n, HW_DPLL_TOD_CTRL_1,
702 &cmd, sizeof(cmd));
703
704 if (err)
705 return err;
706
707 if (wr_trig != HW_TOD_WR_TRIG_SEL_MSB) {
708
709 err = timespec_to_char_array(&local_ts, buf, sizeof(buf));
710
711 if (err)
712 return err;
713
714 err = idtcm_write(idtcm, channel->hw_dpll_n,
715 HW_DPLL_TOD_OVR__0, buf, sizeof(buf));
716
717 if (err)
718 return err;
719 }
720
721 /* ARM HW TOD write trigger. */
722 cmd &= ~(0x08);
723
724 err = idtcm_write(idtcm, channel->hw_dpll_n, HW_DPLL_TOD_CTRL_1,
725 &cmd, sizeof(cmd));
726
727 if (wr_trig == HW_TOD_WR_TRIG_SEL_MSB) {
728
729 if (idtcm->calculate_overhead_flag) {
Vincent Cheng1ece2fb2020-01-07 09:47:57 -0500730 /* Assumption: I2C @ 400KHz */
Min Li7260d1c2020-12-08 10:41:56 -0500731 ktime_t diff = ktime_sub(ktime_get_raw(),
732 idtcm->start_time);
733 total_overhead_ns = ktime_to_ns(diff)
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400734 + idtcm->tod_write_overhead_ns
735 + SETTIME_CORRECTION;
736
737 timespec64_add_ns(&local_ts, total_overhead_ns);
738
739 idtcm->calculate_overhead_flag = 0;
740 }
741
742 err = timespec_to_char_array(&local_ts, buf, sizeof(buf));
743
744 if (err)
745 return err;
746
747 err = idtcm_write(idtcm, channel->hw_dpll_n,
748 HW_DPLL_TOD_OVR__0, buf, sizeof(buf));
749 }
750
751 return err;
752}
753
Min Li7ea5fda2020-07-28 16:00:30 -0400754static int _idtcm_set_dpll_scsr_tod(struct idtcm_channel *channel,
755 struct timespec64 const *ts,
756 enum scsr_tod_write_trig_sel wr_trig,
757 enum scsr_tod_write_type_sel wr_type)
758{
759 struct idtcm *idtcm = channel->idtcm;
760 unsigned char buf[TOD_BYTE_COUNT], cmd;
761 struct timespec64 local_ts = *ts;
762 int err, count = 0;
763
764 timespec64_add_ns(&local_ts, SETTIME_CORRECTION);
765
766 err = timespec_to_char_array(&local_ts, buf, sizeof(buf));
767
768 if (err)
769 return err;
770
771 err = idtcm_write(idtcm, channel->tod_write, TOD_WRITE,
772 buf, sizeof(buf));
773 if (err)
774 return err;
775
776 /* Trigger the write operation. */
777 err = idtcm_read(idtcm, channel->tod_write, TOD_WRITE_CMD,
778 &cmd, sizeof(cmd));
779 if (err)
780 return err;
781
782 cmd &= ~(TOD_WRITE_SELECTION_MASK << TOD_WRITE_SELECTION_SHIFT);
783 cmd &= ~(TOD_WRITE_TYPE_MASK << TOD_WRITE_TYPE_SHIFT);
784 cmd |= (wr_trig << TOD_WRITE_SELECTION_SHIFT);
785 cmd |= (wr_type << TOD_WRITE_TYPE_SHIFT);
786
787 err = idtcm_write(idtcm, channel->tod_write, TOD_WRITE_CMD,
788 &cmd, sizeof(cmd));
789 if (err)
790 return err;
791
792 /* Wait for the operation to complete. */
793 while (1) {
794 /* pps trigger takes up to 1 sec to complete */
795 if (wr_trig == SCSR_TOD_WR_TRIG_SEL_TODPPS)
796 msleep(50);
797
798 err = idtcm_read(idtcm, channel->tod_write, TOD_WRITE_CMD,
799 &cmd, sizeof(cmd));
800 if (err)
801 return err;
802
Min Li251f4fe2020-12-08 10:41:54 -0500803 if ((cmd & TOD_WRITE_SELECTION_MASK) == 0)
Min Li7ea5fda2020-07-28 16:00:30 -0400804 break;
805
806 if (++count > 20) {
807 dev_err(&idtcm->client->dev,
Vincent Cheng1c49d3e2021-02-17 00:42:15 -0500808 "Timed out waiting for the write counter");
Min Li7ea5fda2020-07-28 16:00:30 -0400809 return -EIO;
810 }
811 }
812
813 return 0;
814}
815
Min Li7260d1c2020-12-08 10:41:56 -0500816static int get_output_base_addr(u8 outn)
817{
818 int base;
819
820 switch (outn) {
821 case 0:
822 base = OUTPUT_0;
823 break;
824 case 1:
825 base = OUTPUT_1;
826 break;
827 case 2:
828 base = OUTPUT_2;
829 break;
830 case 3:
831 base = OUTPUT_3;
832 break;
833 case 4:
834 base = OUTPUT_4;
835 break;
836 case 5:
837 base = OUTPUT_5;
838 break;
839 case 6:
840 base = OUTPUT_6;
841 break;
842 case 7:
843 base = OUTPUT_7;
844 break;
845 case 8:
846 base = OUTPUT_8;
847 break;
848 case 9:
849 base = OUTPUT_9;
850 break;
851 case 10:
852 base = OUTPUT_10;
853 break;
854 case 11:
855 base = OUTPUT_11;
856 break;
857 default:
858 base = -EINVAL;
859 }
860
861 return base;
862}
863
Min Lida948232020-12-08 10:41:57 -0500864static int _idtcm_settime_deprecated(struct idtcm_channel *channel,
865 struct timespec64 const *ts)
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400866{
867 struct idtcm *idtcm = channel->idtcm;
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400868 int err;
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400869
Min Li251f4fe2020-12-08 10:41:54 -0500870 err = _idtcm_set_dpll_hw_tod(channel, ts, HW_TOD_WR_TRIG_SEL_MSB);
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400871
Min Li7ea5fda2020-07-28 16:00:30 -0400872 if (err) {
873 dev_err(&idtcm->client->dev,
Vincent Cheng1c49d3e2021-02-17 00:42:15 -0500874 "%s: Set HW ToD failed", __func__);
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400875 return err;
Min Li7ea5fda2020-07-28 16:00:30 -0400876 }
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400877
Min Li7ea5fda2020-07-28 16:00:30 -0400878 return idtcm_sync_pps_output(channel);
879}
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400880
Min Lida948232020-12-08 10:41:57 -0500881static int _idtcm_settime(struct idtcm_channel *channel,
882 struct timespec64 const *ts,
883 enum scsr_tod_write_type_sel wr_type)
Min Li7ea5fda2020-07-28 16:00:30 -0400884{
885 return _idtcm_set_dpll_scsr_tod(channel, ts,
886 SCSR_TOD_WR_TRIG_SEL_IMMEDIATE,
887 wr_type);
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -0400888}
889
890static int idtcm_set_phase_pull_in_offset(struct idtcm_channel *channel,
891 s32 offset_ns)
892{
893 int err;
894 int i;
895 struct idtcm *idtcm = channel->idtcm;
896
897 u8 buf[4];
898
899 for (i = 0; i < 4; i++) {
900 buf[i] = 0xff & (offset_ns);
901 offset_ns >>= 8;
902 }
903
904 err = idtcm_write(idtcm, channel->dpll_phase_pull_in, PULL_IN_OFFSET,
905 buf, sizeof(buf));
906
907 return err;
908}
909
910static int idtcm_set_phase_pull_in_slope_limit(struct idtcm_channel *channel,
911 u32 max_ffo_ppb)
912{
913 int err;
914 u8 i;
915 struct idtcm *idtcm = channel->idtcm;
916
917 u8 buf[3];
918
919 if (max_ffo_ppb & 0xff000000)
920 max_ffo_ppb = 0;
921
922 for (i = 0; i < 3; i++) {
923 buf[i] = 0xff & (max_ffo_ppb);
924 max_ffo_ppb >>= 8;
925 }
926
927 err = idtcm_write(idtcm, channel->dpll_phase_pull_in,
928 PULL_IN_SLOPE_LIMIT, buf, sizeof(buf));
929
930 return err;
931}
932
933static int idtcm_start_phase_pull_in(struct idtcm_channel *channel)
934{
935 int err;
936 struct idtcm *idtcm = channel->idtcm;
937
938 u8 buf;
939
940 err = idtcm_read(idtcm, channel->dpll_phase_pull_in, PULL_IN_CTRL,
941 &buf, sizeof(buf));
942
943 if (err)
944 return err;
945
946 if (buf == 0) {
947 buf = 0x01;
948 err = idtcm_write(idtcm, channel->dpll_phase_pull_in,
949 PULL_IN_CTRL, &buf, sizeof(buf));
950 } else {
951 err = -EBUSY;
952 }
953
954 return err;
955}
956
957static int idtcm_do_phase_pull_in(struct idtcm_channel *channel,
958 s32 offset_ns,
959 u32 max_ffo_ppb)
960{
961 int err;
962
963 err = idtcm_set_phase_pull_in_offset(channel, -offset_ns);
964
965 if (err)
966 return err;
967
968 err = idtcm_set_phase_pull_in_slope_limit(channel, max_ffo_ppb);
969
970 if (err)
971 return err;
972
973 err = idtcm_start_phase_pull_in(channel);
974
975 return err;
976}
977
Min Li7ea5fda2020-07-28 16:00:30 -0400978static int set_tod_write_overhead(struct idtcm_channel *channel)
979{
980 struct idtcm *idtcm = channel->idtcm;
981 s64 current_ns = 0;
982 s64 lowest_ns = 0;
983 int err;
984 u8 i;
985
986 ktime_t start;
987 ktime_t stop;
Min Li7260d1c2020-12-08 10:41:56 -0500988 ktime_t diff;
Min Li7ea5fda2020-07-28 16:00:30 -0400989
990 char buf[TOD_BYTE_COUNT] = {0};
991
992 /* Set page offset */
993 idtcm_write(idtcm, channel->hw_dpll_n, HW_DPLL_TOD_OVR__0,
994 buf, sizeof(buf));
995
996 for (i = 0; i < TOD_WRITE_OVERHEAD_COUNT_MAX; i++) {
997
998 start = ktime_get_raw();
999
1000 err = idtcm_write(idtcm, channel->hw_dpll_n,
1001 HW_DPLL_TOD_OVR__0, buf, sizeof(buf));
1002
1003 if (err)
1004 return err;
1005
1006 stop = ktime_get_raw();
1007
Min Li7260d1c2020-12-08 10:41:56 -05001008 diff = ktime_sub(stop, start);
1009
1010 current_ns = ktime_to_ns(diff);
Min Li7ea5fda2020-07-28 16:00:30 -04001011
1012 if (i == 0) {
1013 lowest_ns = current_ns;
1014 } else {
1015 if (current_ns < lowest_ns)
1016 lowest_ns = current_ns;
1017 }
1018 }
1019
1020 idtcm->tod_write_overhead_ns = lowest_ns;
1021
1022 return err;
1023}
1024
Min Lida948232020-12-08 10:41:57 -05001025static int _idtcm_adjtime_deprecated(struct idtcm_channel *channel, s64 delta)
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001026{
1027 int err;
1028 struct idtcm *idtcm = channel->idtcm;
1029 struct timespec64 ts;
1030 s64 now;
1031
Min Lida948232020-12-08 10:41:57 -05001032 if (abs(delta) < PHASE_PULL_IN_THRESHOLD_NS_DEPRECATED) {
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001033 err = idtcm_do_phase_pull_in(channel, delta, 0);
1034 } else {
1035 idtcm->calculate_overhead_flag = 1;
1036
Min Li7ea5fda2020-07-28 16:00:30 -04001037 err = set_tod_write_overhead(channel);
1038
1039 if (err)
1040 return err;
1041
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001042 err = _idtcm_gettime(channel, &ts);
1043
1044 if (err)
1045 return err;
1046
1047 now = timespec64_to_ns(&ts);
1048 now += delta;
1049
1050 ts = ns_to_timespec64(now);
1051
Min Lida948232020-12-08 10:41:57 -05001052 err = _idtcm_settime_deprecated(channel, &ts);
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001053 }
1054
1055 return err;
1056}
1057
1058static int idtcm_state_machine_reset(struct idtcm *idtcm)
1059{
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001060 u8 byte = SM_RESET_CMD;
Min Li251f4fe2020-12-08 10:41:54 -05001061 u32 status = 0;
1062 int err;
1063 u8 i;
1064
1065 clear_boot_status(idtcm);
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001066
1067 err = idtcm_write(idtcm, RESET_CTRL, SM_RESET, &byte, sizeof(byte));
1068
Min Li251f4fe2020-12-08 10:41:54 -05001069 if (!err) {
1070 for (i = 0; i < 30; i++) {
1071 msleep_interruptible(100);
1072 read_boot_status(idtcm, &status);
1073
1074 if (status == 0xA0) {
1075 dev_dbg(&idtcm->client->dev,
Vincent Cheng1c49d3e2021-02-17 00:42:15 -05001076 "SM_RESET completed in %d ms", i * 100);
Min Li251f4fe2020-12-08 10:41:54 -05001077 break;
1078 }
1079 }
1080
1081 if (!status)
Vincent Cheng1c49d3e2021-02-17 00:42:15 -05001082 dev_err(&idtcm->client->dev,
1083 "Timed out waiting for CM_RESET to complete");
Min Li251f4fe2020-12-08 10:41:54 -05001084 }
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001085
1086 return err;
1087}
1088
1089static int idtcm_read_hw_rev_id(struct idtcm *idtcm, u8 *hw_rev_id)
1090{
Vincent Cheng1ece2fb2020-01-07 09:47:57 -05001091 return idtcm_read(idtcm, HW_REVISION, REV_ID, hw_rev_id, sizeof(u8));
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001092}
1093
1094static int idtcm_read_product_id(struct idtcm *idtcm, u16 *product_id)
1095{
1096 int err;
1097 u8 buf[2] = {0};
1098
1099 err = idtcm_read(idtcm, GENERAL_STATUS, PRODUCT_ID, buf, sizeof(buf));
1100
1101 *product_id = (buf[1] << 8) | buf[0];
1102
1103 return err;
1104}
1105
1106static int idtcm_read_major_release(struct idtcm *idtcm, u8 *major)
1107{
1108 int err;
1109 u8 buf = 0;
1110
1111 err = idtcm_read(idtcm, GENERAL_STATUS, MAJ_REL, &buf, sizeof(buf));
1112
1113 *major = buf >> 1;
1114
1115 return err;
1116}
1117
1118static int idtcm_read_minor_release(struct idtcm *idtcm, u8 *minor)
1119{
1120 return idtcm_read(idtcm, GENERAL_STATUS, MIN_REL, minor, sizeof(u8));
1121}
1122
1123static int idtcm_read_hotfix_release(struct idtcm *idtcm, u8 *hotfix)
1124{
1125 return idtcm_read(idtcm,
1126 GENERAL_STATUS,
1127 HOTFIX_REL,
1128 hotfix,
1129 sizeof(u8));
1130}
1131
Vincent Cheng1ece2fb2020-01-07 09:47:57 -05001132static int idtcm_read_otp_scsr_config_select(struct idtcm *idtcm,
1133 u8 *config_select)
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001134{
Vincent Cheng1ece2fb2020-01-07 09:47:57 -05001135 return idtcm_read(idtcm, GENERAL_STATUS, OTP_SCSR_CONFIG_SELECT,
1136 config_select, sizeof(u8));
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001137}
1138
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001139static int set_pll_output_mask(struct idtcm *idtcm, u16 addr, u8 val)
1140{
1141 int err = 0;
1142
1143 switch (addr) {
Min Li7ea5fda2020-07-28 16:00:30 -04001144 case TOD0_OUT_ALIGN_MASK_ADDR:
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001145 SET_U16_LSB(idtcm->channel[0].output_mask, val);
1146 break;
Min Li7ea5fda2020-07-28 16:00:30 -04001147 case TOD0_OUT_ALIGN_MASK_ADDR + 1:
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001148 SET_U16_MSB(idtcm->channel[0].output_mask, val);
1149 break;
Min Li7ea5fda2020-07-28 16:00:30 -04001150 case TOD1_OUT_ALIGN_MASK_ADDR:
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001151 SET_U16_LSB(idtcm->channel[1].output_mask, val);
1152 break;
Min Li7ea5fda2020-07-28 16:00:30 -04001153 case TOD1_OUT_ALIGN_MASK_ADDR + 1:
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001154 SET_U16_MSB(idtcm->channel[1].output_mask, val);
1155 break;
Min Li7ea5fda2020-07-28 16:00:30 -04001156 case TOD2_OUT_ALIGN_MASK_ADDR:
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001157 SET_U16_LSB(idtcm->channel[2].output_mask, val);
1158 break;
Min Li7ea5fda2020-07-28 16:00:30 -04001159 case TOD2_OUT_ALIGN_MASK_ADDR + 1:
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001160 SET_U16_MSB(idtcm->channel[2].output_mask, val);
1161 break;
Min Li7ea5fda2020-07-28 16:00:30 -04001162 case TOD3_OUT_ALIGN_MASK_ADDR:
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001163 SET_U16_LSB(idtcm->channel[3].output_mask, val);
1164 break;
Min Li7ea5fda2020-07-28 16:00:30 -04001165 case TOD3_OUT_ALIGN_MASK_ADDR + 1:
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001166 SET_U16_MSB(idtcm->channel[3].output_mask, val);
1167 break;
1168 default:
Min Li7ea5fda2020-07-28 16:00:30 -04001169 err = -EFAULT; /* Bad address */;
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001170 break;
1171 }
1172
1173 return err;
1174}
1175
Min Li7ea5fda2020-07-28 16:00:30 -04001176static int set_tod_ptp_pll(struct idtcm *idtcm, u8 index, u8 pll)
1177{
1178 if (index >= MAX_TOD) {
Vincent Cheng1c49d3e2021-02-17 00:42:15 -05001179 dev_err(&idtcm->client->dev, "ToD%d not supported", index);
Min Li7ea5fda2020-07-28 16:00:30 -04001180 return -EINVAL;
1181 }
1182
1183 if (pll >= MAX_PLL) {
Vincent Cheng1c49d3e2021-02-17 00:42:15 -05001184 dev_err(&idtcm->client->dev, "Pll%d not supported", pll);
Min Li7ea5fda2020-07-28 16:00:30 -04001185 return -EINVAL;
1186 }
1187
1188 idtcm->channel[index].pll = pll;
1189
1190 return 0;
1191}
1192
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001193static int check_and_set_masks(struct idtcm *idtcm,
1194 u16 regaddr,
1195 u8 val)
1196{
1197 int err = 0;
1198
Min Li7ea5fda2020-07-28 16:00:30 -04001199 switch (regaddr) {
1200 case TOD_MASK_ADDR:
1201 if ((val & 0xf0) || !(val & 0x0f)) {
Vincent Cheng1c49d3e2021-02-17 00:42:15 -05001202 dev_err(&idtcm->client->dev, "Invalid TOD mask 0x%02x", val);
Min Li7ea5fda2020-07-28 16:00:30 -04001203 err = -EINVAL;
1204 } else {
1205 idtcm->tod_mask = val;
1206 }
1207 break;
1208 case TOD0_PTP_PLL_ADDR:
1209 err = set_tod_ptp_pll(idtcm, 0, val);
1210 break;
1211 case TOD1_PTP_PLL_ADDR:
1212 err = set_tod_ptp_pll(idtcm, 1, val);
1213 break;
1214 case TOD2_PTP_PLL_ADDR:
1215 err = set_tod_ptp_pll(idtcm, 2, val);
1216 break;
1217 case TOD3_PTP_PLL_ADDR:
1218 err = set_tod_ptp_pll(idtcm, 3, val);
1219 break;
1220 default:
1221 err = set_pll_output_mask(idtcm, regaddr, val);
1222 break;
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001223 }
1224
1225 return err;
1226}
1227
Min Li7ea5fda2020-07-28 16:00:30 -04001228static void display_pll_and_masks(struct idtcm *idtcm)
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001229{
1230 u8 i;
1231 u8 mask;
1232
Vincent Cheng1c49d3e2021-02-17 00:42:15 -05001233 dev_dbg(&idtcm->client->dev, "tod_mask = 0x%02x", idtcm->tod_mask);
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001234
Min Li7ea5fda2020-07-28 16:00:30 -04001235 for (i = 0; i < MAX_TOD; i++) {
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001236 mask = 1 << i;
1237
Min Li7ea5fda2020-07-28 16:00:30 -04001238 if (mask & idtcm->tod_mask)
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001239 dev_dbg(&idtcm->client->dev,
Vincent Cheng1c49d3e2021-02-17 00:42:15 -05001240 "TOD%d pll = %d output_mask = 0x%04x",
Min Li7ea5fda2020-07-28 16:00:30 -04001241 i, idtcm->channel[i].pll,
1242 idtcm->channel[i].output_mask);
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001243 }
1244}
1245
1246static int idtcm_load_firmware(struct idtcm *idtcm,
1247 struct device *dev)
1248{
Min Li7ea5fda2020-07-28 16:00:30 -04001249 char fname[128] = FW_FILENAME;
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001250 const struct firmware *fw;
1251 struct idtcm_fwrc *rec;
1252 u32 regaddr;
1253 int err;
1254 s32 len;
1255 u8 val;
1256 u8 loaddr;
1257
Min Li7ea5fda2020-07-28 16:00:30 -04001258 if (firmware) /* module parameter */
1259 snprintf(fname, sizeof(fname), "%s", firmware);
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001260
Vincent Cheng1c49d3e2021-02-17 00:42:15 -05001261 dev_dbg(&idtcm->client->dev, "requesting firmware '%s'", fname);
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001262
Min Li7ea5fda2020-07-28 16:00:30 -04001263 err = request_firmware(&fw, fname, dev);
Min Li7ea5fda2020-07-28 16:00:30 -04001264 if (err) {
1265 dev_err(&idtcm->client->dev,
Vincent Cheng1c49d3e2021-02-17 00:42:15 -05001266 "Failed at line %d in %s!", __LINE__, __func__);
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001267 return err;
Min Li7ea5fda2020-07-28 16:00:30 -04001268 }
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001269
Vincent Cheng1c49d3e2021-02-17 00:42:15 -05001270 dev_dbg(&idtcm->client->dev, "firmware size %zu bytes", fw->size);
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001271
1272 rec = (struct idtcm_fwrc *) fw->data;
1273
Min Li251f4fe2020-12-08 10:41:54 -05001274 if (contains_full_configuration(fw))
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001275 idtcm_state_machine_reset(idtcm);
1276
1277 for (len = fw->size; len > 0; len -= sizeof(*rec)) {
1278
1279 if (rec->reserved) {
1280 dev_err(&idtcm->client->dev,
Vincent Cheng1c49d3e2021-02-17 00:42:15 -05001281 "bad firmware, reserved field non-zero");
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001282 err = -EINVAL;
1283 } else {
1284 regaddr = rec->hiaddr << 8;
1285 regaddr |= rec->loaddr;
1286
1287 val = rec->value;
1288 loaddr = rec->loaddr;
1289
1290 rec++;
1291
1292 err = check_and_set_masks(idtcm, regaddr, val);
1293 }
1294
Min Li7ea5fda2020-07-28 16:00:30 -04001295 if (err != -EINVAL) {
1296 err = 0;
1297
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001298 /* Top (status registers) and bottom are read-only */
1299 if ((regaddr < GPIO_USER_CONTROL)
1300 || (regaddr >= SCRATCH))
1301 continue;
1302
1303 /* Page size 128, last 4 bytes of page skipped */
1304 if (((loaddr > 0x7b) && (loaddr <= 0x7f))
Yang Yingliang3e144622020-04-24 20:52:26 +08001305 || loaddr > 0xfb)
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001306 continue;
1307
1308 err = idtcm_write(idtcm, regaddr, 0, &val, sizeof(val));
1309 }
1310
1311 if (err)
1312 goto out;
1313 }
1314
Min Li7ea5fda2020-07-28 16:00:30 -04001315 display_pll_and_masks(idtcm);
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001316
1317out:
1318 release_firmware(fw);
1319 return err;
1320}
1321
Min Li7ea5fda2020-07-28 16:00:30 -04001322static int idtcm_output_enable(struct idtcm_channel *channel,
1323 bool enable, unsigned int outn)
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001324{
1325 struct idtcm *idtcm = channel->idtcm;
Min Li7260d1c2020-12-08 10:41:56 -05001326 int base;
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001327 int err;
Min Li7ea5fda2020-07-28 16:00:30 -04001328 u8 val;
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001329
Min Li7260d1c2020-12-08 10:41:56 -05001330 base = get_output_base_addr(outn);
1331
1332 if (!(base > 0)) {
1333 dev_err(&idtcm->client->dev,
1334 "%s - Unsupported out%d", __func__, outn);
1335 return base;
1336 }
1337
1338 err = idtcm_read(idtcm, (u16)base, OUT_CTRL_1, &val, sizeof(val));
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001339
1340 if (err)
1341 return err;
1342
1343 if (enable)
1344 val |= SQUELCH_DISABLE;
1345 else
1346 val &= ~SQUELCH_DISABLE;
1347
Min Li7260d1c2020-12-08 10:41:56 -05001348 return idtcm_write(idtcm, (u16)base, OUT_CTRL_1, &val, sizeof(val));
Min Li7ea5fda2020-07-28 16:00:30 -04001349}
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001350
Min Li7ea5fda2020-07-28 16:00:30 -04001351static int idtcm_output_mask_enable(struct idtcm_channel *channel,
1352 bool enable)
1353{
1354 u16 mask;
1355 int err;
1356 u8 outn;
1357
1358 mask = channel->output_mask;
1359 outn = 0;
1360
1361 while (mask) {
1362
1363 if (mask & 0x1) {
1364
1365 err = idtcm_output_enable(channel, enable, outn);
1366
1367 if (err)
1368 return err;
1369 }
1370
1371 mask >>= 0x1;
1372 outn++;
1373 }
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001374
1375 return 0;
1376}
1377
Min Li7ea5fda2020-07-28 16:00:30 -04001378static int idtcm_perout_enable(struct idtcm_channel *channel,
1379 bool enable,
1380 struct ptp_perout_request *perout)
1381{
Vincent Chenge8b4d8b2021-02-17 00:42:13 -05001382 struct idtcm *idtcm = channel->idtcm;
Min Li7ea5fda2020-07-28 16:00:30 -04001383 unsigned int flags = perout->flags;
Vincent Chenge8b4d8b2021-02-17 00:42:13 -05001384 struct timespec64 ts = {0, 0};
1385 int err;
Min Li7ea5fda2020-07-28 16:00:30 -04001386
1387 if (flags == PEROUT_ENABLE_OUTPUT_MASK)
Vincent Chenge8b4d8b2021-02-17 00:42:13 -05001388 err = idtcm_output_mask_enable(channel, enable);
1389 else
1390 err = idtcm_output_enable(channel, enable, perout->index);
Min Li7ea5fda2020-07-28 16:00:30 -04001391
Vincent Chenge8b4d8b2021-02-17 00:42:13 -05001392 if (err) {
1393 dev_err(&idtcm->client->dev, "Unable to set output enable");
1394 return err;
1395 }
1396
1397 /* Align output to internal 1 PPS */
1398 return _idtcm_settime(channel, &ts, SCSR_TOD_WR_TYPE_SEL_DELTA_PLUS);
Min Li7ea5fda2020-07-28 16:00:30 -04001399}
1400
Min Li7260d1c2020-12-08 10:41:56 -05001401static int idtcm_get_pll_mode(struct idtcm_channel *channel,
1402 enum pll_mode *pll_mode)
1403{
1404 struct idtcm *idtcm = channel->idtcm;
1405 int err;
1406 u8 dpll_mode;
1407
1408 err = idtcm_read(idtcm, channel->dpll_n, DPLL_MODE,
1409 &dpll_mode, sizeof(dpll_mode));
1410 if (err)
1411 return err;
1412
1413 *pll_mode = (dpll_mode >> PLL_MODE_SHIFT) & PLL_MODE_MASK;
1414
1415 return 0;
1416}
1417
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001418static int idtcm_set_pll_mode(struct idtcm_channel *channel,
1419 enum pll_mode pll_mode)
1420{
1421 struct idtcm *idtcm = channel->idtcm;
1422 int err;
1423 u8 dpll_mode;
1424
1425 err = idtcm_read(idtcm, channel->dpll_n, DPLL_MODE,
1426 &dpll_mode, sizeof(dpll_mode));
1427 if (err)
1428 return err;
1429
1430 dpll_mode &= ~(PLL_MODE_MASK << PLL_MODE_SHIFT);
1431
1432 dpll_mode |= (pll_mode << PLL_MODE_SHIFT);
1433
1434 channel->pll_mode = pll_mode;
1435
1436 err = idtcm_write(idtcm, channel->dpll_n, DPLL_MODE,
1437 &dpll_mode, sizeof(dpll_mode));
1438 if (err)
1439 return err;
1440
1441 return 0;
1442}
1443
1444/* PTP Hardware Clock interface */
1445
Vincent Cheng425d2b12020-05-01 23:35:38 -04001446/**
1447 * @brief Maximum absolute value for write phase offset in picoseconds
1448 *
1449 * Destination signed register is 32-bit register in resolution of 50ps
1450 *
1451 * 0x7fffffff * 50 = 2147483647 * 50 = 107374182350
1452 */
1453static int _idtcm_adjphase(struct idtcm_channel *channel, s32 delta_ns)
1454{
1455 struct idtcm *idtcm = channel->idtcm;
1456
1457 int err;
1458 u8 i;
1459 u8 buf[4] = {0};
1460 s32 phase_50ps;
1461 s64 offset_ps;
1462
1463 if (channel->pll_mode != PLL_MODE_WRITE_PHASE) {
1464
1465 err = idtcm_set_pll_mode(channel, PLL_MODE_WRITE_PHASE);
1466
1467 if (err)
1468 return err;
Vincent Cheng425d2b12020-05-01 23:35:38 -04001469 }
1470
Vincent Cheng425d2b12020-05-01 23:35:38 -04001471 offset_ps = (s64)delta_ns * 1000;
1472
1473 /*
1474 * Check for 32-bit signed max * 50:
1475 *
1476 * 0x7fffffff * 50 = 2147483647 * 50 = 107374182350
1477 */
1478 if (offset_ps > MAX_ABS_WRITE_PHASE_PICOSECONDS)
1479 offset_ps = MAX_ABS_WRITE_PHASE_PICOSECONDS;
1480 else if (offset_ps < -MAX_ABS_WRITE_PHASE_PICOSECONDS)
1481 offset_ps = -MAX_ABS_WRITE_PHASE_PICOSECONDS;
1482
Min Li7260d1c2020-12-08 10:41:56 -05001483 phase_50ps = div_s64(offset_ps, 50);
Vincent Cheng425d2b12020-05-01 23:35:38 -04001484
1485 for (i = 0; i < 4; i++) {
1486 buf[i] = phase_50ps & 0xff;
1487 phase_50ps >>= 8;
1488 }
1489
1490 err = idtcm_write(idtcm, channel->dpll_phase, DPLL_WR_PHASE,
1491 buf, sizeof(buf));
1492
1493 return err;
1494}
1495
Min Li7ea5fda2020-07-28 16:00:30 -04001496static int _idtcm_adjfine(struct idtcm_channel *channel, long scaled_ppm)
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001497{
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001498 struct idtcm *idtcm = channel->idtcm;
1499 u8 i;
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001500 int err;
1501 u8 buf[6] = {0};
1502 s64 fcw;
1503
1504 if (channel->pll_mode != PLL_MODE_WRITE_FREQUENCY) {
1505 err = idtcm_set_pll_mode(channel, PLL_MODE_WRITE_FREQUENCY);
1506 if (err)
1507 return err;
1508 }
1509
1510 /*
1511 * Frequency Control Word unit is: 1.11 * 10^-10 ppm
1512 *
1513 * adjfreq:
1514 * ppb * 10^9
1515 * FCW = ----------
1516 * 111
1517 *
1518 * adjfine:
1519 * ppm_16 * 5^12
1520 * FCW = -------------
1521 * 111 * 2^4
1522 */
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001523
1524 /* 2 ^ -53 = 1.1102230246251565404236316680908e-16 */
Min Li7ea5fda2020-07-28 16:00:30 -04001525 fcw = scaled_ppm * 244140625ULL;
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001526
Min Li7260d1c2020-12-08 10:41:56 -05001527 fcw = div_s64(fcw, 1776);
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001528
1529 for (i = 0; i < 6; i++) {
1530 buf[i] = fcw & 0xff;
1531 fcw >>= 8;
1532 }
1533
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001534 err = idtcm_write(idtcm, channel->dpll_freq, DPLL_WR_FREQ,
1535 buf, sizeof(buf));
1536
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001537 return err;
1538}
1539
1540static int idtcm_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
1541{
1542 struct idtcm_channel *channel =
1543 container_of(ptp, struct idtcm_channel, caps);
1544 struct idtcm *idtcm = channel->idtcm;
1545 int err;
1546
1547 mutex_lock(&idtcm->reg_lock);
1548
1549 err = _idtcm_gettime(channel, ts);
1550
Min Li7ea5fda2020-07-28 16:00:30 -04001551 if (err)
Vincent Cheng1c49d3e2021-02-17 00:42:15 -05001552 dev_err(&idtcm->client->dev, "Failed at line %d in %s!",
1553 __LINE__, __func__);
Min Li7ea5fda2020-07-28 16:00:30 -04001554
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001555 mutex_unlock(&idtcm->reg_lock);
1556
1557 return err;
1558}
1559
Min Lida948232020-12-08 10:41:57 -05001560static int idtcm_settime_deprecated(struct ptp_clock_info *ptp,
1561 const struct timespec64 *ts)
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001562{
1563 struct idtcm_channel *channel =
1564 container_of(ptp, struct idtcm_channel, caps);
1565 struct idtcm *idtcm = channel->idtcm;
1566 int err;
1567
1568 mutex_lock(&idtcm->reg_lock);
1569
Min Lida948232020-12-08 10:41:57 -05001570 err = _idtcm_settime_deprecated(channel, ts);
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001571
Min Li7ea5fda2020-07-28 16:00:30 -04001572 if (err)
1573 dev_err(&idtcm->client->dev,
Vincent Cheng1c49d3e2021-02-17 00:42:15 -05001574 "Failed at line %d in %s!", __LINE__, __func__);
Min Li7ea5fda2020-07-28 16:00:30 -04001575
1576 mutex_unlock(&idtcm->reg_lock);
1577
1578 return err;
1579}
1580
Min Lida948232020-12-08 10:41:57 -05001581static int idtcm_settime(struct ptp_clock_info *ptp,
Min Li7ea5fda2020-07-28 16:00:30 -04001582 const struct timespec64 *ts)
1583{
1584 struct idtcm_channel *channel =
1585 container_of(ptp, struct idtcm_channel, caps);
1586 struct idtcm *idtcm = channel->idtcm;
1587 int err;
1588
1589 mutex_lock(&idtcm->reg_lock);
1590
Min Lida948232020-12-08 10:41:57 -05001591 err = _idtcm_settime(channel, ts, SCSR_TOD_WR_TYPE_SEL_ABSOLUTE);
1592
1593 if (err)
1594 dev_err(&idtcm->client->dev,
Vincent Cheng1c49d3e2021-02-17 00:42:15 -05001595 "Failed at line %d in %s!", __LINE__, __func__);
Min Lida948232020-12-08 10:41:57 -05001596
1597 mutex_unlock(&idtcm->reg_lock);
1598
1599 return err;
1600}
1601
1602static int idtcm_adjtime_deprecated(struct ptp_clock_info *ptp, s64 delta)
1603{
1604 struct idtcm_channel *channel =
1605 container_of(ptp, struct idtcm_channel, caps);
1606 struct idtcm *idtcm = channel->idtcm;
1607 int err;
1608
1609 mutex_lock(&idtcm->reg_lock);
1610
1611 err = _idtcm_adjtime_deprecated(channel, delta);
Min Li7ea5fda2020-07-28 16:00:30 -04001612
1613 if (err)
1614 dev_err(&idtcm->client->dev,
Vincent Cheng1c49d3e2021-02-17 00:42:15 -05001615 "Failed at line %d in %s!", __LINE__, __func__);
Min Li7ea5fda2020-07-28 16:00:30 -04001616
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001617 mutex_unlock(&idtcm->reg_lock);
1618
1619 return err;
1620}
1621
1622static int idtcm_adjtime(struct ptp_clock_info *ptp, s64 delta)
1623{
1624 struct idtcm_channel *channel =
1625 container_of(ptp, struct idtcm_channel, caps);
1626 struct idtcm *idtcm = channel->idtcm;
Min Li7ea5fda2020-07-28 16:00:30 -04001627 struct timespec64 ts;
1628 enum scsr_tod_write_type_sel type;
1629 int err;
1630
Min Lida948232020-12-08 10:41:57 -05001631 if (abs(delta) < PHASE_PULL_IN_THRESHOLD_NS) {
Min Li7ea5fda2020-07-28 16:00:30 -04001632 err = idtcm_do_phase_pull_in(channel, delta, 0);
1633 if (err)
1634 dev_err(&idtcm->client->dev,
Vincent Cheng1c49d3e2021-02-17 00:42:15 -05001635 "Failed at line %d in %s!", __LINE__, __func__);
Min Li7ea5fda2020-07-28 16:00:30 -04001636 return err;
1637 }
1638
1639 if (delta >= 0) {
1640 ts = ns_to_timespec64(delta);
1641 type = SCSR_TOD_WR_TYPE_SEL_DELTA_PLUS;
1642 } else {
1643 ts = ns_to_timespec64(-delta);
1644 type = SCSR_TOD_WR_TYPE_SEL_DELTA_MINUS;
1645 }
1646
1647 mutex_lock(&idtcm->reg_lock);
1648
Min Lida948232020-12-08 10:41:57 -05001649 err = _idtcm_settime(channel, &ts, type);
Min Li7ea5fda2020-07-28 16:00:30 -04001650
1651 if (err)
1652 dev_err(&idtcm->client->dev,
Vincent Cheng1c49d3e2021-02-17 00:42:15 -05001653 "Failed at line %d in %s!", __LINE__, __func__);
Min Li7ea5fda2020-07-28 16:00:30 -04001654
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001655 mutex_unlock(&idtcm->reg_lock);
1656
1657 return err;
1658}
1659
Vincent Cheng425d2b12020-05-01 23:35:38 -04001660static int idtcm_adjphase(struct ptp_clock_info *ptp, s32 delta)
1661{
1662 struct idtcm_channel *channel =
1663 container_of(ptp, struct idtcm_channel, caps);
1664
1665 struct idtcm *idtcm = channel->idtcm;
1666
1667 int err;
1668
1669 mutex_lock(&idtcm->reg_lock);
1670
1671 err = _idtcm_adjphase(channel, delta);
1672
Min Li7ea5fda2020-07-28 16:00:30 -04001673 if (err)
1674 dev_err(&idtcm->client->dev,
Vincent Cheng1c49d3e2021-02-17 00:42:15 -05001675 "Failed at line %d in %s!", __LINE__, __func__);
Min Li7ea5fda2020-07-28 16:00:30 -04001676
1677 mutex_unlock(&idtcm->reg_lock);
1678
1679 return err;
1680}
1681
1682static int idtcm_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
1683{
1684 struct idtcm_channel *channel =
1685 container_of(ptp, struct idtcm_channel, caps);
1686
1687 struct idtcm *idtcm = channel->idtcm;
1688
1689 int err;
1690
1691 mutex_lock(&idtcm->reg_lock);
1692
1693 err = _idtcm_adjfine(channel, scaled_ppm);
1694
1695 if (err)
1696 dev_err(&idtcm->client->dev,
Vincent Cheng1c49d3e2021-02-17 00:42:15 -05001697 "Failed at line %d in %s!", __LINE__, __func__);
Min Li7ea5fda2020-07-28 16:00:30 -04001698
Vincent Cheng425d2b12020-05-01 23:35:38 -04001699 mutex_unlock(&idtcm->reg_lock);
1700
1701 return err;
1702}
1703
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001704static int idtcm_enable(struct ptp_clock_info *ptp,
1705 struct ptp_clock_request *rq, int on)
1706{
Min Li7ea5fda2020-07-28 16:00:30 -04001707 int err;
1708
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001709 struct idtcm_channel *channel =
1710 container_of(ptp, struct idtcm_channel, caps);
1711
1712 switch (rq->type) {
1713 case PTP_CLK_REQ_PEROUT:
Min Li7ea5fda2020-07-28 16:00:30 -04001714 if (!on) {
1715 err = idtcm_perout_enable(channel, false, &rq->perout);
1716 if (err)
1717 dev_err(&channel->idtcm->client->dev,
Vincent Cheng1c49d3e2021-02-17 00:42:15 -05001718 "Failed at line %d in %s!",
1719 __LINE__, __func__);
Min Li7ea5fda2020-07-28 16:00:30 -04001720 return err;
1721 }
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001722
1723 /* Only accept a 1-PPS aligned to the second. */
1724 if (rq->perout.start.nsec || rq->perout.period.sec != 1 ||
1725 rq->perout.period.nsec)
1726 return -ERANGE;
1727
Min Li7ea5fda2020-07-28 16:00:30 -04001728 err = idtcm_perout_enable(channel, true, &rq->perout);
1729 if (err)
1730 dev_err(&channel->idtcm->client->dev,
Vincent Cheng1c49d3e2021-02-17 00:42:15 -05001731 "Failed at line %d in %s!", __LINE__, __func__);
Min Li7ea5fda2020-07-28 16:00:30 -04001732 return err;
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001733 default:
1734 break;
1735 }
1736
1737 return -EOPNOTSUPP;
1738}
1739
Min Li7ea5fda2020-07-28 16:00:30 -04001740static int _enable_pll_tod_sync(struct idtcm *idtcm,
1741 u8 pll,
1742 u8 sync_src,
1743 u8 qn,
1744 u8 qn_plus_1)
1745{
1746 int err;
1747 u8 val;
1748 u16 dpll;
1749 u16 out0 = 0, out1 = 0;
1750
1751 if ((qn == 0) && (qn_plus_1 == 0))
1752 return 0;
1753
1754 switch (pll) {
1755 case 0:
1756 dpll = DPLL_0;
1757 if (qn)
1758 out0 = OUTPUT_0;
1759 if (qn_plus_1)
1760 out1 = OUTPUT_1;
1761 break;
1762 case 1:
1763 dpll = DPLL_1;
1764 if (qn)
1765 out0 = OUTPUT_2;
1766 if (qn_plus_1)
1767 out1 = OUTPUT_3;
1768 break;
1769 case 2:
1770 dpll = DPLL_2;
1771 if (qn)
1772 out0 = OUTPUT_4;
1773 if (qn_plus_1)
1774 out1 = OUTPUT_5;
1775 break;
1776 case 3:
1777 dpll = DPLL_3;
1778 if (qn)
1779 out0 = OUTPUT_6;
1780 if (qn_plus_1)
1781 out1 = OUTPUT_7;
1782 break;
1783 case 4:
1784 dpll = DPLL_4;
1785 if (qn)
1786 out0 = OUTPUT_8;
1787 break;
1788 case 5:
1789 dpll = DPLL_5;
1790 if (qn)
1791 out0 = OUTPUT_9;
1792 if (qn_plus_1)
1793 out1 = OUTPUT_8;
1794 break;
1795 case 6:
1796 dpll = DPLL_6;
1797 if (qn)
1798 out0 = OUTPUT_10;
1799 if (qn_plus_1)
1800 out1 = OUTPUT_11;
1801 break;
1802 case 7:
1803 dpll = DPLL_7;
1804 if (qn)
1805 out0 = OUTPUT_11;
1806 break;
1807 default:
1808 return -EINVAL;
1809 }
1810
1811 /*
1812 * Enable OUTPUT OUT_SYNC.
1813 */
1814 if (out0) {
1815 err = idtcm_read(idtcm, out0, OUT_CTRL_1, &val, sizeof(val));
1816
1817 if (err)
1818 return err;
1819
1820 val &= ~OUT_SYNC_DISABLE;
1821
1822 err = idtcm_write(idtcm, out0, OUT_CTRL_1, &val, sizeof(val));
1823
1824 if (err)
1825 return err;
1826 }
1827
1828 if (out1) {
1829 err = idtcm_read(idtcm, out1, OUT_CTRL_1, &val, sizeof(val));
1830
1831 if (err)
1832 return err;
1833
1834 val &= ~OUT_SYNC_DISABLE;
1835
1836 err = idtcm_write(idtcm, out1, OUT_CTRL_1, &val, sizeof(val));
1837
1838 if (err)
1839 return err;
1840 }
1841
1842 /* enable dpll sync tod pps, must be set before dpll_mode */
1843 err = idtcm_read(idtcm, dpll, DPLL_TOD_SYNC_CFG, &val, sizeof(val));
1844 if (err)
1845 return err;
1846
1847 val &= ~(TOD_SYNC_SOURCE_MASK << TOD_SYNC_SOURCE_SHIFT);
1848 val |= (sync_src << TOD_SYNC_SOURCE_SHIFT);
1849 val |= TOD_SYNC_EN;
1850
1851 return idtcm_write(idtcm, dpll, DPLL_TOD_SYNC_CFG, &val, sizeof(val));
1852}
1853
1854static int idtcm_enable_tod_sync(struct idtcm_channel *channel)
1855{
1856 struct idtcm *idtcm = channel->idtcm;
1857
1858 u8 pll;
1859 u8 sync_src;
1860 u8 qn;
1861 u8 qn_plus_1;
1862 u8 cfg;
1863 int err = 0;
1864 u16 output_mask = channel->output_mask;
1865 u8 out8_mux = 0;
1866 u8 out11_mux = 0;
1867 u8 temp;
1868
1869 /*
1870 * set tod_out_sync_enable to 0.
1871 */
1872 err = idtcm_read(idtcm, channel->tod_n, TOD_CFG, &cfg, sizeof(cfg));
1873 if (err)
1874 return err;
1875
1876 cfg &= ~TOD_OUT_SYNC_ENABLE;
1877
1878 err = idtcm_write(idtcm, channel->tod_n, TOD_CFG, &cfg, sizeof(cfg));
1879 if (err)
1880 return err;
1881
1882 switch (channel->tod_n) {
1883 case TOD_0:
1884 sync_src = 0;
1885 break;
1886 case TOD_1:
1887 sync_src = 1;
1888 break;
1889 case TOD_2:
1890 sync_src = 2;
1891 break;
1892 case TOD_3:
1893 sync_src = 3;
1894 break;
1895 default:
1896 return -EINVAL;
1897 }
1898
1899 err = idtcm_read(idtcm, 0, HW_Q8_CTRL_SPARE,
1900 &temp, sizeof(temp));
1901 if (err)
1902 return err;
1903
1904 if ((temp & Q9_TO_Q8_FANOUT_AND_CLOCK_SYNC_ENABLE_MASK) ==
1905 Q9_TO_Q8_FANOUT_AND_CLOCK_SYNC_ENABLE_MASK)
1906 out8_mux = 1;
1907
1908 err = idtcm_read(idtcm, 0, HW_Q11_CTRL_SPARE,
1909 &temp, sizeof(temp));
1910 if (err)
1911 return err;
1912
1913 if ((temp & Q10_TO_Q11_FANOUT_AND_CLOCK_SYNC_ENABLE_MASK) ==
1914 Q10_TO_Q11_FANOUT_AND_CLOCK_SYNC_ENABLE_MASK)
1915 out11_mux = 1;
1916
1917 for (pll = 0; pll < 8; pll++) {
1918 qn = 0;
1919 qn_plus_1 = 0;
1920
1921 if (pll < 4) {
1922 /* First 4 pll has 2 outputs */
1923 qn = output_mask & 0x1;
1924 output_mask = output_mask >> 1;
1925 qn_plus_1 = output_mask & 0x1;
1926 output_mask = output_mask >> 1;
1927 } else if (pll == 4) {
1928 if (out8_mux == 0) {
1929 qn = output_mask & 0x1;
1930 output_mask = output_mask >> 1;
1931 }
1932 } else if (pll == 5) {
1933 if (out8_mux) {
1934 qn_plus_1 = output_mask & 0x1;
1935 output_mask = output_mask >> 1;
1936 }
1937 qn = output_mask & 0x1;
1938 output_mask = output_mask >> 1;
1939 } else if (pll == 6) {
1940 qn = output_mask & 0x1;
1941 output_mask = output_mask >> 1;
1942 if (out11_mux) {
1943 qn_plus_1 = output_mask & 0x1;
1944 output_mask = output_mask >> 1;
1945 }
1946 } else if (pll == 7) {
1947 if (out11_mux == 0) {
1948 qn = output_mask & 0x1;
1949 output_mask = output_mask >> 1;
1950 }
1951 }
1952
1953 if ((qn != 0) || (qn_plus_1 != 0))
1954 err = _enable_pll_tod_sync(idtcm, pll, sync_src, qn,
1955 qn_plus_1);
1956
1957 if (err)
1958 return err;
1959 }
1960
1961 return err;
1962}
1963
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001964static int idtcm_enable_tod(struct idtcm_channel *channel)
1965{
1966 struct idtcm *idtcm = channel->idtcm;
1967 struct timespec64 ts = {0, 0};
1968 u8 cfg;
1969 int err;
1970
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001971 /*
1972 * Start the TOD clock ticking.
1973 */
1974 err = idtcm_read(idtcm, channel->tod_n, TOD_CFG, &cfg, sizeof(cfg));
1975 if (err)
1976 return err;
1977
1978 cfg |= TOD_ENABLE;
1979
1980 err = idtcm_write(idtcm, channel->tod_n, TOD_CFG, &cfg, sizeof(cfg));
1981 if (err)
1982 return err;
1983
Min Lida948232020-12-08 10:41:57 -05001984 if (idtcm->deprecated)
1985 return _idtcm_settime_deprecated(channel, &ts);
1986 else
1987 return _idtcm_settime(channel, &ts,
1988 SCSR_TOD_WR_TYPE_SEL_ABSOLUTE);
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001989}
1990
Min Lida948232020-12-08 10:41:57 -05001991static void idtcm_set_version_info(struct idtcm *idtcm)
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001992{
1993 u8 major;
1994 u8 minor;
1995 u8 hotfix;
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001996 u16 product_id;
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001997 u8 hw_rev_id;
Vincent Cheng1ece2fb2020-01-07 09:47:57 -05001998 u8 config_select;
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04001999
2000 idtcm_read_major_release(idtcm, &major);
2001 idtcm_read_minor_release(idtcm, &minor);
2002 idtcm_read_hotfix_release(idtcm, &hotfix);
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04002003
2004 idtcm_read_product_id(idtcm, &product_id);
2005 idtcm_read_hw_rev_id(idtcm, &hw_rev_id);
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04002006
Vincent Cheng1ece2fb2020-01-07 09:47:57 -05002007 idtcm_read_otp_scsr_config_select(idtcm, &config_select);
2008
Min Li7ea5fda2020-07-28 16:00:30 -04002009 snprintf(idtcm->version, sizeof(idtcm->version), "%u.%u.%u",
2010 major, minor, hotfix);
2011
Min Lida948232020-12-08 10:41:57 -05002012 if (idtcm_strverscmp(idtcm->version, "4.8.7") >= 0)
2013 idtcm->deprecated = 0;
2014 else
2015 idtcm->deprecated = 1;
2016
Vincent Cheng1c49d3e2021-02-17 00:42:15 -05002017 dev_info(&idtcm->client->dev,
2018 "%d.%d.%d, Id: 0x%04x HW Rev: %d OTP Config Select: %d",
2019 major, minor, hotfix,
Vincent Cheng1ece2fb2020-01-07 09:47:57 -05002020 product_id, hw_rev_id, config_select);
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04002021}
2022
Julia Lawall6485f9a2020-01-01 08:43:31 +01002023static const struct ptp_clock_info idtcm_caps = {
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04002024 .owner = THIS_MODULE,
2025 .max_adj = 244000,
Min Li7ea5fda2020-07-28 16:00:30 -04002026 .n_per_out = 12,
Vincent Cheng425d2b12020-05-01 23:35:38 -04002027 .adjphase = &idtcm_adjphase,
Min Li7ea5fda2020-07-28 16:00:30 -04002028 .adjfine = &idtcm_adjfine,
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04002029 .adjtime = &idtcm_adjtime,
2030 .gettime64 = &idtcm_gettime,
2031 .settime64 = &idtcm_settime,
2032 .enable = &idtcm_enable,
2033};
2034
Min Lida948232020-12-08 10:41:57 -05002035static const struct ptp_clock_info idtcm_caps_deprecated = {
2036 .owner = THIS_MODULE,
2037 .max_adj = 244000,
2038 .n_per_out = 12,
2039 .adjphase = &idtcm_adjphase,
2040 .adjfine = &idtcm_adjfine,
2041 .adjtime = &idtcm_adjtime_deprecated,
2042 .gettime64 = &idtcm_gettime,
2043 .settime64 = &idtcm_settime_deprecated,
2044 .enable = &idtcm_enable,
2045};
2046
Min Li7ea5fda2020-07-28 16:00:30 -04002047static int configure_channel_pll(struct idtcm_channel *channel)
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04002048{
Min Li7ea5fda2020-07-28 16:00:30 -04002049 int err = 0;
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04002050
Min Li7ea5fda2020-07-28 16:00:30 -04002051 switch (channel->pll) {
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04002052 case 0:
2053 channel->dpll_freq = DPLL_FREQ_0;
2054 channel->dpll_n = DPLL_0;
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04002055 channel->hw_dpll_n = HW_DPLL_0;
2056 channel->dpll_phase = DPLL_PHASE_0;
2057 channel->dpll_ctrl_n = DPLL_CTRL_0;
2058 channel->dpll_phase_pull_in = DPLL_PHASE_PULL_IN_0;
2059 break;
2060 case 1:
2061 channel->dpll_freq = DPLL_FREQ_1;
2062 channel->dpll_n = DPLL_1;
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04002063 channel->hw_dpll_n = HW_DPLL_1;
2064 channel->dpll_phase = DPLL_PHASE_1;
2065 channel->dpll_ctrl_n = DPLL_CTRL_1;
2066 channel->dpll_phase_pull_in = DPLL_PHASE_PULL_IN_1;
2067 break;
2068 case 2:
2069 channel->dpll_freq = DPLL_FREQ_2;
2070 channel->dpll_n = DPLL_2;
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04002071 channel->hw_dpll_n = HW_DPLL_2;
2072 channel->dpll_phase = DPLL_PHASE_2;
2073 channel->dpll_ctrl_n = DPLL_CTRL_2;
2074 channel->dpll_phase_pull_in = DPLL_PHASE_PULL_IN_2;
2075 break;
2076 case 3:
2077 channel->dpll_freq = DPLL_FREQ_3;
2078 channel->dpll_n = DPLL_3;
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04002079 channel->hw_dpll_n = HW_DPLL_3;
2080 channel->dpll_phase = DPLL_PHASE_3;
2081 channel->dpll_ctrl_n = DPLL_CTRL_3;
2082 channel->dpll_phase_pull_in = DPLL_PHASE_PULL_IN_3;
2083 break;
Min Li7ea5fda2020-07-28 16:00:30 -04002084 case 4:
2085 channel->dpll_freq = DPLL_FREQ_4;
2086 channel->dpll_n = DPLL_4;
2087 channel->hw_dpll_n = HW_DPLL_4;
2088 channel->dpll_phase = DPLL_PHASE_4;
2089 channel->dpll_ctrl_n = DPLL_CTRL_4;
2090 channel->dpll_phase_pull_in = DPLL_PHASE_PULL_IN_4;
2091 break;
2092 case 5:
2093 channel->dpll_freq = DPLL_FREQ_5;
2094 channel->dpll_n = DPLL_5;
2095 channel->hw_dpll_n = HW_DPLL_5;
2096 channel->dpll_phase = DPLL_PHASE_5;
2097 channel->dpll_ctrl_n = DPLL_CTRL_5;
2098 channel->dpll_phase_pull_in = DPLL_PHASE_PULL_IN_5;
2099 break;
2100 case 6:
2101 channel->dpll_freq = DPLL_FREQ_6;
2102 channel->dpll_n = DPLL_6;
2103 channel->hw_dpll_n = HW_DPLL_6;
2104 channel->dpll_phase = DPLL_PHASE_6;
2105 channel->dpll_ctrl_n = DPLL_CTRL_6;
2106 channel->dpll_phase_pull_in = DPLL_PHASE_PULL_IN_6;
2107 break;
2108 case 7:
2109 channel->dpll_freq = DPLL_FREQ_7;
2110 channel->dpll_n = DPLL_7;
2111 channel->hw_dpll_n = HW_DPLL_7;
2112 channel->dpll_phase = DPLL_PHASE_7;
2113 channel->dpll_ctrl_n = DPLL_CTRL_7;
2114 channel->dpll_phase_pull_in = DPLL_PHASE_PULL_IN_7;
2115 break;
2116 default:
2117 err = -EINVAL;
2118 }
2119
2120 return err;
2121}
2122
2123static int idtcm_enable_channel(struct idtcm *idtcm, u32 index)
2124{
2125 struct idtcm_channel *channel;
2126 int err;
2127
2128 if (!(index < MAX_TOD))
2129 return -EINVAL;
2130
2131 channel = &idtcm->channel[index];
2132
2133 /* Set pll addresses */
2134 err = configure_channel_pll(channel);
2135 if (err)
2136 return err;
2137
2138 /* Set tod addresses */
2139 switch (index) {
2140 case 0:
2141 channel->tod_read_primary = TOD_READ_PRIMARY_0;
2142 channel->tod_write = TOD_WRITE_0;
2143 channel->tod_n = TOD_0;
2144 break;
2145 case 1:
2146 channel->tod_read_primary = TOD_READ_PRIMARY_1;
2147 channel->tod_write = TOD_WRITE_1;
2148 channel->tod_n = TOD_1;
2149 break;
2150 case 2:
2151 channel->tod_read_primary = TOD_READ_PRIMARY_2;
2152 channel->tod_write = TOD_WRITE_2;
2153 channel->tod_n = TOD_2;
2154 break;
2155 case 3:
2156 channel->tod_read_primary = TOD_READ_PRIMARY_3;
2157 channel->tod_write = TOD_WRITE_3;
2158 channel->tod_n = TOD_3;
2159 break;
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04002160 default:
2161 return -EINVAL;
2162 }
2163
2164 channel->idtcm = idtcm;
2165
Min Lida948232020-12-08 10:41:57 -05002166 if (idtcm->deprecated)
2167 channel->caps = idtcm_caps_deprecated;
Min Li7ea5fda2020-07-28 16:00:30 -04002168 else
2169 channel->caps = idtcm_caps;
2170
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04002171 snprintf(channel->caps.name, sizeof(channel->caps.name),
Min Li7ea5fda2020-07-28 16:00:30 -04002172 "IDT CM TOD%u", index);
2173
Min Lida948232020-12-08 10:41:57 -05002174 if (!idtcm->deprecated) {
Min Li7ea5fda2020-07-28 16:00:30 -04002175 err = idtcm_enable_tod_sync(channel);
2176 if (err) {
2177 dev_err(&idtcm->client->dev,
Vincent Cheng1c49d3e2021-02-17 00:42:15 -05002178 "Failed at line %d in %s!", __LINE__, __func__);
Min Li7ea5fda2020-07-28 16:00:30 -04002179 return err;
2180 }
2181 }
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04002182
Min Li7260d1c2020-12-08 10:41:56 -05002183 /* Sync pll mode with hardware */
2184 err = idtcm_get_pll_mode(channel, &channel->pll_mode);
Min Li7ea5fda2020-07-28 16:00:30 -04002185 if (err) {
2186 dev_err(&idtcm->client->dev,
Vincent Cheng1c49d3e2021-02-17 00:42:15 -05002187 "Error: %s - Unable to read pll mode", __func__);
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04002188 return err;
Min Li7ea5fda2020-07-28 16:00:30 -04002189 }
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04002190
2191 err = idtcm_enable_tod(channel);
Min Li7ea5fda2020-07-28 16:00:30 -04002192 if (err) {
2193 dev_err(&idtcm->client->dev,
Vincent Cheng1c49d3e2021-02-17 00:42:15 -05002194 "Failed at line %d in %s!", __LINE__, __func__);
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04002195 return err;
Min Li7ea5fda2020-07-28 16:00:30 -04002196 }
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04002197
2198 channel->ptp_clock = ptp_clock_register(&channel->caps, NULL);
2199
2200 if (IS_ERR(channel->ptp_clock)) {
2201 err = PTR_ERR(channel->ptp_clock);
2202 channel->ptp_clock = NULL;
2203 return err;
2204 }
2205
2206 if (!channel->ptp_clock)
2207 return -ENOTSUPP;
2208
Vincent Cheng1c49d3e2021-02-17 00:42:15 -05002209 dev_info(&idtcm->client->dev, "PLL%d registered as ptp%d",
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04002210 index, channel->ptp_clock->index);
2211
2212 return 0;
2213}
2214
2215static void ptp_clock_unregister_all(struct idtcm *idtcm)
2216{
2217 u8 i;
2218 struct idtcm_channel *channel;
2219
Min Li7ea5fda2020-07-28 16:00:30 -04002220 for (i = 0; i < MAX_TOD; i++) {
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04002221
2222 channel = &idtcm->channel[i];
2223
2224 if (channel->ptp_clock)
2225 ptp_clock_unregister(channel->ptp_clock);
2226 }
2227}
2228
2229static void set_default_masks(struct idtcm *idtcm)
2230{
Min Li7ea5fda2020-07-28 16:00:30 -04002231 idtcm->tod_mask = DEFAULT_TOD_MASK;
2232
2233 idtcm->channel[0].pll = DEFAULT_TOD0_PTP_PLL;
2234 idtcm->channel[1].pll = DEFAULT_TOD1_PTP_PLL;
2235 idtcm->channel[2].pll = DEFAULT_TOD2_PTP_PLL;
2236 idtcm->channel[3].pll = DEFAULT_TOD3_PTP_PLL;
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04002237
2238 idtcm->channel[0].output_mask = DEFAULT_OUTPUT_MASK_PLL0;
2239 idtcm->channel[1].output_mask = DEFAULT_OUTPUT_MASK_PLL1;
2240 idtcm->channel[2].output_mask = DEFAULT_OUTPUT_MASK_PLL2;
2241 idtcm->channel[3].output_mask = DEFAULT_OUTPUT_MASK_PLL3;
2242}
2243
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04002244static int idtcm_probe(struct i2c_client *client,
2245 const struct i2c_device_id *id)
2246{
2247 struct idtcm *idtcm;
2248 int err;
2249 u8 i;
2250
2251 /* Unused for now */
2252 (void)id;
2253
2254 idtcm = devm_kzalloc(&client->dev, sizeof(struct idtcm), GFP_KERNEL);
2255
2256 if (!idtcm)
2257 return -ENOMEM;
2258
2259 idtcm->client = client;
2260 idtcm->page_offset = 0xff;
2261 idtcm->calculate_overhead_flag = 0;
2262
2263 set_default_masks(idtcm);
2264
2265 mutex_init(&idtcm->reg_lock);
2266 mutex_lock(&idtcm->reg_lock);
2267
Min Lida948232020-12-08 10:41:57 -05002268 idtcm_set_version_info(idtcm);
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04002269
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04002270 err = idtcm_load_firmware(idtcm, &client->dev);
2271
2272 if (err)
2273 dev_warn(&idtcm->client->dev,
Vincent Cheng1c49d3e2021-02-17 00:42:15 -05002274 "loading firmware failed with %d", err);
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04002275
Vincent Cheng797d3182021-02-17 00:42:12 -05002276 wait_for_chip_ready(idtcm);
Min Li251f4fe2020-12-08 10:41:54 -05002277
Min Li7ea5fda2020-07-28 16:00:30 -04002278 if (idtcm->tod_mask) {
2279 for (i = 0; i < MAX_TOD; i++) {
2280 if (idtcm->tod_mask & (1 << i)) {
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04002281 err = idtcm_enable_channel(idtcm, i);
Min Li7ea5fda2020-07-28 16:00:30 -04002282 if (err) {
2283 dev_err(&idtcm->client->dev,
Vincent Cheng1c49d3e2021-02-17 00:42:15 -05002284 "idtcm_enable_channel %d failed!", i);
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04002285 break;
Min Li7ea5fda2020-07-28 16:00:30 -04002286 }
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04002287 }
2288 }
2289 } else {
2290 dev_err(&idtcm->client->dev,
Vincent Cheng1c49d3e2021-02-17 00:42:15 -05002291 "no PLLs flagged as PHCs, nothing to do");
Vincent Cheng3a6ba7d2019-10-31 23:20:07 -04002292 err = -ENODEV;
2293 }
2294
2295 mutex_unlock(&idtcm->reg_lock);
2296
2297 if (err) {
2298 ptp_clock_unregister_all(idtcm);
2299 return err;
2300 }
2301
2302 i2c_set_clientdata(client, idtcm);
2303
2304 return 0;
2305}
2306
2307static int idtcm_remove(struct i2c_client *client)
2308{
2309 struct idtcm *idtcm = i2c_get_clientdata(client);
2310
2311 ptp_clock_unregister_all(idtcm);
2312
2313 mutex_destroy(&idtcm->reg_lock);
2314
2315 return 0;
2316}
2317
2318#ifdef CONFIG_OF
2319static const struct of_device_id idtcm_dt_id[] = {
2320 { .compatible = "idt,8a34000" },
2321 { .compatible = "idt,8a34001" },
2322 { .compatible = "idt,8a34002" },
2323 { .compatible = "idt,8a34003" },
2324 { .compatible = "idt,8a34004" },
2325 { .compatible = "idt,8a34005" },
2326 { .compatible = "idt,8a34006" },
2327 { .compatible = "idt,8a34007" },
2328 { .compatible = "idt,8a34008" },
2329 { .compatible = "idt,8a34009" },
2330 { .compatible = "idt,8a34010" },
2331 { .compatible = "idt,8a34011" },
2332 { .compatible = "idt,8a34012" },
2333 { .compatible = "idt,8a34013" },
2334 { .compatible = "idt,8a34014" },
2335 { .compatible = "idt,8a34015" },
2336 { .compatible = "idt,8a34016" },
2337 { .compatible = "idt,8a34017" },
2338 { .compatible = "idt,8a34018" },
2339 { .compatible = "idt,8a34019" },
2340 { .compatible = "idt,8a34040" },
2341 { .compatible = "idt,8a34041" },
2342 { .compatible = "idt,8a34042" },
2343 { .compatible = "idt,8a34043" },
2344 { .compatible = "idt,8a34044" },
2345 { .compatible = "idt,8a34045" },
2346 { .compatible = "idt,8a34046" },
2347 { .compatible = "idt,8a34047" },
2348 { .compatible = "idt,8a34048" },
2349 { .compatible = "idt,8a34049" },
2350 {},
2351};
2352MODULE_DEVICE_TABLE(of, idtcm_dt_id);
2353#endif
2354
2355static const struct i2c_device_id idtcm_i2c_id[] = {
2356 { "8a34000" },
2357 { "8a34001" },
2358 { "8a34002" },
2359 { "8a34003" },
2360 { "8a34004" },
2361 { "8a34005" },
2362 { "8a34006" },
2363 { "8a34007" },
2364 { "8a34008" },
2365 { "8a34009" },
2366 { "8a34010" },
2367 { "8a34011" },
2368 { "8a34012" },
2369 { "8a34013" },
2370 { "8a34014" },
2371 { "8a34015" },
2372 { "8a34016" },
2373 { "8a34017" },
2374 { "8a34018" },
2375 { "8a34019" },
2376 { "8a34040" },
2377 { "8a34041" },
2378 { "8a34042" },
2379 { "8a34043" },
2380 { "8a34044" },
2381 { "8a34045" },
2382 { "8a34046" },
2383 { "8a34047" },
2384 { "8a34048" },
2385 { "8a34049" },
2386 {},
2387};
2388MODULE_DEVICE_TABLE(i2c, idtcm_i2c_id);
2389
2390static struct i2c_driver idtcm_driver = {
2391 .driver = {
2392 .of_match_table = of_match_ptr(idtcm_dt_id),
2393 .name = "idtcm",
2394 },
2395 .probe = idtcm_probe,
2396 .remove = idtcm_remove,
2397 .id_table = idtcm_i2c_id,
2398};
2399
2400module_i2c_driver(idtcm_driver);