Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/isa/cs423x/cs4236_lib.c
26424 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 long flags;
173
unsigned char rate = divisor_to_rate_register(params->rate_den);
174
175
spin_lock_irqsave(&chip->reg_lock, flags);
176
/* set fast playback format change and clean playback FIFO */
177
snd_wss_out(chip, CS4231_ALT_FEATURE_1,
178
chip->image[CS4231_ALT_FEATURE_1] | 0x10);
179
snd_wss_out(chip, CS4231_PLAYBK_FORMAT, pdfr & 0xf0);
180
snd_wss_out(chip, CS4231_ALT_FEATURE_1,
181
chip->image[CS4231_ALT_FEATURE_1] & ~0x10);
182
snd_cs4236_ext_out(chip, CS4236_DAC_RATE, rate);
183
spin_unlock_irqrestore(&chip->reg_lock, flags);
184
}
185
186
static void snd_cs4236_capture_format(struct snd_wss *chip,
187
struct snd_pcm_hw_params *params,
188
unsigned char cdfr)
189
{
190
unsigned long flags;
191
unsigned char rate = divisor_to_rate_register(params->rate_den);
192
193
spin_lock_irqsave(&chip->reg_lock, flags);
194
/* set fast capture format change and clean capture FIFO */
195
snd_wss_out(chip, CS4231_ALT_FEATURE_1,
196
chip->image[CS4231_ALT_FEATURE_1] | 0x20);
197
snd_wss_out(chip, CS4231_REC_FORMAT, cdfr & 0xf0);
198
snd_wss_out(chip, CS4231_ALT_FEATURE_1,
199
chip->image[CS4231_ALT_FEATURE_1] & ~0x20);
200
snd_cs4236_ext_out(chip, CS4236_ADC_RATE, rate);
201
spin_unlock_irqrestore(&chip->reg_lock, flags);
202
}
203
204
#ifdef CONFIG_PM
205
206
static void snd_cs4236_suspend(struct snd_wss *chip)
207
{
208
int reg;
209
unsigned long flags;
210
211
spin_lock_irqsave(&chip->reg_lock, flags);
212
for (reg = 0; reg < 32; reg++)
213
chip->image[reg] = snd_wss_in(chip, reg);
214
for (reg = 0; reg < 18; reg++)
215
chip->eimage[reg] = snd_cs4236_ext_in(chip, CS4236_I23VAL(reg));
216
for (reg = 2; reg < 9; reg++)
217
chip->cimage[reg] = snd_cs4236_ctrl_in(chip, reg);
218
spin_unlock_irqrestore(&chip->reg_lock, flags);
219
}
220
221
static void snd_cs4236_resume(struct snd_wss *chip)
222
{
223
int reg;
224
unsigned long flags;
225
226
snd_wss_mce_up(chip);
227
spin_lock_irqsave(&chip->reg_lock, flags);
228
for (reg = 0; reg < 32; reg++) {
229
switch (reg) {
230
case CS4236_EXT_REG:
231
case CS4231_VERSION:
232
case 27: /* why? CS4235 - master left */
233
case 29: /* why? CS4235 - master right */
234
break;
235
default:
236
snd_wss_out(chip, reg, chip->image[reg]);
237
break;
238
}
239
}
240
for (reg = 0; reg < 18; reg++)
241
snd_cs4236_ext_out(chip, CS4236_I23VAL(reg), chip->eimage[reg]);
242
for (reg = 2; reg < 9; reg++) {
243
switch (reg) {
244
case 7:
245
break;
246
default:
247
snd_cs4236_ctrl_out(chip, reg, chip->cimage[reg]);
248
}
249
}
250
spin_unlock_irqrestore(&chip->reg_lock, flags);
251
snd_wss_mce_down(chip);
252
}
253
254
#endif /* CONFIG_PM */
255
/*
256
* This function does no fail if the chip is not CS4236B or compatible.
257
* It just an equivalent to the snd_wss_create() then.
258
*/
259
int snd_cs4236_create(struct snd_card *card,
260
unsigned long port,
261
unsigned long cport,
262
int irq, int dma1, int dma2,
263
unsigned short hardware,
264
unsigned short hwshare,
265
struct snd_wss **rchip)
266
{
267
struct snd_wss *chip;
268
unsigned char ver1, ver2;
269
unsigned int reg;
270
int err;
271
272
*rchip = NULL;
273
if (hardware == WSS_HW_DETECT)
274
hardware = WSS_HW_DETECT3;
275
276
err = snd_wss_create(card, port, cport,
277
irq, dma1, dma2, hardware, hwshare, &chip);
278
if (err < 0)
279
return err;
280
281
if ((chip->hardware & WSS_HW_CS4236B_MASK) == 0) {
282
dev_dbg(card->dev, "chip is not CS4236+, hardware=0x%x\n",
283
chip->hardware);
284
*rchip = chip;
285
return 0;
286
}
287
#if 0
288
{
289
int idx;
290
for (idx = 0; idx < 8; idx++)
291
dev_dbg(card->dev, "CD%i = 0x%x\n",
292
idx, inb(chip->cport + idx));
293
for (idx = 0; idx < 9; idx++)
294
dev_dbg(card->dev, "C%i = 0x%x\n",
295
idx, snd_cs4236_ctrl_in(chip, idx));
296
}
297
#endif
298
if (cport < 0x100 || cport == SNDRV_AUTO_PORT) {
299
dev_err(card->dev, "please, specify control port for CS4236+ chips\n");
300
return -ENODEV;
301
}
302
ver1 = snd_cs4236_ctrl_in(chip, 1);
303
ver2 = snd_cs4236_ext_in(chip, CS4236_VERSION);
304
dev_dbg(card->dev, "CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n",
305
cport, ver1, ver2);
306
if (ver1 != ver2) {
307
dev_err(card->dev,
308
"CS4236+ chip detected, but control port 0x%lx is not valid\n",
309
cport);
310
return -ENODEV;
311
}
312
snd_cs4236_ctrl_out(chip, 0, 0x00);
313
snd_cs4236_ctrl_out(chip, 2, 0xff);
314
snd_cs4236_ctrl_out(chip, 3, 0x00);
315
snd_cs4236_ctrl_out(chip, 4, 0x80);
316
reg = ((IEC958_AES1_CON_PCM_CODER & 3) << 6) |
317
IEC958_AES0_CON_EMPHASIS_NONE;
318
snd_cs4236_ctrl_out(chip, 5, reg);
319
snd_cs4236_ctrl_out(chip, 6, IEC958_AES1_CON_PCM_CODER >> 2);
320
snd_cs4236_ctrl_out(chip, 7, 0x00);
321
/*
322
* 0x8c for C8 is valid for Turtle Beach Malibu - the IEC-958
323
* output is working with this setup, other hardware should
324
* have different signal paths and this value should be
325
* selectable in the future
326
*/
327
snd_cs4236_ctrl_out(chip, 8, 0x8c);
328
chip->rate_constraint = snd_cs4236_xrate;
329
chip->set_playback_format = snd_cs4236_playback_format;
330
chip->set_capture_format = snd_cs4236_capture_format;
331
#ifdef CONFIG_PM
332
chip->suspend = snd_cs4236_suspend;
333
chip->resume = snd_cs4236_resume;
334
#endif
335
336
/* initialize extended registers */
337
for (reg = 0; reg < sizeof(snd_cs4236_ext_map); reg++)
338
snd_cs4236_ext_out(chip, CS4236_I23VAL(reg),
339
snd_cs4236_ext_map[reg]);
340
341
/* initialize compatible but more featured registers */
342
snd_wss_out(chip, CS4231_LEFT_INPUT, 0x40);
343
snd_wss_out(chip, CS4231_RIGHT_INPUT, 0x40);
344
snd_wss_out(chip, CS4231_AUX1_LEFT_INPUT, 0xff);
345
snd_wss_out(chip, CS4231_AUX1_RIGHT_INPUT, 0xff);
346
snd_wss_out(chip, CS4231_AUX2_LEFT_INPUT, 0xdf);
347
snd_wss_out(chip, CS4231_AUX2_RIGHT_INPUT, 0xdf);
348
snd_wss_out(chip, CS4231_RIGHT_LINE_IN, 0xff);
349
snd_wss_out(chip, CS4231_LEFT_LINE_IN, 0xff);
350
snd_wss_out(chip, CS4231_RIGHT_LINE_IN, 0xff);
351
switch (chip->hardware) {
352
case WSS_HW_CS4235:
353
case WSS_HW_CS4239:
354
snd_wss_out(chip, CS4235_LEFT_MASTER, 0xff);
355
snd_wss_out(chip, CS4235_RIGHT_MASTER, 0xff);
356
break;
357
}
358
359
*rchip = chip;
360
return 0;
361
}
362
363
int snd_cs4236_pcm(struct snd_wss *chip, int device)
364
{
365
int err;
366
367
err = snd_wss_pcm(chip, device);
368
if (err < 0)
369
return err;
370
chip->pcm->info_flags &= ~SNDRV_PCM_INFO_JOINT_DUPLEX;
371
return 0;
372
}
373
374
/*
375
* MIXER
376
*/
377
378
#define CS4236_SINGLE(xname, xindex, reg, shift, mask, invert) \
379
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
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
384
#define CS4236_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \
385
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
386
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
387
.info = snd_cs4236_info_single, \
388
.get = snd_cs4236_get_single, .put = snd_cs4236_put_single, \
389
.private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \
390
.tlv = { .p = (xtlv) } }
391
392
static int snd_cs4236_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
393
{
394
int mask = (kcontrol->private_value >> 16) & 0xff;
395
396
uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
397
uinfo->count = 1;
398
uinfo->value.integer.min = 0;
399
uinfo->value.integer.max = mask;
400
return 0;
401
}
402
403
static int snd_cs4236_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
404
{
405
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
406
unsigned long flags;
407
int reg = kcontrol->private_value & 0xff;
408
int shift = (kcontrol->private_value >> 8) & 0xff;
409
int mask = (kcontrol->private_value >> 16) & 0xff;
410
int invert = (kcontrol->private_value >> 24) & 0xff;
411
412
spin_lock_irqsave(&chip->reg_lock, flags);
413
ucontrol->value.integer.value[0] = (chip->eimage[CS4236_REG(reg)] >> shift) & mask;
414
spin_unlock_irqrestore(&chip->reg_lock, flags);
415
if (invert)
416
ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
417
return 0;
418
}
419
420
static int snd_cs4236_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
421
{
422
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
423
unsigned long flags;
424
int reg = kcontrol->private_value & 0xff;
425
int shift = (kcontrol->private_value >> 8) & 0xff;
426
int mask = (kcontrol->private_value >> 16) & 0xff;
427
int invert = (kcontrol->private_value >> 24) & 0xff;
428
int change;
429
unsigned short val;
430
431
val = (ucontrol->value.integer.value[0] & mask);
432
if (invert)
433
val = mask - val;
434
val <<= shift;
435
spin_lock_irqsave(&chip->reg_lock, flags);
436
val = (chip->eimage[CS4236_REG(reg)] & ~(mask << shift)) | val;
437
change = val != chip->eimage[CS4236_REG(reg)];
438
snd_cs4236_ext_out(chip, reg, val);
439
spin_unlock_irqrestore(&chip->reg_lock, flags);
440
return change;
441
}
442
443
#define CS4236_SINGLEC(xname, xindex, reg, shift, mask, invert) \
444
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
445
.info = snd_cs4236_info_single, \
446
.get = snd_cs4236_get_singlec, .put = snd_cs4236_put_singlec, \
447
.private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
448
449
static int snd_cs4236_get_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
450
{
451
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
452
unsigned long flags;
453
int reg = kcontrol->private_value & 0xff;
454
int shift = (kcontrol->private_value >> 8) & 0xff;
455
int mask = (kcontrol->private_value >> 16) & 0xff;
456
int invert = (kcontrol->private_value >> 24) & 0xff;
457
458
spin_lock_irqsave(&chip->reg_lock, flags);
459
ucontrol->value.integer.value[0] = (chip->cimage[reg] >> shift) & mask;
460
spin_unlock_irqrestore(&chip->reg_lock, flags);
461
if (invert)
462
ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
463
return 0;
464
}
465
466
static int snd_cs4236_put_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
467
{
468
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
469
unsigned long flags;
470
int reg = kcontrol->private_value & 0xff;
471
int shift = (kcontrol->private_value >> 8) & 0xff;
472
int mask = (kcontrol->private_value >> 16) & 0xff;
473
int invert = (kcontrol->private_value >> 24) & 0xff;
474
int change;
475
unsigned short val;
476
477
val = (ucontrol->value.integer.value[0] & mask);
478
if (invert)
479
val = mask - val;
480
val <<= shift;
481
spin_lock_irqsave(&chip->reg_lock, flags);
482
val = (chip->cimage[reg] & ~(mask << shift)) | val;
483
change = val != chip->cimage[reg];
484
snd_cs4236_ctrl_out(chip, reg, val);
485
spin_unlock_irqrestore(&chip->reg_lock, flags);
486
return change;
487
}
488
489
#define CS4236_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
490
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
491
.info = snd_cs4236_info_double, \
492
.get = snd_cs4236_get_double, .put = snd_cs4236_put_double, \
493
.private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
494
495
#define CS4236_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, \
496
shift_right, mask, invert, xtlv) \
497
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
498
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
499
.info = snd_cs4236_info_double, \
500
.get = snd_cs4236_get_double, .put = snd_cs4236_put_double, \
501
.private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \
502
(shift_right << 19) | (mask << 24) | (invert << 22), \
503
.tlv = { .p = (xtlv) } }
504
505
static int snd_cs4236_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
506
{
507
int mask = (kcontrol->private_value >> 24) & 0xff;
508
509
uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
510
uinfo->count = 2;
511
uinfo->value.integer.min = 0;
512
uinfo->value.integer.max = mask;
513
return 0;
514
}
515
516
static int snd_cs4236_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
517
{
518
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
519
unsigned long flags;
520
int left_reg = kcontrol->private_value & 0xff;
521
int right_reg = (kcontrol->private_value >> 8) & 0xff;
522
int shift_left = (kcontrol->private_value >> 16) & 0x07;
523
int shift_right = (kcontrol->private_value >> 19) & 0x07;
524
int mask = (kcontrol->private_value >> 24) & 0xff;
525
int invert = (kcontrol->private_value >> 22) & 1;
526
527
spin_lock_irqsave(&chip->reg_lock, flags);
528
ucontrol->value.integer.value[0] = (chip->eimage[CS4236_REG(left_reg)] >> shift_left) & mask;
529
ucontrol->value.integer.value[1] = (chip->eimage[CS4236_REG(right_reg)] >> shift_right) & mask;
530
spin_unlock_irqrestore(&chip->reg_lock, flags);
531
if (invert) {
532
ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
533
ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
534
}
535
return 0;
536
}
537
538
static int snd_cs4236_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
539
{
540
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
541
unsigned long flags;
542
int left_reg = kcontrol->private_value & 0xff;
543
int right_reg = (kcontrol->private_value >> 8) & 0xff;
544
int shift_left = (kcontrol->private_value >> 16) & 0x07;
545
int shift_right = (kcontrol->private_value >> 19) & 0x07;
546
int mask = (kcontrol->private_value >> 24) & 0xff;
547
int invert = (kcontrol->private_value >> 22) & 1;
548
int change;
549
unsigned short val1, val2;
550
551
val1 = ucontrol->value.integer.value[0] & mask;
552
val2 = ucontrol->value.integer.value[1] & mask;
553
if (invert) {
554
val1 = mask - val1;
555
val2 = mask - val2;
556
}
557
val1 <<= shift_left;
558
val2 <<= shift_right;
559
spin_lock_irqsave(&chip->reg_lock, flags);
560
if (left_reg != right_reg) {
561
val1 = (chip->eimage[CS4236_REG(left_reg)] & ~(mask << shift_left)) | val1;
562
val2 = (chip->eimage[CS4236_REG(right_reg)] & ~(mask << shift_right)) | val2;
563
change = val1 != chip->eimage[CS4236_REG(left_reg)] || val2 != chip->eimage[CS4236_REG(right_reg)];
564
snd_cs4236_ext_out(chip, left_reg, val1);
565
snd_cs4236_ext_out(chip, right_reg, val2);
566
} else {
567
val1 = (chip->eimage[CS4236_REG(left_reg)] & ~((mask << shift_left) | (mask << shift_right))) | val1 | val2;
568
change = val1 != chip->eimage[CS4236_REG(left_reg)];
569
snd_cs4236_ext_out(chip, left_reg, val1);
570
}
571
spin_unlock_irqrestore(&chip->reg_lock, flags);
572
return change;
573
}
574
575
#define CS4236_DOUBLE1(xname, xindex, left_reg, right_reg, shift_left, \
576
shift_right, mask, invert) \
577
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
578
.info = snd_cs4236_info_double, \
579
.get = snd_cs4236_get_double1, .put = snd_cs4236_put_double1, \
580
.private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
581
582
#define CS4236_DOUBLE1_TLV(xname, xindex, left_reg, right_reg, shift_left, \
583
shift_right, mask, invert, xtlv) \
584
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
585
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
586
.info = snd_cs4236_info_double, \
587
.get = snd_cs4236_get_double1, .put = snd_cs4236_put_double1, \
588
.private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \
589
(shift_right << 19) | (mask << 24) | (invert << 22), \
590
.tlv = { .p = (xtlv) } }
591
592
static int snd_cs4236_get_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
593
{
594
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
595
unsigned long flags;
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
603
spin_lock_irqsave(&chip->reg_lock, flags);
604
ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask;
605
ucontrol->value.integer.value[1] = (chip->eimage[CS4236_REG(right_reg)] >> shift_right) & mask;
606
spin_unlock_irqrestore(&chip->reg_lock, flags);
607
if (invert) {
608
ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
609
ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
610
}
611
return 0;
612
}
613
614
static int snd_cs4236_put_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
615
{
616
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
617
unsigned long flags;
618
int left_reg = kcontrol->private_value & 0xff;
619
int right_reg = (kcontrol->private_value >> 8) & 0xff;
620
int shift_left = (kcontrol->private_value >> 16) & 0x07;
621
int shift_right = (kcontrol->private_value >> 19) & 0x07;
622
int mask = (kcontrol->private_value >> 24) & 0xff;
623
int invert = (kcontrol->private_value >> 22) & 1;
624
int change;
625
unsigned short val1, val2;
626
627
val1 = ucontrol->value.integer.value[0] & mask;
628
val2 = ucontrol->value.integer.value[1] & mask;
629
if (invert) {
630
val1 = mask - val1;
631
val2 = mask - val2;
632
}
633
val1 <<= shift_left;
634
val2 <<= shift_right;
635
spin_lock_irqsave(&chip->reg_lock, flags);
636
val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;
637
val2 = (chip->eimage[CS4236_REG(right_reg)] & ~(mask << shift_right)) | val2;
638
change = val1 != chip->image[left_reg] || val2 != chip->eimage[CS4236_REG(right_reg)];
639
snd_wss_out(chip, left_reg, val1);
640
snd_cs4236_ext_out(chip, right_reg, val2);
641
spin_unlock_irqrestore(&chip->reg_lock, flags);
642
return change;
643
}
644
645
#define CS4236_MASTER_DIGITAL(xname, xindex, xtlv) \
646
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
647
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
648
.info = snd_cs4236_info_double, \
649
.get = snd_cs4236_get_master_digital, .put = snd_cs4236_put_master_digital, \
650
.private_value = 71 << 24, \
651
.tlv = { .p = (xtlv) } }
652
653
static inline int snd_cs4236_mixer_master_digital_invert_volume(int vol)
654
{
655
return (vol < 64) ? 63 - vol : 64 + (71 - vol);
656
}
657
658
static int snd_cs4236_get_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
659
{
660
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
661
unsigned long flags;
662
663
spin_lock_irqsave(&chip->reg_lock, flags);
664
ucontrol->value.integer.value[0] = snd_cs4236_mixer_master_digital_invert_volume(chip->eimage[CS4236_REG(CS4236_LEFT_MASTER)] & 0x7f);
665
ucontrol->value.integer.value[1] = snd_cs4236_mixer_master_digital_invert_volume(chip->eimage[CS4236_REG(CS4236_RIGHT_MASTER)] & 0x7f);
666
spin_unlock_irqrestore(&chip->reg_lock, flags);
667
return 0;
668
}
669
670
static int snd_cs4236_put_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
671
{
672
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
673
unsigned long flags;
674
int change;
675
unsigned short val1, val2;
676
677
val1 = snd_cs4236_mixer_master_digital_invert_volume(ucontrol->value.integer.value[0] & 0x7f);
678
val2 = snd_cs4236_mixer_master_digital_invert_volume(ucontrol->value.integer.value[1] & 0x7f);
679
spin_lock_irqsave(&chip->reg_lock, flags);
680
val1 = (chip->eimage[CS4236_REG(CS4236_LEFT_MASTER)] & ~0x7f) | val1;
681
val2 = (chip->eimage[CS4236_REG(CS4236_RIGHT_MASTER)] & ~0x7f) | val2;
682
change = val1 != chip->eimage[CS4236_REG(CS4236_LEFT_MASTER)] || val2 != chip->eimage[CS4236_REG(CS4236_RIGHT_MASTER)];
683
snd_cs4236_ext_out(chip, CS4236_LEFT_MASTER, val1);
684
snd_cs4236_ext_out(chip, CS4236_RIGHT_MASTER, val2);
685
spin_unlock_irqrestore(&chip->reg_lock, flags);
686
return change;
687
}
688
689
#define CS4235_OUTPUT_ACCU(xname, xindex, xtlv) \
690
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
691
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
692
.info = snd_cs4236_info_double, \
693
.get = snd_cs4235_get_output_accu, .put = snd_cs4235_put_output_accu, \
694
.private_value = 3 << 24, \
695
.tlv = { .p = (xtlv) } }
696
697
static inline int snd_cs4235_mixer_output_accu_get_volume(int vol)
698
{
699
switch ((vol >> 5) & 3) {
700
case 0: return 1;
701
case 1: return 3;
702
case 2: return 2;
703
case 3: return 0;
704
}
705
return 3;
706
}
707
708
static inline int snd_cs4235_mixer_output_accu_set_volume(int vol)
709
{
710
switch (vol & 3) {
711
case 0: return 3 << 5;
712
case 1: return 0 << 5;
713
case 2: return 2 << 5;
714
case 3: return 1 << 5;
715
}
716
return 1 << 5;
717
}
718
719
static int snd_cs4235_get_output_accu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
720
{
721
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
722
unsigned long flags;
723
724
spin_lock_irqsave(&chip->reg_lock, flags);
725
ucontrol->value.integer.value[0] = snd_cs4235_mixer_output_accu_get_volume(chip->image[CS4235_LEFT_MASTER]);
726
ucontrol->value.integer.value[1] = snd_cs4235_mixer_output_accu_get_volume(chip->image[CS4235_RIGHT_MASTER]);
727
spin_unlock_irqrestore(&chip->reg_lock, flags);
728
return 0;
729
}
730
731
static int snd_cs4235_put_output_accu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
732
{
733
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
734
unsigned long flags;
735
int change;
736
unsigned short val1, val2;
737
738
val1 = snd_cs4235_mixer_output_accu_set_volume(ucontrol->value.integer.value[0]);
739
val2 = snd_cs4235_mixer_output_accu_set_volume(ucontrol->value.integer.value[1]);
740
spin_lock_irqsave(&chip->reg_lock, flags);
741
val1 = (chip->image[CS4235_LEFT_MASTER] & ~(3 << 5)) | val1;
742
val2 = (chip->image[CS4235_RIGHT_MASTER] & ~(3 << 5)) | val2;
743
change = val1 != chip->image[CS4235_LEFT_MASTER] || val2 != chip->image[CS4235_RIGHT_MASTER];
744
snd_wss_out(chip, CS4235_LEFT_MASTER, val1);
745
snd_wss_out(chip, CS4235_RIGHT_MASTER, val2);
746
spin_unlock_irqrestore(&chip->reg_lock, flags);
747
return change;
748
}
749
750
static const DECLARE_TLV_DB_SCALE(db_scale_7bit, -9450, 150, 0);
751
static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
752
static const DECLARE_TLV_DB_SCALE(db_scale_6bit_12db_max, -8250, 150, 0);
753
static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
754
static const DECLARE_TLV_DB_SCALE(db_scale_5bit_22db_max, -2400, 150, 0);
755
static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
756
static const DECLARE_TLV_DB_SCALE(db_scale_2bit, -1800, 600, 0);
757
static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
758
759
static const struct snd_kcontrol_new snd_cs4236_controls[] = {
760
761
CS4236_DOUBLE("Master Digital Playback Switch", 0,
762
CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1),
763
CS4236_DOUBLE("Master Digital Capture Switch", 0,
764
CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1),
765
CS4236_MASTER_DIGITAL("Master Digital Volume", 0, db_scale_7bit),
766
767
CS4236_DOUBLE_TLV("Capture Boost Volume", 0,
768
CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1,
769
db_scale_2bit),
770
771
WSS_DOUBLE("PCM Playback Switch", 0,
772
CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
773
WSS_DOUBLE_TLV("PCM Playback Volume", 0,
774
CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1,
775
db_scale_6bit),
776
777
CS4236_DOUBLE("DSP Playback Switch", 0,
778
CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1),
779
CS4236_DOUBLE_TLV("DSP Playback Volume", 0,
780
CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 0, 0, 63, 1,
781
db_scale_6bit),
782
783
CS4236_DOUBLE("FM Playback Switch", 0,
784
CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1),
785
CS4236_DOUBLE_TLV("FM Playback Volume", 0,
786
CS4236_LEFT_FM, CS4236_RIGHT_FM, 0, 0, 63, 1,
787
db_scale_6bit),
788
789
CS4236_DOUBLE("Wavetable Playback Switch", 0,
790
CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1),
791
CS4236_DOUBLE_TLV("Wavetable Playback Volume", 0,
792
CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 0, 0, 63, 1,
793
db_scale_6bit_12db_max),
794
795
WSS_DOUBLE("Synth Playback Switch", 0,
796
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
797
WSS_DOUBLE_TLV("Synth Volume", 0,
798
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1,
799
db_scale_5bit_12db_max),
800
WSS_DOUBLE("Synth Capture Switch", 0,
801
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1),
802
WSS_DOUBLE("Synth Capture Bypass", 0,
803
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 5, 5, 1, 1),
804
805
CS4236_DOUBLE("Mic Playback Switch", 0,
806
CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1),
807
CS4236_DOUBLE("Mic Capture Switch", 0,
808
CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1),
809
CS4236_DOUBLE_TLV("Mic Volume", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC,
810
0, 0, 31, 1, db_scale_5bit_22db_max),
811
CS4236_DOUBLE("Mic Playback Boost (+20dB)", 0,
812
CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 5, 5, 1, 0),
813
814
WSS_DOUBLE("Line Playback Switch", 0,
815
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
816
WSS_DOUBLE_TLV("Line Volume", 0,
817
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1,
818
db_scale_5bit_12db_max),
819
WSS_DOUBLE("Line Capture Switch", 0,
820
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1),
821
WSS_DOUBLE("Line Capture Bypass", 0,
822
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 5, 5, 1, 1),
823
824
WSS_DOUBLE("CD Playback Switch", 0,
825
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
826
WSS_DOUBLE_TLV("CD Volume", 0,
827
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1,
828
db_scale_5bit_12db_max),
829
WSS_DOUBLE("CD Capture Switch", 0,
830
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1),
831
832
CS4236_DOUBLE1("Mono Output Playback Switch", 0,
833
CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1),
834
CS4236_DOUBLE1("Beep Playback Switch", 0,
835
CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1),
836
WSS_SINGLE_TLV("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1,
837
db_scale_4bit),
838
WSS_SINGLE("Beep Bypass Playback Switch", 0, CS4231_MONO_CTRL, 5, 1, 0),
839
840
WSS_DOUBLE_TLV("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT,
841
0, 0, 15, 0, db_scale_rec_gain),
842
WSS_DOUBLE("Analog Loopback Capture Switch", 0,
843
CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0),
844
845
WSS_SINGLE("Loopback Digital Playback Switch", 0, CS4231_LOOPBACK, 0, 1, 0),
846
CS4236_DOUBLE1_TLV("Loopback Digital Playback Volume", 0,
847
CS4231_LOOPBACK, CS4236_RIGHT_LOOPBACK, 2, 0, 63, 1,
848
db_scale_6bit),
849
};
850
851
static const DECLARE_TLV_DB_SCALE(db_scale_5bit_6db_max, -5600, 200, 0);
852
static const DECLARE_TLV_DB_SCALE(db_scale_2bit_16db_max, -2400, 800, 0);
853
854
static const struct snd_kcontrol_new snd_cs4235_controls[] = {
855
856
WSS_DOUBLE("Master Playback Switch", 0,
857
CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 7, 7, 1, 1),
858
WSS_DOUBLE_TLV("Master Playback Volume", 0,
859
CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 0, 0, 31, 1,
860
db_scale_5bit_6db_max),
861
862
CS4235_OUTPUT_ACCU("Playback Volume", 0, db_scale_2bit_16db_max),
863
864
WSS_DOUBLE("Synth Playback Switch", 1,
865
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
866
WSS_DOUBLE("Synth Capture Switch", 1,
867
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1),
868
WSS_DOUBLE_TLV("Synth Volume", 1,
869
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1,
870
db_scale_5bit_12db_max),
871
872
CS4236_DOUBLE_TLV("Capture Volume", 0,
873
CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1,
874
db_scale_2bit),
875
876
WSS_DOUBLE("PCM Playback Switch", 0,
877
CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
878
WSS_DOUBLE("PCM Capture Switch", 0,
879
CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1),
880
WSS_DOUBLE_TLV("PCM Volume", 0,
881
CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1,
882
db_scale_6bit),
883
884
CS4236_DOUBLE("DSP Switch", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1),
885
886
CS4236_DOUBLE("FM Switch", 0, CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1),
887
888
CS4236_DOUBLE("Wavetable Switch", 0,
889
CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1),
890
891
CS4236_DOUBLE("Mic Capture Switch", 0,
892
CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1),
893
CS4236_DOUBLE("Mic Playback Switch", 0,
894
CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1),
895
CS4236_SINGLE_TLV("Mic Volume", 0, CS4236_LEFT_MIC, 0, 31, 1,
896
db_scale_5bit_22db_max),
897
CS4236_SINGLE("Mic Boost (+20dB)", 0, CS4236_LEFT_MIC, 5, 1, 0),
898
899
WSS_DOUBLE("Line Playback Switch", 0,
900
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
901
WSS_DOUBLE("Line Capture Switch", 0,
902
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1),
903
WSS_DOUBLE_TLV("Line Volume", 0,
904
CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1,
905
db_scale_5bit_12db_max),
906
907
WSS_DOUBLE("CD Playback Switch", 1,
908
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
909
WSS_DOUBLE("CD Capture Switch", 1,
910
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1),
911
WSS_DOUBLE_TLV("CD Volume", 1,
912
CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1,
913
db_scale_5bit_12db_max),
914
915
CS4236_DOUBLE1("Beep Playback Switch", 0,
916
CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1),
917
WSS_SINGLE("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
918
919
WSS_DOUBLE("Analog Loopback Switch", 0,
920
CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0),
921
};
922
923
#define CS4236_IEC958_ENABLE(xname, xindex) \
924
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
925
.info = snd_cs4236_info_single, \
926
.get = snd_cs4236_get_iec958_switch, .put = snd_cs4236_put_iec958_switch, \
927
.private_value = 1 << 16 }
928
929
static int snd_cs4236_get_iec958_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
930
{
931
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
932
unsigned long flags;
933
934
spin_lock_irqsave(&chip->reg_lock, flags);
935
ucontrol->value.integer.value[0] = chip->image[CS4231_ALT_FEATURE_1] & 0x02 ? 1 : 0;
936
#if 0
937
dev_dbg(chip->card->dev,
938
"get valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
939
snd_wss_in(chip, CS4231_ALT_FEATURE_1),
940
snd_cs4236_ctrl_in(chip, 3),
941
snd_cs4236_ctrl_in(chip, 4),
942
snd_cs4236_ctrl_in(chip, 5),
943
snd_cs4236_ctrl_in(chip, 6),
944
snd_cs4236_ctrl_in(chip, 8));
945
#endif
946
spin_unlock_irqrestore(&chip->reg_lock, flags);
947
return 0;
948
}
949
950
static int snd_cs4236_put_iec958_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
951
{
952
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
953
unsigned long flags;
954
int change;
955
unsigned short enable, val;
956
957
enable = ucontrol->value.integer.value[0] & 1;
958
959
mutex_lock(&chip->mce_mutex);
960
snd_wss_mce_up(chip);
961
spin_lock_irqsave(&chip->reg_lock, flags);
962
val = (chip->image[CS4231_ALT_FEATURE_1] & ~0x0e) | (0<<2) | (enable << 1);
963
change = val != chip->image[CS4231_ALT_FEATURE_1];
964
snd_wss_out(chip, CS4231_ALT_FEATURE_1, val);
965
val = snd_cs4236_ctrl_in(chip, 4) | 0xc0;
966
snd_cs4236_ctrl_out(chip, 4, val);
967
udelay(100);
968
val &= ~0x40;
969
snd_cs4236_ctrl_out(chip, 4, val);
970
spin_unlock_irqrestore(&chip->reg_lock, flags);
971
snd_wss_mce_down(chip);
972
mutex_unlock(&chip->mce_mutex);
973
974
#if 0
975
dev_dbg(chip->card->dev,
976
"set valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
977
snd_wss_in(chip, CS4231_ALT_FEATURE_1),
978
snd_cs4236_ctrl_in(chip, 3),
979
snd_cs4236_ctrl_in(chip, 4),
980
snd_cs4236_ctrl_in(chip, 5),
981
snd_cs4236_ctrl_in(chip, 6),
982
snd_cs4236_ctrl_in(chip, 8));
983
#endif
984
return change;
985
}
986
987
static const struct snd_kcontrol_new snd_cs4236_iec958_controls[] = {
988
CS4236_IEC958_ENABLE("IEC958 Output Enable", 0),
989
CS4236_SINGLEC("IEC958 Output Validity", 0, 4, 4, 1, 0),
990
CS4236_SINGLEC("IEC958 Output User", 0, 4, 5, 1, 0),
991
CS4236_SINGLEC("IEC958 Output CSBR", 0, 4, 6, 1, 0),
992
CS4236_SINGLEC("IEC958 Output Channel Status Low", 0, 5, 1, 127, 0),
993
CS4236_SINGLEC("IEC958 Output Channel Status High", 0, 6, 0, 255, 0)
994
};
995
996
static const struct snd_kcontrol_new snd_cs4236_3d_controls_cs4235[] = {
997
CS4236_SINGLEC("3D Control - Switch", 0, 3, 4, 1, 0),
998
CS4236_SINGLEC("3D Control - Space", 0, 2, 4, 15, 1)
999
};
1000
1001
static const struct snd_kcontrol_new snd_cs4236_3d_controls_cs4237[] = {
1002
CS4236_SINGLEC("3D Control - Switch", 0, 3, 7, 1, 0),
1003
CS4236_SINGLEC("3D Control - Space", 0, 2, 4, 15, 1),
1004
CS4236_SINGLEC("3D Control - Center", 0, 2, 0, 15, 1),
1005
CS4236_SINGLEC("3D Control - Mono", 0, 3, 6, 1, 0),
1006
CS4236_SINGLEC("3D Control - IEC958", 0, 3, 5, 1, 0)
1007
};
1008
1009
static const struct snd_kcontrol_new snd_cs4236_3d_controls_cs4238[] = {
1010
CS4236_SINGLEC("3D Control - Switch", 0, 3, 4, 1, 0),
1011
CS4236_SINGLEC("3D Control - Space", 0, 2, 4, 15, 1),
1012
CS4236_SINGLEC("3D Control - Volume", 0, 2, 0, 15, 1),
1013
CS4236_SINGLEC("3D Control - IEC958", 0, 3, 5, 1, 0)
1014
};
1015
1016
int snd_cs4236_mixer(struct snd_wss *chip)
1017
{
1018
struct snd_card *card;
1019
unsigned int idx, count;
1020
int err;
1021
const struct snd_kcontrol_new *kcontrol;
1022
1023
if (snd_BUG_ON(!chip || !chip->card))
1024
return -EINVAL;
1025
card = chip->card;
1026
strscpy(card->mixername, snd_wss_chip_id(chip));
1027
1028
if (chip->hardware == WSS_HW_CS4235 ||
1029
chip->hardware == WSS_HW_CS4239) {
1030
for (idx = 0; idx < ARRAY_SIZE(snd_cs4235_controls); idx++) {
1031
err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4235_controls[idx], chip));
1032
if (err < 0)
1033
return err;
1034
}
1035
} else {
1036
for (idx = 0; idx < ARRAY_SIZE(snd_cs4236_controls); idx++) {
1037
err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4236_controls[idx], chip));
1038
if (err < 0)
1039
return err;
1040
}
1041
}
1042
switch (chip->hardware) {
1043
case WSS_HW_CS4235:
1044
case WSS_HW_CS4239:
1045
count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4235);
1046
kcontrol = snd_cs4236_3d_controls_cs4235;
1047
break;
1048
case WSS_HW_CS4237B:
1049
count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4237);
1050
kcontrol = snd_cs4236_3d_controls_cs4237;
1051
break;
1052
case WSS_HW_CS4238B:
1053
count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4238);
1054
kcontrol = snd_cs4236_3d_controls_cs4238;
1055
break;
1056
default:
1057
count = 0;
1058
kcontrol = NULL;
1059
}
1060
for (idx = 0; idx < count; idx++, kcontrol++) {
1061
err = snd_ctl_add(card, snd_ctl_new1(kcontrol, chip));
1062
if (err < 0)
1063
return err;
1064
}
1065
if (chip->hardware == WSS_HW_CS4237B ||
1066
chip->hardware == WSS_HW_CS4238B) {
1067
for (idx = 0; idx < ARRAY_SIZE(snd_cs4236_iec958_controls); idx++) {
1068
err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4236_iec958_controls[idx], chip));
1069
if (err < 0)
1070
return err;
1071
}
1072
}
1073
return 0;
1074
}
1075
1076