Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/dpll/zl3073x/out.c
38189 views
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 "out.h"
12
13
/**
14
* zl3073x_out_state_fetch - fetch output state from hardware
15
* @zldev: pointer to zl3073x_dev structure
16
* @index: output index to fetch state for
17
*
18
* Function fetches state of the given output from hardware and stores it
19
* for later use.
20
*
21
* Return: 0 on success, <0 on error
22
*/
23
int zl3073x_out_state_fetch(struct zl3073x_dev *zldev, u8 index)
24
{
25
struct zl3073x_out *out = &zldev->out[index];
26
int rc;
27
28
/* Read output configuration */
29
rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_CTRL(index), &out->ctrl);
30
if (rc)
31
return rc;
32
33
dev_dbg(zldev->dev, "OUT%u is %s and connected to SYNTH%u\n", index,
34
str_enabled_disabled(zl3073x_out_is_enabled(out)),
35
zl3073x_out_synth_get(out));
36
37
guard(mutex)(&zldev->multiop_lock);
38
39
/* Read output configuration */
40
rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD,
41
ZL_REG_OUTPUT_MB_MASK, BIT(index));
42
if (rc)
43
return rc;
44
45
/* Read output mode */
46
rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_MODE, &out->mode);
47
if (rc)
48
return rc;
49
50
dev_dbg(zldev->dev, "OUT%u has signal format 0x%02x\n", index,
51
zl3073x_out_signal_format_get(out));
52
53
/* Read output divisor */
54
rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_DIV, &out->div);
55
if (rc)
56
return rc;
57
58
if (!out->div) {
59
dev_err(zldev->dev, "Zero divisor for OUT%u got from device\n",
60
index);
61
return -EINVAL;
62
}
63
64
dev_dbg(zldev->dev, "OUT%u divisor: %u\n", index, out->div);
65
66
/* Read output width */
67
rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_WIDTH, &out->width);
68
if (rc)
69
return rc;
70
71
rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD,
72
&out->esync_n_period);
73
if (rc)
74
return rc;
75
76
if (!out->esync_n_period) {
77
dev_err(zldev->dev,
78
"Zero esync divisor for OUT%u got from device\n",
79
index);
80
return -EINVAL;
81
}
82
83
rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_WIDTH,
84
&out->esync_n_width);
85
if (rc)
86
return rc;
87
88
rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_PHASE_COMP,
89
&out->phase_comp);
90
if (rc)
91
return rc;
92
93
return rc;
94
}
95
96
/**
97
* zl3073x_out_state_get - get current output state
98
* @zldev: pointer to zl3073x_dev structure
99
* @index: output index to get state for
100
*
101
* Return: pointer to given output state
102
*/
103
const struct zl3073x_out *zl3073x_out_state_get(struct zl3073x_dev *zldev,
104
u8 index)
105
{
106
return &zldev->out[index];
107
}
108
109
int zl3073x_out_state_set(struct zl3073x_dev *zldev, u8 index,
110
const struct zl3073x_out *out)
111
{
112
struct zl3073x_out *dout = &zldev->out[index];
113
int rc;
114
115
guard(mutex)(&zldev->multiop_lock);
116
117
/* Read output configuration into mailbox */
118
rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD,
119
ZL_REG_OUTPUT_MB_MASK, BIT(index));
120
if (rc)
121
return rc;
122
123
/* Update mailbox with changed values */
124
if (dout->div != out->div)
125
rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_DIV, out->div);
126
if (!rc && dout->width != out->width)
127
rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_WIDTH, out->width);
128
if (!rc && dout->esync_n_period != out->esync_n_period)
129
rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD,
130
out->esync_n_period);
131
if (!rc && dout->esync_n_width != out->esync_n_width)
132
rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_ESYNC_WIDTH,
133
out->esync_n_width);
134
if (!rc && dout->mode != out->mode)
135
rc = zl3073x_write_u8(zldev, ZL_REG_OUTPUT_MODE, out->mode);
136
if (!rc && dout->phase_comp != out->phase_comp)
137
rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_PHASE_COMP,
138
out->phase_comp);
139
if (rc)
140
return rc;
141
142
/* Commit output configuration */
143
rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_WR,
144
ZL_REG_OUTPUT_MB_MASK, BIT(index));
145
if (rc)
146
return rc;
147
148
/* After successful commit store new state */
149
dout->div = out->div;
150
dout->width = out->width;
151
dout->esync_n_period = out->esync_n_period;
152
dout->esync_n_width = out->esync_n_width;
153
dout->mode = out->mode;
154
dout->phase_comp = out->phase_comp;
155
156
return 0;
157
}
158
159