Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/pci/lola/lola_clock.c
26439 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Support for Digigram Lola PCI-e boards
4
*
5
* Copyright (c) 2011 Takashi Iwai <[email protected]>
6
*/
7
8
#include <linux/kernel.h>
9
#include <linux/init.h>
10
#include <linux/delay.h>
11
#include <sound/core.h>
12
#include <sound/pcm.h>
13
#include "lola.h"
14
15
unsigned int lola_sample_rate_convert(unsigned int coded)
16
{
17
unsigned int freq;
18
19
/* base frequency */
20
switch (coded & 0x3) {
21
case 0: freq = 48000; break;
22
case 1: freq = 44100; break;
23
case 2: freq = 32000; break;
24
default: return 0; /* error */
25
}
26
27
/* multiplier / devisor */
28
switch (coded & 0x1c) {
29
case (0 << 2): break;
30
case (4 << 2): break;
31
case (1 << 2): freq *= 2; break;
32
case (2 << 2): freq *= 4; break;
33
case (5 << 2): freq /= 2; break;
34
case (6 << 2): freq /= 4; break;
35
default: return 0; /* error */
36
}
37
38
/* adjustement */
39
switch (coded & 0x60) {
40
case (0 << 5): break;
41
case (1 << 5): freq = (freq * 999) / 1000; break;
42
case (2 << 5): freq = (freq * 1001) / 1000; break;
43
default: return 0; /* error */
44
}
45
return freq;
46
}
47
48
/*
49
* Granualrity
50
*/
51
52
#define LOLA_MAXFREQ_AT_GRANULARITY_MIN 48000
53
#define LOLA_MAXFREQ_AT_GRANULARITY_BELOW_MAX 96000
54
55
static bool check_gran_clock_compatibility(struct lola *chip,
56
unsigned int val,
57
unsigned int freq)
58
{
59
if (!chip->granularity)
60
return true;
61
62
if (val < LOLA_GRANULARITY_MIN || val > LOLA_GRANULARITY_MAX ||
63
(val % LOLA_GRANULARITY_STEP) != 0)
64
return false;
65
66
if (val == LOLA_GRANULARITY_MIN) {
67
if (freq > LOLA_MAXFREQ_AT_GRANULARITY_MIN)
68
return false;
69
} else if (val < LOLA_GRANULARITY_MAX) {
70
if (freq > LOLA_MAXFREQ_AT_GRANULARITY_BELOW_MAX)
71
return false;
72
}
73
return true;
74
}
75
76
int lola_set_granularity(struct lola *chip, unsigned int val, bool force)
77
{
78
int err;
79
80
if (!force) {
81
if (val == chip->granularity)
82
return 0;
83
#if 0
84
/* change Gran only if there are no streams allocated ! */
85
if (chip->audio_in_alloc_mask || chip->audio_out_alloc_mask)
86
return -EBUSY;
87
#endif
88
if (!check_gran_clock_compatibility(chip, val,
89
chip->clock.cur_freq))
90
return -EINVAL;
91
}
92
93
chip->granularity = val;
94
val /= LOLA_GRANULARITY_STEP;
95
96
/* audio function group */
97
err = lola_codec_write(chip, 1, LOLA_VERB_SET_GRANULARITY_STEPS,
98
val, 0);
99
if (err < 0)
100
return err;
101
/* this can be a very slow function !!! */
102
usleep_range(400 * val, 20000);
103
return lola_codec_flush(chip);
104
}
105
106
/*
107
* Clock widget handling
108
*/
109
110
int lola_init_clock_widget(struct lola *chip, int nid)
111
{
112
unsigned int val;
113
int i, j, nitems, nb_verbs, idx, idx_list;
114
int err;
115
116
err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
117
if (err < 0) {
118
dev_err(chip->card->dev, "Can't read wcaps for 0x%x\n", nid);
119
return err;
120
}
121
122
if ((val & 0xfff00000) != 0x01f00000) { /* test SubType and Type */
123
dev_dbg(chip->card->dev, "No valid clock widget\n");
124
return 0;
125
}
126
127
chip->clock.nid = nid;
128
chip->clock.items = val & 0xff;
129
dev_dbg(chip->card->dev, "clock_list nid=%x, entries=%d\n", nid,
130
chip->clock.items);
131
if (chip->clock.items > MAX_SAMPLE_CLOCK_COUNT) {
132
dev_err(chip->card->dev, "CLOCK_LIST too big: %d\n",
133
chip->clock.items);
134
return -EINVAL;
135
}
136
137
nitems = chip->clock.items;
138
nb_verbs = DIV_ROUND_UP(nitems, 4);
139
idx = 0;
140
idx_list = 0;
141
for (i = 0; i < nb_verbs; i++) {
142
unsigned int res_ex;
143
unsigned short items[4];
144
145
err = lola_codec_read(chip, nid, LOLA_VERB_GET_CLOCK_LIST,
146
idx, 0, &val, &res_ex);
147
if (err < 0) {
148
dev_err(chip->card->dev, "Can't read CLOCK_LIST\n");
149
return -EINVAL;
150
}
151
152
items[0] = val & 0xfff;
153
items[1] = (val >> 16) & 0xfff;
154
items[2] = res_ex & 0xfff;
155
items[3] = (res_ex >> 16) & 0xfff;
156
157
for (j = 0; j < 4; j++) {
158
unsigned char type = items[j] >> 8;
159
unsigned int freq = items[j] & 0xff;
160
int format = LOLA_CLOCK_FORMAT_NONE;
161
bool add_clock = true;
162
if (type == LOLA_CLOCK_TYPE_INTERNAL) {
163
freq = lola_sample_rate_convert(freq);
164
if (freq < chip->sample_rate_min)
165
add_clock = false;
166
else if (freq == 48000) {
167
chip->clock.cur_index = idx_list;
168
chip->clock.cur_freq = 48000;
169
chip->clock.cur_valid = true;
170
}
171
} else if (type == LOLA_CLOCK_TYPE_VIDEO) {
172
freq = lola_sample_rate_convert(freq);
173
if (freq < chip->sample_rate_min)
174
add_clock = false;
175
/* video clock has a format (0:NTSC, 1:PAL)*/
176
if (items[j] & 0x80)
177
format = LOLA_CLOCK_FORMAT_NTSC;
178
else
179
format = LOLA_CLOCK_FORMAT_PAL;
180
}
181
if (add_clock) {
182
struct lola_sample_clock *sc;
183
sc = &chip->clock.sample_clock[idx_list];
184
sc->type = type;
185
sc->format = format;
186
sc->freq = freq;
187
/* keep the index used with the board */
188
chip->clock.idx_lookup[idx_list] = idx;
189
idx_list++;
190
} else {
191
chip->clock.items--;
192
}
193
if (++idx >= nitems)
194
break;
195
}
196
}
197
return 0;
198
}
199
200
/* enable unsolicited events of the clock widget */
201
int lola_enable_clock_events(struct lola *chip)
202
{
203
unsigned int res;
204
int err;
205
206
err = lola_codec_read(chip, chip->clock.nid,
207
LOLA_VERB_SET_UNSOLICITED_ENABLE,
208
LOLA_UNSOLICITED_ENABLE | LOLA_UNSOLICITED_TAG,
209
0, &res, NULL);
210
if (err < 0)
211
return err;
212
if (res) {
213
dev_warn(chip->card->dev, "error in enable_clock_events %d\n",
214
res);
215
return -EINVAL;
216
}
217
return 0;
218
}
219
220
int lola_set_clock_index(struct lola *chip, unsigned int idx)
221
{
222
unsigned int res;
223
int err;
224
225
err = lola_codec_read(chip, chip->clock.nid,
226
LOLA_VERB_SET_CLOCK_SELECT,
227
chip->clock.idx_lookup[idx],
228
0, &res, NULL);
229
if (err < 0)
230
return err;
231
if (res) {
232
dev_warn(chip->card->dev, "error in set_clock %d\n", res);
233
return -EINVAL;
234
}
235
return 0;
236
}
237
238
bool lola_update_ext_clock_freq(struct lola *chip, unsigned int val)
239
{
240
unsigned int tag;
241
242
/* the current EXTERNAL clock information gets updated by interrupt
243
* with an unsolicited response
244
*/
245
if (!val)
246
return false;
247
tag = (val >> LOLA_UNSOL_RESP_TAG_OFFSET) & LOLA_UNSOLICITED_TAG_MASK;
248
if (tag != LOLA_UNSOLICITED_TAG)
249
return false;
250
251
/* only for current = external clocks */
252
if (chip->clock.sample_clock[chip->clock.cur_index].type !=
253
LOLA_CLOCK_TYPE_INTERNAL) {
254
chip->clock.cur_freq = lola_sample_rate_convert(val & 0x7f);
255
chip->clock.cur_valid = (val & 0x100) != 0;
256
}
257
return true;
258
}
259
260
int lola_set_clock(struct lola *chip, int idx)
261
{
262
int freq = 0;
263
bool valid = false;
264
265
if (idx == chip->clock.cur_index) {
266
/* current clock is allowed */
267
freq = chip->clock.cur_freq;
268
valid = chip->clock.cur_valid;
269
} else if (chip->clock.sample_clock[idx].type ==
270
LOLA_CLOCK_TYPE_INTERNAL) {
271
/* internal clocks allowed */
272
freq = chip->clock.sample_clock[idx].freq;
273
valid = true;
274
}
275
276
if (!freq || !valid)
277
return -EINVAL;
278
279
if (!check_gran_clock_compatibility(chip, chip->granularity, freq))
280
return -EINVAL;
281
282
if (idx != chip->clock.cur_index) {
283
int err = lola_set_clock_index(chip, idx);
284
if (err < 0)
285
return err;
286
/* update new settings */
287
chip->clock.cur_index = idx;
288
chip->clock.cur_freq = freq;
289
chip->clock.cur_valid = true;
290
}
291
return 0;
292
}
293
294
int lola_set_sample_rate(struct lola *chip, int rate)
295
{
296
int i;
297
298
if (chip->clock.cur_freq == rate && chip->clock.cur_valid)
299
return 0;
300
/* search for new dwClockIndex */
301
for (i = 0; i < chip->clock.items; i++) {
302
if (chip->clock.sample_clock[i].type == LOLA_CLOCK_TYPE_INTERNAL &&
303
chip->clock.sample_clock[i].freq == rate)
304
break;
305
}
306
if (i >= chip->clock.items)
307
return -EINVAL;
308
return lola_set_clock(chip, i);
309
}
310
311
312