xref: /linux/drivers/dpll/zl3073x/core.h (revision 8be4d31cb8aaeea27bde4b7ddb26e28a89062ebf)
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