xref: /linux/drivers/dpll/zl3073x/ref.c (revision 607f2c00c61faa3b437dbb0d38287e7a9d398a52)
1*607f2c00SIvan Vecera // SPDX-License-Identifier: GPL-2.0-only
2*607f2c00SIvan Vecera 
3*607f2c00SIvan Vecera #include <linux/bitfield.h>
4*607f2c00SIvan Vecera #include <linux/cleanup.h>
5*607f2c00SIvan Vecera #include <linux/dev_printk.h>
6*607f2c00SIvan Vecera #include <linux/string.h>
7*607f2c00SIvan Vecera #include <linux/string_choices.h>
8*607f2c00SIvan Vecera #include <linux/types.h>
9*607f2c00SIvan Vecera 
10*607f2c00SIvan Vecera #include "core.h"
11*607f2c00SIvan Vecera #include "ref.h"
12*607f2c00SIvan Vecera 
13*607f2c00SIvan Vecera /**
14*607f2c00SIvan Vecera  * zl3073x_ref_freq_factorize - factorize given frequency
15*607f2c00SIvan Vecera  * @freq: input frequency
16*607f2c00SIvan Vecera  * @base: base frequency
17*607f2c00SIvan Vecera  * @mult: multiplier
18*607f2c00SIvan Vecera  *
19*607f2c00SIvan Vecera  * Checks if the given frequency can be factorized using one of the
20*607f2c00SIvan Vecera  * supported base frequencies. If so the base frequency and multiplier
21*607f2c00SIvan Vecera  * are stored into appropriate parameters if they are not NULL.
22*607f2c00SIvan Vecera  *
23*607f2c00SIvan Vecera  * Return: 0 on success, -EINVAL if the frequency cannot be factorized
24*607f2c00SIvan Vecera  */
25*607f2c00SIvan Vecera int
26*607f2c00SIvan Vecera zl3073x_ref_freq_factorize(u32 freq, u16 *base, u16 *mult)
27*607f2c00SIvan Vecera {
28*607f2c00SIvan Vecera 	static const u16 base_freqs[] = {
29*607f2c00SIvan Vecera 		1, 2, 4, 5, 8, 10, 16, 20, 25, 32, 40, 50, 64, 80, 100, 125,
30*607f2c00SIvan Vecera 		128, 160, 200, 250, 256, 320, 400, 500, 625, 640, 800, 1000,
31*607f2c00SIvan Vecera 		1250, 1280, 1600, 2000, 2500, 3125, 3200, 4000, 5000, 6250,
32*607f2c00SIvan Vecera 		6400, 8000, 10000, 12500, 15625, 16000, 20000, 25000, 31250,
33*607f2c00SIvan Vecera 		32000, 40000, 50000, 62500,
34*607f2c00SIvan Vecera 	};
35*607f2c00SIvan Vecera 	u32 div;
36*607f2c00SIvan Vecera 	int i;
37*607f2c00SIvan Vecera 
38*607f2c00SIvan Vecera 	for (i = 0; i < ARRAY_SIZE(base_freqs); i++) {
39*607f2c00SIvan Vecera 		div = freq / base_freqs[i];
40*607f2c00SIvan Vecera 
41*607f2c00SIvan Vecera 		if (div <= U16_MAX && (freq % base_freqs[i]) == 0) {
42*607f2c00SIvan Vecera 			if (base)
43*607f2c00SIvan Vecera 				*base = base_freqs[i];
44*607f2c00SIvan Vecera 			if (mult)
45*607f2c00SIvan Vecera 				*mult = div;
46*607f2c00SIvan Vecera 
47*607f2c00SIvan Vecera 			return 0;
48*607f2c00SIvan Vecera 		}
49*607f2c00SIvan Vecera 	}
50*607f2c00SIvan Vecera 
51*607f2c00SIvan Vecera 	return -EINVAL;
52*607f2c00SIvan Vecera }
53*607f2c00SIvan Vecera 
54*607f2c00SIvan Vecera /**
55*607f2c00SIvan Vecera  * zl3073x_ref_state_fetch - fetch input reference state from hardware
56*607f2c00SIvan Vecera  * @zldev: pointer to zl3073x_dev structure
57*607f2c00SIvan Vecera  * @index: input reference index to fetch state for
58*607f2c00SIvan Vecera  *
59*607f2c00SIvan Vecera  * Function fetches state for the given input reference from hardware and
60*607f2c00SIvan Vecera  * stores it for later use.
61*607f2c00SIvan Vecera  *
62*607f2c00SIvan Vecera  * Return: 0 on success, <0 on error
63*607f2c00SIvan Vecera  */
64*607f2c00SIvan Vecera int zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index)
65*607f2c00SIvan Vecera {
66*607f2c00SIvan Vecera 	struct zl3073x_ref *ref = &zldev->ref[index];
67*607f2c00SIvan Vecera 	int rc;
68*607f2c00SIvan Vecera 
69*607f2c00SIvan Vecera 	/* For differential type inputs the N-pin reference shares
70*607f2c00SIvan Vecera 	 * part of the configuration with the P-pin counterpart.
71*607f2c00SIvan Vecera 	 */
72*607f2c00SIvan Vecera 	if (zl3073x_is_n_pin(index) && zl3073x_ref_is_diff(ref - 1)) {
73*607f2c00SIvan Vecera 		struct zl3073x_ref *p_ref = &zldev->ref[index - 1];
74*607f2c00SIvan Vecera 
75*607f2c00SIvan Vecera 		/* Copy the shared items from the P-pin */
76*607f2c00SIvan Vecera 		ref->config = p_ref->config;
77*607f2c00SIvan Vecera 
78*607f2c00SIvan Vecera 		return 0; /* Finish - no non-shared items for now */
79*607f2c00SIvan Vecera 	}
80*607f2c00SIvan Vecera 
81*607f2c00SIvan Vecera 	guard(mutex)(&zldev->multiop_lock);
82*607f2c00SIvan Vecera 
83*607f2c00SIvan Vecera 	/* Read reference configuration */
84*607f2c00SIvan Vecera 	rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD,
85*607f2c00SIvan Vecera 			   ZL_REG_REF_MB_MASK, BIT(index));
86*607f2c00SIvan Vecera 	if (rc)
87*607f2c00SIvan Vecera 		return rc;
88*607f2c00SIvan Vecera 
89*607f2c00SIvan Vecera 	/* Read ref_config register */
90*607f2c00SIvan Vecera 	rc = zl3073x_read_u8(zldev, ZL_REG_REF_CONFIG, &ref->config);
91*607f2c00SIvan Vecera 	if (rc)
92*607f2c00SIvan Vecera 		return rc;
93*607f2c00SIvan Vecera 
94*607f2c00SIvan Vecera 	dev_dbg(zldev->dev, "REF%u is %s and configured as %s\n", index,
95*607f2c00SIvan Vecera 		str_enabled_disabled(zl3073x_ref_is_enabled(ref)),
96*607f2c00SIvan Vecera 		zl3073x_ref_is_diff(ref) ? "differential" : "single-ended");
97*607f2c00SIvan Vecera 
98*607f2c00SIvan Vecera 	return rc;
99*607f2c00SIvan Vecera }
100*607f2c00SIvan Vecera 
101*607f2c00SIvan Vecera /**
102*607f2c00SIvan Vecera  * zl3073x_ref_state_get - get current input reference state
103*607f2c00SIvan Vecera  * @zldev: pointer to zl3073x_dev structure
104*607f2c00SIvan Vecera  * @index: input reference index to get state for
105*607f2c00SIvan Vecera  *
106*607f2c00SIvan Vecera  * Return: pointer to given input reference state
107*607f2c00SIvan Vecera  */
108*607f2c00SIvan Vecera const struct zl3073x_ref *
109*607f2c00SIvan Vecera zl3073x_ref_state_get(struct zl3073x_dev *zldev, u8 index)
110*607f2c00SIvan Vecera {
111*607f2c00SIvan Vecera 	return &zldev->ref[index];
112*607f2c00SIvan Vecera }
113