2 * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
3 * Routines for control of CS4235/4236B/4237B/4238B/4239 chips
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.
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.
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
28 * Indirect control registers (CS4236B+)
31 * D8: WSS reset (all chips)
33 * C1 (all chips except CS4236)
43 * D7-D4: 3D Space (CS4235,CS4237B,CS4238B,CS4239)
44 * D3-D0: 3D Center (CS4237B); 3D Volume (CS4238B)
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)
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)
58 * C5 lower channel status (digital serial data description) (CS4237B,CS4238B)
59 * D7-D6: first two bits of category code
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
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)
70 * C7 reserved (must write 0)
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)
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>
96 static unsigned char snd_cs4236_ext_map[18] = {
97 /* CS4236_LEFT_LINE */ 0xff,
98 /* CS4236_RIGHT_LINE */ 0xff,
99 /* CS4236_LEFT_MIC */ 0xdf,
100 /* CS4236_RIGHT_MIC */ 0xdf,
101 /* CS4236_LEFT_MIX_CTRL */ 0xe0 | 0x18,
102 /* CS4236_RIGHT_MIX_CTRL */ 0xe0,
103 /* CS4236_LEFT_FM */ 0xbf,
104 /* CS4236_RIGHT_FM */ 0xbf,
105 /* CS4236_LEFT_DSP */ 0xbf,
106 /* CS4236_RIGHT_DSP */ 0xbf,
107 /* CS4236_RIGHT_LOOPBACK */ 0xbf,
108 /* CS4236_DAC_MUTE */ 0xe0,
109 /* CS4236_ADC_RATE */ 0x01, /* 48kHz */
110 /* CS4236_DAC_RATE */ 0x01, /* 48kHz */
111 /* CS4236_LEFT_MASTER */ 0xbf,
112 /* CS4236_RIGHT_MASTER */ 0xbf,
113 /* CS4236_LEFT_WAVE */ 0xbf,
114 /* CS4236_RIGHT_WAVE */ 0xbf
121 static void snd_cs4236_ctrl_out(struct snd_wss *chip,
122 unsigned char reg, unsigned char val)
124 outb(reg, chip->cport + 3);
125 outb(chip->cimage[reg] = val, chip->cport + 4);
128 static unsigned char snd_cs4236_ctrl_in(struct snd_wss *chip, unsigned char reg)
130 outb(reg, chip->cport + 3);
131 return inb(chip->cport + 4);
140 static struct snd_ratnum clocks[CLOCKS] = {
141 { .num = 16934400, .den_min = 353, .den_max = 353, .den_step = 1 },
142 { .num = 16934400, .den_min = 529, .den_max = 529, .den_step = 1 },
143 { .num = 16934400, .den_min = 617, .den_max = 617, .den_step = 1 },
144 { .num = 16934400, .den_min = 1058, .den_max = 1058, .den_step = 1 },
145 { .num = 16934400, .den_min = 1764, .den_max = 1764, .den_step = 1 },
146 { .num = 16934400, .den_min = 2117, .den_max = 2117, .den_step = 1 },
147 { .num = 16934400, .den_min = 2558, .den_max = 2558, .den_step = 1 },
148 { .num = 16934400/16, .den_min = 21, .den_max = 192, .den_step = 1 }
151 static struct snd_pcm_hw_constraint_ratnums hw_constraints_clocks = {
156 static int snd_cs4236_xrate(struct snd_pcm_runtime *runtime)
158 return snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
159 &hw_constraints_clocks);
162 static unsigned char divisor_to_rate_register(unsigned int divisor)
173 if (divisor < 21 || divisor > 192) {
181 static void snd_cs4236_playback_format(struct snd_wss *chip,
182 struct snd_pcm_hw_params *params,
186 unsigned char rate = divisor_to_rate_register(params->rate_den);
188 spin_lock_irqsave(&chip->reg_lock, flags);
189 /* set fast playback format change and clean playback FIFO */
190 snd_wss_out(chip, CS4231_ALT_FEATURE_1,
191 chip->image[CS4231_ALT_FEATURE_1] | 0x10);
192 snd_wss_out(chip, CS4231_PLAYBK_FORMAT, pdfr & 0xf0);
193 snd_wss_out(chip, CS4231_ALT_FEATURE_1,
194 chip->image[CS4231_ALT_FEATURE_1] & ~0x10);
195 snd_cs4236_ext_out(chip, CS4236_DAC_RATE, rate);
196 spin_unlock_irqrestore(&chip->reg_lock, flags);
199 static void snd_cs4236_capture_format(struct snd_wss *chip,
200 struct snd_pcm_hw_params *params,
204 unsigned char rate = divisor_to_rate_register(params->rate_den);
206 spin_lock_irqsave(&chip->reg_lock, flags);
207 /* set fast capture format change and clean capture FIFO */
208 snd_wss_out(chip, CS4231_ALT_FEATURE_1,
209 chip->image[CS4231_ALT_FEATURE_1] | 0x20);
210 snd_wss_out(chip, CS4231_REC_FORMAT, cdfr & 0xf0);
211 snd_wss_out(chip, CS4231_ALT_FEATURE_1,
212 chip->image[CS4231_ALT_FEATURE_1] & ~0x20);
213 snd_cs4236_ext_out(chip, CS4236_ADC_RATE, rate);
214 spin_unlock_irqrestore(&chip->reg_lock, flags);
219 static void snd_cs4236_suspend(struct snd_wss *chip)
224 spin_lock_irqsave(&chip->reg_lock, flags);
225 for (reg = 0; reg < 32; reg++)
226 chip->image[reg] = snd_wss_in(chip, reg);
227 for (reg = 0; reg < 18; reg++)
228 chip->eimage[reg] = snd_cs4236_ext_in(chip, CS4236_I23VAL(reg));
229 for (reg = 2; reg < 9; reg++)
230 chip->cimage[reg] = snd_cs4236_ctrl_in(chip, reg);
231 spin_unlock_irqrestore(&chip->reg_lock, flags);
234 static void snd_cs4236_resume(struct snd_wss *chip)
239 snd_wss_mce_up(chip);
240 spin_lock_irqsave(&chip->reg_lock, flags);
241 for (reg = 0; reg < 32; reg++) {
245 case 27: /* why? CS4235 - master left */
246 case 29: /* why? CS4235 - master right */
249 snd_wss_out(chip, reg, chip->image[reg]);
253 for (reg = 0; reg < 18; reg++)
254 snd_cs4236_ext_out(chip, CS4236_I23VAL(reg), chip->eimage[reg]);
255 for (reg = 2; reg < 9; reg++) {
260 snd_cs4236_ctrl_out(chip, reg, chip->cimage[reg]);
263 spin_unlock_irqrestore(&chip->reg_lock, flags);
264 snd_wss_mce_down(chip);
267 #endif /* CONFIG_PM */
269 * This function does no fail if the chip is not CS4236B or compatible.
270 * It just an equivalent to the snd_wss_create() then.
272 int snd_cs4236_create(struct snd_card *card,
275 int irq, int dma1, int dma2,
276 unsigned short hardware,
277 unsigned short hwshare,
278 struct snd_wss **rchip)
280 struct snd_wss *chip;
281 unsigned char ver1, ver2;
286 if (hardware == WSS_HW_DETECT)
287 hardware = WSS_HW_DETECT3;
289 err = snd_wss_create(card, port, cport,
290 irq, dma1, dma2, hardware, hwshare, &chip);
294 if ((chip->hardware & WSS_HW_CS4236B_MASK) == 0) {
295 snd_printd("chip is not CS4236+, hardware=0x%x\n",
303 for (idx = 0; idx < 8; idx++)
304 snd_printk(KERN_DEBUG "CD%i = 0x%x\n",
305 idx, inb(chip->cport + idx));
306 for (idx = 0; idx < 9; idx++)
307 snd_printk(KERN_DEBUG "C%i = 0x%x\n",
308 idx, snd_cs4236_ctrl_in(chip, idx));
311 if (cport < 0x100 || cport == SNDRV_AUTO_PORT) {
312 snd_printk(KERN_ERR "please, specify control port "
313 "for CS4236+ chips\n");
314 snd_device_free(card, chip);
317 ver1 = snd_cs4236_ctrl_in(chip, 1);
318 ver2 = snd_cs4236_ext_in(chip, CS4236_VERSION);
319 snd_printdd("CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n",
322 snd_printk(KERN_ERR "CS4236+ chip detected, but "
323 "control port 0x%lx is not valid\n", cport);
324 snd_device_free(card, chip);
327 snd_cs4236_ctrl_out(chip, 0, 0x00);
328 snd_cs4236_ctrl_out(chip, 2, 0xff);
329 snd_cs4236_ctrl_out(chip, 3, 0x00);
330 snd_cs4236_ctrl_out(chip, 4, 0x80);
331 reg = ((IEC958_AES1_CON_PCM_CODER & 3) << 6) |
332 IEC958_AES0_CON_EMPHASIS_NONE;
333 snd_cs4236_ctrl_out(chip, 5, reg);
334 snd_cs4236_ctrl_out(chip, 6, IEC958_AES1_CON_PCM_CODER >> 2);
335 snd_cs4236_ctrl_out(chip, 7, 0x00);
337 * 0x8c for C8 is valid for Turtle Beach Malibu - the IEC-958
338 * output is working with this setup, other hardware should
339 * have different signal paths and this value should be
340 * selectable in the future
342 snd_cs4236_ctrl_out(chip, 8, 0x8c);
343 chip->rate_constraint = snd_cs4236_xrate;
344 chip->set_playback_format = snd_cs4236_playback_format;
345 chip->set_capture_format = snd_cs4236_capture_format;
347 chip->suspend = snd_cs4236_suspend;
348 chip->resume = snd_cs4236_resume;
351 /* initialize extended registers */
352 for (reg = 0; reg < sizeof(snd_cs4236_ext_map); reg++)
353 snd_cs4236_ext_out(chip, CS4236_I23VAL(reg),
354 snd_cs4236_ext_map[reg]);
356 /* initialize compatible but more featured registers */
357 snd_wss_out(chip, CS4231_LEFT_INPUT, 0x40);
358 snd_wss_out(chip, CS4231_RIGHT_INPUT, 0x40);
359 snd_wss_out(chip, CS4231_AUX1_LEFT_INPUT, 0xff);
360 snd_wss_out(chip, CS4231_AUX1_RIGHT_INPUT, 0xff);
361 snd_wss_out(chip, CS4231_AUX2_LEFT_INPUT, 0xdf);
362 snd_wss_out(chip, CS4231_AUX2_RIGHT_INPUT, 0xdf);
363 snd_wss_out(chip, CS4231_RIGHT_LINE_IN, 0xff);
364 snd_wss_out(chip, CS4231_LEFT_LINE_IN, 0xff);
365 snd_wss_out(chip, CS4231_RIGHT_LINE_IN, 0xff);
366 switch (chip->hardware) {
369 snd_wss_out(chip, CS4235_LEFT_MASTER, 0xff);
370 snd_wss_out(chip, CS4235_RIGHT_MASTER, 0xff);
378 int snd_cs4236_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm)
383 err = snd_wss_pcm(chip, device, &pcm);
386 pcm->info_flags &= ~SNDRV_PCM_INFO_JOINT_DUPLEX;
396 #define CS4236_SINGLE(xname, xindex, reg, shift, mask, invert) \
397 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
398 .info = snd_cs4236_info_single, \
399 .get = snd_cs4236_get_single, .put = snd_cs4236_put_single, \
400 .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
402 static int snd_cs4236_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
404 int mask = (kcontrol->private_value >> 16) & 0xff;
406 uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
408 uinfo->value.integer.min = 0;
409 uinfo->value.integer.max = mask;
413 static int snd_cs4236_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
415 struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
417 int reg = kcontrol->private_value & 0xff;
418 int shift = (kcontrol->private_value >> 8) & 0xff;
419 int mask = (kcontrol->private_value >> 16) & 0xff;
420 int invert = (kcontrol->private_value >> 24) & 0xff;
422 spin_lock_irqsave(&chip->reg_lock, flags);
423 ucontrol->value.integer.value[0] = (chip->eimage[CS4236_REG(reg)] >> shift) & mask;
424 spin_unlock_irqrestore(&chip->reg_lock, flags);
426 ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
430 static int snd_cs4236_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
432 struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
434 int reg = kcontrol->private_value & 0xff;
435 int shift = (kcontrol->private_value >> 8) & 0xff;
436 int mask = (kcontrol->private_value >> 16) & 0xff;
437 int invert = (kcontrol->private_value >> 24) & 0xff;
441 val = (ucontrol->value.integer.value[0] & mask);
445 spin_lock_irqsave(&chip->reg_lock, flags);
446 val = (chip->eimage[CS4236_REG(reg)] & ~(mask << shift)) | val;
447 change = val != chip->eimage[CS4236_REG(reg)];
448 snd_cs4236_ext_out(chip, reg, val);
449 spin_unlock_irqrestore(&chip->reg_lock, flags);
453 #define CS4236_SINGLEC(xname, xindex, reg, shift, mask, invert) \
454 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
455 .info = snd_cs4236_info_single, \
456 .get = snd_cs4236_get_singlec, .put = snd_cs4236_put_singlec, \
457 .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
459 static int snd_cs4236_get_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
461 struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
463 int reg = kcontrol->private_value & 0xff;
464 int shift = (kcontrol->private_value >> 8) & 0xff;
465 int mask = (kcontrol->private_value >> 16) & 0xff;
466 int invert = (kcontrol->private_value >> 24) & 0xff;
468 spin_lock_irqsave(&chip->reg_lock, flags);
469 ucontrol->value.integer.value[0] = (chip->cimage[reg] >> shift) & mask;
470 spin_unlock_irqrestore(&chip->reg_lock, flags);
472 ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
476 static int snd_cs4236_put_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
478 struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
480 int reg = kcontrol->private_value & 0xff;
481 int shift = (kcontrol->private_value >> 8) & 0xff;
482 int mask = (kcontrol->private_value >> 16) & 0xff;
483 int invert = (kcontrol->private_value >> 24) & 0xff;
487 val = (ucontrol->value.integer.value[0] & mask);
491 spin_lock_irqsave(&chip->reg_lock, flags);
492 val = (chip->cimage[reg] & ~(mask << shift)) | val;
493 change = val != chip->cimage[reg];
494 snd_cs4236_ctrl_out(chip, reg, val);
495 spin_unlock_irqrestore(&chip->reg_lock, flags);
499 #define CS4236_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
500 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
501 .info = snd_cs4236_info_double, \
502 .get = snd_cs4236_get_double, .put = snd_cs4236_put_double, \
503 .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
505 static int snd_cs4236_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
507 int mask = (kcontrol->private_value >> 24) & 0xff;
509 uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
511 uinfo->value.integer.min = 0;
512 uinfo->value.integer.max = mask;
516 static int snd_cs4236_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
518 struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
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;
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);
532 ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
533 ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
538 static int snd_cs4236_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
540 struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
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;
549 unsigned short val1, val2;
551 val1 = ucontrol->value.integer.value[0] & mask;
552 val2 = ucontrol->value.integer.value[1] & mask;
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);
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);
571 spin_unlock_irqrestore(&chip->reg_lock, flags);
575 #define CS4236_DOUBLE1(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
576 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
577 .info = snd_cs4236_info_double, \
578 .get = snd_cs4236_get_double1, .put = snd_cs4236_put_double1, \
579 .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
581 static int snd_cs4236_get_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
583 struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
585 int left_reg = kcontrol->private_value & 0xff;
586 int right_reg = (kcontrol->private_value >> 8) & 0xff;
587 int shift_left = (kcontrol->private_value >> 16) & 0x07;
588 int shift_right = (kcontrol->private_value >> 19) & 0x07;
589 int mask = (kcontrol->private_value >> 24) & 0xff;
590 int invert = (kcontrol->private_value >> 22) & 1;
592 spin_lock_irqsave(&chip->reg_lock, flags);
593 ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask;
594 ucontrol->value.integer.value[1] = (chip->eimage[CS4236_REG(right_reg)] >> shift_right) & mask;
595 spin_unlock_irqrestore(&chip->reg_lock, flags);
597 ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
598 ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
603 static int snd_cs4236_put_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
605 struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
607 int left_reg = kcontrol->private_value & 0xff;
608 int right_reg = (kcontrol->private_value >> 8) & 0xff;
609 int shift_left = (kcontrol->private_value >> 16) & 0x07;
610 int shift_right = (kcontrol->private_value >> 19) & 0x07;
611 int mask = (kcontrol->private_value >> 24) & 0xff;
612 int invert = (kcontrol->private_value >> 22) & 1;
614 unsigned short val1, val2;
616 val1 = ucontrol->value.integer.value[0] & mask;
617 val2 = ucontrol->value.integer.value[1] & mask;
623 val2 <<= shift_right;
624 spin_lock_irqsave(&chip->reg_lock, flags);
625 val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;
626 val2 = (chip->eimage[CS4236_REG(right_reg)] & ~(mask << shift_right)) | val2;
627 change = val1 != chip->image[left_reg] || val2 != chip->eimage[CS4236_REG(right_reg)];
628 snd_wss_out(chip, left_reg, val1);
629 snd_cs4236_ext_out(chip, right_reg, val2);
630 spin_unlock_irqrestore(&chip->reg_lock, flags);
634 #define CS4236_MASTER_DIGITAL(xname, xindex) \
635 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
636 .info = snd_cs4236_info_double, \
637 .get = snd_cs4236_get_master_digital, .put = snd_cs4236_put_master_digital, \
638 .private_value = 71 << 24 }
640 static inline int snd_cs4236_mixer_master_digital_invert_volume(int vol)
642 return (vol < 64) ? 63 - vol : 64 + (71 - vol);
645 static int snd_cs4236_get_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
647 struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
650 spin_lock_irqsave(&chip->reg_lock, flags);
651 ucontrol->value.integer.value[0] = snd_cs4236_mixer_master_digital_invert_volume(chip->eimage[CS4236_REG(CS4236_LEFT_MASTER)] & 0x7f);
652 ucontrol->value.integer.value[1] = snd_cs4236_mixer_master_digital_invert_volume(chip->eimage[CS4236_REG(CS4236_RIGHT_MASTER)] & 0x7f);
653 spin_unlock_irqrestore(&chip->reg_lock, flags);
657 static int snd_cs4236_put_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
659 struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
662 unsigned short val1, val2;
664 val1 = snd_cs4236_mixer_master_digital_invert_volume(ucontrol->value.integer.value[0] & 0x7f);
665 val2 = snd_cs4236_mixer_master_digital_invert_volume(ucontrol->value.integer.value[1] & 0x7f);
666 spin_lock_irqsave(&chip->reg_lock, flags);
667 val1 = (chip->eimage[CS4236_REG(CS4236_LEFT_MASTER)] & ~0x7f) | val1;
668 val2 = (chip->eimage[CS4236_REG(CS4236_RIGHT_MASTER)] & ~0x7f) | val2;
669 change = val1 != chip->eimage[CS4236_REG(CS4236_LEFT_MASTER)] || val2 != chip->eimage[CS4236_REG(CS4236_RIGHT_MASTER)];
670 snd_cs4236_ext_out(chip, CS4236_LEFT_MASTER, val1);
671 snd_cs4236_ext_out(chip, CS4236_RIGHT_MASTER, val2);
672 spin_unlock_irqrestore(&chip->reg_lock, flags);
676 #define CS4235_OUTPUT_ACCU(xname, xindex) \
677 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
678 .info = snd_cs4236_info_double, \
679 .get = snd_cs4235_get_output_accu, .put = snd_cs4235_put_output_accu, \
680 .private_value = 3 << 24 }
682 static inline int snd_cs4235_mixer_output_accu_get_volume(int vol)
684 switch ((vol >> 5) & 3) {
693 static inline int snd_cs4235_mixer_output_accu_set_volume(int vol)
696 case 0: return 3 << 5;
697 case 1: return 0 << 5;
698 case 2: return 2 << 5;
699 case 3: return 1 << 5;
704 static int snd_cs4235_get_output_accu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
706 struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
709 spin_lock_irqsave(&chip->reg_lock, flags);
710 ucontrol->value.integer.value[0] = snd_cs4235_mixer_output_accu_get_volume(chip->image[CS4235_LEFT_MASTER]);
711 ucontrol->value.integer.value[1] = snd_cs4235_mixer_output_accu_get_volume(chip->image[CS4235_RIGHT_MASTER]);
712 spin_unlock_irqrestore(&chip->reg_lock, flags);
716 static int snd_cs4235_put_output_accu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
718 struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
721 unsigned short val1, val2;
723 val1 = snd_cs4235_mixer_output_accu_set_volume(ucontrol->value.integer.value[0]);
724 val2 = snd_cs4235_mixer_output_accu_set_volume(ucontrol->value.integer.value[1]);
725 spin_lock_irqsave(&chip->reg_lock, flags);
726 val1 = (chip->image[CS4235_LEFT_MASTER] & ~(3 << 5)) | val1;
727 val2 = (chip->image[CS4235_RIGHT_MASTER] & ~(3 << 5)) | val2;
728 change = val1 != chip->image[CS4235_LEFT_MASTER] || val2 != chip->image[CS4235_RIGHT_MASTER];
729 snd_wss_out(chip, CS4235_LEFT_MASTER, val1);
730 snd_wss_out(chip, CS4235_RIGHT_MASTER, val2);
731 spin_unlock_irqrestore(&chip->reg_lock, flags);
735 static struct snd_kcontrol_new snd_cs4236_controls[] = {
737 CS4236_DOUBLE("Master Digital Playback Switch", 0,
738 CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1),
739 CS4236_DOUBLE("Master Digital Capture Switch", 0,
740 CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1),
741 CS4236_MASTER_DIGITAL("Master Digital Volume", 0),
743 CS4236_DOUBLE("Capture Boost Volume", 0,
744 CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1),
746 WSS_DOUBLE("PCM Playback Switch", 0,
747 CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
748 WSS_DOUBLE("PCM Playback Volume", 0,
749 CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
751 CS4236_DOUBLE("DSP Playback Switch", 0,
752 CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1),
753 CS4236_DOUBLE("DSP Playback Volume", 0,
754 CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 0, 0, 63, 1),
756 CS4236_DOUBLE("FM Playback Switch", 0,
757 CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1),
758 CS4236_DOUBLE("FM Playback Volume", 0,
759 CS4236_LEFT_FM, CS4236_RIGHT_FM, 0, 0, 63, 1),
761 CS4236_DOUBLE("Wavetable Playback Switch", 0,
762 CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1),
763 CS4236_DOUBLE("Wavetable Playback Volume", 0,
764 CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 0, 0, 63, 1),
766 WSS_DOUBLE("Synth Playback Switch", 0,
767 CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
768 WSS_DOUBLE("Synth Volume", 0,
769 CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
770 WSS_DOUBLE("Synth Capture Switch", 0,
771 CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1),
772 WSS_DOUBLE("Synth Capture Bypass", 0,
773 CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 5, 5, 1, 1),
775 CS4236_DOUBLE("Mic Playback Switch", 0,
776 CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1),
777 CS4236_DOUBLE("Mic Capture Switch", 0,
778 CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1),
779 CS4236_DOUBLE("Mic Volume", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 0, 0, 31, 1),
780 CS4236_DOUBLE("Mic Playback Boost (+20dB)", 0,
781 CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 5, 5, 1, 0),
783 WSS_DOUBLE("Line Playback Switch", 0,
784 CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
785 WSS_DOUBLE("Line Volume", 0,
786 CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
787 WSS_DOUBLE("Line Capture Switch", 0,
788 CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1),
789 WSS_DOUBLE("Line Capture Bypass", 0,
790 CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 5, 5, 1, 1),
792 WSS_DOUBLE("CD Playback Switch", 0,
793 CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
794 WSS_DOUBLE("CD Volume", 0,
795 CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
796 WSS_DOUBLE("CD Capture Switch", 0,
797 CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1),
799 CS4236_DOUBLE1("Mono Output Playback Switch", 0,
800 CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1),
801 CS4236_DOUBLE1("Beep Playback Switch", 0,
802 CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1),
803 WSS_SINGLE("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
804 WSS_SINGLE("Beep Bypass Playback Switch", 0, CS4231_MONO_CTRL, 5, 1, 0),
806 WSS_DOUBLE("Capture Volume", 0,
807 CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0),
808 WSS_DOUBLE("Analog Loopback Capture Switch", 0,
809 CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0),
811 WSS_SINGLE("Digital Loopback Playback Switch", 0, CS4231_LOOPBACK, 0, 1, 0),
812 CS4236_DOUBLE1("Digital Loopback Playback Volume", 0,
813 CS4231_LOOPBACK, CS4236_RIGHT_LOOPBACK, 2, 0, 63, 1)
816 static struct snd_kcontrol_new snd_cs4235_controls[] = {
818 WSS_DOUBLE("Master Playback Switch", 0,
819 CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 7, 7, 1, 1),
820 WSS_DOUBLE("Master Playback Volume", 0,
821 CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 0, 0, 31, 1),
823 CS4235_OUTPUT_ACCU("Playback Volume", 0),
825 WSS_DOUBLE("Synth Playback Switch", 1,
826 CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
827 WSS_DOUBLE("Synth Capture Switch", 1,
828 CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1),
829 WSS_DOUBLE("Synth Volume", 1,
830 CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
832 CS4236_DOUBLE("Capture Volume", 0,
833 CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1),
835 WSS_DOUBLE("PCM Playback Switch", 0,
836 CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
837 WSS_DOUBLE("PCM Capture Switch", 0,
838 CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1),
839 WSS_DOUBLE("PCM Volume", 0,
840 CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
842 CS4236_DOUBLE("DSP Switch", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1),
844 CS4236_DOUBLE("FM Switch", 0, CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1),
846 CS4236_DOUBLE("Wavetable Switch", 0,
847 CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1),
849 CS4236_DOUBLE("Mic Capture Switch", 0,
850 CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1),
851 CS4236_DOUBLE("Mic Playback Switch", 0,
852 CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1),
853 CS4236_SINGLE("Mic Volume", 0, CS4236_LEFT_MIC, 0, 31, 1),
854 CS4236_SINGLE("Mic Boost (+20dB)", 0, CS4236_LEFT_MIC, 5, 1, 0),
856 WSS_DOUBLE("Line Playback Switch", 0,
857 CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
858 WSS_DOUBLE("Line Capture Switch", 0,
859 CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1),
860 WSS_DOUBLE("Line Volume", 0,
861 CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
863 WSS_DOUBLE("CD Playback Switch", 1,
864 CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
865 WSS_DOUBLE("CD Capture Switch", 1,
866 CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1),
867 WSS_DOUBLE("CD Volume", 1,
868 CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
870 CS4236_DOUBLE1("Beep Playback Switch", 0,
871 CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1),
872 WSS_SINGLE("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
874 WSS_DOUBLE("Analog Loopback Switch", 0,
875 CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0),
878 #define CS4236_IEC958_ENABLE(xname, xindex) \
879 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
880 .info = snd_cs4236_info_single, \
881 .get = snd_cs4236_get_iec958_switch, .put = snd_cs4236_put_iec958_switch, \
882 .private_value = 1 << 16 }
884 static int snd_cs4236_get_iec958_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
886 struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
889 spin_lock_irqsave(&chip->reg_lock, flags);
890 ucontrol->value.integer.value[0] = chip->image[CS4231_ALT_FEATURE_1] & 0x02 ? 1 : 0;
892 printk(KERN_DEBUG "get valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, "
893 "C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
894 snd_wss_in(chip, CS4231_ALT_FEATURE_1),
895 snd_cs4236_ctrl_in(chip, 3),
896 snd_cs4236_ctrl_in(chip, 4),
897 snd_cs4236_ctrl_in(chip, 5),
898 snd_cs4236_ctrl_in(chip, 6),
899 snd_cs4236_ctrl_in(chip, 8));
901 spin_unlock_irqrestore(&chip->reg_lock, flags);
905 static int snd_cs4236_put_iec958_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
907 struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
910 unsigned short enable, val;
912 enable = ucontrol->value.integer.value[0] & 1;
914 mutex_lock(&chip->mce_mutex);
915 snd_wss_mce_up(chip);
916 spin_lock_irqsave(&chip->reg_lock, flags);
917 val = (chip->image[CS4231_ALT_FEATURE_1] & ~0x0e) | (0<<2) | (enable << 1);
918 change = val != chip->image[CS4231_ALT_FEATURE_1];
919 snd_wss_out(chip, CS4231_ALT_FEATURE_1, val);
920 val = snd_cs4236_ctrl_in(chip, 4) | 0xc0;
921 snd_cs4236_ctrl_out(chip, 4, val);
924 snd_cs4236_ctrl_out(chip, 4, val);
925 spin_unlock_irqrestore(&chip->reg_lock, flags);
926 snd_wss_mce_down(chip);
927 mutex_unlock(&chip->mce_mutex);
930 printk(KERN_DEBUG "set valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, "
931 "C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
932 snd_wss_in(chip, CS4231_ALT_FEATURE_1),
933 snd_cs4236_ctrl_in(chip, 3),
934 snd_cs4236_ctrl_in(chip, 4),
935 snd_cs4236_ctrl_in(chip, 5),
936 snd_cs4236_ctrl_in(chip, 6),
937 snd_cs4236_ctrl_in(chip, 8));
942 static struct snd_kcontrol_new snd_cs4236_iec958_controls[] = {
943 CS4236_IEC958_ENABLE("IEC958 Output Enable", 0),
944 CS4236_SINGLEC("IEC958 Output Validity", 0, 4, 4, 1, 0),
945 CS4236_SINGLEC("IEC958 Output User", 0, 4, 5, 1, 0),
946 CS4236_SINGLEC("IEC958 Output CSBR", 0, 4, 6, 1, 0),
947 CS4236_SINGLEC("IEC958 Output Channel Status Low", 0, 5, 1, 127, 0),
948 CS4236_SINGLEC("IEC958 Output Channel Status High", 0, 6, 0, 255, 0)
951 static struct snd_kcontrol_new snd_cs4236_3d_controls_cs4235[] = {
952 CS4236_SINGLEC("3D Control - Switch", 0, 3, 4, 1, 0),
953 CS4236_SINGLEC("3D Control - Space", 0, 2, 4, 15, 1)
956 static struct snd_kcontrol_new snd_cs4236_3d_controls_cs4237[] = {
957 CS4236_SINGLEC("3D Control - Switch", 0, 3, 7, 1, 0),
958 CS4236_SINGLEC("3D Control - Space", 0, 2, 4, 15, 1),
959 CS4236_SINGLEC("3D Control - Center", 0, 2, 0, 15, 1),
960 CS4236_SINGLEC("3D Control - Mono", 0, 3, 6, 1, 0),
961 CS4236_SINGLEC("3D Control - IEC958", 0, 3, 5, 1, 0)
964 static struct snd_kcontrol_new snd_cs4236_3d_controls_cs4238[] = {
965 CS4236_SINGLEC("3D Control - Switch", 0, 3, 4, 1, 0),
966 CS4236_SINGLEC("3D Control - Space", 0, 2, 4, 15, 1),
967 CS4236_SINGLEC("3D Control - Volume", 0, 2, 0, 15, 1),
968 CS4236_SINGLEC("3D Control - IEC958", 0, 3, 5, 1, 0)
971 int snd_cs4236_mixer(struct snd_wss *chip)
973 struct snd_card *card;
974 unsigned int idx, count;
976 struct snd_kcontrol_new *kcontrol;
978 if (snd_BUG_ON(!chip || !chip->card))
981 strcpy(card->mixername, snd_wss_chip_id(chip));
983 if (chip->hardware == WSS_HW_CS4235 ||
984 chip->hardware == WSS_HW_CS4239) {
985 for (idx = 0; idx < ARRAY_SIZE(snd_cs4235_controls); idx++) {
986 if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4235_controls[idx], chip))) < 0)
990 for (idx = 0; idx < ARRAY_SIZE(snd_cs4236_controls); idx++) {
991 if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4236_controls[idx], chip))) < 0)
995 switch (chip->hardware) {
998 count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4235);
999 kcontrol = snd_cs4236_3d_controls_cs4235;
1001 case WSS_HW_CS4237B:
1002 count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4237);
1003 kcontrol = snd_cs4236_3d_controls_cs4237;
1005 case WSS_HW_CS4238B:
1006 count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4238);
1007 kcontrol = snd_cs4236_3d_controls_cs4238;
1013 for (idx = 0; idx < count; idx++, kcontrol++) {
1014 if ((err = snd_ctl_add(card, snd_ctl_new1(kcontrol, chip))) < 0)
1017 if (chip->hardware == WSS_HW_CS4237B ||
1018 chip->hardware == WSS_HW_CS4238B) {
1019 for (idx = 0; idx < ARRAY_SIZE(snd_cs4236_iec958_controls); idx++) {
1020 if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4236_iec958_controls[idx], chip))) < 0)