File Index
Files and directories
Sign in
FILE

ref.c

File preview with syntax highlighting.

linux-6.19.14/drivers/dpll/zl3073x/ref.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2
  3#include <linux/bitfield.h>
  4#include <linux/cleanup.h>
  5#include <linux/dev_printk.h>
  6#include <linux/string.h>
  7#include <linux/string_choices.h>
  8#include <linux/types.h>
  9
 10#include "core.h"
 11#include "ref.h"
 12
 13/**
 14 * zl3073x_ref_freq_factorize - factorize given frequency
 15 * @freq: input frequency
 16 * @base: base frequency
 17 * @mult: multiplier
 18 *
 19 * Checks if the given frequency can be factorized using one of the
 20 * supported base frequencies. If so the base frequency and multiplier
 21 * are stored into appropriate parameters if they are not NULL.
 22 *
 23 * Return: 0 on success, -EINVAL if the frequency cannot be factorized
 24 */
 25int
 26zl3073x_ref_freq_factorize(u32 freq, u16 *base, u16 *mult)
 27{
 28	static const u16 base_freqs[] = {
 29		1, 2, 4, 5, 8, 10, 16, 20, 25, 32, 40, 50, 64, 80, 100, 125,
 30		128, 160, 200, 250, 256, 320, 400, 500, 625, 640, 800, 1000,
 31		1250, 1280, 1600, 2000, 2500, 3125, 3200, 4000, 5000, 6250,
 32		6400, 8000, 10000, 12500, 15625, 16000, 20000, 25000, 31250,
 33		32000, 40000, 50000, 62500,
 34	};
 35	u32 div;
 36	int i;
 37
 38	for (i = 0; i < ARRAY_SIZE(base_freqs); i++) {
 39		div = freq / base_freqs[i];
 40
 41		if (div <= U16_MAX && (freq % base_freqs[i]) == 0) {
 42			if (base)
 43				*base = base_freqs[i];
 44			if (mult)
 45				*mult = div;
 46
 47			return 0;
 48		}
 49	}
 50
 51	return -EINVAL;
 52}
 53
 54/**
 55 * zl3073x_ref_state_fetch - fetch input reference state from hardware
 56 * @zldev: pointer to zl3073x_dev structure
 57 * @index: input reference index to fetch state for
 58 *
 59 * Function fetches state for the given input reference from hardware and
 60 * stores it for later use.
 61 *
 62 * Return: 0 on success, <0 on error
 63 */
 64int zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index)
 65{
 66	struct zl3073x_ref *ref = &zldev->ref[index];
 67	int rc;
 68
 69	/* For differential type inputs the N-pin reference shares
 70	 * part of the configuration with the P-pin counterpart.
 71	 */
 72	if (zl3073x_is_n_pin(index) && zl3073x_ref_is_diff(ref - 1)) {
 73		struct zl3073x_ref *p_ref = ref - 1; /* P-pin counterpart*/
 74
 75		/* Copy the shared items from the P-pin */
 76		ref->config = p_ref->config;
 77		ref->esync_n_div = p_ref->esync_n_div;
 78		ref->freq_base = p_ref->freq_base;
 79		ref->freq_mult = p_ref->freq_mult;
 80		ref->freq_ratio_m = p_ref->freq_ratio_m;
 81		ref->freq_ratio_n = p_ref->freq_ratio_n;
 82		ref->phase_comp = p_ref->phase_comp;
 83		ref->sync_ctrl = p_ref->sync_ctrl;
 84
 85		return 0; /* Finish - no non-shared items for now */
 86	}
 87
 88	guard(mutex)(&zldev->multiop_lock);
 89
 90	/* Read reference configuration */
 91	rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD,
 92			   ZL_REG_REF_MB_MASK, BIT(index));
 93	if (rc)
 94		return rc;
 95
 96	/* Read ref_config register */
 97	rc = zl3073x_read_u8(zldev, ZL_REG_REF_CONFIG, &ref->config);
 98	if (rc)
 99		return rc;
100
101	/* Read frequency related registers */
102	rc = zl3073x_read_u16(zldev, ZL_REG_REF_FREQ_BASE, &ref->freq_base);
103	if (rc)
104		return rc;
105	rc = zl3073x_read_u16(zldev, ZL_REG_REF_FREQ_MULT, &ref->freq_mult);
106	if (rc)
107		return rc;
108	rc = zl3073x_read_u16(zldev, ZL_REG_REF_RATIO_M, &ref->freq_ratio_m);
109	if (rc)
110		return rc;
111	rc = zl3073x_read_u16(zldev, ZL_REG_REF_RATIO_N, &ref->freq_ratio_n);
112	if (rc)
113		return rc;
114
115	/* Read eSync and N-div rated registers */
116	rc = zl3073x_read_u32(zldev, ZL_REG_REF_ESYNC_DIV, &ref->esync_n_div);
117	if (rc)
118		return rc;
119	rc = zl3073x_read_u8(zldev, ZL_REG_REF_SYNC_CTRL, &ref->sync_ctrl);
120	if (rc)
121		return rc;
122
123	/* Read phase compensation register */
124	if (zl3073x_dev_is_ref_phase_comp_32bit(zldev)) {
125		u32 val;
126
127		rc = zl3073x_read_u32(zldev, ZL_REG_REF_PHASE_OFFSET_COMP_32,
128				      &val);
129		ref->phase_comp = val;
130	} else {
131		rc = zl3073x_read_u48(zldev, ZL_REG_REF_PHASE_OFFSET_COMP,
132				      &ref->phase_comp);
133	}
134	if (rc)
135		return rc;
136
137	dev_dbg(zldev->dev, "REF%u is %s and configured as %s\n", index,
138		str_enabled_disabled(zl3073x_ref_is_enabled(ref)),
139		zl3073x_ref_is_diff(ref) ? "differential" : "single-ended");
140
141	return rc;
142}
143
144/**
145 * zl3073x_ref_state_get - get current input reference state
146 * @zldev: pointer to zl3073x_dev structure
147 * @index: input reference index to get state for
148 *
149 * Return: pointer to given input reference state
150 */
151const struct zl3073x_ref *
152zl3073x_ref_state_get(struct zl3073x_dev *zldev, u8 index)
153{
154	return &zldev->ref[index];
155}
156
157int zl3073x_ref_state_set(struct zl3073x_dev *zldev, u8 index,
158			  const struct zl3073x_ref *ref)
159{
160	struct zl3073x_ref *dref = &zldev->ref[index];
161	int rc;
162
163	guard(mutex)(&zldev->multiop_lock);
164
165	/* Read reference configuration into mailbox */
166	rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD,
167			   ZL_REG_REF_MB_MASK, BIT(index));
168	if (rc)
169		return rc;
170
171	/* Update mailbox with changed values */
172	if (dref->freq_base != ref->freq_base)
173		rc = zl3073x_write_u16(zldev, ZL_REG_REF_FREQ_BASE,
174				       ref->freq_base);
175	if (!rc && dref->freq_mult != ref->freq_mult)
176		rc = zl3073x_write_u16(zldev, ZL_REG_REF_FREQ_MULT,
177				       ref->freq_mult);
178	if (!rc && dref->freq_ratio_m != ref->freq_ratio_m)
179		rc = zl3073x_write_u16(zldev, ZL_REG_REF_RATIO_M,
180				       ref->freq_ratio_m);
181	if (!rc && dref->freq_ratio_n != ref->freq_ratio_n)
182		rc = zl3073x_write_u16(zldev, ZL_REG_REF_RATIO_N,
183				       ref->freq_ratio_n);
184	if (!rc && dref->esync_n_div != ref->esync_n_div)
185		rc = zl3073x_write_u32(zldev, ZL_REG_REF_ESYNC_DIV,
186				       ref->esync_n_div);
187	if (!rc && dref->sync_ctrl != ref->sync_ctrl)
188		rc = zl3073x_write_u8(zldev, ZL_REG_REF_SYNC_CTRL,
189				      ref->sync_ctrl);
190	if (!rc && dref->phase_comp != ref->phase_comp) {
191		if (zl3073x_dev_is_ref_phase_comp_32bit(zldev))
192			rc = zl3073x_write_u32(zldev,
193					       ZL_REG_REF_PHASE_OFFSET_COMP_32,
194					       ref->phase_comp);
195		else
196			rc = zl3073x_write_u48(zldev,
197					       ZL_REG_REF_PHASE_OFFSET_COMP,
198					       ref->phase_comp);
199	}
200	if (rc)
201		return rc;
202
203	/* Commit reference configuration */
204	rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_WR,
205			   ZL_REG_REF_MB_MASK, BIT(index));
206	if (rc)
207		return rc;
208
209	/* After successful commit store new state */
210	dref->freq_base = ref->freq_base;
211	dref->freq_mult = ref->freq_mult;
212	dref->freq_ratio_m = ref->freq_ratio_m;
213	dref->freq_ratio_n = ref->freq_ratio_n;
214	dref->esync_n_div = ref->esync_n_div;
215	dref->sync_ctrl = ref->sync_ctrl;
216	dref->phase_comp = ref->phase_comp;
217
218	return 0;
219}
~/ Read-only file preview.