xref: /linux/drivers/dpll/zl3073x/out.c (revision 84318277d6334c6981ab326d4acc87c6a6ddc9b8)
1607f2c00SIvan Vecera // SPDX-License-Identifier: GPL-2.0-only
2607f2c00SIvan Vecera 
3607f2c00SIvan Vecera #include <linux/bitfield.h>
4607f2c00SIvan Vecera #include <linux/cleanup.h>
5607f2c00SIvan Vecera #include <linux/dev_printk.h>
6607f2c00SIvan Vecera #include <linux/string.h>
7607f2c00SIvan Vecera #include <linux/string_choices.h>
8607f2c00SIvan Vecera #include <linux/types.h>
9607f2c00SIvan Vecera 
10607f2c00SIvan Vecera #include "core.h"
11607f2c00SIvan Vecera #include "out.h"
12607f2c00SIvan Vecera 
13607f2c00SIvan Vecera /**
14607f2c00SIvan Vecera  * zl3073x_out_state_fetch - fetch output state from hardware
15607f2c00SIvan Vecera  * @zldev: pointer to zl3073x_dev structure
16607f2c00SIvan Vecera  * @index: output index to fetch state for
17607f2c00SIvan Vecera  *
18607f2c00SIvan Vecera  * Function fetches state of the given output from hardware and stores it
19607f2c00SIvan Vecera  * for later use.
20607f2c00SIvan Vecera  *
21607f2c00SIvan Vecera  * Return: 0 on success, <0 on error
22607f2c00SIvan Vecera  */
23607f2c00SIvan Vecera int zl3073x_out_state_fetch(struct zl3073x_dev *zldev, u8 index)
24607f2c00SIvan Vecera {
25607f2c00SIvan Vecera 	struct zl3073x_out *out = &zldev->out[index];
26607f2c00SIvan Vecera 	int rc;
27607f2c00SIvan Vecera 
28607f2c00SIvan Vecera 	/* Read output configuration */
29607f2c00SIvan Vecera 	rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_CTRL(index), &out->ctrl);
30607f2c00SIvan Vecera 	if (rc)
31607f2c00SIvan Vecera 		return rc;
32607f2c00SIvan Vecera 
33607f2c00SIvan Vecera 	dev_dbg(zldev->dev, "OUT%u is %s and connected to SYNTH%u\n", index,
34607f2c00SIvan Vecera 		str_enabled_disabled(zl3073x_out_is_enabled(out)),
35607f2c00SIvan Vecera 		zl3073x_out_synth_get(out));
36607f2c00SIvan Vecera 
37607f2c00SIvan Vecera 	guard(mutex)(&zldev->multiop_lock);
38607f2c00SIvan Vecera 
39607f2c00SIvan Vecera 	/* Read output configuration */
40607f2c00SIvan Vecera 	rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD,
41607f2c00SIvan Vecera 			   ZL_REG_OUTPUT_MB_MASK, BIT(index));
42607f2c00SIvan Vecera 	if (rc)
43607f2c00SIvan Vecera 		return rc;
44607f2c00SIvan Vecera 
45607f2c00SIvan Vecera 	/* Read output mode */
46607f2c00SIvan Vecera 	rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_MODE, &out->mode);
47607f2c00SIvan Vecera 	if (rc)
48607f2c00SIvan Vecera 		return rc;
49607f2c00SIvan Vecera 
50607f2c00SIvan Vecera 	dev_dbg(zldev->dev, "OUT%u has signal format 0x%02x\n", index,
51607f2c00SIvan Vecera 		zl3073x_out_signal_format_get(out));
52607f2c00SIvan Vecera 
53*5fb9b0d4SIvan Vecera 	/* Read output divisor */
54*5fb9b0d4SIvan Vecera 	rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_DIV, &out->div);
55*5fb9b0d4SIvan Vecera 	if (rc)
56*5fb9b0d4SIvan Vecera 		return rc;
57*5fb9b0d4SIvan Vecera 
58*5fb9b0d4SIvan Vecera 	if (!out->div) {
59*5fb9b0d4SIvan Vecera 		dev_err(zldev->dev, "Zero divisor for OUT%u got from device\n",
60*5fb9b0d4SIvan Vecera 			index);
61*5fb9b0d4SIvan Vecera 		return -EINVAL;
62*5fb9b0d4SIvan Vecera 	}
63*5fb9b0d4SIvan Vecera 
64*5fb9b0d4SIvan Vecera 	dev_dbg(zldev->dev, "OUT%u divisor: %u\n", index, out->div);
65*5fb9b0d4SIvan Vecera 
66*5fb9b0d4SIvan Vecera 	/* Read output width */
67*5fb9b0d4SIvan Vecera 	rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_WIDTH, &out->width);
68*5fb9b0d4SIvan Vecera 	if (rc)
69*5fb9b0d4SIvan Vecera 		return rc;
70*5fb9b0d4SIvan Vecera 
71*5fb9b0d4SIvan Vecera 	rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD,
72*5fb9b0d4SIvan Vecera 			      &out->esync_n_period);
73*5fb9b0d4SIvan Vecera 	if (rc)
74*5fb9b0d4SIvan Vecera 		return rc;
75*5fb9b0d4SIvan Vecera 
76*5fb9b0d4SIvan Vecera 	if (!out->esync_n_period) {
77*5fb9b0d4SIvan Vecera 		dev_err(zldev->dev,
78*5fb9b0d4SIvan Vecera 			"Zero esync divisor for OUT%u got from device\n",
79*5fb9b0d4SIvan Vecera 			index);
80*5fb9b0d4SIvan Vecera 		return -EINVAL;
81*5fb9b0d4SIvan Vecera 	}
82*5fb9b0d4SIvan Vecera 
83*5fb9b0d4SIvan Vecera 	rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_WIDTH,
84*5fb9b0d4SIvan Vecera 			      &out->esync_n_width);
85*5fb9b0d4SIvan Vecera 	if (rc)
86*5fb9b0d4SIvan Vecera 		return rc;
87*5fb9b0d4SIvan Vecera 
88*5fb9b0d4SIvan Vecera 	rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_PHASE_COMP,
89*5fb9b0d4SIvan Vecera 			      &out->phase_comp);
90*5fb9b0d4SIvan Vecera 	if (rc)
91*5fb9b0d4SIvan Vecera 		return rc;
92*5fb9b0d4SIvan Vecera 
93607f2c00SIvan Vecera 	return rc;
94607f2c00SIvan Vecera }
95607f2c00SIvan Vecera 
96607f2c00SIvan Vecera /**
97607f2c00SIvan Vecera  * zl3073x_out_state_get - get current output state
98607f2c00SIvan Vecera  * @zldev: pointer to zl3073x_dev structure
99607f2c00SIvan Vecera  * @index: output index to get state for
100607f2c00SIvan Vecera  *
101607f2c00SIvan Vecera  * Return: pointer to given output state
102607f2c00SIvan Vecera  */
103607f2c00SIvan Vecera const struct zl3073x_out *zl3073x_out_state_get(struct zl3073x_dev *zldev,
104607f2c00SIvan Vecera 						u8 index)
105607f2c00SIvan Vecera {
106607f2c00SIvan Vecera 	return &zldev->out[index];
107607f2c00SIvan Vecera }
108*5fb9b0d4SIvan Vecera 
109*5fb9b0d4SIvan Vecera int zl3073x_out_state_set(struct zl3073x_dev *zldev, u8 index,
110*5fb9b0d4SIvan Vecera 			  const struct zl3073x_out *out)
111*5fb9b0d4SIvan Vecera {
112*5fb9b0d4SIvan Vecera 	struct zl3073x_out *dout = &zldev->out[index];
113*5fb9b0d4SIvan Vecera 	int rc;
114*5fb9b0d4SIvan Vecera 
115*5fb9b0d4SIvan Vecera 	guard(mutex)(&zldev->multiop_lock);
116*5fb9b0d4SIvan Vecera 
117*5fb9b0d4SIvan Vecera 	/* Read output configuration into mailbox */
118*5fb9b0d4SIvan Vecera 	rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD,
119*5fb9b0d4SIvan Vecera 			   ZL_REG_OUTPUT_MB_MASK, BIT(index));
120*5fb9b0d4SIvan Vecera 	if (rc)
121*5fb9b0d4SIvan Vecera 		return rc;
122*5fb9b0d4SIvan Vecera 
123*5fb9b0d4SIvan Vecera 	/* Update mailbox with changed values */
124*5fb9b0d4SIvan Vecera 	if (dout->div != out->div)
125*5fb9b0d4SIvan Vecera 		rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_DIV, out->div);
126*5fb9b0d4SIvan Vecera 	if (!rc && dout->width != out->width)
127*5fb9b0d4SIvan Vecera 		rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_WIDTH, out->width);
128*5fb9b0d4SIvan Vecera 	if (!rc && dout->esync_n_period != out->esync_n_period)
129*5fb9b0d4SIvan Vecera 		rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD,
130*5fb9b0d4SIvan Vecera 				       out->esync_n_period);
131*5fb9b0d4SIvan Vecera 	if (!rc && dout->esync_n_width != out->esync_n_width)
132*5fb9b0d4SIvan Vecera 		rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_ESYNC_WIDTH,
133*5fb9b0d4SIvan Vecera 				       out->esync_n_width);
134*5fb9b0d4SIvan Vecera 	if (!rc && dout->mode != out->mode)
135*5fb9b0d4SIvan Vecera 		rc = zl3073x_write_u8(zldev, ZL_REG_OUTPUT_MODE, out->mode);
136*5fb9b0d4SIvan Vecera 	if (!rc && dout->phase_comp != out->phase_comp)
137*5fb9b0d4SIvan Vecera 		rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_PHASE_COMP,
138*5fb9b0d4SIvan Vecera 				       out->phase_comp);
139*5fb9b0d4SIvan Vecera 	if (rc)
140*5fb9b0d4SIvan Vecera 		return rc;
141*5fb9b0d4SIvan Vecera 
142*5fb9b0d4SIvan Vecera 	/* Commit output configuration */
143*5fb9b0d4SIvan Vecera 	rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_WR,
144*5fb9b0d4SIvan Vecera 			   ZL_REG_OUTPUT_MB_MASK, BIT(index));
145*5fb9b0d4SIvan Vecera 	if (rc)
146*5fb9b0d4SIvan Vecera 		return rc;
147*5fb9b0d4SIvan Vecera 
148*5fb9b0d4SIvan Vecera 	/* After successful commit store new state */
149*5fb9b0d4SIvan Vecera 	dout->div = out->div;
150*5fb9b0d4SIvan Vecera 	dout->width = out->width;
151*5fb9b0d4SIvan Vecera 	dout->esync_n_period = out->esync_n_period;
152*5fb9b0d4SIvan Vecera 	dout->esync_n_width = out->esync_n_width;
153*5fb9b0d4SIvan Vecera 	dout->mode = out->mode;
154*5fb9b0d4SIvan Vecera 	dout->phase_comp = out->phase_comp;
155*5fb9b0d4SIvan Vecera 
156*5fb9b0d4SIvan Vecera 	return 0;
157*5fb9b0d4SIvan Vecera }
158