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
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
|
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _ZL3073X_CORE_H
#define _ZL3073X_CORE_H
#include <linux/bitfield.h>
#include <linux/kthread.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/types.h>
#include "chan.h"
#include "out.h"
#include "ref.h"
#include "regs.h"
#include "synth.h"
struct device;
struct regmap;
struct zl3073x_dpll;
enum zl3073x_flags {
ZL3073X_FLAG_REF_PHASE_COMP_32_BIT,
ZL3073X_FLAG_DIE_TEMP_BIT,
ZL3073X_FLAGS_NBITS /* must be last */
};
#define __ZL3073X_FLAG(name) BIT(ZL3073X_FLAG_ ## name ## _BIT)
#define ZL3073X_FLAG_REF_PHASE_COMP_32 __ZL3073X_FLAG(REF_PHASE_COMP_32)
#define ZL3073X_FLAG_DIE_TEMP __ZL3073X_FLAG(DIE_TEMP)
/**
* struct zl3073x_chip_info - chip variant identification
* @id: chip ID
* @num_channels: number of DPLL channels supported by this variant
* @flags: chip variant flags
*/
struct zl3073x_chip_info {
u16 id;
u8 num_channels;
unsigned long flags;
};
/**
* struct zl3073x_dev - zl3073x device
* @dev: pointer to device
* @regmap: regmap to access device registers
* @info: detected chip info
* @multiop_lock: to serialize multiple register operations
* @ref: array of input references' invariants
* @out: array of outs' invariants
* @synth: array of synths' invariants
* @chan: array of DPLL channels' state
* @dplls: list of DPLLs
* @kworker: thread for periodic work
* @work: periodic work
* @clock_id: clock id of the device
* @phase_avg_factor: phase offset measurement averaging factor
*/
struct zl3073x_dev {
struct device *dev;
struct regmap *regmap;
const struct zl3073x_chip_info *info;
struct mutex multiop_lock;
/* Invariants */
struct zl3073x_ref ref[ZL3073X_NUM_REFS];
struct zl3073x_out out[ZL3073X_NUM_OUTS];
struct zl3073x_synth synth[ZL3073X_NUM_SYNTHS];
struct zl3073x_chan chan[ZL3073X_MAX_CHANNELS];
/* DPLL channels */
struct list_head dplls;
/* Monitor */
struct kthread_worker *kworker;
struct kthread_delayed_work work;
/* Devlink parameters */
u64 clock_id;
u8 phase_avg_factor;
};
extern const struct regmap_config zl3073x_regmap_config;
struct zl3073x_dev *zl3073x_devm_alloc(struct device *dev);
int zl3073x_dev_probe(struct zl3073x_dev *zldev);
int zl3073x_dev_start(struct zl3073x_dev *zldev, bool full);
void zl3073x_dev_stop(struct zl3073x_dev *zldev);
static inline u8 zl3073x_dev_phase_avg_factor_get(struct zl3073x_dev *zldev)
{
return zldev->phase_avg_factor;
}
int zl3073x_dev_phase_avg_factor_set(struct zl3073x_dev *zldev, u8 factor);
/**********************
* Registers operations
**********************/
/**
* struct zl3073x_hwreg_seq_item - HW register write sequence item
* @addr: HW register to be written
* @value: value to be written to HW register
* @mask: bitmask indicating bits to be updated
* @wait: number of ms to wait after register write
*/
struct zl3073x_hwreg_seq_item {
u32 addr;
u32 value;
u32 mask;
u32 wait;
};
#define HWREG_SEQ_ITEM(_addr, _value, _mask, _wait) \
{ \
.addr = _addr, \
.value = FIELD_PREP_CONST(_mask, _value), \
.mask = _mask, \
.wait = _wait, \
}
int zl3073x_mb_op(struct zl3073x_dev *zldev, unsigned int op_reg, u8 op_val,
unsigned int mask_reg, u16 mask_val);
int zl3073x_poll_zero_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 mask);
int zl3073x_read_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 *val);
int zl3073x_read_u16(struct zl3073x_dev *zldev, unsigned int reg, u16 *val);
int zl3073x_read_u32(struct zl3073x_dev *zldev, unsigned int reg, u32 *val);
int zl3073x_read_u48(struct zl3073x_dev *zldev, unsigned int reg, u64 *val);
int zl3073x_write_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 val);
int zl3073x_write_u16(struct zl3073x_dev *zldev, unsigned int reg, u16 val);
int zl3073x_write_u32(struct zl3073x_dev *zldev, unsigned int reg, u32 val);
int zl3073x_write_u48(struct zl3073x_dev *zldev, unsigned int reg, u64 val);
int zl3073x_read_hwreg(struct zl3073x_dev *zldev, u32 addr, u32 *value);
int zl3073x_write_hwreg(struct zl3073x_dev *zldev, u32 addr, u32 value);
int zl3073x_update_hwreg(struct zl3073x_dev *zldev, u32 addr, u32 value,
u32 mask);
int zl3073x_write_hwreg_seq(struct zl3073x_dev *zldev,
const struct zl3073x_hwreg_seq_item *seq,
size_t num_items);
/*****************
* Misc operations
*****************/
int zl3073x_ref_phase_offsets_update(struct zl3073x_dev *zldev, int channel);
/**
* zl3073x_dev_is_ref_phase_comp_32bit - check ref phase comp register size
* @zldev: pointer to zl3073x device
*
* Some chip IDs have a 32-bit wide ref_phase_offset_comp register instead
* of the default 48-bit.
*
* Return: true if the register is 32-bit, false if 48-bit
*/
static inline bool
zl3073x_dev_is_ref_phase_comp_32bit(struct zl3073x_dev *zldev)
{
return zldev->info->flags & ZL3073X_FLAG_REF_PHASE_COMP_32;
}
static inline bool
zl3073x_is_n_pin(u8 id)
{
/* P-pins ids are even while N-pins are odd */
return id & 1;
}
static inline bool
zl3073x_is_p_pin(u8 id)
{
return !zl3073x_is_n_pin(id);
}
/**
* zl3073x_input_pin_ref_get - get reference for given input pin
* @id: input pin id
*
* Return: reference id for the given input pin
*/
static inline u8
zl3073x_input_pin_ref_get(u8 id)
{
return id;
}
/**
* zl3073x_output_pin_out_get - get output for the given output pin
* @id: output pin id
*
* Return: output id for the given output pin
*/
static inline u8
zl3073x_output_pin_out_get(u8 id)
{
/* Output pin pair shares the single output */
return id / 2;
}
/**
* zl3073x_dev_ref_freq_get - get input reference frequency
* @zldev: pointer to zl3073x device
* @index: input reference index
*
* Return: frequency of given input reference
*/
static inline u32
zl3073x_dev_ref_freq_get(struct zl3073x_dev *zldev, u8 index)
{
const struct zl3073x_ref *ref = zl3073x_ref_state_get(zldev, index);
return zl3073x_ref_freq_get(ref);
}
/**
* zl3073x_dev_ref_is_diff - check if the given input reference is differential
* @zldev: pointer to zl3073x device
* @index: input reference index
*
* Return: true if reference is differential, false if reference is single-ended
*/
static inline bool
zl3073x_dev_ref_is_diff(struct zl3073x_dev *zldev, u8 index)
{
const struct zl3073x_ref *ref = zl3073x_ref_state_get(zldev, index);
return zl3073x_ref_is_diff(ref);
}
/*
* zl3073x_dev_ref_is_status_ok - check the given input reference status
* @zldev: pointer to zl3073x device
* @index: input reference index
*
* Return: true if the status is ok, false otherwise
*/
static inline bool
zl3073x_dev_ref_is_status_ok(struct zl3073x_dev *zldev, u8 index)
{
const struct zl3073x_ref *ref = zl3073x_ref_state_get(zldev, index);
return zl3073x_ref_is_status_ok(ref);
}
/**
* zl3073x_dev_synth_freq_get - get synth current freq
* @zldev: pointer to zl3073x device
* @index: synth index
*
* Return: frequency of given synthetizer
*/
static inline u32
zl3073x_dev_synth_freq_get(struct zl3073x_dev *zldev, u8 index)
{
const struct zl3073x_synth *synth;
synth = zl3073x_synth_state_get(zldev, index);
return zl3073x_synth_freq_get(synth);
}
/**
* zl3073x_dev_out_synth_get - get synth connected to given output
* @zldev: pointer to zl3073x device
* @index: output index
*
* Return: index of synth connected to given output.
*/
static inline u8
zl3073x_dev_out_synth_get(struct zl3073x_dev *zldev, u8 index)
{
const struct zl3073x_out *out = zl3073x_out_state_get(zldev, index);
return zl3073x_out_synth_get(out);
}
/**
* zl3073x_dev_out_is_enabled - check if the given output is enabled
* @zldev: pointer to zl3073x device
* @index: output index
*
* Return: true if the output is enabled, false otherwise
*/
static inline bool
zl3073x_dev_out_is_enabled(struct zl3073x_dev *zldev, u8 index)
{
const struct zl3073x_out *out = zl3073x_out_state_get(zldev, index);
const struct zl3073x_synth *synth;
u8 synth_id;
/* Output is enabled only if associated synth is enabled */
synth_id = zl3073x_out_synth_get(out);
synth = zl3073x_synth_state_get(zldev, synth_id);
return zl3073x_synth_is_enabled(synth) && zl3073x_out_is_enabled(out);
}
/**
* zl3073x_dev_out_dpll_get - get DPLL ID the output is driven by
* @zldev: pointer to zl3073x device
* @index: output index
*
* Return: ID of DPLL the given output is driven by
*/
static inline
u8 zl3073x_dev_out_dpll_get(struct zl3073x_dev *zldev, u8 index)
{
const struct zl3073x_out *out = zl3073x_out_state_get(zldev, index);
const struct zl3073x_synth *synth;
u8 synth_id;
/* Get synthesizer connected to given output */
synth_id = zl3073x_out_synth_get(out);
synth = zl3073x_synth_state_get(zldev, synth_id);
/* Return DPLL that drives the synth */
return zl3073x_synth_dpll_get(synth);
}
/**
* zl3073x_dev_output_pin_freq_get - get output pin frequency
* @zldev: pointer to zl3073x device
* @id: output pin id
*
* Computes the output pin frequency based on the synth frequency, output
* divisor, and signal format. For N-div formats, N-pin frequency is
* additionally divided by esync_n_period.
*
* Return: frequency of the given output pin in Hz
*/
static inline u32
zl3073x_dev_output_pin_freq_get(struct zl3073x_dev *zldev, u8 id)
{
const struct zl3073x_synth *synth;
const struct zl3073x_out *out;
u8 out_id;
u32 freq;
out_id = zl3073x_output_pin_out_get(id);
out = zl3073x_out_state_get(zldev, out_id
|