85 #include <linux/time.h>
86 #include <linux/wait.h>
97 static unsigned char snd_cs4236_ext_map[18] = {
122 static void snd_cs4236_ctrl_out(
struct snd_wss *
chip,
123 unsigned char reg,
unsigned char val)
129 static unsigned char snd_cs4236_ctrl_in(
struct snd_wss *
chip,
unsigned char reg)
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 }
160 &hw_constraints_clocks);
163 static unsigned char divisor_to_rate_register(
unsigned int divisor)
174 if (divisor < 21 || divisor > 192) {
182 static void snd_cs4236_playback_format(
struct snd_wss *
chip,
187 unsigned char rate = divisor_to_rate_register(params->
rate_den);
197 spin_unlock_irqrestore(&chip->
reg_lock, flags);
200 static void snd_cs4236_capture_format(
struct snd_wss *
chip,
205 unsigned char rate = divisor_to_rate_register(params->
rate_den);
215 spin_unlock_irqrestore(&chip->
reg_lock, flags);
220 static void snd_cs4236_suspend(
struct snd_wss *
chip)
226 for (reg = 0; reg < 32; reg++)
228 for (reg = 0; reg < 18; 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);
235 static void snd_cs4236_resume(
struct snd_wss *chip)
242 for (reg = 0; reg < 32; reg++) {
254 for (reg = 0; reg < 18; reg++)
256 for (reg = 2; reg < 9; reg++) {
261 snd_cs4236_ctrl_out(chip, reg, chip->
cimage[reg]);
264 spin_unlock_irqrestore(&chip->
reg_lock, flags);
276 int irq,
int dma1,
int dma2,
278 unsigned short hwshare,
282 unsigned char ver1, ver2;
291 irq, dma1, dma2, hardware, hwshare, &chip);
296 snd_printd(
"chip is not CS4236+, hardware=0x%x\n",
304 for (idx = 0; idx < 8; idx++)
307 for (idx = 0; idx < 9; idx++)
309 idx, snd_cs4236_ctrl_in(chip, idx));
314 "for CS4236+ chips\n");
318 ver1 = snd_cs4236_ctrl_in(chip, 1);
320 snd_printdd(
"CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n",
324 "control port 0x%lx is not valid\n", cport);
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);
334 snd_cs4236_ctrl_out(chip, 5, reg);
336 snd_cs4236_ctrl_out(chip, 7, 0x00);
343 snd_cs4236_ctrl_out(chip, 8, 0x8c);
348 chip->suspend = snd_cs4236_suspend;
349 chip->resume = snd_cs4236_resume;
353 for (reg = 0; reg <
sizeof(snd_cs4236_ext_map); reg++)
355 snd_cs4236_ext_map[
reg]);
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) }
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) } }
433 spin_unlock_irqrestore(&chip->
reg_lock, flags);
435 ucontrol->
value.integer.value[0] = mask - ucontrol->
value.integer.value[0];
450 val = (ucontrol->
value.integer.value[0] &
mask);
458 spin_unlock_irqrestore(&chip->
reg_lock, flags);
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) }
478 ucontrol->
value.integer.value[0] = (chip->
cimage[
reg] >> shift) & mask;
479 spin_unlock_irqrestore(&chip->
reg_lock, flags);
481 ucontrol->
value.integer.value[0] = mask - ucontrol->
value.integer.value[0];
496 val = (ucontrol->
value.integer.value[0] &
mask);
503 snd_cs4236_ctrl_out(chip, reg, val);
504 spin_unlock_irqrestore(&chip->
reg_lock, flags);
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) }
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) } }
549 spin_unlock_irqrestore(&chip->
reg_lock, flags);
551 ucontrol->
value.integer.value[0] = mask - ucontrol->
value.integer.value[0];
552 ucontrol->
value.integer.value[1] = mask - ucontrol->
value.integer.value[1];
568 unsigned short val1, val2;
570 val1 = ucontrol->
value.integer.value[0] &
mask;
571 val2 = ucontrol->
value.integer.value[1] &
mask;
579 if (left_reg != right_reg) {
586 val1 = (chip->
eimage[
CS4236_REG(left_reg)] & ~((mask << shift_left) | (mask << shift_right))) | val1 | val2;
590 spin_unlock_irqrestore(&chip->
reg_lock, flags);
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) }
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) } }
623 ucontrol->
value.integer.value[0] = (chip->
image[left_reg] >> shift_left) & mask;
625 spin_unlock_irqrestore(&chip->
reg_lock, flags);
627 ucontrol->
value.integer.value[0] = mask - ucontrol->
value.integer.value[0];
628 ucontrol->
value.integer.value[1] = mask - ucontrol->
value.integer.value[1];
644 unsigned short val1, val2;
646 val1 = ucontrol->
value.integer.value[0] &
mask;
647 val2 = ucontrol->
value.integer.value[1] &
mask;
655 val1 = (chip->
image[left_reg] & ~(mask << shift_left)) | val1;
660 spin_unlock_irqrestore(&chip->
reg_lock, flags);
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) } }
672 static inline int snd_cs4236_mixer_master_digital_invert_volume(
int vol)
674 return (vol < 64) ? 63 - vol : 64 + (71 -
vol);
685 spin_unlock_irqrestore(&chip->
reg_lock, flags);
694 unsigned short val1, val2;
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);
704 spin_unlock_irqrestore(&chip->
reg_lock, flags);
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) } }
716 static inline int snd_cs4235_mixer_output_accu_get_volume(
int vol)
718 switch ((vol >> 5) & 3) {
727 static inline int snd_cs4235_mixer_output_accu_set_volume(
int vol)
730 case 0:
return 3 << 5;
731 case 1:
return 0 << 5;
732 case 2:
return 2 << 5;
733 case 3:
return 1 << 5;
746 spin_unlock_irqrestore(&chip->
reg_lock, flags);
755 unsigned short val1, val2;
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]);
765 spin_unlock_irqrestore(&chip->
reg_lock, flags);
812 db_scale_6bit_12db_max),
818 db_scale_5bit_12db_max),
829 0, 0, 31, 1, db_scale_5bit_22db_max),
837 db_scale_5bit_12db_max),
847 db_scale_5bit_12db_max),
860 0, 0, 15, 0, db_scale_rec_gain),
861 WSS_DOUBLE(
"Analog Loopback Capture Switch", 0,
879 db_scale_5bit_6db_max),
889 db_scale_5bit_12db_max),
915 db_scale_5bit_22db_max),
924 db_scale_5bit_12db_max),
932 db_scale_5bit_12db_max),
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 }
957 "C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
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));
965 spin_unlock_irqrestore(&chip->
reg_lock, flags);
976 enable = ucontrol->
value.integer.value[0] & 1;
984 val = snd_cs4236_ctrl_in(chip, 4) | 0xc0;
985 snd_cs4236_ctrl_out(chip, 4, val);
988 snd_cs4236_ctrl_out(chip, 4, val);
989 spin_unlock_irqrestore(&chip->
reg_lock, flags);
995 "C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
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));
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)
1049 for (idx = 0; idx <
ARRAY_SIZE(snd_cs4235_controls); idx++) {
1054 for (idx = 0; idx <
ARRAY_SIZE(snd_cs4236_controls); idx++) {
1062 count =
ARRAY_SIZE(snd_cs4236_3d_controls_cs4235);
1063 kcontrol = snd_cs4236_3d_controls_cs4235;
1066 count =
ARRAY_SIZE(snd_cs4236_3d_controls_cs4237);
1067 kcontrol = snd_cs4236_3d_controls_cs4237;
1070 count =
ARRAY_SIZE(snd_cs4236_3d_controls_cs4238);
1071 kcontrol = snd_cs4236_3d_controls_cs4238;
1077 for (idx = 0; idx <
count; idx++, kcontrol++) {
1083 for (idx = 0; idx <
ARRAY_SIZE(snd_cs4236_iec958_controls); idx++) {