Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/isa/cs423x/cs4236_lib.c
29266 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Copyright (c) by Jaroslav Kysela <[email protected]>
4
* Routines for control of CS4235/4236B/4237B/4238B/4239 chips
5
*
6
* Note:
7
* -----
8
*
9
* Bugs:
10
* -----
11
*/
12
13
/*
14
* Indirect control registers (CS4236B+)
15
*
16
* C0
17
* D8: WSS reset (all chips)
18
*
19
* C1 (all chips except CS4236)
20
* D7-D5: version
21
* D4-D0: chip id
22
* 11101 - CS4235
23
* 01011 - CS4236B
24
* 01000 - CS4237B
25
* 01001 - CS4238B
26
* 11110 - CS4239
27
*
28
* C2
29
* D7-D4: 3D Space (CS4235,CS4237B,CS4238B,CS4239)
30
* D3-D0: 3D Center (CS4237B); 3D Volume (CS4238B)
31
*
32
* C3
33
* D7: 3D Enable (CS4237B)
34
* D6: 3D Mono Enable (CS4237B)
35
* D5: 3D Serial Output (CS4237B,CS4238B)
36
* D4: 3D Enable (CS4235,CS4238B,CS4239)
37
*
38
* C4
39
* D7: consumer serial port enable (CS4237B,CS4238B)
40
* D6: channels status block reset (CS4237B,CS4238B)
41
* D5: user bit in sub-frame of digital audio data (CS4237B,CS4238B)
42
* D4: validity bit in sub-frame of digital audio data (CS4237B,CS4238B)
43
*
44
* C5 lower channel status (digital serial data description) (CS4237B,CS4238B)
45
* D7-D6: first two bits of category code
46
* D5: lock
47
* D4-D3: pre-emphasis (0 = none, 1 = 50/15us)
48
* D2: copy/copyright (0 = copy inhibited)
49
* D1: 0 = digital audio / 1 = non-digital audio
50
*
51
* C6 upper channel status (digital serial data description) (CS4237B,CS4238B)
52
* D7-D6: sample frequency (0 = 44.1kHz)
53
* D5: generation status (0 = no indication, 1 = original/commercially precaptureed data)
54
* D4-D0: category code (upper bits)
55
*
56
* C7 reserved (must write 0)
57
*
58
* C8 wavetable control
59
* D7: volume control interrupt enable (CS4235,CS4239)
60
* D6: hardware volume control format (CS4235,CS4239)
61
* D3: wavetable serial port enable (all chips)
62
* D2: DSP serial port switch (all chips)
63
* D1: disable MCLK (all chips)
64
* D0: force BRESET low (all chips)
65
*
66
*/
67
68
#include <linux/io.h>
69
#include <linux/delay.h>
70
#include <linux/init.h>
71
#include <linux/time.h>
72
#include <linux/wait.h>
73
#include <sound/core.h>
74
#include <sound/wss.h>
75
#include <sound/asoundef.h>
76
#include <sound/initval.h>
77
#include <sound/tlv.h>
78
79
/*
80
*
81
*/
82
83
static const unsigned char snd_cs4236_ext_map[18] = {
84
/* CS4236_LEFT_LINE */ 0xff,
85
/* CS4236_RIGHT_LINE */ 0xff,
86
/* CS4236_LEFT_MIC */ 0xdf,
87
/* CS4236_RIGHT_MIC */ 0xdf,
88
/* CS4236_LEFT_MIX_CTRL */ 0xe0 | 0x18,
89
/* CS4236_RIGHT_MIX_CTRL */ 0xe0,
90
/* CS4236_LEFT_FM */ 0xbf,
91
/* CS4236_RIGHT_FM */ 0xbf,
92
/* CS4236_LEFT_DSP */ 0xbf,
93
/* CS4236_RIGHT_DSP */ 0xbf,
94
/* CS4236_RIGHT_LOOPBACK */ 0xbf,
95
/* CS4236_DAC_MUTE */ 0xe0,
96
/* CS4236_ADC_RATE */ 0x01, /* 48kHz */
97
/* CS4236_DAC_RATE */ 0x01, /* 48kHz */
98
/* CS4236_LEFT_MASTER */ 0xbf,
99
/* CS4236_RIGHT_MASTER */ 0xbf,
100
/* CS4236_LEFT_WAVE */ 0xbf,
101
/* CS4236_RIGHT_WAVE */ 0xbf
102
};
103
104
/*
105
*
106
*/
107
108
static void snd_cs4236_ctrl_out(struct snd_wss *chip,
109
unsigned char reg, unsigned char val)
110
{
111
outb(reg, chip->cport + 3);
112
outb(chip->cimage[reg] = val, chip->cport + 4);
113
}
114
115
static unsigned char snd_cs4236_ctrl_in(struct snd_wss *chip, unsigned char reg)
116
{
117
outb(reg, chip->cport + 3);
118
return inb(chip->cport + 4);
119
}
120
121
/*
122
* PCM
123
*/
124
125
#define CLOCKS 8
126
127
static const struct snd_ratnum clocks[CLOCKS] = {
128
{ .num = 16934400, .den_min = 353, .den_max = 353, .den_step = 1 },
129
{ .num = 16934400, .den_min = 529, .den_max = 529, .den_step = 1 },
130
{ .num = 16934400, .den_min = 617, .den_max = 617, .den_step = 1 },
131
{ .num = 16934400, .den_min = 1058, .den_max = 1058, .den_step = 1 },
132
{ .num = 16934400, .den_min = 1764, .den_max = 1764, .den_step = 1 },
133
{ .num = 16934400, .den_min = 2117, .den_max = 2117, .den_step = 1 },
134
{ .num = 16934400, .den_min = 2558, .den_max = 2558, .den_step = 1 },
135
{ .num = 16934400/16, .den_min = 21, .den_max = 192, .den_step = 1 }
136
};
137
138
static const struct snd_pcm_hw_constraint_ratnums hw_constraints_clocks = {
139
.nrats = CLOCKS,
140
.rats = clocks,
141
};
142
143
static int snd_cs4236_xrate(struct snd_pcm_runtime *runtime)
144
{
145
return snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
146
&hw_constraints_clocks);
147
}
148
149
static unsigned char divisor_to_rate_register(unsigned int divisor)
150
{
151
switch (divisor) {
152
case 353: return 1;
153
case 529: return 2;
154
case 617: return 3;
155
case 1058: return 4;
156
case 1764: return 5;
157
case 2117: return 6;
158
case 2558: return 7;
159
default:
160
if (divisor < 21 || divisor > 192) {
161
snd_BUG();
162
return 192;
163
}
164
return divisor;
165
}
166
}
167
168
static void snd_cs4236_playback_format(struct snd_wss *chip,
169
struct snd_pcm_hw_params *params,
170
unsigned char pdfr)
171
{
172
unsigned char rate = divisor_to_rate_register(params->rate_den);
173
174
guard(spinlock_irqsave)(&chip->reg_lock);
175
/* set fast playback format change and clean playback FIFO */
176
snd_wss_out(chip, CS4231_ALT_FEATURE_1,
177
chip->image[CS4231_ALT_FEATURE_1] | 0x10);
178
snd_wss_out(chip, CS4231_PLAYBK_FORMAT, pdfr & 0xf0);
179
snd_wss_out(chip, CS4231_ALT_FEATURE_1,
180
chip->image[CS4231_ALT_FEATURE_1] & ~0x10);
181
snd_cs4236_ext_out(chip, CS4236_DAC_RATE, rate);
182
}
183
184
static void snd_cs4236_capture_format(struct snd_wss *chip,
185
struct snd_pcm_hw_params *params,
186
unsigned char cdfr)
187
{
188
unsigned char rate = divisor_to_rate_register(params->rate_den);
189
190
guard(spinlock_irqsave)(&chip->reg_lock);
191
/* set fast capture format change and clean capture FIFO */
192
snd_wss_out(chip, CS4231_ALT_FEATURE_1,
193
chip->image[CS4231_ALT_FEATURE_1] | 0x20);
194
snd_wss_out(chip, CS4231_REC_FORMAT, cdfr & 0xf0);
195
snd_wss_out(chip, CS4231_ALT_FEATURE_1,
196
chip->image[CS4231_ALT_FEATURE_1] & ~0x20);
197
snd_cs4236_ext_out(chip, CS4236_ADC_RATE, rate);
198
}
199
200
#ifdef CONFIG_PM
201
202
static void snd_cs4236_suspend(struct snd_wss *chip)
203
{
204
int reg;
205
206
guard(spinlock_irqsave)(&chip->reg_lock);
207
for (reg = 0; reg < 32; reg++)
208
chip->image[reg] = snd_wss_in(chip, reg);
209
for (reg = 0; reg < 18; reg++)
210
chip->eimage[reg] = snd_cs4236_ext_in(chip, CS4236_I23VAL(reg));
211
for (reg = 2; reg < 9; reg++)
212
chip->cimage[reg] = snd_cs4236_ctrl_in(chip, reg);
213
}
214
215
static void snd_cs4236_resume(struct snd_wss *chip)
216
{
217
int reg;
218
219
snd_wss_mce_up(chip);
220
scoped_guard(spinlock_irqsave, &chip->reg_lock) {
221
for (reg = 0; reg < 32; reg++) {
222
switch (reg) {
223
case CS4236_EXT_REG:
224
case CS4231_VERSION:
225
case 27: /* why? CS4235 - master left */
226
case 29: /* why? CS4235 - master right */
227
break;
228
default:
229
snd_wss_out(chip, reg, chip->image[reg]);
230
break;
231
}
232
}
233
for (reg = 0; reg < 18; reg++)
234
snd_cs4236_ext_out(chip, CS4236_I23VAL(reg), chip->eimage[reg]);
235
for (reg = 2; reg < 9; reg++) {
236
switch (reg) {
237
case 7:
238
break;
239
default:
240
snd_cs4236_ctrl_out(chip, reg, chip->cimage[reg]);
241
}
242
}
243
}
244
snd_wss_mce_down(chip);
245
}
246
247
#endif /* CONFIG_PM */
248
/*
249
* This function does no fail if the chip is not CS4236B or compatible.
250
* It just an equivalent to the snd_wss_create() then.
251
*/
252
int snd_cs4236_create(struct snd_card *card,
253
unsigned long port,
254
unsigned long cport,
255
int irq, int dma1, int dma2,
256
unsigned short hardware,
257
unsigned short hwshare,
258
struct snd_wss **rchip)
259
{
260
struct snd_wss *chip;
261
unsigned char ver1, ver2;
262
unsigned int reg;
263
int err;
264
265
*rchip = NULL;
266
if (hardware == WSS_HW_DETECT)
267
hardware = WSS_HW_DETECT3;
268
269
err = snd_wss_create(card, port, cport,
270
irq, dma1, dma2, hardware, hwshare, &chip);
271
if (err < 0)
272
return err;
273
274
if ((chip->hardware & WSS_HW_CS4236B_MASK) == 0) {
275
dev_dbg(card->dev, "chip is not CS4236+, hardware=0x%x\n",
276
chip->hardware);
277
*rchip = chip;
278
return 0;
279
}
280
#if 0
281
{
282
int idx;
283
for (idx = 0; idx < 8; idx++)
284
dev_dbg(card->dev, "CD%i = 0x%x\n",
285
idx, inb(chip->cport + idx));
286
for (idx = 0; idx < 9; idx++)
287
dev_dbg(card->dev, "C%i = 0x%x\n",
288
idx, snd_cs4236_ctrl_in(chip, idx));
289
}
290
#endif
291
if (cport < 0x100 || cport == SNDRV_AUTO_PORT) {
292
dev_err(card->dev, "please, specify control port for CS4236+ chips\n");
293
return -ENODEV;
294
}
295
ver1 = snd_cs4236_ctrl_in(chip, 1);
296
ver2 = snd_cs4236_ext_in(chip, CS4236_VERSION);
297
dev_dbg(card->dev, "CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n",
298
cport, ver1, ver2);
299
if (ver1 != ver2) {
300
dev_err(card->dev,
301
"CS4236+ chip detected, but control port 0x%lx is not valid\n",
302
cport);
303
return -ENODEV;
304
}
305
snd_cs4236_ctrl_out(chip, 0, 0x00);
306
snd_cs4236_ctrl_out(chip, 2, 0xff);
307
snd_cs4236_ctrl_out(chip, 3, 0x00);
308
snd_cs4236_ctrl_out(chip, 4, 0x80);
309
reg = ((IEC958_AES1_CON_PCM_CODER & 3) << 6) |
310
IEC958_AES0_CON_EMPHASIS_NONE;
311
snd_cs4236_ctrl_out(chip, 5, reg);
312
snd_cs4236_ctrl_out(chip, 6, IEC958_AES1_CON_PCM_CODER >> 2);
313
snd_cs4236_ctrl_out(chip, 7, 0x00);
314
/*
315
* 0x8c for C8 is valid for Turtle Beach Malibu - the IEC-958
316
* output is working with this setup, other hardware should
317
* have different signal paths and this value should be
318
* selectable in the future
319
*/
320
snd_cs4236_ctrl_out(chip, 8, 0x8c);
321
chip->rate_constraint = snd_cs4236_xrate;
322
chip->set_playback_format = snd_cs4236_playback_format;
323
chip->set_capture_format = snd_cs4236_capture_format;
324
#ifdef CONFIG_PM
325
chip->suspend = snd_cs4236_suspend;
326
chip->resume = snd_cs4236_resume;
327
#endif
328
329
/* initialize extended registers */
330
for (reg = 0; reg < sizeof(snd_cs4236_ext_map); reg++)
331
snd_cs4236_ext_out(chip, CS4236_I23VAL(reg),
332
snd_cs4236_ext_map[reg]);
333
334
/* initialize compatible but more featured registers */
335
snd_wss_out(chip, CS4231_LEFT_INPUT, 0x40);
336
snd_wss_out(chip, CS4231_RIGHT_INPUT, 0x40);
337
snd_wss_out(chip, CS4231_AUX1_LEFT_INPUT, 0xff);
338
snd_wss_out(chip, CS4231_AUX1_RIGHT_INPUT, 0xff);
339
snd_wss_out(chip, CS4231_AUX2_LEFT_INPUT, 0xdf);
340
snd_wss_out(chip, CS4231_AUX2_RIGHT_INPUT, 0xdf);
341
snd_wss_out(chip, CS4231_RIGHT_LINE_IN, 0xff);
342
snd_wss_out(chip, CS4231_LEFT_LINE_IN, 0xff);
343
snd_wss_out(chip, CS4231_RIGHT_LINE_IN, 0xff);
344
switch (chip->hardware) {
345
case WSS_HW_CS4235:
346
case WSS_HW_CS4239:
347
snd_wss_out(chip, CS4235_LEFT_MASTER, 0xff);
348
snd_wss_out(chip, CS4235_RIGHT_MASTER, 0xff);
349
break;
350
}
351
352
*rchip = chip;
353
return 0;
354
}
355
356
int snd_cs4236_pcm(struct snd_wss *chip, int device)
357
{
358
int err;
359
360
err = snd_wss_pcm(chip, device);
361
if (err < 0)
362
return err;
363
chip->pcm->info_flags &= ~SNDRV_PCM_INFO_JOINT_DUPLEX;
364
return 0;
365
}
366
367
/*
368
* MIXER
369
*/
370
371
#define CS4236_SINGLE(xname, xindex, reg, shift, mask, invert) \
372
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
373
.info = snd_cs4236_info_single, \
374
.get = snd_cs4236_get_single, .put = snd_cs4236_put_single, \
375
.private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
376
377
#define CS4236_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \
378
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
379
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
380
.info = snd_cs4236_info_single, \
381
.get = snd_cs4236_get_single, .put = snd_cs4236_put_single, \
382
.private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \
383
.tlv = { .p = (xtlv) } }
384
385
static int snd_cs4236_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
386
{
387
int mask = (kcontrol->private_value >> 16) & 0xff;
388
389
uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
390
uinfo->count = 1;
391
uinfo->value.integer.min = 0;
392
uinfo->value.integer.max = mask;
393
return 0;
394
}
395
396
static int snd_cs4236_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
397
{
398
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
399
int reg = kcontrol->private_value & 0xff;
400
int shift = (kcontrol->private_value >> 8) & 0xff;
401
int mask = (kcontrol->private_value >> 16) & 0xff;
402
int invert = (kcontrol->private_value >> 24) & 0xff;
403
404
guard(spinlock_irqsave)(&chip->reg_lock);
405
ucontrol->value.integer.value[0] = (chip->eimage[CS4236_REG(reg)] >> shift) & mask;
406
if (invert)
407
ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
408
return 0;
409
}
410
411
static int snd_cs4236_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
412
{
413
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
414
int reg = kcontrol->private_value & 0xff;
415
int shift = (kcontrol->private_value >> 8) & 0xff;
416
int mask = (kcontrol->private_value >> 16) & 0xff;
417
int invert = (kcontrol->private_value >> 24) & 0xff;
418
int change;
419
unsigned short val;
420
421
val = (ucontrol->value.integer.value[0] & mask);
422
if (invert)
423
val = mask - val;
424
val <<= shift;
425
guard(spinlock_irqsave)(&chip->reg_lock);
426
val = (chip->eimage[CS4236_REG(reg)] & ~(mask << shift)) | val;
427
change = val != chip->eimage[CS4236_REG(reg)];
428
snd_cs4236_ext_out(chip, reg, val);
429
return change;
430
}
431
432
#define CS4236_SINGLEC(xname, xindex, reg, shift, mask, invert) \
433
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
434
.info = snd_cs4236_info_single, \
435
.get = snd_cs4236_get_singlec, .put = snd_cs4236_put_singlec, \
436
.private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
437
438
static int snd_cs4236_get_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
439
{
440
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
441
int reg = kcontrol->private_value & 0xff;
442
int shift = (kcontrol->private_value >> 8) & 0xff;
443
int mask = (kcontrol->private_value >> 16) & 0xff;
444
int invert = (kcontrol->private_value >> 24) & 0xff;
445
446
guard(spinlock_irqsave)(&chip->reg_lock);
447
ucontrol->value.integer.value[0] = (chip->cimage[reg] >> shift) & mask;
448
if (invert)
449
ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
450
return 0;
451
}
452
453
static int snd_cs4236_put_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
454
{
455
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
456
int reg = kcontrol->private_value & 0xff;
457
int shift = (kcontrol->private_value >> 8) & 0xff;
458
int mask = (kcontrol->private_value >> 16) & 0xff;
459
int invert = (kcontrol->private_value >> 24) & 0xff;
460
int change;
461
unsigned short val;
462
463
val = (ucontrol->value.integer.value[0] & mask);
464
if (invert)
465
val = mask - val;
466
val <<= shift;
467
guard(spinlock_irqsave)(&chip->reg_lock);
468
val = (chip->cimage[reg] & ~(mask << shift)) | val;
469
change = val != chip->cimage[reg];
470
snd_cs4236_ctrl_out(chip, reg, val);
471
return change;
472
}
473
474
#define CS4236_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
475
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
476
.info = snd_cs4236_info_double, \
477
.get = snd_cs4236_get_double, .put = snd_cs4236_put_double, \
478
.private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
479
480
#define CS4236_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, \
481
shift_right, mask, invert, xtlv) \
482
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
483
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
484
.info = snd_cs4236_info_double, \
485
.get = snd_cs4236_get_double, .put = snd_cs4236_put_double, \
486
.private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \
487
(shift_right << 19) | (mask << 24) | (invert << 22), \
488
.tlv = { .p = (xtlv) } }
489
490
static int snd_cs4236_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
491
{
492
int mask = (kcontrol->private_value >> 24) & 0xff;
493
494
uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
495
uinfo->count = 2;
496
uinfo->value.integer.min = 0;
497
uinfo->value.integer.max = mask;
498
return 0;
499
}
500
501
static int snd_cs4236_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
502
{
503
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
504
int left_reg = kcontrol->private_value & 0xff;
505
int right_reg = (kcontrol->private_value >> 8) & 0xff;
506
int shift_left = (kcontrol->private_value >> 16) & 0x07;
507
int shift_right = (kcontrol->private_value >> 19) & 0x07;
508
int mask = (kcontrol->private_value >> 24) & 0xff;
509
int invert = (kcontrol->private_value >> 22) & 1;
510
511
guard(spinlock_irqsave)(&chip->reg_lock);
512
ucontrol->value.integer.value[0] = (chip->eimage[CS4236_REG(left_reg)] >> shift_left) & mask;
513
ucontrol->value.integer.value[1] = (chip->eimage[CS4236_REG(right_reg)] >> shift_right) & mask;
514
if (invert) {
515
ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
516
ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
517
}
518
return 0;
519
}
520
521
static int snd_cs4236_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
522
{
523
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
524
int left_reg = kcontrol->private_value & 0xff;
525
int right_reg = (kcontrol->private_value >> 8) & 0xff;
526
int shift_left = (kcontrol->private_value >> 16) & 0x07;
527
int shift_right = (kcontrol->private_value >> 19) & 0x07;
528
int mask = (kcontrol->private_value >> 24) & 0xff;
529
int invert = (kcontrol->private_value >> 22) & 1;
530
int change;
531
unsigned short val1, val2;
532
533
val1 = ucontrol->value.integer.value[0] & mask;
534
val2 = ucontrol->value.integer.value[1] & mask;
535
if (invert) {
536
val1 = mask - val1;
537
val2 = mask - val2;
538
}
539
val1 <<= shift_left;
540
val2 <<= shift_right;
541
guard(spinlock_irqsave)(&chip->reg_lock);
542
if (left_reg != right_reg) {
543
val1 = (chip->eimage[CS4236_REG(left_reg)] & ~(mask << shift_left)) | val1;
544
val2 = (chip->eimage[CS4236_REG(right_reg)] & ~(mask << shift_right)) | val2;
545
change = val1 != chip->eimage[CS4236_REG(left_reg)] || val2 != chip->eimage[CS4236_REG(right_reg)];
546
snd_cs4236_ext_out(chip, left_reg, val1);
547
snd_cs4236_ext_out(chip, right_reg, val2);
548
} else {
549
val1 = (chip->eimage[CS4236_REG(left_reg)] & ~((mask << shift_left) | (mask << shift_right))) | val1 | val2;
550
change = val1 != chip->eimage[CS4236_REG(left_reg)];
551
snd_cs4236_ext_out(chip, left_reg, val1);
552
}
553
return change;
554
}
555
556
#define CS4236_DOUBLE1(xname, xindex, left_reg, right_reg, shift_left, \
557
shift_right, mask, invert) \
558
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
559
.info = snd_cs4236_info_double, \
560
.get = snd_cs4236_get_double1, .put = snd_cs4236_put_double1, \
561
.private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
562
563
#define CS4236_DOUBLE1_TLV(xname, xindex, left_reg, right_reg, shift_left, \
564
shift_right, mask, invert, xtlv) \
565
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
566
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
567
.info = snd_cs4236_info_double, \
568
.get = snd_cs4236_get_double1, .put = snd_cs4236_put_double1, \
569
.private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \
570
(shift_right << 19) | (mask << 24) | (invert << 22), \
571
.tlv = { .p = (xtlv) } }
572
573
static int snd_cs4236_get_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
574
{
575
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
576
int left_reg = kcontrol->private_value & 0xff;
577
int right_reg = (kcontrol->private_value >> 8) & 0xff;
578
int shift_left = (kcontrol->private_value >> 16) & 0x07;
579
int shift_right = (kcontrol->private_value >> 19) & 0x07;
580
int mask = (kcontrol->private_value >> 24) & 0xff;
581
int invert = (kcontrol->private_value >> 22) & 1;
582
583
guard(spinlock_irqsave)(&chip->reg_lock);
584
ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask;
585
ucontrol->value.integer.value[1] = (chip->eimage[CS4236_REG(right_reg)] >> shift_right) & mask;
586
if (invert) {
587
ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
588
ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
589
}
590
return 0;
591
}
592
593
static int snd_cs4236_put_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
594
{
595
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
596
int left_reg = kcontrol->private_value & 0xff;
597
int right_reg = (kcontrol->private_value >> 8) & 0xff;
598
int shift_left = (kcontrol->private_value >> 16) & 0x07;
599
int shift_right = (kcontrol->private_value >> 19) & 0x07;
600
int mask = (kcontrol->private_value >> 24) & 0xff;
601
int invert = (kcontrol->private_value >> 22) & 1;
602
int change;
603
unsigned short val1, val2;
604
605
val1 = ucontrol->value.integer.value[0] & mask;
606
val2 = ucontrol->value.integer.value[1] & mask;
607
if (invert) {
608
val1 = mask - val1;
609
val2 = mask - val2;
610
}
611
val1 <<= shift_left;
612
val2 <<= shift_right;
613
guard(spinlock_irqsave)(&chip->reg_lock);
614
val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;
615
val2 = (chip->eimage[CS4236_REG(right_reg)] & ~(mask << shift_right)) | val2;
616
change = val1 != chip->image[left_reg] || val2 != chip->eimage[CS4236_REG(right_reg)];
617
snd_wss_out(chip, left_reg, val1);
618
snd_cs4236_ext_out(chip, right_reg, val2);
619
return change;
620
}
621
622
#define CS4236_MASTER_DIGITAL(xname, xindex, xtlv) \
623
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
624
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
625
.info = snd_cs4236_info_double, \
626
.get = snd_cs4236_get_master_digital, .put = snd_cs4236_put_master_digital, \
627
.private_value = 71 << 24, \
628
.tlv = { .p = (xtlv) } }
629
630
static inline int snd_cs4236_mixer_master_digital_invert_volume(int vol)
631
{
632
return (vol < 64) ? 63 - vol : 64 + (71 - vol);
633
}
634
635
static int snd_cs4236_get_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
636
{
637
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
638
639
guard(spinlock_irqsave)(&chip->reg_lock);
640
ucontrol->value.integer.value[0] = snd_cs4236_mixer_master_digital_invert_volume(chip->eimage[CS4236_REG(CS4236_LEFT_MASTER)] & 0x7f);
641
ucontrol->value.integer.value[1] = snd_cs4236_mixer_master_digital_invert_volume(chip->eimage[CS4236_REG(CS4236_RIGHT_MASTER)] & 0x7f);
642
return 0;
643
}
644
645
static int snd_cs4236_put_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
646
{
647
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
648
int change;
649
unsigned short val1, val2;
650
651
val1 = snd_cs4236_mixer_master_digital_invert_volume(ucontrol->value.integer.value[0] & 0x7f);
652
val2 = snd_cs4236_mixer_master_digital_invert_volume(ucontrol->value.integer.value[1] & 0x7f);
653
guard(spinlock_irqsave)(&chip->reg_lock);
654
val1 = (chip->eimage[CS4236_REG(CS4236_LEFT_MASTER)] & ~0x7f) | val1;
655
val2 = (chip->eimage[CS4236_REG(CS4236_RIGHT_MASTER)] & ~0x7f) | val2;
656
change = val1 != chip->eimage[CS4236_REG(CS4236_LEFT_MASTER)] || val2 != chip->eimage[CS4236_REG(CS4236_RIGHT_MASTER)];
657
snd_cs4236_ext_out(chip, CS4236_LEFT_MASTER, val1);
658
snd_cs4236_ext_out(chip, CS4236_RIGHT_MASTER, val2);
659
return change;
660
}
661
662
#define CS4235_OUTPUT_ACCU(xname, xindex, xtlv) \
663
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
664
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
665
.info = snd_cs4236_info_double, \
666
.get = snd_cs4235_get_output_accu, .put = snd_cs4235_put_output_accu, \
667
.private_value = 3 << 24, \
668
.tlv = { .p = (xtlv) } }
669
670
static inline int snd_cs4235_mixer_output_accu_get_volume(int vol)
671
{
672
switch ((vol >> 5) & 3) {
673
case 0: return 1;
674
case 1: return 3;
675
case 2: return 2;
676
case 3: return 0;
677
}
678
return 3;
679
}
680
681
static inline int snd_cs4235_mixer_output_accu_set_volume(int vol)
682
{
683
switch (vol & 3) {
684
case 0: return 3 << 5;
685
case 1: return 0 << 5;
686
case 2: return 2 << 5;
687
case 3: return 1 << 5;
688
}
689
return 1 << 5;
690
}
691
692
static int snd_cs4235_get_output_accu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
693
{
694
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
695
696
guard(spinlock_irqsave)(&chip->reg_lock);
697
ucontrol->value.integer.value[0] = snd_cs4235_mixer_output_accu_get_volume(chip->image[CS4235_LEFT_MASTER]);
698
ucontrol->value.integer.value[1] = snd_cs4235_mixer_output_accu_get_volume(chip->image[CS4235_RIGHT_MASTER]);
699
return 0;
700
}
701
702
static int snd_cs4235_put_output_accu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
703
{
704
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
705
int change;
706
unsigned short val1, val2;
707
708
val1 = snd_cs4235_mixer_output_accu_set_volume(ucontrol->value.integer.value[0]);
709
val2 = snd_cs4235_mixer_output_accu_set_volume(ucontrol->value.integer.value[1]);
710
guard(spinlock_irqsave)(&chip->reg_lock);
711
val1 = (chip->image[CS4235_LEFT_MASTER] & ~(3 << 5)) | val1;
712
val2 = (chip->image[CS4235_RIGHT_MASTER] & ~(3 << 5)) | val2;
713
change = val1 != chip->image[CS4235_LEFT_MASTER] || val2 != chip->image[CS4235_RIGHT_MASTER];
714
snd_wss_out(chip, CS4235_LEFT_MASTER, val1);
715
snd_wss_out(chip, CS4235_RIGHT_MASTER, val2);
716
return change;
717
}
718
719
static const DECLARE_TLV_DB_SCALE(db_scale_7bit, -9450, 150, 0);
720
static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
721
static const DECLARE_TLV_DB_SCALE(db_scale_6bit_12db_max, -8250, 150, 0);
722
static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
723
static const DECLARE_TLV_DB_SCALE(db_scale_5bit_22db_max, -2400, 150, 0);
724
static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
725
static const DECLARE_TLV_DB_SCALE(db_scale_2bit, -1800, 600, 0);
726
static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
727
728
static const struct snd_kcontrol_new snd_cs4236_controls[] = {
729
730
CS4236_DOUBLE("Master Digital Playback Switch", 0,
731
CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1),
732
CS4236_DOUBLE("Master Digital Capture Switch", 0,
733
CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1),
734
CS4236_MASTER_DIGITAL("Master Digital Volume", 0, db_scale_7bit),
735
736
CS4236_DOUBLE_TLV("Capture Boost Volume", 0,
737
CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1,
738
db_scale_2bit),
739
740
WSS_DOUBLE("PCM Playback Switch", 0,
741
CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
742
WSS_DOUBLE_TLV("PCM Playback Volume", 0,
743
CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1,
744
db_scale_6bit),
745
746
CS4236_DOUBLE("DSP Playback Switch", 0,
747
CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1),
748
CS4236_DOUBLE_TLV("DSP Playback Volume", 0,
749
CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 0, 0, 63, 1,
750
db_scale_6bit),
751
752
CS4236_DOUBLE("FM Playback Switch", 0,
753
CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1),
754
CS4236_DOUBLE_TLV("FM Playback Volume", 0,
755
CS4236_LEFT_FM, CS4236_RIGHT_FM, 0, 0, 63, 1,
756
db_scale_6bit),
757
758
CS4236_DOUBLE("Wavetable Playback Switch", 0,
759
CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1),
760
CS4236_DOUBLE_TLV("Wavetable Playback Volume", 0,
761
CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 0, 0, 63, 1,
762
db_scale_6bit_12db_max),
763
764
WSS_DOUBLE("Synth Playback Switch", 0,
765
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
766
WSS_DOUBLE_TLV("Synth Volume", 0,
767
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1,
768
db_scale_5bit_12db_max),
769
WSS_DOUBLE("Synth Capture Switch", 0,
770
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1),
771
WSS_DOUBLE("Synth Capture Bypass", 0,
772
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 5, 5, 1, 1),
773
774
CS4236_DOUBLE("Mic Playback Switch", 0,
775
CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1),
776
CS4236_DOUBLE("Mic Capture Switch", 0,
777
CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1),
778
CS4236_DOUBLE_TLV("Mic Volume", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC,
779
0, 0, 31, 1, db_scale_5bit_22db_max),
780
CS4236_DOUBLE("Mic Playback Boost (+20dB)", 0,
781
CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 5, 5, 1, 0),
782
783
WSS_DOUBLE("Line Playback Switch", 0,
784
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
785
WSS_DOUBLE_TLV("Line Volume", 0,
786
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1,
787
db_scale_5bit_12db_max),
788
WSS_DOUBLE("Line Capture Switch", 0,
789
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1),
790
WSS_DOUBLE("Line Capture Bypass", 0,
791
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 5, 5, 1, 1),
792
793
WSS_DOUBLE("CD Playback Switch", 0,
794
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
795
WSS_DOUBLE_TLV("CD Volume", 0,
796
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1,
797
db_scale_5bit_12db_max),
798
WSS_DOUBLE("CD Capture Switch", 0,
799
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1),
800
801
CS4236_DOUBLE1("Mono Output Playback Switch", 0,
802
CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1),
803
CS4236_DOUBLE1("Beep Playback Switch", 0,
804
CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1),
805
WSS_SINGLE_TLV("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1,
806
db_scale_4bit),
807
WSS_SINGLE("Beep Bypass Playback Switch", 0, CS4231_MONO_CTRL, 5, 1, 0),
808
809
WSS_DOUBLE_TLV("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT,
810
0, 0, 15, 0, db_scale_rec_gain),
811
WSS_DOUBLE("Analog Loopback Capture Switch", 0,
812
CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0),
813
814
WSS_SINGLE("Loopback Digital Playback Switch", 0, CS4231_LOOPBACK, 0, 1, 0),
815
CS4236_DOUBLE1_TLV("Loopback Digital Playback Volume", 0,
816
CS4231_LOOPBACK, CS4236_RIGHT_LOOPBACK, 2, 0, 63, 1,
817
db_scale_6bit),
818
};
819
820
static const DECLARE_TLV_DB_SCALE(db_scale_5bit_6db_max, -5600, 200, 0);
821
static const DECLARE_TLV_DB_SCALE(db_scale_2bit_16db_max, -2400, 800, 0);
822
823
static const struct snd_kcontrol_new snd_cs4235_controls[] = {
824
825
WSS_DOUBLE("Master Playback Switch", 0,
826
CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 7, 7, 1, 1),
827
WSS_DOUBLE_TLV("Master Playback Volume", 0,
828
CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 0, 0, 31, 1,
829
db_scale_5bit_6db_max),
830
831
CS4235_OUTPUT_ACCU("Playback Volume", 0, db_scale_2bit_16db_max),
832
833
WSS_DOUBLE("Synth Playback Switch", 1,
834
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
835
WSS_DOUBLE("Synth Capture Switch", 1,
836
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1),
837
WSS_DOUBLE_TLV("Synth Volume", 1,
838
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1,
839
db_scale_5bit_12db_max),
840
841
CS4236_DOUBLE_TLV("Capture Volume", 0,
842
CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1,
843
db_scale_2bit),
844
845
WSS_DOUBLE("PCM Playback Switch", 0,
846
CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
847
WSS_DOUBLE("PCM Capture Switch", 0,
848
CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1),
849
WSS_DOUBLE_TLV("PCM Volume", 0,
850
CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1,
851
db_scale_6bit),
852
853
CS4236_DOUBLE("DSP Switch", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1),
854
855
CS4236_DOUBLE("FM Switch", 0, CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1),
856
857
CS4236_DOUBLE("Wavetable Switch", 0,
858
CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1),
859
860
CS4236_DOUBLE("Mic Capture Switch", 0,
861
CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1),
862
CS4236_DOUBLE("Mic Playback Switch", 0,
863
CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1),
864
CS4236_SINGLE_TLV("Mic Volume", 0, CS4236_LEFT_MIC, 0, 31, 1,
865
db_scale_5bit_22db_max),
866
CS4236_SINGLE("Mic Boost (+20dB)", 0, CS4236_LEFT_MIC, 5, 1, 0),
867
868
WSS_DOUBLE("Line Playback Switch", 0,
869
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
870
WSS_DOUBLE("Line Capture Switch", 0,
871
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1),
872
WSS_DOUBLE_TLV("Line Volume", 0,
873
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1,
874
db_scale_5bit_12db_max),
875
876
WSS_DOUBLE("CD Playback Switch", 1,
877
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
878
WSS_DOUBLE("CD Capture Switch", 1,
879
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1),
880
WSS_DOUBLE_TLV("CD Volume", 1,
881
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1,
882
db_scale_5bit_12db_max),
883
884
CS4236_DOUBLE1("Beep Playback Switch", 0,
885
CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1),
886
WSS_SINGLE("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
887
888
WSS_DOUBLE("Analog Loopback Switch", 0,
889
CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0),
890
};
891
892
#define CS4236_IEC958_ENABLE(xname, xindex) \
893
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
894
.info = snd_cs4236_info_single, \
895
.get = snd_cs4236_get_iec958_switch, .put = snd_cs4236_put_iec958_switch, \
896
.private_value = 1 << 16 }
897
898
static int snd_cs4236_get_iec958_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
899
{
900
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
901
902
guard(spinlock_irqsave)(&chip->reg_lock);
903
ucontrol->value.integer.value[0] = chip->image[CS4231_ALT_FEATURE_1] & 0x02 ? 1 : 0;
904
#if 0
905
dev_dbg(chip->card->dev,
906
"get valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
907
snd_wss_in(chip, CS4231_ALT_FEATURE_1),
908
snd_cs4236_ctrl_in(chip, 3),
909
snd_cs4236_ctrl_in(chip, 4),
910
snd_cs4236_ctrl_in(chip, 5),
911
snd_cs4236_ctrl_in(chip, 6),
912
snd_cs4236_ctrl_in(chip, 8));
913
#endif
914
return 0;
915
}
916
917
static int snd_cs4236_put_iec958_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
918
{
919
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
920
int change;
921
unsigned short enable, val;
922
923
enable = ucontrol->value.integer.value[0] & 1;
924
925
guard(mutex)(&chip->mce_mutex);
926
snd_wss_mce_up(chip);
927
scoped_guard(spinlock_irqsave, &chip->reg_lock) {
928
val = (chip->image[CS4231_ALT_FEATURE_1] & ~0x0e) | (0<<2) | (enable << 1);
929
change = val != chip->image[CS4231_ALT_FEATURE_1];
930
snd_wss_out(chip, CS4231_ALT_FEATURE_1, val);
931
val = snd_cs4236_ctrl_in(chip, 4) | 0xc0;
932
snd_cs4236_ctrl_out(chip, 4, val);
933
udelay(100);
934
val &= ~0x40;
935
snd_cs4236_ctrl_out(chip, 4, val);
936
}
937
snd_wss_mce_down(chip);
938
939
#if 0
940
dev_dbg(chip->card->dev,
941
"set valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
942
snd_wss_in(chip, CS4231_ALT_FEATURE_1),
943
snd_cs4236_ctrl_in(chip, 3),
944
snd_cs4236_ctrl_in(chip, 4),
945
snd_cs4236_ctrl_in(chip, 5),
946
snd_cs4236_ctrl_in(chip, 6),
947
snd_cs4236_ctrl_in(chip, 8));
948
#endif
949
return change;
950
}
951
952
static const struct snd_kcontrol_new snd_cs4236_iec958_controls[] = {
953
CS4236_IEC958_ENABLE("IEC958 Output Enable", 0),
954
CS4236_SINGLEC("IEC958 Output Validity", 0, 4, 4, 1, 0),
955
CS4236_SINGLEC("IEC958 Output User", 0, 4, 5, 1, 0),
956
CS4236_SINGLEC("IEC958 Output CSBR", 0, 4, 6, 1, 0),
957
CS4236_SINGLEC("IEC958 Output Channel Status Low", 0, 5, 1, 127, 0),
958
CS4236_SINGLEC("IEC958 Output Channel Status High", 0, 6, 0, 255, 0)
959
};
960
961
static const struct snd_kcontrol_new snd_cs4236_3d_controls_cs4235[] = {
962
CS4236_SINGLEC("3D Control - Switch", 0, 3, 4, 1, 0),
963
CS4236_SINGLEC("3D Control - Space", 0, 2, 4, 15, 1)
964
};
965
966
static const struct snd_kcontrol_new snd_cs4236_3d_controls_cs4237[] = {
967
CS4236_SINGLEC("3D Control - Switch", 0, 3, 7, 1, 0),
968
CS4236_SINGLEC("3D Control - Space", 0, 2, 4, 15, 1),
969
CS4236_SINGLEC("3D Control - Center", 0, 2, 0, 15, 1),
970
CS4236_SINGLEC("3D Control - Mono", 0, 3, 6, 1, 0),
971
CS4236_SINGLEC("3D Control - IEC958", 0, 3, 5, 1, 0)
972
};
973
974
static const struct snd_kcontrol_new snd_cs4236_3d_controls_cs4238[] = {
975
CS4236_SINGLEC("3D Control - Switch", 0, 3, 4, 1, 0),
976
CS4236_SINGLEC("3D Control - Space", 0, 2, 4, 15, 1),
977
CS4236_SINGLEC("3D Control - Volume", 0, 2, 0, 15, 1),
978
CS4236_SINGLEC("3D Control - IEC958", 0, 3, 5, 1, 0)
979
};
980
981
int snd_cs4236_mixer(struct snd_wss *chip)
982
{
983
struct snd_card *card;
984
unsigned int idx, count;
985
int err;
986
const struct snd_kcontrol_new *kcontrol;
987
988
if (snd_BUG_ON(!chip || !chip->card))
989
return -EINVAL;
990
card = chip->card;
991
strscpy(card->mixername, snd_wss_chip_id(chip));
992
993
if (chip->hardware == WSS_HW_CS4235 ||
994
chip->hardware == WSS_HW_CS4239) {
995
for (idx = 0; idx < ARRAY_SIZE(snd_cs4235_controls); idx++) {
996
err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4235_controls[idx], chip));
997
if (err < 0)
998
return err;
999
}
1000
} else {
1001
for (idx = 0; idx < ARRAY_SIZE(snd_cs4236_controls); idx++) {
1002
err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4236_controls[idx], chip));
1003
if (err < 0)
1004
return err;
1005
}
1006
}
1007
switch (chip->hardware) {
1008
case WSS_HW_CS4235:
1009
case WSS_HW_CS4239:
1010
count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4235);
1011
kcontrol = snd_cs4236_3d_controls_cs4235;
1012
break;
1013
case WSS_HW_CS4237B:
1014
count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4237);
1015
kcontrol = snd_cs4236_3d_controls_cs4237;
1016
break;
1017
case WSS_HW_CS4238B:
1018
count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4238);
1019
kcontrol = snd_cs4236_3d_controls_cs4238;
1020
break;
1021
default:
1022
count = 0;
1023
kcontrol = NULL;
1024
}
1025
for (idx = 0; idx < count; idx++, kcontrol++) {
1026
err = snd_ctl_add(card, snd_ctl_new1(kcontrol, chip));
1027
if (err < 0)
1028
return err;
1029
}
1030
if (chip->hardware == WSS_HW_CS4237B ||
1031
chip->hardware == WSS_HW_CS4238B) {
1032
for (idx = 0; idx < ARRAY_SIZE(snd_cs4236_iec958_controls); idx++) {
1033
err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4236_iec958_controls[idx], chip));
1034
if (err < 0)
1035
return err;
1036
}
1037
}
1038
return 0;
1039
}
1040
1041