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