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