Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/pci/ca0106/ca0106_mixer.c
26424 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Copyright (c) 2004 James Courtier-Dutton <[email protected]>
4
* Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit
5
* Version: 0.0.18
6
*
7
* FEATURES currently supported:
8
* See ca0106_main.c for features.
9
*
10
* Changelog:
11
* Support interrupts per period.
12
* Removed noise from Center/LFE channel when in Analog mode.
13
* Rename and remove mixer controls.
14
* 0.0.6
15
* Use separate card based DMA buffer for periods table list.
16
* 0.0.7
17
* Change remove and rename ctrls into lists.
18
* 0.0.8
19
* Try to fix capture sources.
20
* 0.0.9
21
* Fix AC3 output.
22
* Enable S32_LE format support.
23
* 0.0.10
24
* Enable playback 48000 and 96000 rates. (Rates other that these do not work, even with "plug:front".)
25
* 0.0.11
26
* Add Model name recognition.
27
* 0.0.12
28
* Correct interrupt timing. interrupt at end of period, instead of in the middle of a playback period.
29
* Remove redundent "voice" handling.
30
* 0.0.13
31
* Single trigger call for multi channels.
32
* 0.0.14
33
* Set limits based on what the sound card hardware can do.
34
* playback periods_min=2, periods_max=8
35
* capture hw constraints require period_size = n * 64 bytes.
36
* playback hw constraints require period_size = n * 64 bytes.
37
* 0.0.15
38
* Separated ca0106.c into separate functional .c files.
39
* 0.0.16
40
* Modified Copyright message.
41
* 0.0.17
42
* Implement Mic and Line in Capture.
43
* 0.0.18
44
* Add support for mute control on SB Live 24bit (cards w/ SPI DAC)
45
*
46
* This code was initially based on code from ALSA's emu10k1x.c which is:
47
* Copyright (c) by Francisco Moraes <[email protected]>
48
*/
49
#include <linux/delay.h>
50
#include <linux/init.h>
51
#include <linux/interrupt.h>
52
#include <linux/moduleparam.h>
53
#include <sound/core.h>
54
#include <sound/initval.h>
55
#include <sound/pcm.h>
56
#include <sound/ac97_codec.h>
57
#include <sound/info.h>
58
#include <sound/tlv.h>
59
#include <linux/io.h>
60
61
#include "ca0106.h"
62
63
static void ca0106_spdif_enable(struct snd_ca0106 *emu)
64
{
65
unsigned int val;
66
67
if (emu->spdif_enable) {
68
/* Digital */
69
snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf);
70
snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x0b000000);
71
val = snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) & ~0x1000;
72
snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, val);
73
val = inl(emu->port + CA0106_GPIO) & ~0x101;
74
outl(val, emu->port + CA0106_GPIO);
75
76
} else {
77
/* Analog */
78
snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf);
79
snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000f0000);
80
val = snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000;
81
snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, val);
82
val = inl(emu->port + CA0106_GPIO) | 0x101;
83
outl(val, emu->port + CA0106_GPIO);
84
}
85
}
86
87
static void ca0106_set_capture_source(struct snd_ca0106 *emu)
88
{
89
unsigned int val = emu->capture_source;
90
unsigned int source, mask;
91
source = (val << 28) | (val << 24) | (val << 20) | (val << 16);
92
mask = snd_ca0106_ptr_read(emu, CAPTURE_SOURCE, 0) & 0xffff;
93
snd_ca0106_ptr_write(emu, CAPTURE_SOURCE, 0, source | mask);
94
}
95
96
static void ca0106_set_i2c_capture_source(struct snd_ca0106 *emu,
97
unsigned int val, int force)
98
{
99
unsigned int ngain, ogain;
100
u32 source;
101
102
snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */
103
ngain = emu->i2c_capture_volume[val][0]; /* Left */
104
ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
105
if (force || ngain != ogain)
106
snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ngain & 0xff);
107
ngain = emu->i2c_capture_volume[val][1]; /* Right */
108
ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */
109
if (force || ngain != ogain)
110
snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ngain & 0xff);
111
source = 1 << val;
112
snd_ca0106_i2c_write(emu, ADC_MUX, source); /* Set source */
113
emu->i2c_capture_source = val;
114
}
115
116
static void ca0106_set_capture_mic_line_in(struct snd_ca0106 *emu)
117
{
118
u32 tmp;
119
120
if (emu->capture_mic_line_in) {
121
/* snd_ca0106_i2c_write(emu, ADC_MUX, 0); */ /* Mute input */
122
tmp = inl(emu->port + CA0106_GPIO) & ~0x400;
123
tmp = tmp | 0x400;
124
outl(tmp, emu->port + CA0106_GPIO);
125
/* snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC); */
126
} else {
127
/* snd_ca0106_i2c_write(emu, ADC_MUX, 0); */ /* Mute input */
128
tmp = inl(emu->port + CA0106_GPIO) & ~0x400;
129
outl(tmp, emu->port + CA0106_GPIO);
130
/* snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN); */
131
}
132
}
133
134
static void ca0106_set_spdif_bits(struct snd_ca0106 *emu, int idx)
135
{
136
snd_ca0106_ptr_write(emu, SPCS0 + idx, 0, emu->spdif_str_bits[idx]);
137
}
138
139
/*
140
*/
141
static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1);
142
static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1);
143
144
#define snd_ca0106_shared_spdif_info snd_ctl_boolean_mono_info
145
146
static int snd_ca0106_shared_spdif_get(struct snd_kcontrol *kcontrol,
147
struct snd_ctl_elem_value *ucontrol)
148
{
149
struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
150
151
ucontrol->value.integer.value[0] = emu->spdif_enable;
152
return 0;
153
}
154
155
static int snd_ca0106_shared_spdif_put(struct snd_kcontrol *kcontrol,
156
struct snd_ctl_elem_value *ucontrol)
157
{
158
struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
159
unsigned int val;
160
int change = 0;
161
162
val = !!ucontrol->value.integer.value[0];
163
change = (emu->spdif_enable != val);
164
if (change) {
165
emu->spdif_enable = val;
166
ca0106_spdif_enable(emu);
167
}
168
return change;
169
}
170
171
static int snd_ca0106_capture_source_info(struct snd_kcontrol *kcontrol,
172
struct snd_ctl_elem_info *uinfo)
173
{
174
static const char * const texts[6] = {
175
"IEC958 out", "i2s mixer out", "IEC958 in", "i2s in", "AC97 in", "SRC out"
176
};
177
178
return snd_ctl_enum_info(uinfo, 1, 6, texts);
179
}
180
181
static int snd_ca0106_capture_source_get(struct snd_kcontrol *kcontrol,
182
struct snd_ctl_elem_value *ucontrol)
183
{
184
struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
185
186
ucontrol->value.enumerated.item[0] = emu->capture_source;
187
return 0;
188
}
189
190
static int snd_ca0106_capture_source_put(struct snd_kcontrol *kcontrol,
191
struct snd_ctl_elem_value *ucontrol)
192
{
193
struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
194
unsigned int val;
195
int change = 0;
196
197
val = ucontrol->value.enumerated.item[0] ;
198
if (val >= 6)
199
return -EINVAL;
200
change = (emu->capture_source != val);
201
if (change) {
202
emu->capture_source = val;
203
ca0106_set_capture_source(emu);
204
}
205
return change;
206
}
207
208
static int snd_ca0106_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
209
struct snd_ctl_elem_info *uinfo)
210
{
211
static const char * const texts[4] = {
212
"Phone", "Mic", "Line in", "Aux"
213
};
214
215
return snd_ctl_enum_info(uinfo, 1, 4, texts);
216
}
217
218
static int snd_ca0106_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
219
struct snd_ctl_elem_value *ucontrol)
220
{
221
struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
222
223
ucontrol->value.enumerated.item[0] = emu->i2c_capture_source;
224
return 0;
225
}
226
227
static int snd_ca0106_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
228
struct snd_ctl_elem_value *ucontrol)
229
{
230
struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
231
unsigned int source_id;
232
int change = 0;
233
/* If the capture source has changed,
234
* update the capture volume from the cached value
235
* for the particular source.
236
*/
237
source_id = ucontrol->value.enumerated.item[0] ;
238
if (source_id >= 4)
239
return -EINVAL;
240
change = (emu->i2c_capture_source != source_id);
241
if (change) {
242
ca0106_set_i2c_capture_source(emu, source_id, 0);
243
}
244
return change;
245
}
246
247
static int snd_ca0106_capture_line_in_side_out_info(struct snd_kcontrol *kcontrol,
248
struct snd_ctl_elem_info *uinfo)
249
{
250
static const char * const texts[2] = { "Side out", "Line in" };
251
252
return snd_ctl_enum_info(uinfo, 1, 2, texts);
253
}
254
255
static int snd_ca0106_capture_mic_line_in_info(struct snd_kcontrol *kcontrol,
256
struct snd_ctl_elem_info *uinfo)
257
{
258
static const char * const texts[2] = { "Line in", "Mic in" };
259
260
return snd_ctl_enum_info(uinfo, 1, 2, texts);
261
}
262
263
static int snd_ca0106_capture_mic_line_in_get(struct snd_kcontrol *kcontrol,
264
struct snd_ctl_elem_value *ucontrol)
265
{
266
struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
267
268
ucontrol->value.enumerated.item[0] = emu->capture_mic_line_in;
269
return 0;
270
}
271
272
static int snd_ca0106_capture_mic_line_in_put(struct snd_kcontrol *kcontrol,
273
struct snd_ctl_elem_value *ucontrol)
274
{
275
struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
276
unsigned int val;
277
int change = 0;
278
279
val = ucontrol->value.enumerated.item[0] ;
280
if (val > 1)
281
return -EINVAL;
282
change = (emu->capture_mic_line_in != val);
283
if (change) {
284
emu->capture_mic_line_in = val;
285
ca0106_set_capture_mic_line_in(emu);
286
}
287
return change;
288
}
289
290
static const struct snd_kcontrol_new snd_ca0106_capture_mic_line_in =
291
{
292
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
293
.name = "Shared Mic/Line in Capture Switch",
294
.info = snd_ca0106_capture_mic_line_in_info,
295
.get = snd_ca0106_capture_mic_line_in_get,
296
.put = snd_ca0106_capture_mic_line_in_put
297
};
298
299
static const struct snd_kcontrol_new snd_ca0106_capture_line_in_side_out =
300
{
301
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
302
.name = "Shared Line in/Side out Capture Switch",
303
.info = snd_ca0106_capture_line_in_side_out_info,
304
.get = snd_ca0106_capture_mic_line_in_get,
305
.put = snd_ca0106_capture_mic_line_in_put
306
};
307
308
309
static int snd_ca0106_spdif_info(struct snd_kcontrol *kcontrol,
310
struct snd_ctl_elem_info *uinfo)
311
{
312
uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
313
uinfo->count = 1;
314
return 0;
315
}
316
317
static void decode_spdif_bits(unsigned char *status, unsigned int bits)
318
{
319
status[0] = (bits >> 0) & 0xff;
320
status[1] = (bits >> 8) & 0xff;
321
status[2] = (bits >> 16) & 0xff;
322
status[3] = (bits >> 24) & 0xff;
323
}
324
325
static int snd_ca0106_spdif_get_default(struct snd_kcontrol *kcontrol,
326
struct snd_ctl_elem_value *ucontrol)
327
{
328
struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
329
unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
330
331
decode_spdif_bits(ucontrol->value.iec958.status,
332
emu->spdif_bits[idx]);
333
return 0;
334
}
335
336
static int snd_ca0106_spdif_get_stream(struct snd_kcontrol *kcontrol,
337
struct snd_ctl_elem_value *ucontrol)
338
{
339
struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
340
unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
341
342
decode_spdif_bits(ucontrol->value.iec958.status,
343
emu->spdif_str_bits[idx]);
344
return 0;
345
}
346
347
static int snd_ca0106_spdif_get_mask(struct snd_kcontrol *kcontrol,
348
struct snd_ctl_elem_value *ucontrol)
349
{
350
ucontrol->value.iec958.status[0] = 0xff;
351
ucontrol->value.iec958.status[1] = 0xff;
352
ucontrol->value.iec958.status[2] = 0xff;
353
ucontrol->value.iec958.status[3] = 0xff;
354
return 0;
355
}
356
357
static unsigned int encode_spdif_bits(unsigned char *status)
358
{
359
return ((unsigned int)status[0] << 0) |
360
((unsigned int)status[1] << 8) |
361
((unsigned int)status[2] << 16) |
362
((unsigned int)status[3] << 24);
363
}
364
365
static int snd_ca0106_spdif_put_default(struct snd_kcontrol *kcontrol,
366
struct snd_ctl_elem_value *ucontrol)
367
{
368
struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
369
unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
370
unsigned int val;
371
372
val = encode_spdif_bits(ucontrol->value.iec958.status);
373
if (val != emu->spdif_bits[idx]) {
374
emu->spdif_bits[idx] = val;
375
/* FIXME: this isn't safe, but needed to keep the compatibility
376
* with older alsa-lib config
377
*/
378
emu->spdif_str_bits[idx] = val;
379
ca0106_set_spdif_bits(emu, idx);
380
return 1;
381
}
382
return 0;
383
}
384
385
static int snd_ca0106_spdif_put_stream(struct snd_kcontrol *kcontrol,
386
struct snd_ctl_elem_value *ucontrol)
387
{
388
struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
389
unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
390
unsigned int val;
391
392
val = encode_spdif_bits(ucontrol->value.iec958.status);
393
if (val != emu->spdif_str_bits[idx]) {
394
emu->spdif_str_bits[idx] = val;
395
ca0106_set_spdif_bits(emu, idx);
396
return 1;
397
}
398
return 0;
399
}
400
401
static int snd_ca0106_volume_info(struct snd_kcontrol *kcontrol,
402
struct snd_ctl_elem_info *uinfo)
403
{
404
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
405
uinfo->count = 2;
406
uinfo->value.integer.min = 0;
407
uinfo->value.integer.max = 255;
408
return 0;
409
}
410
411
static int snd_ca0106_volume_get(struct snd_kcontrol *kcontrol,
412
struct snd_ctl_elem_value *ucontrol)
413
{
414
struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
415
unsigned int value;
416
int channel_id, reg;
417
418
channel_id = (kcontrol->private_value >> 8) & 0xff;
419
reg = kcontrol->private_value & 0xff;
420
421
value = snd_ca0106_ptr_read(emu, reg, channel_id);
422
ucontrol->value.integer.value[0] = 0xff - ((value >> 24) & 0xff); /* Left */
423
ucontrol->value.integer.value[1] = 0xff - ((value >> 16) & 0xff); /* Right */
424
return 0;
425
}
426
427
static int snd_ca0106_volume_put(struct snd_kcontrol *kcontrol,
428
struct snd_ctl_elem_value *ucontrol)
429
{
430
struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
431
unsigned int oval, nval;
432
int channel_id, reg;
433
434
channel_id = (kcontrol->private_value >> 8) & 0xff;
435
reg = kcontrol->private_value & 0xff;
436
437
oval = snd_ca0106_ptr_read(emu, reg, channel_id);
438
nval = ((0xff - ucontrol->value.integer.value[0]) << 24) |
439
((0xff - ucontrol->value.integer.value[1]) << 16);
440
nval |= ((0xff - ucontrol->value.integer.value[0]) << 8) |
441
((0xff - ucontrol->value.integer.value[1]) );
442
if (oval == nval)
443
return 0;
444
snd_ca0106_ptr_write(emu, reg, channel_id, nval);
445
return 1;
446
}
447
448
static int snd_ca0106_i2c_volume_info(struct snd_kcontrol *kcontrol,
449
struct snd_ctl_elem_info *uinfo)
450
{
451
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
452
uinfo->count = 2;
453
uinfo->value.integer.min = 0;
454
uinfo->value.integer.max = 255;
455
return 0;
456
}
457
458
static int snd_ca0106_i2c_volume_get(struct snd_kcontrol *kcontrol,
459
struct snd_ctl_elem_value *ucontrol)
460
{
461
struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
462
int source_id;
463
464
source_id = kcontrol->private_value;
465
466
ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0];
467
ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1];
468
return 0;
469
}
470
471
static int snd_ca0106_i2c_volume_put(struct snd_kcontrol *kcontrol,
472
struct snd_ctl_elem_value *ucontrol)
473
{
474
struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
475
unsigned int ogain;
476
unsigned int ngain;
477
int source_id;
478
int change = 0;
479
480
source_id = kcontrol->private_value;
481
ogain = emu->i2c_capture_volume[source_id][0]; /* Left */
482
ngain = ucontrol->value.integer.value[0];
483
if (ngain > 0xff)
484
return -EINVAL;
485
if (ogain != ngain) {
486
if (emu->i2c_capture_source == source_id)
487
snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) );
488
emu->i2c_capture_volume[source_id][0] = ucontrol->value.integer.value[0];
489
change = 1;
490
}
491
ogain = emu->i2c_capture_volume[source_id][1]; /* Right */
492
ngain = ucontrol->value.integer.value[1];
493
if (ngain > 0xff)
494
return -EINVAL;
495
if (ogain != ngain) {
496
if (emu->i2c_capture_source == source_id)
497
snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
498
emu->i2c_capture_volume[source_id][1] = ucontrol->value.integer.value[1];
499
change = 1;
500
}
501
502
return change;
503
}
504
505
#define spi_mute_info snd_ctl_boolean_mono_info
506
507
static int spi_mute_get(struct snd_kcontrol *kcontrol,
508
struct snd_ctl_elem_value *ucontrol)
509
{
510
struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
511
unsigned int reg = kcontrol->private_value >> SPI_REG_SHIFT;
512
unsigned int bit = kcontrol->private_value & SPI_REG_MASK;
513
514
ucontrol->value.integer.value[0] = !(emu->spi_dac_reg[reg] & bit);
515
return 0;
516
}
517
518
static int spi_mute_put(struct snd_kcontrol *kcontrol,
519
struct snd_ctl_elem_value *ucontrol)
520
{
521
struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
522
unsigned int reg = kcontrol->private_value >> SPI_REG_SHIFT;
523
unsigned int bit = kcontrol->private_value & SPI_REG_MASK;
524
int ret;
525
526
ret = emu->spi_dac_reg[reg] & bit;
527
if (ucontrol->value.integer.value[0]) {
528
if (!ret) /* bit already cleared, do nothing */
529
return 0;
530
emu->spi_dac_reg[reg] &= ~bit;
531
} else {
532
if (ret) /* bit already set, do nothing */
533
return 0;
534
emu->spi_dac_reg[reg] |= bit;
535
}
536
537
ret = snd_ca0106_spi_write(emu, emu->spi_dac_reg[reg]);
538
return ret ? -EINVAL : 1;
539
}
540
541
#define CA_VOLUME(xname,chid,reg) \
542
{ \
543
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
544
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
545
SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
546
.info = snd_ca0106_volume_info, \
547
.get = snd_ca0106_volume_get, \
548
.put = snd_ca0106_volume_put, \
549
.tlv = { .p = snd_ca0106_db_scale1 }, \
550
.private_value = ((chid) << 8) | (reg) \
551
}
552
553
static const struct snd_kcontrol_new snd_ca0106_volume_ctls[] = {
554
CA_VOLUME("Analog Front Playback Volume",
555
CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME2),
556
CA_VOLUME("Analog Rear Playback Volume",
557
CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME2),
558
CA_VOLUME("Analog Center/LFE Playback Volume",
559
CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME2),
560
CA_VOLUME("Analog Side Playback Volume",
561
CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME2),
562
563
CA_VOLUME("IEC958 Front Playback Volume",
564
CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME1),
565
CA_VOLUME("IEC958 Rear Playback Volume",
566
CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME1),
567
CA_VOLUME("IEC958 Center/LFE Playback Volume",
568
CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME1),
569
CA_VOLUME("IEC958 Unknown Playback Volume",
570
CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME1),
571
572
CA_VOLUME("CAPTURE feedback Playback Volume",
573
1, CAPTURE_CONTROL),
574
575
{
576
.access = SNDRV_CTL_ELEM_ACCESS_READ,
577
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
578
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
579
.count = 4,
580
.info = snd_ca0106_spdif_info,
581
.get = snd_ca0106_spdif_get_mask
582
},
583
{
584
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
585
.name = "IEC958 Playback Switch",
586
.info = snd_ca0106_shared_spdif_info,
587
.get = snd_ca0106_shared_spdif_get,
588
.put = snd_ca0106_shared_spdif_put
589
},
590
{
591
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
592
.name = "Digital Source Capture Enum",
593
.info = snd_ca0106_capture_source_info,
594
.get = snd_ca0106_capture_source_get,
595
.put = snd_ca0106_capture_source_put
596
},
597
{
598
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
599
.name = "Analog Source Capture Enum",
600
.info = snd_ca0106_i2c_capture_source_info,
601
.get = snd_ca0106_i2c_capture_source_get,
602
.put = snd_ca0106_i2c_capture_source_put
603
},
604
{
605
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
606
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
607
.count = 4,
608
.info = snd_ca0106_spdif_info,
609
.get = snd_ca0106_spdif_get_default,
610
.put = snd_ca0106_spdif_put_default
611
},
612
{
613
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
614
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM),
615
.count = 4,
616
.info = snd_ca0106_spdif_info,
617
.get = snd_ca0106_spdif_get_stream,
618
.put = snd_ca0106_spdif_put_stream
619
},
620
};
621
622
#define I2C_VOLUME(xname,chid) \
623
{ \
624
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
625
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
626
SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
627
.info = snd_ca0106_i2c_volume_info, \
628
.get = snd_ca0106_i2c_volume_get, \
629
.put = snd_ca0106_i2c_volume_put, \
630
.tlv = { .p = snd_ca0106_db_scale2 }, \
631
.private_value = chid \
632
}
633
634
static const struct snd_kcontrol_new snd_ca0106_volume_i2c_adc_ctls[] = {
635
I2C_VOLUME("Phone Capture Volume", 0),
636
I2C_VOLUME("Mic Capture Volume", 1),
637
I2C_VOLUME("Line in Capture Volume", 2),
638
I2C_VOLUME("Aux Capture Volume", 3),
639
};
640
641
static const int spi_dmute_reg[] = {
642
SPI_DMUTE0_REG,
643
SPI_DMUTE1_REG,
644
SPI_DMUTE2_REG,
645
0,
646
SPI_DMUTE4_REG,
647
};
648
static const int spi_dmute_bit[] = {
649
SPI_DMUTE0_BIT,
650
SPI_DMUTE1_BIT,
651
SPI_DMUTE2_BIT,
652
0,
653
SPI_DMUTE4_BIT,
654
};
655
656
static struct snd_kcontrol_new
657
snd_ca0106_volume_spi_dac_ctl(const struct snd_ca0106_details *details,
658
int channel_id)
659
{
660
struct snd_kcontrol_new spi_switch = {0};
661
int reg, bit;
662
int dac_id;
663
664
spi_switch.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
665
spi_switch.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
666
spi_switch.info = spi_mute_info;
667
spi_switch.get = spi_mute_get;
668
spi_switch.put = spi_mute_put;
669
670
switch (channel_id) {
671
case PCM_FRONT_CHANNEL:
672
spi_switch.name = "Analog Front Playback Switch";
673
dac_id = (details->spi_dac & 0xf000) >> (4 * 3);
674
break;
675
case PCM_REAR_CHANNEL:
676
spi_switch.name = "Analog Rear Playback Switch";
677
dac_id = (details->spi_dac & 0x0f00) >> (4 * 2);
678
break;
679
case PCM_CENTER_LFE_CHANNEL:
680
spi_switch.name = "Analog Center/LFE Playback Switch";
681
dac_id = (details->spi_dac & 0x00f0) >> (4 * 1);
682
break;
683
case PCM_UNKNOWN_CHANNEL:
684
spi_switch.name = "Analog Side Playback Switch";
685
dac_id = (details->spi_dac & 0x000f) >> (4 * 0);
686
break;
687
default:
688
/* Unused channel */
689
spi_switch.name = NULL;
690
dac_id = 0;
691
}
692
reg = spi_dmute_reg[dac_id];
693
bit = spi_dmute_bit[dac_id];
694
695
spi_switch.private_value = (reg << SPI_REG_SHIFT) | bit;
696
697
return spi_switch;
698
}
699
700
static int remove_ctl(struct snd_card *card, const char *name)
701
{
702
struct snd_ctl_elem_id id;
703
memset(&id, 0, sizeof(id));
704
strscpy(id.name, name);
705
id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
706
return snd_ctl_remove_id(card, &id);
707
}
708
709
static int rename_ctl(struct snd_card *card, const char *src, const char *dst)
710
{
711
struct snd_kcontrol *kctl = snd_ctl_find_id_mixer(card, src);
712
if (kctl) {
713
snd_ctl_rename(card, kctl, dst);
714
return 0;
715
}
716
return -ENOENT;
717
}
718
719
#define ADD_CTLS(emu, ctls) \
720
do { \
721
int i, _err; \
722
for (i = 0; i < ARRAY_SIZE(ctls); i++) { \
723
_err = snd_ctl_add(card, snd_ctl_new1(&ctls[i], emu)); \
724
if (_err < 0) \
725
return _err; \
726
} \
727
} while (0)
728
729
static
730
DECLARE_TLV_DB_SCALE(snd_ca0106_master_db_scale, -6375, 25, 1);
731
732
static const char * const follower_vols[] = {
733
"Analog Front Playback Volume",
734
"Analog Rear Playback Volume",
735
"Analog Center/LFE Playback Volume",
736
"Analog Side Playback Volume",
737
"IEC958 Front Playback Volume",
738
"IEC958 Rear Playback Volume",
739
"IEC958 Center/LFE Playback Volume",
740
"IEC958 Unknown Playback Volume",
741
"CAPTURE feedback Playback Volume",
742
NULL
743
};
744
745
static const char * const follower_sws[] = {
746
"Analog Front Playback Switch",
747
"Analog Rear Playback Switch",
748
"Analog Center/LFE Playback Switch",
749
"Analog Side Playback Switch",
750
"IEC958 Playback Switch",
751
NULL
752
};
753
754
int snd_ca0106_mixer(struct snd_ca0106 *emu)
755
{
756
int err;
757
struct snd_card *card = emu->card;
758
const char * const *c;
759
struct snd_kcontrol *vmaster;
760
static const char * const ca0106_remove_ctls[] = {
761
"Master Mono Playback Switch",
762
"Master Mono Playback Volume",
763
"3D Control - Switch",
764
"3D Control Sigmatel - Depth",
765
"PCM Playback Switch",
766
"PCM Playback Volume",
767
"CD Playback Switch",
768
"CD Playback Volume",
769
"Phone Playback Switch",
770
"Phone Playback Volume",
771
"Video Playback Switch",
772
"Video Playback Volume",
773
"Beep Playback Switch",
774
"Beep Playback Volume",
775
"Mono Output Select",
776
"Capture Source",
777
"Capture Switch",
778
"Capture Volume",
779
"External Amplifier",
780
"Sigmatel 4-Speaker Stereo Playback Switch",
781
"Surround Phase Inversion Playback Switch",
782
NULL
783
};
784
static const char * const ca0106_rename_ctls[] = {
785
"Master Playback Switch", "Capture Switch",
786
"Master Playback Volume", "Capture Volume",
787
"Line Playback Switch", "AC97 Line Capture Switch",
788
"Line Playback Volume", "AC97 Line Capture Volume",
789
"Aux Playback Switch", "AC97 Aux Capture Switch",
790
"Aux Playback Volume", "AC97 Aux Capture Volume",
791
"Mic Playback Switch", "AC97 Mic Capture Switch",
792
"Mic Playback Volume", "AC97 Mic Capture Volume",
793
"Mic Select", "AC97 Mic Select",
794
"Mic Boost (+20dB)", "AC97 Mic Boost (+20dB)",
795
NULL
796
};
797
#if 1
798
for (c = ca0106_remove_ctls; *c; c++)
799
remove_ctl(card, *c);
800
for (c = ca0106_rename_ctls; *c; c += 2)
801
rename_ctl(card, c[0], c[1]);
802
#endif
803
804
ADD_CTLS(emu, snd_ca0106_volume_ctls);
805
if (emu->details->i2c_adc == 1) {
806
ADD_CTLS(emu, snd_ca0106_volume_i2c_adc_ctls);
807
if (emu->details->gpio_type == 1)
808
err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_mic_line_in, emu));
809
else /* gpio_type == 2 */
810
err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_line_in_side_out, emu));
811
if (err < 0)
812
return err;
813
}
814
if (emu->details->spi_dac) {
815
int i;
816
for (i = 0;; i++) {
817
struct snd_kcontrol_new ctl;
818
ctl = snd_ca0106_volume_spi_dac_ctl(emu->details, i);
819
if (!ctl.name)
820
break;
821
err = snd_ctl_add(card, snd_ctl_new1(&ctl, emu));
822
if (err < 0)
823
return err;
824
}
825
}
826
827
/* Create virtual master controls */
828
vmaster = snd_ctl_make_virtual_master("Master Playback Volume",
829
snd_ca0106_master_db_scale);
830
if (!vmaster)
831
return -ENOMEM;
832
err = snd_ctl_add(card, vmaster);
833
if (err < 0)
834
return err;
835
err = snd_ctl_add_followers(card, vmaster, follower_vols);
836
if (err < 0)
837
return err;
838
839
if (emu->details->spi_dac) {
840
vmaster = snd_ctl_make_virtual_master("Master Playback Switch",
841
NULL);
842
if (!vmaster)
843
return -ENOMEM;
844
err = snd_ctl_add(card, vmaster);
845
if (err < 0)
846
return err;
847
err = snd_ctl_add_followers(card, vmaster, follower_sws);
848
if (err < 0)
849
return err;
850
}
851
852
strscpy(card->mixername, "CA0106");
853
return 0;
854
}
855
856
#ifdef CONFIG_PM_SLEEP
857
struct ca0106_vol_tbl {
858
unsigned int channel_id;
859
unsigned int reg;
860
};
861
862
static const struct ca0106_vol_tbl saved_volumes[NUM_SAVED_VOLUMES] = {
863
{ CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME2 },
864
{ CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME2 },
865
{ CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME2 },
866
{ CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME2 },
867
{ CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME1 },
868
{ CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME1 },
869
{ CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME1 },
870
{ CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME1 },
871
{ 1, CAPTURE_CONTROL },
872
};
873
874
void snd_ca0106_mixer_suspend(struct snd_ca0106 *chip)
875
{
876
int i;
877
878
/* save volumes */
879
for (i = 0; i < NUM_SAVED_VOLUMES; i++)
880
chip->saved_vol[i] =
881
snd_ca0106_ptr_read(chip, saved_volumes[i].reg,
882
saved_volumes[i].channel_id);
883
}
884
885
void snd_ca0106_mixer_resume(struct snd_ca0106 *chip)
886
{
887
int i;
888
889
for (i = 0; i < NUM_SAVED_VOLUMES; i++)
890
snd_ca0106_ptr_write(chip, saved_volumes[i].reg,
891
saved_volumes[i].channel_id,
892
chip->saved_vol[i]);
893
894
ca0106_spdif_enable(chip);
895
ca0106_set_capture_source(chip);
896
ca0106_set_i2c_capture_source(chip, chip->i2c_capture_source, 1);
897
for (i = 0; i < 4; i++)
898
ca0106_set_spdif_bits(chip, i);
899
if (chip->details->i2c_adc)
900
ca0106_set_capture_mic_line_in(chip);
901
}
902
#endif /* CONFIG_PM_SLEEP */
903
904