1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 3 #ifndef _ZL3073X_CHAN_H 4 #define _ZL3073X_CHAN_H 5 6 #include <linux/bitfield.h> 7 #include <linux/stddef.h> 8 #include <linux/time64.h> 9 #include <linux/types.h> 10 11 #include "regs.h" 12 13 struct ptp_system_timestamp; 14 struct zl3073x_dev; 15 16 /** 17 * struct zl3073x_chan - DPLL channel state 18 * @ctrl: DPLL control register value 19 * @mode_refsel: mode and reference selection register value 20 * @ref_prio: reference priority registers (4 bits per ref, P/N packed) 21 * @mon_status: monitor status register value 22 * @refsel_status: reference selection status register value 23 * @df_offset: frequency offset vs tracked reference in 2^-48 steps 24 */ 25 struct zl3073x_chan { 26 struct_group(cfg, 27 u8 ctrl; 28 u8 mode_refsel; 29 u8 ref_prio[ZL3073X_NUM_REFS / 2]; 30 ); 31 struct_group(stat, 32 u8 mon_status; 33 u8 refsel_status; 34 s64 df_offset; 35 ); 36 }; 37 38 int zl3073x_chan_state_fetch(struct zl3073x_dev *zldev, u8 index); 39 const struct zl3073x_chan *zl3073x_chan_state_get(struct zl3073x_dev *zldev, 40 u8 index); 41 int zl3073x_chan_state_set(struct zl3073x_dev *zldev, u8 index, 42 const struct zl3073x_chan *chan); 43 44 int zl3073x_chan_state_update(struct zl3073x_dev *zldev, u8 index); 45 int zl3073x_chan_nco_mode_set(struct zl3073x_dev *zldev, u8 index); 46 47 int zl3073x_chan_tod_ready_wait(struct zl3073x_dev *zldev, u8 ch); 48 int zl3073x_chan_tod_read(struct zl3073x_dev *zldev, u8 ch, 49 bool next_hz, struct timespec64 *ts, 50 struct ptp_system_timestamp *sts); 51 int zl3073x_chan_tod_write(struct zl3073x_dev *zldev, u8 ch, 52 struct timespec64 ts); 53 int zl3073x_chan_tod_adjust(struct zl3073x_dev *zldev, u8 ch, 54 struct timespec64 delta); 55 int zl3073x_chan_phase_step(struct zl3073x_dev *zldev, u8 ch, 56 u16 out_mask, s32 step_cycles, bool tod_step); 57 58 int zl3073x_chan_df_offset_set(struct zl3073x_dev *zldev, u8 ch, s64 offset); 59 60 int zl3073x_chan_tie_write(struct zl3073x_dev *zldev, u8 ch, s64 delta_ns); 61 62 /** 63 * zl3073x_chan_df_offset_get - get cached df_offset vs tracked reference 64 * @chan: pointer to channel state 65 * 66 * Return: frequency offset in 2^-48 steps 67 */ 68 static inline s64 69 zl3073x_chan_df_offset_get(const struct zl3073x_chan *chan) 70 { 71 return chan->df_offset; 72 } 73 74 /** 75 * zl3073x_chan_mode_get - get DPLL channel operating mode 76 * @chan: pointer to channel state 77 * 78 * Return: reference selection mode of the given DPLL channel 79 */ 80 static inline u8 zl3073x_chan_mode_get(const struct zl3073x_chan *chan) 81 { 82 return FIELD_GET(ZL_DPLL_MODE_REFSEL_MODE, chan->mode_refsel); 83 } 84 85 /** 86 * zl3073x_chan_ref_get - get manually selected reference 87 * @chan: pointer to channel state 88 * 89 * Return: reference selected in forced reference lock mode 90 */ 91 static inline u8 zl3073x_chan_ref_get(const struct zl3073x_chan *chan) 92 { 93 return FIELD_GET(ZL_DPLL_MODE_REFSEL_REF, chan->mode_refsel); 94 } 95 96 /** 97 * zl3073x_chan_mode_set - set DPLL channel operating mode 98 * @chan: pointer to channel state 99 * @mode: mode to set 100 */ 101 static inline void zl3073x_chan_mode_set(struct zl3073x_chan *chan, u8 mode) 102 { 103 FIELD_MODIFY(ZL_DPLL_MODE_REFSEL_MODE, &chan->mode_refsel, mode); 104 } 105 106 /** 107 * zl3073x_chan_ref_set - set manually selected reference 108 * @chan: pointer to channel state 109 * @ref: reference to set 110 */ 111 static inline void zl3073x_chan_ref_set(struct zl3073x_chan *chan, u8 ref) 112 { 113 FIELD_MODIFY(ZL_DPLL_MODE_REFSEL_REF, &chan->mode_refsel, ref); 114 } 115 116 /** 117 * zl3073x_chan_ref_prio_get - get reference priority 118 * @chan: pointer to channel state 119 * @ref: input reference index 120 * 121 * Return: priority of the given reference <0, 15> 122 */ 123 static inline u8 124 zl3073x_chan_ref_prio_get(const struct zl3073x_chan *chan, u8 ref) 125 { 126 u8 val = chan->ref_prio[ref / 2]; 127 128 if (!(ref & 1)) 129 return FIELD_GET(ZL_DPLL_REF_PRIO_REF_P, val); 130 else 131 return FIELD_GET(ZL_DPLL_REF_PRIO_REF_N, val); 132 } 133 134 /** 135 * zl3073x_chan_ref_prio_set - set reference priority 136 * @chan: pointer to channel state 137 * @ref: input reference index 138 * @prio: priority to set 139 */ 140 static inline void 141 zl3073x_chan_ref_prio_set(struct zl3073x_chan *chan, u8 ref, u8 prio) 142 { 143 u8 *val = &chan->ref_prio[ref / 2]; 144 145 if (!(ref & 1)) 146 FIELD_MODIFY(ZL_DPLL_REF_PRIO_REF_P, val, prio); 147 else 148 FIELD_MODIFY(ZL_DPLL_REF_PRIO_REF_N, val, prio); 149 } 150 151 /** 152 * zl3073x_chan_ref_is_selectable - check if reference is selectable 153 * @chan: pointer to channel state 154 * @ref: input reference index 155 * 156 * Return: true if the reference priority is not NONE, false otherwise 157 */ 158 static inline bool 159 zl3073x_chan_ref_is_selectable(const struct zl3073x_chan *chan, u8 ref) 160 { 161 return zl3073x_chan_ref_prio_get(chan, ref) != ZL_DPLL_REF_PRIO_NONE; 162 } 163 164 /** 165 * zl3073x_chan_lock_state_get - get DPLL channel lock state 166 * @chan: pointer to channel state 167 * 168 * Return: lock state of the given DPLL channel 169 */ 170 static inline u8 zl3073x_chan_lock_state_get(const struct zl3073x_chan *chan) 171 { 172 return FIELD_GET(ZL_DPLL_MON_STATUS_STATE, chan->mon_status); 173 } 174 175 /** 176 * zl3073x_chan_is_locked - check if channel is locked to a reference 177 * @chan: pointer to channel state 178 * 179 * Return: true if channel is locked, false otherwise 180 */ 181 static inline bool zl3073x_chan_is_locked(const struct zl3073x_chan *chan) 182 { 183 u8 lock_state = zl3073x_chan_lock_state_get(chan); 184 return lock_state == ZL_DPLL_MON_STATUS_STATE_LOCK; 185 } 186 187 /** 188 * zl3073x_chan_mode_is_auto - check if channel is in automatic mode 189 * @chan: pointer to channel state 190 * 191 * Return: true if channel is in automatic mode, false otherwise 192 */ 193 static inline bool zl3073x_chan_mode_is_auto(const struct zl3073x_chan *chan) 194 { 195 return zl3073x_chan_mode_get(chan) == ZL_DPLL_MODE_REFSEL_MODE_AUTO; 196 } 197 198 /** 199 * zl3073x_chan_mode_is_nco - check if channel is in NCO mode 200 * @chan: pointer to channel state 201 * 202 * Return: true if channel is in NCO mode, false otherwise 203 */ 204 static inline bool zl3073x_chan_mode_is_nco(const struct zl3073x_chan *chan) 205 { 206 return zl3073x_chan_mode_get(chan) == ZL_DPLL_MODE_REFSEL_MODE_NCO; 207 } 208 209 /** 210 * zl3073x_chan_mode_is_reflock - check if channel is in reflock mode 211 * @chan: pointer to channel state 212 * 213 * Return: true if channel is in reflock mode, false otherwise 214 */ 215 static inline bool zl3073x_chan_mode_is_reflock(const struct zl3073x_chan *chan) 216 { 217 return zl3073x_chan_mode_get(chan) == ZL_DPLL_MODE_REFSEL_MODE_REFLOCK; 218 } 219 220 /** 221 * zl3073x_chan_mode_supports_tie - check if channel mode supports TIE write 222 * @chan: pointer to channel state 223 * 224 * TIE write is supported in AUTO and REFLOCK modes regardless of lock state. 225 * 226 * Return: true if TIE write is supported, false otherwise 227 */ 228 static inline bool 229 zl3073x_chan_mode_supports_tie(const struct zl3073x_chan *chan) 230 { 231 return zl3073x_chan_mode_is_auto(chan) || 232 zl3073x_chan_mode_is_reflock(chan); 233 } 234 235 /** 236 * zl3073x_chan_is_ho_ready - check if holdover is ready 237 * @chan: pointer to channel state 238 * 239 * Return: true if holdover is ready, false otherwise 240 */ 241 static inline bool zl3073x_chan_is_ho_ready(const struct zl3073x_chan *chan) 242 { 243 return !!FIELD_GET(ZL_DPLL_MON_STATUS_HO_READY, chan->mon_status); 244 } 245 246 /** 247 * zl3073x_chan_refsel_state_get - get reference selection state 248 * @chan: pointer to channel state 249 * 250 * Return: reference selection state of the given DPLL channel 251 */ 252 static inline u8 zl3073x_chan_refsel_state_get(const struct zl3073x_chan *chan) 253 { 254 return FIELD_GET(ZL_DPLL_REFSEL_STATUS_STATE, chan->refsel_status); 255 } 256 257 /** 258 * zl3073x_chan_refsel_ref_get - get currently selected reference in auto mode 259 * @chan: pointer to channel state 260 * 261 * Return: reference selected by the DPLL in automatic mode 262 */ 263 static inline u8 zl3073x_chan_refsel_ref_get(const struct zl3073x_chan *chan) 264 { 265 return FIELD_GET(ZL_DPLL_REFSEL_STATUS_REFSEL, chan->refsel_status); 266 } 267 268 #endif /* _ZL3073X_CHAN_H */ 269