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