1 /* SPDX-License-Identifier: GPL-2.0-only */
2
3 #ifndef _ZL3073X_CORE_H
4 #define _ZL3073X_CORE_H
5
6 #include <linux/kthread.h>
7 #include <linux/list.h>
8 #include <linux/mutex.h>
9 #include <linux/types.h>
10
11 #include "regs.h"
12
13 struct device;
14 struct regmap;
15 struct zl3073x_dpll;
16
17 /*
18 * Hardware limits for ZL3073x chip family
19 */
20 #define ZL3073X_MAX_CHANNELS 5
21 #define ZL3073X_NUM_REFS 10
22 #define ZL3073X_NUM_OUTS 10
23 #define ZL3073X_NUM_SYNTHS 5
24 #define ZL3073X_NUM_INPUT_PINS ZL3073X_NUM_REFS
25 #define ZL3073X_NUM_OUTPUT_PINS (ZL3073X_NUM_OUTS * 2)
26 #define ZL3073X_NUM_PINS (ZL3073X_NUM_INPUT_PINS + \
27 ZL3073X_NUM_OUTPUT_PINS)
28
29 /**
30 * struct zl3073x_ref - input reference invariant info
31 * @enabled: input reference is enabled or disabled
32 * @diff: true if input reference is differential
33 * @ffo: current fractional frequency offset
34 */
35 struct zl3073x_ref {
36 bool enabled;
37 bool diff;
38 s64 ffo;
39 };
40
41 /**
42 * struct zl3073x_out - output invariant info
43 * @enabled: out is enabled or disabled
44 * @synth: synthesizer the out is connected to
45 * @signal_format: out signal format
46 */
47 struct zl3073x_out {
48 bool enabled;
49 u8 synth;
50 u8 signal_format;
51 };
52
53 /**
54 * struct zl3073x_synth - synthesizer invariant info
55 * @freq: synthesizer frequency
56 * @dpll: ID of DPLL the synthesizer is driven by
57 * @enabled: synth is enabled or disabled
58 */
59 struct zl3073x_synth {
60 u32 freq;
61 u8 dpll;
62 bool enabled;
63 };
64
65 /**
66 * struct zl3073x_dev - zl3073x device
67 * @dev: pointer to device
68 * @regmap: regmap to access device registers
69 * @multiop_lock: to serialize multiple register operations
70 * @clock_id: clock id of the device
71 * @ref: array of input references' invariants
72 * @out: array of outs' invariants
73 * @synth: array of synths' invariants
74 * @dplls: list of DPLLs
75 * @kworker: thread for periodic work
76 * @work: periodic work
77 */
78 struct zl3073x_dev {
79 struct device *dev;
80 struct regmap *regmap;
81 struct mutex multiop_lock;
82 u64 clock_id;
83
84 /* Invariants */
85 struct zl3073x_ref ref[ZL3073X_NUM_REFS];
86 struct zl3073x_out out[ZL3073X_NUM_OUTS];
87 struct zl3073x_synth synth[ZL3073X_NUM_SYNTHS];
88
89 /* DPLL channels */
90 struct list_head dplls;
91
92 /* Monitor */
93 struct kthread_worker *kworker;
94 struct kthread_delayed_work work;
95 };
96
97 struct zl3073x_chip_info {
98 const u16 *ids;
99 size_t num_ids;
100 int num_channels;
101 };
102
103 extern const struct zl3073x_chip_info zl30731_chip_info;
104 extern const struct zl3073x_chip_info zl30732_chip_info;
105 extern const struct zl3073x_chip_info zl30733_chip_info;
106 extern const struct zl3073x_chip_info zl30734_chip_info;
107 extern const struct zl3073x_chip_info zl30735_chip_info;
108 extern const struct regmap_config zl3073x_regmap_config;
109
110 struct zl3073x_dev *zl3073x_devm_alloc(struct device *dev);
111 int zl3073x_dev_probe(struct zl3073x_dev *zldev,
112 const struct zl3073x_chip_info *chip_info);
113
114 /**********************
115 * Registers operations
116 **********************/
117
118 int zl3073x_mb_op(struct zl3073x_dev *zldev, unsigned int op_reg, u8 op_val,
119 unsigned int mask_reg, u16 mask_val);
120 int zl3073x_poll_zero_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 mask);
121 int zl3073x_read_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 *val);
122 int zl3073x_read_u16(struct zl3073x_dev *zldev, unsigned int reg, u16 *val);
123 int zl3073x_read_u32(struct zl3073x_dev *zldev, unsigned int reg, u32 *val);
124 int zl3073x_read_u48(struct zl3073x_dev *zldev, unsigned int reg, u64 *val);
125 int zl3073x_write_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 val);
126 int zl3073x_write_u16(struct zl3073x_dev *zldev, unsigned int reg, u16 val);
127 int zl3073x_write_u32(struct zl3073x_dev *zldev, unsigned int reg, u32 val);
128 int zl3073x_write_u48(struct zl3073x_dev *zldev, unsigned int reg, u64 val);
129
130 /*****************
131 * Misc operations
132 *****************/
133
134 int zl3073x_ref_freq_factorize(u32 freq, u16 *base, u16 *mult);
135 int zl3073x_ref_phase_offsets_update(struct zl3073x_dev *zldev, int channel);
136
137 static inline bool
zl3073x_is_n_pin(u8 id)138 zl3073x_is_n_pin(u8 id)
139 {
140 /* P-pins ids are even while N-pins are odd */
141 return id & 1;
142 }
143
144 static inline bool
zl3073x_is_p_pin(u8 id)145 zl3073x_is_p_pin(u8 id)
146 {
147 return !zl3073x_is_n_pin(id);
148 }
149
150 /**
151 * zl3073x_input_pin_ref_get - get reference for given input pin
152 * @id: input pin id
153 *
154 * Return: reference id for the given input pin
155 */
156 static inline u8
zl3073x_input_pin_ref_get(u8 id)157 zl3073x_input_pin_ref_get(u8 id)
158 {
159 return id;
160 }
161
162 /**
163 * zl3073x_output_pin_out_get - get output for the given output pin
164 * @id: output pin id
165 *
166 * Return: output id for the given output pin
167 */
168 static inline u8
zl3073x_output_pin_out_get(u8 id)169 zl3073x_output_pin_out_get(u8 id)
170 {
171 /* Output pin pair shares the single output */
172 return id / 2;
173 }
174
175 /**
176 * zl3073x_ref_ffo_get - get current fractional frequency offset
177 * @zldev: pointer to zl3073x device
178 * @index: input reference index
179 *
180 * Return: the latest measured fractional frequency offset
181 */
182 static inline s64
zl3073x_ref_ffo_get(struct zl3073x_dev * zldev,u8 index)183 zl3073x_ref_ffo_get(struct zl3073x_dev *zldev, u8 index)
184 {
185 return zldev->ref[index].ffo;
186 }
187
188 /**
189 * zl3073x_ref_is_diff - check if the given input reference is differential
190 * @zldev: pointer to zl3073x device
191 * @index: input reference index
192 *
193 * Return: true if reference is differential, false if reference is single-ended
194 */
195 static inline bool
zl3073x_ref_is_diff(struct zl3073x_dev * zldev,u8 index)196 zl3073x_ref_is_diff(struct zl3073x_dev *zldev, u8 index)
197 {
198 return zldev->ref[index].diff;
199 }
200
201 /**
202 * zl3073x_ref_is_enabled - check if the given input reference is enabled
203 * @zldev: pointer to zl3073x device
204 * @index: input reference index
205 *
206 * Return: true if input refernce is enabled, false otherwise
207 */
208 static inline bool
zl3073x_ref_is_enabled(struct zl3073x_dev * zldev,u8 index)209 zl3073x_ref_is_enabled(struct zl3073x_dev *zldev, u8 index)
210 {
211 return zldev->ref[index].enabled;
212 }
213
214 /**
215 * zl3073x_synth_dpll_get - get DPLL ID the synth is driven by
216 * @zldev: pointer to zl3073x device
217 * @index: synth index
218 *
219 * Return: ID of DPLL the given synthetizer is driven by
220 */
221 static inline u8
zl3073x_synth_dpll_get(struct zl3073x_dev * zldev,u8 index)222 zl3073x_synth_dpll_get(struct zl3073x_dev *zldev, u8 index)
223 {
224 return zldev->synth[index].dpll;
225 }
226
227 /**
228 * zl3073x_synth_freq_get - get synth current freq
229 * @zldev: pointer to zl3073x device
230 * @index: synth index
231 *
232 * Return: frequency of given synthetizer
233 */
234 static inline u32
zl3073x_synth_freq_get(struct zl3073x_dev * zldev,u8 index)235 zl3073x_synth_freq_get(struct zl3073x_dev *zldev, u8 index)
236 {
237 return zldev->synth[index].freq;
238 }
239
240 /**
241 * zl3073x_synth_is_enabled - check if the given synth is enabled
242 * @zldev: pointer to zl3073x device
243 * @index: synth index
244 *
245 * Return: true if synth is enabled, false otherwise
246 */
247 static inline bool
zl3073x_synth_is_enabled(struct zl3073x_dev * zldev,u8 index)248 zl3073x_synth_is_enabled(struct zl3073x_dev *zldev, u8 index)
249 {
250 return zldev->synth[index].enabled;
251 }
252
253 /**
254 * zl3073x_out_synth_get - get synth connected to given output
255 * @zldev: pointer to zl3073x device
256 * @index: output index
257 *
258 * Return: index of synth connected to given output.
259 */
260 static inline u8
zl3073x_out_synth_get(struct zl3073x_dev * zldev,u8 index)261 zl3073x_out_synth_get(struct zl3073x_dev *zldev, u8 index)
262 {
263 return zldev->out[index].synth;
264 }
265
266 /**
267 * zl3073x_out_is_enabled - check if the given output is enabled
268 * @zldev: pointer to zl3073x device
269 * @index: output index
270 *
271 * Return: true if the output is enabled, false otherwise
272 */
273 static inline bool
zl3073x_out_is_enabled(struct zl3073x_dev * zldev,u8 index)274 zl3073x_out_is_enabled(struct zl3073x_dev *zldev, u8 index)
275 {
276 u8 synth;
277
278 /* Output is enabled only if associated synth is enabled */
279 synth = zl3073x_out_synth_get(zldev, index);
280 if (zl3073x_synth_is_enabled(zldev, synth))
281 return zldev->out[index].enabled;
282
283 return false;
284 }
285
286 /**
287 * zl3073x_out_signal_format_get - get output signal format
288 * @zldev: pointer to zl3073x device
289 * @index: output index
290 *
291 * Return: signal format of given output
292 */
293 static inline u8
zl3073x_out_signal_format_get(struct zl3073x_dev * zldev,u8 index)294 zl3073x_out_signal_format_get(struct zl3073x_dev *zldev, u8 index)
295 {
296 return zldev->out[index].signal_format;
297 }
298
299 /**
300 * zl3073x_out_dpll_get - get DPLL ID the output is driven by
301 * @zldev: pointer to zl3073x device
302 * @index: output index
303 *
304 * Return: ID of DPLL the given output is driven by
305 */
306 static inline
zl3073x_out_dpll_get(struct zl3073x_dev * zldev,u8 index)307 u8 zl3073x_out_dpll_get(struct zl3073x_dev *zldev, u8 index)
308 {
309 u8 synth;
310
311 /* Get synthesizer connected to given output */
312 synth = zl3073x_out_synth_get(zldev, index);
313
314 /* Return DPLL that drives the synth */
315 return zl3073x_synth_dpll_get(zldev, synth);
316 }
317
318 /**
319 * zl3073x_out_is_diff - check if the given output is differential
320 * @zldev: pointer to zl3073x device
321 * @index: output index
322 *
323 * Return: true if output is differential, false if output is single-ended
324 */
325 static inline bool
zl3073x_out_is_diff(struct zl3073x_dev * zldev,u8 index)326 zl3073x_out_is_diff(struct zl3073x_dev *zldev, u8 index)
327 {
328 switch (zl3073x_out_signal_format_get(zldev, index)) {
329 case ZL_OUTPUT_MODE_SIGNAL_FORMAT_LVDS:
330 case ZL_OUTPUT_MODE_SIGNAL_FORMAT_DIFF:
331 case ZL_OUTPUT_MODE_SIGNAL_FORMAT_LOWVCM:
332 return true;
333 default:
334 break;
335 }
336
337 return false;
338 }
339
340 /**
341 * zl3073x_output_pin_is_enabled - check if the given output pin is enabled
342 * @zldev: pointer to zl3073x device
343 * @id: output pin id
344 *
345 * Checks if the output of the given output pin is enabled and also that
346 * its signal format also enables the given pin.
347 *
348 * Return: true if output pin is enabled, false if output pin is disabled
349 */
350 static inline bool
zl3073x_output_pin_is_enabled(struct zl3073x_dev * zldev,u8 id)351 zl3073x_output_pin_is_enabled(struct zl3073x_dev *zldev, u8 id)
352 {
353 u8 output = zl3073x_output_pin_out_get(id);
354
355 /* Check if the whole output is enabled */
356 if (!zl3073x_out_is_enabled(zldev, output))
357 return false;
358
359 /* Check signal format */
360 switch (zl3073x_out_signal_format_get(zldev, output)) {
361 case ZL_OUTPUT_MODE_SIGNAL_FORMAT_DISABLED:
362 /* Both output pins are disabled by signal format */
363 return false;
364
365 case ZL_OUTPUT_MODE_SIGNAL_FORMAT_1P:
366 /* Output is one single ended P-pin output */
367 if (zl3073x_is_n_pin(id))
368 return false;
369 break;
370 case ZL_OUTPUT_MODE_SIGNAL_FORMAT_1N:
371 /* Output is one single ended N-pin output */
372 if (zl3073x_is_p_pin(id))
373 return false;
374 break;
375 default:
376 /* For other format both pins are enabled */
377 break;
378 }
379
380 return true;
381 }
382
383 #endif /* _ZL3073X_CORE_H */
384