162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// Copyright (C) 2018 Integrated Device Technology, Inc 462306a36Sopenharmony_ci// 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#define pr_fmt(fmt) "IDT_82p33xxx: " fmt 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/firmware.h> 962306a36Sopenharmony_ci#include <linux/platform_device.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/ptp_clock_kernel.h> 1262306a36Sopenharmony_ci#include <linux/delay.h> 1362306a36Sopenharmony_ci#include <linux/jiffies.h> 1462306a36Sopenharmony_ci#include <linux/kernel.h> 1562306a36Sopenharmony_ci#include <linux/timekeeping.h> 1662306a36Sopenharmony_ci#include <linux/bitops.h> 1762306a36Sopenharmony_ci#include <linux/of.h> 1862306a36Sopenharmony_ci#include <linux/mfd/rsmu.h> 1962306a36Sopenharmony_ci#include <linux/mfd/idt82p33_reg.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include "ptp_private.h" 2262306a36Sopenharmony_ci#include "ptp_idt82p33.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ciMODULE_DESCRIPTION("Driver for IDT 82p33xxx clock devices"); 2562306a36Sopenharmony_ciMODULE_AUTHOR("IDT support-1588 <IDT-support-1588@lm.renesas.com>"); 2662306a36Sopenharmony_ciMODULE_VERSION("1.0"); 2762306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2862306a36Sopenharmony_ciMODULE_FIRMWARE(FW_FILENAME); 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define EXTTS_PERIOD_MS (95) 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* Module Parameters */ 3362306a36Sopenharmony_cistatic u32 phase_snap_threshold = SNAP_THRESHOLD_NS; 3462306a36Sopenharmony_cimodule_param(phase_snap_threshold, uint, 0); 3562306a36Sopenharmony_ciMODULE_PARM_DESC(phase_snap_threshold, 3662306a36Sopenharmony_ci"threshold (10000ns by default) below which adjtime would use double dco"); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic char *firmware; 3962306a36Sopenharmony_cimodule_param(firmware, charp, 0); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic struct ptp_pin_desc pin_config[MAX_PHC_PLL][MAX_TRIG_CLK]; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic inline int idt82p33_read(struct idt82p33 *idt82p33, u16 regaddr, 4462306a36Sopenharmony_ci u8 *buf, u16 count) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci return regmap_bulk_read(idt82p33->regmap, regaddr, buf, count); 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic inline int idt82p33_write(struct idt82p33 *idt82p33, u16 regaddr, 5062306a36Sopenharmony_ci u8 *buf, u16 count) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci return regmap_bulk_write(idt82p33->regmap, regaddr, buf, count); 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic void idt82p33_byte_array_to_timespec(struct timespec64 *ts, 5662306a36Sopenharmony_ci u8 buf[TOD_BYTE_COUNT]) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci time64_t sec; 5962306a36Sopenharmony_ci s32 nsec; 6062306a36Sopenharmony_ci u8 i; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci nsec = buf[3]; 6362306a36Sopenharmony_ci for (i = 0; i < 3; i++) { 6462306a36Sopenharmony_ci nsec <<= 8; 6562306a36Sopenharmony_ci nsec |= buf[2 - i]; 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci sec = buf[9]; 6962306a36Sopenharmony_ci for (i = 0; i < 5; i++) { 7062306a36Sopenharmony_ci sec <<= 8; 7162306a36Sopenharmony_ci sec |= buf[8 - i]; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci ts->tv_sec = sec; 7562306a36Sopenharmony_ci ts->tv_nsec = nsec; 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic void idt82p33_timespec_to_byte_array(struct timespec64 const *ts, 7962306a36Sopenharmony_ci u8 buf[TOD_BYTE_COUNT]) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci time64_t sec; 8262306a36Sopenharmony_ci s32 nsec; 8362306a36Sopenharmony_ci u8 i; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci nsec = ts->tv_nsec; 8662306a36Sopenharmony_ci sec = ts->tv_sec; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 8962306a36Sopenharmony_ci buf[i] = nsec & 0xff; 9062306a36Sopenharmony_ci nsec >>= 8; 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci for (i = 4; i < TOD_BYTE_COUNT; i++) { 9462306a36Sopenharmony_ci buf[i] = sec & 0xff; 9562306a36Sopenharmony_ci sec >>= 8; 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic int idt82p33_dpll_set_mode(struct idt82p33_channel *channel, 10062306a36Sopenharmony_ci enum pll_mode mode) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci struct idt82p33 *idt82p33 = channel->idt82p33; 10362306a36Sopenharmony_ci u8 dpll_mode; 10462306a36Sopenharmony_ci int err; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (channel->pll_mode == mode) 10762306a36Sopenharmony_ci return 0; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci err = idt82p33_read(idt82p33, channel->dpll_mode_cnfg, 11062306a36Sopenharmony_ci &dpll_mode, sizeof(dpll_mode)); 11162306a36Sopenharmony_ci if (err) 11262306a36Sopenharmony_ci return err; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci dpll_mode &= ~(PLL_MODE_MASK << PLL_MODE_SHIFT); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci dpll_mode |= (mode << PLL_MODE_SHIFT); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci err = idt82p33_write(idt82p33, channel->dpll_mode_cnfg, 11962306a36Sopenharmony_ci &dpll_mode, sizeof(dpll_mode)); 12062306a36Sopenharmony_ci if (err) 12162306a36Sopenharmony_ci return err; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci channel->pll_mode = mode; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci return 0; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic int idt82p33_set_tod_trigger(struct idt82p33_channel *channel, 12962306a36Sopenharmony_ci u8 trigger, bool write) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci struct idt82p33 *idt82p33 = channel->idt82p33; 13262306a36Sopenharmony_ci int err; 13362306a36Sopenharmony_ci u8 cfg; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (trigger > WR_TRIG_SEL_MAX) 13662306a36Sopenharmony_ci return -EINVAL; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci err = idt82p33_read(idt82p33, channel->dpll_tod_trigger, 13962306a36Sopenharmony_ci &cfg, sizeof(cfg)); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci if (err) 14262306a36Sopenharmony_ci return err; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci if (write == true) 14562306a36Sopenharmony_ci trigger = (trigger << WRITE_TRIGGER_SHIFT) | 14662306a36Sopenharmony_ci (cfg & READ_TRIGGER_MASK); 14762306a36Sopenharmony_ci else 14862306a36Sopenharmony_ci trigger = (trigger << READ_TRIGGER_SHIFT) | 14962306a36Sopenharmony_ci (cfg & WRITE_TRIGGER_MASK); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci return idt82p33_write(idt82p33, channel->dpll_tod_trigger, 15262306a36Sopenharmony_ci &trigger, sizeof(trigger)); 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic int idt82p33_get_extts(struct idt82p33_channel *channel, 15662306a36Sopenharmony_ci struct timespec64 *ts) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci struct idt82p33 *idt82p33 = channel->idt82p33; 15962306a36Sopenharmony_ci u8 buf[TOD_BYTE_COUNT]; 16062306a36Sopenharmony_ci int err; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci err = idt82p33_read(idt82p33, channel->dpll_tod_sts, buf, sizeof(buf)); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci if (err) 16562306a36Sopenharmony_ci return err; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci /* Since trigger is not self clearing itself, we have to poll tod_sts */ 16862306a36Sopenharmony_ci if (memcmp(buf, channel->extts_tod_sts, TOD_BYTE_COUNT) == 0) 16962306a36Sopenharmony_ci return -EAGAIN; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci memcpy(channel->extts_tod_sts, buf, TOD_BYTE_COUNT); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci idt82p33_byte_array_to_timespec(ts, buf); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci if (channel->discard_next_extts) { 17662306a36Sopenharmony_ci channel->discard_next_extts = false; 17762306a36Sopenharmony_ci return -EAGAIN; 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci return 0; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic int map_ref_to_tod_trig_sel(int ref, u8 *trigger) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci int err = 0; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci switch (ref) { 18862306a36Sopenharmony_ci case 0: 18962306a36Sopenharmony_ci *trigger = HW_TOD_TRIG_SEL_IN12; 19062306a36Sopenharmony_ci break; 19162306a36Sopenharmony_ci case 1: 19262306a36Sopenharmony_ci *trigger = HW_TOD_TRIG_SEL_IN13; 19362306a36Sopenharmony_ci break; 19462306a36Sopenharmony_ci case 2: 19562306a36Sopenharmony_ci *trigger = HW_TOD_TRIG_SEL_IN14; 19662306a36Sopenharmony_ci break; 19762306a36Sopenharmony_ci default: 19862306a36Sopenharmony_ci err = -EINVAL; 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci return err; 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic bool is_one_shot(u8 mask) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci /* Treat single bit PLL masks as continuous trigger */ 20762306a36Sopenharmony_ci if ((mask == 1) || (mask == 2)) 20862306a36Sopenharmony_ci return false; 20962306a36Sopenharmony_ci else 21062306a36Sopenharmony_ci return true; 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistatic int arm_tod_read_with_trigger(struct idt82p33_channel *channel, u8 trigger) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci struct idt82p33 *idt82p33 = channel->idt82p33; 21662306a36Sopenharmony_ci u8 buf[TOD_BYTE_COUNT]; 21762306a36Sopenharmony_ci int err; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci /* Remember the current tod_sts before setting the trigger */ 22062306a36Sopenharmony_ci err = idt82p33_read(idt82p33, channel->dpll_tod_sts, buf, sizeof(buf)); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci if (err) 22362306a36Sopenharmony_ci return err; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci memcpy(channel->extts_tod_sts, buf, TOD_BYTE_COUNT); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci err = idt82p33_set_tod_trigger(channel, trigger, false); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci if (err) 23062306a36Sopenharmony_ci dev_err(idt82p33->dev, "%s: err = %d", __func__, err); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci return err; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic int idt82p33_extts_enable(struct idt82p33_channel *channel, 23662306a36Sopenharmony_ci struct ptp_clock_request *rq, int on) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci u8 index = rq->extts.index; 23962306a36Sopenharmony_ci struct idt82p33 *idt82p33; 24062306a36Sopenharmony_ci u8 mask = 1 << index; 24162306a36Sopenharmony_ci int err = 0; 24262306a36Sopenharmony_ci u8 old_mask; 24362306a36Sopenharmony_ci u8 trigger; 24462306a36Sopenharmony_ci int ref; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci idt82p33 = channel->idt82p33; 24762306a36Sopenharmony_ci old_mask = idt82p33->extts_mask; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci /* Reject requests with unsupported flags */ 25062306a36Sopenharmony_ci if (rq->extts.flags & ~(PTP_ENABLE_FEATURE | 25162306a36Sopenharmony_ci PTP_RISING_EDGE | 25262306a36Sopenharmony_ci PTP_FALLING_EDGE | 25362306a36Sopenharmony_ci PTP_STRICT_FLAGS)) 25462306a36Sopenharmony_ci return -EOPNOTSUPP; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci /* Reject requests to enable time stamping on falling edge */ 25762306a36Sopenharmony_ci if ((rq->extts.flags & PTP_ENABLE_FEATURE) && 25862306a36Sopenharmony_ci (rq->extts.flags & PTP_FALLING_EDGE)) 25962306a36Sopenharmony_ci return -EOPNOTSUPP; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci if (index >= MAX_PHC_PLL) 26262306a36Sopenharmony_ci return -EINVAL; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci if (on) { 26562306a36Sopenharmony_ci /* Return if it was already enabled */ 26662306a36Sopenharmony_ci if (idt82p33->extts_mask & mask) 26762306a36Sopenharmony_ci return 0; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci /* Use the pin configured for the channel */ 27062306a36Sopenharmony_ci ref = ptp_find_pin(channel->ptp_clock, PTP_PF_EXTTS, channel->plln); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci if (ref < 0) { 27362306a36Sopenharmony_ci dev_err(idt82p33->dev, "%s: No valid pin found for Pll%d!\n", 27462306a36Sopenharmony_ci __func__, channel->plln); 27562306a36Sopenharmony_ci return -EBUSY; 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci err = map_ref_to_tod_trig_sel(ref, &trigger); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci if (err) { 28162306a36Sopenharmony_ci dev_err(idt82p33->dev, 28262306a36Sopenharmony_ci "%s: Unsupported ref %d!\n", __func__, ref); 28362306a36Sopenharmony_ci return err; 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci err = arm_tod_read_with_trigger(&idt82p33->channel[index], trigger); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci if (err == 0) { 28962306a36Sopenharmony_ci idt82p33->extts_mask |= mask; 29062306a36Sopenharmony_ci idt82p33->channel[index].tod_trigger = trigger; 29162306a36Sopenharmony_ci idt82p33->event_channel[index] = channel; 29262306a36Sopenharmony_ci idt82p33->extts_single_shot = is_one_shot(idt82p33->extts_mask); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci if (old_mask) 29562306a36Sopenharmony_ci return 0; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci schedule_delayed_work(&idt82p33->extts_work, 29862306a36Sopenharmony_ci msecs_to_jiffies(EXTTS_PERIOD_MS)); 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci } else { 30162306a36Sopenharmony_ci idt82p33->extts_mask &= ~mask; 30262306a36Sopenharmony_ci idt82p33->extts_single_shot = is_one_shot(idt82p33->extts_mask); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (idt82p33->extts_mask == 0) 30562306a36Sopenharmony_ci cancel_delayed_work(&idt82p33->extts_work); 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci return err; 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic int idt82p33_extts_check_channel(struct idt82p33 *idt82p33, u8 todn) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci struct idt82p33_channel *event_channel; 31462306a36Sopenharmony_ci struct ptp_clock_event event; 31562306a36Sopenharmony_ci struct timespec64 ts; 31662306a36Sopenharmony_ci int err; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci err = idt82p33_get_extts(&idt82p33->channel[todn], &ts); 31962306a36Sopenharmony_ci if (err == 0) { 32062306a36Sopenharmony_ci event_channel = idt82p33->event_channel[todn]; 32162306a36Sopenharmony_ci event.type = PTP_CLOCK_EXTTS; 32262306a36Sopenharmony_ci event.index = todn; 32362306a36Sopenharmony_ci event.timestamp = timespec64_to_ns(&ts); 32462306a36Sopenharmony_ci ptp_clock_event(event_channel->ptp_clock, 32562306a36Sopenharmony_ci &event); 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci return err; 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_cistatic u8 idt82p33_extts_enable_mask(struct idt82p33_channel *channel, 33162306a36Sopenharmony_ci u8 extts_mask, bool enable) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci struct idt82p33 *idt82p33 = channel->idt82p33; 33462306a36Sopenharmony_ci u8 trigger = channel->tod_trigger; 33562306a36Sopenharmony_ci u8 mask; 33662306a36Sopenharmony_ci int err; 33762306a36Sopenharmony_ci int i; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci if (extts_mask == 0) 34062306a36Sopenharmony_ci return 0; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci if (enable == false) 34362306a36Sopenharmony_ci cancel_delayed_work_sync(&idt82p33->extts_work); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci for (i = 0; i < MAX_PHC_PLL; i++) { 34662306a36Sopenharmony_ci mask = 1 << i; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci if ((extts_mask & mask) == 0) 34962306a36Sopenharmony_ci continue; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci if (enable) { 35262306a36Sopenharmony_ci err = arm_tod_read_with_trigger(&idt82p33->channel[i], trigger); 35362306a36Sopenharmony_ci if (err) 35462306a36Sopenharmony_ci dev_err(idt82p33->dev, 35562306a36Sopenharmony_ci "%s: Arm ToD read trigger failed, err = %d", 35662306a36Sopenharmony_ci __func__, err); 35762306a36Sopenharmony_ci } else { 35862306a36Sopenharmony_ci err = idt82p33_extts_check_channel(idt82p33, i); 35962306a36Sopenharmony_ci if (err == 0 && idt82p33->extts_single_shot) 36062306a36Sopenharmony_ci /* trigger happened so we won't re-enable it */ 36162306a36Sopenharmony_ci extts_mask &= ~mask; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci if (enable) 36662306a36Sopenharmony_ci schedule_delayed_work(&idt82p33->extts_work, 36762306a36Sopenharmony_ci msecs_to_jiffies(EXTTS_PERIOD_MS)); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci return extts_mask; 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic int _idt82p33_gettime(struct idt82p33_channel *channel, 37362306a36Sopenharmony_ci struct timespec64 *ts) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci struct idt82p33 *idt82p33 = channel->idt82p33; 37662306a36Sopenharmony_ci u8 old_mask = idt82p33->extts_mask; 37762306a36Sopenharmony_ci u8 buf[TOD_BYTE_COUNT]; 37862306a36Sopenharmony_ci u8 new_mask = 0; 37962306a36Sopenharmony_ci int err; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci /* Disable extts */ 38262306a36Sopenharmony_ci if (old_mask) 38362306a36Sopenharmony_ci new_mask = idt82p33_extts_enable_mask(channel, old_mask, false); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci err = idt82p33_set_tod_trigger(channel, HW_TOD_RD_TRIG_SEL_LSB_TOD_STS, 38662306a36Sopenharmony_ci false); 38762306a36Sopenharmony_ci if (err) 38862306a36Sopenharmony_ci return err; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci channel->discard_next_extts = true; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci if (idt82p33->calculate_overhead_flag) 39362306a36Sopenharmony_ci idt82p33->start_time = ktime_get_raw(); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci err = idt82p33_read(idt82p33, channel->dpll_tod_sts, buf, sizeof(buf)); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci if (err) 39862306a36Sopenharmony_ci return err; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci /* Re-enable extts */ 40162306a36Sopenharmony_ci if (new_mask) 40262306a36Sopenharmony_ci idt82p33_extts_enable_mask(channel, new_mask, true); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci idt82p33_byte_array_to_timespec(ts, buf); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci return 0; 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci/* 41062306a36Sopenharmony_ci * TOD Trigger: 41162306a36Sopenharmony_ci * Bits[7:4] Write 0x9, MSB write 41262306a36Sopenharmony_ci * Bits[3:0] Read 0x9, LSB read 41362306a36Sopenharmony_ci */ 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic int _idt82p33_settime(struct idt82p33_channel *channel, 41662306a36Sopenharmony_ci struct timespec64 const *ts) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci struct idt82p33 *idt82p33 = channel->idt82p33; 41962306a36Sopenharmony_ci struct timespec64 local_ts = *ts; 42062306a36Sopenharmony_ci char buf[TOD_BYTE_COUNT]; 42162306a36Sopenharmony_ci s64 dynamic_overhead_ns; 42262306a36Sopenharmony_ci int err; 42362306a36Sopenharmony_ci u8 i; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci err = idt82p33_set_tod_trigger(channel, HW_TOD_WR_TRIG_SEL_MSB_TOD_CNFG, 42662306a36Sopenharmony_ci true); 42762306a36Sopenharmony_ci if (err) 42862306a36Sopenharmony_ci return err; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci channel->discard_next_extts = true; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci if (idt82p33->calculate_overhead_flag) { 43362306a36Sopenharmony_ci dynamic_overhead_ns = ktime_to_ns(ktime_get_raw()) 43462306a36Sopenharmony_ci - ktime_to_ns(idt82p33->start_time); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci timespec64_add_ns(&local_ts, dynamic_overhead_ns); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci idt82p33->calculate_overhead_flag = 0; 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci idt82p33_timespec_to_byte_array(&local_ts, buf); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci /* 44462306a36Sopenharmony_ci * Store the new time value. 44562306a36Sopenharmony_ci */ 44662306a36Sopenharmony_ci for (i = 0; i < TOD_BYTE_COUNT; i++) { 44762306a36Sopenharmony_ci err = idt82p33_write(idt82p33, channel->dpll_tod_cnfg + i, 44862306a36Sopenharmony_ci &buf[i], sizeof(buf[i])); 44962306a36Sopenharmony_ci if (err) 45062306a36Sopenharmony_ci return err; 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci return err; 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_cistatic int _idt82p33_adjtime_immediate(struct idt82p33_channel *channel, 45762306a36Sopenharmony_ci s64 delta_ns) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci struct idt82p33 *idt82p33 = channel->idt82p33; 46062306a36Sopenharmony_ci struct timespec64 ts; 46162306a36Sopenharmony_ci s64 now_ns; 46262306a36Sopenharmony_ci int err; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci idt82p33->calculate_overhead_flag = 1; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci err = _idt82p33_gettime(channel, &ts); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci if (err) 46962306a36Sopenharmony_ci return err; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci now_ns = timespec64_to_ns(&ts); 47262306a36Sopenharmony_ci now_ns += delta_ns + idt82p33->tod_write_overhead_ns; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci ts = ns_to_timespec64(now_ns); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci err = _idt82p33_settime(channel, &ts); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci return err; 47962306a36Sopenharmony_ci} 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_cistatic int _idt82p33_adjtime_internal_triggered(struct idt82p33_channel *channel, 48262306a36Sopenharmony_ci s64 delta_ns) 48362306a36Sopenharmony_ci{ 48462306a36Sopenharmony_ci struct idt82p33 *idt82p33 = channel->idt82p33; 48562306a36Sopenharmony_ci char buf[TOD_BYTE_COUNT]; 48662306a36Sopenharmony_ci struct timespec64 ts; 48762306a36Sopenharmony_ci const u8 delay_ns = 32; 48862306a36Sopenharmony_ci s32 remainder; 48962306a36Sopenharmony_ci s64 ns; 49062306a36Sopenharmony_ci int err; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci err = _idt82p33_gettime(channel, &ts); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci if (err) 49562306a36Sopenharmony_ci return err; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci if (ts.tv_nsec > (NSEC_PER_SEC - 5 * NSEC_PER_MSEC)) { 49862306a36Sopenharmony_ci /* Too close to miss next trigger, so skip it */ 49962306a36Sopenharmony_ci mdelay(6); 50062306a36Sopenharmony_ci ns = (ts.tv_sec + 2) * NSEC_PER_SEC + delta_ns + delay_ns; 50162306a36Sopenharmony_ci } else 50262306a36Sopenharmony_ci ns = (ts.tv_sec + 1) * NSEC_PER_SEC + delta_ns + delay_ns; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci ts = ns_to_timespec64(ns); 50562306a36Sopenharmony_ci idt82p33_timespec_to_byte_array(&ts, buf); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci /* 50862306a36Sopenharmony_ci * Store the new time value. 50962306a36Sopenharmony_ci */ 51062306a36Sopenharmony_ci err = idt82p33_write(idt82p33, channel->dpll_tod_cnfg, buf, sizeof(buf)); 51162306a36Sopenharmony_ci if (err) 51262306a36Sopenharmony_ci return err; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci /* Schedule to implement the workaround in one second */ 51562306a36Sopenharmony_ci (void)div_s64_rem(delta_ns, NSEC_PER_SEC, &remainder); 51662306a36Sopenharmony_ci if (remainder != 0) 51762306a36Sopenharmony_ci schedule_delayed_work(&channel->adjtime_work, HZ); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci return idt82p33_set_tod_trigger(channel, HW_TOD_TRIG_SEL_TOD_PPS, true); 52062306a36Sopenharmony_ci} 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_cistatic void idt82p33_adjtime_workaround(struct work_struct *work) 52362306a36Sopenharmony_ci{ 52462306a36Sopenharmony_ci struct idt82p33_channel *channel = container_of(work, 52562306a36Sopenharmony_ci struct idt82p33_channel, 52662306a36Sopenharmony_ci adjtime_work.work); 52762306a36Sopenharmony_ci struct idt82p33 *idt82p33 = channel->idt82p33; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci mutex_lock(idt82p33->lock); 53062306a36Sopenharmony_ci /* Workaround for TOD-to-output alignment issue */ 53162306a36Sopenharmony_ci _idt82p33_adjtime_internal_triggered(channel, 0); 53262306a36Sopenharmony_ci mutex_unlock(idt82p33->lock); 53362306a36Sopenharmony_ci} 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_cistatic int _idt82p33_adjfine(struct idt82p33_channel *channel, long scaled_ppm) 53662306a36Sopenharmony_ci{ 53762306a36Sopenharmony_ci struct idt82p33 *idt82p33 = channel->idt82p33; 53862306a36Sopenharmony_ci unsigned char buf[5] = {0}; 53962306a36Sopenharmony_ci int err, i; 54062306a36Sopenharmony_ci s64 fcw; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci /* 54362306a36Sopenharmony_ci * Frequency Control Word unit is: 1.6861512 * 10^-10 ppm 54462306a36Sopenharmony_ci * 54562306a36Sopenharmony_ci * adjfreq: 54662306a36Sopenharmony_ci * ppb * 10^14 54762306a36Sopenharmony_ci * FCW = ----------- 54862306a36Sopenharmony_ci * 16861512 54962306a36Sopenharmony_ci * 55062306a36Sopenharmony_ci * adjfine: 55162306a36Sopenharmony_ci * scaled_ppm * 5^12 * 10^5 55262306a36Sopenharmony_ci * FCW = ------------------------ 55362306a36Sopenharmony_ci * 16861512 * 2^4 55462306a36Sopenharmony_ci */ 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci fcw = scaled_ppm * 762939453125ULL; 55762306a36Sopenharmony_ci fcw = div_s64(fcw, 8430756LL); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci for (i = 0; i < 5; i++) { 56062306a36Sopenharmony_ci buf[i] = fcw & 0xff; 56162306a36Sopenharmony_ci fcw >>= 8; 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci err = idt82p33_dpll_set_mode(channel, PLL_MODE_DCO); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci if (err) 56762306a36Sopenharmony_ci return err; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci err = idt82p33_write(idt82p33, channel->dpll_freq_cnfg, 57062306a36Sopenharmony_ci buf, sizeof(buf)); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci return err; 57362306a36Sopenharmony_ci} 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci/* ppb = scaled_ppm * 125 / 2^13 */ 57662306a36Sopenharmony_cistatic s32 idt82p33_ddco_scaled_ppm(long current_ppm, s32 ddco_ppb) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci s64 scaled_ppm = div_s64(((s64)ddco_ppb << 13), 125); 57962306a36Sopenharmony_ci s64 max_scaled_ppm = div_s64(((s64)DCO_MAX_PPB << 13), 125); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci current_ppm += scaled_ppm; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci if (current_ppm > max_scaled_ppm) 58462306a36Sopenharmony_ci current_ppm = max_scaled_ppm; 58562306a36Sopenharmony_ci else if (current_ppm < -max_scaled_ppm) 58662306a36Sopenharmony_ci current_ppm = -max_scaled_ppm; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci return (s32)current_ppm; 58962306a36Sopenharmony_ci} 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_cistatic int idt82p33_stop_ddco(struct idt82p33_channel *channel) 59262306a36Sopenharmony_ci{ 59362306a36Sopenharmony_ci int err; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci err = _idt82p33_adjfine(channel, channel->current_freq); 59662306a36Sopenharmony_ci if (err) 59762306a36Sopenharmony_ci return err; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci channel->ddco = false; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci return 0; 60262306a36Sopenharmony_ci} 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_cistatic int idt82p33_start_ddco(struct idt82p33_channel *channel, s32 delta_ns) 60562306a36Sopenharmony_ci{ 60662306a36Sopenharmony_ci s32 current_ppm = channel->current_freq; 60762306a36Sopenharmony_ci u32 duration_ms = MSEC_PER_SEC; 60862306a36Sopenharmony_ci s32 ppb; 60962306a36Sopenharmony_ci int err; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci /* If the ToD correction is less than 5 nanoseconds, then skip it. 61262306a36Sopenharmony_ci * The error introduced by the ToD adjustment procedure would be bigger 61362306a36Sopenharmony_ci * than the required ToD correction 61462306a36Sopenharmony_ci */ 61562306a36Sopenharmony_ci if (abs(delta_ns) < DDCO_THRESHOLD_NS) 61662306a36Sopenharmony_ci return 0; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci /* For most cases, keep ddco duration 1 second */ 61962306a36Sopenharmony_ci ppb = delta_ns; 62062306a36Sopenharmony_ci while (abs(ppb) > DCO_MAX_PPB) { 62162306a36Sopenharmony_ci duration_ms *= 2; 62262306a36Sopenharmony_ci ppb /= 2; 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci err = _idt82p33_adjfine(channel, 62662306a36Sopenharmony_ci idt82p33_ddco_scaled_ppm(current_ppm, ppb)); 62762306a36Sopenharmony_ci if (err) 62862306a36Sopenharmony_ci return err; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci /* schedule the worker to cancel ddco */ 63162306a36Sopenharmony_ci ptp_schedule_worker(channel->ptp_clock, 63262306a36Sopenharmony_ci msecs_to_jiffies(duration_ms) - 1); 63362306a36Sopenharmony_ci channel->ddco = true; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci return 0; 63662306a36Sopenharmony_ci} 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_cistatic int idt82p33_measure_one_byte_write_overhead( 63962306a36Sopenharmony_ci struct idt82p33_channel *channel, s64 *overhead_ns) 64062306a36Sopenharmony_ci{ 64162306a36Sopenharmony_ci struct idt82p33 *idt82p33 = channel->idt82p33; 64262306a36Sopenharmony_ci ktime_t start, stop; 64362306a36Sopenharmony_ci u8 trigger = 0; 64462306a36Sopenharmony_ci s64 total_ns; 64562306a36Sopenharmony_ci int err; 64662306a36Sopenharmony_ci u8 i; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci total_ns = 0; 64962306a36Sopenharmony_ci *overhead_ns = 0; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci for (i = 0; i < MAX_MEASURMENT_COUNT; i++) { 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci start = ktime_get_raw(); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci err = idt82p33_write(idt82p33, channel->dpll_tod_trigger, 65662306a36Sopenharmony_ci &trigger, sizeof(trigger)); 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci stop = ktime_get_raw(); 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci if (err) 66162306a36Sopenharmony_ci return err; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci total_ns += ktime_to_ns(stop) - ktime_to_ns(start); 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci *overhead_ns = div_s64(total_ns, MAX_MEASURMENT_COUNT); 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci return err; 66962306a36Sopenharmony_ci} 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_cistatic int idt82p33_measure_one_byte_read_overhead( 67262306a36Sopenharmony_ci struct idt82p33_channel *channel, s64 *overhead_ns) 67362306a36Sopenharmony_ci{ 67462306a36Sopenharmony_ci struct idt82p33 *idt82p33 = channel->idt82p33; 67562306a36Sopenharmony_ci ktime_t start, stop; 67662306a36Sopenharmony_ci u8 trigger = 0; 67762306a36Sopenharmony_ci s64 total_ns; 67862306a36Sopenharmony_ci int err; 67962306a36Sopenharmony_ci u8 i; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci total_ns = 0; 68262306a36Sopenharmony_ci *overhead_ns = 0; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci for (i = 0; i < MAX_MEASURMENT_COUNT; i++) { 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci start = ktime_get_raw(); 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci err = idt82p33_read(idt82p33, channel->dpll_tod_trigger, 68962306a36Sopenharmony_ci &trigger, sizeof(trigger)); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci stop = ktime_get_raw(); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci if (err) 69462306a36Sopenharmony_ci return err; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci total_ns += ktime_to_ns(stop) - ktime_to_ns(start); 69762306a36Sopenharmony_ci } 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci *overhead_ns = div_s64(total_ns, MAX_MEASURMENT_COUNT); 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci return err; 70262306a36Sopenharmony_ci} 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_cistatic int idt82p33_measure_tod_write_9_byte_overhead( 70562306a36Sopenharmony_ci struct idt82p33_channel *channel) 70662306a36Sopenharmony_ci{ 70762306a36Sopenharmony_ci struct idt82p33 *idt82p33 = channel->idt82p33; 70862306a36Sopenharmony_ci u8 buf[TOD_BYTE_COUNT]; 70962306a36Sopenharmony_ci ktime_t start, stop; 71062306a36Sopenharmony_ci s64 total_ns; 71162306a36Sopenharmony_ci int err = 0; 71262306a36Sopenharmony_ci u8 i, j; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci total_ns = 0; 71562306a36Sopenharmony_ci idt82p33->tod_write_overhead_ns = 0; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci for (i = 0; i < MAX_MEASURMENT_COUNT; i++) { 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci start = ktime_get_raw(); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci /* Need one less byte for applicable overhead */ 72262306a36Sopenharmony_ci for (j = 0; j < (TOD_BYTE_COUNT - 1); j++) { 72362306a36Sopenharmony_ci err = idt82p33_write(idt82p33, 72462306a36Sopenharmony_ci channel->dpll_tod_cnfg + i, 72562306a36Sopenharmony_ci &buf[i], sizeof(buf[i])); 72662306a36Sopenharmony_ci if (err) 72762306a36Sopenharmony_ci return err; 72862306a36Sopenharmony_ci } 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci stop = ktime_get_raw(); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci total_ns += ktime_to_ns(stop) - ktime_to_ns(start); 73362306a36Sopenharmony_ci } 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci idt82p33->tod_write_overhead_ns = div_s64(total_ns, 73662306a36Sopenharmony_ci MAX_MEASURMENT_COUNT); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci return err; 73962306a36Sopenharmony_ci} 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_cistatic int idt82p33_measure_settime_gettime_gap_overhead( 74262306a36Sopenharmony_ci struct idt82p33_channel *channel, s64 *overhead_ns) 74362306a36Sopenharmony_ci{ 74462306a36Sopenharmony_ci struct timespec64 ts1 = {0, 0}; 74562306a36Sopenharmony_ci struct timespec64 ts2; 74662306a36Sopenharmony_ci int err; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci *overhead_ns = 0; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci err = _idt82p33_settime(channel, &ts1); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci if (err) 75362306a36Sopenharmony_ci return err; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci err = _idt82p33_gettime(channel, &ts2); 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci if (!err) 75862306a36Sopenharmony_ci *overhead_ns = timespec64_to_ns(&ts2) - timespec64_to_ns(&ts1); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci return err; 76162306a36Sopenharmony_ci} 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_cistatic int idt82p33_measure_tod_write_overhead(struct idt82p33_channel *channel) 76462306a36Sopenharmony_ci{ 76562306a36Sopenharmony_ci s64 trailing_overhead_ns, one_byte_write_ns, gap_ns, one_byte_read_ns; 76662306a36Sopenharmony_ci struct idt82p33 *idt82p33 = channel->idt82p33; 76762306a36Sopenharmony_ci int err; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci idt82p33->tod_write_overhead_ns = 0; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci err = idt82p33_measure_settime_gettime_gap_overhead(channel, &gap_ns); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci if (err) { 77462306a36Sopenharmony_ci dev_err(idt82p33->dev, 77562306a36Sopenharmony_ci "Failed in %s with err %d!\n", __func__, err); 77662306a36Sopenharmony_ci return err; 77762306a36Sopenharmony_ci } 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci err = idt82p33_measure_one_byte_write_overhead(channel, 78062306a36Sopenharmony_ci &one_byte_write_ns); 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci if (err) 78362306a36Sopenharmony_ci return err; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci err = idt82p33_measure_one_byte_read_overhead(channel, 78662306a36Sopenharmony_ci &one_byte_read_ns); 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci if (err) 78962306a36Sopenharmony_ci return err; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci err = idt82p33_measure_tod_write_9_byte_overhead(channel); 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci if (err) 79462306a36Sopenharmony_ci return err; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci trailing_overhead_ns = gap_ns - 2 * one_byte_write_ns 79762306a36Sopenharmony_ci - one_byte_read_ns; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci idt82p33->tod_write_overhead_ns -= trailing_overhead_ns; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci return err; 80262306a36Sopenharmony_ci} 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_cistatic int idt82p33_check_and_set_masks(struct idt82p33 *idt82p33, 80562306a36Sopenharmony_ci u8 page, 80662306a36Sopenharmony_ci u8 offset, 80762306a36Sopenharmony_ci u8 val) 80862306a36Sopenharmony_ci{ 80962306a36Sopenharmony_ci int err = 0; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci if (page == PLLMASK_ADDR_HI && offset == PLLMASK_ADDR_LO) { 81262306a36Sopenharmony_ci if ((val & 0xfc) || !(val & 0x3)) { 81362306a36Sopenharmony_ci dev_err(idt82p33->dev, 81462306a36Sopenharmony_ci "Invalid PLL mask 0x%x\n", val); 81562306a36Sopenharmony_ci err = -EINVAL; 81662306a36Sopenharmony_ci } else { 81762306a36Sopenharmony_ci idt82p33->pll_mask = val; 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci } else if (page == PLL0_OUTMASK_ADDR_HI && 82062306a36Sopenharmony_ci offset == PLL0_OUTMASK_ADDR_LO) { 82162306a36Sopenharmony_ci idt82p33->channel[0].output_mask = val; 82262306a36Sopenharmony_ci } else if (page == PLL1_OUTMASK_ADDR_HI && 82362306a36Sopenharmony_ci offset == PLL1_OUTMASK_ADDR_LO) { 82462306a36Sopenharmony_ci idt82p33->channel[1].output_mask = val; 82562306a36Sopenharmony_ci } 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci return err; 82862306a36Sopenharmony_ci} 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_cistatic void idt82p33_display_masks(struct idt82p33 *idt82p33) 83162306a36Sopenharmony_ci{ 83262306a36Sopenharmony_ci u8 mask, i; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci dev_info(idt82p33->dev, 83562306a36Sopenharmony_ci "pllmask = 0x%02x\n", idt82p33->pll_mask); 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci for (i = 0; i < MAX_PHC_PLL; i++) { 83862306a36Sopenharmony_ci mask = 1 << i; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci if (mask & idt82p33->pll_mask) 84162306a36Sopenharmony_ci dev_info(idt82p33->dev, 84262306a36Sopenharmony_ci "PLL%d output_mask = 0x%04x\n", 84362306a36Sopenharmony_ci i, idt82p33->channel[i].output_mask); 84462306a36Sopenharmony_ci } 84562306a36Sopenharmony_ci} 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_cistatic int idt82p33_sync_tod(struct idt82p33_channel *channel, bool enable) 84862306a36Sopenharmony_ci{ 84962306a36Sopenharmony_ci struct idt82p33 *idt82p33 = channel->idt82p33; 85062306a36Sopenharmony_ci u8 sync_cnfg; 85162306a36Sopenharmony_ci int err; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci err = idt82p33_read(idt82p33, channel->dpll_sync_cnfg, 85462306a36Sopenharmony_ci &sync_cnfg, sizeof(sync_cnfg)); 85562306a36Sopenharmony_ci if (err) 85662306a36Sopenharmony_ci return err; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci sync_cnfg &= ~SYNC_TOD; 85962306a36Sopenharmony_ci if (enable) 86062306a36Sopenharmony_ci sync_cnfg |= SYNC_TOD; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci return idt82p33_write(idt82p33, channel->dpll_sync_cnfg, 86362306a36Sopenharmony_ci &sync_cnfg, sizeof(sync_cnfg)); 86462306a36Sopenharmony_ci} 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_cistatic long idt82p33_work_handler(struct ptp_clock_info *ptp) 86762306a36Sopenharmony_ci{ 86862306a36Sopenharmony_ci struct idt82p33_channel *channel = 86962306a36Sopenharmony_ci container_of(ptp, struct idt82p33_channel, caps); 87062306a36Sopenharmony_ci struct idt82p33 *idt82p33 = channel->idt82p33; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci mutex_lock(idt82p33->lock); 87362306a36Sopenharmony_ci (void)idt82p33_stop_ddco(channel); 87462306a36Sopenharmony_ci mutex_unlock(idt82p33->lock); 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci /* Return a negative value here to not reschedule */ 87762306a36Sopenharmony_ci return -1; 87862306a36Sopenharmony_ci} 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_cistatic int idt82p33_output_enable(struct idt82p33_channel *channel, 88162306a36Sopenharmony_ci bool enable, unsigned int outn) 88262306a36Sopenharmony_ci{ 88362306a36Sopenharmony_ci struct idt82p33 *idt82p33 = channel->idt82p33; 88462306a36Sopenharmony_ci int err; 88562306a36Sopenharmony_ci u8 val; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci err = idt82p33_read(idt82p33, OUT_MUX_CNFG(outn), &val, sizeof(val)); 88862306a36Sopenharmony_ci if (err) 88962306a36Sopenharmony_ci return err; 89062306a36Sopenharmony_ci if (enable) 89162306a36Sopenharmony_ci val &= ~SQUELCH_ENABLE; 89262306a36Sopenharmony_ci else 89362306a36Sopenharmony_ci val |= SQUELCH_ENABLE; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci return idt82p33_write(idt82p33, OUT_MUX_CNFG(outn), &val, sizeof(val)); 89662306a36Sopenharmony_ci} 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_cistatic int idt82p33_perout_enable(struct idt82p33_channel *channel, 89962306a36Sopenharmony_ci bool enable, 90062306a36Sopenharmony_ci struct ptp_perout_request *perout) 90162306a36Sopenharmony_ci{ 90262306a36Sopenharmony_ci /* Enable/disable individual output instead */ 90362306a36Sopenharmony_ci return idt82p33_output_enable(channel, enable, perout->index); 90462306a36Sopenharmony_ci} 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_cistatic int idt82p33_enable_tod(struct idt82p33_channel *channel) 90762306a36Sopenharmony_ci{ 90862306a36Sopenharmony_ci struct idt82p33 *idt82p33 = channel->idt82p33; 90962306a36Sopenharmony_ci struct timespec64 ts = {0, 0}; 91062306a36Sopenharmony_ci int err; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci err = idt82p33_measure_tod_write_overhead(channel); 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci if (err) { 91562306a36Sopenharmony_ci dev_err(idt82p33->dev, 91662306a36Sopenharmony_ci "Failed in %s with err %d!\n", __func__, err); 91762306a36Sopenharmony_ci return err; 91862306a36Sopenharmony_ci } 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci err = _idt82p33_settime(channel, &ts); 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci if (err) 92362306a36Sopenharmony_ci return err; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci return idt82p33_sync_tod(channel, true); 92662306a36Sopenharmony_ci} 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_cistatic void idt82p33_ptp_clock_unregister_all(struct idt82p33 *idt82p33) 92962306a36Sopenharmony_ci{ 93062306a36Sopenharmony_ci struct idt82p33_channel *channel; 93162306a36Sopenharmony_ci u8 i; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci for (i = 0; i < MAX_PHC_PLL; i++) { 93462306a36Sopenharmony_ci channel = &idt82p33->channel[i]; 93562306a36Sopenharmony_ci cancel_delayed_work_sync(&channel->adjtime_work); 93662306a36Sopenharmony_ci if (channel->ptp_clock) 93762306a36Sopenharmony_ci ptp_clock_unregister(channel->ptp_clock); 93862306a36Sopenharmony_ci } 93962306a36Sopenharmony_ci} 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_cistatic int idt82p33_enable(struct ptp_clock_info *ptp, 94462306a36Sopenharmony_ci struct ptp_clock_request *rq, int on) 94562306a36Sopenharmony_ci{ 94662306a36Sopenharmony_ci struct idt82p33_channel *channel = 94762306a36Sopenharmony_ci container_of(ptp, struct idt82p33_channel, caps); 94862306a36Sopenharmony_ci struct idt82p33 *idt82p33 = channel->idt82p33; 94962306a36Sopenharmony_ci int err = -EOPNOTSUPP; 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci mutex_lock(idt82p33->lock); 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci switch (rq->type) { 95462306a36Sopenharmony_ci case PTP_CLK_REQ_PEROUT: 95562306a36Sopenharmony_ci if (!on) 95662306a36Sopenharmony_ci err = idt82p33_perout_enable(channel, false, 95762306a36Sopenharmony_ci &rq->perout); 95862306a36Sopenharmony_ci /* Only accept a 1-PPS aligned to the second. */ 95962306a36Sopenharmony_ci else if (rq->perout.start.nsec || rq->perout.period.sec != 1 || 96062306a36Sopenharmony_ci rq->perout.period.nsec) 96162306a36Sopenharmony_ci err = -ERANGE; 96262306a36Sopenharmony_ci else 96362306a36Sopenharmony_ci err = idt82p33_perout_enable(channel, true, 96462306a36Sopenharmony_ci &rq->perout); 96562306a36Sopenharmony_ci break; 96662306a36Sopenharmony_ci case PTP_CLK_REQ_EXTTS: 96762306a36Sopenharmony_ci err = idt82p33_extts_enable(channel, rq, on); 96862306a36Sopenharmony_ci break; 96962306a36Sopenharmony_ci default: 97062306a36Sopenharmony_ci break; 97162306a36Sopenharmony_ci } 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci mutex_unlock(idt82p33->lock); 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci if (err) 97662306a36Sopenharmony_ci dev_err(idt82p33->dev, 97762306a36Sopenharmony_ci "Failed in %s with err %d!\n", __func__, err); 97862306a36Sopenharmony_ci return err; 97962306a36Sopenharmony_ci} 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_cistatic s32 idt82p33_getmaxphase(__always_unused struct ptp_clock_info *ptp) 98262306a36Sopenharmony_ci{ 98362306a36Sopenharmony_ci return WRITE_PHASE_OFFSET_LIMIT; 98462306a36Sopenharmony_ci} 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_cistatic int idt82p33_adjwritephase(struct ptp_clock_info *ptp, s32 offset_ns) 98762306a36Sopenharmony_ci{ 98862306a36Sopenharmony_ci struct idt82p33_channel *channel = 98962306a36Sopenharmony_ci container_of(ptp, struct idt82p33_channel, caps); 99062306a36Sopenharmony_ci struct idt82p33 *idt82p33 = channel->idt82p33; 99162306a36Sopenharmony_ci s64 offset_regval; 99262306a36Sopenharmony_ci u8 val[4] = {0}; 99362306a36Sopenharmony_ci int err; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci /* Convert from phaseoffset_fs to register value */ 99662306a36Sopenharmony_ci offset_regval = div_s64((s64)(-offset_ns) * 1000000000ll, 99762306a36Sopenharmony_ci IDT_T0DPLL_PHASE_RESOL); 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci val[0] = offset_regval & 0xFF; 100062306a36Sopenharmony_ci val[1] = (offset_regval >> 8) & 0xFF; 100162306a36Sopenharmony_ci val[2] = (offset_regval >> 16) & 0xFF; 100262306a36Sopenharmony_ci val[3] = (offset_regval >> 24) & 0x1F; 100362306a36Sopenharmony_ci val[3] |= PH_OFFSET_EN; 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci mutex_lock(idt82p33->lock); 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci err = idt82p33_dpll_set_mode(channel, PLL_MODE_WPH); 100862306a36Sopenharmony_ci if (err) { 100962306a36Sopenharmony_ci dev_err(idt82p33->dev, 101062306a36Sopenharmony_ci "Failed in %s with err %d!\n", __func__, err); 101162306a36Sopenharmony_ci goto out; 101262306a36Sopenharmony_ci } 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci err = idt82p33_write(idt82p33, channel->dpll_phase_cnfg, val, 101562306a36Sopenharmony_ci sizeof(val)); 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ciout: 101862306a36Sopenharmony_ci mutex_unlock(idt82p33->lock); 101962306a36Sopenharmony_ci return err; 102062306a36Sopenharmony_ci} 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_cistatic int idt82p33_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) 102362306a36Sopenharmony_ci{ 102462306a36Sopenharmony_ci struct idt82p33_channel *channel = 102562306a36Sopenharmony_ci container_of(ptp, struct idt82p33_channel, caps); 102662306a36Sopenharmony_ci struct idt82p33 *idt82p33 = channel->idt82p33; 102762306a36Sopenharmony_ci int err; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci if (channel->ddco == true) 103062306a36Sopenharmony_ci return 0; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci if (scaled_ppm == channel->current_freq) 103362306a36Sopenharmony_ci return 0; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci mutex_lock(idt82p33->lock); 103662306a36Sopenharmony_ci err = _idt82p33_adjfine(channel, scaled_ppm); 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci if (err == 0) 103962306a36Sopenharmony_ci channel->current_freq = scaled_ppm; 104062306a36Sopenharmony_ci mutex_unlock(idt82p33->lock); 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci if (err) 104362306a36Sopenharmony_ci dev_err(idt82p33->dev, 104462306a36Sopenharmony_ci "Failed in %s with err %d!\n", __func__, err); 104562306a36Sopenharmony_ci return err; 104662306a36Sopenharmony_ci} 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_cistatic int idt82p33_adjtime(struct ptp_clock_info *ptp, s64 delta_ns) 104962306a36Sopenharmony_ci{ 105062306a36Sopenharmony_ci struct idt82p33_channel *channel = 105162306a36Sopenharmony_ci container_of(ptp, struct idt82p33_channel, caps); 105262306a36Sopenharmony_ci struct idt82p33 *idt82p33 = channel->idt82p33; 105362306a36Sopenharmony_ci int err; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci if (channel->ddco == true) 105662306a36Sopenharmony_ci return -EBUSY; 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci mutex_lock(idt82p33->lock); 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci if (abs(delta_ns) < phase_snap_threshold) { 106162306a36Sopenharmony_ci err = idt82p33_start_ddco(channel, delta_ns); 106262306a36Sopenharmony_ci mutex_unlock(idt82p33->lock); 106362306a36Sopenharmony_ci return err; 106462306a36Sopenharmony_ci } 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci /* Use more accurate internal 1pps triggered write first */ 106762306a36Sopenharmony_ci err = _idt82p33_adjtime_internal_triggered(channel, delta_ns); 106862306a36Sopenharmony_ci if (err && delta_ns > IMMEDIATE_SNAP_THRESHOLD_NS) 106962306a36Sopenharmony_ci err = _idt82p33_adjtime_immediate(channel, delta_ns); 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci mutex_unlock(idt82p33->lock); 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci if (err) 107462306a36Sopenharmony_ci dev_err(idt82p33->dev, 107562306a36Sopenharmony_ci "Failed in %s with err %d!\n", __func__, err); 107662306a36Sopenharmony_ci return err; 107762306a36Sopenharmony_ci} 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_cistatic int idt82p33_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) 108062306a36Sopenharmony_ci{ 108162306a36Sopenharmony_ci struct idt82p33_channel *channel = 108262306a36Sopenharmony_ci container_of(ptp, struct idt82p33_channel, caps); 108362306a36Sopenharmony_ci struct idt82p33 *idt82p33 = channel->idt82p33; 108462306a36Sopenharmony_ci int err; 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci mutex_lock(idt82p33->lock); 108762306a36Sopenharmony_ci err = _idt82p33_gettime(channel, ts); 108862306a36Sopenharmony_ci mutex_unlock(idt82p33->lock); 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci if (err) 109162306a36Sopenharmony_ci dev_err(idt82p33->dev, 109262306a36Sopenharmony_ci "Failed in %s with err %d!\n", __func__, err); 109362306a36Sopenharmony_ci return err; 109462306a36Sopenharmony_ci} 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_cistatic int idt82p33_settime(struct ptp_clock_info *ptp, 109762306a36Sopenharmony_ci const struct timespec64 *ts) 109862306a36Sopenharmony_ci{ 109962306a36Sopenharmony_ci struct idt82p33_channel *channel = 110062306a36Sopenharmony_ci container_of(ptp, struct idt82p33_channel, caps); 110162306a36Sopenharmony_ci struct idt82p33 *idt82p33 = channel->idt82p33; 110262306a36Sopenharmony_ci int err; 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci mutex_lock(idt82p33->lock); 110562306a36Sopenharmony_ci err = _idt82p33_settime(channel, ts); 110662306a36Sopenharmony_ci mutex_unlock(idt82p33->lock); 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci if (err) 110962306a36Sopenharmony_ci dev_err(idt82p33->dev, 111062306a36Sopenharmony_ci "Failed in %s with err %d!\n", __func__, err); 111162306a36Sopenharmony_ci return err; 111262306a36Sopenharmony_ci} 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_cistatic int idt82p33_channel_init(struct idt82p33 *idt82p33, u32 index) 111562306a36Sopenharmony_ci{ 111662306a36Sopenharmony_ci struct idt82p33_channel *channel = &idt82p33->channel[index]; 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci switch (index) { 111962306a36Sopenharmony_ci case 0: 112062306a36Sopenharmony_ci channel->dpll_tod_cnfg = DPLL1_TOD_CNFG; 112162306a36Sopenharmony_ci channel->dpll_tod_trigger = DPLL1_TOD_TRIGGER; 112262306a36Sopenharmony_ci channel->dpll_tod_sts = DPLL1_TOD_STS; 112362306a36Sopenharmony_ci channel->dpll_mode_cnfg = DPLL1_OPERATING_MODE_CNFG; 112462306a36Sopenharmony_ci channel->dpll_freq_cnfg = DPLL1_HOLDOVER_FREQ_CNFG; 112562306a36Sopenharmony_ci channel->dpll_phase_cnfg = DPLL1_PHASE_OFFSET_CNFG; 112662306a36Sopenharmony_ci channel->dpll_sync_cnfg = DPLL1_SYNC_EDGE_CNFG; 112762306a36Sopenharmony_ci channel->dpll_input_mode_cnfg = DPLL1_INPUT_MODE_CNFG; 112862306a36Sopenharmony_ci break; 112962306a36Sopenharmony_ci case 1: 113062306a36Sopenharmony_ci channel->dpll_tod_cnfg = DPLL2_TOD_CNFG; 113162306a36Sopenharmony_ci channel->dpll_tod_trigger = DPLL2_TOD_TRIGGER; 113262306a36Sopenharmony_ci channel->dpll_tod_sts = DPLL2_TOD_STS; 113362306a36Sopenharmony_ci channel->dpll_mode_cnfg = DPLL2_OPERATING_MODE_CNFG; 113462306a36Sopenharmony_ci channel->dpll_freq_cnfg = DPLL2_HOLDOVER_FREQ_CNFG; 113562306a36Sopenharmony_ci channel->dpll_phase_cnfg = DPLL2_PHASE_OFFSET_CNFG; 113662306a36Sopenharmony_ci channel->dpll_sync_cnfg = DPLL2_SYNC_EDGE_CNFG; 113762306a36Sopenharmony_ci channel->dpll_input_mode_cnfg = DPLL2_INPUT_MODE_CNFG; 113862306a36Sopenharmony_ci break; 113962306a36Sopenharmony_ci default: 114062306a36Sopenharmony_ci return -EINVAL; 114162306a36Sopenharmony_ci } 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci channel->plln = index; 114462306a36Sopenharmony_ci channel->current_freq = 0; 114562306a36Sopenharmony_ci channel->idt82p33 = idt82p33; 114662306a36Sopenharmony_ci INIT_DELAYED_WORK(&channel->adjtime_work, idt82p33_adjtime_workaround); 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci return 0; 114962306a36Sopenharmony_ci} 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_cistatic int idt82p33_verify_pin(struct ptp_clock_info *ptp, unsigned int pin, 115262306a36Sopenharmony_ci enum ptp_pin_function func, unsigned int chan) 115362306a36Sopenharmony_ci{ 115462306a36Sopenharmony_ci switch (func) { 115562306a36Sopenharmony_ci case PTP_PF_NONE: 115662306a36Sopenharmony_ci case PTP_PF_EXTTS: 115762306a36Sopenharmony_ci break; 115862306a36Sopenharmony_ci case PTP_PF_PEROUT: 115962306a36Sopenharmony_ci case PTP_PF_PHYSYNC: 116062306a36Sopenharmony_ci return -1; 116162306a36Sopenharmony_ci } 116262306a36Sopenharmony_ci return 0; 116362306a36Sopenharmony_ci} 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_cistatic void idt82p33_caps_init(u32 index, struct ptp_clock_info *caps, 116662306a36Sopenharmony_ci struct ptp_pin_desc *pin_cfg, u8 max_pins) 116762306a36Sopenharmony_ci{ 116862306a36Sopenharmony_ci struct ptp_pin_desc *ppd; 116962306a36Sopenharmony_ci int i; 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci caps->owner = THIS_MODULE; 117262306a36Sopenharmony_ci caps->max_adj = DCO_MAX_PPB; 117362306a36Sopenharmony_ci caps->n_per_out = MAX_PER_OUT; 117462306a36Sopenharmony_ci caps->n_ext_ts = MAX_PHC_PLL, 117562306a36Sopenharmony_ci caps->n_pins = max_pins, 117662306a36Sopenharmony_ci caps->adjphase = idt82p33_adjwritephase, 117762306a36Sopenharmony_ci caps->getmaxphase = idt82p33_getmaxphase, 117862306a36Sopenharmony_ci caps->adjfine = idt82p33_adjfine; 117962306a36Sopenharmony_ci caps->adjtime = idt82p33_adjtime; 118062306a36Sopenharmony_ci caps->gettime64 = idt82p33_gettime; 118162306a36Sopenharmony_ci caps->settime64 = idt82p33_settime; 118262306a36Sopenharmony_ci caps->enable = idt82p33_enable; 118362306a36Sopenharmony_ci caps->verify = idt82p33_verify_pin; 118462306a36Sopenharmony_ci caps->do_aux_work = idt82p33_work_handler; 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci snprintf(caps->name, sizeof(caps->name), "IDT 82P33 PLL%u", index); 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci caps->pin_config = pin_cfg; 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci for (i = 0; i < max_pins; ++i) { 119162306a36Sopenharmony_ci ppd = &pin_cfg[i]; 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci ppd->index = i; 119462306a36Sopenharmony_ci ppd->func = PTP_PF_NONE; 119562306a36Sopenharmony_ci ppd->chan = index; 119662306a36Sopenharmony_ci snprintf(ppd->name, sizeof(ppd->name), "in%d", 12 + i); 119762306a36Sopenharmony_ci } 119862306a36Sopenharmony_ci} 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_cistatic int idt82p33_enable_channel(struct idt82p33 *idt82p33, u32 index) 120162306a36Sopenharmony_ci{ 120262306a36Sopenharmony_ci struct idt82p33_channel *channel; 120362306a36Sopenharmony_ci int err; 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci if (!(index < MAX_PHC_PLL)) 120662306a36Sopenharmony_ci return -EINVAL; 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci channel = &idt82p33->channel[index]; 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci err = idt82p33_channel_init(idt82p33, index); 121162306a36Sopenharmony_ci if (err) { 121262306a36Sopenharmony_ci dev_err(idt82p33->dev, 121362306a36Sopenharmony_ci "Channel_init failed in %s with err %d!\n", 121462306a36Sopenharmony_ci __func__, err); 121562306a36Sopenharmony_ci return err; 121662306a36Sopenharmony_ci } 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci idt82p33_caps_init(index, &channel->caps, 121962306a36Sopenharmony_ci pin_config[index], MAX_TRIG_CLK); 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci channel->ptp_clock = ptp_clock_register(&channel->caps, NULL); 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci if (IS_ERR(channel->ptp_clock)) { 122462306a36Sopenharmony_ci err = PTR_ERR(channel->ptp_clock); 122562306a36Sopenharmony_ci channel->ptp_clock = NULL; 122662306a36Sopenharmony_ci return err; 122762306a36Sopenharmony_ci } 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci if (!channel->ptp_clock) 123062306a36Sopenharmony_ci return -ENOTSUPP; 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci err = idt82p33_dpll_set_mode(channel, PLL_MODE_DCO); 123362306a36Sopenharmony_ci if (err) { 123462306a36Sopenharmony_ci dev_err(idt82p33->dev, 123562306a36Sopenharmony_ci "Dpll_set_mode failed in %s with err %d!\n", 123662306a36Sopenharmony_ci __func__, err); 123762306a36Sopenharmony_ci return err; 123862306a36Sopenharmony_ci } 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci err = idt82p33_enable_tod(channel); 124162306a36Sopenharmony_ci if (err) { 124262306a36Sopenharmony_ci dev_err(idt82p33->dev, 124362306a36Sopenharmony_ci "Enable_tod failed in %s with err %d!\n", 124462306a36Sopenharmony_ci __func__, err); 124562306a36Sopenharmony_ci return err; 124662306a36Sopenharmony_ci } 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci dev_info(idt82p33->dev, "PLL%d registered as ptp%d\n", 124962306a36Sopenharmony_ci index, channel->ptp_clock->index); 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci return 0; 125262306a36Sopenharmony_ci} 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_cistatic int idt82p33_reset(struct idt82p33 *idt82p33, bool cold) 125562306a36Sopenharmony_ci{ 125662306a36Sopenharmony_ci int err; 125762306a36Sopenharmony_ci u8 cfg = SOFT_RESET_EN; 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci if (cold == true) 126062306a36Sopenharmony_ci goto cold_reset; 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci err = idt82p33_read(idt82p33, REG_SOFT_RESET, &cfg, sizeof(cfg)); 126362306a36Sopenharmony_ci if (err) { 126462306a36Sopenharmony_ci dev_err(idt82p33->dev, 126562306a36Sopenharmony_ci "Soft reset failed with err %d!\n", err); 126662306a36Sopenharmony_ci return err; 126762306a36Sopenharmony_ci } 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci cfg |= SOFT_RESET_EN; 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_cicold_reset: 127262306a36Sopenharmony_ci err = idt82p33_write(idt82p33, REG_SOFT_RESET, &cfg, sizeof(cfg)); 127362306a36Sopenharmony_ci if (err) 127462306a36Sopenharmony_ci dev_err(idt82p33->dev, 127562306a36Sopenharmony_ci "Cold reset failed with err %d!\n", err); 127662306a36Sopenharmony_ci return err; 127762306a36Sopenharmony_ci} 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_cistatic int idt82p33_load_firmware(struct idt82p33 *idt82p33) 128062306a36Sopenharmony_ci{ 128162306a36Sopenharmony_ci char fname[128] = FW_FILENAME; 128262306a36Sopenharmony_ci const struct firmware *fw; 128362306a36Sopenharmony_ci struct idt82p33_fwrc *rec; 128462306a36Sopenharmony_ci u8 loaddr, page, val; 128562306a36Sopenharmony_ci int err; 128662306a36Sopenharmony_ci s32 len; 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci if (firmware) /* module parameter */ 128962306a36Sopenharmony_ci snprintf(fname, sizeof(fname), "%s", firmware); 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci dev_info(idt82p33->dev, "requesting firmware '%s'\n", fname); 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci err = request_firmware(&fw, fname, idt82p33->dev); 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci if (err) { 129662306a36Sopenharmony_ci dev_err(idt82p33->dev, 129762306a36Sopenharmony_ci "Failed in %s with err %d!\n", __func__, err); 129862306a36Sopenharmony_ci return err; 129962306a36Sopenharmony_ci } 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci dev_dbg(idt82p33->dev, "firmware size %zu bytes\n", fw->size); 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci rec = (struct idt82p33_fwrc *) fw->data; 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci for (len = fw->size; len > 0; len -= sizeof(*rec)) { 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci if (rec->reserved) { 130862306a36Sopenharmony_ci dev_err(idt82p33->dev, 130962306a36Sopenharmony_ci "bad firmware, reserved field non-zero\n"); 131062306a36Sopenharmony_ci err = -EINVAL; 131162306a36Sopenharmony_ci } else { 131262306a36Sopenharmony_ci val = rec->value; 131362306a36Sopenharmony_ci loaddr = rec->loaddr; 131462306a36Sopenharmony_ci page = rec->hiaddr; 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci rec++; 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci err = idt82p33_check_and_set_masks(idt82p33, page, 131962306a36Sopenharmony_ci loaddr, val); 132062306a36Sopenharmony_ci } 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci if (err == 0) { 132362306a36Sopenharmony_ci /* Page size 128, last 4 bytes of page skipped */ 132462306a36Sopenharmony_ci if (loaddr > 0x7b) 132562306a36Sopenharmony_ci continue; 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci err = idt82p33_write(idt82p33, REG_ADDR(page, loaddr), 132862306a36Sopenharmony_ci &val, sizeof(val)); 132962306a36Sopenharmony_ci } 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci if (err) 133262306a36Sopenharmony_ci goto out; 133362306a36Sopenharmony_ci } 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci idt82p33_display_masks(idt82p33); 133662306a36Sopenharmony_ciout: 133762306a36Sopenharmony_ci release_firmware(fw); 133862306a36Sopenharmony_ci return err; 133962306a36Sopenharmony_ci} 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_cistatic void idt82p33_extts_check(struct work_struct *work) 134262306a36Sopenharmony_ci{ 134362306a36Sopenharmony_ci struct idt82p33 *idt82p33 = container_of(work, struct idt82p33, 134462306a36Sopenharmony_ci extts_work.work); 134562306a36Sopenharmony_ci struct idt82p33_channel *channel; 134662306a36Sopenharmony_ci int err; 134762306a36Sopenharmony_ci u8 mask; 134862306a36Sopenharmony_ci int i; 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci if (idt82p33->extts_mask == 0) 135162306a36Sopenharmony_ci return; 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci mutex_lock(idt82p33->lock); 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci for (i = 0; i < MAX_PHC_PLL; i++) { 135662306a36Sopenharmony_ci mask = 1 << i; 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci if ((idt82p33->extts_mask & mask) == 0) 135962306a36Sopenharmony_ci continue; 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci err = idt82p33_extts_check_channel(idt82p33, i); 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci if (err == 0) { 136462306a36Sopenharmony_ci /* trigger clears itself, so clear the mask */ 136562306a36Sopenharmony_ci if (idt82p33->extts_single_shot) { 136662306a36Sopenharmony_ci idt82p33->extts_mask &= ~mask; 136762306a36Sopenharmony_ci } else { 136862306a36Sopenharmony_ci /* Re-arm */ 136962306a36Sopenharmony_ci channel = &idt82p33->channel[i]; 137062306a36Sopenharmony_ci arm_tod_read_with_trigger(channel, channel->tod_trigger); 137162306a36Sopenharmony_ci } 137262306a36Sopenharmony_ci } 137362306a36Sopenharmony_ci } 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci if (idt82p33->extts_mask) 137662306a36Sopenharmony_ci schedule_delayed_work(&idt82p33->extts_work, 137762306a36Sopenharmony_ci msecs_to_jiffies(EXTTS_PERIOD_MS)); 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci mutex_unlock(idt82p33->lock); 138062306a36Sopenharmony_ci} 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_cistatic int idt82p33_probe(struct platform_device *pdev) 138362306a36Sopenharmony_ci{ 138462306a36Sopenharmony_ci struct rsmu_ddata *ddata = dev_get_drvdata(pdev->dev.parent); 138562306a36Sopenharmony_ci struct idt82p33 *idt82p33; 138662306a36Sopenharmony_ci int err; 138762306a36Sopenharmony_ci u8 i; 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ci idt82p33 = devm_kzalloc(&pdev->dev, 139062306a36Sopenharmony_ci sizeof(struct idt82p33), GFP_KERNEL); 139162306a36Sopenharmony_ci if (!idt82p33) 139262306a36Sopenharmony_ci return -ENOMEM; 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci idt82p33->dev = &pdev->dev; 139562306a36Sopenharmony_ci idt82p33->mfd = pdev->dev.parent; 139662306a36Sopenharmony_ci idt82p33->lock = &ddata->lock; 139762306a36Sopenharmony_ci idt82p33->regmap = ddata->regmap; 139862306a36Sopenharmony_ci idt82p33->tod_write_overhead_ns = 0; 139962306a36Sopenharmony_ci idt82p33->calculate_overhead_flag = 0; 140062306a36Sopenharmony_ci idt82p33->pll_mask = DEFAULT_PLL_MASK; 140162306a36Sopenharmony_ci idt82p33->channel[0].output_mask = DEFAULT_OUTPUT_MASK_PLL0; 140262306a36Sopenharmony_ci idt82p33->channel[1].output_mask = DEFAULT_OUTPUT_MASK_PLL1; 140362306a36Sopenharmony_ci idt82p33->extts_mask = 0; 140462306a36Sopenharmony_ci INIT_DELAYED_WORK(&idt82p33->extts_work, idt82p33_extts_check); 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci mutex_lock(idt82p33->lock); 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci /* cold reset before loading firmware */ 140962306a36Sopenharmony_ci idt82p33_reset(idt82p33, true); 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci err = idt82p33_load_firmware(idt82p33); 141262306a36Sopenharmony_ci if (err) 141362306a36Sopenharmony_ci dev_warn(idt82p33->dev, 141462306a36Sopenharmony_ci "loading firmware failed with %d\n", err); 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci /* soft reset after loading firmware */ 141762306a36Sopenharmony_ci idt82p33_reset(idt82p33, false); 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci if (idt82p33->pll_mask) { 142062306a36Sopenharmony_ci for (i = 0; i < MAX_PHC_PLL; i++) { 142162306a36Sopenharmony_ci if (idt82p33->pll_mask & (1 << i)) 142262306a36Sopenharmony_ci err = idt82p33_enable_channel(idt82p33, i); 142362306a36Sopenharmony_ci else 142462306a36Sopenharmony_ci err = idt82p33_channel_init(idt82p33, i); 142562306a36Sopenharmony_ci if (err) { 142662306a36Sopenharmony_ci dev_err(idt82p33->dev, 142762306a36Sopenharmony_ci "Failed in %s with err %d!\n", 142862306a36Sopenharmony_ci __func__, err); 142962306a36Sopenharmony_ci break; 143062306a36Sopenharmony_ci } 143162306a36Sopenharmony_ci } 143262306a36Sopenharmony_ci } else { 143362306a36Sopenharmony_ci dev_err(idt82p33->dev, 143462306a36Sopenharmony_ci "no PLLs flagged as PHCs, nothing to do\n"); 143562306a36Sopenharmony_ci err = -ENODEV; 143662306a36Sopenharmony_ci } 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ci mutex_unlock(idt82p33->lock); 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci if (err) { 144162306a36Sopenharmony_ci idt82p33_ptp_clock_unregister_all(idt82p33); 144262306a36Sopenharmony_ci return err; 144362306a36Sopenharmony_ci } 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci platform_set_drvdata(pdev, idt82p33); 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci return 0; 144862306a36Sopenharmony_ci} 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_cistatic int idt82p33_remove(struct platform_device *pdev) 145162306a36Sopenharmony_ci{ 145262306a36Sopenharmony_ci struct idt82p33 *idt82p33 = platform_get_drvdata(pdev); 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci cancel_delayed_work_sync(&idt82p33->extts_work); 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci idt82p33_ptp_clock_unregister_all(idt82p33); 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci return 0; 145962306a36Sopenharmony_ci} 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_cistatic struct platform_driver idt82p33_driver = { 146262306a36Sopenharmony_ci .driver = { 146362306a36Sopenharmony_ci .name = "82p33x1x-phc", 146462306a36Sopenharmony_ci }, 146562306a36Sopenharmony_ci .probe = idt82p33_probe, 146662306a36Sopenharmony_ci .remove = idt82p33_remove, 146762306a36Sopenharmony_ci}; 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_cimodule_platform_driver(idt82p33_driver); 1470