aboutsummaryrefslogtreecommitdiff
path: root/sound/pci
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci')
-rw-r--r--sound/pci/Kconfig23
-rw-r--r--sound/pci/ac97/ac97_codec.c8
-rw-r--r--sound/pci/ac97/ac97_patch.c62
-rw-r--r--sound/pci/au88x0/au88x0_core.c14
-rw-r--r--sound/pci/au88x0/au88x0_pcm.c24
-rw-r--r--sound/pci/azt3328.c396
-rw-r--r--sound/pci/bt87x.c10
-rw-r--r--sound/pci/ca0106/ca0106.h2
-rw-r--r--sound/pci/ca0106/ca0106_main.c2
-rw-r--r--sound/pci/cmipci.c25
-rw-r--r--sound/pci/cs5535audio/cs5535audio_pm.c7
-rw-r--r--sound/pci/emu10k1/emu10k1x.c2
-rw-r--r--sound/pci/emu10k1/p16v.h2
-rw-r--r--sound/pci/es1968.c2
-rw-r--r--sound/pci/hda/hda_codec.c13
-rw-r--r--sound/pci/hda/hda_eld.c2
-rw-r--r--sound/pci/hda/hda_generic.c7
-rw-r--r--sound/pci/hda/hda_intel.c14
-rw-r--r--sound/pci/hda/hda_local.h6
-rw-r--r--sound/pci/hda/hda_proc.c2
-rw-r--r--sound/pci/hda/patch_analog.c280
-rw-r--r--sound/pci/hda/patch_cirrus.c6
-rw-r--r--sound/pci/hda/patch_cmedia.c2
-rw-r--r--sound/pci/hda/patch_conexant.c339
-rw-r--r--sound/pci/hda/patch_hdmi.c111
-rw-r--r--sound/pci/hda/patch_realtek.c996
-rw-r--r--sound/pci/hda/patch_sigmatel.c117
-rw-r--r--sound/pci/hda/patch_via.c33
-rw-r--r--sound/pci/ice1712/delta.c56
-rw-r--r--sound/pci/ice1712/delta.h11
-rw-r--r--sound/pci/oxygen/Makefile4
-rw-r--r--sound/pci/oxygen/cs4245.h107
-rw-r--r--sound/pci/oxygen/hifier.c239
-rw-r--r--sound/pci/oxygen/oxygen.c356
-rw-r--r--sound/pci/oxygen/oxygen.h21
-rw-r--r--sound/pci/oxygen/oxygen_io.c4
-rw-r--r--sound/pci/oxygen/oxygen_lib.c71
-rw-r--r--sound/pci/oxygen/oxygen_mixer.c112
-rw-r--r--sound/pci/oxygen/oxygen_pcm.c55
-rw-r--r--sound/pci/oxygen/oxygen_regs.h16
-rw-r--r--sound/pci/oxygen/xonar.h2
-rw-r--r--sound/pci/oxygen/xonar_cs43xx.c84
-rw-r--r--sound/pci/oxygen/xonar_dg.c608
-rw-r--r--sound/pci/oxygen/xonar_dg.h8
-rw-r--r--sound/pci/oxygen/xonar_hdmi.c2
-rw-r--r--sound/pci/oxygen/xonar_lib.c6
-rw-r--r--sound/pci/oxygen/xonar_pcm179x.c473
-rw-r--r--sound/pci/oxygen/xonar_wm87x6.c317
-rw-r--r--sound/pci/rme9652/hdsp.c538
-rw-r--r--sound/pci/rme9652/hdspm.c6
-rw-r--r--sound/pci/ymfpci/ymfpci_main.c12
51 files changed, 3854 insertions, 1761 deletions
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 12e34653b8a..9823d59d7ad 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -209,7 +209,7 @@ config SND_OXYGEN_LIB
tristate
config SND_OXYGEN
- tristate "C-Media 8788 (Oxygen)"
+ tristate "C-Media 8786, 8787, 8788 (Oxygen)"
select SND_OXYGEN_LIB
select SND_PCM
select SND_MPU401_UART
@@ -217,13 +217,18 @@ config SND_OXYGEN
Say Y here to include support for sound cards based on the
C-Media CMI8788 (Oxygen HD Audio) chip:
* Asound A-8788
+ * Asus Xonar DG
* AuzenTech X-Meridian
+ * AuzenTech X-Meridian 2G
* Bgears b-Enspirer
* Club3D Theatron DTS
* HT-Omega Claro (plus)
* HT-Omega Claro halo (XT)
+ * Kuroutoshikou CMI8787-HG2PCI
* Razer Barracuda AC-1
* Sondigo Inferno
+ * TempoTec/MediaTek HiFier Fantasia
+ * TempoTec/MediaTek HiFier Serenade
To compile this driver as a module, choose M here: the module
will be called snd-oxygen.
@@ -578,18 +583,6 @@ config SND_HDSPM
To compile this driver as a module, choose M here: the module
will be called snd-hdspm.
-config SND_HIFIER
- tristate "TempoTec HiFier Fantasia"
- select SND_OXYGEN_LIB
- select SND_PCM
- select SND_MPU401_UART
- help
- Say Y here to include support for the MediaTek/TempoTec HiFier
- Fantasia sound card.
-
- To compile this driver as a module, choose M here: the module
- will be called snd-hifier.
-
config SND_ICE1712
tristate "ICEnsemble ICE1712 (Envy24)"
select SND_MPU401_UART
@@ -826,8 +819,8 @@ config SND_VIRTUOSO
Say Y here to include support for sound cards based on the
Asus AV66/AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, DS,
Essence ST (Deluxe), and Essence STX.
- Support for the HDAV1.3 (Deluxe) is incomplete; for the
- HDAV1.3 Slim and Xense, missing.
+ Support for the HDAV1.3 (Deluxe) and HDAV1.3 Slim is experimental;
+ for the Xense, missing.
To compile this driver as a module, choose M here: the module
will be called snd-virtuoso.
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index a7630e9edf8..cb62d178b3e 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -1014,8 +1014,7 @@ static int snd_ac97_free(struct snd_ac97 *ac97)
{
if (ac97) {
#ifdef CONFIG_SND_AC97_POWER_SAVE
- cancel_delayed_work(&ac97->power_work);
- flush_scheduled_work();
+ cancel_delayed_work_sync(&ac97->power_work);
#endif
snd_ac97_proc_done(ac97);
if (ac97->bus)
@@ -1962,7 +1961,7 @@ static int snd_ac97_dev_disconnect(struct snd_device *device)
}
/* build_ops to do nothing */
-static struct snd_ac97_build_ops null_build_ops;
+static const struct snd_ac97_build_ops null_build_ops;
#ifdef CONFIG_SND_AC97_POWER_SAVE
static void do_update_power(struct work_struct *work)
@@ -2456,8 +2455,7 @@ void snd_ac97_suspend(struct snd_ac97 *ac97)
if (ac97->build_ops->suspend)
ac97->build_ops->suspend(ac97);
#ifdef CONFIG_SND_AC97_POWER_SAVE
- cancel_delayed_work(&ac97->power_work);
- flush_scheduled_work();
+ cancel_delayed_work_sync(&ac97->power_work);
#endif
snd_ac97_powerdown(ac97);
}
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index e68c98ef404..bf47574ca1f 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -371,7 +371,7 @@ static int patch_yamaha_ymf743_build_spdif(struct snd_ac97 *ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_yamaha_ymf743_ops = {
+static const struct snd_ac97_build_ops patch_yamaha_ymf743_ops = {
.build_spdif = patch_yamaha_ymf743_build_spdif,
.build_3d = patch_yamaha_ymf7x3_3d,
};
@@ -455,7 +455,7 @@ static int patch_yamaha_ymf753_post_spdif(struct snd_ac97 * ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_yamaha_ymf753_ops = {
+static const struct snd_ac97_build_ops patch_yamaha_ymf753_ops = {
.build_3d = patch_yamaha_ymf7x3_3d,
.build_post_spdif = patch_yamaha_ymf753_post_spdif
};
@@ -502,7 +502,7 @@ static int patch_wolfson_wm9703_specific(struct snd_ac97 * ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_wolfson_wm9703_ops = {
+static const struct snd_ac97_build_ops patch_wolfson_wm9703_ops = {
.build_specific = patch_wolfson_wm9703_specific,
};
@@ -533,7 +533,7 @@ static int patch_wolfson_wm9704_specific(struct snd_ac97 * ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_wolfson_wm9704_ops = {
+static const struct snd_ac97_build_ops patch_wolfson_wm9704_ops = {
.build_specific = patch_wolfson_wm9704_specific,
};
@@ -677,7 +677,7 @@ static int patch_wolfson_wm9711_specific(struct snd_ac97 * ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_wolfson_wm9711_ops = {
+static const struct snd_ac97_build_ops patch_wolfson_wm9711_ops = {
.build_specific = patch_wolfson_wm9711_specific,
};
@@ -871,7 +871,7 @@ static void patch_wolfson_wm9713_resume (struct snd_ac97 * ac97)
}
#endif
-static struct snd_ac97_build_ops patch_wolfson_wm9713_ops = {
+static const struct snd_ac97_build_ops patch_wolfson_wm9713_ops = {
.build_specific = patch_wolfson_wm9713_specific,
.build_3d = patch_wolfson_wm9713_3d,
#ifdef CONFIG_PM
@@ -976,7 +976,7 @@ static int patch_sigmatel_stac97xx_specific(struct snd_ac97 * ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_sigmatel_stac9700_ops = {
+static const struct snd_ac97_build_ops patch_sigmatel_stac9700_ops = {
.build_3d = patch_sigmatel_stac9700_3d,
.build_specific = patch_sigmatel_stac97xx_specific
};
@@ -1023,7 +1023,7 @@ static int patch_sigmatel_stac9708_specific(struct snd_ac97 *ac97)
return patch_sigmatel_stac97xx_specific(ac97);
}
-static struct snd_ac97_build_ops patch_sigmatel_stac9708_ops = {
+static const struct snd_ac97_build_ops patch_sigmatel_stac9708_ops = {
.build_3d = patch_sigmatel_stac9708_3d,
.build_specific = patch_sigmatel_stac9708_specific
};
@@ -1252,7 +1252,7 @@ static int patch_sigmatel_stac9758_specific(struct snd_ac97 *ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_sigmatel_stac9758_ops = {
+static const struct snd_ac97_build_ops patch_sigmatel_stac9758_ops = {
.build_3d = patch_sigmatel_stac9700_3d,
.build_specific = patch_sigmatel_stac9758_specific
};
@@ -1327,7 +1327,7 @@ static int patch_cirrus_build_spdif(struct snd_ac97 * ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_cirrus_ops = {
+static const struct snd_ac97_build_ops patch_cirrus_ops = {
.build_spdif = patch_cirrus_build_spdif
};
@@ -1384,7 +1384,7 @@ static int patch_conexant_build_spdif(struct snd_ac97 * ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_conexant_ops = {
+static const struct snd_ac97_build_ops patch_conexant_ops = {
.build_spdif = patch_conexant_build_spdif
};
@@ -1560,7 +1560,7 @@ static void patch_ad1881_chained(struct snd_ac97 * ac97, int unchained_idx, int
}
}
-static struct snd_ac97_build_ops patch_ad1881_build_ops = {
+static const struct snd_ac97_build_ops patch_ad1881_build_ops = {
#ifdef CONFIG_PM
.resume = ad18xx_resume
#endif
@@ -1647,7 +1647,7 @@ static int patch_ad1885_specific(struct snd_ac97 * ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_ad1885_build_ops = {
+static const struct snd_ac97_build_ops patch_ad1885_build_ops = {
.build_specific = &patch_ad1885_specific,
#ifdef CONFIG_PM
.resume = ad18xx_resume
@@ -1674,7 +1674,7 @@ static int patch_ad1886_specific(struct snd_ac97 * ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_ad1886_build_ops = {
+static const struct snd_ac97_build_ops patch_ad1886_build_ops = {
.build_specific = &patch_ad1886_specific,
#ifdef CONFIG_PM
.resume = ad18xx_resume
@@ -1881,7 +1881,7 @@ static int patch_ad1981a_specific(struct snd_ac97 * ac97)
ARRAY_SIZE(snd_ac97_ad1981x_jack_sense));
}
-static struct snd_ac97_build_ops patch_ad1981a_build_ops = {
+static const struct snd_ac97_build_ops patch_ad1981a_build_ops = {
.build_post_spdif = patch_ad198x_post_spdif,
.build_specific = patch_ad1981a_specific,
#ifdef CONFIG_PM
@@ -1936,7 +1936,7 @@ static int patch_ad1981b_specific(struct snd_ac97 *ac97)
ARRAY_SIZE(snd_ac97_ad1981x_jack_sense));
}
-static struct snd_ac97_build_ops patch_ad1981b_build_ops = {
+static const struct snd_ac97_build_ops patch_ad1981b_build_ops = {
.build_post_spdif = patch_ad198x_post_spdif,
.build_specific = patch_ad1981b_specific,
#ifdef CONFIG_PM
@@ -2075,7 +2075,7 @@ static int patch_ad1888_specific(struct snd_ac97 *ac97)
return patch_build_controls(ac97, snd_ac97_ad1888_controls, ARRAY_SIZE(snd_ac97_ad1888_controls));
}
-static struct snd_ac97_build_ops patch_ad1888_build_ops = {
+static const struct snd_ac97_build_ops patch_ad1888_build_ops = {
.build_post_spdif = patch_ad198x_post_spdif,
.build_specific = patch_ad1888_specific,
#ifdef CONFIG_PM
@@ -2124,7 +2124,7 @@ static int patch_ad1980_specific(struct snd_ac97 *ac97)
return patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1);
}
-static struct snd_ac97_build_ops patch_ad1980_build_ops = {
+static const struct snd_ac97_build_ops patch_ad1980_build_ops = {
.build_post_spdif = patch_ad198x_post_spdif,
.build_specific = patch_ad1980_specific,
#ifdef CONFIG_PM
@@ -2239,7 +2239,7 @@ static int patch_ad1985_specific(struct snd_ac97 *ac97)
ARRAY_SIZE(snd_ac97_ad1985_controls));
}
-static struct snd_ac97_build_ops patch_ad1985_build_ops = {
+static const struct snd_ac97_build_ops patch_ad1985_build_ops = {
.build_post_spdif = patch_ad198x_post_spdif,
.build_specific = patch_ad1985_specific,
#ifdef CONFIG_PM
@@ -2531,7 +2531,7 @@ static int patch_ad1986_specific(struct snd_ac97 *ac97)
ARRAY_SIZE(snd_ac97_ad1985_controls));
}
-static struct snd_ac97_build_ops patch_ad1986_build_ops = {
+static const struct snd_ac97_build_ops patch_ad1986_build_ops = {
.build_post_spdif = patch_ad198x_post_spdif,
.build_specific = patch_ad1986_specific,
#ifdef CONFIG_PM
@@ -2636,7 +2636,7 @@ static int patch_alc650_specific(struct snd_ac97 * ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_alc650_ops = {
+static const struct snd_ac97_build_ops patch_alc650_ops = {
.build_specific = patch_alc650_specific,
.update_jacks = alc650_update_jacks
};
@@ -2788,7 +2788,7 @@ static int patch_alc655_specific(struct snd_ac97 * ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_alc655_ops = {
+static const struct snd_ac97_build_ops patch_alc655_ops = {
.build_specific = patch_alc655_specific,
.update_jacks = alc655_update_jacks
};
@@ -2900,7 +2900,7 @@ static int patch_alc850_specific(struct snd_ac97 *ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_alc850_ops = {
+static const struct snd_ac97_build_ops patch_alc850_ops = {
.build_specific = patch_alc850_specific,
.update_jacks = alc850_update_jacks
};
@@ -2962,7 +2962,7 @@ static int patch_cm9738_specific(struct snd_ac97 * ac97)
return patch_build_controls(ac97, snd_ac97_cm9738_controls, ARRAY_SIZE(snd_ac97_cm9738_controls));
}
-static struct snd_ac97_build_ops patch_cm9738_ops = {
+static const struct snd_ac97_build_ops patch_cm9738_ops = {
.build_specific = patch_cm9738_specific,
.update_jacks = cm9738_update_jacks
};
@@ -3053,7 +3053,7 @@ static int patch_cm9739_post_spdif(struct snd_ac97 * ac97)
return patch_build_controls(ac97, snd_ac97_cm9739_controls_spdif, ARRAY_SIZE(snd_ac97_cm9739_controls_spdif));
}
-static struct snd_ac97_build_ops patch_cm9739_ops = {
+static const struct snd_ac97_build_ops patch_cm9739_ops = {
.build_specific = patch_cm9739_specific,
.build_post_spdif = patch_cm9739_post_spdif,
.update_jacks = cm9739_update_jacks
@@ -3227,7 +3227,7 @@ static int patch_cm9761_specific(struct snd_ac97 * ac97)
return patch_build_controls(ac97, snd_ac97_cm9761_controls, ARRAY_SIZE(snd_ac97_cm9761_controls));
}
-static struct snd_ac97_build_ops patch_cm9761_ops = {
+static const struct snd_ac97_build_ops patch_cm9761_ops = {
.build_specific = patch_cm9761_specific,
.build_post_spdif = patch_cm9761_post_spdif,
.update_jacks = cm9761_update_jacks
@@ -3323,7 +3323,7 @@ static int patch_cm9780_specific(struct snd_ac97 *ac97)
return patch_build_controls(ac97, cm9780_controls, ARRAY_SIZE(cm9780_controls));
}
-static struct snd_ac97_build_ops patch_cm9780_ops = {
+static const struct snd_ac97_build_ops patch_cm9780_ops = {
.build_specific = patch_cm9780_specific,
.build_post_spdif = patch_cm9761_post_spdif /* identical with CM9761 */
};
@@ -3443,7 +3443,7 @@ static int patch_vt1616_specific(struct snd_ac97 * ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_vt1616_ops = {
+static const struct snd_ac97_build_ops patch_vt1616_ops = {
.build_specific = patch_vt1616_specific
};
@@ -3797,7 +3797,7 @@ static int patch_it2646_specific(struct snd_ac97 * ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_it2646_ops = {
+static const struct snd_ac97_build_ops patch_it2646_ops = {
.build_specific = patch_it2646_specific,
.update_jacks = it2646_update_jacks
};
@@ -3831,7 +3831,7 @@ static int patch_si3036_specific(struct snd_ac97 * ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_si3036_ops = {
+static const struct snd_ac97_build_ops patch_si3036_ops = {
.build_specific = patch_si3036_specific,
};
@@ -3898,7 +3898,7 @@ static int patch_ucb1400_specific(struct snd_ac97 * ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_ucb1400_ops = {
+static const struct snd_ac97_build_ops patch_ucb1400_ops = {
.build_specific = patch_ucb1400_specific,
};
diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c
index 23f49f356e0..16c0bdfbb16 100644
--- a/sound/pci/au88x0/au88x0_core.c
+++ b/sound/pci/au88x0/au88x0_core.c
@@ -1252,11 +1252,19 @@ static void vortex_adbdma_resetup(vortex_t *vortex, int adbdma) {
static int inline vortex_adbdma_getlinearpos(vortex_t * vortex, int adbdma)
{
stream_t *dma = &vortex->dma_adb[adbdma];
- int temp;
+ int temp, page, delta;
temp = hwread(vortex->mmio, VORTEX_ADBDMA_STAT + (adbdma << 2));
- temp = (dma->period_virt * dma->period_bytes) + (temp & (dma->period_bytes - 1));
- return temp;
+ page = (temp & ADB_SUBBUF_MASK) >> ADB_SUBBUF_SHIFT;
+ if (dma->nr_periods >= 4)
+ delta = (page - dma->period_real) & 3;
+ else {
+ delta = (page - dma->period_real);
+ if (delta < 0)
+ delta += dma->nr_periods;
+ }
+ return (dma->period_virt + delta) * dma->period_bytes
+ + (temp & (dma->period_bytes - 1));
}
static void vortex_adbdma_startfifo(vortex_t * vortex, int adbdma)
diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c
index b9d2f202cf9..5439d662d10 100644
--- a/sound/pci/au88x0/au88x0_pcm.c
+++ b/sound/pci/au88x0/au88x0_pcm.c
@@ -42,11 +42,7 @@ static struct snd_pcm_hardware snd_vortex_playback_hw_adb = {
.rate_min = 5000,
.rate_max = 48000,
.channels_min = 1,
-#ifdef CHIP_AU8830
- .channels_max = 4,
-#else
.channels_max = 2,
-#endif
.buffer_bytes_max = 0x10000,
.period_bytes_min = 0x1,
.period_bytes_max = 0x1000,
@@ -115,6 +111,17 @@ static struct snd_pcm_hardware snd_vortex_playback_hw_wt = {
.periods_max = 64,
};
#endif
+#ifdef CHIP_AU8830
+static unsigned int au8830_channels[3] = {
+ 1, 2, 4,
+};
+
+static struct snd_pcm_hw_constraint_list hw_constraints_au8830_channels = {
+ .count = ARRAY_SIZE(au8830_channels),
+ .list = au8830_channels,
+ .mask = 0,
+};
+#endif
/* open callback */
static int snd_vortex_pcm_open(struct snd_pcm_substream *substream)
{
@@ -156,6 +163,15 @@ static int snd_vortex_pcm_open(struct snd_pcm_substream *substream)
if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB
|| VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_I2S)
runtime->hw = snd_vortex_playback_hw_adb;
+#ifdef CHIP_AU8830
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
+ VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) {
+ runtime->hw.channels_max = 4;
+ snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ &hw_constraints_au8830_channels);
+ }
+#endif
substream->runtime->private_data = NULL;
}
#ifndef CHIP_AU8810
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index 2f3cacbd552..573594bf322 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -1,6 +1,6 @@
/*
* azt3328.c - driver for Aztech AZF3328 based soundcards (e.g. PCI168).
- * Copyright (C) 2002, 2005 - 2009 by Andreas Mohr <andi AT lisas.de>
+ * Copyright (C) 2002, 2005 - 2010 by Andreas Mohr <andi AT lisas.de>
*
* Framework borrowed from Bart Hartgers's als4000.c.
* Driver developed on PCI168 AP(W) version (PCI rev. 10, subsystem ID 1801),
@@ -175,6 +175,7 @@
#include <asm/io.h>
#include <linux/init.h>
+#include <linux/bug.h> /* WARN_ONCE */
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/slab.h>
@@ -201,14 +202,15 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}");
/* === Debug settings ===
Further diagnostic functionality than the settings below
- does not need to be provided, since one can easily write a bash script
+ does not need to be provided, since one can easily write a POSIX shell script
to dump the card's I/O ports (those listed in lspci -v -v):
- function dump()
+ dump()
{
local descr=$1; local addr=$2; local count=$3
echo "${descr}: ${count} @ ${addr}:"
- dd if=/dev/port skip=$[${addr}] count=${count} bs=1 2>/dev/null| hexdump -C
+ dd if=/dev/port skip=`printf %d ${addr}` count=${count} bs=1 \
+ 2>/dev/null| hexdump -C
}
and then use something like
"dump joy200 0x200 8", "dump mpu388 0x388 4", "dump joy 0xb400 8",
@@ -216,14 +218,14 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}");
possibly within a "while true; do ... sleep 1; done" loop.
Tweaking ports could be done using
VALSTRING="`printf "%02x" $value`"
- printf "\x""$VALSTRING"|dd of=/dev/port seek=$[${addr}] bs=1 2>/dev/null
+ printf "\x""$VALSTRING"|dd of=/dev/port seek=`printf %d ${addr}` bs=1 \
+ 2>/dev/null
*/
#define DEBUG_MISC 0
#define DEBUG_CALLS 0
#define DEBUG_MIXER 0
#define DEBUG_CODEC 0
-#define DEBUG_IO 0
#define DEBUG_TIMER 0
#define DEBUG_GAME 0
#define DEBUG_PM 0
@@ -291,19 +293,23 @@ static int seqtimer_scaling = 128;
module_param(seqtimer_scaling, int, 0444);
MODULE_PARM_DESC(seqtimer_scaling, "Set 1024000Hz sequencer timer scale factor (lockup danger!). Default 128.");
-struct snd_azf3328_codec_data {
- unsigned long io_base;
- struct snd_pcm_substream *substream;
- bool running;
- const char *name;
-};
-
enum snd_azf3328_codec_type {
+ /* warning: fixed indices (also used for bitmask checks!) */
AZF_CODEC_PLAYBACK = 0,
AZF_CODEC_CAPTURE = 1,
AZF_CODEC_I2S_OUT = 2,
};
+struct snd_azf3328_codec_data {
+ unsigned long io_base; /* keep first! (avoid offset calc) */
+ unsigned int dma_base; /* helper to avoid an indirection in hotpath */
+ spinlock_t *lock; /* TODO: convert to our own per-codec lock member */
+ struct snd_pcm_substream *substream;
+ bool running;
+ enum snd_azf3328_codec_type type;
+ const char *name;
+};
+
struct snd_azf3328 {
/* often-used fields towards beginning, then grouped */
@@ -362,6 +368,9 @@ MODULE_DEVICE_TABLE(pci, snd_azf3328_ids);
static int
snd_azf3328_io_reg_setb(unsigned reg, u8 mask, bool do_set)
{
+ /* Well, strictly spoken, the inb/outb sequence isn't atomic
+ and would need locking. However we currently don't care
+ since it potentially complicates matters. */
u8 prev = inb(reg), new;
new = (do_set) ? (prev|mask) : (prev & ~mask);
@@ -413,6 +422,21 @@ snd_azf3328_codec_outl(const struct snd_azf3328_codec_data *codec,
outl(value, codec->io_base + reg);
}
+static inline void
+snd_azf3328_codec_outl_multi(const struct snd_azf3328_codec_data *codec,
+ unsigned reg, const void *buffer, int count
+)
+{
+ unsigned long addr = codec->io_base + reg;
+ if (count) {
+ const u32 *buf = buffer;
+ do {
+ outl(*buf++, addr);
+ addr += 4;
+ } while (--count);
+ }
+}
+
static inline u32
snd_azf3328_codec_inl(const struct snd_azf3328_codec_data *codec, unsigned reg)
{
@@ -943,38 +967,37 @@ snd_azf3328_hw_free(struct snd_pcm_substream *substream)
}
static void
-snd_azf3328_codec_setfmt(struct snd_azf3328 *chip,
- enum snd_azf3328_codec_type codec_type,
+snd_azf3328_codec_setfmt(struct snd_azf3328_codec_data *codec,
enum azf_freq_t bitrate,
unsigned int format_width,
unsigned int channels
)
{
unsigned long flags;
- const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type];
u16 val = 0xff00;
+ u8 freq = 0;
snd_azf3328_dbgcallenter();
switch (bitrate) {
- case AZF_FREQ_4000: val |= SOUNDFORMAT_FREQ_SUSPECTED_4000; break;
- case AZF_FREQ_4800: val |= SOUNDFORMAT_FREQ_SUSPECTED_4800; break;
+ case AZF_FREQ_4000: freq = SOUNDFORMAT_FREQ_SUSPECTED_4000; break;
+ case AZF_FREQ_4800: freq = SOUNDFORMAT_FREQ_SUSPECTED_4800; break;
case AZF_FREQ_5512:
/* the AZF3328 names it "5510" for some strange reason */
- val |= SOUNDFORMAT_FREQ_5510; break;
- case AZF_FREQ_6620: val |= SOUNDFORMAT_FREQ_6620; break;
- case AZF_FREQ_8000: val |= SOUNDFORMAT_FREQ_8000; break;
- case AZF_FREQ_9600: val |= SOUNDFORMAT_FREQ_9600; break;
- case AZF_FREQ_11025: val |= SOUNDFORMAT_FREQ_11025; break;
- case AZF_FREQ_13240: val |= SOUNDFORMAT_FREQ_SUSPECTED_13240; break;
- case AZF_FREQ_16000: val |= SOUNDFORMAT_FREQ_16000; break;
- case AZF_FREQ_22050: val |= SOUNDFORMAT_FREQ_22050; break;
- case AZF_FREQ_32000: val |= SOUNDFORMAT_FREQ_32000; break;
+ freq = SOUNDFORMAT_FREQ_5510; break;
+ case AZF_FREQ_6620: freq = SOUNDFORMAT_FREQ_6620; break;
+ case AZF_FREQ_8000: freq = SOUNDFORMAT_FREQ_8000; break;
+ case AZF_FREQ_9600: freq = SOUNDFORMAT_FREQ_9600; break;
+ case AZF_FREQ_11025: freq = SOUNDFORMAT_FREQ_11025; break;
+ case AZF_FREQ_13240: freq = SOUNDFORMAT_FREQ_SUSPECTED_13240; break;
+ case AZF_FREQ_16000: freq = SOUNDFORMAT_FREQ_16000; break;
+ case AZF_FREQ_22050: freq = SOUNDFORMAT_FREQ_22050; break;
+ case AZF_FREQ_32000: freq = SOUNDFORMAT_FREQ_32000; break;
default:
snd_printk(KERN_WARNING "unknown bitrate %d, assuming 44.1kHz!\n", bitrate);
/* fall-through */
- case AZF_FREQ_44100: val |= SOUNDFORMAT_FREQ_44100; break;
- case AZF_FREQ_48000: val |= SOUNDFORMAT_FREQ_48000; break;
- case AZF_FREQ_66200: val |= SOUNDFORMAT_FREQ_SUSPECTED_66200; break;
+ case AZF_FREQ_44100: freq = SOUNDFORMAT_FREQ_44100; break;
+ case AZF_FREQ_48000: freq = SOUNDFORMAT_FREQ_48000; break;
+ case AZF_FREQ_66200: freq = SOUNDFORMAT_FREQ_SUSPECTED_66200; break;
}
/* val = 0xff07; 3m27.993s (65301Hz; -> 64000Hz???) hmm, 66120, 65967, 66123 */
/* val = 0xff09; 17m15.098s (13123,478Hz; -> 12000Hz???) hmm, 13237.2Hz? */
@@ -986,13 +1009,15 @@ snd_azf3328_codec_setfmt(struct snd_azf3328 *chip,
/* val = 0xff0d; 41m23.135s (5523,600Hz; -> 5512Hz???) */
/* val = 0xff0e; 28m30.777s (8017Hz; -> 8000Hz???) */
+ val |= freq;
+
if (channels == 2)
val |= SOUNDFORMAT_FLAG_2CHANNELS;
if (format_width == 16)
val |= SOUNDFORMAT_FLAG_16BIT;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ spin_lock_irqsave(codec->lock, flags);
/* set bitrate/format */
snd_azf3328_codec_outw(codec, IDX_IO_CODEC_SOUNDFORMAT, val);
@@ -1004,7 +1029,8 @@ snd_azf3328_codec_setfmt(struct snd_azf3328 *chip,
* (FIXME: yes, it works, but what exactly am I doing here?? :)
* FIXME: does this have some side effects for full-duplex
* or other dramatic side effects? */
- if (codec_type == AZF_CODEC_PLAYBACK) /* only do it for playback */
+ /* do it for non-capture codecs only */
+ if (codec->type != AZF_CODEC_CAPTURE)
snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS,
snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS) |
DMA_RUN_SOMETHING1 |
@@ -1014,20 +1040,19 @@ snd_azf3328_codec_setfmt(struct snd_azf3328 *chip,
DMA_SOMETHING_ELSE
);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ spin_unlock_irqrestore(codec->lock, flags);
snd_azf3328_dbgcallleave();
}
static inline void
-snd_azf3328_codec_setfmt_lowpower(struct snd_azf3328 *chip,
- enum snd_azf3328_codec_type codec_type
+snd_azf3328_codec_setfmt_lowpower(struct snd_azf3328_codec_data *codec
)
{
/* choose lowest frequency for low power consumption.
* While this will cause louder noise due to rather coarse frequency,
* it should never matter since output should always
* get disabled properly when idle anyway. */
- snd_azf3328_codec_setfmt(chip, codec_type, AZF_FREQ_4000, 8, 1);
+ snd_azf3328_codec_setfmt(codec, AZF_FREQ_4000, 8, 1);
}
static void
@@ -1101,69 +1126,87 @@ snd_azf3328_ctrl_codec_activity(struct snd_azf3328 *chip,
/* ...and adjust clock, too
* (reduce noise and power consumption) */
if (!enable)
- snd_azf3328_codec_setfmt_lowpower(
- chip,
- codec_type
- );
+ snd_azf3328_codec_setfmt_lowpower(codec);
codec->running = enable;
}
}
static void
-snd_azf3328_codec_setdmaa(struct snd_azf3328 *chip,
- enum snd_azf3328_codec_type codec_type,
+snd_azf3328_codec_setdmaa(struct snd_azf3328_codec_data *codec,
unsigned long addr,
- unsigned int count,
- unsigned int size
+ unsigned int period_bytes,
+ unsigned int buffer_bytes
)
{
- const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type];
snd_azf3328_dbgcallenter();
+ WARN_ONCE(period_bytes & 1, "odd period length!?\n");
+ WARN_ONCE(buffer_bytes != 2 * period_bytes,
+ "missed our input expectations! %u vs. %u\n",
+ buffer_bytes, period_bytes);
if (!codec->running) {
/* AZF3328 uses a two buffer pointer DMA transfer approach */
- unsigned long flags, addr_area2;
+ unsigned long flags;
/* width 32bit (prevent overflow): */
- u32 count_areas, lengths;
+ u32 area_length;
+ struct codec_setup_io {
+ u32 dma_start_1;
+ u32 dma_start_2;
+ u32 dma_lengths;
+ } __attribute__((packed)) setup_io;
+
+ area_length = buffer_bytes/2;
+
+ setup_io.dma_start_1 = addr;
+ setup_io.dma_start_2 = addr+area_length;
- count_areas = size/2;
- addr_area2 = addr+count_areas;
- snd_azf3328_dbgcodec("setdma: buffers %08lx[%u] / %08lx[%u]\n",
- addr, count_areas, addr_area2, count_areas);
+ snd_azf3328_dbgcodec(
+ "setdma: buffers %08x[%u] / %08x[%u], %u, %u\n",
+ setup_io.dma_start_1, area_length,
+ setup_io.dma_start_2, area_length,
+ period_bytes, buffer_bytes);
- count_areas--; /* max. index */
+ /* Hmm, are we really supposed to decrement this by 1??
+ Most definitely certainly not: configuring full length does
+ work properly (i.e. likely better), and BTW we
+ violated possibly differing frame sizes with this...
+
+ area_length--; |* max. index *|
+ */
/* build combined I/O buffer length word */
- lengths = (count_areas << 16) | (count_areas);
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_START_1, addr);
- snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_START_2,
- addr_area2);
- snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_LENGTHS,
- lengths);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ setup_io.dma_lengths = (area_length << 16) | (area_length);
+
+ spin_lock_irqsave(codec->lock, flags);
+ snd_azf3328_codec_outl_multi(
+ codec, IDX_IO_CODEC_DMA_START_1, &setup_io, 3
+ );
+ spin_unlock_irqrestore(codec->lock, flags);
}
snd_azf3328_dbgcallleave();
}
static int
-snd_azf3328_codec_prepare(struct snd_pcm_substream *substream)
+snd_azf3328_pcm_prepare(struct snd_pcm_substream *substream)
{
-#if 0
- struct snd_azf3328 *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_azf3328_codec_data *codec = runtime->private_data;
+#if 0
unsigned int size = snd_pcm_lib_buffer_bytes(substream);
unsigned int count = snd_pcm_lib_period_bytes(substream);
#endif
snd_azf3328_dbgcallenter();
+
+ codec->dma_base = runtime->dma_addr;
+
#if 0
- snd_azf3328_codec_setfmt(chip, AZF_CODEC_...,
+ snd_azf3328_codec_setfmt(codec,
runtime->rate,
snd_pcm_format_width(runtime->format),
runtime->channels);
- snd_azf3328_codec_setdmaa(chip, AZF_CODEC_...,
+ snd_azf3328_codec_setdmaa(codec,
runtime->dma_addr, count, size);
#endif
snd_azf3328_dbgcallleave();
@@ -1171,24 +1214,23 @@ snd_azf3328_codec_prepare(struct snd_pcm_substream *substream)
}
static int
-snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type,
- struct snd_pcm_substream *substream, int cmd)
+snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_azf3328 *chip = snd_pcm_substream_chip(substream);
- const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type];
struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_azf3328_codec_data *codec = runtime->private_data;
int result = 0;
u16 flags1;
bool previously_muted = 0;
- bool is_playback_codec = (AZF_CODEC_PLAYBACK == codec_type);
+ bool is_main_mixer_playback_codec = (AZF_CODEC_PLAYBACK == codec->type);
- snd_azf3328_dbgcalls("snd_azf3328_codec_trigger cmd %d\n", cmd);
+ snd_azf3328_dbgcalls("snd_azf3328_pcm_trigger cmd %d\n", cmd);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
snd_azf3328_dbgcodec("START %s\n", codec->name);
- if (is_playback_codec) {
+ if (is_main_mixer_playback_codec) {
/* mute WaveOut (avoid clicking during setup) */
previously_muted =
snd_azf3328_mixer_set_mute(
@@ -1196,12 +1238,12 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type,
);
}
- snd_azf3328_codec_setfmt(chip, codec_type,
+ snd_azf3328_codec_setfmt(codec,
runtime->rate,
snd_pcm_format_width(runtime->format),
runtime->channels);
- spin_lock(&chip->reg_lock);
+ spin_lock(codec->lock);
/* first, remember current value: */
flags1 = snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS);
@@ -1211,14 +1253,14 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type,
/* FIXME: clear interrupts or what??? */
snd_azf3328_codec_outw(codec, IDX_IO_CODEC_IRQTYPE, 0xffff);
- spin_unlock(&chip->reg_lock);
+ spin_unlock(codec->lock);
- snd_azf3328_codec_setdmaa(chip, codec_type, runtime->dma_addr,
+ snd_azf3328_codec_setdmaa(codec, runtime->dma_addr,
snd_pcm_lib_period_bytes(substream),
snd_pcm_lib_buffer_bytes(substream)
);
- spin_lock(&chip->reg_lock);
+ spin_lock(codec->lock);
#ifdef WIN9X
/* FIXME: enable playback/recording??? */
flags1 |= DMA_RUN_SOMETHING1 | DMA_RUN_SOMETHING2;
@@ -1242,10 +1284,10 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type,
DMA_EPILOGUE_SOMETHING |
DMA_SOMETHING_ELSE);
#endif
- spin_unlock(&chip->reg_lock);
- snd_azf3328_ctrl_codec_activity(chip, codec_type, 1);
+ spin_unlock(codec->lock);
+ snd_azf3328_ctrl_codec_activity(chip, codec->type, 1);
- if (is_playback_codec) {
+ if (is_main_mixer_playback_codec) {
/* now unmute WaveOut */
if (!previously_muted)
snd_azf3328_mixer_set_mute(
@@ -1258,19 +1300,19 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type,
case SNDRV_PCM_TRIGGER_RESUME:
snd_azf3328_dbgcodec("RESUME %s\n", codec->name);
/* resume codec if we were active */
- spin_lock(&chip->reg_lock);
+ spin_lock(codec->lock);
if (codec->running)
snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS,
snd_azf3328_codec_inw(
codec, IDX_IO_CODEC_DMA_FLAGS
) | DMA_RESUME
);
- spin_unlock(&chip->reg_lock);
+ spin_unlock(codec->lock);
break;
case SNDRV_PCM_TRIGGER_STOP:
snd_azf3328_dbgcodec("STOP %s\n", codec->name);
- if (is_playback_codec) {
+ if (is_main_mixer_playback_codec) {
/* mute WaveOut (avoid clicking during setup) */
previously_muted =
snd_azf3328_mixer_set_mute(
@@ -1278,7 +1320,7 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type,
);
}
- spin_lock(&chip->reg_lock);
+ spin_lock(codec->lock);
/* first, remember current value: */
flags1 = snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS);
@@ -1293,10 +1335,10 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type,
flags1 &= ~DMA_RUN_SOMETHING1;
snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1);
- spin_unlock(&chip->reg_lock);
- snd_azf3328_ctrl_codec_activity(chip, codec_type, 0);
+ spin_unlock(codec->lock);
+ snd_azf3328_ctrl_codec_activity(chip, codec->type, 0);
- if (is_playback_codec) {
+ if (is_main_mixer_playback_codec) {
/* now unmute WaveOut */
if (!previously_muted)
snd_azf3328_mixer_set_mute(
@@ -1330,67 +1372,29 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type,
return result;
}
-static int
-snd_azf3328_codec_playback_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- return snd_azf3328_codec_trigger(AZF_CODEC_PLAYBACK, substream, cmd);
-}
-
-static int
-snd_azf3328_codec_capture_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- return snd_azf3328_codec_trigger(AZF_CODEC_CAPTURE, substream, cmd);
-}
-
-static int
-snd_azf3328_codec_i2s_out_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- return snd_azf3328_codec_trigger(AZF_CODEC_I2S_OUT, substream, cmd);
-}
-
static snd_pcm_uframes_t
-snd_azf3328_codec_pointer(struct snd_pcm_substream *substream,
- enum snd_azf3328_codec_type codec_type
+snd_azf3328_pcm_pointer(struct snd_pcm_substream *substream
)
{
- const struct snd_azf3328 *chip = snd_pcm_substream_chip(substream);
- const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type];
- unsigned long bufptr, result;
+ const struct snd_azf3328_codec_data *codec =
+ substream->runtime->private_data;
+ unsigned long result;
snd_pcm_uframes_t frmres;
-#ifdef QUERY_HARDWARE
- bufptr = snd_azf3328_codec_inl(codec, IDX_IO_CODEC_DMA_START_1);
-#else
- bufptr = substream->runtime->dma_addr;
-#endif
result = snd_azf3328_codec_inl(codec, IDX_IO_CODEC_DMA_CURRPOS);
/* calculate offset */
- result -= bufptr;
+#ifdef QUERY_HARDWARE
+ result -= snd_azf3328_codec_inl(codec, IDX_IO_CODEC_DMA_START_1);
+#else
+ result -= codec->dma_base;
+#endif
frmres = bytes_to_frames( substream->runtime, result);
- snd_azf3328_dbgcodec("%s @ 0x%8lx, frames %8ld\n",
- codec->name, result, frmres);
+ snd_azf3328_dbgcodec("%08li %s @ 0x%8lx, frames %8ld\n",
+ jiffies, codec->name, result, frmres);
return frmres;
}
-static snd_pcm_uframes_t
-snd_azf3328_codec_playback_pointer(struct snd_pcm_substream *substream)
-{
- return snd_azf3328_codec_pointer(substream, AZF_CODEC_PLAYBACK);
-}
-
-static snd_pcm_uframes_t
-snd_azf3328_codec_capture_pointer(struct snd_pcm_substream *substream)
-{
- return snd_azf3328_codec_pointer(substream, AZF_CODEC_CAPTURE);
-}
-
-static snd_pcm_uframes_t
-snd_azf3328_codec_i2s_out_pointer(struct snd_pcm_substream *substream)
-{
- return snd_azf3328_codec_pointer(substream, AZF_CODEC_I2S_OUT);
-}
-
/******************************************************************/
#ifdef SUPPORT_GAMEPORT
@@ -1532,7 +1536,7 @@ snd_azf3328_gameport_cooked_read(struct gameport *gameport,
}
}
- /* trigger next axes sampling, to be evaluated the next time we
+ /* trigger next sampling of axes, to be evaluated the next time we
* enter this function */
/* for some very, very strange reason we cannot enable
@@ -1624,29 +1628,29 @@ snd_azf3328_irq_log_unknown_type(u8 which)
}
static inline void
-snd_azf3328_codec_interrupt(struct snd_azf3328 *chip, u8 status)
+snd_azf3328_pcm_interrupt(const struct snd_azf3328_codec_data *first_codec,
+ u8 status
+)
{
u8 which;
enum snd_azf3328_codec_type codec_type;
- const struct snd_azf3328_codec_data *codec;
+ const struct snd_azf3328_codec_data *codec = first_codec;
for (codec_type = AZF_CODEC_PLAYBACK;
codec_type <= AZF_CODEC_I2S_OUT;
- ++codec_type) {
+ ++codec_type, ++codec) {
/* skip codec if there's no interrupt for it */
if (!(status & (1 << codec_type)))
continue;
- codec = &chip->codecs[codec_type];
-
- spin_lock(&chip->reg_lock);
+ spin_lock(codec->lock);
which = snd_azf3328_codec_inb(codec, IDX_IO_CODEC_IRQTYPE);
/* ack all IRQ types immediately */
snd_azf3328_codec_outb(codec, IDX_IO_CODEC_IRQTYPE, which);
- spin_unlock(&chip->reg_lock);
+ spin_unlock(codec->lock);
- if ((chip->pcm[codec_type]) && (codec->substream)) {
+ if (codec->substream) {
snd_pcm_period_elapsed(codec->substream);
snd_azf3328_dbgcodec("%s period done (#%x), @ %x\n",
codec->name,
@@ -1701,7 +1705,7 @@ snd_azf3328_interrupt(int irq, void *dev_id)
}
if (status & (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_I2S_OUT))
- snd_azf3328_codec_interrupt(chip, status);
+ snd_azf3328_pcm_interrupt(chip->codecs, status);
if (status & IRQ_GAMEPORT)
snd_azf3328_gameport_interrupt(chip);
@@ -1789,101 +1793,85 @@ snd_azf3328_pcm_open(struct snd_pcm_substream *substream,
{
struct snd_azf3328 *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type];
snd_azf3328_dbgcallenter();
- chip->codecs[codec_type].substream = substream;
+ codec->substream = substream;
/* same parameters for all our codecs - at least we think so... */
runtime->hw = snd_azf3328_hardware;
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&snd_azf3328_hw_constraints_rates);
+ runtime->private_data = codec;
snd_azf3328_dbgcallleave();
return 0;
}
static int
-snd_azf3328_playback_open(struct snd_pcm_substream *substream)
+snd_azf3328_pcm_playback_open(struct snd_pcm_substream *substream)
{
return snd_azf3328_pcm_open(substream, AZF_CODEC_PLAYBACK);
}
static int
-snd_azf3328_capture_open(struct snd_pcm_substream *substream)
+snd_azf3328_pcm_capture_open(struct snd_pcm_substream *substream)
{
return snd_azf3328_pcm_open(substream, AZF_CODEC_CAPTURE);
}
static int
-snd_azf3328_i2s_out_open(struct snd_pcm_substream *substream)
+snd_azf3328_pcm_i2s_out_open(struct snd_pcm_substream *substream)
{
return snd_azf3328_pcm_open(substream, AZF_CODEC_I2S_OUT);
}
static int
-snd_azf3328_pcm_close(struct snd_pcm_substream *substream,
- enum snd_azf3328_codec_type codec_type
+snd_azf3328_pcm_close(struct snd_pcm_substream *substream
)
{
- struct snd_azf3328 *chip = snd_pcm_substream_chip(substream);
+ struct snd_azf3328_codec_data *codec =
+ substream->runtime->private_data;
snd_azf3328_dbgcallenter();
- chip->codecs[codec_type].substream = NULL;
+ codec->substream = NULL;
snd_azf3328_dbgcallleave();
return 0;
}
-static int
-snd_azf3328_playback_close(struct snd_pcm_substream *substream)
-{
- return snd_azf3328_pcm_close(substream, AZF_CODEC_PLAYBACK);
-}
-
-static int
-snd_azf3328_capture_close(struct snd_pcm_substream *substream)
-{
- return snd_azf3328_pcm_close(substream, AZF_CODEC_CAPTURE);
-}
-
-static int
-snd_azf3328_i2s_out_close(struct snd_pcm_substream *substream)
-{
- return snd_azf3328_pcm_close(substream, AZF_CODEC_I2S_OUT);
-}
-
/******************************************************************/
static struct snd_pcm_ops snd_azf3328_playback_ops = {
- .open = snd_azf3328_playback_open,
- .close = snd_azf3328_playback_close,
+ .open = snd_azf3328_pcm_playback_open,
+ .close = snd_azf3328_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_azf3328_hw_params,
.hw_free = snd_azf3328_hw_free,
- .prepare = snd_azf3328_codec_prepare,
- .trigger = snd_azf3328_codec_playback_trigger,
- .pointer = snd_azf3328_codec_playback_pointer
+ .prepare = snd_azf3328_pcm_prepare,
+ .trigger = snd_azf3328_pcm_trigger,
+ .pointer = snd_azf3328_pcm_pointer
};
static struct snd_pcm_ops snd_azf3328_capture_ops = {
- .open = snd_azf3328_capture_open,
- .close = snd_azf3328_capture_close,
+ .open = snd_azf3328_pcm_capture_open,
+ .close = snd_azf3328_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_azf3328_hw_params,
.hw_free = snd_azf3328_hw_free,
- .prepare = snd_azf3328_codec_prepare,
- .trigger = snd_azf3328_codec_capture_trigger,
- .pointer = snd_azf3328_codec_capture_pointer
+ .prepare = snd_azf3328_pcm_prepare,
+ .trigger = snd_azf3328_pcm_trigger,
+ .pointer = snd_azf3328_pcm_pointer
};
static struct snd_pcm_ops snd_azf3328_i2s_out_ops = {
- .open = snd_azf3328_i2s_out_open,
- .close = snd_azf3328_i2s_out_close,
+ .open = snd_azf3328_pcm_i2s_out_open,
+ .close = snd_azf3328_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_azf3328_hw_params,
.hw_free = snd_azf3328_hw_free,
- .prepare = snd_azf3328_codec_prepare,
- .trigger = snd_azf3328_codec_i2s_out_trigger,
- .pointer = snd_azf3328_codec_i2s_out_pointer
+ .prepare = snd_azf3328_pcm_prepare,
+ .trigger = snd_azf3328_pcm_trigger,
+ .pointer = snd_azf3328_pcm_pointer
};
static int __devinit
@@ -1966,7 +1954,7 @@ snd_azf3328_timer_start(struct snd_timer *timer)
snd_azf3328_dbgtimer("delay was too low (%d)!\n", delay);
delay = 49; /* minimum time is 49 ticks */
}
- snd_azf3328_dbgtimer("setting timer countdown value %d, add COUNTDOWN|IRQ\n", delay);
+ snd_azf3328_dbgtimer("setting timer countdown value %d\n", delay);
delay |= TIMER_COUNTDOWN_ENABLE | TIMER_IRQ_ENABLE;
spin_lock_irqsave(&chip->reg_lock, flags);
snd_azf3328_ctrl_outl(chip, IDX_IO_TIMER_VALUE, delay);
@@ -2180,6 +2168,7 @@ snd_azf3328_create(struct snd_card *card,
};
u8 dma_init;
enum snd_azf3328_codec_type codec_type;
+ struct snd_azf3328_codec_data *codec_setup;
*rchip = NULL;
@@ -2217,15 +2206,23 @@ snd_azf3328_create(struct snd_card *card,
chip->opl3_io = pci_resource_start(pci, 3);
chip->mixer_io = pci_resource_start(pci, 4);
- chip->codecs[AZF_CODEC_PLAYBACK].io_base =
- chip->ctrl_io + AZF_IO_OFFS_CODEC_PLAYBACK;
- chip->codecs[AZF_CODEC_PLAYBACK].name = "PLAYBACK";
- chip->codecs[AZF_CODEC_CAPTURE].io_base =
- chip->ctrl_io + AZF_IO_OFFS_CODEC_CAPTURE;
- chip->codecs[AZF_CODEC_CAPTURE].name = "CAPTURE";
- chip->codecs[AZF_CODEC_I2S_OUT].io_base =
- chip->ctrl_io + AZF_IO_OFFS_CODEC_I2S_OUT;
- chip->codecs[AZF_CODEC_I2S_OUT].name = "I2S_OUT";
+ codec_setup = &chip->codecs[AZF_CODEC_PLAYBACK];
+ codec_setup->io_base = chip->ctrl_io + AZF_IO_OFFS_CODEC_PLAYBACK;
+ codec_setup->lock = &chip->reg_lock;
+ codec_setup->type = AZF_CODEC_PLAYBACK;
+ codec_setup->name = "PLAYBACK";
+
+ codec_setup = &chip->codecs[AZF_CODEC_CAPTURE];
+ codec_setup->io_base = chip->ctrl_io + AZF_IO_OFFS_CODEC_CAPTURE;
+ codec_setup->lock = &chip->reg_lock;
+ codec_setup->type = AZF_CODEC_CAPTURE;
+ codec_setup->name = "CAPTURE";
+
+ codec_setup = &chip->codecs[AZF_CODEC_I2S_OUT];
+ codec_setup->io_base = chip->ctrl_io + AZF_IO_OFFS_CODEC_I2S_OUT;
+ codec_setup->lock = &chip->reg_lock;
+ codec_setup->type = AZF_CODEC_I2S_OUT;
+ codec_setup->name = "I2S_OUT";
if (request_irq(pci->irq, snd_azf3328_interrupt,
IRQF_SHARED, card->shortname, chip)) {
@@ -2257,15 +2254,15 @@ snd_azf3328_create(struct snd_card *card,
struct snd_azf3328_codec_data *codec =
&chip->codecs[codec_type];
- /* shutdown codecs to save power */
+ /* shutdown codecs to reduce power / noise */
/* have ...ctrl_codec_activity() act properly */
codec->running = 1;
snd_azf3328_ctrl_codec_activity(chip, codec_type, 0);
- spin_lock_irq(&chip->reg_lock);
+ spin_lock_irq(codec->lock);
snd_azf3328_codec_outb(codec, IDX_IO_CODEC_DMA_FLAGS,
dma_init);
- spin_unlock_irq(&chip->reg_lock);
+ spin_unlock_irq(codec->lock);
}
snd_card_set_dev(card, &pci->dev);
@@ -2419,6 +2416,7 @@ snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state)
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+ /* same pcm object for playback/capture */
snd_pcm_suspend_all(chip->pcm[AZF_CODEC_PLAYBACK]);
snd_pcm_suspend_all(chip->pcm[AZF_CODEC_I2S_OUT]);
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c
index 37e1b5df5ab..2958a05b529 100644
--- a/sound/pci/bt87x.c
+++ b/sound/pci/bt87x.c
@@ -637,15 +637,9 @@ static struct snd_kcontrol_new snd_bt87x_capture_boost = {
static int snd_bt87x_capture_source_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *info)
{
- static char *texts[3] = {"TV Tuner", "FM", "Mic/Line"};
+ static const char *const texts[3] = {"TV Tuner", "FM", "Mic/Line"};
- info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- info->count = 1;
- info->value.enumerated.items = 3;
- if (info->value.enumerated.item > 2)
- info->value.enumerated.item = 2;
- strcpy(info->value.enumerated.name, texts[info->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(info, 1, 3, texts);
}
static int snd_bt87x_capture_source_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h
index f19c1107725..fc53b9bca26 100644
--- a/sound/pci/ca0106/ca0106.h
+++ b/sound/pci/ca0106/ca0106.h
@@ -188,7 +188,7 @@
#define PLAYBACK_LIST_PTR 0x02 /* Pointer to the current period being played */
/* PTR[5:0], Default: 0x0 */
#define PLAYBACK_UNKNOWN3 0x03 /* Not used ?? */
-#define PLAYBACK_DMA_ADDR 0x04 /* Playback DMA addresss */
+#define PLAYBACK_DMA_ADDR 0x04 /* Playback DMA address */
/* DMA[31:0], Default: 0x0 */
#define PLAYBACK_PERIOD_SIZE 0x05 /* Playback period size. win2000 uses 0x04000000 */
/* SIZE[31:16], Default: 0x0 */
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index d2d12c08f93..01b49388faf 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -1082,7 +1082,7 @@ snd_ca0106_pcm_pointer_capture(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_ca0106_pcm *epcm = runtime->private_data;
snd_pcm_uframes_t ptr, ptr1, ptr2 = 0;
- int channel = channel=epcm->channel_id;
+ int channel = epcm->channel_id;
if (!epcm->running)
return 0;
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c
index 329968edca9..b5bb036ef73 100644
--- a/sound/pci/cmipci.c
+++ b/sound/pci/cmipci.c
@@ -2507,14 +2507,12 @@ static int snd_cmipci_line_in_mode_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct cmipci *cm = snd_kcontrol_chip(kcontrol);
- static char *texts[3] = { "Line-In", "Rear Output", "Bass Output" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = cm->chip_version >= 39 ? 3 : 2;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ static const char *const texts[3] = {
+ "Line-In", "Rear Output", "Bass Output"
+ };
+
+ return snd_ctl_enum_info(uinfo, 1,
+ cm->chip_version >= 39 ? 3 : 2, texts);
}
static inline unsigned int get_line_in_mode(struct cmipci *cm)
@@ -2564,14 +2562,9 @@ static int snd_cmipci_line_in_mode_put(struct snd_kcontrol *kcontrol,
static int snd_cmipci_mic_in_mode_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[2] = { "Mic-In", "Center/LFE Output" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ static const char *const texts[2] = { "Mic-In", "Center/LFE Output" };
+
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int snd_cmipci_mic_in_mode_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/pci/cs5535audio/cs5535audio_pm.c b/sound/pci/cs5535audio/cs5535audio_pm.c
index a3301cc4ab8..185b0008832 100644
--- a/sound/pci/cs5535audio/cs5535audio_pm.c
+++ b/sound/pci/cs5535audio/cs5535audio_pm.c
@@ -90,12 +90,7 @@ int snd_cs5535audio_resume(struct pci_dev *pci)
int i;
pci_set_power_state(pci, PCI_D0);
- if (pci_restore_state(pci) < 0) {
- printk(KERN_ERR "cs5535audio: pci_restore_state failed, "
- "disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
+ pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
printk(KERN_ERR "cs5535audio: pci_enable_device failed, "
"disabling device\n");
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index df47f738098..0c701e4ec8a 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -114,7 +114,7 @@ MODULE_PARM_DESC(enable, "Enable the EMU10K1X soundcard.");
*/
#define PLAYBACK_LIST_SIZE 0x01 /* Size of list in bytes << 16. E.g. 8 periods -> 0x00380000 */
#define PLAYBACK_LIST_PTR 0x02 /* Pointer to the current period being played */
-#define PLAYBACK_DMA_ADDR 0x04 /* Playback DMA addresss */
+#define PLAYBACK_DMA_ADDR 0x04 /* Playback DMA address */
#define PLAYBACK_PERIOD_SIZE 0x05 /* Playback period size */
#define PLAYBACK_POINTER 0x06 /* Playback period pointer. Sample currently in DAC */
#define PLAYBACK_UNKNOWN1 0x07
diff --git a/sound/pci/emu10k1/p16v.h b/sound/pci/emu10k1/p16v.h
index 15321494033..00f4817533b 100644
--- a/sound/pci/emu10k1/p16v.h
+++ b/sound/pci/emu10k1/p16v.h
@@ -96,7 +96,7 @@
#define PLAYBACK_LIST_SIZE 0x01 /* Size of list in bytes << 16. E.g. 8 periods -> 0x00380000 */
#define PLAYBACK_LIST_PTR 0x02 /* Pointer to the current period being played */
#define PLAYBACK_UNKNOWN3 0x03 /* Not used */
-#define PLAYBACK_DMA_ADDR 0x04 /* Playback DMA addresss */
+#define PLAYBACK_DMA_ADDR 0x04 /* Playback DMA address */
#define PLAYBACK_PERIOD_SIZE 0x05 /* Playback period size. win2000 uses 0x04000000 */
#define PLAYBACK_POINTER 0x06 /* Playback period pointer. Used with PLAYBACK_LIST_PTR to determine buffer position currently in DAC */
#define PLAYBACK_FIFO_END_ADDRESS 0x07 /* Playback FIFO end address */
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index 23a58f0d6cb..7c17f45d876 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -220,7 +220,7 @@ MODULE_PARM_DESC(joystick, "Enable joystick.");
#define RINGB_EN_2CODEC 0x0020
#define RINGB_SING_BIT_DUAL 0x0040
-/* ****Port Adresses**** */
+/* ****Port Addresses**** */
/* Write & Read */
#define ESM_INDEX 0x02
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 98b6d02a36c..ae5c5d5e4b7 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -2134,10 +2134,10 @@ int snd_hda_codec_reset(struct hda_codec *codec)
* This function returns zero if successful or a negative error code.
*/
int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
- unsigned int *tlv, const char **slaves)
+ unsigned int *tlv, const char * const *slaves)
{
struct snd_kcontrol *kctl;
- const char **s;
+ const char * const *s;
int err;
for (s = slaves; *s && !snd_hda_find_mixer_ctl(codec, *s); s++)
@@ -3689,7 +3689,7 @@ EXPORT_SYMBOL_HDA(snd_hda_build_pcms);
* If no entries are matching, the function returns a negative value.
*/
int snd_hda_check_board_config(struct hda_codec *codec,
- int num_configs, const char **models,
+ int num_configs, const char * const *models,
const struct snd_pci_quirk *tbl)
{
if (codec->modelname && models) {
@@ -3753,7 +3753,7 @@ EXPORT_SYMBOL_HDA(snd_hda_check_board_config);
* If no entries are matching, the function returns a negative value.
*/
int snd_hda_check_board_codec_sid_config(struct hda_codec *codec,
- int num_configs, const char **models,
+ int num_configs, const char * const *models,
const struct snd_pci_quirk *tbl)
{
const struct snd_pci_quirk *q;
@@ -4571,6 +4571,9 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
}
memset(cfg->hp_pins + cfg->hp_outs, 0,
sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs));
+ if (!cfg->hp_outs)
+ cfg->line_out_type = AUTO_PIN_HP_OUT;
+
}
/* sort by sequence */
@@ -4687,7 +4690,7 @@ const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin,
int check_location)
{
unsigned int def_conf;
- static const char *mic_names[] = {
+ static const char * const mic_names[] = {
"Internal Mic", "Dock Mic", "Mic", "Front Mic", "Rear Mic",
};
int attr;
diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c
index 4a663471dad..74b0560289c 100644
--- a/sound/pci/hda/hda_eld.c
+++ b/sound/pci/hda/hda_eld.c
@@ -381,7 +381,7 @@ static void hdmi_show_short_audio_desc(struct cea_sad *a)
snd_print_pcm_rates(a->rates, buf, sizeof(buf));
if (a->format == AUDIO_CODING_TYPE_LPCM)
- snd_print_pcm_bits(a->sample_bits, buf2 + 8, sizeof(buf2 - 8));
+ snd_print_pcm_bits(a->sample_bits, buf2 + 8, sizeof(buf2) - 8);
else if (a->max_bitrate)
snprintf(buf2, sizeof(buf2),
", max bitrate = %d", a->max_bitrate);
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index fb0582f8d72..a63c54d9d76 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -762,7 +762,8 @@ static int check_existing_control(struct hda_codec *codec, const char *type, con
/*
* build output mixer controls
*/
-static int create_output_mixers(struct hda_codec *codec, const char **names)
+static int create_output_mixers(struct hda_codec *codec,
+ const char * const *names)
{
struct hda_gspec *spec = codec->spec;
int i, err;
@@ -780,8 +781,8 @@ static int create_output_mixers(struct hda_codec *codec, const char **names)
static int build_output_controls(struct hda_codec *codec)
{
struct hda_gspec *spec = codec->spec;
- static const char *types_speaker[] = { "Speaker", "Headphone" };
- static const char *types_line[] = { "Front", "Headphone" };
+ static const char * const types_speaker[] = { "Speaker", "Headphone" };
+ static const char * const types_line[] = { "Front", "Headphone" };
switch (spec->pcm_vol_nodes) {
case 1:
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index a1c4008af89..fcedad9a5fe 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -1235,7 +1235,8 @@ static int azx_setup_periods(struct azx *chip,
pos_adj = 0;
} else {
ofs = setup_bdle(substream, azx_dev,
- &bdl, ofs, pos_adj, 1);
+ &bdl, ofs, pos_adj,
+ !substream->runtime->no_period_wakeup);
if (ofs < 0)
goto error;
}
@@ -1247,7 +1248,8 @@ static int azx_setup_periods(struct azx *chip,
period_bytes - pos_adj, 0);
else
ofs = setup_bdle(substream, azx_dev, &bdl, ofs,
- period_bytes, 1);
+ period_bytes,
+ !substream->runtime->no_period_wakeup);
if (ofs < 0)
goto error;
}
@@ -1515,7 +1517,8 @@ static struct snd_pcm_hardware azx_pcm_hw = {
/* No full-resume yet implemented */
/* SNDRV_PCM_INFO_RESUME |*/
SNDRV_PCM_INFO_PAUSE |
- SNDRV_PCM_INFO_SYNC_START),
+ SNDRV_PCM_INFO_SYNC_START |
+ SNDRV_PCM_INFO_NO_PERIOD_WAKEUP),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.rates = SNDRV_PCM_RATE_48000,
.rate_min = 48000,
@@ -2305,6 +2308,7 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = {
SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS M2V", POS_FIX_LPIB),
+ SND_PCI_QUIRK(0x1043, 0x8410, "ASUS", POS_FIX_LPIB),
SND_PCI_QUIRK(0x104d, 0x9069, "Sony VPCS11V9E", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba A100-259", POS_FIX_LPIB),
@@ -2700,7 +2704,7 @@ static int __devinit azx_probe(struct pci_dev *pci,
if (err < 0)
goto out_free;
#ifdef CONFIG_SND_HDA_PATCH_LOADER
- if (patch[dev]) {
+ if (patch[dev] && *patch[dev]) {
snd_printk(KERN_ERR SFX "Applying patch firmware '%s'\n",
patch[dev]);
err = snd_hda_load_patch(chip->bus, patch[dev]);
@@ -2806,6 +2810,8 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
#endif
/* Vortex86MX */
{ PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC },
+ /* VMware HDAudio */
+ { PCI_DEVICE(0x15ad, 0x1977), .driver_data = AZX_DRIVER_GENERIC },
/* AMD/ATI Generic, PCI class code and Vendor ID for HD Audio */
{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID),
.class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 46bbefe2e4a..3ab5e7a303d 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -140,7 +140,7 @@ void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir,
struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
const char *name);
int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
- unsigned int *tlv, const char **slaves);
+ unsigned int *tlv, const char * const *slaves);
int snd_hda_codec_reset(struct hda_codec *codec);
/* amp value bits */
@@ -341,10 +341,10 @@ void snd_print_pcm_bits(int pcm, char *buf, int buflen);
* Misc
*/
int snd_hda_check_board_config(struct hda_codec *codec, int num_configs,
- const char **modelnames,
+ const char * const *modelnames,
const struct snd_pci_quirk *pci_list);
int snd_hda_check_board_codec_sid_config(struct hda_codec *codec,
- int num_configs, const char **models,
+ int num_configs, const char * const *models,
const struct snd_pci_quirk *tbl);
int snd_hda_add_new_ctls(struct hda_codec *codec,
struct snd_kcontrol_new *knew);
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index f025200f2a6..bfe74c2fb07 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -418,7 +418,7 @@ static void print_digital_conv(struct snd_info_buffer *buffer,
static const char *get_pwr_state(u32 state)
{
- static const char *buf[4] = {
+ static const char * const buf[4] = {
"D0", "D1", "D2", "D3"
};
if (state < 4)
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index f7ff3f7ccb8..8dabab79868 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -46,6 +46,9 @@ struct ad198x_spec {
unsigned int cur_eapd;
unsigned int need_dac_fix;
+ hda_nid_t *alt_dac_nid;
+ struct hda_pcm_stream *stream_analog_alt_playback;
+
/* capture */
unsigned int num_adc_nids;
hda_nid_t *adc_nids;
@@ -81,8 +84,8 @@ struct ad198x_spec {
#endif
/* for virtual master */
hda_nid_t vmaster_nid;
- const char **slave_vols;
- const char **slave_sws;
+ const char * const *slave_vols;
+ const char * const *slave_sws;
};
/*
@@ -130,7 +133,7 @@ static int ad198x_init(struct hda_codec *codec)
return 0;
}
-static const char *ad_slave_vols[] = {
+static const char * const ad_slave_vols[] = {
"Front Playback Volume",
"Surround Playback Volume",
"Center Playback Volume",
@@ -143,7 +146,7 @@ static const char *ad_slave_vols[] = {
NULL
};
-static const char *ad_slave_sws[] = {
+static const char * const ad_slave_sws[] = {
"Front Playback Switch",
"Surround Playback Switch",
"Center Playback Switch",
@@ -156,6 +159,25 @@ static const char *ad_slave_sws[] = {
NULL
};
+static const char * const ad1988_6stack_fp_slave_vols[] = {
+ "Front Playback Volume",
+ "Surround Playback Volume",
+ "Center Playback Volume",
+ "LFE Playback Volume",
+ "Side Playback Volume",
+ "IEC958 Playback Volume",
+ NULL
+};
+
+static const char * const ad1988_6stack_fp_slave_sws[] = {
+ "Front Playback Switch",
+ "Surround Playback Switch",
+ "Center Playback Switch",
+ "LFE Playback Switch",
+ "Side Playback Switch",
+ "IEC958 Playback Switch",
+ NULL
+};
static void ad198x_free_kctls(struct hda_codec *codec);
#ifdef CONFIG_SND_HDA_INPUT_BEEP
@@ -309,6 +331,38 @@ static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
}
+static int ad198x_alt_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ unsigned int stream_tag,
+ unsigned int format,
+ struct snd_pcm_substream *substream)
+{
+ struct ad198x_spec *spec = codec->spec;
+ snd_hda_codec_setup_stream(codec, spec->alt_dac_nid[0], stream_tag,
+ 0, format);
+ return 0;
+}
+
+static int ad198x_alt_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct ad198x_spec *spec = codec->spec;
+ snd_hda_codec_cleanup_stream(codec, spec->alt_dac_nid[0]);
+ return 0;
+}
+
+static struct hda_pcm_stream ad198x_pcm_analog_alt_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ /* NID is set in ad198x_build_pcms */
+ .ops = {
+ .prepare = ad198x_alt_playback_pcm_prepare,
+ .cleanup = ad198x_alt_playback_pcm_cleanup
+ },
+};
+
/*
* Digital out
*/
@@ -446,6 +500,17 @@ static int ad198x_build_pcms(struct hda_codec *codec)
}
}
+ if (spec->alt_dac_nid && spec->stream_analog_alt_playback) {
+ codec->num_pcms++;
+ info = spec->pcm_rec + 2;
+ info->name = "AD198x Headphone";
+ info->pcm_type = HDA_PCM_TYPE_AUDIO;
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
+ *spec->stream_analog_alt_playback;
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
+ spec->alt_dac_nid[0];
+ }
+
return 0;
}
@@ -666,7 +731,7 @@ static struct snd_kcontrol_new ad1986a_mixers[] = {
HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
@@ -729,7 +794,7 @@ static struct snd_kcontrol_new ad1986a_laptop_mixers[] = {
HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
/*
HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), */
@@ -775,7 +840,7 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
{
@@ -1069,7 +1134,7 @@ enum {
AD1986A_MODELS
};
-static const char *ad1986a_models[AD1986A_MODELS] = {
+static const char * const ad1986a_models[AD1986A_MODELS] = {
[AD1986A_6STACK] = "6stack",
[AD1986A_3STACK] = "3stack",
[AD1986A_LAPTOP] = "laptop",
@@ -1358,7 +1423,7 @@ static struct snd_kcontrol_new ad1983_mixers[] = {
HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x0c, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
{
@@ -1515,8 +1580,8 @@ static struct snd_kcontrol_new ad1981_mixers[] = {
HDA_CODEC_MUTE("Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Front Mic Boost", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
{
@@ -1726,8 +1791,8 @@ static struct snd_kcontrol_new ad1981_hp_mixers[] = {
HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
#endif
- HDA_CODEC_VOLUME("Mic Boost", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Internal Mic Boost", 0x18, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x18, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
{
@@ -1774,7 +1839,7 @@ static struct snd_kcontrol_new ad1981_thinkpad_mixers[] = {
HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
{
@@ -1813,7 +1878,7 @@ enum {
AD1981_MODELS
};
-static const char *ad1981_models[AD1981_MODELS] = {
+static const char * const ad1981_models[AD1981_MODELS] = {
[AD1981_HP] = "hp",
[AD1981_THINKPAD] = "thinkpad",
[AD1981_BASIC] = "basic",
@@ -2015,6 +2080,7 @@ static int patch_ad1981(struct hda_codec *codec)
enum {
AD1988_6STACK,
AD1988_6STACK_DIG,
+ AD1988_6STACK_DIG_FP,
AD1988_3STACK,
AD1988_3STACK_DIG,
AD1988_LAPTOP,
@@ -2047,6 +2113,10 @@ static hda_nid_t ad1988_6stack_dac_nids_rev2[4] = {
0x04, 0x05, 0x0a, 0x06
};
+static hda_nid_t ad1988_alt_dac_nid[1] = {
+ 0x03
+};
+
static hda_nid_t ad1988_3stack_dac_nids_rev2[3] = {
0x04, 0x0a, 0x06
};
@@ -2160,8 +2230,37 @@ static struct snd_kcontrol_new ad1988_6stack_mixers2[] = {
HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
+
+ { } /* end */
+};
+
+static struct snd_kcontrol_new ad1988_6stack_fp_mixers[] = {
+ HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+
+ HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
+ HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT),
+ HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT),
+ HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT),
+ HDA_BIND_MUTE("Side Playback Switch", 0x28, 2, HDA_INPUT),
+ HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
+ HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
+
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
+
+ HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
+
+ HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
{ } /* end */
};
@@ -2203,8 +2302,8 @@ static struct snd_kcontrol_new ad1988_3stack_mixers2[] = {
HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Channel Mode",
@@ -2232,7 +2331,7 @@ static struct snd_kcontrol_new ad1988_laptop_mixers[] = {
HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x39, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -2445,6 +2544,68 @@ static struct hda_verb ad1988_6stack_init_verbs[] = {
{ }
};
+static struct hda_verb ad1988_6stack_fp_init_verbs[] = {
+ /* Front, Surround, CLFE, side DAC; unmute as default */
+ {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ /* Headphone; unmute as default */
+ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ /* Port-A front headphon path */
+ {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ /* Port-D line-out path */
+ {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ /* Port-F surround path */
+ {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ /* Port-G CLFE path */
+ {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ /* Port-H side path */
+ {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ /* Mono out path */
+ {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
+ {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
+ /* Port-B front mic-in path */
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ /* Port-C line-in path */
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+ {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
+ /* Port-E mic-in path */
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
+ /* Analog CD Input */
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+ /* Analog Mix output amp */
+ {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
+
+ { }
+};
+
static struct hda_verb ad1988_capture_init_verbs[] = {
/* mute analog mix */
{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
@@ -2792,7 +2953,9 @@ static int ad1988_auto_create_multi_out_ctls(struct ad198x_spec *spec,
const struct auto_pin_cfg *cfg)
{
char name[32];
- static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" };
+ static const char * const chname[4] = {
+ "Front", "Surround", NULL /*CLFE*/, "Side"
+ };
hda_nid_t nid;
int i, err;
@@ -2902,7 +3065,7 @@ static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin,
idx = ad1988_pin_idx(pin);
bnid = ad1988_boost_nids[idx];
if (bnid) {
- sprintf(name, "%s Boost", ctlname);
+ sprintf(name, "%s Boost Volume", ctlname);
return add_control(spec, AD_CTL_WIDGET_VOL, name,
HDA_COMPOSE_AMP_VAL(bnid, 3, idx, HDA_OUTPUT));
@@ -3074,13 +3237,13 @@ static int ad1988_auto_init(struct hda_codec *codec)
return 0;
}
-
/*
*/
-static const char *ad1988_models[AD1988_MODEL_LAST] = {
+static const char * const ad1988_models[AD1988_MODEL_LAST] = {
[AD1988_6STACK] = "6stack",
[AD1988_6STACK_DIG] = "6stack-dig",
+ [AD1988_6STACK_DIG_FP] = "6stack-dig-fp",
[AD1988_3STACK] = "3stack",
[AD1988_3STACK_DIG] = "3stack-dig",
[AD1988_LAPTOP] = "laptop",
@@ -3140,6 +3303,7 @@ static int patch_ad1988(struct hda_codec *codec)
switch (board_config) {
case AD1988_6STACK:
case AD1988_6STACK_DIG:
+ case AD1988_6STACK_DIG_FP:
spec->multiout.max_channels = 8;
spec->multiout.num_dacs = 4;
if (is_rev2(codec))
@@ -3152,10 +3316,22 @@ static int patch_ad1988(struct hda_codec *codec)
spec->mixers[0] = ad1988_6stack_mixers1_rev2;
else
spec->mixers[0] = ad1988_6stack_mixers1;
- spec->mixers[1] = ad1988_6stack_mixers2;
+ if (board_config == AD1988_6STACK_DIG_FP) {
+ spec->mixers[1] = ad1988_6stack_fp_mixers;
+ spec->slave_vols = ad1988_6stack_fp_slave_vols;
+ spec->slave_sws = ad1988_6stack_fp_slave_sws;
+ spec->alt_dac_nid = ad1988_alt_dac_nid;
+ spec->stream_analog_alt_playback =
+ &ad198x_pcm_analog_alt_playback;
+ } else
+ spec->mixers[1] = ad1988_6stack_mixers2;
spec->num_init_verbs = 1;
- spec->init_verbs[0] = ad1988_6stack_init_verbs;
- if (board_config == AD1988_6STACK_DIG) {
+ if (board_config == AD1988_6STACK_DIG_FP)
+ spec->init_verbs[0] = ad1988_6stack_fp_init_verbs;
+ else
+ spec->init_verbs[0] = ad1988_6stack_init_verbs;
+ if ((board_config == AD1988_6STACK_DIG) ||
+ (board_config == AD1988_6STACK_DIG_FP)) {
spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
spec->dig_in_nid = AD1988_SPDIF_IN;
}
@@ -3300,8 +3476,8 @@ static struct snd_kcontrol_new ad1884_base_mixers[] = {
HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x15, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
@@ -3399,7 +3575,7 @@ static struct hda_amp_list ad1884_loopbacks[] = {
};
#endif
-static const char *ad1884_slave_vols[] = {
+static const char * const ad1884_slave_vols[] = {
"PCM Playback Volume",
"Mic Playback Volume",
"Mono Playback Volume",
@@ -3499,9 +3675,9 @@ static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
HDA_CODEC_VOLUME("Docking Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
HDA_CODEC_MUTE("Docking Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Internal Mic Boost", 0x15, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Docking Mic Boost", 0x25, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
@@ -3560,8 +3736,8 @@ static struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = {
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
HDA_CODEC_VOLUME("Line-In Playback Volume", 0x20, 0x01, HDA_INPUT),
HDA_CODEC_MUTE("Line-In Playback Switch", 0x20, 0x01, HDA_INPUT),
- HDA_CODEC_VOLUME("Line-In Boost", 0x15, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line-In Boost Volume", 0x15, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
@@ -3637,7 +3813,7 @@ enum {
AD1984_MODELS
};
-static const char *ad1984_models[AD1984_MODELS] = {
+static const char * const ad1984_models[AD1984_MODELS] = {
[AD1984_BASIC] = "basic",
[AD1984_THINKPAD] = "thinkpad",
[AD1984_DELL_DESKTOP] = "dell_desktop",
@@ -3745,9 +3921,9 @@ static struct snd_kcontrol_new ad1884a_base_mixers[] = {
HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Line Boost", 0x15, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x25, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
@@ -3888,9 +4064,9 @@ static struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Internal Mic Boost", 0x15, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Dock Mic Boost", 0x25, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
{ } /* end */
@@ -4126,8 +4302,8 @@ static struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = {
HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Internal Mic Boost", 0x17, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
{
@@ -4255,8 +4431,8 @@ static struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = {
HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x25, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Internal Mic Boost", 0x17, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT),
{ } /* end */
};
@@ -4308,7 +4484,7 @@ enum {
AD1884A_MODELS
};
-static const char *ad1884a_models[AD1884A_MODELS] = {
+static const char * const ad1884a_models[AD1884A_MODELS] = {
[AD1884A_DESKTOP] = "desktop",
[AD1884A_LAPTOP] = "laptop",
[AD1884A_MOBILE] = "mobile",
@@ -4494,9 +4670,9 @@ static struct snd_kcontrol_new ad1882_base_mixers[] = {
HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Line-In Boost", 0x3a, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Line-In Boost Volume", 0x3a, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
@@ -4547,7 +4723,7 @@ static struct snd_kcontrol_new ad1882a_loopback_mixers[] = {
HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
- HDA_CODEC_VOLUME("Digital Mic Boost", 0x1f, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Digital Mic Boost Volume", 0x1f, 0x0, HDA_INPUT),
{ } /* end */
};
@@ -4696,7 +4872,7 @@ enum {
AD1882_MODELS
};
-static const char *ad1882_models[AD1986A_MODELS] = {
+static const char * const ad1882_models[AD1986A_MODELS] = {
[AD1882_3STACK] = "3stack",
[AD1882_6STACK] = "6stack",
};
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 18af38ebf75..067982f4f18 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -490,7 +490,7 @@ static int parse_digital_input(struct hda_codec *codec)
* create mixer controls
*/
-static const char *dir_sfx[2] = { "Playback", "Capture" };
+static const char * const dir_sfx[2] = { "Playback", "Capture" };
static int add_mute(struct hda_codec *codec, const char *name, int index,
unsigned int pval, int dir, struct snd_kcontrol **kctlp)
@@ -1039,9 +1039,11 @@ static struct hda_verb cs_errata_init_verbs[] = {
{0x11, AC_VERB_SET_PROC_COEF, 0x0008},
{0x11, AC_VERB_SET_PROC_STATE, 0x00},
+#if 0 /* Don't to set to D3 as we are in power-up sequence */
{0x07, AC_VERB_SET_POWER_STATE, 0x03}, /* S/PDIF Rx: D3 */
{0x08, AC_VERB_SET_POWER_STATE, 0x03}, /* S/PDIF Tx: D3 */
/*{0x01, AC_VERB_SET_POWER_STATE, 0x03},*/ /* AFG: D3 This is already handled */
+#endif
{} /* terminator */
};
@@ -1156,7 +1158,7 @@ static int cs_parse_auto_config(struct hda_codec *codec)
return 0;
}
-static const char *cs420x_models[CS420X_MODELS] = {
+static const char * const cs420x_models[CS420X_MODELS] = {
[CS420X_MBP53] = "mbp53",
[CS420X_MBP55] = "mbp55",
[CS420X_IMAC27] = "imac27",
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c
index ff60908f455..1f8bbcd0f80 100644
--- a/sound/pci/hda/patch_cmedia.c
+++ b/sound/pci/hda/patch_cmedia.c
@@ -608,7 +608,7 @@ static void cmi9880_free(struct hda_codec *codec)
/*
*/
-static const char *cmi9880_models[CMI_MODELS] = {
+static const char * const cmi9880_models[CMI_MODELS] = {
[CMI_MINIMAL] = "minimal",
[CMI_MIN_FP] = "min_fp",
[CMI_FULL] = "full",
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 76bd58a0e2b..4d5004e693f 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -85,6 +85,7 @@ struct conexant_spec {
unsigned int auto_mic;
int auto_mic_ext; /* autocfg.inputs[] index for ext mic */
unsigned int need_dac_fix;
+ hda_nid_t slave_dig_outs[2];
/* capture */
unsigned int num_adc_nids;
@@ -127,6 +128,7 @@ struct conexant_spec {
unsigned int ideapad:1;
unsigned int thinkpad:1;
unsigned int hp_laptop:1;
+ unsigned int asus:1;
unsigned int ext_mic_present;
unsigned int recording;
@@ -352,6 +354,8 @@ static int conexant_build_pcms(struct hda_codec *codec)
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
spec->dig_in_nid;
}
+ if (spec->slave_dig_outs[0])
+ codec->slave_dig_outs = spec->slave_dig_outs;
}
return 0;
@@ -403,10 +407,16 @@ static int conexant_add_jack(struct hda_codec *codec,
struct conexant_spec *spec;
struct conexant_jack *jack;
const char *name;
- int err;
+ int i, err;
spec = codec->spec;
snd_array_init(&spec->jacks, sizeof(*jack), 32);
+
+ jack = spec->jacks.list;
+ for (i = 0; i < spec->jacks.used; i++, jack++)
+ if (jack->nid == nid)
+ return 0 ; /* already present */
+
jack = snd_array_new(&spec->jacks);
name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ;
@@ -537,13 +547,13 @@ static struct snd_kcontrol_new cxt_beep_mixer[] = {
};
#endif
-static const char *slave_vols[] = {
+static const char * const slave_vols[] = {
"Headphone Playback Volume",
"Speaker Playback Volume",
NULL
};
-static const char *slave_sws[] = {
+static const char * const slave_sws[] = {
"Headphone Playback Switch",
"Speaker Playback Switch",
NULL
@@ -869,16 +879,16 @@ static void cxt5045_hp_unsol_event(struct hda_codec *codec,
}
static struct snd_kcontrol_new cxt5045_mixers[] = {
- HDA_CODEC_VOLUME("Int Mic Capture Volume", 0x1a, 0x01, HDA_INPUT),
- HDA_CODEC_MUTE("Int Mic Capture Switch", 0x1a, 0x01, HDA_INPUT),
- HDA_CODEC_VOLUME("Ext Mic Capture Volume", 0x1a, 0x02, HDA_INPUT),
- HDA_CODEC_MUTE("Ext Mic Capture Switch", 0x1a, 0x02, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x1a, 0x01, HDA_INPUT),
+ HDA_CODEC_MUTE("Internal Mic Capture Switch", 0x1a, 0x01, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Capture Volume", 0x1a, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Capture Switch", 0x1a, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("PCM Playback Volume", 0x17, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("PCM Playback Switch", 0x17, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x17, 0x1, HDA_INPUT),
- HDA_CODEC_MUTE("Int Mic Playback Switch", 0x17, 0x1, HDA_INPUT),
- HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x17, 0x2, HDA_INPUT),
- HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x17, 0x2, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x1, HDA_INPUT),
+ HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x17, 0x2, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x17, 0x2, HDA_INPUT),
HDA_BIND_VOL("Master Playback Volume", &cxt5045_hp_bind_master_vol),
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -910,16 +920,16 @@ static struct snd_kcontrol_new cxt5045_benq_mixers[] = {
};
static struct snd_kcontrol_new cxt5045_mixers_hp530[] = {
- HDA_CODEC_VOLUME("Int Mic Capture Volume", 0x1a, 0x02, HDA_INPUT),
- HDA_CODEC_MUTE("Int Mic Capture Switch", 0x1a, 0x02, HDA_INPUT),
- HDA_CODEC_VOLUME("Ext Mic Capture Volume", 0x1a, 0x01, HDA_INPUT),
- HDA_CODEC_MUTE("Ext Mic Capture Switch", 0x1a, 0x01, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x1a, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Internal Mic Capture Switch", 0x1a, 0x02, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Capture Volume", 0x1a, 0x01, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Capture Switch", 0x1a, 0x01, HDA_INPUT),
HDA_CODEC_VOLUME("PCM Playback Volume", 0x17, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("PCM Playback Switch", 0x17, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x17, 0x2, HDA_INPUT),
- HDA_CODEC_MUTE("Int Mic Playback Switch", 0x17, 0x2, HDA_INPUT),
- HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x17, 0x1, HDA_INPUT),
- HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x17, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x2, HDA_INPUT),
+ HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x2, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x17, 0x1, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x17, 0x1, HDA_INPUT),
HDA_BIND_VOL("Master Playback Volume", &cxt5045_hp_bind_master_vol),
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -947,7 +957,7 @@ static struct hda_verb cxt5045_init_verbs[] = {
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
- /* Record selector: Int mic */
+ /* Record selector: Internal mic */
{0x1a, AC_VERB_SET_CONNECT_SEL,0x1},
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE,
AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17},
@@ -960,7 +970,7 @@ static struct hda_verb cxt5045_init_verbs[] = {
};
static struct hda_verb cxt5045_benq_init_verbs[] = {
- /* Int Mic, Mic */
+ /* Internal Mic, Mic */
{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
/* Line In,HP, Amp */
@@ -973,7 +983,7 @@ static struct hda_verb cxt5045_benq_init_verbs[] = {
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
- /* Record selector: Int mic */
+ /* Record selector: Internal mic */
{0x1a, AC_VERB_SET_CONNECT_SEL, 0x1},
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE,
AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17},
@@ -1134,7 +1144,7 @@ enum {
CXT5045_MODELS
};
-static const char *cxt5045_models[CXT5045_MODELS] = {
+static const char * const cxt5045_models[CXT5045_MODELS] = {
[CXT5045_LAPTOP_HPSENSE] = "laptop-hpsense",
[CXT5045_LAPTOP_MICSENSE] = "laptop-micsense",
[CXT5045_LAPTOP_HPMICSENSE] = "laptop-hpmicsense",
@@ -1376,7 +1386,7 @@ static void cxt5047_hp_unsol_event(struct hda_codec *codec,
static struct snd_kcontrol_new cxt5047_base_mixers[] = {
HDA_CODEC_VOLUME("Mic Playback Volume", 0x19, 0x02, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x19, 0x02, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x1a, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x1a, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT),
HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT),
HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT),
@@ -1579,7 +1589,7 @@ enum {
CXT5047_MODELS
};
-static const char *cxt5047_models[CXT5047_MODELS] = {
+static const char * const cxt5047_models[CXT5047_MODELS] = {
[CXT5047_LAPTOP] = "laptop",
[CXT5047_LAPTOP_HP] = "laptop-hp",
[CXT5047_LAPTOP_EAPD] = "laptop-eapd",
@@ -1796,8 +1806,8 @@ static struct snd_kcontrol_new cxt5051_playback_mixers[] = {
static struct snd_kcontrol_new cxt5051_capture_mixers[] = {
HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT),
HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
- HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT),
- HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT),
HDA_CODEC_VOLUME("Docking Mic Volume", 0x15, 0x00, HDA_INPUT),
HDA_CODEC_MUTE("Docking Mic Switch", 0x15, 0x00, HDA_INPUT),
{}
@@ -1806,8 +1816,8 @@ static struct snd_kcontrol_new cxt5051_capture_mixers[] = {
static struct snd_kcontrol_new cxt5051_hp_mixers[] = {
HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT),
HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
- HDA_CODEC_VOLUME("External Mic Volume", 0x15, 0x00, HDA_INPUT),
- HDA_CODEC_MUTE("External Mic Switch", 0x15, 0x00, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Volume", 0x15, 0x00, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Switch", 0x15, 0x00, HDA_INPUT),
{}
};
@@ -1826,8 +1836,8 @@ static struct snd_kcontrol_new cxt5051_f700_mixers[] = {
static struct snd_kcontrol_new cxt5051_toshiba_mixers[] = {
HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT),
HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
- HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT),
- HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT),
{}
};
@@ -1847,7 +1857,7 @@ static struct hda_verb cxt5051_init_verbs[] = {
{0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
/* DAC1 */
{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* Record selector: Int mic */
+ /* Record selector: Internal mic */
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44},
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44},
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44},
@@ -1874,7 +1884,7 @@ static struct hda_verb cxt5051_hp_dv6736_init_verbs[] = {
{0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
/* DAC1 */
{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* Record selector: Int mic */
+ /* Record selector: Internal mic */
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44},
{0x14, AC_VERB_SET_CONNECT_SEL, 0x1},
/* SPDIF route: PCM */
@@ -1904,7 +1914,7 @@ static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = {
{0x19, AC_VERB_SET_CONNECT_SEL, 0x00},
/* DAC1 */
{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* Record selector: Int mic */
+ /* Record selector: Internal mic */
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44},
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44},
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44},
@@ -1932,7 +1942,7 @@ static struct hda_verb cxt5051_f700_init_verbs[] = {
{0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
/* DAC1 */
{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* Record selector: Int mic */
+ /* Record selector: Internal mic */
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44},
{0x14, AC_VERB_SET_CONNECT_SEL, 0x1},
/* SPDIF route: PCM */
@@ -1995,7 +2005,7 @@ enum {
CXT5051_MODELS
};
-static const char *cxt5051_models[CXT5051_MODELS] = {
+static const char *const cxt5051_models[CXT5051_MODELS] = {
[CXT5051_LAPTOP] = "laptop",
[CXT5051_HP] = "hp",
[CXT5051_HP_DV6736] = "hp-dv6736",
@@ -2100,7 +2110,7 @@ static int patch_cxt5051(struct hda_codec *codec)
static hda_nid_t cxt5066_dac_nids[1] = { 0x10 };
static hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 };
static hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 };
-#define CXT5066_SPDIF_OUT 0x21
+static hda_nid_t cxt5066_digout_pin_nids[2] = { 0x20, 0x22 };
/* OLPC's microphone port is DC coupled for use with external sensors,
* therefore we use a 50% mic bias in order to center the input signal with
@@ -2111,6 +2121,11 @@ static struct hda_channel_mode cxt5066_modes[1] = {
{ 2, NULL },
};
+#define HP_PRESENT_PORT_A (1 << 0)
+#define HP_PRESENT_PORT_D (1 << 1)
+#define hp_port_a_present(spec) ((spec)->hp_present & HP_PRESENT_PORT_A)
+#define hp_port_d_present(spec) ((spec)->hp_present & HP_PRESENT_PORT_D)
+
static void cxt5066_update_speaker(struct hda_codec *codec)
{
struct conexant_spec *spec = codec->spec;
@@ -2120,24 +2135,20 @@ static void cxt5066_update_speaker(struct hda_codec *codec)
spec->hp_present, spec->cur_eapd);
/* Port A (HP) */
- pinctl = ((spec->hp_present & 1) && spec->cur_eapd) ? PIN_HP : 0;
+ pinctl = (hp_port_a_present(spec) && spec->cur_eapd) ? PIN_HP : 0;
snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
pinctl);
/* Port D (HP/LO) */
- if (spec->dell_automute) {
- /* DELL AIO Port Rule: PortA> PortD> IntSpk */
- pinctl = (!(spec->hp_present & 1) && spec->cur_eapd)
- ? PIN_OUT : 0;
- } else if (spec->thinkpad) {
- if (spec->cur_eapd)
- pinctl = spec->port_d_mode;
- /* Mute dock line-out if Port A (laptop HP) is present */
- if (spec->hp_present& 1)
+ pinctl = spec->cur_eapd ? spec->port_d_mode : 0;
+ if (spec->dell_automute || spec->thinkpad) {
+ /* Mute if Port A is connected */
+ if (hp_port_a_present(spec))
pinctl = 0;
} else {
- pinctl = ((spec->hp_present & 2) && spec->cur_eapd)
- ? spec->port_d_mode : 0;
+ /* Thinkpad/Dell doesn't give pin-D status */
+ if (!hp_port_d_present(spec))
+ pinctl = 0;
}
snd_hda_codec_write(codec, 0x1c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
pinctl);
@@ -2311,6 +2322,19 @@ static void cxt5066_ideapad_automic(struct hda_codec *codec)
}
}
+
+/* toggle input of built-in digital mic and mic jack appropriately */
+static void cxt5066_asus_automic(struct hda_codec *codec)
+{
+ unsigned int present;
+
+ present = snd_hda_jack_detect(codec, 0x1b);
+ snd_printdd("CXT5066: external microphone present=%d\n", present);
+ snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL,
+ present ? 1 : 0);
+}
+
+
/* toggle input of built-in digital mic and mic jack appropriately */
static void cxt5066_hp_laptop_automic(struct hda_codec *codec)
{
@@ -2379,86 +2403,62 @@ static void cxt5066_hp_automute(struct hda_codec *codec)
/* Port D */
portD = snd_hda_jack_detect(codec, 0x1c);
- spec->hp_present = !!(portA);
- spec->hp_present |= portD ? 2 : 0;
+ spec->hp_present = portA ? HP_PRESENT_PORT_A : 0;
+ spec->hp_present |= portD ? HP_PRESENT_PORT_D : 0;
snd_printdd("CXT5066: hp automute portA=%x portD=%x present=%d\n",
portA, portD, spec->hp_present);
cxt5066_update_speaker(codec);
}
-/* unsolicited event for jack sensing */
-static void cxt5066_olpc_unsol_event(struct hda_codec *codec, unsigned int res)
+/* Dispatch the right mic autoswitch function */
+static void cxt5066_automic(struct hda_codec *codec)
{
struct conexant_spec *spec = codec->spec;
- snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26);
- switch (res >> 26) {
- case CONEXANT_HP_EVENT:
- cxt5066_hp_automute(codec);
- break;
- case CONEXANT_MIC_EVENT:
- /* ignore mic events in DC mode; we're always using the jack */
- if (!spec->dc_enable)
- cxt5066_olpc_automic(codec);
- break;
- }
-}
-/* unsolicited event for jack sensing */
-static void cxt5066_vostro_event(struct hda_codec *codec, unsigned int res)
-{
- snd_printdd("CXT5066_vostro: unsol event %x (%x)\n", res, res >> 26);
- switch (res >> 26) {
- case CONEXANT_HP_EVENT:
- cxt5066_hp_automute(codec);
- break;
- case CONEXANT_MIC_EVENT:
+ if (spec->dell_vostro)
cxt5066_vostro_automic(codec);
- break;
- }
-}
-
-/* unsolicited event for jack sensing */
-static void cxt5066_ideapad_event(struct hda_codec *codec, unsigned int res)
-{
- snd_printdd("CXT5066_ideapad: unsol event %x (%x)\n", res, res >> 26);
- switch (res >> 26) {
- case CONEXANT_HP_EVENT:
- cxt5066_hp_automute(codec);
- break;
- case CONEXANT_MIC_EVENT:
+ else if (spec->ideapad)
cxt5066_ideapad_automic(codec);
- break;
- }
+ else if (spec->thinkpad)
+ cxt5066_thinkpad_automic(codec);
+ else if (spec->hp_laptop)
+ cxt5066_hp_laptop_automic(codec);
+ else if (spec->asus)
+ cxt5066_asus_automic(codec);
}
/* unsolicited event for jack sensing */
-static void cxt5066_hp_laptop_event(struct hda_codec *codec, unsigned int res)
+static void cxt5066_olpc_unsol_event(struct hda_codec *codec, unsigned int res)
{
- snd_printdd("CXT5066_hp_laptop: unsol event %x (%x)\n", res, res >> 26);
+ struct conexant_spec *spec = codec->spec;
+ snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26);
switch (res >> 26) {
case CONEXANT_HP_EVENT:
cxt5066_hp_automute(codec);
break;
case CONEXANT_MIC_EVENT:
- cxt5066_hp_laptop_automic(codec);
+ /* ignore mic events in DC mode; we're always using the jack */
+ if (!spec->dc_enable)
+ cxt5066_olpc_automic(codec);
break;
}
}
/* unsolicited event for jack sensing */
-static void cxt5066_thinkpad_event(struct hda_codec *codec, unsigned int res)
+static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res)
{
- snd_printdd("CXT5066_thinkpad: unsol event %x (%x)\n", res, res >> 26);
+ snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26);
switch (res >> 26) {
case CONEXANT_HP_EVENT:
cxt5066_hp_automute(codec);
break;
case CONEXANT_MIC_EVENT:
- cxt5066_thinkpad_automic(codec);
+ cxt5066_automic(codec);
break;
}
}
+
static const struct hda_input_mux cxt5066_analog_mic_boost = {
.num_items = 5,
.items = {
@@ -2632,6 +2632,27 @@ static void cxt5066_olpc_capture_cleanup(struct hda_codec *codec)
spec->recording = 0;
}
+static void conexant_check_dig_outs(struct hda_codec *codec,
+ hda_nid_t *dig_pins,
+ int num_pins)
+{
+ struct conexant_spec *spec = codec->spec;
+ hda_nid_t *nid_loc = &spec->multiout.dig_out_nid;
+ int i;
+
+ for (i = 0; i < num_pins; i++, dig_pins++) {
+ unsigned int cfg = snd_hda_codec_get_pincfg(codec, *dig_pins);
+ if (get_defcfg_connect(cfg) == AC_JACK_PORT_NONE)
+ continue;
+ if (snd_hda_get_connections(codec, *dig_pins, nid_loc, 1) != 1)
+ continue;
+ if (spec->slave_dig_outs[0])
+ nid_loc++;
+ else
+ nid_loc = spec->slave_dig_outs;
+ }
+}
+
static struct hda_input_mux cxt5066_capture_source = {
.num_items = 4,
.items = {
@@ -2728,7 +2749,7 @@ static struct snd_kcontrol_new cxt5066_mixers[] = {
static struct snd_kcontrol_new cxt5066_vostro_mixers[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Int Mic Boost Capture Enum",
+ .name = "Internal Mic Boost Capture Enum",
.info = cxt5066_mic_boost_mux_enum_info,
.get = cxt5066_mic_boost_mux_enum_get,
.put = cxt5066_mic_boost_mux_enum_put,
@@ -2954,7 +2975,7 @@ static struct hda_verb cxt5066_init_verbs_ideapad[] = {
{0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
/* internal microphone */
- {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable int mic */
+ {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable internal mic */
/* EAPD */
{0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
@@ -3009,7 +3030,7 @@ static struct hda_verb cxt5066_init_verbs_thinkpad[] = {
{0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
/* internal microphone */
- {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable int mic */
+ {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable internal mic */
/* EAPD */
{0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
@@ -3038,20 +3059,11 @@ static struct hda_verb cxt5066_init_verbs_hp_laptop[] = {
/* initialize jack-sensing, too */
static int cxt5066_init(struct hda_codec *codec)
{
- struct conexant_spec *spec = codec->spec;
-
snd_printdd("CXT5066: init\n");
conexant_init(codec);
if (codec->patch_ops.unsol_event) {
cxt5066_hp_automute(codec);
- if (spec->dell_vostro)
- cxt5066_vostro_automic(codec);
- else if (spec->ideapad)
- cxt5066_ideapad_automic(codec);
- else if (spec->thinkpad)
- cxt5066_thinkpad_automic(codec);
- else if (spec->hp_laptop)
- cxt5066_hp_laptop_automic(codec);
+ cxt5066_automic(codec);
}
cxt5066_set_mic_boost(codec);
return 0;
@@ -3079,17 +3091,19 @@ enum {
CXT5066_DELL_VOSTRO, /* Dell Vostro 1015i */
CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */
CXT5066_THINKPAD, /* Lenovo ThinkPad T410s, others? */
+ CXT5066_ASUS, /* Asus K52JU, Lenovo G560 - Int mic at 0x1a and Ext mic at 0x1b */
CXT5066_HP_LAPTOP, /* HP Laptop */
CXT5066_MODELS
};
-static const char *cxt5066_models[CXT5066_MODELS] = {
+static const char * const cxt5066_models[CXT5066_MODELS] = {
[CXT5066_LAPTOP] = "laptop",
[CXT5066_DELL_LAPTOP] = "dell-laptop",
[CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5",
[CXT5066_DELL_VOSTRO] = "dell-vostro",
[CXT5066_IDEAPAD] = "ideapad",
[CXT5066_THINKPAD] = "thinkpad",
+ [CXT5066_ASUS] = "asus",
[CXT5066_HP_LAPTOP] = "hp-laptop",
};
@@ -3097,10 +3111,15 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
SND_PCI_QUIRK_MASK(0x1025, 0xff00, 0x0400, "Acer", CXT5066_IDEAPAD),
SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTRO),
SND_PCI_QUIRK(0x1028, 0x02f5, "Dell Vostro 320", CXT5066_IDEAPAD),
+ SND_PCI_QUIRK(0x1028, 0x0401, "Dell Vostro 1014", CXT5066_DELL_VOSTRO),
SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTRO),
SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD),
+ SND_PCI_QUIRK(0x1028, 0x050f, "Dell Inspiron", CXT5066_IDEAPAD),
+ SND_PCI_QUIRK(0x1028, 0x0510, "Dell Vostro", CXT5066_IDEAPAD),
SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP),
- SND_PCI_QUIRK(0x1043, 0x13f3, "Asus A52J", CXT5066_HP_LAPTOP),
+ SND_PCI_QUIRK(0x1043, 0x13f3, "Asus A52J", CXT5066_ASUS),
+ SND_PCI_QUIRK(0x1043, 0x1643, "Asus K52JU", CXT5066_ASUS),
+ SND_PCI_QUIRK(0x1043, 0x1993, "Asus U50F", CXT5066_ASUS),
SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD),
SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5),
SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5),
@@ -3108,16 +3127,11 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
CXT5066_LAPTOP),
SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5),
SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD),
- SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD),
SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD),
- SND_PCI_QUIRK(0x17aa, 0x21b3, "Thinkpad Edge 13 (197)", CXT5066_IDEAPAD),
- SND_PCI_QUIRK(0x17aa, 0x21b4, "Thinkpad Edge", CXT5066_IDEAPAD),
- SND_PCI_QUIRK(0x17aa, 0x21c8, "Thinkpad Edge 11", CXT5066_IDEAPAD),
+ SND_PCI_QUIRK(0x17aa, 0x21c6, "Thinkpad Edge 13", CXT5066_ASUS),
SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD),
- SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G series", CXT5066_IDEAPAD),
- SND_PCI_QUIRK(0x17aa, 0x390a, "Lenovo S10-3t", CXT5066_IDEAPAD),
- SND_PCI_QUIRK(0x17aa, 0x3938, "Lenovo G series (AMD)", CXT5066_IDEAPAD),
- SND_PCI_QUIRK(0x17aa, 0x3a0d, "ideapad", CXT5066_IDEAPAD),
+ SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G560", CXT5066_ASUS),
+ SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", CXT5066_IDEAPAD), /* Fallback for Lenovos without dock mic */
{}
};
@@ -3138,7 +3152,8 @@ static int patch_cxt5066(struct hda_codec *codec)
spec->multiout.max_channels = 2;
spec->multiout.num_dacs = ARRAY_SIZE(cxt5066_dac_nids);
spec->multiout.dac_nids = cxt5066_dac_nids;
- spec->multiout.dig_out_nid = CXT5066_SPDIF_OUT;
+ conexant_check_dig_outs(codec, cxt5066_digout_pin_nids,
+ ARRAY_SIZE(cxt5066_digout_pin_nids));
spec->num_adc_nids = 1;
spec->adc_nids = cxt5066_adc_nids;
spec->capsrc_nids = cxt5066_capsrc_nids;
@@ -3172,17 +3187,20 @@ static int patch_cxt5066(struct hda_codec *codec)
spec->num_init_verbs++;
spec->dell_automute = 1;
break;
+ case CXT5066_ASUS:
case CXT5066_HP_LAPTOP:
codec->patch_ops.init = cxt5066_init;
- codec->patch_ops.unsol_event = cxt5066_hp_laptop_event;
+ codec->patch_ops.unsol_event = cxt5066_unsol_event;
spec->init_verbs[spec->num_init_verbs] =
cxt5066_init_verbs_hp_laptop;
spec->num_init_verbs++;
- spec->hp_laptop = 1;
+ spec->hp_laptop = board_config == CXT5066_HP_LAPTOP;
+ spec->asus = board_config == CXT5066_ASUS;
spec->mixers[spec->num_mixers++] = cxt5066_mixer_master;
spec->mixers[spec->num_mixers++] = cxt5066_mixers;
/* no S/PDIF out */
- spec->multiout.dig_out_nid = 0;
+ if (board_config == CXT5066_HP_LAPTOP)
+ spec->multiout.dig_out_nid = 0;
/* input source automatically selected */
spec->input_mux = NULL;
spec->port_d_mode = 0;
@@ -3212,7 +3230,7 @@ static int patch_cxt5066(struct hda_codec *codec)
break;
case CXT5066_DELL_VOSTRO:
codec->patch_ops.init = cxt5066_init;
- codec->patch_ops.unsol_event = cxt5066_vostro_event;
+ codec->patch_ops.unsol_event = cxt5066_unsol_event;
spec->init_verbs[0] = cxt5066_init_verbs_vostro;
spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc;
spec->mixers[spec->num_mixers++] = cxt5066_mixers;
@@ -3229,7 +3247,7 @@ static int patch_cxt5066(struct hda_codec *codec)
break;
case CXT5066_IDEAPAD:
codec->patch_ops.init = cxt5066_init;
- codec->patch_ops.unsol_event = cxt5066_ideapad_event;
+ codec->patch_ops.unsol_event = cxt5066_unsol_event;
spec->mixers[spec->num_mixers++] = cxt5066_mixer_master;
spec->mixers[spec->num_mixers++] = cxt5066_mixers;
spec->init_verbs[0] = cxt5066_init_verbs_ideapad;
@@ -3245,7 +3263,7 @@ static int patch_cxt5066(struct hda_codec *codec)
break;
case CXT5066_THINKPAD:
codec->patch_ops.init = cxt5066_init;
- codec->patch_ops.unsol_event = cxt5066_thinkpad_event;
+ codec->patch_ops.unsol_event = cxt5066_unsol_event;
spec->mixers[spec->num_mixers++] = cxt5066_mixer_master;
spec->mixers[spec->num_mixers++] = cxt5066_mixers;
spec->init_verbs[0] = cxt5066_init_verbs_thinkpad;
@@ -3394,7 +3412,7 @@ static void cx_auto_parse_output(struct hda_codec *codec)
}
}
spec->multiout.dac_nids = spec->private_dac_nids;
- spec->multiout.max_channels = nums * 2;
+ spec->multiout.max_channels = spec->multiout.num_dacs * 2;
if (cfg->hp_outs > 0)
spec->auto_mute = 1;
@@ -3422,6 +3440,9 @@ static void cx_auto_hp_automute(struct hda_codec *codec)
AC_VERB_SET_PIN_WIDGET_CONTROL,
present ? 0 : PIN_OUT);
}
+ for (i = 0; !present && i < cfg->line_outs; i++)
+ if (snd_hda_jack_detect(codec, cfg->line_out_pins[i]))
+ present = 1;
for (i = 0; i < cfg->speaker_outs; i++) {
snd_hda_codec_write(codec, cfg->speaker_pins[i], 0,
AC_VERB_SET_PIN_WIDGET_CONTROL,
@@ -3710,9 +3731,9 @@ static int cx_auto_init(struct hda_codec *codec)
return 0;
}
-static int cx_auto_add_volume(struct hda_codec *codec, const char *basename,
+static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename,
const char *dir, int cidx,
- hda_nid_t nid, int hda_dir)
+ hda_nid_t nid, int hda_dir, int amp_idx)
{
static char name[32];
static struct snd_kcontrol_new knew[] = {
@@ -3724,7 +3745,8 @@ static int cx_auto_add_volume(struct hda_codec *codec, const char *basename,
for (i = 0; i < 2; i++) {
struct snd_kcontrol *kctl;
- knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, 3, 0, hda_dir);
+ knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, 3, amp_idx,
+ hda_dir);
knew[i].subdevice = HDA_SUBDEV_AMP_FLAG;
knew[i].index = cidx;
snprintf(name, sizeof(name), "%s%s %s", basename, dir, sfx[i]);
@@ -3740,6 +3762,9 @@ static int cx_auto_add_volume(struct hda_codec *codec, const char *basename,
return 0;
}
+#define cx_auto_add_volume(codec, str, dir, cidx, nid, hda_dir) \
+ cx_auto_add_volume_idx(codec, str, dir, cidx, nid, hda_dir, 0)
+
#define cx_auto_add_pb_volume(codec, nid, str, idx) \
cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT)
@@ -3748,7 +3773,7 @@ static int cx_auto_build_output_controls(struct hda_codec *codec)
struct conexant_spec *spec = codec->spec;
int i, err;
int num_line = 0, num_hp = 0, num_spk = 0;
- static const char *texts[3] = { "Front", "Surround", "CLFE" };
+ static const char * const texts[3] = { "Front", "Surround", "CLFE" };
if (spec->dac_info_filled == 1)
return cx_auto_add_pb_volume(codec, spec->dac_info[0].dac,
@@ -3789,29 +3814,60 @@ static int cx_auto_build_input_controls(struct hda_codec *codec)
struct conexant_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
static const char *prev_label;
- int i, err, cidx;
+ int i, err, cidx, conn_len;
+ hda_nid_t conn[HDA_MAX_CONNECTIONS];
+
+ int multi_adc_volume = 0; /* If the ADC nid has several input volumes */
+ int adc_nid = spec->adc_nids[0];
+
+ conn_len = snd_hda_get_connections(codec, adc_nid, conn,
+ HDA_MAX_CONNECTIONS);
+ if (conn_len < 0)
+ return conn_len;
+
+ multi_adc_volume = cfg->num_inputs > 1 && conn_len > 1;
+ if (!multi_adc_volume) {
+ err = cx_auto_add_volume(codec, "Capture", "", 0, adc_nid,
+ HDA_INPUT);
+ if (err < 0)
+ return err;
+ }
- err = cx_auto_add_volume(codec, "Capture", "", 0, spec->adc_nids[0],
- HDA_INPUT);
- if (err < 0)
- return err;
prev_label = NULL;
cidx = 0;
for (i = 0; i < cfg->num_inputs; i++) {
hda_nid_t nid = cfg->inputs[i].pin;
const char *label;
- if (!(get_wcaps(codec, nid) & AC_WCAP_IN_AMP))
+ int j;
+ int pin_amp = get_wcaps(codec, nid) & AC_WCAP_IN_AMP;
+ if (!pin_amp && !multi_adc_volume)
continue;
+
label = hda_get_autocfg_input_label(codec, cfg, i);
if (label == prev_label)
cidx++;
else
cidx = 0;
prev_label = label;
- err = cx_auto_add_volume(codec, label, " Capture", cidx,
- nid, HDA_INPUT);
- if (err < 0)
- return err;
+
+ if (pin_amp) {
+ err = cx_auto_add_volume(codec, label, " Boost", cidx,
+ nid, HDA_INPUT);
+ if (err < 0)
+ return err;
+ }
+
+ if (!multi_adc_volume)
+ continue;
+ for (j = 0; j < conn_len; j++) {
+ if (conn[j] == nid) {
+ err = cx_auto_add_volume_idx(codec, label,
+ " Capture", cidx, adc_nid, HDA_INPUT, j);
+ if (err < 0)
+ return err;
+ break;
+ }
+ }
}
return 0;
}
@@ -3883,6 +3939,8 @@ static struct hda_codec_preset snd_hda_preset_conexant[] = {
.patch = patch_cxt5066 },
{ .id = 0x14f15069, .name = "CX20585",
.patch = patch_cxt5066 },
+ { .id = 0x14f1506e, .name = "CX20590",
+ .patch = patch_cxt5066 },
{ .id = 0x14f15097, .name = "CX20631",
.patch = patch_conexant_auto },
{ .id = 0x14f15098, .name = "CX20632",
@@ -3909,6 +3967,7 @@ MODULE_ALIAS("snd-hda-codec-id:14f15066");
MODULE_ALIAS("snd-hda-codec-id:14f15067");
MODULE_ALIAS("snd-hda-codec-id:14f15068");
MODULE_ALIAS("snd-hda-codec-id:14f15069");
+MODULE_ALIAS("snd-hda-codec-id:14f1506e");
MODULE_ALIAS("snd-hda-codec-id:14f15097");
MODULE_ALIAS("snd-hda-codec-id:14f15098");
MODULE_ALIAS("snd-hda-codec-id:14f150a1");
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 31df7747990..ec0fa2dd0a2 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -31,10 +31,15 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/moduleparam.h>
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
+static bool static_hdmi_pcm;
+module_param(static_hdmi_pcm, bool, 0644);
+MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
+
/*
* The HDMI/DisplayPort configuration can be highly dynamic. A graphics device
* could support two independent pipes, each of them can be connected to one or
@@ -637,6 +642,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
hdmi_ai->ver = 0x01;
hdmi_ai->len = 0x0a;
hdmi_ai->CC02_CT47 = channels - 1;
+ hdmi_ai->CA = ca;
hdmi_checksum_audio_infoframe(hdmi_ai);
} else if (spec->sink_eld[i].conn_type == 1) { /* DisplayPort */
struct dp_audio_infoframe *dp_ai;
@@ -646,6 +652,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
dp_ai->len = 0x1b;
dp_ai->ver = 0x11 << 2;
dp_ai->CC02_CT47 = channels - 1;
+ dp_ai->CA = ca;
} else {
snd_printd("HDMI: unknown connection type at pin %d\n",
pin_nid);
@@ -812,6 +819,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
struct hdmi_spec *spec = codec->spec;
struct hdmi_eld *eld;
struct hda_pcm_stream *codec_pars;
+ struct snd_pcm_runtime *runtime = substream->runtime;
unsigned int idx;
for (idx = 0; idx < spec->num_cvts; idx++)
@@ -827,7 +835,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
*codec_pars = *hinfo;
eld = &spec->sink_eld[idx];
- if (eld->sad_count > 0) {
+ if (!static_hdmi_pcm && eld->eld_valid && eld->sad_count > 0) {
hdmi_eld_update_pcm_info(eld, hinfo, codec_pars);
if (hinfo->channels_min > hinfo->channels_max ||
!hinfo->rates || !hinfo->formats)
@@ -839,6 +847,14 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
hinfo->formats = codec_pars->formats;
hinfo->maxbps = codec_pars->maxbps;
}
+ /* store the updated parameters */
+ runtime->hw.channels_min = hinfo->channels_min;
+ runtime->hw.channels_max = hinfo->channels_max;
+ runtime->hw.formats = hinfo->formats;
+ runtime->hw.rates = hinfo->rates;
+
+ snd_pcm_hw_constraint_step(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS, 2);
return 0;
}
@@ -904,23 +920,28 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
spec->pin[spec->num_pins] = pin_nid;
spec->num_pins++;
- /*
- * It is assumed that converter nodes come first in the node list and
- * hence have been registered and usable now.
- */
return hdmi_read_pin_conn(codec, pin_nid);
}
static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t nid)
{
+ int i, found_pin = 0;
struct hdmi_spec *spec = codec->spec;
- if (spec->num_cvts >= MAX_HDMI_CVTS) {
- snd_printk(KERN_WARNING
- "HDMI: no space for converter %d\n", nid);
- return -E2BIG;
+ for (i = 0; i < spec->num_pins; i++)
+ if (nid == spec->pin_cvt[i]) {
+ found_pin = 1;
+ break;
+ }
+
+ if (!found_pin) {
+ snd_printdd("HDMI: Skipping node %d (no connection)\n", nid);
+ return -EINVAL;
}
+ if (snd_BUG_ON(spec->num_cvts >= MAX_HDMI_CVTS))
+ return -E2BIG;
+
spec->cvt[spec->num_cvts] = nid;
spec->num_cvts++;
@@ -931,6 +952,8 @@ static int hdmi_parse_codec(struct hda_codec *codec)
{
hda_nid_t nid;
int i, nodes;
+ int num_tmp_cvts = 0;
+ hda_nid_t tmp_cvt[MAX_HDMI_CVTS];
nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid);
if (!nid || nodes < 0) {
@@ -941,6 +964,7 @@ static int hdmi_parse_codec(struct hda_codec *codec)
for (i = 0; i < nodes; i++, nid++) {
unsigned int caps;
unsigned int type;
+ unsigned int config;
caps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP);
type = get_wcaps_type(caps);
@@ -950,17 +974,32 @@ static int hdmi_parse_codec(struct hda_codec *codec)
switch (type) {
case AC_WID_AUD_OUT:
- hdmi_add_cvt(codec, nid);
+ if (num_tmp_cvts >= MAX_HDMI_CVTS) {
+ snd_printk(KERN_WARNING
+ "HDMI: no space for converter %d\n", nid);
+ continue;
+ }
+ tmp_cvt[num_tmp_cvts] = nid;
+ num_tmp_cvts++;
break;
case AC_WID_PIN:
caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP)))
continue;
+
+ config = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_CONFIG_DEFAULT, 0);
+ if (get_defcfg_connect(config) == AC_JACK_PORT_NONE)
+ continue;
+
hdmi_add_pin(codec, nid);
break;
}
}
+ for (i = 0; i < num_tmp_cvts; i++)
+ hdmi_add_cvt(codec, tmp_cvt[i]);
+
/*
* G45/IbexPeak don't support EPSS: the unsolicited pin hot plug event
* can be lost and presence sense verb will become inaccurate if the
@@ -1165,11 +1204,56 @@ static int nvhdmi_7x_init(struct hda_codec *codec)
return 0;
}
+static unsigned int channels_2_6_8[] = {
+ 2, 6, 8
+};
+
+static unsigned int channels_2_8[] = {
+ 2, 8
+};
+
+static struct snd_pcm_hw_constraint_list hw_constraints_2_6_8_channels = {
+ .count = ARRAY_SIZE(channels_2_6_8),
+ .list = channels_2_6_8,
+ .mask = 0,
+};
+
+static struct snd_pcm_hw_constraint_list hw_constraints_2_8_channels = {
+ .count = ARRAY_SIZE(channels_2_8),
+ .list = channels_2_8,
+ .mask = 0,
+};
+
static int simple_playback_pcm_open(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
struct hdmi_spec *spec = codec->spec;
+ struct snd_pcm_hw_constraint_list *hw_constraints_channels = NULL;
+
+ switch (codec->preset->id) {
+ case 0x10de0002:
+ case 0x10de0003:
+ case 0x10de0005:
+ case 0x10de0006:
+ hw_constraints_channels = &hw_constraints_2_8_channels;
+ break;
+ case 0x10de0007:
+ hw_constraints_channels = &hw_constraints_2_6_8_channels;
+ break;
+ default:
+ break;
+ }
+
+ if (hw_constraints_channels != NULL) {
+ snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ hw_constraints_channels);
+ } else {
+ snd_pcm_hw_constraint_step(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS, 2);
+ }
+
return snd_hda_multi_out_dig_open(codec, &spec->multiout);
}
@@ -1532,7 +1616,7 @@ static struct hda_codec_preset snd_hda_preset_hdmi[] = {
{ .id = 0x1002793c, .name = "RS600 HDMI", .patch = patch_atihdmi },
{ .id = 0x10027919, .name = "RS600 HDMI", .patch = patch_atihdmi },
{ .id = 0x1002791a, .name = "RS690/780 HDMI", .patch = patch_atihdmi },
-{ .id = 0x1002aa01, .name = "R6xx HDMI", .patch = patch_atihdmi },
+{ .id = 0x1002aa01, .name = "R6xx HDMI", .patch = patch_generic_hdmi },
{ .id = 0x10951390, .name = "SiI1390 HDMI", .patch = patch_generic_hdmi },
{ .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_generic_hdmi },
{ .id = 0x17e80047, .name = "Chrontel HDMI", .patch = patch_generic_hdmi },
@@ -1550,6 +1634,9 @@ static struct hda_codec_preset snd_hda_preset_hdmi[] = {
{ .id = 0x10de0012, .name = "GPU 12 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
{ .id = 0x10de0013, .name = "GPU 13 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
{ .id = 0x10de0014, .name = "GPU 14 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0015, .name = "GPU 15 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0016, .name = "GPU 16 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+/* 17 is known to be absent */
{ .id = 0x10de0018, .name = "GPU 18 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
{ .id = 0x10de0019, .name = "GPU 19 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
{ .id = 0x10de001a, .name = "GPU 1a HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
@@ -1592,6 +1679,8 @@ MODULE_ALIAS("snd-hda-codec-id:10de0011");
MODULE_ALIAS("snd-hda-codec-id:10de0012");
MODULE_ALIAS("snd-hda-codec-id:10de0013");
MODULE_ALIAS("snd-hda-codec-id:10de0014");
+MODULE_ALIAS("snd-hda-codec-id:10de0015");
+MODULE_ALIAS("snd-hda-codec-id:10de0016");
MODULE_ALIAS("snd-hda-codec-id:10de0018");
MODULE_ALIAS("snd-hda-codec-id:10de0019");
MODULE_ALIAS("snd-hda-codec-id:10de001a");
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 552a09e9211..4261bb8eec1 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -231,7 +231,6 @@ enum {
ALC888_ACER_ASPIRE_8930G,
ALC888_ACER_ASPIRE_7730G,
ALC883_MEDION,
- ALC883_MEDION_MD2,
ALC883_MEDION_WIM2160,
ALC883_LAPTOP_EAPD,
ALC883_LENOVO_101E_2ch,
@@ -304,6 +303,8 @@ struct alc_customize_define {
unsigned int fixup:1; /* Means that this sku is set by driver, not read from hw */
};
+struct alc_fixup;
+
struct alc_spec {
/* codec parameterization */
struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
@@ -405,6 +406,11 @@ struct alc_spec {
/* for PLL fix */
hda_nid_t pll_nid;
unsigned int pll_coef_idx, pll_coef_bit;
+
+ /* fix-up list */
+ int fixup_id;
+ const struct alc_fixup *fixup_list;
+ const char *fixup_name;
};
/*
@@ -1127,11 +1133,8 @@ static void alc_automute_speaker(struct hda_codec *codec, int pinctl)
nid = spec->autocfg.hp_pins[i];
if (!nid)
break;
- if (snd_hda_jack_detect(codec, nid)) {
- spec->jack_present = 1;
- break;
- }
- alc_report_jack(codec, spec->autocfg.hp_pins[i]);
+ alc_report_jack(codec, nid);
+ spec->jack_present |= snd_hda_jack_detect(codec, nid);
}
mute = spec->jack_present ? HDA_AMP_MUTE : 0;
@@ -1678,48 +1681,139 @@ struct alc_pincfg {
u32 val;
};
+struct alc_model_fixup {
+ const int id;
+ const char *name;
+};
+
struct alc_fixup {
- unsigned int sku;
- const struct alc_pincfg *pins;
- const struct hda_verb *verbs;
+ int type;
+ bool chained;
+ int chain_id;
+ union {
+ unsigned int sku;
+ const struct alc_pincfg *pins;
+ const struct hda_verb *verbs;
+ void (*func)(struct hda_codec *codec,
+ const struct alc_fixup *fix,
+ int action);
+ } v;
};
-static void alc_pick_fixup(struct hda_codec *codec,
- const struct snd_pci_quirk *quirk,
- const struct alc_fixup *fix,
- int pre_init)
-{
- const struct alc_pincfg *cfg;
- struct alc_spec *spec;
+enum {
+ ALC_FIXUP_INVALID,
+ ALC_FIXUP_SKU,
+ ALC_FIXUP_PINS,
+ ALC_FIXUP_VERBS,
+ ALC_FIXUP_FUNC,
+};
- quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
- if (!quirk)
- return;
- fix += quirk->value;
- cfg = fix->pins;
- if (pre_init && fix->sku) {
+enum {
+ ALC_FIXUP_ACT_PRE_PROBE,
+ ALC_FIXUP_ACT_PROBE,
+ ALC_FIXUP_ACT_INIT,
+};
+
+static void alc_apply_fixup(struct hda_codec *codec, int action)
+{
+ struct alc_spec *spec = codec->spec;
+ int id = spec->fixup_id;
#ifdef CONFIG_SND_DEBUG_VERBOSE
- snd_printdd(KERN_INFO "hda_codec: %s: Apply sku override for %s\n",
- codec->chip_name, quirk->name);
+ const char *modelname = spec->fixup_name;
#endif
- spec = codec->spec;
- spec->cdefine.sku_cfg = fix->sku;
- spec->cdefine.fixup = 1;
+ int depth = 0;
+
+ if (!spec->fixup_list)
+ return;
+
+ while (id >= 0) {
+ const struct alc_fixup *fix = spec->fixup_list + id;
+ const struct alc_pincfg *cfg;
+
+ switch (fix->type) {
+ case ALC_FIXUP_SKU:
+ if (action != ALC_FIXUP_ACT_PRE_PROBE || !fix->v.sku)
+ break;;
+ snd_printdd(KERN_INFO "hda_codec: %s: "
+ "Apply sku override for %s\n",
+ codec->chip_name, modelname);
+ spec->cdefine.sku_cfg = fix->v.sku;
+ spec->cdefine.fixup = 1;
+ break;
+ case ALC_FIXUP_PINS:
+ cfg = fix->v.pins;
+ if (action != ALC_FIXUP_ACT_PRE_PROBE || !cfg)
+ break;
+ snd_printdd(KERN_INFO "hda_codec: %s: "
+ "Apply pincfg for %s\n",
+ codec->chip_name, modelname);
+ for (; cfg->nid; cfg++)
+ snd_hda_codec_set_pincfg(codec, cfg->nid,
+ cfg->val);
+ break;
+ case ALC_FIXUP_VERBS:
+ if (action != ALC_FIXUP_ACT_PROBE || !fix->v.verbs)
+ break;
+ snd_printdd(KERN_INFO "hda_codec: %s: "
+ "Apply fix-verbs for %s\n",
+ codec->chip_name, modelname);
+ add_verb(codec->spec, fix->v.verbs);
+ break;
+ case ALC_FIXUP_FUNC:
+ if (!fix->v.func)
+ break;
+ snd_printdd(KERN_INFO "hda_codec: %s: "
+ "Apply fix-func for %s\n",
+ codec->chip_name, modelname);
+ fix->v.func(codec, fix, action);
+ break;
+ default:
+ snd_printk(KERN_ERR "hda_codec: %s: "
+ "Invalid fixup type %d\n",
+ codec->chip_name, fix->type);
+ break;
+ }
+ if (!fix[id].chained)
+ break;
+ if (++depth > 10)
+ break;
+ id = fix[id].chain_id;
}
- if (pre_init && cfg) {
-#ifdef CONFIG_SND_DEBUG_VERBOSE
- snd_printdd(KERN_INFO "hda_codec: %s: Apply pincfg for %s\n",
- codec->chip_name, quirk->name);
-#endif
- for (; cfg->nid; cfg++)
- snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
+}
+
+static void alc_pick_fixup(struct hda_codec *codec,
+ const struct alc_model_fixup *models,
+ const struct snd_pci_quirk *quirk,
+ const struct alc_fixup *fixlist)
+{
+ struct alc_spec *spec = codec->spec;
+ int id = -1;
+ const char *name = NULL;
+
+ if (codec->modelname && models) {
+ while (models->name) {
+ if (!strcmp(codec->modelname, models->name)) {
+ id = models->id;
+ name = models->name;
+ break;
+ }
+ models++;
+ }
}
- if (!pre_init && fix->verbs) {
+ if (id < 0) {
+ quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
+ if (quirk) {
+ id = quirk->value;
#ifdef CONFIG_SND_DEBUG_VERBOSE
- snd_printdd(KERN_INFO "hda_codec: %s: Apply fix-verbs for %s\n",
- codec->chip_name, quirk->name);
+ name = quirk->name;
#endif
- add_verb(codec->spec, fix->verbs);
+ }
+ }
+
+ spec->fixup_id = id;
+ if (id >= 0) {
+ spec->fixup_list = fixlist;
+ spec->fixup_name = name;
}
}
@@ -1981,6 +2075,7 @@ static struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
{ }
};
@@ -2120,17 +2215,17 @@ static struct hda_input_mux alc888_acer_aspire_6530_sources[2] = {
{
.num_items = 5,
.items = {
- { "Ext Mic", 0x0 },
+ { "Mic", 0x0 },
{ "Line In", 0x2 },
{ "CD", 0x4 },
{ "Input Mix", 0xa },
- { "Int Mic", 0xb },
+ { "Internal Mic", 0xb },
},
},
{
.num_items = 4,
.items = {
- { "Ext Mic", 0x0 },
+ { "Mic", 0x0 },
{ "Line In", 0x2 },
{ "CD", 0x4 },
{ "Input Mix", 0xa },
@@ -2187,11 +2282,34 @@ static struct snd_kcontrol_new alc888_base_mixer[] = {
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
{ } /* end */
};
+static struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0f, 2, 0x0,
+ HDA_OUTPUT),
+ HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0f, 2, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0f, 1, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0f, 1, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("Side Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Side Playback Switch", 0x0e, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ { } /* end */
+};
+
+
static struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = {
HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
@@ -2205,7 +2323,7 @@ static struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = {
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
{ } /* end */
};
@@ -2796,10 +2914,10 @@ static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
- HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
{ } /* end */
};
@@ -2820,7 +2938,7 @@ static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
/*
* slave controls for virtual master
*/
-static const char *alc_slave_vols[] = {
+static const char * const alc_slave_vols[] = {
"Front Playback Volume",
"Surround Playback Volume",
"Center Playback Volume",
@@ -2834,7 +2952,7 @@ static const char *alc_slave_vols[] = {
NULL,
};
-static const char *alc_slave_sws[] = {
+static const char * const alc_slave_sws[] = {
"Front Playback Switch",
"Surround Playback Switch",
"Center Playback Switch",
@@ -3307,7 +3425,7 @@ static struct hda_verb alc880_beep_init_verbs[] = {
};
/* auto-toggle front mic */
-static void alc880_uniwill_mic_automute(struct hda_codec *codec)
+static void alc88x_simple_mic_automute(struct hda_codec *codec)
{
unsigned int present;
unsigned char bits;
@@ -3329,7 +3447,7 @@ static void alc880_uniwill_setup(struct hda_codec *codec)
static void alc880_uniwill_init_hook(struct hda_codec *codec)
{
alc_automute_amp(codec);
- alc880_uniwill_mic_automute(codec);
+ alc88x_simple_mic_automute(codec);
}
static void alc880_uniwill_unsol_event(struct hda_codec *codec,
@@ -3340,7 +3458,7 @@ static void alc880_uniwill_unsol_event(struct hda_codec *codec,
*/
switch (res >> 28) {
case ALC880_MIC_EVENT:
- alc880_uniwill_mic_automute(codec);
+ alc88x_simple_mic_automute(codec);
break;
default:
alc_automute_amp_unsol_event(codec, res);
@@ -3815,6 +3933,8 @@ static int alc_init(struct hda_codec *codec)
if (spec->init_hook)
spec->init_hook(codec);
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT);
+
hda_call_check_power_status(codec, 0x01);
return 0;
}
@@ -4513,7 +4633,7 @@ static struct hda_verb alc880_test_init_verbs[] = {
/*
*/
-static const char *alc880_models[ALC880_MODEL_LAST] = {
+static const char * const alc880_models[ALC880_MODEL_LAST] = {
[ALC880_3ST] = "3stack",
[ALC880_TCL_S700] = "tcl",
[ALC880_3ST_DIG] = "3stack-digout",
@@ -5023,13 +5143,33 @@ static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
return 0;
}
+static const char *alc_get_line_out_pfx(const struct auto_pin_cfg *cfg,
+ bool can_be_master)
+{
+ if (!cfg->hp_outs && !cfg->speaker_outs && can_be_master)
+ return "Master";
+
+ switch (cfg->line_out_type) {
+ case AUTO_PIN_SPEAKER_OUT:
+ return "Speaker";
+ case AUTO_PIN_HP_OUT:
+ return "Headphone";
+ default:
+ if (cfg->line_outs == 1)
+ return "PCM";
+ break;
+ }
+ return NULL;
+}
+
/* add playback controls from the parsed DAC table */
static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
const struct auto_pin_cfg *cfg)
{
- static const char *chname[4] = {
+ static const char * const chname[4] = {
"Front", "Surround", NULL /*CLFE*/, "Side"
};
+ const char *pfx = alc_get_line_out_pfx(cfg, false);
hda_nid_t nid;
int i, err;
@@ -5037,7 +5177,7 @@ static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
if (!spec->multiout.dac_nids[i])
continue;
nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
- if (i == 2) {
+ if (!pfx && i == 2) {
/* Center/LFE */
err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
"Center",
@@ -5064,18 +5204,17 @@ static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
if (err < 0)
return err;
} else {
- const char *pfx;
- if (cfg->line_outs == 1 &&
- cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
- pfx = "Speaker";
- else
- pfx = chname[i];
- err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
+ const char *name = pfx;
+ if (!name)
+ name = chname[i];
+ err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
+ name, i,
HDA_COMPOSE_AMP_VAL(nid, 3, 0,
HDA_OUTPUT));
if (err < 0)
return err;
- err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
+ err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
+ name, i,
HDA_COMPOSE_AMP_VAL(nid, 3, 2,
HDA_INPUT));
if (err < 0)
@@ -5155,7 +5294,8 @@ static int alc_auto_create_input_ctls(struct hda_codec *codec,
{
struct alc_spec *spec = codec->spec;
struct hda_input_mux *imux = &spec->private_imux[0];
- int i, err, idx, type, type_idx = 0;
+ int i, err, idx, type_idx = 0;
+ const char *prev_label = NULL;
for (i = 0; i < cfg->num_inputs; i++) {
hda_nid_t pin;
@@ -5165,12 +5305,13 @@ static int alc_auto_create_input_ctls(struct hda_codec *codec,
if (!alc_is_input_pin(codec, pin))
continue;
- type = cfg->inputs[i].type;
- if (i > 0 && type == cfg->inputs[i - 1].type)
+ label = hda_get_autocfg_input_label(codec, cfg, i);
+ if (prev_label && !strcmp(label, prev_label))
type_idx++;
else
type_idx = 0;
- label = hda_get_autocfg_input_label(codec, cfg, i);
+ prev_label = label;
+
if (mixer) {
idx = get_connection_index(codec, mixer, pin);
if (idx >= 0) {
@@ -7023,7 +7164,8 @@ enum {
static const struct alc_fixup alc260_fixups[] = {
[PINFIX_HP_DC5750] = {
- .pins = (const struct alc_pincfg[]) {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
{ 0x11, 0x90130110 }, /* speaker */
{ }
}
@@ -7038,7 +7180,7 @@ static struct snd_pci_quirk alc260_fixup_tbl[] = {
/*
* ALC260 configurations
*/
-static const char *alc260_models[ALC260_MODEL_LAST] = {
+static const char * const alc260_models[ALC260_MODEL_LAST] = {
[ALC260_BASIC] = "basic",
[ALC260_HP] = "hp",
[ALC260_HP_3013] = "hp-3013",
@@ -7234,8 +7376,10 @@ static int patch_alc260(struct hda_codec *codec)
board_config = ALC260_AUTO;
}
- if (board_config == ALC260_AUTO)
- alc_pick_fixup(codec, alc260_fixup_tbl, alc260_fixups, 1);
+ if (board_config == ALC260_AUTO) {
+ alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups);
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
+ }
if (board_config == ALC260_AUTO) {
/* automatic parse from the BIOS config */
@@ -7283,8 +7427,7 @@ static int patch_alc260(struct hda_codec *codec)
set_capture_mixer(codec);
set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
- if (board_config == ALC260_AUTO)
- alc_pick_fixup(codec, alc260_fixup_tbl, alc260_fixups, 0);
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
spec->vmaster_nid = 0x08;
@@ -7406,7 +7549,7 @@ static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
.num_items = 4,
.items = {
{ "Mic", 0x0 },
- { "Int Mic", 0x1 },
+ { "Internal Mic", 0x1 },
{ "Line", 0x2 },
{ "CD", 0x4 },
},
@@ -7416,7 +7559,7 @@ static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
.num_items = 2,
.items = {
{ "Mic", 0x0 },
- { "Int Mic", 0x1 },
+ { "Internal Mic", 0x1 },
},
};
@@ -7851,10 +7994,10 @@ static struct snd_kcontrol_new alc882_base_mixer[] = {
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
{ } /* end */
};
@@ -7878,8 +8021,8 @@ static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
- HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT),
{ } /* end */
};
@@ -7896,8 +8039,8 @@ static struct snd_kcontrol_new alc885_mb5_mixer[] = {
HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
- HDA_CODEC_VOLUME("Line Boost", 0x15, 0x00, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x19, 0x00, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0x00, HDA_INPUT),
{ } /* end */
};
@@ -7912,7 +8055,7 @@ static struct snd_kcontrol_new alc885_macmini3_mixer[] = {
HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
- HDA_CODEC_VOLUME("Line Boost", 0x15, 0x00, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT),
{ } /* end */
};
@@ -7931,7 +8074,7 @@ static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
{ } /* end */
};
@@ -7946,10 +8089,10 @@ static struct snd_kcontrol_new alc882_targa_mixer[] = {
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
{ } /* end */
};
@@ -7969,7 +8112,7 @@ static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
{ } /* end */
};
@@ -7982,7 +8125,7 @@ static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
{ } /* end */
};
@@ -8763,10 +8906,10 @@ static struct snd_kcontrol_new alc883_mitac_mixer[] = {
HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
{ } /* end */
};
@@ -8777,11 +8920,11 @@ static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
- HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
{ } /* end */
};
@@ -8791,11 +8934,11 @@ static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
- HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
{ } /* end */
};
@@ -8808,10 +8951,10 @@ static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
{ } /* end */
};
@@ -8831,10 +8974,10 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
{ } /* end */
};
@@ -8855,10 +8998,10 @@ static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
{ } /* end */
};
@@ -8879,10 +9022,10 @@ static struct snd_kcontrol_new alc885_8ch_intel_mixer[] = {
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x1b, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x1b, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
{ } /* end */
};
@@ -8902,10 +9045,10 @@ static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
{ } /* end */
};
@@ -8926,7 +9069,7 @@ static struct snd_kcontrol_new alc883_targa_mixer[] = {
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
{ } /* end */
};
@@ -8939,20 +9082,20 @@ static struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
- HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
{ } /* end */
};
static struct snd_kcontrol_new alc883_targa_8ch_mixer[] = {
HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
- HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
- HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
{ } /* end */
};
@@ -8963,7 +9106,7 @@ static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
{ } /* end */
};
@@ -8976,21 +9119,8 @@ static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
- { } /* end */
-};
-
-static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
- HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
- HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
{ } /* end */
};
@@ -9037,7 +9167,7 @@ static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
{ } /* end */
};
@@ -9050,7 +9180,7 @@ static struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = {
HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
{ } /* end */
};
@@ -9072,10 +9202,10 @@ static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
{ } /* end */
};
@@ -9096,8 +9226,8 @@ static struct snd_kcontrol_new alc889A_mb31_mixer[] = {
HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT),
HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT),
/* Boost mixers */
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
- HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT),
/* Input mixers */
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
@@ -9111,7 +9241,7 @@ static struct snd_kcontrol_new alc883_vaiott_mixer[] = {
HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
{ } /* end */
};
@@ -9141,7 +9271,7 @@ static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
{ } /* end */
};
@@ -9182,16 +9312,6 @@ static void alc883_mitac_setup(struct hda_codec *codec)
spec->autocfg.speaker_pins[1] = 0x17;
}
-/* auto-toggle front mic */
-/*
-static void alc883_mitac_mic_automute(struct hda_codec *codec)
-{
- unsigned char bits = snd_hda_jack_detect(codec, 0x18) ? HDA_AMP_MUTE : 0;
-
- snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
-}
-*/
-
static struct hda_verb alc883_mitac_verbs[] = {
/* HP */
{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
@@ -9435,18 +9555,8 @@ static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
alc888_lenovo_ms7195_rca_automute(codec);
}
-static struct hda_verb alc883_medion_md2_verbs[] = {
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-
- {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- { } /* end */
-};
-
/* toggle speaker-output according to the hp-jack state */
-static void alc883_medion_md2_setup(struct hda_codec *codec)
+static void alc883_lenovo_nb0763_setup(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
@@ -9458,15 +9568,6 @@ static void alc883_medion_md2_setup(struct hda_codec *codec)
#define alc883_targa_init_hook alc882_targa_init_hook
#define alc883_targa_unsol_event alc882_targa_unsol_event
-static void alc883_clevo_m720_mic_automute(struct hda_codec *codec)
-{
- unsigned int present;
-
- present = snd_hda_jack_detect(codec, 0x18);
- snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
- HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-}
-
static void alc883_clevo_m720_setup(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
@@ -9478,7 +9579,7 @@ static void alc883_clevo_m720_setup(struct hda_codec *codec)
static void alc883_clevo_m720_init_hook(struct hda_codec *codec)
{
alc_automute_amp(codec);
- alc883_clevo_m720_mic_automute(codec);
+ alc88x_simple_mic_automute(codec);
}
static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
@@ -9486,7 +9587,7 @@ static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
{
switch (res >> 26) {
case ALC880_MIC_EVENT:
- alc883_clevo_m720_mic_automute(codec);
+ alc88x_simple_mic_automute(codec);
break;
default:
alc_automute_amp_unsol_event(codec, res);
@@ -9702,7 +9803,7 @@ static hda_nid_t alc1200_slave_dig_outs[] = {
/*
* configuration and preset
*/
-static const char *alc882_models[ALC882_MODEL_LAST] = {
+static const char * const alc882_models[ALC882_MODEL_LAST] = {
[ALC882_3ST_DIG] = "3stack-dig",
[ALC882_6ST_DIG] = "6stack-dig",
[ALC882_ARIMA] = "arima",
@@ -9731,7 +9832,6 @@ static const char *alc882_models[ALC882_MODEL_LAST] = {
[ALC888_ACER_ASPIRE_8930G] = "acer-aspire-8930g",
[ALC888_ACER_ASPIRE_7730G] = "acer-aspire-7730g",
[ALC883_MEDION] = "medion",
- [ALC883_MEDION_MD2] = "medion-md2",
[ALC883_MEDION_WIM2160] = "medion-wim2160",
[ALC883_LAPTOP_EAPD] = "laptop-eapd",
[ALC883_LENOVO_101E_2ch] = "lenovo-101e",
@@ -10279,7 +10379,7 @@ static struct alc_config_preset alc882_presets[] = {
.init_hook = alc_automute_amp,
},
[ALC888_ACER_ASPIRE_4930G] = {
- .mixers = { alc888_base_mixer,
+ .mixers = { alc888_acer_aspire_4930g_mixer,
alc883_chmode_mixer },
.init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
alc888_acer_aspire_4930g_verbs },
@@ -10379,19 +10479,6 @@ static struct alc_config_preset alc882_presets[] = {
.channel_mode = alc883_sixstack_modes,
.input_mux = &alc883_capture_source,
},
- [ALC883_MEDION_MD2] = {
- .mixers = { alc883_medion_md2_mixer},
- .init_verbs = { alc883_init_verbs, alc883_medion_md2_verbs},
- .num_dacs = ARRAY_SIZE(alc883_dac_nids),
- .dac_nids = alc883_dac_nids,
- .dig_out_nid = ALC883_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
- .channel_mode = alc883_3ST_2ch_modes,
- .input_mux = &alc883_capture_source,
- .unsol_event = alc_automute_amp_unsol_event,
- .setup = alc883_medion_md2_setup,
- .init_hook = alc_automute_amp,
- },
[ALC883_MEDION_WIM2160] = {
.mixers = { alc883_medion_wim2160_mixer },
.init_verbs = { alc883_init_verbs, alc883_medion_wim2160_verbs },
@@ -10468,7 +10555,7 @@ static struct alc_config_preset alc882_presets[] = {
.need_dac_fix = 1,
.input_mux = &alc883_lenovo_nb0763_capture_source,
.unsol_event = alc_automute_amp_unsol_event,
- .setup = alc883_medion_md2_setup,
+ .setup = alc883_lenovo_nb0763_setup,
.init_hook = alc_automute_amp,
},
[ALC888_LENOVO_MS7195_DIG] = {
@@ -10667,7 +10754,8 @@ enum {
static const struct alc_fixup alc882_fixups[] = {
[PINFIX_ABIT_AW9D_MAX] = {
- .pins = (const struct alc_pincfg[]) {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
{ 0x15, 0x01080104 }, /* side */
{ 0x16, 0x01011012 }, /* rear */
{ 0x17, 0x01016011 }, /* clfe */
@@ -10675,13 +10763,15 @@ static const struct alc_fixup alc882_fixups[] = {
}
},
[PINFIX_PB_M5210] = {
- .verbs = (const struct hda_verb[]) {
+ .type = ALC_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
{ 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
{}
}
},
[PINFIX_ACER_ASPIRE_7736] = {
- .sku = ALC_FIXUP_SKU_IGNORE,
+ .type = ALC_FIXUP_SKU,
+ .v.sku = ALC_FIXUP_SKU_IGNORE,
},
};
@@ -10830,25 +10920,30 @@ static int alc_auto_add_mic_boost(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
- int i, err, type;
+ int i, err;
int type_idx = 0;
hda_nid_t nid;
+ const char *prev_label = NULL;
for (i = 0; i < cfg->num_inputs; i++) {
if (cfg->inputs[i].type > AUTO_PIN_MIC)
break;
nid = cfg->inputs[i].pin;
if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
- char label[32];
- type = cfg->inputs[i].type;
- if (i > 0 && type == cfg->inputs[i - 1].type)
+ const char *label;
+ char boost_label[32];
+
+ label = hda_get_autocfg_input_label(codec, cfg, i);
+ if (prev_label && !strcmp(label, prev_label))
type_idx++;
else
type_idx = 0;
- snprintf(label, sizeof(label), "%s Boost",
- hda_get_autocfg_input_label(codec, cfg, i));
- err = add_control(spec, ALC_CTL_WIDGET_VOL, label,
- type_idx,
+ prev_label = label;
+
+ snprintf(boost_label, sizeof(boost_label),
+ "%s Boost Volume", label);
+ err = add_control(spec, ALC_CTL_WIDGET_VOL,
+ boost_label, type_idx,
HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
if (err < 0)
return err;
@@ -10962,8 +11057,10 @@ static int patch_alc882(struct hda_codec *codec)
board_config = ALC882_AUTO;
}
- if (board_config == ALC882_AUTO)
- alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 1);
+ if (board_config == ALC882_AUTO) {
+ alc_pick_fixup(codec, NULL, alc882_fixup_tbl, alc882_fixups);
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
+ }
alc_auto_parse_customize_define(codec);
@@ -11039,8 +11136,7 @@ static int patch_alc882(struct hda_codec *codec)
if (has_cdefine_beep(codec))
set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
- if (board_config == ALC882_AUTO)
- alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 0);
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
spec->vmaster_nid = 0x0c;
@@ -11090,10 +11186,10 @@ static struct snd_kcontrol_new alc262_base_mixer[] = {
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
@@ -11194,10 +11290,10 @@ static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
HDA_OUTPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
@@ -11219,7 +11315,7 @@ static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
HDA_OUTPUT),
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x1a, 0, HDA_INPUT),
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
@@ -11230,7 +11326,7 @@ static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Rear Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Rear Mic Boost Volume", 0x18, 0, HDA_INPUT),
{ } /* end */
};
@@ -11250,7 +11346,7 @@ static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
{ } /* end */
};
@@ -11357,10 +11453,10 @@ static struct snd_kcontrol_new alc262_hippo_mixer[] = {
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
{ } /* end */
};
@@ -11374,10 +11470,10 @@ static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
{ } /* end */
};
@@ -11445,10 +11541,10 @@ static struct snd_kcontrol_new alc262_tyan_mixer[] = {
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
{ } /* end */
};
@@ -11632,7 +11728,7 @@ static struct snd_kcontrol_new alc262_nec_mixer[] = {
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
@@ -11687,7 +11783,7 @@ static struct hda_input_mux alc262_fujitsu_capture_source = {
.num_items = 3,
.items = {
{ "Mic", 0x0 },
- { "Int Mic", 0x1 },
+ { "Internal Mic", 0x1 },
{ "CD", 0x4 },
},
};
@@ -11839,12 +11935,12 @@ static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
},
HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
- HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
{ } /* end */
};
@@ -11875,12 +11971,12 @@ static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
},
HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
- HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
{ } /* end */
};
@@ -11889,10 +11985,10 @@ static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
ALC262_HIPPO_MASTER_SWITCH,
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
{ } /* end */
};
@@ -11918,8 +12014,8 @@ static struct snd_kcontrol_new alc262_ultra_mixer[] = {
HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
- HDA_CODEC_VOLUME("Headphone Mic Boost", 0x15, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Headphone Mic Boost Volume", 0x15, 0, HDA_INPUT),
{ } /* end */
};
@@ -12089,13 +12185,8 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
spec->multiout.dac_nids = spec->private_dac_nids;
spec->multiout.dac_nids[0] = 2;
- if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
- pfx = "Master";
- else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
- pfx = "Speaker";
- else if (cfg->line_out_type == AUTO_PIN_HP_OUT)
- pfx = "Headphone";
- else
+ pfx = alc_get_line_out_pfx(cfg, true);
+ if (!pfx)
pfx = "Front";
for (i = 0; i < 2; i++) {
err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[i], pfx, i);
@@ -12435,19 +12526,14 @@ enum {
static const struct alc_fixup alc262_fixups[] = {
[PINFIX_FSC_H270] = {
- .pins = (const struct alc_pincfg[]) {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
{ 0x14, 0x99130110 }, /* speaker */
{ 0x15, 0x0221142f }, /* front HP */
{ 0x1b, 0x0121141f }, /* rear HP */
{ }
}
},
- [PINFIX_PB_M5210] = {
- .verbs = (const struct hda_verb[]) {
- { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
- {}
- }
- },
};
static struct snd_pci_quirk alc262_fixup_tbl[] = {
@@ -12537,7 +12623,7 @@ static void alc262_auto_init(struct hda_codec *codec)
/*
* configuration and preset
*/
-static const char *alc262_models[ALC262_MODEL_LAST] = {
+static const char * const alc262_models[ALC262_MODEL_LAST] = {
[ALC262_BASIC] = "basic",
[ALC262_HIPPO] = "hippo",
[ALC262_HIPPO_1] = "hippo_1",
@@ -12565,6 +12651,8 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = {
ALC262_HP_BPC),
SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series",
ALC262_HP_BPC),
+ SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1500, "HP z series",
+ ALC262_HP_BPC),
SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series",
ALC262_HP_BPC),
SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
@@ -12878,8 +12966,10 @@ static int patch_alc262(struct hda_codec *codec)
board_config = ALC262_AUTO;
}
- if (board_config == ALC262_AUTO)
- alc_pick_fixup(codec, alc262_fixup_tbl, alc262_fixups, 1);
+ if (board_config == ALC262_AUTO) {
+ alc_pick_fixup(codec, NULL, alc262_fixup_tbl, alc262_fixups);
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
+ }
if (board_config == ALC262_AUTO) {
/* automatic parse from the BIOS config */
@@ -12949,8 +13039,7 @@ static int patch_alc262(struct hda_codec *codec)
if (!spec->no_analog && has_cdefine_beep(codec))
set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
- if (board_config == ALC262_AUTO)
- alc_pick_fixup(codec, alc262_fixup_tbl, alc262_fixups, 0);
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
spec->vmaster_nid = 0x0c;
@@ -12996,9 +13085,9 @@ static struct snd_kcontrol_new alc268_base_mixer[] = {
HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
- HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
{ }
};
@@ -13007,9 +13096,9 @@ static struct snd_kcontrol_new alc268_toshiba_mixer[] = {
HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
ALC262_HIPPO_MASTER_SWITCH,
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
- HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
{ }
};
@@ -13113,9 +13202,9 @@ static struct snd_kcontrol_new alc268_acer_mixer[] = {
.put = alc268_acer_master_sw_put,
.private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
},
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
- HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
- HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
{ }
};
@@ -13131,8 +13220,8 @@ static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
.put = alc268_acer_master_sw_put,
.private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
},
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
- HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
{ }
};
@@ -13224,8 +13313,8 @@ static struct snd_kcontrol_new alc268_dell_mixer[] = {
HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
- HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
{ }
};
@@ -13258,8 +13347,8 @@ static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
- HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
{ }
};
@@ -13724,7 +13813,7 @@ static void alc268_auto_init(struct hda_codec *codec)
/*
* configuration and preset
*/
-static const char *alc268_models[ALC268_MODEL_LAST] = {
+static const char * const alc268_models[ALC268_MODEL_LAST] = {
[ALC267_QUANTA_IL1] = "quanta-il1",
[ALC268_3ST] = "3stack",
[ALC268_TOSHIBA] = "toshiba",
@@ -14082,10 +14171,10 @@ static struct snd_kcontrol_new alc269_base_mixer[] = {
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
{ } /* end */
@@ -14105,10 +14194,10 @@ static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
},
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
- HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
{ }
};
@@ -14126,13 +14215,13 @@ static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
},
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
- HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
- HDA_CODEC_VOLUME("Dock Mic Boost", 0x1b, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x1b, 0, HDA_INPUT),
{ }
};
@@ -14162,30 +14251,30 @@ static struct snd_kcontrol_new alc269_asus_mixer[] = {
static struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = {
HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
- HDA_CODEC_VOLUME("IntMic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
{ } /* end */
};
static struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = {
HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
{ } /* end */
};
static struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = {
HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
- HDA_CODEC_VOLUME("IntMic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
{ } /* end */
};
static struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = {
HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
{ } /* end */
};
@@ -14804,31 +14893,49 @@ static int alc269_resume(struct hda_codec *codec)
}
#endif /* SND_HDA_NEEDS_RESUME */
+static void alc269_fixup_hweq(struct hda_codec *codec,
+ const struct alc_fixup *fix, int action)
+{
+ int coef;
+
+ if (action != ALC_FIXUP_ACT_INIT)
+ return;
+ coef = alc_read_coef_idx(codec, 0x1e);
+ alc_write_coef_idx(codec, 0x1e, coef | 0x80);
+}
+
enum {
ALC269_FIXUP_SONY_VAIO,
- ALC275_FIX_SONY_VAIO_GPIO2,
+ ALC275_FIXUP_SONY_VAIO_GPIO2,
ALC269_FIXUP_DELL_M101Z,
ALC269_FIXUP_SKU_IGNORE,
ALC269_FIXUP_ASUS_G73JW,
+ ALC269_FIXUP_LENOVO_EAPD,
+ ALC275_FIXUP_SONY_HWEQ,
};
static const struct alc_fixup alc269_fixups[] = {
[ALC269_FIXUP_SONY_VAIO] = {
- .verbs = (const struct hda_verb[]) {
+ .type = ALC_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
{}
}
},
- [ALC275_FIX_SONY_VAIO_GPIO2] = {
- .verbs = (const struct hda_verb[]) {
+ [ALC275_FIXUP_SONY_VAIO_GPIO2] = {
+ .type = ALC_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
{0x01, AC_VERB_SET_GPIO_MASK, 0x04},
{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04},
{0x01, AC_VERB_SET_GPIO_DATA, 0x00},
{ }
- }
+ },
+ .chained = true,
+ .chain_id = ALC269_FIXUP_SONY_VAIO
},
[ALC269_FIXUP_DELL_M101Z] = {
- .verbs = (const struct hda_verb[]) {
+ .type = ALC_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
/* Enables internal speaker */
{0x20, AC_VERB_SET_COEF_INDEX, 13},
{0x20, AC_VERB_SET_PROC_COEF, 0x4040},
@@ -14836,25 +14943,44 @@ static const struct alc_fixup alc269_fixups[] = {
}
},
[ALC269_FIXUP_SKU_IGNORE] = {
- .sku = ALC_FIXUP_SKU_IGNORE,
+ .type = ALC_FIXUP_SKU,
+ .v.sku = ALC_FIXUP_SKU_IGNORE,
},
[ALC269_FIXUP_ASUS_G73JW] = {
- .pins = (const struct alc_pincfg[]) {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
{ 0x17, 0x99130111 }, /* subwoofer */
{ }
}
},
+ [ALC269_FIXUP_LENOVO_EAPD] = {
+ .type = ALC_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
+ {}
+ }
+ },
+ [ALC275_FIXUP_SONY_HWEQ] = {
+ .type = ALC_FIXUP_FUNC,
+ .v.func = alc269_fixup_hweq,
+ .chained = true,
+ .chain_id = ALC275_FIXUP_SONY_VAIO_GPIO2
+ }
};
static struct snd_pci_quirk alc269_fixup_tbl[] = {
- SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIX_SONY_VAIO_GPIO2),
- SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIX_SONY_VAIO_GPIO2),
- SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIX_SONY_VAIO_GPIO2),
+ SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2),
+ SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
+ SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
- SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
+ SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE),
+ SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
+ SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE),
+ SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE),
SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
+ SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
{}
};
@@ -14862,7 +14988,7 @@ static struct snd_pci_quirk alc269_fixup_tbl[] = {
/*
* configuration and preset
*/
-static const char *alc269_models[ALC269_MODEL_LAST] = {
+static const char * const alc269_models[ALC269_MODEL_LAST] = {
[ALC269_BASIC] = "basic",
[ALC269_QUANTA_FL1] = "quanta",
[ALC269_AMIC] = "laptop-amic",
@@ -14886,7 +15012,7 @@ static struct snd_pci_quirk alc269_cfg_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269VB_AMIC),
SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269VB_AMIC),
SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_AMIC),
- SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82Jv", ALC269_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82JV", ALC269VB_AMIC),
SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_AMIC),
SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_AMIC),
SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_AMIC),
@@ -15138,8 +15264,10 @@ static int patch_alc269(struct hda_codec *codec)
board_config = ALC269_AUTO;
}
- if (board_config == ALC269_AUTO)
- alc_pick_fixup(codec, alc269_fixup_tbl, alc269_fixups, 1);
+ if (board_config == ALC269_AUTO) {
+ alc_pick_fixup(codec, NULL, alc269_fixup_tbl, alc269_fixups);
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
+ }
if (board_config == ALC269_AUTO) {
/* automatic parse from the BIOS config */
@@ -15200,8 +15328,7 @@ static int patch_alc269(struct hda_codec *codec)
if (has_cdefine_beep(codec))
set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
- if (board_config == ALC269_AUTO)
- alc_pick_fixup(codec, alc269_fixup_tbl, alc269_fixups, 0);
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
spec->vmaster_nid = 0x02;
@@ -15889,41 +16016,33 @@ static int alc861_auto_fill_dac_nids(struct hda_codec *codec,
return 0;
}
-static int alc861_create_out_sw(struct hda_codec *codec, const char *pfx,
- hda_nid_t nid, unsigned int chs)
+static int __alc861_create_out_sw(struct hda_codec *codec, const char *pfx,
+ hda_nid_t nid, int idx, unsigned int chs)
{
- return add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx,
+ return __add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx, idx,
HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
}
+#define alc861_create_out_sw(codec, pfx, nid, chs) \
+ __alc861_create_out_sw(codec, pfx, nid, 0, chs)
+
/* add playback controls from the parsed DAC table */
static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
const struct auto_pin_cfg *cfg)
{
struct alc_spec *spec = codec->spec;
- static const char *chname[4] = {
+ static const char * const chname[4] = {
"Front", "Surround", NULL /*CLFE*/, "Side"
};
+ const char *pfx = alc_get_line_out_pfx(cfg, true);
hda_nid_t nid;
int i, err;
- if (cfg->line_outs == 1) {
- const char *pfx = NULL;
- if (!cfg->hp_outs)
- pfx = "Master";
- else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
- pfx = "Speaker";
- if (pfx) {
- nid = spec->multiout.dac_nids[0];
- return alc861_create_out_sw(codec, pfx, nid, 3);
- }
- }
-
for (i = 0; i < cfg->line_outs; i++) {
nid = spec->multiout.dac_nids[i];
if (!nid)
continue;
- if (i == 2) {
+ if (!pfx && i == 2) {
/* Center/LFE */
err = alc861_create_out_sw(codec, "Center", nid, 1);
if (err < 0)
@@ -15932,7 +16051,10 @@ static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
if (err < 0)
return err;
} else {
- err = alc861_create_out_sw(codec, chname[i], nid, 3);
+ const char *name = pfx;
+ if (!name)
+ name = chname[i];
+ err = __alc861_create_out_sw(codec, name, nid, i, 3);
if (err < 0)
return err;
}
@@ -16115,7 +16237,7 @@ static struct hda_amp_list alc861_loopbacks[] = {
/*
* configuration and preset
*/
-static const char *alc861_models[ALC861_MODEL_LAST] = {
+static const char * const alc861_models[ALC861_MODEL_LAST] = {
[ALC861_3ST] = "3stack",
[ALC660_3ST] = "3stack-660",
[ALC861_3ST_DIG] = "3stack-dig",
@@ -16265,7 +16387,8 @@ enum {
static const struct alc_fixup alc861_fixups[] = {
[PINFIX_FSC_AMILO_PI1505] = {
- .pins = (const struct alc_pincfg[]) {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
{ 0x0b, 0x0221101f }, /* HP */
{ 0x0f, 0x90170310 }, /* speaker */
{ }
@@ -16300,8 +16423,10 @@ static int patch_alc861(struct hda_codec *codec)
board_config = ALC861_AUTO;
}
- if (board_config == ALC861_AUTO)
- alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups, 1);
+ if (board_config == ALC861_AUTO) {
+ alc_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups);
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
+ }
if (board_config == ALC861_AUTO) {
/* automatic parse from the BIOS config */
@@ -16338,8 +16463,7 @@ static int patch_alc861(struct hda_codec *codec)
spec->vmaster_nid = 0x03;
- if (board_config == ALC861_AUTO)
- alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups, 0);
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
codec->patch_ops = alc_patch_ops;
if (board_config == ALC861_AUTO) {
@@ -16404,8 +16528,8 @@ static struct hda_input_mux alc861vd_capture_source = {
static struct hda_input_mux alc861vd_dallas_capture_source = {
.num_items = 2,
.items = {
- { "Ext Mic", 0x0 },
- { "Int Mic", 0x1 },
+ { "Mic", 0x0 },
+ { "Internal Mic", 0x1 },
},
};
@@ -16484,11 +16608,11 @@ static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
@@ -16507,11 +16631,11 @@ static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
@@ -16531,11 +16655,11 @@ static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
@@ -16546,19 +16670,19 @@ static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
};
/* Pin assignment: Speaker=0x14, HP = 0x15,
- * Ext Mic=0x18, Int Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
+ * Mic=0x18, Internal Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
*/
static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
- HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
- HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
- HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
{ } /* end */
};
@@ -16723,18 +16847,6 @@ static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
{}
};
-static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
-{
- unsigned int present;
- unsigned char bits;
-
- present = snd_hda_jack_detect(codec, 0x18);
- bits = present ? HDA_AMP_MUTE : 0;
-
- snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
- HDA_AMP_MUTE, bits);
-}
-
static void alc861vd_lenovo_setup(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
@@ -16745,7 +16857,7 @@ static void alc861vd_lenovo_setup(struct hda_codec *codec)
static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
{
alc_automute_amp(codec);
- alc861vd_lenovo_mic_automute(codec);
+ alc88x_simple_mic_automute(codec);
}
static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
@@ -16753,7 +16865,7 @@ static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
{
switch (res >> 26) {
case ALC880_MIC_EVENT:
- alc861vd_lenovo_mic_automute(codec);
+ alc88x_simple_mic_automute(codec);
break;
default:
alc_automute_amp_unsol_event(codec, res);
@@ -16828,7 +16940,7 @@ static void alc861vd_dallas_setup(struct hda_codec *codec)
/*
* configuration and preset
*/
-static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
+static const char * const alc861vd_models[ALC861VD_MODEL_LAST] = {
[ALC660VD_3ST] = "3stack-660",
[ALC660VD_3ST_DIG] = "3stack-660-digout",
[ALC660VD_ASUS_V1S] = "asus-v1s",
@@ -17048,7 +17160,10 @@ static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
const struct auto_pin_cfg *cfg)
{
- static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
+ static const char * const chname[4] = {
+ "Front", "Surround", "CLFE", "Side"
+ };
+ const char *pfx = alc_get_line_out_pfx(cfg, true);
hda_nid_t nid_v, nid_s;
int i, err;
@@ -17062,7 +17177,7 @@ static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
alc880_dac_to_idx(
spec->multiout.dac_nids[i]));
- if (i == 2) {
+ if (!pfx && i == 2) {
/* Center/LFE */
err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
"Center",
@@ -17089,24 +17204,17 @@ static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
if (err < 0)
return err;
} else {
- const char *pfx;
- if (cfg->line_outs == 1 &&
- cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
- if (!cfg->hp_pins)
- pfx = "Speaker";
- else
- pfx = "PCM";
- } else
- pfx = chname[i];
- err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
+ const char *name = pfx;
+ if (!name)
+ name = chname[i];
+ err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
+ name, i,
HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
HDA_OUTPUT));
if (err < 0)
return err;
- if (cfg->line_outs == 1 &&
- cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
- pfx = "Speaker";
- err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
+ err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
+ name, i,
HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
HDA_INPUT));
if (err < 0)
@@ -17239,7 +17347,8 @@ enum {
/* reset GPIO1 */
static const struct alc_fixup alc861vd_fixups[] = {
[ALC660VD_FIX_ASUS_GPIO1] = {
- .verbs = (const struct hda_verb[]) {
+ .type = ALC_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
{0x01, AC_VERB_SET_GPIO_MASK, 0x03},
{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
{0x01, AC_VERB_SET_GPIO_DATA, 0x01},
@@ -17274,8 +17383,10 @@ static int patch_alc861vd(struct hda_codec *codec)
board_config = ALC861VD_AUTO;
}
- if (board_config == ALC861VD_AUTO)
- alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups, 1);
+ if (board_config == ALC861VD_AUTO) {
+ alc_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups);
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
+ }
if (board_config == ALC861VD_AUTO) {
/* automatic parse from the BIOS config */
@@ -17323,8 +17434,7 @@ static int patch_alc861vd(struct hda_codec *codec)
spec->vmaster_nid = 0x02;
- if (board_config == ALC861VD_AUTO)
- alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups, 0);
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
codec->patch_ops = alc_patch_ops;
@@ -17570,13 +17680,13 @@ static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
ALC262_HIPPO_MASTER_SWITCH,
- HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
- HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
- HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
{ } /* end */
};
@@ -17720,8 +17830,8 @@ static struct snd_kcontrol_new alc663_g71v_mixer[] = {
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
{ } /* end */
};
@@ -17732,8 +17842,8 @@ static struct snd_kcontrol_new alc663_g50v_mixer[] = {
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
{ } /* end */
@@ -18566,13 +18676,13 @@ static struct snd_kcontrol_new alc662_ecs_mixer[] = {
HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
ALC262_HIPPO_MASTER_SWITCH,
- HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT),
- HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("e-Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic/LineIn Boost Volume", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
- HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
{ } /* end */
};
@@ -18583,13 +18693,13 @@ static struct snd_kcontrol_new alc272_nc10_mixer[] = {
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
- HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
{ } /* end */
};
@@ -18607,7 +18717,7 @@ static struct snd_kcontrol_new alc272_nc10_mixer[] = {
/*
* configuration and preset
*/
-static const char *alc662_models[ALC662_MODEL_LAST] = {
+static const char * const alc662_models[ALC662_MODEL_LAST] = {
[ALC662_3ST_2ch_DIG] = "3stack-dig",
[ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
[ALC662_3ST_6ch] = "3stack-6ch",
@@ -18712,6 +18822,7 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = {
ALC662_3ST_6ch_DIG),
SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x",
ALC663_ASUS_H13),
+ SND_PCI_QUIRK(0x1991, 0x5628, "Ordissimo EVE", ALC662_LENOVO_101E),
{}
};
@@ -19094,20 +19205,24 @@ static int alc662_auto_fill_dac_nids(struct hda_codec *codec,
return 0;
}
-static inline int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
- hda_nid_t nid, unsigned int chs)
+static inline int __alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
+ hda_nid_t nid, int idx, unsigned int chs)
{
- return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
+ return __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, idx,
HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
}
-static inline int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
- hda_nid_t nid, unsigned int chs)
+static inline int __alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
+ hda_nid_t nid, int idx, unsigned int chs)
{
- return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
+ return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, idx,
HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT));
}
+#define alc662_add_vol_ctl(spec, pfx, nid, chs) \
+ __alc662_add_vol_ctl(spec, pfx, nid, 0, chs)
+#define alc662_add_sw_ctl(spec, pfx, nid, chs) \
+ __alc662_add_sw_ctl(spec, pfx, nid, 0, chs)
#define alc662_add_stereo_vol(spec, pfx, nid) \
alc662_add_vol_ctl(spec, pfx, nid, 3)
#define alc662_add_stereo_sw(spec, pfx, nid) \
@@ -19118,9 +19233,10 @@ static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec,
const struct auto_pin_cfg *cfg)
{
struct alc_spec *spec = codec->spec;
- static const char *chname[4] = {
+ static const char * const chname[4] = {
"Front", "Surround", NULL /*CLFE*/, "Side"
};
+ const char *pfx = alc_get_line_out_pfx(cfg, true);
hda_nid_t nid, mix;
int i, err;
@@ -19131,7 +19247,7 @@ static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec,
mix = alc662_dac_to_mix(codec, cfg->line_out_pins[i], nid);
if (!mix)
continue;
- if (i == 2) {
+ if (!pfx && i == 2) {
/* Center/LFE */
err = alc662_add_vol_ctl(spec, "Center", nid, 1);
if (err < 0)
@@ -19146,22 +19262,13 @@ static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec,
if (err < 0)
return err;
} else {
- const char *pfx;
- if (cfg->line_outs == 1 &&
- cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
- if (cfg->hp_outs)
- pfx = "Speaker";
- else
- pfx = "PCM";
- } else
- pfx = chname[i];
- err = alc662_add_vol_ctl(spec, pfx, nid, 3);
+ const char *name = pfx;
+ if (!name)
+ name = chname[i];
+ err = __alc662_add_vol_ctl(spec, name, nid, i, 3);
if (err < 0)
return err;
- if (cfg->line_outs == 1 &&
- cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
- pfx = "Speaker";
- err = alc662_add_sw_ctl(spec, pfx, mix, 3);
+ err = __alc662_add_sw_ctl(spec, name, mix, i, 3);
if (err < 0)
return err;
}
@@ -19358,34 +19465,69 @@ static void alc662_auto_init(struct hda_codec *codec)
alc_inithook(codec);
}
+static void alc272_fixup_mario(struct hda_codec *codec,
+ const struct alc_fixup *fix, int action)
+{
+ if (action != ALC_FIXUP_ACT_PROBE)
+ return;
+ if (snd_hda_override_amp_caps(codec, 0x2, HDA_OUTPUT,
+ (0x3b << AC_AMPCAP_OFFSET_SHIFT) |
+ (0x3b << AC_AMPCAP_NUM_STEPS_SHIFT) |
+ (0x03 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+ (0 << AC_AMPCAP_MUTE_SHIFT)))
+ printk(KERN_WARNING
+ "hda_codec: failed to override amp caps for NID 0x2\n");
+}
+
enum {
ALC662_FIXUP_ASPIRE,
ALC662_FIXUP_IDEAPAD,
+ ALC272_FIXUP_MARIO,
+ ALC662_FIXUP_CZC_P10T,
};
static const struct alc_fixup alc662_fixups[] = {
[ALC662_FIXUP_ASPIRE] = {
- .pins = (const struct alc_pincfg[]) {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
{ 0x15, 0x99130112 }, /* subwoofer */
{ }
}
},
[ALC662_FIXUP_IDEAPAD] = {
- .pins = (const struct alc_pincfg[]) {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
{ 0x17, 0x99130112 }, /* subwoofer */
{ }
}
},
+ [ALC272_FIXUP_MARIO] = {
+ .type = ALC_FIXUP_FUNC,
+ .v.func = alc272_fixup_mario,
+ },
+ [ALC662_FIXUP_CZC_P10T] = {
+ .type = ALC_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
+ {}
+ }
+ },
};
static struct snd_pci_quirk alc662_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
+ SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T),
{}
};
+static const struct alc_model_fixup alc662_fixup_models[] = {
+ {.id = ALC272_FIXUP_MARIO, .name = "mario"},
+ {}
+};
static int patch_alc662(struct hda_codec *codec)
@@ -19424,7 +19566,9 @@ static int patch_alc662(struct hda_codec *codec)
}
if (board_config == ALC662_AUTO) {
- alc_pick_fixup(codec, alc662_fixup_tbl, alc662_fixups, 1);
+ alc_pick_fixup(codec, alc662_fixup_models,
+ alc662_fixup_tbl, alc662_fixups);
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
/* automatic parse from the BIOS config */
err = alc662_parse_auto_config(codec);
if (err < 0) {
@@ -19482,11 +19626,11 @@ static int patch_alc662(struct hda_codec *codec)
}
spec->vmaster_nid = 0x02;
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
+
codec->patch_ops = alc_patch_ops;
- if (board_config == ALC662_AUTO) {
+ if (board_config == ALC662_AUTO)
spec->init_hook = alc662_auto_init;
- alc_pick_fixup(codec, alc662_fixup_tbl, alc662_fixups, 0);
- }
alc_init_jacks(codec);
@@ -19612,9 +19756,9 @@ static struct snd_kcontrol_new alc680_base_mixer[] = {
HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Int Mic Boost", 0x12, 0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
- HDA_CODEC_VOLUME("Line In Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x12, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line In Boost Volume", 0x19, 0, HDA_INPUT),
{ }
};
@@ -19874,7 +20018,7 @@ static void alc680_auto_init(struct hda_codec *codec)
/*
* configuration and preset
*/
-static const char *alc680_models[ALC680_MODEL_LAST] = {
+static const char * const alc680_models[ALC680_MODEL_LAST] = {
[ALC680_BASE] = "base",
[ALC680_AUTO] = "auto",
};
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index f03b2ff9049..bd7b123f644 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -266,7 +266,7 @@ struct sigmatel_spec {
struct sigmatel_mic_route int_mic;
struct sigmatel_mic_route dock_mic;
- const char **spdif_labels;
+ const char * const *spdif_labels;
hda_nid_t dig_in_nid;
hda_nid_t mono_nid;
@@ -389,6 +389,9 @@ static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = {
0x11, 0x20, 0
};
+#define STAC92HD88XXX_NUM_DMICS STAC92HD83XXX_NUM_DMICS
+#define stac92hd88xxx_dmic_nids stac92hd83xxx_dmic_nids
+
#define STAC92HD87B_NUM_DMICS 1
static hda_nid_t stac92hd87b_dmic_nids[STAC92HD87B_NUM_DMICS + 1] = {
0x11, 0
@@ -521,7 +524,7 @@ static unsigned long stac927x_capsws[] = {
HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT),
};
-static const char *stac927x_spdif_labels[5] = {
+static const char * const stac927x_spdif_labels[5] = {
"Digital Playback", "ADAT", "Analog Mux 1",
"Analog Mux 2", "Analog Mux 3"
};
@@ -583,7 +586,12 @@ static hda_nid_t stac92hd83xxx_pin_nids[10] = {
0x0f, 0x10, 0x11, 0x1f, 0x20,
};
-static hda_nid_t stac92hd88xxx_pin_nids[10] = {
+static hda_nid_t stac92hd87xxx_pin_nids[6] = {
+ 0x0a, 0x0b, 0x0c, 0x0d,
+ 0x0f, 0x11,
+};
+
+static hda_nid_t stac92hd88xxx_pin_nids[8] = {
0x0a, 0x0b, 0x0c, 0x0d,
0x0f, 0x11, 0x1f, 0x20,
};
@@ -1059,7 +1067,7 @@ static struct snd_kcontrol_new stac_smux_mixer = {
.put = stac92xx_smux_enum_put,
};
-static const char *slave_vols[] = {
+static const char * const slave_vols[] = {
"Front Playback Volume",
"Surround Playback Volume",
"Center Playback Volume",
@@ -1070,7 +1078,7 @@ static const char *slave_vols[] = {
NULL
};
-static const char *slave_sws[] = {
+static const char * const slave_sws[] = {
"Front Playback Switch",
"Surround Playback Switch",
"Center Playback Switch",
@@ -1351,7 +1359,7 @@ static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
[STAC_9200_PANASONIC] = ref9200_pin_configs,
};
-static const char *stac9200_models[STAC_9200_MODELS] = {
+static const char * const stac9200_models[STAC_9200_MODELS] = {
[STAC_AUTO] = "auto",
[STAC_REF] = "ref",
[STAC_9200_OQO] = "oqo",
@@ -1497,7 +1505,7 @@ static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
[STAC_M6] = stac925xM6_pin_configs,
};
-static const char *stac925x_models[STAC_925x_MODELS] = {
+static const char * const stac925x_models[STAC_925x_MODELS] = {
[STAC_925x_AUTO] = "auto",
[STAC_REF] = "ref",
[STAC_M1] = "m1",
@@ -1571,7 +1579,7 @@ static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
[STAC_92HD73XX_INTEL] = intel_dg45id_pin_configs,
};
-static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
+static const char * const stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
[STAC_92HD73XX_AUTO] = "auto",
[STAC_92HD73XX_NO_JD] = "no-jd",
[STAC_92HD73XX_REF] = "ref",
@@ -1657,7 +1665,7 @@ static unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = {
[STAC_HP_DV7_4000] = hp_dv7_4000_pin_configs,
};
-static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
+static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
[STAC_92HD83XXX_AUTO] = "auto",
[STAC_92HD83XXX_REF] = "ref",
[STAC_92HD83XXX_PWR_REF] = "mic-ref",
@@ -1719,7 +1727,7 @@ static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
[STAC_HP_DV4_1222NR] = NULL,
};
-static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
+static const char * const stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
[STAC_92HD71BXX_AUTO] = "auto",
[STAC_92HD71BXX_REF] = "ref",
[STAC_DELL_M4_1] = "dell-m4-1",
@@ -1912,7 +1920,7 @@ static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
[STAC_922X_DELL_M82] = dell_922x_m82_pin_configs,
};
-static const char *stac922x_models[STAC_922X_MODELS] = {
+static const char * const stac922x_models[STAC_922X_MODELS] = {
[STAC_922X_AUTO] = "auto",
[STAC_D945_REF] = "ref",
[STAC_D945GTP5] = "5stack",
@@ -2074,7 +2082,7 @@ static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
[STAC_927X_VOLKNOB] = NULL,
};
-static const char *stac927x_models[STAC_927X_MODELS] = {
+static const char * const stac927x_models[STAC_927X_MODELS] = {
[STAC_927X_AUTO] = "auto",
[STAC_D965_REF_NO_JD] = "ref-no-jd",
[STAC_D965_REF] = "ref",
@@ -2177,7 +2185,7 @@ static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
[STAC_9205_EAPD] = NULL,
};
-static const char *stac9205_models[STAC_9205_MODELS] = {
+static const char * const stac9205_models[STAC_9205_MODELS] = {
[STAC_9205_AUTO] = "auto",
[STAC_9205_REF] = "ref",
[STAC_9205_DELL_M42] = "dell-m42",
@@ -3120,7 +3128,7 @@ static int create_multi_out_ctls(struct hda_codec *codec, int num_outs,
int type)
{
struct sigmatel_spec *spec = codec->spec;
- static const char *chname[4] = {
+ static const char * const chname[4] = {
"Front", "Surround", NULL /*CLFE*/, "Side"
};
hda_nid_t nid;
@@ -3253,7 +3261,7 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
}
/* labels for mono mux outputs */
-static const char *stac92xx_mono_labels[4] = {
+static const char * const stac92xx_mono_labels[4] = {
"DAC0", "DAC1", "Mixer", "DAC2"
};
@@ -3377,7 +3385,7 @@ static int stac92xx_auto_create_mux_input_ctls(struct hda_codec *codec)
return 0;
};
-static const char *stac92xx_spdif_labels[3] = {
+static const char * const stac92xx_spdif_labels[3] = {
"Digital Playback", "Analog Mux 1", "Analog Mux 2",
};
@@ -3385,7 +3393,7 @@ static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec)
{
struct sigmatel_spec *spec = codec->spec;
struct hda_input_mux *spdif_mux = &spec->private_smux;
- const char **labels = spec->spdif_labels;
+ const char * const *labels = spec->spdif_labels;
int i, num_cons;
hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
@@ -3406,7 +3414,7 @@ static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec)
}
/* labels for dmic mux inputs */
-static const char *stac92xx_dmic_labels[5] = {
+static const char * const stac92xx_dmic_labels[5] = {
"Analog Inputs", "Digital Mic 1", "Digital Mic 2",
"Digital Mic 3", "Digital Mic 4"
};
@@ -3591,7 +3599,7 @@ static int stac_check_auto_mic(struct hda_codec *codec)
if (check_mic_pin(codec, spec->dmic_nids[i],
&fixed, &ext, &dock))
return 0;
- if (!fixed && !ext && !dock)
+ if (!fixed || (!ext && !dock))
return 0; /* no input to switch */
if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP))
return 0; /* no unsol support */
@@ -5330,7 +5338,7 @@ again:
return 0;
}
-static int stac92hd83xxx_set_system_btl_amp(struct hda_codec *codec)
+static int hp_bnb2011_with_dock(struct hda_codec *codec)
{
if (codec->vendor_id != 0x111d7605 &&
codec->vendor_id != 0x111d76d1)
@@ -5345,10 +5353,6 @@ static int stac92hd83xxx_set_system_btl_amp(struct hda_codec *codec)
case 0x103c161d:
case 0x103c161e:
case 0x103c161f:
- case 0x103c1620:
- case 0x103c1621:
- case 0x103c1622:
- case 0x103c1623:
case 0x103c162a:
case 0x103c162b:
@@ -5357,41 +5361,9 @@ static int stac92hd83xxx_set_system_btl_amp(struct hda_codec *codec)
case 0x103c1631:
case 0x103c1633:
-
+ case 0x103c1634:
case 0x103c1635:
- case 0x103c164f:
-
- case 0x103c1676:
- case 0x103c1677:
- case 0x103c1678:
- case 0x103c1679:
- case 0x103c167a:
- case 0x103c167b:
- case 0x103c167c:
- case 0x103c167d:
- case 0x103c167e:
- case 0x103c167f:
- case 0x103c1680:
- case 0x103c1681:
- case 0x103c1682:
- case 0x103c1683:
- case 0x103c1684:
- case 0x103c1685:
- case 0x103c1686:
- case 0x103c1687:
- case 0x103c1688:
- case 0x103c1689:
- case 0x103c168a:
- case 0x103c168b:
- case 0x103c168c:
- case 0x103c168d:
- case 0x103c168e:
- case 0x103c168f:
- case 0x103c1690:
- case 0x103c1691:
- case 0x103c1692:
-
case 0x103c3587:
case 0x103c3588:
case 0x103c3589:
@@ -5399,9 +5371,9 @@ static int stac92hd83xxx_set_system_btl_amp(struct hda_codec *codec)
case 0x103c3667:
case 0x103c3668:
- /* set BTL amp level to 13.43dB for louder speaker output */
- return snd_hda_codec_write_cache(codec, codec->afg, 0,
- 0x7F4, 0x14);
+ case 0x103c3669:
+
+ return 1;
}
return 0;
}
@@ -5417,12 +5389,17 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
if (spec == NULL)
return -ENOMEM;
+ if (hp_bnb2011_with_dock(codec)) {
+ snd_hda_codec_set_pincfg(codec, 0xa, 0x2101201f);
+ snd_hda_codec_set_pincfg(codec, 0xf, 0x2181205e);
+ }
+
/* reset pin power-down; Windows may leave these bits after reboot */
snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7EC, 0);
snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7ED, 0);
codec->no_trigger_sense = 1;
codec->spec = spec;
- spec->linear_tone_beep = 1;
+ spec->linear_tone_beep = 0;
codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs;
spec->digbeep_nid = 0x21;
spec->dmic_nids = stac92hd83xxx_dmic_nids;
@@ -5458,19 +5435,27 @@ again:
switch (codec->vendor_id) {
case 0x111d76d1:
case 0x111d76d9:
+ case 0x111d76e5:
spec->dmic_nids = stac92hd87b_dmic_nids;
spec->num_dmics = stac92xx_connected_ports(codec,
stac92hd87b_dmic_nids,
STAC92HD87B_NUM_DMICS);
- /* Fall through */
+ spec->num_pins = ARRAY_SIZE(stac92hd87xxx_pin_nids);
+ spec->pin_nids = stac92hd87xxx_pin_nids;
+ spec->mono_nid = 0;
+ spec->num_pwrs = 0;
+ break;
case 0x111d7666:
case 0x111d7667:
case 0x111d7668:
case 0x111d7669:
+ case 0x111d76e3:
+ spec->num_dmics = stac92xx_connected_ports(codec,
+ stac92hd88xxx_dmic_nids,
+ STAC92HD88XXX_NUM_DMICS);
spec->num_pins = ARRAY_SIZE(stac92hd88xxx_pin_nids);
spec->pin_nids = stac92hd88xxx_pin_nids;
spec->mono_nid = 0;
- spec->digbeep_nid = 0;
spec->num_pwrs = 0;
break;
case 0x111d7604:
@@ -5537,8 +5522,6 @@ again:
AC_VERB_SET_CONNECT_SEL, num_dacs);
}
- stac92hd83xxx_set_system_btl_amp(codec);
-
codec->proc_widget_hook = stac92hd_proc_hook;
return 0;
@@ -6261,7 +6244,7 @@ static unsigned int stac9872_vaio_pin_configs[9] = {
0x90a7013e
};
-static const char *stac9872_models[STAC_9872_MODELS] = {
+static const char * const stac9872_models[STAC_9872_MODELS] = {
[STAC_9872_AUTO] = "auto",
[STAC_9872_VAIO] = "vaio",
};
@@ -6411,6 +6394,8 @@ static struct hda_codec_preset snd_hda_preset_sigmatel[] = {
{ .id = 0x111d76cd, .name = "92HD89F2", .patch = patch_stac92hd73xx },
{ .id = 0x111d76ce, .name = "92HD89F1", .patch = patch_stac92hd73xx },
{ .id = 0x111d76e0, .name = "92HD91BXX", .patch = patch_stac92hd83xxx},
+ { .id = 0x111d76e3, .name = "92HD98BXX", .patch = patch_stac92hd83xxx},
+ { .id = 0x111d76e5, .name = "92HD99BXX", .patch = patch_stac92hd83xxx},
{ .id = 0x111d76e7, .name = "92HD90BXX", .patch = patch_stac92hd83xxx},
{} /* terminator */
};
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index d1c3f8defc4..63b0054200a 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -263,8 +263,7 @@ static void vt1708_stop_hp_work(struct via_spec *spec)
return;
snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81,
!spec->vt1708_jack_detectect);
- cancel_delayed_work(&spec->vt1708_hp_work);
- flush_scheduled_work();
+ cancel_delayed_work_sync(&spec->vt1708_hp_work);
}
@@ -568,7 +567,7 @@ static void via_auto_init_analog_input(struct hda_codec *codec)
hda_nid_t nid = cfg->inputs[i].pin;
if (spec->smart51_enabled && is_smart51_pins(spec, nid))
ctl = PIN_OUT;
- else if (i == AUTO_PIN_MIC)
+ else if (cfg->inputs[i].type == AUTO_PIN_MIC)
ctl = PIN_VREF50;
else
ctl = PIN_IN;
@@ -2282,7 +2281,9 @@ static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,
const struct auto_pin_cfg *cfg)
{
char name[32];
- static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
+ static const char * const chname[4] = {
+ "Front", "Surround", "C/LFE", "Side"
+ };
hda_nid_t nid, nid_vol, nid_vols[] = {0x17, 0x19, 0x1a, 0x1b};
int i, err;
@@ -2371,7 +2372,7 @@ static void create_hp_imux(struct via_spec *spec)
{
int i;
struct hda_input_mux *imux = &spec->private_imux[1];
- static const char *texts[] = { "OFF", "ON", NULL};
+ static const char * const texts[] = { "OFF", "ON", NULL};
/* for hp mode select */
for (i = 0; texts[i]; i++)
@@ -2891,7 +2892,9 @@ static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec,
const struct auto_pin_cfg *cfg)
{
char name[32];
- static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
+ static const char * const chname[4] = {
+ "Front", "Surround", "C/LFE", "Side"
+ };
hda_nid_t nid, nid_vol, nid_vols[] = {0x18, 0x1a, 0x1b, 0x29};
int i, err;
@@ -3434,7 +3437,9 @@ static int vt1708B_auto_create_multi_out_ctls(struct via_spec *spec,
const struct auto_pin_cfg *cfg)
{
char name[32];
- static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
+ static const char * const chname[4] = {
+ "Front", "Surround", "C/LFE", "Side"
+ };
hda_nid_t nid_vols[] = {0x16, 0x18, 0x26, 0x27};
hda_nid_t nid, nid_vol = 0;
int i, err;
@@ -3862,7 +3867,9 @@ static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec,
const struct auto_pin_cfg *cfg)
{
char name[32];
- static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
+ static const char * const chname[4] = {
+ "Front", "Surround", "C/LFE", "Side"
+ };
hda_nid_t nid_vols[] = {0x10, 0x11, 0x24, 0x25};
hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x26, 0x27};
hda_nid_t nid, nid_vol, nid_mute;
@@ -4305,7 +4312,7 @@ static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
{
int err, i;
struct hda_input_mux *imux;
- static const char *texts[] = { "ON", "OFF", NULL};
+ static const char * const texts[] = { "ON", "OFF", NULL};
if (!pin)
return 0;
spec->multiout.hp_nid = 0x1D;
@@ -4616,7 +4623,9 @@ static int vt1718S_auto_create_multi_out_ctls(struct via_spec *spec,
const struct auto_pin_cfg *cfg)
{
char name[32];
- static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
+ static const char * const chname[4] = {
+ "Front", "Surround", "C/LFE", "Side"
+ };
hda_nid_t nid_vols[] = {0x8, 0x9, 0xa, 0xb};
hda_nid_t nid_mutes[] = {0x24, 0x25, 0x26, 0x27};
hda_nid_t nid, nid_vol, nid_mute = 0;
@@ -5065,7 +5074,9 @@ static int vt1716S_auto_create_multi_out_ctls(struct via_spec *spec,
const struct auto_pin_cfg *cfg)
{
char name[32];
- static const char *chname[3] = { "Front", "Surround", "C/LFE" };
+ static const char * const chname[3] = {
+ "Front", "Surround", "C/LFE"
+ };
hda_nid_t nid_vols[] = {0x10, 0x11, 0x25};
hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x27};
hda_nid_t nid, nid_vol, nid_mute;
diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c
index 712c1710f9a..20c6b079d0d 100644
--- a/sound/pci/ice1712/delta.c
+++ b/sound/pci/ice1712/delta.c
@@ -96,6 +96,11 @@ static unsigned char ap_cs8427_codec_select(struct snd_ice1712 *ice)
tmp |= ICE1712_DELTA_AP_CCLK | ICE1712_DELTA_AP_CS_CODEC;
tmp &= ~ICE1712_DELTA_AP_CS_DIGITAL;
break;
+ case ICE1712_SUBDEVICE_DELTA66E:
+ tmp |= ICE1712_DELTA_66E_CCLK | ICE1712_DELTA_66E_CS_CHIP_A |
+ ICE1712_DELTA_66E_CS_CHIP_B;
+ tmp &= ~ICE1712_DELTA_66E_CS_CS8427;
+ break;
case ICE1712_SUBDEVICE_VX442:
tmp |= ICE1712_VX442_CCLK | ICE1712_VX442_CODEC_CHIP_A | ICE1712_VX442_CODEC_CHIP_B;
tmp &= ~ICE1712_VX442_CS_DIGITAL;
@@ -119,6 +124,9 @@ static void ap_cs8427_codec_deassert(struct snd_ice1712 *ice, unsigned char tmp)
case ICE1712_SUBDEVICE_DELTA410:
tmp |= ICE1712_DELTA_AP_CS_DIGITAL;
break;
+ case ICE1712_SUBDEVICE_DELTA66E:
+ tmp |= ICE1712_DELTA_66E_CS_CS8427;
+ break;
case ICE1712_SUBDEVICE_VX442:
tmp |= ICE1712_VX442_CS_DIGITAL;
break;
@@ -276,6 +284,20 @@ static void delta1010lt_ak4524_lock(struct snd_akm4xxx *ak, int chip)
}
/*
+ * AK4524 on Delta66 rev E to choose the chip address
+ */
+static void delta66e_ak4524_lock(struct snd_akm4xxx *ak, int chip)
+{
+ struct snd_ak4xxx_private *priv = (void *)ak->private_value[0];
+ struct snd_ice1712 *ice = ak->private_data[0];
+
+ snd_ice1712_save_gpio_status(ice);
+ priv->cs_mask =
+ priv->cs_addr = chip == 0 ? ICE1712_DELTA_66E_CS_CHIP_A :
+ ICE1712_DELTA_66E_CS_CHIP_B;
+}
+
+/*
* AK4528 on VX442 to choose the chip mask
*/
static void vx442_ak4524_lock(struct snd_akm4xxx *ak, int chip)
@@ -487,6 +509,29 @@ static struct snd_ak4xxx_private akm_delta1010lt_priv __devinitdata = {
.mask_flags = 0,
};
+static struct snd_akm4xxx akm_delta66e __devinitdata = {
+ .type = SND_AK4524,
+ .num_adcs = 4,
+ .num_dacs = 4,
+ .ops = {
+ .lock = delta66e_ak4524_lock,
+ .set_rate_val = delta_ak4524_set_rate_val
+ }
+};
+
+static struct snd_ak4xxx_private akm_delta66e_priv __devinitdata = {
+ .caddr = 2,
+ .cif = 0, /* the default level of the CIF pin from AK4524 */
+ .data_mask = ICE1712_DELTA_66E_DOUT,
+ .clk_mask = ICE1712_DELTA_66E_CCLK,
+ .cs_mask = 0,
+ .cs_addr = 0, /* set later */
+ .cs_none = 0,
+ .add_flags = 0,
+ .mask_flags = 0,
+};
+
+
static struct snd_akm4xxx akm_delta44 __devinitdata = {
.type = SND_AK4524,
.num_adcs = 4,
@@ -535,6 +580,7 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice)
{
int err;
struct snd_akm4xxx *ak;
+ unsigned char tmp;
if (ice->eeprom.subvendor == ICE1712_SUBDEVICE_DELTA1010 &&
ice->eeprom.gpiodir == 0x7b)
@@ -577,6 +623,12 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice)
break;
}
+ /* initialize the SPI clock to high */
+ tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA);
+ tmp |= ICE1712_DELTA_AP_CCLK;
+ snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
+ udelay(5);
+
/* initialize spdif */
switch (ice->eeprom.subvendor) {
case ICE1712_SUBDEVICE_AUDIOPHILE:
@@ -644,9 +696,11 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice)
err = snd_ice1712_akm4xxx_init(ak, &akm_delta44, &akm_delta44_priv, ice);
break;
case ICE1712_SUBDEVICE_VX442:
- case ICE1712_SUBDEVICE_DELTA66E:
err = snd_ice1712_akm4xxx_init(ak, &akm_vx442, &akm_vx442_priv, ice);
break;
+ case ICE1712_SUBDEVICE_DELTA66E:
+ err = snd_ice1712_akm4xxx_init(ak, &akm_delta66e, &akm_delta66e_priv, ice);
+ break;
default:
snd_BUG();
return -EINVAL;
diff --git a/sound/pci/ice1712/delta.h b/sound/pci/ice1712/delta.h
index 1a0ac6cd650..11a9c3a7650 100644
--- a/sound/pci/ice1712/delta.h
+++ b/sound/pci/ice1712/delta.h
@@ -144,6 +144,17 @@ extern struct snd_ice1712_card_info snd_ice1712_delta_cards[];
#define ICE1712_DELTA_1010LT_CS_NONE 0x50 /* nothing */
#define ICE1712_DELTA_1010LT_WORDCLOCK 0x80 /* sample clock source: 0 = Word Clock Input, 1 = S/PDIF Input ??? */
+/* M-Audio Delta 66 rev. E definitions.
+ * Newer revisions of Delta 66 have CS8427 over SPI for
+ * S/PDIF transceiver instead of CS8404/CS8414. */
+/* 0x01 = DFS */
+#define ICE1712_DELTA_66E_CCLK 0x02 /* SPI clock */
+#define ICE1712_DELTA_66E_DIN 0x04 /* data input */
+#define ICE1712_DELTA_66E_DOUT 0x08 /* data output */
+#define ICE1712_DELTA_66E_CS_CS8427 0x10 /* chip select, low = CS8427 */
+#define ICE1712_DELTA_66E_CS_CHIP_A 0x20 /* AK4524 #0 */
+#define ICE1712_DELTA_66E_CS_CHIP_B 0x40 /* AK4524 #1 */
+
/* Digigram VX442 definitions */
#define ICE1712_VX442_CCLK 0x02 /* SPI clock */
#define ICE1712_VX442_DIN 0x04 /* data input */
diff --git a/sound/pci/oxygen/Makefile b/sound/pci/oxygen/Makefile
index acd8f15f7bf..0f8726551fd 100644
--- a/sound/pci/oxygen/Makefile
+++ b/sound/pci/oxygen/Makefile
@@ -1,10 +1,8 @@
snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o
-snd-hifier-objs := hifier.o
-snd-oxygen-objs := oxygen.o
+snd-oxygen-objs := oxygen.o xonar_dg.o
snd-virtuoso-objs := virtuoso.o xonar_lib.o \
xonar_pcm179x.o xonar_cs43xx.o xonar_wm87x6.o xonar_hdmi.o
obj-$(CONFIG_SND_OXYGEN_LIB) += snd-oxygen-lib.o
-obj-$(CONFIG_SND_HIFIER) += snd-hifier.o
obj-$(CONFIG_SND_OXYGEN) += snd-oxygen.o
obj-$(CONFIG_SND_VIRTUOSO) += snd-virtuoso.o
diff --git a/sound/pci/oxygen/cs4245.h b/sound/pci/oxygen/cs4245.h
new file mode 100644
index 00000000000..5e0197e07dd
--- /dev/null
+++ b/sound/pci/oxygen/cs4245.h
@@ -0,0 +1,107 @@
+#define CS4245_CHIP_ID 0x01
+#define CS4245_POWER_CTRL 0x02
+#define CS4245_DAC_CTRL_1 0x03
+#define CS4245_ADC_CTRL 0x04
+#define CS4245_MCLK_FREQ 0x05
+#define CS4245_SIGNAL_SEL 0x06
+#define CS4245_PGA_B_CTRL 0x07
+#define CS4245_PGA_A_CTRL 0x08
+#define CS4245_ANALOG_IN 0x09
+#define CS4245_DAC_A_CTRL 0x0a
+#define CS4245_DAC_B_CTRL 0x0b
+#define CS4245_DAC_CTRL_2 0x0c
+#define CS4245_INT_STATUS 0x0d
+#define CS4245_INT_MASK 0x0e
+#define CS4245_INT_MODE_MSB 0x0f
+#define CS4245_INT_MODE_LSB 0x10
+
+/* Chip ID */
+#define CS4245_CHIP_PART_MASK 0xf0
+#define CS4245_CHIP_REV_MASK 0x0f
+
+/* Power Control */
+#define CS4245_FREEZE 0x80
+#define CS4245_PDN_MIC 0x08
+#define CS4245_PDN_ADC 0x04
+#define CS4245_PDN_DAC 0x02
+#define CS4245_PDN 0x01
+
+/* DAC Control */
+#define CS4245_DAC_FM_MASK 0xc0
+#define CS4245_DAC_FM_SINGLE 0x00
+#define CS4245_DAC_FM_DOUBLE 0x40
+#define CS4245_DAC_FM_QUAD 0x80
+#define CS4245_DAC_DIF_MASK 0x30
+#define CS4245_DAC_DIF_LJUST 0x00
+#define CS4245_DAC_DIF_I2S 0x10
+#define CS4245_DAC_DIF_RJUST_16 0x20
+#define CS4245_DAC_DIF_RJUST_24 0x30
+#define CS4245_RESERVED_1 0x08
+#define CS4245_MUTE_DAC 0x04
+#define CS4245_DEEMPH 0x02
+#define CS4245_DAC_MASTER 0x01
+
+/* ADC Control */
+#define CS4245_ADC_FM_MASK 0xc0
+#define CS4245_ADC_FM_SINGLE 0x00
+#define CS4245_ADC_FM_DOUBLE 0x40
+#define CS4245_ADC_FM_QUAD 0x80
+#define CS4245_ADC_DIF_MASK 0x10
+#define CS4245_ADC_DIF_LJUST 0x00
+#define CS4245_ADC_DIF_I2S 0x10
+#define CS4245_MUTE_ADC 0x04
+#define CS4245_HPF_FREEZE 0x02
+#define CS4245_ADC_MASTER 0x01
+
+/* MCLK Frequency */
+#define CS4245_MCLK1_MASK 0x70
+#define CS4245_MCLK1_SHIFT 4
+#define CS4245_MCLK2_MASK 0x07
+#define CS4245_MCLK2_SHIFT 0
+#define CS4245_MCLK_1 0
+#define CS4245_MCLK_1_5 1
+#define CS4245_MCLK_2 2
+#define CS4245_MCLK_3 3
+#define CS4245_MCLK_4 4
+
+/* Signal Selection */
+#define CS4245_A_OUT_SEL_MASK 0x60
+#define CS4245_A_OUT_SEL_HIZ 0x00
+#define CS4245_A_OUT_SEL_DAC 0x20
+#define CS4245_A_OUT_SEL_PGA 0x40
+#define CS4245_LOOP 0x02
+#define CS4245_ASYNCH 0x01
+
+/* Channel B/A PGA Control */
+#define CS4245_PGA_GAIN_MASK 0x3f
+
+/* ADC Input Control */
+#define CS4245_PGA_SOFT 0x10
+#define CS4245_PGA_ZERO 0x08
+#define CS4245_SEL_MASK 0x07
+#define CS4245_SEL_MIC 0x00
+#define CS4245_SEL_INPUT_1 0x01
+#define CS4245_SEL_INPUT_2 0x02
+#define CS4245_SEL_INPUT_3 0x03
+#define CS4245_SEL_INPUT_4 0x04
+#define CS4245_SEL_INPUT_5 0x05
+#define CS4245_SEL_INPUT_6 0x06
+
+/* DAC Channel A/B Volume Control */
+#define CS4245_VOL_MASK 0xff
+
+/* DAC Control 2 */
+#define CS4245_DAC_SOFT 0x80
+#define CS4245_DAC_ZERO 0x40
+#define CS4245_INVERT_DAC 0x20
+#define CS4245_INT_ACTIVE_HIGH 0x01
+
+/* Interrupt Status/Mask/Mode */
+#define CS4245_ADC_CLK_ERR 0x08
+#define CS4245_DAC_CLK_ERR 0x04
+#define CS4245_ADC_OVFL 0x02
+#define CS4245_ADC_UNDRFL 0x01
+
+
+#define CS4245_SPI_ADDRESS (0x9e << 16)
+#define CS4245_SPI_WRITE (0 << 16)
diff --git a/sound/pci/oxygen/hifier.c b/sound/pci/oxygen/hifier.c
deleted file mode 100644
index 5a87d683691..00000000000
--- a/sound/pci/oxygen/hifier.c
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * C-Media CMI8788 driver for the MediaTek/TempoTec HiFier Fantasia
- *
- * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
- *
- *
- * This driver is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2.
- *
- * This driver is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this driver; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/*
- * CMI8788:
- *
- * SPI 0 -> AK4396
- */
-
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <sound/control.h>
-#include <sound/core.h>
-#include <sound/initval.h>
-#include <sound/pcm.h>
-#include <sound/tlv.h>
-#include "oxygen.h"
-#include "ak4396.h"
-
-MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
-MODULE_DESCRIPTION("TempoTec HiFier driver");
-MODULE_LICENSE("GPL v2");
-
-static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
-static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
-
-module_param_array(index, int, NULL, 0444);
-MODULE_PARM_DESC(index, "card index");
-module_param_array(id, charp, NULL, 0444);
-MODULE_PARM_DESC(id, "ID string");
-module_param_array(enable, bool, NULL, 0444);
-MODULE_PARM_DESC(enable, "enable card");
-
-static DEFINE_PCI_DEVICE_TABLE(hifier_ids) = {
- { OXYGEN_PCI_SUBID(0x14c3, 0x1710) },
- { OXYGEN_PCI_SUBID(0x14c3, 0x1711) },
- { OXYGEN_PCI_SUBID_BROKEN_EEPROM },
- { }
-};
-MODULE_DEVICE_TABLE(pci, hifier_ids);
-
-struct hifier_data {
- u8 ak4396_regs[5];
-};
-
-static void ak4396_write(struct oxygen *chip, u8 reg, u8 value)
-{
- struct hifier_data *data = chip->model_data;
-
- oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
- OXYGEN_SPI_DATA_LENGTH_2 |
- OXYGEN_SPI_CLOCK_160 |
- (0 << OXYGEN_SPI_CODEC_SHIFT) |
- OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
- AK4396_WRITE | (reg << 8) | value);
- data->ak4396_regs[reg] = value;
-}
-
-static void ak4396_write_cached(struct oxygen *chip, u8 reg, u8 value)
-{
- struct hifier_data *data = chip->model_data;
-
- if (value != data->ak4396_regs[reg])
- ak4396_write(chip, reg, value);
-}
-
-static void hifier_registers_init(struct oxygen *chip)
-{
- struct hifier_data *data = chip->model_data;
-
- ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN);
- ak4396_write(chip, AK4396_CONTROL_2,
- data->ak4396_regs[AK4396_CONTROL_2]);
- ak4396_write(chip, AK4396_CONTROL_3, AK4396_PCM);
- ak4396_write(chip, AK4396_LCH_ATT, chip->dac_volume[0]);
- ak4396_write(chip, AK4396_RCH_ATT, chip->dac_volume[1]);
-}
-
-static void hifier_init(struct oxygen *chip)
-{
- struct hifier_data *data = chip->model_data;
-
- data->ak4396_regs[AK4396_CONTROL_2] =
- AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL;
- hifier_registers_init(chip);
-
- snd_component_add(chip->card, "AK4396");
- snd_component_add(chip->card, "CS5340");
-}
-
-static void hifier_cleanup(struct oxygen *chip)
-{
-}
-
-static void hifier_resume(struct oxygen *chip)
-{
- hifier_registers_init(chip);
-}
-
-static void set_ak4396_params(struct oxygen *chip,
- struct snd_pcm_hw_params *params)
-{
- struct hifier_data *data = chip->model_data;
- u8 value;
-
- value = data->ak4396_regs[AK4396_CONTROL_2] & ~AK4396_DFS_MASK;
- if (params_rate(params) <= 54000)
- value |= AK4396_DFS_NORMAL;
- else if (params_rate(params) <= 108000)
- value |= AK4396_DFS_DOUBLE;
- else
- value |= AK4396_DFS_QUAD;
-
- msleep(1); /* wait for the new MCLK to become stable */
-
- if (value != data->ak4396_regs[AK4396_CONTROL_2]) {
- ak4396_write(chip, AK4396_CONTROL_1,
- AK4396_DIF_24_MSB);
- ak4396_write(chip, AK4396_CONTROL_2, value);
- ak4396_write(chip, AK4396_CONTROL_1,
- AK4396_DIF_24_MSB | AK4396_RSTN);
- }
-}
-
-static void update_ak4396_volume(struct oxygen *chip)
-{
- ak4396_write_cached(chip, AK4396_LCH_ATT, chip->dac_volume[0]);
- ak4396_write_cached(chip, AK4396_RCH_ATT, chip->dac_volume[1]);
-}
-
-static void update_ak4396_mute(struct oxygen *chip)
-{
- struct hifier_data *data = chip->model_data;
- u8 value;
-
- value = data->ak4396_regs[AK4396_CONTROL_2] & ~AK4396_SMUTE;
- if (chip->dac_mute)
- value |= AK4396_SMUTE;
- ak4396_write_cached(chip, AK4396_CONTROL_2, value);
-}
-
-static void set_cs5340_params(struct oxygen *chip,
- struct snd_pcm_hw_params *params)
-{
-}
-
-static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0);
-
-static const struct oxygen_model model_hifier = {
- .shortname = "C-Media CMI8787",
- .longname = "C-Media Oxygen HD Audio",
- .chip = "CMI8788",
- .init = hifier_init,
- .cleanup = hifier_cleanup,
- .resume = hifier_resume,
- .get_i2s_mclk = oxygen_default_i2s_mclk,
- .set_dac_params = set_ak4396_params,
- .set_adc_params = set_cs5340_params,
- .update_dac_volume = update_ak4396_volume,
- .update_dac_mute = update_ak4396_mute,
- .dac_tlv = ak4396_db_scale,
- .model_data_size = sizeof(struct hifier_data),
- .device_config = PLAYBACK_0_TO_I2S |
- PLAYBACK_1_TO_SPDIF |
- CAPTURE_0_FROM_I2S_1,
- .dac_channels = 2,
- .dac_volume_min = 0,
- .dac_volume_max = 255,
- .function_flags = OXYGEN_FUNCTION_SPI,
- .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
- .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-};
-
-static int __devinit get_hifier_model(struct oxygen *chip,
- const struct pci_device_id *id)
-{
- chip->model = model_hifier;
- return 0;
-}
-
-static int __devinit hifier_probe(struct pci_dev *pci,
- const struct pci_device_id *pci_id)
-{
- static int dev;
- int err;
-
- if (dev >= SNDRV_CARDS)
- return -ENODEV;
- if (!enable[dev]) {
- ++dev;
- return -ENOENT;
- }
- err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE,
- hifier_ids, get_hifier_model);
- if (err >= 0)
- ++dev;
- return err;
-}
-
-static struct pci_driver hifier_driver = {
- .name = "CMI8787HiFier",
- .id_table = hifier_ids,
- .probe = hifier_probe,
- .remove = __devexit_p(oxygen_pci_remove),
-#ifdef CONFIG_PM
- .suspend = oxygen_pci_suspend,
- .resume = oxygen_pci_resume,
-#endif
-};
-
-static int __init alsa_card_hifier_init(void)
-{
- return pci_register_driver(&hifier_driver);
-}
-
-static void __exit alsa_card_hifier_exit(void)
-{
- pci_unregister_driver(&hifier_driver);
-}
-
-module_init(alsa_card_hifier_init)
-module_exit(alsa_card_hifier_exit)
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c
index 98a8eb3c92f..d7e8ddd9a67 100644
--- a/sound/pci/oxygen/oxygen.c
+++ b/sound/pci/oxygen/oxygen.c
@@ -20,19 +20,32 @@
/*
* CMI8788:
*
- * SPI 0 -> 1st AK4396 (front)
- * SPI 1 -> 2nd AK4396 (surround)
- * SPI 2 -> 3rd AK4396 (center/LFE)
- * SPI 3 -> WM8785
- * SPI 4 -> 4th AK4396 (back)
+ * SPI 0 -> 1st AK4396 (front)
+ * SPI 1 -> 2nd AK4396 (surround)
+ * SPI 2 -> 3rd AK4396 (center/LFE)
+ * SPI 3 -> WM8785
+ * SPI 4 -> 4th AK4396 (back)
*
- * GPIO 0 -> DFS0 of AK5385
- * GPIO 1 -> DFS1 of AK5385
- * GPIO 8 -> enable headphone amplifier on HT-Omega models
+ * GPIO 0 -> DFS0 of AK5385
+ * GPIO 1 -> DFS1 of AK5385
+ *
+ * X-Meridian models:
+ * GPIO 4 -> enable extension S/PDIF input
+ * GPIO 6 -> enable on-board S/PDIF input
+ *
+ * Claro models:
+ * GPIO 6 -> S/PDIF from optical (0) or coaxial (1) input
+ * GPIO 8 -> enable headphone amplifier
*
* CM9780:
*
- * GPO 0 -> route line-in (0) or AC97 output (1) to ADC input
+ * LINE_OUT -> input of ADC
+ *
+ * AUX_IN <- aux
+ * CD_IN <- CD
+ * MIC_IN <- mic
+ *
+ * GPO 0 -> route line-in (0) or AC97 output (1) to ADC input
*/
#include <linux/delay.h>
@@ -41,18 +54,22 @@
#include <sound/ac97_codec.h>
#include <sound/control.h>
#include <sound/core.h>
+#include <sound/info.h>
#include <sound/initval.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/tlv.h>
#include "oxygen.h"
+#include "xonar_dg.h"
#include "ak4396.h"
#include "wm8785.h"
MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
MODULE_DESCRIPTION("C-Media CMI8788 driver");
MODULE_LICENSE("GPL v2");
-MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8788}}");
+MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8786}"
+ ",{C-Media,CMI8787}"
+ ",{C-Media,CMI8788}}");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
@@ -66,24 +83,46 @@ module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "enable card");
enum {
- MODEL_CMEDIA_REF, /* C-Media's reference design */
- MODEL_MERIDIAN, /* AuzenTech X-Meridian */
- MODEL_CLARO, /* HT-Omega Claro */
- MODEL_CLARO_HALO, /* HT-Omega Claro halo */
+ MODEL_CMEDIA_REF,
+ MODEL_MERIDIAN,
+ MODEL_MERIDIAN_2G,
+ MODEL_CLARO,
+ MODEL_CLARO_HALO,
+ MODEL_FANTASIA,
+ MODEL_SERENADE,
+ MODEL_2CH_OUTPUT,
+ MODEL_HG2PCI,
+ MODEL_XONAR_DG,
};
static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = {
+ /* C-Media's reference design */
{ OXYGEN_PCI_SUBID(0x10b0, 0x0216), .driver_data = MODEL_CMEDIA_REF },
+ { OXYGEN_PCI_SUBID(0x10b0, 0x0217), .driver_data = MODEL_CMEDIA_REF },
{ OXYGEN_PCI_SUBID(0x10b0, 0x0218), .driver_data = MODEL_CMEDIA_REF },
{ OXYGEN_PCI_SUBID(0x10b0, 0x0219), .driver_data = MODEL_CMEDIA_REF },
{ OXYGEN_PCI_SUBID(0x13f6, 0x0001), .driver_data = MODEL_CMEDIA_REF },
{ OXYGEN_PCI_SUBID(0x13f6, 0x0010), .driver_data = MODEL_CMEDIA_REF },
{ OXYGEN_PCI_SUBID(0x13f6, 0x8788), .driver_data = MODEL_CMEDIA_REF },
- { OXYGEN_PCI_SUBID(0x13f6, 0xffff), .driver_data = MODEL_CMEDIA_REF },
{ OXYGEN_PCI_SUBID(0x147a, 0xa017), .driver_data = MODEL_CMEDIA_REF },
{ OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF },
+ /* Asus Xonar DG */
+ { OXYGEN_PCI_SUBID(0x1043, 0x8467), .driver_data = MODEL_XONAR_DG },
+ /* PCI 2.0 HD Audio */
+ { OXYGEN_PCI_SUBID(0x13f6, 0x8782), .driver_data = MODEL_2CH_OUTPUT },
+ /* Kuroutoshikou CMI8787-HG2PCI */
+ { OXYGEN_PCI_SUBID(0x13f6, 0xffff), .driver_data = MODEL_HG2PCI },
+ /* TempoTec HiFier Fantasia */
+ { OXYGEN_PCI_SUBID(0x14c3, 0x1710), .driver_data = MODEL_FANTASIA },
+ /* TempoTec HiFier Serenade */
+ { OXYGEN_PCI_SUBID(0x14c3, 0x1711), .driver_data = MODEL_SERENADE },
+ /* AuzenTech X-Meridian */
{ OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN },
+ /* AuzenTech X-Meridian 2G */
+ { OXYGEN_PCI_SUBID(0x5431, 0x017a), .driver_data = MODEL_MERIDIAN_2G },
+ /* HT-Omega Claro */
{ OXYGEN_PCI_SUBID(0x7284, 0x9761), .driver_data = MODEL_CLARO },
+ /* HT-Omega Claro halo */
{ OXYGEN_PCI_SUBID(0x7284, 0x9781), .driver_data = MODEL_CLARO_HALO },
{ }
};
@@ -95,9 +134,15 @@ MODULE_DEVICE_TABLE(pci, oxygen_ids);
#define GPIO_AK5385_DFS_DOUBLE 0x0001
#define GPIO_AK5385_DFS_QUAD 0x0002
+#define GPIO_MERIDIAN_DIG_MASK 0x0050
+#define GPIO_MERIDIAN_DIG_EXT 0x0010
+#define GPIO_MERIDIAN_DIG_BOARD 0x0040
+
+#define GPIO_CLARO_DIG_COAX 0x0040
#define GPIO_CLARO_HP 0x0100
struct generic_data {
+ unsigned int dacs;
u8 ak4396_regs[4][5];
u16 wm8785_regs[3];
};
@@ -148,7 +193,7 @@ static void ak4396_registers_init(struct oxygen *chip)
struct generic_data *data = chip->model_data;
unsigned int i;
- for (i = 0; i < 4; ++i) {
+ for (i = 0; i < data->dacs; ++i) {
ak4396_write(chip, i, AK4396_CONTROL_1,
AK4396_DIF_24_MSB | AK4396_RSTN);
ak4396_write(chip, i, AK4396_CONTROL_2,
@@ -166,6 +211,7 @@ static void ak4396_init(struct oxygen *chip)
{
struct generic_data *data = chip->model_data;
+ data->dacs = chip->model.dac_channels_pcm / 2;
data->ak4396_regs[0][AK4396_CONTROL_2] =
AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL;
ak4396_registers_init(chip);
@@ -207,6 +253,10 @@ static void generic_init(struct oxygen *chip)
static void meridian_init(struct oxygen *chip)
{
+ oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
+ GPIO_MERIDIAN_DIG_MASK);
+ oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
+ GPIO_MERIDIAN_DIG_BOARD, GPIO_MERIDIAN_DIG_MASK);
ak4396_init(chip);
ak5385_init(chip);
}
@@ -220,6 +270,8 @@ static void claro_enable_hp(struct oxygen *chip)
static void claro_init(struct oxygen *chip)
{
+ oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CLARO_DIG_COAX);
+ oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_DIG_COAX);
ak4396_init(chip);
wm8785_init(chip);
claro_enable_hp(chip);
@@ -227,11 +279,24 @@ static void claro_init(struct oxygen *chip)
static void claro_halo_init(struct oxygen *chip)
{
+ oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CLARO_DIG_COAX);
+ oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_DIG_COAX);
ak4396_init(chip);
ak5385_init(chip);
claro_enable_hp(chip);
}
+static void fantasia_init(struct oxygen *chip)
+{
+ ak4396_init(chip);
+ snd_component_add(chip->card, "CS5340");
+}
+
+static void stereo_output_init(struct oxygen *chip)
+{
+ ak4396_init(chip);
+}
+
static void generic_cleanup(struct oxygen *chip)
{
}
@@ -268,6 +333,11 @@ static void claro_resume(struct oxygen *chip)
claro_enable_hp(chip);
}
+static void stereo_resume(struct oxygen *chip)
+{
+ ak4396_registers_init(chip);
+}
+
static void set_ak4396_params(struct oxygen *chip,
struct snd_pcm_hw_params *params)
{
@@ -286,7 +356,7 @@ static void set_ak4396_params(struct oxygen *chip,
msleep(1); /* wait for the new MCLK to become stable */
if (value != data->ak4396_regs[0][AK4396_CONTROL_2]) {
- for (i = 0; i < 4; ++i) {
+ for (i = 0; i < data->dacs; ++i) {
ak4396_write(chip, i, AK4396_CONTROL_1,
AK4396_DIF_24_MSB);
ak4396_write(chip, i, AK4396_CONTROL_2, value);
@@ -298,9 +368,10 @@ static void set_ak4396_params(struct oxygen *chip,
static void update_ak4396_volume(struct oxygen *chip)
{
+ struct generic_data *data = chip->model_data;
unsigned int i;
- for (i = 0; i < 4; ++i) {
+ for (i = 0; i < data->dacs; ++i) {
ak4396_write_cached(chip, i, AK4396_LCH_ATT,
chip->dac_volume[i * 2]);
ak4396_write_cached(chip, i, AK4396_RCH_ATT,
@@ -317,7 +388,7 @@ static void update_ak4396_mute(struct oxygen *chip)
value = data->ak4396_regs[0][AK4396_CONTROL_2] & ~AK4396_SMUTE;
if (chip->dac_mute)
value |= AK4396_SMUTE;
- for (i = 0; i < 4; ++i)
+ for (i = 0; i < data->dacs; ++i)
ak4396_write_cached(chip, i, AK4396_CONTROL_2, value);
}
@@ -356,6 +427,10 @@ static void set_ak5385_params(struct oxygen *chip,
value, GPIO_AK5385_DFS_MASK);
}
+static void set_no_params(struct oxygen *chip, struct snd_pcm_hw_params *params)
+{
+}
+
static int rolloff_info(struct snd_kcontrol *ctl,
struct snd_ctl_elem_info *info)
{
@@ -363,13 +438,7 @@ static int rolloff_info(struct snd_kcontrol *ctl,
"Sharp Roll-off", "Slow Roll-off"
};
- info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- info->count = 1;
- info->value.enumerated.items = 2;
- if (info->value.enumerated.item >= 2)
- info->value.enumerated.item = 1;
- strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(info, 1, 2, names);
}
static int rolloff_get(struct snd_kcontrol *ctl,
@@ -400,7 +469,7 @@ static int rolloff_put(struct snd_kcontrol *ctl,
reg &= ~AK4396_SLOW;
changed = reg != data->ak4396_regs[0][AK4396_CONTROL_2];
if (changed) {
- for (i = 0; i < 4; ++i)
+ for (i = 0; i < data->dacs; ++i)
ak4396_write(chip, i, AK4396_CONTROL_2, reg);
}
mutex_unlock(&chip->mutex);
@@ -421,13 +490,7 @@ static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
"None", "High-pass Filter"
};
- info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- info->count = 1;
- info->value.enumerated.items = 2;
- if (info->value.enumerated.item >= 2)
- info->value.enumerated.item = 1;
- strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(info, 1, 2, names);
}
static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
@@ -466,6 +529,100 @@ static const struct snd_kcontrol_new hpf_control = {
.put = hpf_put,
};
+static int meridian_dig_source_info(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_info *info)
+{
+ static const char *const names[2] = { "On-board", "Extension" };
+
+ return snd_ctl_enum_info(info, 1, 2, names);
+}
+
+static int claro_dig_source_info(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_info *info)
+{
+ static const char *const names[2] = { "Optical", "Coaxial" };
+
+ return snd_ctl_enum_info(info, 1, 2, names);
+}
+
+static int meridian_dig_source_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+
+ value->value.enumerated.item[0] =
+ !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) &
+ GPIO_MERIDIAN_DIG_EXT);
+ return 0;
+}
+
+static int claro_dig_source_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+
+ value->value.enumerated.item[0] =
+ !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) &
+ GPIO_CLARO_DIG_COAX);
+ return 0;
+}
+
+static int meridian_dig_source_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ u16 old_reg, new_reg;
+ int changed;
+
+ mutex_lock(&chip->mutex);
+ old_reg = oxygen_read16(chip, OXYGEN_GPIO_DATA);
+ new_reg = old_reg & ~GPIO_MERIDIAN_DIG_MASK;
+ if (value->value.enumerated.item[0] == 0)
+ new_reg |= GPIO_MERIDIAN_DIG_BOARD;
+ else
+ new_reg |= GPIO_MERIDIAN_DIG_EXT;
+ changed = new_reg != old_reg;
+ if (changed)
+ oxygen_write16(chip, OXYGEN_GPIO_DATA, new_reg);
+ mutex_unlock(&chip->mutex);
+ return changed;
+}
+
+static int claro_dig_source_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ u16 old_reg, new_reg;
+ int changed;
+
+ mutex_lock(&chip->mutex);
+ old_reg = oxygen_read16(chip, OXYGEN_GPIO_DATA);
+ new_reg = old_reg & ~GPIO_CLARO_DIG_COAX;
+ if (value->value.enumerated.item[0])
+ new_reg |= GPIO_CLARO_DIG_COAX;
+ changed = new_reg != old_reg;
+ if (changed)
+ oxygen_write16(chip, OXYGEN_GPIO_DATA, new_reg);
+ mutex_unlock(&chip->mutex);
+ return changed;
+}
+
+static const struct snd_kcontrol_new meridian_dig_source_control = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "IEC958 Source Capture Enum",
+ .info = meridian_dig_source_info,
+ .get = meridian_dig_source_get,
+ .put = meridian_dig_source_put,
+};
+
+static const struct snd_kcontrol_new claro_dig_source_control = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "IEC958 Source Capture Enum",
+ .info = claro_dig_source_info,
+ .get = claro_dig_source_get,
+ .put = claro_dig_source_put,
+};
+
static int generic_mixer_init(struct oxygen *chip)
{
return snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip));
@@ -484,6 +641,81 @@ static int generic_wm8785_mixer_init(struct oxygen *chip)
return 0;
}
+static int meridian_mixer_init(struct oxygen *chip)
+{
+ int err;
+
+ err = generic_mixer_init(chip);
+ if (err < 0)
+ return err;
+ err = snd_ctl_add(chip->card,
+ snd_ctl_new1(&meridian_dig_source_control, chip));
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+static int claro_mixer_init(struct oxygen *chip)
+{
+ int err;
+
+ err = generic_wm8785_mixer_init(chip);
+ if (err < 0)
+ return err;
+ err = snd_ctl_add(chip->card,
+ snd_ctl_new1(&claro_dig_source_control, chip));
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+static int claro_halo_mixer_init(struct oxygen *chip)
+{
+ int err;
+
+ err = generic_mixer_init(chip);
+ if (err < 0)
+ return err;
+ err = snd_ctl_add(chip->card,
+ snd_ctl_new1(&claro_dig_source_control, chip));
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+static void dump_ak4396_registers(struct oxygen *chip,
+ struct snd_info_buffer *buffer)
+{
+ struct generic_data *data = chip->model_data;
+ unsigned int dac, i;
+
+ for (dac = 0; dac < data->dacs; ++dac) {
+ snd_iprintf(buffer, "\nAK4396 %u:", dac + 1);
+ for (i = 0; i < 5; ++i)
+ snd_iprintf(buffer, " %02x", data->ak4396_regs[dac][i]);
+ }
+ snd_iprintf(buffer, "\n");
+}
+
+static void dump_wm8785_registers(struct oxygen *chip,
+ struct snd_info_buffer *buffer)
+{
+ struct generic_data *data = chip->model_data;
+ unsigned int i;
+
+ snd_iprintf(buffer, "\nWM8785:");
+ for (i = 0; i < 3; ++i)
+ snd_iprintf(buffer, " %03x", data->wm8785_regs[i]);
+ snd_iprintf(buffer, "\n");
+}
+
+static void dump_oxygen_registers(struct oxygen *chip,
+ struct snd_info_buffer *buffer)
+{
+ dump_ak4396_registers(chip, buffer);
+ dump_wm8785_registers(chip, buffer);
+}
+
static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0);
static const struct oxygen_model model_generic = {
@@ -494,11 +726,11 @@ static const struct oxygen_model model_generic = {
.mixer_init = generic_wm8785_mixer_init,
.cleanup = generic_cleanup,
.resume = generic_resume,
- .get_i2s_mclk = oxygen_default_i2s_mclk,
.set_dac_params = set_ak4396_params,
.set_adc_params = set_wm8785_params,
.update_dac_volume = update_ak4396_volume,
.update_dac_mute = update_ak4396_mute,
+ .dump_registers = dump_oxygen_registers,
.dac_tlv = ak4396_db_scale,
.model_data_size = sizeof(struct generic_data),
.device_config = PLAYBACK_0_TO_I2S |
@@ -508,11 +740,14 @@ static const struct oxygen_model model_generic = {
CAPTURE_1_FROM_SPDIF |
CAPTURE_2_FROM_AC97_1 |
AC97_CD_INPUT,
- .dac_channels = 8,
+ .dac_channels_pcm = 8,
+ .dac_channels_mixer = 8,
.dac_volume_min = 0,
.dac_volume_max = 255,
.function_flags = OXYGEN_FUNCTION_SPI |
OXYGEN_FUNCTION_ENABLE_SPI_4_5,
+ .dac_mclks = OXYGEN_MCLKS(256, 128, 128),
+ .adc_mclks = OXYGEN_MCLKS(256, 256, 128),
.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
};
@@ -520,42 +755,87 @@ static const struct oxygen_model model_generic = {
static int __devinit get_oxygen_model(struct oxygen *chip,
const struct pci_device_id *id)
{
+ static const char *const names[] = {
+ [MODEL_MERIDIAN] = "AuzenTech X-Meridian",
+ [MODEL_MERIDIAN_2G] = "AuzenTech X-Meridian 2G",
+ [MODEL_CLARO] = "HT-Omega Claro",
+ [MODEL_CLARO_HALO] = "HT-Omega Claro halo",
+ [MODEL_FANTASIA] = "TempoTec HiFier Fantasia",
+ [MODEL_SERENADE] = "TempoTec HiFier Serenade",
+ [MODEL_HG2PCI] = "CMI8787-HG2PCI",
+ };
+
chip->model = model_generic;
switch (id->driver_data) {
case MODEL_MERIDIAN:
+ case MODEL_MERIDIAN_2G:
chip->model.init = meridian_init;
- chip->model.mixer_init = generic_mixer_init;
+ chip->model.mixer_init = meridian_mixer_init;
chip->model.resume = meridian_resume;
chip->model.set_adc_params = set_ak5385_params;
+ chip->model.dump_registers = dump_ak4396_registers;
chip->model.device_config = PLAYBACK_0_TO_I2S |
PLAYBACK_1_TO_SPDIF |
CAPTURE_0_FROM_I2S_2 |
CAPTURE_1_FROM_SPDIF;
+ if (id->driver_data == MODEL_MERIDIAN)
+ chip->model.device_config |= AC97_CD_INPUT;
break;
case MODEL_CLARO:
chip->model.init = claro_init;
+ chip->model.mixer_init = claro_mixer_init;
chip->model.cleanup = claro_cleanup;
chip->model.suspend = claro_suspend;
chip->model.resume = claro_resume;
break;
case MODEL_CLARO_HALO:
chip->model.init = claro_halo_init;
- chip->model.mixer_init = generic_mixer_init;
+ chip->model.mixer_init = claro_halo_mixer_init;
chip->model.cleanup = claro_cleanup;
chip->model.suspend = claro_suspend;
chip->model.resume = claro_resume;
chip->model.set_adc_params = set_ak5385_params;
+ chip->model.dump_registers = dump_ak4396_registers;
chip->model.device_config = PLAYBACK_0_TO_I2S |
PLAYBACK_1_TO_SPDIF |
CAPTURE_0_FROM_I2S_2 |
CAPTURE_1_FROM_SPDIF;
break;
+ case MODEL_FANTASIA:
+ case MODEL_SERENADE:
+ case MODEL_2CH_OUTPUT:
+ case MODEL_HG2PCI:
+ chip->model.shortname = "C-Media CMI8787";
+ chip->model.chip = "CMI8787";
+ if (id->driver_data == MODEL_FANTASIA)
+ chip->model.init = fantasia_init;
+ else
+ chip->model.init = stereo_output_init;
+ chip->model.resume = stereo_resume;
+ chip->model.mixer_init = generic_mixer_init;
+ chip->model.set_adc_params = set_no_params;
+ chip->model.dump_registers = dump_ak4396_registers;
+ chip->model.device_config = PLAYBACK_0_TO_I2S |
+ PLAYBACK_1_TO_SPDIF;
+ if (id->driver_data == MODEL_FANTASIA) {
+ chip->model.device_config |= CAPTURE_0_FROM_I2S_1;
+ chip->model.adc_mclks = OXYGEN_MCLKS(256, 128, 128);
+ }
+ chip->model.dac_channels_pcm = 2;
+ chip->model.dac_channels_mixer = 2;
+ break;
+ case MODEL_XONAR_DG:
+ chip->model = model_xonar_dg;
+ break;
}
if (id->driver_data == MODEL_MERIDIAN ||
+ id->driver_data == MODEL_MERIDIAN_2G ||
id->driver_data == MODEL_CLARO_HALO) {
chip->model.misc_flags = OXYGEN_MISC_MIDI;
chip->model.device_config |= MIDI_OUTPUT | MIDI_INPUT;
}
+ if (id->driver_data < ARRAY_SIZE(names) && names[id->driver_data])
+ chip->model.shortname = names[id->driver_data];
return 0;
}
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h
index 7d5222caa0a..f53897a708b 100644
--- a/sound/pci/oxygen/oxygen.h
+++ b/sound/pci/oxygen/oxygen.h
@@ -16,6 +16,10 @@
#define PCM_AC97 5
#define PCM_COUNT 6
+#define OXYGEN_MCLKS(f_single, f_double, f_quad) ((MCLK_##f_single << 0) | \
+ (MCLK_##f_double << 2) | \
+ (MCLK_##f_quad << 4))
+
#define OXYGEN_IO_SIZE 0x100
#define OXYGEN_EEPROM_ID 0x434d /* "CM" */
@@ -35,6 +39,7 @@
#define MIDI_OUTPUT 0x0800
#define MIDI_INPUT 0x1000
#define AC97_CD_INPUT 0x2000
+#define AC97_FMIC_SWITCH 0x4000
enum {
CONTROL_SPDIF_PCM,
@@ -65,6 +70,7 @@ struct snd_pcm_hardware;
struct snd_pcm_hw_params;
struct snd_kcontrol_new;
struct snd_rawmidi;
+struct snd_info_buffer;
struct oxygen;
struct oxygen_model {
@@ -79,8 +85,6 @@ struct oxygen_model {
void (*resume)(struct oxygen *chip);
void (*pcm_hardware_filter)(unsigned int channel,
struct snd_pcm_hardware *hardware);
- unsigned int (*get_i2s_mclk)(struct oxygen *chip, unsigned int channel,
- struct snd_pcm_hw_params *hw_params);
void (*set_dac_params)(struct oxygen *chip,
struct snd_pcm_hw_params *params);
void (*set_adc_params)(struct oxygen *chip,
@@ -88,19 +92,25 @@ struct oxygen_model {
void (*update_dac_volume)(struct oxygen *chip);
void (*update_dac_mute)(struct oxygen *chip);
void (*update_center_lfe_mix)(struct oxygen *chip, bool mixed);
+ unsigned int (*adjust_dac_routing)(struct oxygen *chip,
+ unsigned int play_routing);
void (*gpio_changed)(struct oxygen *chip);
void (*uart_input)(struct oxygen *chip);
void (*ac97_switch)(struct oxygen *chip,
unsigned int reg, unsigned int mute);
+ void (*dump_registers)(struct oxygen *chip,
+ struct snd_info_buffer *buffer);
const unsigned int *dac_tlv;
- unsigned long private_data;
size_t model_data_size;
unsigned int device_config;
- u8 dac_channels;
+ u8 dac_channels_pcm;
+ u8 dac_channels_mixer;
u8 dac_volume_min;
u8 dac_volume_max;
u8 misc_flags;
u8 function_flags;
+ u8 dac_mclks;
+ u8 adc_mclks;
u16 dac_i2s_format;
u16 adc_i2s_format;
};
@@ -121,7 +131,6 @@ struct oxygen {
u8 pcm_running;
u8 dac_routing;
u8 spdif_playback_enable;
- u8 revision;
u8 has_ac97_0;
u8 has_ac97_1;
u32 spdif_bits;
@@ -167,8 +176,6 @@ void oxygen_update_spdif_source(struct oxygen *chip);
/* oxygen_pcm.c */
int oxygen_pcm_init(struct oxygen *chip);
-unsigned int oxygen_default_i2s_mclk(struct oxygen *chip, unsigned int channel,
- struct snd_pcm_hw_params *hw_params);
/* oxygen_io.c */
diff --git a/sound/pci/oxygen/oxygen_io.c b/sound/pci/oxygen/oxygen_io.c
index 09b2b2a36df..f5164b1e1c8 100644
--- a/sound/pci/oxygen/oxygen_io.c
+++ b/sound/pci/oxygen/oxygen_io.c
@@ -197,11 +197,11 @@ void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data)
{
unsigned int count;
- /* should not need more than 7.68 us (24 * 320 ns) */
+ /* should not need more than 30.72 us (24 * 1.28 us) */
count = 10;
while ((oxygen_read8(chip, OXYGEN_SPI_CONTROL) & OXYGEN_SPI_BUSY)
&& count > 0) {
- udelay(1);
+ udelay(4);
--count;
}
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c
index e5ebe56fb0c..70b739816fc 100644
--- a/sound/pci/oxygen/oxygen_lib.c
+++ b/sound/pci/oxygen/oxygen_lib.c
@@ -202,7 +202,13 @@ static void oxygen_proc_read(struct snd_info_entry *entry,
struct oxygen *chip = entry->private_data;
int i, j;
- snd_iprintf(buffer, "CMI8788\n\n");
+ switch (oxygen_read8(chip, OXYGEN_REVISION) & OXYGEN_PACKAGE_ID_MASK) {
+ case OXYGEN_PACKAGE_ID_8786: i = '6'; break;
+ case OXYGEN_PACKAGE_ID_8787: i = '7'; break;
+ case OXYGEN_PACKAGE_ID_8788: i = '8'; break;
+ default: i = '?'; break;
+ }
+ snd_iprintf(buffer, "CMI878%c:\n", i);
for (i = 0; i < OXYGEN_IO_SIZE; i += 0x10) {
snd_iprintf(buffer, "%02x:", i);
for (j = 0; j < 0x10; ++j)
@@ -212,7 +218,7 @@ static void oxygen_proc_read(struct snd_info_entry *entry,
if (mutex_lock_interruptible(&chip->mutex) < 0)
return;
if (chip->has_ac97_0) {
- snd_iprintf(buffer, "\nAC97\n");
+ snd_iprintf(buffer, "\nAC97:\n");
for (i = 0; i < 0x80; i += 0x10) {
snd_iprintf(buffer, "%02x:", i);
for (j = 0; j < 0x10; j += 2)
@@ -222,7 +228,7 @@ static void oxygen_proc_read(struct snd_info_entry *entry,
}
}
if (chip->has_ac97_1) {
- snd_iprintf(buffer, "\nAC97 2\n");
+ snd_iprintf(buffer, "\nAC97 2:\n");
for (i = 0; i < 0x80; i += 0x10) {
snd_iprintf(buffer, "%02x:", i);
for (j = 0; j < 0x10; j += 2)
@@ -232,13 +238,15 @@ static void oxygen_proc_read(struct snd_info_entry *entry,
}
}
mutex_unlock(&chip->mutex);
+ if (chip->model.dump_registers)
+ chip->model.dump_registers(chip, buffer);
}
static void oxygen_proc_init(struct oxygen *chip)
{
struct snd_info_entry *entry;
- if (!snd_card_proc_new(chip->card, "cmi8788", &entry))
+ if (!snd_card_proc_new(chip->card, "oxygen", &entry))
snd_info_set_text_ops(entry, chip, oxygen_proc_read);
}
#else
@@ -262,7 +270,7 @@ oxygen_search_pci_id(struct oxygen *chip, const struct pci_device_id ids[])
*/
subdevice = oxygen_read_eeprom(chip, 2);
/* use default ID if EEPROM is missing */
- if (subdevice == 0xffff)
+ if (subdevice == 0xffff && oxygen_read_eeprom(chip, 1) == 0xffff)
subdevice = 0x8788;
/*
* We use only the subsystem device ID for searching because it is
@@ -364,12 +372,7 @@ static void oxygen_init(struct oxygen *chip)
(IEC958_AES1_CON_PCM_CODER << OXYGEN_SPDIF_CATEGORY_SHIFT);
chip->spdif_pcm_bits = chip->spdif_bits;
- if (oxygen_read8(chip, OXYGEN_REVISION) & OXYGEN_REVISION_2)
- chip->revision = 2;
- else
- chip->revision = 1;
-
- if (chip->revision == 1)
+ if (!(oxygen_read8(chip, OXYGEN_REVISION) & OXYGEN_REVISION_2))
oxygen_set_bits8(chip, OXYGEN_MISC,
OXYGEN_MISC_PCI_MEM_W_1_CLOCK);
@@ -406,28 +409,40 @@ static void oxygen_init(struct oxygen *chip)
(OXYGEN_FORMAT_16 << OXYGEN_MULTICH_FORMAT_SHIFT));
oxygen_write8(chip, OXYGEN_REC_CHANNELS, OXYGEN_REC_CHANNELS_2_2_2);
oxygen_write16(chip, OXYGEN_I2S_MULTICH_FORMAT,
- OXYGEN_RATE_48000 | chip->model.dac_i2s_format |
- OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 |
- OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
+ OXYGEN_RATE_48000 |
+ chip->model.dac_i2s_format |
+ OXYGEN_I2S_MCLK(chip->model.dac_mclks) |
+ OXYGEN_I2S_BITS_16 |
+ OXYGEN_I2S_MASTER |
+ OXYGEN_I2S_BCLK_64);
if (chip->model.device_config & CAPTURE_0_FROM_I2S_1)
oxygen_write16(chip, OXYGEN_I2S_A_FORMAT,
- OXYGEN_RATE_48000 | chip->model.adc_i2s_format |
- OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 |
- OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
+ OXYGEN_RATE_48000 |
+ chip->model.adc_i2s_format |
+ OXYGEN_I2S_MCLK(chip->model.adc_mclks) |
+ OXYGEN_I2S_BITS_16 |
+ OXYGEN_I2S_MASTER |
+ OXYGEN_I2S_BCLK_64);
else
oxygen_write16(chip, OXYGEN_I2S_A_FORMAT,
- OXYGEN_I2S_MASTER | OXYGEN_I2S_MUTE_MCLK);
+ OXYGEN_I2S_MASTER |
+ OXYGEN_I2S_MUTE_MCLK);
if (chip->model.device_config & (CAPTURE_0_FROM_I2S_2 |
CAPTURE_2_FROM_I2S_2))
oxygen_write16(chip, OXYGEN_I2S_B_FORMAT,
- OXYGEN_RATE_48000 | chip->model.adc_i2s_format |
- OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 |
- OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
+ OXYGEN_RATE_48000 |
+ chip->model.adc_i2s_format |
+ OXYGEN_I2S_MCLK(chip->model.adc_mclks) |
+ OXYGEN_I2S_BITS_16 |
+ OXYGEN_I2S_MASTER |
+ OXYGEN_I2S_BCLK_64);
else
oxygen_write16(chip, OXYGEN_I2S_B_FORMAT,
- OXYGEN_I2S_MASTER | OXYGEN_I2S_MUTE_MCLK);
+ OXYGEN_I2S_MASTER |
+ OXYGEN_I2S_MUTE_MCLK);
oxygen_write16(chip, OXYGEN_I2S_C_FORMAT,
- OXYGEN_I2S_MASTER | OXYGEN_I2S_MUTE_MCLK);
+ OXYGEN_I2S_MASTER |
+ OXYGEN_I2S_MUTE_MCLK);
oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL,
OXYGEN_SPDIF_OUT_ENABLE |
OXYGEN_SPDIF_LOOPBACK);
@@ -557,7 +572,8 @@ static void oxygen_card_free(struct snd_card *card)
oxygen_shutdown(chip);
if (chip->irq >= 0)
free_irq(chip->irq, chip);
- flush_scheduled_work();
+ flush_work_sync(&chip->spdif_input_bits_work);
+ flush_work_sync(&chip->gpio_work);
chip->model.cleanup(chip);
kfree(chip->model_data);
mutex_destroy(&chip->mutex);
@@ -648,8 +664,8 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
strcpy(card->driver, chip->model.chip);
strcpy(card->shortname, chip->model.shortname);
- sprintf(card->longname, "%s (rev %u) at %#lx, irq %i",
- chip->model.longname, chip->revision, chip->addr, chip->irq);
+ sprintf(card->longname, "%s at %#lx, irq %i",
+ chip->model.longname, chip->addr, chip->irq);
strcpy(card->mixername, chip->model.chip);
snd_component_add(card, chip->model.chip);
@@ -733,7 +749,8 @@ int oxygen_pci_suspend(struct pci_dev *pci, pm_message_t state)
spin_unlock_irq(&chip->reg_lock);
synchronize_irq(chip->irq);
- flush_scheduled_work();
+ flush_work_sync(&chip->spdif_input_bits_work);
+ flush_work_sync(&chip->gpio_work);
chip->interrupt_mask = saved_interrupt_mask;
pci_disable_device(pci);
diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c
index 2849b36f5f7..26c7e8bcb22 100644
--- a/sound/pci/oxygen/oxygen_mixer.c
+++ b/sound/pci/oxygen/oxygen_mixer.c
@@ -31,7 +31,7 @@ static int dac_volume_info(struct snd_kcontrol *ctl,
struct oxygen *chip = ctl->private_data;
info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- info->count = chip->model.dac_channels;
+ info->count = chip->model.dac_channels_mixer;
info->value.integer.min = chip->model.dac_volume_min;
info->value.integer.max = chip->model.dac_volume_max;
return 0;
@@ -44,7 +44,7 @@ static int dac_volume_get(struct snd_kcontrol *ctl,
unsigned int i;
mutex_lock(&chip->mutex);
- for (i = 0; i < chip->model.dac_channels; ++i)
+ for (i = 0; i < chip->model.dac_channels_mixer; ++i)
value->value.integer.value[i] = chip->dac_volume[i];
mutex_unlock(&chip->mutex);
return 0;
@@ -59,7 +59,7 @@ static int dac_volume_put(struct snd_kcontrol *ctl,
changed = 0;
mutex_lock(&chip->mutex);
- for (i = 0; i < chip->model.dac_channels; ++i)
+ for (i = 0; i < chip->model.dac_channels_mixer; ++i)
if (value->value.integer.value[i] != chip->dac_volume[i]) {
chip->dac_volume[i] = value->value.integer.value[i];
changed = 1;
@@ -97,6 +97,16 @@ static int dac_mute_put(struct snd_kcontrol *ctl,
return changed;
}
+static unsigned int upmix_item_count(struct oxygen *chip)
+{
+ if (chip->model.dac_channels_pcm < 8)
+ return 2;
+ else if (chip->model.update_center_lfe_mix)
+ return 5;
+ else
+ return 3;
+}
+
static int upmix_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
{
static const char *const names[5] = {
@@ -107,15 +117,9 @@ static int upmix_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
"Front+Surround+Center/LFE+Back",
};
struct oxygen *chip = ctl->private_data;
- unsigned int count = chip->model.update_center_lfe_mix ? 5 : 3;
+ unsigned int count = upmix_item_count(chip);
- info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- info->count = 1;
- info->value.enumerated.items = count;
- if (info->value.enumerated.item >= count)
- info->value.enumerated.item = count - 1;
- strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(info, 1, count, names);
}
static int upmix_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
@@ -176,6 +180,8 @@ void oxygen_update_dac_routing(struct oxygen *chip)
(1 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
(2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
(3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT);
+ if (chip->model.adjust_dac_routing)
+ reg_value = chip->model.adjust_dac_routing(chip, reg_value);
oxygen_write16_masked(chip, OXYGEN_PLAY_ROUTING, reg_value,
OXYGEN_PLAY_DAC0_SOURCE_MASK |
OXYGEN_PLAY_DAC1_SOURCE_MASK |
@@ -188,7 +194,7 @@ void oxygen_update_dac_routing(struct oxygen *chip)
static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
{
struct oxygen *chip = ctl->private_data;
- unsigned int count = chip->model.update_center_lfe_mix ? 5 : 3;
+ unsigned int count = upmix_item_count(chip);
int changed;
if (value->value.enumerated.item[0] >= count)
@@ -430,30 +436,31 @@ static int spdif_input_default_get(struct snd_kcontrol *ctl,
return 0;
}
-static int spdif_loopback_get(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_value *value)
+static int spdif_bit_switch_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
{
struct oxygen *chip = ctl->private_data;
+ u32 bit = ctl->private_value;
value->value.integer.value[0] =
- !!(oxygen_read32(chip, OXYGEN_SPDIF_CONTROL)
- & OXYGEN_SPDIF_LOOPBACK);
+ !!(oxygen_read32(chip, OXYGEN_SPDIF_CONTROL) & bit);
return 0;
}
-static int spdif_loopback_put(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_value *value)
+static int spdif_bit_switch_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
{
struct oxygen *chip = ctl->private_data;
+ u32 bit = ctl->private_value;
u32 oldreg, newreg;
int changed;
spin_lock_irq(&chip->reg_lock);
oldreg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL);
if (value->value.integer.value[0])
- newreg = oldreg | OXYGEN_SPDIF_LOOPBACK;
+ newreg = oldreg | bit;
else
- newreg = oldreg & ~OXYGEN_SPDIF_LOOPBACK;
+ newreg = oldreg & ~bit;
changed = newreg != oldreg;
if (changed)
oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, newreg);
@@ -644,6 +651,46 @@ static int ac97_volume_put(struct snd_kcontrol *ctl,
return change;
}
+static int mic_fmic_source_info(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_info *info)
+{
+ static const char *const names[] = { "Mic Jack", "Front Panel" };
+
+ return snd_ctl_enum_info(info, 1, 2, names);
+}
+
+static int mic_fmic_source_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+
+ mutex_lock(&chip->mutex);
+ value->value.enumerated.item[0] =
+ !!(oxygen_read_ac97(chip, 0, CM9780_JACK) & CM9780_FMIC2MIC);
+ mutex_unlock(&chip->mutex);
+ return 0;
+}
+
+static int mic_fmic_source_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ u16 oldreg, newreg;
+ int change;
+
+ mutex_lock(&chip->mutex);
+ oldreg = oxygen_read_ac97(chip, 0, CM9780_JACK);
+ if (value->value.enumerated.item[0])
+ newreg = oldreg | CM9780_FMIC2MIC;
+ else
+ newreg = oldreg & ~CM9780_FMIC2MIC;
+ change = newreg != oldreg;
+ if (change)
+ oxygen_write_ac97(chip, 0, CM9780_JACK, newreg);
+ mutex_unlock(&chip->mutex);
+ return change;
+}
+
static int ac97_fp_rec_volume_info(struct snd_kcontrol *ctl,
struct snd_ctl_elem_info *info)
{
@@ -791,8 +838,17 @@ static const struct snd_kcontrol_new spdif_input_controls[] = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = SNDRV_CTL_NAME_IEC958("Loopback ", NONE, SWITCH),
.info = snd_ctl_boolean_mono_info,
- .get = spdif_loopback_get,
- .put = spdif_loopback_put,
+ .get = spdif_bit_switch_get,
+ .put = spdif_bit_switch_put,
+ .private_value = OXYGEN_SPDIF_LOOPBACK,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = SNDRV_CTL_NAME_IEC958("Validity Check ",CAPTURE,SWITCH),
+ .info = snd_ctl_boolean_mono_info,
+ .get = spdif_bit_switch_get,
+ .put = spdif_bit_switch_put,
+ .private_value = OXYGEN_SPDIF_SPDVALID,
},
};
@@ -908,6 +964,13 @@ static const struct snd_kcontrol_new ac97_controls[] = {
AC97_VOLUME("Mic Capture Volume", 0, AC97_MIC, 0),
AC97_SWITCH("Mic Capture Switch", 0, AC97_MIC, 15, 1),
AC97_SWITCH("Mic Boost (+20dB)", 0, AC97_MIC, 6, 0),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Mic Source Capture Enum",
+ .info = mic_fmic_source_info,
+ .get = mic_fmic_source_get,
+ .put = mic_fmic_source_put,
+ },
AC97_SWITCH("Line Capture Switch", 0, AC97_LINE, 15, 1),
AC97_VOLUME("CD Capture Volume", 0, AC97_CD, 1),
AC97_SWITCH("CD Capture Switch", 0, AC97_CD, 15, 1),
@@ -970,7 +1033,10 @@ static int add_controls(struct oxygen *chip,
continue;
}
if (!strcmp(template.name, "Stereo Upmixing") &&
- chip->model.dac_channels == 2)
+ chip->model.dac_channels_pcm == 2)
+ continue;
+ if (!strcmp(template.name, "Mic Source Capture Enum") &&
+ !(chip->model.device_config & AC97_FMIC_SWITCH))
continue;
if (!strncmp(template.name, "CD Capture ", 11) &&
!(chip->model.device_config & AC97_CD_INPUT))
diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c
index 814667442eb..d5533e34ece 100644
--- a/sound/pci/oxygen/oxygen_pcm.c
+++ b/sound/pci/oxygen/oxygen_pcm.c
@@ -39,7 +39,8 @@ static const struct snd_pcm_hardware oxygen_stereo_hardware = {
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE |
- SNDRV_PCM_INFO_SYNC_START,
+ SNDRV_PCM_INFO_SYNC_START |
+ SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.rates = SNDRV_PCM_RATE_32000 |
@@ -65,7 +66,8 @@ static const struct snd_pcm_hardware oxygen_multichannel_hardware = {
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE |
- SNDRV_PCM_INFO_SYNC_START,
+ SNDRV_PCM_INFO_SYNC_START |
+ SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.rates = SNDRV_PCM_RATE_32000 |
@@ -91,7 +93,8 @@ static const struct snd_pcm_hardware oxygen_ac97_hardware = {
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE |
- SNDRV_PCM_INFO_SYNC_START,
+ SNDRV_PCM_INFO_SYNC_START |
+ SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.rates = SNDRV_PCM_RATE_48000,
.rate_min = 48000,
@@ -140,7 +143,7 @@ static int oxygen_open(struct snd_pcm_substream *substream,
runtime->hw.rate_min = 44100;
break;
case PCM_MULTICH:
- runtime->hw.channels_max = chip->model.dac_channels;
+ runtime->hw.channels_max = chip->model.dac_channels_pcm;
break;
}
if (chip->model.pcm_hardware_filter)
@@ -271,17 +274,6 @@ static unsigned int oxygen_rate(struct snd_pcm_hw_params *hw_params)
}
}
-unsigned int oxygen_default_i2s_mclk(struct oxygen *chip,
- unsigned int channel,
- struct snd_pcm_hw_params *hw_params)
-{
- if (params_rate(hw_params) <= 96000)
- return OXYGEN_I2S_MCLK_256;
- else
- return OXYGEN_I2S_MCLK_128;
-}
-EXPORT_SYMBOL(oxygen_default_i2s_mclk);
-
static unsigned int oxygen_i2s_bits(struct snd_pcm_hw_params *hw_params)
{
if (params_format(hw_params) == SNDRV_PCM_FORMAT_S32_LE)
@@ -341,6 +333,26 @@ static int oxygen_hw_params(struct snd_pcm_substream *substream,
return 0;
}
+static u16 get_mclk(struct oxygen *chip, unsigned int channel,
+ struct snd_pcm_hw_params *params)
+{
+ unsigned int mclks, shift;
+
+ if (channel == PCM_MULTICH)
+ mclks = chip->model.dac_mclks;
+ else
+ mclks = chip->model.adc_mclks;
+
+ if (params_rate(params) <= 48000)
+ shift = 0;
+ else if (params_rate(params) <= 96000)
+ shift = 2;
+ else
+ shift = 4;
+
+ return OXYGEN_I2S_MCLK(mclks >> shift);
+}
+
static int oxygen_rec_a_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
@@ -357,8 +369,8 @@ static int oxygen_rec_a_hw_params(struct snd_pcm_substream *substream,
OXYGEN_REC_FORMAT_A_MASK);
oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT,
oxygen_rate(hw_params) |
- chip->model.get_i2s_mclk(chip, PCM_A, hw_params) |
chip->model.adc_i2s_format |
+ get_mclk(chip, PCM_A, hw_params) |
oxygen_i2s_bits(hw_params),
OXYGEN_I2S_RATE_MASK |
OXYGEN_I2S_FORMAT_MASK |
@@ -393,9 +405,8 @@ static int oxygen_rec_b_hw_params(struct snd_pcm_substream *substream,
if (!is_ac97)
oxygen_write16_masked(chip, OXYGEN_I2S_B_FORMAT,
oxygen_rate(hw_params) |
- chip->model.get_i2s_mclk(chip, PCM_B,
- hw_params) |
chip->model.adc_i2s_format |
+ get_mclk(chip, PCM_B, hw_params) |
oxygen_i2s_bits(hw_params),
OXYGEN_I2S_RATE_MASK |
OXYGEN_I2S_FORMAT_MASK |
@@ -476,8 +487,7 @@ static int oxygen_multich_hw_params(struct snd_pcm_substream *substream,
oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT,
oxygen_rate(hw_params) |
chip->model.dac_i2s_format |
- chip->model.get_i2s_mclk(chip, PCM_MULTICH,
- hw_params) |
+ get_mclk(chip, PCM_MULTICH, hw_params) |
oxygen_i2s_bits(hw_params),
OXYGEN_I2S_RATE_MASK |
OXYGEN_I2S_FORMAT_MASK |
@@ -530,7 +540,10 @@ static int oxygen_prepare(struct snd_pcm_substream *substream)
oxygen_set_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask);
oxygen_clear_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask);
- chip->interrupt_mask |= channel_mask;
+ if (substream->runtime->no_period_wakeup)
+ chip->interrupt_mask &= ~channel_mask;
+ else
+ chip->interrupt_mask |= channel_mask;
oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask);
spin_unlock_irq(&chip->reg_lock);
return 0;
diff --git a/sound/pci/oxygen/oxygen_regs.h b/sound/pci/oxygen/oxygen_regs.h
index 4dcd41b7825..63dc7a0ab55 100644
--- a/sound/pci/oxygen/oxygen_regs.h
+++ b/sound/pci/oxygen/oxygen_regs.h
@@ -139,9 +139,11 @@
#define OXYGEN_I2S_FORMAT_I2S 0x0000
#define OXYGEN_I2S_FORMAT_LJUST 0x0008
#define OXYGEN_I2S_MCLK_MASK 0x0030 /* MCLK/LRCK */
-#define OXYGEN_I2S_MCLK_128 0x0000
-#define OXYGEN_I2S_MCLK_256 0x0010
-#define OXYGEN_I2S_MCLK_512 0x0020
+#define OXYGEN_I2S_MCLK_SHIFT 4
+#define MCLK_128 0
+#define MCLK_256 1
+#define MCLK_512 2
+#define OXYGEN_I2S_MCLK(f) (((f) & 3) << OXYGEN_I2S_MCLK_SHIFT)
#define OXYGEN_I2S_BITS_MASK 0x00c0
#define OXYGEN_I2S_BITS_16 0x0000
#define OXYGEN_I2S_BITS_20 0x0040
@@ -238,11 +240,11 @@
#define OXYGEN_SPI_DATA_LENGTH_MASK 0x02
#define OXYGEN_SPI_DATA_LENGTH_2 0x00
#define OXYGEN_SPI_DATA_LENGTH_3 0x02
-#define OXYGEN_SPI_CLOCK_MASK 0xc0
+#define OXYGEN_SPI_CLOCK_MASK 0x0c
#define OXYGEN_SPI_CLOCK_160 0x00 /* ns */
-#define OXYGEN_SPI_CLOCK_320 0x40
-#define OXYGEN_SPI_CLOCK_640 0x80
-#define OXYGEN_SPI_CLOCK_1280 0xc0
+#define OXYGEN_SPI_CLOCK_320 0x04
+#define OXYGEN_SPI_CLOCK_640 0x08
+#define OXYGEN_SPI_CLOCK_1280 0x0c
#define OXYGEN_SPI_CODEC_MASK 0x70 /* 0..5 */
#define OXYGEN_SPI_CODEC_SHIFT 4
#define OXYGEN_SPI_CEN_MASK 0x80
diff --git a/sound/pci/oxygen/xonar.h b/sound/pci/oxygen/xonar.h
index b35343b0a9a..0434c207e81 100644
--- a/sound/pci/oxygen/xonar.h
+++ b/sound/pci/oxygen/xonar.h
@@ -24,6 +24,8 @@ void xonar_init_ext_power(struct oxygen *chip);
void xonar_init_cs53x1(struct oxygen *chip);
void xonar_set_cs53x1_params(struct oxygen *chip,
struct snd_pcm_hw_params *params);
+
+#define XONAR_GPIO_BIT_INVERT (1 << 16)
int xonar_gpio_bit_switch_get(struct snd_kcontrol *ctl,
struct snd_ctl_elem_value *value);
int xonar_gpio_bit_switch_put(struct snd_kcontrol *ctl,
diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c
index aa27c31049a..252719101c4 100644
--- a/sound/pci/oxygen/xonar_cs43xx.c
+++ b/sound/pci/oxygen/xonar_cs43xx.c
@@ -22,29 +22,28 @@
*
* CMI8788:
*
- * I²C <-> CS4398 (front)
- * <-> CS4362A (surround, center/LFE, back)
+ * I²C <-> CS4398 (addr 1001111) (front)
+ * <-> CS4362A (addr 0011000) (surround, center/LFE, back)
*
- * GPI 0 <- external power present (DX only)
+ * GPI 0 <- external power present (DX only)
*
- * GPIO 0 -> enable output to speakers
- * GPIO 1 -> enable front panel I/O
- * GPIO 2 -> M0 of CS5361
- * GPIO 3 -> M1 of CS5361
- * GPIO 8 -> route input jack to line-in (0) or mic-in (1)
+ * GPIO 0 -> enable output to speakers
+ * GPIO 1 -> route output to front panel
+ * GPIO 2 -> M0 of CS5361
+ * GPIO 3 -> M1 of CS5361
+ * GPIO 6 -> ?
+ * GPIO 7 -> ?
+ * GPIO 8 -> route input jack to line-in (0) or mic-in (1)
*
- * CS4398:
- *
- * AD0 <- 1
- * AD1 <- 1
+ * CM9780:
*
- * CS4362A:
+ * LINE_OUT -> input of ADC
*
- * AD0 <- 0
+ * AUX_IN <- aux
+ * MIC_IN <- mic
+ * FMIC_IN <- front mic
*
- * CM9780:
- *
- * GPO 0 -> route line-in (0) or AC97 output (1) to CS5361 input
+ * GPO 0 -> route line-in (0) or AC97 output (1) to CS5361 input
*/
#include <linux/pci.h>
@@ -63,6 +62,7 @@
#define GPI_EXT_POWER 0x01
#define GPIO_D1_OUTPUT_ENABLE 0x0001
#define GPIO_D1_FRONT_PANEL 0x0002
+#define GPIO_D1_MAGIC 0x00c0
#define GPIO_D1_INPUT_ROUTE 0x0100
#define I2C_DEVICE_CS4398 0x9e /* 10011, AD1=1, AD0=1, /W=0 */
@@ -169,12 +169,12 @@ static void xonar_d1_init(struct oxygen *chip)
cs43xx_registers_init(chip);
oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
- GPIO_D1_FRONT_PANEL | GPIO_D1_INPUT_ROUTE);
+ GPIO_D1_FRONT_PANEL |
+ GPIO_D1_MAGIC |
+ GPIO_D1_INPUT_ROUTE);
oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
GPIO_D1_FRONT_PANEL | GPIO_D1_INPUT_ROUTE);
- oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC);
-
xonar_init_cs53x1(chip);
xonar_enable_output(chip);
@@ -284,7 +284,7 @@ static void update_cs43xx_center_lfe_mix(struct oxygen *chip, bool mixed)
static const struct snd_kcontrol_new front_panel_switch = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Front Panel Switch",
+ .name = "Front Panel Playback Switch",
.info = snd_ctl_boolean_mono_info,
.get = xonar_gpio_bit_switch_get,
.put = xonar_gpio_bit_switch_put,
@@ -298,13 +298,7 @@ static int rolloff_info(struct snd_kcontrol *ctl,
"Fast Roll-off", "Slow Roll-off"
};
- info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- info->count = 1;
- info->value.enumerated.items = 2;
- if (info->value.enumerated.item >= 2)
- info->value.enumerated.item = 1;
- strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(info, 1, 2, names);
}
static int rolloff_get(struct snd_kcontrol *ctl,
@@ -380,6 +374,30 @@ static int xonar_d1_mixer_init(struct oxygen *chip)
return 0;
}
+static void dump_cs4362a_registers(struct xonar_cs43xx *data,
+ struct snd_info_buffer *buffer)
+{
+ unsigned int i;
+
+ snd_iprintf(buffer, "\nCS4362A:");
+ for (i = 1; i <= 14; ++i)
+ snd_iprintf(buffer, " %02x", data->cs4362a_regs[i]);
+ snd_iprintf(buffer, "\n");
+}
+
+static void dump_d1_registers(struct oxygen *chip,
+ struct snd_info_buffer *buffer)
+{
+ struct xonar_cs43xx *data = chip->model_data;
+ unsigned int i;
+
+ snd_iprintf(buffer, "\nCS4398: 7?");
+ for (i = 2; i < 8; ++i)
+ snd_iprintf(buffer, " %02x", data->cs4398_regs[i]);
+ snd_iprintf(buffer, "\n");
+ dump_cs4362a_registers(data, buffer);
+}
+
static const struct oxygen_model model_xonar_d1 = {
.longname = "Asus Virtuoso 100",
.chip = "AV200",
@@ -388,22 +406,26 @@ static const struct oxygen_model model_xonar_d1 = {
.cleanup = xonar_d1_cleanup,
.suspend = xonar_d1_suspend,
.resume = xonar_d1_resume,
- .get_i2s_mclk = oxygen_default_i2s_mclk,
.set_dac_params = set_cs43xx_params,
.set_adc_params = xonar_set_cs53x1_params,
.update_dac_volume = update_cs43xx_volume,
.update_dac_mute = update_cs43xx_mute,
.update_center_lfe_mix = update_cs43xx_center_lfe_mix,
.ac97_switch = xonar_d1_line_mic_ac97_switch,
+ .dump_registers = dump_d1_registers,
.dac_tlv = cs4362a_db_scale,
.model_data_size = sizeof(struct xonar_cs43xx),
.device_config = PLAYBACK_0_TO_I2S |
PLAYBACK_1_TO_SPDIF |
- CAPTURE_0_FROM_I2S_2,
- .dac_channels = 8,
+ CAPTURE_0_FROM_I2S_2 |
+ AC97_FMIC_SWITCH,
+ .dac_channels_pcm = 8,
+ .dac_channels_mixer = 8,
.dac_volume_min = 127 - 60,
.dac_volume_max = 127,
.function_flags = OXYGEN_FUNCTION_2WIRE,
+ .dac_mclks = OXYGEN_MCLKS(256, 128, 128),
+ .adc_mclks = OXYGEN_MCLKS(256, 128, 128),
.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
};
diff --git a/sound/pci/oxygen/xonar_dg.c b/sound/pci/oxygen/xonar_dg.c
new file mode 100644
index 00000000000..bc6eb58be38
--- /dev/null
+++ b/sound/pci/oxygen/xonar_dg.c
@@ -0,0 +1,608 @@
+/*
+ * card driver for the Xonar DG
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ *
+ *
+ * This driver is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2.
+ *
+ * This driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this driver; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Xonar DG
+ * --------
+ *
+ * CMI8788:
+ *
+ * SPI 0 -> CS4245
+ *
+ * I²S 1 -> CS4245
+ * I²S 2 -> CS4361 (center/LFE)
+ * I²S 3 -> CS4361 (surround)
+ * I²S 4 -> CS4361 (front)
+ *
+ * GPIO 3 <- ?
+ * GPIO 4 <- headphone detect
+ * GPIO 5 -> route input jack to line-in (0) or mic-in (1)
+ * GPIO 6 -> route input jack to line-in (0) or mic-in (1)
+ * GPIO 7 -> enable rear headphone amp
+ * GPIO 8 -> enable output to speakers
+ *
+ * CS4245:
+ *
+ * input 1 <- aux
+ * input 2 <- front mic
+ * input 4 <- line/mic
+ * DAC out -> headphones
+ * aux out -> front panel headphones
+ */
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <sound/control.h>
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/pcm.h>
+#include <sound/tlv.h>
+#include "oxygen.h"
+#include "xonar_dg.h"
+#include "cs4245.h"
+
+#define GPIO_MAGIC 0x0008
+#define GPIO_HP_DETECT 0x0010
+#define GPIO_INPUT_ROUTE 0x0060
+#define GPIO_HP_REAR 0x0080
+#define GPIO_OUTPUT_ENABLE 0x0100
+
+struct dg {
+ unsigned int output_sel;
+ s8 input_vol[4][2];
+ unsigned int input_sel;
+ u8 hp_vol_att;
+ u8 cs4245_regs[0x11];
+};
+
+static void cs4245_write(struct oxygen *chip, unsigned int reg, u8 value)
+{
+ struct dg *data = chip->model_data;
+
+ oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
+ OXYGEN_SPI_DATA_LENGTH_3 |
+ OXYGEN_SPI_CLOCK_1280 |
+ (0 << OXYGEN_SPI_CODEC_SHIFT) |
+ OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
+ CS4245_SPI_ADDRESS |
+ CS4245_SPI_WRITE |
+ (reg << 8) | value);
+ data->cs4245_regs[reg] = value;
+}
+
+static void cs4245_write_cached(struct oxygen *chip, unsigned int reg, u8 value)
+{
+ struct dg *data = chip->model_data;
+
+ if (value != data->cs4245_regs[reg])
+ cs4245_write(chip, reg, value);
+}
+
+static void cs4245_registers_init(struct oxygen *chip)
+{
+ struct dg *data = chip->model_data;
+
+ cs4245_write(chip, CS4245_POWER_CTRL, CS4245_PDN);
+ cs4245_write(chip, CS4245_DAC_CTRL_1,
+ data->cs4245_regs[CS4245_DAC_CTRL_1]);
+ cs4245_write(chip, CS4245_ADC_CTRL,
+ data->cs4245_regs[CS4245_ADC_CTRL]);
+ cs4245_write(chip, CS4245_SIGNAL_SEL,
+ data->cs4245_regs[CS4245_SIGNAL_SEL]);
+ cs4245_write(chip, CS4245_PGA_B_CTRL,
+ data->cs4245_regs[CS4245_PGA_B_CTRL]);
+ cs4245_write(chip, CS4245_PGA_A_CTRL,
+ data->cs4245_regs[CS4245_PGA_A_CTRL]);
+ cs4245_write(chip, CS4245_ANALOG_IN,
+ data->cs4245_regs[CS4245_ANALOG_IN]);
+ cs4245_write(chip, CS4245_DAC_A_CTRL,
+ data->cs4245_regs[CS4245_DAC_A_CTRL]);
+ cs4245_write(chip, CS4245_DAC_B_CTRL,
+ data->cs4245_regs[CS4245_DAC_B_CTRL]);
+ cs4245_write(chip, CS4245_DAC_CTRL_2,
+ CS4245_DAC_SOFT | CS4245_DAC_ZERO | CS4245_INVERT_DAC);
+ cs4245_write(chip, CS4245_INT_MASK, 0);
+ cs4245_write(chip, CS4245_POWER_CTRL, 0);
+}
+
+static void cs4245_init(struct oxygen *chip)
+{
+ struct dg *data = chip->model_data;
+
+ data->cs4245_regs[CS4245_DAC_CTRL_1] =
+ CS4245_DAC_FM_SINGLE | CS4245_DAC_DIF_LJUST;
+ data->cs4245_regs[CS4245_ADC_CTRL] =
+ CS4245_ADC_FM_SINGLE | CS4245_ADC_DIF_LJUST;
+ data->cs4245_regs[CS4245_SIGNAL_SEL] =
+ CS4245_A_OUT_SEL_HIZ | CS4245_ASYNCH;
+ data->cs4245_regs[CS4245_PGA_B_CTRL] = 0;
+ data->cs4245_regs[CS4245_PGA_A_CTRL] = 0;
+ data->cs4245_regs[CS4245_ANALOG_IN] =
+ CS4245_PGA_SOFT | CS4245_PGA_ZERO | CS4245_SEL_INPUT_4;
+ data->cs4245_regs[CS4245_DAC_A_CTRL] = 0;
+ data->cs4245_regs[CS4245_DAC_B_CTRL] = 0;
+ cs4245_registers_init(chip);
+ snd_component_add(chip->card, "CS4245");
+}
+
+static void dg_output_enable(struct oxygen *chip)
+{
+ msleep(2500);
+ oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
+}
+
+static void dg_init(struct oxygen *chip)
+{
+ struct dg *data = chip->model_data;
+
+ data->output_sel = 0;
+ data->input_sel = 3;
+ data->hp_vol_att = 2 * 16;
+
+ cs4245_init(chip);
+
+ oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
+ GPIO_MAGIC | GPIO_HP_DETECT);
+ oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
+ GPIO_INPUT_ROUTE | GPIO_HP_REAR | GPIO_OUTPUT_ENABLE);
+ oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
+ GPIO_INPUT_ROUTE | GPIO_HP_REAR);
+ dg_output_enable(chip);
+}
+
+static void dg_cleanup(struct oxygen *chip)
+{
+ oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
+}
+
+static void dg_suspend(struct oxygen *chip)
+{
+ dg_cleanup(chip);
+}
+
+static void dg_resume(struct oxygen *chip)
+{
+ cs4245_registers_init(chip);
+ dg_output_enable(chip);
+}
+
+static void set_cs4245_dac_params(struct oxygen *chip,
+ struct snd_pcm_hw_params *params)
+{
+ struct dg *data = chip->model_data;
+ u8 value;
+
+ value = data->cs4245_regs[CS4245_DAC_CTRL_1] & ~CS4245_DAC_FM_MASK;
+ if (params_rate(params) <= 50000)
+ value |= CS4245_DAC_FM_SINGLE;
+ else if (params_rate(params) <= 100000)
+ value |= CS4245_DAC_FM_DOUBLE;
+ else
+ value |= CS4245_DAC_FM_QUAD;
+ cs4245_write_cached(chip, CS4245_DAC_CTRL_1, value);
+}
+
+static void set_cs4245_adc_params(struct oxygen *chip,
+ struct snd_pcm_hw_params *params)
+{
+ struct dg *data = chip->model_data;
+ u8 value;
+
+ value = data->cs4245_regs[CS4245_ADC_CTRL] & ~CS4245_ADC_FM_MASK;
+ if (params_rate(params) <= 50000)
+ value |= CS4245_ADC_FM_SINGLE;
+ else if (params_rate(params) <= 100000)
+ value |= CS4245_ADC_FM_DOUBLE;
+ else
+ value |= CS4245_ADC_FM_QUAD;
+ cs4245_write_cached(chip, CS4245_ADC_CTRL, value);
+}
+
+static inline unsigned int shift_bits(unsigned int value,
+ unsigned int shift_from,
+ unsigned int shift_to,
+ unsigned int mask)
+{
+ if (shift_from < shift_to)
+ return (value << (shift_to - shift_from)) & mask;
+ else
+ return (value >> (shift_from - shift_to)) & mask;
+}
+
+static unsigned int adjust_dg_dac_routing(struct oxygen *chip,
+ unsigned int play_routing)
+{
+ return (play_routing & OXYGEN_PLAY_DAC0_SOURCE_MASK) |
+ shift_bits(play_routing,
+ OXYGEN_PLAY_DAC2_SOURCE_SHIFT,
+ OXYGEN_PLAY_DAC1_SOURCE_SHIFT,
+ OXYGEN_PLAY_DAC1_SOURCE_MASK) |
+ shift_bits(play_routing,
+ OXYGEN_PLAY_DAC1_SOURCE_SHIFT,
+ OXYGEN_PLAY_DAC2_SOURCE_SHIFT,
+ OXYGEN_PLAY_DAC2_SOURCE_MASK) |
+ shift_bits(play_routing,
+ OXYGEN_PLAY_DAC0_SOURCE_SHIFT,
+ OXYGEN_PLAY_DAC3_SOURCE_SHIFT,
+ OXYGEN_PLAY_DAC3_SOURCE_MASK);
+}
+
+static int output_switch_info(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_info *info)
+{
+ static const char *const names[3] = {
+ "Speakers", "Headphones", "FP Headphones"
+ };
+
+ return snd_ctl_enum_info(info, 1, 3, names);
+}
+
+static int output_switch_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+
+ mutex_lock(&chip->mutex);
+ value->value.enumerated.item[0] = data->output_sel;
+ mutex_unlock(&chip->mutex);
+ return 0;
+}
+
+static int output_switch_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+ u8 reg;
+ int changed;
+
+ if (value->value.enumerated.item[0] > 2)
+ return -EINVAL;
+
+ mutex_lock(&chip->mutex);
+ changed = value->value.enumerated.item[0] != data->output_sel;
+ if (changed) {
+ data->output_sel = value->value.enumerated.item[0];
+
+ reg = data->cs4245_regs[CS4245_SIGNAL_SEL] &
+ ~CS4245_A_OUT_SEL_MASK;
+ reg |= data->output_sel == 2 ?
+ CS4245_A_OUT_SEL_DAC : CS4245_A_OUT_SEL_HIZ;
+ cs4245_write_cached(chip, CS4245_SIGNAL_SEL, reg);
+
+ cs4245_write_cached(chip, CS4245_DAC_A_CTRL,
+ data->output_sel ? data->hp_vol_att : 0);
+ cs4245_write_cached(chip, CS4245_DAC_B_CTRL,
+ data->output_sel ? data->hp_vol_att : 0);
+
+ oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
+ data->output_sel == 1 ? GPIO_HP_REAR : 0,
+ GPIO_HP_REAR);
+ }
+ mutex_unlock(&chip->mutex);
+ return changed;
+}
+
+static int hp_volume_offset_info(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_info *info)
+{
+ static const char *const names[3] = {
+ "< 64 ohms", "64-150 ohms", "150-300 ohms"
+ };
+
+ return snd_ctl_enum_info(info, 1, 3, names);
+}
+
+static int hp_volume_offset_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+
+ mutex_lock(&chip->mutex);
+ if (data->hp_vol_att > 2 * 7)
+ value->value.enumerated.item[0] = 0;
+ else if (data->hp_vol_att > 0)
+ value->value.enumerated.item[0] = 1;
+ else
+ value->value.enumerated.item[0] = 2;
+ mutex_unlock(&chip->mutex);
+ return 0;
+}
+
+static int hp_volume_offset_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ static const s8 atts[3] = { 2 * 16, 2 * 7, 0 };
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+ s8 att;
+ int changed;
+
+ if (value->value.enumerated.item[0] > 2)
+ return -EINVAL;
+ att = atts[value->value.enumerated.item[0]];
+ mutex_lock(&chip->mutex);
+ changed = att != data->hp_vol_att;
+ if (changed) {
+ data->hp_vol_att = att;
+ if (data->output_sel) {
+ cs4245_write_cached(chip, CS4245_DAC_A_CTRL, att);
+ cs4245_write_cached(chip, CS4245_DAC_B_CTRL, att);
+ }
+ }
+ mutex_unlock(&chip->mutex);
+ return changed;
+}
+
+static int input_vol_info(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_info *info)
+{
+ info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ info->count = 2;
+ info->value.integer.min = 2 * -12;
+ info->value.integer.max = 2 * 12;
+ return 0;
+}
+
+static int input_vol_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+ unsigned int idx = ctl->private_value;
+
+ mutex_lock(&chip->mutex);
+ value->value.integer.value[0] = data->input_vol[idx][0];
+ value->value.integer.value[1] = data->input_vol[idx][1];
+ mutex_unlock(&chip->mutex);
+ return 0;
+}
+
+static int input_vol_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+ unsigned int idx = ctl->private_value;
+ int changed = 0;
+
+ if (value->value.integer.value[0] < 2 * -12 ||
+ value->value.integer.value[0] > 2 * 12 ||
+ value->value.integer.value[1] < 2 * -12 ||
+ value->value.integer.value[1] > 2 * 12)
+ return -EINVAL;
+ mutex_lock(&chip->mutex);
+ changed = data->input_vol[idx][0] != value->value.integer.value[0] ||
+ data->input_vol[idx][1] != value->value.integer.value[1];
+ if (changed) {
+ data->input_vol[idx][0] = value->value.integer.value[0];
+ data->input_vol[idx][1] = value->value.integer.value[1];
+ if (idx == data->input_sel) {
+ cs4245_write_cached(chip, CS4245_PGA_A_CTRL,
+ data->input_vol[idx][0]);
+ cs4245_write_cached(chip, CS4245_PGA_B_CTRL,
+ data->input_vol[idx][1]);
+ }
+ }
+ mutex_unlock(&chip->mutex);
+ return changed;
+}
+
+static DECLARE_TLV_DB_SCALE(cs4245_pga_db_scale, -1200, 50, 0);
+
+static int input_sel_info(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_info *info)
+{
+ static const char *const names[4] = {
+ "Mic", "Aux", "Front Mic", "Line"
+ };
+
+ return snd_ctl_enum_info(info, 1, 4, names);
+}
+
+static int input_sel_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+
+ mutex_lock(&chip->mutex);
+ value->value.enumerated.item[0] = data->input_sel;
+ mutex_unlock(&chip->mutex);
+ return 0;
+}
+
+static int input_sel_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ static const u8 sel_values[4] = {
+ CS4245_SEL_MIC,
+ CS4245_SEL_INPUT_1,
+ CS4245_SEL_INPUT_2,
+ CS4245_SEL_INPUT_4
+ };
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+ int changed;
+
+ if (value->value.enumerated.item[0] > 3)
+ return -EINVAL;
+
+ mutex_lock(&chip->mutex);
+ changed = value->value.enumerated.item[0] != data->input_sel;
+ if (changed) {
+ data->input_sel = value->value.enumerated.item[0];
+
+ cs4245_write(chip, CS4245_ANALOG_IN,
+ (data->cs4245_regs[CS4245_ANALOG_IN] &
+ ~CS4245_SEL_MASK) |
+ sel_values[data->input_sel]);
+
+ cs4245_write_cached(chip, CS4245_PGA_A_CTRL,
+ data->input_vol[data->input_sel][0]);
+ cs4245_write_cached(chip, CS4245_PGA_B_CTRL,
+ data->input_vol[data->input_sel][1]);
+
+ oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
+ data->input_sel ? 0 : GPIO_INPUT_ROUTE,
+ GPIO_INPUT_ROUTE);
+ }
+ mutex_unlock(&chip->mutex);
+ return changed;
+}
+
+static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
+{
+ static const char *const names[2] = { "Active", "Frozen" };
+
+ return snd_ctl_enum_info(info, 1, 2, names);
+}
+
+static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+
+ value->value.enumerated.item[0] =
+ !!(data->cs4245_regs[CS4245_ADC_CTRL] & CS4245_HPF_FREEZE);
+ return 0;
+}
+
+static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+ u8 reg;
+ int changed;
+
+ mutex_lock(&chip->mutex);
+ reg = data->cs4245_regs[CS4245_ADC_CTRL] & ~CS4245_HPF_FREEZE;
+ if (value->value.enumerated.item[0])
+ reg |= CS4245_HPF_FREEZE;
+ changed = reg != data->cs4245_regs[CS4245_ADC_CTRL];
+ if (changed)
+ cs4245_write(chip, CS4245_ADC_CTRL, reg);
+ mutex_unlock(&chip->mutex);
+ return changed;
+}
+
+#define INPUT_VOLUME(xname, index) { \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .info = input_vol_info, \
+ .get = input_vol_get, \
+ .put = input_vol_put, \
+ .tlv = { .p = cs4245_pga_db_scale }, \
+ .private_value = index, \
+}
+static const struct snd_kcontrol_new dg_controls[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Analog Output Playback Enum",
+ .info = output_switch_info,
+ .get = output_switch_get,
+ .put = output_switch_put,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Headphones Impedance Playback Enum",
+ .info = hp_volume_offset_info,
+ .get = hp_volume_offset_get,
+ .put = hp_volume_offset_put,
+ },
+ INPUT_VOLUME("Mic Capture Volume", 0),
+ INPUT_VOLUME("Aux Capture Volume", 1),
+ INPUT_VOLUME("Front Mic Capture Volume", 2),
+ INPUT_VOLUME("Line Capture Volume", 3),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Source",
+ .info = input_sel_info,
+ .get = input_sel_get,
+ .put = input_sel_put,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "ADC High-pass Filter Capture Enum",
+ .info = hpf_info,
+ .get = hpf_get,
+ .put = hpf_put,
+ },
+};
+
+static int dg_control_filter(struct snd_kcontrol_new *template)
+{
+ if (!strncmp(template->name, "Master Playback ", 16))
+ return 1;
+ return 0;
+}
+
+static int dg_mixer_init(struct oxygen *chip)
+{
+ unsigned int i;
+ int err;
+
+ for (i = 0; i < ARRAY_SIZE(dg_controls); ++i) {
+ err = snd_ctl_add(chip->card,
+ snd_ctl_new1(&dg_controls[i], chip));
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
+
+static void dump_cs4245_registers(struct oxygen *chip,
+ struct snd_info_buffer *buffer)
+{
+ struct dg *data = chip->model_data;
+ unsigned int i;
+
+ snd_iprintf(buffer, "\nCS4245:");
+ for (i = 1; i <= 0x10; ++i)
+ snd_iprintf(buffer, " %02x", data->cs4245_regs[i]);
+ snd_iprintf(buffer, "\n");
+}
+
+struct oxygen_model model_xonar_dg = {
+ .shortname = "Xonar DG",
+ .longname = "C-Media Oxygen HD Audio",
+ .chip = "CMI8786",
+ .init = dg_init,
+ .control_filter = dg_control_filter,
+ .mixer_init = dg_mixer_init,
+ .cleanup = dg_cleanup,
+ .suspend = dg_suspend,
+ .resume = dg_resume,
+ .set_dac_params = set_cs4245_dac_params,
+ .set_adc_params = set_cs4245_adc_params,
+ .adjust_dac_routing = adjust_dg_dac_routing,
+ .dump_registers = dump_cs4245_registers,
+ .model_data_size = sizeof(struct dg),
+ .device_config = PLAYBACK_0_TO_I2S |
+ PLAYBACK_1_TO_SPDIF |
+ CAPTURE_0_FROM_I2S_2,
+ .dac_channels_pcm = 6,
+ .dac_channels_mixer = 0,
+ .function_flags = OXYGEN_FUNCTION_SPI,
+ .dac_mclks = OXYGEN_MCLKS(256, 128, 128),
+ .adc_mclks = OXYGEN_MCLKS(256, 128, 128),
+ .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+ .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+};
diff --git a/sound/pci/oxygen/xonar_dg.h b/sound/pci/oxygen/xonar_dg.h
new file mode 100644
index 00000000000..5688d78609a
--- /dev/null
+++ b/sound/pci/oxygen/xonar_dg.h
@@ -0,0 +1,8 @@
+#ifndef XONAR_DG_H_INCLUDED
+#define XONAR_DG_H_INCLUDED
+
+#include "oxygen.h"
+
+extern struct oxygen_model model_xonar_dg;
+
+#endif
diff --git a/sound/pci/oxygen/xonar_hdmi.c b/sound/pci/oxygen/xonar_hdmi.c
index b12db1f1cea..136dac6a396 100644
--- a/sound/pci/oxygen/xonar_hdmi.c
+++ b/sound/pci/oxygen/xonar_hdmi.c
@@ -1,5 +1,5 @@
/*
- * helper functions for HDMI models (Xonar HDAV1.3)
+ * helper functions for HDMI models (Xonar HDAV1.3/HDAV1.3 Slim)
*
* Copyright (c) Clemens Ladisch <clemens@ladisch.de>
*
diff --git a/sound/pci/oxygen/xonar_lib.c b/sound/pci/oxygen/xonar_lib.c
index b3ff7131665..0ebe7f5916f 100644
--- a/sound/pci/oxygen/xonar_lib.c
+++ b/sound/pci/oxygen/xonar_lib.c
@@ -104,9 +104,10 @@ int xonar_gpio_bit_switch_get(struct snd_kcontrol *ctl,
{
struct oxygen *chip = ctl->private_data;
u16 bit = ctl->private_value;
+ bool invert = ctl->private_value & XONAR_GPIO_BIT_INVERT;
value->value.integer.value[0] =
- !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & bit);
+ !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & bit) ^ invert;
return 0;
}
@@ -115,12 +116,13 @@ int xonar_gpio_bit_switch_put(struct snd_kcontrol *ctl,
{
struct oxygen *chip = ctl->private_data;
u16 bit = ctl->private_value;
+ bool invert = ctl->private_value & XONAR_GPIO_BIT_INVERT;
u16 old_bits, new_bits;
int changed;
spin_lock_irq(&chip->reg_lock);
old_bits = oxygen_read16(chip, OXYGEN_GPIO_DATA);
- if (value->value.integer.value[0])
+ if (!!value->value.integer.value[0] ^ invert)
new_bits = old_bits | bit;
else
new_bits = old_bits & ~bit;
diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c
index d491fd6c0be..54cad38ec30 100644
--- a/sound/pci/oxygen/xonar_pcm179x.c
+++ b/sound/pci/oxygen/xonar_pcm179x.c
@@ -22,20 +22,26 @@
*
* CMI8788:
*
- * SPI 0 -> 1st PCM1796 (front)
- * SPI 1 -> 2nd PCM1796 (surround)
- * SPI 2 -> 3rd PCM1796 (center/LFE)
- * SPI 4 -> 4th PCM1796 (back)
+ * SPI 0 -> 1st PCM1796 (front)
+ * SPI 1 -> 2nd PCM1796 (surround)
+ * SPI 2 -> 3rd PCM1796 (center/LFE)
+ * SPI 4 -> 4th PCM1796 (back)
*
- * GPIO 2 -> M0 of CS5381
- * GPIO 3 -> M1 of CS5381
- * GPIO 5 <- external power present (D2X only)
- * GPIO 7 -> ALT
- * GPIO 8 -> enable output to speakers
+ * GPIO 2 -> M0 of CS5381
+ * GPIO 3 -> M1 of CS5381
+ * GPIO 5 <- external power present (D2X only)
+ * GPIO 7 -> ALT
+ * GPIO 8 -> enable output to speakers
*
* CM9780:
*
- * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input
+ * LINE_OUT -> input of ADC
+ *
+ * AUX_IN <- aux
+ * VIDEO_IN <- CD
+ * FMIC_IN <- mic
+ *
+ * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input
*/
/*
@@ -44,52 +50,53 @@
*
* CMI8788:
*
- * I²C <-> PCM1796 (front)
+ * I²C <-> PCM1796 (addr 1001100) (front)
*
- * GPI 0 <- external power present
+ * GPI 0 <- external power present
*
- * GPIO 0 -> enable output to speakers
- * GPIO 2 -> M0 of CS5381
- * GPIO 3 -> M1 of CS5381
- * GPIO 8 -> route input jack to line-in (0) or mic-in (1)
+ * GPIO 0 -> enable HDMI (0) or speaker (1) output
+ * GPIO 2 -> M0 of CS5381
+ * GPIO 3 -> M1 of CS5381
+ * GPIO 4 <- daughterboard detection
+ * GPIO 5 <- daughterboard detection
+ * GPIO 6 -> ?
+ * GPIO 7 -> ?
+ * GPIO 8 -> route input jack to line-in (0) or mic-in (1)
*
- * TXD -> HDMI controller
- * RXD <- HDMI controller
- *
- * PCM1796 front: AD1,0 <- 0,0
+ * UART <-> HDMI controller
*
* CM9780:
*
- * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input
+ * LINE_OUT -> input of ADC
+ *
+ * AUX_IN <- aux
+ * CD_IN <- CD
+ * MIC_IN <- mic
+ *
+ * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input
*
* no daughterboard
* ----------------
*
- * GPIO 4 <- 1
+ * GPIO 4 <- 1
*
* H6 daughterboard
* ----------------
*
- * GPIO 4 <- 0
- * GPIO 5 <- 0
- *
- * I²C <-> PCM1796 (surround)
- * <-> PCM1796 (center/LFE)
- * <-> PCM1796 (back)
+ * GPIO 4 <- 0
+ * GPIO 5 <- 0
*
- * PCM1796 surround: AD1,0 <- 0,1
- * PCM1796 center/LFE: AD1,0 <- 1,0
- * PCM1796 back: AD1,0 <- 1,1
+ * I²C <-> PCM1796 (addr 1001101) (surround)
+ * <-> PCM1796 (addr 1001110) (center/LFE)
+ * <-> PCM1796 (addr 1001111) (back)
*
* unknown daughterboard
* ---------------------
*
- * GPIO 4 <- 0
- * GPIO 5 <- 1
- *
- * I²C <-> CS4362A (surround, center/LFE, back)
+ * GPIO 4 <- 0
+ * GPIO 5 <- 1
*
- * CS4362A: AD0 <- 0
+ * I²C <-> CS4362A (addr 0011000) (surround, center/LFE, back)
*/
/*
@@ -98,32 +105,35 @@
*
* CMI8788:
*
- * I²C <-> PCM1792A
- * <-> CS2000 (ST only)
+ * I²C <-> PCM1792A (addr 1001100)
+ * <-> CS2000 (addr 1001110) (ST only)
*
- * ADC1 MCLK -> REF_CLK of CS2000 (ST only)
+ * ADC1 MCLK -> REF_CLK of CS2000 (ST only)
*
- * GPI 0 <- external power present (STX only)
+ * GPI 0 <- external power present (STX only)
*
- * GPIO 0 -> enable output to speakers
- * GPIO 1 -> route HP to front panel (0) or rear jack (1)
- * GPIO 2 -> M0 of CS5381
- * GPIO 3 -> M1 of CS5381
- * GPIO 7 -> route output to speaker jacks (0) or HP (1)
- * GPIO 8 -> route input jack to line-in (0) or mic-in (1)
+ * GPIO 0 -> enable output to speakers
+ * GPIO 1 -> route HP to front panel (0) or rear jack (1)
+ * GPIO 2 -> M0 of CS5381
+ * GPIO 3 -> M1 of CS5381
+ * GPIO 4 <- daughterboard detection
+ * GPIO 5 <- daughterboard detection
+ * GPIO 6 -> ?
+ * GPIO 7 -> route output to speaker jacks (0) or HP (1)
+ * GPIO 8 -> route input jack to line-in (0) or mic-in (1)
*
* PCM1792A:
*
- * AD1,0 <- 0,0
- * SCK <- CLK_OUT of CS2000 (ST only)
+ * SCK <- CLK_OUT of CS2000 (ST only)
*
- * CS2000:
+ * CM9780:
*
- * AD0 <- 0
+ * LINE_OUT -> input of ADC
*
- * CM9780:
+ * AUX_IN <- aux
+ * MIC_IN <- mic
*
- * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input
+ * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input
*
* H6 daughterboard
* ----------------
@@ -133,15 +143,39 @@
*/
/*
- * Xonar HDAV1.3 Slim
- * ------------------
+ * Xonar Xense
+ * -----------
*
* CMI8788:
*
- * GPIO 1 -> enable output
+ * I²C <-> PCM1796 (addr 1001100) (front)
+ * <-> CS4362A (addr 0011000) (surround, center/LFE, back)
+ * <-> CS2000 (addr 1001110)
+ *
+ * ADC1 MCLK -> REF_CLK of CS2000
+ *
+ * GPI 0 <- external power present
+ *
+ * GPIO 0 -> enable output
+ * GPIO 1 -> route HP to front panel (0) or rear jack (1)
+ * GPIO 2 -> M0 of CS5381
+ * GPIO 3 -> M1 of CS5381
+ * GPIO 4 -> enable output
+ * GPIO 5 -> enable output
+ * GPIO 6 -> ?
+ * GPIO 7 -> route output to HP (0) or speaker (1)
+ * GPIO 8 -> route input jack to mic-in (0) or line-in (1)
*
- * TXD -> HDMI controller
- * RXD <- HDMI controller
+ * CM9780:
+ *
+ * LINE_OUT -> input of ADC
+ *
+ * AUX_IN <- aux
+ * VIDEO_IN <- ?
+ * FMIC_IN <- mic
+ *
+ * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input
+ * GPO 1 -> route mic-in from input jack (0) or front panel header (1)
*/
#include <linux/pci.h>
@@ -150,6 +184,7 @@
#include <sound/ac97_codec.h>
#include <sound/control.h>
#include <sound/core.h>
+#include <sound/info.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/tlv.h>
@@ -167,12 +202,14 @@
#define GPIO_INPUT_ROUTE 0x0100
#define GPIO_HDAV_OUTPUT_ENABLE 0x0001
+#define GPIO_HDAV_MAGIC 0x00c0
#define GPIO_DB_MASK 0x0030
#define GPIO_DB_H6 0x0000
#define GPIO_ST_OUTPUT_ENABLE 0x0001
#define GPIO_ST_HP_REAR 0x0002
+#define GPIO_ST_MAGIC 0x0040
#define GPIO_ST_HP 0x0080
#define I2C_DEVICE_PCM1796(i) (0x98 + ((i) << 1)) /* 10011, ii, /W=0 */
@@ -186,11 +223,12 @@ struct xonar_pcm179x {
unsigned int dacs;
u8 pcm1796_regs[4][5];
unsigned int current_rate;
- bool os_128;
+ bool h6;
bool hp_active;
s8 hp_gain_offset;
bool has_cs2000;
- u8 cs2000_fun_cfg_1;
+ u8 cs2000_regs[0x1f];
+ bool broken_i2c;
};
struct xonar_hdav {
@@ -249,16 +287,14 @@ static void cs2000_write(struct oxygen *chip, u8 reg, u8 value)
struct xonar_pcm179x *data = chip->model_data;
oxygen_write_i2c(chip, I2C_DEVICE_CS2000, reg, value);
- if (reg == CS2000_FUN_CFG_1)
- data->cs2000_fun_cfg_1 = value;
+ data->cs2000_regs[reg] = value;
}
static void cs2000_write_cached(struct oxygen *chip, u8 reg, u8 value)
{
struct xonar_pcm179x *data = chip->model_data;
- if (reg != CS2000_FUN_CFG_1 ||
- value != data->cs2000_fun_cfg_1)
+ if (value != data->cs2000_regs[reg])
cs2000_write(chip, reg, value);
}
@@ -268,6 +304,7 @@ static void pcm1796_registers_init(struct oxygen *chip)
unsigned int i;
s8 gain_offset;
+ msleep(1);
gain_offset = data->hp_active ? data->hp_gain_offset : 0;
for (i = 0; i < data->dacs; ++i) {
/* set ATLD before ATL/ATR */
@@ -282,6 +319,7 @@ static void pcm1796_registers_init(struct oxygen *chip)
pcm1796_write(chip, i, 20,
data->pcm1796_regs[0][20 - PCM1796_REG_BASE]);
pcm1796_write(chip, i, 21, 0);
+ gain_offset = 0;
}
}
@@ -290,10 +328,11 @@ static void pcm1796_init(struct oxygen *chip)
struct xonar_pcm179x *data = chip->model_data;
data->pcm1796_regs[0][18 - PCM1796_REG_BASE] = PCM1796_MUTE |
- PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD;
+ PCM1796_DMF_DISABLED | PCM1796_FMT_24_I2S | PCM1796_ATLD;
data->pcm1796_regs[0][19 - PCM1796_REG_BASE] =
PCM1796_FLT_SHARP | PCM1796_ATS_1;
- data->pcm1796_regs[0][20 - PCM1796_REG_BASE] = PCM1796_OS_64;
+ data->pcm1796_regs[0][20 - PCM1796_REG_BASE] =
+ data->h6 ? PCM1796_OS_64 : PCM1796_OS_128;
pcm1796_registers_init(chip);
data->current_rate = 48000;
}
@@ -339,18 +378,20 @@ static void xonar_hdav_init(struct oxygen *chip)
oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
OXYGEN_2WIRE_LENGTH_8 |
OXYGEN_2WIRE_INTERRUPT_MASK |
- OXYGEN_2WIRE_SPEED_FAST);
+ OXYGEN_2WIRE_SPEED_STANDARD);
data->pcm179x.generic.anti_pop_delay = 100;
data->pcm179x.generic.output_enable_bit = GPIO_HDAV_OUTPUT_ENABLE;
data->pcm179x.generic.ext_power_reg = OXYGEN_GPI_DATA;
data->pcm179x.generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
data->pcm179x.generic.ext_power_bit = GPI_EXT_POWER;
- data->pcm179x.dacs = chip->model.private_data ? 4 : 1;
+ data->pcm179x.dacs = chip->model.dac_channels_mixer / 2;
+ data->pcm179x.h6 = chip->model.dac_channels_mixer > 2;
pcm1796_init(chip);
- oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_INPUT_ROUTE);
+ oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
+ GPIO_HDAV_MAGIC | GPIO_INPUT_ROUTE);
oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_INPUT_ROUTE);
xonar_init_cs53x1(chip);
@@ -367,7 +408,7 @@ static void xonar_st_init_i2c(struct oxygen *chip)
oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
OXYGEN_2WIRE_LENGTH_8 |
OXYGEN_2WIRE_INTERRUPT_MASK |
- OXYGEN_2WIRE_SPEED_FAST);
+ OXYGEN_2WIRE_SPEED_STANDARD);
}
static void xonar_st_init_common(struct oxygen *chip)
@@ -375,13 +416,14 @@ static void xonar_st_init_common(struct oxygen *chip)
struct xonar_pcm179x *data = chip->model_data;
data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE;
- data->dacs = chip->model.private_data ? 4 : 1;
+ data->dacs = chip->model.dac_channels_mixer / 2;
data->hp_gain_offset = 2*-18;
pcm1796_init(chip);
oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
- GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP);
+ GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR |
+ GPIO_ST_MAGIC | GPIO_ST_HP);
oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP);
@@ -410,9 +452,11 @@ static void cs2000_registers_init(struct oxygen *chip)
cs2000_write(chip, CS2000_RATIO_0 + 1, 0x10);
cs2000_write(chip, CS2000_RATIO_0 + 2, 0x00);
cs2000_write(chip, CS2000_RATIO_0 + 3, 0x00);
- cs2000_write(chip, CS2000_FUN_CFG_1, data->cs2000_fun_cfg_1);
+ cs2000_write(chip, CS2000_FUN_CFG_1,
+ data->cs2000_regs[CS2000_FUN_CFG_1]);
cs2000_write(chip, CS2000_FUN_CFG_2, 0);
cs2000_write(chip, CS2000_GLOBAL_CFG, CS2000_EN_DEV_CFG_2);
+ msleep(3); /* PLL lock delay */
}
static void xonar_st_init(struct oxygen *chip)
@@ -420,13 +464,18 @@ static void xonar_st_init(struct oxygen *chip)
struct xonar_pcm179x *data = chip->model_data;
data->generic.anti_pop_delay = 100;
+ data->h6 = chip->model.dac_channels_mixer > 2;
data->has_cs2000 = 1;
- data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1;
+ data->cs2000_regs[CS2000_FUN_CFG_1] = CS2000_REF_CLK_DIV_1;
+ data->broken_i2c = true;
oxygen_write16(chip, OXYGEN_I2S_A_FORMAT,
- OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_I2S |
- OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 |
- OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
+ OXYGEN_RATE_48000 |
+ OXYGEN_I2S_FORMAT_I2S |
+ OXYGEN_I2S_MCLK(data->h6 ? MCLK_256 : MCLK_512) |
+ OXYGEN_I2S_BITS_16 |
+ OXYGEN_I2S_MASTER |
+ OXYGEN_I2S_BCLK_64);
xonar_st_init_i2c(chip);
cs2000_registers_init(chip);
@@ -507,44 +556,16 @@ static void xonar_st_resume(struct oxygen *chip)
xonar_stx_resume(chip);
}
-static unsigned int mclk_from_rate(struct oxygen *chip, unsigned int rate)
-{
- struct xonar_pcm179x *data = chip->model_data;
-
- if (rate <= 32000)
- return OXYGEN_I2S_MCLK_512;
- else if (rate <= 48000 && data->os_128)
- return OXYGEN_I2S_MCLK_512;
- else if (rate <= 96000)
- return OXYGEN_I2S_MCLK_256;
- else
- return OXYGEN_I2S_MCLK_128;
-}
-
-static unsigned int get_pcm1796_i2s_mclk(struct oxygen *chip,
- unsigned int channel,
- struct snd_pcm_hw_params *params)
-{
- if (channel == PCM_MULTICH)
- return mclk_from_rate(chip, params_rate(params));
- else
- return oxygen_default_i2s_mclk(chip, channel, params);
-}
-
static void update_pcm1796_oversampling(struct oxygen *chip)
{
struct xonar_pcm179x *data = chip->model_data;
unsigned int i;
u8 reg;
- if (data->current_rate <= 32000)
+ if (data->current_rate <= 48000 && !data->h6)
reg = PCM1796_OS_128;
- else if (data->current_rate <= 48000 && data->os_128)
- reg = PCM1796_OS_128;
- else if (data->current_rate <= 96000 || data->os_128)
- reg = PCM1796_OS_64;
else
- reg = PCM1796_OS_32;
+ reg = PCM1796_OS_64;
for (i = 0; i < data->dacs; ++i)
pcm1796_write_cached(chip, i, 20, reg);
}
@@ -554,6 +575,7 @@ static void set_pcm1796_params(struct oxygen *chip,
{
struct xonar_pcm179x *data = chip->model_data;
+ msleep(1);
data->current_rate = params_rate(params);
update_pcm1796_oversampling(chip);
}
@@ -570,6 +592,7 @@ static void update_pcm1796_volume(struct oxygen *chip)
+ gain_offset);
pcm1796_write_cached(chip, i, 17, chip->dac_volume[i * 2 + 1]
+ gain_offset);
+ gain_offset = 0;
}
}
@@ -579,7 +602,7 @@ static void update_pcm1796_mute(struct oxygen *chip)
unsigned int i;
u8 value;
- value = PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD;
+ value = PCM1796_DMF_DISABLED | PCM1796_FMT_24_I2S | PCM1796_ATLD;
if (chip->dac_mute)
value |= PCM1796_MUTE;
for (i = 0; i < data->dacs; ++i)
@@ -592,45 +615,35 @@ static void update_cs2000_rate(struct oxygen *chip, unsigned int rate)
u8 rate_mclk, reg;
switch (rate) {
- /* XXX Why is the I2S A MCLK half the actual I2S MCLK? */
case 32000:
- rate_mclk = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_256;
- break;
- case 44100:
- if (data->os_128)
- rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256;
- else
- rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_128;
- break;
- default: /* 48000 */
- if (data->os_128)
- rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256;
- else
- rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_128;
- break;
case 64000:
- rate_mclk = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_256;
+ rate_mclk = OXYGEN_RATE_32000;
break;
+ case 44100:
case 88200:
- rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256;
- break;
- case 96000:
- rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256;
- break;
case 176400:
- rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256;
+ rate_mclk = OXYGEN_RATE_44100;
break;
+ default:
+ case 48000:
+ case 96000:
case 192000:
- rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256;
+ rate_mclk = OXYGEN_RATE_48000;
break;
}
- oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, rate_mclk,
- OXYGEN_I2S_RATE_MASK | OXYGEN_I2S_MCLK_MASK);
- if ((rate_mclk & OXYGEN_I2S_MCLK_MASK) <= OXYGEN_I2S_MCLK_128)
+
+ if (rate <= 96000 && (rate > 48000 || data->h6)) {
+ rate_mclk |= OXYGEN_I2S_MCLK(MCLK_256);
reg = CS2000_REF_CLK_DIV_1;
- else
+ } else {
+ rate_mclk |= OXYGEN_I2S_MCLK(MCLK_512);
reg = CS2000_REF_CLK_DIV_2;
+ }
+
+ oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, rate_mclk,
+ OXYGEN_I2S_RATE_MASK | OXYGEN_I2S_MCLK_MASK);
cs2000_write_cached(chip, CS2000_FUN_CFG_1, reg);
+ msleep(3); /* PLL lock delay */
}
static void set_st_params(struct oxygen *chip,
@@ -665,13 +678,7 @@ static int rolloff_info(struct snd_kcontrol *ctl,
"Sharp Roll-off", "Slow Roll-off"
};
- info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- info->count = 1;
- info->value.enumerated.items = 2;
- if (info->value.enumerated.item >= 2)
- info->value.enumerated.item = 1;
- strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(info, 1, 2, names);
}
static int rolloff_get(struct snd_kcontrol *ctl,
@@ -719,57 +726,13 @@ static const struct snd_kcontrol_new rolloff_control = {
.put = rolloff_put,
};
-static int os_128_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
-{
- static const char *const names[2] = { "64x", "128x" };
-
- info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- info->count = 1;
- info->value.enumerated.items = 2;
- if (info->value.enumerated.item >= 2)
- info->value.enumerated.item = 1;
- strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
- return 0;
-}
-
-static int os_128_get(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_value *value)
-{
- struct oxygen *chip = ctl->private_data;
- struct xonar_pcm179x *data = chip->model_data;
-
- value->value.enumerated.item[0] = data->os_128;
- return 0;
-}
-
-static int os_128_put(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_value *value)
-{
- struct oxygen *chip = ctl->private_data;
- struct xonar_pcm179x *data = chip->model_data;
- int changed;
-
- mutex_lock(&chip->mutex);
- changed = value->value.enumerated.item[0] != data->os_128;
- if (changed) {
- data->os_128 = value->value.enumerated.item[0];
- if (data->has_cs2000)
- update_cs2000_rate(chip, data->current_rate);
- oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT,
- mclk_from_rate(chip, data->current_rate),
- OXYGEN_I2S_MCLK_MASK);
- update_pcm1796_oversampling(chip);
- }
- mutex_unlock(&chip->mutex);
- return changed;
-}
-
-static const struct snd_kcontrol_new os_128_control = {
+static const struct snd_kcontrol_new hdav_hdmi_control = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "DAC Oversampling Playback Enum",
- .info = os_128_info,
- .get = os_128_get,
- .put = os_128_put,
+ .name = "HDMI Playback Switch",
+ .info = snd_ctl_boolean_mono_info,
+ .get = xonar_gpio_bit_switch_get,
+ .put = xonar_gpio_bit_switch_put,
+ .private_value = GPIO_HDAV_OUTPUT_ENABLE | XONAR_GPIO_BIT_INVERT,
};
static int st_output_switch_info(struct snd_kcontrol *ctl,
@@ -779,13 +742,7 @@ static int st_output_switch_info(struct snd_kcontrol *ctl,
"Speakers", "Headphones", "FP Headphones"
};
- info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- info->count = 1;
- info->value.enumerated.items = 3;
- if (info->value.enumerated.item >= 3)
- info->value.enumerated.item = 2;
- strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(info, 1, 3, names);
}
static int st_output_switch_get(struct snd_kcontrol *ctl,
@@ -840,13 +797,7 @@ static int st_hp_volume_offset_info(struct snd_kcontrol *ctl,
"< 64 ohms", "64-300 ohms", "300-600 ohms"
};
- info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- info->count = 1;
- info->value.enumerated.items = 3;
- if (info->value.enumerated.item > 2)
- info->value.enumerated.item = 2;
- strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(info, 1, 3, names);
}
static int st_hp_volume_offset_get(struct snd_kcontrol *ctl,
@@ -928,16 +879,25 @@ static int xonar_d2_control_filter(struct snd_kcontrol_new *template)
return 0;
}
+static int xonar_st_h6_control_filter(struct snd_kcontrol_new *template)
+{
+ if (!strncmp(template->name, "Master Playback ", 16))
+ /* no volume/mute, as I²C to the third DAC does not work */
+ return 1;
+ return 0;
+}
+
static int add_pcm1796_controls(struct oxygen *chip)
{
+ struct xonar_pcm179x *data = chip->model_data;
int err;
- err = snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip));
- if (err < 0)
- return err;
- err = snd_ctl_add(chip->card, snd_ctl_new1(&os_128_control, chip));
- if (err < 0)
- return err;
+ if (!data->broken_i2c) {
+ err = snd_ctl_add(chip->card,
+ snd_ctl_new1(&rolloff_control, chip));
+ if (err < 0)
+ return err;
+ }
return 0;
}
@@ -956,7 +916,15 @@ static int xonar_d2_mixer_init(struct oxygen *chip)
static int xonar_hdav_mixer_init(struct oxygen *chip)
{
- return add_pcm1796_controls(chip);
+ int err;
+
+ err = snd_ctl_add(chip->card, snd_ctl_new1(&hdav_hdmi_control, chip));
+ if (err < 0)
+ return err;
+ err = add_pcm1796_controls(chip);
+ if (err < 0)
+ return err;
+ return 0;
}
static int xonar_st_mixer_init(struct oxygen *chip)
@@ -976,6 +944,45 @@ static int xonar_st_mixer_init(struct oxygen *chip)
return 0;
}
+static void dump_pcm1796_registers(struct oxygen *chip,
+ struct snd_info_buffer *buffer)
+{
+ struct xonar_pcm179x *data = chip->model_data;
+ unsigned int dac, i;
+
+ for (dac = 0; dac < data->dacs; ++dac) {
+ snd_iprintf(buffer, "\nPCM1796 %u:", dac + 1);
+ for (i = 0; i < 5; ++i)
+ snd_iprintf(buffer, " %02x",
+ data->pcm1796_regs[dac][i]);
+ }
+ snd_iprintf(buffer, "\n");
+}
+
+static void dump_cs2000_registers(struct oxygen *chip,
+ struct snd_info_buffer *buffer)
+{
+ struct xonar_pcm179x *data = chip->model_data;
+ unsigned int i;
+
+ if (data->has_cs2000) {
+ snd_iprintf(buffer, "\nCS2000:\n00: ");
+ for (i = 1; i < 0x10; ++i)
+ snd_iprintf(buffer, " %02x", data->cs2000_regs[i]);
+ snd_iprintf(buffer, "\n10:");
+ for (i = 0x10; i < 0x1f; ++i)
+ snd_iprintf(buffer, " %02x", data->cs2000_regs[i]);
+ snd_iprintf(buffer, "\n");
+ }
+}
+
+static void dump_st_registers(struct oxygen *chip,
+ struct snd_info_buffer *buffer)
+{
+ dump_pcm1796_registers(chip, buffer);
+ dump_cs2000_registers(chip, buffer);
+}
+
static const struct oxygen_model model_xonar_d2 = {
.longname = "Asus Virtuoso 200",
.chip = "AV200",
@@ -985,11 +992,11 @@ static const struct oxygen_model model_xonar_d2 = {
.cleanup = xonar_d2_cleanup,
.suspend = xonar_d2_suspend,
.resume = xonar_d2_resume,
- .get_i2s_mclk = get_pcm1796_i2s_mclk,
.set_dac_params = set_pcm1796_params,
.set_adc_params = xonar_set_cs53x1_params,
.update_dac_volume = update_pcm1796_volume,
.update_dac_mute = update_pcm1796_mute,
+ .dump_registers = dump_pcm1796_registers,
.dac_tlv = pcm1796_db_scale,
.model_data_size = sizeof(struct xonar_pcm179x),
.device_config = PLAYBACK_0_TO_I2S |
@@ -999,13 +1006,16 @@ static const struct oxygen_model model_xonar_d2 = {
MIDI_OUTPUT |
MIDI_INPUT |
AC97_CD_INPUT,
- .dac_channels = 8,
+ .dac_channels_pcm = 8,
+ .dac_channels_mixer = 8,
.dac_volume_min = 255 - 2*60,
.dac_volume_max = 255,
.misc_flags = OXYGEN_MISC_MIDI,
.function_flags = OXYGEN_FUNCTION_SPI |
OXYGEN_FUNCTION_ENABLE_SPI_4_5,
- .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+ .dac_mclks = OXYGEN_MCLKS(512, 128, 128),
+ .adc_mclks = OXYGEN_MCLKS(256, 128, 128),
+ .dac_i2s_format = OXYGEN_I2S_FORMAT_I2S,
.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
};
@@ -1018,25 +1028,28 @@ static const struct oxygen_model model_xonar_hdav = {
.suspend = xonar_hdav_suspend,
.resume = xonar_hdav_resume,
.pcm_hardware_filter = xonar_hdmi_pcm_hardware_filter,
- .get_i2s_mclk = get_pcm1796_i2s_mclk,
.set_dac_params = set_hdav_params,
.set_adc_params = xonar_set_cs53x1_params,
.update_dac_volume = update_pcm1796_volume,
.update_dac_mute = update_pcm1796_mute,
.uart_input = xonar_hdmi_uart_input,
.ac97_switch = xonar_line_mic_ac97_switch,
+ .dump_registers = dump_pcm1796_registers,
.dac_tlv = pcm1796_db_scale,
.model_data_size = sizeof(struct xonar_hdav),
.device_config = PLAYBACK_0_TO_I2S |
PLAYBACK_1_TO_SPDIF |
CAPTURE_0_FROM_I2S_2 |
CAPTURE_1_FROM_SPDIF,
- .dac_channels = 8,
+ .dac_channels_pcm = 8,
+ .dac_channels_mixer = 2,
.dac_volume_min = 255 - 2*60,
.dac_volume_max = 255,
.misc_flags = OXYGEN_MISC_MIDI,
.function_flags = OXYGEN_FUNCTION_2WIRE,
- .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+ .dac_mclks = OXYGEN_MCLKS(512, 128, 128),
+ .adc_mclks = OXYGEN_MCLKS(256, 128, 128),
+ .dac_i2s_format = OXYGEN_I2S_FORMAT_I2S,
.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
};
@@ -1048,22 +1061,26 @@ static const struct oxygen_model model_xonar_st = {
.cleanup = xonar_st_cleanup,
.suspend = xonar_st_suspend,
.resume = xonar_st_resume,
- .get_i2s_mclk = get_pcm1796_i2s_mclk,
.set_dac_params = set_st_params,
.set_adc_params = xonar_set_cs53x1_params,
.update_dac_volume = update_pcm1796_volume,
.update_dac_mute = update_pcm1796_mute,
.ac97_switch = xonar_line_mic_ac97_switch,
+ .dump_registers = dump_st_registers,
.dac_tlv = pcm1796_db_scale,
.model_data_size = sizeof(struct xonar_pcm179x),
.device_config = PLAYBACK_0_TO_I2S |
PLAYBACK_1_TO_SPDIF |
- CAPTURE_0_FROM_I2S_2,
- .dac_channels = 2,
+ CAPTURE_0_FROM_I2S_2 |
+ AC97_FMIC_SWITCH,
+ .dac_channels_pcm = 2,
+ .dac_channels_mixer = 2,
.dac_volume_min = 255 - 2*60,
.dac_volume_max = 255,
.function_flags = OXYGEN_FUNCTION_2WIRE,
- .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+ .dac_mclks = OXYGEN_MCLKS(512, 128, 128),
+ .adc_mclks = OXYGEN_MCLKS(256, 128, 128),
+ .dac_i2s_format = OXYGEN_I2S_FORMAT_I2S,
.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
};
@@ -1089,7 +1106,8 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip,
break;
case GPIO_DB_H6:
chip->model.shortname = "Xonar HDAV1.3+H6";
- chip->model.private_data = 1;
+ chip->model.dac_channels_mixer = 8;
+ chip->model.dac_mclks = OXYGEN_MCLKS(256, 128, 128);
break;
}
break;
@@ -1102,8 +1120,10 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip,
break;
case GPIO_DB_H6:
chip->model.shortname = "Xonar ST+H6";
- chip->model.dac_channels = 8;
- chip->model.private_data = 1;
+ chip->model.control_filter = xonar_st_h6_control_filter;
+ chip->model.dac_channels_pcm = 8;
+ chip->model.dac_channels_mixer = 8;
+ chip->model.dac_mclks = OXYGEN_MCLKS(256, 128, 128);
break;
}
break;
@@ -1114,9 +1134,6 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip,
chip->model.resume = xonar_stx_resume;
chip->model.set_dac_params = set_pcm1796_params;
break;
- case 0x835e:
- snd_printk(KERN_ERR "the HDAV1.3 Slim is not supported\n");
- return -ENODEV;
default:
return -EINVAL;
}
diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c
index 200f7601276..42d1ab13621 100644
--- a/sound/pci/oxygen/xonar_wm87x6.c
+++ b/sound/pci/oxygen/xonar_wm87x6.c
@@ -1,5 +1,5 @@
/*
- * card driver for models with WM8776/WM8766 DACs (Xonar DS)
+ * card driver for models with WM8776/WM8766 DACs (Xonar DS/HDAV1.3 Slim)
*
* Copyright (c) Clemens Ladisch <clemens@ladisch.de>
*
@@ -22,26 +22,48 @@
*
* CMI8788:
*
- * SPI 0 -> WM8766 (surround, center/LFE, back)
- * SPI 1 -> WM8776 (front, input)
+ * SPI 0 -> WM8766 (surround, center/LFE, back)
+ * SPI 1 -> WM8776 (front, input)
*
- * GPIO 4 <- headphone detect, 0 = plugged
- * GPIO 6 -> route input jack to mic-in (0) or line-in (1)
- * GPIO 7 -> enable output to front L/R speaker channels
- * GPIO 8 -> enable output to other speaker channels and front panel headphone
+ * GPIO 4 <- headphone detect, 0 = plugged
+ * GPIO 6 -> route input jack to mic-in (0) or line-in (1)
+ * GPIO 7 -> enable output to front L/R speaker channels
+ * GPIO 8 -> enable output to other speaker channels and front panel headphone
*
- * WM8766:
+ * WM8776:
*
- * input 1 <- line
- * input 2 <- mic
- * input 3 <- front mic
- * input 4 <- aux
+ * input 1 <- line
+ * input 2 <- mic
+ * input 3 <- front mic
+ * input 4 <- aux
+ */
+
+/*
+ * Xonar HDAV1.3 Slim
+ * ------------------
+ *
+ * CMI8788:
+ *
+ * I²C <-> WM8776 (addr 0011010)
+ *
+ * GPIO 0 -> disable HDMI output
+ * GPIO 1 -> enable HP output
+ * GPIO 6 -> firmware EEPROM I²C clock
+ * GPIO 7 <-> firmware EEPROM I²C data
+ *
+ * UART <-> HDMI controller
+ *
+ * WM8776:
+ *
+ * input 1 <- mic
+ * input 2 <- aux
*/
#include <linux/pci.h>
#include <linux/delay.h>
#include <sound/control.h>
#include <sound/core.h>
+#include <sound/info.h>
#include <sound/jack.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -55,6 +77,13 @@
#define GPIO_DS_OUTPUT_FRONTLR 0x0080
#define GPIO_DS_OUTPUT_ENABLE 0x0100
+#define GPIO_SLIM_HDMI_DISABLE 0x0001
+#define GPIO_SLIM_OUTPUT_ENABLE 0x0002
+#define GPIO_SLIM_FIRMWARE_CLK 0x0040
+#define GPIO_SLIM_FIRMWARE_DATA 0x0080
+
+#define I2C_DEVICE_WM8776 0x34 /* 001101, 0, /W=0 */
+
#define LC_CONTROL_LIMITER 0x40000000
#define LC_CONTROL_ALC 0x20000000
@@ -66,19 +95,37 @@ struct xonar_wm87x6 {
struct snd_kcontrol *mic_adcmux_control;
struct snd_kcontrol *lc_controls[13];
struct snd_jack *hp_jack;
+ struct xonar_hdmi hdmi;
};
-static void wm8776_write(struct oxygen *chip,
- unsigned int reg, unsigned int value)
+static void wm8776_write_spi(struct oxygen *chip,
+ unsigned int reg, unsigned int value)
{
- struct xonar_wm87x6 *data = chip->model_data;
-
oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
OXYGEN_SPI_DATA_LENGTH_2 |
OXYGEN_SPI_CLOCK_160 |
(1 << OXYGEN_SPI_CODEC_SHIFT) |
OXYGEN_SPI_CEN_LATCH_CLOCK_LO,
(reg << 9) | value);
+}
+
+static void wm8776_write_i2c(struct oxygen *chip,
+ unsigned int reg, unsigned int value)
+{
+ oxygen_write_i2c(chip, I2C_DEVICE_WM8776,
+ (reg << 1) | (value >> 8), value);
+}
+
+static void wm8776_write(struct oxygen *chip,
+ unsigned int reg, unsigned int value)
+{
+ struct xonar_wm87x6 *data = chip->model_data;
+
+ if ((chip->model.function_flags & OXYGEN_FUNCTION_2WIRE_SPI_MASK) ==
+ OXYGEN_FUNCTION_SPI)
+ wm8776_write_spi(chip, reg, value);
+ else
+ wm8776_write_i2c(chip, reg, value);
if (reg < ARRAY_SIZE(data->wm8776_regs)) {
if (reg >= WM8776_HPLVOL && reg <= WM8776_DACMASTER)
value &= ~WM8776_UPDATE;
@@ -245,17 +292,50 @@ static void xonar_ds_init(struct oxygen *chip)
snd_component_add(chip->card, "WM8766");
}
+static void xonar_hdav_slim_init(struct oxygen *chip)
+{
+ struct xonar_wm87x6 *data = chip->model_data;
+
+ data->generic.anti_pop_delay = 300;
+ data->generic.output_enable_bit = GPIO_SLIM_OUTPUT_ENABLE;
+
+ wm8776_init(chip);
+
+ oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
+ GPIO_SLIM_HDMI_DISABLE |
+ GPIO_SLIM_FIRMWARE_CLK |
+ GPIO_SLIM_FIRMWARE_DATA);
+
+ xonar_hdmi_init(chip, &data->hdmi);
+ xonar_enable_output(chip);
+
+ snd_component_add(chip->card, "WM8776");
+}
+
static void xonar_ds_cleanup(struct oxygen *chip)
{
xonar_disable_output(chip);
wm8776_write(chip, WM8776_RESET, 0);
}
+static void xonar_hdav_slim_cleanup(struct oxygen *chip)
+{
+ xonar_hdmi_cleanup(chip);
+ xonar_disable_output(chip);
+ wm8776_write(chip, WM8776_RESET, 0);
+ msleep(2);
+}
+
static void xonar_ds_suspend(struct oxygen *chip)
{
xonar_ds_cleanup(chip);
}
+static void xonar_hdav_slim_suspend(struct oxygen *chip)
+{
+ xonar_hdav_slim_cleanup(chip);
+}
+
static void xonar_ds_resume(struct oxygen *chip)
{
wm8776_registers_init(chip);
@@ -264,6 +344,15 @@ static void xonar_ds_resume(struct oxygen *chip)
xonar_ds_handle_hp_jack(chip);
}
+static void xonar_hdav_slim_resume(struct oxygen *chip)
+{
+ struct xonar_wm87x6 *data = chip->model_data;
+
+ wm8776_registers_init(chip);
+ xonar_hdmi_resume(chip, &data->hdmi);
+ xonar_enable_output(chip);
+}
+
static void wm8776_adc_hardware_filter(unsigned int channel,
struct snd_pcm_hardware *hardware)
{
@@ -278,6 +367,13 @@ static void wm8776_adc_hardware_filter(unsigned int channel,
}
}
+static void xonar_hdav_slim_hardware_filter(unsigned int channel,
+ struct snd_pcm_hardware *hardware)
+{
+ wm8776_adc_hardware_filter(channel, hardware);
+ xonar_hdmi_pcm_hardware_filter(channel, hardware);
+}
+
static void set_wm87x6_dac_params(struct oxygen *chip,
struct snd_pcm_hw_params *params)
{
@@ -294,6 +390,14 @@ static void set_wm8776_adc_params(struct oxygen *chip,
wm8776_write_cached(chip, WM8776_MSTRCTRL, reg);
}
+static void set_hdav_slim_dac_params(struct oxygen *chip,
+ struct snd_pcm_hw_params *params)
+{
+ struct xonar_wm87x6 *data = chip->model_data;
+
+ xonar_set_hdmi_params(chip, &data->hdmi, params);
+}
+
static void update_wm8776_volume(struct oxygen *chip)
{
struct xonar_wm87x6 *data = chip->model_data;
@@ -473,11 +577,6 @@ static int wm8776_field_enum_info(struct snd_kcontrol *ctl,
const char *const *names;
max = (ctl->private_value >> 12) & 0xf;
- info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- info->count = 1;
- info->value.enumerated.items = max + 1;
- if (info->value.enumerated.item > max)
- info->value.enumerated.item = max;
switch ((ctl->private_value >> 24) & 0x1f) {
case WM8776_ALCCTRL2:
names = hld;
@@ -501,8 +600,7 @@ static int wm8776_field_enum_info(struct snd_kcontrol *ctl,
default:
return -ENXIO;
}
- strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(info, 1, max + 1, names);
}
static int wm8776_field_volume_info(struct snd_kcontrol *ctl,
@@ -759,13 +857,8 @@ static int wm8776_level_control_info(struct snd_kcontrol *ctl,
static const char *const names[3] = {
"None", "Peak Limiter", "Automatic Level Control"
};
- info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- info->count = 1;
- info->value.enumerated.items = 3;
- if (info->value.enumerated.item >= 3)
- info->value.enumerated.item = 2;
- strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
- return 0;
+
+ return snd_ctl_enum_info(info, 1, 3, names);
}
static int wm8776_level_control_get(struct snd_kcontrol *ctl,
@@ -851,13 +944,7 @@ static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
"None", "High-pass Filter"
};
- info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- info->count = 1;
- info->value.enumerated.items = 2;
- if (info->value.enumerated.item >= 2)
- info->value.enumerated.item = 1;
- strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(info, 1, 2, names);
}
static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
@@ -985,6 +1072,53 @@ static const struct snd_kcontrol_new ds_controls[] = {
.private_value = 0,
},
};
+static const struct snd_kcontrol_new hdav_slim_controls[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "HDMI Playback Switch",
+ .info = snd_ctl_boolean_mono_info,
+ .get = xonar_gpio_bit_switch_get,
+ .put = xonar_gpio_bit_switch_put,
+ .private_value = GPIO_SLIM_HDMI_DISABLE | XONAR_GPIO_BIT_INVERT,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Headphone Playback Volume",
+ .info = wm8776_hp_vol_info,
+ .get = wm8776_hp_vol_get,
+ .put = wm8776_hp_vol_put,
+ .tlv = { .p = wm8776_hp_db_scale },
+ },
+ WM8776_BIT_SWITCH("Headphone Playback Switch",
+ WM8776_PWRDOWN, WM8776_HPPD, 1, 0),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Input Capture Volume",
+ .info = wm8776_input_vol_info,
+ .get = wm8776_input_vol_get,
+ .put = wm8776_input_vol_put,
+ .tlv = { .p = wm8776_adc_db_scale },
+ },
+ WM8776_BIT_SWITCH("Mic Capture Switch",
+ WM8776_ADCMUX, 1 << 0, 0, 0),
+ WM8776_BIT_SWITCH("Aux Capture Switch",
+ WM8776_ADCMUX, 1 << 1, 0, 0),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "ADC Filter Capture Enum",
+ .info = hpf_info,
+ .get = hpf_get,
+ .put = hpf_put,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Level Control Capture Enum",
+ .info = wm8776_level_control_info,
+ .get = wm8776_level_control_get,
+ .put = wm8776_level_control_put,
+ .private_value = 0,
+ },
+};
static const struct snd_kcontrol_new lc_controls[] = {
WM8776_FIELD_CTL_VOLUME("Limiter Threshold",
WM8776_ALCCTRL1, 0, 11, 0, 15, 0xf,
@@ -1028,6 +1162,26 @@ static const struct snd_kcontrol_new lc_controls[] = {
LC_CONTROL_ALC, wm8776_ngth_db_scale),
};
+static int add_lc_controls(struct oxygen *chip)
+{
+ struct xonar_wm87x6 *data = chip->model_data;
+ unsigned int i;
+ struct snd_kcontrol *ctl;
+ int err;
+
+ BUILD_BUG_ON(ARRAY_SIZE(lc_controls) != ARRAY_SIZE(data->lc_controls));
+ for (i = 0; i < ARRAY_SIZE(lc_controls); ++i) {
+ ctl = snd_ctl_new1(&lc_controls[i], chip);
+ if (!ctl)
+ return -ENOMEM;
+ err = snd_ctl_add(chip->card, ctl);
+ if (err < 0)
+ return err;
+ data->lc_controls[i] = ctl;
+ }
+ return 0;
+}
+
static int xonar_ds_mixer_init(struct oxygen *chip)
{
struct xonar_wm87x6 *data = chip->model_data;
@@ -1049,17 +1203,54 @@ static int xonar_ds_mixer_init(struct oxygen *chip)
}
if (!data->line_adcmux_control || !data->mic_adcmux_control)
return -ENXIO;
- BUILD_BUG_ON(ARRAY_SIZE(lc_controls) != ARRAY_SIZE(data->lc_controls));
- for (i = 0; i < ARRAY_SIZE(lc_controls); ++i) {
- ctl = snd_ctl_new1(&lc_controls[i], chip);
+
+ return add_lc_controls(chip);
+}
+
+static int xonar_hdav_slim_mixer_init(struct oxygen *chip)
+{
+ unsigned int i;
+ struct snd_kcontrol *ctl;
+ int err;
+
+ for (i = 0; i < ARRAY_SIZE(hdav_slim_controls); ++i) {
+ ctl = snd_ctl_new1(&hdav_slim_controls[i], chip);
if (!ctl)
return -ENOMEM;
err = snd_ctl_add(chip->card, ctl);
if (err < 0)
return err;
- data->lc_controls[i] = ctl;
}
- return 0;
+
+ return add_lc_controls(chip);
+}
+
+static void dump_wm8776_registers(struct oxygen *chip,
+ struct snd_info_buffer *buffer)
+{
+ struct xonar_wm87x6 *data = chip->model_data;
+ unsigned int i;
+
+ snd_iprintf(buffer, "\nWM8776:\n00:");
+ for (i = 0; i < 0x10; ++i)
+ snd_iprintf(buffer, " %03x", data->wm8776_regs[i]);
+ snd_iprintf(buffer, "\n10:");
+ for (i = 0x10; i < 0x17; ++i)
+ snd_iprintf(buffer, " %03x", data->wm8776_regs[i]);
+ snd_iprintf(buffer, "\n");
+}
+
+static void dump_wm87x6_registers(struct oxygen *chip,
+ struct snd_info_buffer *buffer)
+{
+ struct xonar_wm87x6 *data = chip->model_data;
+ unsigned int i;
+
+ dump_wm8776_registers(chip, buffer);
+ snd_iprintf(buffer, "\nWM8766:\n00:");
+ for (i = 0; i < 0x10; ++i)
+ snd_iprintf(buffer, " %03x", data->wm8766_regs[i]);
+ snd_iprintf(buffer, "\n");
}
static const struct oxygen_model model_xonar_ds = {
@@ -1072,22 +1263,57 @@ static const struct oxygen_model model_xonar_ds = {
.suspend = xonar_ds_suspend,
.resume = xonar_ds_resume,
.pcm_hardware_filter = wm8776_adc_hardware_filter,
- .get_i2s_mclk = oxygen_default_i2s_mclk,
.set_dac_params = set_wm87x6_dac_params,
.set_adc_params = set_wm8776_adc_params,
.update_dac_volume = update_wm87x6_volume,
.update_dac_mute = update_wm87x6_mute,
.update_center_lfe_mix = update_wm8766_center_lfe_mix,
.gpio_changed = xonar_ds_gpio_changed,
+ .dump_registers = dump_wm87x6_registers,
.dac_tlv = wm87x6_dac_db_scale,
.model_data_size = sizeof(struct xonar_wm87x6),
.device_config = PLAYBACK_0_TO_I2S |
PLAYBACK_1_TO_SPDIF |
CAPTURE_0_FROM_I2S_1,
- .dac_channels = 8,
+ .dac_channels_pcm = 8,
+ .dac_channels_mixer = 8,
.dac_volume_min = 255 - 2*60,
.dac_volume_max = 255,
.function_flags = OXYGEN_FUNCTION_SPI,
+ .dac_mclks = OXYGEN_MCLKS(256, 256, 128),
+ .adc_mclks = OXYGEN_MCLKS(256, 256, 128),
+ .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+ .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+};
+
+static const struct oxygen_model model_xonar_hdav_slim = {
+ .shortname = "Xonar HDAV1.3 Slim",
+ .longname = "Asus Virtuoso 200",
+ .chip = "AV200",
+ .init = xonar_hdav_slim_init,
+ .mixer_init = xonar_hdav_slim_mixer_init,
+ .cleanup = xonar_hdav_slim_cleanup,
+ .suspend = xonar_hdav_slim_suspend,
+ .resume = xonar_hdav_slim_resume,
+ .pcm_hardware_filter = xonar_hdav_slim_hardware_filter,
+ .set_dac_params = set_hdav_slim_dac_params,
+ .set_adc_params = set_wm8776_adc_params,
+ .update_dac_volume = update_wm8776_volume,
+ .update_dac_mute = update_wm8776_mute,
+ .uart_input = xonar_hdmi_uart_input,
+ .dump_registers = dump_wm8776_registers,
+ .dac_tlv = wm87x6_dac_db_scale,
+ .model_data_size = sizeof(struct xonar_wm87x6),
+ .device_config = PLAYBACK_0_TO_I2S |
+ PLAYBACK_1_TO_SPDIF |
+ CAPTURE_0_FROM_I2S_1,
+ .dac_channels_pcm = 8,
+ .dac_channels_mixer = 2,
+ .dac_volume_min = 255 - 2*60,
+ .dac_volume_max = 255,
+ .function_flags = OXYGEN_FUNCTION_2WIRE,
+ .dac_mclks = OXYGEN_MCLKS(256, 256, 128),
+ .adc_mclks = OXYGEN_MCLKS(256, 256, 128),
.dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
};
@@ -1099,6 +1325,9 @@ int __devinit get_xonar_wm87x6_model(struct oxygen *chip,
case 0x838e:
chip->model = model_xonar_ds;
break;
+ case 0x835e:
+ chip->model = model_xonar_hdav_slim;
+ break;
default:
return -EINVAL;
}
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index 0b720cf7783..2d8332416c8 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -60,6 +60,7 @@ MODULE_SUPPORTED_DEVICE("{{RME Hammerfall-DSP},"
"{RME HDSP-9652},"
"{RME HDSP-9632}}");
#ifdef HDSP_FW_LOADER
+MODULE_FIRMWARE("rpm_firmware.bin");
MODULE_FIRMWARE("multiface_firmware.bin");
MODULE_FIRMWARE("multiface_firmware_rev11.bin");
MODULE_FIRMWARE("digiface_firmware.bin");
@@ -81,6 +82,7 @@ MODULE_FIRMWARE("digiface_firmware_rev11.bin");
#define H9632_SS_CHANNELS 12
#define H9632_DS_CHANNELS 8
#define H9632_QS_CHANNELS 4
+#define RPM_CHANNELS 6
/* Write registers. These are defined as byte-offsets from the iobase value.
*/
@@ -191,6 +193,25 @@ MODULE_FIRMWARE("digiface_firmware_rev11.bin");
#define HDSP_PhoneGain1 (1<<30)
#define HDSP_QuadSpeed (1<<31)
+/* RPM uses some of the registers for special purposes */
+#define HDSP_RPM_Inp12 0x04A00
+#define HDSP_RPM_Inp12_Phon_6dB 0x00800 /* Dolby */
+#define HDSP_RPM_Inp12_Phon_0dB 0x00000 /* .. */
+#define HDSP_RPM_Inp12_Phon_n6dB 0x04000 /* inp_0 */
+#define HDSP_RPM_Inp12_Line_0dB 0x04200 /* Dolby+PRO */
+#define HDSP_RPM_Inp12_Line_n6dB 0x00200 /* PRO */
+
+#define HDSP_RPM_Inp34 0x32000
+#define HDSP_RPM_Inp34_Phon_6dB 0x20000 /* SyncRef1 */
+#define HDSP_RPM_Inp34_Phon_0dB 0x00000 /* .. */
+#define HDSP_RPM_Inp34_Phon_n6dB 0x02000 /* SyncRef2 */
+#define HDSP_RPM_Inp34_Line_0dB 0x30000 /* SyncRef1+SyncRef0 */
+#define HDSP_RPM_Inp34_Line_n6dB 0x10000 /* SyncRef0 */
+
+#define HDSP_RPM_Bypass 0x01000
+
+#define HDSP_RPM_Disconnect 0x00001
+
#define HDSP_ADGainMask (HDSP_ADGain0|HDSP_ADGain1)
#define HDSP_ADGainMinus10dBV HDSP_ADGainMask
#define HDSP_ADGainPlus4dBu (HDSP_ADGain0)
@@ -450,7 +471,7 @@ struct hdsp {
u32 creg_spdif;
u32 creg_spdif_stream;
int clock_source_locked;
- char *card_name; /* digiface/multiface */
+ char *card_name; /* digiface/multiface/rpm */
enum HDSP_IO_Type io_type; /* ditto, but for code use */
unsigned short firmware_rev;
unsigned short state; /* stores state bits */
@@ -612,6 +633,7 @@ static int hdsp_playback_to_output_key (struct hdsp *hdsp, int in, int out)
switch (hdsp->io_type) {
case Multiface:
case Digiface:
+ case RPM:
default:
if (hdsp->firmware_rev == 0xa)
return (64 * out) + (32 + (in));
@@ -629,6 +651,7 @@ static int hdsp_input_to_output_key (struct hdsp *hdsp, int in, int out)
switch (hdsp->io_type) {
case Multiface:
case Digiface:
+ case RPM:
default:
if (hdsp->firmware_rev == 0xa)
return (64 * out) + in;
@@ -655,7 +678,7 @@ static int hdsp_check_for_iobox (struct hdsp *hdsp)
{
if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return 0;
if (hdsp_read (hdsp, HDSP_statusRegister) & HDSP_ConfigError) {
- snd_printk ("Hammerfall-DSP: no Digiface or Multiface connected!\n");
+ snd_printk("Hammerfall-DSP: no IO box connected!\n");
hdsp->state &= ~HDSP_FirmwareLoaded;
return -EIO;
}
@@ -680,7 +703,7 @@ static int hdsp_wait_for_iobox(struct hdsp *hdsp, unsigned int loops,
}
}
- snd_printk("Hammerfall-DSP: no Digiface or Multiface connected!\n");
+ snd_printk("Hammerfall-DSP: no IO box connected!\n");
hdsp->state &= ~HDSP_FirmwareLoaded;
return -EIO;
}
@@ -752,17 +775,21 @@ static int hdsp_get_iobox_version (struct hdsp *hdsp)
hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_LOAD);
hdsp_write (hdsp, HDSP_fifoData, 0);
- if (hdsp_fifo_wait (hdsp, 0, HDSP_SHORT_WAIT)) {
- hdsp->io_type = Multiface;
- hdsp_write (hdsp, HDSP_control2Reg, HDSP_VERSION_BIT);
- hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_LOAD);
- hdsp_fifo_wait (hdsp, 0, HDSP_SHORT_WAIT);
+ if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT)) {
+ hdsp_write(hdsp, HDSP_control2Reg, HDSP_VERSION_BIT);
+ hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD);
+ if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT))
+ hdsp->io_type = RPM;
+ else
+ hdsp->io_type = Multiface;
} else {
hdsp->io_type = Digiface;
}
} else {
/* firmware was already loaded, get iobox type */
- if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1)
+ if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version2)
+ hdsp->io_type = RPM;
+ else if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1)
hdsp->io_type = Multiface;
else
hdsp->io_type = Digiface;
@@ -1184,6 +1211,7 @@ static int hdsp_set_rate(struct hdsp *hdsp, int rate, int called_internally)
hdsp->channel_map = channel_map_ds;
} else {
switch (hdsp->io_type) {
+ case RPM:
case Multiface:
hdsp->channel_map = channel_map_mf_ss;
break;
@@ -3231,6 +3259,318 @@ HDSP_PRECISE_POINTER("Precise Pointer", 0),
HDSP_USE_MIDI_TASKLET("Use Midi Tasklet", 0),
};
+
+static int hdsp_rpm_input12(struct hdsp *hdsp)
+{
+ switch (hdsp->control_register & HDSP_RPM_Inp12) {
+ case HDSP_RPM_Inp12_Phon_6dB:
+ return 0;
+ case HDSP_RPM_Inp12_Phon_n6dB:
+ return 2;
+ case HDSP_RPM_Inp12_Line_0dB:
+ return 3;
+ case HDSP_RPM_Inp12_Line_n6dB:
+ return 4;
+ }
+ return 1;
+}
+
+
+static int snd_hdsp_get_rpm_input12(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.enumerated.item[0] = hdsp_rpm_input12(hdsp);
+ return 0;
+}
+
+
+static int hdsp_set_rpm_input12(struct hdsp *hdsp, int mode)
+{
+ hdsp->control_register &= ~HDSP_RPM_Inp12;
+ switch (mode) {
+ case 0:
+ hdsp->control_register |= HDSP_RPM_Inp12_Phon_6dB;
+ break;
+ case 1:
+ break;
+ case 2:
+ hdsp->control_register |= HDSP_RPM_Inp12_Phon_n6dB;
+ break;
+ case 3:
+ hdsp->control_register |= HDSP_RPM_Inp12_Line_0dB;
+ break;
+ case 4:
+ hdsp->control_register |= HDSP_RPM_Inp12_Line_n6dB;
+ break;
+ default:
+ return -1;
+ }
+
+ hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
+ return 0;
+}
+
+
+static int snd_hdsp_put_rpm_input12(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
+ int change;
+ int val;
+
+ if (!snd_hdsp_use_is_exclusive(hdsp))
+ return -EBUSY;
+ val = ucontrol->value.enumerated.item[0];
+ if (val < 0)
+ val = 0;
+ if (val > 4)
+ val = 4;
+ spin_lock_irq(&hdsp->lock);
+ if (val != hdsp_rpm_input12(hdsp))
+ change = (hdsp_set_rpm_input12(hdsp, val) == 0) ? 1 : 0;
+ else
+ change = 0;
+ spin_unlock_irq(&hdsp->lock);
+ return change;
+}
+
+
+static int snd_hdsp_info_rpm_input(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
+ static char *texts[] = {"Phono +6dB", "Phono 0dB", "Phono -6dB", "Line 0dB", "Line -6dB"};
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 5;
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+ strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+
+static int hdsp_rpm_input34(struct hdsp *hdsp)
+{
+ switch (hdsp->control_register & HDSP_RPM_Inp34) {
+ case HDSP_RPM_Inp34_Phon_6dB:
+ return 0;
+ case HDSP_RPM_Inp34_Phon_n6dB:
+ return 2;
+ case HDSP_RPM_Inp34_Line_0dB:
+ return 3;
+ case HDSP_RPM_Inp34_Line_n6dB:
+ return 4;
+ }
+ return 1;
+}
+
+
+static int snd_hdsp_get_rpm_input34(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.enumerated.item[0] = hdsp_rpm_input34(hdsp);
+ return 0;
+}
+
+
+static int hdsp_set_rpm_input34(struct hdsp *hdsp, int mode)
+{
+ hdsp->control_register &= ~HDSP_RPM_Inp34;
+ switch (mode) {
+ case 0:
+ hdsp->control_register |= HDSP_RPM_Inp34_Phon_6dB;
+ break;
+ case 1:
+ break;
+ case 2:
+ hdsp->control_register |= HDSP_RPM_Inp34_Phon_n6dB;
+ break;
+ case 3:
+ hdsp->control_register |= HDSP_RPM_Inp34_Line_0dB;
+ break;
+ case 4:
+ hdsp->control_register |= HDSP_RPM_Inp34_Line_n6dB;
+ break;
+ default:
+ return -1;
+ }
+
+ hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
+ return 0;
+}
+
+
+static int snd_hdsp_put_rpm_input34(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
+ int change;
+ int val;
+
+ if (!snd_hdsp_use_is_exclusive(hdsp))
+ return -EBUSY;
+ val = ucontrol->value.enumerated.item[0];
+ if (val < 0)
+ val = 0;
+ if (val > 4)
+ val = 4;
+ spin_lock_irq(&hdsp->lock);
+ if (val != hdsp_rpm_input34(hdsp))
+ change = (hdsp_set_rpm_input34(hdsp, val) == 0) ? 1 : 0;
+ else
+ change = 0;
+ spin_unlock_irq(&hdsp->lock);
+ return change;
+}
+
+
+/* RPM Bypass switch */
+static int hdsp_rpm_bypass(struct hdsp *hdsp)
+{
+ return (hdsp->control_register & HDSP_RPM_Bypass) ? 1 : 0;
+}
+
+
+static int snd_hdsp_get_rpm_bypass(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] = hdsp_rpm_bypass(hdsp);
+ return 0;
+}
+
+
+static int hdsp_set_rpm_bypass(struct hdsp *hdsp, int on)
+{
+ if (on)
+ hdsp->control_register |= HDSP_RPM_Bypass;
+ else
+ hdsp->control_register &= ~HDSP_RPM_Bypass;
+ hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
+ return 0;
+}
+
+
+static int snd_hdsp_put_rpm_bypass(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
+ int change;
+ unsigned int val;
+
+ if (!snd_hdsp_use_is_exclusive(hdsp))
+ return -EBUSY;
+ val = ucontrol->value.integer.value[0] & 1;
+ spin_lock_irq(&hdsp->lock);
+ change = (int)val != hdsp_rpm_bypass(hdsp);
+ hdsp_set_rpm_bypass(hdsp, val);
+ spin_unlock_irq(&hdsp->lock);
+ return change;
+}
+
+
+static int snd_hdsp_info_rpm_bypass(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
+ static char *texts[] = {"On", "Off"};
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 2;
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+ strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+
+/* RPM Disconnect switch */
+static int hdsp_rpm_disconnect(struct hdsp *hdsp)
+{
+ return (hdsp->control_register & HDSP_RPM_Disconnect) ? 1 : 0;
+}
+
+
+static int snd_hdsp_get_rpm_disconnect(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] = hdsp_rpm_disconnect(hdsp);
+ return 0;
+}
+
+
+static int hdsp_set_rpm_disconnect(struct hdsp *hdsp, int on)
+{
+ if (on)
+ hdsp->control_register |= HDSP_RPM_Disconnect;
+ else
+ hdsp->control_register &= ~HDSP_RPM_Disconnect;
+ hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
+ return 0;
+}
+
+
+static int snd_hdsp_put_rpm_disconnect(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
+ int change;
+ unsigned int val;
+
+ if (!snd_hdsp_use_is_exclusive(hdsp))
+ return -EBUSY;
+ val = ucontrol->value.integer.value[0] & 1;
+ spin_lock_irq(&hdsp->lock);
+ change = (int)val != hdsp_rpm_disconnect(hdsp);
+ hdsp_set_rpm_disconnect(hdsp, val);
+ spin_unlock_irq(&hdsp->lock);
+ return change;
+}
+
+static int snd_hdsp_info_rpm_disconnect(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
+ static char *texts[] = {"On", "Off"};
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 2;
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+ strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static struct snd_kcontrol_new snd_hdsp_rpm_controls[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "RPM Bypass",
+ .get = snd_hdsp_get_rpm_bypass,
+ .put = snd_hdsp_put_rpm_bypass,
+ .info = snd_hdsp_info_rpm_bypass
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "RPM Disconnect",
+ .get = snd_hdsp_get_rpm_disconnect,
+ .put = snd_hdsp_put_rpm_disconnect,
+ .info = snd_hdsp_info_rpm_disconnect
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Input 1/2",
+ .get = snd_hdsp_get_rpm_input12,
+ .put = snd_hdsp_put_rpm_input12,
+ .info = snd_hdsp_info_rpm_input
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Input 3/4",
+ .get = snd_hdsp_get_rpm_input34,
+ .put = snd_hdsp_put_rpm_input34,
+ .info = snd_hdsp_info_rpm_input
+ },
+ HDSP_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
+ HDSP_MIXER("Mixer", 0)
+};
+
static struct snd_kcontrol_new snd_hdsp_96xx_aeb = HDSP_AEB("Analog Extension Board", 0);
static struct snd_kcontrol_new snd_hdsp_adat_sync_check = HDSP_ADAT_SYNC_CHECK;
@@ -3240,6 +3580,16 @@ static int snd_hdsp_create_controls(struct snd_card *card, struct hdsp *hdsp)
int err;
struct snd_kcontrol *kctl;
+ if (hdsp->io_type == RPM) {
+ /* RPM Bypass, Disconnect and Input switches */
+ for (idx = 0; idx < ARRAY_SIZE(snd_hdsp_rpm_controls); idx++) {
+ err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_rpm_controls[idx], hdsp));
+ if (err < 0)
+ return err;
+ }
+ return 0;
+ }
+
for (idx = 0; idx < ARRAY_SIZE(snd_hdsp_controls); idx++) {
if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_controls[idx], hdsp))) < 0)
return err;
@@ -3459,48 +3809,102 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
snd_iprintf(buffer, "\n");
- switch (hdsp_spdif_in(hdsp)) {
- case HDSP_SPDIFIN_OPTICAL:
- snd_iprintf(buffer, "IEC958 input: Optical\n");
- break;
- case HDSP_SPDIFIN_COAXIAL:
- snd_iprintf(buffer, "IEC958 input: Coaxial\n");
- break;
- case HDSP_SPDIFIN_INTERNAL:
- snd_iprintf(buffer, "IEC958 input: Internal\n");
- break;
- case HDSP_SPDIFIN_AES:
- snd_iprintf(buffer, "IEC958 input: AES\n");
- break;
- default:
- snd_iprintf(buffer, "IEC958 input: ???\n");
- break;
+ if (hdsp->io_type != RPM) {
+ switch (hdsp_spdif_in(hdsp)) {
+ case HDSP_SPDIFIN_OPTICAL:
+ snd_iprintf(buffer, "IEC958 input: Optical\n");
+ break;
+ case HDSP_SPDIFIN_COAXIAL:
+ snd_iprintf(buffer, "IEC958 input: Coaxial\n");
+ break;
+ case HDSP_SPDIFIN_INTERNAL:
+ snd_iprintf(buffer, "IEC958 input: Internal\n");
+ break;
+ case HDSP_SPDIFIN_AES:
+ snd_iprintf(buffer, "IEC958 input: AES\n");
+ break;
+ default:
+ snd_iprintf(buffer, "IEC958 input: ???\n");
+ break;
+ }
}
- if (hdsp->control_register & HDSP_SPDIFOpticalOut)
- snd_iprintf(buffer, "IEC958 output: Coaxial & ADAT1\n");
- else
- snd_iprintf(buffer, "IEC958 output: Coaxial only\n");
+ if (RPM == hdsp->io_type) {
+ if (hdsp->control_register & HDSP_RPM_Bypass)
+ snd_iprintf(buffer, "RPM Bypass: disabled\n");
+ else
+ snd_iprintf(buffer, "RPM Bypass: enabled\n");
+ if (hdsp->control_register & HDSP_RPM_Disconnect)
+ snd_iprintf(buffer, "RPM disconnected\n");
+ else
+ snd_iprintf(buffer, "RPM connected\n");
- if (hdsp->control_register & HDSP_SPDIFProfessional)
- snd_iprintf(buffer, "IEC958 quality: Professional\n");
- else
- snd_iprintf(buffer, "IEC958 quality: Consumer\n");
+ switch (hdsp->control_register & HDSP_RPM_Inp12) {
+ case HDSP_RPM_Inp12_Phon_6dB:
+ snd_iprintf(buffer, "Input 1/2: Phono, 6dB\n");
+ break;
+ case HDSP_RPM_Inp12_Phon_0dB:
+ snd_iprintf(buffer, "Input 1/2: Phono, 0dB\n");
+ break;
+ case HDSP_RPM_Inp12_Phon_n6dB:
+ snd_iprintf(buffer, "Input 1/2: Phono, -6dB\n");
+ break;
+ case HDSP_RPM_Inp12_Line_0dB:
+ snd_iprintf(buffer, "Input 1/2: Line, 0dB\n");
+ break;
+ case HDSP_RPM_Inp12_Line_n6dB:
+ snd_iprintf(buffer, "Input 1/2: Line, -6dB\n");
+ break;
+ default:
+ snd_iprintf(buffer, "Input 1/2: ???\n");
+ }
- if (hdsp->control_register & HDSP_SPDIFEmphasis)
- snd_iprintf(buffer, "IEC958 emphasis: on\n");
- else
- snd_iprintf(buffer, "IEC958 emphasis: off\n");
+ switch (hdsp->control_register & HDSP_RPM_Inp34) {
+ case HDSP_RPM_Inp34_Phon_6dB:
+ snd_iprintf(buffer, "Input 3/4: Phono, 6dB\n");
+ break;
+ case HDSP_RPM_Inp34_Phon_0dB:
+ snd_iprintf(buffer, "Input 3/4: Phono, 0dB\n");
+ break;
+ case HDSP_RPM_Inp34_Phon_n6dB:
+ snd_iprintf(buffer, "Input 3/4: Phono, -6dB\n");
+ break;
+ case HDSP_RPM_Inp34_Line_0dB:
+ snd_iprintf(buffer, "Input 3/4: Line, 0dB\n");
+ break;
+ case HDSP_RPM_Inp34_Line_n6dB:
+ snd_iprintf(buffer, "Input 3/4: Line, -6dB\n");
+ break;
+ default:
+ snd_iprintf(buffer, "Input 3/4: ???\n");
+ }
- if (hdsp->control_register & HDSP_SPDIFNonAudio)
- snd_iprintf(buffer, "IEC958 NonAudio: on\n");
- else
- snd_iprintf(buffer, "IEC958 NonAudio: off\n");
- if ((x = hdsp_spdif_sample_rate (hdsp)) != 0)
- snd_iprintf (buffer, "IEC958 sample rate: %d\n", x);
- else
- snd_iprintf (buffer, "IEC958 sample rate: Error flag set\n");
+ } else {
+ if (hdsp->control_register & HDSP_SPDIFOpticalOut)
+ snd_iprintf(buffer, "IEC958 output: Coaxial & ADAT1\n");
+ else
+ snd_iprintf(buffer, "IEC958 output: Coaxial only\n");
+
+ if (hdsp->control_register & HDSP_SPDIFProfessional)
+ snd_iprintf(buffer, "IEC958 quality: Professional\n");
+ else
+ snd_iprintf(buffer, "IEC958 quality: Consumer\n");
+
+ if (hdsp->control_register & HDSP_SPDIFEmphasis)
+ snd_iprintf(buffer, "IEC958 emphasis: on\n");
+ else
+ snd_iprintf(buffer, "IEC958 emphasis: off\n");
+ if (hdsp->control_register & HDSP_SPDIFNonAudio)
+ snd_iprintf(buffer, "IEC958 NonAudio: on\n");
+ else
+ snd_iprintf(buffer, "IEC958 NonAudio: off\n");
+ x = hdsp_spdif_sample_rate(hdsp);
+ if (x != 0)
+ snd_iprintf(buffer, "IEC958 sample rate: %d\n", x);
+ else
+ snd_iprintf(buffer, "IEC958 sample rate: Error flag set\n");
+ }
snd_iprintf(buffer, "\n");
/* Sync Check */
@@ -3765,7 +4169,7 @@ static irqreturn_t snd_hdsp_interrupt(int irq, void *dev_id)
snd_hdsp_midi_input_read (&hdsp->midi[0]);
}
}
- if (hdsp->io_type != Multiface && hdsp->io_type != H9632 && midi1 && midi1status) {
+ if (hdsp->io_type != Multiface && hdsp->io_type != RPM && hdsp->io_type != H9632 && midi1 && midi1status) {
if (hdsp->use_midi_tasklet) {
/* we disable interrupts for this input until processing is done */
hdsp->control_register &= ~HDSP_Midi1InterruptEnable;
@@ -4093,7 +4497,7 @@ static struct snd_pcm_hardware snd_hdsp_playback_subinfo =
SNDRV_PCM_RATE_96000),
.rate_min = 32000,
.rate_max = 96000,
- .channels_min = 14,
+ .channels_min = 6,
.channels_max = HDSP_MAX_CHANNELS,
.buffer_bytes_max = HDSP_CHANNEL_BUFFER_BYTES * HDSP_MAX_CHANNELS,
.period_bytes_min = (64 * 4) * 10,
@@ -4122,7 +4526,7 @@ static struct snd_pcm_hardware snd_hdsp_capture_subinfo =
SNDRV_PCM_RATE_96000),
.rate_min = 32000,
.rate_max = 96000,
- .channels_min = 14,
+ .channels_min = 5,
.channels_max = HDSP_MAX_CHANNELS,
.buffer_bytes_max = HDSP_CHANNEL_BUFFER_BYTES * HDSP_MAX_CHANNELS,
.period_bytes_min = (64 * 4) * 10,
@@ -4357,10 +4761,12 @@ static int snd_hdsp_playback_open(struct snd_pcm_substream *substream)
snd_hdsp_hw_rule_rate_out_channels, hdsp,
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
- hdsp->creg_spdif_stream = hdsp->creg_spdif;
- hdsp->spdif_ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
- snd_ctl_notify(hdsp->card, SNDRV_CTL_EVENT_MASK_VALUE |
- SNDRV_CTL_EVENT_MASK_INFO, &hdsp->spdif_ctl->id);
+ if (RPM != hdsp->io_type) {
+ hdsp->creg_spdif_stream = hdsp->creg_spdif;
+ hdsp->spdif_ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+ snd_ctl_notify(hdsp->card, SNDRV_CTL_EVENT_MASK_VALUE |
+ SNDRV_CTL_EVENT_MASK_INFO, &hdsp->spdif_ctl->id);
+ }
return 0;
}
@@ -4375,9 +4781,11 @@ static int snd_hdsp_playback_release(struct snd_pcm_substream *substream)
spin_unlock_irq(&hdsp->lock);
- hdsp->spdif_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
- snd_ctl_notify(hdsp->card, SNDRV_CTL_EVENT_MASK_VALUE |
- SNDRV_CTL_EVENT_MASK_INFO, &hdsp->spdif_ctl->id);
+ if (RPM != hdsp->io_type) {
+ hdsp->spdif_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+ snd_ctl_notify(hdsp->card, SNDRV_CTL_EVENT_MASK_VALUE |
+ SNDRV_CTL_EVENT_MASK_INFO, &hdsp->spdif_ctl->id);
+ }
return 0;
}
@@ -4616,7 +5024,7 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne
if (hdsp->io_type != H9632)
info.adatsync_sync_check = (unsigned char)hdsp_adatsync_sync_check(hdsp);
info.spdif_sync_check = (unsigned char)hdsp_spdif_sync_check(hdsp);
- for (i = 0; i < ((hdsp->io_type != Multiface && hdsp->io_type != H9632) ? 3 : 1); ++i)
+ for (i = 0; i < ((hdsp->io_type != Multiface && hdsp->io_type != RPM && hdsp->io_type != H9632) ? 3 : 1); ++i)
info.adat_sync_check[i] = (unsigned char)hdsp_adat_sync_check(hdsp, i);
info.spdif_in = (unsigned char)hdsp_spdif_in(hdsp);
info.spdif_out = (unsigned char)hdsp_spdif_out(hdsp);
@@ -4636,6 +5044,9 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne
info.phone_gain = (unsigned char)hdsp_phone_gain(hdsp);
info.xlr_breakout_cable = (unsigned char)hdsp_xlr_breakout_cable(hdsp);
+ } else if (hdsp->io_type == RPM) {
+ info.da_gain = (unsigned char) hdsp_rpm_input12(hdsp);
+ info.ad_gain = (unsigned char) hdsp_rpm_input34(hdsp);
}
if (hdsp->io_type == H9632 || hdsp->io_type == H9652)
info.analog_extension_board = (unsigned char)hdsp_aeb(hdsp);
@@ -4844,6 +5255,14 @@ static void snd_hdsp_initialize_channels(struct hdsp *hdsp)
hdsp->ds_in_channels = hdsp->ds_out_channels = MULTIFACE_DS_CHANNELS;
break;
+ case RPM:
+ hdsp->card_name = "RME Hammerfall DSP + RPM";
+ hdsp->ss_in_channels = RPM_CHANNELS-1;
+ hdsp->ss_out_channels = RPM_CHANNELS;
+ hdsp->ds_in_channels = RPM_CHANNELS-1;
+ hdsp->ds_out_channels = RPM_CHANNELS;
+ break;
+
default:
/* should never get here */
break;
@@ -4930,6 +5349,9 @@ static int hdsp_request_fw_loader(struct hdsp *hdsp)
/* caution: max length of firmware filename is 30! */
switch (hdsp->io_type) {
+ case RPM:
+ fwfile = "rpm_firmware.bin";
+ break;
case Multiface:
if (hdsp->firmware_rev == 0xa)
fwfile = "multiface_firmware.bin";
@@ -5100,7 +5522,9 @@ static int __devinit snd_hdsp_create(struct snd_card *card,
return 0;
} else {
snd_printk(KERN_INFO "Hammerfall-DSP: Firmware already present, initializing card.\n");
- if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1)
+ if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version2)
+ hdsp->io_type = RPM;
+ else if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1)
hdsp->io_type = Multiface;
else
hdsp->io_type = Digiface;
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index 0c98ef9156d..f5eadfc0672 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -487,7 +487,7 @@ struct hdspm {
struct snd_kcontrol *playback_mixer_ctls[HDSPM_MAX_CHANNELS];
/* but input to much, so not used */
struct snd_kcontrol *input_mixer_ctls[HDSPM_MAX_CHANNELS];
- /* full mixer accessable over mixer ioctl or hwdep-device */
+ /* full mixer accessible over mixer ioctl or hwdep-device */
struct hdspm_mixer *mixer;
};
@@ -550,7 +550,7 @@ static inline int HDSPM_bit2freq(int n)
return bit2freq_tab[n];
}
-/* Write/read to/from HDSPM with Adresses in Bytes
+/* Write/read to/from HDSPM with Addresses in Bytes
not words but only 32Bit writes are allowed */
static inline void hdspm_write(struct hdspm * hdspm, unsigned int reg,
@@ -2908,7 +2908,7 @@ static int snd_hdspm_create_controls(struct snd_card *card, struct hdspm * hdspm
/* Channel playback mixer as default control
Note: the whole matrix would be 128*HDSPM_MIXER_CHANNELS Faders,
- thats too * big for any alsamixer they are accesible via special
+ thats too * big for any alsamixer they are accessible via special
IOCTL on hwdep and the mixer 2dimensional mixer control
*/
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
index 5518371db13..c94c051ad0c 100644
--- a/sound/pci/ymfpci/ymfpci_main.c
+++ b/sound/pci/ymfpci/ymfpci_main.c
@@ -1389,15 +1389,9 @@ static struct snd_kcontrol_new snd_ymfpci_spdif_stream __devinitdata =
static int snd_ymfpci_drec_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *info)
{
- static char *texts[3] = {"AC'97", "IEC958", "ZV Port"};
-
- info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- info->count = 1;
- info->value.enumerated.items = 3;
- if (info->value.enumerated.item > 2)
- info->value.enumerated.item = 2;
- strcpy(info->value.enumerated.name, texts[info->value.enumerated.item]);
- return 0;
+ static const char *const texts[3] = {"AC'97", "IEC958", "ZV Port"};
+
+ return snd_ctl_enum_info(info, 1, 3, texts);
}
static int snd_ymfpci_drec_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value)