summaryrefslogtreecommitdiffstats
path: root/drivers/dpll/zl3073x/chan.h
blob: 99c3b7088f678f5b3e5c01f47a2b2a1ac1077602 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
/* SPDX-License-Identifier: GPL-2.0-only */

#ifndef _ZL3073X_CHAN_H
#define _ZL3073X_CHAN_H

#include <linux/bitfield.h>
#include <linux/stddef.h>
#include <linux/time64.h>
#include <linux/types.h>

#include "regs.h"

struct ptp_system_timestamp;
struct zl3073x_dev;

/**
 * struct zl3073x_chan - DPLL channel state
 * @ctrl: DPLL control register value
 * @mode_refsel: mode and reference selection register value
 * @ref_prio: reference priority registers (4 bits per ref, P/N packed)
 * @mon_status: monitor status register value
 * @refsel_status: reference selection status register value
 * @df_offset: frequency offset vs tracked reference in 2^-48 steps
 */
struct zl3073x_chan {
	struct_group(cfg,
		u8	ctrl;
		u8	mode_refsel;
		u8	ref_prio[ZL3073X_NUM_REFS / 2];
	);
	struct_group(stat,
		u8	mon_status;
		u8	refsel_status;
		s64	df_offset;
	);
};

int zl3073x_chan_state_fetch(struct zl3073x_dev *zldev, u8 index);
const struct zl3073x_chan *zl3073x_chan_state_get(struct zl3073x_dev *zldev,
						 u8 index);
int zl3073x_chan_state_set(struct zl3073x_dev *zldev, u8 index,
			   const struct zl3073x_chan *chan);

int zl3073x_chan_state_update(struct zl3073x_dev *zldev, u8 index);
int zl3073x_chan_nco_mode_set(struct zl3073x_dev *zldev, u8 index);

int zl3073x_chan_tod_ready_wait(struct zl3073x_dev *zldev, u8 ch);
int zl3073x_chan_tod_read(struct zl3073x_dev *zldev, u8 ch,
			  bool next_hz, struct timespec64 *ts,
			  struct ptp_system_timestamp *sts);
int zl3073x_chan_tod_write(struct zl3073x_dev *zldev, u8 ch,
			   struct timespec64 ts);
int zl3073x_chan_tod_adjust(struct zl3073x_dev *zldev, u8 ch,
			    struct timespec64 delta);
int zl3073x_chan_phase_step(struct zl3073x_dev *zldev, u8 ch,
			    u16 out_mask, s32 step_cycles, bool tod_step);

int zl3073x_chan_df_offset_set(struct zl3073x_dev *zldev, u8 ch, s64 offset);

int zl3073x_chan_tie_write(struct zl3073x_dev *zldev, u8 ch, s64 delta_ns);

/**
 * zl3073x_chan_df_offset_get - get cached df_offset vs tracked reference
 * @chan: pointer to channel state
 *
 * Return: frequency offset in 2^-48 steps
 */
static inline s64
zl3073x_chan_df_offset_get(const struct zl3073x_chan *chan)
{
	return chan->df_offset;
}

/**
 * zl3073x_chan_mode_get - get DPLL channel operating mode
 * @chan: pointer to channel state
 *
 * Return: reference selection mode of the given DPLL channel
 */
static inline u8 zl3073x_chan_mode_get(const struct zl3073x_chan *chan)
{
	return FIELD_GET(ZL_DPLL_MODE_REFSEL_MODE, chan->mode_refsel);
}

/**
 * zl3073x_chan_ref_get - get manually selected reference
 * @chan: pointer to channel state
 *
 * Return: reference selected in forced reference lock mode
 */
static inline u8 zl3073x_chan_ref_get(const struct zl3073x_chan *chan)
{
	return FIELD_GET(ZL_DPLL_MODE_REFSEL_REF, chan->mode_refsel);
}

/**
 * zl3073x_chan_mode_set - set DPLL channel operating mode
 * @chan: pointer to channel state
 * @mode: mode to set
 */
static inline void zl3073x_chan_mode_set(struct zl3073x_chan *chan, u8 mode)
{
	FIELD_MODIFY(ZL_DPLL_MODE_REFSEL_MODE, &chan->mode_refsel, mode);
}

/**
 * zl3073x_chan_ref_set - set manually selected reference
 * @chan: pointer to channel state
 * @ref: reference to set
 */
static inline void zl3073x_chan_ref_set(struct zl3073x_chan *chan, u8 ref)
{
	FIELD_MODIFY(ZL_DPLL_MODE_REFSEL_REF, &chan->mode_refsel, ref);
}

/**
 * zl3073x_chan_ref_prio_get - get reference priority
 * @chan: pointer to channel state
 * @ref: input reference index
 *
 * Return: priority of the given reference <0, 15>
 */
static inline u8
zl3073x_chan_ref_prio_get(const struct zl3073x_chan *chan, u8 ref)
{
	u8 val = chan->ref_prio[ref / 2];

	if (!(ref & 1))
		return FIELD_GET(ZL_DPLL_REF_PRIO_REF_P, val);
	else
		return FIELD_GET(ZL_DPLL_REF_PRIO_REF_N, val);
}

/**
 * zl3073x_chan_ref_prio_set - set reference priority
 * @chan: pointer to channel state
 * @ref: input reference index
 * @prio: priority to set
 */
static inline void
zl3073x_chan_ref_prio_set(struct zl3073x_chan *chan, u8 ref, u8 prio)
{
	u8 *val = &chan->ref_prio[ref / 2];

	if (!(ref & 1))
		FIELD_MODIFY(ZL_DPLL_REF_PRIO_REF_P, val, prio);
	else
		FIELD_MODIFY(ZL_DPLL_REF_PRIO_REF_N, val, prio);
}

/**
 * zl3073x_chan_ref_is_selectable - check if reference is selectable
 * @chan: pointer to channel state
 * @ref: input reference index
 *
 * Return: true if the reference priority is not NONE, false otherwise
 */
static inline bool
zl3073x_chan_ref_is_selectable(const struct zl3073x_chan *chan, u8 ref)
{
	return zl3073x_chan_ref_prio_get(chan, ref) != ZL_DPLL_REF_PRIO_NONE;
}

/**
 * zl3073x_chan_lock_state_get - get DPLL channel lock state
 * @chan: pointer to channel state
 *
 * Return: lock state of the given DPLL channel
 */
static inline u8 zl3073x_chan_lock_state_get(const struct zl3073x_chan *chan)
{
	return FIELD_GET(ZL_DPLL_MON_STATUS_STATE, chan->mon_status);
}

/**
 * zl3073x_chan_is_locked - check if channel is locked to a reference
 * @chan: pointer to channel state
 *
 * Return: true if channel is locked, false otherwise
 */
static inline bool zl3073x_chan_is_locked(const struct zl3073x_chan *chan)
{
	u8 lock_state = zl3073x_chan_lock_state_get(chan);
	return lock_state == ZL_DPLL_MON_STATUS_STATE_LOCK;
}

/**
 * zl3073x_chan_mode_is_auto - check if channel is in automatic mode
 * @chan: pointer to channel state
 *
 * Return: true if channel is in automatic mode, false otherwise
 */
static inline bool zl3073x_chan_mode_is_auto(const struct zl3073x_chan *chan)
{
	return zl3073x_chan_mode_get(chan) == ZL_DPLL_MODE_REFSEL_MODE_AUTO;
}

/**
 * zl3073x_chan_mode_is_nco - check if channel is in NCO mode
 * @chan: pointer to channel state
 *
 * Return: true if channel is in NCO mode, false otherwise
 */
static inline bool zl3073x_chan_mode_is_nco(const struct zl3073x_chan *chan)
{
	return zl3073x_chan_mode_get(chan) == ZL_DPLL_MODE_REFSEL_MODE_NCO;
}

/**
 * zl3073x_chan_mode_is_reflock - check if channel is in reflock mode
 * @chan: pointer to channel state
 *
 * Return: true if channel is in reflock mode, false otherwise
 */
static inline bool zl3073x_chan_mode_is_reflock(const struct zl3073x_chan *chan)
{
	return zl3073x_chan_mode_get(chan) == ZL_DPLL_MODE_REFSEL_MODE_REFLOCK;
}

/**
 * zl3073x_chan_mode_supports_tie - check if channel mode supports TIE write
 * @chan: pointer to channel state
 *
 * TIE write is supported in AUTO and REFLOCK modes regardless of lock state.
 *
 * Return: true if TIE write is supported, false otherwise
 */
static inline bool
zl3073x_chan_mode_supports_tie(const struct zl3073x_chan *chan)
{
	return zl3073x_chan_mode_is_auto(chan) ||
		zl3073x_chan_mode_is_reflock(chan);
}

/**
 * zl3073x_chan_is_ho_ready - check if holdover is ready
 * @chan: pointer to channel state
 *
 * Return: true if holdover is ready, false otherwise
 */
static inline bool zl3073x_chan_is_ho_ready(const struct zl3073x_chan *chan)
{
	return !!FIELD_GET(ZL_DPLL_MON_STATUS_HO_READY, chan->mon_status);
}

/**
 * zl3073x_chan_refsel_state_get - get reference selection state
 * @chan: pointer to channel state
 *
 * Return: reference selection state of the given DPLL channel
 */
static inline u8 zl3073x_chan_refsel_state_get(const struct zl3073x_chan *chan)
{
	return FIELD_GET(ZL_DPLL_REFSEL_STATUS_STATE, chan->refsel_status);
}

/**
 * zl3073x_chan_refsel_ref_get - get currently selected reference in auto mode
 * @chan: pointer to channel state
 *
 * Return: reference selected by the DPLL in automatic mode
 */
static inline u8 zl3073x_chan_refsel_ref_get(const struct zl3073x_chan *chan)
{
	return FIELD_GET(ZL_DPLL_REFSEL_STATUS_REFSEL, chan->refsel_status);
}

#endif /* _ZL3073X_CHAN_H */