return 0;
}
+static const char* wm9713_mic_mixer[] = {"Stereo", "Mic1", "Mic2", "Mute"};
+static const char* wm9713_rec_mux[] = {"Stereo", "Left", "Right", "Mute"};
+static const char* wm9713_rec_src_l[] = {"Mic1", "Mic2", "Line L", "Mono In", "HP Mix L", "Spk Mix", "Mono Mix", "Zh"};
+static const char* wm9713_rec_src_r[] = {"Mic1", "Mic2", "Line R", "Mono In", "HP Mix R", "Spk Mix", "Mono Mix", "Zh"};
+
+static const struct ac97_enum wm9713_enum[] = {
+AC97_ENUM_SINGLE(AC97_LINE, 3, 4, wm9713_mic_mixer),
+AC97_ENUM_SINGLE(AC97_VIDEO, 14, 4, wm9713_rec_mux),
+AC97_ENUM_SINGLE(AC97_VIDEO, 9, 4, wm9713_rec_mux),
+AC97_ENUM_SINGLE(AC97_VIDEO, 3, 8, wm9713_rec_src_l),
+AC97_ENUM_SINGLE(AC97_VIDEO, 0, 8, wm9713_rec_src_r),
+};
+
+static const snd_kcontrol_new_t wm13_snd_ac97_controls_line_in[] = {
+AC97_DOUBLE("Line In Volume", AC97_PC_BEEP, 8, 0, 31, 1),
+AC97_SINGLE("Line In to Headphone Mute", AC97_PC_BEEP, 15, 1, 1),
+AC97_SINGLE("Line In to Speaker Mute", AC97_PC_BEEP, 14, 1, 1),
+AC97_SINGLE("Line In to Mono Mute", AC97_PC_BEEP, 13, 1, 1),
+};
+
+static const snd_kcontrol_new_t wm13_snd_ac97_controls_dac[] = {
+AC97_DOUBLE("DAC Volume", AC97_PHONE, 8, 0, 31, 1),
+AC97_SINGLE("DAC to Headphone Mute", AC97_PHONE, 15, 1, 1),
+AC97_SINGLE("DAC to Speaker Mute", AC97_PHONE, 14, 1, 1),
+AC97_SINGLE("DAC to Mono Mute", AC97_PHONE, 13, 1, 1),
+};
+
+static const snd_kcontrol_new_t wm13_snd_ac97_controls_mic[] = {
+AC97_SINGLE("MICA Volume", AC97_MIC, 8, 31, 1),
+AC97_SINGLE("MICB Volume", AC97_MIC, 0, 31, 1),
+AC97_SINGLE("MICA to Mono Mute", AC97_LINE, 7, 1, 1),
+AC97_SINGLE("MICB to Mono Mute", AC97_LINE, 6, 1, 1),
+AC97_SINGLE("MIC Boost (+20dB)", AC97_LINE, 5, 1, 1),
+AC97_ENUM("MIC Headphone Routing", wm9713_enum[0]),
+AC97_SINGLE("MIC Headphone Mixer Volume", AC97_LINE, 0, 7, 1)
+};
+
+static const snd_kcontrol_new_t wm13_snd_ac97_controls_adc[] = {
+AC97_SINGLE("ADC Mute", AC97_CD, 15, 1, 1),
+AC97_DOUBLE("Gain Step Size (1.5dB/0.75dB)", AC97_CD, 14, 6, 1, 1),
+AC97_DOUBLE("ADC Volume",AC97_CD, 8, 0, 15, 0),
+AC97_SINGLE("ADC Zero Cross", AC97_CD, 7, 1, 1),
+};
+
+static const snd_kcontrol_new_t wm13_snd_ac97_controls_recsel[] = {
+AC97_ENUM("Record to Headphone Path", wm9713_enum[1]),
+AC97_SINGLE("Record to Headphone Volume", AC97_VIDEO, 11, 7, 0),
+AC97_ENUM("Record to Mono Path", wm9713_enum[2]),
+AC97_SINGLE("Record to Mono Boost (+20dB)", AC97_VIDEO, 8, 1, 0),
+AC97_SINGLE("Record ADC Boost (+20dB)", AC97_VIDEO, 6, 1, 0),
+AC97_ENUM("Record Select Left", wm9713_enum[3]),
+AC97_ENUM("Record Select Right", wm9713_enum[4]),
+};
+
+static int patch_wolfson_wm9713_specific(ac97_t * ac97)
+{
+ int err, i;
+
+ for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_line_in); i++) {
+ if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_line_in[i], ac97))) < 0)
+ return err;
+ }
+ snd_ac97_write_cache(ac97, AC97_PC_BEEP, 0x0808);
+
+ for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_dac); i++) {
+ if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_dac[i], ac97))) < 0)
+ return err;
+ }
+ snd_ac97_write_cache(ac97, AC97_PHONE, 0x0808);
+
+ for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_mic); i++) {
+ if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_mic[i], ac97))) < 0)
+ return err;
+ }
+ snd_ac97_write_cache(ac97, AC97_MIC, 0x0808);
+ snd_ac97_write_cache(ac97, AC97_LINE, 0x00da);
+
+ for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_adc); i++) {
+ if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_adc[i], ac97))) < 0)
+ return err;
+ }
+ snd_ac97_write_cache(ac97, AC97_CD, 0x0808);
+
+ for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_recsel); i++) {
+ if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_recsel[i], ac97))) < 0)
+ return err;
+ }
+ snd_ac97_write_cache(ac97, AC97_VIDEO, 0xd612);
+ snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x1ba0);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static void patch_wolfson_wm9713_suspend (ac97_t * ac97)
+{
+ snd_ac97_write_cache(ac97, AC97_EXTENDED_MID, 0xfeff);
+ snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0xffff);
+}
+
+static void patch_wolfson_wm9713_resume (ac97_t * ac97)
+{
+ snd_ac97_write_cache(ac97, AC97_EXTENDED_MID, 0xda00);
+ snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0x3810);
+ snd_ac97_write_cache(ac97, AC97_POWERDOWN, 0x0);
+}
+#endif
+
+static struct snd_ac97_build_ops patch_wolfson_wm9713_ops = {
+ .build_specific = patch_wolfson_wm9713_specific,
+#ifdef CONFIG_PM
+ .suspend = patch_wolfson_wm9713_suspend,
+ .resume = patch_wolfson_wm9713_resume
+#endif
+};
+
+int patch_wolfson13(ac97_t * ac97)
+{
+ ac97->build_ops = &patch_wolfson_wm9713_ops;
+
+ ac97->flags |= AC97_HAS_NO_REC_GAIN | AC97_STEREO_MUTES | AC97_HAS_NO_PHONE |
+ AC97_HAS_NO_PC_BEEP | AC97_HAS_NO_VIDEO | AC97_HAS_NO_CD;
+
+ snd_ac97_write_cache(ac97, AC97_EXTENDED_MID, 0xda00);
+ snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0x3810);
+ snd_ac97_write_cache(ac97, AC97_POWERDOWN, 0x0);
+
+ return 0;
+}
+
/*
* Tritech codec
*/
return 0;
}
+static int snd_ac97_stac9708_put_bias(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+ int err;
+
+ down(&ac97->page_mutex);
+ snd_ac97_write(ac97, AC97_SIGMATEL_BIAS1, 0xabba);
+ err = snd_ac97_update_bits(ac97, AC97_SIGMATEL_BIAS2, 0x0010,
+ (ucontrol->value.integer.value[0] & 1) << 4);
+ snd_ac97_write(ac97, AC97_SIGMATEL_BIAS1, 0);
+ up(&ac97->page_mutex);
+ return err;
+}
+
+static const snd_kcontrol_new_t snd_ac97_stac9708_bias_control = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Sigmatel Output Bias Switch",
+ .info = snd_ac97_info_volsw,
+ .get = snd_ac97_get_volsw,
+ .put = snd_ac97_stac9708_put_bias,
+ .private_value = AC97_SINGLE_VALUE(AC97_SIGMATEL_BIAS2, 4, 1, 0),
+};
+
static int patch_sigmatel_stac9708_specific(ac97_t *ac97)
{
+ int err;
+
snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Sigmatel Surround Playback");
+ if ((err = patch_build_controls(ac97, &snd_ac97_stac9708_bias_control, 1)) < 0)
+ return err;
return patch_sigmatel_stac97xx_specific(ac97);
}
ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
return ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 3 << 12,
- (unsigned short)ucontrol->value.enumerated.item[0],
+ (unsigned short)ucontrol->value.enumerated.item[0] << 12,
0);
}
{
unsigned short val;
- /* CM9761 has no Master and PCM volume although the register reacts */
- ac97->flags |= AC97_HAS_NO_MASTER_VOL | AC97_HAS_NO_PCM_VOL;
- snd_ac97_write_cache(ac97, AC97_MASTER, 0x8000);
- snd_ac97_write_cache(ac97, AC97_PCM, 0x8000);
+ /* CM9761 has no PCM volume although the register reacts */
+ /* Master volume seems to have _some_ influence on the analog
+ * input sounds
+ */
+ ac97->flags |= /*AC97_HAS_NO_MASTER_VOL |*/ AC97_HAS_NO_PCM_VOL;
+ snd_ac97_write_cache(ac97, AC97_MASTER, 0x8808);
+ snd_ac97_write_cache(ac97, AC97_PCM, 0x8808);
ac97->spec.dev_flags = 0; /* 1 = model 82 revision B */
if (ac97->id == AC97_ID_CM9761_82) {
ac97->ext_id |= AC97_EI_SPDIF;
/* to be sure: we overwrite the ext status bits */
snd_ac97_write_cache(ac97, AC97_EXTENDED_STATUS, 0x05c0);
- snd_ac97_write_cache(ac97, AC97_CM9761_SPDIF_CTRL, 0x0209);
+ /* Don't set 0x0200 here. This results in the silent analog output */
+ snd_ac97_write_cache(ac97, AC97_CM9761_SPDIF_CTRL, 0x0009);
ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */
/* set-up multi channel */
val = 0x0214;
else
val = 0x321c;
- snd_ac97_write_cache(ac97, AC97_CM9761_MULTI_CHAN, val);
#endif
+ val = snd_ac97_read(ac97, AC97_CM9761_MULTI_CHAN);
+ val |= (1 << 4); /* front on */
+ snd_ac97_write_cache(ac97, AC97_CM9761_MULTI_CHAN, val);
/* FIXME: set up GPIO */
snd_ac97_write_cache(ac97, 0x70, 0x0100);