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