aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/Kconfig2
-rw-r--r--sound/arm/Kconfig15
-rw-r--r--sound/arm/aaci.c2
-rw-r--r--sound/arm/pxa2xx-ac97-lib.c21
-rw-r--r--sound/arm/pxa2xx-pcm-lib.c2
-rw-r--r--sound/arm/pxa2xx-pcm.c1
-rw-r--r--sound/core/control_compat.c4
-rw-r--r--sound/core/device.c1
-rw-r--r--sound/core/hwdep.c10
-rw-r--r--sound/core/info.c3
-rw-r--r--sound/core/info_oss.c1
-rw-r--r--sound/core/isadma.c1
-rw-r--r--sound/core/memalloc.c4
-rw-r--r--sound/core/memory.c1
-rw-r--r--sound/core/misc.c2
-rw-r--r--sound/core/oss/mixer_oss.c3
-rw-r--r--sound/core/oss/pcm_oss.c2
-rw-r--r--sound/core/pcm.c1
-rw-r--r--sound/core/pcm_compat.c2
-rw-r--r--sound/core/pcm_lib.c55
-rw-r--r--sound/core/pcm_memory.c1
-rw-r--r--sound/core/pcm_misc.c1
-rw-r--r--sound/core/rtctimer.c2
-rw-r--r--sound/core/seq/oss/seq_oss.c2
-rw-r--r--sound/core/seq/oss/seq_oss_init.c1
-rw-r--r--sound/core/seq/oss/seq_oss_synth.c1
-rw-r--r--sound/core/seq/seq.c2
-rw-r--r--sound/core/seq/seq_clientmgr.c1
-rw-r--r--sound/core/seq/seq_device.c1
-rw-r--r--sound/core/seq/seq_dummy.c33
-rw-r--r--sound/core/seq/seq_info.c1
-rw-r--r--sound/core/seq/seq_lock.c1
-rw-r--r--sound/core/seq/seq_memory.c1
-rw-r--r--sound/core/seq/seq_midi.c2
-rw-r--r--sound/core/seq/seq_midi_emul.c1
-rw-r--r--sound/core/seq/seq_midi_event.c1
-rw-r--r--sound/core/seq/seq_ports.c1
-rw-r--r--sound/core/seq/seq_system.c1
-rw-r--r--sound/core/seq/seq_virmidi.c1
-rw-r--r--sound/core/sound.c2
-rw-r--r--sound/core/sound_oss.c1
-rw-r--r--sound/core/timer.c5
-rw-r--r--sound/core/vmaster.c19
-rw-r--r--sound/drivers/aloop.c20
-rw-r--r--sound/drivers/dummy.c2
-rw-r--r--sound/drivers/ml403-ac97cr.c6
-rw-r--r--sound/drivers/mtpav.c3
-rw-r--r--sound/drivers/mts64.c1
-rw-r--r--sound/drivers/portman2x4.c1
-rw-r--r--sound/drivers/serial-u16550.c4
-rw-r--r--sound/drivers/virmidi.c2
-rw-r--r--sound/pci/Kconfig26
-rw-r--r--sound/pci/ad1889.c5
-rw-r--r--sound/pci/ak4531_codec.c1
-rw-r--r--sound/pci/als300.c6
-rw-r--r--sound/pci/als4000.c9
-rw-r--r--sound/pci/atiixp.c8
-rw-r--r--sound/pci/atiixp_modem.c8
-rw-r--r--sound/pci/azt3328.c22
-rw-r--r--sound/pci/bt87x.c6
-rw-r--r--sound/pci/cmipci.c11
-rw-r--r--sound/pci/cs4281.c6
-rw-r--r--sound/pci/cs5530.c4
-rw-r--r--sound/pci/ens1370.c6
-rw-r--r--sound/pci/es1938.c13
-rw-r--r--sound/pci/es1968.c75
-rw-r--r--sound/pci/fm801.c26
-rw-r--r--sound/pci/hda/Kconfig40
-rw-r--r--sound/pci/hda/Makefile7
-rw-r--r--sound/pci/hda/hda_beep.c1
-rw-r--r--sound/pci/hda/hda_codec.c646
-rw-r--r--sound/pci/hda/hda_codec.h47
-rw-r--r--sound/pci/hda/hda_eld.c139
-rw-r--r--sound/pci/hda/hda_generic.c1
-rw-r--r--sound/pci/hda/hda_hwdep.c9
-rw-r--r--sound/pci/hda/hda_intel.c341
-rw-r--r--sound/pci/hda/hda_local.h62
-rw-r--r--sound/pci/hda/hda_proc.c14
-rw-r--r--sound/pci/hda/patch_analog.c188
-rw-r--r--sound/pci/hda/patch_ca0110.c4
-rw-r--r--sound/pci/hda/patch_cirrus.c801
-rw-r--r--sound/pci/hda/patch_cmedia.c18
-rw-r--r--sound/pci/hda/patch_conexant.c406
-rw-r--r--sound/pci/hda/patch_hdmi.c843
-rw-r--r--sound/pci/hda/patch_realtek.c19403
-rw-r--r--sound/pci/hda/patch_si3054.c1
-rw-r--r--sound/pci/hda/patch_sigmatel.c480
-rw-r--r--sound/pci/hda/patch_via.c6233
-rw-r--r--sound/pci/intel8x0.c79
-rw-r--r--sound/pci/intel8x0m.c8
-rw-r--r--sound/pci/korg1212/korg1212.c6
-rw-r--r--sound/pci/lola/lola.c6
-rw-r--r--sound/pci/lola/lola.h2
-rw-r--r--sound/pci/lola/lola_mixer.c130
-rw-r--r--sound/pci/lx6464es/lx6464es.c25
-rw-r--r--sound/pci/lx6464es/lx6464es.h4
-rw-r--r--sound/pci/lx6464es/lx_core.c21
-rw-r--r--sound/pci/lx6464es/lx_core.h5
-rw-r--r--sound/pci/maestro3.c81
-rw-r--r--sound/pci/mixart/mixart.c6
-rw-r--r--sound/pci/mixart/mixart_hwdep.c1
-rw-r--r--sound/pci/nm256/nm256.c6
-rw-r--r--sound/pci/rme32.c6
-rw-r--r--sound/pci/rme96.c6
-rw-r--r--sound/pci/sis7019.c12
-rw-r--r--sound/pci/sonicvibes.c13
-rw-r--r--sound/pci/trident/trident.c9
-rw-r--r--sound/pci/trident/trident_main.c3
-rw-r--r--sound/pci/via82xx.c19
-rw-r--r--sound/pci/via82xx_modem.c6
-rw-r--r--sound/pci/vx222/vx222.c6
-rw-r--r--sound/pci/ymfpci/ymfpci.c9
-rw-r--r--sound/pci/ymfpci/ymfpci_main.c35
-rw-r--r--sound/pcmcia/pdaudiocf/pdaudiocf.c2
-rw-r--r--sound/sh/aica.c2
-rw-r--r--sound/sh/sh_dac_audio.c1
-rw-r--r--sound/soc/Kconfig3
-rw-r--r--sound/soc/Makefile1
-rw-r--r--sound/soc/blackfin/Kconfig40
-rw-r--r--sound/soc/blackfin/Makefile6
-rw-r--r--sound/soc/blackfin/bf5xx-ac97-pcm.c6
-rw-r--r--sound/soc/blackfin/bf5xx-ad193x.c2
-rw-r--r--sound/soc/blackfin/bf5xx-ad73311.c2
-rw-r--r--sound/soc/blackfin/bf5xx-i2s-pcm.c12
-rw-r--r--sound/soc/blackfin/bf5xx-sport.c1
-rw-r--r--sound/soc/blackfin/bf5xx-tdm-pcm.c6
-rw-r--r--sound/soc/omap/Kconfig11
-rw-r--r--sound/soc/omap/Makefile6
-rw-r--r--sound/soc/omap/am3517evm.c51
-rw-r--r--sound/soc/omap/ams-delta.c13
-rw-r--r--sound/soc/omap/igep0020.c24
-rw-r--r--sound/soc/omap/mcpdm.c470
-rw-r--r--sound/soc/omap/mcpdm.h153
-rw-r--r--sound/soc/omap/n810.c47
-rw-r--r--sound/soc/omap/omap-mcbsp.c31
-rw-r--r--sound/soc/omap/omap-mcbsp.h2
-rw-r--r--sound/soc/omap/omap-mcpdm.c481
-rw-r--r--sound/soc/omap/omap-pcm.c23
-rw-r--r--sound/soc/omap/omap-pcm.h2
-rw-r--r--sound/soc/omap/omap3beagle.c1
-rw-r--r--sound/soc/omap/omap3evm.c24
-rw-r--r--sound/soc/omap/omap3pandora.c29
-rw-r--r--sound/soc/omap/osk5912.c51
-rw-r--r--sound/soc/omap/overo.c24
-rw-r--r--sound/soc/omap/rx51.c25
-rw-r--r--sound/soc/omap/sdp3430.c91
-rw-r--r--sound/soc/omap/sdp4430.c100
-rw-r--r--sound/soc/omap/zoom2.c99
148 files changed, 8814 insertions, 23702 deletions
diff --git a/sound/Kconfig b/sound/Kconfig
index 1fef141..261a03c 100644
--- a/sound/Kconfig
+++ b/sound/Kconfig
@@ -59,7 +59,7 @@ config SOUND_OSS_CORE_PRECLAIM
source "sound/oss/dmasound/Kconfig"
-if !M68K
+if !M68K && !UML
menuconfig SND
tristate "Advanced Linux Sound Architecture"
diff --git a/sound/arm/Kconfig b/sound/arm/Kconfig
index 885683a..e040621 100644
--- a/sound/arm/Kconfig
+++ b/sound/arm/Kconfig
@@ -9,6 +9,14 @@ menuconfig SND_ARM
Drivers that are implemented on ASoC can be found in
"ALSA for SoC audio support" section.
+config SND_PXA2XX_LIB
+ tristate
+ select SND_AC97_CODEC if SND_PXA2XX_LIB_AC97
+ select SND_DMAENGINE_PCM
+
+config SND_PXA2XX_LIB_AC97
+ bool
+
if SND_ARM
config SND_ARMAACI
@@ -21,13 +29,6 @@ config SND_PXA2XX_PCM
tristate
select SND_PCM
-config SND_PXA2XX_LIB
- tristate
- select SND_AC97_CODEC if SND_PXA2XX_LIB_AC97
-
-config SND_PXA2XX_LIB_AC97
- bool
-
config SND_PXA2XX_AC97
tristate "AC97 driver for the Intel PXA2xx chip"
depends on ARCH_PXA
diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c
index d0cead3..e518d38 100644
--- a/sound/arm/aaci.c
+++ b/sound/arm/aaci.c
@@ -443,7 +443,7 @@ static int aaci_pcm_open(struct snd_pcm_substream *substream)
mutex_lock(&aaci->irq_lock);
if (!aaci->users++) {
ret = request_irq(aaci->dev->irq[0], aaci_irq,
- IRQF_SHARED | IRQF_DISABLED, DRIVER_NAME, aaci);
+ IRQF_SHARED, DRIVER_NAME, aaci);
if (ret != 0)
aaci->users--;
}
diff --git a/sound/arm/pxa2xx-ac97-lib.c b/sound/arm/pxa2xx-ac97-lib.c
index 05bdcb2..52a4318 100644
--- a/sound/arm/pxa2xx-ac97-lib.c
+++ b/sound/arm/pxa2xx-ac97-lib.c
@@ -16,6 +16,8 @@
#include <linux/interrupt.h>
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
#include <sound/ac97_codec.h>
#include <sound/pxa2xx-lib.h>
@@ -342,8 +344,21 @@ int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev)
}
if (cpu_is_pxa27x()) {
- /* Use GPIO 113 as AC97 Reset on Bulverde */
+ /*
+ * This gpio is needed for a work-around to a bug in the ac97
+ * controller during warm reset. The direction and level is set
+ * here so that it is an output driven high when switching from
+ * AC97_nRESET alt function to generic gpio.
+ */
+ ret = gpio_request_one(reset_gpio, GPIOF_OUT_INIT_HIGH,
+ "pxa27x ac97 reset");
+ if (ret < 0) {
+ pr_err("%s: gpio_request_one() failed: %d\n",
+ __func__, ret);
+ goto err_conf;
+ }
pxa27x_assert_ac97reset(reset_gpio, 0);
+
ac97conf_clk = clk_get(&dev->dev, "AC97CONFCLK");
if (IS_ERR(ac97conf_clk)) {
ret = PTR_ERR(ac97conf_clk);
@@ -363,7 +378,7 @@ int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev)
if (ret)
goto err_clk2;
- ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, IRQF_DISABLED, "AC97", NULL);
+ ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, 0, "AC97", NULL);
if (ret < 0)
goto err_irq;
@@ -386,6 +401,8 @@ EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_probe);
void pxa2xx_ac97_hw_remove(struct platform_device *dev)
{
+ if (cpu_is_pxa27x())
+ gpio_free(reset_gpio);
GCR |= GCR_ACLINK_OFF;
free_irq(IRQ_AC97, NULL);
if (ac97conf_clk) {
diff --git a/sound/arm/pxa2xx-pcm-lib.c b/sound/arm/pxa2xx-pcm-lib.c
index 76e0d56..823359e 100644
--- a/sound/arm/pxa2xx-pcm-lib.c
+++ b/sound/arm/pxa2xx-pcm-lib.c
@@ -166,7 +166,9 @@ void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id)
} else {
printk(KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n",
rtd->params->name, dma_ch, dcsr);
+ snd_pcm_stream_lock(substream);
snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+ snd_pcm_stream_unlock(substream);
}
}
EXPORT_SYMBOL(pxa2xx_pcm_dma_irq);
diff --git a/sound/arm/pxa2xx-pcm.c b/sound/arm/pxa2xx-pcm.c
index 535704f..26422a3 100644
--- a/sound/arm/pxa2xx-pcm.c
+++ b/sound/arm/pxa2xx-pcm.c
@@ -10,6 +10,7 @@
* published by the Free Software Foundation.
*/
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/pxa2xx-lib.h>
diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c
index 4268744..2bb95a7 100644
--- a/sound/core/control_compat.c
+++ b/sound/core/control_compat.c
@@ -83,6 +83,8 @@ struct snd_ctl_elem_info32 {
u32 items;
u32 item;
char name[64];
+ u64 names_ptr;
+ u32 names_length;
} enumerated;
unsigned char reserved[128];
} value;
@@ -372,6 +374,8 @@ static int snd_ctl_elem_add_compat(struct snd_ctl_file *file,
&data32->value.enumerated,
sizeof(data->value.enumerated)))
goto error;
+ data->value.enumerated.names_ptr =
+ (uintptr_t)compat_ptr(data->value.enumerated.names_ptr);
break;
default:
break;
diff --git a/sound/core/device.c b/sound/core/device.c
index 2d1ad4b..f03cb54 100644
--- a/sound/core/device.c
+++ b/sound/core/device.c
@@ -21,6 +21,7 @@
#include <linux/slab.h>
#include <linux/time.h>
+#include <linux/export.h>
#include <linux/errno.h>
#include <sound/core.h>
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
index 32fb2fe..3f7f662 100644
--- a/sound/core/hwdep.c
+++ b/sound/core/hwdep.c
@@ -24,6 +24,7 @@
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/mutex.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/minors.h>
@@ -279,7 +280,14 @@ static int snd_hwdep_control_ioctl(struct snd_card *card,
if (get_user(device, (int __user *)arg))
return -EFAULT;
mutex_lock(&register_mutex);
- device = device < 0 ? 0 : device + 1;
+
+ if (device < 0)
+ device = 0;
+ else if (device < SNDRV_MINOR_HWDEPS)
+ device++;
+ else
+ device = SNDRV_MINOR_HWDEPS;
+
while (device < SNDRV_MINOR_HWDEPS) {
if (snd_hwdep_search(card, device))
break;
diff --git a/sound/core/info.c b/sound/core/info.c
index 7077f60..c1e611c 100644
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -24,6 +24,7 @@
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/string.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/minors.h>
#include <sound/info.h>
@@ -531,7 +532,7 @@ int __init snd_info_init(void)
{
struct proc_dir_entry *p;
- p = create_proc_entry("asound", S_IFDIR | S_IRUGO | S_IXUGO, NULL);
+ p = proc_mkdir("asound", NULL);
if (p == NULL)
return -ENOMEM;
snd_proc_root = p;
diff --git a/sound/core/info_oss.c b/sound/core/info_oss.c
index e4af138..cf42ab5 100644
--- a/sound/core/info_oss.c
+++ b/sound/core/info_oss.c
@@ -22,6 +22,7 @@
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/string.h>
+#include <linux/export.h>
#include <sound/core.h>
#include <sound/minors.h>
#include <sound/info.h>
diff --git a/sound/core/isadma.c b/sound/core/isadma.c
index 950e19b..c0f1208 100644
--- a/sound/core/isadma.c
+++ b/sound/core/isadma.c
@@ -26,6 +26,7 @@
#undef HAVE_REALLY_SLOW_DMA_CONTROLLER
+#include <linux/export.h>
#include <sound/core.h>
#include <asm/dma.h>
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c
index 16bd9c0..6915692 100644
--- a/sound/core/memalloc.c
+++ b/sound/core/memalloc.c
@@ -176,7 +176,7 @@ static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr,
* Calls the memory-allocator function for the corresponding
* buffer type.
*
- * Returns zero if the buffer with the given size is allocated successfuly,
+ * Returns zero if the buffer with the given size is allocated successfully,
* other a negative value at error.
*/
int snd_dma_alloc_pages(int type, struct device *device, size_t size,
@@ -230,7 +230,7 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size,
* tries to allocate again. The size actually allocated is stored in
* res_size argument.
*
- * Returns zero if the buffer with the given size is allocated successfuly,
+ * Returns zero if the buffer with the given size is allocated successfully,
* other a negative value at error.
*/
int snd_dma_alloc_pages_fallback(int type, struct device *device, size_t size,
diff --git a/sound/core/memory.c b/sound/core/memory.c
index 1161158..66a278d 100644
--- a/sound/core/memory.c
+++ b/sound/core/memory.c
@@ -20,6 +20,7 @@
*
*/
+#include <linux/export.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <sound/core.h>
diff --git a/sound/core/misc.c b/sound/core/misc.c
index eb9fe2e..465f0ce 100644
--- a/sound/core/misc.c
+++ b/sound/core/misc.c
@@ -20,6 +20,8 @@
*/
#include <linux/init.h>
+#include <linux/export.h>
+#include <linux/moduleparam.h>
#include <linux/time.h>
#include <linux/slab.h>
#include <linux/ioport.h>
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
index e7c1183..c353768 100644
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -23,6 +23,7 @@
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/string.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/minors.h>
#include <sound/control.h>
@@ -506,7 +507,7 @@ static struct snd_kcontrol *snd_mixer_oss_test_id(struct snd_mixer_oss *mixer, c
memset(&id, 0, sizeof(id));
id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- strcpy(id.name, name);
+ strlcpy(id.name, name, sizeof(id.name));
id.index = index;
return snd_ctl_find_id(card, &id);
}
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index 725a161..542f69e 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -30,7 +30,7 @@
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/vmalloc.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <linux/math64.h>
#include <linux/string.h>
#include <sound/core.h>
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 6e86ed5..13eaeb3 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -21,6 +21,7 @@
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/module.h>
#include <linux/time.h>
#include <linux/mutex.h>
#include <sound/core.h>
diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c
index 91cdf94..4dbb66e 100644
--- a/sound/core/pcm_compat.c
+++ b/sound/core/pcm_compat.c
@@ -204,6 +204,8 @@ static int snd_pcm_status_user_compat(struct snd_pcm_substream *substream,
if (err < 0)
return err;
+ if (clear_user(src, sizeof(*src)))
+ return -EFAULT;
if (put_user(status.state, &src->state) ||
put_user(status.trigger_tstamp.tv_sec, &src->trigger_tstamp.tv_sec) ||
put_user(status.trigger_tstamp.tv_nsec, &src->trigger_tstamp.tv_nsec) ||
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 397d9ad..7f00d34 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -23,6 +23,7 @@
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/math64.h>
+#include <linux/export.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/info.h>
@@ -128,7 +129,8 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
}
}
-static void pcm_debug_name(struct snd_pcm_substream *substream,
+#ifdef CONFIG_SND_DEBUG
+void snd_pcm_debug_name(struct snd_pcm_substream *substream,
char *name, size_t len)
{
snprintf(name, len, "pcmC%dD%d%c:%d",
@@ -137,6 +139,8 @@ static void pcm_debug_name(struct snd_pcm_substream *substream,
substream->stream ? 'c' : 'p',
substream->number);
}
+EXPORT_SYMBOL(snd_pcm_debug_name);
+#endif
#define XRUN_DEBUG_BASIC (1<<0)
#define XRUN_DEBUG_STACK (1<<1) /* dump also stack */
@@ -168,7 +172,7 @@ static void xrun(struct snd_pcm_substream *substream)
snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
if (xrun_debug(substream, XRUN_DEBUG_BASIC)) {
char name[16];
- pcm_debug_name(substream, name, sizeof(name));
+ snd_pcm_debug_name(substream, name, sizeof(name));
snd_printd(KERN_DEBUG "XRUN: %s\n", name);
dump_stack_on_xrun(substream);
}
@@ -243,7 +247,7 @@ static void xrun_log_show(struct snd_pcm_substream *substream)
return;
if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit)
return;
- pcm_debug_name(substream, name, sizeof(name));
+ snd_pcm_debug_name(substream, name, sizeof(name));
for (cnt = 0, idx = log->idx; cnt < XRUN_LOG_CNT; cnt++) {
entry = &log->entries[idx];
if (entry->period_size == 0)
@@ -319,7 +323,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
if (pos >= runtime->buffer_size) {
if (printk_ratelimit()) {
char name[16];
- pcm_debug_name(substream, name, sizeof(name));
+ snd_pcm_debug_name(substream, name, sizeof(name));
xrun_log_show(substream);
snd_printd(KERN_ERR "BUG: %s, pos = %ld, "
"buffer size = %ld, period size = %ld\n",
@@ -364,7 +368,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
if (xrun_debug(substream, in_interrupt ?
XRUN_DEBUG_PERIODUPDATE : XRUN_DEBUG_HWPTRUPDATE)) {
char name[16];
- pcm_debug_name(substream, name, sizeof(name));
+ snd_pcm_debug_name(substream, name, sizeof(name));
snd_printd("%s_update: %s: pos=%u/%u/%u, "
"hwptr=%ld/%ld/%ld/%ld\n",
in_interrupt ? "period" : "hwptr",
@@ -1396,6 +1400,32 @@ int snd_pcm_hw_constraint_pow2(struct snd_pcm_runtime *runtime,
EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2);
+static int snd_pcm_hw_rule_noresample_func(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ unsigned int base_rate = (unsigned int)(uintptr_t)rule->private;
+ struct snd_interval *rate;
+
+ rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ return snd_interval_list(rate, 1, &base_rate, 0);
+}
+
+/**
+ * snd_pcm_hw_rule_noresample - add a rule to allow disabling hw resampling
+ * @runtime: PCM runtime instance
+ * @base_rate: the rate at which the hardware does not resample
+ */
+int snd_pcm_hw_rule_noresample(struct snd_pcm_runtime *runtime,
+ unsigned int base_rate)
+{
+ return snd_pcm_hw_rule_add(runtime, SNDRV_PCM_HW_PARAMS_NORESAMPLE,
+ SNDRV_PCM_HW_PARAM_RATE,
+ snd_pcm_hw_rule_noresample_func,
+ (void *)(uintptr_t)base_rate,
+ SNDRV_PCM_HW_PARAM_RATE, -1);
+}
+EXPORT_SYMBOL(snd_pcm_hw_rule_noresample);
+
static void _snd_pcm_hw_param_any(struct snd_pcm_hw_params *params,
snd_pcm_hw_param_t var)
{
@@ -1662,14 +1692,16 @@ static int snd_pcm_lib_ioctl_fifo_size(struct snd_pcm_substream *substream,
{
struct snd_pcm_hw_params *params = arg;
snd_pcm_format_t format;
- int channels, width;
+ int channels;
+ ssize_t frame_size;
params->fifo_size = substream->runtime->hw.fifo_size;
if (!(substream->runtime->hw.info & SNDRV_PCM_INFO_FIFO_IN_FRAMES)) {
format = params_format(params);
channels = params_channels(params);
- width = snd_pcm_format_physical_width(format);
- params->fifo_size /= width * channels;
+ frame_size = snd_pcm_format_size(format, channels);
+ if (frame_size > 0)
+ params->fifo_size /= (unsigned)frame_size;
}
return 0;
}
@@ -1765,10 +1797,7 @@ static int wait_for_avail(struct snd_pcm_substream *substream,
if (runtime->no_period_wakeup)
wait_time = MAX_SCHEDULE_TIMEOUT;
else {
- if (substream->pcm->card->number != 0)
- wait_time = 1;
- else
- wait_time = 10;
+ wait_time = 10;
if (runtime->rate) {
long t = runtime->period_size * 2 / runtime->rate;
wait_time = max(t, wait_time);
@@ -1819,6 +1848,8 @@ static int wait_for_avail(struct snd_pcm_substream *substream,
case SNDRV_PCM_STATE_DISCONNECTED:
err = -EBADFD;
goto _endloop;
+ case SNDRV_PCM_STATE_PAUSED:
+ continue;
}
if (!tout) {
snd_printd("%s write error (DMA or IRQ trouble?)\n",
diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c
index 150cb7e..9571313 100644
--- a/sound/core/pcm_memory.c
+++ b/sound/core/pcm_memory.c
@@ -25,6 +25,7 @@
#include <linux/slab.h>
#include <linux/moduleparam.h>
#include <linux/vmalloc.h>
+#include <linux/export.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/info.h>
diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c
index 88f02e3..9c9eff9 100644
--- a/sound/core/pcm_misc.c
+++ b/sound/core/pcm_misc.c
@@ -20,6 +20,7 @@
*/
#include <linux/time.h>
+#include <linux/export.h>
#include <sound/core.h>
#include <sound/pcm.h>
#define SND_PCM_FORMAT_UNKNOWN (-1)
diff --git a/sound/core/rtctimer.c b/sound/core/rtctimer.c
index 0851cd1..e85e72b 100644
--- a/sound/core/rtctimer.c
+++ b/sound/core/rtctimer.c
@@ -22,7 +22,7 @@
#include <linux/init.h>
#include <linux/interrupt.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <linux/log2.h>
#include <sound/core.h>
#include <sound/timer.h>
diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c
index a1f1a2f..8d4d5e8 100644
--- a/sound/core/seq/oss/seq_oss.c
+++ b/sound/core/seq/oss/seq_oss.c
@@ -21,7 +21,7 @@
*/
#include <linux/init.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <linux/mutex.h>
#include <sound/core.h>
#include <sound/minors.h>
diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c
index 69cd7b3..e3cb46f 100644
--- a/sound/core/seq/oss/seq_oss_init.c
+++ b/sound/core/seq/oss/seq_oss_init.c
@@ -28,6 +28,7 @@
#include "seq_oss_timer.h"
#include "seq_oss_event.h"
#include <linux/init.h>
+#include <linux/export.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c
index ee44ab9..c5b773a 100644
--- a/sound/core/seq/oss/seq_oss_synth.c
+++ b/sound/core/seq/oss/seq_oss_synth.c
@@ -24,6 +24,7 @@
#include "seq_oss_midi.h"
#include "../seq_lock.h"
#include <linux/init.h>
+#include <linux/module.h>
#include <linux/slab.h>
/*
diff --git a/sound/core/seq/seq.c b/sound/core/seq/seq.c
index 119fddb6..9d8379a 100644
--- a/sound/core/seq/seq.c
+++ b/sound/core/seq/seq.c
@@ -20,7 +20,7 @@
*/
#include <linux/init.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/initval.h>
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index f2436d3..4dc6bae 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -22,6 +22,7 @@
*/
#include <linux/init.h>
+#include <linux/export.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/minors.h>
diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c
index 1f99767..5cf8d65 100644
--- a/sound/core/seq/seq_device.c
+++ b/sound/core/seq/seq_device.c
@@ -37,6 +37,7 @@
*/
#include <linux/init.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/seq_device.h>
diff --git a/sound/core/seq/seq_dummy.c b/sound/core/seq/seq_dummy.c
index 1d7d90c..5b41e04 100644
--- a/sound/core/seq/seq_dummy.c
+++ b/sound/core/seq/seq_dummy.c
@@ -20,7 +20,7 @@
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <sound/core.h>
#include "seq_clientmgr.h"
#include <sound/initval.h>
@@ -82,36 +82,6 @@ struct snd_seq_dummy_port {
static int my_client = -1;
/*
- * unuse callback - send ALL_SOUNDS_OFF and RESET_CONTROLLERS events
- * to subscribers.
- * Note: this callback is called only after all subscribers are removed.
- */
-static int
-dummy_unuse(void *private_data, struct snd_seq_port_subscribe *info)
-{
- struct snd_seq_dummy_port *p;
- int i;
- struct snd_seq_event ev;
-
- p = private_data;
- memset(&ev, 0, sizeof(ev));
- if (p->duplex)
- ev.source.port = p->connect;
- else
- ev.source.port = p->port;
- ev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;
- ev.type = SNDRV_SEQ_EVENT_CONTROLLER;
- for (i = 0; i < 16; i++) {
- ev.data.control.channel = i;
- ev.data.control.param = MIDI_CTL_ALL_SOUNDS_OFF;
- snd_seq_kernel_client_dispatch(p->client, &ev, 0, 0);
- ev.data.control.param = MIDI_CTL_RESET_CONTROLLERS;
- snd_seq_kernel_client_dispatch(p->client, &ev, 0, 0);
- }
- return 0;
-}
-
-/*
* event input callback - just redirect events to subscribers
*/
static int
@@ -175,7 +145,6 @@ create_port(int idx, int type)
| SNDRV_SEQ_PORT_TYPE_PORT;
memset(&pcb, 0, sizeof(pcb));
pcb.owner = THIS_MODULE;
- pcb.unuse = dummy_unuse;
pcb.event_input = dummy_input;
pcb.private_free = dummy_free;
pcb.private_data = rec;
diff --git a/sound/core/seq/seq_info.c b/sound/core/seq/seq_info.c
index 201f810..acf7769 100644
--- a/sound/core/seq/seq_info.c
+++ b/sound/core/seq/seq_info.c
@@ -20,6 +20,7 @@
*/
#include <linux/init.h>
+#include <linux/export.h>
#include <sound/core.h>
#include "seq_info.h"
diff --git a/sound/core/seq/seq_lock.c b/sound/core/seq/seq_lock.c
index 54f921e..2cfe50c 100644
--- a/sound/core/seq/seq_lock.c
+++ b/sound/core/seq/seq_lock.c
@@ -19,6 +19,7 @@
*
*/
+#include <linux/export.h>
#include <sound/core.h>
#include "seq_lock.h"
diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c
index 7f50c14..f478f77 100644
--- a/sound/core/seq/seq_memory.c
+++ b/sound/core/seq/seq_memory.c
@@ -21,6 +21,7 @@
*/
#include <linux/init.h>
+#include <linux/export.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <sound/core.h>
diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c
index ebaf1b5..64069db 100644
--- a/sound/core/seq/seq_midi.c
+++ b/sound/core/seq/seq_midi.c
@@ -30,7 +30,7 @@ Possible options for midisynth module:
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/string.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <linux/mutex.h>
#include <sound/core.h>
#include <sound/rawmidi.h>
diff --git a/sound/core/seq/seq_midi_emul.c b/sound/core/seq/seq_midi_emul.c
index 07c6631..6f64471 100644
--- a/sound/core/seq/seq_midi_emul.c
+++ b/sound/core/seq/seq_midi_emul.c
@@ -32,6 +32,7 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/string.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/seq_kernel.h>
#include <sound/seq_midi_emul.h>
diff --git a/sound/core/seq/seq_midi_event.c b/sound/core/seq/seq_midi_event.c
index b5d6ea4..37db7ba 100644
--- a/sound/core/seq/seq_midi_event.c
+++ b/sound/core/seq/seq_midi_event.c
@@ -22,6 +22,7 @@
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/string.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/seq_kernel.h>
#include <sound/seq_midi_event.h>
diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c
index e12bcd9..9516e5c 100644
--- a/sound/core/seq/seq_ports.c
+++ b/sound/core/seq/seq_ports.c
@@ -22,6 +22,7 @@
#include <sound/core.h>
#include <linux/slab.h>
+#include <linux/module.h>
#include "seq_system.h"
#include "seq_ports.h"
#include "seq_clientmgr.h"
diff --git a/sound/core/seq/seq_system.c b/sound/core/seq/seq_system.c
index c38b90c..8ce1d0b 100644
--- a/sound/core/seq/seq_system.c
+++ b/sound/core/seq/seq_system.c
@@ -20,6 +20,7 @@
*/
#include <linux/init.h>
+#include <linux/export.h>
#include <linux/slab.h>
#include <sound/core.h>
#include "seq_system.h"
diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c
index 86e7739..4b50e60 100644
--- a/sound/core/seq/seq_virmidi.c
+++ b/sound/core/seq/seq_virmidi.c
@@ -37,6 +37,7 @@
#include <linux/init.h>
#include <linux/wait.h>
+#include <linux/module.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/rawmidi.h>
diff --git a/sound/core/sound.c b/sound/core/sound.c
index e9b79b5..8e17b4d 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -23,7 +23,7 @@
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/device.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/minors.h>
#include <sound/info.h>
diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c
index b6ff6d6..ec86009 100644
--- a/sound/core/sound_oss.c
+++ b/sound/core/sound_oss.c
@@ -26,6 +26,7 @@
#endif
#include <linux/init.h>
+#include <linux/export.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <sound/core.h>
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 950eed0..8e7561d 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -24,7 +24,7 @@
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/mutex.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <linux/string.h>
#include <sound/core.h>
#include <sound/timer.h>
@@ -328,6 +328,8 @@ int snd_timer_close(struct snd_timer_instance *timeri)
mutex_unlock(&register_mutex);
} else {
timer = timeri->timer;
+ if (snd_BUG_ON(!timer))
+ goto out;
/* wait, until the active callback is finished */
spin_lock_irq(&timer->lock);
while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) {
@@ -353,6 +355,7 @@ int snd_timer_close(struct snd_timer_instance *timeri)
}
mutex_unlock(&register_mutex);
}
+ out:
if (timeri->private_free)
timeri->private_free(timeri);
kfree(timeri->owner);
diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c
index 6058a37..ac0af03 100644
--- a/sound/core/vmaster.c
+++ b/sound/core/vmaster.c
@@ -10,6 +10,7 @@
*/
#include <linux/slab.h>
+#include <linux/export.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/tlv.h>
@@ -51,6 +52,7 @@ struct link_slave {
struct link_ctl_info info;
int vals[2]; /* current values */
unsigned int flags;
+ struct snd_kcontrol *kctl; /* original kcontrol pointer */
struct snd_kcontrol slave; /* the copy of original control entry */
};
@@ -254,6 +256,7 @@ int _snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave,
slave->count * sizeof(*slave->vd), GFP_KERNEL);
if (!srec)
return -ENOMEM;
+ srec->kctl = slave;
srec->slave = *slave;
memcpy(srec->slave.vd, slave->vd, slave->count * sizeof(*slave->vd));
srec->master = master_link;
@@ -335,10 +338,18 @@ static int master_put(struct snd_kcontrol *kcontrol,
static void master_free(struct snd_kcontrol *kcontrol)
{
struct link_master *master = snd_kcontrol_chip(kcontrol);
- struct link_slave *slave;
-
- list_for_each_entry(slave, &master->slaves, list)
- slave->master = NULL;
+ struct link_slave *slave, *n;
+
+ /* free all slave links and retore the original slave kctls */
+ list_for_each_entry_safe(slave, n, &master->slaves, list) {
+ struct snd_kcontrol *sctl = slave->kctl;
+ struct list_head olist = sctl->list;
+ memcpy(sctl, &slave->slave, sizeof(*sctl));
+ memcpy(sctl->vd, slave->slave.vd,
+ sctl->count * sizeof(*sctl->vd));
+ sctl->list = olist; /* keep the current linked-list */
+ kfree(slave);
+ }
kfree(master);
}
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
index 5eab948..42b876d 100644
--- a/sound/drivers/aloop.c
+++ b/sound/drivers/aloop.c
@@ -34,7 +34,7 @@
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/wait.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <linux/platform_device.h>
#include <sound/core.h>
#include <sound/control.h>
@@ -287,12 +287,14 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd)
loopback_active_notify(dpcm);
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
spin_lock(&cable->lock);
cable->pause |= stream;
spin_unlock(&cable->lock);
loopback_timer_stop(dpcm);
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ case SNDRV_PCM_TRIGGER_RESUME:
spin_lock(&cable->lock);
dpcm->last_jiffies = jiffies;
cable->pause &= ~stream;
@@ -552,7 +554,8 @@ static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream)
static struct snd_pcm_hardware loopback_pcm_hardware =
{
.info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE),
+ SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME),
.formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |
SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE),
@@ -580,7 +583,8 @@ static void loopback_runtime_free(struct snd_pcm_runtime *runtime)
static int loopback_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+ return snd_pcm_lib_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(params));
}
static int loopback_hw_free(struct snd_pcm_substream *substream)
@@ -592,7 +596,7 @@ static int loopback_hw_free(struct snd_pcm_substream *substream)
mutex_lock(&dpcm->loopback->cable_lock);
cable->valid &= ~(1 << substream->stream);
mutex_unlock(&dpcm->loopback->cable_lock);
- return snd_pcm_lib_free_pages(substream);
+ return snd_pcm_lib_free_vmalloc_buffer(substream);
}
static unsigned int get_cable_index(struct snd_pcm_substream *substream)
@@ -746,6 +750,8 @@ static struct snd_pcm_ops loopback_playback_ops = {
.prepare = loopback_prepare,
.trigger = loopback_trigger,
.pointer = loopback_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ .mmap = snd_pcm_lib_mmap_vmalloc,
};
static struct snd_pcm_ops loopback_capture_ops = {
@@ -757,6 +763,8 @@ static struct snd_pcm_ops loopback_capture_ops = {
.prepare = loopback_prepare,
.trigger = loopback_trigger,
.pointer = loopback_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ .mmap = snd_pcm_lib_mmap_vmalloc,
};
static int __devinit loopback_pcm_new(struct loopback *loopback,
@@ -777,10 +785,6 @@ static int __devinit loopback_pcm_new(struct loopback *loopback,
strcpy(pcm->name, "Loopback PCM");
loopback->pcm[device] = pcm;
-
- snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
- snd_dma_continuous_data(GFP_KERNEL),
- 0, 2 * 1024 * 1024);
return 0;
}
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c
index 7f41990..97f1f93 100644
--- a/sound/drivers/dummy.c
+++ b/sound/drivers/dummy.c
@@ -27,7 +27,7 @@
#include <linux/wait.h>
#include <linux/hrtimer.h>
#include <linux/math64.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/tlv.h>
diff --git a/sound/drivers/ml403-ac97cr.c b/sound/drivers/ml403-ac97cr.c
index 5cfcb90..2ee82c5 100644
--- a/sound/drivers/ml403-ac97cr.c
+++ b/sound/drivers/ml403-ac97cr.c
@@ -34,7 +34,7 @@
*/
#include <linux/init.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <linux/platform_device.h>
@@ -1153,7 +1153,7 @@ snd_ml403_ac97cr_create(struct snd_card *card, struct platform_device *pfdev,
"0x%x done\n", (unsigned int)ml403_ac97cr->port);
/* get irq */
irq = platform_get_irq(pfdev, 0);
- if (request_irq(irq, snd_ml403_ac97cr_irq, IRQF_DISABLED,
+ if (request_irq(irq, snd_ml403_ac97cr_irq, 0,
dev_name(&pfdev->dev), (void *)ml403_ac97cr)) {
snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": "
"unable to grab IRQ %d\n",
@@ -1166,7 +1166,7 @@ snd_ml403_ac97cr_create(struct snd_card *card, struct platform_device *pfdev,
"request (playback) irq %d done\n",
ml403_ac97cr->irq);
irq = platform_get_irq(pfdev, 1);
- if (request_irq(irq, snd_ml403_ac97cr_irq, IRQF_DISABLED,
+ if (request_irq(irq, snd_ml403_ac97cr_irq, 0,
dev_name(&pfdev->dev), (void *)ml403_ac97cr)) {
snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": "
"unable to grab IRQ %d\n",
diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c
index 5c426df..7693079 100644
--- a/sound/drivers/mtpav.c
+++ b/sound/drivers/mtpav.c
@@ -52,6 +52,7 @@
#include <linux/init.h>
#include <linux/interrupt.h>
+#include <linux/module.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>
@@ -589,7 +590,7 @@ static int __devinit snd_mtpav_get_ISA(struct mtpav * mcard)
return -EBUSY;
}
mcard->port = port;
- if (request_irq(irq, snd_mtpav_irqh, IRQF_DISABLED, "MOTU MTPAV", mcard)) {
+ if (request_irq(irq, snd_mtpav_irqh, 0, "MOTU MTPAV", mcard)) {
snd_printk(KERN_ERR "MTVAP IRQ %d busy\n", irq);
return -EBUSY;
}
diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c
index 8539ab0..f24bf9a 100644
--- a/sound/drivers/mts64.c
+++ b/sound/drivers/mts64.c
@@ -22,6 +22,7 @@
#include <linux/platform_device.h>
#include <linux/parport.h>
#include <linux/spinlock.h>
+#include <linux/module.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <sound/core.h>
diff --git a/sound/drivers/portman2x4.c b/sound/drivers/portman2x4.c
index f2b0ba2..f664823 100644
--- a/sound/drivers/portman2x4.c
+++ b/sound/drivers/portman2x4.c
@@ -43,6 +43,7 @@
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/rawmidi.h>
diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c
index a25fb7b..85aad43 100644
--- a/sound/drivers/serial-u16550.c
+++ b/sound/drivers/serial-u16550.c
@@ -36,7 +36,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/ioport.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/rawmidi.h>
#include <sound/initval.h>
@@ -816,7 +816,7 @@ static int __devinit snd_uart16550_create(struct snd_card *card,
if (irq >= 0 && irq != SNDRV_AUTO_IRQ) {
if (request_irq(irq, snd_uart16550_interrupt,
- IRQF_DISABLED, "Serial MIDI", uart)) {
+ 0, "Serial MIDI", uart)) {
snd_printk(KERN_WARNING
"irq %d busy. Using Polling.\n", irq);
} else {
diff --git a/sound/drivers/virmidi.c b/sound/drivers/virmidi.c
index f4cd493..d79d6ed 100644
--- a/sound/drivers/virmidi.c
+++ b/sound/drivers/virmidi.c
@@ -45,7 +45,7 @@
#include <linux/wait.h>
#include <linux/err.h>
#include <linux/platform_device.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/seq_kernel.h>
#include <sound/seq_virmidi.h>
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index e90d103..e2e4829 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -1,5 +1,10 @@
# ALSA PCI drivers
+config SND_TEA575X
+ tristate
+ depends on SND_FM801_TEA575X_BOOL || SND_ES1968_RADIO || RADIO_SF16FMR2
+ default SND_FM801 || SND_ES1968 || RADIO_SF16FMR2
+
menuconfig SND_PCI
bool "PCI sound devices"
depends on PCI
@@ -25,6 +30,7 @@ config SND_ALS300
select SND_PCM
select SND_AC97_CODEC
select SND_OPL3_LIB
+ select ZONE_DMA
help
Say 'Y' or 'M' to include support for Avance Logic ALS300/ALS300+
@@ -49,6 +55,7 @@ config SND_ALI5451
tristate "ALi M5451 PCI Audio Controller"
select SND_MPU401_UART
select SND_AC97_CODEC
+ select ZONE_DMA
help
Say Y here to include support for the integrated AC97 sound
device on motherboards using the ALi M5451 Audio Controller
@@ -153,6 +160,7 @@ config SND_AZT3328
select SND_PCM
select SND_RAWMIDI
select SND_AC97_CODEC
+ select ZONE_DMA
help
Say Y here to include support for Aztech AZF3328 (PCI168)
soundcards.
@@ -458,6 +466,7 @@ config SND_EMU10K1
select SND_HWDEP
select SND_RAWMIDI
select SND_AC97_CODEC
+ select ZONE_DMA
help
Say Y to include support for Sound Blaster PCI 512, Live!,
Audigy and E-mu APS (partially supported) soundcards.
@@ -473,6 +482,7 @@ config SND_EMU10K1X
tristate "Emu10k1X (Dell OEM Version)"
select SND_AC97_CODEC
select SND_RAWMIDI
+ select ZONE_DMA
help
Say Y here to include support for the Dell OEM version of the
Sound Blaster Live!.
@@ -506,6 +516,7 @@ config SND_ES1938
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_AC97_CODEC
+ select ZONE_DMA
help
Say Y here to include support for soundcards based on ESS Solo-1
(ES1938, ES1946, ES1969) chips.
@@ -517,6 +528,7 @@ config SND_ES1968
tristate "ESS ES1968/1978 (Maestro-1/2/2E)"
select SND_MPU401_UART
select SND_AC97_CODEC
+ select ZONE_DMA
help
Say Y here to include support for soundcards based on ESS Maestro
1/2/2E chips.
@@ -563,11 +575,6 @@ config SND_FM801_TEA575X_BOOL
FM801 chip with a TEA5757 tuner (MediaForte SF256-PCS, SF256-PCP and
SF64-PCR) into the snd-fm801 driver.
-config SND_TEA575X
- tristate
- depends on SND_FM801_TEA575X_BOOL || SND_ES1968_RADIO
- default SND_FM801 || SND_ES1968
-
source "sound/pci/hda/Kconfig"
config SND_HDSP
@@ -602,6 +609,7 @@ config SND_ICE1712
select SND_MPU401_UART
select SND_AC97_CODEC
select BITREVERSE
+ select ZONE_DMA
help
Say Y here to include support for soundcards based on the
ICE1712 (Envy24) chip.
@@ -688,6 +696,7 @@ config SND_LX6464ES
config SND_MAESTRO3
tristate "ESS Allegro/Maestro3"
select SND_AC97_CODEC
+ select ZONE_DMA
help
Say Y here to include support for soundcards based on ESS Maestro 3
(Allegro) chips.
@@ -782,6 +791,7 @@ config SND_SIS7019
tristate "SiS 7019 Audio Accelerator"
depends on X86 && !X86_64
select SND_AC97_CODEC
+ select ZONE_DMA
help
Say Y here to include support for the SiS 7019 Audio Accelerator.
@@ -793,6 +803,7 @@ config SND_SONICVIBES
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_AC97_CODEC
+ select ZONE_DMA
help
Say Y here to include support for soundcards based on the S3
SonicVibes chip.
@@ -804,6 +815,7 @@ config SND_TRIDENT
tristate "Trident 4D-Wave DX/NX; SiS 7018"
select SND_MPU401_UART
select SND_AC97_CODEC
+ select ZONE_DMA
help
Say Y here to include support for soundcards based on Trident
4D-Wave DX/NX or SiS 7018 chips.
@@ -840,8 +852,8 @@ config SND_VIRTUOSO
select SND_JACK if INPUT=y || INPUT=SND
help
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.
+ Asus AV66/AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, DS, DSX,
+ Essence ST (Deluxe), and Essence STX (II).
Support for the HDAV1.3 (Deluxe) and HDAV1.3 Slim is experimental;
for the Xense, missing.
diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c
index d8f6fd6..6e31118 100644
--- a/sound/pci/ad1889.c
+++ b/sound/pci/ad1889.c
@@ -39,6 +39,7 @@
#include <linux/interrupt.h>
#include <linux/compiler.h>
#include <linux/delay.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -944,7 +945,7 @@ snd_ad1889_create(struct snd_card *card,
spin_lock_init(&chip->lock); /* only now can we call ad1889_free */
if (request_irq(pci->irq, snd_ad1889_interrupt,
- IRQF_SHARED, card->driver, chip)) {
+ IRQF_SHARED, KBUILD_MODNAME, chip)) {
printk(KERN_ERR PFX "cannot obtain IRQ %d\n", pci->irq);
snd_ad1889_free(chip);
return -EBUSY;
@@ -1055,7 +1056,7 @@ static DEFINE_PCI_DEVICE_TABLE(snd_ad1889_ids) = {
MODULE_DEVICE_TABLE(pci, snd_ad1889_ids);
static struct pci_driver ad1889_pci_driver = {
- .name = "AD1889 Audio",
+ .name = KBUILD_MODNAME,
.id_table = snd_ad1889_ids,
.probe = snd_ad1889_probe,
.remove = __devexit_p(snd_ad1889_remove),
diff --git a/sound/pci/ak4531_codec.c b/sound/pci/ak4531_codec.c
index fd135e3..cadf7b9 100644
--- a/sound/pci/ak4531_codec.c
+++ b/sound/pci/ak4531_codec.c
@@ -23,6 +23,7 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/mutex.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/ak4531_codec.h>
diff --git a/sound/pci/als300.c b/sound/pci/als300.c
index d7653cb..8dc77a0 100644
--- a/sound/pci/als300.c
+++ b/sound/pci/als300.c
@@ -32,7 +32,7 @@
#include <linux/delay.h>
#include <linux/init.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
@@ -722,7 +722,7 @@ static int __devinit snd_als300_create(struct snd_card *card,
irq_handler = snd_als300_interrupt;
if (request_irq(pci->irq, irq_handler, IRQF_SHARED,
- card->shortname, chip)) {
+ KBUILD_MODNAME, chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_als300_free(chip);
return -EBUSY;
@@ -846,7 +846,7 @@ static int __devinit snd_als300_probe(struct pci_dev *pci,
}
static struct pci_driver driver = {
- .name = "ALS300",
+ .name = KBUILD_MODNAME,
.id_table = snd_als300_ids,
.probe = snd_als300_probe,
.remove = __devexit_p(snd_als300_remove),
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c
index 0e247cb..28ef40e 100644
--- a/sound/pci/als4000.c
+++ b/sound/pci/als4000.c
@@ -69,7 +69,7 @@
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/gameport.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <linux/dma-mapping.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -931,8 +931,9 @@ static int __devinit snd_card_als4000_probe(struct pci_dev *pci,
if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_ALS4000,
iobase + ALS4K_IOB_30_MIDI_DATA,
- MPU401_INFO_INTEGRATED,
- pci->irq, 0, &chip->rmidi)) < 0) {
+ MPU401_INFO_INTEGRATED |
+ MPU401_INFO_IRQ_HOOK,
+ -1, &chip->rmidi)) < 0) {
printk(KERN_ERR "als4000: no MPU-401 device at 0x%lx?\n",
iobase + ALS4K_IOB_30_MIDI_DATA);
goto out_err;
@@ -1036,7 +1037,7 @@ static int snd_als4000_resume(struct pci_dev *pci)
static struct pci_driver driver = {
- .name = "ALS4000",
+ .name = KBUILD_MODNAME,
.id_table = snd_als4000_ids,
.probe = snd_card_als4000_probe,
.remove = __devexit_p(snd_card_als4000_remove),
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index 3119cd9..6faa173 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -25,7 +25,7 @@
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/slab.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <linux/mutex.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -688,7 +688,9 @@ static void snd_atiixp_xrun_dma(struct atiixp *chip, struct atiixp_dma *dma)
if (! dma->substream || ! dma->running)
return;
snd_printdd("atiixp: XRUN detected (DMA %d)\n", dma->ops->type);
+ snd_pcm_stream_lock(dma->substream);
snd_pcm_stop(dma->substream, SNDRV_PCM_STATE_XRUN);
+ snd_pcm_stream_unlock(dma->substream);
}
/*
@@ -1624,7 +1626,7 @@ static int __devinit snd_atiixp_create(struct snd_card *card,
}
if (request_irq(pci->irq, snd_atiixp_interrupt, IRQF_SHARED,
- card->shortname, chip)) {
+ KBUILD_MODNAME, chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_atiixp_free(chip);
return -EBUSY;
@@ -1701,7 +1703,7 @@ static void __devexit snd_atiixp_remove(struct pci_dev *pci)
}
static struct pci_driver driver = {
- .name = "ATI IXP AC97 controller",
+ .name = KBUILD_MODNAME,
.id_table = snd_atiixp_ids,
.probe = snd_atiixp_probe,
.remove = __devexit_p(snd_atiixp_remove),
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
index 2f74c2f..d752120 100644
--- a/sound/pci/atiixp_modem.c
+++ b/sound/pci/atiixp_modem.c
@@ -25,7 +25,7 @@
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/slab.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <linux/mutex.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -638,7 +638,9 @@ static void snd_atiixp_xrun_dma(struct atiixp_modem *chip,
if (! dma->substream || ! dma->running)
return;
snd_printdd("atiixp-modem: XRUN detected (DMA %d)\n", dma->ops->type);
+ snd_pcm_stream_lock(dma->substream);
snd_pcm_stop(dma->substream, SNDRV_PCM_STATE_XRUN);
+ snd_pcm_stream_unlock(dma->substream);
}
/*
@@ -1260,7 +1262,7 @@ static int __devinit snd_atiixp_create(struct snd_card *card,
}
if (request_irq(pci->irq, snd_atiixp_interrupt, IRQF_SHARED,
- card->shortname, chip)) {
+ KBUILD_MODNAME, chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_atiixp_free(chip);
return -EBUSY;
@@ -1332,7 +1334,7 @@ static void __devexit snd_atiixp_remove(struct pci_dev *pci)
}
static struct pci_driver driver = {
- .name = "ATI IXP MC97 controller",
+ .name = KBUILD_MODNAME,
.id_table = snd_atiixp_ids,
.probe = snd_atiixp_probe,
.remove = __devexit_p(snd_atiixp_remove),
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index 9b7a634..bc1e683 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -186,7 +186,7 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/gameport.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <linux/dma-mapping.h>
#include <sound/core.h>
#include <sound/control.h>
@@ -2559,7 +2559,7 @@ snd_azf3328_create(struct snd_card *card,
codec_setup->name = "I2S_OUT";
if (request_irq(pci->irq, snd_azf3328_interrupt,
- IRQF_SHARED, card->shortname, chip)) {
+ IRQF_SHARED, KBUILD_MODNAME, chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
err = -EBUSY;
goto out_err;
@@ -2625,16 +2625,19 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
int err;
snd_azf3328_dbgcallenter();
- if (dev >= SNDRV_CARDS)
- return -ENODEV;
+ if (dev >= SNDRV_CARDS) {
+ err = -ENODEV;
+ goto out;
+ }
if (!enable[dev]) {
dev++;
- return -ENOENT;
+ err = -ENOENT;
+ goto out;
}
err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
if (err < 0)
- return err;
+ goto out;
strcpy(card->driver, "AZF3328");
strcpy(card->shortname, "Aztech AZF3328 (PCI168)");
@@ -2649,8 +2652,9 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
since our hardware ought to be similar, thus use same ID. */
err = snd_mpu401_uart_new(
card, 0,
- MPU401_HW_AZT2320, chip->mpu_io, MPU401_INFO_INTEGRATED,
- pci->irq, 0, &chip->rmidi
+ MPU401_HW_AZT2320, chip->mpu_io,
+ MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK,
+ -1, &chip->rmidi
);
if (err < 0) {
snd_printk(KERN_ERR "azf3328: no MPU-401 device at 0x%lx?\n",
@@ -2860,7 +2864,7 @@ snd_azf3328_resume(struct pci_dev *pci)
static struct pci_driver driver = {
- .name = "AZF3328",
+ .name = KBUILD_MODNAME,
.id_table = snd_azf3328_ids,
.probe = snd_azf3328_probe,
.remove = __devexit_p(snd_azf3328_remove),
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c
index 2958a05..c1c2d0c 100644
--- a/sound/pci/bt87x.c
+++ b/sound/pci/bt87x.c
@@ -25,7 +25,7 @@
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/slab.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <linux/bitops.h>
#include <asm/io.h>
#include <sound/core.h>
@@ -760,7 +760,7 @@ static int __devinit snd_bt87x_create(struct snd_card *card,
snd_bt87x_writel(chip, REG_INT_STAT, MY_INTERRUPTS);
err = request_irq(pci->irq, snd_bt87x_interrupt, IRQF_SHARED,
- "Bt87x audio", chip);
+ KBUILD_MODNAME, chip);
if (err < 0) {
snd_printk(KERN_ERR "cannot grab irq %d\n", pci->irq);
goto fail;
@@ -965,7 +965,7 @@ static DEFINE_PCI_DEVICE_TABLE(snd_bt87x_default_ids) = {
};
static struct pci_driver driver = {
- .name = "Bt87x",
+ .name = KBUILD_MODNAME,
.id_table = snd_bt87x_ids,
.probe = snd_bt87x_probe,
.remove = __devexit_p(snd_bt87x_remove),
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c
index f4e5735..954c993 100644
--- a/sound/pci/cmipci.c
+++ b/sound/pci/cmipci.c
@@ -27,7 +27,7 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/gameport.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <linux/mutex.h>
#include <sound/core.h>
#include <sound/info.h>
@@ -3053,7 +3053,7 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc
cm->iobase = pci_resource_start(pci, 0);
if (request_irq(pci->irq, snd_cmipci_interrupt,
- IRQF_SHARED, card->driver, cm)) {
+ IRQF_SHARED, KBUILD_MODNAME, cm)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_cmipci_free(cm);
return -EBUSY;
@@ -3228,8 +3228,9 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc
if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_CMIPCI,
iomidi,
(integrated_midi ?
- MPU401_INFO_INTEGRATED : 0),
- cm->irq, 0, &cm->rmidi)) < 0) {
+ MPU401_INFO_INTEGRATED : 0) |
+ MPU401_INFO_IRQ_HOOK,
+ -1, &cm->rmidi)) < 0) {
printk(KERN_ERR "cmipci: no UART401 device at 0x%lx\n", iomidi);
}
}
@@ -3398,7 +3399,7 @@ static int snd_cmipci_resume(struct pci_dev *pci)
#endif /* CONFIG_PM */
static struct pci_driver driver = {
- .name = "C-Media PCI",
+ .name = KBUILD_MODNAME,
.id_table = snd_cmipci_ids,
.probe = snd_cmipci_probe,
.remove = __devexit_p(snd_cmipci_remove),
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c
index 6772070..a6c6c5c 100644
--- a/sound/pci/cs4281.c
+++ b/sound/pci/cs4281.c
@@ -26,7 +26,7 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/gameport.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/pcm.h>
@@ -1382,7 +1382,7 @@ static int __devinit snd_cs4281_create(struct snd_card *card,
}
if (request_irq(pci->irq, snd_cs4281_interrupt, IRQF_SHARED,
- "CS4281", chip)) {
+ KBUILD_MODNAME, chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_cs4281_free(chip);
return -ENOMEM;
@@ -2085,7 +2085,7 @@ static int cs4281_resume(struct pci_dev *pci)
#endif /* CONFIG_PM */
static struct pci_driver driver = {
- .name = "CS4281",
+ .name = KBUILD_MODNAME,
.id_table = snd_cs4281_ids,
.probe = snd_cs4281_probe,
.remove = __devexit_p(snd_cs4281_remove),
diff --git a/sound/pci/cs5530.c b/sound/pci/cs5530.c
index bc07e27..958f494 100644
--- a/sound/pci/cs5530.c
+++ b/sound/pci/cs5530.c
@@ -37,7 +37,7 @@
*/
#include <linux/delay.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <sound/core.h>
@@ -285,7 +285,7 @@ static int __devinit snd_cs5530_probe(struct pci_dev *pci,
}
static struct pci_driver driver = {
- .name = "CS5530_Audio",
+ .name = KBUILD_MODNAME,
.id_table = snd_cs5530_ids,
.probe = snd_cs5530_probe,
.remove = __devexit_p(snd_cs5530_remove),
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
index 863eafe..d085ad0 100644
--- a/sound/pci/ens1370.c
+++ b/sound/pci/ens1370.c
@@ -33,7 +33,7 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/gameport.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <linux/mutex.h>
#include <sound/core.h>
@@ -2120,7 +2120,7 @@ static int __devinit snd_ensoniq_create(struct snd_card *card,
}
ensoniq->port = pci_resource_start(pci, 0);
if (request_irq(pci->irq, snd_audiopci_interrupt, IRQF_SHARED,
- "Ensoniq AudioPCI", ensoniq)) {
+ KBUILD_MODNAME, ensoniq)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_ensoniq_free(ensoniq);
return -EBUSY;
@@ -2489,7 +2489,7 @@ static void __devexit snd_audiopci_remove(struct pci_dev *pci)
}
static struct pci_driver driver = {
- .name = DRIVER_NAME,
+ .name = KBUILD_MODNAME,
.id_table = snd_audiopci_ids,
.probe = snd_audiopci_probe,
.remove = __devexit_p(snd_audiopci_remove),
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c
index 553b752..04cc21f 100644
--- a/sound/pci/es1938.c
+++ b/sound/pci/es1938.c
@@ -52,7 +52,7 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/gameport.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <sound/core.h>
@@ -1514,7 +1514,7 @@ static int es1938_resume(struct pci_dev *pci)
}
if (request_irq(pci->irq, snd_es1938_interrupt,
- IRQF_SHARED, "ES1938", chip)) {
+ IRQF_SHARED, KBUILD_MODNAME, chip)) {
printk(KERN_ERR "es1938: unable to grab IRQ %d, "
"disabling device\n", pci->irq);
snd_card_disconnect(card);
@@ -1636,7 +1636,7 @@ static int __devinit snd_es1938_create(struct snd_card *card,
chip->mpu_port = pci_resource_start(pci, 3);
chip->game_port = pci_resource_start(pci, 4);
if (request_irq(pci->irq, snd_es1938_interrupt, IRQF_SHARED,
- "ES1938", chip)) {
+ KBUILD_MODNAME, chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_es1938_free(chip);
return -EBUSY;
@@ -1854,8 +1854,9 @@ static int __devinit snd_es1938_probe(struct pci_dev *pci,
}
}
if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
- chip->mpu_port, MPU401_INFO_INTEGRATED,
- chip->irq, 0, &chip->rmidi) < 0) {
+ chip->mpu_port,
+ MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK,
+ -1, &chip->rmidi) < 0) {
printk(KERN_ERR "es1938: unable to initialize MPU-401\n");
} else {
// this line is vital for MIDI interrupt handling on ess-solo1
@@ -1882,7 +1883,7 @@ static void __devexit snd_es1938_remove(struct pci_dev *pci)
}
static struct pci_driver driver = {
- .name = "ESS ES1938 (Solo-1)",
+ .name = KBUILD_MODNAME,
.id_table = snd_es1938_ids,
.probe = snd_es1938_probe,
.remove = __devexit_p(snd_es1938_remove),
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index ab0a615..297a151 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -102,7 +102,7 @@
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/gameport.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/input.h>
@@ -554,9 +554,8 @@ struct es1968 {
#else
struct snd_kcontrol *master_switch; /* for h/w volume control */
struct snd_kcontrol *master_volume;
- spinlock_t ac97_lock;
- struct tasklet_struct hwvol_tq;
#endif
+ struct work_struct hwvol_work;
#ifdef CONFIG_SND_ES1968_RADIO
struct snd_tea575x tea;
@@ -646,38 +645,23 @@ static int snd_es1968_ac97_wait_poll(struct es1968 *chip)
static void snd_es1968_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val)
{
struct es1968 *chip = ac97->private_data;
-#ifndef CONFIG_SND_ES1968_INPUT
- unsigned long flags;
-#endif
snd_es1968_ac97_wait(chip);
/* Write the bus */
-#ifndef CONFIG_SND_ES1968_INPUT
- spin_lock_irqsave(&chip->ac97_lock, flags);
-#endif
outw(val, chip->io_port + ESM_AC97_DATA);
/*msleep(1);*/
outb(reg, chip->io_port + ESM_AC97_INDEX);
/*msleep(1);*/
-#ifndef CONFIG_SND_ES1968_INPUT
- spin_unlock_irqrestore(&chip->ac97_lock, flags);
-#endif
}
static unsigned short snd_es1968_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
{
u16 data = 0;
struct es1968 *chip = ac97->private_data;
-#ifndef CONFIG_SND_ES1968_INPUT
- unsigned long flags;
-#endif
snd_es1968_ac97_wait(chip);
-#ifndef CONFIG_SND_ES1968_INPUT
- spin_lock_irqsave(&chip->ac97_lock, flags);
-#endif
outb(reg | 0x80, chip->io_port + ESM_AC97_INDEX);
/*msleep(1);*/
@@ -685,9 +669,6 @@ static unsigned short snd_es1968_ac97_read(struct snd_ac97 *ac97, unsigned short
data = inw(chip->io_port + ESM_AC97_DATA);
/*msleep(1);*/
}
-#ifndef CONFIG_SND_ES1968_INPUT
- spin_unlock_irqrestore(&chip->ac97_lock, flags);
-#endif
return data;
}
@@ -1904,13 +1885,10 @@ static void snd_es1968_update_pcm(struct es1968 *chip, struct esschan *es)
(without wrap around) in response to volume button presses and then
generating an interrupt. The pair of counters is stored in bits 1-3 and 5-7
of a byte wide register. The meaning of bits 0 and 4 is unknown. */
-static void es1968_update_hw_volume(unsigned long private_data)
+static void es1968_update_hw_volume(struct work_struct *work)
{
- struct es1968 *chip = (struct es1968 *) private_data;
+ struct es1968 *chip = container_of(work, struct es1968, hwvol_work);
int x, val;
-#ifndef CONFIG_SND_ES1968_INPUT
- unsigned long flags;
-#endif
/* Figure out which volume control button was pushed,
based on differences from the default register
@@ -1929,18 +1907,11 @@ static void es1968_update_hw_volume(unsigned long private_data)
if (! chip->master_switch || ! chip->master_volume)
return;
- /* FIXME: we can't call snd_ac97_* functions since here is in tasklet. */
- spin_lock_irqsave(&chip->ac97_lock, flags);
- val = chip->ac97->regs[AC97_MASTER];
+ val = snd_ac97_read(chip->ac97, AC97_MASTER);
switch (x) {
case 0x88:
/* mute */
val ^= 0x8000;
- chip->ac97->regs[AC97_MASTER] = val;
- outw(val, chip->io_port + ESM_AC97_DATA);
- outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX);
- snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
- &chip->master_switch->id);
break;
case 0xaa:
/* volume up */
@@ -1948,11 +1919,6 @@ static void es1968_update_hw_volume(unsigned long private_data)
val--;
if ((val & 0x7f00) > 0)
val -= 0x0100;
- chip->ac97->regs[AC97_MASTER] = val;
- outw(val, chip->io_port + ESM_AC97_DATA);
- outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX);
- snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
- &chip->master_volume->id);
break;
case 0x66:
/* volume down */
@@ -1960,14 +1926,11 @@ static void es1968_update_hw_volume(unsigned long private_data)
val++;
if ((val & 0x7f00) < 0x1f00)
val += 0x0100;
- chip->ac97->regs[AC97_MASTER] = val;
- outw(val, chip->io_port + ESM_AC97_DATA);
- outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX);
- snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
- &chip->master_volume->id);
break;
}
- spin_unlock_irqrestore(&chip->ac97_lock, flags);
+ if (snd_ac97_update(chip->ac97, AC97_MASTER, val))
+ snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &chip->master_volume->id);
#else
if (!chip->input_dev)
return;
@@ -2013,11 +1976,7 @@ static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id)
outw(inw(chip->io_port + 4) & 1, chip->io_port + 4);
if (event & ESM_HWVOL_IRQ)
-#ifdef CONFIG_SND_ES1968_INPUT
- es1968_update_hw_volume((unsigned long)chip);
-#else
- tasklet_schedule(&chip->hwvol_tq); /* we'll do this later */
-#endif
+ schedule_work(&chip->hwvol_work);
/* else ack 'em all, i imagine */
outb(0xFF, chip->io_port + 0x1A);
@@ -2426,6 +2385,7 @@ static int es1968_suspend(struct pci_dev *pci, pm_message_t state)
return 0;
chip->in_suspend = 1;
+ cancel_work_sync(&chip->hwvol_work);
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
snd_pcm_suspend_all(chip->pcm);
snd_ac97_suspend(chip->ac97);
@@ -2638,6 +2598,7 @@ static struct snd_tea575x_ops snd_es1968_tea_ops = {
static int snd_es1968_free(struct es1968 *chip)
{
+ cancel_work_sync(&chip->hwvol_work);
#ifdef CONFIG_SND_ES1968_INPUT
if (chip->input_dev)
input_unregister_device(chip->input_dev);
@@ -2728,10 +2689,7 @@ static int __devinit snd_es1968_create(struct snd_card *card,
INIT_LIST_HEAD(&chip->buf_list);
INIT_LIST_HEAD(&chip->substream_list);
mutex_init(&chip->memory_mutex);
-#ifndef CONFIG_SND_ES1968_INPUT
- spin_lock_init(&chip->ac97_lock);
- tasklet_init(&chip->hwvol_tq, es1968_update_hw_volume, (unsigned long)chip);
-#endif
+ INIT_WORK(&chip->hwvol_work, es1968_update_hw_volume);
chip->card = card;
chip->pci = pci;
chip->irq = -1;
@@ -2746,7 +2704,7 @@ static int __devinit snd_es1968_create(struct snd_card *card,
}
chip->io_port = pci_resource_start(pci, 0);
if (request_irq(pci->irq, snd_es1968_interrupt, IRQF_SHARED,
- "ESS Maestro", chip)) {
+ KBUILD_MODNAME, chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_es1968_free(chip);
return -EBUSY;
@@ -2885,8 +2843,9 @@ static int __devinit snd_es1968_probe(struct pci_dev *pci,
if (enable_mpu[dev]) {
if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
chip->io_port + ESM_MPU401_PORT,
- MPU401_INFO_INTEGRATED,
- chip->irq, 0, &chip->rmidi)) < 0) {
+ MPU401_INFO_INTEGRATED |
+ MPU401_INFO_IRQ_HOOK,
+ -1, &chip->rmidi)) < 0) {
printk(KERN_WARNING "es1968: skipping MPU-401 MIDI support..\n");
}
}
@@ -2925,7 +2884,7 @@ static void __devexit snd_es1968_remove(struct pci_dev *pci)
}
static struct pci_driver driver = {
- .name = "ES1968 (ESS Maestro)",
+ .name = KBUILD_MODNAME,
.id_table = snd_es1968_ids,
.probe = snd_es1968_probe,
.remove = __devexit_p(snd_es1968_remove),
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index ecce948..ec05ef5 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -25,7 +25,7 @@
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/slab.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/tlv.h>
@@ -729,11 +729,14 @@ static struct snd_fm801_tea575x_gpio snd_fm801_tea575x_gpios[] = {
{ .data = 2, .clk = 0, .wren = 1, .most = 3, .name = "SF64-PCR" },
};
+#define get_tea575x_gpio(chip) \
+ (&snd_fm801_tea575x_gpios[((chip)->tea575x_tuner & TUNER_TYPE_MASK) - 1])
+
static void snd_fm801_tea575x_set_pins(struct snd_tea575x *tea, u8 pins)
{
struct fm801 *chip = tea->private_data;
unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL));
- struct snd_fm801_tea575x_gpio gpio = snd_fm801_tea575x_gpios[(chip->tea575x_tuner & TUNER_TYPE_MASK) - 1];
+ struct snd_fm801_tea575x_gpio gpio = *get_tea575x_gpio(chip);
reg &= ~(FM801_GPIO_GP(gpio.data) |
FM801_GPIO_GP(gpio.clk) |
@@ -751,7 +754,7 @@ static u8 snd_fm801_tea575x_get_pins(struct snd_tea575x *tea)
{
struct fm801 *chip = tea->private_data;
unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL));
- struct snd_fm801_tea575x_gpio gpio = snd_fm801_tea575x_gpios[(chip->tea575x_tuner & TUNER_TYPE_MASK) - 1];
+ struct snd_fm801_tea575x_gpio gpio = *get_tea575x_gpio(chip);
return (reg & FM801_GPIO_GP(gpio.data)) ? TEA575X_DATA : 0 |
(reg & FM801_GPIO_GP(gpio.most)) ? TEA575X_MOST : 0;
@@ -761,7 +764,7 @@ static void snd_fm801_tea575x_set_direction(struct snd_tea575x *tea, bool output
{
struct fm801 *chip = tea->private_data;
unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL));
- struct snd_fm801_tea575x_gpio gpio = snd_fm801_tea575x_gpios[(chip->tea575x_tuner & TUNER_TYPE_MASK) - 1];
+ struct snd_fm801_tea575x_gpio gpio = *get_tea575x_gpio(chip);
/* use GPIO lines and set write enable bit */
reg |= FM801_GPIO_GS(gpio.data) |
@@ -1201,7 +1204,7 @@ static int __devinit snd_fm801_create(struct snd_card *card,
chip->port = pci_resource_start(pci, 0);
if ((tea575x_tuner & TUNER_ONLY) == 0) {
if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_SHARED,
- "FM801", chip)) {
+ KBUILD_MODNAME, chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->irq);
snd_fm801_free(chip);
return -EBUSY;
@@ -1246,7 +1249,7 @@ static int __devinit snd_fm801_create(struct snd_card *card,
chip->tea575x_tuner = tea575x_tuner;
if (!snd_tea575x_init(&chip->tea)) {
snd_printk(KERN_INFO "detected TEA575x radio type %s\n",
- snd_fm801_tea575x_gpios[tea575x_tuner - 1].name);
+ get_tea575x_gpio(chip)->name);
break;
}
}
@@ -1256,9 +1259,7 @@ static int __devinit snd_fm801_create(struct snd_card *card,
}
}
if (!(chip->tea575x_tuner & TUNER_DISABLED)) {
- strlcpy(chip->tea.card,
- snd_fm801_tea575x_gpios[(tea575x_tuner &
- TUNER_TYPE_MASK) - 1].name,
+ strlcpy(chip->tea.card, get_tea575x_gpio(chip)->name,
sizeof(chip->tea.card));
}
#endif
@@ -1311,8 +1312,9 @@ static int __devinit snd_card_fm801_probe(struct pci_dev *pci,
}
if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_FM801,
FM801_REG(chip, MPU401_DATA),
- MPU401_INFO_INTEGRATED,
- chip->irq, 0, &chip->rmidi)) < 0) {
+ MPU401_INFO_INTEGRATED |
+ MPU401_INFO_IRQ_HOOK,
+ -1, &chip->rmidi)) < 0) {
snd_card_free(card);
return err;
}
@@ -1399,7 +1401,7 @@ static int snd_fm801_resume(struct pci_dev *pci)
#endif
static struct pci_driver driver = {
- .name = "FM801",
+ .name = KBUILD_MODNAME,
.id_table = snd_fm801_ids,
.probe = snd_card_fm801_probe,
.remove = __devexit_p(snd_card_fm801_remove),
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index 0ea5cc6..bb7e102 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -14,6 +14,19 @@ menuconfig SND_HDA_INTEL
if SND_HDA_INTEL
+config SND_HDA_PREALLOC_SIZE
+ int "Pre-allocated buffer size for HD-audio driver"
+ range 0 32768
+ default 64
+ help
+ Specifies the default pre-allocated buffer-size in kB for the
+ HD-audio driver. A larger buffer (e.g. 2048) is preferred
+ for systems using PulseAudio. The default 64 is chosen just
+ for compatibility reasons.
+
+ Note that the pre-allocation size can be changed dynamically
+ via a proc file (/proc/asound/card*/pcm*/sub*/prealloc), too.
+
config SND_HDA_HWDEP
bool "Build hwdep interface for HD-audio driver"
select SND_HWDEP
@@ -83,6 +96,19 @@ config SND_HDA_CODEC_REALTEK
snd-hda-codec-realtek.
This module is automatically loaded at probing.
+config SND_HDA_ENABLE_REALTEK_QUIRKS
+ bool "Build static quirks for Realtek codecs"
+ depends on SND_HDA_CODEC_REALTEK
+ default y
+ help
+ Say Y here to build the static quirks codes for Realtek codecs.
+ If you need the "model" preset that the default BIOS auto-parser
+ can't handle, turn this option on.
+
+ If your device works with model=auto option, basically you don't
+ need the quirk code. By turning this off, you can reduce the
+ module size quite a lot.
+
config SND_HDA_CODEC_ANALOG
bool "Build Analog Device HD-audio codec support"
default y
@@ -171,6 +197,19 @@ config SND_HDA_CODEC_CA0110
snd-hda-codec-ca0110.
This module is automatically loaded at probing.
+config SND_HDA_CODEC_CA0132
+ bool "Build Creative CA0132 codec support"
+ depends on SND_HDA_INTEL
+ default y
+ help
+ Say Y here to include Creative CA0132 codec support in
+ snd-hda-intel driver.
+
+ When the HD-audio driver is built as a module, the codec
+ support code is also built as another module,
+ snd-hda-codec-ca0132.
+ This module is automatically loaded at probing.
+
config SND_HDA_CODEC_CMEDIA
bool "Build C-Media HD-audio codec support"
default y
@@ -204,6 +243,7 @@ config SND_HDA_GENERIC
config SND_HDA_POWER_SAVE
bool "Aggressive power-saving on HD-audio"
+ depends on PM
help
Say Y here to enable more aggressive power-saving mode on
HD-audio driver. The power-saving timeout can be configured
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index 17ef365..f928d66 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -6,6 +6,9 @@ snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o
snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o
+# for trace-points
+CFLAGS_hda_codec.o := -I$(src)
+
snd-hda-codec-realtek-objs := patch_realtek.o
snd-hda-codec-cmedia-objs := patch_cmedia.o
snd-hda-codec-analog-objs := patch_analog.o
@@ -13,6 +16,7 @@ snd-hda-codec-idt-objs := patch_sigmatel.o
snd-hda-codec-si3054-objs := patch_si3054.o
snd-hda-codec-cirrus-objs := patch_cirrus.o
snd-hda-codec-ca0110-objs := patch_ca0110.o
+snd-hda-codec-ca0132-objs := patch_ca0132.o
snd-hda-codec-conexant-objs := patch_conexant.o
snd-hda-codec-via-objs := patch_via.o
snd-hda-codec-hdmi-objs := patch_hdmi.o hda_eld.o
@@ -42,6 +46,9 @@ endif
ifdef CONFIG_SND_HDA_CODEC_CA0110
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-ca0110.o
endif
+ifdef CONFIG_SND_HDA_CODEC_CA0132
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-ca0132.o
+endif
ifdef CONFIG_SND_HDA_CODEC_CONEXANT
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-conexant.o
endif
diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c
index 29714c8..60738e5 100644
--- a/sound/pci/hda/hda_beep.c
+++ b/sound/pci/hda/hda_beep.c
@@ -23,6 +23,7 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
+#include <linux/export.h>
#include <sound/core.h>
#include "hda_beep.h"
#include "hda_local.h"
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 7031412..ee95618 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -24,6 +24,7 @@
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/mutex.h>
+#include <linux/module.h>
#include <sound/core.h>
#include "hda_codec.h"
#include <sound/asoundef.h>
@@ -34,6 +35,9 @@
#include "hda_beep.h"
#include <sound/hda_hwdep.h>
+#define CREATE_TRACE_POINTS
+#include "hda_trace.h"
+
/*
* vendor / preset table
*/
@@ -91,8 +95,10 @@ EXPORT_SYMBOL_HDA(snd_hda_delete_codec_preset);
#ifdef CONFIG_SND_HDA_POWER_SAVE
static void hda_power_work(struct work_struct *work);
static void hda_keep_power_on(struct hda_codec *codec);
+#define hda_codec_is_power_on(codec) ((codec)->power_on)
#else
static inline void hda_keep_power_on(struct hda_codec *codec) {}
+#define hda_codec_is_power_on(codec) 1
#endif
/**
@@ -206,15 +212,19 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
again:
snd_hda_power_up(codec);
mutex_lock(&bus->cmd_mutex);
+ trace_hda_send_cmd(codec, cmd);
err = bus->ops.command(bus, cmd);
- if (!err && res)
+ if (!err && res) {
*res = bus->ops.get_response(bus, codec->addr);
+ trace_hda_get_response(codec, *res);
+ }
mutex_unlock(&bus->cmd_mutex);
snd_hda_power_down(codec);
if (res && *res == -1 && bus->rirb_error) {
if (bus->response_reset) {
snd_printd("hda_codec: resetting BUS due to "
"fatal communication error\n");
+ trace_hda_bus_reset(bus);
bus->ops.bus_reset(bus);
}
goto again;
@@ -243,7 +253,8 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid,
{
unsigned cmd = make_codec_cmd(codec, nid, direct, verb, parm);
unsigned int res;
- codec_exec_verb(codec, cmd, &res);
+ if (codec_exec_verb(codec, cmd, &res))
+ return -1;
return res;
}
EXPORT_SYMBOL_HDA(snd_hda_codec_read);
@@ -300,70 +311,116 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid,
unsigned int parm;
parm = snd_hda_param_read(codec, nid, AC_PAR_NODE_COUNT);
- if (parm == -1)
+ if (parm == -1) {
+ *start_id = 0;
return 0;
+ }
*start_id = (parm >> 16) & 0x7fff;
return (int)(parm & 0x7fff);
}
EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes);
-static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
- hda_nid_t *conn_list, int max_conns);
-static bool add_conn_list(struct snd_array *array, hda_nid_t nid);
-static int copy_conn_list(hda_nid_t nid, hda_nid_t *dst, int max_dst,
- hda_nid_t *src, int len);
+/* look up the cached results */
+static hda_nid_t *lookup_conn_list(struct snd_array *array, hda_nid_t nid)
+{
+ int i, len;
+ for (i = 0; i < array->used; ) {
+ hda_nid_t *p = snd_array_elem(array, i);
+ if (nid == *p)
+ return p;
+ len = p[1];
+ i += len + 2;
+ }
+ return NULL;
+}
/**
- * snd_hda_get_connections - get connection list
+ * snd_hda_get_conn_list - get connection list
* @codec: the HDA codec
* @nid: NID to parse
- * @conn_list: connection list array
- * @max_conns: max. number of connections to store
+ * @listp: the pointer to store NID list
*
* Parses the connection list of the given widget and stores the list
* of NIDs.
*
* Returns the number of connections, or a negative error code.
*/
-int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
- hda_nid_t *conn_list, int max_conns)
+int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
+ const hda_nid_t **listp)
{
struct snd_array *array = &codec->conn_lists;
- int i, len, old_used;
+ int len, err;
hda_nid_t list[HDA_MAX_CONNECTIONS];
+ hda_nid_t *p;
+ bool added = false;
- /* look up the cached results */
- for (i = 0; i < array->used; ) {
- hda_nid_t *p = snd_array_elem(array, i);
- len = p[1];
- if (nid == *p)
- return copy_conn_list(nid, conn_list, max_conns,
- p + 2, len);
- i += len + 2;
+ again:
+ /* if the connection-list is already cached, read it */
+ p = lookup_conn_list(array, nid);
+ if (p) {
+ if (listp)
+ *listp = p + 2;
+ return p[1];
}
+ if (snd_BUG_ON(added))
+ return -EINVAL;
- len = _hda_get_connections(codec, nid, list, HDA_MAX_CONNECTIONS);
+ /* read the connection and add to the cache */
+ len = snd_hda_get_raw_connections(codec, nid, list, HDA_MAX_CONNECTIONS);
if (len < 0)
return len;
+ err = snd_hda_override_conn_list(codec, nid, len, list);
+ if (err < 0)
+ return err;
+ added = true;
+ goto again;
+}
+EXPORT_SYMBOL_HDA(snd_hda_get_conn_list);
- /* add to the cache */
- old_used = array->used;
- if (!add_conn_list(array, nid) || !add_conn_list(array, len))
- goto error_add;
- for (i = 0; i < len; i++)
- if (!add_conn_list(array, list[i]))
- goto error_add;
+/**
+ * snd_hda_get_connections - copy connection list
+ * @codec: the HDA codec
+ * @nid: NID to parse
+ * @conn_list: connection list array
+ * @max_conns: max. number of connections to store
+ *
+ * Parses the connection list of the given widget and stores the list
+ * of NIDs.
+ *
+ * Returns the number of connections, or a negative error code.
+ */
+int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
+ hda_nid_t *conn_list, int max_conns)
+{
+ const hda_nid_t *list;
+ int len = snd_hda_get_conn_list(codec, nid, &list);
- return copy_conn_list(nid, conn_list, max_conns, list, len);
-
- error_add:
- array->used = old_used;
- return -ENOMEM;
+ if (len <= 0)
+ return len;
+ if (len > max_conns) {
+ snd_printk(KERN_ERR "hda_codec: "
+ "Too many connections %d for NID 0x%x\n",
+ len, nid);
+ return -EINVAL;
+ }
+ memcpy(conn_list, list, len * sizeof(hda_nid_t));
+ return len;
}
EXPORT_SYMBOL_HDA(snd_hda_get_connections);
-static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
- hda_nid_t *conn_list, int max_conns)
+/**
+ * snd_hda_get_raw_connections - copy connection list without cache
+ * @codec: the HDA codec
+ * @nid: NID to parse
+ * @conn_list: connection list array
+ * @max_conns: max. number of connections to store
+ *
+ * Like snd_hda_get_connections(), copy the connection list but without
+ * checking through the connection-list cache.
+ * Currently called only from hda_proc.c, so not exported.
+ */
+int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
+ hda_nid_t *conn_list, int max_conns)
{
unsigned int parm;
int i, conn_len, conns;
@@ -376,11 +433,8 @@ static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
wcaps = get_wcaps(codec, nid);
if (!(wcaps & AC_WCAP_CONN_LIST) &&
- get_wcaps_type(wcaps) != AC_WID_VOL_KNB) {
- snd_printk(KERN_WARNING "hda_codec: "
- "connection list not available for 0x%x\n", nid);
- return -EINVAL;
- }
+ get_wcaps_type(wcaps) != AC_WID_VOL_KNB)
+ return 0;
parm = snd_hda_param_read(codec, nid, AC_PAR_CONNLIST_LEN);
if (parm & AC_CLIST_LONG) {
@@ -470,18 +524,81 @@ static bool add_conn_list(struct snd_array *array, hda_nid_t nid)
return true;
}
-static int copy_conn_list(hda_nid_t nid, hda_nid_t *dst, int max_dst,
- hda_nid_t *src, int len)
+/**
+ * snd_hda_override_conn_list - add/modify the connection-list to cache
+ * @codec: the HDA codec
+ * @nid: NID to parse
+ * @len: number of connection list entries
+ * @list: the list of connection entries
+ *
+ * Add or modify the given connection-list to the cache. If the corresponding
+ * cache already exists, invalidate it and append a new one.
+ *
+ * Returns zero or a negative error code.
+ */
+int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int len,
+ const hda_nid_t *list)
{
- if (len > max_dst) {
- snd_printk(KERN_ERR "hda_codec: "
- "Too many connections %d for NID 0x%x\n",
- len, nid);
- return -EINVAL;
+ struct snd_array *array = &codec->conn_lists;
+ hda_nid_t *p;
+ int i, old_used;
+
+ p = lookup_conn_list(array, nid);
+ if (p)
+ *p = -1; /* invalidate the old entry */
+
+ old_used = array->used;
+ if (!add_conn_list(array, nid) || !add_conn_list(array, len))
+ goto error_add;
+ for (i = 0; i < len; i++)
+ if (!add_conn_list(array, list[i]))
+ goto error_add;
+ return 0;
+
+ error_add:
+ array->used = old_used;
+ return -ENOMEM;
+}
+EXPORT_SYMBOL_HDA(snd_hda_override_conn_list);
+
+/**
+ * snd_hda_get_conn_index - get the connection index of the given NID
+ * @codec: the HDA codec
+ * @mux: NID containing the list
+ * @nid: NID to select
+ * @recursive: 1 when searching NID recursively, otherwise 0
+ *
+ * Parses the connection list of the widget @mux and checks whether the
+ * widget @nid is present. If it is, return the connection index.
+ * Otherwise it returns -1.
+ */
+int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
+ hda_nid_t nid, int recursive)
+{
+ hda_nid_t conn[HDA_MAX_NUM_INPUTS];
+ int i, nums;
+
+ nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
+ for (i = 0; i < nums; i++)
+ if (conn[i] == nid)
+ return i;
+ if (!recursive)
+ return -1;
+ if (recursive > 5) {
+ snd_printd("hda_codec: too deep connection for 0x%x\n", nid);
+ return -1;
}
- memcpy(dst, src, len * sizeof(hda_nid_t));
- return len;
+ recursive++;
+ for (i = 0; i < nums; i++) {
+ unsigned int type = get_wcaps_type(get_wcaps(codec, conn[i]));
+ if (type == AC_WID_PIN || type == AC_WID_AUD_OUT)
+ continue;
+ if (snd_hda_get_conn_index(codec, conn[i], nid, recursive) >= 0)
+ return i;
+ }
+ return -1;
}
+EXPORT_SYMBOL_HDA(snd_hda_get_conn_index);
/**
* snd_hda_queue_unsol_event - add an unsolicited event to queue
@@ -500,6 +617,10 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex)
struct hda_bus_unsolicited *unsol;
unsigned int wp;
+ if (!bus || !bus->workq)
+ return 0;
+
+ trace_hda_unsol_event(bus, res, res_ex);
unsol = bus->unsol;
if (!unsol)
return 0;
@@ -1000,7 +1121,7 @@ void snd_hda_shutup_pins(struct hda_codec *codec)
}
EXPORT_SYMBOL_HDA(snd_hda_shutup_pins);
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
/* Restore the pin controls cleared previously via snd_hda_shutup_pins() */
static void restore_shutup_pins(struct hda_codec *codec)
{
@@ -1083,6 +1204,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
snd_array_free(&codec->mixers);
snd_array_free(&codec->nids);
snd_array_free(&codec->conn_lists);
+ snd_array_free(&codec->spdif_out);
codec->bus->caddr_tbl[codec->addr] = NULL;
if (codec->patch_ops.free)
codec->patch_ops.free(codec);
@@ -1144,6 +1266,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16);
snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8);
snd_array_init(&codec->conn_lists, sizeof(hda_nid_t), 64);
+ snd_array_init(&codec->spdif_out, sizeof(struct hda_spdif_out), 16);
if (codec->bus->modelname) {
codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL);
if (!codec->modelname) {
@@ -1374,8 +1497,11 @@ static void really_cleanup_stream(struct hda_codec *codec,
struct hda_cvt_setup *q)
{
hda_nid_t nid = q->nid;
- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0);
- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0);
+ if (q->stream_tag || q->channel_id)
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0);
+ if (q->format_id)
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0
+);
memset(q, 0, sizeof(*q));
q->nid = nid;
}
@@ -1396,7 +1522,7 @@ static void purify_inactive_streams(struct hda_codec *codec)
}
}
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
/* clean up all streams; called from suspend */
static void hda_cleanup_all_streams(struct hda_codec *codec)
{
@@ -1580,6 +1706,29 @@ u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid)
EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps);
/**
+ * snd_hda_override_pin_caps - Override the pin capabilities
+ * @codec: the CODEC
+ * @nid: the NID to override
+ * @caps: the capability bits to set
+ *
+ * Override the cached PIN capabilitiy bits value by the given one.
+ *
+ * Returns zero if successful or a negative error code.
+ */
+int snd_hda_override_pin_caps(struct hda_codec *codec, hda_nid_t nid,
+ unsigned int caps)
+{
+ struct hda_amp_info *info;
+ info = get_alloc_amp_hash(codec, HDA_HASH_PINCAP_KEY(nid));
+ if (!info)
+ return -ENOMEM;
+ info->amp_caps = caps;
+ info->head.val |= INFO_AMP_CAPS;
+ return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_override_pin_caps);
+
+/**
* snd_hda_pin_sense - execute pin sense measurement
* @codec: the CODEC to sense
* @nid: the pin NID to sense
@@ -1739,7 +1888,7 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid,
}
EXPORT_SYMBOL_HDA(snd_hda_codec_amp_stereo);
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
/**
* snd_hda_codec_resume_amp - Resume all AMP commands from the cache
* @codec: HD-audio codec
@@ -1769,7 +1918,7 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec)
}
}
EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp);
-#endif /* SND_HDA_NEEDS_RESUME */
+#endif /* CONFIG_PM */
static u32 get_amp_max_value(struct hda_codec *codec, hda_nid_t nid, int dir,
unsigned int ofs)
@@ -2168,6 +2317,7 @@ int snd_hda_codec_reset(struct hda_codec *codec)
}
if (codec->patch_ops.free)
codec->patch_ops.free(codec);
+ memset(&codec->patch_ops, 0, sizeof(codec->patch_ops));
codec->proc_widget_hook = NULL;
codec->spec = NULL;
free_hda_cache(&codec->amp_cache);
@@ -2180,7 +2330,6 @@ int snd_hda_codec_reset(struct hda_codec *codec)
codec->num_pcms = 0;
codec->pcm_info = NULL;
codec->preset = NULL;
- memset(&codec->patch_ops, 0, sizeof(codec->patch_ops));
codec->slave_dig_outs = NULL;
codec->spdif_status_reset = 0;
module_put(codec->owner);
@@ -2195,7 +2344,7 @@ typedef int (*map_slave_func_t)(void *, struct snd_kcontrol *);
/* apply the function to all matching slave ctls in the mixer list */
static int map_slaves(struct hda_codec *codec, const char * const *slaves,
- map_slave_func_t func, void *data)
+ map_slave_func_t func, void *data)
{
struct hda_nid_item *items;
const char * const *s;
@@ -2577,11 +2726,13 @@ static int snd_hda_spdif_default_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ int idx = kcontrol->private_value;
+ struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
- ucontrol->value.iec958.status[0] = codec->spdif_status & 0xff;
- ucontrol->value.iec958.status[1] = (codec->spdif_status >> 8) & 0xff;
- ucontrol->value.iec958.status[2] = (codec->spdif_status >> 16) & 0xff;
- ucontrol->value.iec958.status[3] = (codec->spdif_status >> 24) & 0xff;
+ ucontrol->value.iec958.status[0] = spdif->status & 0xff;
+ ucontrol->value.iec958.status[1] = (spdif->status >> 8) & 0xff;
+ ucontrol->value.iec958.status[2] = (spdif->status >> 16) & 0xff;
+ ucontrol->value.iec958.status[3] = (spdif->status >> 24) & 0xff;
return 0;
}
@@ -2666,23 +2817,23 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- hda_nid_t nid = kcontrol->private_value;
+ int idx = kcontrol->private_value;
+ struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
+ hda_nid_t nid = spdif->nid;
unsigned short val;
int change;
mutex_lock(&codec->spdif_mutex);
- codec->spdif_status = ucontrol->value.iec958.status[0] |
+ spdif->status = ucontrol->value.iec958.status[0] |
((unsigned int)ucontrol->value.iec958.status[1] << 8) |
((unsigned int)ucontrol->value.iec958.status[2] << 16) |
((unsigned int)ucontrol->value.iec958.status[3] << 24);
- val = convert_from_spdif_status(codec->spdif_status);
- val |= codec->spdif_ctls & 1;
- change = codec->spdif_ctls != val;
- codec->spdif_ctls = val;
-
- if (change)
+ val = convert_from_spdif_status(spdif->status);
+ val |= spdif->ctls & 1;
+ change = spdif->ctls != val;
+ spdif->ctls = val;
+ if (change && nid != (u16)-1)
set_dig_out_convert(codec, nid, val & 0xff, (val >> 8) & 0xff);
-
mutex_unlock(&codec->spdif_mutex);
return change;
}
@@ -2693,33 +2844,42 @@ static int snd_hda_spdif_out_switch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ int idx = kcontrol->private_value;
+ struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
- ucontrol->value.integer.value[0] = codec->spdif_ctls & AC_DIG1_ENABLE;
+ ucontrol->value.integer.value[0] = spdif->ctls & AC_DIG1_ENABLE;
return 0;
}
+static inline void set_spdif_ctls(struct hda_codec *codec, hda_nid_t nid,
+ int dig1, int dig2)
+{
+ set_dig_out_convert(codec, nid, dig1, dig2);
+ /* unmute amp switch (if any) */
+ if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) &&
+ (dig1 & AC_DIG1_ENABLE))
+ snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
+ HDA_AMP_MUTE, 0);
+}
+
static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- hda_nid_t nid = kcontrol->private_value;
+ int idx = kcontrol->private_value;
+ struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
+ hda_nid_t nid = spdif->nid;
unsigned short val;
int change;
mutex_lock(&codec->spdif_mutex);
- val = codec->spdif_ctls & ~AC_DIG1_ENABLE;
+ val = spdif->ctls & ~AC_DIG1_ENABLE;
if (ucontrol->value.integer.value[0])
val |= AC_DIG1_ENABLE;
- change = codec->spdif_ctls != val;
- if (change) {
- codec->spdif_ctls = val;
- set_dig_out_convert(codec, nid, val & 0xff, -1);
- /* unmute amp switch (if any) */
- if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) &&
- (val & AC_DIG1_ENABLE))
- snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
- HDA_AMP_MUTE, 0);
- }
+ change = spdif->ctls != val;
+ spdif->ctls = val;
+ if (change && nid != (u16)-1)
+ set_spdif_ctls(codec, nid, val & 0xff, -1);
mutex_unlock(&codec->spdif_mutex);
return change;
}
@@ -2766,36 +2926,79 @@ static struct snd_kcontrol_new dig_mixes[] = {
*
* Returns 0 if successful, or a negative error code.
*/
-int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid)
+int snd_hda_create_spdif_out_ctls(struct hda_codec *codec,
+ hda_nid_t associated_nid,
+ hda_nid_t cvt_nid)
{
int err;
struct snd_kcontrol *kctl;
struct snd_kcontrol_new *dig_mix;
int idx;
+ struct hda_spdif_out *spdif;
idx = find_empty_mixer_ctl_idx(codec, "IEC958 Playback Switch");
if (idx < 0) {
printk(KERN_ERR "hda_codec: too many IEC958 outputs\n");
return -EBUSY;
}
+ spdif = snd_array_new(&codec->spdif_out);
for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) {
kctl = snd_ctl_new1(dig_mix, codec);
if (!kctl)
return -ENOMEM;
kctl->id.index = idx;
- kctl->private_value = nid;
- err = snd_hda_ctl_add(codec, nid, kctl);
+ kctl->private_value = codec->spdif_out.used - 1;
+ err = snd_hda_ctl_add(codec, associated_nid, kctl);
if (err < 0)
return err;
}
- codec->spdif_ctls =
- snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_DIGI_CONVERT_1, 0);
- codec->spdif_status = convert_to_spdif_status(codec->spdif_ctls);
+ spdif->nid = cvt_nid;
+ spdif->ctls = snd_hda_codec_read(codec, cvt_nid, 0,
+ AC_VERB_GET_DIGI_CONVERT_1, 0);
+ spdif->status = convert_to_spdif_status(spdif->ctls);
return 0;
}
EXPORT_SYMBOL_HDA(snd_hda_create_spdif_out_ctls);
+struct hda_spdif_out *snd_hda_spdif_out_of_nid(struct hda_codec *codec,
+ hda_nid_t nid)
+{
+ int i;
+ for (i = 0; i < codec->spdif_out.used; i++) {
+ struct hda_spdif_out *spdif =
+ snd_array_elem(&codec->spdif_out, i);
+ if (spdif->nid == nid)
+ return spdif;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL_HDA(snd_hda_spdif_out_of_nid);
+
+void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx)
+{
+ struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
+
+ mutex_lock(&codec->spdif_mutex);
+ spdif->nid = (u16)-1;
+ mutex_unlock(&codec->spdif_mutex);
+}
+EXPORT_SYMBOL_HDA(snd_hda_spdif_ctls_unassign);
+
+void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid)
+{
+ struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
+ unsigned short val;
+
+ mutex_lock(&codec->spdif_mutex);
+ if (spdif->nid != nid) {
+ spdif->nid = nid;
+ val = spdif->ctls;
+ set_spdif_ctls(codec, nid, val & 0xff, (val >> 8) & 0xff);
+ }
+ mutex_unlock(&codec->spdif_mutex);
+}
+EXPORT_SYMBOL_HDA(snd_hda_spdif_ctls_assign);
+
/*
* SPDIF sharing with analog output
*/
@@ -2947,7 +3150,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid)
}
EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls);
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
/*
* command cache
*/
@@ -3064,53 +3267,32 @@ void snd_hda_sequence_write_cache(struct hda_codec *codec,
seq->param);
}
EXPORT_SYMBOL_HDA(snd_hda_sequence_write_cache);
-#endif /* SND_HDA_NEEDS_RESUME */
+#endif /* CONFIG_PM */
-/*
- * set power state of the codec
- */
-static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
- unsigned int power_state)
+void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg,
+ unsigned int power_state,
+ bool eapd_workaround)
{
- hda_nid_t nid;
+ hda_nid_t nid = codec->start_nid;
int i;
- /* this delay seems necessary to avoid click noise at power-down */
- if (power_state == AC_PWRST_D3)
- msleep(100);
- snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE,
- power_state);
- /* partial workaround for "azx_get_response timeout" */
- if (power_state == AC_PWRST_D0 &&
- (codec->vendor_id & 0xffff0000) == 0x14f10000)
- msleep(10);
-
- nid = codec->start_nid;
for (i = 0; i < codec->num_nodes; i++, nid++) {
unsigned int wcaps = get_wcaps(codec, nid);
- if (wcaps & AC_WCAP_POWER) {
- unsigned int wid_type = get_wcaps_type(wcaps);
- if (power_state == AC_PWRST_D3 &&
- wid_type == AC_WID_PIN) {
- unsigned int pincap;
- /*
- * don't power down the widget if it controls
- * eapd and EAPD_BTLENABLE is set.
- */
- pincap = snd_hda_query_pin_caps(codec, nid);
- if (pincap & AC_PINCAP_EAPD) {
- int eapd = snd_hda_codec_read(codec,
- nid, 0,
+ if (!(wcaps & AC_WCAP_POWER))
+ continue;
+ /* don't power down the widget if it controls eapd and
+ * EAPD_BTLENABLE is set.
+ */
+ if (eapd_workaround && power_state == AC_PWRST_D3 &&
+ get_wcaps_type(wcaps) == AC_WID_PIN &&
+ (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)) {
+ int eapd = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_EAPD_BTLENABLE, 0);
- eapd &= 0x02;
- if (eapd)
- continue;
- }
- }
- snd_hda_codec_write(codec, nid, 0,
- AC_VERB_SET_POWER_STATE,
- power_state);
+ if (eapd & 0x02)
+ continue;
}
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE,
+ power_state);
}
if (power_state == AC_PWRST_D0) {
@@ -3127,6 +3309,26 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
} while (time_after_eq(end_time, jiffies));
}
}
+EXPORT_SYMBOL_HDA(snd_hda_codec_set_power_to_all);
+
+/*
+ * set power state of the codec
+ */
+static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
+ unsigned int power_state)
+{
+ if (codec->patch_ops.set_power_state) {
+ codec->patch_ops.set_power_state(codec, fg, power_state);
+ return;
+ }
+
+ /* this delay seems necessary to avoid click noise at power-down */
+ if (power_state == AC_PWRST_D3)
+ msleep(100);
+ snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE,
+ power_state);
+ snd_hda_codec_set_power_to_all(codec, fg, power_state, true);
+}
#ifdef CONFIG_SND_HDA_HWDEP
/* execute additional init verbs */
@@ -3139,7 +3341,7 @@ static void hda_exec_init_verbs(struct hda_codec *codec)
static inline void hda_exec_init_verbs(struct hda_codec *codec) {}
#endif
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
/*
* call suspend and power-down; used both from PM and power-save
*/
@@ -3180,7 +3382,7 @@ static void hda_call_codec_resume(struct hda_codec *codec)
snd_hda_codec_resume_cache(codec);
}
}
-#endif /* SND_HDA_NEEDS_RESUME */
+#endif /* CONFIG_PM */
/**
@@ -3378,7 +3580,7 @@ static unsigned int query_stream_param(struct hda_codec *codec, hda_nid_t nid)
*
* Returns 0 if successful, otherwise a negative error code.
*/
-static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
+int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
u32 *ratesp, u64 *formatsp, unsigned int *bpsp)
{
unsigned int i, val, wcaps;
@@ -3470,6 +3672,7 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
return 0;
}
+EXPORT_SYMBOL_HDA(snd_hda_query_supported_pcm);
/**
* snd_hda_is_supported_format - Check the validity of the format
@@ -3852,9 +4055,9 @@ int snd_hda_check_board_codec_sid_config(struct hda_codec *codec,
/* Search for codec ID */
for (q = tbl; q->subvendor; q++) {
- unsigned long vendorid = (q->subdevice) | (q->subvendor << 16);
-
- if (vendorid == codec->subsystem_id)
+ unsigned int mask = 0xffff0000 | q->subdevice_mask;
+ unsigned int id = (q->subdevice | (q->subvendor << 16)) & mask;
+ if ((codec->subsystem_id & mask) == id)
break;
}
@@ -3935,9 +4138,6 @@ int snd_hda_add_new_ctls(struct hda_codec *codec,
EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls);
#ifdef CONFIG_SND_HDA_POWER_SAVE
-static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
- unsigned int power_state);
-
static void hda_power_work(struct work_struct *work)
{
struct hda_codec *codec =
@@ -3949,6 +4149,7 @@ static void hda_power_work(struct work_struct *work)
return;
}
+ trace_hda_power_down(codec);
hda_call_codec_suspend(codec);
if (bus->ops.pm_notify)
bus->ops.pm_notify(bus);
@@ -3987,6 +4188,7 @@ void snd_hda_power_up(struct hda_codec *codec)
if (codec->power_on || codec->power_transition)
return;
+ trace_hda_power_up(codec);
snd_hda_update_power_acct(codec);
codec->power_on = 1;
codec->power_jiffies = jiffies;
@@ -4199,10 +4401,12 @@ EXPORT_SYMBOL_HDA(snd_hda_input_mux_put);
static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid,
unsigned int stream_tag, unsigned int format)
{
+ struct hda_spdif_out *spdif = snd_hda_spdif_out_of_nid(codec, nid);
+
/* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
- if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
+ if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE))
set_dig_out_convert(codec, nid,
- codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff,
+ spdif->ctls & ~AC_DIG1_ENABLE & 0xff,
-1);
snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
if (codec->slave_dig_outs) {
@@ -4212,9 +4416,9 @@ static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid,
format);
}
/* turn on again (if needed) */
- if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
+ if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE))
set_dig_out_convert(codec, nid,
- codec->spdif_ctls & 0xff, -1);
+ spdif->ctls & 0xff, -1);
}
static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid)
@@ -4238,11 +4442,8 @@ void snd_hda_bus_reboot_notify(struct hda_bus *bus)
if (!bus)
return;
list_for_each_entry(codec, &bus->codec_list, list) {
-#ifdef CONFIG_SND_HDA_POWER_SAVE
- if (!codec->power_on)
- continue;
-#endif
- if (codec->patch_ops.reboot_notify)
+ if (hda_codec_is_power_on(codec) &&
+ codec->patch_ops.reboot_notify)
codec->patch_ops.reboot_notify(codec);
}
}
@@ -4370,6 +4571,8 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
{
const hda_nid_t *nids = mout->dac_nids;
int chs = substream->runtime->channels;
+ struct hda_spdif_out *spdif =
+ snd_hda_spdif_out_of_nid(codec, mout->dig_out_nid);
int i;
mutex_lock(&codec->spdif_mutex);
@@ -4378,7 +4581,7 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
if (chs == 2 &&
snd_hda_is_supported_format(codec, mout->dig_out_nid,
format) &&
- !(codec->spdif_status & IEC958_AES0_NONAUDIO)) {
+ !(spdif->status & IEC958_AES0_NONAUDIO)) {
mout->dig_out_used = HDA_DIG_ANALOG_DUP;
setup_dig_out_stream(codec, mout->dig_out_nid,
stream_tag, format);
@@ -4398,6 +4601,11 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag,
0, format);
/* extra outputs copied from front */
+ for (i = 0; i < ARRAY_SIZE(mout->hp_out_nid); i++)
+ if (!mout->no_share_stream && mout->hp_out_nid[i])
+ snd_hda_codec_setup_stream(codec,
+ mout->hp_out_nid[i],
+ stream_tag, 0, format);
for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
if (!mout->no_share_stream && mout->extra_out_nid[i])
snd_hda_codec_setup_stream(codec,
@@ -4430,6 +4638,10 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec,
snd_hda_codec_cleanup_stream(codec, nids[i]);
if (mout->hp_nid)
snd_hda_codec_cleanup_stream(codec, mout->hp_nid);
+ for (i = 0; i < ARRAY_SIZE(mout->hp_out_nid); i++)
+ if (mout->hp_out_nid[i])
+ snd_hda_codec_cleanup_stream(codec,
+ mout->hp_out_nid[i]);
for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
if (mout->extra_out_nid[i])
snd_hda_codec_cleanup_stream(codec,
@@ -4510,6 +4722,27 @@ static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg)
}
}
+/* Reorder the surround channels
+ * ALSA sequence is front/surr/clfe/side
+ * HDA sequence is:
+ * 4-ch: front/surr => OK as it is
+ * 6-ch: front/clfe/surr
+ * 8-ch: front/clfe/rear/side|fc
+ */
+static void reorder_outputs(unsigned int nums, hda_nid_t *pins)
+{
+ hda_nid_t nid;
+
+ switch (nums) {
+ case 3:
+ case 4:
+ nid = pins[1];
+ pins[1] = pins[2];
+ pins[2] = nid;
+ break;
+ }
+}
+
/*
* Parse all pin widgets and store the useful pin nids to cfg
*
@@ -4527,12 +4760,13 @@ static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg)
* The digital input/output pins are assigned to dig_in_pin and dig_out_pin,
* respectively.
*/
-int snd_hda_parse_pin_def_config(struct hda_codec *codec,
- struct auto_pin_cfg *cfg,
- const hda_nid_t *ignore_nids)
+int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
+ struct auto_pin_cfg *cfg,
+ const hda_nid_t *ignore_nids,
+ unsigned int cond_flags)
{
hda_nid_t nid, end_nid;
- short seq, assoc_line_out, assoc_speaker;
+ short seq, assoc_line_out;
short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)];
short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)];
short sequences_hp[ARRAY_SIZE(cfg->hp_pins)];
@@ -4543,14 +4777,15 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
memset(sequences_line_out, 0, sizeof(sequences_line_out));
memset(sequences_speaker, 0, sizeof(sequences_speaker));
memset(sequences_hp, 0, sizeof(sequences_hp));
- assoc_line_out = assoc_speaker = 0;
+ assoc_line_out = 0;
+ codec->ignore_misc_bit = true;
end_nid = codec->start_nid + codec->num_nodes;
for (nid = codec->start_nid; nid < end_nid; nid++) {
unsigned int wid_caps = get_wcaps(codec, nid);
unsigned int wid_type = get_wcaps_type(wid_caps);
unsigned int def_conf;
- short assoc, loc;
+ short assoc, loc, conn, dev;
/* read all default configuration for pin complex */
if (wid_type != AC_WID_PIN)
@@ -4560,10 +4795,22 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
continue;
def_conf = snd_hda_codec_get_pincfg(codec, nid);
- if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
+ if (!(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
+ AC_DEFCFG_MISC_NO_PRESENCE))
+ codec->ignore_misc_bit = false;
+ conn = get_defcfg_connect(def_conf);
+ if (conn == AC_JACK_PORT_NONE)
continue;
loc = get_defcfg_location(def_conf);
- switch (get_defcfg_device(def_conf)) {
+ dev = get_defcfg_device(def_conf);
+
+ /* workaround for buggy BIOS setups */
+ if (dev == AC_JACK_LINE_OUT) {
+ if (conn == AC_JACK_PORT_FIXED)
+ dev = AC_JACK_SPEAKER;
+ }
+
+ switch (dev) {
case AC_JACK_LINE_OUT:
seq = get_defcfg_sequence(def_conf);
assoc = get_defcfg_association(def_conf);
@@ -4586,16 +4833,10 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
case AC_JACK_SPEAKER:
seq = get_defcfg_sequence(def_conf);
assoc = get_defcfg_association(def_conf);
- if (!assoc)
- continue;
- if (!assoc_speaker)
- assoc_speaker = assoc;
- else if (assoc_speaker != assoc)
- continue;
if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins))
continue;
cfg->speaker_pins[cfg->speaker_outs] = nid;
- sequences_speaker[cfg->speaker_outs] = seq;
+ sequences_speaker[cfg->speaker_outs] = (assoc << 4) | seq;
cfg->speaker_outs++;
break;
case AC_JACK_HP_OUT:
@@ -4644,7 +4885,8 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
* If no line-out is defined but multiple HPs are found,
* some of them might be the real line-outs.
*/
- if (!cfg->line_outs && cfg->hp_outs > 1) {
+ if (!cfg->line_outs && cfg->hp_outs > 1 &&
+ !(cond_flags & HDA_PINCFG_NO_HP_FIXUP)) {
int i = 0;
while (i < cfg->hp_outs) {
/* The real HPs should have the sequence 0x0f */
@@ -4681,7 +4923,8 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
* FIX-UP: if no line-outs are detected, try to use speaker or HP pin
* as a primary output
*/
- if (!cfg->line_outs) {
+ if (!cfg->line_outs &&
+ !(cond_flags & HDA_PINCFG_NO_LO_FIXUP)) {
if (cfg->speaker_outs) {
cfg->line_outs = cfg->speaker_outs;
memcpy(cfg->line_out_pins, cfg->speaker_pins,
@@ -4699,21 +4942,9 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
}
}
- /* Reorder the surround channels
- * ALSA sequence is front/surr/clfe/side
- * HDA sequence is:
- * 4-ch: front/surr => OK as it is
- * 6-ch: front/clfe/surr
- * 8-ch: front/clfe/rear/side|fc
- */
- switch (cfg->line_outs) {
- case 3:
- case 4:
- nid = cfg->line_out_pins[1];
- cfg->line_out_pins[1] = cfg->line_out_pins[2];
- cfg->line_out_pins[2] = nid;
- break;
- }
+ reorder_outputs(cfg->line_outs, cfg->line_out_pins);
+ reorder_outputs(cfg->hp_outs, cfg->hp_pins);
+ reorder_outputs(cfg->speaker_outs, cfg->speaker_pins);
sort_autocfg_input_pins(cfg);
@@ -4751,7 +4982,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_parse_pin_def_config);
+EXPORT_SYMBOL_HDA(snd_hda_parse_pin_defcfg);
int snd_hda_get_input_pin_attr(unsigned int def_conf)
{
@@ -4930,11 +5161,10 @@ int snd_hda_suspend(struct hda_bus *bus)
struct hda_codec *codec;
list_for_each_entry(codec, &bus->codec_list, list) {
-#ifdef CONFIG_SND_HDA_POWER_SAVE
- if (!codec->power_on)
- continue;
-#endif
- hda_call_codec_suspend(codec);
+ if (hda_codec_is_power_on(codec))
+ hda_call_codec_suspend(codec);
+ if (codec->patch_ops.post_suspend)
+ codec->patch_ops.post_suspend(codec);
}
return 0;
}
@@ -4954,6 +5184,8 @@ int snd_hda_resume(struct hda_bus *bus)
struct hda_codec *codec;
list_for_each_entry(codec, &bus->codec_list, list) {
+ if (codec->patch_ops.pre_resume)
+ codec->patch_ops.pre_resume(codec);
if (snd_hda_codec_needs_resume(codec))
hda_call_codec_resume(codec);
}
@@ -4979,17 +5211,15 @@ void *snd_array_new(struct snd_array *array)
{
if (array->used >= array->alloced) {
int num = array->alloced + array->alloc_align;
+ int size = (num + 1) * array->elem_size;
+ int oldsize = array->alloced * array->elem_size;
void *nlist;
if (snd_BUG_ON(num >= 4096))
return NULL;
- nlist = kcalloc(num + 1, array->elem_size, GFP_KERNEL);
+ nlist = krealloc(array->list, size, GFP_KERNEL);
if (!nlist)
return NULL;
- if (array->list) {
- memcpy(nlist, array->list,
- array->elem_size * array->alloced);
- kfree(array->list);
- }
+ memset(nlist + oldsize, 0, size - oldsize);
array->list = nlist;
array->alloced = num;
}
@@ -5011,30 +5241,6 @@ void snd_array_free(struct snd_array *array)
EXPORT_SYMBOL_HDA(snd_array_free);
/**
- * snd_print_pcm_rates - Print the supported PCM rates to the string buffer
- * @pcm: PCM caps bits
- * @buf: the string buffer to write
- * @buflen: the max buffer length
- *
- * used by hda_proc.c and hda_eld.c
- */
-void snd_print_pcm_rates(int pcm, char *buf, int buflen)
-{
- static unsigned int rates[] = {
- 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200,
- 96000, 176400, 192000, 384000
- };
- int i, j;
-
- for (i = 0, j = 0; i < ARRAY_SIZE(rates); i++)
- if (pcm & (1 << i))
- j += snprintf(buf + j, buflen - j, " %d", rates[i]);
-
- buf[j] = '\0'; /* necessary when j == 0 */
-}
-EXPORT_SYMBOL_HDA(snd_print_pcm_rates);
-
-/**
* snd_print_pcm_bits - Print the supported PCM fmt bits to the string buffer
* @pcm: PCM caps bits
* @buf: the string buffer to write
@@ -5075,6 +5281,8 @@ static const char *get_jack_default_name(struct hda_codec *codec, hda_nid_t nid,
return "Mic";
case SND_JACK_LINEOUT:
return "Line-out";
+ case SND_JACK_LINEIN:
+ return "Line-in";
case SND_JACK_HEADSET:
return "Headset";
case SND_JACK_VIDEOOUT:
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index eff1fc5..78b2223 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -26,10 +26,6 @@
#include <sound/pcm.h>
#include <sound/hwdep.h>
-#if defined(CONFIG_PM) || defined(CONFIG_SND_HDA_POWER_SAVE)
-#define SND_HDA_NEEDS_RESUME /* resume control code is required */
-#endif
-
/*
* nodes
*/
@@ -707,8 +703,12 @@ struct hda_codec_ops {
int (*init)(struct hda_codec *codec);
void (*free)(struct hda_codec *codec);
void (*unsol_event)(struct hda_codec *codec, unsigned int res);
-#ifdef SND_HDA_NEEDS_RESUME
+ void (*set_power_state)(struct hda_codec *codec, hda_nid_t fg,
+ unsigned int power_state);
+#ifdef CONFIG_PM
int (*suspend)(struct hda_codec *codec, pm_message_t state);
+ int (*post_suspend)(struct hda_codec *codec);
+ int (*pre_resume)(struct hda_codec *codec);
int (*resume)(struct hda_codec *codec);
#endif
#ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -832,8 +832,7 @@ struct hda_codec {
struct mutex spdif_mutex;
struct mutex control_mutex;
- unsigned int spdif_status; /* IEC958 status bits */
- unsigned short spdif_ctls; /* SPDIF control bits */
+ struct snd_array spdif_out;
unsigned int spdif_in_enable; /* SPDIF input enable? */
const hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
struct snd_array init_pins; /* initial (BIOS) pin configurations */
@@ -858,6 +857,8 @@ struct hda_codec {
unsigned int no_sticky_stream:1; /* no sticky-PCM stream assignment */
unsigned int pins_shutup:1; /* pins are shut up */
unsigned int no_trigger_sense:1; /* don't trigger at pin-sensing */
+ unsigned int ignore_misc_bit:1; /* ignore MISC_NO_PRESENCE bit */
+ unsigned int no_jack_detect:1; /* Machine has no jack-detection */
#ifdef CONFIG_SND_HDA_POWER_SAVE
unsigned int power_on :1; /* current (global) power-state */
unsigned int power_transition :1; /* power-state in transition */
@@ -907,6 +908,16 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid,
hda_nid_t *start_id);
int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
hda_nid_t *conn_list, int max_conns);
+int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
+ hda_nid_t *conn_list, int max_conns);
+int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
+ const hda_nid_t **listp);
+int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int nums,
+ const hda_nid_t *list);
+int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
+ hda_nid_t nid, int recursive);
+int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
+ u32 *ratesp, u64 *formatsp, unsigned int *bpsp);
struct hda_verb {
hda_nid_t nid;
@@ -921,7 +932,7 @@ void snd_hda_sequence_write(struct hda_codec *codec,
int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex);
/* cached write */
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
int direct, unsigned int verb, unsigned int parm);
void snd_hda_sequence_write_cache(struct hda_codec *codec,
@@ -950,6 +961,17 @@ int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list,
hda_nid_t nid, unsigned int cfg); /* for hwdep */
void snd_hda_shutup_pins(struct hda_codec *codec);
+/* SPDIF controls */
+struct hda_spdif_out {
+ hda_nid_t nid; /* Converter nid values relate to */
+ unsigned int status; /* IEC958 status bits */
+ unsigned short ctls; /* SPDIF control bits */
+};
+struct hda_spdif_out *snd_hda_spdif_out_of_nid(struct hda_codec *codec,
+ hda_nid_t nid);
+void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx);
+void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid);
+
/*
* Mixer
*/
@@ -991,6 +1013,9 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid,
*/
void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen);
void snd_hda_bus_reboot_notify(struct hda_bus *bus);
+void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg,
+ unsigned int power_state,
+ bool eapd_workaround);
/*
* power management
@@ -1000,17 +1025,15 @@ int snd_hda_suspend(struct hda_bus *bus);
int snd_hda_resume(struct hda_bus *bus);
#endif
-#ifdef CONFIG_SND_HDA_POWER_SAVE
static inline
int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid)
{
+#ifdef CONFIG_SND_HDA_POWER_SAVE
if (codec->patch_ops.check_power_status)
return codec->patch_ops.check_power_status(codec, nid);
+#endif
return 0;
}
-#else
-#define hda_call_check_power_status(codec, nid) 0
-#endif
/*
* get widget information
diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c
index 64365a5..b58b4b1 100644
--- a/sound/pci/hda/hda_eld.c
+++ b/sound/pci/hda/hda_eld.c
@@ -144,25 +144,17 @@ static int cea_sampling_frequencies[8] = {
SNDRV_PCM_RATE_192000, /* 7: 192000Hz */
};
-static unsigned char hdmi_get_eld_byte(struct hda_codec *codec, hda_nid_t nid,
+static unsigned int hdmi_get_eld_data(struct hda_codec *codec, hda_nid_t nid,
int byte_index)
{
unsigned int val;
val = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_HDMI_ELDD, byte_index);
-
#ifdef BE_PARANOID
printk(KERN_INFO "HDMI: ELD data byte %d: 0x%x\n", byte_index, val);
#endif
-
- if ((val & AC_ELDD_ELD_VALID) == 0) {
- snd_printd(KERN_INFO "HDMI: invalid ELD data byte %d\n",
- byte_index);
- val = 0;
- }
-
- return val & AC_ELDD_ELD_DATA;
+ return val;
}
#define GRAB_BITS(buf, byte, lowbit, bits) \
@@ -305,10 +297,18 @@ static int hdmi_update_eld(struct hdmi_eld *e,
buf + ELD_FIXED_BYTES + mnl + 3 * i);
}
+ /*
+ * HDMI sink's ELD info cannot always be retrieved for now, e.g.
+ * in console or for audio devices. Assume the highest speakers
+ * configuration, to _not_ prohibit multi-channel audio playback.
+ */
+ if (!e->spk_alloc)
+ e->spk_alloc = 0xffff;
+
+ e->eld_valid = true;
return 0;
out_fail:
- e->eld_ver = 0;
return -EINVAL;
}
@@ -322,12 +322,14 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
struct hda_codec *codec, hda_nid_t nid)
{
int i;
- int ret = 0;
+ int ret;
int size;
unsigned char *buf;
- if (!eld->eld_valid)
- return -ENOENT;
+ /*
+ * ELD size is initialized to zero in caller function. If no errors and
+ * ELD is valid, actual eld_size is assigned in hdmi_update_eld()
+ */
size = snd_hdmi_get_eld_size(codec, nid);
if (size == 0) {
@@ -335,24 +337,69 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
snd_printd(KERN_INFO "HDMI: ELD buf size is 0, force 128\n");
size = 128;
}
- if (size < ELD_FIXED_BYTES || size > PAGE_SIZE) {
+ if (size < ELD_FIXED_BYTES || size > ELD_MAX_SIZE) {
snd_printd(KERN_INFO "HDMI: invalid ELD buf size %d\n", size);
return -ERANGE;
}
- buf = kmalloc(size, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
+ /* set ELD buffer */
+ buf = eld->eld_buffer;
- for (i = 0; i < size; i++)
- buf[i] = hdmi_get_eld_byte(codec, nid, i);
+ for (i = 0; i < size; i++) {
+ unsigned int val = hdmi_get_eld_data(codec, nid, i);
+ /*
+ * Graphics driver might be writing to ELD buffer right now.
+ * Just abort. The caller will repoll after a while.
+ */
+ if (!(val & AC_ELDD_ELD_VALID)) {
+ snd_printd(KERN_INFO
+ "HDMI: invalid ELD data byte %d\n", i);
+ ret = -EINVAL;
+ goto error;
+ }
+ val &= AC_ELDD_ELD_DATA;
+ /*
+ * The first byte cannot be zero. This can happen on some DVI
+ * connections. Some Intel chips may also need some 250ms delay
+ * to return non-zero ELD data, even when the graphics driver
+ * correctly writes ELD content before setting ELD_valid bit.
+ */
+ if (!val && !i) {
+ snd_printdd(KERN_INFO "HDMI: 0 ELD data\n");
+ ret = -EINVAL;
+ goto error;
+ }
+ buf[i] = val;
+ }
ret = hdmi_update_eld(eld, buf, size);
- kfree(buf);
+error:
return ret;
}
+/**
+ * SNDRV_PCM_RATE_* and AC_PAR_PCM values don't match, print correct rates with
+ * hdmi-specific routine.
+ */
+static void hdmi_print_pcm_rates(int pcm, char *buf, int buflen)
+{
+ static unsigned int alsa_rates[] = {
+ 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000,
+ 88200, 96000, 176400, 192000, 384000
+ };
+ int i, j;
+
+ for (i = 0, j = 0; i < ARRAY_SIZE(alsa_rates); i++)
+ if (pcm & (1 << i))
+ j += snprintf(buf + j, buflen - j, " %d",
+ alsa_rates[i]);
+
+ buf[j] = '\0'; /* necessary when j == 0 */
+}
+
+#define SND_PRINT_RATES_ADVISED_BUFSIZE 80
+
static void hdmi_show_short_audio_desc(struct cea_sad *a)
{
char buf[SND_PRINT_RATES_ADVISED_BUFSIZE];
@@ -361,7 +408,7 @@ static void hdmi_show_short_audio_desc(struct cea_sad *a)
if (!a->format)
return;
- snd_print_pcm_rates(a->rates, buf, sizeof(buf));
+ hdmi_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);
@@ -420,7 +467,7 @@ static void hdmi_print_sad_info(int i, struct cea_sad *a,
i, a->format, cea_audio_coding_type_names[a->format]);
snd_iprintf(buffer, "sad%d_channels\t\t%d\n", i, a->channels);
- snd_print_pcm_rates(a->rates, buf, sizeof(buf));
+ hdmi_print_pcm_rates(a->rates, buf, sizeof(buf));
snd_iprintf(buffer, "sad%d_rates\t\t[0x%x]%s\n", i, a->rates, buf);
if (a->format == AUDIO_CODING_TYPE_LPCM) {
@@ -580,43 +627,45 @@ void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld)
#endif /* CONFIG_PROC_FS */
/* update PCM info based on ELD */
-void hdmi_eld_update_pcm_info(struct hdmi_eld *eld, struct hda_pcm_stream *pcm,
- struct hda_pcm_stream *codec_pars)
+void snd_hdmi_eld_update_pcm_info(struct hdmi_eld *eld,
+ struct hda_pcm_stream *hinfo)
{
+ u32 rates;
+ u64 formats;
+ unsigned int maxbps;
+ unsigned int channels_max;
int i;
/* assume basic audio support (the basic audio flag is not in ELD;
* however, all audio capable sinks are required to support basic
* audio) */
- pcm->rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000;
- pcm->formats = SNDRV_PCM_FMTBIT_S16_LE;
- pcm->maxbps = 16;
- pcm->channels_max = 2;
+ rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000;
+ formats = SNDRV_PCM_FMTBIT_S16_LE;
+ maxbps = 16;
+ channels_max = 2;
for (i = 0; i < eld->sad_count; i++) {
struct cea_sad *a = &eld->sad[i];
- pcm->rates |= a->rates;
- if (a->channels > pcm->channels_max)
- pcm->channels_max = a->channels;
+ rates |= a->rates;
+ if (a->channels > channels_max)
+ channels_max = a->channels;
if (a->format == AUDIO_CODING_TYPE_LPCM) {
if (a->sample_bits & AC_SUPPCM_BITS_20) {
- pcm->formats |= SNDRV_PCM_FMTBIT_S32_LE;
- if (pcm->maxbps < 20)
- pcm->maxbps = 20;
+ formats |= SNDRV_PCM_FMTBIT_S32_LE;
+ if (maxbps < 20)
+ maxbps = 20;
}
if (a->sample_bits & AC_SUPPCM_BITS_24) {
- pcm->formats |= SNDRV_PCM_FMTBIT_S32_LE;
- if (pcm->maxbps < 24)
- pcm->maxbps = 24;
+ formats |= SNDRV_PCM_FMTBIT_S32_LE;
+ if (maxbps < 24)
+ maxbps = 24;
}
}
}
- if (!codec_pars)
- return;
-
/* restrict the parameters by the values the codec provides */
- pcm->rates &= codec_pars->rates;
- pcm->formats &= codec_pars->formats;
- pcm->channels_max = min(pcm->channels_max, codec_pars->channels_max);
- pcm->maxbps = min(pcm->maxbps, codec_pars->maxbps);
+ hinfo->rates &= rates;
+ hinfo->formats &= formats;
+ hinfo->maxbps = min(hinfo->maxbps, maxbps);
+ hinfo->channels_max = min(hinfo->channels_max, channels_max);
}
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index a63c54d..431bf86 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -22,6 +22,7 @@
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/export.h>
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c
index bf3ced5..6b2efb8 100644
--- a/sound/pci/hda/hda_hwdep.c
+++ b/sound/pci/hda/hda_hwdep.c
@@ -26,6 +26,7 @@
#include <linux/ctype.h>
#include <linux/string.h>
#include <linux/firmware.h>
+#include <linux/export.h>
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
@@ -643,14 +644,14 @@ static inline int strmatch(const char *a, const char *b)
static void parse_codec_mode(char *buf, struct hda_bus *bus,
struct hda_codec **codecp)
{
- unsigned int vendorid, subid, caddr;
+ int vendorid, subid, caddr;
struct hda_codec *codec;
*codecp = NULL;
if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) {
list_for_each_entry(codec, &bus->codec_list, list) {
- if (codec->vendor_id == vendorid &&
- codec->subsystem_id == subid &&
+ if ((vendorid <= 0 || codec->vendor_id == vendorid) &&
+ (subid <= 0 || codec->subsystem_id == subid) &&
codec->addr == caddr) {
*codecp = codec;
break;
@@ -756,8 +757,6 @@ static int get_line_from_fw(char *buf, int size, struct firmware *fw)
}
if (!fw->size)
return 0;
- if (size < fw->size)
- size = fw->size;
for (len = 0; len < fw->size; len++) {
if (!*p)
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index a9537d4..dcc95c5 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -34,7 +34,6 @@
*
*/
-#include <asm/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
@@ -46,6 +45,12 @@
#include <linux/pci.h>
#include <linux/mutex.h>
#include <linux/reboot.h>
+#include <linux/io.h>
+#ifdef CONFIG_X86
+/* for snoop control */
+#include <asm/pgtable.h>
+#include <asm/cacheflush.h>
+#endif
#include <sound/core.h>
#include <sound/initval.h>
#include "hda_codec.h"
@@ -116,6 +121,22 @@ module_param(power_save_controller, bool, 0644);
MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode.");
#endif
+static int align_buffer_size = 1;
+module_param(align_buffer_size, bool, 0644);
+MODULE_PARM_DESC(align_buffer_size,
+ "Force buffer and period sizes to be multiple of 128 bytes.");
+
+#ifdef CONFIG_X86
+static bool hda_snoop = true;
+module_param_named(snoop, hda_snoop, bool, 0444);
+MODULE_PARM_DESC(snoop, "Enable/disable snooping");
+#define azx_snoop(chip) (chip)->snoop
+#else
+#define hda_snoop true
+#define azx_snoop(chip) true
+#endif
+
+
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
"{Intel, ICH6M},"
@@ -127,6 +148,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
"{Intel, PCH},"
"{Intel, CPT},"
"{Intel, PPT},"
+ "{Intel, LPT},"
"{Intel, PBG},"
"{Intel, SCH},"
"{ATI, SB450},"
@@ -177,7 +199,8 @@ MODULE_DESCRIPTION("Intel HDA driver");
#define ICH6_REG_INTCTL 0x20
#define ICH6_REG_INTSTS 0x24
#define ICH6_REG_WALLCLK 0x30 /* 24Mhz source */
-#define ICH6_REG_SYNC 0x34
+#define ICH6_REG_OLD_SSYNC 0x34 /* SSYNC for old ICH */
+#define ICH6_REG_SSYNC 0x38
#define ICH6_REG_CORBLBASE 0x40
#define ICH6_REG_CORBUBASE 0x44
#define ICH6_REG_CORBWP 0x48
@@ -359,7 +382,7 @@ struct azx_dev {
*/
unsigned char stream_tag; /* assigned stream */
unsigned char index; /* stream index */
- int device; /* last device number assigned to */
+ int assigned_key; /* last device# key assigned to */
unsigned int opened :1;
unsigned int running :1;
@@ -370,6 +393,7 @@ struct azx_dev {
* when link position is not greater than FIFO size
*/
unsigned int insufficient :1;
+ unsigned int wc_marked:1;
};
/* CORB/RIRB */
@@ -437,6 +461,8 @@ struct azx {
unsigned int msi :1;
unsigned int irq_pending_warned :1;
unsigned int probing :1; /* codec probing phase */
+ unsigned int snoop:1;
+ unsigned int align_buffer_size:1;
/* for debugging */
unsigned int last_cmd[AZX_MAX_CODECS];
@@ -479,6 +505,8 @@ enum {
#define AZX_DCAPS_POSFIX_VIA (1 << 17) /* Use VIACOMBO as default */
#define AZX_DCAPS_NO_64BIT (1 << 18) /* No 64bit address */
#define AZX_DCAPS_SYNC_WRITE (1 << 19) /* sync each cmd write */
+#define AZX_DCAPS_OLD_SSYNC (1 << 20) /* Old SSYNC reg for ICH */
+#define AZX_DCAPS_BUFSIZE (1 << 21) /* no buffer size alignment */
/* quirks for ATI SB / AMD Hudson */
#define AZX_DCAPS_PRESET_ATI_SB \
@@ -540,6 +568,59 @@ static char *driver_short_names[] __devinitdata = {
/* for pcm support */
#define get_azx_dev(substream) (substream->runtime->private_data)
+#ifdef CONFIG_X86
+static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on)
+{
+ int pages;
+
+ if (azx_snoop(chip))
+ return;
+ if (!dmab || !dmab->area || !dmab->bytes)
+ return;
+
+#ifdef CONFIG_SND_DMA_SGBUF
+ if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_SG) {
+ struct snd_sg_buf *sgbuf = dmab->private_data;
+ if (on)
+ set_pages_array_wc(sgbuf->page_table, sgbuf->pages);
+ else
+ set_pages_array_wb(sgbuf->page_table, sgbuf->pages);
+ return;
+ }
+#endif
+
+ pages = (dmab->bytes + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ if (on)
+ set_memory_wc((unsigned long)dmab->area, pages);
+ else
+ set_memory_wb((unsigned long)dmab->area, pages);
+}
+
+static inline void mark_pages_wc(struct azx *chip, struct snd_dma_buffer *buf,
+ bool on)
+{
+ __mark_pages_wc(chip, buf, on);
+}
+static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev,
+ struct snd_pcm_substream *substream, bool on)
+{
+ if (azx_dev->wc_marked != on) {
+ __mark_pages_wc(chip, substream->runtime->dma_buffer_p, on);
+ azx_dev->wc_marked = on;
+ }
+}
+#else
+/* NOP for other archs */
+static inline void mark_pages_wc(struct azx *chip, struct snd_dma_buffer *buf,
+ bool on)
+{
+}
+static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev,
+ struct snd_pcm_substream *substream, bool on)
+{
+}
+#endif
+
static int azx_acquire_irq(struct azx *chip, int do_disconnect);
static int azx_send_cmd(struct hda_bus *bus, unsigned int val);
/*
@@ -561,6 +642,7 @@ static int azx_alloc_cmd_io(struct azx *chip)
snd_printk(KERN_ERR SFX "cannot allocate CORB/RIRB\n");
return err;
}
+ mark_pages_wc(chip, &chip->rb, true);
return 0;
}
@@ -1079,7 +1161,15 @@ static void update_pci_byte(struct pci_dev *pci, unsigned int reg,
static void azx_init_pci(struct azx *chip)
{
- unsigned short snoop;
+ /* force to non-snoop mode for a new VIA controller when BIOS is set */
+ if (chip->snoop && chip->driver_type == AZX_DRIVER_VIA) {
+ u8 snoop;
+ pci_read_config_byte(chip->pci, 0x42, &snoop);
+ if (!(snoop & 0x80) && chip->pci->revision == 0x30) {
+ chip->snoop = 0;
+ snd_printdd(SFX "Force to non-snoop mode\n");
+ }
+ }
/* Clear bits 0-2 of PCI register TCSEL (at offset 0x44)
* TCSEL == Traffic Class Select Register, which sets PCI express QOS
@@ -1096,15 +1186,15 @@ static void azx_init_pci(struct azx *chip)
* we need to enable snoop.
*/
if (chip->driver_caps & AZX_DCAPS_ATI_SNOOP) {
- snd_printdd(SFX "Enabling ATI snoop\n");
+ snd_printdd(SFX "Setting ATI snoop: %d\n", azx_snoop(chip));
update_pci_byte(chip->pci,
- ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR,
- 0x07, ATI_SB450_HDAUDIO_ENABLE_SNOOP);
+ ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, 0x07,
+ azx_snoop(chip) ? ATI_SB450_HDAUDIO_ENABLE_SNOOP : 0);
}
/* For NVIDIA HDA, enable snoop */
if (chip->driver_caps & AZX_DCAPS_NVIDIA_SNOOP) {
- snd_printdd(SFX "Enabling Nvidia snoop\n");
+ snd_printdd(SFX "Setting Nvidia snoop: %d\n", azx_snoop(chip));
update_pci_byte(chip->pci,
NVIDIA_HDA_TRANSREG_ADDR,
0x0f, NVIDIA_HDA_ENABLE_COHBITS);
@@ -1118,16 +1208,20 @@ static void azx_init_pci(struct azx *chip)
/* Enable SCH/PCH snoop if needed */
if (chip->driver_caps & AZX_DCAPS_SCH_SNOOP) {
+ unsigned short snoop;
pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop);
- if (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) {
- pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC,
- snoop & (~INTEL_SCH_HDA_DEVC_NOSNOOP));
+ if ((!azx_snoop(chip) && !(snoop & INTEL_SCH_HDA_DEVC_NOSNOOP)) ||
+ (azx_snoop(chip) && (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP))) {
+ snoop &= ~INTEL_SCH_HDA_DEVC_NOSNOOP;
+ if (!azx_snoop(chip))
+ snoop |= INTEL_SCH_HDA_DEVC_NOSNOOP;
+ pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC, snoop);
pci_read_config_word(chip->pci,
INTEL_SCH_HDA_DEVC, &snoop);
- snd_printdd(SFX "HDA snoop disabled, enabling ... %s\n",
- (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP)
- ? "Failed" : "OK");
}
+ snd_printdd(SFX "SCH snoop: %s\n",
+ (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP)
+ ? "Disabled" : "Enabled");
}
}
@@ -1334,12 +1428,16 @@ static void azx_stream_reset(struct azx *chip, struct azx_dev *azx_dev)
*/
static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
{
+ unsigned int val;
/* make sure the run bit is zero for SD */
azx_stream_clear(chip, azx_dev);
/* program the stream_tag */
- azx_sd_writel(azx_dev, SD_CTL,
- (azx_sd_readl(azx_dev, SD_CTL) & ~SD_CTL_STREAM_TAG_MASK)|
- (azx_dev->stream_tag << SD_CTL_STREAM_TAG_SHIFT));
+ val = azx_sd_readl(azx_dev, SD_CTL);
+ val = (val & ~SD_CTL_STREAM_TAG_MASK) |
+ (azx_dev->stream_tag << SD_CTL_STREAM_TAG_SHIFT);
+ if (!azx_snoop(chip))
+ val |= SD_CTL_TRAFFIC_PRIO;
+ azx_sd_writel(azx_dev, SD_CTL, val);
/* program the length of samples in cyclic buffer */
azx_sd_writel(azx_dev, SD_CBL, azx_dev->bufsize);
@@ -1533,6 +1631,9 @@ azx_assign_device(struct azx *chip, struct snd_pcm_substream *substream)
{
int dev, i, nums;
struct azx_dev *res = NULL;
+ /* make a non-zero unique key for the substream */
+ int key = (substream->pcm->device << 16) | (substream->number << 2) |
+ (substream->stream + 1);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
dev = chip->playback_index_offset;
@@ -1544,12 +1645,12 @@ azx_assign_device(struct azx *chip, struct snd_pcm_substream *substream)
for (i = 0; i < nums; i++, dev++)
if (!chip->azx_dev[dev].opened) {
res = &chip->azx_dev[dev];
- if (res->device == substream->pcm->device)
+ if (res->assigned_key == key)
break;
}
if (res) {
res->opened = 1;
- res->device = substream->pcm->device;
+ res->assigned_key = key;
}
return res;
}
@@ -1599,6 +1700,7 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned long flags;
int err;
+ int buff_step;
mutex_lock(&chip->open_mutex);
azx_dev = azx_assign_device(chip, substream);
@@ -1613,10 +1715,25 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
runtime->hw.rates = hinfo->rates;
snd_pcm_limit_hw_rates(runtime);
snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+ if (chip->align_buffer_size)
+ /* constrain buffer sizes to be multiple of 128
+ bytes. This is more efficient in terms of memory
+ access but isn't required by the HDA spec and
+ prevents users from specifying exact period/buffer
+ sizes. For example for 44.1kHz, a period size set
+ to 20ms will be rounded to 19.59ms. */
+ buff_step = 128;
+ else
+ /* Don't enforce steps on buffer sizes, still need to
+ be multiple of 4 bytes (HDA spec). Tested on Intel
+ HDA controllers, may not work on all devices where
+ option needs to be disabled */
+ buff_step = 4;
+
snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
- 128);
+ buff_step);
snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
- 128);
+ buff_step);
snd_hda_power_up(apcm->codec);
err = hinfo->ops.open(hinfo, apcm->codec, substream);
if (err < 0) {
@@ -1671,19 +1788,28 @@ static int azx_pcm_close(struct snd_pcm_substream *substream)
static int azx_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
+ struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+ struct azx *chip = apcm->chip;
struct azx_dev *azx_dev = get_azx_dev(substream);
+ int ret;
+ mark_runtime_wc(chip, azx_dev, substream, false);
azx_dev->bufsize = 0;
azx_dev->period_bytes = 0;
azx_dev->format_val = 0;
- return snd_pcm_lib_malloc_pages(substream,
+ ret = snd_pcm_lib_malloc_pages(substream,
params_buffer_bytes(hw_params));
+ if (ret < 0)
+ return ret;
+ mark_runtime_wc(chip, azx_dev, substream, true);
+ return ret;
}
static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
{
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
struct azx_dev *azx_dev = get_azx_dev(substream);
+ struct azx *chip = apcm->chip;
struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
/* reset BDL address */
@@ -1696,6 +1822,7 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
snd_hda_codec_cleanup(apcm->codec, hinfo, substream);
+ mark_runtime_wc(chip, azx_dev, substream, false);
return snd_pcm_lib_free_pages(substream);
}
@@ -1708,13 +1835,16 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned int bufsize, period_bytes, format_val, stream_tag;
int err;
+ struct hda_spdif_out *spdif =
+ snd_hda_spdif_out_of_nid(apcm->codec, hinfo->nid);
+ unsigned short ctls = spdif ? spdif->ctls : 0;
azx_stream_reset(chip, azx_dev);
format_val = snd_hda_calc_stream_format(runtime->rate,
runtime->channels,
runtime->format,
hinfo->maxbps,
- apcm->codec->spdif_ctls);
+ ctls);
if (!format_val) {
snd_printk(KERN_ERR SFX
"invalid format_val, rate=%d, ch=%d, format=%d\n",
@@ -1794,7 +1924,11 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
spin_lock(&chip->reg_lock);
if (nsync > 1) {
/* first, set SYNC bits of corresponding streams */
- azx_writel(chip, SYNC, azx_readl(chip, SYNC) | sbits);
+ if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC)
+ azx_writel(chip, OLD_SSYNC,
+ azx_readl(chip, OLD_SSYNC) | sbits);
+ else
+ azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) | sbits);
}
snd_pcm_group_for_each_entry(s, substream) {
if (s->pcm->card != substream->pcm->card)
@@ -1850,7 +1984,11 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
if (nsync > 1) {
spin_lock(&chip->reg_lock);
/* reset SYNC bits */
- azx_writel(chip, SYNC, azx_readl(chip, SYNC) & ~sbits);
+ if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC)
+ azx_writel(chip, OLD_SSYNC,
+ azx_readl(chip, OLD_SSYNC) & ~sbits);
+ else
+ azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) & ~sbits);
spin_unlock(&chip->reg_lock);
}
return 0;
@@ -1865,7 +2003,7 @@ static unsigned int azx_via_get_position(struct azx *chip,
unsigned int fifo_size;
link_pos = azx_sd_readl(azx_dev, SD_LPIB);
- if (azx_dev->index >= 4) {
+ if (azx_dev->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
/* Playback, no problem using link position */
return link_pos;
}
@@ -1913,7 +2051,8 @@ static unsigned int azx_via_get_position(struct azx *chip,
}
static unsigned int azx_get_position(struct azx *chip,
- struct azx_dev *azx_dev)
+ struct azx_dev *azx_dev,
+ bool with_check)
{
unsigned int pos;
int stream = azx_dev->substream->stream;
@@ -1929,6 +2068,17 @@ static unsigned int azx_get_position(struct azx *chip,
default:
/* use the position buffer */
pos = le32_to_cpu(*azx_dev->posbuf);
+ if (with_check && chip->position_fix[stream] == POS_FIX_AUTO) {
+ if (!pos || pos == (u32)-1) {
+ printk(KERN_WARNING
+ "hda-intel: Invalid position buffer, "
+ "using LPIB read method instead.\n");
+ chip->position_fix[stream] = POS_FIX_LPIB;
+ pos = azx_sd_readl(azx_dev, SD_LPIB);
+ } else
+ chip->position_fix[stream] = POS_FIX_POSBUF;
+ }
+ break;
}
if (pos >= azx_dev->bufsize)
@@ -1942,7 +2092,7 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream)
struct azx *chip = apcm->chip;
struct azx_dev *azx_dev = get_azx_dev(substream);
return bytes_to_frames(substream->runtime,
- azx_get_position(chip, azx_dev));
+ azx_get_position(chip, azx_dev, false));
}
/*
@@ -1965,17 +2115,7 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
return -1; /* bogus (too early) interrupt */
stream = azx_dev->substream->stream;
- pos = azx_get_position(chip, azx_dev);
- if (chip->position_fix[stream] == POS_FIX_AUTO) {
- if (!pos) {
- printk(KERN_WARNING
- "hda-intel: Invalid position buffer, "
- "using LPIB read method instead.\n");
- chip->position_fix[stream] = POS_FIX_LPIB;
- pos = azx_get_position(chip, azx_dev);
- } else
- chip->position_fix[stream] = POS_FIX_POSBUF;
- }
+ pos = azx_get_position(chip, azx_dev, true);
if (WARN_ONCE(!azx_dev->period_bytes,
"hda-intel: zero azx_dev->period_bytes"))
@@ -2042,6 +2182,20 @@ static void azx_clear_irq_pending(struct azx *chip)
spin_unlock_irq(&chip->reg_lock);
}
+#ifdef CONFIG_X86
+static int azx_pcm_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *area)
+{
+ struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+ struct azx *chip = apcm->chip;
+ if (!azx_snoop(chip))
+ area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
+ return snd_pcm_lib_default_mmap(substream, area);
+}
+#else
+#define azx_pcm_mmap NULL
+#endif
+
static struct snd_pcm_ops azx_pcm_ops = {
.open = azx_pcm_open,
.close = azx_pcm_close,
@@ -2051,6 +2205,7 @@ static struct snd_pcm_ops azx_pcm_ops = {
.prepare = azx_pcm_prepare,
.trigger = azx_pcm_trigger,
.pointer = azx_pcm_pointer,
+ .mmap = azx_pcm_mmap,
.page = snd_pcm_sgbuf_ops_page,
};
@@ -2063,6 +2218,8 @@ static void azx_pcm_free(struct snd_pcm *pcm)
}
}
+#define MAX_PREALLOC_SIZE (32 * 1024 * 1024)
+
static int
azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
struct hda_pcm *cpcm)
@@ -2071,6 +2228,7 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
struct snd_pcm *pcm;
struct azx_pcm *apcm;
int pcm_dev = cpcm->device;
+ unsigned int size;
int s, err;
if (pcm_dev >= HDA_MAX_PCMS) {
@@ -2106,9 +2264,12 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
snd_pcm_set_ops(pcm, s, &azx_pcm_ops);
}
/* buffer pre-allocation */
+ size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024;
+ if (size > MAX_PREALLOC_SIZE)
+ size = MAX_PREALLOC_SIZE;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
snd_dma_pci_data(chip->pci),
- 1024 * 64, 32 * 1024 * 1024);
+ size, MAX_PREALLOC_SIZE);
return 0;
}
@@ -2151,7 +2312,7 @@ static int azx_acquire_irq(struct azx *chip, int do_disconnect)
{
if (request_irq(chip->pci->irq, azx_interrupt,
chip->msi ? 0 : IRQF_SHARED,
- "hda_intel", chip)) {
+ KBUILD_MODNAME, chip)) {
printk(KERN_ERR "hda-intel: unable to grab IRQ %d, "
"disabling device\n", chip->pci->irq);
if (do_disconnect)
@@ -2325,13 +2486,19 @@ static int azx_free(struct azx *chip)
if (chip->azx_dev) {
for (i = 0; i < chip->num_streams; i++)
- if (chip->azx_dev[i].bdl.area)
+ if (chip->azx_dev[i].bdl.area) {
+ mark_pages_wc(chip, &chip->azx_dev[i].bdl, false);
snd_dma_free_pages(&chip->azx_dev[i].bdl);
+ }
}
- if (chip->rb.area)
+ if (chip->rb.area) {
+ mark_pages_wc(chip, &chip->rb, false);
snd_dma_free_pages(&chip->rb);
- if (chip->posbuf.area)
+ }
+ if (chip->posbuf.area) {
+ mark_pages_wc(chip, &chip->posbuf, false);
snd_dma_free_pages(&chip->posbuf);
+ }
pci_release_regions(chip->pci);
pci_disable_device(chip->pci);
kfree(chip->azx_dev);
@@ -2349,29 +2516,22 @@ static int azx_dev_free(struct snd_device *device)
* white/black-listing for position_fix
*/
static struct snd_pci_quirk position_fix_list[] __devinitdata = {
- SND_PCI_QUIRK(0x1025, 0x009f, "Acer Aspire 5110", POS_FIX_LPIB),
- SND_PCI_QUIRK(0x1025, 0x026f, "Acer Aspire 5538", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB),
- SND_PCI_QUIRK(0x1028, 0x01f6, "Dell Latitude 131L", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1028, 0x02c6, "Dell Inspiron 1010", POS_FIX_LPIB),
- SND_PCI_QUIRK(0x1028, 0x0470, "Dell Inspiron 1120", POS_FIX_LPIB),
SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB),
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(0x1043, 0x83ce, "ASUS 1101HA", 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),
+ SND_PCI_QUIRK(0x10de, 0xcb89, "Macbook Pro 7,1", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1297, 0x3166, "Shuttle", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1458, 0xa022, "ga-ma770-ud3", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB),
- SND_PCI_QUIRK(0x1565, 0x820f, "Biostar Microtech", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1565, 0x8218, "Biostar Microtech", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1849, 0x0888, "775Dual-VSTA", POS_FIX_LPIB),
SND_PCI_QUIRK(0x8086, 0x2503, "DG965OT AAD63733-203", POS_FIX_LPIB),
- SND_PCI_QUIRK(0x8086, 0xd601, "eMachines T5212", POS_FIX_LPIB),
{}
};
@@ -2458,6 +2618,10 @@ static void __devinit check_probe_mask(struct azx *chip, int dev)
* white/black-list for enable_msi
*/
static struct snd_pci_quirk msi_black_list[] __devinitdata = {
+ SND_PCI_QUIRK(0x103c, 0x2191, "HP", 0), /* AMD Hudson */
+ SND_PCI_QUIRK(0x103c, 0x2192, "HP", 0), /* AMD Hudson */
+ SND_PCI_QUIRK(0x103c, 0x21f7, "HP", 0), /* AMD Hudson */
+ SND_PCI_QUIRK(0x103c, 0x21fa, "HP", 0), /* AMD Hudson */
SND_PCI_QUIRK(0x1043, 0x81f2, "ASUS", 0), /* Athlon64 X2 + nvidia */
SND_PCI_QUIRK(0x1043, 0x81f6, "ASUS", 0), /* nvidia */
SND_PCI_QUIRK(0x1043, 0x822d, "ASUS", 0), /* Athlon64 X2 + nvidia MCP55 */
@@ -2503,6 +2667,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
struct azx *chip;
int i, err;
unsigned short gcap;
+ unsigned int dma_bits = 64;
static struct snd_device_ops ops = {
.dev_free = azx_dev_free,
};
@@ -2536,6 +2701,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
check_probe_mask(chip, dev);
chip->single_cmd = single_cmd;
+ chip->snoop = hda_snoop;
if (bdl_pos_adj[dev] < 0) {
switch (chip->driver_type) {
@@ -2589,9 +2755,14 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
gcap = azx_readw(chip, GCAP);
snd_printdd(SFX "chipset global capabilities = 0x%x\n", gcap);
+ /* AMD devices support 40 or 48bit DMA, take the safe one */
+ if (chip->pci->vendor == PCI_VENDOR_ID_AMD)
+ dma_bits = 40;
+
/* disable SB600 64bit support for safety */
if (chip->pci->vendor == PCI_VENDOR_ID_ATI) {
struct pci_dev *p_smbus;
+ dma_bits = 40;
p_smbus = pci_get_device(PCI_VENDOR_ID_ATI,
PCI_DEVICE_ID_ATI_SBX00_SMBUS,
NULL);
@@ -2608,10 +2779,17 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
gcap &= ~ICH6_GCAP_64OK;
}
+ /* disable buffer size rounding to 128-byte multiples if supported */
+ chip->align_buffer_size = align_buffer_size;
+ if (chip->driver_caps & AZX_DCAPS_BUFSIZE)
+ chip->align_buffer_size = 0;
+
/* allow 64bit DMA address if supported by H/W */
- if ((gcap & ICH6_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64)))
- pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64));
- else {
+ if (!(gcap & ICH6_GCAP_64OK))
+ dma_bits = 32;
+ if (!pci_set_dma_mask(pci, DMA_BIT_MASK(dma_bits))) {
+ pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(dma_bits));
+ } else {
pci_set_dma_mask(pci, DMA_BIT_MASK(32));
pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32));
}
@@ -2659,6 +2837,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
snd_printk(KERN_ERR SFX "cannot allocate BDL\n");
goto errout;
}
+ mark_pages_wc(chip, &chip->azx_dev[i].bdl, true);
}
/* allocate memory for the position buffer */
err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
@@ -2668,6 +2847,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
snd_printk(KERN_ERR SFX "cannot allocate posbuf\n");
goto errout;
}
+ mark_pages_wc(chip, &chip->posbuf, true);
/* allocate CORB/RIRB */
err = azx_alloc_cmd_io(chip);
if (err < 0)
@@ -2809,21 +2989,54 @@ static void __devexit azx_remove(struct pci_dev *pci)
static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
/* CPT */
{ PCI_DEVICE(0x8086, 0x1c20),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP },
+ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
+ AZX_DCAPS_BUFSIZE },
/* PBG */
{ PCI_DEVICE(0x8086, 0x1d20),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP },
+ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
+ AZX_DCAPS_BUFSIZE},
/* Panther Point */
{ PCI_DEVICE(0x8086, 0x1e20),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP },
+ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
+ AZX_DCAPS_BUFSIZE},
+ /* Lynx Point */
+ { PCI_DEVICE(0x8086, 0x8c20),
+ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
+ AZX_DCAPS_BUFSIZE},
/* SCH */
{ PCI_DEVICE(0x8086, 0x811b),
- .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP },
+ .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP |
+ AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_LPIB }, /* Poulsbo */
+ /* ICH */
+ { PCI_DEVICE(0x8086, 0x2668),
+ .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
+ AZX_DCAPS_BUFSIZE }, /* ICH6 */
+ { PCI_DEVICE(0x8086, 0x27d8),
+ .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
+ AZX_DCAPS_BUFSIZE }, /* ICH7 */
+ { PCI_DEVICE(0x8086, 0x269a),
+ .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
+ AZX_DCAPS_BUFSIZE }, /* ESB2 */
+ { PCI_DEVICE(0x8086, 0x284b),
+ .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
+ AZX_DCAPS_BUFSIZE }, /* ICH8 */
+ { PCI_DEVICE(0x8086, 0x293e),
+ .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
+ AZX_DCAPS_BUFSIZE }, /* ICH9 */
+ { PCI_DEVICE(0x8086, 0x293f),
+ .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
+ AZX_DCAPS_BUFSIZE }, /* ICH9 */
+ { PCI_DEVICE(0x8086, 0x3a3e),
+ .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
+ AZX_DCAPS_BUFSIZE }, /* ICH10 */
+ { PCI_DEVICE(0x8086, 0x3a6e),
+ .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
+ AZX_DCAPS_BUFSIZE }, /* ICH10 */
/* Generic Intel */
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID),
.class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
.class_mask = 0xffffff,
- .driver_data = AZX_DRIVER_ICH },
+ .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_BUFSIZE },
/* ATI SB 450/600/700/800/900 */
{ PCI_DEVICE(0x1002, 0x437b),
.driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB },
@@ -2886,12 +3099,12 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
.class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
.class_mask = 0xffffff,
.driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND |
- AZX_DCAPS_RIRB_PRE_DELAY },
+ AZX_DCAPS_RIRB_PRE_DELAY | AZX_DCAPS_POSFIX_LPIB },
#else
/* this entry seems still valid -- i.e. without emu20kx chip */
{ PCI_DEVICE(0x1102, 0x0009),
.driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND |
- AZX_DCAPS_RIRB_PRE_DELAY },
+ AZX_DCAPS_RIRB_PRE_DELAY | AZX_DCAPS_POSFIX_LPIB },
#endif
/* Vortex86MX */
{ PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC },
@@ -2912,7 +3125,7 @@ MODULE_DEVICE_TABLE(pci, azx_ids);
/* pci_driver definition */
static struct pci_driver driver = {
- .name = "HDA Intel",
+ .name = KBUILD_MODNAME,
.id_table = azx_ids,
.probe = azx_probe,
.remove = __devexit_p(azx_remove),
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index e289a13..c78b753 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -131,7 +131,7 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
int direction, int idx, int mask, int val);
int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid,
int dir, int idx, int mask, int val);
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
void snd_hda_codec_resume_amp(struct hda_codec *codec);
#endif
@@ -212,7 +212,9 @@ int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag,
/*
* SPDIF I/O
*/
-int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid);
+int snd_hda_create_spdif_out_ctls(struct hda_codec *codec,
+ hda_nid_t associated_nid,
+ hda_nid_t cvt_nid);
int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid);
/*
@@ -265,11 +267,14 @@ int snd_hda_ch_mode_put(struct hda_codec *codec,
enum { HDA_FRONT, HDA_REAR, HDA_CLFE, HDA_SIDE }; /* index for dac_nidx */
enum { HDA_DIG_NONE, HDA_DIG_EXCLUSIVE, HDA_DIG_ANALOG_DUP }; /* dig_out_used */
+#define HDA_MAX_OUTS 5
+
struct hda_multi_out {
int num_dacs; /* # of DACs, must be more than 1 */
const hda_nid_t *dac_nids; /* DAC list */
hda_nid_t hp_nid; /* optional DAC for HP, 0 when not exists */
- hda_nid_t extra_out_nid[3]; /* optional DACs, 0 when not exists */
+ hda_nid_t hp_out_nid[HDA_MAX_OUTS]; /* DACs for multiple HPs */
+ hda_nid_t extra_out_nid[HDA_MAX_OUTS]; /* other (e.g. speaker) DACs */
hda_nid_t dig_out_nid; /* digital out audio widget */
const hda_nid_t *slave_dig_outs;
int max_channels; /* currently supported analog channels */
@@ -331,9 +336,6 @@ int snd_hda_codec_proc_new(struct hda_codec *codec);
static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; }
#endif
-#define SND_PRINT_RATES_ADVISED_BUFSIZE 80
-void snd_print_pcm_rates(int pcm, char *buf, int buflen);
-
#define SND_PRINT_BITS_ADVISED_BUFSIZE 16
void snd_print_pcm_bits(int pcm, char *buf, int buflen);
@@ -383,7 +385,7 @@ enum {
AUTO_PIN_HP_OUT
};
-#define AUTO_CFG_MAX_OUTS 5
+#define AUTO_CFG_MAX_OUTS HDA_MAX_OUTS
#define AUTO_CFG_MAX_INS 8
struct auto_pin_cfg_item {
@@ -440,10 +442,21 @@ struct auto_pin_cfg {
(cfg & AC_DEFCFG_SEQUENCE)
#define get_defcfg_device(cfg) \
((cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT)
+#define get_defcfg_misc(cfg) \
+ ((cfg & AC_DEFCFG_MISC) >> AC_DEFCFG_MISC_SHIFT)
+
+/* bit-flags for snd_hda_parse_pin_def_config() behavior */
+#define HDA_PINCFG_NO_HP_FIXUP (1 << 0) /* no HP-split */
+#define HDA_PINCFG_NO_LO_FIXUP (1 << 1) /* don't take other outs as LO */
-int snd_hda_parse_pin_def_config(struct hda_codec *codec,
- struct auto_pin_cfg *cfg,
- const hda_nid_t *ignore_nids);
+int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
+ struct auto_pin_cfg *cfg,
+ const hda_nid_t *ignore_nids,
+ unsigned int cond_flags);
+
+/* older function */
+#define snd_hda_parse_pin_def_config(codec, cfg, ignore) \
+ snd_hda_parse_pin_defcfg(codec, cfg, ignore, 0)
/* amp values */
#define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8))
@@ -495,13 +508,24 @@ u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction);
int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
unsigned int caps);
u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid);
+int snd_hda_override_pin_caps(struct hda_codec *codec, hda_nid_t nid,
+ unsigned int caps);
u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid);
int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid);
static inline bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid)
{
- return (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT) &&
- (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP);
+ if (codec->no_jack_detect)
+ return false;
+ if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT))
+ return false;
+ if (!codec->ignore_misc_bit &&
+ (get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
+ AC_DEFCFG_MISC_NO_PRESENCE))
+ return false;
+ if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP))
+ return false;
+ return true;
}
/* flags for hda_nid_item */
@@ -568,7 +592,6 @@ int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
* power-management
*/
-#ifdef CONFIG_SND_HDA_POWER_SAVE
void snd_hda_schedule_power_save(struct hda_codec *codec);
struct hda_amp_list {
@@ -585,7 +608,6 @@ struct hda_loopback_check {
int snd_hda_check_amp_list_power(struct hda_codec *codec,
struct hda_loopback_check *check,
hda_nid_t nid);
-#endif /* CONFIG_SND_HDA_POWER_SAVE */
/*
* AMP control callbacks
@@ -594,7 +616,8 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
#define get_amp_nid_(pv) ((pv) & 0xffff)
#define get_amp_nid(kc) get_amp_nid_((kc)->private_value)
#define get_amp_channels(kc) (((kc)->private_value >> 16) & 0x3)
-#define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1)
+#define get_amp_direction_(pv) (((pv) >> 18) & 0x1)
+#define get_amp_direction(kc) get_amp_direction_((kc)->private_value)
#define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf)
#define get_amp_offset(kc) (((kc)->private_value >> 23) & 0x3f)
#define get_amp_min_mute(kc) (((kc)->private_value >> 29) & 0x1)
@@ -612,6 +635,7 @@ struct cea_sad {
};
#define ELD_FIXED_BYTES 20
+#define ELD_MAX_SIZE 256
#define ELD_MAX_MNL 16
#define ELD_MAX_SAD 16
@@ -636,6 +660,10 @@ struct hdmi_eld {
int spk_alloc;
int sad_count;
struct cea_sad sad[ELD_MAX_SAD];
+ /*
+ * all fields above eld_buffer will be cleared before updating ELD
+ */
+ char eld_buffer[ELD_MAX_SIZE];
#ifdef CONFIG_PROC_FS
struct snd_info_entry *proc_entry;
#endif
@@ -644,8 +672,8 @@ struct hdmi_eld {
int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid);
int snd_hdmi_get_eld(struct hdmi_eld *, struct hda_codec *, hda_nid_t);
void snd_hdmi_show_eld(struct hdmi_eld *eld);
-void hdmi_eld_update_pcm_info(struct hdmi_eld *eld, struct hda_pcm_stream *pcm,
- struct hda_pcm_stream *codec_pars);
+void snd_hdmi_eld_update_pcm_info(struct hdmi_eld *eld,
+ struct hda_pcm_stream *hinfo);
#ifdef CONFIG_PROC_FS
int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld,
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index d0e5dec..2210b83 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -154,12 +154,18 @@ static void print_amp_vals(struct snd_info_buffer *buffer,
static void print_pcm_rates(struct snd_info_buffer *buffer, unsigned int pcm)
{
- char buf[SND_PRINT_RATES_ADVISED_BUFSIZE];
+ static unsigned int rates[] = {
+ 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200,
+ 96000, 176400, 192000, 384000
+ };
+ int i;
pcm &= AC_SUPPCM_RATES;
snd_iprintf(buffer, " rates [0x%x]:", pcm);
- snd_print_pcm_rates(pcm, buf, sizeof(buf));
- snd_iprintf(buffer, "%s\n", buf);
+ for (i = 0; i < ARRAY_SIZE(rates); i++)
+ if (pcm & (1 << i))
+ snd_iprintf(buffer, " %d", rates[i]);
+ snd_iprintf(buffer, "\n");
}
static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm)
@@ -638,7 +644,7 @@ static void print_codec_info(struct snd_info_entry *entry,
wid_caps |= AC_WCAP_CONN_LIST;
if (wid_caps & AC_WCAP_CONN_LIST)
- conn_len = snd_hda_get_connections(codec, nid, conn,
+ conn_len = snd_hda_get_raw_connections(codec, nid, conn,
HDA_MAX_CONNECTIONS);
if (wid_caps & AC_WCAP_IN_AMP) {
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 7b6f959..b4890f9 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -23,6 +23,7 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/pci.h>
+#include <linux/module.h>
#include <sound/core.h>
#include "hda_codec.h"
@@ -48,6 +49,8 @@ struct ad198x_spec {
const hda_nid_t *alt_dac_nid;
const struct hda_pcm_stream *stream_analog_alt_playback;
+ int independent_hp;
+ int num_active_streams;
/* capture */
unsigned int num_adc_nids;
@@ -213,7 +216,9 @@ static int ad198x_build_controls(struct hda_codec *codec)
return err;
}
if (spec->multiout.dig_out_nid) {
- err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
+ err = snd_hda_create_spdif_out_ctls(codec,
+ spec->multiout.dig_out_nid,
+ spec->multiout.dig_out_nid);
if (err < 0)
return err;
err = snd_hda_create_spdif_share_sw(codec,
@@ -300,6 +305,72 @@ static int ad198x_check_power_status(struct hda_codec *codec, hda_nid_t nid)
}
#endif
+static void activate_ctl(struct hda_codec *codec, const char *name, int active)
+{
+ struct snd_kcontrol *ctl = snd_hda_find_mixer_ctl(codec, name);
+ if (ctl) {
+ ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+ ctl->vd[0].access |= active ? 0 :
+ SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+ ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_WRITE;
+ ctl->vd[0].access |= active ?
+ SNDRV_CTL_ELEM_ACCESS_WRITE : 0;
+ snd_ctl_notify(codec->bus->card,
+ SNDRV_CTL_EVENT_MASK_INFO, &ctl->id);
+ }
+}
+
+static void set_stream_active(struct hda_codec *codec, bool active)
+{
+ struct ad198x_spec *spec = codec->spec;
+ if (active)
+ spec->num_active_streams++;
+ else
+ spec->num_active_streams--;
+ activate_ctl(codec, "Independent HP", spec->num_active_streams == 0);
+}
+
+static int ad1988_independent_hp_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static const char * const texts[] = { "OFF", "ON", NULL};
+ int index;
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 2;
+ index = uinfo->value.enumerated.item;
+ if (index >= 2)
+ index = 1;
+ strcpy(uinfo->value.enumerated.name, texts[index]);
+ return 0;
+}
+
+static int ad1988_independent_hp_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct ad198x_spec *spec = codec->spec;
+ ucontrol->value.enumerated.item[0] = spec->independent_hp;
+ return 0;
+}
+
+static int ad1988_independent_hp_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct ad198x_spec *spec = codec->spec;
+ unsigned int select = ucontrol->value.enumerated.item[0];
+ if (spec->independent_hp != select) {
+ spec->independent_hp = select;
+ if (spec->independent_hp)
+ spec->multiout.hp_nid = 0;
+ else
+ spec->multiout.hp_nid = spec->alt_dac_nid[0];
+ return 1;
+ }
+ return 0;
+}
+
/*
* Analog playback callbacks
*/
@@ -308,8 +379,15 @@ static int ad198x_playback_pcm_open(struct hda_pcm_stream *hinfo,
struct snd_pcm_substream *substream)
{
struct ad198x_spec *spec = codec->spec;
- return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
+ int err;
+ set_stream_active(codec, true);
+ err = snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
hinfo);
+ if (err < 0) {
+ set_stream_active(codec, false);
+ return err;
+ }
+ return 0;
}
static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
@@ -331,11 +409,41 @@ static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
}
+static int ad198x_playback_pcm_close(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ set_stream_active(codec, false);
+ return 0;
+}
+
+static int ad1988_alt_playback_pcm_open(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct ad198x_spec *spec = codec->spec;
+ if (!spec->independent_hp)
+ return -EBUSY;
+ set_stream_active(codec, true);
+ return 0;
+}
+
+static int ad1988_alt_playback_pcm_close(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ set_stream_active(codec, false);
+ return 0;
+}
+
static const 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 = {
+ .open = ad1988_alt_playback_pcm_open,
+ .close = ad1988_alt_playback_pcm_close
+ },
};
/*
@@ -400,7 +508,6 @@ static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
return 0;
}
-
/*
*/
static const struct hda_pcm_stream ad198x_pcm_analog_playback = {
@@ -411,7 +518,8 @@ static const struct hda_pcm_stream ad198x_pcm_analog_playback = {
.ops = {
.open = ad198x_playback_pcm_open,
.prepare = ad198x_playback_pcm_prepare,
- .cleanup = ad198x_playback_pcm_cleanup
+ .cleanup = ad198x_playback_pcm_cleanup,
+ .close = ad198x_playback_pcm_close
},
};
@@ -562,7 +670,7 @@ static void ad198x_free(struct hda_codec *codec)
snd_hda_detach_beep_device(codec);
}
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
static int ad198x_suspend(struct hda_codec *codec, pm_message_t state)
{
ad198x_shutup(codec);
@@ -578,7 +686,7 @@ static const struct hda_codec_ops ad198x_patch_ops = {
#ifdef CONFIG_SND_HDA_POWER_SAVE
.check_power_status = ad198x_check_power_status,
#endif
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
.suspend = ad198x_suspend,
#endif
.reboot_notify = ad198x_shutup,
@@ -1921,7 +2029,8 @@ static int patch_ad1981(struct hda_codec *codec)
spec->mixers[0] = ad1981_hp_mixers;
spec->num_init_verbs = 2;
spec->init_verbs[1] = ad1981_hp_init_verbs;
- spec->multiout.dig_out_nid = 0;
+ if (!is_jack_available(codec, 0x0a))
+ spec->multiout.dig_out_nid = 0;
spec->input_mux = &ad1981_hp_capture_source;
codec->patch_ops.init = ad1981_hp_init;
@@ -2056,7 +2165,6 @@ 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,
@@ -2166,6 +2274,17 @@ static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
return err;
}
+static const struct snd_kcontrol_new ad1988_hp_mixers[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Independent HP",
+ .info = ad1988_independent_hp_info,
+ .get = ad1988_independent_hp_get,
+ .put = ad1988_independent_hp_put,
+ },
+ { } /* end */
+};
+
/* 6-stack mode */
static const struct snd_kcontrol_new ad1988_6stack_mixers1[] = {
HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
@@ -2186,6 +2305,7 @@ static const struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = {
};
static const struct snd_kcontrol_new ad1988_6stack_mixers2[] = {
+ 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),
@@ -2208,13 +2328,6 @@ static const struct snd_kcontrol_new ad1988_6stack_mixers2[] = {
HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
-
- { } /* end */
-};
-
-static const struct snd_kcontrol_new ad1988_6stack_fp_mixers[] = {
- HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-
{ } /* end */
};
@@ -2236,6 +2349,7 @@ static const struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = {
};
static const struct snd_kcontrol_new ad1988_3stack_mixers2[] = {
+ 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", 0x2c, 2, HDA_INPUT),
HDA_BIND_MUTE_MONO("Center Playback Switch", 0x26, 1, 2, HDA_INPUT),
@@ -2270,6 +2384,7 @@ static const struct snd_kcontrol_new ad1988_3stack_mixers2[] = {
/* laptop mode */
static const struct snd_kcontrol_new ad1988_laptop_mixers[] = {
+ HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE("PCM Playback Switch", 0x29, 0x0, HDA_INPUT),
HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
@@ -2444,7 +2559,7 @@ static const struct hda_verb ad1988_6stack_init_verbs[] = {
{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
/* Port-A front headphon path */
- {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */
+ {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},
@@ -2592,7 +2707,7 @@ static const struct hda_verb ad1988_3stack_init_verbs[] = {
{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
/* Port-A front headphon path */
- {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */
+ {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},
@@ -2667,7 +2782,7 @@ static const struct hda_verb ad1988_laptop_init_verbs[] = {
{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
/* Port-A front headphon path */
- {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */
+ {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},
@@ -2780,11 +2895,11 @@ static inline hda_nid_t ad1988_idx_to_dac(struct hda_codec *codec, int idx)
{
static const hda_nid_t idx_to_dac[8] = {
/* A B C D E F G H */
- 0x04, 0x06, 0x05, 0x04, 0x0a, 0x06, 0x05, 0x0a
+ 0x03, 0x06, 0x05, 0x04, 0x0a, 0x06, 0x05, 0x0a
};
static const hda_nid_t idx_to_dac_rev2[8] = {
/* A B C D E F G H */
- 0x04, 0x05, 0x0a, 0x04, 0x06, 0x05, 0x0a, 0x06
+ 0x03, 0x05, 0x0a, 0x04, 0x06, 0x05, 0x0a, 0x06
};
if (is_rev2(codec))
return idx_to_dac_rev2[idx];
@@ -3021,8 +3136,8 @@ static void ad1988_auto_set_output_and_unmute(struct hda_codec *codec,
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
switch (nid) {
- case 0x11: /* port-A - DAC 04 */
- snd_hda_codec_write(codec, 0x37, 0, AC_VERB_SET_CONNECT_SEL, 0x01);
+ case 0x11: /* port-A - DAC 03 */
+ snd_hda_codec_write(codec, 0x37, 0, AC_VERB_SET_CONNECT_SEL, 0x00);
break;
case 0x14: /* port-B - DAC 06 */
snd_hda_codec_write(codec, 0x30, 0, AC_VERB_SET_CONNECT_SEL, 0x02);
@@ -3148,7 +3263,6 @@ static int ad1988_auto_init(struct hda_codec *codec)
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",
@@ -3206,10 +3320,11 @@ static int patch_ad1988(struct hda_codec *codec)
}
set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
+ if (!spec->multiout.hp_nid)
+ spec->multiout.hp_nid = ad1988_alt_dac_nid[0];
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))
@@ -3225,19 +3340,7 @@ static int patch_ad1988(struct hda_codec *codec)
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_FP) {
- spec->num_mixers++;
- spec->mixers[2] = ad1988_6stack_fp_mixers;
- spec->num_init_verbs++;
- spec->init_verbs[1] = ad1988_6stack_fp_init_verbs;
- 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;
- }
- if ((board_config == AD1988_6STACK_DIG) ||
- (board_config == AD1988_6STACK_DIG_FP)) {
+ if (board_config == AD1988_6STACK_DIG) {
spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
spec->dig_in_nid = AD1988_SPDIF_IN;
}
@@ -3280,6 +3383,15 @@ static int patch_ad1988(struct hda_codec *codec)
break;
}
+ if (spec->autocfg.hp_pins[0]) {
+ spec->mixers[spec->num_mixers++] = ad1988_hp_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;
+ }
+
spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids);
spec->adc_nids = ad1988_adc_nids;
spec->capsrc_nids = ad1988_capsrc_nids;
diff --git a/sound/pci/hda/patch_ca0110.c b/sound/pci/hda/patch_ca0110.c
index 61b9263..993757b 100644
--- a/sound/pci/hda/patch_ca0110.c
+++ b/sound/pci/hda/patch_ca0110.c
@@ -22,6 +22,7 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/pci.h>
+#include <linux/module.h>
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
@@ -240,7 +241,8 @@ static int ca0110_build_controls(struct hda_codec *codec)
}
if (spec->dig_out) {
- err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out);
+ err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out,
+ spec->dig_out);
if (err < 0)
return err;
err = snd_hda_create_spdif_share_sw(codec, &spec->multiout);
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 15bfe9d..0ed6867 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -22,9 +22,11 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/pci.h>
+#include <linux/module.h>
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
+#include <sound/tlv.h>
/*
*/
@@ -56,28 +58,43 @@ struct cs_spec {
unsigned int gpio_mask;
unsigned int gpio_dir;
unsigned int gpio_data;
+ unsigned int gpio_eapd_hp; /* EAPD GPIO bit for headphones */
+ unsigned int gpio_eapd_speaker; /* EAPD GPIO bit for speakers */
struct hda_pcm pcm_rec[2]; /* PCM information */
unsigned int hp_detect:1;
unsigned int mic_detect:1;
+ /* CS421x */
+ unsigned int spdif_detect:1;
+ unsigned int sense_b:1;
+ hda_nid_t vendor_nid;
+ struct hda_input_mux input_mux;
+ unsigned int last_input;
};
-/* available models */
+/* available models with CS420x */
enum {
CS420X_MBP53,
CS420X_MBP55,
CS420X_IMAC27,
+ CS420X_APPLE,
CS420X_AUTO,
CS420X_MODELS
};
+/* CS421x boards */
+enum {
+ CS421X_CDB4210,
+ CS421X_MODELS
+};
+
/* Vendor-specific processing widget */
#define CS420X_VENDOR_NID 0x11
#define CS_DIG_OUT1_PIN_NID 0x10
#define CS_DIG_OUT2_PIN_NID 0x15
-#define CS_DMIC1_PIN_NID 0x12
-#define CS_DMIC2_PIN_NID 0x0e
+#define CS_DMIC1_PIN_NID 0x0e
+#define CS_DMIC2_PIN_NID 0x12
/* coef indices */
#define IDX_SPDIF_STAT 0x0000
@@ -111,21 +128,42 @@ enum {
/* 0x0009 - 0x0014 -> 12 test regs */
/* 0x0015 - visibility reg */
+/*
+ * Cirrus Logic CS4210
+ *
+ * 1 DAC => HP(sense) / Speakers,
+ * 1 ADC <= LineIn(sense) / MicIn / DMicIn,
+ * 1 SPDIF OUT => SPDIF Trasmitter(sense)
+*/
+#define CS4210_DAC_NID 0x02
+#define CS4210_ADC_NID 0x03
+#define CS421X_VENDOR_NID 0x0B
+#define CS421X_DMIC_PIN_NID 0x09 /* Port E */
+#define CS421X_SPDIF_PIN_NID 0x0A /* Port H */
+
+#define CS421X_IDX_DEV_CFG 0x01
+#define CS421X_IDX_ADC_CFG 0x02
+#define CS421X_IDX_DAC_CFG 0x03
+#define CS421X_IDX_SPK_CTL 0x04
+
+#define SPDIF_EVENT 0x04
static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx)
{
- snd_hda_codec_write(codec, CS420X_VENDOR_NID, 0,
+ struct cs_spec *spec = codec->spec;
+ snd_hda_codec_write(codec, spec->vendor_nid, 0,
AC_VERB_SET_COEF_INDEX, idx);
- return snd_hda_codec_read(codec, CS420X_VENDOR_NID, 0,
+ return snd_hda_codec_read(codec, spec->vendor_nid, 0,
AC_VERB_GET_PROC_COEF, 0);
}
static inline void cs_vendor_coef_set(struct hda_codec *codec, unsigned int idx,
unsigned int coef)
{
- snd_hda_codec_write(codec, CS420X_VENDOR_NID, 0,
+ struct cs_spec *spec = codec->spec;
+ snd_hda_codec_write(codec, spec->vendor_nid, 0,
AC_VERB_SET_COEF_INDEX, idx);
- snd_hda_codec_write(codec, CS420X_VENDOR_NID, 0,
+ snd_hda_codec_write(codec, spec->vendor_nid, 0,
AC_VERB_SET_PROC_COEF, coef);
}
@@ -202,6 +240,15 @@ static int cs_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
}
+static void cs_update_input_select(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+ if (spec->cur_adc)
+ snd_hda_codec_write(codec, spec->cur_adc, 0,
+ AC_VERB_SET_CONNECT_SEL,
+ spec->adc_idx[spec->cur_input]);
+}
+
/*
* Analog capture
*/
@@ -215,6 +262,7 @@ static int cs_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
spec->cur_adc = spec->adc_nid[spec->cur_input];
spec->cur_adc_stream_tag = stream_tag;
spec->cur_adc_format = format;
+ cs_update_input_select(codec);
snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
return 0;
}
@@ -341,26 +389,19 @@ static int is_ext_mic(struct hda_codec *codec, unsigned int idx)
static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin,
unsigned int *idxp)
{
- int i;
+ int i, idx;
hda_nid_t nid;
nid = codec->start_nid;
for (i = 0; i < codec->num_nodes; i++, nid++) {
- hda_nid_t pins[2];
unsigned int type;
- int j, nums;
type = get_wcaps_type(get_wcaps(codec, nid));
if (type != AC_WID_AUD_IN)
continue;
- nums = snd_hda_get_connections(codec, nid, pins,
- ARRAY_SIZE(pins));
- if (nums <= 0)
- continue;
- for (j = 0; j < nums; j++) {
- if (pins[j] == pin) {
- *idxp = j;
- return nid;
- }
+ idx = snd_hda_get_conn_index(codec, nid, pin, false);
+ if (idx >= 0) {
+ *idxp = idx;
+ return nid;
}
}
return 0;
@@ -661,10 +702,8 @@ static int change_cur_input(struct hda_codec *codec, unsigned int idx,
spec->cur_adc_stream_tag, 0,
spec->cur_adc_format);
}
- snd_hda_codec_write(codec, spec->cur_adc, 0,
- AC_VERB_SET_CONNECT_SEL,
- spec->adc_idx[idx]);
spec->cur_input = idx;
+ cs_update_input_select(codec);
return 1;
}
@@ -821,7 +860,8 @@ static int build_digital_output(struct hda_codec *codec)
if (!spec->multiout.dig_out_nid)
return 0;
- err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
+ err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid,
+ spec->multiout.dig_out_nid);
if (err < 0)
return err;
err = snd_hda_create_spdif_share_sw(codec, &spec->multiout);
@@ -840,6 +880,8 @@ static int build_digital_input(struct hda_codec *codec)
/*
* auto-mute and auto-mic switching
+ * CS421x auto-output redirecting
+ * HP/SPK/SPDIF
*/
static void cs_automute(struct hda_codec *codec)
@@ -847,9 +889,25 @@ static void cs_automute(struct hda_codec *codec)
struct cs_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
unsigned int hp_present;
+ unsigned int spdif_present;
hda_nid_t nid;
int i;
+ spdif_present = 0;
+ if (cfg->dig_outs) {
+ nid = cfg->dig_out_pins[0];
+ if (is_jack_detectable(codec, nid)) {
+ /*
+ TODO: SPDIF output redirect when SENSE_B is enabled.
+ Shared (SENSE_A) jack (e.g HP/mini-TOSLINK)
+ assumed.
+ */
+ if (snd_hda_jack_detect(codec, nid)
+ /* && spec->sense_b */)
+ spdif_present = 1;
+ }
+ }
+
hp_present = 0;
for (i = 0; i < cfg->hp_outs; i++) {
nid = cfg->hp_pins[i];
@@ -859,34 +917,79 @@ static void cs_automute(struct hda_codec *codec)
if (hp_present)
break;
}
+
+ /* mute speakers if spdif or hp jack is plugged in */
for (i = 0; i < cfg->speaker_outs; i++) {
+ int pin_ctl = hp_present ? 0 : PIN_OUT;
+ /* detect on spdif is specific to CS421x */
+ if (spdif_present && (spec->vendor_nid == CS421X_VENDOR_NID))
+ pin_ctl = 0;
+
nid = cfg->speaker_pins[i];
snd_hda_codec_write(codec, nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
- hp_present ? 0 : PIN_OUT);
+ AC_VERB_SET_PIN_WIDGET_CONTROL, pin_ctl);
}
- if (spec->board_config == CS420X_MBP53 ||
- spec->board_config == CS420X_MBP55 ||
- spec->board_config == CS420X_IMAC27) {
- unsigned int gpio = hp_present ? 0x02 : 0x08;
+ if (spec->gpio_eapd_hp) {
+ unsigned int gpio = hp_present ?
+ spec->gpio_eapd_hp : spec->gpio_eapd_speaker;
snd_hda_codec_write(codec, 0x01, 0,
AC_VERB_SET_GPIO_DATA, gpio);
}
+
+ /* specific to CS421x */
+ if (spec->vendor_nid == CS421X_VENDOR_NID) {
+ /* mute HPs if spdif jack (SENSE_B) is present */
+ for (i = 0; i < cfg->hp_outs; i++) {
+ nid = cfg->hp_pins[i];
+ snd_hda_codec_write(codec, nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
+ (spdif_present && spec->sense_b) ? 0 : PIN_HP);
+ }
+
+ /* SPDIF TX on/off */
+ if (cfg->dig_outs) {
+ nid = cfg->dig_out_pins[0];
+ snd_hda_codec_write(codec, nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
+ spdif_present ? PIN_OUT : 0);
+
+ }
+ /* Update board GPIOs if neccessary ... */
+ }
}
+/*
+ * Auto-input redirect for CS421x
+ * Switch max 3 inputs of a single ADC (nid 3)
+*/
+
static void cs_automic(struct hda_codec *codec)
{
struct cs_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
hda_nid_t nid;
unsigned int present;
-
+
nid = cfg->inputs[spec->automic_idx].pin;
present = snd_hda_jack_detect(codec, nid);
- if (present)
- change_cur_input(codec, spec->automic_idx, 0);
- else
- change_cur_input(codec, !spec->automic_idx, 0);
+
+ /* specific to CS421x, single ADC */
+ if (spec->vendor_nid == CS421X_VENDOR_NID) {
+ if (present) {
+ if (spec->cur_input != spec->automic_idx) {
+ spec->last_input = spec->cur_input;
+ spec->cur_input = spec->automic_idx;
+ }
+ } else {
+ spec->cur_input = spec->last_input;
+ }
+ cs_update_input_select(codec);
+ } else {
+ if (present)
+ change_cur_input(codec, spec->automic_idx, 0);
+ else
+ change_cur_input(codec, !spec->automic_idx, 0);
+ }
}
/*
@@ -916,23 +1019,28 @@ static void init_output(struct hda_codec *codec)
for (i = 0; i < cfg->line_outs; i++)
snd_hda_codec_write(codec, cfg->line_out_pins[i], 0,
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+ /* HP */
for (i = 0; i < cfg->hp_outs; i++) {
hda_nid_t nid = cfg->hp_pins[i];
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
if (!cfg->speaker_outs)
continue;
- if (is_jack_detectable(codec, nid)) {
+ if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_UNSOLICITED_ENABLE,
AC_USRSP_EN | HP_EVENT);
spec->hp_detect = 1;
}
}
+
+ /* Speaker */
for (i = 0; i < cfg->speaker_outs; i++)
snd_hda_codec_write(codec, cfg->speaker_pins[i], 0,
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
- if (spec->hp_detect)
+
+ /* SPDIF is enabled on presence detect for CS421x */
+ if (spec->hp_detect || spec->spdif_detect)
cs_automute(codec);
}
@@ -966,19 +1074,33 @@ static void init_input(struct hda_codec *codec)
AC_VERB_SET_UNSOLICITED_ENABLE,
AC_USRSP_EN | MIC_EVENT);
}
- change_cur_input(codec, spec->cur_input, 1);
- if (spec->mic_detect)
- cs_automic(codec);
-
- coef = 0x000a; /* ADC1/2 - Digital and Analog Soft Ramp */
- if (is_active_pin(codec, CS_DMIC2_PIN_NID))
- coef |= 0x0500; /* DMIC2 enable 2 channels, disable GPIO1 */
- if (is_active_pin(codec, CS_DMIC1_PIN_NID))
- coef |= 0x1800; /* DMIC1 enable 2 channels, disable GPIO0
- * No effect if SPDIF_OUT2 is selected in
- * IDX_SPDIF_CTL.
- */
- cs_vendor_coef_set(codec, IDX_ADC_CFG, coef);
+ /* specific to CS421x */
+ if (spec->vendor_nid == CS421X_VENDOR_NID) {
+ if (spec->mic_detect)
+ cs_automic(codec);
+ else {
+ spec->cur_adc = spec->adc_nid[spec->cur_input];
+ cs_update_input_select(codec);
+ }
+ } else {
+ change_cur_input(codec, spec->cur_input, 1);
+ if (spec->mic_detect)
+ cs_automic(codec);
+
+ coef = 0x000a; /* ADC1/2 - Digital and Analog Soft Ramp */
+ cs_vendor_coef_set(codec, IDX_ADC_CFG, coef);
+
+ coef = cs_vendor_coef_get(codec, IDX_BEEP_CFG);
+ if (is_active_pin(codec, CS_DMIC2_PIN_NID))
+ coef |= 1 << 4; /* DMIC2 2 chan on, GPIO1 off */
+ if (is_active_pin(codec, CS_DMIC1_PIN_NID))
+ coef |= 1 << 3; /* DMIC1 2 chan on, GPIO0 off
+ * No effect if SPDIF_OUT2 is
+ * selected in IDX_SPDIF_CTL.
+ */
+
+ cs_vendor_coef_set(codec, IDX_BEEP_CFG, coef);
+ }
}
static const struct hda_verb cs_coef_init_verbs[] = {
@@ -1160,6 +1282,7 @@ static const char * const cs420x_models[CS420X_MODELS] = {
[CS420X_MBP53] = "mbp53",
[CS420X_MBP55] = "mbp55",
[CS420X_IMAC27] = "imac27",
+ [CS420X_APPLE] = "apple",
[CS420X_AUTO] = "auto",
};
@@ -1169,7 +1292,13 @@ static const struct snd_pci_quirk cs420x_cfg_tbl[] = {
SND_PCI_QUIRK(0x10de, 0x0d94, "MacBookAir 3,1(2)", CS420X_MBP55),
SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55),
SND_PCI_QUIRK(0x10de, 0xcb89, "MacBookPro 7,1", CS420X_MBP55),
- SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),
+ /* this conflicts with too many other models */
+ /*SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),*/
+ {} /* terminator */
+};
+
+static const struct snd_pci_quirk cs420x_codec_cfg_tbl[] = {
+ SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS420X_APPLE),
{} /* terminator */
};
@@ -1226,16 +1355,16 @@ static const struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = {
[CS420X_IMAC27] = imac27_pincfgs,
};
-static void fix_pincfg(struct hda_codec *codec, int model)
+static void fix_pincfg(struct hda_codec *codec, int model,
+ const struct cs_pincfg **pin_configs)
{
- const struct cs_pincfg *cfg = cs_pincfgs[model];
+ const struct cs_pincfg *cfg = pin_configs[model];
if (!cfg)
return;
for (; cfg->nid; cfg++)
snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
}
-
static int patch_cs420x(struct hda_codec *codec)
{
struct cs_spec *spec;
@@ -1246,20 +1375,27 @@ static int patch_cs420x(struct hda_codec *codec)
return -ENOMEM;
codec->spec = spec;
+ spec->vendor_nid = CS420X_VENDOR_NID;
+
spec->board_config =
snd_hda_check_board_config(codec, CS420X_MODELS,
cs420x_models, cs420x_cfg_tbl);
+ if (spec->board_config < 0)
+ spec->board_config =
+ snd_hda_check_board_codec_sid_config(codec,
+ CS420X_MODELS, NULL, cs420x_codec_cfg_tbl);
if (spec->board_config >= 0)
- fix_pincfg(codec, spec->board_config);
+ fix_pincfg(codec, spec->board_config, cs_pincfgs);
switch (spec->board_config) {
case CS420X_IMAC27:
case CS420X_MBP53:
case CS420X_MBP55:
- /* GPIO1 = headphones */
- /* GPIO3 = speakers */
- spec->gpio_mask = 0x0a;
- spec->gpio_dir = 0x0a;
+ case CS420X_APPLE:
+ spec->gpio_eapd_hp = 2; /* GPIO1 = headphones */
+ spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */
+ spec->gpio_mask = spec->gpio_dir =
+ spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
break;
}
@@ -1272,7 +1408,552 @@ static int patch_cs420x(struct hda_codec *codec)
return 0;
error:
- kfree(codec->spec);
+ cs_free(codec);
+ codec->spec = NULL;
+ return err;
+}
+
+/*
+ * Cirrus Logic CS4210
+ *
+ * 1 DAC => HP(sense) / Speakers,
+ * 1 ADC <= LineIn(sense) / MicIn / DMicIn,
+ * 1 SPDIF OUT => SPDIF Trasmitter(sense)
+*/
+
+/* CS4210 board names */
+static const char *cs421x_models[CS421X_MODELS] = {
+ [CS421X_CDB4210] = "cdb4210",
+};
+
+static const struct snd_pci_quirk cs421x_cfg_tbl[] = {
+ /* Test Intel board + CDB2410 */
+ SND_PCI_QUIRK(0x8086, 0x5001, "DP45SG/CDB4210", CS421X_CDB4210),
+ {} /* terminator */
+};
+
+/* CS4210 board pinconfigs */
+/* Default CS4210 (CDB4210)*/
+static const struct cs_pincfg cdb4210_pincfgs[] = {
+ { 0x05, 0x0321401f },
+ { 0x06, 0x90170010 },
+ { 0x07, 0x03813031 },
+ { 0x08, 0xb7a70037 },
+ { 0x09, 0xb7a6003e },
+ { 0x0a, 0x034510f0 },
+ {} /* terminator */
+};
+
+static const struct cs_pincfg *cs421x_pincfgs[CS421X_MODELS] = {
+ [CS421X_CDB4210] = cdb4210_pincfgs,
+};
+
+static const struct hda_verb cs421x_coef_init_verbs[] = {
+ {0x0B, AC_VERB_SET_PROC_STATE, 1},
+ {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DEV_CFG},
+ /*
+ Disable Coefficient Index Auto-Increment(DAI)=1,
+ PDREF=0
+ */
+ {0x0B, AC_VERB_SET_PROC_COEF, 0x0001 },
+
+ {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_ADC_CFG},
+ /* ADC SZCMode = Digital Soft Ramp */
+ {0x0B, AC_VERB_SET_PROC_COEF, 0x0002 },
+
+ {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DAC_CFG},
+ {0x0B, AC_VERB_SET_PROC_COEF,
+ (0x0002 /* DAC SZCMode = Digital Soft Ramp */
+ | 0x0004 /* Mute DAC on FIFO error */
+ | 0x0008 /* Enable DAC High Pass Filter */
+ )},
+ {} /* terminator */
+};
+
+/* Errata: CS4210 rev A1 Silicon
+ *
+ * http://www.cirrus.com/en/pubs/errata/
+ *
+ * Description:
+ * 1. Performance degredation is present in the ADC.
+ * 2. Speaker output is not completely muted upon HP detect.
+ * 3. Noise is present when clipping occurs on the amplified
+ * speaker outputs.
+ *
+ * Workaround:
+ * The following verb sequence written to the registers during
+ * initialization will correct the issues listed above.
+ */
+
+static const struct hda_verb cs421x_coef_init_verbs_A1_silicon_fixes[] = {
+ {0x0B, AC_VERB_SET_PROC_STATE, 0x01}, /* VPW: processing on */
+
+ {0x0B, AC_VERB_SET_COEF_INDEX, 0x0006},
+ {0x0B, AC_VERB_SET_PROC_COEF, 0x9999}, /* Test mode: on */
+
+ {0x0B, AC_VERB_SET_COEF_INDEX, 0x000A},
+ {0x0B, AC_VERB_SET_PROC_COEF, 0x14CB}, /* Chop double */
+
+ {0x0B, AC_VERB_SET_COEF_INDEX, 0x0011},
+ {0x0B, AC_VERB_SET_PROC_COEF, 0xA2D0}, /* Increase ADC current */
+
+ {0x0B, AC_VERB_SET_COEF_INDEX, 0x001A},
+ {0x0B, AC_VERB_SET_PROC_COEF, 0x02A9}, /* Mute speaker */
+
+ {0x0B, AC_VERB_SET_COEF_INDEX, 0x001B},
+ {0x0B, AC_VERB_SET_PROC_COEF, 0X1006}, /* Remove noise */
+
+ {} /* terminator */
+};
+
+/* Speaker Amp Gain is controlled by the vendor widget's coef 4 */
+static const DECLARE_TLV_DB_SCALE(cs421x_speaker_boost_db_scale, 900, 300, 0);
+
+static int cs421x_boost_vol_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 3;
+ return 0;
+}
+
+static int cs421x_boost_vol_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] =
+ cs_vendor_coef_get(codec, CS421X_IDX_SPK_CTL) & 0x0003;
+ return 0;
+}
+
+static int cs421x_boost_vol_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ unsigned int vol = ucontrol->value.integer.value[0];
+ unsigned int coef =
+ cs_vendor_coef_get(codec, CS421X_IDX_SPK_CTL);
+ unsigned int original_coef = coef;
+
+ coef &= ~0x0003;
+ coef |= (vol & 0x0003);
+ if (original_coef == coef)
+ return 0;
+ else {
+ cs_vendor_coef_set(codec, CS421X_IDX_SPK_CTL, coef);
+ return 1;
+ }
+}
+
+static const struct snd_kcontrol_new cs421x_speaker_bost_ctl = {
+
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+ .name = "Speaker Boost Playback Volume",
+ .info = cs421x_boost_vol_info,
+ .get = cs421x_boost_vol_get,
+ .put = cs421x_boost_vol_put,
+ .tlv = { .p = cs421x_speaker_boost_db_scale },
+};
+
+static void cs421x_pinmux_init(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+ unsigned int def_conf, coef;
+
+ /* GPIO, DMIC_SCL, DMIC_SDA and SENSE_B are multiplexed */
+ coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG);
+
+ if (spec->gpio_mask)
+ coef |= 0x0008; /* B1,B2 are GPIOs */
+ else
+ coef &= ~0x0008;
+
+ if (spec->sense_b)
+ coef |= 0x0010; /* B2 is SENSE_B, not inverted */
+ else
+ coef &= ~0x0010;
+
+ cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef);
+
+ if ((spec->gpio_mask || spec->sense_b) &&
+ is_active_pin(codec, CS421X_DMIC_PIN_NID)) {
+
+ /*
+ GPIO or SENSE_B forced - disconnect the DMIC pin.
+ */
+ def_conf = snd_hda_codec_get_pincfg(codec, CS421X_DMIC_PIN_NID);
+ def_conf &= ~AC_DEFCFG_PORT_CONN;
+ def_conf |= (AC_JACK_PORT_NONE << AC_DEFCFG_PORT_CONN_SHIFT);
+ snd_hda_codec_set_pincfg(codec, CS421X_DMIC_PIN_NID, def_conf);
+ }
+}
+
+static void init_cs421x_digital(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ int i;
+
+
+ for (i = 0; i < cfg->dig_outs; i++) {
+ hda_nid_t nid = cfg->dig_out_pins[i];
+ if (!cfg->speaker_outs)
+ continue;
+ if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
+
+ snd_hda_codec_write(codec, nid, 0,
+ AC_VERB_SET_UNSOLICITED_ENABLE,
+ AC_USRSP_EN | SPDIF_EVENT);
+ spec->spdif_detect = 1;
+ }
+ }
+}
+
+static int cs421x_init(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+
+ snd_hda_sequence_write(codec, cs421x_coef_init_verbs);
+ snd_hda_sequence_write(codec, cs421x_coef_init_verbs_A1_silicon_fixes);
+
+ cs421x_pinmux_init(codec);
+
+ if (spec->gpio_mask) {
+ snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
+ spec->gpio_mask);
+ snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION,
+ spec->gpio_dir);
+ snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+ spec->gpio_data);
+ }
+
+ init_output(codec);
+ init_input(codec);
+ init_cs421x_digital(codec);
+
+ return 0;
+}
+
+/*
+ * CS4210 Input MUX (1 ADC)
+ */
+static int cs421x_mux_enum_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct cs_spec *spec = codec->spec;
+
+ return snd_hda_input_mux_info(&spec->input_mux, uinfo);
+}
+
+static int cs421x_mux_enum_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct cs_spec *spec = codec->spec;
+
+ ucontrol->value.enumerated.item[0] = spec->cur_input;
+ return 0;
+}
+
+static int cs421x_mux_enum_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct cs_spec *spec = codec->spec;
+
+ return snd_hda_input_mux_put(codec, &spec->input_mux, ucontrol,
+ spec->adc_nid[0], &spec->cur_input);
+
+}
+
+static struct snd_kcontrol_new cs421x_capture_source = {
+
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Source",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = cs421x_mux_enum_info,
+ .get = cs421x_mux_enum_get,
+ .put = cs421x_mux_enum_put,
+};
+
+static int cs421x_add_input_volume_control(struct hda_codec *codec, int item)
+{
+ struct cs_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ const struct hda_input_mux *imux = &spec->input_mux;
+ hda_nid_t pin = cfg->inputs[item].pin;
+ struct snd_kcontrol *kctl;
+ u32 caps;
+
+ if (!(get_wcaps(codec, pin) & AC_WCAP_IN_AMP))
+ return 0;
+
+ caps = query_amp_caps(codec, pin, HDA_INPUT);
+ caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
+ if (caps <= 1)
+ return 0;
+
+ return add_volume(codec, imux->items[item].label, 0,
+ HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_INPUT), 1, &kctl);
+}
+
+/* add a (input-boost) volume control to the given input pin */
+static int build_cs421x_input(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ struct hda_input_mux *imux = &spec->input_mux;
+ int i, err, type_idx;
+ const char *label;
+
+ if (!spec->num_inputs)
+ return 0;
+
+ /* make bind-capture */
+ spec->capture_bind[0] = make_bind_capture(codec, &snd_hda_bind_sw);
+ spec->capture_bind[1] = make_bind_capture(codec, &snd_hda_bind_vol);
+ for (i = 0; i < 2; i++) {
+ struct snd_kcontrol *kctl;
+ int n;
+ if (!spec->capture_bind[i])
+ return -ENOMEM;
+ kctl = snd_ctl_new1(&cs_capture_ctls[i], codec);
+ if (!kctl)
+ return -ENOMEM;
+ kctl->private_value = (long)spec->capture_bind[i];
+ err = snd_hda_ctl_add(codec, 0, kctl);
+ if (err < 0)
+ return err;
+ for (n = 0; n < AUTO_PIN_LAST; n++) {
+ if (!spec->adc_nid[n])
+ continue;
+ err = snd_hda_add_nid(codec, kctl, 0, spec->adc_nid[n]);
+ if (err < 0)
+ return err;
+ }
+ }
+
+ /* Add Input MUX Items + Capture Volume/Switch */
+ for (i = 0; i < spec->num_inputs; i++) {
+ label = hda_get_autocfg_input_label(codec, cfg, i);
+ snd_hda_add_imux_item(imux, label, spec->adc_idx[i], &type_idx);
+
+ err = cs421x_add_input_volume_control(codec, i);
+ if (err < 0)
+ return err;
+ }
+
+ /*
+ Add 'Capture Source' Switch if
+ * 2 inputs and no mic detec
+ * 3 inputs
+ */
+ if ((spec->num_inputs == 2 && !spec->mic_detect) ||
+ (spec->num_inputs == 3)) {
+
+ err = snd_hda_ctl_add(codec, spec->adc_nid[0],
+ snd_ctl_new1(&cs421x_capture_source, codec));
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+/* Single DAC (Mute/Gain) */
+static int build_cs421x_output(struct hda_codec *codec)
+{
+ hda_nid_t dac = CS4210_DAC_NID;
+ struct cs_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ struct snd_kcontrol *kctl;
+ int err;
+ char *name = "Master";
+
+ fix_volume_caps(codec, dac);
+
+ err = add_mute(codec, name, 0,
+ HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl);
+ if (err < 0)
+ return err;
+
+ err = add_volume(codec, name, 0,
+ HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl);
+ if (err < 0)
+ return err;
+
+ if (cfg->speaker_outs) {
+ err = snd_hda_ctl_add(codec, 0,
+ snd_ctl_new1(&cs421x_speaker_bost_ctl, codec));
+ if (err < 0)
+ return err;
+ }
+ return err;
+}
+
+static int cs421x_build_controls(struct hda_codec *codec)
+{
+ int err;
+
+ err = build_cs421x_output(codec);
+ if (err < 0)
+ return err;
+ err = build_cs421x_input(codec);
+ if (err < 0)
+ return err;
+ err = build_digital_output(codec);
+ if (err < 0)
+ return err;
+ return cs421x_init(codec);
+}
+
+static void cs421x_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+ switch ((res >> 26) & 0x3f) {
+ case HP_EVENT:
+ case SPDIF_EVENT:
+ cs_automute(codec);
+ break;
+
+ case MIC_EVENT:
+ cs_automic(codec);
+ break;
+ }
+}
+
+static int parse_cs421x_input(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ int i;
+
+ for (i = 0; i < cfg->num_inputs; i++) {
+ hda_nid_t pin = cfg->inputs[i].pin;
+ spec->adc_nid[i] = get_adc(codec, pin, &spec->adc_idx[i]);
+ spec->cur_input = spec->last_input = i;
+ spec->num_inputs++;
+
+ /* check whether the automatic mic switch is available */
+ if (is_ext_mic(codec, i) && cfg->num_inputs >= 2) {
+ spec->mic_detect = 1;
+ spec->automic_idx = i;
+ }
+ }
+ return 0;
+}
+
+static int cs421x_parse_auto_config(struct hda_codec *codec)
+{
+ struct cs_spec *spec = codec->spec;
+ int err;
+
+ err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
+ if (err < 0)
+ return err;
+ err = parse_output(codec);
+ if (err < 0)
+ return err;
+ err = parse_cs421x_input(codec);
+ if (err < 0)
+ return err;
+ err = parse_digital_output(codec);
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+#ifdef CONFIG_PM
+/*
+ Manage PDREF, when transitioning to D3hot
+ (DAC,ADC) -> D3, PDREF=1, AFG->D3
+*/
+static int cs421x_suspend(struct hda_codec *codec, pm_message_t state)
+{
+ unsigned int coef;
+
+ snd_hda_shutup_pins(codec);
+
+ snd_hda_codec_write(codec, CS4210_DAC_NID, 0,
+ AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+ snd_hda_codec_write(codec, CS4210_ADC_NID, 0,
+ AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+
+ coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG);
+ coef |= 0x0004; /* PDREF */
+ cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef);
+
+ return 0;
+}
+#endif
+
+static struct hda_codec_ops cs4210_patch_ops = {
+ .build_controls = cs421x_build_controls,
+ .build_pcms = cs_build_pcms,
+ .init = cs421x_init,
+ .free = cs_free,
+ .unsol_event = cs421x_unsol_event,
+#ifdef CONFIG_PM
+ .suspend = cs421x_suspend,
+#endif
+};
+
+static int patch_cs421x(struct hda_codec *codec)
+{
+ struct cs_spec *spec;
+ int err;
+
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (!spec)
+ return -ENOMEM;
+ codec->spec = spec;
+
+ spec->vendor_nid = CS421X_VENDOR_NID;
+
+ spec->board_config =
+ snd_hda_check_board_config(codec, CS421X_MODELS,
+ cs421x_models, cs421x_cfg_tbl);
+ if (spec->board_config >= 0)
+ fix_pincfg(codec, spec->board_config, cs421x_pincfgs);
+ /*
+ Setup GPIO/SENSE for each board (if used)
+ */
+ switch (spec->board_config) {
+ case CS421X_CDB4210:
+ snd_printd("CS4210 board: %s\n",
+ cs421x_models[spec->board_config]);
+/* spec->gpio_mask = 3;
+ spec->gpio_dir = 3;
+ spec->gpio_data = 3;
+*/
+ spec->sense_b = 1;
+
+ break;
+ }
+
+ /*
+ Update the GPIO/DMIC/SENSE_B pinmux before the configuration
+ is auto-parsed. If GPIO or SENSE_B is forced, DMIC input
+ is disabled.
+ */
+ cs421x_pinmux_init(codec);
+
+ err = cs421x_parse_auto_config(codec);
+ if (err < 0)
+ goto error;
+
+ codec->patch_ops = cs4210_patch_ops;
+
+ return 0;
+
+ error:
+ cs_free(codec);
codec->spec = NULL;
return err;
}
@@ -1284,11 +1965,13 @@ static int patch_cs420x(struct hda_codec *codec)
static const struct hda_codec_preset snd_hda_preset_cirrus[] = {
{ .id = 0x10134206, .name = "CS4206", .patch = patch_cs420x },
{ .id = 0x10134207, .name = "CS4207", .patch = patch_cs420x },
+ { .id = 0x10134210, .name = "CS4210", .patch = patch_cs421x },
{} /* terminator */
};
MODULE_ALIAS("snd-hda-codec-id:10134206");
MODULE_ALIAS("snd-hda-codec-id:10134207");
+MODULE_ALIAS("snd-hda-codec-id:10134210");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Cirrus Logic HD-audio codec");
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c
index ab3308d..b6767b4 100644
--- a/sound/pci/hda/patch_cmedia.c
+++ b/sound/pci/hda/patch_cmedia.c
@@ -25,6 +25,7 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/pci.h>
+#include <linux/module.h>
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
@@ -327,7 +328,9 @@ static int cmi9880_build_controls(struct hda_codec *codec)
return err;
}
if (spec->multiout.dig_out_nid) {
- err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
+ err = snd_hda_create_spdif_out_ctls(codec,
+ spec->multiout.dig_out_nid,
+ spec->multiout.dig_out_nid);
if (err < 0)
return err;
err = snd_hda_create_spdif_share_sw(codec,
@@ -396,12 +399,11 @@ static int cmi9880_fill_multi_init(struct hda_codec *codec, const struct auto_pi
{
struct cmi_spec *spec = codec->spec;
hda_nid_t nid;
- int i, j, k, len;
+ int i, j, k;
/* clear the table, only one c-media dac assumed here */
memset(spec->multi_init, 0, sizeof(spec->multi_init));
for (j = 0, i = 0; i < cfg->line_outs; i++) {
- hda_nid_t conn[4];
nid = cfg->line_out_pins[i];
/* set as output */
spec->multi_init[j].nid = nid;
@@ -414,12 +416,10 @@ static int cmi9880_fill_multi_init(struct hda_codec *codec, const struct auto_pi
spec->multi_init[j].verb = AC_VERB_SET_CONNECT_SEL;
spec->multi_init[j].param = 0;
/* find the index in connect list */
- len = snd_hda_get_connections(codec, nid, conn, 4);
- for (k = 0; k < len; k++)
- if (conn[k] == spec->dac_nids[i]) {
- spec->multi_init[j].param = k;
- break;
- }
+ k = snd_hda_get_conn_index(codec, nid,
+ spec->dac_nids[i], 0);
+ if (k >= 0)
+ spec->multi_init[j].param = k;
j++;
}
}
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 4cf3266..6a524fb 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -24,6 +24,7 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/pci.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/jack.h>
@@ -136,7 +137,9 @@ struct conexant_spec {
unsigned int thinkpad:1;
unsigned int hp_laptop:1;
unsigned int asus:1;
+ unsigned int pin_eapd_ctrls:1;
unsigned int single_adc_amp:1;
+ unsigned int fixup_stereo_dmic:1;
unsigned int adc_switching:1;
@@ -156,6 +159,10 @@ struct conexant_spec {
unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */
unsigned int beep_amp;
+
+ /* extra EAPD pins */
+ unsigned int num_eapds;
+ hda_nid_t eapds[4];
};
static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo,
@@ -443,6 +450,19 @@ static int conexant_init_jacks(struct hda_codec *codec)
return 0;
}
+static void conexant_set_power(struct hda_codec *codec, hda_nid_t fg,
+ unsigned int power_state)
+{
+ if (power_state == AC_PWRST_D3)
+ msleep(100);
+ snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE,
+ power_state);
+ /* partial workaround for "azx_get_response timeout" */
+ if (power_state == AC_PWRST_D0)
+ msleep(10);
+ snd_hda_codec_set_power_to_all(codec, fg, power_state, true);
+}
+
static int conexant_init(struct hda_codec *codec)
{
struct conexant_spec *spec = codec->spec;
@@ -511,6 +531,7 @@ static int conexant_build_controls(struct hda_codec *codec)
}
if (spec->multiout.dig_out_nid) {
err = snd_hda_create_spdif_out_ctls(codec,
+ spec->multiout.dig_out_nid,
spec->multiout.dig_out_nid);
if (err < 0)
return err;
@@ -571,23 +592,12 @@ static int conexant_build_controls(struct hda_codec *codec)
return 0;
}
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static int conexant_suspend(struct hda_codec *codec, pm_message_t state)
-{
- snd_hda_shutup_pins(codec);
- return 0;
-}
-#endif
-
static const struct hda_codec_ops conexant_patch_ops = {
.build_controls = conexant_build_controls,
.build_pcms = conexant_build_pcms,
.init = conexant_init,
.free = conexant_free,
-#ifdef CONFIG_SND_HDA_POWER_SAVE
- .suspend = conexant_suspend,
-#endif
- .reboot_notify = snd_hda_shutup_pins,
+ .set_power_state = conexant_set_power,
};
#ifdef CONFIG_SND_HDA_INPUT_BEEP
@@ -1099,8 +1109,6 @@ static const char * const cxt5045_models[CXT5045_MODELS] = {
static const struct snd_pci_quirk cxt5045_cfg_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HP530),
- SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series",
- CXT5045_LAPTOP_HPSENSE),
SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P105", CXT5045_LAPTOP_MICSENSE),
SND_PCI_QUIRK(0x152d, 0x0753, "Benq R55E", CXT5045_BENQ),
SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_LAPTOP_MICSENSE),
@@ -1124,10 +1132,8 @@ static int patch_cxt5045(struct hda_codec *codec)
board_config = snd_hda_check_board_config(codec, CXT5045_MODELS,
cxt5045_models,
cxt5045_cfg_tbl);
-#if 0 /* use the old method just for safety */
if (board_config < 0)
- board_config = CXT5045_AUTO;
-#endif
+ board_config = CXT5045_AUTO; /* model=auto as default */
if (board_config == CXT5045_AUTO)
return patch_conexant_auto(codec);
@@ -1230,7 +1236,7 @@ static int patch_cxt5045(struct hda_codec *codec)
}
if (spec->beep_amp)
- snd_hda_attach_beep_device(codec, spec->beep_amp);
+ snd_hda_attach_beep_device(codec, get_amp_nid_(spec->beep_amp));
return 0;
}
@@ -1565,10 +1571,8 @@ static int patch_cxt5047(struct hda_codec *codec)
board_config = snd_hda_check_board_config(codec, CXT5047_MODELS,
cxt5047_models,
cxt5047_cfg_tbl);
-#if 0 /* not enabled as default, as BIOS often broken for this codec */
if (board_config < 0)
- board_config = CXT5047_AUTO;
-#endif
+ board_config = CXT5047_AUTO; /* model=auto as default */
if (board_config == CXT5047_AUTO)
return patch_conexant_auto(codec);
@@ -1853,39 +1857,6 @@ static const struct hda_verb cxt5051_hp_dv6736_init_verbs[] = {
{ } /* end */
};
-static const struct hda_verb cxt5051_lenovo_x200_init_verbs[] = {
- /* Line in, Mic */
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
- {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
- /* SPK */
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* HP, Amp */
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* Docking HP */
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x19, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* DAC1 */
- {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* 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},
- /* SPDIF route: PCM */
- {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* needed for W500 Advanced Mini Dock 250410 */
- {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0},
- /* EAPD */
- {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
- {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT},
- {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT},
- { } /* end */
-};
-
static const struct hda_verb cxt5051_f700_init_verbs[] = {
/* Line in, Mic */
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
@@ -1957,7 +1928,6 @@ enum {
CXT5051_LAPTOP, /* Laptops w/ EAPD support */
CXT5051_HP, /* no docking */
CXT5051_HP_DV6736, /* HP without mic switch */
- CXT5051_LENOVO_X200, /* Lenovo X200 laptop, also used for Advanced Mini Dock 250410 */
CXT5051_F700, /* HP Compaq Presario F700 */
CXT5051_TOSHIBA, /* Toshiba M300 & co */
CXT5051_IDEAPAD, /* Lenovo IdeaPad Y430 */
@@ -1969,7 +1939,6 @@ static const char *const cxt5051_models[CXT5051_MODELS] = {
[CXT5051_LAPTOP] = "laptop",
[CXT5051_HP] = "hp",
[CXT5051_HP_DV6736] = "hp-dv6736",
- [CXT5051_LENOVO_X200] = "lenovo-x200",
[CXT5051_F700] = "hp-700",
[CXT5051_TOSHIBA] = "toshiba",
[CXT5051_IDEAPAD] = "ideapad",
@@ -1984,7 +1953,6 @@ static const struct snd_pci_quirk cxt5051_cfg_tbl[] = {
SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board",
CXT5051_LAPTOP),
SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP),
- SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT5051_LENOVO_X200),
SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo IdeaPad", CXT5051_IDEAPAD),
{}
};
@@ -1997,10 +1965,8 @@ static int patch_cxt5051(struct hda_codec *codec)
board_config = snd_hda_check_board_config(codec, CXT5051_MODELS,
cxt5051_models,
cxt5051_cfg_tbl);
-#if 0 /* use the old method just for safety */
if (board_config < 0)
- board_config = CXT5051_AUTO;
-#endif
+ board_config = CXT5051_AUTO; /* model=auto as default */
if (board_config == CXT5051_AUTO)
return patch_conexant_auto(codec);
@@ -2044,13 +2010,6 @@ static int patch_cxt5051(struct hda_codec *codec)
spec->mixers[0] = cxt5051_hp_dv6736_mixers;
spec->auto_mic = 0;
break;
- case CXT5051_LENOVO_X200:
- spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs;
- /* Thinkpad X301 does not have S/PDIF wired and no ability
- to use a docking station. */
- if (codec->subsystem_id == 0x17aa211f)
- spec->multiout.dig_out_nid = 0;
- break;
case CXT5051_F700:
spec->init_verbs[0] = cxt5051_f700_init_verbs;
spec->mixers[0] = cxt5051_f700_mixers;
@@ -2068,7 +2027,7 @@ static int patch_cxt5051(struct hda_codec *codec)
}
if (spec->beep_amp)
- snd_hda_attach_beep_device(codec, spec->beep_amp);
+ snd_hda_attach_beep_device(codec, get_amp_nid_(spec->beep_amp));
conexant_init_jacks(codec);
if (spec->auto_mic & AUTO_MIC_PORTB)
@@ -3089,7 +3048,6 @@ static const struct snd_pci_quirk cxt5066_cfg_tbl[] = {
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),
@@ -3099,7 +3057,6 @@ static const struct snd_pci_quirk cxt5066_cfg_tbl[] = {
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),
SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board",
CXT5066_LAPTOP),
SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5),
@@ -3125,10 +3082,8 @@ static int patch_cxt5066(struct hda_codec *codec)
board_config = snd_hda_check_board_config(codec, CXT5066_MODELS,
cxt5066_models, cxt5066_cfg_tbl);
-#if 0 /* use the old method just for safety */
if (board_config < 0)
- board_config = CXT5066_AUTO;
-#endif
+ board_config = CXT5066_AUTO; /* model=auto as default */
if (board_config == CXT5066_AUTO)
return patch_conexant_auto(codec);
@@ -3270,7 +3225,7 @@ static int patch_cxt5066(struct hda_codec *codec)
}
if (spec->beep_amp)
- snd_hda_attach_beep_device(codec, spec->beep_amp);
+ snd_hda_attach_beep_device(codec, get_amp_nid_(spec->beep_amp));
return 0;
}
@@ -3319,19 +3274,8 @@ static const struct hda_pcm_stream cx_auto_pcm_analog_capture = {
static const hda_nid_t cx_auto_adc_nids[] = { 0x14 };
-/* get the connection index of @nid in the widget @mux */
-static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
- hda_nid_t nid)
-{
- hda_nid_t conn[HDA_MAX_NUM_INPUTS];
- int i, nums;
-
- nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
- for (i = 0; i < nums; i++)
- if (conn[i] == nid)
- return i;
- return -1;
-}
+#define get_connection_index(codec, mux, nid)\
+ snd_hda_get_conn_index(codec, mux, nid, 0)
/* get an unassigned DAC from the given list.
* Return the nid if found and reduce the DAC list, or return zero if
@@ -3359,6 +3303,8 @@ static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t pin,
#define MAX_AUTO_DACS 5
+#define DAC_SLAVE_FLAG 0x8000 /* filled dac is a slave */
+
/* fill analog DAC list from the widget tree */
static int fill_cx_auto_dacs(struct hda_codec *codec, hda_nid_t *dacs)
{
@@ -3381,16 +3327,26 @@ static int fill_cx_auto_dacs(struct hda_codec *codec, hda_nid_t *dacs)
/* fill pin_dac_pair list from the pin and dac list */
static int fill_dacs_for_pins(struct hda_codec *codec, hda_nid_t *pins,
int num_pins, hda_nid_t *dacs, int *rest,
- struct pin_dac_pair *filled, int type)
+ struct pin_dac_pair *filled, int nums,
+ int type)
{
- int i, nums;
+ int i, start = nums;
- nums = 0;
- for (i = 0; i < num_pins; i++) {
+ for (i = 0; i < num_pins; i++, nums++) {
filled[nums].pin = pins[i];
filled[nums].type = type;
filled[nums].dac = get_unassigned_dac(codec, pins[i], dacs, rest);
- nums++;
+ if (filled[nums].dac)
+ continue;
+ if (filled[start].dac && get_connection_index(codec, pins[i], filled[start].dac) >= 0) {
+ filled[nums].dac = filled[start].dac | DAC_SLAVE_FLAG;
+ continue;
+ }
+ if (filled[0].dac && get_connection_index(codec, pins[i], filled[0].dac) >= 0) {
+ filled[nums].dac = filled[0].dac | DAC_SLAVE_FLAG;
+ continue;
+ }
+ snd_printdd("Failed to find a DAC for pin 0x%x", pins[i]);
}
return nums;
}
@@ -3406,19 +3362,19 @@ static void cx_auto_parse_output(struct hda_codec *codec)
rest = fill_cx_auto_dacs(codec, dacs);
/* parse all analog output pins */
nums = fill_dacs_for_pins(codec, cfg->line_out_pins, cfg->line_outs,
- dacs, &rest, spec->dac_info,
- AUTO_PIN_LINE_OUT);
- nums += fill_dacs_for_pins(codec, cfg->hp_pins, cfg->hp_outs,
- dacs, &rest, spec->dac_info + nums,
- AUTO_PIN_HP_OUT);
- nums += fill_dacs_for_pins(codec, cfg->speaker_pins, cfg->speaker_outs,
- dacs, &rest, spec->dac_info + nums,
- AUTO_PIN_SPEAKER_OUT);
+ dacs, &rest, spec->dac_info, 0,
+ AUTO_PIN_LINE_OUT);
+ nums = fill_dacs_for_pins(codec, cfg->hp_pins, cfg->hp_outs,
+ dacs, &rest, spec->dac_info, nums,
+ AUTO_PIN_HP_OUT);
+ nums = fill_dacs_for_pins(codec, cfg->speaker_pins, cfg->speaker_outs,
+ dacs, &rest, spec->dac_info, nums,
+ AUTO_PIN_SPEAKER_OUT);
spec->dac_info_filled = nums;
/* fill multiout struct */
for (i = 0; i < nums; i++) {
hda_nid_t dac = spec->dac_info[i].dac;
- if (!dac)
+ if (!dac || (dac & DAC_SLAVE_FLAG))
continue;
switch (spec->dac_info[i].type) {
case AUTO_PIN_LINE_OUT:
@@ -3471,12 +3427,14 @@ static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins,
static void do_automute(struct hda_codec *codec, int num_pins,
hda_nid_t *pins, bool on)
{
+ struct conexant_spec *spec = codec->spec;
int i;
for (i = 0; i < num_pins; i++)
snd_hda_codec_write(codec, pins[i], 0,
AC_VERB_SET_PIN_WIDGET_CONTROL,
on ? PIN_OUT : 0);
- cx_auto_turn_eapd(codec, num_pins, pins, on);
+ if (spec->pin_eapd_ctrls)
+ cx_auto_turn_eapd(codec, num_pins, pins, on);
}
static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
@@ -3501,9 +3459,12 @@ static void cx_auto_update_speakers(struct hda_codec *codec)
int on = 1;
/* turn on HP EAPD when HP jacks are present */
- if (spec->auto_mute)
- on = spec->hp_present;
- cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, on);
+ if (spec->pin_eapd_ctrls) {
+ if (spec->auto_mute)
+ on = spec->hp_present;
+ cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, on);
+ }
+
/* mute speakers in auto-mode if HP or LO jacks are plugged */
if (spec->auto_mute)
on = !(spec->hp_present ||
@@ -3873,7 +3834,7 @@ static void cx_auto_parse_input(struct hda_codec *codec)
}
if (imux->num_items >= 2 && cfg->num_inputs == imux->num_items)
cx_auto_check_auto_mic(codec);
- if (imux->num_items > 1 && !spec->auto_mic) {
+ if (imux->num_items > 1) {
for (i = 1; i < imux->num_items; i++) {
if (spec->imux_info[i].adc != spec->imux_info[0].adc) {
spec->adc_switching = 1;
@@ -3930,6 +3891,32 @@ static void cx_auto_parse_beep(struct hda_codec *codec)
#define cx_auto_parse_beep(codec)
#endif
+/* parse EAPDs */
+static void cx_auto_parse_eapd(struct hda_codec *codec)
+{
+ struct conexant_spec *spec = codec->spec;
+ hda_nid_t nid, end_nid;
+
+ end_nid = codec->start_nid + codec->num_nodes;
+ for (nid = codec->start_nid; nid < end_nid; nid++) {
+ if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
+ continue;
+ if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD))
+ continue;
+ spec->eapds[spec->num_eapds++] = nid;
+ if (spec->num_eapds >= ARRAY_SIZE(spec->eapds))
+ break;
+ }
+
+ /* NOTE: below is a wild guess; if we have more than two EAPDs,
+ * it's a new chip, where EAPDs are supposed to be associated to
+ * pins, and we can control EAPD per pin.
+ * OTOH, if only one or two EAPDs are found, it's an old chip,
+ * thus it might control over all pins.
+ */
+ spec->pin_eapd_ctrls = spec->num_eapds > 2;
+}
+
static int cx_auto_parse_auto_config(struct hda_codec *codec)
{
struct conexant_spec *spec = codec->spec;
@@ -3943,6 +3930,7 @@ static int cx_auto_parse_auto_config(struct hda_codec *codec)
cx_auto_parse_input(codec);
cx_auto_parse_digital(codec);
cx_auto_parse_beep(codec);
+ cx_auto_parse_eapd(codec);
return 0;
}
@@ -4018,6 +4006,8 @@ static void cx_auto_init_output(struct hda_codec *codec)
nid = spec->dac_info[i].dac;
if (!nid)
nid = spec->multiout.dac_nids[0];
+ else if (nid & DAC_SLAVE_FLAG)
+ nid &= ~DAC_SLAVE_FLAG;
select_connection(codec, spec->dac_info[i].pin, nid);
}
if (spec->auto_mute) {
@@ -4035,6 +4025,9 @@ static void cx_auto_init_output(struct hda_codec *codec)
}
}
cx_auto_update_speakers(codec);
+ /* turn on all EAPDs if no individual EAPD control is available */
+ if (!spec->pin_eapd_ctrls)
+ cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true);
}
static void cx_auto_init_input(struct hda_codec *codec)
@@ -4109,9 +4102,9 @@ static int cx_auto_init(struct hda_codec *codec)
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, int amp_idx)
+ hda_nid_t nid, int hda_dir, int amp_idx, int chs)
{
- static char name[32];
+ static char name[44];
static struct snd_kcontrol_new knew[] = {
HDA_CODEC_VOLUME(name, 0, 0, 0),
HDA_CODEC_MUTE(name, 0, 0, 0),
@@ -4121,7 +4114,7 @@ static int cx_auto_add_volume_idx(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, amp_idx,
+ knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, chs, amp_idx,
hda_dir);
knew[i].subdevice = HDA_SUBDEV_AMP_FLAG;
knew[i].index = cidx;
@@ -4140,7 +4133,7 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename,
}
#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)
+ cx_auto_add_volume_idx(codec, str, dir, cidx, nid, hda_dir, 0, 3)
#define cx_auto_add_pb_volume(codec, nid, str, idx) \
cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT)
@@ -4149,9 +4142,11 @@ static int try_add_pb_volume(struct hda_codec *codec, hda_nid_t dac,
hda_nid_t pin, const char *name, int idx)
{
unsigned int caps;
- caps = query_amp_caps(codec, dac, HDA_OUTPUT);
- if (caps & AC_AMPCAP_NUM_STEPS)
- return cx_auto_add_pb_volume(codec, dac, name, idx);
+ if (dac && !(dac & DAC_SLAVE_FLAG)) {
+ caps = query_amp_caps(codec, dac, HDA_OUTPUT);
+ if (caps & AC_AMPCAP_NUM_STEPS)
+ return cx_auto_add_pb_volume(codec, dac, name, idx);
+ }
caps = query_amp_caps(codec, pin, HDA_OUTPUT);
if (caps & AC_AMPCAP_NUM_STEPS)
return cx_auto_add_pb_volume(codec, pin, name, idx);
@@ -4173,8 +4168,7 @@ static int cx_auto_build_output_controls(struct hda_codec *codec)
for (i = 0; i < spec->dac_info_filled; i++) {
const char *label;
int idx, type;
- if (!spec->dac_info[i].dac)
- continue;
+ hda_nid_t dac = spec->dac_info[i].dac;
type = spec->dac_info[i].type;
if (type == AUTO_PIN_LINE_OUT)
type = spec->autocfg.line_out_type;
@@ -4193,7 +4187,7 @@ static int cx_auto_build_output_controls(struct hda_codec *codec)
idx = num_spk++;
break;
}
- err = try_add_pb_volume(codec, spec->dac_info[i].dac,
+ err = try_add_pb_volume(codec, dac,
spec->dac_info[i].pin,
label, idx);
if (err < 0)
@@ -4209,6 +4203,36 @@ static int cx_auto_build_output_controls(struct hda_codec *codec)
return 0;
}
+/* Returns zero if this is a normal stereo channel, and non-zero if it should
+ be split in two independent channels.
+ dest_label must be at least 44 characters. */
+static int cx_auto_get_rightch_label(struct hda_codec *codec, const char *label,
+ char *dest_label, int nid)
+{
+ struct conexant_spec *spec = codec->spec;
+ int i;
+
+ if (!spec->fixup_stereo_dmic)
+ return 0;
+
+ for (i = 0; i < AUTO_CFG_MAX_INS; i++) {
+ int def_conf;
+ if (spec->autocfg.inputs[i].pin != nid)
+ continue;
+
+ if (spec->autocfg.inputs[i].type != AUTO_PIN_MIC)
+ return 0;
+ def_conf = snd_hda_codec_get_pincfg(codec, nid);
+ if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT)
+ return 0;
+
+ /* Finally found the inverted internal mic! */
+ snprintf(dest_label, 44, "Inverted %s", label);
+ return 1;
+ }
+ return 0;
+}
+
static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid,
const char *label, const char *pfx,
int cidx)
@@ -4217,14 +4241,25 @@ static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid,
int i;
for (i = 0; i < spec->num_adc_nids; i++) {
+ char rightch_label[44];
hda_nid_t adc_nid = spec->adc_nids[i];
int idx = get_input_connection(codec, adc_nid, nid);
if (idx < 0)
continue;
if (spec->single_adc_amp)
idx = 0;
+
+ if (cx_auto_get_rightch_label(codec, label, rightch_label, nid)) {
+ /* Make two independent kcontrols for left and right */
+ int err = cx_auto_add_volume_idx(codec, label, pfx,
+ cidx, adc_nid, HDA_INPUT, idx, 1);
+ if (err < 0)
+ return err;
+ return cx_auto_add_volume_idx(codec, rightch_label, pfx,
+ cidx, adc_nid, HDA_INPUT, idx, 2);
+ }
return cx_auto_add_volume_idx(codec, label, pfx,
- cidx, adc_nid, HDA_INPUT, idx);
+ cidx, adc_nid, HDA_INPUT, idx, 3);
}
return 0;
}
@@ -4237,9 +4272,19 @@ static int cx_auto_add_boost_volume(struct hda_codec *codec, int idx,
int i, con;
nid = spec->imux_info[idx].pin;
- if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
+ if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
+ char rightch_label[44];
+ if (cx_auto_get_rightch_label(codec, label, rightch_label, nid)) {
+ int err = cx_auto_add_volume_idx(codec, label, " Boost",
+ cidx, nid, HDA_INPUT, 0, 1);
+ if (err < 0)
+ return err;
+ return cx_auto_add_volume_idx(codec, rightch_label, " Boost",
+ cidx, nid, HDA_INPUT, 0, 2);
+ }
return cx_auto_add_volume(codec, label, " Boost", cidx,
nid, HDA_INPUT);
+ }
con = __select_input_connection(codec, spec->imux_info[idx].adc, nid,
&mux, false, 0);
if (con < 0)
@@ -4372,10 +4417,88 @@ static const struct hda_codec_ops cx_auto_patch_ops = {
.init = cx_auto_init,
.free = conexant_free,
.unsol_event = cx_auto_unsol_event,
-#ifdef CONFIG_SND_HDA_POWER_SAVE
- .suspend = conexant_suspend,
-#endif
- .reboot_notify = snd_hda_shutup_pins,
+};
+
+/*
+ * pin fix-up
+ */
+struct cxt_pincfg {
+ hda_nid_t nid;
+ u32 val;
+};
+
+static void apply_pincfg(struct hda_codec *codec, const struct cxt_pincfg *cfg)
+{
+ for (; cfg->nid; cfg++)
+ snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
+
+}
+
+enum {
+ CXT_PINCFG_LENOVO_X200,
+ CXT_PINCFG_LENOVO_TP410,
+ CXT_FIXUP_STEREO_DMIC,
+};
+
+static void apply_fixup(struct hda_codec *codec,
+ const struct snd_pci_quirk *quirk,
+ const struct cxt_pincfg **table)
+{
+ struct conexant_spec *spec = codec->spec;
+
+ quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
+ if (!quirk)
+ return;
+ if (table[quirk->value]) {
+ snd_printdd(KERN_INFO "hda_codec: applying pincfg for %s\n",
+ quirk->name);
+ apply_pincfg(codec, table[quirk->value]);
+ }
+ if (quirk->value == CXT_FIXUP_STEREO_DMIC) {
+ snd_printdd(KERN_INFO "hda_codec: applying internal mic workaround for %s\n",
+ quirk->name);
+ spec->fixup_stereo_dmic = 1;
+ }
+}
+
+/* ThinkPad X200 & co with cxt5051 */
+static const struct cxt_pincfg cxt_pincfg_lenovo_x200[] = {
+ { 0x16, 0x042140ff }, /* HP (seq# overridden) */
+ { 0x17, 0x21a11000 }, /* dock-mic */
+ { 0x19, 0x2121103f }, /* dock-HP */
+ {}
+};
+
+/* ThinkPad 410/420/510/520, X201 & co with cxt5066 */
+static const struct cxt_pincfg cxt_pincfg_lenovo_tp410[] = {
+ { 0x19, 0x042110ff }, /* HP (seq# overridden) */
+ { 0x1a, 0x21a190f0 }, /* dock-mic */
+ { 0x1c, 0x212140ff }, /* dock-HP */
+ {}
+};
+
+static const struct cxt_pincfg *cxt_pincfg_tbl[] = {
+ [CXT_PINCFG_LENOVO_X200] = cxt_pincfg_lenovo_x200,
+ [CXT_PINCFG_LENOVO_TP410] = cxt_pincfg_lenovo_tp410,
+ [CXT_FIXUP_STEREO_DMIC] = NULL,
+};
+
+static const struct snd_pci_quirk cxt5051_fixups[] = {
+ SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT_PINCFG_LENOVO_X200),
+ {}
+};
+
+static const struct snd_pci_quirk cxt5066_fixups[] = {
+ SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC),
+ SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410),
+ SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410),
+ SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410),
+ SND_PCI_QUIRK(0x17aa, 0x21ce, "Lenovo T420", CXT_PINCFG_LENOVO_TP410),
+ SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520", CXT_PINCFG_LENOVO_TP410),
+ SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
+ SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC),
+ SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC),
+ {}
};
/* add "fake" mute amp-caps to DACs on cx5051 so that mixer mute switches
@@ -4414,6 +4537,10 @@ static int patch_conexant_auto(struct hda_codec *codec)
break;
case 0x14f15051:
add_cx5051_fake_mutes(codec);
+ apply_fixup(codec, cxt5051_fixups, cxt_pincfg_tbl);
+ break;
+ default:
+ apply_fixup(codec, cxt5066_fixups, cxt_pincfg_tbl);
break;
}
@@ -4429,7 +4556,7 @@ static int patch_conexant_auto(struct hda_codec *codec)
spec->capture_stream = &cx_auto_pcm_analog_capture;
codec->patch_ops = cx_auto_patch_ops;
if (spec->beep_amp)
- snd_hda_attach_beep_device(codec, spec->beep_amp);
+ snd_hda_attach_beep_device(codec, get_amp_nid_(spec->beep_amp));
return 0;
}
@@ -4471,6 +4598,28 @@ static const struct hda_codec_preset snd_hda_preset_conexant[] = {
.patch = patch_conexant_auto },
{ .id = 0x14f150b9, .name = "CX20665",
.patch = patch_conexant_auto },
+ { .id = 0x14f150f1, .name = "CX20721",
+ .patch = patch_conexant_auto },
+ { .id = 0x14f150f2, .name = "CX20722",
+ .patch = patch_conexant_auto },
+ { .id = 0x14f150f3, .name = "CX20723",
+ .patch = patch_conexant_auto },
+ { .id = 0x14f150f4, .name = "CX20724",
+ .patch = patch_conexant_auto },
+ { .id = 0x14f1510f, .name = "CX20751/2",
+ .patch = patch_conexant_auto },
+ { .id = 0x14f15110, .name = "CX20751/2",
+ .patch = patch_conexant_auto },
+ { .id = 0x14f15111, .name = "CX20753/4",
+ .patch = patch_conexant_auto },
+ { .id = 0x14f15113, .name = "CX20755",
+ .patch = patch_conexant_auto },
+ { .id = 0x14f15114, .name = "CX20756",
+ .patch = patch_conexant_auto },
+ { .id = 0x14f15115, .name = "CX20757",
+ .patch = patch_conexant_auto },
+ { .id = 0x14f151d7, .name = "CX20952",
+ .patch = patch_conexant_auto },
{} /* terminator */
};
@@ -4491,6 +4640,17 @@ MODULE_ALIAS("snd-hda-codec-id:14f150ab");
MODULE_ALIAS("snd-hda-codec-id:14f150ac");
MODULE_ALIAS("snd-hda-codec-id:14f150b8");
MODULE_ALIAS("snd-hda-codec-id:14f150b9");
+MODULE_ALIAS("snd-hda-codec-id:14f150f1");
+MODULE_ALIAS("snd-hda-codec-id:14f150f2");
+MODULE_ALIAS("snd-hda-codec-id:14f150f3");
+MODULE_ALIAS("snd-hda-codec-id:14f150f4");
+MODULE_ALIAS("snd-hda-codec-id:14f1510f");
+MODULE_ALIAS("snd-hda-codec-id:14f15110");
+MODULE_ALIAS("snd-hda-codec-id:14f15111");
+MODULE_ALIAS("snd-hda-codec-id:14f15113");
+MODULE_ALIAS("snd-hda-codec-id:14f15114");
+MODULE_ALIAS("snd-hda-codec-id:14f15115");
+MODULE_ALIAS("snd-hda-codec-id:14f151d7");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Conexant HD-audio codec");
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index bd0ae69..05f097a 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -31,7 +31,7 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/slab.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/jack.h>
#include "hda_codec.h"
@@ -43,7 +43,7 @@ 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
+ * could support N independent pipes, each of them can be connected to one or
* more ports (DVI, HDMI or DisplayPort).
*
* The HDA correspondence of pipes/ports are converter/pin nodes.
@@ -51,30 +51,37 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
#define MAX_HDMI_CVTS 4
#define MAX_HDMI_PINS 4
-struct hdmi_spec {
- int num_cvts;
- int num_pins;
- hda_nid_t cvt[MAX_HDMI_CVTS+1]; /* audio sources */
- hda_nid_t pin[MAX_HDMI_PINS+1]; /* audio sinks */
+struct hdmi_spec_per_cvt {
+ hda_nid_t cvt_nid;
+ int assigned;
+ unsigned int channels_min;
+ unsigned int channels_max;
+ u32 rates;
+ u64 formats;
+ unsigned int maxbps;
+};
- /*
- * source connection for each pin
- */
- hda_nid_t pin_cvt[MAX_HDMI_PINS+1];
+struct hdmi_spec_per_pin {
+ hda_nid_t pin_nid;
+ int num_mux_nids;
+ hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
- /*
- * HDMI sink attached to each pin
- */
- struct hdmi_eld sink_eld[MAX_HDMI_PINS];
+ struct hda_codec *codec;
+ struct hdmi_eld sink_eld;
+ struct delayed_work work;
+ int repoll_count;
+};
- /*
- * export one pcm per pipe
- */
- struct hda_pcm pcm_rec[MAX_HDMI_CVTS];
- struct hda_pcm_stream codec_pcm_pars[MAX_HDMI_CVTS];
+struct hdmi_spec {
+ int num_cvts;
+ struct hdmi_spec_per_cvt cvts[MAX_HDMI_CVTS];
+
+ int num_pins;
+ struct hdmi_spec_per_pin pins[MAX_HDMI_PINS];
+ struct hda_pcm pcm_rec[MAX_HDMI_PINS];
/*
- * ati/nvhdmi specific
+ * Non-generic ATI/NVIDIA specific
*/
struct hda_multi_out multiout;
const struct hda_pcm_stream *pcm_playback;
@@ -284,18 +291,103 @@ static struct cea_channel_speaker_allocation channel_allocations[] = {
* HDMI routines
*/
-static int hda_node_index(hda_nid_t *nids, hda_nid_t nid)
+static int pin_nid_to_pin_index(struct hdmi_spec *spec, hda_nid_t pin_nid)
{
- int i;
+ int pin_idx;
- for (i = 0; nids[i]; i++)
- if (nids[i] == nid)
- return i;
+ for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++)
+ if (spec->pins[pin_idx].pin_nid == pin_nid)
+ return pin_idx;
- snd_printk(KERN_WARNING "HDMI: nid %d not registered\n", nid);
+ snd_printk(KERN_WARNING "HDMI: pin nid %d not registered\n", pin_nid);
return -EINVAL;
}
+static int hinfo_to_pin_index(struct hdmi_spec *spec,
+ struct hda_pcm_stream *hinfo)
+{
+ int pin_idx;
+
+ for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++)
+ if (&spec->pcm_rec[pin_idx].stream[0] == hinfo)
+ return pin_idx;
+
+ snd_printk(KERN_WARNING "HDMI: hinfo %p not registered\n", hinfo);
+ return -EINVAL;
+}
+
+static int cvt_nid_to_cvt_index(struct hdmi_spec *spec, hda_nid_t cvt_nid)
+{
+ int cvt_idx;
+
+ for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++)
+ if (spec->cvts[cvt_idx].cvt_nid == cvt_nid)
+ return cvt_idx;
+
+ snd_printk(KERN_WARNING "HDMI: cvt nid %d not registered\n", cvt_nid);
+ return -EINVAL;
+}
+
+static int hdmi_eld_ctl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct hdmi_spec *spec;
+ int pin_idx;
+
+ spec = codec->spec;
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+
+ pin_idx = kcontrol->private_value;
+ uinfo->count = spec->pins[pin_idx].sink_eld.eld_size;
+
+ return 0;
+}
+
+static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct hdmi_spec *spec;
+ int pin_idx;
+
+ spec = codec->spec;
+ pin_idx = kcontrol->private_value;
+
+ memcpy(ucontrol->value.bytes.data,
+ spec->pins[pin_idx].sink_eld.eld_buffer, ELD_MAX_SIZE);
+
+ return 0;
+}
+
+static struct snd_kcontrol_new eld_bytes_ctl = {
+ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "ELD",
+ .info = hdmi_eld_ctl_info,
+ .get = hdmi_eld_ctl_get,
+};
+
+static int hdmi_create_eld_ctl(struct hda_codec *codec, int pin_idx,
+ int device)
+{
+ struct snd_kcontrol *kctl;
+ struct hdmi_spec *spec = codec->spec;
+ int err;
+
+ kctl = snd_ctl_new1(&eld_bytes_ctl, codec);
+ if (!kctl)
+ return -ENOMEM;
+ kctl->private_value = pin_idx;
+ kctl->id.device = device;
+
+ err = snd_hda_ctl_add(codec, spec->pins[pin_idx].pin_nid, kctl);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
#ifdef BE_PARANOID
static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t pin_nid,
int *packet_index, int *byte_index)
@@ -326,28 +418,30 @@ static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t pin_nid,
snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val);
}
-static void hdmi_enable_output(struct hda_codec *codec, hda_nid_t pin_nid)
+static void hdmi_init_pin(struct hda_codec *codec, hda_nid_t pin_nid)
{
/* Unmute */
if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP)
snd_hda_codec_write(codec, pin_nid, 0,
AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
- /* Enable pin out */
+ /* Enable pin out: some machines with GM965 gets broken output when
+ * the pin is disabled or changed while using with HDMI
+ */
snd_hda_codec_write(codec, pin_nid, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
}
-static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t nid)
+static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t cvt_nid)
{
- return 1 + snd_hda_codec_read(codec, nid, 0,
+ return 1 + snd_hda_codec_read(codec, cvt_nid, 0,
AC_VERB_GET_CVT_CHAN_COUNT, 0);
}
static void hdmi_set_channel_count(struct hda_codec *codec,
- hda_nid_t nid, int chs)
+ hda_nid_t cvt_nid, int chs)
{
- if (chs != hdmi_get_channel_count(codec, nid))
- snd_hda_codec_write(codec, nid, 0,
+ if (chs != hdmi_get_channel_count(codec, cvt_nid))
+ snd_hda_codec_write(codec, cvt_nid, 0,
AC_VERB_SET_CVT_CHAN_COUNT, chs - 1);
}
@@ -384,11 +478,8 @@ static void init_channel_allocations(void)
*
* TODO: it could select the wrong CA from multiple candidates.
*/
-static int hdmi_channel_allocation(struct hda_codec *codec, hda_nid_t nid,
- int channels)
+static int hdmi_channel_allocation(struct hdmi_eld *eld, int channels)
{
- struct hdmi_spec *spec = codec->spec;
- struct hdmi_eld *eld;
int i;
int ca = 0;
int spk_mask = 0;
@@ -400,19 +491,6 @@ static int hdmi_channel_allocation(struct hda_codec *codec, hda_nid_t nid,
if (channels <= 2)
return 0;
- i = hda_node_index(spec->pin_cvt, nid);
- if (i < 0)
- return 0;
- eld = &spec->sink_eld[i];
-
- /*
- * HDMI sink's ELD info cannot always be retrieved for now, e.g.
- * in console or for audio devices. Assume the highest speakers
- * configuration, to _not_ prohibit multi-channel audio playback.
- */
- if (!eld->spk_alloc)
- eld->spk_alloc = 0xffff;
-
/*
* expand ELD's speaker allocation mask
*
@@ -434,6 +512,17 @@ static int hdmi_channel_allocation(struct hda_codec *codec, hda_nid_t nid,
}
}
+ if (!ca) {
+ /* if there was no match, select the regular ALSA channel
+ * allocation with the matching number of channels */
+ for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
+ if (channels == channel_allocations[i].channels) {
+ ca = channel_allocations[i].ca_index;
+ break;
+ }
+ }
+ }
+
snd_print_channel_allocation(eld->spk_alloc, buf, sizeof(buf));
snd_printdd("HDMI: select CA 0x%x for %d-channel allocation: %s\n",
ca, channels, buf);
@@ -608,67 +697,63 @@ static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid,
return true;
}
-static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
+static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,
struct snd_pcm_substream *substream)
{
struct hdmi_spec *spec = codec->spec;
- hda_nid_t pin_nid;
+ struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+ hda_nid_t pin_nid = per_pin->pin_nid;
int channels = substream->runtime->channels;
+ struct hdmi_eld *eld;
int ca;
- int i;
union audio_infoframe ai;
- ca = hdmi_channel_allocation(codec, nid, channels);
-
- for (i = 0; i < spec->num_pins; i++) {
- if (spec->pin_cvt[i] != nid)
- continue;
- if (!spec->sink_eld[i].monitor_present)
- continue;
+ eld = &spec->pins[pin_idx].sink_eld;
+ if (!eld->monitor_present)
+ return;
- pin_nid = spec->pin[i];
-
- memset(&ai, 0, sizeof(ai));
- if (spec->sink_eld[i].conn_type == 0) { /* HDMI */
- struct hdmi_audio_infoframe *hdmi_ai = &ai.hdmi;
-
- hdmi_ai->type = 0x84;
- 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 = &ai.dp;
-
- dp_ai->type = 0x84;
- 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);
- continue;
- }
+ ca = hdmi_channel_allocation(eld, channels);
+
+ memset(&ai, 0, sizeof(ai));
+ if (eld->conn_type == 0) { /* HDMI */
+ struct hdmi_audio_infoframe *hdmi_ai = &ai.hdmi;
+
+ hdmi_ai->type = 0x84;
+ 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 (eld->conn_type == 1) { /* DisplayPort */
+ struct dp_audio_infoframe *dp_ai = &ai.dp;
+
+ dp_ai->type = 0x84;
+ 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);
+ return;
+ }
- /*
- * sizeof(ai) is used instead of sizeof(*hdmi_ai) or
- * sizeof(*dp_ai) to avoid partial match/update problems when
- * the user switches between HDMI/DP monitors.
- */
- if (!hdmi_infoframe_uptodate(codec, pin_nid, ai.bytes,
- sizeof(ai))) {
- snd_printdd("hdmi_setup_audio_infoframe: "
- "cvt=%d pin=%d channels=%d\n",
- nid, pin_nid,
- channels);
- hdmi_setup_channel_mapping(codec, pin_nid, ca);
- hdmi_stop_infoframe_trans(codec, pin_nid);
- hdmi_fill_audio_infoframe(codec, pin_nid,
- ai.bytes, sizeof(ai));
- hdmi_start_infoframe_trans(codec, pin_nid);
- }
+ /*
+ * sizeof(ai) is used instead of sizeof(*hdmi_ai) or
+ * sizeof(*dp_ai) to avoid partial match/update problems when
+ * the user switches between HDMI/DP monitors.
+ */
+ if (!hdmi_infoframe_uptodate(codec, pin_nid, ai.bytes,
+ sizeof(ai))) {
+ snd_printdd("hdmi_setup_audio_infoframe: "
+ "pin=%d channels=%d\n",
+ pin_nid,
+ channels);
+ hdmi_setup_channel_mapping(codec, pin_nid, ca);
+ hdmi_stop_infoframe_trans(codec, pin_nid);
+ hdmi_fill_audio_infoframe(codec, pin_nid,
+ ai.bytes, sizeof(ai));
+ hdmi_start_infoframe_trans(codec, pin_nid);
}
}
@@ -677,8 +762,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
* Unsolicited events
*/
-static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid,
- struct hdmi_eld *eld);
+static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll);
static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
{
@@ -686,17 +770,17 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
int pin_nid = res >> AC_UNSOL_RES_TAG_SHIFT;
int pd = !!(res & AC_UNSOL_RES_PD);
int eldv = !!(res & AC_UNSOL_RES_ELDV);
- int index;
+ int pin_idx;
printk(KERN_INFO
- "HDMI hot plug event: Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
- pin_nid, pd, eldv);
+ "HDMI hot plug event: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
+ codec->addr, pin_nid, pd, eldv);
- index = hda_node_index(spec->pin, pin_nid);
- if (index < 0)
+ pin_idx = pin_nid_to_pin_index(spec, pin_nid);
+ if (pin_idx < 0)
return;
- hdmi_present_sense(codec, pin_nid, &spec->sink_eld[index]);
+ hdmi_present_sense(&spec->pins[pin_idx], 1);
}
static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
@@ -707,7 +791,8 @@ static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
int cp_ready = !!(res & AC_UNSOL_RES_CP_READY);
printk(KERN_INFO
- "HDMI CP event: PIN=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n",
+ "HDMI CP event: CODEC=%d PIN=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n",
+ codec->addr,
tag,
subtag,
cp_state,
@@ -727,7 +812,7 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
- if (hda_node_index(spec->pin, tag) < 0) {
+ if (pin_nid_to_pin_index(spec, tag) < 0) {
snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag);
return;
}
@@ -746,21 +831,14 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
#define is_hbr_format(format) \
((format & AC_FMT_TYPE_NON_PCM) && (format & AC_FMT_CHAN_MASK) == 7)
-static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid,
- u32 stream_tag, int format)
+static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
+ hda_nid_t pin_nid, u32 stream_tag, int format)
{
- struct hdmi_spec *spec = codec->spec;
int pinctl;
int new_pinctl = 0;
- int i;
-
- for (i = 0; i < spec->num_pins; i++) {
- if (spec->pin_cvt[i] != nid)
- continue;
- if (!(snd_hda_query_pin_caps(codec, spec->pin[i]) & AC_PINCAP_HBR))
- continue;
- pinctl = snd_hda_codec_read(codec, spec->pin[i], 0,
+ if (snd_hda_query_pin_caps(codec, pin_nid) & AC_PINCAP_HBR) {
+ pinctl = snd_hda_codec_read(codec, pin_nid, 0,
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
new_pinctl = pinctl & ~AC_PINCTL_EPT;
@@ -771,22 +849,22 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid,
snd_printdd("hdmi_setup_stream: "
"NID=0x%x, %spinctl=0x%x\n",
- spec->pin[i],
+ pin_nid,
pinctl == new_pinctl ? "" : "new-",
new_pinctl);
if (pinctl != new_pinctl)
- snd_hda_codec_write(codec, spec->pin[i], 0,
+ snd_hda_codec_write(codec, pin_nid, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL,
new_pinctl);
- }
+ }
if (is_hbr_format(format) && !new_pinctl) {
snd_printdd("hdmi_setup_stream: HBR is not supported\n");
return -EINVAL;
}
- snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
+ snd_hda_codec_setup_stream(codec, cvt_nid, stream_tag, 0, format);
return 0;
}
@@ -798,37 +876,68 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
struct snd_pcm_substream *substream)
{
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;
+ int pin_idx, cvt_idx, mux_idx = 0;
+ struct hdmi_spec_per_pin *per_pin;
+ struct hdmi_eld *eld;
+ struct hdmi_spec_per_cvt *per_cvt = NULL;
- for (idx = 0; idx < spec->num_cvts; idx++)
- if (hinfo->nid == spec->cvt[idx])
- break;
- if (snd_BUG_ON(idx >= spec->num_cvts) ||
- snd_BUG_ON(idx >= spec->num_pins))
+ /* Validate hinfo */
+ pin_idx = hinfo_to_pin_index(spec, hinfo);
+ if (snd_BUG_ON(pin_idx < 0))
return -EINVAL;
+ per_pin = &spec->pins[pin_idx];
+ eld = &per_pin->sink_eld;
- /* save the PCM info the codec provides */
- codec_pars = &spec->codec_pcm_pars[idx];
- if (!codec_pars->rates)
- *codec_pars = *hinfo;
+ /* Dynamically assign converter to stream */
+ for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
+ per_cvt = &spec->cvts[cvt_idx];
- eld = &spec->sink_eld[idx];
- if (!static_hdmi_pcm && eld->eld_valid && eld->sad_count > 0) {
- hdmi_eld_update_pcm_info(eld, hinfo, codec_pars);
+ /* Must not already be assigned */
+ if (per_cvt->assigned)
+ continue;
+ /* Must be in pin's mux's list of converters */
+ for (mux_idx = 0; mux_idx < per_pin->num_mux_nids; mux_idx++)
+ if (per_pin->mux_nids[mux_idx] == per_cvt->cvt_nid)
+ break;
+ /* Not in mux list */
+ if (mux_idx == per_pin->num_mux_nids)
+ continue;
+ break;
+ }
+ /* No free converters */
+ if (cvt_idx == spec->num_cvts)
+ return -ENODEV;
+
+ /* Claim converter */
+ per_cvt->assigned = 1;
+ hinfo->nid = per_cvt->cvt_nid;
+
+ snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
+ AC_VERB_SET_CONNECT_SEL,
+ mux_idx);
+ snd_hda_spdif_ctls_assign(codec, pin_idx, per_cvt->cvt_nid);
+
+ /* Initially set the converter's capabilities */
+ hinfo->channels_min = per_cvt->channels_min;
+ hinfo->channels_max = per_cvt->channels_max;
+ hinfo->rates = per_cvt->rates;
+ hinfo->formats = per_cvt->formats;
+ hinfo->maxbps = per_cvt->maxbps;
+
+ /* Restrict capabilities by ELD if this isn't disabled */
+ if (!static_hdmi_pcm && eld->eld_valid) {
+ snd_hdmi_eld_update_pcm_info(eld, hinfo);
if (hinfo->channels_min > hinfo->channels_max ||
- !hinfo->rates || !hinfo->formats)
+ !hinfo->rates || !hinfo->formats) {
+ per_cvt->assigned = 0;
+ hinfo->nid = 0;
+ snd_hda_spdif_ctls_unassign(codec, pin_idx);
return -ENODEV;
- } else {
- /* fallback to the codec default */
- hinfo->channels_max = codec_pars->channels_max;
- hinfo->rates = codec_pars->rates;
- hinfo->formats = codec_pars->formats;
- hinfo->maxbps = codec_pars->maxbps;
+ }
}
- /* store the updated parameters */
+
+ /* Store the updated parameters */
runtime->hw.channels_min = hinfo->channels_min;
runtime->hw.channels_max = hinfo->channels_max;
runtime->hw.formats = hinfo->formats;
@@ -842,12 +951,11 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
/*
* HDA/HDMI auto parsing
*/
-static int hdmi_read_pin_conn(struct hda_codec *codec, hda_nid_t pin_nid)
+static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx)
{
struct hdmi_spec *spec = codec->spec;
- hda_nid_t conn_list[HDA_MAX_CONNECTIONS];
- int conn_len, curr;
- int index;
+ struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+ hda_nid_t pin_nid = per_pin->pin_nid;
if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) {
snd_printk(KERN_WARNING
@@ -857,26 +965,18 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, hda_nid_t pin_nid)
return -EINVAL;
}
- conn_len = snd_hda_get_connections(codec, pin_nid, conn_list,
- HDA_MAX_CONNECTIONS);
- if (conn_len > 1)
- curr = snd_hda_codec_read(codec, pin_nid, 0,
- AC_VERB_GET_CONNECT_SEL, 0);
- else
- curr = 0;
-
- index = hda_node_index(spec->pin, pin_nid);
- if (index < 0)
- return -EINVAL;
-
- spec->pin_cvt[index] = conn_list[curr];
+ per_pin->num_mux_nids = snd_hda_get_connections(codec, pin_nid,
+ per_pin->mux_nids,
+ HDA_MAX_CONNECTIONS);
return 0;
}
-static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid,
- struct hdmi_eld *eld)
+static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
{
+ struct hda_codec *codec = per_pin->codec;
+ struct hdmi_eld *eld = &per_pin->sink_eld;
+ hda_nid_t pin_nid = per_pin->pin_nid;
/*
* Always execute a GetPinSense verb here, even when called from
* hdmi_intrinsic_event; for some NVIDIA HW, the unsolicited
@@ -886,70 +986,106 @@ static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid,
* the unsolicited response to avoid custom WARs.
*/
int present = snd_hda_pin_sense(codec, pin_nid);
+ bool eld_valid = false;
- memset(eld, 0, sizeof(*eld));
+ memset(eld, 0, offsetof(struct hdmi_eld, eld_buffer));
eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE);
if (eld->monitor_present)
- eld->eld_valid = !!(present & AC_PINSENSE_ELDV);
- else
- eld->eld_valid = 0;
+ eld_valid = !!(present & AC_PINSENSE_ELDV);
printk(KERN_INFO
- "HDMI status: Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
- pin_nid, eld->monitor_present, eld->eld_valid);
+ "HDMI status: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
+ codec->addr, pin_nid, eld->monitor_present, eld_valid);
- if (eld->eld_valid)
+ eld->eld_valid = false;
+ if (eld_valid) {
if (!snd_hdmi_get_eld(eld, codec, pin_nid))
snd_hdmi_show_eld(eld);
+ else if (repoll) {
+ queue_delayed_work(codec->bus->workq,
+ &per_pin->work,
+ msecs_to_jiffies(300));
+ }
+ }
snd_hda_input_jack_report(codec, pin_nid);
}
+static void hdmi_repoll_eld(struct work_struct *work)
+{
+ struct hdmi_spec_per_pin *per_pin =
+ container_of(to_delayed_work(work), struct hdmi_spec_per_pin, work);
+
+ if (per_pin->repoll_count++ > 6)
+ per_pin->repoll_count = 0;
+
+ hdmi_present_sense(per_pin, per_pin->repoll_count);
+}
+
static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
{
struct hdmi_spec *spec = codec->spec;
+ unsigned int caps, config;
+ int pin_idx;
+ struct hdmi_spec_per_pin *per_pin;
int err;
- if (spec->num_pins >= MAX_HDMI_PINS) {
- snd_printk(KERN_WARNING
- "HDMI: no space for pin %d\n", pin_nid);
+ caps = snd_hda_param_read(codec, pin_nid, AC_PAR_PIN_CAP);
+ if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP)))
+ return 0;
+
+ config = snd_hda_codec_read(codec, pin_nid, 0,
+ AC_VERB_GET_CONFIG_DEFAULT, 0);
+ if (get_defcfg_connect(config) == AC_JACK_PORT_NONE)
+ return 0;
+
+ if (snd_BUG_ON(spec->num_pins >= MAX_HDMI_PINS))
return -E2BIG;
- }
- err = snd_hda_input_jack_add(codec, pin_nid,
- SND_JACK_VIDEOOUT, NULL);
+ pin_idx = spec->num_pins;
+ per_pin = &spec->pins[pin_idx];
+
+ per_pin->pin_nid = pin_nid;
+
+ err = hdmi_read_pin_conn(codec, pin_idx);
if (err < 0)
return err;
- hdmi_present_sense(codec, pin_nid, &spec->sink_eld[spec->num_pins]);
-
- spec->pin[spec->num_pins] = pin_nid;
spec->num_pins++;
- return hdmi_read_pin_conn(codec, pin_nid);
+ return 0;
}
-static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t nid)
+static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
{
- int i, found_pin = 0;
struct hdmi_spec *spec = codec->spec;
-
- 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;
- }
+ int cvt_idx;
+ struct hdmi_spec_per_cvt *per_cvt;
+ unsigned int chans;
+ int err;
if (snd_BUG_ON(spec->num_cvts >= MAX_HDMI_CVTS))
return -E2BIG;
- spec->cvt[spec->num_cvts] = nid;
+ chans = get_wcaps(codec, cvt_nid);
+ chans = get_wcaps_channels(chans);
+
+ cvt_idx = spec->num_cvts;
+ per_cvt = &spec->cvts[cvt_idx];
+
+ per_cvt->cvt_nid = cvt_nid;
+ per_cvt->channels_min = 2;
+ if (chans <= 16)
+ per_cvt->channels_max = chans;
+
+ err = snd_hda_query_supported_pcm(codec, cvt_nid,
+ &per_cvt->rates,
+ &per_cvt->formats,
+ &per_cvt->maxbps);
+ if (err < 0)
+ return err;
+
spec->num_cvts++;
return 0;
@@ -959,8 +1095,6 @@ 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) {
@@ -971,7 +1105,6 @@ 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);
@@ -981,32 +1114,14 @@ static int hdmi_parse_codec(struct hda_codec *codec)
switch (type) {
case AC_WID_AUD_OUT:
- 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++;
+ hdmi_add_cvt(codec, nid);
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
@@ -1023,7 +1138,7 @@ static int hdmi_parse_codec(struct hda_codec *codec)
/*
*/
-static char *generic_hdmi_pcm_names[MAX_HDMI_CVTS] = {
+static char *generic_hdmi_pcm_names[MAX_HDMI_PINS] = {
"HDMI 0",
"HDMI 1",
"HDMI 2",
@@ -1040,51 +1155,97 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
unsigned int format,
struct snd_pcm_substream *substream)
{
- hdmi_set_channel_count(codec, hinfo->nid,
- substream->runtime->channels);
+ hda_nid_t cvt_nid = hinfo->nid;
+ struct hdmi_spec *spec = codec->spec;
+ int pin_idx = hinfo_to_pin_index(spec, hinfo);
+ hda_nid_t pin_nid = spec->pins[pin_idx].pin_nid;
+
+ hdmi_set_channel_count(codec, cvt_nid, substream->runtime->channels);
- hdmi_setup_audio_infoframe(codec, hinfo->nid, substream);
+ hdmi_setup_audio_infoframe(codec, pin_idx, substream);
- return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
+ return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format);
}
-static const struct hda_pcm_stream generic_hdmi_pcm_playback = {
- .substreams = 1,
- .channels_min = 2,
- .ops = {
- .open = hdmi_pcm_open,
- .prepare = generic_hdmi_playback_pcm_prepare,
- },
+static int generic_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct hdmi_spec *spec = codec->spec;
+ int cvt_idx, pin_idx;
+ struct hdmi_spec_per_cvt *per_cvt;
+ struct hdmi_spec_per_pin *per_pin;
+
+ snd_hda_codec_cleanup_stream(codec, hinfo->nid);
+
+ if (hinfo->nid) {
+ cvt_idx = cvt_nid_to_cvt_index(spec, hinfo->nid);
+ if (snd_BUG_ON(cvt_idx < 0))
+ return -EINVAL;
+ per_cvt = &spec->cvts[cvt_idx];
+
+ snd_BUG_ON(!per_cvt->assigned);
+ per_cvt->assigned = 0;
+ hinfo->nid = 0;
+
+ pin_idx = hinfo_to_pin_index(spec, hinfo);
+ if (snd_BUG_ON(pin_idx < 0))
+ return -EINVAL;
+ per_pin = &spec->pins[pin_idx];
+
+ snd_hda_spdif_ctls_unassign(codec, pin_idx);
+ }
+
+ return 0;
+}
+
+static const struct hda_pcm_ops generic_ops = {
+ .open = hdmi_pcm_open,
+ .prepare = generic_hdmi_playback_pcm_prepare,
+ .cleanup = generic_hdmi_playback_pcm_cleanup,
};
static int generic_hdmi_build_pcms(struct hda_codec *codec)
{
struct hdmi_spec *spec = codec->spec;
- struct hda_pcm *info = spec->pcm_rec;
- int i;
-
- codec->num_pcms = spec->num_cvts;
- codec->pcm_info = info;
+ int pin_idx;
- for (i = 0; i < codec->num_pcms; i++, info++) {
- unsigned int chans;
+ for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+ struct hda_pcm *info;
struct hda_pcm_stream *pstr;
- chans = get_wcaps(codec, spec->cvt[i]);
- chans = get_wcaps_channels(chans);
-
- info->name = generic_hdmi_pcm_names[i];
+ info = &spec->pcm_rec[pin_idx];
+ info->name = generic_hdmi_pcm_names[pin_idx];
info->pcm_type = HDA_PCM_TYPE_HDMI;
+
pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
- if (spec->pcm_playback)
- *pstr = *spec->pcm_playback;
- else
- *pstr = generic_hdmi_pcm_playback;
- pstr->nid = spec->cvt[i];
- if (pstr->channels_max <= 2 && chans && chans <= 16)
- pstr->channels_max = chans;
+ pstr->substreams = 1;
+ pstr->ops = generic_ops;
+ /* other pstr fields are set in open */
}
+ codec->num_pcms = spec->num_pins;
+ codec->pcm_info = spec->pcm_rec;
+
+ return 0;
+}
+
+static int generic_hdmi_build_jack(struct hda_codec *codec, int pin_idx)
+{
+ int err;
+ char hdmi_str[32];
+ struct hdmi_spec *spec = codec->spec;
+ struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+ int pcmdev = spec->pcm_rec[pin_idx].device;
+
+ snprintf(hdmi_str, sizeof(hdmi_str), "HDMI/DP,pcm=%d", pcmdev);
+
+ err = snd_hda_input_jack_add(codec, per_pin->pin_nid,
+ SND_JACK_VIDEOOUT, pcmdev > 0 ? hdmi_str : NULL);
+ if (err < 0)
+ return err;
+
+ hdmi_present_sense(per_pin, 0);
return 0;
}
@@ -1092,10 +1253,27 @@ static int generic_hdmi_build_controls(struct hda_codec *codec)
{
struct hdmi_spec *spec = codec->spec;
int err;
- int i;
+ int pin_idx;
+
+ for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+ struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+
+ err = generic_hdmi_build_jack(codec, pin_idx);
+ if (err < 0)
+ return err;
+
+ err = snd_hda_create_spdif_out_ctls(codec,
+ per_pin->pin_nid,
+ per_pin->mux_nids[0]);
+ if (err < 0)
+ return err;
+ snd_hda_spdif_ctls_unassign(codec, pin_idx);
+
+ /* add control for ELD Bytes */
+ err = hdmi_create_eld_ctl(codec,
+ pin_idx,
+ spec->pcm_rec[pin_idx].device);
- for (i = 0; i < codec->num_pcms; i++) {
- err = snd_hda_create_spdif_out_ctls(codec, spec->cvt[i]);
if (err < 0)
return err;
}
@@ -1106,13 +1284,21 @@ static int generic_hdmi_build_controls(struct hda_codec *codec)
static int generic_hdmi_init(struct hda_codec *codec)
{
struct hdmi_spec *spec = codec->spec;
- int i;
+ int pin_idx;
+
+ for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+ struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+ hda_nid_t pin_nid = per_pin->pin_nid;
+ struct hdmi_eld *eld = &per_pin->sink_eld;
- for (i = 0; spec->pin[i]; i++) {
- hdmi_enable_output(codec, spec->pin[i]);
- snd_hda_codec_write(codec, spec->pin[i], 0,
+ hdmi_init_pin(codec, pin_nid);
+ snd_hda_codec_write(codec, pin_nid, 0,
AC_VERB_SET_UNSOLICITED_ENABLE,
- AC_USRSP_EN | spec->pin[i]);
+ AC_USRSP_EN | pin_nid);
+
+ per_pin->codec = codec;
+ INIT_DELAYED_WORK(&per_pin->work, hdmi_repoll_eld);
+ snd_hda_eld_proc_new(codec, eld, pin_idx);
}
return 0;
}
@@ -1120,12 +1306,18 @@ static int generic_hdmi_init(struct hda_codec *codec)
static void generic_hdmi_free(struct hda_codec *codec)
{
struct hdmi_spec *spec = codec->spec;
- int i;
+ int pin_idx;
+
+ for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+ struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+ struct hdmi_eld *eld = &per_pin->sink_eld;
- for (i = 0; i < spec->num_pins; i++)
- snd_hda_eld_proc_free(codec, &spec->sink_eld[i]);
+ cancel_delayed_work(&per_pin->work);
+ snd_hda_eld_proc_free(codec, eld);
+ }
snd_hda_input_jack_free(codec);
+ flush_workqueue(codec->bus->workq);
kfree(spec);
}
@@ -1140,7 +1332,6 @@ static const struct hda_codec_ops generic_hdmi_patch_ops = {
static int patch_generic_hdmi(struct hda_codec *codec)
{
struct hdmi_spec *spec;
- int i;
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (spec == NULL)
@@ -1154,15 +1345,69 @@ static int patch_generic_hdmi(struct hda_codec *codec)
}
codec->patch_ops = generic_hdmi_patch_ops;
- for (i = 0; i < spec->num_pins; i++)
- snd_hda_eld_proc_new(codec, &spec->sink_eld[i], i);
-
init_channel_allocations();
return 0;
}
/*
+ * Shared non-generic implementations
+ */
+
+static int simple_playback_build_pcms(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+ struct hda_pcm *info = spec->pcm_rec;
+ int i;
+
+ codec->num_pcms = spec->num_cvts;
+ codec->pcm_info = info;
+
+ for (i = 0; i < codec->num_pcms; i++, info++) {
+ unsigned int chans;
+ struct hda_pcm_stream *pstr;
+
+ chans = get_wcaps(codec, spec->cvts[i].cvt_nid);
+ chans = get_wcaps_channels(chans);
+
+ info->name = generic_hdmi_pcm_names[i];
+ info->pcm_type = HDA_PCM_TYPE_HDMI;
+ pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
+ snd_BUG_ON(!spec->pcm_playback);
+ *pstr = *spec->pcm_playback;
+ pstr->nid = spec->cvts[i].cvt_nid;
+ if (pstr->channels_max <= 2 && chans && chans <= 16)
+ pstr->channels_max = chans;
+ }
+
+ return 0;
+}
+
+static int simple_playback_build_controls(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+ int err;
+ int i;
+
+ for (i = 0; i < codec->num_pcms; i++) {
+ err = snd_hda_create_spdif_out_ctls(codec,
+ spec->cvts[i].cvt_nid,
+ spec->cvts[i].cvt_nid);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static void simple_playback_free(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec = codec->spec;
+
+ kfree(spec);
+}
+
+/*
* Nvidia specific implementations
*/
@@ -1350,23 +1595,25 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo,
struct snd_pcm_substream *substream)
{
int chs;
- unsigned int dataDCC1, dataDCC2, channel_id;
+ unsigned int dataDCC2, channel_id;
int i;
+ struct hdmi_spec *spec = codec->spec;
+ struct hda_spdif_out *spdif =
+ snd_hda_spdif_out_of_nid(codec, spec->cvts[0].cvt_nid);
mutex_lock(&codec->spdif_mutex);
chs = substream->runtime->channels;
- dataDCC1 = AC_DIG1_ENABLE | AC_DIG1_COPYRIGHT;
dataDCC2 = 0x2;
/* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
- if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
+ if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE))
snd_hda_codec_write(codec,
nvhdmi_master_con_nid_7x,
0,
AC_VERB_SET_DIGI_CONVERT_1,
- codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
+ spdif->ctls & ~AC_DIG1_ENABLE & 0xff);
/* set the stream id */
snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
@@ -1378,12 +1625,12 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo,
/* turn on again (if needed) */
/* enable and set the channel status audio/data flag */
- if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) {
+ if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE)) {
snd_hda_codec_write(codec,
nvhdmi_master_con_nid_7x,
0,
AC_VERB_SET_DIGI_CONVERT_1,
- codec->spdif_ctls & 0xff);
+ spdif->ctls & 0xff);
snd_hda_codec_write(codec,
nvhdmi_master_con_nid_7x,
0,
@@ -1400,12 +1647,12 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo,
*otherwise the IEC958 bits won't be updated
*/
if (codec->spdif_status_reset &&
- (codec->spdif_ctls & AC_DIG1_ENABLE))
+ (spdif->ctls & AC_DIG1_ENABLE))
snd_hda_codec_write(codec,
nvhdmi_con_nids_7x[i],
0,
AC_VERB_SET_DIGI_CONVERT_1,
- codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
+ spdif->ctls & ~AC_DIG1_ENABLE & 0xff);
/* set the stream id */
snd_hda_codec_write(codec,
nvhdmi_con_nids_7x[i],
@@ -1421,12 +1668,12 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo,
/* turn on again (if needed) */
/* enable and set the channel status audio/data flag */
if (codec->spdif_status_reset &&
- (codec->spdif_ctls & AC_DIG1_ENABLE)) {
+ (spdif->ctls & AC_DIG1_ENABLE)) {
snd_hda_codec_write(codec,
nvhdmi_con_nids_7x[i],
0,
AC_VERB_SET_DIGI_CONVERT_1,
- codec->spdif_ctls & 0xff);
+ spdif->ctls & 0xff);
snd_hda_codec_write(codec,
nvhdmi_con_nids_7x[i],
0,
@@ -1471,17 +1718,17 @@ static const struct hda_pcm_stream nvhdmi_pcm_playback_2ch = {
};
static const struct hda_codec_ops nvhdmi_patch_ops_8ch_7x = {
- .build_controls = generic_hdmi_build_controls,
- .build_pcms = generic_hdmi_build_pcms,
+ .build_controls = simple_playback_build_controls,
+ .build_pcms = simple_playback_build_pcms,
.init = nvhdmi_7x_init,
- .free = generic_hdmi_free,
+ .free = simple_playback_free,
};
static const struct hda_codec_ops nvhdmi_patch_ops_2ch = {
- .build_controls = generic_hdmi_build_controls,
- .build_pcms = generic_hdmi_build_pcms,
+ .build_controls = simple_playback_build_controls,
+ .build_pcms = simple_playback_build_pcms,
.init = nvhdmi_7x_init,
- .free = generic_hdmi_free,
+ .free = simple_playback_free,
};
static int patch_nvhdmi_2ch(struct hda_codec *codec)
@@ -1498,7 +1745,7 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec)
spec->multiout.max_channels = 2;
spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x;
spec->num_cvts = 1;
- spec->cvt[0] = nvhdmi_master_con_nid_7x;
+ spec->cvts[0].cvt_nid = nvhdmi_master_con_nid_7x;
spec->pcm_playback = &nvhdmi_pcm_playback_2ch;
codec->patch_ops = nvhdmi_patch_ops_2ch;
@@ -1549,11 +1796,11 @@ static int atihdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
substream);
if (err < 0)
return err;
- snd_hda_codec_write(codec, spec->cvt[0], 0, AC_VERB_SET_CVT_CHAN_COUNT,
- chans - 1);
+ snd_hda_codec_write(codec, spec->cvts[0].cvt_nid, 0,
+ AC_VERB_SET_CVT_CHAN_COUNT, chans - 1);
/* FIXME: XXX */
for (i = 0; i < chans; i++) {
- snd_hda_codec_write(codec, spec->cvt[0], 0,
+ snd_hda_codec_write(codec, spec->cvts[0].cvt_nid, 0,
AC_VERB_SET_HDMI_CHAN_SLOT,
(i << 4) | i);
}
@@ -1584,18 +1831,18 @@ static int atihdmi_init(struct hda_codec *codec)
snd_hda_sequence_write(codec, atihdmi_basic_init);
/* SI codec requires to unmute the pin */
- if (get_wcaps(codec, spec->pin[0]) & AC_WCAP_OUT_AMP)
- snd_hda_codec_write(codec, spec->pin[0], 0,
+ if (get_wcaps(codec, spec->pins[0].pin_nid) & AC_WCAP_OUT_AMP)
+ snd_hda_codec_write(codec, spec->pins[0].pin_nid, 0,
AC_VERB_SET_AMP_GAIN_MUTE,
AMP_OUT_UNMUTE);
return 0;
}
static const struct hda_codec_ops atihdmi_patch_ops = {
- .build_controls = generic_hdmi_build_controls,
- .build_pcms = generic_hdmi_build_pcms,
+ .build_controls = simple_playback_build_controls,
+ .build_pcms = simple_playback_build_pcms,
.init = atihdmi_init,
- .free = generic_hdmi_free,
+ .free = simple_playback_free,
};
@@ -1613,8 +1860,8 @@ static int patch_atihdmi(struct hda_codec *codec)
spec->multiout.max_channels = 2;
spec->multiout.dig_out_nid = ATIHDMI_CVT_NID;
spec->num_cvts = 1;
- spec->cvt[0] = ATIHDMI_CVT_NID;
- spec->pin[0] = ATIHDMI_PIN_NID;
+ spec->cvts[0].cvt_nid = ATIHDMI_CVT_NID;
+ spec->pins[0].pin_nid = ATIHDMI_PIN_NID;
spec->pcm_playback = &atihdmi_pcm_digital_playback;
codec->patch_ops = atihdmi_patch_ops;
@@ -1661,6 +1908,8 @@ static const struct hda_codec_preset snd_hda_preset_hdmi[] = {
{ .id = 0x10de0042, .name = "GPU 42 HDMI/DP", .patch = patch_generic_hdmi },
{ .id = 0x10de0043, .name = "GPU 43 HDMI/DP", .patch = patch_generic_hdmi },
{ .id = 0x10de0044, .name = "GPU 44 HDMI/DP", .patch = patch_generic_hdmi },
+{ .id = 0x10de0051, .name = "GPU 51 HDMI/DP", .patch = patch_generic_hdmi },
+{ .id = 0x10de0060, .name = "GPU 60 HDMI/DP", .patch = patch_generic_hdmi },
{ .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch },
{ .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch },
{ .id = 0x80860054, .name = "IbexPeak HDMI", .patch = patch_generic_hdmi },
@@ -1670,6 +1919,7 @@ static const struct hda_codec_preset snd_hda_preset_hdmi[] = {
{ .id = 0x80862804, .name = "IbexPeak HDMI", .patch = patch_generic_hdmi },
{ .id = 0x80862805, .name = "CougarPoint HDMI", .patch = patch_generic_hdmi },
{ .id = 0x80862806, .name = "PantherPoint HDMI", .patch = patch_generic_hdmi },
+{ .id = 0x80862880, .name = "CedarTrail HDMI", .patch = patch_generic_hdmi },
{ .id = 0x808629fb, .name = "Crestline HDMI", .patch = patch_generic_hdmi },
{} /* terminator */
};
@@ -1706,6 +1956,8 @@ MODULE_ALIAS("snd-hda-codec-id:10de0041");
MODULE_ALIAS("snd-hda-codec-id:10de0042");
MODULE_ALIAS("snd-hda-codec-id:10de0043");
MODULE_ALIAS("snd-hda-codec-id:10de0044");
+MODULE_ALIAS("snd-hda-codec-id:10de0051");
+MODULE_ALIAS("snd-hda-codec-id:10de0060");
MODULE_ALIAS("snd-hda-codec-id:10de0067");
MODULE_ALIAS("snd-hda-codec-id:10de8001");
MODULE_ALIAS("snd-hda-codec-id:17e80047");
@@ -1716,6 +1968,7 @@ MODULE_ALIAS("snd-hda-codec-id:80862803");
MODULE_ALIAS("snd-hda-codec-id:80862804");
MODULE_ALIAS("snd-hda-codec-id:80862805");
MODULE_ALIAS("snd-hda-codec-id:80862806");
+MODULE_ALIAS("snd-hda-codec-id:80862880");
MODULE_ALIAS("snd-hda-codec-id:808629fb");
MODULE_LICENSE("GPL");
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 3315816..6d19f99 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -1,7 +1,7 @@
/*
* Universal Interface for Intel High Definition Audio Codec
*
- * HD audio interface patch for ALC 260/880/882 codecs
+ * HD audio interface patch for Realtek ALC codecs
*
* Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
* PeiSen Hou <pshou@realtek.com.tw>
@@ -27,242 +27,18 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/pci.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/jack.h>
#include "hda_codec.h"
#include "hda_local.h"
#include "hda_beep.h"
-#define ALC880_FRONT_EVENT 0x01
-#define ALC880_DCVOL_EVENT 0x02
-#define ALC880_HP_EVENT 0x04
-#define ALC880_MIC_EVENT 0x08
-
-/* ALC880 board config type */
-enum {
- ALC880_3ST,
- ALC880_3ST_DIG,
- ALC880_5ST,
- ALC880_5ST_DIG,
- ALC880_W810,
- ALC880_Z71V,
- ALC880_6ST,
- ALC880_6ST_DIG,
- ALC880_F1734,
- ALC880_ASUS,
- ALC880_ASUS_DIG,
- ALC880_ASUS_W1V,
- ALC880_ASUS_DIG2,
- ALC880_FUJITSU,
- ALC880_UNIWILL_DIG,
- ALC880_UNIWILL,
- ALC880_UNIWILL_P53,
- ALC880_CLEVO,
- ALC880_TCL_S700,
- ALC880_LG,
- ALC880_LG_LW,
- ALC880_MEDION_RIM,
-#ifdef CONFIG_SND_DEBUG
- ALC880_TEST,
-#endif
- ALC880_AUTO,
- ALC880_MODEL_LAST /* last tag */
-};
-
-/* ALC260 models */
-enum {
- ALC260_BASIC,
- ALC260_HP,
- ALC260_HP_DC7600,
- ALC260_HP_3013,
- ALC260_FUJITSU_S702X,
- ALC260_ACER,
- ALC260_WILL,
- ALC260_REPLACER_672V,
- ALC260_FAVORIT100,
-#ifdef CONFIG_SND_DEBUG
- ALC260_TEST,
-#endif
- ALC260_AUTO,
- ALC260_MODEL_LAST /* last tag */
-};
-
-/* ALC262 models */
-enum {
- ALC262_BASIC,
- ALC262_HIPPO,
- ALC262_HIPPO_1,
- ALC262_FUJITSU,
- ALC262_HP_BPC,
- ALC262_HP_BPC_D7000_WL,
- ALC262_HP_BPC_D7000_WF,
- ALC262_HP_TC_T5735,
- ALC262_HP_RP5700,
- ALC262_BENQ_ED8,
- ALC262_SONY_ASSAMD,
- ALC262_BENQ_T31,
- ALC262_ULTRA,
- ALC262_LENOVO_3000,
- ALC262_NEC,
- ALC262_TOSHIBA_S06,
- ALC262_TOSHIBA_RX1,
- ALC262_TYAN,
- ALC262_AUTO,
- ALC262_MODEL_LAST /* last tag */
-};
-
-/* ALC268 models */
-enum {
- ALC267_QUANTA_IL1,
- ALC268_3ST,
- ALC268_TOSHIBA,
- ALC268_ACER,
- ALC268_ACER_DMIC,
- ALC268_ACER_ASPIRE_ONE,
- ALC268_DELL,
- ALC268_ZEPTO,
-#ifdef CONFIG_SND_DEBUG
- ALC268_TEST,
-#endif
- ALC268_AUTO,
- ALC268_MODEL_LAST /* last tag */
-};
-
-/* ALC269 models */
-enum {
- ALC269_BASIC,
- ALC269_QUANTA_FL1,
- ALC269_AMIC,
- ALC269_DMIC,
- ALC269VB_AMIC,
- ALC269VB_DMIC,
- ALC269_FUJITSU,
- ALC269_LIFEBOOK,
- ALC271_ACER,
- ALC269_AUTO,
- ALC269_MODEL_LAST /* last tag */
-};
-
-/* ALC861 models */
-enum {
- ALC861_3ST,
- ALC660_3ST,
- ALC861_3ST_DIG,
- ALC861_6ST_DIG,
- ALC861_UNIWILL_M31,
- ALC861_TOSHIBA,
- ALC861_ASUS,
- ALC861_ASUS_LAPTOP,
- ALC861_AUTO,
- ALC861_MODEL_LAST,
-};
-
-/* ALC861-VD models */
-enum {
- ALC660VD_3ST,
- ALC660VD_3ST_DIG,
- ALC660VD_ASUS_V1S,
- ALC861VD_3ST,
- ALC861VD_3ST_DIG,
- ALC861VD_6ST_DIG,
- ALC861VD_LENOVO,
- ALC861VD_DALLAS,
- ALC861VD_HP,
- ALC861VD_AUTO,
- ALC861VD_MODEL_LAST,
-};
-
-/* ALC662 models */
-enum {
- ALC662_3ST_2ch_DIG,
- ALC662_3ST_6ch_DIG,
- ALC662_3ST_6ch,
- ALC662_5ST_DIG,
- ALC662_LENOVO_101E,
- ALC662_ASUS_EEEPC_P701,
- ALC662_ASUS_EEEPC_EP20,
- ALC663_ASUS_M51VA,
- ALC663_ASUS_G71V,
- ALC663_ASUS_H13,
- ALC663_ASUS_G50V,
- ALC662_ECS,
- ALC663_ASUS_MODE1,
- ALC662_ASUS_MODE2,
- ALC663_ASUS_MODE3,
- ALC663_ASUS_MODE4,
- ALC663_ASUS_MODE5,
- ALC663_ASUS_MODE6,
- ALC663_ASUS_MODE7,
- ALC663_ASUS_MODE8,
- ALC272_DELL,
- ALC272_DELL_ZM1,
- ALC272_SAMSUNG_NC10,
- ALC662_AUTO,
- ALC662_MODEL_LAST,
-};
-
-/* ALC882 models */
-enum {
- ALC882_3ST_DIG,
- ALC882_6ST_DIG,
- ALC882_ARIMA,
- ALC882_W2JC,
- ALC882_TARGA,
- ALC882_ASUS_A7J,
- ALC882_ASUS_A7M,
- ALC885_MACPRO,
- ALC885_MBA21,
- ALC885_MBP3,
- ALC885_MB5,
- ALC885_MACMINI3,
- ALC885_IMAC24,
- ALC885_IMAC91,
- ALC883_3ST_2ch_DIG,
- ALC883_3ST_6ch_DIG,
- ALC883_3ST_6ch,
- ALC883_6ST_DIG,
- ALC883_TARGA_DIG,
- ALC883_TARGA_2ch_DIG,
- ALC883_TARGA_8ch_DIG,
- ALC883_ACER,
- ALC883_ACER_ASPIRE,
- ALC888_ACER_ASPIRE_4930G,
- ALC888_ACER_ASPIRE_6530G,
- ALC888_ACER_ASPIRE_8930G,
- ALC888_ACER_ASPIRE_7730G,
- ALC883_MEDION,
- ALC883_MEDION_WIM2160,
- ALC883_LAPTOP_EAPD,
- ALC883_LENOVO_101E_2ch,
- ALC883_LENOVO_NB0763,
- ALC888_LENOVO_MS7195_DIG,
- ALC888_LENOVO_SKY,
- ALC883_HAIER_W66,
- ALC888_3ST_HP,
- ALC888_6ST_DELL,
- ALC883_MITAC,
- ALC883_CLEVO_M540R,
- ALC883_CLEVO_M720,
- ALC883_FUJITSU_PI2515,
- ALC888_FUJITSU_XA3530,
- ALC883_3ST_6ch_INTEL,
- ALC889A_INTEL,
- ALC889_INTEL,
- ALC888_ASUS_M90V,
- ALC888_ASUS_EEE1601,
- ALC889A_MB31,
- ALC1200_ASUS_P5Q,
- ALC883_SONY_VAIO_TT,
- ALC882_AUTO,
- ALC882_MODEL_LAST,
-};
-
-/* ALC680 models */
-enum {
- ALC680_BASE,
- ALC680_AUTO,
- ALC680_MODEL_LAST,
-};
+/* unsol event tags */
+#define ALC_FRONT_EVENT 0x01
+#define ALC_DCVOL_EVENT 0x02
+#define ALC_HP_EVENT 0x04
+#define ALC_MIC_EVENT 0x08
/* for GPIO Poll */
#define GPIO_MASK 0x03
@@ -276,14 +52,6 @@ enum {
ALC_INIT_GPIO3,
};
-struct alc_mic_route {
- hda_nid_t pin;
- unsigned char mux_idx;
- unsigned char amix_idx;
-};
-
-#define MUX_IDX_UNDEF ((unsigned char)-1)
-
struct alc_customize_define {
unsigned int sku_cfg;
unsigned char port_connectivity;
@@ -311,6 +79,8 @@ enum {
ALC_AUTOMUTE_MIXER, /* mute/unmute mixer widget AMP */
};
+#define MAX_VOL_NIDS 0x40
+
struct alc_spec {
/* codec parameterization */
const struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
@@ -348,9 +118,11 @@ struct alc_spec {
const hda_nid_t *adc_nids;
const hda_nid_t *capsrc_nids;
hda_nid_t dig_in_nid; /* digital-in NID; optional */
+ hda_nid_t mixer_nid; /* analog-mixer NID */
+ DECLARE_BITMAP(vol_ctls, MAX_VOL_NIDS << 1);
+ DECLARE_BITMAP(sw_ctls, MAX_VOL_NIDS << 1);
/* capture setup for dynamic dual-adc switch */
- unsigned int cur_adc_idx;
hda_nid_t cur_adc;
unsigned int cur_adc_stream_tag;
unsigned int cur_adc_format;
@@ -359,9 +131,9 @@ struct alc_spec {
unsigned int num_mux_defs;
const struct hda_input_mux *input_mux;
unsigned int cur_mux[3];
- struct alc_mic_route ext_mic;
- struct alc_mic_route dock_mic;
- struct alc_mic_route int_mic;
+ hda_nid_t ext_mic_pin;
+ hda_nid_t dock_mic_pin;
+ hda_nid_t int_mic_pin;
/* channel model */
const struct hda_channel_mode *channel_mode;
@@ -381,6 +153,9 @@ struct alc_spec {
hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
hda_nid_t private_adc_nids[AUTO_CFG_MAX_OUTS];
hda_nid_t private_capsrc_nids[AUTO_CFG_MAX_OUTS];
+ hda_nid_t imux_pins[HDA_MAX_NUM_INPUTS];
+ unsigned int dyn_adc_idx[HDA_MAX_NUM_INPUTS];
+ int int_mic_idx, ext_mic_idx, dock_mic_idx; /* for auto-mic */
/* hooks */
void (*init_hook)(struct hda_codec *codec);
@@ -389,21 +164,28 @@ struct alc_spec {
void (*power_hook)(struct hda_codec *codec);
#endif
void (*shutup)(struct hda_codec *codec);
+ void (*automute_hook)(struct hda_codec *codec);
/* for pin sensing */
- unsigned int jack_present: 1;
+ unsigned int hp_jack_present:1;
unsigned int line_jack_present:1;
unsigned int master_mute:1;
unsigned int auto_mic:1;
- unsigned int automute:1; /* HP automute enabled */
- unsigned int detect_line:1; /* Line-out detection enabled */
- unsigned int automute_lines:1; /* automute line-out as well; NOP when automute_hp_lo isn't set */
- unsigned int automute_hp_lo:1; /* both HP and LO available */
+ unsigned int auto_mic_valid_imux:1; /* valid imux for auto-mic */
+ unsigned int automute_speaker:1; /* automute speaker outputs */
+ unsigned int automute_lo:1; /* automute LO outputs */
+ unsigned int detect_hp:1; /* Headphone detection enabled */
+ unsigned int detect_lo:1; /* Line-out detection enabled */
+ unsigned int automute_speaker_possible:1; /* there are speakers and either LO or HP */
+ unsigned int automute_lo_possible:1; /* there are line outs and HP */
+ unsigned int keep_vref_in_automute:1; /* Don't clear VREF in automute */
/* other flags */
unsigned int no_analog :1; /* digital I/O only */
- unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */
+ unsigned int dyn_adc_switch:1; /* switch ADCs (for ALC275) */
unsigned int single_input_src:1;
+ unsigned int vol_in_capsrc:1; /* use capsrc volume (ADC has no vol) */
+ unsigned int parse_flags; /* passed to snd_hda_parse_pin_defcfg() */
/* auto-mute control */
int automute_mode;
@@ -421,6 +203,7 @@ struct alc_spec {
/* for PLL fix */
hda_nid_t pll_nid;
unsigned int pll_coef_idx, pll_coef_bit;
+ unsigned int coef0;
/* fix-up list */
int fixup_id;
@@ -430,41 +213,28 @@ struct alc_spec {
/* multi-io */
int multi_ios;
struct alc_multi_io multi_io[4];
-};
-/*
- * configuration template - to be copied to the spec instance
- */
-struct alc_config_preset {
- const struct snd_kcontrol_new *mixers[5]; /* should be identical size
- * with spec
- */
- const struct snd_kcontrol_new *cap_mixer; /* capture mixer */
- const struct hda_verb *init_verbs[5];
- unsigned int num_dacs;
- const hda_nid_t *dac_nids;
- hda_nid_t dig_out_nid; /* optional */
- hda_nid_t hp_nid; /* optional */
- const hda_nid_t *slave_dig_outs;
- unsigned int num_adc_nids;
- const hda_nid_t *adc_nids;
- const hda_nid_t *capsrc_nids;
- hda_nid_t dig_in_nid;
- unsigned int num_channel_mode;
- const struct hda_channel_mode *channel_mode;
- int need_dac_fix;
- int const_channel_count;
- unsigned int num_mux_defs;
- const struct hda_input_mux *input_mux;
- void (*unsol_event)(struct hda_codec *, unsigned int);
- void (*setup)(struct hda_codec *);
- void (*init_hook)(struct hda_codec *);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
- const struct hda_amp_list *loopbacks;
- void (*power_hook)(struct hda_codec *codec);
-#endif
+ /* bind volumes */
+ struct snd_array bind_ctls;
};
+#define ALC_MODEL_AUTO 0 /* common for all chips */
+
+static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid,
+ int dir, unsigned int bits)
+{
+ if (!nid)
+ return false;
+ if (get_wcaps(codec, nid) & (1 << (dir + 1)))
+ if (query_amp_caps(codec, nid, dir) & bits)
+ return true;
+ return false;
+}
+
+#define nid_has_mute(codec, nid, dir) \
+ check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE)
+#define nid_has_volume(codec, nid, dir) \
+ check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS)
/*
* input MUX handling
@@ -493,17 +263,38 @@ static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static bool alc_dyn_adc_pcm_resetup(struct hda_codec *codec, int cur)
+{
+ struct alc_spec *spec = codec->spec;
+ hda_nid_t new_adc = spec->adc_nids[spec->dyn_adc_idx[cur]];
+
+ if (spec->cur_adc && spec->cur_adc != new_adc) {
+ /* stream is running, let's swap the current ADC */
+ __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
+ spec->cur_adc = new_adc;
+ snd_hda_codec_setup_stream(codec, new_adc,
+ spec->cur_adc_stream_tag, 0,
+ spec->cur_adc_format);
+ return true;
+ }
+ return false;
+}
+
+static inline hda_nid_t get_capsrc(struct alc_spec *spec, int idx)
+{
+ return spec->capsrc_nids ?
+ spec->capsrc_nids[idx] : spec->adc_nids[idx];
+}
+
+/* select the given imux item; either unmute exclusively or select the route */
+static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx,
+ unsigned int idx, bool force)
{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct alc_spec *spec = codec->spec;
const struct hda_input_mux *imux;
- unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
unsigned int mux_idx;
- hda_nid_t nid = spec->capsrc_nids ?
- spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
- unsigned int type;
+ int i, type, num_conns;
+ hda_nid_t nid;
mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
imux = &spec->input_mux[mux_idx];
@@ -512,371 +303,51 @@ static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
if (!imux->num_items)
return 0;
+ if (idx >= imux->num_items)
+ idx = imux->num_items - 1;
+ if (spec->cur_mux[adc_idx] == idx && !force)
+ return 0;
+ spec->cur_mux[adc_idx] = idx;
+
+ if (spec->dyn_adc_switch) {
+ alc_dyn_adc_pcm_resetup(codec, idx);
+ adc_idx = spec->dyn_adc_idx[idx];
+ }
+
+ nid = get_capsrc(spec, adc_idx);
+
+ /* no selection? */
+ num_conns = snd_hda_get_conn_list(codec, nid, NULL);
+ if (num_conns <= 1)
+ return 1;
+
type = get_wcaps_type(get_wcaps(codec, nid));
if (type == AC_WID_AUD_MIX) {
/* Matrix-mixer style (e.g. ALC882) */
- unsigned int *cur_val = &spec->cur_mux[adc_idx];
- unsigned int i, idx;
-
- idx = ucontrol->value.enumerated.item[0];
- if (idx >= imux->num_items)
- idx = imux->num_items - 1;
- if (*cur_val == idx)
- return 0;
- for (i = 0; i < imux->num_items; i++) {
- unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
- snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
- imux->items[i].index,
+ int active = imux->items[idx].index;
+ for (i = 0; i < num_conns; i++) {
+ unsigned int v = (i == active) ? 0 : HDA_AMP_MUTE;
+ snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, i,
HDA_AMP_MUTE, v);
}
- *cur_val = idx;
- return 1;
} else {
/* MUX style (e.g. ALC880) */
- return snd_hda_input_mux_put(codec, imux, ucontrol, nid,
- &spec->cur_mux[adc_idx]);
- }
-}
-
-/*
- * channel mode setting
- */
-static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct alc_spec *spec = codec->spec;
- return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
- spec->num_channel_mode);
-}
-
-static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct alc_spec *spec = codec->spec;
- return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
- spec->num_channel_mode,
- spec->ext_channel_count);
-}
-
-static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct alc_spec *spec = codec->spec;
- int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
- spec->num_channel_mode,
- &spec->ext_channel_count);
- if (err >= 0 && !spec->const_channel_count) {
- spec->multiout.max_channels = spec->ext_channel_count;
- if (spec->need_dac_fix)
- spec->multiout.num_dacs = spec->multiout.max_channels / 2;
- }
- return err;
-}
-
-/*
- * Control the mode of pin widget settings via the mixer. "pc" is used
- * instead of "%" to avoid consequences of accidentally treating the % as
- * being part of a format specifier. Maximum allowed length of a value is
- * 63 characters plus NULL terminator.
- *
- * Note: some retasking pin complexes seem to ignore requests for input
- * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
- * are requested. Therefore order this list so that this behaviour will not
- * cause problems when mixer clients move through the enum sequentially.
- * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
- * March 2006.
- */
-static const char * const alc_pin_mode_names[] = {
- "Mic 50pc bias", "Mic 80pc bias",
- "Line in", "Line out", "Headphone out",
-};
-static const unsigned char alc_pin_mode_values[] = {
- PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
-};
-/* The control can present all 5 options, or it can limit the options based
- * in the pin being assumed to be exclusively an input or an output pin. In
- * addition, "input" pins may or may not process the mic bias option
- * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
- * accept requests for bias as of chip versions up to March 2006) and/or
- * wiring in the computer.
- */
-#define ALC_PIN_DIR_IN 0x00
-#define ALC_PIN_DIR_OUT 0x01
-#define ALC_PIN_DIR_INOUT 0x02
-#define ALC_PIN_DIR_IN_NOMICBIAS 0x03
-#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
-
-/* Info about the pin modes supported by the different pin direction modes.
- * For each direction the minimum and maximum values are given.
- */
-static const signed char alc_pin_mode_dir_info[5][2] = {
- { 0, 2 }, /* ALC_PIN_DIR_IN */
- { 3, 4 }, /* ALC_PIN_DIR_OUT */
- { 0, 4 }, /* ALC_PIN_DIR_INOUT */
- { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */
- { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */
-};
-#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
-#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
-#define alc_pin_mode_n_items(_dir) \
- (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
-
-static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- unsigned int item_num = uinfo->value.enumerated.item;
- unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
-
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
-
- if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
- item_num = alc_pin_mode_min(dir);
- strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
- return 0;
-}
-
-static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- unsigned int i;
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- hda_nid_t nid = kcontrol->private_value & 0xffff;
- unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
- long *valp = ucontrol->value.integer.value;
- unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_PIN_WIDGET_CONTROL,
- 0x00);
-
- /* Find enumerated value for current pinctl setting */
- i = alc_pin_mode_min(dir);
- while (i <= alc_pin_mode_max(dir) && alc_pin_mode_values[i] != pinctl)
- i++;
- *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
- return 0;
-}
-
-static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- signed int change;
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- hda_nid_t nid = kcontrol->private_value & 0xffff;
- unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
- long val = *ucontrol->value.integer.value;
- unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_PIN_WIDGET_CONTROL,
- 0x00);
-
- if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir))
- val = alc_pin_mode_min(dir);
-
- change = pinctl != alc_pin_mode_values[val];
- if (change) {
- /* Set pin mode to that requested */
snd_hda_codec_write_cache(codec, nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
- alc_pin_mode_values[val]);
-
- /* Also enable the retasking pin's input/output as required
- * for the requested pin mode. Enum values of 2 or less are
- * input modes.
- *
- * Dynamically switching the input/output buffers probably
- * reduces noise slightly (particularly on input) so we'll
- * do it. However, having both input and output buffers
- * enabled simultaneously doesn't seem to be problematic if
- * this turns out to be necessary in the future.
- */
- if (val <= 2) {
- snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
- HDA_AMP_MUTE, HDA_AMP_MUTE);
- snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
- HDA_AMP_MUTE, 0);
- } else {
- snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
- HDA_AMP_MUTE, HDA_AMP_MUTE);
- snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
- HDA_AMP_MUTE, 0);
- }
+ AC_VERB_SET_CONNECT_SEL,
+ imux->items[idx].index);
}
- return change;
-}
-
-#define ALC_PIN_MODE(xname, nid, dir) \
- { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
- .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
- .info = alc_pin_mode_info, \
- .get = alc_pin_mode_get, \
- .put = alc_pin_mode_put, \
- .private_value = nid | (dir<<16) }
-
-/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged
- * together using a mask with more than one bit set. This control is
- * currently used only by the ALC260 test model. At this stage they are not
- * needed for any "production" models.
- */
-#ifdef CONFIG_SND_DEBUG
-#define alc_gpio_data_info snd_ctl_boolean_mono_info
-
-static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- hda_nid_t nid = kcontrol->private_value & 0xffff;
- unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
- long *valp = ucontrol->value.integer.value;
- unsigned int val = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_GPIO_DATA, 0x00);
-
- *valp = (val & mask) != 0;
- return 0;
-}
-static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- signed int change;
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- hda_nid_t nid = kcontrol->private_value & 0xffff;
- unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
- long val = *ucontrol->value.integer.value;
- unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_GPIO_DATA,
- 0x00);
-
- /* Set/unset the masked GPIO bit(s) as needed */
- change = (val == 0 ? 0 : mask) != (gpio_data & mask);
- if (val == 0)
- gpio_data &= ~mask;
- else
- gpio_data |= mask;
- snd_hda_codec_write_cache(codec, nid, 0,
- AC_VERB_SET_GPIO_DATA, gpio_data);
-
- return change;
-}
-#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
- { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
- .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
- .info = alc_gpio_data_info, \
- .get = alc_gpio_data_get, \
- .put = alc_gpio_data_put, \
- .private_value = nid | (mask<<16) }
-#endif /* CONFIG_SND_DEBUG */
-
-/* A switch control to allow the enabling of the digital IO pins on the
- * ALC260. This is incredibly simplistic; the intention of this control is
- * to provide something in the test model allowing digital outputs to be
- * identified if present. If models are found which can utilise these
- * outputs a more complete mixer control can be devised for those models if
- * necessary.
- */
-#ifdef CONFIG_SND_DEBUG
-#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info
-
-static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- hda_nid_t nid = kcontrol->private_value & 0xffff;
- unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
- long *valp = ucontrol->value.integer.value;
- unsigned int val = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_DIGI_CONVERT_1, 0x00);
-
- *valp = (val & mask) != 0;
- return 0;
-}
-static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- signed int change;
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- hda_nid_t nid = kcontrol->private_value & 0xffff;
- unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
- long val = *ucontrol->value.integer.value;
- unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_DIGI_CONVERT_1,
- 0x00);
-
- /* Set/unset the masked control bit(s) as needed */
- change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
- if (val==0)
- ctrl_data &= ~mask;
- else
- ctrl_data |= mask;
- snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
- ctrl_data);
-
- return change;
-}
-#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
- { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
- .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
- .info = alc_spdif_ctrl_info, \
- .get = alc_spdif_ctrl_get, \
- .put = alc_spdif_ctrl_put, \
- .private_value = nid | (mask<<16) }
-#endif /* CONFIG_SND_DEBUG */
-
-/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
- * Again, this is only used in the ALC26x test models to help identify when
- * the EAPD line must be asserted for features to work.
- */
-#ifdef CONFIG_SND_DEBUG
-#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info
-
-static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- hda_nid_t nid = kcontrol->private_value & 0xffff;
- unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
- long *valp = ucontrol->value.integer.value;
- unsigned int val = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_EAPD_BTLENABLE, 0x00);
-
- *valp = (val & mask) != 0;
- return 0;
+ return 1;
}
-static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
- int change;
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- hda_nid_t nid = kcontrol->private_value & 0xffff;
- unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
- long val = *ucontrol->value.integer.value;
- unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_EAPD_BTLENABLE,
- 0x00);
-
- /* Set/unset the masked control bit(s) as needed */
- change = (!val ? 0 : mask) != (ctrl_data & mask);
- if (!val)
- ctrl_data &= ~mask;
- else
- ctrl_data |= mask;
- snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
- ctrl_data);
-
- return change;
+ unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ return alc_mux_select(codec, adc_idx,
+ ucontrol->value.enumerated.item[0], false);
}
-#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
- { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
- .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
- .info = alc_eapd_ctrl_info, \
- .get = alc_eapd_ctrl_get, \
- .put = alc_eapd_ctrl_put, \
- .private_value = nid | (mask<<16) }
-#endif /* CONFIG_SND_DEBUG */
-
/*
* set up the input pin config (depending on the given auto-pin type)
*/
@@ -905,29 +376,10 @@ static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val);
}
-static void alc_fixup_autocfg_pin_nums(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- struct auto_pin_cfg *cfg = &spec->autocfg;
-
- if (!cfg->line_outs) {
- while (cfg->line_outs < AUTO_CFG_MAX_OUTS &&
- cfg->line_out_pins[cfg->line_outs])
- cfg->line_outs++;
- }
- if (!cfg->speaker_outs) {
- while (cfg->speaker_outs < AUTO_CFG_MAX_OUTS &&
- cfg->speaker_pins[cfg->speaker_outs])
- cfg->speaker_outs++;
- }
- if (!cfg->hp_outs) {
- while (cfg->hp_outs < AUTO_CFG_MAX_OUTS &&
- cfg->hp_pins[cfg->hp_outs])
- cfg->hp_outs++;
- }
-}
-
/*
+ * Append the given mixer and verb elements for the later use
+ * The mixer array is referred in build_controls(), and init_verbs are
+ * called in init().
*/
static void add_mixer(struct alc_spec *spec, const struct snd_kcontrol_new *mix)
{
@@ -944,61 +396,8 @@ static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
}
/*
- * set up from the preset table
+ * GPIO setup tables, used in initialization
*/
-static void setup_preset(struct hda_codec *codec,
- const struct alc_config_preset *preset)
-{
- struct alc_spec *spec = codec->spec;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
- add_mixer(spec, preset->mixers[i]);
- spec->cap_mixer = preset->cap_mixer;
- for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
- i++)
- add_verb(spec, preset->init_verbs[i]);
-
- spec->channel_mode = preset->channel_mode;
- spec->num_channel_mode = preset->num_channel_mode;
- spec->need_dac_fix = preset->need_dac_fix;
- spec->const_channel_count = preset->const_channel_count;
-
- if (preset->const_channel_count)
- spec->multiout.max_channels = preset->const_channel_count;
- else
- spec->multiout.max_channels = spec->channel_mode[0].channels;
- spec->ext_channel_count = spec->channel_mode[0].channels;
-
- spec->multiout.num_dacs = preset->num_dacs;
- spec->multiout.dac_nids = preset->dac_nids;
- spec->multiout.dig_out_nid = preset->dig_out_nid;
- spec->multiout.slave_dig_outs = preset->slave_dig_outs;
- spec->multiout.hp_nid = preset->hp_nid;
-
- spec->num_mux_defs = preset->num_mux_defs;
- if (!spec->num_mux_defs)
- spec->num_mux_defs = 1;
- spec->input_mux = preset->input_mux;
-
- spec->num_adc_nids = preset->num_adc_nids;
- spec->adc_nids = preset->adc_nids;
- spec->capsrc_nids = preset->capsrc_nids;
- spec->dig_in_nid = preset->dig_in_nid;
-
- spec->unsol_event = preset->unsol_event;
- spec->init_hook = preset->init_hook;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
- spec->power_hook = preset->power_hook;
- spec->loopback.amplist = preset->loopbacks;
-#endif
-
- if (preset->setup)
- preset->setup(codec);
-
- alc_fixup_autocfg_pin_nums(codec);
-}
-
/* Enable GPIO mask and set output */
static const struct hda_verb alc_gpio1_init_verbs[] = {
{0x01, AC_VERB_SET_GPIO_MASK, 0x01},
@@ -1037,6 +436,8 @@ static void alc_fix_pll(struct hda_codec *codec)
spec->pll_coef_idx);
val = snd_hda_codec_read(codec, spec->pll_nid, 0,
AC_VERB_GET_PROC_COEF, 0);
+ if (val == -1)
+ return;
snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
spec->pll_coef_idx);
snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
@@ -1053,14 +454,19 @@ static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
alc_fix_pll(codec);
}
+/*
+ * Jack-reporting via input-jack layer
+ */
+
+/* initialization of jacks; currently checks only a few known pins */
static int alc_init_jacks(struct hda_codec *codec)
{
#ifdef CONFIG_SND_HDA_INPUT_JACK
struct alc_spec *spec = codec->spec;
int err;
unsigned int hp_nid = spec->autocfg.hp_pins[0];
- unsigned int mic_nid = spec->ext_mic.pin;
- unsigned int dock_nid = spec->dock_mic.pin;
+ unsigned int mic_nid = spec->ext_mic_pin;
+ unsigned int dock_nid = spec->dock_mic_pin;
if (hp_nid) {
err = snd_hda_input_jack_add(codec, hp_nid,
@@ -1088,7 +494,12 @@ static int alc_init_jacks(struct hda_codec *codec)
return 0;
}
-static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
+/*
+ * Jack detections for HP auto-mute and mic-switch
+ */
+
+/* check each pin in the given array; returns true if any of them is plugged */
+static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
{
int i, present = 0;
@@ -1102,6 +513,7 @@ static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
return present;
}
+/* standard HP/line-out auto-mute helper */
static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
bool mute, bool hp_out)
{
@@ -1112,13 +524,24 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
for (i = 0; i < num_pins; i++) {
hda_nid_t nid = pins[i];
+ unsigned int val;
if (!nid)
break;
switch (spec->automute_mode) {
case ALC_AUTOMUTE_PIN:
+ /* don't reset VREF value in case it's controlling
+ * the amp (see alc861_fixup_asus_amp_vref_0f())
+ */
+ if (spec->keep_vref_in_automute) {
+ val = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+ val &= ~PIN_HP;
+ } else
+ val = 0;
+ val |= pin_bits;
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL,
- pin_bits);
+ val);
break;
case ALC_AUTOMUTE_AMP:
snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
@@ -1137,8 +560,8 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
}
}
-/* Toggle internal speakers muting */
-static void update_speakers(struct hda_codec *codec)
+/* Toggle outputs muting */
+static void update_outputs(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
int on;
@@ -1150,10 +573,10 @@ static void update_speakers(struct hda_codec *codec)
do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
spec->autocfg.hp_pins, spec->master_mute, true);
- if (!spec->automute)
+ if (!spec->automute_speaker)
on = 0;
else
- on = spec->jack_present | spec->line_jack_present;
+ on = spec->hp_jack_present | spec->line_jack_present;
on |= spec->master_mute;
do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins),
spec->autocfg.speaker_pins, on, false);
@@ -1163,139 +586,83 @@ static void update_speakers(struct hda_codec *codec)
if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] ||
spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0])
return;
- if (!spec->automute || (spec->automute_hp_lo && !spec->automute_lines))
+ if (!spec->automute_lo)
on = 0;
else
- on = spec->jack_present;
+ on = spec->hp_jack_present;
on |= spec->master_mute;
do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
spec->autocfg.line_out_pins, on, false);
}
+static void call_update_outputs(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ if (spec->automute_hook)
+ spec->automute_hook(codec);
+ else
+ update_outputs(codec);
+}
+
+/* standard HP-automute helper */
static void alc_hp_automute(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
- if (!spec->automute)
- return;
- spec->jack_present =
+ spec->hp_jack_present =
detect_jacks(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
spec->autocfg.hp_pins);
- update_speakers(codec);
+ if (!spec->detect_hp || (!spec->automute_speaker && !spec->automute_lo))
+ return;
+ call_update_outputs(codec);
}
+/* standard line-out-automute helper */
static void alc_line_automute(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
- if (!spec->automute || !spec->detect_line)
+ if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
+ return;
+ /* check LO jack only when it's different from HP */
+ if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0])
return;
+
spec->line_jack_present =
detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
spec->autocfg.line_out_pins);
- update_speakers(codec);
-}
-
-static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
- hda_nid_t nid)
-{
- hda_nid_t conn[HDA_MAX_NUM_INPUTS];
- int i, nums;
-
- nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
- for (i = 0; i < nums; i++)
- if (conn[i] == nid)
- return i;
- return -1;
+ if (!spec->automute_speaker || !spec->detect_lo)
+ return;
+ call_update_outputs(codec);
}
-/* switch the current ADC according to the jack state */
-static void alc_dual_mic_adc_auto_switch(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- unsigned int present;
- hda_nid_t new_adc;
-
- present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
- if (present)
- spec->cur_adc_idx = 1;
- else
- spec->cur_adc_idx = 0;
- new_adc = spec->adc_nids[spec->cur_adc_idx];
- if (spec->cur_adc && spec->cur_adc != new_adc) {
- /* stream is running, let's swap the current ADC */
- __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
- spec->cur_adc = new_adc;
- snd_hda_codec_setup_stream(codec, new_adc,
- spec->cur_adc_stream_tag, 0,
- spec->cur_adc_format);
- }
-}
+#define get_connection_index(codec, mux, nid) \
+ snd_hda_get_conn_index(codec, mux, nid, 0)
+/* standard mic auto-switch helper */
static void alc_mic_automute(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
- struct alc_mic_route *dead1, *dead2, *alive;
- unsigned int present, type;
- hda_nid_t cap_nid;
+ hda_nid_t *pins = spec->imux_pins;
- if (!spec->auto_mic)
- return;
- if (!spec->int_mic.pin || !spec->ext_mic.pin)
+ if (!spec->auto_mic || !spec->auto_mic_valid_imux)
return;
if (snd_BUG_ON(!spec->adc_nids))
return;
-
- if (spec->dual_adc_switch) {
- alc_dual_mic_adc_auto_switch(codec);
+ if (snd_BUG_ON(spec->int_mic_idx < 0 || spec->ext_mic_idx < 0))
return;
- }
-
- cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0];
- alive = &spec->int_mic;
- dead1 = &spec->ext_mic;
- dead2 = &spec->dock_mic;
-
- present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
- if (present) {
- alive = &spec->ext_mic;
- dead1 = &spec->int_mic;
- dead2 = &spec->dock_mic;
- }
- if (!present && spec->dock_mic.pin > 0) {
- present = snd_hda_jack_detect(codec, spec->dock_mic.pin);
- if (present) {
- alive = &spec->dock_mic;
- dead1 = &spec->int_mic;
- dead2 = &spec->ext_mic;
- }
- snd_hda_input_jack_report(codec, spec->dock_mic.pin);
- }
-
- type = get_wcaps_type(get_wcaps(codec, cap_nid));
- if (type == AC_WID_AUD_MIX) {
- /* Matrix-mixer style (e.g. ALC882) */
- snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
- alive->mux_idx,
- HDA_AMP_MUTE, 0);
- if (dead1->pin > 0)
- snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
- dead1->mux_idx,
- HDA_AMP_MUTE, HDA_AMP_MUTE);
- if (dead2->pin > 0)
- snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
- dead2->mux_idx,
- HDA_AMP_MUTE, HDA_AMP_MUTE);
- } else {
- /* MUX style (e.g. ALC880) */
- snd_hda_codec_write_cache(codec, cap_nid, 0,
- AC_VERB_SET_CONNECT_SEL,
- alive->mux_idx);
- }
- snd_hda_input_jack_report(codec, spec->ext_mic.pin);
+ if (snd_hda_jack_detect(codec, pins[spec->ext_mic_idx]))
+ alc_mux_select(codec, 0, spec->ext_mic_idx, false);
+ else if (spec->dock_mic_idx >= 0 &&
+ snd_hda_jack_detect(codec, pins[spec->dock_mic_idx]))
+ alc_mux_select(codec, 0, spec->dock_mic_idx, false);
+ else
+ alc_mux_select(codec, 0, spec->int_mic_idx, false);
- /* FIXME: analog mixer */
+ snd_hda_input_jack_report(codec, pins[spec->ext_mic_idx]);
+ if (spec->dock_mic_idx >= 0)
+ snd_hda_input_jack_report(codec, pins[spec->dock_mic_idx]);
}
/* unsolicited event for HP jack sensing */
@@ -1306,18 +673,19 @@ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
else
res >>= 26;
switch (res) {
- case ALC880_HP_EVENT:
+ case ALC_HP_EVENT:
alc_hp_automute(codec);
break;
- case ALC880_FRONT_EVENT:
+ case ALC_FRONT_EVENT:
alc_line_automute(codec);
break;
- case ALC880_MIC_EVENT:
+ case ALC_MIC_EVENT:
alc_mic_automute(codec);
break;
}
}
+/* call init functions of standard auto-mute helpers */
static void alc_inithook(struct hda_codec *codec)
{
alc_hp_automute(codec);
@@ -1343,6 +711,7 @@ static void alc888_coef_init(struct hda_codec *codec)
AC_VERB_SET_PROC_COEF, 0x3030);
}
+/* additional initialization for ALC889 variants */
static void alc889_coef_init(struct hda_codec *codec)
{
unsigned int tmp;
@@ -1367,28 +736,12 @@ static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on)
static void alc_auto_setup_eapd(struct hda_codec *codec, bool on)
{
/* We currently only handle front, HP */
- switch (codec->vendor_id) {
- case 0x10ec0260:
- set_eapd(codec, 0x0f, on);
- set_eapd(codec, 0x10, on);
- break;
- case 0x10ec0262:
- case 0x10ec0267:
- case 0x10ec0268:
- case 0x10ec0269:
- case 0x10ec0270:
- case 0x10ec0272:
- case 0x10ec0660:
- case 0x10ec0662:
- case 0x10ec0663:
- case 0x10ec0665:
- case 0x10ec0862:
- case 0x10ec0889:
- case 0x10ec0892:
- set_eapd(codec, 0x14, on);
- set_eapd(codec, 0x15, on);
- break;
- }
+ static hda_nid_t pins[] = {
+ 0x0f, 0x10, 0x14, 0x15, 0x17, 0
+ };
+ hda_nid_t *p;
+ for (p = pins; *p; p++)
+ set_eapd(codec, *p, on);
}
/* generic shutup callback;
@@ -1400,10 +753,12 @@ static void alc_eapd_shutup(struct hda_codec *codec)
msleep(200);
}
+/* generic EAPD initialization */
static void alc_auto_init_amp(struct hda_codec *codec, int type)
{
unsigned int tmp;
+ alc_auto_setup_eapd(codec, true);
switch (type) {
case ALC_INIT_GPIO1:
snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
@@ -1415,7 +770,6 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type)
snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
break;
case ALC_INIT_DEFAULT:
- alc_auto_setup_eapd(codec, true);
switch (codec->vendor_id) {
case 0x10ec0260:
snd_hda_codec_write(codec, 0x1a, 0,
@@ -1435,6 +789,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type)
case 0x10ec0885:
case 0x10ec0887:
/*case 0x10ec0889:*/ /* this causes an SPDIF problem */
+ case 0x10ec0900:
alc889_coef_init(codec);
break;
case 0x10ec0888:
@@ -1459,6 +814,9 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type)
}
}
+/*
+ * Auto-Mute mode mixer enum support
+ */
static int alc_automute_mode_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
@@ -1474,7 +832,7 @@ static int alc_automute_mode_info(struct snd_kcontrol *kcontrol,
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
- if (spec->automute_hp_lo) {
+ if (spec->automute_speaker_possible && spec->automute_lo_possible) {
uinfo->value.enumerated.items = 3;
texts = texts3;
} else {
@@ -1493,13 +851,12 @@ static int alc_automute_mode_get(struct snd_kcontrol *kcontrol,
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct alc_spec *spec = codec->spec;
- unsigned int val;
- if (!spec->automute)
- val = 0;
- else if (!spec->automute_hp_lo || !spec->automute_lines)
- val = 1;
- else
- val = 2;
+ unsigned int val = 0;
+ if (spec->automute_speaker)
+ val++;
+ if (spec->automute_lo)
+ val++;
+
ucontrol->value.enumerated.item[0] = val;
return 0;
}
@@ -1512,29 +869,36 @@ static int alc_automute_mode_put(struct snd_kcontrol *kcontrol,
switch (ucontrol->value.enumerated.item[0]) {
case 0:
- if (!spec->automute)
+ if (!spec->automute_speaker && !spec->automute_lo)
return 0;
- spec->automute = 0;
+ spec->automute_speaker = 0;
+ spec->automute_lo = 0;
break;
case 1:
- if (spec->automute &&
- (!spec->automute_hp_lo || !spec->automute_lines))
- return 0;
- spec->automute = 1;
- spec->automute_lines = 0;
+ if (spec->automute_speaker_possible) {
+ if (!spec->automute_lo && spec->automute_speaker)
+ return 0;
+ spec->automute_speaker = 1;
+ spec->automute_lo = 0;
+ } else if (spec->automute_lo_possible) {
+ if (spec->automute_lo)
+ return 0;
+ spec->automute_lo = 1;
+ } else
+ return -EINVAL;
break;
case 2:
- if (!spec->automute_hp_lo)
+ if (!spec->automute_lo_possible || !spec->automute_speaker_possible)
return -EINVAL;
- if (spec->automute && spec->automute_lines)
+ if (spec->automute_speaker && spec->automute_lo)
return 0;
- spec->automute = 1;
- spec->automute_lines = 1;
+ spec->automute_speaker = 1;
+ spec->automute_lo = 1;
break;
default:
return -EINVAL;
}
- update_speakers(codec);
+ call_update_outputs(codec);
return 1;
}
@@ -1546,7 +910,11 @@ static const struct snd_kcontrol_new alc_automute_mode_enum = {
.put = alc_automute_mode_put,
};
-static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec);
+static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec)
+{
+ snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32);
+ return snd_array_new(&spec->kctls);
+}
static int alc_add_automute_mode_enum(struct hda_codec *codec)
{
@@ -1563,7 +931,11 @@ static int alc_add_automute_mode_enum(struct hda_codec *codec)
return 0;
}
-static void alc_init_auto_hp(struct hda_codec *codec)
+/*
+ * Check the availability of HP/line-out auto-mute;
+ * Set up appropriately if really supported
+ */
+static void alc_init_automute(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
@@ -1578,8 +950,6 @@ static void alc_init_auto_hp(struct hda_codec *codec)
present++;
if (present < 2) /* need two different output types */
return;
- if (present == 3)
- spec->automute_hp_lo = 1; /* both HP and LO automute */
if (!cfg->speaker_pins[0] &&
cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
@@ -1595,6 +965,8 @@ static void alc_init_auto_hp(struct hda_codec *codec)
cfg->hp_outs = cfg->line_outs;
}
+ spec->automute_mode = ALC_AUTOMUTE_PIN;
+
for (i = 0; i < cfg->hp_outs; i++) {
hda_nid_t nid = cfg->hp_pins[i];
if (!is_jack_detectable(codec, nid))
@@ -1603,35 +975,176 @@ static void alc_init_auto_hp(struct hda_codec *codec)
nid);
snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_UNSOLICITED_ENABLE,
- AC_USRSP_EN | ALC880_HP_EVENT);
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_PIN;
+ AC_USRSP_EN | ALC_HP_EVENT);
+ spec->detect_hp = 1;
}
- if (spec->automute && cfg->line_out_pins[0] &&
- cfg->speaker_pins[0] &&
- cfg->line_out_pins[0] != cfg->hp_pins[0] &&
- cfg->line_out_pins[0] != cfg->speaker_pins[0]) {
- for (i = 0; i < cfg->line_outs; i++) {
- hda_nid_t nid = cfg->line_out_pins[i];
- if (!is_jack_detectable(codec, nid))
- continue;
- snd_printdd("realtek: Enable Line-Out auto-muting "
- "on NID 0x%x\n", nid);
- snd_hda_codec_write_cache(codec, nid, 0,
- AC_VERB_SET_UNSOLICITED_ENABLE,
- AC_USRSP_EN | ALC880_FRONT_EVENT);
- spec->detect_line = 1;
+
+ if (cfg->line_out_type == AUTO_PIN_LINE_OUT && cfg->line_outs) {
+ if (cfg->speaker_outs)
+ for (i = 0; i < cfg->line_outs; i++) {
+ hda_nid_t nid = cfg->line_out_pins[i];
+ if (!is_jack_detectable(codec, nid))
+ continue;
+ snd_printdd("realtek: Enable Line-Out "
+ "auto-muting on NID 0x%x\n", nid);
+ snd_hda_codec_write_cache(codec, nid, 0,
+ AC_VERB_SET_UNSOLICITED_ENABLE,
+ AC_USRSP_EN | ALC_FRONT_EVENT);
+ spec->detect_lo = 1;
}
- spec->automute_lines = spec->detect_line;
+ spec->automute_lo_possible = spec->detect_hp;
}
- if (spec->automute) {
+ spec->automute_speaker_possible = cfg->speaker_outs &&
+ (spec->detect_hp || spec->detect_lo);
+
+ spec->automute_lo = spec->automute_lo_possible;
+ spec->automute_speaker = spec->automute_speaker_possible;
+
+ if (spec->automute_speaker_possible || spec->automute_lo_possible) {
/* create a control for automute mode */
alc_add_automute_mode_enum(codec);
spec->unsol_event = alc_sku_unsol_event;
}
}
+/* return the position of NID in the list, or -1 if not found */
+static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
+{
+ int i;
+ for (i = 0; i < nums; i++)
+ if (list[i] == nid)
+ return i;
+ return -1;
+}
+
+/* check whether dynamic ADC-switching is available */
+static bool alc_check_dyn_adc_switch(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ struct hda_input_mux *imux = &spec->private_imux[0];
+ int i, n, idx;
+ hda_nid_t cap, pin;
+
+ if (imux != spec->input_mux) /* no dynamic imux? */
+ return false;
+
+ for (n = 0; n < spec->num_adc_nids; n++) {
+ cap = spec->private_capsrc_nids[n];
+ for (i = 0; i < imux->num_items; i++) {
+ pin = spec->imux_pins[i];
+ if (!pin)
+ return false;
+ if (get_connection_index(codec, cap, pin) < 0)
+ break;
+ }
+ if (i >= imux->num_items)
+ return true; /* no ADC-switch is needed */
+ }
+
+ for (i = 0; i < imux->num_items; i++) {
+ pin = spec->imux_pins[i];
+ for (n = 0; n < spec->num_adc_nids; n++) {
+ cap = spec->private_capsrc_nids[n];
+ idx = get_connection_index(codec, cap, pin);
+ if (idx >= 0) {
+ imux->items[i].index = idx;
+ spec->dyn_adc_idx[i] = n;
+ break;
+ }
+ }
+ }
+
+ snd_printdd("realtek: enabling ADC switching\n");
+ spec->dyn_adc_switch = 1;
+ return true;
+}
+
+/* rebuild imux for matching with the given auto-mic pins (if not yet) */
+static bool alc_rebuild_imux_for_auto_mic(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ struct hda_input_mux *imux;
+ static char * const texts[3] = {
+ "Mic", "Internal Mic", "Dock Mic"
+ };
+ int i;
+
+ if (!spec->auto_mic)
+ return false;
+ imux = &spec->private_imux[0];
+ if (spec->input_mux == imux)
+ return true;
+ spec->imux_pins[0] = spec->ext_mic_pin;
+ spec->imux_pins[1] = spec->int_mic_pin;
+ spec->imux_pins[2] = spec->dock_mic_pin;
+ for (i = 0; i < 3; i++) {
+ strcpy(imux->items[i].label, texts[i]);
+ if (spec->imux_pins[i]) {
+ hda_nid_t pin = spec->imux_pins[i];
+ int c;
+ for (c = 0; c < spec->num_adc_nids; c++) {
+ hda_nid_t cap = get_capsrc(spec, c);
+ int idx = get_connection_index(codec, cap, pin);
+ if (idx >= 0) {
+ imux->items[i].index = idx;
+ break;
+ }
+ }
+ imux->num_items = i + 1;
+ }
+ }
+ spec->num_mux_defs = 1;
+ spec->input_mux = imux;
+ return true;
+}
+
+/* check whether all auto-mic pins are valid; setup indices if OK */
+static bool alc_auto_mic_check_imux(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ const struct hda_input_mux *imux;
+
+ if (!spec->auto_mic)
+ return false;
+ if (spec->auto_mic_valid_imux)
+ return true; /* already checked */
+
+ /* fill up imux indices */
+ if (!alc_check_dyn_adc_switch(codec)) {
+ spec->auto_mic = 0;
+ return false;
+ }
+
+ imux = spec->input_mux;
+ spec->ext_mic_idx = find_idx_in_nid_list(spec->ext_mic_pin,
+ spec->imux_pins, imux->num_items);
+ spec->int_mic_idx = find_idx_in_nid_list(spec->int_mic_pin,
+ spec->imux_pins, imux->num_items);
+ spec->dock_mic_idx = find_idx_in_nid_list(spec->dock_mic_pin,
+ spec->imux_pins, imux->num_items);
+ if (spec->ext_mic_idx < 0 || spec->int_mic_idx < 0) {
+ spec->auto_mic = 0;
+ return false; /* no corresponding imux */
+ }
+
+ snd_hda_codec_write_cache(codec, spec->ext_mic_pin, 0,
+ AC_VERB_SET_UNSOLICITED_ENABLE,
+ AC_USRSP_EN | ALC_MIC_EVENT);
+ if (spec->dock_mic_pin)
+ snd_hda_codec_write_cache(codec, spec->dock_mic_pin, 0,
+ AC_VERB_SET_UNSOLICITED_ENABLE,
+ AC_USRSP_EN | ALC_MIC_EVENT);
+
+ spec->auto_mic_valid_imux = 1;
+ spec->auto_mic = 1;
+ return true;
+}
+
+/*
+ * Check the availability of auto-mic switch;
+ * Set up if really supported
+ */
static void alc_init_auto_mic(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
@@ -1639,6 +1152,8 @@ static void alc_init_auto_mic(struct hda_codec *codec)
hda_nid_t fixed, ext, dock;
int i;
+ spec->ext_mic_idx = spec->int_mic_idx = spec->dock_mic_idx = -1;
+
fixed = ext = dock = 0;
for (i = 0; i < cfg->num_inputs; i++) {
hda_nid_t nid = cfg->inputs[i].pin;
@@ -1680,21 +1195,32 @@ static void alc_init_auto_mic(struct hda_codec *codec)
return; /* no unsol support */
if (dock && !is_jack_detectable(codec, dock))
return; /* no unsol support */
+
+ /* check imux indices */
+ spec->ext_mic_pin = ext;
+ spec->int_mic_pin = fixed;
+ spec->dock_mic_pin = dock;
+
+ spec->auto_mic = 1;
+ if (!alc_auto_mic_check_imux(codec))
+ return;
+
snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n",
ext, fixed, dock);
- spec->ext_mic.pin = ext;
- spec->dock_mic.pin = dock;
- spec->int_mic.pin = fixed;
- spec->ext_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
- spec->dock_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
- spec->int_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
- spec->auto_mic = 1;
- snd_hda_codec_write_cache(codec, spec->ext_mic.pin, 0,
- AC_VERB_SET_UNSOLICITED_ENABLE,
- AC_USRSP_EN | ALC880_MIC_EVENT);
spec->unsol_event = alc_sku_unsol_event;
}
+/* check the availabilities of auto-mute and auto-mic switches */
+static void alc_auto_check_switches(struct hda_codec *codec)
+{
+ alc_init_automute(codec);
+ alc_init_auto_mic(codec);
+}
+
+/*
+ * Realtek SSID verification
+ */
+
/* Could be any non-zero and even value. When used as fixup, tells
* the driver to ignore any present sku defines.
*/
@@ -1765,6 +1291,12 @@ do_sku:
return 0;
}
+/* return true if the given NID is found in the list */
+static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
+{
+ return find_idx_in_nid_list(nid, list, nums) >= 0;
+}
+
/* check subsystem ID and set up device-specific initialization;
* return 1 if initialized, 0 if invalid SSID
*/
@@ -1876,27 +1408,24 @@ do_sku:
nid = porti;
else
return 1;
- for (i = 0; i < spec->autocfg.line_outs; i++)
- if (spec->autocfg.line_out_pins[i] == nid)
- return 1;
+ if (found_in_nid_list(nid, spec->autocfg.line_out_pins,
+ spec->autocfg.line_outs))
+ return 1;
spec->autocfg.hp_pins[0] = nid;
}
return 1;
}
-static void alc_ssid_check(struct hda_codec *codec,
- hda_nid_t porta, hda_nid_t porte,
- hda_nid_t portd, hda_nid_t porti)
+/* Check the validity of ALC subsystem-id
+ * ports contains an array of 4 pin NIDs for port-A, E, D and I */
+static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports)
{
- if (!alc_subsystem_id(codec, porta, porte, portd, porti)) {
+ if (!alc_subsystem_id(codec, ports[0], ports[1], ports[2], ports[3])) {
struct alc_spec *spec = codec->spec;
snd_printd("realtek: "
"Enable default setup for auto mode as fallback\n");
spec->init_amp = ALC_INIT_DEFAULT;
}
-
- alc_init_auto_hp(codec);
- alc_init_auto_mic(codec);
}
/*
@@ -1960,7 +1489,7 @@ static void alc_apply_fixup(struct hda_codec *codec, int action)
switch (fix->type) {
case ALC_FIXUP_SKU:
if (action != ALC_FIXUP_ACT_PRE_PROBE || !fix->v.sku)
- break;;
+ break;
snd_printdd(KERN_INFO "hda_codec: %s: "
"Apply sku override for %s\n",
codec->chip_name, modelname);
@@ -2044,6 +1573,9 @@ static void alc_pick_fixup(struct hda_codec *codec,
}
}
+/*
+ * COEF access helper functions
+ */
static int alc_read_coef_idx(struct hda_codec *codec,
unsigned int coef_idx)
{
@@ -2064,20 +1596,41 @@ static void alc_write_coef_idx(struct hda_codec *codec, unsigned int coef_idx,
coef_val);
}
+/* a special bypass for COEF 0; read the cached value at the second time */
+static unsigned int alc_get_coef0(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ if (!spec->coef0)
+ spec->coef0 = alc_read_coef_idx(codec, 0);
+ return spec->coef0;
+}
+
+/*
+ * Digital I/O handling
+ */
+
/* set right pin controls for digital I/O */
static void alc_auto_init_digital(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
int i;
- hda_nid_t pin;
+ hda_nid_t pin, dac;
for (i = 0; i < spec->autocfg.dig_outs; i++) {
pin = spec->autocfg.dig_out_pins[i];
- if (pin) {
- snd_hda_codec_write(codec, pin, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
- PIN_OUT);
- }
+ if (!pin)
+ continue;
+ snd_hda_codec_write(codec, pin, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+ if (!i)
+ dac = spec->multiout.dig_out_nid;
+ else
+ dac = spec->slave_dig_outs[i - 1];
+ if (!dac || !(get_wcaps(codec, dac) & AC_WCAP_OUT_AMP))
+ continue;
+ snd_hda_codec_write(codec, dac, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE,
+ AMP_OUT_UNMUTE);
}
pin = spec->autocfg.dig_in_pin;
if (pin)
@@ -2096,11 +1649,13 @@ static void alc_auto_parse_digital(struct hda_codec *codec)
/* support multiple SPDIFs; the secondary is set up as a slave */
nums = 0;
for (i = 0; i < spec->autocfg.dig_outs; i++) {
+ hda_nid_t conn[4];
err = snd_hda_get_connections(codec,
spec->autocfg.dig_out_pins[i],
- &dig_nid, 1);
+ conn, ARRAY_SIZE(conn));
if (err <= 0)
continue;
+ dig_nid = conn[0]; /* assume the first element is audio-out */
if (!nums) {
spec->multiout.dig_out_nid = dig_nid;
spec->dig_out_type = spec->autocfg.dig_out_type[0];
@@ -2134,572 +1689,22 @@ static void alc_auto_parse_digital(struct hda_codec *codec)
}
/*
- * ALC888
- */
-
-/*
- * 2ch mode
- */
-static const struct hda_verb alc888_4ST_ch2_intel_init[] = {
-/* Mic-in jack as mic in */
- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-/* Line-in jack as Line in */
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-/* Line-Out as Front */
- { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
- { } /* end */
-};
-
-/*
- * 4ch mode
- */
-static const struct hda_verb alc888_4ST_ch4_intel_init[] = {
-/* Mic-in jack as mic in */
- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-/* Line-in jack as Surround */
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-/* Line-Out as Front */
- { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
- { } /* end */
-};
-
-/*
- * 6ch mode
- */
-static const struct hda_verb alc888_4ST_ch6_intel_init[] = {
-/* Mic-in jack as CLFE */
- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-/* Line-in jack as Surround */
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-/* Line-Out as CLFE (workaround because Mic-in is not loud enough) */
- { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
- { } /* end */
-};
-
-/*
- * 8ch mode
- */
-static const struct hda_verb alc888_4ST_ch8_intel_init[] = {
-/* Mic-in jack as CLFE */
- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-/* Line-in jack as Surround */
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-/* Line-Out as Side */
- { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
- { } /* end */
-};
-
-static const struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = {
- { 2, alc888_4ST_ch2_intel_init },
- { 4, alc888_4ST_ch4_intel_init },
- { 6, alc888_4ST_ch6_intel_init },
- { 8, alc888_4ST_ch8_intel_init },
-};
-
-/*
- * ALC888 Fujitsu Siemens Amillo xa3530
- */
-
-static const struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
-/* Front Mic: set to PIN_IN (empty by default) */
- {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-/* Connect Internal HP to Front */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-/* Connect Bass HP to Front */
- {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},
-/* Connect Line-Out side jack (SPDIF) to Side */
- {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
-/* Connect Mic jack to CLFE */
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
-/* Connect Line-in jack to Surround */
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
-/* Connect HP out jack to Front */
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
-/* Enable unsolicited event for HP jack and Line-out jack */
- {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- {}
-};
-
-static void alc889_automute_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x15;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->autocfg.speaker_pins[1] = 0x16;
- spec->autocfg.speaker_pins[2] = 0x17;
- spec->autocfg.speaker_pins[3] = 0x19;
- spec->autocfg.speaker_pins[4] = 0x1a;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static void alc889_intel_init_hook(struct hda_codec *codec)
-{
- alc889_coef_init(codec);
- alc_hp_automute(codec);
-}
-
-static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x17; /* line-out */
- spec->autocfg.hp_pins[1] = 0x1b; /* hp */
- spec->autocfg.speaker_pins[0] = 0x14; /* speaker */
- spec->autocfg.speaker_pins[1] = 0x15; /* bass */
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-/*
- * ALC888 Acer Aspire 4930G model
- */
-
-static const struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
-/* Front Mic: set to PIN_IN (empty by default) */
- {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-/* Unselect Front Mic by default in input mixer 3 */
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
-/* Enable unsolicited event for HP jack */
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-/* Connect Internal HP to front */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-/* Connect HP out to front */
- {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},
- { }
-};
-
-/*
- * ALC888 Acer Aspire 6530G model
- */
-
-static const struct hda_verb alc888_acer_aspire_6530g_verbs[] = {
-/* Route to built-in subwoofer as well as speakers */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-/* Bias voltage on for external mic port */
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
-/* Front Mic: set to PIN_IN (empty by default) */
- {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-/* Unselect Front Mic by default in input mixer 3 */
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
-/* Enable unsolicited event for HP jack */
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-/* Enable speaker output */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
-/* Enable headphone output */
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
- { }
-};
-
-/*
- *ALC888 Acer Aspire 7730G model
- */
-
-static const struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
-/* Bias voltage on for external mic port */
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
-/* Front Mic: set to PIN_IN (empty by default) */
- {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-/* Unselect Front Mic by default in input mixer 3 */
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
-/* Enable unsolicited event for HP jack */
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-/* Enable speaker output */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
-/* Enable headphone output */
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
-/*Enable internal subwoofer */
- {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
- {0x17, AC_VERB_SET_EAPD_BTLENABLE, 2},
- { }
-};
-
-/*
- * ALC889 Acer Aspire 8930G model
- */
-
-static const struct hda_verb alc889_acer_aspire_8930g_verbs[] = {
-/* Front Mic: set to PIN_IN (empty by default) */
- {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-/* Unselect Front Mic by default in input mixer 3 */
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
-/* Enable unsolicited event for HP jack */
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-/* Connect Internal Front to Front */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-/* Connect Internal Rear to Rear */
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
-/* Connect Internal CLFE to CLFE */
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
-/* Connect HP out to Front */
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-/* Enable all DACs */
-/* DAC DISABLE/MUTE 1? */
-/* setting bits 1-5 disables DAC nids 0x02-0x06 apparently. Init=0x38 */
- {0x20, AC_VERB_SET_COEF_INDEX, 0x03},
- {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
-/* DAC DISABLE/MUTE 2? */
-/* some bit here disables the other DACs. Init=0x4900 */
- {0x20, AC_VERB_SET_COEF_INDEX, 0x08},
- {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
-/* DMIC fix
- * This laptop has a stereo digital microphone. The mics are only 1cm apart
- * which makes the stereo useless. However, either the mic or the ALC889
- * makes the signal become a difference/sum signal instead of standard
- * stereo, which is annoying. So instead we flip this bit which makes the
- * codec replicate the sum signal to both channels, turning it into a
- * normal mono mic.
+ * capture mixer elements
*/
-/* DMIC_CONTROL? Init value = 0x0001 */
- {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
- {0x20, AC_VERB_SET_PROC_COEF, 0x0003},
- { }
-};
-
-static const struct hda_input_mux alc888_2_capture_sources[2] = {
- /* Front mic only available on one ADC */
- {
- .num_items = 4,
- .items = {
- { "Mic", 0x0 },
- { "Line", 0x2 },
- { "CD", 0x4 },
- { "Front Mic", 0xb },
- },
- },
- {
- .num_items = 3,
- .items = {
- { "Mic", 0x0 },
- { "Line", 0x2 },
- { "CD", 0x4 },
- },
- }
-};
-
-static const struct hda_input_mux alc888_acer_aspire_6530_sources[2] = {
- /* Interal mic only available on one ADC */
- {
- .num_items = 5,
- .items = {
- { "Mic", 0x0 },
- { "Line In", 0x2 },
- { "CD", 0x4 },
- { "Input Mix", 0xa },
- { "Internal Mic", 0xb },
- },
- },
- {
- .num_items = 4,
- .items = {
- { "Mic", 0x0 },
- { "Line In", 0x2 },
- { "CD", 0x4 },
- { "Input Mix", 0xa },
- },
- }
-};
-
-static const struct hda_input_mux alc889_capture_sources[3] = {
- /* Digital mic only available on first "ADC" */
- {
- .num_items = 5,
- .items = {
- { "Mic", 0x0 },
- { "Line", 0x2 },
- { "CD", 0x4 },
- { "Front Mic", 0xb },
- { "Input Mix", 0xa },
- },
- },
- {
- .num_items = 4,
- .items = {
- { "Mic", 0x0 },
- { "Line", 0x2 },
- { "CD", 0x4 },
- { "Input Mix", 0xa },
- },
- },
- {
- .num_items = 4,
- .items = {
- { "Mic", 0x0 },
- { "Line", 0x2 },
- { "CD", 0x4 },
- { "Input Mix", 0xa },
- },
- }
-};
-
-static const struct snd_kcontrol_new alc888_base_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", 0x0e, 1, 0x0,
- HDA_OUTPUT),
- HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
- HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
- HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Side Playback Switch", 0x0f, 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 const 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", 0x0e, 1, 0x0,
- HDA_OUTPUT),
- HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
- HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
- HDA_CODEC_VOLUME_MONO("Internal LFE Playback Volume", 0x0f, 1, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE_MONO("Internal LFE Playback Switch", 0x0f, 1, 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 const 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),
- 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", 0x0e, 1, 0x0,
- HDA_OUTPUT),
- HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
- HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, 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 void alc888_acer_aspire_4930g_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x15;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->autocfg.speaker_pins[1] = 0x16;
- spec->autocfg.speaker_pins[2] = 0x17;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x15;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->autocfg.speaker_pins[1] = 0x16;
- spec->autocfg.speaker_pins[2] = 0x17;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x15;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->autocfg.speaker_pins[1] = 0x16;
- spec->autocfg.speaker_pins[2] = 0x17;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x15;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->autocfg.speaker_pins[1] = 0x16;
- spec->autocfg.speaker_pins[2] = 0x1b;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-/*
- * ALC880 3-stack model
- *
- * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
- * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
- * F-Mic = 0x1b, HP = 0x19
- */
-
-static const hda_nid_t alc880_dac_nids[4] = {
- /* front, rear, clfe, rear_surr */
- 0x02, 0x05, 0x04, 0x03
-};
-
-static const hda_nid_t alc880_adc_nids[3] = {
- /* ADC0-2 */
- 0x07, 0x08, 0x09,
-};
-
-/* The datasheet says the node 0x07 is connected from inputs,
- * but it shows zero connection in the real implementation on some devices.
- * Note: this is a 915GAV bug, fixed on 915GLV
- */
-static const hda_nid_t alc880_adc_nids_alt[2] = {
- /* ADC1-2 */
- 0x08, 0x09,
-};
-
-#define ALC880_DIGOUT_NID 0x06
-#define ALC880_DIGIN_NID 0x0a
-
-static const struct hda_input_mux alc880_capture_source = {
- .num_items = 4,
- .items = {
- { "Mic", 0x0 },
- { "Front Mic", 0x3 },
- { "Line", 0x2 },
- { "CD", 0x4 },
- },
-};
-
-/* channel source setting (2/6 channel selection for 3-stack) */
-/* 2ch mode */
-static const struct hda_verb alc880_threestack_ch2_init[] = {
- /* set line-in to input, mute it */
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
- /* set mic-in to input vref 80%, mute it */
- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
- { } /* end */
-};
-
-/* 6ch mode */
-static const struct hda_verb alc880_threestack_ch6_init[] = {
- /* set line-in to output, unmute it */
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- /* set mic-in to output, unmute it */
- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { } /* end */
-};
-
-static const struct hda_channel_mode alc880_threestack_modes[2] = {
- { 2, alc880_threestack_ch2_init },
- { 6, alc880_threestack_ch6_init },
-};
-
-static const struct snd_kcontrol_new alc880_three_stack_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", 0x0f, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
- HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
- HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 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_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
- HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Channel Mode",
- .info = alc_ch_mode_info,
- .get = alc_ch_mode_get,
- .put = alc_ch_mode_put,
- },
- { } /* end */
-};
-
-/* capture mixer elements */
static int alc_cap_vol_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct alc_spec *spec = codec->spec;
+ unsigned long val;
int err;
mutex_lock(&codec->control_mutex);
- kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
- HDA_INPUT);
+ if (spec->vol_in_capsrc)
+ val = HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[0], 3, 0, HDA_OUTPUT);
+ else
+ val = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, HDA_INPUT);
+ kcontrol->private_value = val;
err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
mutex_unlock(&codec->control_mutex);
return err;
@@ -2710,11 +1715,15 @@ static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct alc_spec *spec = codec->spec;
+ unsigned long val;
int err;
mutex_lock(&codec->control_mutex);
- kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
- HDA_INPUT);
+ if (spec->vol_in_capsrc)
+ val = HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[0], 3, 0, HDA_OUTPUT);
+ else
+ val = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, HDA_INPUT);
+ kcontrol->private_value = val;
err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
mutex_unlock(&codec->control_mutex);
return err;
@@ -2732,7 +1741,7 @@ static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
int i, err = 0;
mutex_lock(&codec->control_mutex);
- if (check_adc_switch && spec->dual_adc_switch) {
+ if (check_adc_switch && spec->dyn_adc_switch) {
for (i = 0; i < spec->num_adc_nids; i++) {
kcontrol->private_value =
HDA_COMPOSE_AMP_VAL(spec->adc_nids[i],
@@ -2743,9 +1752,14 @@ static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
}
} else {
i = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
- kcontrol->private_value =
- HDA_COMPOSE_AMP_VAL(spec->adc_nids[i],
- 3, 0, HDA_INPUT);
+ if (spec->vol_in_capsrc)
+ kcontrol->private_value =
+ HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[i],
+ 3, 0, HDA_OUTPUT);
+ else
+ kcontrol->private_value =
+ HDA_COMPOSE_AMP_VAL(spec->adc_nids[i],
+ 3, 0, HDA_INPUT);
err = func(kcontrol, ucontrol);
}
error:
@@ -2840,335 +1854,6 @@ DEFINE_CAPMIX_NOSRC(2);
DEFINE_CAPMIX_NOSRC(3);
/*
- * ALC880 5-stack model
- *
- * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
- * Side = 0x02 (0xd)
- * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
- * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
- */
-
-/* additional mixers to alc880_three_stack_mixer */
-static const struct snd_kcontrol_new alc880_five_stack_mixer[] = {
- HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
- { } /* end */
-};
-
-/* channel source setting (6/8 channel selection for 5-stack) */
-/* 6ch mode */
-static const struct hda_verb alc880_fivestack_ch6_init[] = {
- /* set line-in to input, mute it */
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
- { } /* end */
-};
-
-/* 8ch mode */
-static const struct hda_verb alc880_fivestack_ch8_init[] = {
- /* set line-in to output, unmute it */
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { } /* end */
-};
-
-static const struct hda_channel_mode alc880_fivestack_modes[2] = {
- { 6, alc880_fivestack_ch6_init },
- { 8, alc880_fivestack_ch8_init },
-};
-
-
-/*
- * ALC880 6-stack model
- *
- * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
- * Side = 0x05 (0x0f)
- * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
- * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
- */
-
-static const hda_nid_t alc880_6st_dac_nids[4] = {
- /* front, rear, clfe, rear_surr */
- 0x02, 0x03, 0x04, 0x05
-};
-
-static const struct hda_input_mux alc880_6stack_capture_source = {
- .num_items = 4,
- .items = {
- { "Mic", 0x0 },
- { "Front Mic", 0x1 },
- { "Line", 0x2 },
- { "CD", 0x4 },
- },
-};
-
-/* fixed 8-channels */
-static const struct hda_channel_mode alc880_sixstack_modes[1] = {
- { 8, NULL },
-};
-
-static const struct snd_kcontrol_new alc880_six_stack_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", 0x0e, 1, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
- HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
- HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Side Playback Switch", 0x0f, 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_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Channel Mode",
- .info = alc_ch_mode_info,
- .get = alc_ch_mode_get,
- .put = alc_ch_mode_put,
- },
- { } /* end */
-};
-
-
-/*
- * ALC880 W810 model
- *
- * W810 has rear IO for:
- * Front (DAC 02)
- * Surround (DAC 03)
- * Center/LFE (DAC 04)
- * Digital out (06)
- *
- * The system also has a pair of internal speakers, and a headphone jack.
- * These are both connected to Line2 on the codec, hence to DAC 02.
- *
- * There is a variable resistor to control the speaker or headphone
- * volume. This is a hardware-only device without a software API.
- *
- * Plugging headphones in will disable the internal speakers. This is
- * implemented in hardware, not via the driver using jack sense. In
- * a similar fashion, plugging into the rear socket marked "front" will
- * disable both the speakers and headphones.
- *
- * For input, there's a microphone jack, and an "audio in" jack.
- * These may not do anything useful with this driver yet, because I
- * haven't setup any initialization verbs for these yet...
- */
-
-static const hda_nid_t alc880_w810_dac_nids[3] = {
- /* front, rear/surround, clfe */
- 0x02, 0x03, 0x04
-};
-
-/* fixed 6 channels */
-static const struct hda_channel_mode alc880_w810_modes[1] = {
- { 6, NULL }
-};
-
-/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
-static const struct snd_kcontrol_new alc880_w810_base_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", 0x0e, 1, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
- HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
- { } /* end */
-};
-
-
-/*
- * Z710V model
- *
- * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
- * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
- * Line = 0x1a
- */
-
-static const hda_nid_t alc880_z71v_dac_nids[1] = {
- 0x02
-};
-#define ALC880_Z71V_HP_DAC 0x03
-
-/* fixed 2 channels */
-static const struct hda_channel_mode alc880_2_jack_modes[1] = {
- { 2, NULL }
-};
-
-static const struct snd_kcontrol_new alc880_z71v_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
- HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Headphone 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("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- { } /* end */
-};
-
-
-/*
- * ALC880 F1734 model
- *
- * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
- * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
- */
-
-static const hda_nid_t alc880_f1734_dac_nids[1] = {
- 0x03
-};
-#define ALC880_F1734_HP_DAC 0x02
-
-static const struct snd_kcontrol_new alc880_f1734_mixer[] = {
- HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
- HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
- 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("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
- { } /* end */
-};
-
-static const struct hda_input_mux alc880_f1734_capture_source = {
- .num_items = 2,
- .items = {
- { "Mic", 0x1 },
- { "CD", 0x4 },
- },
-};
-
-
-/*
- * ALC880 ASUS model
- *
- * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
- * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
- * Mic = 0x18, Line = 0x1a
- */
-
-#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
-#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
-
-static const struct snd_kcontrol_new alc880_asus_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", 0x0e, 1, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
- HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 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_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Channel Mode",
- .info = alc_ch_mode_info,
- .get = alc_ch_mode_get,
- .put = alc_ch_mode_put,
- },
- { } /* end */
-};
-
-/*
- * ALC880 ASUS W1V model
- *
- * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
- * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
- * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
- */
-
-/* additional mixers to alc880_asus_mixer */
-static const struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
- HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
- HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
- { } /* end */
-};
-
-/* TCL S700 */
-static const struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 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("Capture Volume", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
- { } /* end */
-};
-
-/* Uniwill */
-static const struct snd_kcontrol_new alc880_uniwill_mixer[] = {
- HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
- HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
- HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
- HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 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_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Channel Mode",
- .info = alc_ch_mode_info,
- .get = alc_ch_mode_get,
- .put = alc_ch_mode_put,
- },
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
- HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
- HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
- 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("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 */
-};
-
-static const struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
- HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
- 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_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- { } /* end */
-};
-
-/*
* virtual master controls
*/
@@ -3185,6 +1870,7 @@ static const char * const alc_slave_vols[] = {
"Speaker Playback Volume",
"Mono Playback Volume",
"Line-Out Playback Volume",
+ "PCM Playback Volume",
NULL,
};
@@ -3199,6 +1885,7 @@ static const char * const alc_slave_sws[] = {
"Mono Playback Switch",
"IEC958 Playback Switch",
"Line-Out Playback Switch",
+ "PCM Playback Switch",
NULL,
};
@@ -3247,6 +1934,7 @@ static int alc_build_controls(struct hda_codec *codec)
}
if (spec->multiout.dig_out_nid) {
err = snd_hda_create_spdif_out_ctls(codec,
+ spec->multiout.dig_out_nid,
spec->multiout.dig_out_nid);
if (err < 0)
return err;
@@ -3306,15 +1994,13 @@ static int alc_build_controls(struct hda_codec *codec)
if (!kctl)
kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
for (i = 0; kctl && i < kctl->count; i++) {
- const hda_nid_t *nids = spec->capsrc_nids;
- if (!nids)
- nids = spec->adc_nids;
- err = snd_hda_add_nid(codec, kctl, i, nids[i]);
+ err = snd_hda_add_nid(codec, kctl, i,
+ get_capsrc(spec, i));
if (err < 0)
return err;
}
}
- if (spec->cap_mixer) {
+ if (spec->cap_mixer && spec->adc_nids) {
const char *kname = kctl ? kctl->id.name : NULL;
for (knew = spec->cap_mixer; knew->name; knew++) {
if (kname && strcmp(knew->name, kname) == 0)
@@ -3378,799 +2064,20 @@ static int alc_build_controls(struct hda_codec *codec)
/*
- * initialize the codec volumes, etc
- */
-
-/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static const struct hda_verb alc880_volume_init_verbs[] = {
- /*
- * Unmute ADC0-2 and set the default input to mic-in
- */
- {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
- /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
- * mixer widget
- * Note: PASD motherboards uses the Line In 2 as the input for front
- * panel mic (mic 2)
- */
- /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
-
- /*
- * Set up output mixers (0x0c - 0x0f)
- */
- /* set vol=0 to output mixers */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- /* set up input amps for analog loopback */
- /* Amp Indices: DAC = 0, mixer = 1 */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-
- { }
-};
-
-/*
- * 3-stack pin configuration:
- * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
- */
-static const struct hda_verb alc880_pin_3stack_init_verbs[] = {
- /*
- * preset connection lists of input pins
- * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
- */
- {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
- {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
- {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
-
- /*
- * Set pin mode and muting
- */
- /* set front pin widgets 0x14 for output */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* Mic1 (rear panel) pin widget for input and vref at 80% */
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* Mic2 (as headphone out) for HP output */
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* Line In pin widget for input */
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* Line2 (as front mic) pin widget for input and vref at 80% */
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* CD pin widget for input */
- {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
- { }
-};
-
-/*
- * 5-stack pin configuration:
- * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
- * line-in/side = 0x1a, f-mic = 0x1b
- */
-static const struct hda_verb alc880_pin_5stack_init_verbs[] = {
- /*
- * preset connection lists of input pins
- * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
- */
- {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
- {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
-
- /*
- * Set pin mode and muting
- */
- /* set pin widgets 0x14-0x17 for output */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- /* unmute pins for output (no gain on this amp) */
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
- /* Mic1 (rear panel) pin widget for input and vref at 80% */
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* Mic2 (as headphone out) for HP output */
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* Line In pin widget for input */
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* Line2 (as front mic) pin widget for input and vref at 80% */
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* CD pin widget for input */
- {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
- { }
-};
-
-/*
- * W810 pin configuration:
- * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
- */
-static const struct hda_verb alc880_pin_w810_init_verbs[] = {
- /* hphone/speaker input selector: front DAC */
- {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
-
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-
- { }
-};
-
-/*
- * Z71V pin configuration:
- * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
- */
-static const struct hda_verb alc880_pin_z71v_init_verbs[] = {
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
- { }
-};
-
-/*
- * 6-stack pin configuration:
- * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
- * f-mic = 0x19, line = 0x1a, HP = 0x1b
- */
-static const struct hda_verb alc880_pin_6stack_init_verbs[] = {
- {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
-
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
- { }
-};
-
-/*
- * Uniwill pin configuration:
- * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
- * line = 0x1a
- */
-static const struct hda_verb alc880_uniwill_init_verbs[] = {
- {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
-
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
-
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
- /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
- {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
- {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
-
- { }
-};
-
-/*
-* Uniwill P53
-* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
- */
-static const struct hda_verb alc880_uniwill_p53_init_verbs[] = {
- {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
-
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
-
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-
- {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
-
- { }
-};
-
-static const struct hda_verb alc880_beep_init_verbs[] = {
- { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
- { }
-};
-
-/* auto-toggle front mic */
-static void alc88x_simple_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 alc880_uniwill_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x14;
- spec->autocfg.speaker_pins[0] = 0x15;
- spec->autocfg.speaker_pins[0] = 0x16;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static void alc880_uniwill_init_hook(struct hda_codec *codec)
-{
- alc_hp_automute(codec);
- alc88x_simple_mic_automute(codec);
-}
-
-static void alc880_uniwill_unsol_event(struct hda_codec *codec,
- unsigned int res)
-{
- /* Looks like the unsol event is incompatible with the standard
- * definition. 4bit tag is placed at 28 bit!
- */
- switch (res >> 28) {
- case ALC880_MIC_EVENT:
- alc88x_simple_mic_automute(codec);
- break;
- default:
- alc_sku_unsol_event(codec, res);
- break;
- }
-}
-
-static void alc880_uniwill_p53_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x14;
- spec->autocfg.speaker_pins[0] = 0x15;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
-{
- unsigned int present;
-
- present = snd_hda_codec_read(codec, 0x21, 0,
- AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
- present &= HDA_AMP_VOLMASK;
- snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
- HDA_AMP_VOLMASK, present);
- snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
- HDA_AMP_VOLMASK, present);
-}
-
-static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
- unsigned int res)
-{
- /* Looks like the unsol event is incompatible with the standard
- * definition. 4bit tag is placed at 28 bit!
- */
- if ((res >> 28) == ALC880_DCVOL_EVENT)
- alc880_uniwill_p53_dcvol_automute(codec);
- else
- alc_sku_unsol_event(codec, res);
-}
-
-/*
- * F1734 pin configuration:
- * HP = 0x14, speaker-out = 0x15, mic = 0x18
- */
-static const struct hda_verb alc880_pin_f1734_init_verbs[] = {
- {0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
- {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
- {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
- {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
-
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
- {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
- {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
-
- { }
-};
-
-/*
- * ASUS pin configuration:
- * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
- */
-static const struct hda_verb alc880_pin_asus_init_verbs[] = {
- {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
- {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
- {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
-
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
- { }
-};
-
-/* Enable GPIO mask and set output */
-#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
-#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
-#define alc880_gpio3_init_verbs alc_gpio3_init_verbs
-
-/* Clevo m520g init */
-static const struct hda_verb alc880_pin_clevo_init_verbs[] = {
- /* headphone output */
- {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
- /* line-out */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* Line-in */
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* CD */
- {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* Mic1 (rear panel) */
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* Mic2 (front panel) */
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* headphone */
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* change to EAPD mode */
- {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
- {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
-
- { }
-};
-
-static const struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
- /* change to EAPD mode */
- {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
- {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
-
- /* Headphone output */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- /* Front output*/
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
-
- /* Line In pin widget for input */
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- /* CD pin widget for input */
- {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- /* Mic1 (rear panel) pin widget for input and vref at 80% */
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-
- /* change to EAPD mode */
- {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
- {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
-
- { }
-};
-
-/*
- * LG m1 express dual
- *
- * Pin assignment:
- * Rear Line-In/Out (blue): 0x14
- * Build-in Mic-In: 0x15
- * Speaker-out: 0x17
- * HP-Out (green): 0x1b
- * Mic-In/Out (red): 0x19
- * SPDIF-Out: 0x1e
- */
-
-/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
-static const hda_nid_t alc880_lg_dac_nids[3] = {
- 0x05, 0x02, 0x03
-};
-
-/* seems analog CD is not working */
-static const struct hda_input_mux alc880_lg_capture_source = {
- .num_items = 3,
- .items = {
- { "Mic", 0x1 },
- { "Line", 0x5 },
- { "Internal Mic", 0x6 },
- },
-};
-
-/* 2,4,6 channel modes */
-static const struct hda_verb alc880_lg_ch2_init[] = {
- /* set line-in and mic-in to input */
- { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
- { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
- { }
-};
-
-static const struct hda_verb alc880_lg_ch4_init[] = {
- /* set line-in to out and mic-in to input */
- { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
- { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
- { }
-};
-
-static const struct hda_verb alc880_lg_ch6_init[] = {
- /* set line-in and mic-in to output */
- { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
- { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
- { }
-};
-
-static const struct hda_channel_mode alc880_lg_ch_modes[3] = {
- { 2, alc880_lg_ch2_init },
- { 4, alc880_lg_ch4_init },
- { 6, alc880_lg_ch6_init },
-};
-
-static const struct snd_kcontrol_new alc880_lg_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
- HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
- HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
- HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
- HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
- HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
- HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Channel Mode",
- .info = alc_ch_mode_info,
- .get = alc_ch_mode_get,
- .put = alc_ch_mode_put,
- },
- { } /* end */
-};
-
-static const struct hda_verb alc880_lg_init_verbs[] = {
- /* set capture source to mic-in */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- /* mute all amp mixer inputs */
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
- /* line-in to input */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* built-in mic */
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* speaker-out */
- {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* mic-in to input */
- {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* HP-out */
- {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* jack sense */
- {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- { }
-};
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc880_lg_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x1b;
- spec->autocfg.speaker_pins[0] = 0x17;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-/*
- * LG LW20
- *
- * Pin assignment:
- * Speaker-out: 0x14
- * Mic-In: 0x18
- * Built-in Mic-In: 0x19
- * Line-In: 0x1b
- * HP-Out: 0x1a
- * SPDIF-Out: 0x1e
- */
-
-static const struct hda_input_mux alc880_lg_lw_capture_source = {
- .num_items = 3,
- .items = {
- { "Mic", 0x0 },
- { "Internal Mic", 0x1 },
- { "Line In", 0x2 },
- },
-};
-
-#define alc880_lg_lw_modes alc880_threestack_modes
-
-static const struct snd_kcontrol_new alc880_lg_lw_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", 0x0f, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
- HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
- HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, 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_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
- HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Channel Mode",
- .info = alc_ch_mode_info,
- .get = alc_ch_mode_get,
- .put = alc_ch_mode_put,
- },
- { } /* end */
-};
-
-static const struct hda_verb alc880_lg_lw_init_verbs[] = {
- {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
- {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
- {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
-
- /* set capture source to mic-in */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
- /* speaker-out */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* HP-out */
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* mic-in to input */
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* built-in mic */
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* jack sense */
- {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- { }
-};
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc880_lg_lw_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x1b;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static const struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
- HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, 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 Playback Switch", 0x0b, 0x1, HDA_INPUT),
- { } /* end */
-};
-
-static const struct hda_input_mux alc880_medion_rim_capture_source = {
- .num_items = 2,
- .items = {
- { "Mic", 0x0 },
- { "Internal Mic", 0x1 },
- },
-};
-
-static const struct hda_verb alc880_medion_rim_init_verbs[] = {
- {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
-
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
- /* Mic1 (rear panel) pin widget for input and vref at 80% */
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* Mic2 (as headphone out) for HP output */
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* Internal Speaker */
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
- {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
- {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
-
- {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- { }
-};
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc880_medion_rim_automute(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- alc_hp_automute(codec);
- /* toggle EAPD */
- if (spec->jack_present)
- snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
- else
- snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
-}
-
-static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
- unsigned int res)
-{
- /* Looks like the unsol event is incompatible with the standard
- * definition. 4bit tag is placed at 28 bit!
- */
- if ((res >> 28) == ALC880_HP_EVENT)
- alc880_medion_rim_automute(codec);
-}
-
-static void alc880_medion_rim_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x14;
- spec->autocfg.speaker_pins[0] = 0x1b;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static const struct hda_amp_list alc880_loopbacks[] = {
- { 0x0b, HDA_INPUT, 0 },
- { 0x0b, HDA_INPUT, 1 },
- { 0x0b, HDA_INPUT, 2 },
- { 0x0b, HDA_INPUT, 3 },
- { 0x0b, HDA_INPUT, 4 },
- { } /* end */
-};
-
-static const struct hda_amp_list alc880_lg_loopbacks[] = {
- { 0x0b, HDA_INPUT, 1 },
- { 0x0b, HDA_INPUT, 6 },
- { 0x0b, HDA_INPUT, 7 },
- { } /* end */
-};
-#endif
-
-/*
* Common callbacks
*/
static void alc_init_special_input_src(struct hda_codec *codec);
+static int alc269_fill_coef(struct hda_codec *codec);
static int alc_init(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
unsigned int i;
+ if (codec->vendor_id == 0x10ec0269)
+ alc269_fill_coef(codec);
+
alc_fix_pll(codec);
alc_auto_init_amp(codec, spec->init_amp);
@@ -4206,7 +2113,7 @@ static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
/*
* Analog playback callbacks
*/
-static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
+static int alc_playback_pcm_open(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
@@ -4215,7 +2122,7 @@ static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
hinfo);
}
-static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+static int alc_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
unsigned int stream_tag,
unsigned int format,
@@ -4226,7 +2133,7 @@ static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
stream_tag, format, substream);
}
-static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+static int alc_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
@@ -4237,7 +2144,7 @@ static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
/*
* Digital out
*/
-static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
+static int alc_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
@@ -4245,7 +2152,7 @@ static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
return snd_hda_multi_out_dig_open(codec, &spec->multiout);
}
-static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+static int alc_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
unsigned int stream_tag,
unsigned int format,
@@ -4256,7 +2163,7 @@ static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
stream_tag, format, substream);
}
-static int alc880_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+static int alc_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
@@ -4264,7 +2171,7 @@ static int alc880_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
}
-static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
+static int alc_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
@@ -4275,7 +2182,7 @@ static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
/*
* Analog capture
*/
-static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
+static int alc_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
unsigned int stream_tag,
unsigned int format,
@@ -4288,7 +2195,7 @@ static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
return 0;
}
-static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+static int alc_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
@@ -4300,21 +2207,21 @@ static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
}
/* analog capture with dynamic dual-adc changes */
-static int dualmic_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
+static int dyn_adc_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
unsigned int stream_tag,
unsigned int format,
struct snd_pcm_substream *substream)
{
struct alc_spec *spec = codec->spec;
- spec->cur_adc = spec->adc_nids[spec->cur_adc_idx];
+ spec->cur_adc = spec->adc_nids[spec->dyn_adc_idx[spec->cur_mux[0]]];
spec->cur_adc_stream_tag = stream_tag;
spec->cur_adc_format = format;
snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
return 0;
}
-static int dualmic_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+static int dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
@@ -4324,70 +2231,70 @@ static int dualmic_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
return 0;
}
-static const struct hda_pcm_stream dualmic_pcm_analog_capture = {
+static const struct hda_pcm_stream dyn_adc_pcm_analog_capture = {
.substreams = 1,
.channels_min = 2,
.channels_max = 2,
.nid = 0, /* fill later */
.ops = {
- .prepare = dualmic_capture_pcm_prepare,
- .cleanup = dualmic_capture_pcm_cleanup
+ .prepare = dyn_adc_capture_pcm_prepare,
+ .cleanup = dyn_adc_capture_pcm_cleanup
},
};
/*
*/
-static const struct hda_pcm_stream alc880_pcm_analog_playback = {
+static const struct hda_pcm_stream alc_pcm_analog_playback = {
.substreams = 1,
.channels_min = 2,
.channels_max = 8,
/* NID is set in alc_build_pcms */
.ops = {
- .open = alc880_playback_pcm_open,
- .prepare = alc880_playback_pcm_prepare,
- .cleanup = alc880_playback_pcm_cleanup
+ .open = alc_playback_pcm_open,
+ .prepare = alc_playback_pcm_prepare,
+ .cleanup = alc_playback_pcm_cleanup
},
};
-static const struct hda_pcm_stream alc880_pcm_analog_capture = {
+static const struct hda_pcm_stream alc_pcm_analog_capture = {
.substreams = 1,
.channels_min = 2,
.channels_max = 2,
/* NID is set in alc_build_pcms */
};
-static const struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
+static const struct hda_pcm_stream alc_pcm_analog_alt_playback = {
.substreams = 1,
.channels_min = 2,
.channels_max = 2,
/* NID is set in alc_build_pcms */
};
-static const struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
+static const struct hda_pcm_stream alc_pcm_analog_alt_capture = {
.substreams = 2, /* can be overridden */
.channels_min = 2,
.channels_max = 2,
/* NID is set in alc_build_pcms */
.ops = {
- .prepare = alc880_alt_capture_pcm_prepare,
- .cleanup = alc880_alt_capture_pcm_cleanup
+ .prepare = alc_alt_capture_pcm_prepare,
+ .cleanup = alc_alt_capture_pcm_cleanup
},
};
-static const struct hda_pcm_stream alc880_pcm_digital_playback = {
+static const struct hda_pcm_stream alc_pcm_digital_playback = {
.substreams = 1,
.channels_min = 2,
.channels_max = 2,
/* NID is set in alc_build_pcms */
.ops = {
- .open = alc880_dig_playback_pcm_open,
- .close = alc880_dig_playback_pcm_close,
- .prepare = alc880_dig_playback_pcm_prepare,
- .cleanup = alc880_dig_playback_pcm_cleanup
+ .open = alc_dig_playback_pcm_open,
+ .close = alc_dig_playback_pcm_close,
+ .prepare = alc_dig_playback_pcm_prepare,
+ .cleanup = alc_dig_playback_pcm_cleanup
},
};
-static const struct hda_pcm_stream alc880_pcm_digital_capture = {
+static const struct hda_pcm_stream alc_pcm_digital_capture = {
.substreams = 1,
.channels_min = 2,
.channels_max = 2,
@@ -4405,6 +2312,8 @@ static int alc_build_pcms(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
struct hda_pcm *info = spec->pcm_rec;
+ const struct hda_pcm_stream *p;
+ bool have_multi_adcs;
int i;
codec->num_pcms = 1;
@@ -4417,16 +2326,22 @@ static int alc_build_pcms(struct hda_codec *codec)
"%s Analog", codec->chip_name);
info->name = spec->stream_name_analog;
- if (spec->stream_analog_playback) {
- if (snd_BUG_ON(!spec->multiout.dac_nids))
- return -EINVAL;
- info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
+ if (spec->multiout.dac_nids > 0) {
+ p = spec->stream_analog_playback;
+ if (!p)
+ p = &alc_pcm_analog_playback;
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
}
- if (spec->stream_analog_capture) {
- if (snd_BUG_ON(!spec->adc_nids))
- return -EINVAL;
- info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
+ if (spec->adc_nids) {
+ p = spec->stream_analog_capture;
+ if (!p) {
+ if (spec->dyn_adc_switch)
+ p = &dyn_adc_pcm_analog_capture;
+ else
+ p = &alc_pcm_analog_capture;
+ }
+ info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
}
@@ -4453,14 +2368,18 @@ static int alc_build_pcms(struct hda_codec *codec)
info->pcm_type = spec->dig_out_type;
else
info->pcm_type = HDA_PCM_TYPE_SPDIF;
- if (spec->multiout.dig_out_nid &&
- spec->stream_digital_playback) {
- info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
+ if (spec->multiout.dig_out_nid) {
+ p = spec->stream_digital_playback;
+ if (!p)
+ p = &alc_pcm_digital_playback;
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
}
- if (spec->dig_in_nid &&
- spec->stream_digital_capture) {
- info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
+ if (spec->dig_in_nid) {
+ p = spec->stream_digital_capture;
+ if (!p)
+ p = &alc_pcm_digital_capture;
+ info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
}
/* FIXME: do we need this for all Realtek codec models? */
@@ -4473,15 +2392,19 @@ static int alc_build_pcms(struct hda_codec *codec)
/* If the use of more than one ADC is requested for the current
* model, configure a second analog capture-only PCM.
*/
+ have_multi_adcs = (spec->num_adc_nids > 1) &&
+ !spec->dyn_adc_switch && !spec->auto_mic &&
+ (!spec->input_mux || spec->input_mux->num_items > 1);
/* Additional Analaog capture for index #2 */
- if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
- (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
+ if (spec->alt_dac_nid || have_multi_adcs) {
codec->num_pcms = 3;
info = spec->pcm_rec + 2;
info->name = spec->stream_name_analog;
if (spec->alt_dac_nid) {
- info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
- *spec->stream_analog_alt_playback;
+ p = spec->stream_analog_alt_playback;
+ if (!p)
+ p = &alc_pcm_analog_alt_playback;
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
spec->alt_dac_nid;
} else {
@@ -4489,9 +2412,11 @@ static int alc_build_pcms(struct hda_codec *codec)
alc_pcm_null_stream;
info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
}
- if (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture) {
- info->stream[SNDRV_PCM_STREAM_CAPTURE] =
- *spec->stream_analog_alt_capture;
+ if (have_multi_adcs) {
+ p = spec->stream_analog_alt_capture;
+ if (!p)
+ p = &alc_pcm_analog_alt_capture;
+ info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
spec->adc_nids[1];
info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
@@ -4528,6 +2453,18 @@ static void alc_free_kctls(struct hda_codec *codec)
snd_array_free(&spec->kctls);
}
+static void alc_free_bind_ctls(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ if (spec->bind_ctls.list) {
+ struct hda_bind_ctls **ctl = spec->bind_ctls.list;
+ int i;
+ for (i = 0; i < spec->bind_ctls.used; i++)
+ kfree(ctl[i]);
+ }
+ snd_array_free(&spec->bind_ctls);
+}
+
static void alc_free(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
@@ -4538,6 +2475,7 @@ static void alc_free(struct hda_codec *codec)
alc_shutup(codec);
snd_hda_input_jack_free(codec);
alc_free_kctls(codec);
+ alc_free_bind_ctls(codec);
kfree(spec);
snd_hda_detach_beep_device(codec);
}
@@ -4558,7 +2496,7 @@ static int alc_suspend(struct hda_codec *codec, pm_message_t state)
}
#endif
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
static int alc_resume(struct hda_codec *codec)
{
msleep(150); /* to avoid pop noise */
@@ -4578,7 +2516,7 @@ static const struct hda_codec_ops alc_patch_ops = {
.init = alc_init,
.free = alc_free,
.unsol_event = alc_unsol_event,
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
.resume = alc_resume,
#endif
#ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -4601,678 +2539,46 @@ static int alc_codec_rename(struct hda_codec *codec, const char *name)
}
/*
- * Test configuration for debugging
- *
- * Almost all inputs/outputs are enabled. I/O pins can be configured via
- * enum controls.
+ * Rename codecs appropriately from COEF value
*/
-#ifdef CONFIG_SND_DEBUG
-static const hda_nid_t alc880_test_dac_nids[4] = {
- 0x02, 0x03, 0x04, 0x05
-};
-
-static const struct hda_input_mux alc880_test_capture_source = {
- .num_items = 7,
- .items = {
- { "In-1", 0x0 },
- { "In-2", 0x1 },
- { "In-3", 0x2 },
- { "In-4", 0x3 },
- { "CD", 0x4 },
- { "Front", 0x5 },
- { "Surround", 0x6 },
- },
+struct alc_codec_rename_table {
+ unsigned int vendor_id;
+ unsigned short coef_mask;
+ unsigned short coef_bits;
+ const char *name;
};
-static const struct hda_channel_mode alc880_test_modes[4] = {
- { 2, NULL },
- { 4, NULL },
- { 6, NULL },
- { 8, NULL },
+static struct alc_codec_rename_table rename_tbl[] = {
+ { 0x10ec0269, 0xfff0, 0x3010, "ALC277" },
+ { 0x10ec0269, 0xf0f0, 0x2010, "ALC259" },
+ { 0x10ec0269, 0xf0f0, 0x3010, "ALC258" },
+ { 0x10ec0269, 0x00f0, 0x0010, "ALC269VB" },
+ { 0x10ec0269, 0xffff, 0xa023, "ALC259" },
+ { 0x10ec0269, 0xffff, 0x6023, "ALC281X" },
+ { 0x10ec0269, 0x00f0, 0x0020, "ALC269VC" },
+ { 0x10ec0887, 0x00f0, 0x0030, "ALC887-VD" },
+ { 0x10ec0888, 0x00f0, 0x0030, "ALC888-VD" },
+ { 0x10ec0888, 0xf0f0, 0x3020, "ALC886" },
+ { 0x10ec0899, 0x2000, 0x2000, "ALC899" },
+ { 0x10ec0892, 0xffff, 0x8020, "ALC661" },
+ { 0x10ec0892, 0xffff, 0x8011, "ALC661" },
+ { 0x10ec0892, 0xffff, 0x4011, "ALC656" },
+ { } /* terminator */
};
-static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- static const char * const texts[] = {
- "N/A", "Line Out", "HP Out",
- "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
- };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 8;
- if (uinfo->value.enumerated.item >= 8)
- uinfo->value.enumerated.item = 7;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
-}
-
-static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
- unsigned int pin_ctl, item = 0;
-
- pin_ctl = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
- if (pin_ctl & AC_PINCTL_OUT_EN) {
- if (pin_ctl & AC_PINCTL_HP_EN)
- item = 2;
- else
- item = 1;
- } else if (pin_ctl & AC_PINCTL_IN_EN) {
- switch (pin_ctl & AC_PINCTL_VREFEN) {
- case AC_PINCTL_VREF_HIZ: item = 3; break;
- case AC_PINCTL_VREF_50: item = 4; break;
- case AC_PINCTL_VREF_GRD: item = 5; break;
- case AC_PINCTL_VREF_80: item = 6; break;
- case AC_PINCTL_VREF_100: item = 7; break;
- }
- }
- ucontrol->value.enumerated.item[0] = item;
- return 0;
-}
-
-static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
- static const unsigned int ctls[] = {
- 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
- AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
- AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
- AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
- AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
- AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
- };
- unsigned int old_ctl, new_ctl;
-
- old_ctl = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
- new_ctl = ctls[ucontrol->value.enumerated.item[0]];
- if (old_ctl != new_ctl) {
- int val;
- snd_hda_codec_write_cache(codec, nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
- new_ctl);
- val = ucontrol->value.enumerated.item[0] >= 3 ?
- HDA_AMP_MUTE : 0;
- snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
- HDA_AMP_MUTE, val);
- return 1;
- }
- return 0;
-}
-
-static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- static const char * const texts[] = {
- "Front", "Surround", "CLFE", "Side"
- };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 4;
- if (uinfo->value.enumerated.item >= 4)
- uinfo->value.enumerated.item = 3;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
-}
-
-static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int alc_codec_rename_from_preset(struct hda_codec *codec)
{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
- unsigned int sel;
-
- sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
- ucontrol->value.enumerated.item[0] = sel & 3;
- return 0;
-}
+ const struct alc_codec_rename_table *p;
-static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
- unsigned int sel;
-
- sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
- if (ucontrol->value.enumerated.item[0] != sel) {
- sel = ucontrol->value.enumerated.item[0] & 3;
- snd_hda_codec_write_cache(codec, nid, 0,
- AC_VERB_SET_CONNECT_SEL, sel);
- return 1;
+ for (p = rename_tbl; p->vendor_id; p++) {
+ if (p->vendor_id != codec->vendor_id)
+ continue;
+ if ((alc_get_coef0(codec) & p->coef_mask) == p->coef_bits)
+ return alc_codec_rename(codec, p->name);
}
return 0;
}
-#define PIN_CTL_TEST(xname,nid) { \
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
- .name = xname, \
- .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
- .info = alc_test_pin_ctl_info, \
- .get = alc_test_pin_ctl_get, \
- .put = alc_test_pin_ctl_put, \
- .private_value = nid \
- }
-
-#define PIN_SRC_TEST(xname,nid) { \
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
- .name = xname, \
- .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
- .info = alc_test_pin_src_info, \
- .get = alc_test_pin_src_get, \
- .put = alc_test_pin_src_put, \
- .private_value = nid \
- }
-
-static const struct snd_kcontrol_new alc880_test_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
- HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
- HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
- HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
- PIN_CTL_TEST("Front Pin Mode", 0x14),
- PIN_CTL_TEST("Surround Pin Mode", 0x15),
- PIN_CTL_TEST("CLFE Pin Mode", 0x16),
- PIN_CTL_TEST("Side Pin Mode", 0x17),
- PIN_CTL_TEST("In-1 Pin Mode", 0x18),
- PIN_CTL_TEST("In-2 Pin Mode", 0x19),
- PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
- PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
- PIN_SRC_TEST("In-1 Pin Source", 0x18),
- PIN_SRC_TEST("In-2 Pin Source", 0x19),
- PIN_SRC_TEST("In-3 Pin Source", 0x1a),
- PIN_SRC_TEST("In-4 Pin Source", 0x1b),
- HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
- HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
- HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
- HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
- HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
- HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Channel Mode",
- .info = alc_ch_mode_info,
- .get = alc_ch_mode_get,
- .put = alc_ch_mode_put,
- },
- { } /* end */
-};
-
-static const struct hda_verb alc880_test_init_verbs[] = {
- /* Unmute inputs of 0x0c - 0x0f */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- /* Vol output for 0x0c-0x0f */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- /* Set output pins 0x14-0x17 */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- /* Unmute output pins 0x14-0x17 */
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* Set input pins 0x18-0x1c */
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- /* Mute input pins 0x18-0x1b */
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* ADC set up */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* Analog input/passthru */
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
- { }
-};
-#endif
-
-/*
- */
-
-static const char * const alc880_models[ALC880_MODEL_LAST] = {
- [ALC880_3ST] = "3stack",
- [ALC880_TCL_S700] = "tcl",
- [ALC880_3ST_DIG] = "3stack-digout",
- [ALC880_CLEVO] = "clevo",
- [ALC880_5ST] = "5stack",
- [ALC880_5ST_DIG] = "5stack-digout",
- [ALC880_W810] = "w810",
- [ALC880_Z71V] = "z71v",
- [ALC880_6ST] = "6stack",
- [ALC880_6ST_DIG] = "6stack-digout",
- [ALC880_ASUS] = "asus",
- [ALC880_ASUS_W1V] = "asus-w1v",
- [ALC880_ASUS_DIG] = "asus-dig",
- [ALC880_ASUS_DIG2] = "asus-dig2",
- [ALC880_UNIWILL_DIG] = "uniwill",
- [ALC880_UNIWILL_P53] = "uniwill-p53",
- [ALC880_FUJITSU] = "fujitsu",
- [ALC880_F1734] = "F1734",
- [ALC880_LG] = "lg",
- [ALC880_LG_LW] = "lg-lw",
- [ALC880_MEDION_RIM] = "medion",
-#ifdef CONFIG_SND_DEBUG
- [ALC880_TEST] = "test",
-#endif
- [ALC880_AUTO] = "auto",
-};
-
-static const struct snd_pci_quirk alc880_cfg_tbl[] = {
- SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
- SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
- SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
- SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
- SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
- SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
- SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
- SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
- SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
- SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
- SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
- SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
- SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
- SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
- SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
- SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
- SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
- /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
- SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
- SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
- SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG),
- SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
- SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
- SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
- SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_ASUS), /* default ASUS */
- SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
- SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
- SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
- SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
- SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
- SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
- SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
- SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
- SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
- SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
- SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
- SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
- SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
- SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
- SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_F1734),
- SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
- SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
- SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
- SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM),
- SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
- SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
- SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
- SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU),
- SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_F1734),
- SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
- SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
- SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
- SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_LG),
- SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
- SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
- SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
- SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
- SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
- SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
- SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
- SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
- SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
- SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
- SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
- SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
- SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
- SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
- SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
- /* default Intel */
- SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_3ST),
- SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
- SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
- {}
-};
-
-/*
- * ALC880 codec presets
- */
-static const struct alc_config_preset alc880_presets[] = {
- [ALC880_3ST] = {
- .mixers = { alc880_three_stack_mixer },
- .init_verbs = { alc880_volume_init_verbs,
- alc880_pin_3stack_init_verbs },
- .num_dacs = ARRAY_SIZE(alc880_dac_nids),
- .dac_nids = alc880_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
- .channel_mode = alc880_threestack_modes,
- .need_dac_fix = 1,
- .input_mux = &alc880_capture_source,
- },
- [ALC880_3ST_DIG] = {
- .mixers = { alc880_three_stack_mixer },
- .init_verbs = { alc880_volume_init_verbs,
- alc880_pin_3stack_init_verbs },
- .num_dacs = ARRAY_SIZE(alc880_dac_nids),
- .dac_nids = alc880_dac_nids,
- .dig_out_nid = ALC880_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
- .channel_mode = alc880_threestack_modes,
- .need_dac_fix = 1,
- .input_mux = &alc880_capture_source,
- },
- [ALC880_TCL_S700] = {
- .mixers = { alc880_tcl_s700_mixer },
- .init_verbs = { alc880_volume_init_verbs,
- alc880_pin_tcl_S700_init_verbs,
- alc880_gpio2_init_verbs },
- .num_dacs = ARRAY_SIZE(alc880_dac_nids),
- .dac_nids = alc880_dac_nids,
- .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */
- .num_adc_nids = 1, /* single ADC */
- .hp_nid = 0x03,
- .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
- .channel_mode = alc880_2_jack_modes,
- .input_mux = &alc880_capture_source,
- },
- [ALC880_5ST] = {
- .mixers = { alc880_three_stack_mixer,
- alc880_five_stack_mixer},
- .init_verbs = { alc880_volume_init_verbs,
- alc880_pin_5stack_init_verbs },
- .num_dacs = ARRAY_SIZE(alc880_dac_nids),
- .dac_nids = alc880_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
- .channel_mode = alc880_fivestack_modes,
- .input_mux = &alc880_capture_source,
- },
- [ALC880_5ST_DIG] = {
- .mixers = { alc880_three_stack_mixer,
- alc880_five_stack_mixer },
- .init_verbs = { alc880_volume_init_verbs,
- alc880_pin_5stack_init_verbs },
- .num_dacs = ARRAY_SIZE(alc880_dac_nids),
- .dac_nids = alc880_dac_nids,
- .dig_out_nid = ALC880_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
- .channel_mode = alc880_fivestack_modes,
- .input_mux = &alc880_capture_source,
- },
- [ALC880_6ST] = {
- .mixers = { alc880_six_stack_mixer },
- .init_verbs = { alc880_volume_init_verbs,
- alc880_pin_6stack_init_verbs },
- .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
- .dac_nids = alc880_6st_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
- .channel_mode = alc880_sixstack_modes,
- .input_mux = &alc880_6stack_capture_source,
- },
- [ALC880_6ST_DIG] = {
- .mixers = { alc880_six_stack_mixer },
- .init_verbs = { alc880_volume_init_verbs,
- alc880_pin_6stack_init_verbs },
- .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
- .dac_nids = alc880_6st_dac_nids,
- .dig_out_nid = ALC880_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
- .channel_mode = alc880_sixstack_modes,
- .input_mux = &alc880_6stack_capture_source,
- },
- [ALC880_W810] = {
- .mixers = { alc880_w810_base_mixer },
- .init_verbs = { alc880_volume_init_verbs,
- alc880_pin_w810_init_verbs,
- alc880_gpio2_init_verbs },
- .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
- .dac_nids = alc880_w810_dac_nids,
- .dig_out_nid = ALC880_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
- .channel_mode = alc880_w810_modes,
- .input_mux = &alc880_capture_source,
- },
- [ALC880_Z71V] = {
- .mixers = { alc880_z71v_mixer },
- .init_verbs = { alc880_volume_init_verbs,
- alc880_pin_z71v_init_verbs },
- .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
- .dac_nids = alc880_z71v_dac_nids,
- .dig_out_nid = ALC880_DIGOUT_NID,
- .hp_nid = 0x03,
- .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
- .channel_mode = alc880_2_jack_modes,
- .input_mux = &alc880_capture_source,
- },
- [ALC880_F1734] = {
- .mixers = { alc880_f1734_mixer },
- .init_verbs = { alc880_volume_init_verbs,
- alc880_pin_f1734_init_verbs },
- .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
- .dac_nids = alc880_f1734_dac_nids,
- .hp_nid = 0x02,
- .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
- .channel_mode = alc880_2_jack_modes,
- .input_mux = &alc880_f1734_capture_source,
- .unsol_event = alc880_uniwill_p53_unsol_event,
- .setup = alc880_uniwill_p53_setup,
- .init_hook = alc_hp_automute,
- },
- [ALC880_ASUS] = {
- .mixers = { alc880_asus_mixer },
- .init_verbs = { alc880_volume_init_verbs,
- alc880_pin_asus_init_verbs,
- alc880_gpio1_init_verbs },
- .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
- .dac_nids = alc880_asus_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
- .channel_mode = alc880_asus_modes,
- .need_dac_fix = 1,
- .input_mux = &alc880_capture_source,
- },
- [ALC880_ASUS_DIG] = {
- .mixers = { alc880_asus_mixer },
- .init_verbs = { alc880_volume_init_verbs,
- alc880_pin_asus_init_verbs,
- alc880_gpio1_init_verbs },
- .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
- .dac_nids = alc880_asus_dac_nids,
- .dig_out_nid = ALC880_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
- .channel_mode = alc880_asus_modes,
- .need_dac_fix = 1,
- .input_mux = &alc880_capture_source,
- },
- [ALC880_ASUS_DIG2] = {
- .mixers = { alc880_asus_mixer },
- .init_verbs = { alc880_volume_init_verbs,
- alc880_pin_asus_init_verbs,
- alc880_gpio2_init_verbs }, /* use GPIO2 */
- .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
- .dac_nids = alc880_asus_dac_nids,
- .dig_out_nid = ALC880_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
- .channel_mode = alc880_asus_modes,
- .need_dac_fix = 1,
- .input_mux = &alc880_capture_source,
- },
- [ALC880_ASUS_W1V] = {
- .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
- .init_verbs = { alc880_volume_init_verbs,
- alc880_pin_asus_init_verbs,
- alc880_gpio1_init_verbs },
- .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
- .dac_nids = alc880_asus_dac_nids,
- .dig_out_nid = ALC880_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
- .channel_mode = alc880_asus_modes,
- .need_dac_fix = 1,
- .input_mux = &alc880_capture_source,
- },
- [ALC880_UNIWILL_DIG] = {
- .mixers = { alc880_asus_mixer },
- .init_verbs = { alc880_volume_init_verbs,
- alc880_pin_asus_init_verbs },
- .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
- .dac_nids = alc880_asus_dac_nids,
- .dig_out_nid = ALC880_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
- .channel_mode = alc880_asus_modes,
- .need_dac_fix = 1,
- .input_mux = &alc880_capture_source,
- },
- [ALC880_UNIWILL] = {
- .mixers = { alc880_uniwill_mixer },
- .init_verbs = { alc880_volume_init_verbs,
- alc880_uniwill_init_verbs },
- .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
- .dac_nids = alc880_asus_dac_nids,
- .dig_out_nid = ALC880_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
- .channel_mode = alc880_threestack_modes,
- .need_dac_fix = 1,
- .input_mux = &alc880_capture_source,
- .unsol_event = alc880_uniwill_unsol_event,
- .setup = alc880_uniwill_setup,
- .init_hook = alc880_uniwill_init_hook,
- },
- [ALC880_UNIWILL_P53] = {
- .mixers = { alc880_uniwill_p53_mixer },
- .init_verbs = { alc880_volume_init_verbs,
- alc880_uniwill_p53_init_verbs },
- .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
- .dac_nids = alc880_asus_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
- .channel_mode = alc880_threestack_modes,
- .input_mux = &alc880_capture_source,
- .unsol_event = alc880_uniwill_p53_unsol_event,
- .setup = alc880_uniwill_p53_setup,
- .init_hook = alc_hp_automute,
- },
- [ALC880_FUJITSU] = {
- .mixers = { alc880_fujitsu_mixer },
- .init_verbs = { alc880_volume_init_verbs,
- alc880_uniwill_p53_init_verbs,
- alc880_beep_init_verbs },
- .num_dacs = ARRAY_SIZE(alc880_dac_nids),
- .dac_nids = alc880_dac_nids,
- .dig_out_nid = ALC880_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
- .channel_mode = alc880_2_jack_modes,
- .input_mux = &alc880_capture_source,
- .unsol_event = alc880_uniwill_p53_unsol_event,
- .setup = alc880_uniwill_p53_setup,
- .init_hook = alc_hp_automute,
- },
- [ALC880_CLEVO] = {
- .mixers = { alc880_three_stack_mixer },
- .init_verbs = { alc880_volume_init_verbs,
- alc880_pin_clevo_init_verbs },
- .num_dacs = ARRAY_SIZE(alc880_dac_nids),
- .dac_nids = alc880_dac_nids,
- .hp_nid = 0x03,
- .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
- .channel_mode = alc880_threestack_modes,
- .need_dac_fix = 1,
- .input_mux = &alc880_capture_source,
- },
- [ALC880_LG] = {
- .mixers = { alc880_lg_mixer },
- .init_verbs = { alc880_volume_init_verbs,
- alc880_lg_init_verbs },
- .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
- .dac_nids = alc880_lg_dac_nids,
- .dig_out_nid = ALC880_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
- .channel_mode = alc880_lg_ch_modes,
- .need_dac_fix = 1,
- .input_mux = &alc880_lg_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc880_lg_setup,
- .init_hook = alc_hp_automute,
-#ifdef CONFIG_SND_HDA_POWER_SAVE
- .loopbacks = alc880_lg_loopbacks,
-#endif
- },
- [ALC880_LG_LW] = {
- .mixers = { alc880_lg_lw_mixer },
- .init_verbs = { alc880_volume_init_verbs,
- alc880_lg_lw_init_verbs },
- .num_dacs = ARRAY_SIZE(alc880_dac_nids),
- .dac_nids = alc880_dac_nids,
- .dig_out_nid = ALC880_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
- .channel_mode = alc880_lg_lw_modes,
- .input_mux = &alc880_lg_lw_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc880_lg_lw_setup,
- .init_hook = alc_hp_automute,
- },
- [ALC880_MEDION_RIM] = {
- .mixers = { alc880_medion_rim_mixer },
- .init_verbs = { alc880_volume_init_verbs,
- alc880_medion_rim_init_verbs,
- alc_gpio2_init_verbs },
- .num_dacs = ARRAY_SIZE(alc880_dac_nids),
- .dac_nids = alc880_dac_nids,
- .dig_out_nid = ALC880_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
- .channel_mode = alc880_2_jack_modes,
- .input_mux = &alc880_medion_rim_capture_source,
- .unsol_event = alc880_medion_rim_unsol_event,
- .setup = alc880_medion_rim_setup,
- .init_hook = alc880_medion_rim_automute,
- },
-#ifdef CONFIG_SND_DEBUG
- [ALC880_TEST] = {
- .mixers = { alc880_test_mixer },
- .init_verbs = { alc880_test_init_verbs },
- .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
- .dac_nids = alc880_test_dac_nids,
- .dig_out_nid = ALC880_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
- .channel_mode = alc880_test_modes,
- .input_mux = &alc880_test_capture_source,
- },
-#endif
-};
-
/*
* Automatic parse of I/O pins from the BIOS configuration
*/
@@ -5281,19 +2587,17 @@ enum {
ALC_CTL_WIDGET_VOL,
ALC_CTL_WIDGET_MUTE,
ALC_CTL_BIND_MUTE,
+ ALC_CTL_BIND_VOL,
+ ALC_CTL_BIND_SW,
};
-static const struct snd_kcontrol_new alc880_control_templates[] = {
+static const struct snd_kcontrol_new alc_control_templates[] = {
HDA_CODEC_VOLUME(NULL, 0, 0, 0),
HDA_CODEC_MUTE(NULL, 0, 0, 0),
HDA_BIND_MUTE(NULL, 0, 0, 0),
+ HDA_BIND_VOL(NULL, 0),
+ HDA_BIND_SW(NULL, 0),
};
-static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec)
-{
- snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32);
- return snd_array_new(&spec->kctls);
-}
-
/* add dynamic controls */
static int add_control(struct alc_spec *spec, int type, const char *name,
int cidx, unsigned long val)
@@ -5303,7 +2607,7 @@ static int add_control(struct alc_spec *spec, int type, const char *name,
knew = alc_kcontrol_new(spec);
if (!knew)
return -ENOMEM;
- *knew = alc880_control_templates[type];
+ *knew = alc_control_templates[type];
knew->name = kstrdup(name, GFP_KERNEL);
if (!knew->name)
return -ENOMEM;
@@ -5332,60 +2636,16 @@ static int add_control_with_pfx(struct alc_spec *spec, int type,
#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \
add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val)
-#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
-#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
-#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
-#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
-#define alc880_idx_to_dac(nid) ((nid) + 0x02)
-#define alc880_dac_to_idx(nid) ((nid) - 0x02)
-#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
-#define alc880_idx_to_selector(nid) ((nid) + 0x10)
-#define ALC880_PIN_CD_NID 0x1c
-
-/* fill in the dac_nids table from the parsed pin configuration */
-static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
- const struct auto_pin_cfg *cfg)
-{
- hda_nid_t nid;
- int assigned[4];
- int i, j;
-
- memset(assigned, 0, sizeof(assigned));
- spec->multiout.dac_nids = spec->private_dac_nids;
-
- /* check the pins hardwired to audio widget */
- for (i = 0; i < cfg->line_outs; i++) {
- nid = cfg->line_out_pins[i];
- if (alc880_is_fixed_pin(nid)) {
- int idx = alc880_fixed_pin_idx(nid);
- spec->private_dac_nids[i] = alc880_idx_to_dac(idx);
- assigned[idx] = 1;
- }
- }
- /* left pins can be connect to any audio widget */
- for (i = 0; i < cfg->line_outs; i++) {
- nid = cfg->line_out_pins[i];
- if (alc880_is_fixed_pin(nid))
- continue;
- /* search for an empty channel */
- for (j = 0; j < cfg->line_outs; j++) {
- if (!assigned[j]) {
- spec->private_dac_nids[i] =
- alc880_idx_to_dac(j);
- assigned[j] = 1;
- break;
- }
- }
- }
- spec->multiout.num_dacs = cfg->line_outs;
- return 0;
-}
+static const char * const channel_name[4] = {
+ "Front", "Surround", "CLFE", "Side"
+};
-static const char *alc_get_line_out_pfx(struct alc_spec *spec,
- bool can_be_master)
+static const char *alc_get_line_out_pfx(struct alc_spec *spec, int ch,
+ bool can_be_master, int *index)
{
struct auto_pin_cfg *cfg = &spec->autocfg;
+ *index = 0;
if (cfg->line_outs == 1 && !spec->multi_ios &&
!cfg->hp_outs && !cfg->speaker_outs && can_be_master)
return "Master";
@@ -5394,122 +2654,26 @@ static const char *alc_get_line_out_pfx(struct alc_spec *spec,
case AUTO_PIN_SPEAKER_OUT:
if (cfg->line_outs == 1)
return "Speaker";
+ if (cfg->line_outs == 2)
+ return ch ? "Bass Speaker" : "Speaker";
break;
case AUTO_PIN_HP_OUT:
+ /* for multi-io case, only the primary out */
+ if (ch && spec->multi_ios)
+ break;
+ *index = ch;
return "Headphone";
default:
if (cfg->line_outs == 1 && !spec->multi_ios)
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 * const chname[4] = {
- "Front", "Surround", NULL /*CLFE*/, "Side"
- };
- const char *pfx = alc_get_line_out_pfx(spec, false);
- hda_nid_t nid;
- int i, err, noutputs;
-
- noutputs = cfg->line_outs;
- if (spec->multi_ios > 0)
- noutputs += spec->multi_ios;
-
- for (i = 0; i < noutputs; i++) {
- if (!spec->multiout.dac_nids[i])
- continue;
- nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
- if (!pfx && i == 2) {
- /* Center/LFE */
- err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
- "Center",
- HDA_COMPOSE_AMP_VAL(nid, 1, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
- "LFE",
- HDA_COMPOSE_AMP_VAL(nid, 2, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
- "Center",
- HDA_COMPOSE_AMP_VAL(nid, 1, 2,
- HDA_INPUT));
- if (err < 0)
- return err;
- err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
- "LFE",
- HDA_COMPOSE_AMP_VAL(nid, 2, 2,
- HDA_INPUT));
- if (err < 0)
- return err;
- } else {
- const char *name = pfx;
- int index = i;
- if (!name) {
- name = chname[i];
- index = 0;
- }
- err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
- name, index,
- HDA_COMPOSE_AMP_VAL(nid, 3, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
- name, index,
- HDA_COMPOSE_AMP_VAL(nid, 3, 2,
- HDA_INPUT));
- if (err < 0)
- return err;
- }
+ if (ch >= ARRAY_SIZE(channel_name)) {
+ snd_BUG();
+ return "PCM";
}
- return 0;
-}
-
-/* add playback controls for speaker and HP outputs */
-static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
- const char *pfx)
-{
- hda_nid_t nid;
- int err;
- if (!pin)
- return 0;
-
- if (alc880_is_fixed_pin(pin)) {
- nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
- /* specify the DAC as the extra output */
- if (!spec->multiout.hp_nid)
- spec->multiout.hp_nid = nid;
- else
- spec->multiout.extra_out_nid[0] = nid;
- /* control HP volume/switch on the output mixer amp */
- nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
- err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
- 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,
- HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
- if (err < 0)
- return err;
- } else if (alc880_is_multi_pin(pin)) {
- /* set manual connection */
- /* we have only a switch on HP-out PIN */
- err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
- HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
- }
- return 0;
+ return channel_name[ch];
}
/* create input playback/capture controls for the given pin */
@@ -5536,17 +2700,69 @@ static int alc_is_input_pin(struct hda_codec *codec, hda_nid_t nid)
return (pincap & AC_PINCAP_IN) != 0;
}
+/* Parse the codec tree and retrieve ADCs and corresponding capsrc MUXs */
+static int alc_auto_fill_adc_caps(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ hda_nid_t nid;
+ hda_nid_t *adc_nids = spec->private_adc_nids;
+ hda_nid_t *cap_nids = spec->private_capsrc_nids;
+ int max_nums = ARRAY_SIZE(spec->private_adc_nids);
+ int i, nums = 0;
+
+ nid = codec->start_nid;
+ for (i = 0; i < codec->num_nodes; i++, nid++) {
+ hda_nid_t src;
+ const hda_nid_t *list;
+ unsigned int caps = get_wcaps(codec, nid);
+ int type = get_wcaps_type(caps);
+
+ if (type != AC_WID_AUD_IN || (caps & AC_WCAP_DIGITAL))
+ continue;
+ adc_nids[nums] = nid;
+ cap_nids[nums] = nid;
+ src = nid;
+ for (;;) {
+ int n;
+ type = get_wcaps_type(get_wcaps(codec, src));
+ if (type == AC_WID_PIN)
+ break;
+ if (type == AC_WID_AUD_SEL) {
+ cap_nids[nums] = src;
+ break;
+ }
+ n = snd_hda_get_conn_list(codec, src, &list);
+ if (n > 1) {
+ cap_nids[nums] = src;
+ break;
+ } else if (n != 1)
+ break;
+ src = *list;
+ }
+ if (++nums >= max_nums)
+ break;
+ }
+ spec->adc_nids = spec->private_adc_nids;
+ spec->capsrc_nids = spec->private_capsrc_nids;
+ spec->num_adc_nids = nums;
+ return nums;
+}
+
/* create playback/capture controls for input pins */
-static int alc_auto_create_input_ctls(struct hda_codec *codec,
- const struct auto_pin_cfg *cfg,
- hda_nid_t mixer,
- hda_nid_t cap1, hda_nid_t cap2)
+static int alc_auto_create_input_ctls(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
+ const struct auto_pin_cfg *cfg = &spec->autocfg;
+ hda_nid_t mixer = spec->mixer_nid;
struct hda_input_mux *imux = &spec->private_imux[0];
- int i, err, idx, type_idx = 0;
+ int num_adcs;
+ int i, c, err, idx, type_idx = 0;
const char *prev_label = NULL;
+ num_adcs = alc_auto_fill_adc_caps(codec);
+ if (num_adcs < 0)
+ return 0;
+
for (i = 0; i < cfg->num_inputs; i++) {
hda_nid_t pin;
const char *label;
@@ -5573,21 +2789,21 @@ static int alc_auto_create_input_ctls(struct hda_codec *codec,
}
}
- if (!cap1)
- continue;
- idx = get_connection_index(codec, cap1, pin);
- if (idx < 0 && cap2)
- idx = get_connection_index(codec, cap2, pin);
- if (idx >= 0)
- snd_hda_add_imux_item(imux, label, idx, NULL);
+ for (c = 0; c < num_adcs; c++) {
+ hda_nid_t cap = get_capsrc(spec, c);
+ idx = get_connection_index(codec, cap, pin);
+ if (idx >= 0) {
+ spec->imux_pins[imux->num_items] = pin;
+ snd_hda_add_imux_item(imux, label, idx, NULL);
+ break;
+ }
+ }
}
- return 0;
-}
-static int alc880_auto_create_input_ctls(struct hda_codec *codec,
- const struct auto_pin_cfg *cfg)
-{
- return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x08, 0x09);
+ spec->num_mux_defs = 1;
+ spec->input_mux = imux;
+
+ return 0;
}
static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
@@ -5596,25 +2812,11 @@ static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
pin_type);
/* unmute pin */
- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+ if (nid_has_mute(codec, nid, HDA_OUTPUT))
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
AMP_OUT_UNMUTE);
}
-static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
- hda_nid_t nid, int pin_type,
- int dac_idx)
-{
- alc_set_pin_output(codec, nid, pin_type);
- /* need the manual connection? */
- if (alc880_is_multi_pin(nid)) {
- struct alc_spec *spec = codec->spec;
- int idx = alc880_multi_pin_idx(nid);
- snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
- AC_VERB_SET_CONNECT_SEL,
- alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
- }
-}
-
static int get_pin_type(int line_out_type)
{
if (line_out_type == AUTO_PIN_HP_OUT)
@@ -5623,32 +2825,7 @@ static int get_pin_type(int line_out_type)
return PIN_OUT;
}
-static void alc880_auto_init_multi_out(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- int i;
-
- for (i = 0; i < spec->autocfg.line_outs; i++) {
- hda_nid_t nid = spec->autocfg.line_out_pins[i];
- int pin_type = get_pin_type(spec->autocfg.line_out_type);
- alc880_auto_set_output_and_unmute(codec, nid, pin_type, i);
- }
-}
-
-static void alc880_auto_init_extra_out(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- hda_nid_t pin;
-
- pin = spec->autocfg.speaker_pins[0];
- if (pin) /* connect to front */
- alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
- pin = spec->autocfg.hp_pins[0];
- if (pin) /* connect to front */
- alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
-}
-
-static void alc880_auto_init_analog_input(struct hda_codec *codec)
+static void alc_auto_init_analog_input(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
@@ -5658,1734 +2835,1256 @@ static void alc880_auto_init_analog_input(struct hda_codec *codec)
hda_nid_t nid = cfg->inputs[i].pin;
if (alc_is_input_pin(codec, nid)) {
alc_set_input_pin(codec, nid, cfg->inputs[i].type);
- if (nid != ALC880_PIN_CD_NID &&
- (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
+ if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_AMP_GAIN_MUTE,
AMP_OUT_MUTE);
}
}
-}
-static void alc880_auto_init_input_src(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- int c;
-
- for (c = 0; c < spec->num_adc_nids; c++) {
- unsigned int mux_idx;
- const struct hda_input_mux *imux;
- mux_idx = c >= spec->num_mux_defs ? 0 : c;
- imux = &spec->input_mux[mux_idx];
- if (!imux->num_items && mux_idx > 0)
- imux = &spec->input_mux[0];
- if (imux)
- snd_hda_codec_write(codec, spec->adc_nids[c], 0,
- AC_VERB_SET_CONNECT_SEL,
- imux->items[0].index);
+ /* mute all loopback inputs */
+ if (spec->mixer_nid) {
+ int nums = snd_hda_get_conn_list(codec, spec->mixer_nid, NULL);
+ for (i = 0; i < nums; i++)
+ snd_hda_codec_write(codec, spec->mixer_nid, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE,
+ AMP_IN_MUTE(i));
}
}
-static int alc_auto_add_multi_channel_mode(struct hda_codec *codec);
-
-/* parse the BIOS configuration and set up the alc_spec */
-/* return 1 if successful, 0 if the proper config is not found,
- * or a negative error code
- */
-static int alc880_parse_auto_config(struct hda_codec *codec)
+/* convert from MIX nid to DAC */
+static hda_nid_t alc_auto_mix_to_dac(struct hda_codec *codec, hda_nid_t nid)
{
- struct alc_spec *spec = codec->spec;
- int err;
- static const hda_nid_t alc880_ignore[] = { 0x1d, 0 };
-
- err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
- alc880_ignore);
- if (err < 0)
- return err;
- if (!spec->autocfg.line_outs)
- return 0; /* can't find valid BIOS pin config */
-
- err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
- if (err < 0)
- return err;
- err = alc_auto_add_multi_channel_mode(codec);
- if (err < 0)
- return err;
- err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
- if (err < 0)
- return err;
- err = alc880_auto_create_extra_out(spec,
- spec->autocfg.speaker_pins[0],
- "Speaker");
- if (err < 0)
- return err;
- err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
- "Headphone");
- if (err < 0)
- return err;
- err = alc880_auto_create_input_ctls(codec, &spec->autocfg);
- if (err < 0)
- return err;
-
- spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-
- alc_auto_parse_digital(codec);
-
- if (spec->kctls.list)
- add_mixer(spec, spec->kctls.list);
+ hda_nid_t list[5];
+ int i, num;
- add_verb(spec, alc880_volume_init_verbs);
+ if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_AUD_OUT)
+ return nid;
+ num = snd_hda_get_connections(codec, nid, list, ARRAY_SIZE(list));
+ for (i = 0; i < num; i++) {
+ if (get_wcaps_type(get_wcaps(codec, list[i])) == AC_WID_AUD_OUT)
+ return list[i];
+ }
+ return 0;
+}
- spec->num_mux_defs = 1;
- spec->input_mux = &spec->private_imux[0];
+/* go down to the selector widget before the mixer */
+static hda_nid_t alc_go_down_to_selector(struct hda_codec *codec, hda_nid_t pin)
+{
+ hda_nid_t srcs[5];
+ int num = snd_hda_get_connections(codec, pin, srcs,
+ ARRAY_SIZE(srcs));
+ if (num != 1 ||
+ get_wcaps_type(get_wcaps(codec, srcs[0])) != AC_WID_AUD_SEL)
+ return pin;
+ return srcs[0];
+}
- alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
+/* get MIX nid connected to the given pin targeted to DAC */
+static hda_nid_t alc_auto_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
+ hda_nid_t dac)
+{
+ hda_nid_t mix[5];
+ int i, num;
- return 1;
+ pin = alc_go_down_to_selector(codec, pin);
+ num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
+ for (i = 0; i < num; i++) {
+ if (alc_auto_mix_to_dac(codec, mix[i]) == dac)
+ return mix[i];
+ }
+ return 0;
}
-/* additional initialization for auto-configuration model */
-static void alc880_auto_init(struct hda_codec *codec)
+/* select the connection from pin to DAC if needed */
+static int alc_auto_select_dac(struct hda_codec *codec, hda_nid_t pin,
+ hda_nid_t dac)
{
- struct alc_spec *spec = codec->spec;
- alc880_auto_init_multi_out(codec);
- alc880_auto_init_extra_out(codec);
- alc880_auto_init_analog_input(codec);
- alc880_auto_init_input_src(codec);
- alc_auto_init_digital(codec);
- if (spec->unsol_event)
- alc_inithook(codec);
+ hda_nid_t mix[5];
+ int i, num;
+
+ pin = alc_go_down_to_selector(codec, pin);
+ num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
+ if (num < 2)
+ return 0;
+ for (i = 0; i < num; i++) {
+ if (alc_auto_mix_to_dac(codec, mix[i]) == dac) {
+ snd_hda_codec_update_cache(codec, pin, 0,
+ AC_VERB_SET_CONNECT_SEL, i);
+ return 0;
+ }
+ }
+ return 0;
}
-/* check the ADC/MUX contains all input pins; some ADC/MUX contains only
- * one of two digital mic pins, e.g. on ALC272
- */
-static void fixup_automic_adc(struct hda_codec *codec)
+/* look for an empty DAC slot */
+static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
{
struct alc_spec *spec = codec->spec;
- int i;
-
- for (i = 0; i < spec->num_adc_nids; i++) {
- hda_nid_t cap = spec->capsrc_nids ?
- spec->capsrc_nids[i] : spec->adc_nids[i];
- int iidx, eidx;
+ hda_nid_t srcs[5];
+ int i, num;
- iidx = get_connection_index(codec, cap, spec->int_mic.pin);
- if (iidx < 0)
+ pin = alc_go_down_to_selector(codec, pin);
+ num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
+ for (i = 0; i < num; i++) {
+ hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]);
+ if (!nid)
continue;
- eidx = get_connection_index(codec, cap, spec->ext_mic.pin);
- if (eidx < 0)
+ if (found_in_nid_list(nid, spec->multiout.dac_nids,
+ ARRAY_SIZE(spec->private_dac_nids)))
continue;
- spec->int_mic.mux_idx = iidx;
- spec->ext_mic.mux_idx = eidx;
- if (spec->capsrc_nids)
- spec->capsrc_nids += i;
- spec->adc_nids += i;
- spec->num_adc_nids = 1;
- /* optional dock-mic */
- eidx = get_connection_index(codec, cap, spec->dock_mic.pin);
- if (eidx < 0)
- spec->dock_mic.pin = 0;
- else
- spec->dock_mic.mux_idx = eidx;
- return;
+ if (found_in_nid_list(nid, spec->multiout.hp_out_nid,
+ ARRAY_SIZE(spec->multiout.hp_out_nid)))
+ continue;
+ if (found_in_nid_list(nid, spec->multiout.extra_out_nid,
+ ARRAY_SIZE(spec->multiout.extra_out_nid)))
+ continue;
+ return nid;
}
- snd_printd(KERN_INFO "hda_codec: %s: "
- "No ADC/MUX containing both 0x%x and 0x%x pins\n",
- codec->chip_name, spec->int_mic.pin, spec->ext_mic.pin);
- spec->auto_mic = 0; /* disable auto-mic to be sure */
+ return 0;
}
-/* select or unmute the given capsrc route */
-static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap,
- int idx)
+static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin)
{
- if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
- snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
- HDA_AMP_MUTE, 0);
- } else {
- snd_hda_codec_write_cache(codec, cap, 0,
- AC_VERB_SET_CONNECT_SEL, idx);
- }
+ hda_nid_t sel = alc_go_down_to_selector(codec, pin);
+ if (snd_hda_get_conn_list(codec, sel, NULL) == 1)
+ return alc_auto_look_for_dac(codec, pin);
+ return 0;
}
-/* set the default connection to that pin */
-static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin)
+/* return 0 if no possible DAC is found, 1 if one or more found */
+static int alc_auto_fill_extra_dacs(struct hda_codec *codec, int num_outs,
+ const hda_nid_t *pins, hda_nid_t *dacs)
{
- struct alc_spec *spec = codec->spec;
int i;
- if (!pin)
- return 0;
- for (i = 0; i < spec->num_adc_nids; i++) {
- hda_nid_t cap = spec->capsrc_nids ?
- spec->capsrc_nids[i] : spec->adc_nids[i];
- int idx;
+ if (num_outs && !dacs[0]) {
+ dacs[0] = alc_auto_look_for_dac(codec, pins[0]);
+ if (!dacs[0])
+ return 0;
+ }
- idx = get_connection_index(codec, cap, pin);
- if (idx < 0)
- continue;
- select_or_unmute_capsrc(codec, cap, idx);
- return i; /* return the found index */
+ for (i = 1; i < num_outs; i++)
+ dacs[i] = get_dac_if_single(codec, pins[i]);
+ for (i = 1; i < num_outs; i++) {
+ if (!dacs[i])
+ dacs[i] = alc_auto_look_for_dac(codec, pins[i]);
}
- return -1; /* not found */
+ return 1;
}
-/* choose the ADC/MUX containing the input pin and initialize the setup */
-static void fixup_single_adc(struct hda_codec *codec)
+static int alc_auto_fill_multi_ios(struct hda_codec *codec,
+ unsigned int location);
+
+/* fill in the dac_nids table from the parsed pin configuration */
+static int alc_auto_fill_dac_nids(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
+ bool redone = false;
int i;
- /* search for the input pin; there must be only one */
- if (cfg->num_inputs != 1)
- return;
- i = init_capsrc_for_pin(codec, cfg->inputs[0].pin);
- if (i >= 0) {
- /* use only this ADC */
- if (spec->capsrc_nids)
- spec->capsrc_nids += i;
- spec->adc_nids += i;
- spec->num_adc_nids = 1;
- spec->single_input_src = 1;
+ again:
+ /* set num_dacs once to full for alc_auto_look_for_dac() */
+ spec->multiout.num_dacs = cfg->line_outs;
+ spec->multiout.hp_out_nid[0] = 0;
+ spec->multiout.extra_out_nid[0] = 0;
+ memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids));
+ spec->multiout.dac_nids = spec->private_dac_nids;
+ spec->multi_ios = 0;
+
+ /* fill hard-wired DACs first */
+ if (!redone) {
+ for (i = 0; i < cfg->line_outs; i++)
+ spec->private_dac_nids[i] =
+ get_dac_if_single(codec, cfg->line_out_pins[i]);
+ if (cfg->hp_outs)
+ spec->multiout.hp_out_nid[0] =
+ get_dac_if_single(codec, cfg->hp_pins[0]);
+ if (cfg->speaker_outs)
+ spec->multiout.extra_out_nid[0] =
+ get_dac_if_single(codec, cfg->speaker_pins[0]);
}
+
+ for (i = 0; i < cfg->line_outs; i++) {
+ hda_nid_t pin = cfg->line_out_pins[i];
+ if (spec->private_dac_nids[i])
+ continue;
+ spec->private_dac_nids[i] = alc_auto_look_for_dac(codec, pin);
+ if (!spec->private_dac_nids[i] && !redone) {
+ /* if we can't find primary DACs, re-probe without
+ * checking the hard-wired DACs
+ */
+ redone = true;
+ goto again;
+ }
+ }
+
+ /* re-count num_dacs and squash invalid entries */
+ spec->multiout.num_dacs = 0;
+ for (i = 0; i < cfg->line_outs; i++) {
+ if (spec->private_dac_nids[i])
+ spec->multiout.num_dacs++;
+ else {
+ memmove(spec->private_dac_nids + i,
+ spec->private_dac_nids + i + 1,
+ sizeof(hda_nid_t) * (cfg->line_outs - i - 1));
+ spec->private_dac_nids[cfg->line_outs - 1] = 0;
+ }
+ }
+
+ if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
+ /* try to fill multi-io first */
+ unsigned int location, defcfg;
+ int num_pins;
+
+ defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]);
+ location = get_defcfg_location(defcfg);
+
+ num_pins = alc_auto_fill_multi_ios(codec, location);
+ if (num_pins > 0) {
+ spec->multi_ios = num_pins;
+ spec->ext_channel_count = 2;
+ spec->multiout.num_dacs = num_pins + 1;
+ }
+ }
+
+ if (cfg->line_out_type != AUTO_PIN_HP_OUT)
+ alc_auto_fill_extra_dacs(codec, cfg->hp_outs, cfg->hp_pins,
+ spec->multiout.hp_out_nid);
+ if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
+ int err = alc_auto_fill_extra_dacs(codec, cfg->speaker_outs,
+ cfg->speaker_pins,
+ spec->multiout.extra_out_nid);
+ /* if no speaker volume is assigned, try again as the primary
+ * output
+ */
+ if (!err && cfg->speaker_outs > 0 &&
+ cfg->line_out_type == AUTO_PIN_HP_OUT) {
+ cfg->hp_outs = cfg->line_outs;
+ memcpy(cfg->hp_pins, cfg->line_out_pins,
+ sizeof(cfg->hp_pins));
+ cfg->line_outs = cfg->speaker_outs;
+ memcpy(cfg->line_out_pins, cfg->speaker_pins,
+ sizeof(cfg->speaker_pins));
+ cfg->speaker_outs = 0;
+ memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins));
+ cfg->line_out_type = AUTO_PIN_SPEAKER_OUT;
+ redone = false;
+ goto again;
+ }
+ }
+
+ return 0;
}
-/* initialize dual adcs */
-static void fixup_dual_adc_switch(struct hda_codec *codec)
+static inline unsigned int get_ctl_pos(unsigned int data)
{
- struct alc_spec *spec = codec->spec;
- init_capsrc_for_pin(codec, spec->ext_mic.pin);
- init_capsrc_for_pin(codec, spec->dock_mic.pin);
- init_capsrc_for_pin(codec, spec->int_mic.pin);
+ hda_nid_t nid = get_amp_nid_(data);
+ unsigned int dir;
+ if (snd_BUG_ON(nid >= MAX_VOL_NIDS))
+ return 0;
+ dir = get_amp_direction_(data);
+ return (nid << 1) | dir;
}
-/* initialize some special cases for input sources */
-static void alc_init_special_input_src(struct hda_codec *codec)
+#define is_ctl_used(bits, data) \
+ test_bit(get_ctl_pos(data), bits)
+#define mark_ctl_usage(bits, data) \
+ set_bit(get_ctl_pos(data), bits)
+
+static int alc_auto_add_vol_ctl(struct hda_codec *codec,
+ const char *pfx, int cidx,
+ hda_nid_t nid, unsigned int chs)
{
struct alc_spec *spec = codec->spec;
- if (spec->dual_adc_switch)
- fixup_dual_adc_switch(codec);
- else if (spec->single_input_src)
- init_capsrc_for_pin(codec, spec->autocfg.inputs[0].pin);
+ unsigned int val;
+ if (!nid)
+ return 0;
+ val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT);
+ if (is_ctl_used(spec->vol_ctls, val) && chs != 2) /* exclude LFE */
+ return 0;
+ mark_ctl_usage(spec->vol_ctls, val);
+ return __add_pb_vol_ctrl(codec->spec, ALC_CTL_WIDGET_VOL, pfx, cidx,
+ val);
}
-static void set_capture_mixer(struct hda_codec *codec)
+#define alc_auto_add_stereo_vol(codec, pfx, cidx, nid) \
+ alc_auto_add_vol_ctl(codec, pfx, cidx, nid, 3)
+
+/* create a mute-switch for the given mixer widget;
+ * if it has multiple sources (e.g. DAC and loopback), create a bind-mute
+ */
+static int alc_auto_add_sw_ctl(struct hda_codec *codec,
+ const char *pfx, int cidx,
+ hda_nid_t nid, unsigned int chs)
{
struct alc_spec *spec = codec->spec;
- static const struct snd_kcontrol_new *caps[2][3] = {
- { alc_capture_mixer_nosrc1,
- alc_capture_mixer_nosrc2,
- alc_capture_mixer_nosrc3 },
- { alc_capture_mixer1,
- alc_capture_mixer2,
- alc_capture_mixer3 },
- };
- if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) {
- int mux = 0;
- int num_adcs = spec->num_adc_nids;
- if (spec->dual_adc_switch)
- num_adcs = 1;
- else if (spec->auto_mic)
- fixup_automic_adc(codec);
- else if (spec->input_mux) {
- if (spec->input_mux->num_items > 1)
- mux = 1;
- else if (spec->input_mux->num_items == 1)
- fixup_single_adc(codec);
- }
- spec->cap_mixer = caps[mux][num_adcs - 1];
+ int wid_type;
+ int type;
+ unsigned long val;
+ if (!nid)
+ return 0;
+ wid_type = get_wcaps_type(get_wcaps(codec, nid));
+ if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT) {
+ type = ALC_CTL_WIDGET_MUTE;
+ val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT);
+ } else if (snd_hda_get_conn_list(codec, nid, NULL) == 1) {
+ type = ALC_CTL_WIDGET_MUTE;
+ val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT);
+ } else {
+ type = ALC_CTL_BIND_MUTE;
+ val = HDA_COMPOSE_AMP_VAL(nid, chs, 2, HDA_INPUT);
}
+ if (is_ctl_used(spec->sw_ctls, val) && chs != 2) /* exclude LFE */
+ return 0;
+ mark_ctl_usage(spec->sw_ctls, val);
+ return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val);
+}
+
+#define alc_auto_add_stereo_sw(codec, pfx, cidx, nid) \
+ alc_auto_add_sw_ctl(codec, pfx, cidx, nid, 3)
+
+static hda_nid_t alc_look_for_out_mute_nid(struct hda_codec *codec,
+ hda_nid_t pin, hda_nid_t dac)
+{
+ hda_nid_t mix = alc_auto_dac_to_mix(codec, pin, dac);
+ if (nid_has_mute(codec, pin, HDA_OUTPUT))
+ return pin;
+ else if (mix && nid_has_mute(codec, mix, HDA_INPUT))
+ return mix;
+ else if (nid_has_mute(codec, dac, HDA_OUTPUT))
+ return dac;
+ return 0;
}
-/* fill adc_nids (and capsrc_nids) containing all active input pins */
-static void fillup_priv_adc_nids(struct hda_codec *codec, const hda_nid_t *nids,
- int num_nids)
+static hda_nid_t alc_look_for_out_vol_nid(struct hda_codec *codec,
+ hda_nid_t pin, hda_nid_t dac)
+{
+ hda_nid_t mix = alc_auto_dac_to_mix(codec, pin, dac);
+ if (nid_has_volume(codec, dac, HDA_OUTPUT))
+ return dac;
+ else if (nid_has_volume(codec, mix, HDA_OUTPUT))
+ return mix;
+ else if (nid_has_volume(codec, pin, HDA_OUTPUT))
+ return pin;
+ return 0;
+}
+
+/* add playback controls from the parsed DAC table */
+static int alc_auto_create_multi_out_ctls(struct hda_codec *codec,
+ const struct auto_pin_cfg *cfg)
{
struct alc_spec *spec = codec->spec;
- struct auto_pin_cfg *cfg = &spec->autocfg;
- int n;
- hda_nid_t fallback_adc = 0, fallback_cap = 0;
+ int i, err, noutputs;
- for (n = 0; n < num_nids; n++) {
- hda_nid_t adc, cap;
- hda_nid_t conn[HDA_MAX_NUM_INPUTS];
- int nconns, i, j;
+ noutputs = cfg->line_outs;
+ if (spec->multi_ios > 0)
+ noutputs += spec->multi_ios;
- adc = nids[n];
- if (get_wcaps_type(get_wcaps(codec, adc)) != AC_WID_AUD_IN)
- continue;
- cap = adc;
- nconns = snd_hda_get_connections(codec, cap, conn,
- ARRAY_SIZE(conn));
- if (nconns == 1) {
- cap = conn[0];
- nconns = snd_hda_get_connections(codec, cap, conn,
- ARRAY_SIZE(conn));
- }
- if (nconns <= 0)
+ for (i = 0; i < noutputs; i++) {
+ const char *name;
+ int index;
+ hda_nid_t dac, pin;
+ hda_nid_t sw, vol;
+
+ dac = spec->multiout.dac_nids[i];
+ if (!dac)
continue;
- if (!fallback_adc) {
- fallback_adc = adc;
- fallback_cap = cap;
- }
- for (i = 0; i < cfg->num_inputs; i++) {
- hda_nid_t nid = cfg->inputs[i].pin;
- for (j = 0; j < nconns; j++) {
- if (conn[j] == nid)
- break;
- }
- if (j >= nconns)
- break;
- }
- if (i >= cfg->num_inputs) {
- int num_adcs = spec->num_adc_nids;
- spec->private_adc_nids[num_adcs] = adc;
- spec->private_capsrc_nids[num_adcs] = cap;
- spec->num_adc_nids++;
- spec->adc_nids = spec->private_adc_nids;
- if (adc != cap)
- spec->capsrc_nids = spec->private_capsrc_nids;
- }
- }
- if (!spec->num_adc_nids) {
- printk(KERN_WARNING "hda_codec: %s: no valid ADC found;"
- " using fallback 0x%x\n",
- codec->chip_name, fallback_adc);
- spec->private_adc_nids[0] = fallback_adc;
- spec->adc_nids = spec->private_adc_nids;
- if (fallback_adc != fallback_cap) {
- spec->private_capsrc_nids[0] = fallback_cap;
- spec->capsrc_nids = spec->private_adc_nids;
+ if (i >= cfg->line_outs)
+ pin = spec->multi_io[i - 1].pin;
+ else
+ pin = cfg->line_out_pins[i];
+
+ sw = alc_look_for_out_mute_nid(codec, pin, dac);
+ vol = alc_look_for_out_vol_nid(codec, pin, dac);
+ name = alc_get_line_out_pfx(spec, i, true, &index);
+ if (!name || !strcmp(name, "CLFE")) {
+ /* Center/LFE */
+ err = alc_auto_add_vol_ctl(codec, "Center", 0, vol, 1);
+ if (err < 0)
+ return err;
+ err = alc_auto_add_vol_ctl(codec, "LFE", 0, vol, 2);
+ if (err < 0)
+ return err;
+ err = alc_auto_add_sw_ctl(codec, "Center", 0, sw, 1);
+ if (err < 0)
+ return err;
+ err = alc_auto_add_sw_ctl(codec, "LFE", 0, sw, 2);
+ if (err < 0)
+ return err;
+ } else {
+ err = alc_auto_add_stereo_vol(codec, name, index, vol);
+ if (err < 0)
+ return err;
+ err = alc_auto_add_stereo_sw(codec, name, index, sw);
+ if (err < 0)
+ return err;
}
}
+ return 0;
}
-#ifdef CONFIG_SND_HDA_INPUT_BEEP
-#define set_beep_amp(spec, nid, idx, dir) \
- ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
+static int alc_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
+ hda_nid_t dac, const char *pfx,
+ int cidx)
+{
+ struct alc_spec *spec = codec->spec;
+ hda_nid_t sw, vol;
+ int err;
-static const struct snd_pci_quirk beep_white_list[] = {
- SND_PCI_QUIRK(0x1043, 0x103c, "ASUS", 1),
- SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
- SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
- SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1),
- SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1),
- SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
- {}
-};
+ if (!dac) {
+ unsigned int val;
+ /* the corresponding DAC is already occupied */
+ if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
+ return 0; /* no way */
+ /* create a switch only */
+ val = HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT);
+ if (is_ctl_used(spec->sw_ctls, val))
+ return 0; /* already created */
+ mark_ctl_usage(spec->sw_ctls, val);
+ return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, cidx, val);
+ }
-static inline int has_cdefine_beep(struct hda_codec *codec)
+ sw = alc_look_for_out_mute_nid(codec, pin, dac);
+ vol = alc_look_for_out_vol_nid(codec, pin, dac);
+ err = alc_auto_add_stereo_vol(codec, pfx, cidx, vol);
+ if (err < 0)
+ return err;
+ err = alc_auto_add_stereo_sw(codec, pfx, cidx, sw);
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+static struct hda_bind_ctls *new_bind_ctl(struct hda_codec *codec,
+ unsigned int nums,
+ struct hda_ctl_ops *ops)
{
struct alc_spec *spec = codec->spec;
- const struct snd_pci_quirk *q;
- q = snd_pci_quirk_lookup(codec->bus->pci, beep_white_list);
- if (q)
- return q->value;
- return spec->cdefine.enable_pcbeep;
+ struct hda_bind_ctls **ctlp, *ctl;
+ snd_array_init(&spec->bind_ctls, sizeof(ctl), 8);
+ ctlp = snd_array_new(&spec->bind_ctls);
+ if (!ctlp)
+ return NULL;
+ ctl = kzalloc(sizeof(*ctl) + sizeof(long) * (nums + 1), GFP_KERNEL);
+ *ctlp = ctl;
+ if (ctl)
+ ctl->ops = ops;
+ return ctl;
}
-#else
-#define set_beep_amp(spec, nid, idx, dir) /* NOP */
-#define has_cdefine_beep(codec) 0
-#endif
-/*
- * OK, here we have finally the patch for ALC880
- */
-
-static int patch_alc880(struct hda_codec *codec)
+/* add playback controls for speaker and HP outputs */
+static int alc_auto_create_extra_outs(struct hda_codec *codec, int num_pins,
+ const hda_nid_t *pins,
+ const hda_nid_t *dacs,
+ const char *pfx)
{
- struct alc_spec *spec;
- int board_config;
- int err;
-
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
- if (spec == NULL)
- return -ENOMEM;
-
- codec->spec = spec;
+ struct alc_spec *spec = codec->spec;
+ struct hda_bind_ctls *ctl;
+ char name[32];
+ int i, n, err;
- board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
- alc880_models,
- alc880_cfg_tbl);
- if (board_config < 0) {
- printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
- codec->chip_name);
- board_config = ALC880_AUTO;
- }
+ if (!num_pins || !pins[0])
+ return 0;
- if (board_config == ALC880_AUTO) {
- /* automatic parse from the BIOS config */
- err = alc880_parse_auto_config(codec);
- if (err < 0) {
- alc_free(codec);
- return err;
- } else if (!err) {
- printk(KERN_INFO
- "hda_codec: Cannot set up configuration "
- "from BIOS. Using 3-stack mode...\n");
- board_config = ALC880_3ST;
+ if (num_pins == 1) {
+ hda_nid_t dac = *dacs;
+ if (!dac)
+ dac = spec->multiout.dac_nids[0];
+ return alc_auto_create_extra_out(codec, *pins, dac, pfx, 0);
+ }
+
+ if (dacs[num_pins - 1]) {
+ /* OK, we have a multi-output system with individual volumes */
+ for (i = 0; i < num_pins; i++) {
+ if (num_pins >= 3) {
+ snprintf(name, sizeof(name), "%s %s",
+ pfx, channel_name[i]);
+ err = alc_auto_create_extra_out(codec, pins[i], dacs[i],
+ name, 0);
+ } else {
+ err = alc_auto_create_extra_out(codec, pins[i], dacs[i],
+ pfx, i);
+ }
+ if (err < 0)
+ return err;
}
+ return 0;
}
- err = snd_hda_attach_beep_device(codec, 0x1);
- if (err < 0) {
- alc_free(codec);
- return err;
+ /* Let's create a bind-controls */
+ ctl = new_bind_ctl(codec, num_pins, &snd_hda_bind_sw);
+ if (!ctl)
+ return -ENOMEM;
+ n = 0;
+ for (i = 0; i < num_pins; i++) {
+ if (get_wcaps(codec, pins[i]) & AC_WCAP_OUT_AMP)
+ ctl->values[n++] =
+ HDA_COMPOSE_AMP_VAL(pins[i], 3, 0, HDA_OUTPUT);
}
-
- if (board_config != ALC880_AUTO)
- setup_preset(codec, &alc880_presets[board_config]);
-
- spec->stream_analog_playback = &alc880_pcm_analog_playback;
- spec->stream_analog_capture = &alc880_pcm_analog_capture;
- spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
-
- spec->stream_digital_playback = &alc880_pcm_digital_playback;
- spec->stream_digital_capture = &alc880_pcm_digital_capture;
-
- if (!spec->adc_nids && spec->input_mux) {
- /* check whether NID 0x07 is valid */
- unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
- /* get type */
- wcap = get_wcaps_type(wcap);
- if (wcap != AC_WID_AUD_IN) {
- spec->adc_nids = alc880_adc_nids_alt;
- spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
- } else {
- spec->adc_nids = alc880_adc_nids;
- spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
- }
+ if (n) {
+ snprintf(name, sizeof(name), "%s Playback Switch", pfx);
+ err = add_control(spec, ALC_CTL_BIND_SW, name, 0, (long)ctl);
+ if (err < 0)
+ return err;
}
- set_capture_mixer(codec);
- set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
-
- spec->vmaster_nid = 0x0c;
-
- codec->patch_ops = alc_patch_ops;
- if (board_config == ALC880_AUTO)
- spec->init_hook = alc880_auto_init;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
- if (!spec->loopback.amplist)
- spec->loopback.amplist = alc880_loopbacks;
-#endif
+ ctl = new_bind_ctl(codec, num_pins, &snd_hda_bind_vol);
+ if (!ctl)
+ return -ENOMEM;
+ n = 0;
+ for (i = 0; i < num_pins; i++) {
+ hda_nid_t vol;
+ if (!pins[i] || !dacs[i])
+ continue;
+ vol = alc_look_for_out_vol_nid(codec, pins[i], dacs[i]);
+ if (vol)
+ ctl->values[n++] =
+ HDA_COMPOSE_AMP_VAL(vol, 3, 0, HDA_OUTPUT);
+ }
+ if (n) {
+ snprintf(name, sizeof(name), "%s Playback Volume", pfx);
+ err = add_control(spec, ALC_CTL_BIND_VOL, name, 0, (long)ctl);
+ if (err < 0)
+ return err;
+ }
return 0;
}
+static int alc_auto_create_hp_out(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ return alc_auto_create_extra_outs(codec, spec->autocfg.hp_outs,
+ spec->autocfg.hp_pins,
+ spec->multiout.hp_out_nid,
+ "Headphone");
+}
-/*
- * ALC260 support
- */
-
-static const hda_nid_t alc260_dac_nids[1] = {
- /* front */
- 0x02,
-};
-
-static const hda_nid_t alc260_adc_nids[1] = {
- /* ADC0 */
- 0x04,
-};
+static int alc_auto_create_speaker_out(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ return alc_auto_create_extra_outs(codec, spec->autocfg.speaker_outs,
+ spec->autocfg.speaker_pins,
+ spec->multiout.extra_out_nid,
+ "Speaker");
+}
-static const hda_nid_t alc260_adc_nids_alt[1] = {
- /* ADC1 */
- 0x05,
-};
+static void alc_auto_set_output_and_unmute(struct hda_codec *codec,
+ hda_nid_t pin, int pin_type,
+ hda_nid_t dac)
+{
+ int i, num;
+ hda_nid_t nid, mix = 0;
+ hda_nid_t srcs[HDA_MAX_CONNECTIONS];
-/* NIDs used when simultaneous access to both ADCs makes sense. Note that
- * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
- */
-static const hda_nid_t alc260_dual_adc_nids[2] = {
- /* ADC0, ADC1 */
- 0x04, 0x05
-};
+ alc_set_pin_output(codec, pin, pin_type);
+ nid = alc_go_down_to_selector(codec, pin);
+ num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
+ for (i = 0; i < num; i++) {
+ if (alc_auto_mix_to_dac(codec, srcs[i]) != dac)
+ continue;
+ mix = srcs[i];
+ break;
+ }
+ if (!mix)
+ return;
-#define ALC260_DIGOUT_NID 0x03
-#define ALC260_DIGIN_NID 0x06
+ /* need the manual connection? */
+ if (num > 1)
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i);
+ /* unmute mixer widget inputs */
+ if (nid_has_mute(codec, mix, HDA_INPUT)) {
+ snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+ AMP_IN_UNMUTE(0));
+ snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+ AMP_IN_UNMUTE(1));
+ }
+ /* initialize volume */
+ nid = alc_look_for_out_vol_nid(codec, pin, dac);
+ if (nid)
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+ AMP_OUT_ZERO);
-static const struct hda_input_mux alc260_capture_source = {
- .num_items = 4,
- .items = {
- { "Mic", 0x0 },
- { "Front Mic", 0x1 },
- { "Line", 0x2 },
- { "CD", 0x4 },
- },
-};
+ /* unmute DAC if it's not assigned to a mixer */
+ nid = alc_look_for_out_mute_nid(codec, pin, dac);
+ if (nid == mix && nid_has_mute(codec, dac, HDA_OUTPUT))
+ snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+ AMP_OUT_ZERO);
+}
-/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
- * headphone jack and the internal CD lines since these are the only pins at
- * which audio can appear. For flexibility, also allow the option of
- * recording the mixer output on the second ADC (ADC0 doesn't have a
- * connection to the mixer output).
- */
-static const struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
- {
- .num_items = 3,
- .items = {
- { "Mic/Line", 0x0 },
- { "CD", 0x4 },
- { "Headphone", 0x2 },
- },
- },
- {
- .num_items = 4,
- .items = {
- { "Mic/Line", 0x0 },
- { "CD", 0x4 },
- { "Headphone", 0x2 },
- { "Mixer", 0x5 },
- },
- },
+static void alc_auto_init_multi_out(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ int pin_type = get_pin_type(spec->autocfg.line_out_type);
+ int i;
-};
+ for (i = 0; i <= HDA_SIDE; i++) {
+ hda_nid_t nid = spec->autocfg.line_out_pins[i];
+ if (nid)
+ alc_auto_set_output_and_unmute(codec, nid, pin_type,
+ spec->multiout.dac_nids[i]);
+ }
+}
-/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
- * the Fujitsu S702x, but jacks are marked differently.
- */
-static const struct hda_input_mux alc260_acer_capture_sources[2] = {
- {
- .num_items = 4,
- .items = {
- { "Mic", 0x0 },
- { "Line", 0x2 },
- { "CD", 0x4 },
- { "Headphone", 0x5 },
- },
- },
- {
- .num_items = 5,
- .items = {
- { "Mic", 0x0 },
- { "Line", 0x2 },
- { "CD", 0x4 },
- { "Headphone", 0x6 },
- { "Mixer", 0x5 },
- },
- },
-};
+static void alc_auto_init_extra_out(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ int i;
+ hda_nid_t pin, dac;
-/* Maxdata Favorit 100XS */
-static const struct hda_input_mux alc260_favorit100_capture_sources[2] = {
- {
- .num_items = 2,
- .items = {
- { "Line/Mic", 0x0 },
- { "CD", 0x4 },
- },
- },
- {
- .num_items = 3,
- .items = {
- { "Line/Mic", 0x0 },
- { "CD", 0x4 },
- { "Mixer", 0x5 },
- },
- },
-};
+ for (i = 0; i < spec->autocfg.hp_outs; i++) {
+ if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)
+ break;
+ pin = spec->autocfg.hp_pins[i];
+ if (!pin)
+ break;
+ dac = spec->multiout.hp_out_nid[i];
+ if (!dac) {
+ if (i > 0 && spec->multiout.hp_out_nid[0])
+ dac = spec->multiout.hp_out_nid[0];
+ else
+ dac = spec->multiout.dac_nids[0];
+ }
+ alc_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
+ }
+ for (i = 0; i < spec->autocfg.speaker_outs; i++) {
+ if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
+ break;
+ pin = spec->autocfg.speaker_pins[i];
+ if (!pin)
+ break;
+ dac = spec->multiout.extra_out_nid[i];
+ if (!dac) {
+ if (i > 0 && spec->multiout.extra_out_nid[0])
+ dac = spec->multiout.extra_out_nid[0];
+ else
+ dac = spec->multiout.dac_nids[0];
+ }
+ alc_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac);
+ }
+}
/*
- * This is just place-holder, so there's something for alc_build_pcms to look
- * at when it calculates the maximum number of channels. ALC260 has no mixer
- * element which allows changing the channel mode, so the verb list is
- * never used.
+ * multi-io helper
*/
-static const struct hda_channel_mode alc260_modes[1] = {
- { 2, NULL },
-};
-
+static int alc_auto_fill_multi_ios(struct hda_codec *codec,
+ unsigned int location)
+{
+ struct alc_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ hda_nid_t prime_dac = spec->private_dac_nids[0];
+ int type, i, num_pins = 0;
-/* Mixer combinations
- *
- * basic: base_output + input + pc_beep + capture
- * HP: base_output + input + capture_alt
- * HP_3013: hp_3013 + input + capture
- * fujitsu: fujitsu + capture
- * acer: acer + capture
- */
+ for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
+ for (i = 0; i < cfg->num_inputs; i++) {
+ hda_nid_t nid = cfg->inputs[i].pin;
+ hda_nid_t dac;
+ unsigned int defcfg, caps;
+ if (cfg->inputs[i].type != type)
+ continue;
+ defcfg = snd_hda_codec_get_pincfg(codec, nid);
+ if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX)
+ continue;
+ if (location && get_defcfg_location(defcfg) != location)
+ continue;
+ caps = snd_hda_query_pin_caps(codec, nid);
+ if (!(caps & AC_PINCAP_OUT))
+ continue;
+ dac = alc_auto_look_for_dac(codec, nid);
+ if (!dac)
+ continue;
+ spec->multi_io[num_pins].pin = nid;
+ spec->multi_io[num_pins].dac = dac;
+ num_pins++;
+ spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
+ }
+ }
+ spec->multiout.num_dacs = 1;
+ if (num_pins < 2) {
+ /* clear up again */
+ memset(spec->private_dac_nids, 0,
+ sizeof(spec->private_dac_nids));
+ spec->private_dac_nids[0] = prime_dac;
+ return 0;
+ }
+ return num_pins;
+}
-static const struct snd_kcontrol_new alc260_base_output_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
- HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
- HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
- { } /* end */
-};
+static int alc_auto_ch_mode_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct alc_spec *spec = codec->spec;
-static const struct snd_kcontrol_new alc260_input_mixer[] = {
- HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
- HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
- HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
- HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
- HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
- { } /* end */
-};
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = spec->multi_ios + 1;
+ if (uinfo->value.enumerated.item > spec->multi_ios)
+ uinfo->value.enumerated.item = spec->multi_ios;
+ sprintf(uinfo->value.enumerated.name, "%dch",
+ (uinfo->value.enumerated.item + 1) * 2);
+ return 0;
+}
-/* update HP, line and mono out pins according to the master switch */
-static void alc260_hp_master_update(struct hda_codec *codec)
+static int alc_auto_ch_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
- update_speakers(codec);
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct alc_spec *spec = codec->spec;
+ ucontrol->value.enumerated.item[0] = (spec->ext_channel_count - 1) / 2;
+ return 0;
}
-static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output)
{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct alc_spec *spec = codec->spec;
- *ucontrol->value.integer.value = !spec->master_mute;
+ hda_nid_t nid = spec->multi_io[idx].pin;
+
+ if (!spec->multi_io[idx].ctl_in)
+ spec->multi_io[idx].ctl_in =
+ snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+ if (output) {
+ snd_hda_codec_update_cache(codec, nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
+ PIN_OUT);
+ if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
+ snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
+ HDA_AMP_MUTE, 0);
+ alc_auto_select_dac(codec, nid, spec->multi_io[idx].dac);
+ } else {
+ if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
+ snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
+ HDA_AMP_MUTE, HDA_AMP_MUTE);
+ snd_hda_codec_update_cache(codec, nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
+ spec->multi_io[idx].ctl_in);
+ }
return 0;
}
-static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int alc_auto_ch_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct alc_spec *spec = codec->spec;
- int val = !*ucontrol->value.integer.value;
+ int i, ch;
- if (val == spec->master_mute)
+ ch = ucontrol->value.enumerated.item[0];
+ if (ch < 0 || ch > spec->multi_ios)
+ return -EINVAL;
+ if (ch == (spec->ext_channel_count - 1) / 2)
return 0;
- spec->master_mute = val;
- alc260_hp_master_update(codec);
+ spec->ext_channel_count = (ch + 1) * 2;
+ for (i = 0; i < spec->multi_ios; i++)
+ alc_set_multi_io(codec, i, i < ch);
+ spec->multiout.max_channels = spec->ext_channel_count;
+ if (spec->need_dac_fix && !spec->const_channel_count)
+ spec->multiout.num_dacs = spec->multiout.max_channels / 2;
return 1;
}
-static const struct snd_kcontrol_new alc260_hp_output_mixer[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Master Playback Switch",
- .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
- .info = snd_ctl_boolean_mono_info,
- .get = alc260_hp_master_sw_get,
- .put = alc260_hp_master_sw_put,
- },
- HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
- HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
- HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
- HDA_OUTPUT),
- HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
- { } /* end */
-};
-
-static const struct hda_verb alc260_hp_unsol_verbs[] = {
- {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {},
+static const struct snd_kcontrol_new alc_auto_channel_mode_enum = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Channel Mode",
+ .info = alc_auto_ch_mode_info,
+ .get = alc_auto_ch_mode_get,
+ .put = alc_auto_ch_mode_put,
};
-static void alc260_hp_setup(struct hda_codec *codec)
+static int alc_auto_add_multi_channel_mode(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
- spec->autocfg.hp_pins[0] = 0x0f;
- spec->autocfg.speaker_pins[0] = 0x10;
- spec->autocfg.speaker_pins[1] = 0x11;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_PIN;
-}
+ if (spec->multi_ios > 0) {
+ struct snd_kcontrol_new *knew;
-static const struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Master Playback Switch",
- .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
- .info = snd_ctl_boolean_mono_info,
- .get = alc260_hp_master_sw_get,
- .put = alc260_hp_master_sw_put,
- },
- HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
- HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
- HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
- { } /* end */
-};
+ knew = alc_kcontrol_new(spec);
+ if (!knew)
+ return -ENOMEM;
+ *knew = alc_auto_channel_mode_enum;
+ knew->name = kstrdup("Channel Mode", GFP_KERNEL);
+ if (!knew->name)
+ return -ENOMEM;
+ }
+ return 0;
+}
-static void alc260_hp_3013_setup(struct hda_codec *codec)
+/* filter out invalid adc_nids (and capsrc_nids) that don't give all
+ * active input pins
+ */
+static void alc_remove_invalid_adc_nids(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
+ const struct hda_input_mux *imux;
+ hda_nid_t adc_nids[ARRAY_SIZE(spec->private_adc_nids)];
+ hda_nid_t capsrc_nids[ARRAY_SIZE(spec->private_adc_nids)];
+ int i, n, nums;
- spec->autocfg.hp_pins[0] = 0x15;
- spec->autocfg.speaker_pins[0] = 0x10;
- spec->autocfg.speaker_pins[1] = 0x11;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_PIN;
-}
+ imux = spec->input_mux;
+ if (!imux)
+ return;
+ if (spec->dyn_adc_switch)
+ return;
-static const struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
- .ops = &snd_hda_bind_vol,
- .values = {
- HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
- HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
- HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT),
- 0
- },
-};
+ nums = 0;
+ for (n = 0; n < spec->num_adc_nids; n++) {
+ hda_nid_t cap = spec->private_capsrc_nids[n];
+ int num_conns = snd_hda_get_conn_list(codec, cap, NULL);
+ for (i = 0; i < imux->num_items; i++) {
+ hda_nid_t pin = spec->imux_pins[i];
+ if (pin) {
+ if (get_connection_index(codec, cap, pin) < 0)
+ break;
+ } else if (num_conns <= imux->items[i].index)
+ break;
+ }
+ if (i >= imux->num_items) {
+ adc_nids[nums] = spec->private_adc_nids[n];
+ capsrc_nids[nums++] = cap;
+ }
+ }
+ if (!nums) {
+ /* check whether ADC-switch is possible */
+ if (!alc_check_dyn_adc_switch(codec)) {
+ printk(KERN_WARNING "hda_codec: %s: no valid ADC found;"
+ " using fallback 0x%x\n",
+ codec->chip_name, spec->private_adc_nids[0]);
+ spec->num_adc_nids = 1;
+ spec->auto_mic = 0;
+ return;
+ }
+ } else if (nums != spec->num_adc_nids) {
+ memcpy(spec->private_adc_nids, adc_nids,
+ nums * sizeof(hda_nid_t));
+ memcpy(spec->private_capsrc_nids, capsrc_nids,
+ nums * sizeof(hda_nid_t));
+ spec->num_adc_nids = nums;
+ }
-static const struct hda_bind_ctls alc260_dc7600_bind_switch = {
- .ops = &snd_hda_bind_sw,
- .values = {
- HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
- HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
- 0
- },
-};
+ if (spec->auto_mic)
+ alc_auto_mic_check_imux(codec); /* check auto-mic setups */
+ else if (spec->input_mux->num_items == 1)
+ spec->num_adc_nids = 1; /* reduce to a single ADC */
+}
-static const struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
- HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
- HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
- HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
- { } /* end */
-};
+/*
+ * initialize ADC paths
+ */
+static void alc_auto_init_adc(struct hda_codec *codec, int adc_idx)
+{
+ struct alc_spec *spec = codec->spec;
+ hda_nid_t nid;
-static const struct hda_verb alc260_hp_3013_unsol_verbs[] = {
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {},
-};
+ nid = spec->adc_nids[adc_idx];
+ /* mute ADC */
+ if (nid_has_mute(codec, nid, HDA_INPUT)) {
+ snd_hda_codec_write(codec, nid, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE,
+ AMP_IN_MUTE(0));
+ return;
+ }
+ if (!spec->capsrc_nids)
+ return;
+ nid = spec->capsrc_nids[adc_idx];
+ if (nid_has_mute(codec, nid, HDA_OUTPUT))
+ snd_hda_codec_write(codec, nid, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE,
+ AMP_OUT_MUTE);
+}
-static void alc260_hp_3012_setup(struct hda_codec *codec)
+static void alc_auto_init_input_src(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
+ int c, nums;
- spec->autocfg.hp_pins[0] = 0x10;
- spec->autocfg.speaker_pins[0] = 0x0f;
- spec->autocfg.speaker_pins[1] = 0x11;
- spec->autocfg.speaker_pins[2] = 0x15;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_PIN;
+ for (c = 0; c < spec->num_adc_nids; c++)
+ alc_auto_init_adc(codec, c);
+ if (spec->dyn_adc_switch)
+ nums = 1;
+ else
+ nums = spec->num_adc_nids;
+ for (c = 0; c < nums; c++)
+ alc_mux_select(codec, c, spec->cur_mux[c], true);
}
-/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
- * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
- */
-static const struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
- HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
- ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
- HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
- HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
- ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
- HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
- { } /* end */
-};
+/* add mic boosts if needed */
+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;
+ int type_idx = 0;
+ hda_nid_t nid;
+ const char *prev_label = NULL;
-/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
- * versions of the ALC260 don't act on requests to enable mic bias from NID
- * 0x0f (used to drive the headphone jack in these laptops). The ALC260
- * datasheet doesn't mention this restriction. At this stage it's not clear
- * whether this behaviour is intentional or is a hardware bug in chip
- * revisions available in early 2006. Therefore for now allow the
- * "Headphone Jack Mode" control to span all choices, but if it turns out
- * that the lack of mic bias for this NID is intentional we could change the
- * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
- *
- * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
- * don't appear to make the mic bias available from the "line" jack, even
- * though the NID used for this jack (0x14) can supply it. The theory is
- * that perhaps Acer have included blocking capacitors between the ALC260
- * and the output jack. If this turns out to be the case for all such
- * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
- * to ALC_PIN_DIR_INOUT_NOMICBIAS.
- *
- * The C20x Tablet series have a mono internal speaker which is controlled
- * via the chip's Mono sum widget and pin complex, so include the necessary
- * controls for such models. On models without a "mono speaker" the control
- * won't do anything.
- */
-static const struct snd_kcontrol_new alc260_acer_mixer[] = {
- HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
- ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
- HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
- HDA_OUTPUT),
- HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
- HDA_INPUT),
- HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
- HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
- ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
- HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
- HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
- ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
- { } /* end */
-};
+ 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) {
+ const char *label;
+ char boost_label[32];
-/* Maxdata Favorit 100XS: one output and one input (0x12) jack
- */
-static const struct snd_kcontrol_new alc260_favorit100_mixer[] = {
- HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
- ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
- HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
- ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
- { } /* end */
-};
+ label = hda_get_autocfg_input_label(codec, cfg, i);
+ if (prev_label && !strcmp(label, prev_label))
+ type_idx++;
+ else
+ type_idx = 0;
+ prev_label = label;
-/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
- * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
- */
-static const struct snd_kcontrol_new alc260_will_mixer[] = {
- HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
- ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
- HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
- HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
- ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
- HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
- HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
- { } /* end */
-};
+ 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;
+ }
+ }
+ return 0;
+}
-/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
- * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
- */
-static const struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
- HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
- ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
- HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
- HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
- HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
- HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
- ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
- { } /* end */
-};
+/* select or unmute the given capsrc route */
+static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap,
+ int idx)
+{
+ if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
+ snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
+ HDA_AMP_MUTE, 0);
+ } else if (snd_hda_get_conn_list(codec, cap, NULL) > 1) {
+ snd_hda_codec_write_cache(codec, cap, 0,
+ AC_VERB_SET_CONNECT_SEL, idx);
+ }
+}
-/*
- * initialization verbs
- */
-static const struct hda_verb alc260_init_verbs[] = {
- /* Line In pin widget for input */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- /* CD pin widget for input */
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- /* Mic1 (rear panel) pin widget for input and vref at 80% */
- {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- /* Mic2 (front panel) pin widget for input and vref at 80% */
- {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- /* LINE-2 is used for line-out in rear */
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- /* select line-out */
- {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* LINE-OUT pin */
- {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- /* enable HP */
- {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- /* enable Mono */
- {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- /* mute capture amp left and right */
- {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- /* set connection select to line in (default select for this ADC) */
- {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
- /* mute capture amp left and right */
- {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- /* set connection select to line in (default select for this ADC) */
- {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
- /* set vol=0 Line-Out mixer amp left and right */
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- /* unmute pin widget amp left and right (no gain on this amp) */
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* set vol=0 HP mixer amp left and right */
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- /* unmute pin widget amp left and right (no gain on this amp) */
- {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* set vol=0 Mono mixer amp left and right */
- {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- /* unmute pin widget amp left and right (no gain on this amp) */
- {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* unmute LINE-2 out pin */
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
- * Line In 2 = 0x03
- */
- /* mute analog inputs */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
- /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
- /* mute Front out path */
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- /* mute Headphone out path */
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- /* mute Mono out path */
- {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- { }
-};
+/* set the default connection to that pin */
+static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin)
+{
+ struct alc_spec *spec = codec->spec;
+ int i;
-#if 0 /* should be identical with alc260_init_verbs? */
-static const struct hda_verb alc260_hp_init_verbs[] = {
- /* Headphone and output */
- {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
- /* mono output */
- {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
- /* Mic1 (rear panel) pin widget for input and vref at 80% */
- {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
- /* Mic2 (front panel) pin widget for input and vref at 80% */
- {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
- /* Line In pin widget for input */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
- /* Line-2 pin widget for output */
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
- /* CD pin widget for input */
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
- /* unmute amp left and right */
- {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
- /* set connection select to line in (default select for this ADC) */
- {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
- /* unmute Line-Out mixer amp left and right (volume = 0) */
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
- /* mute pin widget amp left and right (no gain on this amp) */
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
- /* unmute HP mixer amp left and right (volume = 0) */
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
- /* mute pin widget amp left and right (no gain on this amp) */
- {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
- /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
- * Line In 2 = 0x03
- */
- /* mute analog inputs */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
- /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
- /* Unmute Front out path */
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
- /* Unmute Headphone out path */
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
- /* Unmute Mono out path */
- {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
- { }
-};
-#endif
+ if (!pin)
+ return 0;
+ for (i = 0; i < spec->num_adc_nids; i++) {
+ hda_nid_t cap = get_capsrc(spec, i);
+ int idx;
-static const struct hda_verb alc260_hp_3013_init_verbs[] = {
- /* Line out and output */
- {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
- /* mono output */
- {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
- /* Mic1 (rear panel) pin widget for input and vref at 80% */
- {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
- /* Mic2 (front panel) pin widget for input and vref at 80% */
- {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
- /* Line In pin widget for input */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
- /* Headphone pin widget for output */
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
- /* CD pin widget for input */
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
- /* unmute amp left and right */
- {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
- /* set connection select to line in (default select for this ADC) */
- {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
- /* unmute Line-Out mixer amp left and right (volume = 0) */
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
- /* mute pin widget amp left and right (no gain on this amp) */
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
- /* unmute HP mixer amp left and right (volume = 0) */
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
- /* mute pin widget amp left and right (no gain on this amp) */
- {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
- /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
- * Line In 2 = 0x03
- */
- /* mute analog inputs */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
- /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
- /* Unmute Front out path */
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
- /* Unmute Headphone out path */
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
- /* Unmute Mono out path */
- {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
- { }
-};
+ idx = get_connection_index(codec, cap, pin);
+ if (idx < 0)
+ continue;
+ select_or_unmute_capsrc(codec, cap, idx);
+ return i; /* return the found index */
+ }
+ return -1; /* not found */
+}
-/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
- * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
- * audio = 0x16, internal speaker = 0x10.
- */
-static const struct hda_verb alc260_fujitsu_init_verbs[] = {
- /* Disable all GPIOs */
- {0x01, AC_VERB_SET_GPIO_MASK, 0},
- /* Internal speaker is connected to headphone pin */
- {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- /* Headphone/Line-out jack connects to Line1 pin; make it an output */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
- {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- /* Ensure all other unused pins are disabled and muted. */
- {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
- {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
- {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-
- /* Disable digital (SPDIF) pins */
- {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
- {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
-
- /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
- * when acting as an output.
- */
- {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
-
- /* Start with output sum widgets muted and their output gains at min */
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
- /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
- {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* Unmute Line1 pin widget output buffer since it starts as an output.
- * If the pin mode is changed by the user the pin mode control will
- * take care of enabling the pin's input/output buffers as needed.
- * Therefore there's no need to enable the input buffer at this
- * stage.
- */
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* Unmute input buffer of pin widget used for Line-in (no equiv
- * mixer ctrl)
- */
- {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+/* initialize some special cases for input sources */
+static void alc_init_special_input_src(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ int i;
- /* Mute capture amp left and right */
- {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- /* Set ADC connection select to match default mixer setting - line
- * in (on mic1 pin)
- */
- {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
+ for (i = 0; i < spec->autocfg.num_inputs; i++)
+ init_capsrc_for_pin(codec, spec->autocfg.inputs[i].pin);
+}
- /* Do the same for the second ADC: mute capture input amp and
- * set ADC connection to line in (on mic1 pin)
- */
- {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
-
- /* Mute all inputs to mixer widget (even unconnected ones) */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
+/* assign appropriate capture mixers */
+static void set_capture_mixer(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ static const struct snd_kcontrol_new *caps[2][3] = {
+ { alc_capture_mixer_nosrc1,
+ alc_capture_mixer_nosrc2,
+ alc_capture_mixer_nosrc3 },
+ { alc_capture_mixer1,
+ alc_capture_mixer2,
+ alc_capture_mixer3 },
+ };
- { }
-};
+ /* check whether either of ADC or MUX has a volume control */
+ if (!nid_has_volume(codec, spec->adc_nids[0], HDA_INPUT)) {
+ if (!spec->capsrc_nids)
+ return; /* no volume */
+ if (!nid_has_volume(codec, spec->capsrc_nids[0], HDA_OUTPUT))
+ return; /* no volume in capsrc, too */
+ spec->vol_in_capsrc = 1;
+ }
-/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
- * similar laptops (adapted from Fujitsu init verbs).
- */
-static const struct hda_verb alc260_acer_init_verbs[] = {
- /* On TravelMate laptops, GPIO 0 enables the internal speaker and
- * the headphone jack. Turn this on and rely on the standard mute
- * methods whenever the user wants to turn these outputs off.
- */
- {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
- {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
- {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
- /* Internal speaker/Headphone jack is connected to Line-out pin */
- {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- /* Internal microphone/Mic jack is connected to Mic1 pin */
- {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
- /* Line In jack is connected to Line1 pin */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
- {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- /* Ensure all other unused pins are disabled and muted. */
- {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
- {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
- {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- /* Disable digital (SPDIF) pins */
- {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
- {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
-
- /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
- * bus when acting as outputs.
- */
- {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
- {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
-
- /* Start with output sum widgets muted and their output gains at min */
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
- /* Unmute Line-out pin widget amp left and right
- * (no equiv mixer ctrl)
- */
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
- {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* Unmute Mic1 and Line1 pin widget input buffers since they start as
- * inputs. If the pin mode is changed by the user the pin mode control
- * will take care of enabling the pin's input/output buffers as needed.
- * Therefore there's no need to enable the input buffer at this
- * stage.
- */
- {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ if (spec->num_adc_nids > 0) {
+ int mux = 0;
+ int num_adcs = 0;
- /* Mute capture amp left and right */
- {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- /* Set ADC connection select to match default mixer setting - mic
- * (on mic1 pin)
- */
- {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
+ if (spec->input_mux && spec->input_mux->num_items > 1)
+ mux = 1;
+ if (spec->auto_mic) {
+ num_adcs = 1;
+ mux = 0;
+ } else if (spec->dyn_adc_switch)
+ num_adcs = 1;
+ if (!num_adcs) {
+ if (spec->num_adc_nids > 3)
+ spec->num_adc_nids = 3;
+ else if (!spec->num_adc_nids)
+ return;
+ num_adcs = spec->num_adc_nids;
+ }
+ spec->cap_mixer = caps[mux][num_adcs - 1];
+ }
+}
- /* Do similar with the second ADC: mute capture input amp and
- * set ADC connection to mic to match ALSA's default state.
- */
- {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
-
- /* Mute all inputs to mixer widget (even unconnected ones) */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
+/*
+ * standard auto-parser initializations
+ */
+static void alc_auto_init_std(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ alc_auto_init_multi_out(codec);
+ alc_auto_init_extra_out(codec);
+ alc_auto_init_analog_input(codec);
+ alc_auto_init_input_src(codec);
+ alc_auto_init_digital(codec);
+ if (spec->unsol_event)
+ alc_inithook(codec);
+}
- { }
+/*
+ * Digital-beep handlers
+ */
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+#define set_beep_amp(spec, nid, idx, dir) \
+ ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
+
+static const struct snd_pci_quirk beep_white_list[] = {
+ SND_PCI_QUIRK(0x1043, 0x103c, "ASUS", 1),
+ SND_PCI_QUIRK(0x1043, 0x115d, "ASUS", 1),
+ SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
+ SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
+ SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1),
+ SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1),
+ SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
+ {}
};
-/* Initialisation sequence for Maxdata Favorit 100XS
- * (adapted from Acer init verbs).
+static inline int has_cdefine_beep(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ const struct snd_pci_quirk *q;
+ q = snd_pci_quirk_lookup(codec->bus->pci, beep_white_list);
+ if (q)
+ return q->value;
+ return spec->cdefine.enable_pcbeep;
+}
+#else
+#define set_beep_amp(spec, nid, idx, dir) /* NOP */
+#define has_cdefine_beep(codec) 0
+#endif
+
+/* parse the BIOS configuration and set up the alc_spec */
+/* return 1 if successful, 0 if the proper config is not found,
+ * or a negative error code
*/
-static const struct hda_verb alc260_favorit100_init_verbs[] = {
- /* GPIO 0 enables the output jack.
- * Turn this on and rely on the standard mute
- * methods whenever the user wants to turn these outputs off.
- */
- {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
- {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
- {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
- /* Line/Mic input jack is connected to Mic1 pin */
- {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
- /* Ensure all other unused pins are disabled and muted. */
- {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
- {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
- {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
- {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- /* Disable digital (SPDIF) pins */
- {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
- {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
-
- /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
- * bus when acting as outputs.
- */
- {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
- {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
-
- /* Start with output sum widgets muted and their output gains at min */
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
- /* Unmute Line-out pin widget amp left and right
- * (no equiv mixer ctrl)
- */
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* Unmute Mic1 and Line1 pin widget input buffers since they start as
- * inputs. If the pin mode is changed by the user the pin mode control
- * will take care of enabling the pin's input/output buffers as needed.
- * Therefore there's no need to enable the input buffer at this
- * stage.
- */
- {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+static int alc_parse_auto_config(struct hda_codec *codec,
+ const hda_nid_t *ignore_nids,
+ const hda_nid_t *ssid_nids)
+{
+ struct alc_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ int err;
- /* Mute capture amp left and right */
- {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- /* Set ADC connection select to match default mixer setting - mic
- * (on mic1 pin)
- */
- {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
+ err = snd_hda_parse_pin_defcfg(codec, cfg, ignore_nids,
+ spec->parse_flags);
+ if (err < 0)
+ return err;
+ if (!cfg->line_outs) {
+ if (cfg->dig_outs || cfg->dig_in_pin) {
+ spec->multiout.max_channels = 2;
+ spec->no_analog = 1;
+ goto dig_only;
+ }
+ return 0; /* can't find valid BIOS pin config */
+ }
- /* Do similar with the second ADC: mute capture input amp and
- * set ADC connection to mic to match ALSA's default state.
- */
- {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
-
- /* Mute all inputs to mixer widget (even unconnected ones) */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
+ if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT &&
+ cfg->line_outs <= cfg->hp_outs) {
+ /* use HP as primary out */
+ cfg->speaker_outs = cfg->line_outs;
+ memcpy(cfg->speaker_pins, cfg->line_out_pins,
+ sizeof(cfg->speaker_pins));
+ cfg->line_outs = cfg->hp_outs;
+ memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins));
+ cfg->hp_outs = 0;
+ memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
+ cfg->line_out_type = AUTO_PIN_HP_OUT;
+ }
- { }
-};
+ err = alc_auto_fill_dac_nids(codec);
+ if (err < 0)
+ return err;
+ err = alc_auto_add_multi_channel_mode(codec);
+ if (err < 0)
+ return err;
+ err = alc_auto_create_multi_out_ctls(codec, cfg);
+ if (err < 0)
+ return err;
+ err = alc_auto_create_hp_out(codec);
+ if (err < 0)
+ return err;
+ err = alc_auto_create_speaker_out(codec);
+ if (err < 0)
+ return err;
+ err = alc_auto_create_input_ctls(codec);
+ if (err < 0)
+ return err;
-static const struct hda_verb alc260_will_verbs[] = {
- {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
- {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
- {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
- {}
-};
+ spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-static const struct hda_verb alc260_replacer_672v_verbs[] = {
- {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
- {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
- {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
+ dig_only:
+ alc_auto_parse_digital(codec);
- {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
- {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
- {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
+ if (!spec->no_analog)
+ alc_remove_invalid_adc_nids(codec);
- {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {}
-};
+ if (ssid_nids)
+ alc_ssid_check(codec, ssid_nids);
-/* toggle speaker-output according to the hp-jack state */
-static void alc260_replacer_672v_automute(struct hda_codec *codec)
-{
- unsigned int present;
-
- /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
- present = snd_hda_jack_detect(codec, 0x0f);
- if (present) {
- snd_hda_codec_write_cache(codec, 0x01, 0,
- AC_VERB_SET_GPIO_DATA, 1);
- snd_hda_codec_write_cache(codec, 0x0f, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
- PIN_HP);
- } else {
- snd_hda_codec_write_cache(codec, 0x01, 0,
- AC_VERB_SET_GPIO_DATA, 0);
- snd_hda_codec_write_cache(codec, 0x0f, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
- PIN_OUT);
+ if (!spec->no_analog) {
+ alc_auto_check_switches(codec);
+ err = alc_auto_add_mic_boost(codec);
+ if (err < 0)
+ return err;
}
+
+ if (spec->kctls.list)
+ add_mixer(spec, spec->kctls.list);
+
+ return 1;
}
-static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
- unsigned int res)
+static int alc880_parse_auto_config(struct hda_codec *codec)
{
- if ((res >> 26) == ALC880_HP_EVENT)
- alc260_replacer_672v_automute(codec);
+ static const hda_nid_t alc880_ignore[] = { 0x1d, 0 };
+ static const hda_nid_t alc880_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+ return alc_parse_auto_config(codec, alc880_ignore, alc880_ssids);
}
-static const struct hda_verb alc260_hp_dc7600_verbs[] = {
- {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
- {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {}
-};
-
-/* Test configuration for debugging, modelled after the ALC880 test
- * configuration.
- */
-#ifdef CONFIG_SND_DEBUG
-static const hda_nid_t alc260_test_dac_nids[1] = {
- 0x02,
-};
-static const hda_nid_t alc260_test_adc_nids[2] = {
- 0x04, 0x05,
-};
-/* For testing the ALC260, each input MUX needs its own definition since
- * the signal assignments are different. This assumes that the first ADC
- * is NID 0x04.
- */
-static const struct hda_input_mux alc260_test_capture_sources[2] = {
- {
- .num_items = 7,
- .items = {
- { "MIC1 pin", 0x0 },
- { "MIC2 pin", 0x1 },
- { "LINE1 pin", 0x2 },
- { "LINE2 pin", 0x3 },
- { "CD pin", 0x4 },
- { "LINE-OUT pin", 0x5 },
- { "HP-OUT pin", 0x6 },
- },
- },
- {
- .num_items = 8,
- .items = {
- { "MIC1 pin", 0x0 },
- { "MIC2 pin", 0x1 },
- { "LINE1 pin", 0x2 },
- { "LINE2 pin", 0x3 },
- { "CD pin", 0x4 },
- { "Mixer", 0x5 },
- { "LINE-OUT pin", 0x6 },
- { "HP-OUT pin", 0x7 },
- },
- },
-};
-static const struct snd_kcontrol_new alc260_test_mixer[] = {
- /* Output driver widgets */
- HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
- HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
- HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
-
- /* Modes for retasking pin widgets
- * Note: the ALC260 doesn't seem to act on requests to enable mic
- * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
- * mention this restriction. At this stage it's not clear whether
- * this behaviour is intentional or is a hardware bug in chip
- * revisions available at least up until early 2006. Therefore for
- * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
- * choices, but if it turns out that the lack of mic bias for these
- * NIDs is intentional we could change their modes from
- * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
- */
- ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
- ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
- ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
- ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
- ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
- ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
-
- /* Loopback mixer controls */
- HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
- HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
- HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
- HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
- HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
- HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
- HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
- HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
- HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
- HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
- HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
- HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
- HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
- HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
-
- /* Controls for GPIO pins, assuming they are configured as outputs */
- ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
- ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
- ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
- ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
-
- /* Switches to allow the digital IO pins to be enabled. The datasheet
- * is ambigious as to which NID is which; testing on laptops which
- * make this output available should provide clarification.
- */
- ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
- ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
-
- /* A switch allowing EAPD to be enabled. Some laptops seem to use
- * this output to turn on an external amplifier.
- */
- ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
- ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
-
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static const struct hda_amp_list alc880_loopbacks[] = {
+ { 0x0b, HDA_INPUT, 0 },
+ { 0x0b, HDA_INPUT, 1 },
+ { 0x0b, HDA_INPUT, 2 },
+ { 0x0b, HDA_INPUT, 3 },
+ { 0x0b, HDA_INPUT, 4 },
{ } /* end */
};
-static const struct hda_verb alc260_test_init_verbs[] = {
- /* Enable all GPIOs as outputs with an initial value of 0 */
- {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
- {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
- {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
-
- /* Enable retasking pins as output, initially without power amp */
- {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-
- /* Disable digital (SPDIF) pins initially, but users can enable
- * them via a mixer switch. In the case of SPDIF-out, this initverb
- * payload also sets the generation to 0, output to be in "consumer"
- * PCM format, copyright asserted, no pre-emphasis and no validity
- * control.
- */
- {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
- {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
-
- /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
- * OUT1 sum bus when acting as an output.
- */
- {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
- {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
- {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
- {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
-
- /* Start with output sum widgets muted and their output gains at min */
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
- /* Unmute retasking pin widget output buffers since the default
- * state appears to be output. As the pin mode is changed by the
- * user the pin mode control will take care of enabling the pin's
- * input/output buffers as needed.
- */
- {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* Also unmute the mono-out pin widget */
- {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
- /* Mute capture amp left and right */
- {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- /* Set ADC connection select to match default mixer setting (mic1
- * pin)
- */
- {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
-
- /* Do the same for the second ADC: mute capture input amp and
- * set ADC connection to mic1 pin
- */
- {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
-
- /* Mute all inputs to mixer widget (even unconnected ones) */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
-
- { }
-};
#endif
-#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback
-#define alc260_pcm_analog_capture alc880_pcm_analog_capture
-
-#define alc260_pcm_digital_playback alc880_pcm_digital_playback
-#define alc260_pcm_digital_capture alc880_pcm_digital_capture
+/*
+ * board setups
+ */
+#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
+#define alc_board_config \
+ snd_hda_check_board_config
+#define alc_board_codec_sid_config \
+ snd_hda_check_board_codec_sid_config
+#include "alc_quirks.c"
+#else
+#define alc_board_config(codec, nums, models, tbl) -1
+#define alc_board_codec_sid_config(codec, nums, models, tbl) -1
+#define setup_preset(codec, x) /* NOP */
+#endif
/*
- * for BIOS auto-configuration
+ * OK, here we have finally the patch for ALC880
*/
+#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
+#include "alc880_quirks.c"
+#endif
-static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
- const char *pfx, int *vol_bits)
+static int patch_alc880(struct hda_codec *codec)
{
- hda_nid_t nid_vol;
- unsigned long vol_val, sw_val;
+ struct alc_spec *spec;
+ int board_config;
int err;
- if (nid >= 0x0f && nid < 0x11) {
- nid_vol = nid - 0x7;
- vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
- sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
- } else if (nid == 0x11) {
- nid_vol = nid - 0x7;
- vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
- sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
- } else if (nid >= 0x12 && nid <= 0x15) {
- nid_vol = 0x08;
- vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
- sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
- } else
- return 0; /* N/A */
-
- if (!(*vol_bits & (1 << nid_vol))) {
- /* first control for the volume widget */
- err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, vol_val);
- if (err < 0)
- return err;
- *vol_bits |= (1 << nid_vol);
- }
- err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, sw_val);
- if (err < 0)
- return err;
- return 1;
-}
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
-/* add playback controls from the parsed DAC table */
-static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
- const struct auto_pin_cfg *cfg)
-{
- hda_nid_t nid;
- int err;
- int vols = 0;
+ codec->spec = spec;
- spec->multiout.num_dacs = 1;
- spec->multiout.dac_nids = spec->private_dac_nids;
- spec->private_dac_nids[0] = 0x02;
-
- nid = cfg->line_out_pins[0];
- if (nid) {
- const char *pfx;
- if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
- pfx = "Master";
- else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
- pfx = "Speaker";
- else
- pfx = "Front";
- err = alc260_add_playback_controls(spec, nid, pfx, &vols);
- if (err < 0)
- return err;
- }
+ spec->mixer_nid = 0x0b;
+ spec->need_dac_fix = 1;
- nid = cfg->speaker_pins[0];
- if (nid) {
- err = alc260_add_playback_controls(spec, nid, "Speaker", &vols);
- if (err < 0)
- return err;
+ board_config = alc_board_config(codec, ALC880_MODEL_LAST,
+ alc880_models, alc880_cfg_tbl);
+ if (board_config < 0) {
+ printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
+ codec->chip_name);
+ board_config = ALC_MODEL_AUTO;
}
- nid = cfg->hp_pins[0];
- if (nid) {
- err = alc260_add_playback_controls(spec, nid, "Headphone",
- &vols);
+ if (board_config == ALC_MODEL_AUTO) {
+ /* automatic parse from the BIOS config */
+ err = alc880_parse_auto_config(codec);
if (err < 0)
- return err;
+ goto error;
+#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
+ else if (!err) {
+ printk(KERN_INFO
+ "hda_codec: Cannot set up configuration "
+ "from BIOS. Using 3-stack mode...\n");
+ board_config = ALC880_3ST;
+ }
+#endif
}
- return 0;
-}
-/* create playback/capture controls for input pins */
-static int alc260_auto_create_input_ctls(struct hda_codec *codec,
- const struct auto_pin_cfg *cfg)
-{
- return alc_auto_create_input_ctls(codec, cfg, 0x07, 0x04, 0x05);
-}
+ if (board_config != ALC_MODEL_AUTO)
+ setup_preset(codec, &alc880_presets[board_config]);
-static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
- hda_nid_t nid, int pin_type,
- int sel_idx)
-{
- alc_set_pin_output(codec, nid, pin_type);
- /* need the manual connection? */
- if (nid >= 0x12) {
- int idx = nid - 0x12;
- snd_hda_codec_write(codec, idx + 0x0b, 0,
- AC_VERB_SET_CONNECT_SEL, sel_idx);
+ if (!spec->no_analog && !spec->adc_nids) {
+ alc_auto_fill_adc_caps(codec);
+ alc_rebuild_imux_for_auto_mic(codec);
+ alc_remove_invalid_adc_nids(codec);
}
-}
-static void alc260_auto_init_multi_out(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- hda_nid_t nid;
+ if (!spec->no_analog && !spec->cap_mixer)
+ set_capture_mixer(codec);
- nid = spec->autocfg.line_out_pins[0];
- if (nid) {
- int pin_type = get_pin_type(spec->autocfg.line_out_type);
- alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
+ if (!spec->no_analog) {
+ err = snd_hda_attach_beep_device(codec, 0x1);
+ if (err < 0)
+ goto error;
+ set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
}
- nid = spec->autocfg.speaker_pins[0];
- if (nid)
- alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
+ spec->vmaster_nid = 0x0c;
- nid = spec->autocfg.hp_pins[0];
- if (nid)
- alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
-}
+ codec->patch_ops = alc_patch_ops;
+ if (board_config == ALC_MODEL_AUTO)
+ spec->init_hook = alc_auto_init_std;
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+ if (!spec->loopback.amplist)
+ spec->loopback.amplist = alc880_loopbacks;
+#endif
-#define ALC260_PIN_CD_NID 0x16
-static void alc260_auto_init_analog_input(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- struct auto_pin_cfg *cfg = &spec->autocfg;
- int i;
+ return 0;
- for (i = 0; i < cfg->num_inputs; i++) {
- hda_nid_t nid = cfg->inputs[i].pin;
- if (nid >= 0x12) {
- alc_set_input_pin(codec, nid, cfg->inputs[i].type);
- if (nid != ALC260_PIN_CD_NID &&
- (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
- snd_hda_codec_write(codec, nid, 0,
- AC_VERB_SET_AMP_GAIN_MUTE,
- AMP_OUT_MUTE);
- }
- }
+ error:
+ alc_free(codec);
+ return err;
}
-#define alc260_auto_init_input_src alc880_auto_init_input_src
/*
- * generic initialization of ADC, input mixers and output mixers
+ * ALC260 support
*/
-static const struct hda_verb alc260_volume_init_verbs[] = {
- /*
- * Unmute ADC0-1 and set the default input to mic-in
- */
- {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
- /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
- * mixer widget
- * Note: PASD motherboards uses the Line In 2 as the input for
- * front panel mic (mic 2)
- */
- /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
- /* mute analog inputs */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-
- /*
- * Set up output mixers (0x08 - 0x0a)
- */
- /* set vol=0 to output mixers */
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- /* set up input amps for analog loopback */
- /* Amp Indices: DAC = 0, mixer = 1 */
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
- { }
-};
-
static int alc260_parse_auto_config(struct hda_codec *codec)
{
- struct alc_spec *spec = codec->spec;
- int err;
static const hda_nid_t alc260_ignore[] = { 0x17, 0 };
-
- err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
- alc260_ignore);
- if (err < 0)
- return err;
- err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
- if (err < 0)
- return err;
- if (!spec->kctls.list)
- return 0; /* can't find valid BIOS pin config */
- err = alc260_auto_create_input_ctls(codec, &spec->autocfg);
- if (err < 0)
- return err;
-
- spec->multiout.max_channels = 2;
-
- if (spec->autocfg.dig_outs)
- spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
- if (spec->kctls.list)
- add_mixer(spec, spec->kctls.list);
-
- add_verb(spec, alc260_volume_init_verbs);
-
- spec->num_mux_defs = 1;
- spec->input_mux = &spec->private_imux[0];
-
- alc_ssid_check(codec, 0x10, 0x15, 0x0f, 0);
-
- return 1;
-}
-
-/* additional initialization for auto-configuration model */
-static void alc260_auto_init(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- alc260_auto_init_multi_out(codec);
- alc260_auto_init_analog_input(codec);
- alc260_auto_init_input_src(codec);
- alc_auto_init_digital(codec);
- if (spec->unsol_event)
- alc_inithook(codec);
+ static const hda_nid_t alc260_ssids[] = { 0x10, 0x15, 0x0f, 0 };
+ return alc_parse_auto_config(codec, alc260_ignore, alc260_ssids);
}
#ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -7422,186 +4121,10 @@ static const struct snd_pci_quirk alc260_fixup_tbl[] = {
};
/*
- * ALC260 configurations
*/
-static const char * const alc260_models[ALC260_MODEL_LAST] = {
- [ALC260_BASIC] = "basic",
- [ALC260_HP] = "hp",
- [ALC260_HP_3013] = "hp-3013",
- [ALC260_HP_DC7600] = "hp-dc7600",
- [ALC260_FUJITSU_S702X] = "fujitsu",
- [ALC260_ACER] = "acer",
- [ALC260_WILL] = "will",
- [ALC260_REPLACER_672V] = "replacer",
- [ALC260_FAVORIT100] = "favorit100",
-#ifdef CONFIG_SND_DEBUG
- [ALC260_TEST] = "test",
+#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
+#include "alc260_quirks.c"
#endif
- [ALC260_AUTO] = "auto",
-};
-
-static const struct snd_pci_quirk alc260_cfg_tbl[] = {
- SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
- SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL),
- SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
- SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100),
- SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
- SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_AUTO), /* no quirk */
- SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
- SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
- SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600),
- SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
- SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
- SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
- SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
- SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
- SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
- SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
- SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
- SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
- SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
- SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
- {}
-};
-
-static const struct alc_config_preset alc260_presets[] = {
- [ALC260_BASIC] = {
- .mixers = { alc260_base_output_mixer,
- alc260_input_mixer },
- .init_verbs = { alc260_init_verbs },
- .num_dacs = ARRAY_SIZE(alc260_dac_nids),
- .dac_nids = alc260_dac_nids,
- .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
- .adc_nids = alc260_dual_adc_nids,
- .num_channel_mode = ARRAY_SIZE(alc260_modes),
- .channel_mode = alc260_modes,
- .input_mux = &alc260_capture_source,
- },
- [ALC260_HP] = {
- .mixers = { alc260_hp_output_mixer,
- alc260_input_mixer },
- .init_verbs = { alc260_init_verbs,
- alc260_hp_unsol_verbs },
- .num_dacs = ARRAY_SIZE(alc260_dac_nids),
- .dac_nids = alc260_dac_nids,
- .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
- .adc_nids = alc260_adc_nids_alt,
- .num_channel_mode = ARRAY_SIZE(alc260_modes),
- .channel_mode = alc260_modes,
- .input_mux = &alc260_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc260_hp_setup,
- .init_hook = alc_inithook,
- },
- [ALC260_HP_DC7600] = {
- .mixers = { alc260_hp_dc7600_mixer,
- alc260_input_mixer },
- .init_verbs = { alc260_init_verbs,
- alc260_hp_dc7600_verbs },
- .num_dacs = ARRAY_SIZE(alc260_dac_nids),
- .dac_nids = alc260_dac_nids,
- .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
- .adc_nids = alc260_adc_nids_alt,
- .num_channel_mode = ARRAY_SIZE(alc260_modes),
- .channel_mode = alc260_modes,
- .input_mux = &alc260_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc260_hp_3012_setup,
- .init_hook = alc_inithook,
- },
- [ALC260_HP_3013] = {
- .mixers = { alc260_hp_3013_mixer,
- alc260_input_mixer },
- .init_verbs = { alc260_hp_3013_init_verbs,
- alc260_hp_3013_unsol_verbs },
- .num_dacs = ARRAY_SIZE(alc260_dac_nids),
- .dac_nids = alc260_dac_nids,
- .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
- .adc_nids = alc260_adc_nids_alt,
- .num_channel_mode = ARRAY_SIZE(alc260_modes),
- .channel_mode = alc260_modes,
- .input_mux = &alc260_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc260_hp_3013_setup,
- .init_hook = alc_inithook,
- },
- [ALC260_FUJITSU_S702X] = {
- .mixers = { alc260_fujitsu_mixer },
- .init_verbs = { alc260_fujitsu_init_verbs },
- .num_dacs = ARRAY_SIZE(alc260_dac_nids),
- .dac_nids = alc260_dac_nids,
- .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
- .adc_nids = alc260_dual_adc_nids,
- .num_channel_mode = ARRAY_SIZE(alc260_modes),
- .channel_mode = alc260_modes,
- .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
- .input_mux = alc260_fujitsu_capture_sources,
- },
- [ALC260_ACER] = {
- .mixers = { alc260_acer_mixer },
- .init_verbs = { alc260_acer_init_verbs },
- .num_dacs = ARRAY_SIZE(alc260_dac_nids),
- .dac_nids = alc260_dac_nids,
- .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
- .adc_nids = alc260_dual_adc_nids,
- .num_channel_mode = ARRAY_SIZE(alc260_modes),
- .channel_mode = alc260_modes,
- .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
- .input_mux = alc260_acer_capture_sources,
- },
- [ALC260_FAVORIT100] = {
- .mixers = { alc260_favorit100_mixer },
- .init_verbs = { alc260_favorit100_init_verbs },
- .num_dacs = ARRAY_SIZE(alc260_dac_nids),
- .dac_nids = alc260_dac_nids,
- .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
- .adc_nids = alc260_dual_adc_nids,
- .num_channel_mode = ARRAY_SIZE(alc260_modes),
- .channel_mode = alc260_modes,
- .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources),
- .input_mux = alc260_favorit100_capture_sources,
- },
- [ALC260_WILL] = {
- .mixers = { alc260_will_mixer },
- .init_verbs = { alc260_init_verbs, alc260_will_verbs },
- .num_dacs = ARRAY_SIZE(alc260_dac_nids),
- .dac_nids = alc260_dac_nids,
- .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
- .adc_nids = alc260_adc_nids,
- .dig_out_nid = ALC260_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc260_modes),
- .channel_mode = alc260_modes,
- .input_mux = &alc260_capture_source,
- },
- [ALC260_REPLACER_672V] = {
- .mixers = { alc260_replacer_672v_mixer },
- .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
- .num_dacs = ARRAY_SIZE(alc260_dac_nids),
- .dac_nids = alc260_dac_nids,
- .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
- .adc_nids = alc260_adc_nids,
- .dig_out_nid = ALC260_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc260_modes),
- .channel_mode = alc260_modes,
- .input_mux = &alc260_capture_source,
- .unsol_event = alc260_replacer_672v_unsol_event,
- .init_hook = alc260_replacer_672v_automute,
- },
-#ifdef CONFIG_SND_DEBUG
- [ALC260_TEST] = {
- .mixers = { alc260_test_mixer },
- .init_verbs = { alc260_test_init_verbs },
- .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
- .dac_nids = alc260_test_dac_nids,
- .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
- .adc_nids = alc260_test_adc_nids,
- .num_channel_mode = ARRAY_SIZE(alc260_modes),
- .channel_mode = alc260_modes,
- .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
- .input_mux = alc260_test_capture_sources,
- },
-#endif
-};
static int patch_alc260(struct hda_codec *codec)
{
@@ -7614,73 +4137,62 @@ static int patch_alc260(struct hda_codec *codec)
codec->spec = spec;
- board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
- alc260_models,
- alc260_cfg_tbl);
+ spec->mixer_nid = 0x07;
+
+ board_config = alc_board_config(codec, ALC260_MODEL_LAST,
+ alc260_models, alc260_cfg_tbl);
if (board_config < 0) {
snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
codec->chip_name);
- board_config = ALC260_AUTO;
+ board_config = ALC_MODEL_AUTO;
}
- if (board_config == ALC260_AUTO) {
+ if (board_config == ALC_MODEL_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) {
+ if (board_config == ALC_MODEL_AUTO) {
/* automatic parse from the BIOS config */
err = alc260_parse_auto_config(codec);
- if (err < 0) {
- alc_free(codec);
- return err;
- } else if (!err) {
+ if (err < 0)
+ goto error;
+#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
+ else if (!err) {
printk(KERN_INFO
"hda_codec: Cannot set up configuration "
"from BIOS. Using base mode...\n");
board_config = ALC260_BASIC;
}
+#endif
}
- err = snd_hda_attach_beep_device(codec, 0x1);
- if (err < 0) {
- alc_free(codec);
- return err;
+ if (board_config != ALC_MODEL_AUTO)
+ setup_preset(codec, &alc260_presets[board_config]);
+
+ if (!spec->no_analog && !spec->adc_nids) {
+ alc_auto_fill_adc_caps(codec);
+ alc_rebuild_imux_for_auto_mic(codec);
+ alc_remove_invalid_adc_nids(codec);
}
- if (board_config != ALC260_AUTO)
- setup_preset(codec, &alc260_presets[board_config]);
+ if (!spec->no_analog && !spec->cap_mixer)
+ set_capture_mixer(codec);
- spec->stream_analog_playback = &alc260_pcm_analog_playback;
- spec->stream_analog_capture = &alc260_pcm_analog_capture;
- spec->stream_analog_alt_capture = &alc260_pcm_analog_capture;
-
- spec->stream_digital_playback = &alc260_pcm_digital_playback;
- spec->stream_digital_capture = &alc260_pcm_digital_capture;
-
- if (!spec->adc_nids && spec->input_mux) {
- /* check whether NID 0x04 is valid */
- unsigned int wcap = get_wcaps(codec, 0x04);
- wcap = get_wcaps_type(wcap);
- /* get type */
- if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
- spec->adc_nids = alc260_adc_nids_alt;
- spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
- } else {
- spec->adc_nids = alc260_adc_nids;
- spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
- }
+ if (!spec->no_analog) {
+ err = snd_hda_attach_beep_device(codec, 0x1);
+ if (err < 0)
+ goto error;
+ set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
}
- set_capture_mixer(codec);
- set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
spec->vmaster_nid = 0x08;
codec->patch_ops = alc_patch_ops;
- if (board_config == ALC260_AUTO)
- spec->init_hook = alc260_auto_init;
+ if (board_config == ALC_MODEL_AUTO)
+ spec->init_hook = alc_auto_init_std;
spec->shutup = alc_eapd_shutup;
#ifdef CONFIG_SND_HDA_POWER_SAVE
if (!spec->loopback.amplist)
@@ -7688,6 +4200,10 @@ static int patch_alc260(struct hda_codec *codec)
#endif
return 0;
+
+ error:
+ alc_free(codec);
+ return err;
}
@@ -7702,3299 +4218,10 @@ static int patch_alc260(struct hda_codec *codec)
* In addition, an independent DAC for the multi-playback (not used in this
* driver yet).
*/
-#define ALC882_DIGOUT_NID 0x06
-#define ALC882_DIGIN_NID 0x0a
-#define ALC883_DIGOUT_NID ALC882_DIGOUT_NID
-#define ALC883_DIGIN_NID ALC882_DIGIN_NID
-#define ALC1200_DIGOUT_NID 0x10
-
-
-static const struct hda_channel_mode alc882_ch_modes[1] = {
- { 8, NULL }
-};
-
-/* DACs */
-static const hda_nid_t alc882_dac_nids[4] = {
- /* front, rear, clfe, rear_surr */
- 0x02, 0x03, 0x04, 0x05
-};
-#define alc883_dac_nids alc882_dac_nids
-
-/* ADCs */
-#define alc882_adc_nids alc880_adc_nids
-#define alc882_adc_nids_alt alc880_adc_nids_alt
-#define alc883_adc_nids alc882_adc_nids_alt
-static const hda_nid_t alc883_adc_nids_alt[1] = { 0x08 };
-static const hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 };
-#define alc889_adc_nids alc880_adc_nids
-
-static const hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
-static const hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
-#define alc883_capsrc_nids alc882_capsrc_nids_alt
-static const hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
-#define alc889_capsrc_nids alc882_capsrc_nids
-
-/* input MUX */
-/* FIXME: should be a matrix-type input source selection */
-
-static const struct hda_input_mux alc882_capture_source = {
- .num_items = 4,
- .items = {
- { "Mic", 0x0 },
- { "Front Mic", 0x1 },
- { "Line", 0x2 },
- { "CD", 0x4 },
- },
-};
-
-#define alc883_capture_source alc882_capture_source
-
-static const struct hda_input_mux alc889_capture_source = {
- .num_items = 3,
- .items = {
- { "Front Mic", 0x0 },
- { "Mic", 0x3 },
- { "Line", 0x2 },
- },
-};
-
-static const struct hda_input_mux mb5_capture_source = {
- .num_items = 3,
- .items = {
- { "Mic", 0x1 },
- { "Line", 0x7 },
- { "CD", 0x4 },
- },
-};
-
-static const struct hda_input_mux macmini3_capture_source = {
- .num_items = 2,
- .items = {
- { "Line", 0x2 },
- { "CD", 0x4 },
- },
-};
-
-static const struct hda_input_mux alc883_3stack_6ch_intel = {
- .num_items = 4,
- .items = {
- { "Mic", 0x1 },
- { "Front Mic", 0x0 },
- { "Line", 0x2 },
- { "CD", 0x4 },
- },
-};
-
-static const struct hda_input_mux alc883_lenovo_101e_capture_source = {
- .num_items = 2,
- .items = {
- { "Mic", 0x1 },
- { "Line", 0x2 },
- },
-};
-
-static const struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
- .num_items = 4,
- .items = {
- { "Mic", 0x0 },
- { "Internal Mic", 0x1 },
- { "Line", 0x2 },
- { "CD", 0x4 },
- },
-};
-
-static const struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
- .num_items = 2,
- .items = {
- { "Mic", 0x0 },
- { "Internal Mic", 0x1 },
- },
-};
-
-static const struct hda_input_mux alc883_lenovo_sky_capture_source = {
- .num_items = 3,
- .items = {
- { "Mic", 0x0 },
- { "Front Mic", 0x1 },
- { "Line", 0x4 },
- },
-};
-
-static const struct hda_input_mux alc883_asus_eee1601_capture_source = {
- .num_items = 2,
- .items = {
- { "Mic", 0x0 },
- { "Line", 0x2 },
- },
-};
-
-static const struct hda_input_mux alc889A_mb31_capture_source = {
- .num_items = 2,
- .items = {
- { "Mic", 0x0 },
- /* Front Mic (0x01) unused */
- { "Line", 0x2 },
- /* Line 2 (0x03) unused */
- /* CD (0x04) unused? */
- },
-};
-
-static const struct hda_input_mux alc889A_imac91_capture_source = {
- .num_items = 2,
- .items = {
- { "Mic", 0x01 },
- { "Line", 0x2 }, /* Not sure! */
- },
-};
-
-/*
- * 2ch mode
- */
-static const struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
- { 2, NULL }
-};
-
-/*
- * 2ch mode
- */
-static const struct hda_verb alc882_3ST_ch2_init[] = {
- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
- { } /* end */
-};
-
-/*
- * 4ch mode
- */
-static const struct hda_verb alc882_3ST_ch4_init[] = {
- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
- { } /* end */
-};
-
-/*
- * 6ch mode
- */
-static const struct hda_verb alc882_3ST_ch6_init[] = {
- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
- { } /* end */
-};
-
-static const struct hda_channel_mode alc882_3ST_6ch_modes[3] = {
- { 2, alc882_3ST_ch2_init },
- { 4, alc882_3ST_ch4_init },
- { 6, alc882_3ST_ch6_init },
-};
-
-#define alc883_3ST_6ch_modes alc882_3ST_6ch_modes
-
-/*
- * 2ch mode
- */
-static const struct hda_verb alc883_3ST_ch2_clevo_init[] = {
- { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
- { } /* end */
-};
-
-/*
- * 4ch mode
- */
-static const struct hda_verb alc883_3ST_ch4_clevo_init[] = {
- { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
- { } /* end */
-};
-
-/*
- * 6ch mode
- */
-static const struct hda_verb alc883_3ST_ch6_clevo_init[] = {
- { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
- { } /* end */
-};
-
-static const struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = {
- { 2, alc883_3ST_ch2_clevo_init },
- { 4, alc883_3ST_ch4_clevo_init },
- { 6, alc883_3ST_ch6_clevo_init },
-};
-
-
-/*
- * 6ch mode
- */
-static const struct hda_verb alc882_sixstack_ch6_init[] = {
- { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
- { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { } /* end */
-};
-
-/*
- * 8ch mode
- */
-static const struct hda_verb alc882_sixstack_ch8_init[] = {
- { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { } /* end */
-};
-
-static const struct hda_channel_mode alc882_sixstack_modes[2] = {
- { 6, alc882_sixstack_ch6_init },
- { 8, alc882_sixstack_ch8_init },
-};
-
-
-/* Macbook Air 2,1 */
-
-static const struct hda_channel_mode alc885_mba21_ch_modes[1] = {
- { 2, NULL },
-};
-
-/*
- * macbook pro ALC885 can switch LineIn to LineOut without losing Mic
- */
-
-/*
- * 2ch mode
- */
-static const struct hda_verb alc885_mbp_ch2_init[] = {
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
- { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- { } /* end */
-};
-
-/*
- * 4ch mode
- */
-static const struct hda_verb alc885_mbp_ch4_init[] = {
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
- { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- { } /* end */
-};
-
-static const struct hda_channel_mode alc885_mbp_4ch_modes[2] = {
- { 2, alc885_mbp_ch2_init },
- { 4, alc885_mbp_ch4_init },
-};
-
-/*
- * 2ch
- * Speakers/Woofer/HP = Front
- * LineIn = Input
- */
-static const struct hda_verb alc885_mb5_ch2_init[] = {
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- { } /* end */
-};
-
-/*
- * 6ch mode
- * Speakers/HP = Front
- * Woofer = LFE
- * LineIn = Surround
- */
-static const struct hda_verb alc885_mb5_ch6_init[] = {
- {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, 0x01},
- { } /* end */
-};
-
-static const struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
- { 2, alc885_mb5_ch2_init },
- { 6, alc885_mb5_ch6_init },
-};
-
-#define alc885_macmini3_6ch_modes alc885_mb5_6ch_modes
-
-/*
- * 2ch mode
- */
-static const struct hda_verb alc883_4ST_ch2_init[] = {
- { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
- { } /* end */
-};
-
-/*
- * 4ch mode
- */
-static const struct hda_verb alc883_4ST_ch4_init[] = {
- { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
- { } /* end */
-};
-
-/*
- * 6ch mode
- */
-static const struct hda_verb alc883_4ST_ch6_init[] = {
- { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
- { } /* end */
-};
-
-/*
- * 8ch mode
- */
-static const struct hda_verb alc883_4ST_ch8_init[] = {
- { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
- { } /* end */
-};
-
-static const struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
- { 2, alc883_4ST_ch2_init },
- { 4, alc883_4ST_ch4_init },
- { 6, alc883_4ST_ch6_init },
- { 8, alc883_4ST_ch8_init },
-};
-
-
-/*
- * 2ch mode
- */
-static const struct hda_verb alc883_3ST_ch2_intel_init[] = {
- { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
- { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
- { } /* end */
-};
-
-/*
- * 4ch mode
- */
-static const struct hda_verb alc883_3ST_ch4_intel_init[] = {
- { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
- { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
- { } /* end */
-};
-
-/*
- * 6ch mode
- */
-static const struct hda_verb alc883_3ST_ch6_intel_init[] = {
- { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
- { } /* end */
-};
-
-static const struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
- { 2, alc883_3ST_ch2_intel_init },
- { 4, alc883_3ST_ch4_intel_init },
- { 6, alc883_3ST_ch6_intel_init },
-};
-
-/*
- * 2ch mode
- */
-static const struct hda_verb alc889_ch2_intel_init[] = {
- { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
- { 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 },
- { 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 },
- { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00 },
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
- { } /* end */
-};
-
-/*
- * 6ch mode
- */
-static const struct hda_verb alc889_ch6_intel_init[] = {
- { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
- { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
- { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
- { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
- { } /* end */
-};
-
-/*
- * 8ch mode
- */
-static const struct hda_verb alc889_ch8_intel_init[] = {
- { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
- { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
- { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
- { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x03 },
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { } /* end */
-};
-
-static const struct hda_channel_mode alc889_8ch_intel_modes[3] = {
- { 2, alc889_ch2_intel_init },
- { 6, alc889_ch6_intel_init },
- { 8, alc889_ch8_intel_init },
-};
-
-/*
- * 6ch mode
- */
-static const struct hda_verb alc883_sixstack_ch6_init[] = {
- { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
- { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { } /* end */
-};
-
-/*
- * 8ch mode
- */
-static const struct hda_verb alc883_sixstack_ch8_init[] = {
- { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { } /* end */
-};
-
-static const struct hda_channel_mode alc883_sixstack_modes[2] = {
- { 6, alc883_sixstack_ch6_init },
- { 8, alc883_sixstack_ch8_init },
-};
-
-
-/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
- * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
- */
-static const struct snd_kcontrol_new alc882_base_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", 0x0e, 1, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
- HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
- HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 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("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),
- HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, 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 */
-};
-
-/* Macbook Air 2,1 same control for HP and internal Speaker */
-
-static const struct snd_kcontrol_new alc885_mba21_mixer[] = {
- HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
- HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_OUTPUT),
- { }
-};
-
-
-static const struct snd_kcontrol_new alc885_mbp3_mixer[] = {
- HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
- HDA_BIND_MUTE ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
- HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
- HDA_BIND_MUTE ("Headphone Playback Switch", 0x0e, 0x02, HDA_INPUT),
- HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
- 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, 0x00, HDA_INPUT),
- HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
- HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT),
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc885_mb5_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
- HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
- HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
- HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
- HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
- HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
- HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
- 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("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
- HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
- HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0x00, HDA_INPUT),
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc885_macmini3_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
- HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
- HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
- HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
- HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
- HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
- HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
- 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 Volume", 0x15, 0x00, HDA_INPUT),
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc885_imac91_mixer[] = {
- HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
- HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
- { } /* end */
-};
-
-
-static const struct snd_kcontrol_new alc882_w2jc_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Front Playback Switch", 0x0c, 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 const struct snd_kcontrol_new alc882_targa_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 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("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_MUTE("Mic Playback Switch", 0x0b, 0x0, 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 Volume", 0x19, 0, HDA_INPUT),
- { } /* end */
-};
-
-/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
- * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
- */
-static const struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 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("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
- HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
- HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
- 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 Volume", 0x18, 0, HDA_INPUT),
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
- HDA_CODEC_MUTE("Headphone 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("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 const struct snd_kcontrol_new alc882_chmode_mixer[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Channel Mode",
- .info = alc_ch_mode_info,
- .get = alc_ch_mode_get,
- .put = alc_ch_mode_put,
- },
- { } /* end */
-};
-
-static const struct hda_verb alc882_base_init_verbs[] = {
- /* Front mixer: unmute input/output amp left and right (volume = 0) */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- /* Rear mixer */
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- /* CLFE mixer */
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- /* Side mixer */
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-
- /* Front Pin: output 0 (0x0c) */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* Rear Pin: output 1 (0x0d) */
- {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, 0x01},
- /* CLFE Pin: output 2 (0x0e) */
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
- /* Side Pin: output 3 (0x0f) */
- {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
- /* Mic (rear) pin: input vref at 80% */
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* Front Mic pin: input vref at 80% */
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* Line In pin: input */
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* Line-2 In: Headphone output (output 0 - 0x0c) */
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* CD pin widget for input */
- {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
- /* FIXME: use matrix-type input source selection */
- /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
- /* Input mixer2 */
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- /* Input mixer3 */
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- /* ADC2: mute amp left and right */
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* ADC3: mute amp left and right */
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
-
- { }
-};
-
-static const struct hda_verb alc882_adc1_init_verbs[] = {
- /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
- /* ADC1: mute amp left and right */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
- { }
-};
-
-static const struct hda_verb alc882_eapd_verbs[] = {
- /* change to EAPD mode */
- {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
- {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
- { }
-};
-
-static const struct hda_verb alc889_eapd_verbs[] = {
- {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
- {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
- { }
-};
-
-static const struct hda_verb alc_hp15_unsol_verbs[] = {
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {}
-};
-
-static const struct hda_verb alc885_init_verbs[] = {
- /* Front mixer: unmute input/output amp left and right (volume = 0) */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- /* Rear mixer */
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- /* CLFE mixer */
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- /* Side mixer */
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
- /* Front HP Pin: output 0 (0x0c) */
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* Front Pin: output 0 (0x0c) */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* Rear Pin: output 1 (0x0d) */
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x19, AC_VERB_SET_CONNECT_SEL, 0x01},
- /* CLFE Pin: output 2 (0x0e) */
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
- /* Side Pin: output 3 (0x0f) */
- {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
- /* Mic (rear) pin: input vref at 80% */
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* Front Mic pin: input vref at 80% */
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* Line In pin: input */
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-
- /* Mixer elements: 0x18, , 0x1a, 0x1b */
- /* Input mixer1 */
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- /* Input mixer2 */
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- /* Input mixer3 */
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- /* ADC2: mute amp left and right */
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- /* ADC3: mute amp left and right */
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-
- { }
-};
-
-static const struct hda_verb alc885_init_input_verbs[] = {
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
- { }
-};
-
-
-/* Unmute Selector 24h and set the default input to front mic */
-static const struct hda_verb alc889_init_input_verbs[] = {
- {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- { }
-};
-
-
-#define alc883_init_verbs alc882_base_init_verbs
-
-/* Mac Pro test */
-static const struct snd_kcontrol_new alc882_macpro_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
- HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
- /* FIXME: this looks suspicious...
- HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x02, HDA_INPUT),
- HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x02, HDA_INPUT),
- */
- { } /* end */
-};
-
-static const struct hda_verb alc882_macpro_init_verbs[] = {
- /* Front mixer: unmute input/output amp left and right (volume = 0) */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- /* Front Pin: output 0 (0x0c) */
- {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},
- /* Front Mic pin: input vref at 80% */
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* Speaker: output */
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
- /* Headphone output (output 0 - 0x0c) */
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
-
- /* FIXME: use matrix-type input source selection */
- /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
- /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
- /* Input mixer2 */
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
- /* Input mixer3 */
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
- /* ADC1: mute amp left and right */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* ADC2: mute amp left and right */
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* ADC3: mute amp left and right */
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
-
- { }
-};
-
-/* Macbook 5,1 */
-static const struct hda_verb alc885_mb5_init_verbs[] = {
- /* DACs */
- {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* Front mixer */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- /* Surround mixer */
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- /* LFE mixer */
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- /* HP mixer */
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- /* Front Pin (0x0c) */
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* LFE Pin (0x0e) */
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
- /* HP Pin (0x0f) */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
- {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- /* Front Mic pin: input vref at 80% */
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* Line In pin */
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0x1)},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x7)},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x4)},
- { }
-};
-
-/* Macmini 3,1 */
-static const struct hda_verb alc885_macmini3_init_verbs[] = {
- /* DACs */
- {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* Front mixer */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- /* Surround mixer */
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- /* LFE mixer */
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- /* HP mixer */
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- /* Front Pin (0x0c) */
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* LFE Pin (0x0e) */
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
- /* HP Pin (0x0f) */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
- {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- /* Line In pin */
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
- { }
-};
-
-
-static const struct hda_verb alc885_mba21_init_verbs[] = {
- /*Internal and HP Speaker Mixer*/
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- /*Internal Speaker Pin (0x0c)*/
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* HP Pin: output 0 (0x0e) */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
- /* Line in (is hp when jack connected)*/
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-
- { }
- };
-
-
-/* Macbook Pro rev3 */
-static const struct hda_verb alc885_mbp3_init_verbs[] = {
- /* Front mixer: unmute input/output amp left and right (volume = 0) */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- /* Rear mixer */
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- /* HP mixer */
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- /* Front Pin: output 0 (0x0c) */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* HP Pin: output 0 (0x0e) */
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x02},
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- /* Mic (rear) pin: input vref at 80% */
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* Front Mic pin: input vref at 80% */
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* Line In pin: use output 1 when in LineOut mode */
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
-
- /* FIXME: use matrix-type input source selection */
- /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
- /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
- /* Input mixer2 */
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
- /* Input mixer3 */
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
- /* ADC1: mute amp left and right */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* ADC2: mute amp left and right */
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* ADC3: mute amp left and right */
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
-
- { }
-};
-
-/* iMac 9,1 */
-static const struct hda_verb alc885_imac91_init_verbs[] = {
- /* Internal Speaker Pin (0x0c) */
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* HP Pin: Rear */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
- /* Line in Rear */
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* Front Mic pin: input vref at 80% */
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* Rear mixer */
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- /* Line-Out mixer: unmute input/output amp left and right (volume = 0) */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- /* 0x24 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
- /* 0x23 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
- /* 0x22 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
- /* 0x07 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* 0x08 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* 0x09 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
- { }
-};
-
-/* iMac 24 mixer. */
-static const struct snd_kcontrol_new alc885_imac24_mixer[] = {
- HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
- HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
- { } /* end */
-};
-
-/* iMac 24 init verbs. */
-static const struct hda_verb alc885_imac24_init_verbs[] = {
- /* Internal speakers: output 0 (0x0c) */
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* Internal speakers: output 0 (0x0c) */
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* Headphone: output 0 (0x0c) */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- /* Front Mic: input vref at 80% */
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- { }
-};
-
-/* Toggle speaker-output according to the hp-jack state */
-static void alc885_imac24_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x14;
- spec->autocfg.speaker_pins[0] = 0x18;
- spec->autocfg.speaker_pins[1] = 0x1a;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-#define alc885_mb5_setup alc885_imac24_setup
-#define alc885_macmini3_setup alc885_imac24_setup
-
-/* Macbook Air 2,1 */
-static void alc885_mba21_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x14;
- spec->autocfg.speaker_pins[0] = 0x18;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-
-
-static void alc885_mbp3_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x15;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static void alc885_imac91_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x14;
- spec->autocfg.speaker_pins[0] = 0x18;
- spec->autocfg.speaker_pins[1] = 0x1a;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static const struct hda_verb alc882_targa_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},
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-
- {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
- {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
- {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* 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 alc882_targa_automute(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- alc_hp_automute(codec);
- snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
- spec->jack_present ? 1 : 3);
-}
-
-static void alc882_targa_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x14;
- spec->autocfg.speaker_pins[0] = 0x1b;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
-{
- if ((res >> 26) == ALC880_HP_EVENT)
- alc882_targa_automute(codec);
-}
-
-static const struct hda_verb alc882_asus_a7j_verbs[] = {
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-
- {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
- {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
-
- {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
- {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
- {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
- { } /* end */
-};
-
-static const struct hda_verb alc882_asus_a7m_verbs[] = {
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-
- {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
- {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
-
- {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
- {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
- {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
- { } /* end */
-};
-
-static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
-{
- unsigned int gpiostate, gpiomask, gpiodir;
-
- gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
- AC_VERB_GET_GPIO_DATA, 0);
-
- if (!muted)
- gpiostate |= (1 << pin);
- else
- gpiostate &= ~(1 << pin);
-
- gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
- AC_VERB_GET_GPIO_MASK, 0);
- gpiomask |= (1 << pin);
-
- gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
- AC_VERB_GET_GPIO_DIRECTION, 0);
- gpiodir |= (1 << pin);
-
-
- snd_hda_codec_write(codec, codec->afg, 0,
- AC_VERB_SET_GPIO_MASK, gpiomask);
- snd_hda_codec_write(codec, codec->afg, 0,
- AC_VERB_SET_GPIO_DIRECTION, gpiodir);
-
- msleep(1);
-
- snd_hda_codec_write(codec, codec->afg, 0,
- AC_VERB_SET_GPIO_DATA, gpiostate);
-}
-
-/* set up GPIO at initialization */
-static void alc885_macpro_init_hook(struct hda_codec *codec)
-{
- alc882_gpio_mute(codec, 0, 0);
- alc882_gpio_mute(codec, 1, 0);
-}
-
-/* set up GPIO and update auto-muting at initialization */
-static void alc885_imac24_init_hook(struct hda_codec *codec)
-{
- alc885_macpro_init_hook(codec);
- alc_hp_automute(codec);
-}
-
-/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static const struct hda_verb alc883_auto_init_verbs[] = {
- /*
- * Unmute ADC0-2 and set the default input to mic-in
- */
- {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
- /*
- * Set up output mixers (0x0c - 0x0f)
- */
- /* set vol=0 to output mixers */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- /* set up input amps for analog loopback */
- /* Amp Indices: DAC = 0, mixer = 1 */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
- /* FIXME: use matrix-type input source selection */
- /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
- /* Input mixer2 */
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- /* Input mixer3 */
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- { }
-};
-
-/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */
-static const struct hda_verb alc889A_mb31_ch2_init[] = {
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
- { } /* end */
-};
-
-/* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */
-static const struct hda_verb alc889A_mb31_ch4_init[] = {
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
- { } /* end */
-};
-
-/* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */
-static const struct hda_verb alc889A_mb31_ch5_init[] = {
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as rear */
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
- { } /* end */
-};
-
-/* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */
-static const struct hda_verb alc889A_mb31_ch6_init[] = {
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as front */
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Subwoofer off */
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
- { } /* end */
-};
-
-static const struct hda_channel_mode alc889A_mb31_6ch_modes[4] = {
- { 2, alc889A_mb31_ch2_init },
- { 4, alc889A_mb31_ch4_init },
- { 5, alc889A_mb31_ch5_init },
- { 6, alc889A_mb31_ch6_init },
-};
-
-static const struct hda_verb alc883_medion_eapd_verbs[] = {
- /* eanable EAPD on medion laptop */
- {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
- {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
- { }
-};
-
-#define alc883_base_mixer alc882_base_mixer
-
-static const struct snd_kcontrol_new alc883_mitac_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
- HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
- 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 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 Volume", 0x19, 0, HDA_INPUT),
- HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
- HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
- 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 Volume", 0x18, 0, 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_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
- HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
- HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
- 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 Volume", 0x18, 0, 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_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
- HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 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("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),
- HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, 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 */
-};
-
-static const struct snd_kcontrol_new alc883_3ST_6ch_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", 0x0e, 1, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
- HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 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("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),
- HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, 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 */
-};
-
-static const struct snd_kcontrol_new alc883_3ST_6ch_intel_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", 0x0e, 1, 0x0,
- HDA_OUTPUT),
- HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
- 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("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, 0x1, 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 Volume", 0x18, 0, HDA_INPUT),
- HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc885_8ch_intel_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", 0x0e, 1, 0x0,
- HDA_OUTPUT),
- HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
- HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
- HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Speaker Playback Switch", 0x0f, 2, HDA_INPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
- 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 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 Volume", 0x18, 0, HDA_INPUT),
- HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_fivestack_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", 0x0e, 1, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
- HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 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("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),
- HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, 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 */
-};
-
-static const struct snd_kcontrol_new alc883_targa_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
- 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", 0x0e, 1, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
- HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 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 const struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 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_VOLUME("Mic Boost Volume", 0x18, 0, 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_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
- HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
- { } /* end */
-};
-
-static const 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("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 const struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
- HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
- 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 Volume", 0x18, 0, HDA_INPUT),
- HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
- HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 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("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
- HDA_CODEC_MUTE("Speaker Playback Switch", 0x15, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Line Playback Volume", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Line Playback Switch", 0x08, 0x0, HDA_INPUT),
- { } /* end */
-};
-
-static const struct hda_verb alc883_medion_wim2160_verbs[] = {
- /* Unmute front mixer */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
- /* Set speaker pin to front mixer */
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-
- /* Init headphone pin */
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x1a, 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_wim2160_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x1a;
- spec->autocfg.speaker_pins[0] = 0x15;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static const struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
- 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 const struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
- 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),
- 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 Volume", 0x18, 0, HDA_INPUT),
- HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc888_lenovo_sky_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", 0x0e, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
- HDA_CODEC_VOLUME_MONO("Center Playback Volume",
- 0x0d, 1, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
- HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
- HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Side Playback Switch", 0x0f, 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),
- HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, 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 */
-};
-
-static const struct snd_kcontrol_new alc889A_mb31_mixer[] = {
- /* Output mixers */
- HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
- HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
- HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
- HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
- HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x00,
- HDA_OUTPUT),
- HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x02, HDA_INPUT),
- HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x00, HDA_OUTPUT),
- HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x02, HDA_INPUT),
- /* Output switches */
- HDA_CODEC_MUTE("Enable Speaker", 0x14, 0x00, HDA_OUTPUT),
- 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 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),
- HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
- HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_vaiott_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- 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 Volume", 0x19, 0, HDA_INPUT),
- HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
- { } /* end */
-};
-
-static const struct hda_bind_ctls alc883_bind_cap_vol = {
- .ops = &snd_hda_bind_vol,
- .values = {
- HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
- HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
- 0
- },
-};
-
-static const struct hda_bind_ctls alc883_bind_cap_switch = {
- .ops = &snd_hda_bind_sw,
- .values = {
- HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
- HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
- 0
- },
-};
-
-static const struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
- 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 const struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
- HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
- HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 1,
- .info = alc_mux_enum_info,
- .get = alc_mux_enum_get,
- .put = alc_mux_enum_put,
- },
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_chmode_mixer[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Channel Mode",
- .info = alc_ch_mode_info,
- .get = alc_ch_mode_get,
- .put = alc_ch_mode_put,
- },
- { } /* end */
-};
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc883_mitac_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x15;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->autocfg.speaker_pins[1] = 0x17;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static const struct hda_verb alc883_mitac_verbs[] = {
- /* HP */
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- /* Subwoofer */
- {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
- {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-
- /* enable unsolicited event */
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
-
- { } /* end */
-};
-
-static const struct hda_verb alc883_clevo_m540r_verbs[] = {
- /* HP */
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- /* Int speaker */
- /*{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},*/
-
- /* enable unsolicited event */
- /*
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
- */
-
- { } /* end */
-};
-
-static const struct hda_verb alc883_clevo_m720_verbs[] = {
- /* HP */
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- /* Int speaker */
- {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-
- /* enable unsolicited event */
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
-
- { } /* end */
-};
-
-static const struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
- /* HP */
- {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- /* Subwoofer */
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-
- /* enable unsolicited event */
- {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-
- { } /* end */
-};
-
-static const struct hda_verb alc883_targa_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},
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-
-/* Connect Line-Out side jack (SPDIF) to Side */
- {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
-/* Connect Mic jack to CLFE */
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
-/* Connect Line-in jack to Surround */
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
-/* Connect HP out jack to Front */
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
-
- {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-
- { } /* end */
-};
-
-static const struct hda_verb alc883_lenovo_101e_verbs[] = {
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
- {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
- { } /* end */
-};
-
-static const struct hda_verb alc883_lenovo_nb0763_verbs[] = {
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- { } /* end */
-};
-
-static const struct hda_verb alc888_lenovo_ms7195_verbs[] = {
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
- {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- { } /* end */
-};
-
-static const struct hda_verb alc883_haier_w66_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_OUT},
-
- {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- { } /* end */
-};
-
-static const struct hda_verb alc888_lenovo_sky_verbs[] = {
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- { } /* end */
-};
-
-static const struct hda_verb alc888_6st_dell_verbs[] = {
- {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- { }
-};
-
-static const struct hda_verb alc883_vaiott_verbs[] = {
- /* HP */
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-
- /* enable unsolicited event */
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-
- { } /* end */
-};
-
-static void alc888_3st_hp_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x1b;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->autocfg.speaker_pins[1] = 0x16;
- spec->autocfg.speaker_pins[2] = 0x18;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static const struct hda_verb alc888_3st_hp_verbs[] = {
- {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
- {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
- {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
- {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- { } /* end */
-};
-
-/*
- * 2ch mode
- */
-static const struct hda_verb alc888_3st_hp_2ch_init[] = {
- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
- { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
- { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
- { } /* end */
-};
-
-/*
- * 4ch mode
- */
-static const struct hda_verb alc888_3st_hp_4ch_init[] = {
- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
- { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
- { } /* end */
-};
-
-/*
- * 6ch mode
- */
-static const struct hda_verb alc888_3st_hp_6ch_init[] = {
- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
- { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
- { } /* end */
-};
-
-static const struct hda_channel_mode alc888_3st_hp_modes[3] = {
- { 2, alc888_3st_hp_2ch_init },
- { 4, alc888_3st_hp_4ch_init },
- { 6, alc888_3st_hp_6ch_init },
-};
-
-static void alc888_lenovo_ms7195_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x1b;
- spec->autocfg.line_out_pins[0] = 0x14;
- spec->autocfg.speaker_pins[0] = 0x15;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc883_lenovo_nb0763_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x14;
- spec->autocfg.speaker_pins[0] = 0x15;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-/* toggle speaker-output according to the hp-jack state */
-#define alc883_targa_init_hook alc882_targa_init_hook
-#define alc883_targa_unsol_event alc882_targa_unsol_event
-
-static void alc883_clevo_m720_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x15;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static void alc883_clevo_m720_init_hook(struct hda_codec *codec)
-{
- alc_hp_automute(codec);
- alc88x_simple_mic_automute(codec);
-}
-
-static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
- unsigned int res)
-{
- switch (res >> 26) {
- case ALC880_MIC_EVENT:
- alc88x_simple_mic_automute(codec);
- break;
- default:
- alc_sku_unsol_event(codec, res);
- break;
- }
-}
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x14;
- spec->autocfg.speaker_pins[0] = 0x15;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static void alc883_haier_w66_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x1b;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static void alc883_lenovo_101e_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x1b;
- spec->autocfg.line_out_pins[0] = 0x14;
- spec->autocfg.speaker_pins[0] = 0x15;
- spec->automute = 1;
- spec->detect_line = 1;
- spec->automute_lines = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc883_acer_aspire_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x14;
- spec->autocfg.speaker_pins[0] = 0x15;
- spec->autocfg.speaker_pins[1] = 0x16;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static const struct hda_verb alc883_acer_eapd_verbs[] = {
- /* HP Pin: output 0 (0x0c) */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* Front Pin: output 0 (0x0c) */
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* eanable EAPD on medion laptop */
- {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
- {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
- /* enable unsolicited event */
- {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- { }
-};
-
-static void alc888_6st_dell_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x1b;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->autocfg.speaker_pins[1] = 0x15;
- spec->autocfg.speaker_pins[2] = 0x16;
- spec->autocfg.speaker_pins[3] = 0x17;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static void alc888_lenovo_sky_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x1b;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->autocfg.speaker_pins[1] = 0x15;
- spec->autocfg.speaker_pins[2] = 0x16;
- spec->autocfg.speaker_pins[3] = 0x17;
- spec->autocfg.speaker_pins[4] = 0x1a;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static void alc883_vaiott_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x15;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->autocfg.speaker_pins[1] = 0x17;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static const struct hda_verb alc888_asus_m90v_verbs[] = {
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- /* enable unsolicited event */
- {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
- { } /* end */
-};
-
-static void alc883_mode2_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x1b;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->autocfg.speaker_pins[1] = 0x15;
- spec->autocfg.speaker_pins[2] = 0x16;
- spec->ext_mic.pin = 0x18;
- spec->int_mic.pin = 0x19;
- spec->ext_mic.mux_idx = 0;
- spec->int_mic.mux_idx = 1;
- spec->auto_mic = 1;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static const struct hda_verb alc888_asus_eee1601_verbs[] = {
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
- {0x20, AC_VERB_SET_PROC_COEF, 0x0838},
- /* enable unsolicited event */
- {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- { } /* end */
-};
-
-static void alc883_eee1601_inithook(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x14;
- spec->autocfg.speaker_pins[0] = 0x1b;
- alc_hp_automute(codec);
-}
-
-static const struct hda_verb alc889A_mb31_verbs[] = {
- /* Init rear pin (used as headphone output) */
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, /* Apple Headphones */
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Connect to front */
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- /* Init line pin (used as output in 4ch and 6ch mode) */
- {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Connect to CLFE */
- /* Init line 2 pin (used as headphone out by default) */
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Use as input */
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Mute output */
- { } /* end */
-};
-
-/* Mute speakers according to the headphone jack state */
-static void alc889A_mb31_automute(struct hda_codec *codec)
-{
- unsigned int present;
-
- /* Mute only in 2ch or 4ch mode */
- if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0)
- == 0x00) {
- present = snd_hda_jack_detect(codec, 0x15);
- snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
- HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
- snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
- HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
- }
-}
-
-static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res)
-{
- if ((res >> 26) == ALC880_HP_EVENT)
- alc889A_mb31_automute(codec);
-}
-
-
#ifdef CONFIG_SND_HDA_POWER_SAVE
#define alc882_loopbacks alc880_loopbacks
#endif
-/* pcm configuration: identical with ALC880 */
-#define alc882_pcm_analog_playback alc880_pcm_analog_playback
-#define alc882_pcm_analog_capture alc880_pcm_analog_capture
-#define alc882_pcm_digital_playback alc880_pcm_digital_playback
-#define alc882_pcm_digital_capture alc880_pcm_digital_capture
-
-static const hda_nid_t alc883_slave_dig_outs[] = {
- ALC1200_DIGOUT_NID, 0,
-};
-
-static const hda_nid_t alc1200_slave_dig_outs[] = {
- ALC883_DIGOUT_NID, 0,
-};
-
-/*
- * configuration and preset
- */
-static const char * const alc882_models[ALC882_MODEL_LAST] = {
- [ALC882_3ST_DIG] = "3stack-dig",
- [ALC882_6ST_DIG] = "6stack-dig",
- [ALC882_ARIMA] = "arima",
- [ALC882_W2JC] = "w2jc",
- [ALC882_TARGA] = "targa",
- [ALC882_ASUS_A7J] = "asus-a7j",
- [ALC882_ASUS_A7M] = "asus-a7m",
- [ALC885_MACPRO] = "macpro",
- [ALC885_MB5] = "mb5",
- [ALC885_MACMINI3] = "macmini3",
- [ALC885_MBA21] = "mba21",
- [ALC885_MBP3] = "mbp3",
- [ALC885_IMAC24] = "imac24",
- [ALC885_IMAC91] = "imac91",
- [ALC883_3ST_2ch_DIG] = "3stack-2ch-dig",
- [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
- [ALC883_3ST_6ch] = "3stack-6ch",
- [ALC883_6ST_DIG] = "alc883-6stack-dig",
- [ALC883_TARGA_DIG] = "targa-dig",
- [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
- [ALC883_TARGA_8ch_DIG] = "targa-8ch-dig",
- [ALC883_ACER] = "acer",
- [ALC883_ACER_ASPIRE] = "acer-aspire",
- [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g",
- [ALC888_ACER_ASPIRE_6530G] = "acer-aspire-6530g",
- [ALC888_ACER_ASPIRE_8930G] = "acer-aspire-8930g",
- [ALC888_ACER_ASPIRE_7730G] = "acer-aspire-7730g",
- [ALC883_MEDION] = "medion",
- [ALC883_MEDION_WIM2160] = "medion-wim2160",
- [ALC883_LAPTOP_EAPD] = "laptop-eapd",
- [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
- [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
- [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
- [ALC888_LENOVO_SKY] = "lenovo-sky",
- [ALC883_HAIER_W66] = "haier-w66",
- [ALC888_3ST_HP] = "3stack-hp",
- [ALC888_6ST_DELL] = "6stack-dell",
- [ALC883_MITAC] = "mitac",
- [ALC883_CLEVO_M540R] = "clevo-m540r",
- [ALC883_CLEVO_M720] = "clevo-m720",
- [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
- [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
- [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel",
- [ALC889A_INTEL] = "intel-alc889a",
- [ALC889_INTEL] = "intel-x58",
- [ALC1200_ASUS_P5Q] = "asus-p5q",
- [ALC889A_MB31] = "mb31",
- [ALC883_SONY_VAIO_TT] = "sony-vaio-tt",
- [ALC882_AUTO] = "auto",
-};
-
-static const struct snd_pci_quirk alc882_cfg_tbl[] = {
- SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
-
- SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
- SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
- SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE),
- SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
- SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
- SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
- SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
- ALC888_ACER_ASPIRE_4930G),
- SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
- ALC888_ACER_ASPIRE_4930G),
- SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
- ALC888_ACER_ASPIRE_8930G),
- SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
- ALC888_ACER_ASPIRE_8930G),
- SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC882_AUTO),
- SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC882_AUTO),
- SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
- ALC888_ACER_ASPIRE_6530G),
- SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
- ALC888_ACER_ASPIRE_6530G),
- SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
- ALC888_ACER_ASPIRE_7730G),
- /* default Acer -- disabled as it causes more problems.
- * model=auto should work fine now
- */
- /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */
-
- SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
-
- SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavilion", ALC883_6ST_DIG),
- SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
- SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
- SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
- SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
- SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP),
-
- SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
- SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
- SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
- SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
- SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
- SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
- SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
- SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
- SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG),
- SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
- SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
-
- SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT),
- SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
- SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
- SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC),
- SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
- SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
- SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
- SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
- SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
-
- SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
- SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
- SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
- SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
- SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC882_AUTO),
- SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
- SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
- SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
- SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
- SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
- SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
- SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
- SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
- SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
- SND_PCI_QUIRK(0x1462, 0x42cd, "MSI", ALC883_TARGA_DIG),
- SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
- SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
- SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
- SND_PCI_QUIRK(0x1462, 0x4570, "MSI Wind Top AE2220", ALC883_TARGA_DIG),
- SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG),
- SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
- SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
- SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
- SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG),
- SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
- SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
- SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
- SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG),
- SND_PCI_QUIRK(0x1462, 0x7437, "MSI NetOn AP1900", ALC883_TARGA_DIG),
- SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
- SND_PCI_QUIRK(0x1462, 0xaa08, "MSI", ALC883_TARGA_2ch_DIG),
-
- SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
- SND_PCI_QUIRK(0x1558, 0x0571, "Clevo laptop M570U", ALC883_3ST_6ch_DIG),
- SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
- SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
- SND_PCI_QUIRK(0x1558, 0x5409, "Clevo laptop M540R", ALC883_CLEVO_M540R),
- SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
- SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
- /* SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), */
- SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
- SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx",
- ALC883_FUJITSU_PI2515),
- SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1130, "Fujitsu AMILO Xa35xx",
- ALC888_FUJITSU_XA3530),
- SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
- SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
- SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
- SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
- SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
- SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG),
- SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
- SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
-
- SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
- SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
- SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC),
- SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_INTEL),
- SND_PCI_QUIRK(0x8086, 0x0021, "Intel IbexPeak", ALC889A_INTEL),
- SND_PCI_QUIRK(0x8086, 0x3b56, "Intel IbexPeak", ALC889A_INTEL),
- SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC882_6ST_DIG),
-
- {}
-};
-
-/* codec SSID table for Intel Mac */
-static const struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
- SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3),
- SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3),
- SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3),
- SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_MACPRO),
- SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24),
- SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24),
- SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3),
- SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31),
- SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_ASUS_A7M),
- SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC885_MBP3),
- SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC885_MBA21),
- SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31),
- SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3),
- SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24),
- SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC885_IMAC91),
- SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5),
- SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC885_MB5),
- /* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2,
- * so apparently no perfect solution yet
- */
- SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5),
- SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5),
- SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC885_MACMINI3),
- {} /* terminator */
-};
-
-static const struct alc_config_preset alc882_presets[] = {
- [ALC882_3ST_DIG] = {
- .mixers = { alc882_base_mixer },
- .init_verbs = { alc882_base_init_verbs,
- alc882_adc1_init_verbs },
- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
- .dac_nids = alc882_dac_nids,
- .dig_out_nid = ALC882_DIGOUT_NID,
- .dig_in_nid = ALC882_DIGIN_NID,
- .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
- .channel_mode = alc882_ch_modes,
- .need_dac_fix = 1,
- .input_mux = &alc882_capture_source,
- },
- [ALC882_6ST_DIG] = {
- .mixers = { alc882_base_mixer, alc882_chmode_mixer },
- .init_verbs = { alc882_base_init_verbs,
- alc882_adc1_init_verbs },
- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
- .dac_nids = alc882_dac_nids,
- .dig_out_nid = ALC882_DIGOUT_NID,
- .dig_in_nid = ALC882_DIGIN_NID,
- .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
- .channel_mode = alc882_sixstack_modes,
- .input_mux = &alc882_capture_source,
- },
- [ALC882_ARIMA] = {
- .mixers = { alc882_base_mixer, alc882_chmode_mixer },
- .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
- alc882_eapd_verbs },
- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
- .dac_nids = alc882_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
- .channel_mode = alc882_sixstack_modes,
- .input_mux = &alc882_capture_source,
- },
- [ALC882_W2JC] = {
- .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
- .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
- alc882_eapd_verbs, alc880_gpio1_init_verbs },
- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
- .dac_nids = alc882_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
- .channel_mode = alc880_threestack_modes,
- .need_dac_fix = 1,
- .input_mux = &alc882_capture_source,
- .dig_out_nid = ALC882_DIGOUT_NID,
- },
- [ALC885_MBA21] = {
- .mixers = { alc885_mba21_mixer },
- .init_verbs = { alc885_mba21_init_verbs, alc880_gpio1_init_verbs },
- .num_dacs = 2,
- .dac_nids = alc882_dac_nids,
- .channel_mode = alc885_mba21_ch_modes,
- .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
- .input_mux = &alc882_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc885_mba21_setup,
- .init_hook = alc_hp_automute,
- },
- [ALC885_MBP3] = {
- .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
- .init_verbs = { alc885_mbp3_init_verbs,
- alc880_gpio1_init_verbs },
- .num_dacs = 2,
- .dac_nids = alc882_dac_nids,
- .hp_nid = 0x04,
- .channel_mode = alc885_mbp_4ch_modes,
- .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes),
- .input_mux = &alc882_capture_source,
- .dig_out_nid = ALC882_DIGOUT_NID,
- .dig_in_nid = ALC882_DIGIN_NID,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc885_mbp3_setup,
- .init_hook = alc_hp_automute,
- },
- [ALC885_MB5] = {
- .mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
- .init_verbs = { alc885_mb5_init_verbs,
- alc880_gpio1_init_verbs },
- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
- .dac_nids = alc882_dac_nids,
- .channel_mode = alc885_mb5_6ch_modes,
- .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes),
- .input_mux = &mb5_capture_source,
- .dig_out_nid = ALC882_DIGOUT_NID,
- .dig_in_nid = ALC882_DIGIN_NID,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc885_mb5_setup,
- .init_hook = alc_hp_automute,
- },
- [ALC885_MACMINI3] = {
- .mixers = { alc885_macmini3_mixer, alc882_chmode_mixer },
- .init_verbs = { alc885_macmini3_init_verbs,
- alc880_gpio1_init_verbs },
- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
- .dac_nids = alc882_dac_nids,
- .channel_mode = alc885_macmini3_6ch_modes,
- .num_channel_mode = ARRAY_SIZE(alc885_macmini3_6ch_modes),
- .input_mux = &macmini3_capture_source,
- .dig_out_nid = ALC882_DIGOUT_NID,
- .dig_in_nid = ALC882_DIGIN_NID,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc885_macmini3_setup,
- .init_hook = alc_hp_automute,
- },
- [ALC885_MACPRO] = {
- .mixers = { alc882_macpro_mixer },
- .init_verbs = { alc882_macpro_init_verbs },
- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
- .dac_nids = alc882_dac_nids,
- .dig_out_nid = ALC882_DIGOUT_NID,
- .dig_in_nid = ALC882_DIGIN_NID,
- .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
- .channel_mode = alc882_ch_modes,
- .input_mux = &alc882_capture_source,
- .init_hook = alc885_macpro_init_hook,
- },
- [ALC885_IMAC24] = {
- .mixers = { alc885_imac24_mixer },
- .init_verbs = { alc885_imac24_init_verbs },
- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
- .dac_nids = alc882_dac_nids,
- .dig_out_nid = ALC882_DIGOUT_NID,
- .dig_in_nid = ALC882_DIGIN_NID,
- .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
- .channel_mode = alc882_ch_modes,
- .input_mux = &alc882_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc885_imac24_setup,
- .init_hook = alc885_imac24_init_hook,
- },
- [ALC885_IMAC91] = {
- .mixers = {alc885_imac91_mixer},
- .init_verbs = { alc885_imac91_init_verbs,
- alc880_gpio1_init_verbs },
- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
- .dac_nids = alc882_dac_nids,
- .channel_mode = alc885_mba21_ch_modes,
- .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
- .input_mux = &alc889A_imac91_capture_source,
- .dig_out_nid = ALC882_DIGOUT_NID,
- .dig_in_nid = ALC882_DIGIN_NID,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc885_imac91_setup,
- .init_hook = alc_hp_automute,
- },
- [ALC882_TARGA] = {
- .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
- .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
- alc880_gpio3_init_verbs, alc882_targa_verbs},
- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
- .dac_nids = alc882_dac_nids,
- .dig_out_nid = ALC882_DIGOUT_NID,
- .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
- .adc_nids = alc882_adc_nids,
- .capsrc_nids = alc882_capsrc_nids,
- .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
- .channel_mode = alc882_3ST_6ch_modes,
- .need_dac_fix = 1,
- .input_mux = &alc882_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc882_targa_setup,
- .init_hook = alc882_targa_automute,
- },
- [ALC882_ASUS_A7J] = {
- .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
- .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
- alc882_asus_a7j_verbs},
- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
- .dac_nids = alc882_dac_nids,
- .dig_out_nid = ALC882_DIGOUT_NID,
- .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
- .adc_nids = alc882_adc_nids,
- .capsrc_nids = alc882_capsrc_nids,
- .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
- .channel_mode = alc882_3ST_6ch_modes,
- .need_dac_fix = 1,
- .input_mux = &alc882_capture_source,
- },
- [ALC882_ASUS_A7M] = {
- .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
- .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
- alc882_eapd_verbs, alc880_gpio1_init_verbs,
- alc882_asus_a7m_verbs },
- .num_dacs = ARRAY_SIZE(alc882_dac_nids),
- .dac_nids = alc882_dac_nids,
- .dig_out_nid = ALC882_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
- .channel_mode = alc880_threestack_modes,
- .need_dac_fix = 1,
- .input_mux = &alc882_capture_source,
- },
- [ALC883_3ST_2ch_DIG] = {
- .mixers = { alc883_3ST_2ch_mixer },
- .init_verbs = { alc883_init_verbs },
- .num_dacs = ARRAY_SIZE(alc883_dac_nids),
- .dac_nids = alc883_dac_nids,
- .dig_out_nid = ALC883_DIGOUT_NID,
- .dig_in_nid = ALC883_DIGIN_NID,
- .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
- .channel_mode = alc883_3ST_2ch_modes,
- .input_mux = &alc883_capture_source,
- },
- [ALC883_3ST_6ch_DIG] = {
- .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
- .init_verbs = { alc883_init_verbs },
- .num_dacs = ARRAY_SIZE(alc883_dac_nids),
- .dac_nids = alc883_dac_nids,
- .dig_out_nid = ALC883_DIGOUT_NID,
- .dig_in_nid = ALC883_DIGIN_NID,
- .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
- .channel_mode = alc883_3ST_6ch_modes,
- .need_dac_fix = 1,
- .input_mux = &alc883_capture_source,
- },
- [ALC883_3ST_6ch] = {
- .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
- .init_verbs = { alc883_init_verbs },
- .num_dacs = ARRAY_SIZE(alc883_dac_nids),
- .dac_nids = alc883_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
- .channel_mode = alc883_3ST_6ch_modes,
- .need_dac_fix = 1,
- .input_mux = &alc883_capture_source,
- },
- [ALC883_3ST_6ch_INTEL] = {
- .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
- .init_verbs = { alc883_init_verbs },
- .num_dacs = ARRAY_SIZE(alc883_dac_nids),
- .dac_nids = alc883_dac_nids,
- .dig_out_nid = ALC883_DIGOUT_NID,
- .dig_in_nid = ALC883_DIGIN_NID,
- .slave_dig_outs = alc883_slave_dig_outs,
- .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
- .channel_mode = alc883_3ST_6ch_intel_modes,
- .need_dac_fix = 1,
- .input_mux = &alc883_3stack_6ch_intel,
- },
- [ALC889A_INTEL] = {
- .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
- .init_verbs = { alc885_init_verbs, alc885_init_input_verbs,
- alc_hp15_unsol_verbs },
- .num_dacs = ARRAY_SIZE(alc883_dac_nids),
- .dac_nids = alc883_dac_nids,
- .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
- .adc_nids = alc889_adc_nids,
- .dig_out_nid = ALC883_DIGOUT_NID,
- .dig_in_nid = ALC883_DIGIN_NID,
- .slave_dig_outs = alc883_slave_dig_outs,
- .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
- .channel_mode = alc889_8ch_intel_modes,
- .capsrc_nids = alc889_capsrc_nids,
- .input_mux = &alc889_capture_source,
- .setup = alc889_automute_setup,
- .init_hook = alc_hp_automute,
- .unsol_event = alc_sku_unsol_event,
- .need_dac_fix = 1,
- },
- [ALC889_INTEL] = {
- .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
- .init_verbs = { alc885_init_verbs, alc889_init_input_verbs,
- alc889_eapd_verbs, alc_hp15_unsol_verbs},
- .num_dacs = ARRAY_SIZE(alc883_dac_nids),
- .dac_nids = alc883_dac_nids,
- .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
- .adc_nids = alc889_adc_nids,
- .dig_out_nid = ALC883_DIGOUT_NID,
- .dig_in_nid = ALC883_DIGIN_NID,
- .slave_dig_outs = alc883_slave_dig_outs,
- .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
- .channel_mode = alc889_8ch_intel_modes,
- .capsrc_nids = alc889_capsrc_nids,
- .input_mux = &alc889_capture_source,
- .setup = alc889_automute_setup,
- .init_hook = alc889_intel_init_hook,
- .unsol_event = alc_sku_unsol_event,
- .need_dac_fix = 1,
- },
- [ALC883_6ST_DIG] = {
- .mixers = { alc883_base_mixer, alc883_chmode_mixer },
- .init_verbs = { alc883_init_verbs },
- .num_dacs = ARRAY_SIZE(alc883_dac_nids),
- .dac_nids = alc883_dac_nids,
- .dig_out_nid = ALC883_DIGOUT_NID,
- .dig_in_nid = ALC883_DIGIN_NID,
- .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
- .channel_mode = alc883_sixstack_modes,
- .input_mux = &alc883_capture_source,
- },
- [ALC883_TARGA_DIG] = {
- .mixers = { alc883_targa_mixer, alc883_chmode_mixer },
- .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
- alc883_targa_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_6ch_modes),
- .channel_mode = alc883_3ST_6ch_modes,
- .need_dac_fix = 1,
- .input_mux = &alc883_capture_source,
- .unsol_event = alc883_targa_unsol_event,
- .setup = alc882_targa_setup,
- .init_hook = alc882_targa_automute,
- },
- [ALC883_TARGA_2ch_DIG] = {
- .mixers = { alc883_targa_2ch_mixer},
- .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
- alc883_targa_verbs},
- .num_dacs = ARRAY_SIZE(alc883_dac_nids),
- .dac_nids = alc883_dac_nids,
- .adc_nids = alc883_adc_nids_alt,
- .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
- .capsrc_nids = alc883_capsrc_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 = alc883_targa_unsol_event,
- .setup = alc882_targa_setup,
- .init_hook = alc882_targa_automute,
- },
- [ALC883_TARGA_8ch_DIG] = {
- .mixers = { alc883_targa_mixer, alc883_targa_8ch_mixer,
- alc883_chmode_mixer },
- .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
- alc883_targa_verbs },
- .num_dacs = ARRAY_SIZE(alc883_dac_nids),
- .dac_nids = alc883_dac_nids,
- .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
- .adc_nids = alc883_adc_nids_rev,
- .capsrc_nids = alc883_capsrc_nids_rev,
- .dig_out_nid = ALC883_DIGOUT_NID,
- .dig_in_nid = ALC883_DIGIN_NID,
- .num_channel_mode = ARRAY_SIZE(alc883_4ST_8ch_modes),
- .channel_mode = alc883_4ST_8ch_modes,
- .need_dac_fix = 1,
- .input_mux = &alc883_capture_source,
- .unsol_event = alc883_targa_unsol_event,
- .setup = alc882_targa_setup,
- .init_hook = alc882_targa_automute,
- },
- [ALC883_ACER] = {
- .mixers = { alc883_base_mixer },
- /* On TravelMate laptops, GPIO 0 enables the internal speaker
- * and the headphone jack. Turn this on and rely on the
- * standard mute methods whenever the user wants to turn
- * these outputs off.
- */
- .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
- .num_dacs = ARRAY_SIZE(alc883_dac_nids),
- .dac_nids = alc883_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
- .channel_mode = alc883_3ST_2ch_modes,
- .input_mux = &alc883_capture_source,
- },
- [ALC883_ACER_ASPIRE] = {
- .mixers = { alc883_acer_aspire_mixer },
- .init_verbs = { alc883_init_verbs, alc883_acer_eapd_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_sku_unsol_event,
- .setup = alc883_acer_aspire_setup,
- .init_hook = alc_hp_automute,
- },
- [ALC888_ACER_ASPIRE_4930G] = {
- .mixers = { alc888_acer_aspire_4930g_mixer,
- alc883_chmode_mixer },
- .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
- alc888_acer_aspire_4930g_verbs },
- .num_dacs = ARRAY_SIZE(alc883_dac_nids),
- .dac_nids = alc883_dac_nids,
- .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
- .adc_nids = alc883_adc_nids_rev,
- .capsrc_nids = alc883_capsrc_nids_rev,
- .dig_out_nid = ALC883_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
- .channel_mode = alc883_3ST_6ch_modes,
- .need_dac_fix = 1,
- .const_channel_count = 6,
- .num_mux_defs =
- ARRAY_SIZE(alc888_2_capture_sources),
- .input_mux = alc888_2_capture_sources,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc888_acer_aspire_4930g_setup,
- .init_hook = alc_hp_automute,
- },
- [ALC888_ACER_ASPIRE_6530G] = {
- .mixers = { alc888_acer_aspire_6530_mixer },
- .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
- alc888_acer_aspire_6530g_verbs },
- .num_dacs = ARRAY_SIZE(alc883_dac_nids),
- .dac_nids = alc883_dac_nids,
- .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
- .adc_nids = alc883_adc_nids_rev,
- .capsrc_nids = alc883_capsrc_nids_rev,
- .dig_out_nid = ALC883_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
- .channel_mode = alc883_3ST_2ch_modes,
- .num_mux_defs =
- ARRAY_SIZE(alc888_2_capture_sources),
- .input_mux = alc888_acer_aspire_6530_sources,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc888_acer_aspire_6530g_setup,
- .init_hook = alc_hp_automute,
- },
- [ALC888_ACER_ASPIRE_8930G] = {
- .mixers = { alc889_acer_aspire_8930g_mixer,
- alc883_chmode_mixer },
- .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
- alc889_acer_aspire_8930g_verbs,
- alc889_eapd_verbs},
- .num_dacs = ARRAY_SIZE(alc883_dac_nids),
- .dac_nids = alc883_dac_nids,
- .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
- .adc_nids = alc889_adc_nids,
- .capsrc_nids = alc889_capsrc_nids,
- .dig_out_nid = ALC883_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
- .channel_mode = alc883_3ST_6ch_modes,
- .need_dac_fix = 1,
- .const_channel_count = 6,
- .num_mux_defs =
- ARRAY_SIZE(alc889_capture_sources),
- .input_mux = alc889_capture_sources,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc889_acer_aspire_8930g_setup,
- .init_hook = alc_hp_automute,
-#ifdef CONFIG_SND_HDA_POWER_SAVE
- .power_hook = alc_power_eapd,
-#endif
- },
- [ALC888_ACER_ASPIRE_7730G] = {
- .mixers = { alc883_3ST_6ch_mixer,
- alc883_chmode_mixer },
- .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
- alc888_acer_aspire_7730G_verbs },
- .num_dacs = ARRAY_SIZE(alc883_dac_nids),
- .dac_nids = alc883_dac_nids,
- .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
- .adc_nids = alc883_adc_nids_rev,
- .capsrc_nids = alc883_capsrc_nids_rev,
- .dig_out_nid = ALC883_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
- .channel_mode = alc883_3ST_6ch_modes,
- .need_dac_fix = 1,
- .const_channel_count = 6,
- .input_mux = &alc883_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc888_acer_aspire_7730g_setup,
- .init_hook = alc_hp_automute,
- },
- [ALC883_MEDION] = {
- .mixers = { alc883_fivestack_mixer,
- alc883_chmode_mixer },
- .init_verbs = { alc883_init_verbs,
- alc883_medion_eapd_verbs },
- .num_dacs = ARRAY_SIZE(alc883_dac_nids),
- .dac_nids = alc883_dac_nids,
- .adc_nids = alc883_adc_nids_alt,
- .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
- .capsrc_nids = alc883_capsrc_nids,
- .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
- .channel_mode = alc883_sixstack_modes,
- .input_mux = &alc883_capture_source,
- },
- [ALC883_MEDION_WIM2160] = {
- .mixers = { alc883_medion_wim2160_mixer },
- .init_verbs = { alc883_init_verbs, alc883_medion_wim2160_verbs },
- .num_dacs = ARRAY_SIZE(alc883_dac_nids),
- .dac_nids = alc883_dac_nids,
- .dig_out_nid = ALC883_DIGOUT_NID,
- .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
- .adc_nids = alc883_adc_nids,
- .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
- .channel_mode = alc883_3ST_2ch_modes,
- .input_mux = &alc883_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc883_medion_wim2160_setup,
- .init_hook = alc_hp_automute,
- },
- [ALC883_LAPTOP_EAPD] = {
- .mixers = { alc883_base_mixer },
- .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
- .num_dacs = ARRAY_SIZE(alc883_dac_nids),
- .dac_nids = alc883_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
- .channel_mode = alc883_3ST_2ch_modes,
- .input_mux = &alc883_capture_source,
- },
- [ALC883_CLEVO_M540R] = {
- .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
- .init_verbs = { alc883_init_verbs, alc883_clevo_m540r_verbs },
- .num_dacs = ARRAY_SIZE(alc883_dac_nids),
- .dac_nids = alc883_dac_nids,
- .dig_out_nid = ALC883_DIGOUT_NID,
- .dig_in_nid = ALC883_DIGIN_NID,
- .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_clevo_modes),
- .channel_mode = alc883_3ST_6ch_clevo_modes,
- .need_dac_fix = 1,
- .input_mux = &alc883_capture_source,
- /* This machine has the hardware HP auto-muting, thus
- * we need no software mute via unsol event
- */
- },
- [ALC883_CLEVO_M720] = {
- .mixers = { alc883_clevo_m720_mixer },
- .init_verbs = { alc883_init_verbs, alc883_clevo_m720_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 = alc883_clevo_m720_unsol_event,
- .setup = alc883_clevo_m720_setup,
- .init_hook = alc883_clevo_m720_init_hook,
- },
- [ALC883_LENOVO_101E_2ch] = {
- .mixers = { alc883_lenovo_101e_2ch_mixer},
- .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
- .num_dacs = ARRAY_SIZE(alc883_dac_nids),
- .dac_nids = alc883_dac_nids,
- .adc_nids = alc883_adc_nids_alt,
- .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
- .capsrc_nids = alc883_capsrc_nids,
- .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
- .channel_mode = alc883_3ST_2ch_modes,
- .input_mux = &alc883_lenovo_101e_capture_source,
- .setup = alc883_lenovo_101e_setup,
- .unsol_event = alc_sku_unsol_event,
- .init_hook = alc_inithook,
- },
- [ALC883_LENOVO_NB0763] = {
- .mixers = { alc883_lenovo_nb0763_mixer },
- .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
- .num_dacs = ARRAY_SIZE(alc883_dac_nids),
- .dac_nids = alc883_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
- .channel_mode = alc883_3ST_2ch_modes,
- .need_dac_fix = 1,
- .input_mux = &alc883_lenovo_nb0763_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc883_lenovo_nb0763_setup,
- .init_hook = alc_hp_automute,
- },
- [ALC888_LENOVO_MS7195_DIG] = {
- .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
- .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_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_6ch_modes),
- .channel_mode = alc883_3ST_6ch_modes,
- .need_dac_fix = 1,
- .input_mux = &alc883_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc888_lenovo_ms7195_setup,
- .init_hook = alc_inithook,
- },
- [ALC883_HAIER_W66] = {
- .mixers = { alc883_targa_2ch_mixer},
- .init_verbs = { alc883_init_verbs, alc883_haier_w66_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_sku_unsol_event,
- .setup = alc883_haier_w66_setup,
- .init_hook = alc_hp_automute,
- },
- [ALC888_3ST_HP] = {
- .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
- .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
- .num_dacs = ARRAY_SIZE(alc883_dac_nids),
- .dac_nids = alc883_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
- .channel_mode = alc888_3st_hp_modes,
- .need_dac_fix = 1,
- .input_mux = &alc883_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc888_3st_hp_setup,
- .init_hook = alc_hp_automute,
- },
- [ALC888_6ST_DELL] = {
- .mixers = { alc883_base_mixer, alc883_chmode_mixer },
- .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
- .num_dacs = ARRAY_SIZE(alc883_dac_nids),
- .dac_nids = alc883_dac_nids,
- .dig_out_nid = ALC883_DIGOUT_NID,
- .dig_in_nid = ALC883_DIGIN_NID,
- .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
- .channel_mode = alc883_sixstack_modes,
- .input_mux = &alc883_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc888_6st_dell_setup,
- .init_hook = alc_hp_automute,
- },
- [ALC883_MITAC] = {
- .mixers = { alc883_mitac_mixer },
- .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
- .num_dacs = ARRAY_SIZE(alc883_dac_nids),
- .dac_nids = alc883_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
- .channel_mode = alc883_3ST_2ch_modes,
- .input_mux = &alc883_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc883_mitac_setup,
- .init_hook = alc_hp_automute,
- },
- [ALC883_FUJITSU_PI2515] = {
- .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
- .init_verbs = { alc883_init_verbs,
- alc883_2ch_fujitsu_pi2515_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_fujitsu_pi2515_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc883_2ch_fujitsu_pi2515_setup,
- .init_hook = alc_hp_automute,
- },
- [ALC888_FUJITSU_XA3530] = {
- .mixers = { alc888_base_mixer, alc883_chmode_mixer },
- .init_verbs = { alc883_init_verbs,
- alc888_fujitsu_xa3530_verbs },
- .num_dacs = ARRAY_SIZE(alc883_dac_nids),
- .dac_nids = alc883_dac_nids,
- .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
- .adc_nids = alc883_adc_nids_rev,
- .capsrc_nids = alc883_capsrc_nids_rev,
- .dig_out_nid = ALC883_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes),
- .channel_mode = alc888_4ST_8ch_intel_modes,
- .num_mux_defs =
- ARRAY_SIZE(alc888_2_capture_sources),
- .input_mux = alc888_2_capture_sources,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc888_fujitsu_xa3530_setup,
- .init_hook = alc_hp_automute,
- },
- [ALC888_LENOVO_SKY] = {
- .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
- .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_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_sixstack_modes),
- .channel_mode = alc883_sixstack_modes,
- .need_dac_fix = 1,
- .input_mux = &alc883_lenovo_sky_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc888_lenovo_sky_setup,
- .init_hook = alc_hp_automute,
- },
- [ALC888_ASUS_M90V] = {
- .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
- .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
- .num_dacs = ARRAY_SIZE(alc883_dac_nids),
- .dac_nids = alc883_dac_nids,
- .dig_out_nid = ALC883_DIGOUT_NID,
- .dig_in_nid = ALC883_DIGIN_NID,
- .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
- .channel_mode = alc883_3ST_6ch_modes,
- .need_dac_fix = 1,
- .input_mux = &alc883_fujitsu_pi2515_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc883_mode2_setup,
- .init_hook = alc_inithook,
- },
- [ALC888_ASUS_EEE1601] = {
- .mixers = { alc883_asus_eee1601_mixer },
- .cap_mixer = alc883_asus_eee1601_cap_mixer,
- .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
- .num_dacs = ARRAY_SIZE(alc883_dac_nids),
- .dac_nids = alc883_dac_nids,
- .dig_out_nid = ALC883_DIGOUT_NID,
- .dig_in_nid = ALC883_DIGIN_NID,
- .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
- .channel_mode = alc883_3ST_2ch_modes,
- .need_dac_fix = 1,
- .input_mux = &alc883_asus_eee1601_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .init_hook = alc883_eee1601_inithook,
- },
- [ALC1200_ASUS_P5Q] = {
- .mixers = { alc883_base_mixer, alc883_chmode_mixer },
- .init_verbs = { alc883_init_verbs },
- .num_dacs = ARRAY_SIZE(alc883_dac_nids),
- .dac_nids = alc883_dac_nids,
- .dig_out_nid = ALC1200_DIGOUT_NID,
- .dig_in_nid = ALC883_DIGIN_NID,
- .slave_dig_outs = alc1200_slave_dig_outs,
- .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
- .channel_mode = alc883_sixstack_modes,
- .input_mux = &alc883_capture_source,
- },
- [ALC889A_MB31] = {
- .mixers = { alc889A_mb31_mixer, alc883_chmode_mixer},
- .init_verbs = { alc883_init_verbs, alc889A_mb31_verbs,
- alc880_gpio1_init_verbs },
- .adc_nids = alc883_adc_nids,
- .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
- .capsrc_nids = alc883_capsrc_nids,
- .dac_nids = alc883_dac_nids,
- .num_dacs = ARRAY_SIZE(alc883_dac_nids),
- .channel_mode = alc889A_mb31_6ch_modes,
- .num_channel_mode = ARRAY_SIZE(alc889A_mb31_6ch_modes),
- .input_mux = &alc889A_mb31_capture_source,
- .dig_out_nid = ALC883_DIGOUT_NID,
- .unsol_event = alc889A_mb31_unsol_event,
- .init_hook = alc889A_mb31_automute,
- },
- [ALC883_SONY_VAIO_TT] = {
- .mixers = { alc883_vaiott_mixer },
- .init_verbs = { alc883_init_verbs, alc883_vaiott_verbs },
- .num_dacs = ARRAY_SIZE(alc883_dac_nids),
- .dac_nids = alc883_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
- .channel_mode = alc883_3ST_2ch_modes,
- .input_mux = &alc883_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc883_vaiott_setup,
- .init_hook = alc_hp_automute,
- },
-};
-
-
/*
* Pin config fixes
*/
@@ -11003,8 +4230,35 @@ enum {
PINFIX_LENOVO_Y530,
PINFIX_PB_M5210,
PINFIX_ACER_ASPIRE_7736,
+ PINFIX_ASUS_W90V,
+ ALC889_FIXUP_DAC_ROUTE,
};
+/* Fix the connection of some pins for ALC889:
+ * At least, Acer Aspire 5935 shows the connections to DAC3/4 don't
+ * work correctly (bko#42740)
+ */
+static void alc889_fixup_dac_route(struct hda_codec *codec,
+ const struct alc_fixup *fix, int action)
+{
+ if (action == ALC_FIXUP_ACT_PRE_PROBE) {
+ /* fake the connections during parsing the tree */
+ hda_nid_t conn1[2] = { 0x0c, 0x0d };
+ hda_nid_t conn2[2] = { 0x0e, 0x0f };
+ snd_hda_override_conn_list(codec, 0x14, 2, conn1);
+ snd_hda_override_conn_list(codec, 0x15, 2, conn1);
+ snd_hda_override_conn_list(codec, 0x18, 2, conn2);
+ snd_hda_override_conn_list(codec, 0x1a, 2, conn2);
+ } else if (action == ALC_FIXUP_ACT_PROBE) {
+ /* restore the connections */
+ hda_nid_t conn[5] = { 0x0c, 0x0d, 0x0e, 0x0f, 0x26 };
+ snd_hda_override_conn_list(codec, 0x14, 5, conn);
+ snd_hda_override_conn_list(codec, 0x15, 5, conn);
+ snd_hda_override_conn_list(codec, 0x18, 5, conn);
+ snd_hda_override_conn_list(codec, 0x1a, 5, conn);
+ }
+}
+
static const struct alc_fixup alc882_fixups[] = {
[PINFIX_ABIT_AW9D_MAX] = {
.type = ALC_FIXUP_PINS,
@@ -11034,10 +4288,23 @@ static const struct alc_fixup alc882_fixups[] = {
.type = ALC_FIXUP_SKU,
.v.sku = ALC_FIXUP_SKU_IGNORE,
},
+ [PINFIX_ASUS_W90V] = {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
+ { 0x16, 0x99130110 }, /* fix sequence for CLFE */
+ { }
+ }
+ },
+ [ALC889_FIXUP_DAC_ROUTE] = {
+ .type = ALC_FIXUP_FUNC,
+ .v.func = alc889_fixup_dac_route,
+ },
};
static const struct snd_pci_quirk alc882_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210),
+ SND_PCI_QUIRK(0x1025, 0x0259, "Acer Aspire 5935", ALC889_FIXUP_DAC_ROUTE),
+ SND_PCI_QUIRK(0x1043, 0x1873, "ASUS W90V", PINFIX_ASUS_W90V),
SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", PINFIX_LENOVO_Y530),
SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", PINFIX_ACER_ASPIRE_7736),
@@ -11047,255 +4314,19 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
/*
* BIOS auto configuration
*/
-static int alc882_auto_create_input_ctls(struct hda_codec *codec,
- const struct auto_pin_cfg *cfg)
-{
- return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x23, 0x22);
-}
-
-static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
- hda_nid_t nid, int pin_type,
- hda_nid_t dac)
-{
- int idx;
-
- /* set as output */
- alc_set_pin_output(codec, nid, pin_type);
-
- if (dac == 0x25)
- idx = 4;
- else if (dac >= 0x02 && dac <= 0x05)
- idx = dac - 2;
- else
- return;
- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
-}
-
-static void alc882_auto_init_multi_out(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- int i;
-
- for (i = 0; i <= HDA_SIDE; i++) {
- hda_nid_t nid = spec->autocfg.line_out_pins[i];
- int pin_type = get_pin_type(spec->autocfg.line_out_type);
- if (nid)
- alc882_auto_set_output_and_unmute(codec, nid, pin_type,
- spec->multiout.dac_nids[i]);
- }
-}
-
-static void alc882_auto_init_hp_out(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- hda_nid_t pin, dac;
- int i;
-
- if (spec->autocfg.line_out_type != AUTO_PIN_HP_OUT) {
- for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
- pin = spec->autocfg.hp_pins[i];
- if (!pin)
- break;
- dac = spec->multiout.hp_nid;
- if (!dac)
- dac = spec->multiout.dac_nids[0]; /* to front */
- alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
- }
- }
-
- if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT) {
- for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
- pin = spec->autocfg.speaker_pins[i];
- if (!pin)
- break;
- dac = spec->multiout.extra_out_nid[0];
- if (!dac)
- dac = spec->multiout.dac_nids[0]; /* to front */
- alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac);
- }
- }
-}
-
-static void alc882_auto_init_analog_input(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- struct auto_pin_cfg *cfg = &spec->autocfg;
- int i;
-
- for (i = 0; i < cfg->num_inputs; i++) {
- hda_nid_t nid = cfg->inputs[i].pin;
- alc_set_input_pin(codec, nid, cfg->inputs[i].type);
- if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
- snd_hda_codec_write(codec, nid, 0,
- AC_VERB_SET_AMP_GAIN_MUTE,
- AMP_OUT_MUTE);
- }
-}
-
-static void alc882_auto_init_input_src(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- int c;
-
- for (c = 0; c < spec->num_adc_nids; c++) {
- hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
- hda_nid_t nid = spec->capsrc_nids[c];
- unsigned int mux_idx;
- const struct hda_input_mux *imux;
- int conns, mute, idx, item;
-
- /* mute ADC */
- snd_hda_codec_write(codec, spec->adc_nids[c], 0,
- AC_VERB_SET_AMP_GAIN_MUTE,
- AMP_IN_MUTE(0));
-
- conns = snd_hda_get_connections(codec, nid, conn_list,
- ARRAY_SIZE(conn_list));
- if (conns < 0)
- continue;
- mux_idx = c >= spec->num_mux_defs ? 0 : c;
- imux = &spec->input_mux[mux_idx];
- if (!imux->num_items && mux_idx > 0)
- imux = &spec->input_mux[0];
- for (idx = 0; idx < conns; idx++) {
- /* if the current connection is the selected one,
- * unmute it as default - otherwise mute it
- */
- mute = AMP_IN_MUTE(idx);
- for (item = 0; item < imux->num_items; item++) {
- if (imux->items[item].index == idx) {
- if (spec->cur_mux[c] == item)
- mute = AMP_IN_UNMUTE(idx);
- break;
- }
- }
- /* check if we have a selector or mixer
- * we could check for the widget type instead, but
- * just check for Amp-In presence (in case of mixer
- * without amp-in there is something wrong, this
- * function shouldn't be used or capsrc nid is wrong)
- */
- if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
- snd_hda_codec_write(codec, nid, 0,
- AC_VERB_SET_AMP_GAIN_MUTE,
- mute);
- else if (mute != AMP_IN_MUTE(idx))
- snd_hda_codec_write(codec, nid, 0,
- AC_VERB_SET_CONNECT_SEL,
- idx);
- }
- }
-}
-
-/* add mic boosts if needed */
-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;
- 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) {
- 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;
- 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;
- }
- }
- return 0;
-}
-
/* almost identical with ALC880 parser... */
static int alc882_parse_auto_config(struct hda_codec *codec)
{
- struct alc_spec *spec = codec->spec;
static const hda_nid_t alc882_ignore[] = { 0x1d, 0 };
- int err;
-
- err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
- alc882_ignore);
- if (err < 0)
- return err;
- if (!spec->autocfg.line_outs)
- return 0; /* can't find valid BIOS pin config */
-
- err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
- if (err < 0)
- return err;
- err = alc_auto_add_multi_channel_mode(codec);
- if (err < 0)
- return err;
- err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
- if (err < 0)
- return err;
- err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
- "Headphone");
- if (err < 0)
- return err;
- err = alc880_auto_create_extra_out(spec,
- spec->autocfg.speaker_pins[0],
- "Speaker");
- if (err < 0)
- return err;
- err = alc882_auto_create_input_ctls(codec, &spec->autocfg);
- if (err < 0)
- return err;
-
- spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-
- alc_auto_parse_digital(codec);
-
- if (spec->kctls.list)
- add_mixer(spec, spec->kctls.list);
-
- add_verb(spec, alc883_auto_init_verbs);
- /* if ADC 0x07 is available, initialize it, too */
- if (get_wcaps_type(get_wcaps(codec, 0x07)) == AC_WID_AUD_IN)
- add_verb(spec, alc882_adc1_init_verbs);
-
- spec->num_mux_defs = 1;
- spec->input_mux = &spec->private_imux[0];
-
- alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
-
- err = alc_auto_add_mic_boost(codec);
- if (err < 0)
- return err;
-
- return 1; /* config found */
+ static const hda_nid_t alc882_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+ return alc_parse_auto_config(codec, alc882_ignore, alc882_ssids);
}
-/* additional initialization for auto-configuration model */
-static void alc882_auto_init(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- alc882_auto_init_multi_out(codec);
- alc882_auto_init_hp_out(codec);
- alc882_auto_init_analog_input(codec);
- alc882_auto_init_input_src(codec);
- alc_auto_init_digital(codec);
- if (spec->unsol_event)
- alc_inithook(codec);
-}
+/*
+ */
+#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
+#include "alc882_quirks.c"
+#endif
static int patch_alc882(struct hda_codec *codec)
{
@@ -11308,9 +4339,12 @@ static int patch_alc882(struct hda_codec *codec)
codec->spec = spec;
+ spec->mixer_nid = 0x0b;
+
switch (codec->vendor_id) {
case 0x10ec0882:
case 0x10ec0885:
+ case 0x10ec0900:
break;
default:
/* ALC883 and variants */
@@ -11318,106 +4352,71 @@ static int patch_alc882(struct hda_codec *codec)
break;
}
- board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
- alc882_models,
- alc882_cfg_tbl);
+ err = alc_codec_rename_from_preset(codec);
+ if (err < 0)
+ goto error;
+
+ board_config = alc_board_config(codec, ALC882_MODEL_LAST,
+ alc882_models, alc882_cfg_tbl);
- if (board_config < 0 || board_config >= ALC882_MODEL_LAST)
- board_config = snd_hda_check_board_codec_sid_config(codec,
+ if (board_config < 0)
+ board_config = alc_board_codec_sid_config(codec,
ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl);
- if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
+ if (board_config < 0) {
printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
codec->chip_name);
- board_config = ALC882_AUTO;
+ board_config = ALC_MODEL_AUTO;
}
- if (board_config == ALC882_AUTO) {
+ if (board_config == ALC_MODEL_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);
- if (board_config == ALC882_AUTO) {
+ if (board_config == ALC_MODEL_AUTO) {
/* automatic parse from the BIOS config */
err = alc882_parse_auto_config(codec);
- if (err < 0) {
- alc_free(codec);
- return err;
- } else if (!err) {
+ if (err < 0)
+ goto error;
+#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
+ else if (!err) {
printk(KERN_INFO
"hda_codec: Cannot set up configuration "
"from BIOS. Using base mode...\n");
board_config = ALC882_3ST_DIG;
}
+#endif
}
- if (has_cdefine_beep(codec)) {
- err = snd_hda_attach_beep_device(codec, 0x1);
- if (err < 0) {
- alc_free(codec);
- return err;
- }
- }
-
- if (board_config != ALC882_AUTO)
+ if (board_config != ALC_MODEL_AUTO)
setup_preset(codec, &alc882_presets[board_config]);
- spec->stream_analog_playback = &alc882_pcm_analog_playback;
- spec->stream_analog_capture = &alc882_pcm_analog_capture;
- /* FIXME: setup DAC5 */
- /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
- spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
-
- spec->stream_digital_playback = &alc882_pcm_digital_playback;
- spec->stream_digital_capture = &alc882_pcm_digital_capture;
-
- if (!spec->adc_nids && spec->input_mux) {
- int i, j;
- spec->num_adc_nids = 0;
- for (i = 0; i < ARRAY_SIZE(alc882_adc_nids); i++) {
- const struct hda_input_mux *imux = spec->input_mux;
- hda_nid_t cap;
- hda_nid_t items[16];
- hda_nid_t nid = alc882_adc_nids[i];
- unsigned int wcap = get_wcaps(codec, nid);
- /* get type */
- wcap = get_wcaps_type(wcap);
- if (wcap != AC_WID_AUD_IN)
- continue;
- spec->private_adc_nids[spec->num_adc_nids] = nid;
- err = snd_hda_get_connections(codec, nid, &cap, 1);
- if (err < 0)
- continue;
- err = snd_hda_get_connections(codec, cap, items,
- ARRAY_SIZE(items));
- if (err < 0)
- continue;
- for (j = 0; j < imux->num_items; j++)
- if (imux->items[j].index >= err)
- break;
- if (j < imux->num_items)
- continue;
- spec->private_capsrc_nids[spec->num_adc_nids] = cap;
- spec->num_adc_nids++;
- }
- spec->adc_nids = spec->private_adc_nids;
- spec->capsrc_nids = spec->private_capsrc_nids;
+ if (!spec->no_analog && !spec->adc_nids) {
+ alc_auto_fill_adc_caps(codec);
+ alc_rebuild_imux_for_auto_mic(codec);
+ alc_remove_invalid_adc_nids(codec);
}
- set_capture_mixer(codec);
+ if (!spec->no_analog && !spec->cap_mixer)
+ set_capture_mixer(codec);
- if (has_cdefine_beep(codec))
+ if (!spec->no_analog && has_cdefine_beep(codec)) {
+ err = snd_hda_attach_beep_device(codec, 0x1);
+ if (err < 0)
+ goto error;
set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+ }
alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
spec->vmaster_nid = 0x0c;
codec->patch_ops = alc_patch_ops;
- if (board_config == ALC882_AUTO)
- spec->init_hook = alc882_auto_init;
+ if (board_config == ALC_MODEL_AUTO)
+ spec->init_hook = alc_auto_init_std;
alc_init_jacks(codec);
#ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -11426,1198 +4425,23 @@ static int patch_alc882(struct hda_codec *codec)
#endif
return 0;
-}
-
-
-/*
- * ALC262 support
- */
-
-#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
-#define ALC262_DIGIN_NID ALC880_DIGIN_NID
-
-#define alc262_dac_nids alc260_dac_nids
-#define alc262_adc_nids alc882_adc_nids
-#define alc262_adc_nids_alt alc882_adc_nids_alt
-#define alc262_capsrc_nids alc882_capsrc_nids
-#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
-
-#define alc262_modes alc260_modes
-#define alc262_capture_source alc882_capture_source
-
-static const hda_nid_t alc262_dmic_adc_nids[1] = {
- /* ADC0 */
- 0x09
-};
-
-static const hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
-
-static const struct snd_kcontrol_new alc262_base_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Front Playback Switch", 0x14, 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("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_MUTE("Mic Playback Switch", 0x0b, 0x0, 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 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),
- HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
- { } /* end */
-};
-
-/* update HP, line and mono-out pins according to the master switch */
-#define alc262_hp_master_update alc260_hp_master_update
-
-static void alc262_hp_bpc_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x1b;
- spec->autocfg.speaker_pins[0] = 0x16;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_PIN;
-}
-
-static void alc262_hp_wildwest_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x15;
- spec->autocfg.speaker_pins[0] = 0x16;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_PIN;
-}
-
-#define alc262_hp_master_sw_get alc260_hp_master_sw_get
-#define alc262_hp_master_sw_put alc260_hp_master_sw_put
-
-#define ALC262_HP_MASTER_SWITCH \
- { \
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
- .name = "Master Playback Switch", \
- .info = snd_ctl_boolean_mono_info, \
- .get = alc262_hp_master_sw_get, \
- .put = alc262_hp_master_sw_put, \
- }, \
- { \
- .iface = NID_MAPPING, \
- .name = "Master Playback Switch", \
- .private_value = 0x15 | (0x16 << 8) | (0x1b << 16), \
- }
-
-
-static const struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
- ALC262_HP_MASTER_SWITCH,
- HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
- HDA_OUTPUT),
- HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 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 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 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),
- HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
- HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
- HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
- ALC262_HP_MASTER_SWITCH,
- HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
- HDA_OUTPUT),
- HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
- 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 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),
- HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
- { } /* end */
-};
-
-static const 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 Volume", 0x18, 0, HDA_INPUT),
- { } /* end */
-};
-
-/* mute/unmute internal speaker according to the hp jack and mute state */
-static void alc262_hp_t5735_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x15;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_PIN;
-}
-
-static const struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
- HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
- 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 Volume", 0x18, 0, HDA_INPUT),
- { } /* end */
-};
-
-static const struct hda_verb alc262_hp_t5735_verbs[] = {
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- { }
-};
-
-static const struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
- HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
- HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
- { } /* end */
-};
-
-static const struct hda_verb alc262_hp_rp5700_verbs[] = {
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
- {}
-};
-
-static const struct hda_input_mux alc262_hp_rp5700_capture_source = {
- .num_items = 1,
- .items = {
- { "Line", 0x1 },
- },
-};
-
-/* bind hp and internal speaker mute (with plug check) as master switch */
-#define alc262_hippo_master_update alc262_hp_master_update
-#define alc262_hippo_master_sw_get alc262_hp_master_sw_get
-#define alc262_hippo_master_sw_put alc262_hp_master_sw_put
-
-#define ALC262_HIPPO_MASTER_SWITCH \
- { \
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
- .name = "Master Playback Switch", \
- .info = snd_ctl_boolean_mono_info, \
- .get = alc262_hippo_master_sw_get, \
- .put = alc262_hippo_master_sw_put, \
- }, \
- { \
- .iface = NID_MAPPING, \
- .name = "Master Playback Switch", \
- .subdevice = SUBDEV_HP(0) | (SUBDEV_LINE(0) << 8) | \
- (SUBDEV_SPEAKER(0) << 16), \
- }
-
-static const struct snd_kcontrol_new alc262_hippo_mixer[] = {
- ALC262_HIPPO_MASTER_SWITCH,
- HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 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("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_MUTE("Mic Playback Switch", 0x0b, 0x0, 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 Volume", 0x19, 0, HDA_INPUT),
- HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc262_hippo1_mixer[] = {
- HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- ALC262_HIPPO_MASTER_SWITCH,
- 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_MUTE("Mic Playback Switch", 0x0b, 0x0, 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 Volume", 0x19, 0, HDA_INPUT),
- { } /* end */
-};
-
-/* mute/unmute internal speaker according to the hp jack and mute state */
-static void alc262_hippo_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x15;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static void alc262_hippo1_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x1b;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-
-static const struct snd_kcontrol_new alc262_sony_mixer[] = {
- HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- 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("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
- HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
- HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- ALC262_HIPPO_MASTER_SWITCH,
- 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("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
- HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc262_tyan_mixer[] = {
- HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
- HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT),
- HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, 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_MUTE("Mic Playback Switch", 0x0b, 0x0, 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 Volume", 0x19, 0, HDA_INPUT),
- { } /* end */
-};
-
-static const struct hda_verb alc262_tyan_verbs[] = {
- /* Headphone automute */
- {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-
- /* P11 AUX_IN, white 4-pin connector */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1},
- {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93},
- {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19},
-
- {}
-};
-
-/* unsolicited event for HP jack sensing */
-static void alc262_tyan_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x1b;
- spec->autocfg.speaker_pins[0] = 0x15;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-
-#define alc262_capture_mixer alc882_capture_mixer
-#define alc262_capture_alt_mixer alc882_capture_alt_mixer
-
-/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static const struct hda_verb alc262_init_verbs[] = {
- /*
- * Unmute ADC0-2 and set the default input to mic-in
- */
- {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
- /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
- * mixer widget
- * Note: PASD motherboards uses the Line In 2 as the input for
- * front panel mic (mic 2)
- */
- /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-
- /*
- * Set up output mixers (0x0c - 0x0e)
- */
- /* set vol=0 to output mixers */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- /* set up input amps for analog loopback */
- /* Amp Indices: DAC = 0, mixer = 1 */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
- {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
-
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
-
- {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
-
- /* FIXME: use matrix-type input source selection */
- /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
- /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
- /* Input mixer2 */
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
- /* Input mixer3 */
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
-
- { }
-};
-
-static const struct hda_verb alc262_eapd_verbs[] = {
- {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
- {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
- { }
-};
-
-static const struct hda_verb alc262_hippo1_unsol_verbs[] = {
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
- {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
-
- {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {}
-};
-
-static const struct hda_verb alc262_sony_unsol_verbs[] = {
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
-
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {}
-};
-
-static const struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
- HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
- 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),
- { } /* end */
-};
-static const struct hda_verb alc262_toshiba_s06_verbs[] = {
- {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
- {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {}
-};
-
-static void alc262_toshiba_s06_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x15;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->ext_mic.pin = 0x18;
- spec->ext_mic.mux_idx = 0;
- spec->int_mic.pin = 0x12;
- spec->int_mic.mux_idx = 9;
- spec->auto_mic = 1;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_PIN;
+ error:
+ alc_free(codec);
+ return err;
}
-/*
- * nec model
- * 0x15 = headphone
- * 0x16 = internal speaker
- * 0x18 = external mic
- */
-
-static const struct snd_kcontrol_new alc262_nec_mixer[] = {
- HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 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 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),
- { } /* end */
-};
-
-static const struct hda_verb alc262_nec_verbs[] = {
- /* Unmute Speaker */
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
- /* Headphone */
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-
- /* External mic to headphone */
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- /* External mic to speaker */
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {}
-};
/*
- * fujitsu model
- * 0x14 = headphone/spdif-out, 0x15 = internal speaker,
- * 0x1b = port replicator headphone out
- */
-
-#define ALC_HP_EVENT ALC880_HP_EVENT
-
-static const struct hda_verb alc262_fujitsu_unsol_verbs[] = {
- {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {}
-};
-
-static const struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
- {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {}
-};
-
-static const struct hda_verb alc262_lenovo_3000_init_verbs[] = {
- /* Front Mic pin: input vref at 50% */
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {}
-};
-
-static const struct hda_input_mux alc262_fujitsu_capture_source = {
- .num_items = 3,
- .items = {
- { "Mic", 0x0 },
- { "Internal Mic", 0x1 },
- { "CD", 0x4 },
- },
-};
-
-static const struct hda_input_mux alc262_HP_capture_source = {
- .num_items = 5,
- .items = {
- { "Mic", 0x0 },
- { "Front Mic", 0x1 },
- { "Line", 0x2 },
- { "CD", 0x4 },
- { "AUX IN", 0x6 },
- },
-};
-
-static const struct hda_input_mux alc262_HP_D7000_capture_source = {
- .num_items = 4,
- .items = {
- { "Mic", 0x0 },
- { "Front Mic", 0x2 },
- { "Line", 0x1 },
- { "CD", 0x4 },
- },
-};
-
-static void alc262_fujitsu_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x14;
- spec->autocfg.hp_pins[1] = 0x1b;
- spec->autocfg.speaker_pins[0] = 0x15;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-/* bind volumes of both NID 0x0c and 0x0d */
-static const struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
- .ops = &snd_hda_bind_vol,
- .values = {
- HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
- HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
- 0
- },
-};
-
-static const struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
- HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Master Playback Switch",
- .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
- .info = snd_ctl_boolean_mono_info,
- .get = alc262_hp_master_sw_get,
- .put = alc262_hp_master_sw_put,
- },
- {
- .iface = NID_MAPPING,
- .name = "Master Playback Switch",
- .private_value = 0x1b,
- },
- 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 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 */
-};
-
-static void alc262_lenovo_3000_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x1b;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->autocfg.speaker_pins[1] = 0x16;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static const struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
- HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Master Playback Switch",
- .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
- .info = snd_ctl_boolean_mono_info,
- .get = alc262_hp_master_sw_get,
- .put = alc262_hp_master_sw_put,
- },
- 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 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 */
-};
-
-static const struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
- HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
- 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 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 Volume", 0x19, 0, HDA_INPUT),
- { } /* end */
-};
-
-/* additional init verbs for Benq laptops */
-static const struct hda_verb alc262_EAPD_verbs[] = {
- {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
- {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
- {}
-};
-
-static const struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
-
- {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
- {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
- {}
-};
-
-/* Samsung Q1 Ultra Vista model setup */
-static const struct snd_kcontrol_new alc262_ultra_mixer[] = {
- HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- 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 Volume", 0x19, 0, HDA_INPUT),
- HDA_CODEC_VOLUME("Headphone Mic Boost Volume", 0x15, 0, HDA_INPUT),
- { } /* end */
-};
-
-static const struct hda_verb alc262_ultra_verbs[] = {
- /* output mixer */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- /* speaker */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* HP */
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- /* internal mic */
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- /* ADC, choose mic */
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
- {}
-};
-
-/* mute/unmute internal speaker according to the hp jack and mute state */
-static void alc262_ultra_automute(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- unsigned int mute;
-
- mute = 0;
- /* auto-mute only when HP is used as HP */
- if (!spec->cur_mux[0]) {
- spec->jack_present = snd_hda_jack_detect(codec, 0x15);
- if (spec->jack_present)
- mute = HDA_AMP_MUTE;
- }
- /* mute/unmute internal speaker */
- snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
- HDA_AMP_MUTE, mute);
- /* mute/unmute HP */
- snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
- HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
-}
-
-/* unsolicited event for HP jack sensing */
-static void alc262_ultra_unsol_event(struct hda_codec *codec,
- unsigned int res)
-{
- if ((res >> 26) != ALC880_HP_EVENT)
- return;
- alc262_ultra_automute(codec);
-}
-
-static const struct hda_input_mux alc262_ultra_capture_source = {
- .num_items = 2,
- .items = {
- { "Mic", 0x1 },
- { "Headphone", 0x7 },
- },
-};
-
-static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct alc_spec *spec = codec->spec;
- int ret;
-
- ret = alc_mux_enum_put(kcontrol, ucontrol);
- if (!ret)
- return 0;
- /* reprogram the HP pin as mic or HP according to the input source */
- snd_hda_codec_write_cache(codec, 0x15, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
- spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
- alc262_ultra_automute(codec); /* mute/unmute HP */
- return ret;
-}
-
-static const struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
- HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Capture Source",
- .info = alc_mux_enum_info,
- .get = alc_mux_enum_get,
- .put = alc262_ultra_mux_enum_put,
- },
- {
- .iface = NID_MAPPING,
- .name = "Capture Source",
- .private_value = 0x15,
- },
- { } /* end */
-};
-
-/* We use two mixers depending on the output pin; 0x16 is a mono output
- * and thus it's bound with a different mixer.
- * This function returns which mixer amp should be used.
+ * ALC262 support
*/
-static int alc262_check_volbit(hda_nid_t nid)
-{
- if (!nid)
- return 0;
- else if (nid == 0x16)
- return 2;
- else
- return 1;
-}
-
-static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid,
- const char *pfx, int *vbits, int idx)
-{
- unsigned long val;
- int vbit;
-
- vbit = alc262_check_volbit(nid);
- if (!vbit)
- return 0;
- if (*vbits & vbit) /* a volume control for this mixer already there */
- return 0;
- *vbits |= vbit;
- if (vbit == 2)
- val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT);
- else
- val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT);
- return __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, idx, val);
-}
-
-static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid,
- const char *pfx, int idx)
-{
- unsigned long val;
-
- if (!nid)
- return 0;
- if (nid == 0x16)
- val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
- else
- val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
- return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, idx, val);
-}
-
-/* add playback controls from the parsed DAC table */
-static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
- const struct auto_pin_cfg *cfg)
+static int alc262_parse_auto_config(struct hda_codec *codec)
{
- const char *pfx;
- int vbits;
- int i, err;
-
- spec->multiout.num_dacs = 1; /* only use one dac */
- spec->multiout.dac_nids = spec->private_dac_nids;
- spec->private_dac_nids[0] = 2;
-
- pfx = alc_get_line_out_pfx(spec, 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);
- if (err < 0)
- return err;
- if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
- err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[i],
- "Speaker", i);
- if (err < 0)
- return err;
- }
- if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
- err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[i],
- "Headphone", i);
- if (err < 0)
- return err;
- }
- }
-
- vbits = alc262_check_volbit(cfg->line_out_pins[0]) |
- alc262_check_volbit(cfg->speaker_pins[0]) |
- alc262_check_volbit(cfg->hp_pins[0]);
- if (vbits == 1 || vbits == 2)
- pfx = "Master"; /* only one mixer is used */
- vbits = 0;
- for (i = 0; i < 2; i++) {
- err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[i], pfx,
- &vbits, i);
- if (err < 0)
- return err;
- if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
- err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[i],
- "Speaker", &vbits, i);
- if (err < 0)
- return err;
- }
- if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
- err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[i],
- "Headphone", &vbits, i);
- if (err < 0)
- return err;
- }
- }
- return 0;
+ static const hda_nid_t alc262_ignore[] = { 0x1d, 0 };
+ static const hda_nid_t alc262_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+ return alc_parse_auto_config(codec, alc262_ignore, alc262_ssids);
}
-#define alc262_auto_create_input_ctls \
- alc882_auto_create_input_ctls
-
-/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static const struct hda_verb alc262_volume_init_verbs[] = {
- /*
- * Unmute ADC0-2 and set the default input to mic-in
- */
- {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
- /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
- * mixer widget
- * Note: PASD motherboards uses the Line In 2 as the input for
- * front panel mic (mic 2)
- */
- /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-
- /*
- * Set up output mixers (0x0c - 0x0f)
- */
- /* set vol=0 to output mixers */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
- /* set up input amps for analog loopback */
- /* Amp Indices: DAC = 0, mixer = 1 */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
- /* FIXME: use matrix-type input source selection */
- /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
- /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
- /* Input mixer2 */
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
- /* Input mixer3 */
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
-
- { }
-};
-
-static const struct hda_verb alc262_HP_BPC_init_verbs[] = {
- /*
- * Unmute ADC0-2 and set the default input to mic-in
- */
- {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
- /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
- * mixer widget
- * Note: PASD motherboards uses the Line In 2 as the input for
- * front panel mic (mic 2)
- */
- /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
-
- /*
- * Set up output mixers (0x0c - 0x0e)
- */
- /* set vol=0 to output mixers */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
- /* set up input amps for analog loopback */
- /* Amp Indices: DAC = 0, mixer = 1 */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-
- {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
- {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
-
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
- {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
- {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
-
-
- /* FIXME: use matrix-type input source selection */
- /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 0b, 12 */
- /* Input mixer1: only unmute Mic */
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
- /* Input mixer2 */
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
- /* Input mixer3 */
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
-
- {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-
- { }
-};
-
-static const struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
- /*
- * Unmute ADC0-2 and set the default input to mic-in
- */
- {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
- /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
- * mixer widget
- * Note: PASD motherboards uses the Line In 2 as the input for front
- * panel mic (mic 2)
- */
- /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
- /*
- * Set up output mixers (0x0c - 0x0e)
- */
- /* set vol=0 to output mixers */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
- /* set up input amps for analog loopback */
- /* Amp Indices: DAC = 0, mixer = 1 */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
- {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
-
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-
- {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
-
- /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
- {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
- {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
-
- /* FIXME: use matrix-type input source selection */
- /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
- /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
- /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
- /* Input mixer2 */
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
- /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
- /* Input mixer3 */
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
- /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
-
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-
- { }
-};
-
-static const struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
-
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
-
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* MIC jack */
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
-
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP jack */
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {}
-};
-
/*
* Pin config fixes
*/
@@ -12656,396 +4480,11 @@ static const struct snd_pci_quirk alc262_fixup_tbl[] = {
#define alc262_loopbacks alc880_loopbacks
#endif
-/* pcm configuration: identical with ALC880 */
-#define alc262_pcm_analog_playback alc880_pcm_analog_playback
-#define alc262_pcm_analog_capture alc880_pcm_analog_capture
-#define alc262_pcm_digital_playback alc880_pcm_digital_playback
-#define alc262_pcm_digital_capture alc880_pcm_digital_capture
-
/*
- * BIOS auto configuration
*/
-static int alc262_parse_auto_config(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- int err;
- static const hda_nid_t alc262_ignore[] = { 0x1d, 0 };
-
- err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
- alc262_ignore);
- if (err < 0)
- return err;
- if (!spec->autocfg.line_outs) {
- if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
- spec->multiout.max_channels = 2;
- spec->no_analog = 1;
- goto dig_only;
- }
- return 0; /* can't find valid BIOS pin config */
- }
- err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
- if (err < 0)
- return err;
- err = alc262_auto_create_input_ctls(codec, &spec->autocfg);
- if (err < 0)
- return err;
-
- spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-
- dig_only:
- alc_auto_parse_digital(codec);
-
- if (spec->kctls.list)
- add_mixer(spec, spec->kctls.list);
-
- add_verb(spec, alc262_volume_init_verbs);
- spec->num_mux_defs = 1;
- spec->input_mux = &spec->private_imux[0];
-
- err = alc_auto_add_mic_boost(codec);
- if (err < 0)
- return err;
-
- alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
-
- return 1;
-}
-
-#define alc262_auto_init_multi_out alc882_auto_init_multi_out
-#define alc262_auto_init_hp_out alc882_auto_init_hp_out
-#define alc262_auto_init_analog_input alc882_auto_init_analog_input
-#define alc262_auto_init_input_src alc882_auto_init_input_src
-
-
-/* init callback for auto-configuration model -- overriding the default init */
-static void alc262_auto_init(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- alc262_auto_init_multi_out(codec);
- alc262_auto_init_hp_out(codec);
- alc262_auto_init_analog_input(codec);
- alc262_auto_init_input_src(codec);
- alc_auto_init_digital(codec);
- if (spec->unsol_event)
- alc_inithook(codec);
-}
-
-/*
- * configuration and preset
- */
-static const char * const alc262_models[ALC262_MODEL_LAST] = {
- [ALC262_BASIC] = "basic",
- [ALC262_HIPPO] = "hippo",
- [ALC262_HIPPO_1] = "hippo_1",
- [ALC262_FUJITSU] = "fujitsu",
- [ALC262_HP_BPC] = "hp-bpc",
- [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
- [ALC262_HP_TC_T5735] = "hp-tc-t5735",
- [ALC262_HP_RP5700] = "hp-rp5700",
- [ALC262_BENQ_ED8] = "benq",
- [ALC262_BENQ_T31] = "benq-t31",
- [ALC262_SONY_ASSAMD] = "sony-assamd",
- [ALC262_TOSHIBA_S06] = "toshiba-s06",
- [ALC262_TOSHIBA_RX1] = "toshiba-rx1",
- [ALC262_ULTRA] = "ultra",
- [ALC262_LENOVO_3000] = "lenovo-3000",
- [ALC262_NEC] = "nec",
- [ALC262_TYAN] = "tyan",
- [ALC262_AUTO] = "auto",
-};
-
-static const struct snd_pci_quirk alc262_cfg_tbl[] = {
- SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
- SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
- SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series",
- 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(0x103c, 0x170b, "HP Z200",
- ALC262_AUTO),
- 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),
- SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
- SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
- SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
- SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
- SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
- SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
- SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
- SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
- SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
- SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
- SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
- ALC262_HP_TC_T5735),
- SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
- SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
- SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
- SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
- SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */
- SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06),
- SND_PCI_QUIRK(0x104d, 0x9035, "Sony VAIO VGN-FW170J", ALC262_AUTO),
- SND_PCI_QUIRK(0x104d, 0x9047, "Sony VAIO Type G", ALC262_AUTO),
-#if 0 /* disable the quirk since model=auto works better in recent versions */
- SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO",
- ALC262_SONY_ASSAMD),
+#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
+#include "alc262_quirks.c"
#endif
- SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
- ALC262_TOSHIBA_RX1),
- SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
- SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
- SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
- SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN),
- SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc032, "Samsung Q1",
- ALC262_ULTRA),
- SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO),
- SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
- SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
- SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
- SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
- {}
-};
-
-static const struct alc_config_preset alc262_presets[] = {
- [ALC262_BASIC] = {
- .mixers = { alc262_base_mixer },
- .init_verbs = { alc262_init_verbs },
- .num_dacs = ARRAY_SIZE(alc262_dac_nids),
- .dac_nids = alc262_dac_nids,
- .hp_nid = 0x03,
- .num_channel_mode = ARRAY_SIZE(alc262_modes),
- .channel_mode = alc262_modes,
- .input_mux = &alc262_capture_source,
- },
- [ALC262_HIPPO] = {
- .mixers = { alc262_hippo_mixer },
- .init_verbs = { alc262_init_verbs, alc_hp15_unsol_verbs},
- .num_dacs = ARRAY_SIZE(alc262_dac_nids),
- .dac_nids = alc262_dac_nids,
- .hp_nid = 0x03,
- .dig_out_nid = ALC262_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc262_modes),
- .channel_mode = alc262_modes,
- .input_mux = &alc262_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc262_hippo_setup,
- .init_hook = alc_inithook,
- },
- [ALC262_HIPPO_1] = {
- .mixers = { alc262_hippo1_mixer },
- .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
- .num_dacs = ARRAY_SIZE(alc262_dac_nids),
- .dac_nids = alc262_dac_nids,
- .hp_nid = 0x02,
- .dig_out_nid = ALC262_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc262_modes),
- .channel_mode = alc262_modes,
- .input_mux = &alc262_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc262_hippo1_setup,
- .init_hook = alc_inithook,
- },
- [ALC262_FUJITSU] = {
- .mixers = { alc262_fujitsu_mixer },
- .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
- alc262_fujitsu_unsol_verbs },
- .num_dacs = ARRAY_SIZE(alc262_dac_nids),
- .dac_nids = alc262_dac_nids,
- .hp_nid = 0x03,
- .dig_out_nid = ALC262_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc262_modes),
- .channel_mode = alc262_modes,
- .input_mux = &alc262_fujitsu_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc262_fujitsu_setup,
- .init_hook = alc_inithook,
- },
- [ALC262_HP_BPC] = {
- .mixers = { alc262_HP_BPC_mixer },
- .init_verbs = { alc262_HP_BPC_init_verbs },
- .num_dacs = ARRAY_SIZE(alc262_dac_nids),
- .dac_nids = alc262_dac_nids,
- .hp_nid = 0x03,
- .num_channel_mode = ARRAY_SIZE(alc262_modes),
- .channel_mode = alc262_modes,
- .input_mux = &alc262_HP_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc262_hp_bpc_setup,
- .init_hook = alc_inithook,
- },
- [ALC262_HP_BPC_D7000_WF] = {
- .mixers = { alc262_HP_BPC_WildWest_mixer },
- .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
- .num_dacs = ARRAY_SIZE(alc262_dac_nids),
- .dac_nids = alc262_dac_nids,
- .hp_nid = 0x03,
- .num_channel_mode = ARRAY_SIZE(alc262_modes),
- .channel_mode = alc262_modes,
- .input_mux = &alc262_HP_D7000_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc262_hp_wildwest_setup,
- .init_hook = alc_inithook,
- },
- [ALC262_HP_BPC_D7000_WL] = {
- .mixers = { alc262_HP_BPC_WildWest_mixer,
- alc262_HP_BPC_WildWest_option_mixer },
- .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
- .num_dacs = ARRAY_SIZE(alc262_dac_nids),
- .dac_nids = alc262_dac_nids,
- .hp_nid = 0x03,
- .num_channel_mode = ARRAY_SIZE(alc262_modes),
- .channel_mode = alc262_modes,
- .input_mux = &alc262_HP_D7000_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc262_hp_wildwest_setup,
- .init_hook = alc_inithook,
- },
- [ALC262_HP_TC_T5735] = {
- .mixers = { alc262_hp_t5735_mixer },
- .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
- .num_dacs = ARRAY_SIZE(alc262_dac_nids),
- .dac_nids = alc262_dac_nids,
- .hp_nid = 0x03,
- .num_channel_mode = ARRAY_SIZE(alc262_modes),
- .channel_mode = alc262_modes,
- .input_mux = &alc262_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc262_hp_t5735_setup,
- .init_hook = alc_inithook,
- },
- [ALC262_HP_RP5700] = {
- .mixers = { alc262_hp_rp5700_mixer },
- .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
- .num_dacs = ARRAY_SIZE(alc262_dac_nids),
- .dac_nids = alc262_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc262_modes),
- .channel_mode = alc262_modes,
- .input_mux = &alc262_hp_rp5700_capture_source,
- },
- [ALC262_BENQ_ED8] = {
- .mixers = { alc262_base_mixer },
- .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
- .num_dacs = ARRAY_SIZE(alc262_dac_nids),
- .dac_nids = alc262_dac_nids,
- .hp_nid = 0x03,
- .num_channel_mode = ARRAY_SIZE(alc262_modes),
- .channel_mode = alc262_modes,
- .input_mux = &alc262_capture_source,
- },
- [ALC262_SONY_ASSAMD] = {
- .mixers = { alc262_sony_mixer },
- .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
- .num_dacs = ARRAY_SIZE(alc262_dac_nids),
- .dac_nids = alc262_dac_nids,
- .hp_nid = 0x02,
- .num_channel_mode = ARRAY_SIZE(alc262_modes),
- .channel_mode = alc262_modes,
- .input_mux = &alc262_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc262_hippo_setup,
- .init_hook = alc_inithook,
- },
- [ALC262_BENQ_T31] = {
- .mixers = { alc262_benq_t31_mixer },
- .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs,
- alc_hp15_unsol_verbs },
- .num_dacs = ARRAY_SIZE(alc262_dac_nids),
- .dac_nids = alc262_dac_nids,
- .hp_nid = 0x03,
- .num_channel_mode = ARRAY_SIZE(alc262_modes),
- .channel_mode = alc262_modes,
- .input_mux = &alc262_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc262_hippo_setup,
- .init_hook = alc_inithook,
- },
- [ALC262_ULTRA] = {
- .mixers = { alc262_ultra_mixer },
- .cap_mixer = alc262_ultra_capture_mixer,
- .init_verbs = { alc262_ultra_verbs },
- .num_dacs = ARRAY_SIZE(alc262_dac_nids),
- .dac_nids = alc262_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc262_modes),
- .channel_mode = alc262_modes,
- .input_mux = &alc262_ultra_capture_source,
- .adc_nids = alc262_adc_nids, /* ADC0 */
- .capsrc_nids = alc262_capsrc_nids,
- .num_adc_nids = 1, /* single ADC */
- .unsol_event = alc262_ultra_unsol_event,
- .init_hook = alc262_ultra_automute,
- },
- [ALC262_LENOVO_3000] = {
- .mixers = { alc262_lenovo_3000_mixer },
- .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
- alc262_lenovo_3000_unsol_verbs,
- alc262_lenovo_3000_init_verbs },
- .num_dacs = ARRAY_SIZE(alc262_dac_nids),
- .dac_nids = alc262_dac_nids,
- .hp_nid = 0x03,
- .dig_out_nid = ALC262_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc262_modes),
- .channel_mode = alc262_modes,
- .input_mux = &alc262_fujitsu_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc262_lenovo_3000_setup,
- .init_hook = alc_inithook,
- },
- [ALC262_NEC] = {
- .mixers = { alc262_nec_mixer },
- .init_verbs = { alc262_nec_verbs },
- .num_dacs = ARRAY_SIZE(alc262_dac_nids),
- .dac_nids = alc262_dac_nids,
- .hp_nid = 0x03,
- .num_channel_mode = ARRAY_SIZE(alc262_modes),
- .channel_mode = alc262_modes,
- .input_mux = &alc262_capture_source,
- },
- [ALC262_TOSHIBA_S06] = {
- .mixers = { alc262_toshiba_s06_mixer },
- .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
- alc262_eapd_verbs },
- .num_dacs = ARRAY_SIZE(alc262_dac_nids),
- .capsrc_nids = alc262_dmic_capsrc_nids,
- .dac_nids = alc262_dac_nids,
- .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
- .num_adc_nids = 1, /* single ADC */
- .dig_out_nid = ALC262_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc262_modes),
- .channel_mode = alc262_modes,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc262_toshiba_s06_setup,
- .init_hook = alc_inithook,
- },
- [ALC262_TOSHIBA_RX1] = {
- .mixers = { alc262_toshiba_rx1_mixer },
- .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs },
- .num_dacs = ARRAY_SIZE(alc262_dac_nids),
- .dac_nids = alc262_dac_nids,
- .hp_nid = 0x03,
- .num_channel_mode = ARRAY_SIZE(alc262_modes),
- .channel_mode = alc262_modes,
- .input_mux = &alc262_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc262_hippo_setup,
- .init_hook = alc_inithook,
- },
- [ALC262_TYAN] = {
- .mixers = { alc262_tyan_mixer },
- .init_verbs = { alc262_init_verbs, alc262_tyan_verbs},
- .num_dacs = ARRAY_SIZE(alc262_dac_nids),
- .dac_nids = alc262_dac_nids,
- .hp_nid = 0x02,
- .dig_out_nid = ALC262_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc262_modes),
- .channel_mode = alc262_modes,
- .input_mux = &alc262_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc262_tyan_setup,
- .init_hook = alc_hp_automute,
- },
-};
static int patch_alc262(struct hda_codec *codec)
{
@@ -13058,6 +4497,9 @@ static int patch_alc262(struct hda_codec *codec)
return -ENOMEM;
codec->spec = spec;
+
+ spec->mixer_nid = 0x0b;
+
#if 0
/* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
* under-run
@@ -13074,96 +4516,61 @@ static int patch_alc262(struct hda_codec *codec)
alc_fix_pll_init(codec, 0x20, 0x0a, 10);
- board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
- alc262_models,
- alc262_cfg_tbl);
+ board_config = alc_board_config(codec, ALC262_MODEL_LAST,
+ alc262_models, alc262_cfg_tbl);
if (board_config < 0) {
printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
codec->chip_name);
- board_config = ALC262_AUTO;
+ board_config = ALC_MODEL_AUTO;
}
- if (board_config == ALC262_AUTO) {
+ if (board_config == ALC_MODEL_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) {
+ if (board_config == ALC_MODEL_AUTO) {
/* automatic parse from the BIOS config */
err = alc262_parse_auto_config(codec);
- if (err < 0) {
- alc_free(codec);
- return err;
- } else if (!err) {
+ if (err < 0)
+ goto error;
+#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
+ else if (!err) {
printk(KERN_INFO
"hda_codec: Cannot set up configuration "
"from BIOS. Using base mode...\n");
board_config = ALC262_BASIC;
}
+#endif
}
- if (!spec->no_analog && has_cdefine_beep(codec)) {
- err = snd_hda_attach_beep_device(codec, 0x1);
- if (err < 0) {
- alc_free(codec);
- return err;
- }
- }
-
- if (board_config != ALC262_AUTO)
+ if (board_config != ALC_MODEL_AUTO)
setup_preset(codec, &alc262_presets[board_config]);
- spec->stream_analog_playback = &alc262_pcm_analog_playback;
- spec->stream_analog_capture = &alc262_pcm_analog_capture;
-
- spec->stream_digital_playback = &alc262_pcm_digital_playback;
- spec->stream_digital_capture = &alc262_pcm_digital_capture;
-
- if (!spec->adc_nids && spec->input_mux) {
- int i;
- /* check whether the digital-mic has to be supported */
- for (i = 0; i < spec->input_mux->num_items; i++) {
- if (spec->input_mux->items[i].index >= 9)
- break;
- }
- if (i < spec->input_mux->num_items) {
- /* use only ADC0 */
- spec->adc_nids = alc262_dmic_adc_nids;
- spec->num_adc_nids = 1;
- spec->capsrc_nids = alc262_dmic_capsrc_nids;
- } else {
- /* all analog inputs */
- /* check whether NID 0x07 is valid */
- unsigned int wcap = get_wcaps(codec, 0x07);
-
- /* get type */
- wcap = get_wcaps_type(wcap);
- if (wcap != AC_WID_AUD_IN) {
- spec->adc_nids = alc262_adc_nids_alt;
- spec->num_adc_nids =
- ARRAY_SIZE(alc262_adc_nids_alt);
- spec->capsrc_nids = alc262_capsrc_nids_alt;
- } else {
- spec->adc_nids = alc262_adc_nids;
- spec->num_adc_nids =
- ARRAY_SIZE(alc262_adc_nids);
- spec->capsrc_nids = alc262_capsrc_nids;
- }
- }
+ if (!spec->no_analog && !spec->adc_nids) {
+ alc_auto_fill_adc_caps(codec);
+ alc_rebuild_imux_for_auto_mic(codec);
+ alc_remove_invalid_adc_nids(codec);
}
- if (!spec->cap_mixer && !spec->no_analog)
+
+ if (!spec->no_analog && !spec->cap_mixer)
set_capture_mixer(codec);
- if (!spec->no_analog && has_cdefine_beep(codec))
+
+ if (!spec->no_analog && has_cdefine_beep(codec)) {
+ err = snd_hda_attach_beep_device(codec, 0x1);
+ if (err < 0)
+ goto error;
set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+ }
alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
spec->vmaster_nid = 0x0c;
codec->patch_ops = alc_patch_ops;
- if (board_config == ALC262_AUTO)
- spec->init_hook = alc262_auto_init;
+ if (board_config == ALC_MODEL_AUTO)
+ spec->init_hook = alc_auto_init_std;
spec->shutup = alc_eapd_shutup;
alc_init_jacks(codec);
@@ -13173,54 +4580,15 @@ static int patch_alc262(struct hda_codec *codec)
#endif
return 0;
+
+ error:
+ alc_free(codec);
+ return err;
}
/*
- * ALC268 channel source setting (2 channel)
+ * ALC268
*/
-#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
-#define alc268_modes alc260_modes
-
-static const hda_nid_t alc268_dac_nids[2] = {
- /* front, hp */
- 0x02, 0x03
-};
-
-static const hda_nid_t alc268_adc_nids[2] = {
- /* ADC0-1 */
- 0x08, 0x07
-};
-
-static const hda_nid_t alc268_adc_nids_alt[1] = {
- /* ADC0 */
- 0x08
-};
-
-static const hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
-
-static const struct snd_kcontrol_new alc268_base_mixer[] = {
- /* output mixer control */
- HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
- 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 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),
- { }
-};
-
-static const struct snd_kcontrol_new alc268_toshiba_mixer[] = {
- /* output mixer control */
- 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 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),
- { }
-};
-
/* bind Beep switches of both NID 0x0f and 0x10 */
static const struct hda_bind_ctls alc268_bind_beep_sw = {
.ops = &snd_hda_bind_sw,
@@ -13237,851 +4605,36 @@ static const struct snd_kcontrol_new alc268_beep_mixer[] = {
{ }
};
-static const struct hda_verb alc268_eapd_verbs[] = {
- {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
- {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
- { }
-};
-
-/* Toshiba specific */
-static const struct hda_verb alc268_toshiba_verbs[] = {
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- { } /* end */
-};
-
-/* Acer specific */
-/* bind volumes of both NID 0x02 and 0x03 */
-static const struct hda_bind_ctls alc268_acer_bind_master_vol = {
- .ops = &snd_hda_bind_vol,
- .values = {
- HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
- HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
- 0
- },
-};
-
-static void alc268_acer_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x14;
- spec->autocfg.speaker_pins[0] = 0x15;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-#define alc268_acer_master_sw_get alc262_hp_master_sw_get
-#define alc268_acer_master_sw_put alc262_hp_master_sw_put
-
-static const struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
- /* output mixer control */
- HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Master Playback Switch",
- .subdevice = HDA_SUBDEV_NID_FLAG | 0x15,
- .info = snd_ctl_boolean_mono_info,
- .get = alc268_acer_master_sw_get,
- .put = alc268_acer_master_sw_put,
- },
- HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
- { }
-};
-
-static const struct snd_kcontrol_new alc268_acer_mixer[] = {
- /* output mixer control */
- HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Master Playback Switch",
- .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
- .info = snd_ctl_boolean_mono_info,
- .get = alc268_acer_master_sw_get,
- .put = alc268_acer_master_sw_put,
- },
- 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),
- { }
-};
-
-static const struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
- /* output mixer control */
- HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Master Playback Switch",
- .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
- .info = snd_ctl_boolean_mono_info,
- .get = alc268_acer_master_sw_get,
- .put = alc268_acer_master_sw_put,
- },
- HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
- HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
- { }
-};
-
-static const struct hda_verb alc268_acer_aspire_one_verbs[] = {
- {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
- {0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
- { }
-};
-
-static const struct hda_verb alc268_acer_verbs[] = {
- {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
- {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- { }
-};
-
-/* unsolicited event for HP jack sensing */
-#define alc268_toshiba_setup alc262_hippo_setup
-
-static void alc268_acer_lc_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- spec->autocfg.hp_pins[0] = 0x15;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
- spec->ext_mic.pin = 0x18;
- spec->ext_mic.mux_idx = 0;
- spec->int_mic.pin = 0x12;
- spec->int_mic.mux_idx = 6;
- spec->auto_mic = 1;
-}
-
-static const struct snd_kcontrol_new alc268_dell_mixer[] = {
- /* output mixer control */
- HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
- 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 Volume", 0x18, 0, HDA_INPUT),
- HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
- { }
-};
-
-static const struct hda_verb alc268_dell_verbs[] = {
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
- { }
-};
-
-/* mute/unmute internal speaker according to the hp jack and mute state */
-static void alc268_dell_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x15;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->ext_mic.pin = 0x18;
- spec->ext_mic.mux_idx = 0;
- spec->int_mic.pin = 0x19;
- spec->int_mic.mux_idx = 1;
- spec->auto_mic = 1;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_PIN;
-}
-
-static const struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
- HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Speaker 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 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
- HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
- { }
-};
-
-static const struct hda_verb alc267_quanta_il1_verbs[] = {
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
- { }
-};
-
-static void alc267_quanta_il1_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- spec->autocfg.hp_pins[0] = 0x15;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->ext_mic.pin = 0x18;
- spec->ext_mic.mux_idx = 0;
- spec->int_mic.pin = 0x19;
- spec->int_mic.mux_idx = 1;
- spec->auto_mic = 1;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_PIN;
-}
-
-/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static const struct hda_verb alc268_base_init_verbs[] = {
- /* Unmute DAC0-1 and set vol = 0 */
- {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
- /*
- * Set up output mixers (0x0c - 0x0e)
- */
- /* set vol=0 to output mixers */
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
-
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
- {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
- {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
-
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-
- /* set PCBEEP vol = 0, mute connections */
+/* set PCBEEP vol = 0, mute connections */
+static const struct hda_verb alc268_beep_init_verbs[] = {
{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-
- /* Unmute Selector 23h,24h and set the default input to mic-in */
-
- {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
{ }
};
/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static const struct hda_verb alc268_volume_init_verbs[] = {
- /* set output DAC */
- {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
- {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
- {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
-
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-
- /* set PCBEEP vol = 0, mute connections */
- {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-
- { }
-};
-
-static const struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = {
- HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
- HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
- _DEFINE_CAPSRC(1),
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc268_capture_mixer[] = {
- HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
- _DEFINE_CAPSRC(2),
- { } /* end */
-};
-
-static const struct hda_input_mux alc268_capture_source = {
- .num_items = 4,
- .items = {
- { "Mic", 0x0 },
- { "Front Mic", 0x1 },
- { "Line", 0x2 },
- { "CD", 0x3 },
- },
-};
-
-static const struct hda_input_mux alc268_acer_capture_source = {
- .num_items = 3,
- .items = {
- { "Mic", 0x0 },
- { "Internal Mic", 0x1 },
- { "Line", 0x2 },
- },
-};
-
-static const struct hda_input_mux alc268_acer_dmic_capture_source = {
- .num_items = 3,
- .items = {
- { "Mic", 0x0 },
- { "Internal Mic", 0x6 },
- { "Line", 0x2 },
- },
-};
-
-#ifdef CONFIG_SND_DEBUG
-static const struct snd_kcontrol_new alc268_test_mixer[] = {
- /* Volume widgets */
- HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
- HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
- HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
- HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
- HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
- HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
- HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
- HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
- HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
- HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
- /* The below appears problematic on some hardwares */
- /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
- HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
- HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
-
- /* Modes for retasking pin widgets */
- ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
- ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
- ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
- ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
-
- /* Controls for GPIO pins, assuming they are configured as outputs */
- ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
- ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
- ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
- ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
-
- /* Switches to allow the digital SPDIF output pin to be enabled.
- * The ALC268 does not have an SPDIF input.
- */
- ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
-
- /* A switch allowing EAPD to be enabled. Some laptops seem to use
- * this output to turn on an external amplifier.
- */
- ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
- ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
-
- { } /* end */
-};
-#endif
-
-/* create input playback/capture controls for the given pin */
-static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
- const char *ctlname, int idx)
-{
- hda_nid_t dac;
- int err;
-
- switch (nid) {
- case 0x14:
- case 0x16:
- dac = 0x02;
- break;
- case 0x15:
- case 0x1a: /* ALC259/269 only */
- case 0x1b: /* ALC259/269 only */
- case 0x21: /* ALC269vb has this pin, too */
- dac = 0x03;
- break;
- default:
- snd_printd(KERN_WARNING "hda_codec: "
- "ignoring pin 0x%x as unknown\n", nid);
- return 0;
- }
- if (spec->multiout.dac_nids[0] != dac &&
- spec->multiout.dac_nids[1] != dac) {
- err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
- HDA_COMPOSE_AMP_VAL(dac, 3, idx,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
- }
-
- if (nid != 0x16)
- err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
- HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
- else /* mono */
- err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
- HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT));
- if (err < 0)
- return err;
- return 0;
-}
-
-/* add playback controls from the parsed DAC table */
-static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
- const struct auto_pin_cfg *cfg)
-{
- hda_nid_t nid;
- int err;
-
- spec->multiout.dac_nids = spec->private_dac_nids;
-
- nid = cfg->line_out_pins[0];
- if (nid) {
- const char *name;
- if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
- name = "Speaker";
- else
- name = "Front";
- err = alc268_new_analog_output(spec, nid, name, 0);
- if (err < 0)
- return err;
- }
-
- nid = cfg->speaker_pins[0];
- if (nid == 0x1d) {
- err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, "Speaker",
- HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
- if (err < 0)
- return err;
- } else if (nid) {
- err = alc268_new_analog_output(spec, nid, "Speaker", 0);
- if (err < 0)
- return err;
- }
- nid = cfg->hp_pins[0];
- if (nid) {
- err = alc268_new_analog_output(spec, nid, "Headphone", 0);
- if (err < 0)
- return err;
- }
-
- nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
- if (nid == 0x16) {
- err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, "Mono",
- HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
- }
- return 0;
-}
-
-/* create playback/capture controls for input pins */
-static int alc268_auto_create_input_ctls(struct hda_codec *codec,
- const struct auto_pin_cfg *cfg)
-{
- return alc_auto_create_input_ctls(codec, cfg, 0, 0x23, 0x24);
-}
-
-static void alc268_auto_set_output_and_unmute(struct hda_codec *codec,
- hda_nid_t nid, int pin_type)
-{
- int idx;
-
- alc_set_pin_output(codec, nid, pin_type);
- if (nid == 0x14 || nid == 0x16)
- idx = 0;
- else
- idx = 1;
- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
-}
-
-static void alc268_auto_init_multi_out(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- int i;
-
- for (i = 0; i < spec->autocfg.line_outs; i++) {
- hda_nid_t nid = spec->autocfg.line_out_pins[i];
- int pin_type = get_pin_type(spec->autocfg.line_out_type);
- alc268_auto_set_output_and_unmute(codec, nid, pin_type);
- }
-}
-
-static void alc268_auto_init_hp_out(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- hda_nid_t pin;
- int i;
-
- for (i = 0; i < spec->autocfg.hp_outs; i++) {
- pin = spec->autocfg.hp_pins[i];
- alc268_auto_set_output_and_unmute(codec, pin, PIN_HP);
- }
- for (i = 0; i < spec->autocfg.speaker_outs; i++) {
- pin = spec->autocfg.speaker_pins[i];
- alc268_auto_set_output_and_unmute(codec, pin, PIN_OUT);
- }
- if (spec->autocfg.mono_out_pin)
- snd_hda_codec_write(codec, spec->autocfg.mono_out_pin, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-}
-
-static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
- hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
- hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
- unsigned int dac_vol1, dac_vol2;
-
- if (line_nid == 0x1d || speaker_nid == 0x1d) {
- snd_hda_codec_write(codec, speaker_nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
- /* mute mixer inputs from 0x1d */
- snd_hda_codec_write(codec, 0x0f, 0,
- AC_VERB_SET_AMP_GAIN_MUTE,
- AMP_IN_UNMUTE(1));
- snd_hda_codec_write(codec, 0x10, 0,
- AC_VERB_SET_AMP_GAIN_MUTE,
- AMP_IN_UNMUTE(1));
- } else {
- /* unmute mixer inputs from 0x1d */
- snd_hda_codec_write(codec, 0x0f, 0,
- AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
- snd_hda_codec_write(codec, 0x10, 0,
- AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
- }
-
- dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
- if (line_nid == 0x14)
- dac_vol2 = AMP_OUT_ZERO;
- else if (line_nid == 0x15)
- dac_vol1 = AMP_OUT_ZERO;
- if (hp_nid == 0x14)
- dac_vol2 = AMP_OUT_ZERO;
- else if (hp_nid == 0x15)
- dac_vol1 = AMP_OUT_ZERO;
- if (line_nid != 0x16 || hp_nid != 0x16 ||
- spec->autocfg.line_out_pins[1] != 0x16 ||
- spec->autocfg.line_out_pins[2] != 0x16)
- dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
-
- snd_hda_codec_write(codec, 0x02, 0,
- AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
- snd_hda_codec_write(codec, 0x03, 0,
- AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
-}
-
-/* pcm configuration: identical with ALC880 */
-#define alc268_pcm_analog_playback alc880_pcm_analog_playback
-#define alc268_pcm_analog_capture alc880_pcm_analog_capture
-#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
-#define alc268_pcm_digital_playback alc880_pcm_digital_playback
-
-/*
* BIOS auto configuration
*/
static int alc268_parse_auto_config(struct hda_codec *codec)
{
+ static const hda_nid_t alc268_ssids[] = { 0x15, 0x1b, 0x14, 0 };
struct alc_spec *spec = codec->spec;
- int err;
- static const hda_nid_t alc268_ignore[] = { 0 };
-
- err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
- alc268_ignore);
- if (err < 0)
- return err;
- if (!spec->autocfg.line_outs) {
- if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
- spec->multiout.max_channels = 2;
- spec->no_analog = 1;
- goto dig_only;
+ int err = alc_parse_auto_config(codec, NULL, alc268_ssids);
+ if (err > 0) {
+ if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d) {
+ add_mixer(spec, alc268_beep_mixer);
+ add_verb(spec, alc268_beep_init_verbs);
}
- return 0; /* can't find valid BIOS pin config */
}
- err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
- if (err < 0)
- return err;
- err = alc268_auto_create_input_ctls(codec, &spec->autocfg);
- if (err < 0)
- return err;
-
- spec->multiout.max_channels = 2;
-
- dig_only:
- /* digital only support output */
- alc_auto_parse_digital(codec);
- if (spec->kctls.list)
- add_mixer(spec, spec->kctls.list);
-
- if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d)
- add_mixer(spec, alc268_beep_mixer);
-
- add_verb(spec, alc268_volume_init_verbs);
- spec->num_mux_defs = 2;
- spec->input_mux = &spec->private_imux[0];
-
- err = alc_auto_add_mic_boost(codec);
- if (err < 0)
- return err;
-
- alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
-
- return 1;
-}
-
-#define alc268_auto_init_analog_input alc882_auto_init_analog_input
-#define alc268_auto_init_input_src alc882_auto_init_input_src
-
-/* init callback for auto-configuration model -- overriding the default init */
-static void alc268_auto_init(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- alc268_auto_init_multi_out(codec);
- alc268_auto_init_hp_out(codec);
- alc268_auto_init_mono_speaker_out(codec);
- alc268_auto_init_analog_input(codec);
- alc268_auto_init_input_src(codec);
- alc_auto_init_digital(codec);
- if (spec->unsol_event)
- alc_inithook(codec);
+ return err;
}
/*
- * configuration and preset
*/
-static const char * const alc268_models[ALC268_MODEL_LAST] = {
- [ALC267_QUANTA_IL1] = "quanta-il1",
- [ALC268_3ST] = "3stack",
- [ALC268_TOSHIBA] = "toshiba",
- [ALC268_ACER] = "acer",
- [ALC268_ACER_DMIC] = "acer-dmic",
- [ALC268_ACER_ASPIRE_ONE] = "acer-aspire",
- [ALC268_DELL] = "dell",
- [ALC268_ZEPTO] = "zepto",
-#ifdef CONFIG_SND_DEBUG
- [ALC268_TEST] = "test",
-#endif
- [ALC268_AUTO] = "auto",
-};
-
-static const struct snd_pci_quirk alc268_cfg_tbl[] = {
- SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
- SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
- SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
- SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
- SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
- SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
- ALC268_ACER_ASPIRE_ONE),
- SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
- SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron 910", ALC268_AUTO),
- SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0,
- "Dell Inspiron Mini9/Vostro A90", ALC268_DELL),
- /* almost compatible with toshiba but with optional digital outs;
- * auto-probing seems working fine
- */
- SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series",
- ALC268_AUTO),
- SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
- SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
- SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
- SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
- {}
-};
-
-/* Toshiba laptops have no unique PCI SSID but only codec SSID */
-static const struct snd_pci_quirk alc268_ssid_cfg_tbl[] = {
- SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO),
- SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO),
- SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05",
- ALC268_TOSHIBA),
- {}
-};
-
-static const struct alc_config_preset alc268_presets[] = {
- [ALC267_QUANTA_IL1] = {
- .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer,
- alc268_capture_nosrc_mixer },
- .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
- alc267_quanta_il1_verbs },
- .num_dacs = ARRAY_SIZE(alc268_dac_nids),
- .dac_nids = alc268_dac_nids,
- .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
- .adc_nids = alc268_adc_nids_alt,
- .hp_nid = 0x03,
- .num_channel_mode = ARRAY_SIZE(alc268_modes),
- .channel_mode = alc268_modes,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc267_quanta_il1_setup,
- .init_hook = alc_inithook,
- },
- [ALC268_3ST] = {
- .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
- alc268_beep_mixer },
- .init_verbs = { alc268_base_init_verbs },
- .num_dacs = ARRAY_SIZE(alc268_dac_nids),
- .dac_nids = alc268_dac_nids,
- .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
- .adc_nids = alc268_adc_nids_alt,
- .capsrc_nids = alc268_capsrc_nids,
- .hp_nid = 0x03,
- .dig_out_nid = ALC268_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc268_modes),
- .channel_mode = alc268_modes,
- .input_mux = &alc268_capture_source,
- },
- [ALC268_TOSHIBA] = {
- .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer,
- alc268_beep_mixer },
- .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
- alc268_toshiba_verbs },
- .num_dacs = ARRAY_SIZE(alc268_dac_nids),
- .dac_nids = alc268_dac_nids,
- .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
- .adc_nids = alc268_adc_nids_alt,
- .capsrc_nids = alc268_capsrc_nids,
- .hp_nid = 0x03,
- .num_channel_mode = ARRAY_SIZE(alc268_modes),
- .channel_mode = alc268_modes,
- .input_mux = &alc268_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc268_toshiba_setup,
- .init_hook = alc_inithook,
- },
- [ALC268_ACER] = {
- .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
- alc268_beep_mixer },
- .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
- alc268_acer_verbs },
- .num_dacs = ARRAY_SIZE(alc268_dac_nids),
- .dac_nids = alc268_dac_nids,
- .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
- .adc_nids = alc268_adc_nids_alt,
- .capsrc_nids = alc268_capsrc_nids,
- .hp_nid = 0x02,
- .num_channel_mode = ARRAY_SIZE(alc268_modes),
- .channel_mode = alc268_modes,
- .input_mux = &alc268_acer_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc268_acer_setup,
- .init_hook = alc_inithook,
- },
- [ALC268_ACER_DMIC] = {
- .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
- alc268_beep_mixer },
- .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
- alc268_acer_verbs },
- .num_dacs = ARRAY_SIZE(alc268_dac_nids),
- .dac_nids = alc268_dac_nids,
- .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
- .adc_nids = alc268_adc_nids_alt,
- .capsrc_nids = alc268_capsrc_nids,
- .hp_nid = 0x02,
- .num_channel_mode = ARRAY_SIZE(alc268_modes),
- .channel_mode = alc268_modes,
- .input_mux = &alc268_acer_dmic_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc268_acer_setup,
- .init_hook = alc_inithook,
- },
- [ALC268_ACER_ASPIRE_ONE] = {
- .mixers = { alc268_acer_aspire_one_mixer,
- alc268_beep_mixer,
- alc268_capture_nosrc_mixer },
- .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
- alc268_acer_aspire_one_verbs },
- .num_dacs = ARRAY_SIZE(alc268_dac_nids),
- .dac_nids = alc268_dac_nids,
- .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
- .adc_nids = alc268_adc_nids_alt,
- .capsrc_nids = alc268_capsrc_nids,
- .hp_nid = 0x03,
- .num_channel_mode = ARRAY_SIZE(alc268_modes),
- .channel_mode = alc268_modes,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc268_acer_lc_setup,
- .init_hook = alc_inithook,
- },
- [ALC268_DELL] = {
- .mixers = { alc268_dell_mixer, alc268_beep_mixer,
- alc268_capture_nosrc_mixer },
- .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
- alc268_dell_verbs },
- .num_dacs = ARRAY_SIZE(alc268_dac_nids),
- .dac_nids = alc268_dac_nids,
- .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
- .adc_nids = alc268_adc_nids_alt,
- .capsrc_nids = alc268_capsrc_nids,
- .hp_nid = 0x02,
- .num_channel_mode = ARRAY_SIZE(alc268_modes),
- .channel_mode = alc268_modes,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc268_dell_setup,
- .init_hook = alc_inithook,
- },
- [ALC268_ZEPTO] = {
- .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
- alc268_beep_mixer },
- .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
- alc268_toshiba_verbs },
- .num_dacs = ARRAY_SIZE(alc268_dac_nids),
- .dac_nids = alc268_dac_nids,
- .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
- .adc_nids = alc268_adc_nids_alt,
- .capsrc_nids = alc268_capsrc_nids,
- .hp_nid = 0x03,
- .dig_out_nid = ALC268_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc268_modes),
- .channel_mode = alc268_modes,
- .input_mux = &alc268_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc268_toshiba_setup,
- .init_hook = alc_inithook,
- },
-#ifdef CONFIG_SND_DEBUG
- [ALC268_TEST] = {
- .mixers = { alc268_test_mixer, alc268_capture_mixer },
- .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
- alc268_volume_init_verbs },
- .num_dacs = ARRAY_SIZE(alc268_dac_nids),
- .dac_nids = alc268_dac_nids,
- .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
- .adc_nids = alc268_adc_nids_alt,
- .capsrc_nids = alc268_capsrc_nids,
- .hp_nid = 0x03,
- .dig_out_nid = ALC268_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc268_modes),
- .channel_mode = alc268_modes,
- .input_mux = &alc268_capture_source,
- },
-#endif
-};
-
static int patch_alc268(struct hda_codec *codec)
{
struct alc_spec *spec;
- int board_config;
int i, has_beep, err;
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
@@ -14090,42 +4643,12 @@ static int patch_alc268(struct hda_codec *codec)
codec->spec = spec;
- board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
- alc268_models,
- alc268_cfg_tbl);
+ /* ALC268 has no aa-loopback mixer */
- if (board_config < 0 || board_config >= ALC268_MODEL_LAST)
- board_config = snd_hda_check_board_codec_sid_config(codec,
- ALC268_MODEL_LAST, alc268_models, alc268_ssid_cfg_tbl);
-
- if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
- printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
- codec->chip_name);
- board_config = ALC268_AUTO;
- }
-
- if (board_config == ALC268_AUTO) {
- /* automatic parse from the BIOS config */
- err = alc268_parse_auto_config(codec);
- if (err < 0) {
- alc_free(codec);
- return err;
- } else if (!err) {
- printk(KERN_INFO
- "hda_codec: Cannot set up configuration "
- "from BIOS. Using base mode...\n");
- board_config = ALC268_3ST;
- }
- }
-
- if (board_config != ALC268_AUTO)
- setup_preset(codec, &alc268_presets[board_config]);
-
- spec->stream_analog_playback = &alc268_pcm_analog_playback;
- spec->stream_analog_capture = &alc268_pcm_analog_capture;
- spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
-
- spec->stream_digital_playback = &alc268_pcm_digital_playback;
+ /* automatic parse from the BIOS config */
+ err = alc268_parse_auto_config(codec);
+ if (err < 0)
+ goto error;
has_beep = 0;
for (i = 0; i < spec->num_mixers; i++) {
@@ -14137,10 +4660,8 @@ static int patch_alc268(struct hda_codec *codec)
if (has_beep) {
err = snd_hda_attach_beep_device(codec, 0x1);
- if (err < 0) {
- alc_free(codec);
- return err;
- }
+ if (err < 0)
+ goto error;
if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
/* override the amp caps for beep generator */
snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
@@ -14150,535 +4671,37 @@ static int patch_alc268(struct hda_codec *codec)
(0 << AC_AMPCAP_MUTE_SHIFT));
}
- if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
- /* check whether NID 0x07 is valid */
- unsigned int wcap = get_wcaps(codec, 0x07);
-
- spec->capsrc_nids = alc268_capsrc_nids;
- /* get type */
- wcap = get_wcaps_type(wcap);
- if (spec->auto_mic ||
- wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
- spec->adc_nids = alc268_adc_nids_alt;
- spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
- if (spec->auto_mic)
- fixup_automic_adc(codec);
- if (spec->auto_mic || spec->input_mux->num_items == 1)
- add_mixer(spec, alc268_capture_nosrc_mixer);
- else
- add_mixer(spec, alc268_capture_alt_mixer);
- } else {
- spec->adc_nids = alc268_adc_nids;
- spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
- add_mixer(spec, alc268_capture_mixer);
- }
+ if (!spec->no_analog && !spec->adc_nids) {
+ alc_auto_fill_adc_caps(codec);
+ alc_rebuild_imux_for_auto_mic(codec);
+ alc_remove_invalid_adc_nids(codec);
}
+ if (!spec->no_analog && !spec->cap_mixer)
+ set_capture_mixer(codec);
+
spec->vmaster_nid = 0x02;
codec->patch_ops = alc_patch_ops;
- if (board_config == ALC268_AUTO)
- spec->init_hook = alc268_auto_init;
+ spec->init_hook = alc_auto_init_std;
spec->shutup = alc_eapd_shutup;
alc_init_jacks(codec);
return 0;
-}
-
-/*
- * ALC269 channel source setting (2 channel)
- */
-#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
-
-#define alc269_dac_nids alc260_dac_nids
-
-static const hda_nid_t alc269_adc_nids[1] = {
- /* ADC1 */
- 0x08,
-};
-
-static const hda_nid_t alc269_capsrc_nids[1] = {
- 0x23,
-};
-
-static const hda_nid_t alc269vb_adc_nids[1] = {
- /* ADC1 */
- 0x09,
-};
-
-static const hda_nid_t alc269vb_capsrc_nids[1] = {
- 0x22,
-};
-
-static const hda_nid_t alc269_adc_candidates[] = {
- 0x08, 0x09, 0x07, 0x11,
-};
-
-#define alc269_modes alc260_modes
-#define alc269_capture_source alc880_lg_lw_capture_source
-
-static const struct snd_kcontrol_new alc269_base_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
- 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_MUTE("Mic Playback Switch", 0x0b, 0x0, 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 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 */
-};
-
-static const struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
- /* output mixer control */
- HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Master Playback Switch",
- .subdevice = HDA_SUBDEV_AMP_FLAG,
- .info = snd_hda_mixer_amp_switch_info,
- .get = snd_hda_mixer_amp_switch_get,
- .put = alc268_acer_master_sw_put,
- .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, 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 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 Volume", 0x19, 0, HDA_INPUT),
- { }
-};
-
-static const struct snd_kcontrol_new alc269_lifebook_mixer[] = {
- /* output mixer control */
- HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Master Playback Switch",
- .subdevice = HDA_SUBDEV_AMP_FLAG,
- .info = snd_hda_mixer_amp_switch_info,
- .get = snd_hda_mixer_amp_switch_get,
- .put = alc268_acer_master_sw_put,
- .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, 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 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 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 Volume", 0x1b, 0, HDA_INPUT),
- { }
-};
-
-static const struct snd_kcontrol_new alc269_laptop_mixer[] = {
- HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc269vb_laptop_mixer[] = {
- HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc269_asus_mixer[] = {
- HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x0, HDA_INPUT),
- { } /* end */
-};
-
-/* capture mixer elements */
-static const 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 Volume", 0x18, 0, HDA_INPUT),
- HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
- { } /* end */
-};
-
-static const 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 Volume", 0x18, 0, HDA_INPUT),
- { } /* end */
-};
-
-static const 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 Volume", 0x18, 0, HDA_INPUT),
- HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
- { } /* end */
-};
-
-static const 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 Volume", 0x18, 0, HDA_INPUT),
- { } /* end */
-};
-
-/* FSC amilo */
-#define alc269_fujitsu_mixer alc269_laptop_mixer
-
-static const struct hda_verb alc269_quanta_fl1_verbs[] = {
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
- {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
- {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- { }
-};
-
-static const struct hda_verb alc269_lifebook_verbs[] = {
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
- {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
- {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
- {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- { }
-};
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
-{
- alc_hp_automute(codec);
-
- snd_hda_codec_write(codec, 0x20, 0,
- AC_VERB_SET_COEF_INDEX, 0x0c);
- snd_hda_codec_write(codec, 0x20, 0,
- AC_VERB_SET_PROC_COEF, 0x680);
-
- snd_hda_codec_write(codec, 0x20, 0,
- AC_VERB_SET_COEF_INDEX, 0x0c);
- snd_hda_codec_write(codec, 0x20, 0,
- AC_VERB_SET_PROC_COEF, 0x480);
-}
-
-#define alc269_lifebook_speaker_automute \
- alc269_quanta_fl1_speaker_automute
-
-static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
-{
- unsigned int present_laptop;
- unsigned int present_dock;
-
- present_laptop = snd_hda_jack_detect(codec, 0x18);
- present_dock = snd_hda_jack_detect(codec, 0x1b);
-
- /* Laptop mic port overrides dock mic port, design decision */
- if (present_dock)
- snd_hda_codec_write(codec, 0x23, 0,
- AC_VERB_SET_CONNECT_SEL, 0x3);
- if (present_laptop)
- snd_hda_codec_write(codec, 0x23, 0,
- AC_VERB_SET_CONNECT_SEL, 0x0);
- if (!present_dock && !present_laptop)
- snd_hda_codec_write(codec, 0x23, 0,
- AC_VERB_SET_CONNECT_SEL, 0x1);
-}
-
-static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
- unsigned int res)
-{
- switch (res >> 26) {
- case ALC880_HP_EVENT:
- alc269_quanta_fl1_speaker_automute(codec);
- break;
- case ALC880_MIC_EVENT:
- alc_mic_automute(codec);
- break;
- }
-}
-
-static void alc269_lifebook_unsol_event(struct hda_codec *codec,
- unsigned int res)
-{
- if ((res >> 26) == ALC880_HP_EVENT)
- alc269_lifebook_speaker_automute(codec);
- if ((res >> 26) == ALC880_MIC_EVENT)
- alc269_lifebook_mic_autoswitch(codec);
-}
-
-static void alc269_quanta_fl1_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- spec->autocfg.hp_pins[0] = 0x15;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->automute_mixer_nid[0] = 0x0c;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_MIXER;
- spec->ext_mic.pin = 0x18;
- spec->ext_mic.mux_idx = 0;
- spec->int_mic.pin = 0x19;
- spec->int_mic.mux_idx = 1;
- spec->auto_mic = 1;
-}
-
-static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
-{
- alc269_quanta_fl1_speaker_automute(codec);
- alc_mic_automute(codec);
-}
-
-static void alc269_lifebook_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- spec->autocfg.hp_pins[0] = 0x15;
- spec->autocfg.hp_pins[1] = 0x1a;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->automute_mixer_nid[0] = 0x0c;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_MIXER;
-}
-
-static void alc269_lifebook_init_hook(struct hda_codec *codec)
-{
- alc269_lifebook_speaker_automute(codec);
- alc269_lifebook_mic_autoswitch(codec);
-}
-
-static const struct hda_verb alc269_laptop_dmic_init_verbs[] = {
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
- {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
- {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
- {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {}
-};
-
-static const struct hda_verb alc269_laptop_amic_init_verbs[] = {
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
- {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
- {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
- {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {}
-};
-
-static const struct hda_verb alc269vb_laptop_dmic_init_verbs[] = {
- {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
- {0x22, AC_VERB_SET_CONNECT_SEL, 0x06},
- {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
- {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
- {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {}
-};
-
-static const struct hda_verb alc269vb_laptop_amic_init_verbs[] = {
- {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
- {0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
- {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
- {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
- {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {}
-};
-
-static const struct hda_verb alc271_acer_dmic_verbs[] = {
- {0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
- {0x20, AC_VERB_SET_PROC_COEF, 0x4000},
- {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x21, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
- {0x22, AC_VERB_SET_CONNECT_SEL, 6},
- { }
-};
-
-static void alc269_laptop_amic_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- spec->autocfg.hp_pins[0] = 0x15;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->automute_mixer_nid[0] = 0x0c;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_MIXER;
- spec->ext_mic.pin = 0x18;
- spec->ext_mic.mux_idx = 0;
- spec->int_mic.pin = 0x19;
- spec->int_mic.mux_idx = 1;
- spec->auto_mic = 1;
-}
-
-static void alc269_laptop_dmic_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- spec->autocfg.hp_pins[0] = 0x15;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->automute_mixer_nid[0] = 0x0c;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_MIXER;
- spec->ext_mic.pin = 0x18;
- spec->ext_mic.mux_idx = 0;
- spec->int_mic.pin = 0x12;
- spec->int_mic.mux_idx = 5;
- spec->auto_mic = 1;
-}
-
-static void alc269vb_laptop_amic_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- spec->autocfg.hp_pins[0] = 0x21;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->automute_mixer_nid[0] = 0x0c;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_MIXER;
- spec->ext_mic.pin = 0x18;
- spec->ext_mic.mux_idx = 0;
- spec->int_mic.pin = 0x19;
- spec->int_mic.mux_idx = 1;
- spec->auto_mic = 1;
-}
-static void alc269vb_laptop_dmic_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- spec->autocfg.hp_pins[0] = 0x21;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->automute_mixer_nid[0] = 0x0c;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_MIXER;
- spec->ext_mic.pin = 0x18;
- spec->ext_mic.mux_idx = 0;
- spec->int_mic.pin = 0x12;
- spec->int_mic.mux_idx = 6;
- spec->auto_mic = 1;
+ error:
+ alc_free(codec);
+ return err;
}
/*
- * generic initialization of ADC, input mixers and output mixers
+ * ALC269
*/
-static const struct hda_verb alc269_init_verbs[] = {
- /*
- * Unmute ADC0 and set the default input to mic-in
- */
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
- /*
- * Set up output mixers (0x02 - 0x03)
- */
- /* set vol=0 to output mixers */
- {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
- /* set up input amps for analog loopback */
- /* Amp Indices: DAC = 0, mixer = 1 */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
- /* FIXME: use Mux-type input source selection */
- /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
- /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
- {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
-
- /* set EAPD */
- {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
- { }
-};
-
-static const struct hda_verb alc269vb_init_verbs[] = {
- /*
- * Unmute ADC0 and set the default input to mic-in
- */
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
- /*
- * Set up output mixers (0x02 - 0x03)
- */
- /* set vol=0 to output mixers */
- {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
- /* set up input amps for analog loopback */
- /* Amp Indices: DAC = 0, mixer = 1 */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
- /* FIXME: use Mux-type input source selection */
- /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
- /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
- {0x22, AC_VERB_SET_CONNECT_SEL, 0x00},
-
- /* set EAPD */
- {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
- { }
-};
-
-#define alc269_auto_create_multi_out_ctls \
- alc268_auto_create_multi_out_ctls
-#define alc269_auto_create_input_ctls \
- alc268_auto_create_input_ctls
-
#ifdef CONFIG_SND_HDA_POWER_SAVE
#define alc269_loopbacks alc880_loopbacks
#endif
-/* pcm configuration: identical with ALC880 */
-#define alc269_pcm_analog_playback alc880_pcm_analog_playback
-#define alc269_pcm_analog_capture alc880_pcm_analog_capture
-#define alc269_pcm_digital_playback alc880_pcm_digital_playback
-#define alc269_pcm_digital_capture alc880_pcm_digital_capture
-
static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
.substreams = 1,
.channels_min = 2,
@@ -14686,9 +4709,9 @@ static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
.rates = SNDRV_PCM_RATE_44100, /* fixed rate */
/* NID is set in alc_build_pcms */
.ops = {
- .open = alc880_playback_pcm_open,
- .prepare = alc880_playback_pcm_prepare,
- .cleanup = alc880_playback_pcm_cleanup
+ .open = alc_playback_pcm_open,
+ .prepare = alc_playback_pcm_prepare,
+ .cleanup = alc_playback_pcm_cleanup
},
};
@@ -14729,44 +4752,11 @@ static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid)
}
#endif /* CONFIG_SND_HDA_POWER_SAVE */
-static int alc275_setup_dual_adc(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- if (codec->vendor_id != 0x10ec0275 || !spec->auto_mic)
- return 0;
- if ((spec->ext_mic.pin >= 0x18 && spec->int_mic.pin <= 0x13) ||
- (spec->ext_mic.pin <= 0x12 && spec->int_mic.pin >= 0x18)) {
- if (spec->ext_mic.pin <= 0x12) {
- spec->private_adc_nids[0] = 0x08;
- spec->private_adc_nids[1] = 0x11;
- spec->private_capsrc_nids[0] = 0x23;
- spec->private_capsrc_nids[1] = 0x22;
- } else {
- spec->private_adc_nids[0] = 0x11;
- spec->private_adc_nids[1] = 0x08;
- spec->private_capsrc_nids[0] = 0x22;
- spec->private_capsrc_nids[1] = 0x23;
- }
- spec->adc_nids = spec->private_adc_nids;
- spec->capsrc_nids = spec->private_capsrc_nids;
- spec->num_adc_nids = 2;
- spec->dual_adc_switch = 1;
- snd_printdd("realtek: enabling dual ADC switchg (%02x:%02x)\n",
- spec->adc_nids[0], spec->adc_nids[1]);
- return 1;
- }
- return 0;
-}
-
/* different alc269-variants */
enum {
- ALC269_TYPE_NORMAL,
- ALC269_TYPE_ALC258,
- ALC269_TYPE_ALC259,
+ ALC269_TYPE_ALC269VA,
ALC269_TYPE_ALC269VB,
- ALC269_TYPE_ALC270,
- ALC269_TYPE_ALC271X,
+ ALC269_TYPE_ALC269VC,
};
/*
@@ -14774,81 +4764,21 @@ enum {
*/
static int alc269_parse_auto_config(struct hda_codec *codec)
{
- struct alc_spec *spec = codec->spec;
- int err;
static const hda_nid_t alc269_ignore[] = { 0x1d, 0 };
-
- err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
- alc269_ignore);
- if (err < 0)
- return err;
-
- err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
- if (err < 0)
- return err;
- if (spec->codec_variant == ALC269_TYPE_NORMAL)
- err = alc269_auto_create_input_ctls(codec, &spec->autocfg);
- else
- err = alc_auto_create_input_ctls(codec, &spec->autocfg, 0,
- 0x22, 0);
- if (err < 0)
- return err;
-
- spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-
- alc_auto_parse_digital(codec);
-
- if (spec->kctls.list)
- add_mixer(spec, spec->kctls.list);
-
- if (spec->codec_variant != ALC269_TYPE_NORMAL) {
- add_verb(spec, alc269vb_init_verbs);
- alc_ssid_check(codec, 0, 0x1b, 0x14, 0x21);
- } else {
- add_verb(spec, alc269_init_verbs);
- alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
- }
-
- spec->num_mux_defs = 1;
- spec->input_mux = &spec->private_imux[0];
-
- if (!alc275_setup_dual_adc(codec))
- fillup_priv_adc_nids(codec, alc269_adc_candidates,
- sizeof(alc269_adc_candidates));
-
- err = alc_auto_add_mic_boost(codec);
- if (err < 0)
- return err;
-
- if (!spec->cap_mixer && !spec->no_analog)
- set_capture_mixer(codec);
-
- return 1;
-}
-
-#define alc269_auto_init_multi_out alc268_auto_init_multi_out
-#define alc269_auto_init_hp_out alc268_auto_init_hp_out
-#define alc269_auto_init_analog_input alc882_auto_init_analog_input
-#define alc269_auto_init_input_src alc882_auto_init_input_src
-
-
-/* init callback for auto-configuration model -- overriding the default init */
-static void alc269_auto_init(struct hda_codec *codec)
-{
+ static const hda_nid_t alc269_ssids[] = { 0, 0x1b, 0x14, 0x21 };
+ static const hda_nid_t alc269va_ssids[] = { 0x15, 0x1b, 0x14, 0 };
struct alc_spec *spec = codec->spec;
- alc269_auto_init_multi_out(codec);
- alc269_auto_init_hp_out(codec);
- alc269_auto_init_analog_input(codec);
- if (!spec->dual_adc_switch)
- alc269_auto_init_input_src(codec);
- alc_auto_init_digital(codec);
- if (spec->unsol_event)
- alc_inithook(codec);
+ const hda_nid_t *ssids = spec->codec_variant == ALC269_TYPE_ALC269VA ?
+ alc269va_ssids : alc269_ssids;
+
+ return alc_parse_auto_config(codec, alc269_ignore, ssids);
}
static void alc269_toggle_power_output(struct hda_codec *codec, int power_up)
{
int val = alc_read_coef_idx(codec, 0x04);
+ if (val == -1)
+ return;
if (power_up)
val |= 1 << 11;
else
@@ -14858,30 +4788,30 @@ static void alc269_toggle_power_output(struct hda_codec *codec, int power_up)
static void alc269_shutup(struct hda_codec *codec)
{
- if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017)
+ if ((alc_get_coef0(codec) & 0x00ff) == 0x017)
alc269_toggle_power_output(codec, 0);
- if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
+ if ((alc_get_coef0(codec) & 0x00ff) == 0x018) {
alc269_toggle_power_output(codec, 0);
msleep(150);
}
}
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
static int alc269_resume(struct hda_codec *codec)
{
- if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
+ if ((alc_get_coef0(codec) & 0x00ff) == 0x018) {
alc269_toggle_power_output(codec, 0);
msleep(150);
}
codec->patch_ops.init(codec);
- if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
+ if ((alc_get_coef0(codec) & 0x00ff) == 0x017) {
alc269_toggle_power_output(codec, 1);
msleep(200);
}
- if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018)
+ if ((alc_get_coef0(codec) & 0x00ff) == 0x018)
alc269_toggle_power_output(codec, 1);
snd_hda_codec_resume_amp(codec);
@@ -14889,7 +4819,16 @@ static int alc269_resume(struct hda_codec *codec)
hda_call_check_power_status(codec, 0x01);
return 0;
}
-#endif /* SND_HDA_NEEDS_RESUME */
+#endif /* CONFIG_PM */
+
+static void alc269_fixup_pincfg_no_hp_to_lineout(struct hda_codec *codec,
+ const struct alc_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (action == ALC_FIXUP_ACT_PRE_PROBE)
+ spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
+}
static void alc269_fixup_hweq(struct hda_codec *codec,
const struct alc_fixup *fix, int action)
@@ -14919,6 +4858,61 @@ static void alc271_fixup_dmic(struct hda_codec *codec,
snd_hda_sequence_write(codec, verbs);
}
+static void alc269_fixup_pcm_44k(struct hda_codec *codec,
+ const struct alc_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (action != ALC_FIXUP_ACT_PROBE)
+ return;
+
+ /* Due to a hardware problem on Lenovo Ideadpad, we need to
+ * fix the sample rate of analog I/O to 44.1kHz
+ */
+ spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
+ spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
+}
+
+static void alc269_fixup_stereo_dmic(struct hda_codec *codec,
+ const struct alc_fixup *fix, int action)
+{
+ int coef;
+
+ if (action != ALC_FIXUP_ACT_INIT)
+ return;
+ /* The digital-mic unit sends PDM (differential signal) instead of
+ * the standard PCM, thus you can't record a valid mono stream as is.
+ * Below is a workaround specific to ALC269 to control the dmic
+ * signal source as mono.
+ */
+ coef = alc_read_coef_idx(codec, 0x07);
+ alc_write_coef_idx(codec, 0x07, coef | 0x80);
+}
+
+static void alc269_quanta_automute(struct hda_codec *codec)
+{
+ update_outputs(codec);
+
+ snd_hda_codec_write(codec, 0x20, 0,
+ AC_VERB_SET_COEF_INDEX, 0x0c);
+ snd_hda_codec_write(codec, 0x20, 0,
+ AC_VERB_SET_PROC_COEF, 0x680);
+
+ snd_hda_codec_write(codec, 0x20, 0,
+ AC_VERB_SET_COEF_INDEX, 0x0c);
+ snd_hda_codec_write(codec, 0x20, 0,
+ AC_VERB_SET_PROC_COEF, 0x480);
+}
+
+static void alc269_fixup_quanta_mute(struct hda_codec *codec,
+ const struct alc_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+ if (action != ALC_FIXUP_ACT_PROBE)
+ return;
+ spec->automute_hook = alc269_quanta_automute;
+}
+
enum {
ALC269_FIXUP_SONY_VAIO,
ALC275_FIXUP_SONY_VAIO_GPIO2,
@@ -14928,6 +4922,17 @@ enum {
ALC269_FIXUP_LENOVO_EAPD,
ALC275_FIXUP_SONY_HWEQ,
ALC271_FIXUP_DMIC,
+ ALC269_FIXUP_PCM_44K,
+ ALC269_FIXUP_STEREO_DMIC,
+ ALC269_FIXUP_QUANTA_MUTE,
+ ALC269_FIXUP_LIFEBOOK,
+ ALC269_FIXUP_LIFEBOOK_EXTMIC,
+ ALC269_FIXUP_AMIC,
+ ALC269_FIXUP_DMIC,
+ ALC269VB_FIXUP_AMIC,
+ ALC269VB_FIXUP_DMIC,
+ ALC269_FIXUP_LENOVO_DOCK,
+ ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT,
};
static const struct alc_fixup alc269_fixups[] = {
@@ -14986,270 +4991,239 @@ static const struct alc_fixup alc269_fixups[] = {
.type = ALC_FIXUP_FUNC,
.v.func = alc271_fixup_dmic,
},
+ [ALC269_FIXUP_PCM_44K] = {
+ .type = ALC_FIXUP_FUNC,
+ .v.func = alc269_fixup_pcm_44k,
+ .chained = true,
+ .chain_id = ALC269_FIXUP_QUANTA_MUTE
+ },
+ [ALC269_FIXUP_STEREO_DMIC] = {
+ .type = ALC_FIXUP_FUNC,
+ .v.func = alc269_fixup_stereo_dmic,
+ },
+ [ALC269_FIXUP_QUANTA_MUTE] = {
+ .type = ALC_FIXUP_FUNC,
+ .v.func = alc269_fixup_quanta_mute,
+ },
+ [ALC269_FIXUP_LIFEBOOK] = {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
+ { 0x1a, 0x2101103f }, /* dock line-out */
+ { 0x1b, 0x23a11040 }, /* dock mic-in */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC269_FIXUP_QUANTA_MUTE
+ },
+ [ALC269_FIXUP_LIFEBOOK_EXTMIC] = {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
+ { 0x19, 0x01a1903c }, /* headset mic, with jack detect */
+ { }
+ },
+ },
+ [ALC269_FIXUP_AMIC] = {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
+ { 0x14, 0x99130110 }, /* speaker */
+ { 0x15, 0x0121401f }, /* HP out */
+ { 0x18, 0x01a19c20 }, /* mic */
+ { 0x19, 0x99a3092f }, /* int-mic */
+ { }
+ },
+ },
+ [ALC269_FIXUP_DMIC] = {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
+ { 0x12, 0x99a3092f }, /* int-mic */
+ { 0x14, 0x99130110 }, /* speaker */
+ { 0x15, 0x0121401f }, /* HP out */
+ { 0x18, 0x01a19c20 }, /* mic */
+ { }
+ },
+ },
+ [ALC269VB_FIXUP_AMIC] = {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
+ { 0x14, 0x99130110 }, /* speaker */
+ { 0x18, 0x01a19c20 }, /* mic */
+ { 0x19, 0x99a3092f }, /* int-mic */
+ { 0x21, 0x0121401f }, /* HP out */
+ { }
+ },
+ },
+ [ALC269_FIXUP_DMIC] = {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
+ { 0x12, 0x99a3092f }, /* int-mic */
+ { 0x14, 0x99130110 }, /* speaker */
+ { 0x18, 0x01a19c20 }, /* mic */
+ { 0x21, 0x0121401f }, /* HP out */
+ { }
+ },
+ },
+ [ALC269_FIXUP_LENOVO_DOCK] = {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
+ { 0x19, 0x23a11040 }, /* dock mic */
+ { 0x1b, 0x2121103f }, /* dock headphone */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT
+ },
+ [ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT] = {
+ .type = ALC_FIXUP_FUNC,
+ .v.func = alc269_fixup_pincfg_no_hp_to_lineout,
+ },
};
static const struct snd_pci_quirk alc269_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_DMIC),
+ SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
+ SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
+ SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC),
+ SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC),
+ SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
+ SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
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_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC),
+ SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK),
+ SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC),
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, 0x21f6, "Thinkpad T530", ALC269_FIXUP_LENOVO_DOCK),
+ SND_PCI_QUIRK(0x17aa, 0x21fa, "Thinkpad X230", ALC269_FIXUP_LENOVO_DOCK),
+ SND_PCI_QUIRK(0x17aa, 0x21f3, "Thinkpad T430", ALC269_FIXUP_LENOVO_DOCK),
+ SND_PCI_QUIRK(0x17aa, 0x21fb, "Thinkpad T430s", ALC269_FIXUP_LENOVO_DOCK),
+ SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK),
+ SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
- {}
-};
-
-/*
- * configuration and preset
- */
-static const char * const alc269_models[ALC269_MODEL_LAST] = {
- [ALC269_BASIC] = "basic",
- [ALC269_QUANTA_FL1] = "quanta",
- [ALC269_AMIC] = "laptop-amic",
- [ALC269_DMIC] = "laptop-dmic",
- [ALC269_FUJITSU] = "fujitsu",
- [ALC269_LIFEBOOK] = "lifebook",
- [ALC269_AUTO] = "auto",
-};
-
-static const struct snd_pci_quirk alc269_cfg_tbl[] = {
- SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
- SND_PCI_QUIRK(0x1025, 0x047c, "ACER ZGA", ALC271_ACER),
+#if 1
+ /* Below is a quirk table taken from the old code.
+ * Basically the device should work as is without the fixup table.
+ * If BIOS doesn't give a proper info, enable the corresponding
+ * fixup entry.
+ */
SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
- ALC269_AMIC),
- SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269VB_AMIC),
- SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269VB_AMIC),
- SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269VB_AMIC),
- SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_AMIC),
- SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269VB_AMIC),
- SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269VB_AMIC),
- 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", 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),
- SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_AMIC),
- SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_AMIC),
- SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_AMIC),
- SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_AMIC),
- SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_AMIC),
- SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_AMIC),
- SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_AMIC),
- SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_AMIC),
- SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_AMIC),
- SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_AMIC),
- SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_AMIC),
- SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_AMIC),
- SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_AMIC),
- SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_AMIC),
- SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_AMIC),
- SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_AMIC),
- SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_AMIC),
- SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_AMIC),
- SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_DMIC),
- SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_AMIC),
- SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_AMIC),
- SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_AMIC),
- SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_AMIC),
- SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
- ALC269_DMIC),
- SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
- ALC269_DMIC),
- SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_DMIC),
- SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_DMIC),
- SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_AUTO),
- SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
- SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_DMIC),
- SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
- SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_AMIC),
- SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_AMIC),
- SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_DMIC),
- SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_DMIC),
+ ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82JV", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_FIXUP_DMIC),
+ SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_AMIC),
+ SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_FIXUP_DMIC),
+ SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_FIXUP_DMIC),
+#endif
{}
};
-static const struct alc_config_preset alc269_presets[] = {
- [ALC269_BASIC] = {
- .mixers = { alc269_base_mixer },
- .init_verbs = { alc269_init_verbs },
- .num_dacs = ARRAY_SIZE(alc269_dac_nids),
- .dac_nids = alc269_dac_nids,
- .hp_nid = 0x03,
- .num_channel_mode = ARRAY_SIZE(alc269_modes),
- .channel_mode = alc269_modes,
- .input_mux = &alc269_capture_source,
- },
- [ALC269_QUANTA_FL1] = {
- .mixers = { alc269_quanta_fl1_mixer },
- .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
- .num_dacs = ARRAY_SIZE(alc269_dac_nids),
- .dac_nids = alc269_dac_nids,
- .hp_nid = 0x03,
- .num_channel_mode = ARRAY_SIZE(alc269_modes),
- .channel_mode = alc269_modes,
- .input_mux = &alc269_capture_source,
- .unsol_event = alc269_quanta_fl1_unsol_event,
- .setup = alc269_quanta_fl1_setup,
- .init_hook = alc269_quanta_fl1_init_hook,
- },
- [ALC269_AMIC] = {
- .mixers = { alc269_laptop_mixer },
- .cap_mixer = alc269_laptop_analog_capture_mixer,
- .init_verbs = { alc269_init_verbs,
- alc269_laptop_amic_init_verbs },
- .num_dacs = ARRAY_SIZE(alc269_dac_nids),
- .dac_nids = alc269_dac_nids,
- .hp_nid = 0x03,
- .num_channel_mode = ARRAY_SIZE(alc269_modes),
- .channel_mode = alc269_modes,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc269_laptop_amic_setup,
- .init_hook = alc_inithook,
- },
- [ALC269_DMIC] = {
- .mixers = { alc269_laptop_mixer },
- .cap_mixer = alc269_laptop_digital_capture_mixer,
- .init_verbs = { alc269_init_verbs,
- alc269_laptop_dmic_init_verbs },
- .num_dacs = ARRAY_SIZE(alc269_dac_nids),
- .dac_nids = alc269_dac_nids,
- .hp_nid = 0x03,
- .num_channel_mode = ARRAY_SIZE(alc269_modes),
- .channel_mode = alc269_modes,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc269_laptop_dmic_setup,
- .init_hook = alc_inithook,
- },
- [ALC269VB_AMIC] = {
- .mixers = { alc269vb_laptop_mixer },
- .cap_mixer = alc269vb_laptop_analog_capture_mixer,
- .init_verbs = { alc269vb_init_verbs,
- alc269vb_laptop_amic_init_verbs },
- .num_dacs = ARRAY_SIZE(alc269_dac_nids),
- .dac_nids = alc269_dac_nids,
- .hp_nid = 0x03,
- .num_channel_mode = ARRAY_SIZE(alc269_modes),
- .channel_mode = alc269_modes,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc269vb_laptop_amic_setup,
- .init_hook = alc_inithook,
- },
- [ALC269VB_DMIC] = {
- .mixers = { alc269vb_laptop_mixer },
- .cap_mixer = alc269vb_laptop_digital_capture_mixer,
- .init_verbs = { alc269vb_init_verbs,
- alc269vb_laptop_dmic_init_verbs },
- .num_dacs = ARRAY_SIZE(alc269_dac_nids),
- .dac_nids = alc269_dac_nids,
- .hp_nid = 0x03,
- .num_channel_mode = ARRAY_SIZE(alc269_modes),
- .channel_mode = alc269_modes,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc269vb_laptop_dmic_setup,
- .init_hook = alc_inithook,
- },
- [ALC269_FUJITSU] = {
- .mixers = { alc269_fujitsu_mixer },
- .cap_mixer = alc269_laptop_digital_capture_mixer,
- .init_verbs = { alc269_init_verbs,
- alc269_laptop_dmic_init_verbs },
- .num_dacs = ARRAY_SIZE(alc269_dac_nids),
- .dac_nids = alc269_dac_nids,
- .hp_nid = 0x03,
- .num_channel_mode = ARRAY_SIZE(alc269_modes),
- .channel_mode = alc269_modes,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc269_laptop_dmic_setup,
- .init_hook = alc_inithook,
- },
- [ALC269_LIFEBOOK] = {
- .mixers = { alc269_lifebook_mixer },
- .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs },
- .num_dacs = ARRAY_SIZE(alc269_dac_nids),
- .dac_nids = alc269_dac_nids,
- .hp_nid = 0x03,
- .num_channel_mode = ARRAY_SIZE(alc269_modes),
- .channel_mode = alc269_modes,
- .input_mux = &alc269_capture_source,
- .unsol_event = alc269_lifebook_unsol_event,
- .setup = alc269_lifebook_setup,
- .init_hook = alc269_lifebook_init_hook,
- },
- [ALC271_ACER] = {
- .mixers = { alc269_asus_mixer },
- .cap_mixer = alc269vb_laptop_digital_capture_mixer,
- .init_verbs = { alc269_init_verbs, alc271_acer_dmic_verbs },
- .num_dacs = ARRAY_SIZE(alc269_dac_nids),
- .dac_nids = alc269_dac_nids,
- .adc_nids = alc262_dmic_adc_nids,
- .num_adc_nids = ARRAY_SIZE(alc262_dmic_adc_nids),
- .capsrc_nids = alc262_dmic_capsrc_nids,
- .num_channel_mode = ARRAY_SIZE(alc269_modes),
- .channel_mode = alc269_modes,
- .input_mux = &alc269_capture_source,
- .dig_out_nid = ALC880_DIGOUT_NID,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc269vb_laptop_dmic_setup,
- .init_hook = alc_inithook,
- },
+static const struct alc_model_fixup alc269_fixup_models[] = {
+ {.id = ALC269_FIXUP_AMIC, .name = "laptop-amic"},
+ {.id = ALC269_FIXUP_DMIC, .name = "laptop-dmic"},
+ {.id = ALC269_FIXUP_LENOVO_DOCK, .name = "lenovo-dock"},
+ {}
};
+
static int alc269_fill_coef(struct hda_codec *codec)
{
+ struct alc_spec *spec = codec->spec;
int val;
- if ((alc_read_coef_idx(codec, 0) & 0x00ff) < 0x015) {
+ if (spec->codec_variant != ALC269_TYPE_ALC269VB)
+ return 0;
+ /* ALC271X doesn't seem to support these COEFs (bko#52181) */
+ if (!strcmp(codec->chip_name, "ALC271X"))
+ return 0;
+
+ if ((alc_get_coef0(codec) & 0x00ff) < 0x015) {
alc_write_coef_idx(codec, 0xf, 0x960b);
alc_write_coef_idx(codec, 0xe, 0x8817);
}
- if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x016) {
+ if ((alc_get_coef0(codec) & 0x00ff) == 0x016) {
alc_write_coef_idx(codec, 0xf, 0x960b);
alc_write_coef_idx(codec, 0xe, 0x8814);
}
- if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
+ if ((alc_get_coef0(codec) & 0x00ff) == 0x017) {
val = alc_read_coef_idx(codec, 0x04);
/* Power up output pin */
- alc_write_coef_idx(codec, 0x04, val | (1<<11));
+ if (val != -1)
+ alc_write_coef_idx(codec, 0x04, val | (1<<11));
}
- if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
+ if ((alc_get_coef0(codec) & 0x00ff) == 0x018) {
val = alc_read_coef_idx(codec, 0xd);
- if ((val & 0x0c00) >> 10 != 0x1) {
+ if (val != -1 && (val & 0x0c00) >> 10 != 0x1) {
/* Capless ramp up clock control */
alc_write_coef_idx(codec, 0xd, val | (1<<10));
}
val = alc_read_coef_idx(codec, 0x17);
- if ((val & 0x01c0) >> 6 != 0x4) {
+ if (val != -1 && (val & 0x01c0) >> 6 != 0x4) {
/* Class D power on reset */
alc_write_coef_idx(codec, 0x17, val | (1<<7));
}
}
val = alc_read_coef_idx(codec, 0xd); /* Class D */
- alc_write_coef_idx(codec, 0xd, val | (1<<14));
+ if (val != -1)
+ alc_write_coef_idx(codec, 0xd, val | (1<<14));
val = alc_read_coef_idx(codec, 0x4); /* HP */
- alc_write_coef_idx(codec, 0x4, val | (1<<11));
+ if (val != -1)
+ alc_write_coef_idx(codec, 0x4, val | (1<<11));
return 0;
}
+/*
+ */
static int patch_alc269(struct hda_codec *codec)
{
struct alc_spec *spec;
- int board_config, coef;
- int err;
+ int err = 0;
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (spec == NULL)
@@ -15257,116 +5231,71 @@ static int patch_alc269(struct hda_codec *codec)
codec->spec = spec;
+ spec->mixer_nid = 0x0b;
+
alc_auto_parse_customize_define(codec);
+ err = alc_codec_rename_from_preset(codec);
+ if (err < 0)
+ goto error;
+
if (codec->vendor_id == 0x10ec0269) {
- coef = alc_read_coef_idx(codec, 0);
- if ((coef & 0x00f0) == 0x0010) {
+ spec->codec_variant = ALC269_TYPE_ALC269VA;
+ switch (alc_get_coef0(codec) & 0x00f0) {
+ case 0x0010:
if (codec->bus->pci->subsystem_vendor == 0x1025 &&
- spec->cdefine.platform_type == 1) {
- alc_codec_rename(codec, "ALC271X");
- spec->codec_variant = ALC269_TYPE_ALC271X;
- } else if ((coef & 0xf000) == 0x1000) {
- spec->codec_variant = ALC269_TYPE_ALC270;
- } else if ((coef & 0xf000) == 0x2000) {
- alc_codec_rename(codec, "ALC259");
- spec->codec_variant = ALC269_TYPE_ALC259;
- } else if ((coef & 0xf000) == 0x3000) {
- alc_codec_rename(codec, "ALC258");
- spec->codec_variant = ALC269_TYPE_ALC258;
- } else {
- alc_codec_rename(codec, "ALC269VB");
- spec->codec_variant = ALC269_TYPE_ALC269VB;
- }
- } else
+ spec->cdefine.platform_type == 1)
+ err = alc_codec_rename(codec, "ALC271X");
+ spec->codec_variant = ALC269_TYPE_ALC269VB;
+ break;
+ case 0x0020:
+ if (codec->bus->pci->subsystem_vendor == 0x17aa &&
+ codec->bus->pci->subsystem_device == 0x21f3)
+ err = alc_codec_rename(codec, "ALC3202");
+ spec->codec_variant = ALC269_TYPE_ALC269VC;
+ break;
+ default:
alc_fix_pll_init(codec, 0x20, 0x04, 15);
+ }
+ if (err < 0)
+ goto error;
alc269_fill_coef(codec);
}
- board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
- alc269_models,
- alc269_cfg_tbl);
+ alc_pick_fixup(codec, alc269_fixup_models,
+ alc269_fixup_tbl, alc269_fixups);
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
- if (board_config < 0) {
- printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
- codec->chip_name);
- board_config = ALC269_AUTO;
- }
+ /* automatic parse from the BIOS config */
+ err = alc269_parse_auto_config(codec);
+ if (err < 0)
+ goto error;
- 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 (!spec->no_analog && !spec->adc_nids) {
+ alc_auto_fill_adc_caps(codec);
+ alc_rebuild_imux_for_auto_mic(codec);
+ alc_remove_invalid_adc_nids(codec);
}
- if (board_config == ALC269_AUTO) {
- /* automatic parse from the BIOS config */
- err = alc269_parse_auto_config(codec);
- if (err < 0) {
- alc_free(codec);
- return err;
- } else if (!err) {
- printk(KERN_INFO
- "hda_codec: Cannot set up configuration "
- "from BIOS. Using base mode...\n");
- board_config = ALC269_BASIC;
- }
- }
+ if (!spec->no_analog && !spec->cap_mixer)
+ set_capture_mixer(codec);
- if (has_cdefine_beep(codec)) {
+ if (!spec->no_analog && has_cdefine_beep(codec)) {
err = snd_hda_attach_beep_device(codec, 0x1);
- if (err < 0) {
- alc_free(codec);
- return err;
- }
- }
-
- if (board_config != ALC269_AUTO)
- setup_preset(codec, &alc269_presets[board_config]);
-
- if (board_config == ALC269_QUANTA_FL1) {
- /* Due to a hardware problem on Lenovo Ideadpad, we need to
- * fix the sample rate of analog I/O to 44.1kHz
- */
- spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
- spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
- } else if (spec->dual_adc_switch) {
- spec->stream_analog_playback = &alc269_pcm_analog_playback;
- /* switch ADC dynamically */
- spec->stream_analog_capture = &dualmic_pcm_analog_capture;
- } else {
- spec->stream_analog_playback = &alc269_pcm_analog_playback;
- spec->stream_analog_capture = &alc269_pcm_analog_capture;
- }
- spec->stream_digital_playback = &alc269_pcm_digital_playback;
- spec->stream_digital_capture = &alc269_pcm_digital_capture;
-
- if (!spec->adc_nids) { /* wasn't filled automatically? use default */
- if (spec->codec_variant == ALC269_TYPE_NORMAL) {
- spec->adc_nids = alc269_adc_nids;
- spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
- spec->capsrc_nids = alc269_capsrc_nids;
- } else {
- spec->adc_nids = alc269vb_adc_nids;
- spec->num_adc_nids = ARRAY_SIZE(alc269vb_adc_nids);
- spec->capsrc_nids = alc269vb_capsrc_nids;
- }
- }
-
- if (!spec->cap_mixer)
- set_capture_mixer(codec);
- if (has_cdefine_beep(codec))
+ if (err < 0)
+ goto error;
set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
+ }
alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
spec->vmaster_nid = 0x02;
codec->patch_ops = alc_patch_ops;
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
codec->patch_ops.resume = alc269_resume;
#endif
- if (board_config == ALC269_AUTO)
- spec->init_hook = alc269_auto_init;
+ spec->init_hook = alc_auto_init_std;
spec->shutup = alc269_shutup;
alc_init_jacks(codec);
@@ -15378,886 +5307,21 @@ static int patch_alc269(struct hda_codec *codec)
#endif
return 0;
-}
-
-/*
- * ALC861 channel source setting (2/6 channel selection for 3-stack)
- */
-
-/*
- * set the path ways for 2 channel output
- * need to set the codec line out and mic 1 pin widgets to inputs
- */
-static const struct hda_verb alc861_threestack_ch2_init[] = {
- /* set pin widget 1Ah (line in) for input */
- { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
- /* set pin widget 18h (mic1/2) for input, for mic also enable
- * the vref
- */
- { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
-
- { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
-#if 0
- { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
- { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
-#endif
- { } /* end */
-};
-/*
- * 6ch mode
- * need to set the codec line out and mic 1 pin widgets to outputs
- */
-static const struct hda_verb alc861_threestack_ch6_init[] = {
- /* set pin widget 1Ah (line in) for output (Back Surround)*/
- { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
- /* set pin widget 18h (mic1) for output (CLFE)*/
- { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-
- { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
- { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
-
- { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
-#if 0
- { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
- { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
-#endif
- { } /* end */
-};
-
-static const struct hda_channel_mode alc861_threestack_modes[2] = {
- { 2, alc861_threestack_ch2_init },
- { 6, alc861_threestack_ch6_init },
-};
-/* Set mic1 as input and unmute the mixer */
-static const struct hda_verb alc861_uniwill_m31_ch2_init[] = {
- { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
- { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
- { } /* end */
-};
-/* Set mic1 as output and mute mixer */
-static const struct hda_verb alc861_uniwill_m31_ch4_init[] = {
- { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
- { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
- { } /* end */
-};
-
-static const struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
- { 2, alc861_uniwill_m31_ch2_init },
- { 4, alc861_uniwill_m31_ch4_init },
-};
-
-/* Set mic1 and line-in as input and unmute the mixer */
-static const struct hda_verb alc861_asus_ch2_init[] = {
- /* set pin widget 1Ah (line in) for input */
- { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
- /* set pin widget 18h (mic1/2) for input, for mic also enable
- * the vref
- */
- { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
-
- { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
-#if 0
- { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
- { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
-#endif
- { } /* end */
-};
-/* Set mic1 nad line-in as output and mute mixer */
-static const struct hda_verb alc861_asus_ch6_init[] = {
- /* set pin widget 1Ah (line in) for output (Back Surround)*/
- { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
- /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
- /* set pin widget 18h (mic1) for output (CLFE)*/
- { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
- /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
- { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
- { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
-
- { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
-#if 0
- { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
- { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
-#endif
- { } /* end */
-};
-static const struct hda_channel_mode alc861_asus_modes[2] = {
- { 2, alc861_asus_ch2_init },
- { 6, alc861_asus_ch6_init },
-};
-
-/* patch-ALC861 */
-
-static const struct snd_kcontrol_new alc861_base_mixer[] = {
- /* output mixer control */
- HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
-
- /*Input mixer control */
- /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
- HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
- HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
- HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
- HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
-
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc861_3ST_mixer[] = {
- /* output mixer control */
- HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
- /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
-
- /* Input mixer control */
- /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
- HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
- HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
- HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
- HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
-
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Channel Mode",
- .info = alc_ch_mode_info,
- .get = alc_ch_mode_get,
- .put = alc_ch_mode_put,
- .private_value = ARRAY_SIZE(alc861_threestack_modes),
- },
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc861_toshiba_mixer[] = {
- /* output mixer control */
- HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
- HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
-
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
- /* output mixer control */
- HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
- /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
-
- /* Input mixer control */
- /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
- HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
- HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
- HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
- HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
-
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Channel Mode",
- .info = alc_ch_mode_info,
- .get = alc_ch_mode_get,
- .put = alc_ch_mode_put,
- .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
- },
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc861_asus_mixer[] = {
- /* output mixer control */
- HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
-
- /* Input mixer control */
- HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
- HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
- HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
- HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
-
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Channel Mode",
- .info = alc_ch_mode_info,
- .get = alc_ch_mode_get,
- .put = alc_ch_mode_put,
- .private_value = ARRAY_SIZE(alc861_asus_modes),
- },
- { }
-};
-
-/* additional mixer */
-static const struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
- HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
- { }
-};
-
-/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static const struct hda_verb alc861_base_init_verbs[] = {
- /*
- * Unmute ADC0 and set the default input to mic-in
- */
- /* port-A for surround (rear panel) */
- { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
- { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
- /* port-B for mic-in (rear panel) with vref */
- { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
- /* port-C for line-in (rear panel) */
- { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
- /* port-D for Front */
- { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
- { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
- /* port-E for HP out (front panel) */
- { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
- /* route front PCM to HP */
- { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
- /* port-F for mic-in (front panel) with vref */
- { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
- /* port-G for CLFE (rear panel) */
- { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
- { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
- /* port-H for side (rear panel) */
- { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
- { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
- /* CD-in */
- { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
- /* route front mic to ADC1*/
- {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
- /* Unmute DAC0~3 & spdif out*/
- {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
- /* Unmute Mixer 14 (mic) 1c (Line in)*/
- {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
- /* Unmute Stereo Mixer 15 */
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
-
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- /* hp used DAC 3 (Front) */
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
-
- { }
-};
-
-static const struct hda_verb alc861_threestack_init_verbs[] = {
- /*
- * Unmute ADC0 and set the default input to mic-in
- */
- /* port-A for surround (rear panel) */
- { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
- /* port-B for mic-in (rear panel) with vref */
- { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
- /* port-C for line-in (rear panel) */
- { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
- /* port-D for Front */
- { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
- { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
- /* port-E for HP out (front panel) */
- { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
- /* route front PCM to HP */
- { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
- /* port-F for mic-in (front panel) with vref */
- { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
- /* port-G for CLFE (rear panel) */
- { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
- /* port-H for side (rear panel) */
- { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
- /* CD-in */
- { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
- /* route front mic to ADC1*/
- {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- /* Unmute DAC0~3 & spdif out*/
- {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
- /* Unmute Mixer 14 (mic) 1c (Line in)*/
- {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
- /* Unmute Stereo Mixer 15 */
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
-
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- /* hp used DAC 3 (Front) */
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
- { }
-};
-
-static const struct hda_verb alc861_uniwill_m31_init_verbs[] = {
- /*
- * Unmute ADC0 and set the default input to mic-in
- */
- /* port-A for surround (rear panel) */
- { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
- /* port-B for mic-in (rear panel) with vref */
- { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
- /* port-C for line-in (rear panel) */
- { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
- /* port-D for Front */
- { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
- { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
- /* port-E for HP out (front panel) */
- /* this has to be set to VREF80 */
- { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
- /* route front PCM to HP */
- { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
- /* port-F for mic-in (front panel) with vref */
- { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
- /* port-G for CLFE (rear panel) */
- { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
- /* port-H for side (rear panel) */
- { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
- /* CD-in */
- { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
- /* route front mic to ADC1*/
- {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- /* Unmute DAC0~3 & spdif out*/
- {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
- /* Unmute Mixer 14 (mic) 1c (Line in)*/
- {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
- /* Unmute Stereo Mixer 15 */
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
-
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- /* hp used DAC 3 (Front) */
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
- { }
-};
-
-static const struct hda_verb alc861_asus_init_verbs[] = {
- /*
- * Unmute ADC0 and set the default input to mic-in
- */
- /* port-A for surround (rear panel)
- * according to codec#0 this is the HP jack
- */
- { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
- /* route front PCM to HP */
- { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
- /* port-B for mic-in (rear panel) with vref */
- { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
- /* port-C for line-in (rear panel) */
- { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
- /* port-D for Front */
- { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
- { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
- /* port-E for HP out (front panel) */
- /* this has to be set to VREF80 */
- { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
- /* route front PCM to HP */
- { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
- /* port-F for mic-in (front panel) with vref */
- { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
- /* port-G for CLFE (rear panel) */
- { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
- /* port-H for side (rear panel) */
- { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
- /* CD-in */
- { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
- /* route front mic to ADC1*/
- {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- /* Unmute DAC0~3 & spdif out*/
- {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* Unmute Mixer 14 (mic) 1c (Line in)*/
- {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
- /* Unmute Stereo Mixer 15 */
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
-
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- /* hp used DAC 3 (Front) */
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
- { }
-};
-
-/* additional init verbs for ASUS laptops */
-static const struct hda_verb alc861_asus_laptop_init_verbs[] = {
- { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
- { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
- { }
-};
+ error:
+ alc_free(codec);
+ return err;
+}
/*
- * generic initialization of ADC, input mixers and output mixers
+ * ALC861
*/
-static const struct hda_verb alc861_auto_init_verbs[] = {
- /*
- * Unmute ADC0 and set the default input to mic-in
- */
- /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
- /* Unmute DAC0~3 & spdif out*/
- {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
- /* Unmute Mixer 14 (mic) 1c (Line in)*/
- {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
- /* Unmute Stereo Mixer 15 */
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
-
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-
- {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
-
- { }
-};
-
-static const struct hda_verb alc861_toshiba_init_verbs[] = {
- {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-
- { }
-};
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc861_toshiba_automute(struct hda_codec *codec)
-{
- unsigned int present = snd_hda_jack_detect(codec, 0x0f);
-
- snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
- HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
- snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
- HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
-}
-
-static void alc861_toshiba_unsol_event(struct hda_codec *codec,
- unsigned int res)
-{
- if ((res >> 26) == ALC880_HP_EVENT)
- alc861_toshiba_automute(codec);
-}
-
-/* pcm configuration: identical with ALC880 */
-#define alc861_pcm_analog_playback alc880_pcm_analog_playback
-#define alc861_pcm_analog_capture alc880_pcm_analog_capture
-#define alc861_pcm_digital_playback alc880_pcm_digital_playback
-#define alc861_pcm_digital_capture alc880_pcm_digital_capture
-
-
-#define ALC861_DIGOUT_NID 0x07
-
-static const struct hda_channel_mode alc861_8ch_modes[1] = {
- { 8, NULL }
-};
-
-static const hda_nid_t alc861_dac_nids[4] = {
- /* front, surround, clfe, side */
- 0x03, 0x06, 0x05, 0x04
-};
-
-static const hda_nid_t alc660_dac_nids[3] = {
- /* front, clfe, surround */
- 0x03, 0x05, 0x06
-};
-
-static const hda_nid_t alc861_adc_nids[1] = {
- /* ADC0-2 */
- 0x08,
-};
-
-static const struct hda_input_mux alc861_capture_source = {
- .num_items = 5,
- .items = {
- { "Mic", 0x0 },
- { "Front Mic", 0x3 },
- { "Line", 0x1 },
- { "CD", 0x4 },
- { "Mixer", 0x5 },
- },
-};
-
-static hda_nid_t alc861_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
-{
- struct alc_spec *spec = codec->spec;
- hda_nid_t mix, srcs[5];
- int i, j, num;
-
- if (snd_hda_get_connections(codec, pin, &mix, 1) != 1)
- return 0;
- num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
- if (num < 0)
- return 0;
- for (i = 0; i < num; i++) {
- unsigned int type;
- type = get_wcaps_type(get_wcaps(codec, srcs[i]));
- if (type != AC_WID_AUD_OUT)
- continue;
- for (j = 0; j < spec->multiout.num_dacs; j++)
- if (spec->multiout.dac_nids[j] == srcs[i])
- break;
- if (j >= spec->multiout.num_dacs)
- return srcs[i];
- }
- return 0;
-}
-
-/* fill in the dac_nids table from the parsed pin configuration */
-static int alc861_auto_fill_dac_nids(struct hda_codec *codec,
- const struct auto_pin_cfg *cfg)
-{
- struct alc_spec *spec = codec->spec;
- int i;
- hda_nid_t nid, dac;
-
- spec->multiout.dac_nids = spec->private_dac_nids;
- for (i = 0; i < cfg->line_outs; i++) {
- nid = cfg->line_out_pins[i];
- dac = alc861_look_for_dac(codec, nid);
- if (!dac)
- continue;
- spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
- }
- return 0;
-}
-
-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, 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 * const chname[4] = {
- "Front", "Surround", NULL /*CLFE*/, "Side"
- };
- const char *pfx = alc_get_line_out_pfx(spec, true);
- hda_nid_t nid;
- int i, err, noutputs;
-
- noutputs = cfg->line_outs;
- if (spec->multi_ios > 0)
- noutputs += spec->multi_ios;
-
- for (i = 0; i < noutputs; i++) {
- nid = spec->multiout.dac_nids[i];
- if (!nid)
- continue;
- if (!pfx && i == 2) {
- /* Center/LFE */
- err = alc861_create_out_sw(codec, "Center", nid, 1);
- if (err < 0)
- return err;
- err = alc861_create_out_sw(codec, "LFE", nid, 2);
- if (err < 0)
- return err;
- } else {
- const char *name = pfx;
- int index = i;
- if (!name) {
- name = chname[i];
- index = 0;
- }
- err = __alc861_create_out_sw(codec, name, nid, index, 3);
- if (err < 0)
- return err;
- }
- }
- return 0;
-}
-
-static int alc861_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
-{
- struct alc_spec *spec = codec->spec;
- int err;
- hda_nid_t nid;
-
- if (!pin)
- return 0;
-
- if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
- nid = alc861_look_for_dac(codec, pin);
- if (nid) {
- err = alc861_create_out_sw(codec, "Headphone", nid, 3);
- if (err < 0)
- return err;
- spec->multiout.hp_nid = nid;
- }
- }
- return 0;
-}
-/* create playback/capture controls for input pins */
-static int alc861_auto_create_input_ctls(struct hda_codec *codec,
- const struct auto_pin_cfg *cfg)
-{
- return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x08, 0);
-}
-
-static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
- hda_nid_t nid,
- int pin_type, hda_nid_t dac)
-{
- hda_nid_t mix, srcs[5];
- int i, num;
-
- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
- pin_type);
- snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE,
- AMP_OUT_UNMUTE);
- if (snd_hda_get_connections(codec, nid, &mix, 1) != 1)
- return;
- num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
- if (num < 0)
- return;
- for (i = 0; i < num; i++) {
- unsigned int mute;
- if (srcs[i] == dac || srcs[i] == 0x15)
- mute = AMP_IN_UNMUTE(i);
- else
- mute = AMP_IN_MUTE(i);
- snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
- mute);
- }
-}
-
-static void alc861_auto_init_multi_out(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- int i;
-
- for (i = 0; i < spec->autocfg.line_outs; i++) {
- hda_nid_t nid = spec->autocfg.line_out_pins[i];
- int pin_type = get_pin_type(spec->autocfg.line_out_type);
- if (nid)
- alc861_auto_set_output_and_unmute(codec, nid, pin_type,
- spec->multiout.dac_nids[i]);
- }
-}
-
-static void alc861_auto_init_hp_out(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- if (spec->autocfg.hp_outs)
- alc861_auto_set_output_and_unmute(codec,
- spec->autocfg.hp_pins[0],
- PIN_HP,
- spec->multiout.hp_nid);
- if (spec->autocfg.speaker_outs)
- alc861_auto_set_output_and_unmute(codec,
- spec->autocfg.speaker_pins[0],
- PIN_OUT,
- spec->multiout.dac_nids[0]);
-}
-
-static void alc861_auto_init_analog_input(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- struct auto_pin_cfg *cfg = &spec->autocfg;
- int i;
-
- for (i = 0; i < cfg->num_inputs; i++) {
- hda_nid_t nid = cfg->inputs[i].pin;
- if (nid >= 0x0c && nid <= 0x11)
- alc_set_input_pin(codec, nid, cfg->inputs[i].type);
- }
-}
-
-/* parse the BIOS configuration and set up the alc_spec */
-/* return 1 if successful, 0 if the proper config is not found,
- * or a negative error code
- */
static int alc861_parse_auto_config(struct hda_codec *codec)
{
- struct alc_spec *spec = codec->spec;
- int err;
static const hda_nid_t alc861_ignore[] = { 0x1d, 0 };
-
- err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
- alc861_ignore);
- if (err < 0)
- return err;
- if (!spec->autocfg.line_outs)
- return 0; /* can't find valid BIOS pin config */
-
- err = alc861_auto_fill_dac_nids(codec, &spec->autocfg);
- if (err < 0)
- return err;
- err = alc_auto_add_multi_channel_mode(codec);
- if (err < 0)
- return err;
- err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg);
- if (err < 0)
- return err;
- err = alc861_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]);
- if (err < 0)
- return err;
- err = alc861_auto_create_input_ctls(codec, &spec->autocfg);
- if (err < 0)
- return err;
-
- spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-
- alc_auto_parse_digital(codec);
-
- if (spec->kctls.list)
- add_mixer(spec, spec->kctls.list);
-
- add_verb(spec, alc861_auto_init_verbs);
-
- spec->num_mux_defs = 1;
- spec->input_mux = &spec->private_imux[0];
-
- spec->adc_nids = alc861_adc_nids;
- spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
- set_capture_mixer(codec);
-
- alc_ssid_check(codec, 0x0e, 0x0f, 0x0b, 0);
-
- return 1;
-}
-
-/* additional initialization for auto-configuration model */
-static void alc861_auto_init(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- alc861_auto_init_multi_out(codec);
- alc861_auto_init_hp_out(codec);
- alc861_auto_init_analog_input(codec);
- alc_auto_init_digital(codec);
- if (spec->unsol_event)
- alc_inithook(codec);
+ static const hda_nid_t alc861_ssids[] = { 0x0e, 0x0f, 0x0b, 0 };
+ return alc_parse_auto_config(codec, alc861_ignore, alc861_ssids);
}
#ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -16271,160 +5335,43 @@ static const struct hda_amp_list alc861_loopbacks[] = {
#endif
-/*
- * configuration and preset
- */
-static const char * const alc861_models[ALC861_MODEL_LAST] = {
- [ALC861_3ST] = "3stack",
- [ALC660_3ST] = "3stack-660",
- [ALC861_3ST_DIG] = "3stack-dig",
- [ALC861_6ST_DIG] = "6stack-dig",
- [ALC861_UNIWILL_M31] = "uniwill-m31",
- [ALC861_TOSHIBA] = "toshiba",
- [ALC861_ASUS] = "asus",
- [ALC861_ASUS_LAPTOP] = "asus-laptop",
- [ALC861_AUTO] = "auto",
+/* Pin config fixes */
+enum {
+ ALC861_FIXUP_FSC_AMILO_PI1505,
+ ALC861_FIXUP_AMP_VREF_0F,
+ ALC861_FIXUP_NO_JACK_DETECT,
+ ALC861_FIXUP_ASUS_A6RP,
};
-static const struct snd_pci_quirk alc861_cfg_tbl[] = {
- SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
- SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
- SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
- SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
- SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
- SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
- SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
- /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
- * Any other models that need this preset?
- */
- /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
- SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
- SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
- SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
- SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
- SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
- /* FIXME: the below seems conflict */
- /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
- SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
- SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
- {}
-};
+/* On some laptops, VREF of pin 0x0f is abused for controlling the main amp */
+static void alc861_fixup_asus_amp_vref_0f(struct hda_codec *codec,
+ const struct alc_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+ unsigned int val;
-static const struct alc_config_preset alc861_presets[] = {
- [ALC861_3ST] = {
- .mixers = { alc861_3ST_mixer },
- .init_verbs = { alc861_threestack_init_verbs },
- .num_dacs = ARRAY_SIZE(alc861_dac_nids),
- .dac_nids = alc861_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
- .channel_mode = alc861_threestack_modes,
- .need_dac_fix = 1,
- .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
- .adc_nids = alc861_adc_nids,
- .input_mux = &alc861_capture_source,
- },
- [ALC861_3ST_DIG] = {
- .mixers = { alc861_base_mixer },
- .init_verbs = { alc861_threestack_init_verbs },
- .num_dacs = ARRAY_SIZE(alc861_dac_nids),
- .dac_nids = alc861_dac_nids,
- .dig_out_nid = ALC861_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
- .channel_mode = alc861_threestack_modes,
- .need_dac_fix = 1,
- .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
- .adc_nids = alc861_adc_nids,
- .input_mux = &alc861_capture_source,
- },
- [ALC861_6ST_DIG] = {
- .mixers = { alc861_base_mixer },
- .init_verbs = { alc861_base_init_verbs },
- .num_dacs = ARRAY_SIZE(alc861_dac_nids),
- .dac_nids = alc861_dac_nids,
- .dig_out_nid = ALC861_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
- .channel_mode = alc861_8ch_modes,
- .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
- .adc_nids = alc861_adc_nids,
- .input_mux = &alc861_capture_source,
- },
- [ALC660_3ST] = {
- .mixers = { alc861_3ST_mixer },
- .init_verbs = { alc861_threestack_init_verbs },
- .num_dacs = ARRAY_SIZE(alc660_dac_nids),
- .dac_nids = alc660_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
- .channel_mode = alc861_threestack_modes,
- .need_dac_fix = 1,
- .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
- .adc_nids = alc861_adc_nids,
- .input_mux = &alc861_capture_source,
- },
- [ALC861_UNIWILL_M31] = {
- .mixers = { alc861_uniwill_m31_mixer },
- .init_verbs = { alc861_uniwill_m31_init_verbs },
- .num_dacs = ARRAY_SIZE(alc861_dac_nids),
- .dac_nids = alc861_dac_nids,
- .dig_out_nid = ALC861_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
- .channel_mode = alc861_uniwill_m31_modes,
- .need_dac_fix = 1,
- .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
- .adc_nids = alc861_adc_nids,
- .input_mux = &alc861_capture_source,
- },
- [ALC861_TOSHIBA] = {
- .mixers = { alc861_toshiba_mixer },
- .init_verbs = { alc861_base_init_verbs,
- alc861_toshiba_init_verbs },
- .num_dacs = ARRAY_SIZE(alc861_dac_nids),
- .dac_nids = alc861_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
- .channel_mode = alc883_3ST_2ch_modes,
- .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
- .adc_nids = alc861_adc_nids,
- .input_mux = &alc861_capture_source,
- .unsol_event = alc861_toshiba_unsol_event,
- .init_hook = alc861_toshiba_automute,
- },
- [ALC861_ASUS] = {
- .mixers = { alc861_asus_mixer },
- .init_verbs = { alc861_asus_init_verbs },
- .num_dacs = ARRAY_SIZE(alc861_dac_nids),
- .dac_nids = alc861_dac_nids,
- .dig_out_nid = ALC861_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
- .channel_mode = alc861_asus_modes,
- .need_dac_fix = 1,
- .hp_nid = 0x06,
- .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
- .adc_nids = alc861_adc_nids,
- .input_mux = &alc861_capture_source,
- },
- [ALC861_ASUS_LAPTOP] = {
- .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
- .init_verbs = { alc861_asus_init_verbs,
- alc861_asus_laptop_init_verbs },
- .num_dacs = ARRAY_SIZE(alc861_dac_nids),
- .dac_nids = alc861_dac_nids,
- .dig_out_nid = ALC861_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
- .channel_mode = alc883_3ST_2ch_modes,
- .need_dac_fix = 1,
- .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
- .adc_nids = alc861_adc_nids,
- .input_mux = &alc861_capture_source,
- },
-};
+ if (action != ALC_FIXUP_ACT_INIT)
+ return;
+ val = snd_hda_codec_read(codec, 0x0f, 0,
+ AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+ if (!(val & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN)))
+ val |= AC_PINCTL_IN_EN;
+ val |= AC_PINCTL_VREF_50;
+ snd_hda_codec_write(codec, 0x0f, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, val);
+ spec->keep_vref_in_automute = 1;
+}
-/* Pin config fixes */
-enum {
- PINFIX_FSC_AMILO_PI1505,
- PINFIX_ASUS_A6RP,
-};
+/* suppress the jack-detection */
+static void alc_fixup_no_jack_detect(struct hda_codec *codec,
+ const struct alc_fixup *fix, int action)
+{
+ if (action == ALC_FIXUP_ACT_PRE_PROBE)
+ codec->no_jack_detect = 1;
+}
static const struct alc_fixup alc861_fixups[] = {
- [PINFIX_FSC_AMILO_PI1505] = {
+ [ALC861_FIXUP_FSC_AMILO_PI1505] = {
.type = ALC_FIXUP_PINS,
.v.pins = (const struct alc_pincfg[]) {
{ 0x0b, 0x0221101f }, /* HP */
@@ -16432,27 +5379,37 @@ static const struct alc_fixup alc861_fixups[] = {
{ }
}
},
- [PINFIX_ASUS_A6RP] = {
- .type = ALC_FIXUP_VERBS,
- .v.verbs = (const struct hda_verb[]) {
- /* node 0x0f VREF seems controlling the master output */
- { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
- { }
- },
+ [ALC861_FIXUP_AMP_VREF_0F] = {
+ .type = ALC_FIXUP_FUNC,
+ .v.func = alc861_fixup_asus_amp_vref_0f,
+ },
+ [ALC861_FIXUP_NO_JACK_DETECT] = {
+ .type = ALC_FIXUP_FUNC,
+ .v.func = alc_fixup_no_jack_detect,
},
+ [ALC861_FIXUP_ASUS_A6RP] = {
+ .type = ALC_FIXUP_FUNC,
+ .v.func = alc861_fixup_asus_amp_vref_0f,
+ .chained = true,
+ .chain_id = ALC861_FIXUP_NO_JACK_DETECT,
+ }
};
static const struct snd_pci_quirk alc861_fixup_tbl[] = {
- SND_PCI_QUIRK(0x1043, 0x1393, "ASUS A6Rp", PINFIX_ASUS_A6RP),
- SND_PCI_QUIRK(0x1584, 0x2b01, "Haier W18", PINFIX_ASUS_A6RP),
- SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
+ SND_PCI_QUIRK(0x1043, 0x1393, "ASUS A6Rp", ALC861_FIXUP_ASUS_A6RP),
+ SND_PCI_QUIRK_VENDOR(0x1043, "ASUS laptop", ALC861_FIXUP_AMP_VREF_0F),
+ SND_PCI_QUIRK(0x1462, 0x7254, "HP DX2200", ALC861_FIXUP_NO_JACK_DETECT),
+ SND_PCI_QUIRK(0x1584, 0x2b01, "Haier W18", ALC861_FIXUP_AMP_VREF_0F),
+ SND_PCI_QUIRK(0x1584, 0x0000, "Uniwill ECS M31EI", ALC861_FIXUP_AMP_VREF_0F),
+ SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", ALC861_FIXUP_FSC_AMILO_PI1505),
{}
};
+/*
+ */
static int patch_alc861(struct hda_codec *codec)
{
struct alc_spec *spec;
- int board_config;
int err;
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
@@ -16461,71 +5418,49 @@ static int patch_alc861(struct hda_codec *codec)
codec->spec = spec;
- board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
- alc861_models,
- alc861_cfg_tbl);
+ spec->mixer_nid = 0x15;
- if (board_config < 0) {
- printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
- codec->chip_name);
- 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) {
- alc_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups);
- alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
- }
+ /* automatic parse from the BIOS config */
+ err = alc861_parse_auto_config(codec);
+ if (err < 0)
+ goto error;
- if (board_config == ALC861_AUTO) {
- /* automatic parse from the BIOS config */
- err = alc861_parse_auto_config(codec);
- if (err < 0) {
- alc_free(codec);
- return err;
- } else if (!err) {
- printk(KERN_INFO
- "hda_codec: Cannot set up configuration "
- "from BIOS. Using base mode...\n");
- board_config = ALC861_3ST_DIG;
- }
+ if (!spec->no_analog && !spec->adc_nids) {
+ alc_auto_fill_adc_caps(codec);
+ alc_rebuild_imux_for_auto_mic(codec);
+ alc_remove_invalid_adc_nids(codec);
}
- err = snd_hda_attach_beep_device(codec, 0x23);
- if (err < 0) {
- alc_free(codec);
- return err;
- }
-
- if (board_config != ALC861_AUTO)
- setup_preset(codec, &alc861_presets[board_config]);
-
- spec->stream_analog_playback = &alc861_pcm_analog_playback;
- spec->stream_analog_capture = &alc861_pcm_analog_capture;
-
- spec->stream_digital_playback = &alc861_pcm_digital_playback;
- spec->stream_digital_capture = &alc861_pcm_digital_capture;
-
- if (!spec->cap_mixer)
+ if (!spec->no_analog && !spec->cap_mixer)
set_capture_mixer(codec);
- set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
+
+ if (!spec->no_analog) {
+ err = snd_hda_attach_beep_device(codec, 0x23);
+ if (err < 0)
+ goto error;
+ set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
+ }
spec->vmaster_nid = 0x03;
alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
codec->patch_ops = alc_patch_ops;
- if (board_config == ALC861_AUTO) {
- spec->init_hook = alc861_auto_init;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
- spec->power_hook = alc_power_eapd;
-#endif
- }
+ spec->init_hook = alc_auto_init_std;
#ifdef CONFIG_SND_HDA_POWER_SAVE
+ spec->power_hook = alc_power_eapd;
if (!spec->loopback.amplist)
spec->loopback.amplist = alc861_loopbacks;
#endif
return 0;
+
+ error:
+ alc_free(codec);
+ return err;
}
/*
@@ -16535,899 +5470,68 @@ static int patch_alc861(struct hda_codec *codec)
*
* In addition, an independent DAC
*/
-#define ALC861VD_DIGOUT_NID 0x06
-
-static const hda_nid_t alc861vd_dac_nids[4] = {
- /* front, surr, clfe, side surr */
- 0x02, 0x03, 0x04, 0x05
-};
-
-/* dac_nids for ALC660vd are in a different order - according to
- * Realtek's driver.
- * This should probably result in a different mixer for 6stack models
- * of ALC660vd codecs, but for now there is only 3stack mixer
- * - and it is the same as in 861vd.
- * adc_nids in ALC660vd are (is) the same as in 861vd
- */
-static const hda_nid_t alc660vd_dac_nids[3] = {
- /* front, rear, clfe, rear_surr */
- 0x02, 0x04, 0x03
-};
-
-static const hda_nid_t alc861vd_adc_nids[1] = {
- /* ADC0 */
- 0x09,
-};
-
-static const hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
-
-/* input MUX */
-/* FIXME: should be a matrix-type input source selection */
-static const struct hda_input_mux alc861vd_capture_source = {
- .num_items = 4,
- .items = {
- { "Mic", 0x0 },
- { "Front Mic", 0x1 },
- { "Line", 0x2 },
- { "CD", 0x4 },
- },
-};
-
-static const struct hda_input_mux alc861vd_dallas_capture_source = {
- .num_items = 2,
- .items = {
- { "Mic", 0x0 },
- { "Internal Mic", 0x1 },
- },
-};
-
-static const struct hda_input_mux alc861vd_hp_capture_source = {
- .num_items = 2,
- .items = {
- { "Front Mic", 0x0 },
- { "ATAPI Mic", 0x1 },
- },
-};
-
-/*
- * 2ch mode
- */
-static const struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
- { 2, NULL }
-};
-
-/*
- * 6ch mode
- */
-static const struct hda_verb alc861vd_6stack_ch6_init[] = {
- { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
- { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { } /* end */
-};
-
-/*
- * 8ch mode
- */
-static const struct hda_verb alc861vd_6stack_ch8_init[] = {
- { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { } /* end */
-};
-
-static const struct hda_channel_mode alc861vd_6stack_modes[2] = {
- { 6, alc861vd_6stack_ch6_init },
- { 8, alc861vd_6stack_ch8_init },
-};
-
-static const struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Channel Mode",
- .info = alc_ch_mode_info,
- .get = alc_ch_mode_get,
- .put = alc_ch_mode_put,
- },
- { } /* end */
-};
-
-/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
- * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
- */
-static const struct snd_kcontrol_new alc861vd_6st_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-
- HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
-
- HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
- HDA_OUTPUT),
- HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
- HDA_OUTPUT),
- HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
- HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-
- HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
-
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-
- 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 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),
-
- 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),
- HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc861vd_3st_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-
- 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 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),
-
- 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),
- HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
- /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
- HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-
- 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 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),
-
- HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
- HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-
- { } /* end */
-};
-
-/* Pin assignment: Speaker=0x14, HP = 0x15,
- * Mic=0x18, Internal Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
- */
-static const 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("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 */
-};
-
-/* Pin assignment: Speaker=0x14, Line-out = 0x15,
- * Front Mic=0x18, ATAPI Mic = 0x19,
- */
-static const struct snd_kcontrol_new alc861vd_hp_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Front 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("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-
- { } /* end */
-};
-
-/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static const struct hda_verb alc861vd_volume_init_verbs[] = {
- /*
- * Unmute ADC0 and set the default input to mic-in
- */
- {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
- /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
- * the analog-loopback mixer widget
- */
- /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-
- /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
-
- /*
- * Set up output mixers (0x02 - 0x05)
- */
- /* set vol=0 to output mixers */
- {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
- /* set up input amps for analog loopback */
- /* Amp Indices: DAC = 0, mixer = 1 */
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-
- { }
-};
-
-/*
- * 3-stack pin configuration:
- * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
- */
-static const struct hda_verb alc861vd_3stack_init_verbs[] = {
- /*
- * Set pin mode and muting
- */
- /* set front pin widgets 0x14 for output */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-
- /* Mic (rear) pin: input vref at 80% */
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* Front Mic pin: input vref at 80% */
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* Line In pin: input */
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* Line-2 In: Headphone output (output 0 - 0x0c) */
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* CD pin widget for input */
- {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
- { }
-};
-
-/*
- * 6-stack pin configuration:
- */
-static const struct hda_verb alc861vd_6stack_init_verbs[] = {
- /*
- * Set pin mode and muting
- */
- /* set front pin widgets 0x14 for output */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-
- /* Rear Pin: output 1 (0x0d) */
- {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, 0x01},
- /* CLFE Pin: output 2 (0x0e) */
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
- /* Side Pin: output 3 (0x0f) */
- {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
-
- /* Mic (rear) pin: input vref at 80% */
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* Front Mic pin: input vref at 80% */
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* Line In pin: input */
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* Line-2 In: Headphone output (output 0 - 0x0c) */
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* CD pin widget for input */
- {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
- { }
-};
-
-static const struct hda_verb alc861vd_eapd_verbs[] = {
- {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
- { }
-};
-
-static const struct hda_verb alc660vd_eapd_verbs[] = {
- {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
- {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
- { }
-};
-
-static const struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
- {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
- {}
-};
-
-static void alc861vd_lenovo_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- spec->autocfg.hp_pins[0] = 0x1b;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
-{
- alc_hp_automute(codec);
- alc88x_simple_mic_automute(codec);
-}
-
-static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
- unsigned int res)
-{
- switch (res >> 26) {
- case ALC880_MIC_EVENT:
- alc88x_simple_mic_automute(codec);
- break;
- default:
- alc_sku_unsol_event(codec, res);
- break;
- }
-}
-
-static const struct hda_verb alc861vd_dallas_verbs[] = {
- {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
-
- { } /* end */
-};
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc861vd_dallas_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x15;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
#ifdef CONFIG_SND_HDA_POWER_SAVE
#define alc861vd_loopbacks alc880_loopbacks
#endif
-/* pcm configuration: identical with ALC880 */
-#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
-#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
-#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
-#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
-
-/*
- * configuration and preset
- */
-static const char * const alc861vd_models[ALC861VD_MODEL_LAST] = {
- [ALC660VD_3ST] = "3stack-660",
- [ALC660VD_3ST_DIG] = "3stack-660-digout",
- [ALC660VD_ASUS_V1S] = "asus-v1s",
- [ALC861VD_3ST] = "3stack",
- [ALC861VD_3ST_DIG] = "3stack-digout",
- [ALC861VD_6ST_DIG] = "6stack-digout",
- [ALC861VD_LENOVO] = "lenovo",
- [ALC861VD_DALLAS] = "dallas",
- [ALC861VD_HP] = "hp",
- [ALC861VD_AUTO] = "auto",
-};
-
-static const struct snd_pci_quirk alc861vd_cfg_tbl[] = {
- SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
- SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
- SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
- /*SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),*/ /* auto */
- SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
- SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
- SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
- SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
- /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
- SND_PCI_QUIRK(0x1179, 0xff01, "Toshiba A135", ALC861VD_LENOVO),
- SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
- SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
- SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
- SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO),
- SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
- {}
-};
-
-static const struct alc_config_preset alc861vd_presets[] = {
- [ALC660VD_3ST] = {
- .mixers = { alc861vd_3st_mixer },
- .init_verbs = { alc861vd_volume_init_verbs,
- alc861vd_3stack_init_verbs },
- .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
- .dac_nids = alc660vd_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
- .channel_mode = alc861vd_3stack_2ch_modes,
- .input_mux = &alc861vd_capture_source,
- },
- [ALC660VD_3ST_DIG] = {
- .mixers = { alc861vd_3st_mixer },
- .init_verbs = { alc861vd_volume_init_verbs,
- alc861vd_3stack_init_verbs },
- .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
- .dac_nids = alc660vd_dac_nids,
- .dig_out_nid = ALC861VD_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
- .channel_mode = alc861vd_3stack_2ch_modes,
- .input_mux = &alc861vd_capture_source,
- },
- [ALC861VD_3ST] = {
- .mixers = { alc861vd_3st_mixer },
- .init_verbs = { alc861vd_volume_init_verbs,
- alc861vd_3stack_init_verbs },
- .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
- .dac_nids = alc861vd_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
- .channel_mode = alc861vd_3stack_2ch_modes,
- .input_mux = &alc861vd_capture_source,
- },
- [ALC861VD_3ST_DIG] = {
- .mixers = { alc861vd_3st_mixer },
- .init_verbs = { alc861vd_volume_init_verbs,
- alc861vd_3stack_init_verbs },
- .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
- .dac_nids = alc861vd_dac_nids,
- .dig_out_nid = ALC861VD_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
- .channel_mode = alc861vd_3stack_2ch_modes,
- .input_mux = &alc861vd_capture_source,
- },
- [ALC861VD_6ST_DIG] = {
- .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
- .init_verbs = { alc861vd_volume_init_verbs,
- alc861vd_6stack_init_verbs },
- .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
- .dac_nids = alc861vd_dac_nids,
- .dig_out_nid = ALC861VD_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
- .channel_mode = alc861vd_6stack_modes,
- .input_mux = &alc861vd_capture_source,
- },
- [ALC861VD_LENOVO] = {
- .mixers = { alc861vd_lenovo_mixer },
- .init_verbs = { alc861vd_volume_init_verbs,
- alc861vd_3stack_init_verbs,
- alc861vd_eapd_verbs,
- alc861vd_lenovo_unsol_verbs },
- .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
- .dac_nids = alc660vd_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
- .channel_mode = alc861vd_3stack_2ch_modes,
- .input_mux = &alc861vd_capture_source,
- .unsol_event = alc861vd_lenovo_unsol_event,
- .setup = alc861vd_lenovo_setup,
- .init_hook = alc861vd_lenovo_init_hook,
- },
- [ALC861VD_DALLAS] = {
- .mixers = { alc861vd_dallas_mixer },
- .init_verbs = { alc861vd_dallas_verbs },
- .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
- .dac_nids = alc861vd_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
- .channel_mode = alc861vd_3stack_2ch_modes,
- .input_mux = &alc861vd_dallas_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc861vd_dallas_setup,
- .init_hook = alc_hp_automute,
- },
- [ALC861VD_HP] = {
- .mixers = { alc861vd_hp_mixer },
- .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
- .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
- .dac_nids = alc861vd_dac_nids,
- .dig_out_nid = ALC861VD_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
- .channel_mode = alc861vd_3stack_2ch_modes,
- .input_mux = &alc861vd_hp_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc861vd_dallas_setup,
- .init_hook = alc_hp_automute,
- },
- [ALC660VD_ASUS_V1S] = {
- .mixers = { alc861vd_lenovo_mixer },
- .init_verbs = { alc861vd_volume_init_verbs,
- alc861vd_3stack_init_verbs,
- alc861vd_eapd_verbs,
- alc861vd_lenovo_unsol_verbs },
- .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
- .dac_nids = alc660vd_dac_nids,
- .dig_out_nid = ALC861VD_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
- .channel_mode = alc861vd_3stack_2ch_modes,
- .input_mux = &alc861vd_capture_source,
- .unsol_event = alc861vd_lenovo_unsol_event,
- .setup = alc861vd_lenovo_setup,
- .init_hook = alc861vd_lenovo_init_hook,
- },
-};
-
-/*
- * BIOS auto configuration
- */
-static int alc861vd_auto_create_input_ctls(struct hda_codec *codec,
- const struct auto_pin_cfg *cfg)
-{
- return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x22, 0);
-}
-
-
-static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
- hda_nid_t nid, int pin_type, int dac_idx)
-{
- alc_set_pin_output(codec, nid, pin_type);
-}
-
-static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- int i;
-
- for (i = 0; i <= HDA_SIDE; i++) {
- hda_nid_t nid = spec->autocfg.line_out_pins[i];
- int pin_type = get_pin_type(spec->autocfg.line_out_type);
- if (nid)
- alc861vd_auto_set_output_and_unmute(codec, nid,
- pin_type, i);
- }
-}
-
-
-static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- hda_nid_t pin;
-
- pin = spec->autocfg.hp_pins[0];
- if (pin) /* connect to front and use dac 0 */
- alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
- pin = spec->autocfg.speaker_pins[0];
- if (pin)
- alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
-}
-
-#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
-
-static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- struct auto_pin_cfg *cfg = &spec->autocfg;
- int i;
-
- for (i = 0; i < cfg->num_inputs; i++) {
- hda_nid_t nid = cfg->inputs[i].pin;
- if (alc_is_input_pin(codec, nid)) {
- alc_set_input_pin(codec, nid, cfg->inputs[i].type);
- if (nid != ALC861VD_PIN_CD_NID &&
- (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
- snd_hda_codec_write(codec, nid, 0,
- AC_VERB_SET_AMP_GAIN_MUTE,
- AMP_OUT_MUTE);
- }
- }
-}
-
-#define alc861vd_auto_init_input_src alc882_auto_init_input_src
-
-#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
-#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
-
-/* add playback controls from the parsed DAC table */
-/* Based on ALC880 version. But ALC861VD has separate,
- * different NIDs for mute/unmute switch and volume control */
-static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
- const struct auto_pin_cfg *cfg)
-{
- static const char * const chname[4] = {
- "Front", "Surround", "CLFE", "Side"
- };
- const char *pfx = alc_get_line_out_pfx(spec, true);
- hda_nid_t nid_v, nid_s;
- int i, err, noutputs;
-
- noutputs = cfg->line_outs;
- if (spec->multi_ios > 0)
- noutputs += spec->multi_ios;
-
- for (i = 0; i < noutputs; i++) {
- if (!spec->multiout.dac_nids[i])
- continue;
- nid_v = alc861vd_idx_to_mixer_vol(
- alc880_dac_to_idx(
- spec->multiout.dac_nids[i]));
- nid_s = alc861vd_idx_to_mixer_switch(
- alc880_dac_to_idx(
- spec->multiout.dac_nids[i]));
-
- if (!pfx && i == 2) {
- /* Center/LFE */
- err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
- "Center",
- HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
- "LFE",
- HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
- "Center",
- HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
- HDA_INPUT));
- if (err < 0)
- return err;
- err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
- "LFE",
- HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
- HDA_INPUT));
- if (err < 0)
- return err;
- } else {
- const char *name = pfx;
- int index = i;
- if (!name) {
- name = chname[i];
- index = 0;
- }
- err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
- name, index,
- HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
- name, index,
- HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
- HDA_INPUT));
- if (err < 0)
- return err;
- }
- }
- return 0;
-}
-
-/* add playback controls for speaker and HP outputs */
-/* Based on ALC880 version. But ALC861VD has separate,
- * different NIDs for mute/unmute switch and volume control */
-static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
- hda_nid_t pin, const char *pfx)
-{
- hda_nid_t nid_v, nid_s;
- int err;
-
- if (!pin)
- return 0;
-
- if (alc880_is_fixed_pin(pin)) {
- nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
- /* specify the DAC as the extra output */
- if (!spec->multiout.hp_nid)
- spec->multiout.hp_nid = nid_v;
- else
- spec->multiout.extra_out_nid[0] = nid_v;
- /* control HP volume/switch on the output mixer amp */
- nid_v = alc861vd_idx_to_mixer_vol(
- alc880_fixed_pin_idx(pin));
- nid_s = alc861vd_idx_to_mixer_switch(
- alc880_fixed_pin_idx(pin));
-
- err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
- HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
- err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
- HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
- if (err < 0)
- return err;
- } else if (alc880_is_multi_pin(pin)) {
- /* set manual connection */
- /* we have only a switch on HP-out PIN */
- err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
- HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
- }
- return 0;
-}
-
-/* parse the BIOS configuration and set up the alc_spec
- * return 1 if successful, 0 if the proper config is not found,
- * or a negative error code
- * Based on ALC880 version - had to change it to override
- * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
static int alc861vd_parse_auto_config(struct hda_codec *codec)
{
- struct alc_spec *spec = codec->spec;
- int err;
static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
-
- err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
- alc861vd_ignore);
- if (err < 0)
- return err;
- if (!spec->autocfg.line_outs)
- return 0; /* can't find valid BIOS pin config */
-
- err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
- if (err < 0)
- return err;
- err = alc_auto_add_multi_channel_mode(codec);
- if (err < 0)
- return err;
- err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
- if (err < 0)
- return err;
- err = alc861vd_auto_create_extra_out(spec,
- spec->autocfg.speaker_pins[0],
- "Speaker");
- if (err < 0)
- return err;
- err = alc861vd_auto_create_extra_out(spec,
- spec->autocfg.hp_pins[0],
- "Headphone");
- if (err < 0)
- return err;
- err = alc861vd_auto_create_input_ctls(codec, &spec->autocfg);
- if (err < 0)
- return err;
-
- spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-
- alc_auto_parse_digital(codec);
-
- if (spec->kctls.list)
- add_mixer(spec, spec->kctls.list);
-
- add_verb(spec, alc861vd_volume_init_verbs);
-
- spec->num_mux_defs = 1;
- spec->input_mux = &spec->private_imux[0];
-
- err = alc_auto_add_mic_boost(codec);
- if (err < 0)
- return err;
-
- alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
-
- return 1;
-}
-
-/* additional initialization for auto-configuration model */
-static void alc861vd_auto_init(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- alc861vd_auto_init_multi_out(codec);
- alc861vd_auto_init_hp_out(codec);
- alc861vd_auto_init_analog_input(codec);
- alc861vd_auto_init_input_src(codec);
- alc_auto_init_digital(codec);
- if (spec->unsol_event)
- alc_inithook(codec);
+ static const hda_nid_t alc861vd_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+ return alc_parse_auto_config(codec, alc861vd_ignore, alc861vd_ssids);
}
enum {
- ALC660VD_FIX_ASUS_GPIO1
+ ALC660VD_FIX_ASUS_GPIO1,
+ ALC861VD_FIX_DALLAS,
};
-/* reset GPIO1 */
+/* exclude VREF80 */
+static void alc861vd_fixup_dallas(struct hda_codec *codec,
+ const struct alc_fixup *fix, int action)
+{
+ if (action == ALC_FIXUP_ACT_PRE_PROBE) {
+ snd_hda_override_pin_caps(codec, 0x18, 0x00000734);
+ snd_hda_override_pin_caps(codec, 0x19, 0x0000073c);
+ }
+}
+
static const struct alc_fixup alc861vd_fixups[] = {
[ALC660VD_FIX_ASUS_GPIO1] = {
.type = ALC_FIXUP_VERBS,
.v.verbs = (const struct hda_verb[]) {
+ /* reset GPIO1 */
{0x01, AC_VERB_SET_GPIO_MASK, 0x03},
{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
{0x01, AC_VERB_SET_GPIO_DATA, 0x01},
{ }
}
},
+ [ALC861VD_FIX_DALLAS] = {
+ .type = ALC_FIXUP_FUNC,
+ .v.func = alc861vd_fixup_dallas,
+ },
};
static const struct snd_pci_quirk alc861vd_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_FIX_DALLAS),
SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
+ SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_FIX_DALLAS),
{}
};
+static const struct hda_verb alc660vd_eapd_verbs[] = {
+ {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
+ {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
+ { }
+};
+
+/*
+ */
static int patch_alc861vd(struct hda_codec *codec)
{
struct alc_spec *spec;
- int err, board_config;
+ int err;
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (spec == NULL)
@@ -17435,64 +5539,36 @@ static int patch_alc861vd(struct hda_codec *codec)
codec->spec = spec;
- board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
- alc861vd_models,
- alc861vd_cfg_tbl);
-
- if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
- printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
- codec->chip_name);
- board_config = ALC861VD_AUTO;
- }
+ spec->mixer_nid = 0x0b;
- 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 */
- err = alc861vd_parse_auto_config(codec);
- if (err < 0) {
- alc_free(codec);
- return err;
- } else if (!err) {
- printk(KERN_INFO
- "hda_codec: Cannot set up configuration "
- "from BIOS. Using base mode...\n");
- board_config = ALC861VD_3ST;
- }
- }
-
- err = snd_hda_attach_beep_device(codec, 0x23);
- if (err < 0) {
- alc_free(codec);
- return err;
- }
+ alc_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups);
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
- if (board_config != ALC861VD_AUTO)
- setup_preset(codec, &alc861vd_presets[board_config]);
+ /* automatic parse from the BIOS config */
+ err = alc861vd_parse_auto_config(codec);
+ if (err < 0)
+ goto error;
if (codec->vendor_id == 0x10ec0660) {
/* always turn on EAPD */
add_verb(spec, alc660vd_eapd_verbs);
}
- spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
- spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
+ if (!spec->no_analog && !spec->adc_nids) {
+ alc_auto_fill_adc_caps(codec);
+ alc_rebuild_imux_for_auto_mic(codec);
+ alc_remove_invalid_adc_nids(codec);
+ }
- spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
- spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
+ if (!spec->no_analog && !spec->cap_mixer)
+ set_capture_mixer(codec);
- if (!spec->adc_nids) {
- spec->adc_nids = alc861vd_adc_nids;
- spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
+ if (!spec->no_analog) {
+ err = snd_hda_attach_beep_device(codec, 0x23);
+ if (err < 0)
+ goto error;
+ set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
}
- if (!spec->capsrc_nids)
- spec->capsrc_nids = alc861vd_capsrc_nids;
-
- set_capture_mixer(codec);
- set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
spec->vmaster_nid = 0x02;
@@ -17500,8 +5576,7 @@ static int patch_alc861vd(struct hda_codec *codec)
codec->patch_ops = alc_patch_ops;
- if (board_config == ALC861VD_AUTO)
- spec->init_hook = alc861vd_auto_init;
+ spec->init_hook = alc_auto_init_std;
spec->shutup = alc_eapd_shutup;
#ifdef CONFIG_SND_HDA_POWER_SAVE
if (!spec->loopback.amplist)
@@ -17509,6 +5584,10 @@ static int patch_alc861vd(struct hda_codec *codec)
#endif
return 0;
+
+ error:
+ alc_free(codec);
+ return err;
}
/*
@@ -17522,1943 +5601,28 @@ static int patch_alc861vd(struct hda_codec *codec)
* In addition, an independent DAC for the multi-playback (not used in this
* driver yet).
*/
-#define ALC662_DIGOUT_NID 0x06
-#define ALC662_DIGIN_NID 0x0a
-
-static const hda_nid_t alc662_dac_nids[3] = {
- /* front, rear, clfe */
- 0x02, 0x03, 0x04
-};
-
-static const hda_nid_t alc272_dac_nids[2] = {
- 0x02, 0x03
-};
-
-static const hda_nid_t alc662_adc_nids[2] = {
- /* ADC1-2 */
- 0x09, 0x08
-};
-
-static const hda_nid_t alc272_adc_nids[1] = {
- /* ADC1-2 */
- 0x08,
-};
-
-static const hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 };
-static const hda_nid_t alc272_capsrc_nids[1] = { 0x23 };
-
-
-/* input MUX */
-/* FIXME: should be a matrix-type input source selection */
-static const struct hda_input_mux alc662_capture_source = {
- .num_items = 4,
- .items = {
- { "Mic", 0x0 },
- { "Front Mic", 0x1 },
- { "Line", 0x2 },
- { "CD", 0x4 },
- },
-};
-
-static const struct hda_input_mux alc662_lenovo_101e_capture_source = {
- .num_items = 2,
- .items = {
- { "Mic", 0x1 },
- { "Line", 0x2 },
- },
-};
-
-static const struct hda_input_mux alc663_capture_source = {
- .num_items = 3,
- .items = {
- { "Mic", 0x0 },
- { "Front Mic", 0x1 },
- { "Line", 0x2 },
- },
-};
-
-#if 0 /* set to 1 for testing other input sources below */
-static const struct hda_input_mux alc272_nc10_capture_source = {
- .num_items = 16,
- .items = {
- { "Autoselect Mic", 0x0 },
- { "Internal Mic", 0x1 },
- { "In-0x02", 0x2 },
- { "In-0x03", 0x3 },
- { "In-0x04", 0x4 },
- { "In-0x05", 0x5 },
- { "In-0x06", 0x6 },
- { "In-0x07", 0x7 },
- { "In-0x08", 0x8 },
- { "In-0x09", 0x9 },
- { "In-0x0a", 0x0a },
- { "In-0x0b", 0x0b },
- { "In-0x0c", 0x0c },
- { "In-0x0d", 0x0d },
- { "In-0x0e", 0x0e },
- { "In-0x0f", 0x0f },
- },
-};
-#endif
-
-/*
- * 2ch mode
- */
-static const struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
- { 2, NULL }
-};
-
-/*
- * 2ch mode
- */
-static const struct hda_verb alc662_3ST_ch2_init[] = {
- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
- { } /* end */
-};
-
-/*
- * 6ch mode
- */
-static const struct hda_verb alc662_3ST_ch6_init[] = {
- { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
- { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
- { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
- { } /* end */
-};
-
-static const struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
- { 2, alc662_3ST_ch2_init },
- { 6, alc662_3ST_ch6_init },
-};
-
-/*
- * 2ch mode
- */
-static const struct hda_verb alc662_sixstack_ch6_init[] = {
- { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
- { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
- { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { } /* end */
-};
-
-/*
- * 6ch mode
- */
-static const struct hda_verb alc662_sixstack_ch8_init[] = {
- { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
- { } /* end */
-};
-
-static const struct hda_channel_mode alc662_5stack_modes[2] = {
- { 2, alc662_sixstack_ch6_init },
- { 6, alc662_sixstack_ch8_init },
-};
-
-/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
- * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
- */
-
-static const struct snd_kcontrol_new alc662_base_mixer[] = {
- /* output mixer control */
- HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-
- /*Input mixer control */
- HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
- HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
- HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
- HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
- HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 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("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_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 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("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_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
- HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
- 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_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
- { } /* end */
-};
-
-static const 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("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 */
-};
-
-static const struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
- ALC262_HIPPO_MASTER_SWITCH,
- HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, 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_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- { } /* end */
-};
-
-static const struct hda_bind_ctls alc663_asus_bind_master_vol = {
- .ops = &snd_hda_bind_vol,
- .values = {
- HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
- HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
- 0
- },
-};
-
-static const struct hda_bind_ctls alc663_asus_one_bind_switch = {
- .ops = &snd_hda_bind_sw,
- .values = {
- HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
- HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
- 0
- },
-};
-
-static const struct snd_kcontrol_new alc663_m51va_mixer[] = {
- HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
- HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
- HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- { } /* end */
-};
-
-static const struct hda_bind_ctls alc663_asus_tree_bind_switch = {
- .ops = &snd_hda_bind_sw,
- .values = {
- HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
- HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
- HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
- 0
- },
-};
-
-static const struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
- HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
- HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
- HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-
- { } /* end */
-};
-
-static const struct hda_bind_ctls alc663_asus_four_bind_switch = {
- .ops = &snd_hda_bind_sw,
- .values = {
- HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
- HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
- HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
- 0
- },
-};
-
-static const struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
- HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
- HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
- HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc662_1bjd_mixer[] = {
- HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 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("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
- { } /* end */
-};
-
-static const struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
- .ops = &snd_hda_bind_vol,
- .values = {
- HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
- HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
- 0
- },
-};
-
-static const struct hda_bind_ctls alc663_asus_two_bind_switch = {
- .ops = &snd_hda_bind_sw,
- .values = {
- HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
- HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
- 0
- },
-};
-
-static const struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
- HDA_BIND_VOL("Master Playback Volume",
- &alc663_asus_two_bind_master_vol),
- HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
- HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
- HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
- HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
- HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
- 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),
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc663_g71v_mixer[] = {
- HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 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("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc663_g50v_mixer[] = {
- HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 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("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 */
-};
-
-static const struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = {
- .ops = &snd_hda_bind_sw,
- .values = {
- HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
- HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
- HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
- HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
- HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
- 0
- },
-};
-
-static const struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = {
- .ops = &snd_hda_bind_sw,
- .values = {
- HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
- HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
- 0
- },
-};
-
-static const struct snd_kcontrol_new alc663_mode7_mixer[] = {
- HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
- HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
- HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
- HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("IntMic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("IntMic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
- HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc663_mode8_mixer[] = {
- HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
- HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
- HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
- HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x15, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- { } /* end */
-};
-
-
-static const struct snd_kcontrol_new alc662_chmode_mixer[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Channel Mode",
- .info = alc_ch_mode_info,
- .get = alc_ch_mode_get,
- .put = alc_ch_mode_put,
- },
- { } /* end */
-};
-
-static const struct hda_verb alc662_init_verbs[] = {
- /* ADC: mute amp left and right */
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
-
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
- /* Front Pin: output 0 (0x0c) */
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
- /* Rear Pin: output 1 (0x0d) */
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
- /* CLFE Pin: output 2 (0x0e) */
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
- /* Mic (rear) pin: input vref at 80% */
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* Front Mic pin: input vref at 80% */
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* Line In pin: input */
- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- /* Line-2 In: Headphone output (output 0 - 0x0c) */
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
- /* CD pin widget for input */
- {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
- /* FIXME: use matrix-type input source selection */
- /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
- /* Input mixer */
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
- { }
-};
-
-static const struct hda_verb alc662_eapd_init_verbs[] = {
- /* always trun on EAPD */
- {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
- {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
- { }
-};
-
-static const struct hda_verb alc662_sue_init_verbs[] = {
- {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
- {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
- {}
-};
-
-static const struct hda_verb alc662_eeepc_sue_init_verbs[] = {
- {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
- {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {}
-};
-
-/* Set Unsolicited Event*/
-static const struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {}
-};
-
-static const struct hda_verb alc663_m51va_init_verbs[] = {
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
- {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
- {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {}
-};
-
-static const struct hda_verb alc663_21jd_amic_init_verbs[] = {
- {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
- {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {}
-};
-
-static const struct hda_verb alc662_1bjd_amic_init_verbs[] = {
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
- {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {}
-};
-
-static const struct hda_verb alc663_15jd_amic_init_verbs[] = {
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {}
-};
-
-static const struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
- {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {}
-};
-
-static const struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
- {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {}
-};
-
-static const struct hda_verb alc663_g71v_init_verbs[] = {
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
- /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
-
- {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
-
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
- {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
- {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
- {}
-};
-
-static const struct hda_verb alc663_g50v_init_verbs[] = {
- {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
-
- {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
- {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {}
-};
-
-static const struct hda_verb alc662_ecs_init_verbs[] = {
- {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
- {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {}
-};
-
-static const struct hda_verb alc272_dell_zm1_init_verbs[] = {
- {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
- {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
- {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {}
-};
-
-static const struct hda_verb alc272_dell_init_verbs[] = {
- {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
- {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
- {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {}
-};
-
-static const struct hda_verb alc663_mode7_init_verbs[] = {
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
- {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
- {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
- {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {}
-};
-
-static const struct hda_verb alc663_mode8_init_verbs[] = {
- {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
- {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
- {}
-};
-
-static const struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
- HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
- { } /* end */
-};
-
-static const struct snd_kcontrol_new alc272_auto_capture_mixer[] = {
- HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
- { } /* end */
-};
-
-static void alc662_lenovo_101e_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x1b;
- spec->autocfg.line_out_pins[0] = 0x14;
- spec->autocfg.speaker_pins[0] = 0x15;
- spec->automute = 1;
- spec->detect_line = 1;
- spec->automute_lines = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static void alc662_eeepc_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- alc262_hippo1_setup(codec);
- spec->ext_mic.pin = 0x18;
- spec->ext_mic.mux_idx = 0;
- spec->int_mic.pin = 0x19;
- spec->int_mic.mux_idx = 1;
- spec->auto_mic = 1;
-}
-
-static void alc662_eeepc_ep20_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x14;
- spec->autocfg.speaker_pins[0] = 0x1b;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static void alc663_m51va_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- spec->autocfg.hp_pins[0] = 0x21;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->automute_mixer_nid[0] = 0x0c;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_MIXER;
- spec->ext_mic.pin = 0x18;
- spec->ext_mic.mux_idx = 0;
- spec->int_mic.pin = 0x12;
- spec->int_mic.mux_idx = 9;
- spec->auto_mic = 1;
-}
-
-/* ***************** Mode1 ******************************/
-static void alc663_mode1_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- spec->autocfg.hp_pins[0] = 0x21;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->automute_mixer_nid[0] = 0x0c;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_MIXER;
- spec->ext_mic.pin = 0x18;
- spec->ext_mic.mux_idx = 0;
- spec->int_mic.pin = 0x19;
- spec->int_mic.mux_idx = 1;
- spec->auto_mic = 1;
-}
-
-/* ***************** Mode2 ******************************/
-static void alc662_mode2_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- spec->autocfg.hp_pins[0] = 0x1b;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_PIN;
- spec->ext_mic.pin = 0x18;
- spec->ext_mic.mux_idx = 0;
- spec->int_mic.pin = 0x19;
- spec->int_mic.mux_idx = 1;
- spec->auto_mic = 1;
-}
-
-/* ***************** Mode3 ******************************/
-static void alc663_mode3_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- spec->autocfg.hp_pins[0] = 0x21;
- spec->autocfg.hp_pins[0] = 0x15;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_PIN;
- spec->ext_mic.pin = 0x18;
- spec->ext_mic.mux_idx = 0;
- spec->int_mic.pin = 0x19;
- spec->int_mic.mux_idx = 1;
- spec->auto_mic = 1;
-}
-
-/* ***************** Mode4 ******************************/
-static void alc663_mode4_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- spec->autocfg.hp_pins[0] = 0x21;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->autocfg.speaker_pins[1] = 0x16;
- spec->automute_mixer_nid[0] = 0x0c;
- spec->automute_mixer_nid[1] = 0x0e;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_MIXER;
- spec->ext_mic.pin = 0x18;
- spec->ext_mic.mux_idx = 0;
- spec->int_mic.pin = 0x19;
- spec->int_mic.mux_idx = 1;
- spec->auto_mic = 1;
-}
-
-/* ***************** Mode5 ******************************/
-static void alc663_mode5_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- spec->autocfg.hp_pins[0] = 0x15;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->autocfg.speaker_pins[1] = 0x16;
- spec->automute_mixer_nid[0] = 0x0c;
- spec->automute_mixer_nid[1] = 0x0e;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_MIXER;
- spec->ext_mic.pin = 0x18;
- spec->ext_mic.mux_idx = 0;
- spec->int_mic.pin = 0x19;
- spec->int_mic.mux_idx = 1;
- spec->auto_mic = 1;
-}
-
-/* ***************** Mode6 ******************************/
-static void alc663_mode6_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- spec->autocfg.hp_pins[0] = 0x1b;
- spec->autocfg.hp_pins[0] = 0x15;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->automute_mixer_nid[0] = 0x0c;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_MIXER;
- spec->ext_mic.pin = 0x18;
- spec->ext_mic.mux_idx = 0;
- spec->int_mic.pin = 0x19;
- spec->int_mic.mux_idx = 1;
- spec->auto_mic = 1;
-}
-
-/* ***************** Mode7 ******************************/
-static void alc663_mode7_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- spec->autocfg.hp_pins[0] = 0x1b;
- spec->autocfg.hp_pins[0] = 0x21;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->autocfg.speaker_pins[0] = 0x17;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_PIN;
- spec->ext_mic.pin = 0x18;
- spec->ext_mic.mux_idx = 0;
- spec->int_mic.pin = 0x19;
- spec->int_mic.mux_idx = 1;
- spec->auto_mic = 1;
-}
-
-/* ***************** Mode8 ******************************/
-static void alc663_mode8_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- spec->autocfg.hp_pins[0] = 0x21;
- spec->autocfg.hp_pins[1] = 0x15;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->autocfg.speaker_pins[0] = 0x17;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_PIN;
- spec->ext_mic.pin = 0x18;
- spec->ext_mic.mux_idx = 0;
- spec->int_mic.pin = 0x12;
- spec->int_mic.mux_idx = 9;
- spec->auto_mic = 1;
-}
-
-static void alc663_g71v_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- spec->autocfg.hp_pins[0] = 0x21;
- spec->autocfg.line_out_pins[0] = 0x15;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
- spec->detect_line = 1;
- spec->automute_lines = 1;
- spec->ext_mic.pin = 0x18;
- spec->ext_mic.mux_idx = 0;
- spec->int_mic.pin = 0x12;
- spec->int_mic.mux_idx = 9;
- spec->auto_mic = 1;
-}
-
-#define alc663_g50v_setup alc663_m51va_setup
-
-static const struct snd_kcontrol_new alc662_ecs_mixer[] = {
- HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
- ALC262_HIPPO_MASTER_SWITCH,
-
- 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("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 */
-};
-
-static const struct snd_kcontrol_new alc272_nc10_mixer[] = {
- /* Master Playback automatically created from Speaker and Headphone */
- HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
- 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", 0x21, 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 Volume", 0x18, 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 */
-};
-
#ifdef CONFIG_SND_HDA_POWER_SAVE
#define alc662_loopbacks alc880_loopbacks
#endif
-
-/* pcm configuration: identical with ALC880 */
-#define alc662_pcm_analog_playback alc880_pcm_analog_playback
-#define alc662_pcm_analog_capture alc880_pcm_analog_capture
-#define alc662_pcm_digital_playback alc880_pcm_digital_playback
-#define alc662_pcm_digital_capture alc880_pcm_digital_capture
-
-/*
- * configuration and preset
- */
-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",
- [ALC662_5ST_DIG] = "5stack-dig",
- [ALC662_LENOVO_101E] = "lenovo-101e",
- [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
- [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
- [ALC662_ECS] = "ecs",
- [ALC663_ASUS_M51VA] = "m51va",
- [ALC663_ASUS_G71V] = "g71v",
- [ALC663_ASUS_H13] = "h13",
- [ALC663_ASUS_G50V] = "g50v",
- [ALC663_ASUS_MODE1] = "asus-mode1",
- [ALC662_ASUS_MODE2] = "asus-mode2",
- [ALC663_ASUS_MODE3] = "asus-mode3",
- [ALC663_ASUS_MODE4] = "asus-mode4",
- [ALC663_ASUS_MODE5] = "asus-mode5",
- [ALC663_ASUS_MODE6] = "asus-mode6",
- [ALC663_ASUS_MODE7] = "asus-mode7",
- [ALC663_ASUS_MODE8] = "asus-mode8",
- [ALC272_DELL] = "dell",
- [ALC272_DELL_ZM1] = "dell-zm1",
- [ALC272_SAMSUNG_NC10] = "samsung-nc10",
- [ALC662_AUTO] = "auto",
-};
-
-static const struct snd_pci_quirk alc662_cfg_tbl[] = {
- SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
- SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL),
- SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1),
- SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
- SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC663_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
- SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
- SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC663_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC663_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
- SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC663_ASUS_MODE7),
- SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC663_ASUS_MODE7),
- SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC663_ASUS_MODE8),
- SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC663_ASUS_MODE3),
- SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC663_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
- SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_ASUS_MODE2),
- SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC663_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
- SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
- SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
- SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
- SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC663_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3),
- SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA),
- SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2),
- SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
- SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
- SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
- SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
- SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC663_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
- SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
- SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
- /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/
- SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
- SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
- SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC663_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
- SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
- SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC663_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
- SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC663_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
- /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/
- SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
- SND_PCI_QUIRK(0x1043, 0x19d3, "ASUS NB", ALC663_ASUS_M51VA),
- SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
- SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
- SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
- SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
- SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
- SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
- SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
- ALC662_3ST_6ch_DIG),
- SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB20x", ALC662_AUTO),
- SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10),
- SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
- ALC662_3ST_6ch_DIG),
- SND_PCI_QUIRK(0x152d, 0x2304, "Quanta WH1", ALC663_ASUS_H13),
- SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
- SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA),
- SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
- SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
- 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),
- {}
-};
-
-static const struct alc_config_preset alc662_presets[] = {
- [ALC662_3ST_2ch_DIG] = {
- .mixers = { alc662_3ST_2ch_mixer },
- .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
- .num_dacs = ARRAY_SIZE(alc662_dac_nids),
- .dac_nids = alc662_dac_nids,
- .dig_out_nid = ALC662_DIGOUT_NID,
- .dig_in_nid = ALC662_DIGIN_NID,
- .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
- .channel_mode = alc662_3ST_2ch_modes,
- .input_mux = &alc662_capture_source,
- },
- [ALC662_3ST_6ch_DIG] = {
- .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
- .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
- .num_dacs = ARRAY_SIZE(alc662_dac_nids),
- .dac_nids = alc662_dac_nids,
- .dig_out_nid = ALC662_DIGOUT_NID,
- .dig_in_nid = ALC662_DIGIN_NID,
- .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
- .channel_mode = alc662_3ST_6ch_modes,
- .need_dac_fix = 1,
- .input_mux = &alc662_capture_source,
- },
- [ALC662_3ST_6ch] = {
- .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
- .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
- .num_dacs = ARRAY_SIZE(alc662_dac_nids),
- .dac_nids = alc662_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
- .channel_mode = alc662_3ST_6ch_modes,
- .need_dac_fix = 1,
- .input_mux = &alc662_capture_source,
- },
- [ALC662_5ST_DIG] = {
- .mixers = { alc662_base_mixer, alc662_chmode_mixer },
- .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
- .num_dacs = ARRAY_SIZE(alc662_dac_nids),
- .dac_nids = alc662_dac_nids,
- .dig_out_nid = ALC662_DIGOUT_NID,
- .dig_in_nid = ALC662_DIGIN_NID,
- .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
- .channel_mode = alc662_5stack_modes,
- .input_mux = &alc662_capture_source,
- },
- [ALC662_LENOVO_101E] = {
- .mixers = { alc662_lenovo_101e_mixer },
- .init_verbs = { alc662_init_verbs,
- alc662_eapd_init_verbs,
- alc662_sue_init_verbs },
- .num_dacs = ARRAY_SIZE(alc662_dac_nids),
- .dac_nids = alc662_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
- .channel_mode = alc662_3ST_2ch_modes,
- .input_mux = &alc662_lenovo_101e_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc662_lenovo_101e_setup,
- .init_hook = alc_inithook,
- },
- [ALC662_ASUS_EEEPC_P701] = {
- .mixers = { alc662_eeepc_p701_mixer },
- .init_verbs = { alc662_init_verbs,
- alc662_eapd_init_verbs,
- alc662_eeepc_sue_init_verbs },
- .num_dacs = ARRAY_SIZE(alc662_dac_nids),
- .dac_nids = alc662_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
- .channel_mode = alc662_3ST_2ch_modes,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc662_eeepc_setup,
- .init_hook = alc_inithook,
- },
- [ALC662_ASUS_EEEPC_EP20] = {
- .mixers = { alc662_eeepc_ep20_mixer,
- alc662_chmode_mixer },
- .init_verbs = { alc662_init_verbs,
- alc662_eapd_init_verbs,
- alc662_eeepc_ep20_sue_init_verbs },
- .num_dacs = ARRAY_SIZE(alc662_dac_nids),
- .dac_nids = alc662_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
- .channel_mode = alc662_3ST_6ch_modes,
- .input_mux = &alc662_lenovo_101e_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc662_eeepc_ep20_setup,
- .init_hook = alc_inithook,
- },
- [ALC662_ECS] = {
- .mixers = { alc662_ecs_mixer },
- .init_verbs = { alc662_init_verbs,
- alc662_eapd_init_verbs,
- alc662_ecs_init_verbs },
- .num_dacs = ARRAY_SIZE(alc662_dac_nids),
- .dac_nids = alc662_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
- .channel_mode = alc662_3ST_2ch_modes,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc662_eeepc_setup,
- .init_hook = alc_inithook,
- },
- [ALC663_ASUS_M51VA] = {
- .mixers = { alc663_m51va_mixer },
- .init_verbs = { alc662_init_verbs,
- alc662_eapd_init_verbs,
- alc663_m51va_init_verbs },
- .num_dacs = ARRAY_SIZE(alc662_dac_nids),
- .dac_nids = alc662_dac_nids,
- .dig_out_nid = ALC662_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
- .channel_mode = alc662_3ST_2ch_modes,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc663_m51va_setup,
- .init_hook = alc_inithook,
- },
- [ALC663_ASUS_G71V] = {
- .mixers = { alc663_g71v_mixer },
- .init_verbs = { alc662_init_verbs,
- alc662_eapd_init_verbs,
- alc663_g71v_init_verbs },
- .num_dacs = ARRAY_SIZE(alc662_dac_nids),
- .dac_nids = alc662_dac_nids,
- .dig_out_nid = ALC662_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
- .channel_mode = alc662_3ST_2ch_modes,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc663_g71v_setup,
- .init_hook = alc_inithook,
- },
- [ALC663_ASUS_H13] = {
- .mixers = { alc663_m51va_mixer },
- .init_verbs = { alc662_init_verbs,
- alc662_eapd_init_verbs,
- alc663_m51va_init_verbs },
- .num_dacs = ARRAY_SIZE(alc662_dac_nids),
- .dac_nids = alc662_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
- .channel_mode = alc662_3ST_2ch_modes,
- .setup = alc663_m51va_setup,
- .unsol_event = alc_sku_unsol_event,
- .init_hook = alc_inithook,
- },
- [ALC663_ASUS_G50V] = {
- .mixers = { alc663_g50v_mixer },
- .init_verbs = { alc662_init_verbs,
- alc662_eapd_init_verbs,
- alc663_g50v_init_verbs },
- .num_dacs = ARRAY_SIZE(alc662_dac_nids),
- .dac_nids = alc662_dac_nids,
- .dig_out_nid = ALC662_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
- .channel_mode = alc662_3ST_6ch_modes,
- .input_mux = &alc663_capture_source,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc663_g50v_setup,
- .init_hook = alc_inithook,
- },
- [ALC663_ASUS_MODE1] = {
- .mixers = { alc663_m51va_mixer },
- .cap_mixer = alc662_auto_capture_mixer,
- .init_verbs = { alc662_init_verbs,
- alc662_eapd_init_verbs,
- alc663_21jd_amic_init_verbs },
- .num_dacs = ARRAY_SIZE(alc662_dac_nids),
- .hp_nid = 0x03,
- .dac_nids = alc662_dac_nids,
- .dig_out_nid = ALC662_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
- .channel_mode = alc662_3ST_2ch_modes,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc663_mode1_setup,
- .init_hook = alc_inithook,
- },
- [ALC662_ASUS_MODE2] = {
- .mixers = { alc662_1bjd_mixer },
- .cap_mixer = alc662_auto_capture_mixer,
- .init_verbs = { alc662_init_verbs,
- alc662_eapd_init_verbs,
- alc662_1bjd_amic_init_verbs },
- .num_dacs = ARRAY_SIZE(alc662_dac_nids),
- .dac_nids = alc662_dac_nids,
- .dig_out_nid = ALC662_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
- .channel_mode = alc662_3ST_2ch_modes,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc662_mode2_setup,
- .init_hook = alc_inithook,
- },
- [ALC663_ASUS_MODE3] = {
- .mixers = { alc663_two_hp_m1_mixer },
- .cap_mixer = alc662_auto_capture_mixer,
- .init_verbs = { alc662_init_verbs,
- alc662_eapd_init_verbs,
- alc663_two_hp_amic_m1_init_verbs },
- .num_dacs = ARRAY_SIZE(alc662_dac_nids),
- .hp_nid = 0x03,
- .dac_nids = alc662_dac_nids,
- .dig_out_nid = ALC662_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
- .channel_mode = alc662_3ST_2ch_modes,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc663_mode3_setup,
- .init_hook = alc_inithook,
- },
- [ALC663_ASUS_MODE4] = {
- .mixers = { alc663_asus_21jd_clfe_mixer },
- .cap_mixer = alc662_auto_capture_mixer,
- .init_verbs = { alc662_init_verbs,
- alc662_eapd_init_verbs,
- alc663_21jd_amic_init_verbs},
- .num_dacs = ARRAY_SIZE(alc662_dac_nids),
- .hp_nid = 0x03,
- .dac_nids = alc662_dac_nids,
- .dig_out_nid = ALC662_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
- .channel_mode = alc662_3ST_2ch_modes,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc663_mode4_setup,
- .init_hook = alc_inithook,
- },
- [ALC663_ASUS_MODE5] = {
- .mixers = { alc663_asus_15jd_clfe_mixer },
- .cap_mixer = alc662_auto_capture_mixer,
- .init_verbs = { alc662_init_verbs,
- alc662_eapd_init_verbs,
- alc663_15jd_amic_init_verbs },
- .num_dacs = ARRAY_SIZE(alc662_dac_nids),
- .hp_nid = 0x03,
- .dac_nids = alc662_dac_nids,
- .dig_out_nid = ALC662_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
- .channel_mode = alc662_3ST_2ch_modes,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc663_mode5_setup,
- .init_hook = alc_inithook,
- },
- [ALC663_ASUS_MODE6] = {
- .mixers = { alc663_two_hp_m2_mixer },
- .cap_mixer = alc662_auto_capture_mixer,
- .init_verbs = { alc662_init_verbs,
- alc662_eapd_init_verbs,
- alc663_two_hp_amic_m2_init_verbs },
- .num_dacs = ARRAY_SIZE(alc662_dac_nids),
- .hp_nid = 0x03,
- .dac_nids = alc662_dac_nids,
- .dig_out_nid = ALC662_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
- .channel_mode = alc662_3ST_2ch_modes,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc663_mode6_setup,
- .init_hook = alc_inithook,
- },
- [ALC663_ASUS_MODE7] = {
- .mixers = { alc663_mode7_mixer },
- .cap_mixer = alc662_auto_capture_mixer,
- .init_verbs = { alc662_init_verbs,
- alc662_eapd_init_verbs,
- alc663_mode7_init_verbs },
- .num_dacs = ARRAY_SIZE(alc662_dac_nids),
- .hp_nid = 0x03,
- .dac_nids = alc662_dac_nids,
- .dig_out_nid = ALC662_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
- .channel_mode = alc662_3ST_2ch_modes,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc663_mode7_setup,
- .init_hook = alc_inithook,
- },
- [ALC663_ASUS_MODE8] = {
- .mixers = { alc663_mode8_mixer },
- .cap_mixer = alc662_auto_capture_mixer,
- .init_verbs = { alc662_init_verbs,
- alc662_eapd_init_verbs,
- alc663_mode8_init_verbs },
- .num_dacs = ARRAY_SIZE(alc662_dac_nids),
- .hp_nid = 0x03,
- .dac_nids = alc662_dac_nids,
- .dig_out_nid = ALC662_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
- .channel_mode = alc662_3ST_2ch_modes,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc663_mode8_setup,
- .init_hook = alc_inithook,
- },
- [ALC272_DELL] = {
- .mixers = { alc663_m51va_mixer },
- .cap_mixer = alc272_auto_capture_mixer,
- .init_verbs = { alc662_init_verbs,
- alc662_eapd_init_verbs,
- alc272_dell_init_verbs },
- .num_dacs = ARRAY_SIZE(alc272_dac_nids),
- .dac_nids = alc272_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
- .adc_nids = alc272_adc_nids,
- .num_adc_nids = ARRAY_SIZE(alc272_adc_nids),
- .capsrc_nids = alc272_capsrc_nids,
- .channel_mode = alc662_3ST_2ch_modes,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc663_m51va_setup,
- .init_hook = alc_inithook,
- },
- [ALC272_DELL_ZM1] = {
- .mixers = { alc663_m51va_mixer },
- .cap_mixer = alc662_auto_capture_mixer,
- .init_verbs = { alc662_init_verbs,
- alc662_eapd_init_verbs,
- alc272_dell_zm1_init_verbs },
- .num_dacs = ARRAY_SIZE(alc272_dac_nids),
- .dac_nids = alc272_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
- .adc_nids = alc662_adc_nids,
- .num_adc_nids = 1,
- .capsrc_nids = alc662_capsrc_nids,
- .channel_mode = alc662_3ST_2ch_modes,
- .unsol_event = alc_sku_unsol_event,
- .setup = alc663_m51va_setup,
- .init_hook = alc_inithook,
- },
- [ALC272_SAMSUNG_NC10] = {
- .mixers = { alc272_nc10_mixer },
- .init_verbs = { alc662_init_verbs,
- alc662_eapd_init_verbs,
- alc663_21jd_amic_init_verbs },
- .num_dacs = ARRAY_SIZE(alc272_dac_nids),
- .dac_nids = alc272_dac_nids,
- .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
- .channel_mode = alc662_3ST_2ch_modes,
- /*.input_mux = &alc272_nc10_capture_source,*/
- .unsol_event = alc_sku_unsol_event,
- .setup = alc663_mode4_setup,
- .init_hook = alc_inithook,
- },
-};
-
-
/*
* BIOS auto configuration
*/
-/* convert from MIX nid to DAC */
-static hda_nid_t alc_auto_mix_to_dac(struct hda_codec *codec, hda_nid_t nid)
-{
- hda_nid_t list[5];
- int i, num;
-
- num = snd_hda_get_connections(codec, nid, list, ARRAY_SIZE(list));
- for (i = 0; i < num; i++) {
- if (get_wcaps_type(get_wcaps(codec, list[i])) == AC_WID_AUD_OUT)
- return list[i];
- }
- return 0;
-}
-
-/* go down to the selector widget before the mixer */
-static hda_nid_t alc_go_down_to_selector(struct hda_codec *codec, hda_nid_t pin)
-{
- hda_nid_t srcs[5];
- int num = snd_hda_get_connections(codec, pin, srcs,
- ARRAY_SIZE(srcs));
- if (num != 1 ||
- get_wcaps_type(get_wcaps(codec, srcs[0])) != AC_WID_AUD_SEL)
- return pin;
- return srcs[0];
-}
-
-/* get MIX nid connected to the given pin targeted to DAC */
-static hda_nid_t alc_auto_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
- hda_nid_t dac)
-{
- hda_nid_t mix[5];
- int i, num;
-
- pin = alc_go_down_to_selector(codec, pin);
- num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
- for (i = 0; i < num; i++) {
- if (alc_auto_mix_to_dac(codec, mix[i]) == dac)
- return mix[i];
- }
- return 0;
-}
-
-/* select the connection from pin to DAC if needed */
-static int alc_auto_select_dac(struct hda_codec *codec, hda_nid_t pin,
- hda_nid_t dac)
-{
- hda_nid_t mix[5];
- int i, num;
-
- pin = alc_go_down_to_selector(codec, pin);
- num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
- if (num < 2)
- return 0;
- for (i = 0; i < num; i++) {
- if (alc_auto_mix_to_dac(codec, mix[i]) == dac) {
- snd_hda_codec_update_cache(codec, pin, 0,
- AC_VERB_SET_CONNECT_SEL, i);
- return 0;
- }
- }
- return 0;
-}
-
-/* look for an empty DAC slot */
-static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
-{
- struct alc_spec *spec = codec->spec;
- hda_nid_t srcs[5];
- int i, j, num;
-
- pin = alc_go_down_to_selector(codec, pin);
- num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
- for (i = 0; i < num; i++) {
- hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]);
- if (!nid)
- continue;
- for (j = 0; j < spec->multiout.num_dacs; j++)
- if (spec->multiout.dac_nids[j] == nid)
- break;
- if (j >= spec->multiout.num_dacs)
- return nid;
- }
- return 0;
-}
-
-/* fill in the dac_nids table from the parsed pin configuration */
-static int alc662_auto_fill_dac_nids(struct hda_codec *codec,
- const struct auto_pin_cfg *cfg)
-{
- struct alc_spec *spec = codec->spec;
- int i;
- hda_nid_t dac;
-
- spec->multiout.dac_nids = spec->private_dac_nids;
- for (i = 0; i < cfg->line_outs; i++) {
- dac = alc_auto_look_for_dac(codec, cfg->line_out_pins[i]);
- if (!dac)
- continue;
- spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
- }
- return 0;
-}
-
-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, 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, int idx, unsigned int chs)
-{
- 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) \
- alc662_add_sw_ctl(spec, pfx, nid, 3)
-
-/* add playback controls from the parsed DAC table */
-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 * const chname[4] = {
- "Front", "Surround", NULL /*CLFE*/, "Side"
- };
- const char *pfx = alc_get_line_out_pfx(spec, true);
- hda_nid_t nid, mix, pin;
- int i, err, noutputs;
-
- noutputs = cfg->line_outs;
- if (spec->multi_ios > 0)
- noutputs += spec->multi_ios;
-
- for (i = 0; i < noutputs; i++) {
- nid = spec->multiout.dac_nids[i];
- if (!nid)
- continue;
- if (i >= cfg->line_outs)
- pin = spec->multi_io[i - 1].pin;
- else
- pin = cfg->line_out_pins[i];
- mix = alc_auto_dac_to_mix(codec, pin, nid);
- if (!mix)
- continue;
- if (!pfx && i == 2) {
- /* Center/LFE */
- err = alc662_add_vol_ctl(spec, "Center", nid, 1);
- if (err < 0)
- return err;
- err = alc662_add_vol_ctl(spec, "LFE", nid, 2);
- if (err < 0)
- return err;
- err = alc662_add_sw_ctl(spec, "Center", mix, 1);
- if (err < 0)
- return err;
- err = alc662_add_sw_ctl(spec, "LFE", mix, 2);
- if (err < 0)
- return err;
- } else {
- const char *name = pfx;
- int index = i;
- if (!name) {
- name = chname[i];
- index = 0;
- }
- err = __alc662_add_vol_ctl(spec, name, nid, index, 3);
- if (err < 0)
- return err;
- err = __alc662_add_sw_ctl(spec, name, mix, index, 3);
- if (err < 0)
- return err;
- }
- }
- return 0;
-}
-
-/* add playback controls for speaker and HP outputs */
-/* return DAC nid if any new DAC is assigned */
-static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
- const char *pfx)
-{
- struct alc_spec *spec = codec->spec;
- hda_nid_t nid, mix;
- int err;
-
- if (!pin)
- return 0;
- nid = alc_auto_look_for_dac(codec, pin);
- if (!nid) {
- /* the corresponding DAC is already occupied */
- if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
- return 0; /* no way */
- /* create a switch only */
- return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
- HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
- }
-
- mix = alc_auto_dac_to_mix(codec, pin, nid);
- if (!mix)
- return 0;
- err = alc662_add_vol_ctl(spec, pfx, nid, 3);
- if (err < 0)
- return err;
- err = alc662_add_sw_ctl(spec, pfx, mix, 3);
- if (err < 0)
- return err;
- return nid;
-}
-
-/* create playback/capture controls for input pins */
-#define alc662_auto_create_input_ctls \
- alc882_auto_create_input_ctls
-
-static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
- hda_nid_t nid, int pin_type,
- hda_nid_t dac)
-{
- int i, num;
- hda_nid_t srcs[HDA_MAX_CONNECTIONS];
-
- alc_set_pin_output(codec, nid, pin_type);
- num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
- for (i = 0; i < num; i++) {
- if (alc_auto_mix_to_dac(codec, srcs[i]) != dac)
- continue;
- /* need the manual connection? */
- if (num > 1)
- snd_hda_codec_write(codec, nid, 0,
- AC_VERB_SET_CONNECT_SEL, i);
- /* unmute mixer widget inputs */
- snd_hda_codec_write(codec, srcs[i], 0,
- AC_VERB_SET_AMP_GAIN_MUTE,
- AMP_IN_UNMUTE(0));
- snd_hda_codec_write(codec, srcs[i], 0,
- AC_VERB_SET_AMP_GAIN_MUTE,
- AMP_IN_UNMUTE(1));
- return;
- }
-}
-
-static void alc662_auto_init_multi_out(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- int pin_type = get_pin_type(spec->autocfg.line_out_type);
- int i;
-
- for (i = 0; i <= HDA_SIDE; i++) {
- hda_nid_t nid = spec->autocfg.line_out_pins[i];
- if (nid)
- alc662_auto_set_output_and_unmute(codec, nid, pin_type,
- spec->multiout.dac_nids[i]);
- }
-}
-
-static void alc662_auto_init_hp_out(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- hda_nid_t pin;
-
- pin = spec->autocfg.hp_pins[0];
- if (pin)
- alc662_auto_set_output_and_unmute(codec, pin, PIN_HP,
- spec->multiout.hp_nid);
- pin = spec->autocfg.speaker_pins[0];
- if (pin)
- alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT,
- spec->multiout.extra_out_nid[0]);
-}
-
-#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
-
-static void alc662_auto_init_analog_input(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- struct auto_pin_cfg *cfg = &spec->autocfg;
- int i;
-
- for (i = 0; i < cfg->num_inputs; i++) {
- hda_nid_t nid = cfg->inputs[i].pin;
- if (alc_is_input_pin(codec, nid)) {
- alc_set_input_pin(codec, nid, cfg->inputs[i].type);
- if (nid != ALC662_PIN_CD_NID &&
- (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
- snd_hda_codec_write(codec, nid, 0,
- AC_VERB_SET_AMP_GAIN_MUTE,
- AMP_OUT_MUTE);
- }
- }
-}
-
-#define alc662_auto_init_input_src alc882_auto_init_input_src
-
-/*
- * multi-io helper
- */
-static int alc_auto_fill_multi_ios(struct hda_codec *codec,
- unsigned int location)
-{
- struct alc_spec *spec = codec->spec;
- struct auto_pin_cfg *cfg = &spec->autocfg;
- int type, i, num_pins = 0;
-
- for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
- for (i = 0; i < cfg->num_inputs; i++) {
- hda_nid_t nid = cfg->inputs[i].pin;
- hda_nid_t dac;
- unsigned int defcfg, caps;
- if (cfg->inputs[i].type != type)
- continue;
- defcfg = snd_hda_codec_get_pincfg(codec, nid);
- if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX)
- continue;
- if (location && get_defcfg_location(defcfg) != location)
- continue;
- caps = snd_hda_query_pin_caps(codec, nid);
- if (!(caps & AC_PINCAP_OUT))
- continue;
- dac = alc_auto_look_for_dac(codec, nid);
- if (!dac)
- continue;
- spec->multi_io[num_pins].pin = nid;
- spec->multi_io[num_pins].dac = dac;
- num_pins++;
- spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
- }
- }
- spec->multiout.num_dacs = 1;
- if (num_pins < 2)
- return 0;
- return num_pins;
-}
-
-static int alc_auto_ch_mode_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct alc_spec *spec = codec->spec;
-
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = spec->multi_ios + 1;
- if (uinfo->value.enumerated.item > spec->multi_ios)
- uinfo->value.enumerated.item = spec->multi_ios;
- sprintf(uinfo->value.enumerated.name, "%dch",
- (uinfo->value.enumerated.item + 1) * 2);
- return 0;
-}
-
-static int alc_auto_ch_mode_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct alc_spec *spec = codec->spec;
- ucontrol->value.enumerated.item[0] = (spec->ext_channel_count - 1) / 2;
- return 0;
-}
-
-static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output)
-{
- struct alc_spec *spec = codec->spec;
- hda_nid_t nid = spec->multi_io[idx].pin;
-
- if (!spec->multi_io[idx].ctl_in)
- spec->multi_io[idx].ctl_in =
- snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
- if (output) {
- snd_hda_codec_update_cache(codec, nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
- PIN_OUT);
- if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
- snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
- HDA_AMP_MUTE, 0);
- alc_auto_select_dac(codec, nid, spec->multi_io[idx].dac);
- } else {
- if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
- snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
- HDA_AMP_MUTE, HDA_AMP_MUTE);
- snd_hda_codec_update_cache(codec, nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
- spec->multi_io[idx].ctl_in);
- }
- return 0;
-}
-
-static int alc_auto_ch_mode_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct alc_spec *spec = codec->spec;
- int i, ch;
-
- ch = ucontrol->value.enumerated.item[0];
- if (ch < 0 || ch > spec->multi_ios)
- return -EINVAL;
- if (ch == (spec->ext_channel_count - 1) / 2)
- return 0;
- spec->ext_channel_count = (ch + 1) * 2;
- for (i = 0; i < spec->multi_ios; i++)
- alc_set_multi_io(codec, i, i < ch);
- spec->multiout.max_channels = spec->ext_channel_count;
- return 1;
-}
-
-static const struct snd_kcontrol_new alc_auto_channel_mode_enum = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Channel Mode",
- .info = alc_auto_ch_mode_info,
- .get = alc_auto_ch_mode_get,
- .put = alc_auto_ch_mode_put,
-};
-
-static int alc_auto_add_multi_channel_mode(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- struct auto_pin_cfg *cfg = &spec->autocfg;
- unsigned int location, defcfg;
- int num_pins;
-
- if (cfg->line_outs != 1 ||
- cfg->line_out_type != AUTO_PIN_LINE_OUT)
- return 0;
-
- defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]);
- location = get_defcfg_location(defcfg);
-
- num_pins = alc_auto_fill_multi_ios(codec, location);
- if (num_pins > 0) {
- struct snd_kcontrol_new *knew;
-
- knew = alc_kcontrol_new(spec);
- if (!knew)
- return -ENOMEM;
- *knew = alc_auto_channel_mode_enum;
- knew->name = kstrdup("Channel Mode", GFP_KERNEL);
- if (!knew->name)
- return -ENOMEM;
-
- spec->multi_ios = num_pins;
- spec->ext_channel_count = 2;
- spec->multiout.num_dacs = num_pins + 1;
- }
- return 0;
-}
-
static int alc662_parse_auto_config(struct hda_codec *codec)
{
- struct alc_spec *spec = codec->spec;
- int err;
static const hda_nid_t alc662_ignore[] = { 0x1d, 0 };
-
- err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
- alc662_ignore);
- if (err < 0)
- return err;
- if (!spec->autocfg.line_outs)
- return 0; /* can't find valid BIOS pin config */
-
- err = alc662_auto_fill_dac_nids(codec, &spec->autocfg);
- if (err < 0)
- return err;
- err = alc_auto_add_multi_channel_mode(codec);
- if (err < 0)
- return err;
- err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg);
- if (err < 0)
- return err;
- err = alc662_auto_create_extra_out(codec,
- spec->autocfg.speaker_pins[0],
- "Speaker");
- if (err < 0)
- return err;
- if (err)
- spec->multiout.extra_out_nid[0] = err;
- err = alc662_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
- "Headphone");
- if (err < 0)
- return err;
- if (err)
- spec->multiout.hp_nid = err;
- err = alc662_auto_create_input_ctls(codec, &spec->autocfg);
- if (err < 0)
- return err;
-
- spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-
- alc_auto_parse_digital(codec);
-
- if (spec->kctls.list)
- add_mixer(spec, spec->kctls.list);
-
- spec->num_mux_defs = 1;
- spec->input_mux = &spec->private_imux[0];
-
- err = alc_auto_add_mic_boost(codec);
- if (err < 0)
- return err;
+ static const hda_nid_t alc663_ssids[] = { 0x15, 0x1b, 0x14, 0x21 };
+ static const hda_nid_t alc662_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+ const hda_nid_t *ssids;
if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
- codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
- alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0x21);
+ codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670 ||
+ codec->vendor_id == 0x10ec0671)
+ ssids = alc663_ssids;
else
- alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
-
- return 1;
-}
-
-/* additional initialization for auto-configuration model */
-static void alc662_auto_init(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- alc662_auto_init_multi_out(codec);
- alc662_auto_init_hp_out(codec);
- alc662_auto_init_analog_input(codec);
- alc662_auto_init_input_src(codec);
- alc_auto_init_digital(codec);
- if (spec->unsol_event)
- alc_inithook(codec);
+ ssids = alc662_ssids;
+ return alc_parse_auto_config(codec, alc662_ignore, ssids);
}
static void alc272_fixup_mario(struct hda_codec *codec,
@@ -19481,6 +5645,17 @@ enum {
ALC272_FIXUP_MARIO,
ALC662_FIXUP_CZC_P10T,
ALC662_FIXUP_SKU_IGNORE,
+ ALC662_FIXUP_HP_RP5800,
+ ALC662_FIXUP_ASUS_MODE1,
+ ALC662_FIXUP_ASUS_MODE2,
+ ALC662_FIXUP_ASUS_MODE3,
+ ALC662_FIXUP_ASUS_MODE4,
+ ALC662_FIXUP_ASUS_MODE5,
+ ALC662_FIXUP_ASUS_MODE6,
+ ALC662_FIXUP_ASUS_MODE7,
+ ALC662_FIXUP_ASUS_MODE8,
+ ALC662_FIXUP_NO_JACK_DETECT,
+ ALC662_FIXUP_ZOTAC_Z68,
};
static const struct alc_fixup alc662_fixups[] = {
@@ -19513,30 +5688,228 @@ static const struct alc_fixup alc662_fixups[] = {
.type = ALC_FIXUP_SKU,
.v.sku = ALC_FIXUP_SKU_IGNORE,
},
+ [ALC662_FIXUP_HP_RP5800] = {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
+ { 0x14, 0x0221201f }, /* HP out */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC662_FIXUP_SKU_IGNORE
+ },
+ [ALC662_FIXUP_ASUS_MODE1] = {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
+ { 0x14, 0x99130110 }, /* speaker */
+ { 0x18, 0x01a19c20 }, /* mic */
+ { 0x19, 0x99a3092f }, /* int-mic */
+ { 0x21, 0x0121401f }, /* HP out */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC662_FIXUP_SKU_IGNORE
+ },
+ [ALC662_FIXUP_ASUS_MODE2] = {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
+ { 0x14, 0x99130110 }, /* speaker */
+ { 0x18, 0x01a19820 }, /* mic */
+ { 0x19, 0x99a3092f }, /* int-mic */
+ { 0x1b, 0x0121401f }, /* HP out */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC662_FIXUP_SKU_IGNORE
+ },
+ [ALC662_FIXUP_ASUS_MODE3] = {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
+ { 0x14, 0x99130110 }, /* speaker */
+ { 0x15, 0x0121441f }, /* HP */
+ { 0x18, 0x01a19840 }, /* mic */
+ { 0x19, 0x99a3094f }, /* int-mic */
+ { 0x21, 0x01211420 }, /* HP2 */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC662_FIXUP_SKU_IGNORE
+ },
+ [ALC662_FIXUP_ASUS_MODE4] = {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
+ { 0x14, 0x99130110 }, /* speaker */
+ { 0x16, 0x99130111 }, /* speaker */
+ { 0x18, 0x01a19840 }, /* mic */
+ { 0x19, 0x99a3094f }, /* int-mic */
+ { 0x21, 0x0121441f }, /* HP */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC662_FIXUP_SKU_IGNORE
+ },
+ [ALC662_FIXUP_ASUS_MODE5] = {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
+ { 0x14, 0x99130110 }, /* speaker */
+ { 0x15, 0x0121441f }, /* HP */
+ { 0x16, 0x99130111 }, /* speaker */
+ { 0x18, 0x01a19840 }, /* mic */
+ { 0x19, 0x99a3094f }, /* int-mic */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC662_FIXUP_SKU_IGNORE
+ },
+ [ALC662_FIXUP_ASUS_MODE6] = {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
+ { 0x14, 0x99130110 }, /* speaker */
+ { 0x15, 0x01211420 }, /* HP2 */
+ { 0x18, 0x01a19840 }, /* mic */
+ { 0x19, 0x99a3094f }, /* int-mic */
+ { 0x1b, 0x0121441f }, /* HP */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC662_FIXUP_SKU_IGNORE
+ },
+ [ALC662_FIXUP_ASUS_MODE7] = {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
+ { 0x14, 0x99130110 }, /* speaker */
+ { 0x17, 0x99130111 }, /* speaker */
+ { 0x18, 0x01a19840 }, /* mic */
+ { 0x19, 0x99a3094f }, /* int-mic */
+ { 0x1b, 0x01214020 }, /* HP */
+ { 0x21, 0x0121401f }, /* HP */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC662_FIXUP_SKU_IGNORE
+ },
+ [ALC662_FIXUP_ASUS_MODE8] = {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
+ { 0x14, 0x99130110 }, /* speaker */
+ { 0x12, 0x99a30970 }, /* int-mic */
+ { 0x15, 0x01214020 }, /* HP */
+ { 0x17, 0x99130111 }, /* speaker */
+ { 0x18, 0x01a19840 }, /* mic */
+ { 0x21, 0x0121401f }, /* HP */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC662_FIXUP_SKU_IGNORE
+ },
+ [ALC662_FIXUP_NO_JACK_DETECT] = {
+ .type = ALC_FIXUP_FUNC,
+ .v.func = alc_fixup_no_jack_detect,
+ },
+ [ALC662_FIXUP_ZOTAC_Z68] = {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
+ { 0x1b, 0x02214020 }, /* Front HP */
+ { }
+ }
+ },
};
static const struct snd_pci_quirk alc662_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2),
SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
+ SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
+ SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_ASUS_MODE4),
+ SND_PCI_QUIRK(0x1043, 0x1bf3, "ASUS N76VZ", ALC662_FIXUP_ASUS_MODE4),
+ SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT),
+ SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2),
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(0x19da, 0xa130, "Zotac Z68", ALC662_FIXUP_ZOTAC_Z68),
SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T),
+
+#if 0
+ /* Below is a quirk table taken from the old code.
+ * Basically the device should work as is without the fixup table.
+ * If BIOS doesn't give a proper info, enable the corresponding
+ * fixup entry.
+ */
+ SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC662_FIXUP_ASUS_MODE3),
+ SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC662_FIXUP_ASUS_MODE3),
+ SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+ SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+ SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC662_FIXUP_ASUS_MODE7),
+ SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC662_FIXUP_ASUS_MODE7),
+ SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC662_FIXUP_ASUS_MODE8),
+ SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC662_FIXUP_ASUS_MODE3),
+ SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+ SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_FIXUP_ASUS_MODE2),
+ SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+ SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
+ SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
+ SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+ SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC662_FIXUP_ASUS_MODE3),
+ SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_FIXUP_ASUS_MODE2),
+ SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+ SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC662_FIXUP_ASUS_MODE5),
+ SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
+ SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+ SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+ SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+ SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC662_FIXUP_ASUS_MODE3),
+ SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC662_FIXUP_ASUS_MODE3),
+ SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+ SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_FIXUP_ASUS_MODE2),
+ SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC662_FIXUP_ASUS_MODE3),
+ SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_FIXUP_ASUS_MODE2),
+ SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
+ SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC662_FIXUP_ASUS_MODE4),
+#endif
{}
};
static const struct alc_model_fixup alc662_fixup_models[] = {
{.id = ALC272_FIXUP_MARIO, .name = "mario"},
+ {.id = ALC662_FIXUP_ASUS_MODE1, .name = "asus-mode1"},
+ {.id = ALC662_FIXUP_ASUS_MODE2, .name = "asus-mode2"},
+ {.id = ALC662_FIXUP_ASUS_MODE3, .name = "asus-mode3"},
+ {.id = ALC662_FIXUP_ASUS_MODE4, .name = "asus-mode4"},
+ {.id = ALC662_FIXUP_ASUS_MODE5, .name = "asus-mode5"},
+ {.id = ALC662_FIXUP_ASUS_MODE6, .name = "asus-mode6"},
+ {.id = ALC662_FIXUP_ASUS_MODE7, .name = "asus-mode7"},
+ {.id = ALC662_FIXUP_ASUS_MODE8, .name = "asus-mode8"},
{}
};
+/*
+ */
static int patch_alc662(struct hda_codec *codec)
{
struct alc_spec *spec;
- int err, board_config;
- int coef;
+ int err = 0;
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (!spec)
@@ -19544,74 +5917,47 @@ static int patch_alc662(struct hda_codec *codec)
codec->spec = spec;
+ spec->mixer_nid = 0x0b;
+
+ /* handle multiple HPs as is */
+ spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
+
alc_auto_parse_customize_define(codec);
alc_fix_pll_init(codec, 0x20, 0x04, 15);
- coef = alc_read_coef_idx(codec, 0);
- if (coef == 0x8020 || coef == 0x8011)
- alc_codec_rename(codec, "ALC661");
- else if (coef & (1 << 14) &&
- codec->bus->pci->subsystem_vendor == 0x1025 &&
- spec->cdefine.platform_type == 1)
- alc_codec_rename(codec, "ALC272X");
- else if (coef == 0x4011)
- alc_codec_rename(codec, "ALC656");
-
- board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
- alc662_models,
- alc662_cfg_tbl);
- if (board_config < 0) {
- printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
- codec->chip_name);
- board_config = ALC662_AUTO;
- }
+ err = alc_codec_rename_from_preset(codec);
+ if (err < 0)
+ goto error;
- if (board_config == ALC662_AUTO) {
- 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) {
- alc_free(codec);
- return err;
- } else if (!err) {
- printk(KERN_INFO
- "hda_codec: Cannot set up configuration "
- "from BIOS. Using base mode...\n");
- board_config = ALC662_3ST_2ch_DIG;
- }
+ if ((alc_get_coef0(codec) & (1 << 14)) &&
+ codec->bus->pci->subsystem_vendor == 0x1025 &&
+ spec->cdefine.platform_type == 1) {
+ if (alc_codec_rename(codec, "ALC272X") < 0)
+ goto error;
}
- if (has_cdefine_beep(codec)) {
- err = snd_hda_attach_beep_device(codec, 0x1);
- if (err < 0) {
- alc_free(codec);
- return err;
- }
- }
-
- if (board_config != ALC662_AUTO)
- setup_preset(codec, &alc662_presets[board_config]);
-
- spec->stream_analog_playback = &alc662_pcm_analog_playback;
- spec->stream_analog_capture = &alc662_pcm_analog_capture;
-
- spec->stream_digital_playback = &alc662_pcm_digital_playback;
- spec->stream_digital_capture = &alc662_pcm_digital_capture;
+ 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)
+ goto error;
- if (!spec->adc_nids) {
- spec->adc_nids = alc662_adc_nids;
- spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
+ if (!spec->no_analog && !spec->adc_nids) {
+ alc_auto_fill_adc_caps(codec);
+ alc_rebuild_imux_for_auto_mic(codec);
+ alc_remove_invalid_adc_nids(codec);
}
- if (!spec->capsrc_nids)
- spec->capsrc_nids = alc662_capsrc_nids;
- if (!spec->cap_mixer)
+ if (!spec->no_analog && !spec->cap_mixer)
set_capture_mixer(codec);
- if (has_cdefine_beep(codec)) {
+ if (!spec->no_analog && has_cdefine_beep(codec)) {
+ err = snd_hda_attach_beep_device(codec, 0x1);
+ if (err < 0)
+ goto error;
switch (codec->vendor_id) {
case 0x10ec0662:
set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
@@ -19619,6 +5965,7 @@ static int patch_alc662(struct hda_codec *codec)
case 0x10ec0272:
case 0x10ec0663:
case 0x10ec0665:
+ case 0x10ec0668:
set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
break;
case 0x10ec0273:
@@ -19631,8 +5978,7 @@ static int patch_alc662(struct hda_codec *codec)
alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
codec->patch_ops = alc_patch_ops;
- if (board_config == ALC662_AUTO)
- spec->init_hook = alc662_auto_init;
+ spec->init_hook = alc_auto_init_std;
spec->shutup = alc_eapd_shutup;
alc_init_jacks(codec);
@@ -19643,425 +5989,26 @@ static int patch_alc662(struct hda_codec *codec)
#endif
return 0;
-}
-static int patch_alc888(struct hda_codec *codec)
-{
- if ((alc_read_coef_idx(codec, 0) & 0x00f0)==0x0030){
- kfree(codec->chip_name);
- if (codec->vendor_id == 0x10ec0887)
- codec->chip_name = kstrdup("ALC887-VD", GFP_KERNEL);
- else
- codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL);
- if (!codec->chip_name) {
- alc_free(codec);
- return -ENOMEM;
- }
- return patch_alc662(codec);
- }
- return patch_alc882(codec);
-}
-
-static int patch_alc899(struct hda_codec *codec)
-{
- if ((alc_read_coef_idx(codec, 0) & 0x2000) != 0x2000) {
- kfree(codec->chip_name);
- codec->chip_name = kstrdup("ALC898", GFP_KERNEL);
- }
- return patch_alc882(codec);
+ error:
+ alc_free(codec);
+ return err;
}
/*
* ALC680 support
*/
-#define ALC680_DIGIN_NID ALC880_DIGIN_NID
-#define ALC680_DIGOUT_NID ALC880_DIGOUT_NID
-#define alc680_modes alc260_modes
-
-static const hda_nid_t alc680_dac_nids[3] = {
- /* Lout1, Lout2, hp */
- 0x02, 0x03, 0x04
-};
-
-static const hda_nid_t alc680_adc_nids[3] = {
- /* ADC0-2 */
- /* DMIC, MIC, Line-in*/
- 0x07, 0x08, 0x09
-};
-
-/*
- * Analog capture ADC cgange
- */
-static void alc680_rec_autoswitch(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- struct auto_pin_cfg *cfg = &spec->autocfg;
- int pin_found = 0;
- int type_found = AUTO_PIN_LAST;
- hda_nid_t nid;
- int i;
- for (i = 0; i < cfg->num_inputs; i++) {
- nid = cfg->inputs[i].pin;
- if (!is_jack_detectable(codec, nid))
- continue;
- if (snd_hda_jack_detect(codec, nid)) {
- if (cfg->inputs[i].type < type_found) {
- type_found = cfg->inputs[i].type;
- pin_found = nid;
- }
- }
- }
-
- nid = 0x07;
- if (pin_found)
- snd_hda_get_connections(codec, pin_found, &nid, 1);
-
- if (nid != spec->cur_adc)
- __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
- spec->cur_adc = nid;
- snd_hda_codec_setup_stream(codec, nid, spec->cur_adc_stream_tag, 0,
- spec->cur_adc_format);
-}
-
-static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- unsigned int stream_tag,
- unsigned int format,
- struct snd_pcm_substream *substream)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->cur_adc = 0x07;
- spec->cur_adc_stream_tag = stream_tag;
- spec->cur_adc_format = format;
-
- alc680_rec_autoswitch(codec);
- return 0;
-}
-
-static int alc680_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- struct snd_pcm_substream *substream)
-{
- snd_hda_codec_cleanup_stream(codec, 0x07);
- snd_hda_codec_cleanup_stream(codec, 0x08);
- snd_hda_codec_cleanup_stream(codec, 0x09);
- return 0;
-}
-
-static const struct hda_pcm_stream alc680_pcm_analog_auto_capture = {
- .substreams = 1, /* can be overridden */
- .channels_min = 2,
- .channels_max = 2,
- /* NID is set in alc_build_pcms */
- .ops = {
- .prepare = alc680_capture_pcm_prepare,
- .cleanup = alc680_capture_pcm_cleanup
- },
-};
-
-static const struct snd_kcontrol_new alc680_base_mixer[] = {
- /* output mixer control */
- HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
- 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("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),
- { }
-};
-
-static const struct hda_bind_ctls alc680_bind_cap_vol = {
- .ops = &snd_hda_bind_vol,
- .values = {
- HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
- HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
- HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
- 0
- },
-};
-
-static const struct hda_bind_ctls alc680_bind_cap_switch = {
- .ops = &snd_hda_bind_sw,
- .values = {
- HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
- HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
- HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
- 0
- },
-};
-
-static const struct snd_kcontrol_new alc680_master_capture_mixer[] = {
- HDA_BIND_VOL("Capture Volume", &alc680_bind_cap_vol),
- HDA_BIND_SW("Capture Switch", &alc680_bind_cap_switch),
- { } /* end */
-};
-
-/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static const struct hda_verb alc680_init_verbs[] = {
- {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
- {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-
- {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
- {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
-
- { }
-};
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc680_base_setup(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
-
- spec->autocfg.hp_pins[0] = 0x16;
- spec->autocfg.speaker_pins[0] = 0x14;
- spec->autocfg.speaker_pins[1] = 0x15;
- spec->autocfg.num_inputs = 2;
- spec->autocfg.inputs[0].pin = 0x18;
- spec->autocfg.inputs[0].type = AUTO_PIN_MIC;
- spec->autocfg.inputs[1].pin = 0x19;
- spec->autocfg.inputs[1].type = AUTO_PIN_LINE_IN;
- spec->automute = 1;
- spec->automute_mode = ALC_AUTOMUTE_AMP;
-}
-
-static void alc680_unsol_event(struct hda_codec *codec,
- unsigned int res)
-{
- if ((res >> 26) == ALC880_HP_EVENT)
- alc_hp_automute(codec);
- if ((res >> 26) == ALC880_MIC_EVENT)
- alc680_rec_autoswitch(codec);
-}
-
-static void alc680_inithook(struct hda_codec *codec)
-{
- alc_hp_automute(codec);
- alc680_rec_autoswitch(codec);
-}
-
-/* create input playback/capture controls for the given pin */
-static int alc680_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
- const char *ctlname, int idx)
-{
- hda_nid_t dac;
- int err;
-
- switch (nid) {
- case 0x14:
- dac = 0x02;
- break;
- case 0x15:
- dac = 0x03;
- break;
- case 0x16:
- dac = 0x04;
- break;
- default:
- return 0;
- }
- if (spec->multiout.dac_nids[0] != dac &&
- spec->multiout.dac_nids[1] != dac) {
- err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
- HDA_COMPOSE_AMP_VAL(dac, 3, idx,
- HDA_OUTPUT));
- if (err < 0)
- return err;
-
- err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
- HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
-
- if (err < 0)
- return err;
- spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
- }
-
- return 0;
-}
-
-/* add playback controls from the parsed DAC table */
-static int alc680_auto_create_multi_out_ctls(struct alc_spec *spec,
- const struct auto_pin_cfg *cfg)
-{
- hda_nid_t nid;
- int err;
-
- spec->multiout.dac_nids = spec->private_dac_nids;
-
- nid = cfg->line_out_pins[0];
- if (nid) {
- const char *name;
- if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
- name = "Speaker";
- else
- name = "Front";
- err = alc680_new_analog_output(spec, nid, name, 0);
- if (err < 0)
- return err;
- }
-
- nid = cfg->speaker_pins[0];
- if (nid) {
- err = alc680_new_analog_output(spec, nid, "Speaker", 0);
- if (err < 0)
- return err;
- }
- nid = cfg->hp_pins[0];
- if (nid) {
- err = alc680_new_analog_output(spec, nid, "Headphone", 0);
- if (err < 0)
- return err;
- }
-
- return 0;
-}
-
-static void alc680_auto_set_output_and_unmute(struct hda_codec *codec,
- hda_nid_t nid, int pin_type)
-{
- alc_set_pin_output(codec, nid, pin_type);
-}
-
-static void alc680_auto_init_multi_out(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- hda_nid_t nid = spec->autocfg.line_out_pins[0];
- if (nid) {
- int pin_type = get_pin_type(spec->autocfg.line_out_type);
- alc680_auto_set_output_and_unmute(codec, nid, pin_type);
- }
-}
-
-static void alc680_auto_init_hp_out(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- hda_nid_t pin;
-
- pin = spec->autocfg.hp_pins[0];
- if (pin)
- alc680_auto_set_output_and_unmute(codec, pin, PIN_HP);
- pin = spec->autocfg.speaker_pins[0];
- if (pin)
- alc680_auto_set_output_and_unmute(codec, pin, PIN_OUT);
-}
-
-/* pcm configuration: identical with ALC880 */
-#define alc680_pcm_analog_playback alc880_pcm_analog_playback
-#define alc680_pcm_analog_capture alc880_pcm_analog_capture
-#define alc680_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
-#define alc680_pcm_digital_playback alc880_pcm_digital_playback
-#define alc680_pcm_digital_capture alc880_pcm_digital_capture
-
-/*
- * BIOS auto configuration
- */
static int alc680_parse_auto_config(struct hda_codec *codec)
{
- struct alc_spec *spec = codec->spec;
- int err;
- static const hda_nid_t alc680_ignore[] = { 0 };
-
- err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
- alc680_ignore);
- if (err < 0)
- return err;
-
- if (!spec->autocfg.line_outs) {
- if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
- spec->multiout.max_channels = 2;
- spec->no_analog = 1;
- goto dig_only;
- }
- return 0; /* can't find valid BIOS pin config */
- }
- err = alc680_auto_create_multi_out_ctls(spec, &spec->autocfg);
- if (err < 0)
- return err;
-
- spec->multiout.max_channels = 2;
-
- dig_only:
- /* digital only support output */
- alc_auto_parse_digital(codec);
- if (spec->kctls.list)
- add_mixer(spec, spec->kctls.list);
-
- add_verb(spec, alc680_init_verbs);
-
- err = alc_auto_add_mic_boost(codec);
- if (err < 0)
- return err;
-
- return 1;
-}
-
-#define alc680_auto_init_analog_input alc882_auto_init_analog_input
-
-/* init callback for auto-configuration model -- overriding the default init */
-static void alc680_auto_init(struct hda_codec *codec)
-{
- struct alc_spec *spec = codec->spec;
- alc680_auto_init_multi_out(codec);
- alc680_auto_init_hp_out(codec);
- alc680_auto_init_analog_input(codec);
- alc_auto_init_digital(codec);
- if (spec->unsol_event)
- alc_inithook(codec);
+ return alc_parse_auto_config(codec, NULL, NULL);
}
/*
- * configuration and preset
*/
-static const char * const alc680_models[ALC680_MODEL_LAST] = {
- [ALC680_BASE] = "base",
- [ALC680_AUTO] = "auto",
-};
-
-static const struct snd_pci_quirk alc680_cfg_tbl[] = {
- SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE),
- {}
-};
-
-static const struct alc_config_preset alc680_presets[] = {
- [ALC680_BASE] = {
- .mixers = { alc680_base_mixer },
- .cap_mixer = alc680_master_capture_mixer,
- .init_verbs = { alc680_init_verbs },
- .num_dacs = ARRAY_SIZE(alc680_dac_nids),
- .dac_nids = alc680_dac_nids,
- .dig_out_nid = ALC680_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc680_modes),
- .channel_mode = alc680_modes,
- .unsol_event = alc680_unsol_event,
- .setup = alc680_base_setup,
- .init_hook = alc680_inithook,
-
- },
-};
-
static int patch_alc680(struct hda_codec *codec)
{
struct alc_spec *spec;
- int board_config;
int err;
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
@@ -20070,51 +6017,22 @@ static int patch_alc680(struct hda_codec *codec)
codec->spec = spec;
- board_config = snd_hda_check_board_config(codec, ALC680_MODEL_LAST,
- alc680_models,
- alc680_cfg_tbl);
+ /* ALC680 has no aa-loopback mixer */
- if (board_config < 0 || board_config >= ALC680_MODEL_LAST) {
- printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
- codec->chip_name);
- board_config = ALC680_AUTO;
- }
-
- if (board_config == ALC680_AUTO) {
- /* automatic parse from the BIOS config */
- err = alc680_parse_auto_config(codec);
- if (err < 0) {
- alc_free(codec);
- return err;
- } else if (!err) {
- printk(KERN_INFO
- "hda_codec: Cannot set up configuration "
- "from BIOS. Using base mode...\n");
- board_config = ALC680_BASE;
- }
- }
-
- if (board_config != ALC680_AUTO)
- setup_preset(codec, &alc680_presets[board_config]);
-
- spec->stream_analog_playback = &alc680_pcm_analog_playback;
- spec->stream_analog_capture = &alc680_pcm_analog_auto_capture;
- spec->stream_digital_playback = &alc680_pcm_digital_playback;
- spec->stream_digital_capture = &alc680_pcm_digital_capture;
-
- if (!spec->adc_nids) {
- spec->adc_nids = alc680_adc_nids;
- spec->num_adc_nids = ARRAY_SIZE(alc680_adc_nids);
+ /* automatic parse from the BIOS config */
+ err = alc680_parse_auto_config(codec);
+ if (err < 0) {
+ alc_free(codec);
+ return err;
}
- if (!spec->cap_mixer)
+ if (!spec->no_analog && !spec->cap_mixer)
set_capture_mixer(codec);
spec->vmaster_nid = 0x02;
codec->patch_ops = alc_patch_ops;
- if (board_config == ALC680_AUTO)
- spec->init_hook = alc680_auto_init;
+ spec->init_hook = alc_auto_init_std;
return 0;
}
@@ -20124,6 +6042,7 @@ static int patch_alc680(struct hda_codec *codec)
*/
static const struct hda_codec_preset snd_hda_preset_realtek[] = {
{ .id = 0x10ec0221, .name = "ALC221", .patch = patch_alc269 },
+ { .id = 0x10ec0231, .name = "ALC231", .patch = patch_alc269 },
{ .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
{ .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
{ .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
@@ -20151,8 +6070,11 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = {
.patch = patch_alc662 },
{ .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
{ .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 },
+ { .id = 0x10ec0668, .name = "ALC668", .patch = patch_alc662 },
{ .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 },
+ { .id = 0x10ec0671, .name = "ALC671", .patch = patch_alc662 },
{ .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 },
+ { .id = 0x10ec0867, .name = "ALC891", .patch = patch_alc882 },
{ .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
{ .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
{ .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
@@ -20161,13 +6083,14 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = {
{ .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
.patch = patch_alc882 },
{ .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
- { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc888 },
+ { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc882 },
{ .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
.patch = patch_alc882 },
- { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 },
+ { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc882 },
{ .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
{ .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 },
- { .id = 0x10ec0899, .name = "ALC899", .patch = patch_alc899 },
+ { .id = 0x10ec0899, .name = "ALC898", .patch = patch_alc882 },
+ { .id = 0x10ec0900, .name = "ALC1150", .patch = patch_alc882 },
{} /* terminator */
};
diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c
index 2f55f32..6679a50 100644
--- a/sound/pci/hda/patch_si3054.c
+++ b/sound/pci/hda/patch_si3054.c
@@ -25,6 +25,7 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/module.h>
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 8670682..240658b 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -29,6 +29,7 @@
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/dmi.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/asoundef.h>
#include <sound/jack.h>
@@ -94,7 +95,9 @@ enum {
STAC_92HD83XXX_REF,
STAC_92HD83XXX_PWR_REF,
STAC_DELL_S14,
+ STAC_DELL_VOSTRO_3500,
STAC_92HD83XXX_HP,
+ STAC_92HD83XXX_HP_cNB11_INTQUAD,
STAC_HP_DV7_4000,
STAC_92HD83XXX_MODELS
};
@@ -212,6 +215,8 @@ struct sigmatel_spec {
unsigned int gpio_mute;
unsigned int gpio_led;
unsigned int gpio_led_polarity;
+ unsigned int vref_mute_led_nid; /* pin NID for mute-LED vref control */
+ unsigned int vref_led;
/* stream */
unsigned int stream_delay;
@@ -223,7 +228,6 @@ struct sigmatel_spec {
/* power management */
unsigned int num_pwrs;
- const unsigned int *pwr_mapping;
const hda_nid_t *pwr_nids;
const hda_nid_t *dac_list;
@@ -370,18 +374,15 @@ static const unsigned long stac92hd73xx_capvols[] = {
#define STAC92HD83_DAC_COUNT 3
-static const hda_nid_t stac92hd83xxx_pwr_nids[4] = {
- 0xa, 0xb, 0xd, 0xe,
+static const hda_nid_t stac92hd83xxx_pwr_nids[7] = {
+ 0x0a, 0x0b, 0x0c, 0xd, 0x0e,
+ 0x0f, 0x10
};
static const hda_nid_t stac92hd83xxx_slave_dig_outs[2] = {
0x1e, 0,
};
-static const unsigned int stac92hd83xxx_pwr_mapping[4] = {
- 0x03, 0x0c, 0x20, 0x40,
-};
-
static const hda_nid_t stac92hd83xxx_dmic_nids[] = {
0x11, 0x20,
};
@@ -671,6 +672,32 @@ static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol,
return 0;
}
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static int stac_vrefout_set(struct hda_codec *codec,
+ hda_nid_t nid, unsigned int new_vref)
+{
+ int error, pinctl;
+
+ snd_printdd("%s, nid %x ctl %x\n", __func__, nid, new_vref);
+ pinctl = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+
+ if (pinctl < 0)
+ return pinctl;
+
+ pinctl &= 0xff;
+ pinctl &= ~AC_PINCTL_VREFEN;
+ pinctl |= (new_vref & AC_PINCTL_VREFEN);
+
+ error = snd_hda_codec_write_cache(codec, nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl);
+ if (error < 0)
+ return error;
+
+ return 1;
+}
+#endif
+
static unsigned int stac92xx_vref_set(struct hda_codec *codec,
hda_nid_t nid, unsigned int new_vref)
{
@@ -1112,7 +1139,9 @@ static int stac92xx_build_controls(struct hda_codec *codec)
}
if (spec->multiout.dig_out_nid) {
- err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
+ err = snd_hda_create_spdif_out_ctls(codec,
+ spec->multiout.dig_out_nid,
+ spec->multiout.dig_out_nid);
if (err < 0)
return err;
err = snd_hda_create_spdif_share_sw(codec,
@@ -1613,6 +1642,8 @@ static const struct snd_pci_quirk stac92hd73xx_codec_id_cfg_tbl[] = {
"Alienware M17x", STAC_ALIENWARE_M17X),
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x043a,
"Alienware M17x", STAC_ALIENWARE_M17X),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0490,
+ "Alienware M17x", STAC_ALIENWARE_M17X),
{} /* terminator */
};
@@ -1628,16 +1659,30 @@ static const unsigned int dell_s14_pin_configs[10] = {
0x40f000f0, 0x40f000f0,
};
+static const unsigned int dell_vostro_3500_pin_configs[10] = {
+ 0x02a11020, 0x0221101f, 0x400000f0, 0x90170110,
+ 0x400000f1, 0x400000f2, 0x400000f3, 0x90a60160,
+ 0x400000f4, 0x400000f5,
+};
+
static const unsigned int hp_dv7_4000_pin_configs[10] = {
0x03a12050, 0x0321201f, 0x40f000f0, 0x90170110,
0x40f000f0, 0x40f000f0, 0x90170110, 0xd5a30140,
0x40f000f0, 0x40f000f0,
};
+static const unsigned int hp_cNB11_intquad_pin_configs[10] = {
+ 0x40f000f0, 0x0221101f, 0x02a11020, 0x92170110,
+ 0x40f000f0, 0x92170110, 0x40f000f0, 0xd5a30130,
+ 0x40f000f0, 0x40f000f0,
+};
+
static const unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = {
[STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs,
[STAC_92HD83XXX_PWR_REF] = ref92hd83xxx_pin_configs,
[STAC_DELL_S14] = dell_s14_pin_configs,
+ [STAC_DELL_VOSTRO_3500] = dell_vostro_3500_pin_configs,
+ [STAC_92HD83XXX_HP_cNB11_INTQUAD] = hp_cNB11_intquad_pin_configs,
[STAC_HP_DV7_4000] = hp_dv7_4000_pin_configs,
};
@@ -1646,7 +1691,9 @@ static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
[STAC_92HD83XXX_REF] = "ref",
[STAC_92HD83XXX_PWR_REF] = "mic-ref",
[STAC_DELL_S14] = "dell-s14",
+ [STAC_DELL_VOSTRO_3500] = "dell-vostro-3500",
[STAC_92HD83XXX_HP] = "hp",
+ [STAC_92HD83XXX_HP_cNB11_INTQUAD] = "hp_cNB11_intquad",
[STAC_HP_DV7_4000] = "hp-dv7-4000",
};
@@ -1658,8 +1705,50 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
"DFI LanParty", STAC_92HD83XXX_REF),
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ba,
"unknown Dell", STAC_DELL_S14),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x1028,
+ "Dell Vostro 3500", STAC_DELL_VOSTRO_3500),
SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x3600,
- "HP", STAC_92HD83XXX_HP),
+ "HP", STAC_92HD83XXX_HP),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1656,
+ "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1657,
+ "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1658,
+ "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1659,
+ "HP Pavilion dv7", STAC_HP_DV7_4000),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165A,
+ "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165B,
+ "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3388,
+ "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3389,
+ "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355B,
+ "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355C,
+ "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355D,
+ "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355E,
+ "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355F,
+ "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3560,
+ "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x358B,
+ "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x358C,
+ "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x358D,
+ "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3591,
+ "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3592,
+ "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3593,
+ "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
{} /* terminator */
};
@@ -2894,8 +2983,9 @@ static int check_all_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid)
{
struct sigmatel_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
int j, conn_len;
- hda_nid_t conn[HDA_MAX_CONNECTIONS];
+ hda_nid_t conn[HDA_MAX_CONNECTIONS], fallback_dac;
unsigned int wcaps, wtype;
conn_len = snd_hda_get_connections(codec, nid, conn,
@@ -2923,10 +3013,21 @@ static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid)
return conn[j];
}
}
- /* if all DACs are already assigned, connect to the primary DAC */
+
+ /* if all DACs are already assigned, connect to the primary DAC,
+ unless we're assigning a secondary headphone */
+ fallback_dac = spec->multiout.dac_nids[0];
+ if (spec->multiout.hp_nid) {
+ for (j = 0; j < cfg->hp_outs; j++)
+ if (cfg->hp_pins[j] == nid) {
+ fallback_dac = spec->multiout.hp_nid;
+ break;
+ }
+ }
+
if (conn_len > 1) {
for (j = 0; j < conn_len; j++) {
- if (conn[j] == spec->multiout.dac_nids[0]) {
+ if (conn[j] == fallback_dac) {
snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_CONNECT_SEL, j);
break;
@@ -3406,30 +3507,9 @@ static hda_nid_t get_connected_node(struct hda_codec *codec, hda_nid_t mux,
return 0;
}
-static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
- hda_nid_t nid)
-{
- hda_nid_t conn[HDA_MAX_NUM_INPUTS];
- int i, nums;
-
- if (!(get_wcaps(codec, mux) & AC_WCAP_CONN_LIST))
- return -1;
-
- nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
- for (i = 0; i < nums; i++)
- if (conn[i] == nid)
- return i;
-
- for (i = 0; i < nums; i++) {
- unsigned int wid_caps = get_wcaps(codec, conn[i]);
- unsigned int wid_type = get_wcaps_type(wid_caps);
-
- if (wid_type != AC_WID_PIN && wid_type != AC_WID_AUD_MIX)
- if (get_connection_index(codec, conn[i], nid) >= 0)
- return i;
- }
- return -1;
-}
+/* look for NID recursively */
+#define get_connection_index(codec, mux, nid) \
+ snd_hda_get_conn_index(codec, mux, nid, 1)
/* create a volume assigned to the given pin (only if supported) */
/* return 1 if the volume control is created */
@@ -3722,9 +3802,10 @@ static int is_dual_headphones(struct hda_codec *codec)
}
-static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out, hda_nid_t dig_in)
+static int stac92xx_parse_auto_config(struct hda_codec *codec)
{
struct sigmatel_spec *spec = codec->spec;
+ hda_nid_t dig_out = 0, dig_in = 0;
int hp_swap = 0;
int i, err;
@@ -3907,6 +3988,22 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
if (spec->multiout.max_channels > 2)
spec->surr_switch = 1;
+ /* find digital out and in converters */
+ for (i = codec->start_nid; i < codec->start_nid + codec->num_nodes; i++) {
+ unsigned int wid_caps = get_wcaps(codec, i);
+ if (wid_caps & AC_WCAP_DIGITAL) {
+ switch (get_wcaps_type(wid_caps)) {
+ case AC_WID_AUD_OUT:
+ if (!dig_out)
+ dig_out = i;
+ break;
+ case AC_WID_AUD_IN:
+ if (!dig_in)
+ dig_in = i;
+ break;
+ }
+ }
+ }
if (spec->autocfg.dig_outs)
spec->multiout.dig_out_nid = dig_out;
if (dig_in && spec->autocfg.dig_in_pin)
@@ -4039,6 +4136,8 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
{
unsigned int gpiostate, gpiomask, gpiodir;
+ snd_printdd("%s msk %x dir %x gpio %x\n", __func__, mask, dir_mask, data);
+
gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
AC_VERB_GET_GPIO_DATA, 0);
gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask);
@@ -4071,22 +4170,14 @@ static int stac92xx_add_jack(struct hda_codec *codec,
#ifdef CONFIG_SND_HDA_INPUT_JACK
int def_conf = snd_hda_codec_get_pincfg(codec, nid);
int connectivity = get_defcfg_connect(def_conf);
- char name[32];
- int err;
if (connectivity && connectivity != AC_JACK_PORT_FIXED)
return 0;
- snprintf(name, sizeof(name), "%s at %s %s Jack",
- snd_hda_get_jack_type(def_conf),
- snd_hda_get_jack_connectivity(def_conf),
- snd_hda_get_jack_location(def_conf));
-
- err = snd_hda_input_jack_add(codec, nid, type, name);
- if (err < 0)
- return err;
-#endif /* CONFIG_SND_HDA_INPUT_JACK */
+ return snd_hda_input_jack_add(codec, nid, type, NULL);
+#else
return 0;
+#endif /* CONFIG_SND_HDA_INPUT_JACK */
}
static int stac_add_event(struct sigmatel_spec *spec, hda_nid_t nid,
@@ -4218,9 +4309,9 @@ static void stac_store_hints(struct hda_codec *codec)
spec->gpio_mask;
}
if (get_int_hint(codec, "gpio_dir", &spec->gpio_dir))
- spec->gpio_mask &= spec->gpio_mask;
- if (get_int_hint(codec, "gpio_data", &spec->gpio_data))
spec->gpio_dir &= spec->gpio_mask;
+ if (get_int_hint(codec, "gpio_data", &spec->gpio_data))
+ spec->gpio_data &= spec->gpio_mask;
if (get_int_hint(codec, "eapd_mask", &spec->eapd_mask))
spec->eapd_mask &= spec->gpio_mask;
if (get_int_hint(codec, "gpio_mute", &spec->gpio_mute))
@@ -4237,6 +4328,27 @@ static void stac_store_hints(struct hda_codec *codec)
}
}
+static void stac_issue_unsol_events(struct hda_codec *codec, int num_pins,
+ const hda_nid_t *pins)
+{
+ while (num_pins--)
+ stac_issue_unsol_event(codec, *pins++);
+}
+
+/* fake event to set up pins */
+static void stac_fake_hp_events(struct hda_codec *codec)
+{
+ struct sigmatel_spec *spec = codec->spec;
+
+ if (spec->autocfg.hp_outs)
+ stac_issue_unsol_events(codec, spec->autocfg.hp_outs,
+ spec->autocfg.hp_pins);
+ if (spec->autocfg.line_outs &&
+ spec->autocfg.line_out_pins[0] != spec->autocfg.hp_pins[0])
+ stac_issue_unsol_events(codec, spec->autocfg.line_outs,
+ spec->autocfg.line_out_pins);
+}
+
static int stac92xx_init(struct hda_codec *codec)
{
struct sigmatel_spec *spec = codec->spec;
@@ -4287,10 +4399,7 @@ static int stac92xx_init(struct hda_codec *codec)
stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
AC_PINCTL_OUT_EN);
/* fake event to set up pins */
- if (cfg->hp_pins[0])
- stac_issue_unsol_event(codec, cfg->hp_pins[0]);
- else if (cfg->line_out_pins[0])
- stac_issue_unsol_event(codec, cfg->line_out_pins[0]);
+ stac_fake_hp_events(codec);
} else {
stac92xx_auto_init_multi_out(codec);
stac92xx_auto_init_hp_out(codec);
@@ -4348,10 +4457,12 @@ static int stac92xx_init(struct hda_codec *codec)
AC_PINCTL_IN_EN);
for (i = 0; i < spec->num_pwrs; i++) {
hda_nid_t nid = spec->pwr_nids[i];
- int pinctl, def_conf;
+ unsigned int pinctl, def_conf;
/* power on when no jack detection is available */
- if (!spec->hp_detect) {
+ /* or when the VREF is used for controlling LED */
+ if (!spec->hp_detect ||
+ spec->vref_mute_led_nid == nid) {
stac_toggle_power_map(codec, nid, 1);
continue;
}
@@ -4373,13 +4484,17 @@ static int stac92xx_init(struct hda_codec *codec)
def_conf = get_defcfg_connect(def_conf);
/* skip any ports that don't have jacks since presence
* detection is useless */
- if (def_conf != AC_JACK_PORT_COMPLEX) {
- if (def_conf != AC_JACK_PORT_NONE)
- stac_toggle_power_map(codec, nid, 1);
+ if (def_conf != AC_JACK_PORT_COMPLEX ||
+ !is_jack_detectable(codec, nid)) {
+ stac_toggle_power_map(codec, nid, 1);
continue;
}
- if (enable_pin_detect(codec, nid, STAC_PWR_EVENT))
+ if (enable_pin_detect(codec, nid, STAC_PWR_EVENT)) {
stac_issue_unsol_event(codec, nid);
+ continue;
+ }
+ /* none of the above, turn the port OFF */
+ stac_toggle_power_map(codec, nid, 0);
}
/* sync mute LED */
@@ -4403,11 +4518,26 @@ static void stac92xx_free_kctls(struct hda_codec *codec)
snd_array_free(&spec->kctls);
}
+static void stac92xx_shutup_pins(struct hda_codec *codec)
+{
+ unsigned int i, def_conf;
+
+ if (codec->bus->shutdown)
+ return;
+ for (i = 0; i < codec->init_pins.used; i++) {
+ struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i);
+ def_conf = snd_hda_codec_get_pincfg(codec, pin->nid);
+ if (get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)
+ snd_hda_codec_write(codec, pin->nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
+ }
+}
+
static void stac92xx_shutup(struct hda_codec *codec)
{
struct sigmatel_spec *spec = codec->spec;
- snd_hda_shutup_pins(codec);
+ stac92xx_shutup_pins(codec);
if (spec->eapd_mask)
stac_gpio_set(codec, spec->gpio_mask,
@@ -4620,11 +4750,7 @@ static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid,
if (idx >= spec->num_pwrs)
return;
- /* several codecs have two power down bits */
- if (spec->pwr_mapping)
- idx = spec->pwr_mapping[idx];
- else
- idx = 1 << idx;
+ idx = 1 << idx;
val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0) & 0xff;
if (enable)
@@ -4805,10 +4931,17 @@ static int find_mute_led_gpio(struct hda_codec *codec, int default_polarity)
if ((codec->subsystem_id >> 16) == PCI_VENDOR_ID_HP) {
while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING,
NULL, dev))) {
- if (sscanf(dev->name, "HP_Mute_LED_%d_%d",
+ if (sscanf(dev->name, "HP_Mute_LED_%d_%x",
&spec->gpio_led_polarity,
&spec->gpio_led) == 2) {
- spec->gpio_led = 1 << spec->gpio_led;
+ unsigned int max_gpio;
+ max_gpio = snd_hda_param_read(codec, codec->afg,
+ AC_PAR_GPIO_CAP);
+ max_gpio &= AC_GPIO_IO_COUNT;
+ if (spec->gpio_led < max_gpio)
+ spec->gpio_led = 1 << spec->gpio_led;
+ else
+ spec->vref_mute_led_nid = spec->gpio_led;
return 1;
}
if (sscanf(dev->name, "HP_Mute_LED_%d",
@@ -4816,6 +4949,19 @@ static int find_mute_led_gpio(struct hda_codec *codec, int default_polarity)
set_hp_led_gpio(codec);
return 1;
}
+ /* BIOS bug: unfilled OEM string */
+ if (strstr(dev->name, "HP_Mute_LED_P_G")) {
+ set_hp_led_gpio(codec);
+ switch (codec->subsystem_id) {
+ case 0x103c148a:
+ spec->gpio_led_polarity = 0;
+ break;
+ default:
+ spec->gpio_led_polarity = 1;
+ break;
+ }
+ return 1;
+ }
}
/*
@@ -4906,45 +5052,72 @@ static void stac927x_proc_hook(struct snd_info_buffer *buffer,
#define stac927x_proc_hook NULL
#endif
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
static int stac92xx_resume(struct hda_codec *codec)
{
- struct sigmatel_spec *spec = codec->spec;
-
stac92xx_init(codec);
snd_hda_codec_resume_amp(codec);
snd_hda_codec_resume_cache(codec);
/* fake event to set up pins again to override cached values */
- if (spec->hp_detect) {
- if (spec->autocfg.hp_pins[0])
- stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0]);
- else if (spec->autocfg.line_out_pins[0])
- stac_issue_unsol_event(codec,
- spec->autocfg.line_out_pins[0]);
- }
+ stac_fake_hp_events(codec);
+ return 0;
+}
+
+static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state)
+{
+ stac92xx_shutup(codec);
+ return 0;
+}
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static int stac92xx_pre_resume(struct hda_codec *codec)
+{
+ struct sigmatel_spec *spec = codec->spec;
+
/* sync mute LED */
- if (spec->gpio_led)
- hda_call_check_power_status(codec, 0x01);
+ if (spec->vref_mute_led_nid)
+ stac_vrefout_set(codec, spec->vref_mute_led_nid,
+ spec->vref_led);
+ else if (spec->gpio_led)
+ stac_gpio_set(codec, spec->gpio_mask,
+ spec->gpio_dir, spec->gpio_data);
return 0;
}
+static void stac92xx_set_power_state(struct hda_codec *codec, hda_nid_t fg,
+ unsigned int power_state)
+{
+ unsigned int afg_power_state = power_state;
+ struct sigmatel_spec *spec = codec->spec;
+
+ if (power_state == AC_PWRST_D3) {
+ if (spec->vref_mute_led_nid) {
+ /* with vref-out pin used for mute led control
+ * codec AFG is prevented from D3 state
+ */
+ afg_power_state = AC_PWRST_D1;
+ }
+ /* this delay seems necessary to avoid click noise at power-down */
+ msleep(100);
+ }
+ snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE,
+ afg_power_state);
+ snd_hda_codec_set_power_to_all(codec, fg, power_state, true);
+}
+
/*
- * using power check for controlling mute led of HP notebooks
- * check for mute state only on Speakers (nid = 0x10)
- *
- * For this feature CONFIG_SND_HDA_POWER_SAVE is needed, otherwise
- * the LED is NOT working properly !
- *
- * Changed name to reflect that it now works for any designated
- * model, not just HP HDX.
+ * For this feature CONFIG_SND_HDA_POWER_SAVE is needed
+ * as mute LED state is updated in check_power_status hook
*/
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static int stac92xx_hp_check_power_status(struct hda_codec *codec,
- hda_nid_t nid)
+static int stac92xx_update_led_status(struct hda_codec *codec)
{
struct sigmatel_spec *spec = codec->spec;
- int i, muted = 1;
+ int i, num_ext_dacs, muted = 1;
+ unsigned int muted_lvl, notmtd_lvl;
+ hda_nid_t nid;
+
+ if (!spec->gpio_led)
+ return 0;
for (i = 0; i < spec->multiout.num_dacs; i++) {
nid = spec->multiout.dac_nids[i];
@@ -4954,27 +5127,59 @@ static int stac92xx_hp_check_power_status(struct hda_codec *codec,
break;
}
}
- if (muted)
- spec->gpio_data &= ~spec->gpio_led; /* orange */
- else
- spec->gpio_data |= spec->gpio_led; /* white */
-
- if (!spec->gpio_led_polarity) {
- /* LED state is inverted on these systems */
- spec->gpio_data ^= spec->gpio_led;
+ if (muted && spec->multiout.hp_nid)
+ if (!(snd_hda_codec_amp_read(codec,
+ spec->multiout.hp_nid, 0, HDA_OUTPUT, 0) &
+ HDA_AMP_MUTE)) {
+ muted = 0; /* HP is not muted */
+ }
+ num_ext_dacs = ARRAY_SIZE(spec->multiout.extra_out_nid);
+ for (i = 0; muted && i < num_ext_dacs; i++) {
+ nid = spec->multiout.extra_out_nid[i];
+ if (nid == 0)
+ break;
+ if (!(snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) &
+ HDA_AMP_MUTE)) {
+ muted = 0; /* extra output is not muted */
+ }
}
+ /*polarity defines *not* muted state level*/
+ if (!spec->vref_mute_led_nid) {
+ if (muted)
+ spec->gpio_data &= ~spec->gpio_led; /* orange */
+ else
+ spec->gpio_data |= spec->gpio_led; /* white */
- stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data);
+ if (!spec->gpio_led_polarity) {
+ /* LED state is inverted on these systems */
+ spec->gpio_data ^= spec->gpio_led;
+ }
+ stac_gpio_set(codec, spec->gpio_mask,
+ spec->gpio_dir, spec->gpio_data);
+ } else {
+ notmtd_lvl = spec->gpio_led_polarity ?
+ AC_PINCTL_VREF_HIZ : AC_PINCTL_VREF_GRD;
+ muted_lvl = spec->gpio_led_polarity ?
+ AC_PINCTL_VREF_GRD : AC_PINCTL_VREF_HIZ;
+ spec->vref_led = muted ? muted_lvl : notmtd_lvl;
+ stac_vrefout_set(codec, spec->vref_mute_led_nid,
+ spec->vref_led);
+ }
return 0;
}
-#endif
-static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state)
+/*
+ * use power check for controlling mute led of HP notebooks
+ */
+static int stac92xx_check_power_status(struct hda_codec *codec,
+ hda_nid_t nid)
{
- stac92xx_shutup(codec);
+ stac92xx_update_led_status(codec);
+
return 0;
}
-#endif
+#endif /* CONFIG_SND_HDA_POWER_SAVE */
+#endif /* CONFIG_PM */
static const struct hda_codec_ops stac92xx_patch_ops = {
.build_controls = stac92xx_build_controls,
@@ -4982,7 +5187,7 @@ static const struct hda_codec_ops stac92xx_patch_ops = {
.init = stac92xx_init,
.free = stac92xx_free,
.unsol_event = stac92xx_unsol_event,
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
.suspend = stac92xx_suspend,
.resume = stac92xx_resume,
#endif
@@ -5117,7 +5322,7 @@ static int patch_stac925x(struct hda_codec *codec)
spec->capvols = stac925x_capvols;
spec->capsws = stac925x_capsws;
- err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
+ err = stac92xx_parse_auto_config(codec);
if (!err) {
if (spec->board_config < 0) {
printk(KERN_WARNING "hda_codec: No auto-config is "
@@ -5258,7 +5463,7 @@ again:
spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
spec->pwr_nids = stac92hd73xx_pwr_nids;
- err = stac92xx_parse_auto_config(codec, 0x25, 0x27);
+ err = stac92xx_parse_auto_config(codec);
if (!err) {
if (spec->board_config < 0) {
@@ -5438,9 +5643,6 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
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;
@@ -5450,7 +5652,6 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs;
spec->digbeep_nid = 0x21;
spec->pwr_nids = stac92hd83xxx_pwr_nids;
- spec->pwr_mapping = stac92hd83xxx_pwr_mapping;
spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids);
spec->multiout.dac_nids = spec->dac_nids;
spec->init = stac92hd83xxx_core_init;
@@ -5467,9 +5668,6 @@ again:
stac92xx_set_config_regs(codec,
stac92hd83xxx_brd_tbl[spec->board_config]);
- if (spec->board_config != STAC_92HD83XXX_PWR_REF)
- spec->num_pwrs = 0;
-
codec->patch_ops = stac92xx_patch_ops;
if (find_mute_led_gpio(codec, 0))
@@ -5479,20 +5677,21 @@ again:
#ifdef CONFIG_SND_HDA_POWER_SAVE
if (spec->gpio_led) {
- spec->gpio_mask |= spec->gpio_led;
- spec->gpio_dir |= spec->gpio_led;
- spec->gpio_data |= spec->gpio_led;
- /* register check_power_status callback. */
+ if (!spec->vref_mute_led_nid) {
+ spec->gpio_mask |= spec->gpio_led;
+ spec->gpio_dir |= spec->gpio_led;
+ spec->gpio_data |= spec->gpio_led;
+ } else {
+ codec->patch_ops.set_power_state =
+ stac92xx_set_power_state;
+ }
+ codec->patch_ops.pre_resume = stac92xx_pre_resume;
codec->patch_ops.check_power_status =
- stac92xx_hp_check_power_status;
+ stac92xx_check_power_status;
}
#endif
- /* 92HD65/66 series has S/PDIF-IN */
- if (codec->vendor_id >= 0x111d76e8 && codec->vendor_id <= 0x111d76f3)
- err = stac92xx_parse_auto_config(codec, 0x1d, 0x22);
- else
- err = stac92xx_parse_auto_config(codec, 0x1d, 0);
+ err = stac92xx_parse_auto_config(codec);
if (!err) {
if (spec->board_config < 0) {
printk(KERN_WARNING "hda_codec: No auto-config is "
@@ -5675,8 +5874,6 @@ again:
(codec->revision_id & 0xf) == 1)
spec->stream_delay = 40; /* 40 milliseconds */
- /* no output amps */
- spec->num_pwrs = 0;
/* disable VSW */
spec->init = stac92hd71bxx_core_init;
unmute_init++;
@@ -5691,8 +5888,6 @@ again:
if ((codec->revision_id & 0xf) == 1)
spec->stream_delay = 40; /* 40 milliseconds */
- /* no output amps */
- spec->num_pwrs = 0;
/* fallthru */
default:
spec->init = stac92hd71bxx_core_init;
@@ -5795,18 +5990,23 @@ again:
#ifdef CONFIG_SND_HDA_POWER_SAVE
if (spec->gpio_led) {
- spec->gpio_mask |= spec->gpio_led;
- spec->gpio_dir |= spec->gpio_led;
- spec->gpio_data |= spec->gpio_led;
- /* register check_power_status callback. */
+ if (!spec->vref_mute_led_nid) {
+ spec->gpio_mask |= spec->gpio_led;
+ spec->gpio_dir |= spec->gpio_led;
+ spec->gpio_data |= spec->gpio_led;
+ } else {
+ codec->patch_ops.set_power_state =
+ stac92xx_set_power_state;
+ }
+ codec->patch_ops.pre_resume = stac92xx_pre_resume;
codec->patch_ops.check_power_status =
- stac92xx_hp_check_power_status;
+ stac92xx_check_power_status;
}
#endif
spec->multiout.dac_nids = spec->dac_nids;
- err = stac92xx_parse_auto_config(codec, 0x21, 0);
+ err = stac92xx_parse_auto_config(codec);
if (!err) {
if (spec->board_config < 0) {
printk(KERN_WARNING "hda_codec: No auto-config is "
@@ -5915,7 +6115,7 @@ static int patch_stac922x(struct hda_codec *codec)
spec->multiout.dac_nids = spec->dac_nids;
- err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
+ err = stac92xx_parse_auto_config(codec);
if (!err) {
if (spec->board_config < 0) {
printk(KERN_WARNING "hda_codec: No auto-config is "
@@ -6040,7 +6240,7 @@ static int patch_stac927x(struct hda_codec *codec)
spec->aloopback_shift = 0;
spec->eapd_switch = 1;
- err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
+ err = stac92xx_parse_auto_config(codec);
if (!err) {
if (spec->board_config < 0) {
printk(KERN_WARNING "hda_codec: No auto-config is "
@@ -6165,7 +6365,7 @@ static int patch_stac9205(struct hda_codec *codec)
break;
}
- err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
+ err = stac92xx_parse_auto_config(codec);
if (!err) {
if (spec->board_config < 0) {
printk(KERN_WARNING "hda_codec: No auto-config is "
@@ -6270,7 +6470,7 @@ static int patch_stac9872(struct hda_codec *codec)
spec->capvols = stac9872_capvols;
spec->capsws = stac9872_capsws;
- err = stac92xx_parse_auto_config(codec, 0x10, 0x12);
+ err = stac92xx_parse_auto_config(codec);
if (err < 0) {
stac92xx_free(codec);
return -EINVAL;
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index f43bb0e..9e0c889 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -49,41 +49,16 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/asoundef.h>
#include "hda_codec.h"
#include "hda_local.h"
-#define NID_MAPPING (-1)
-
-/* amp values */
-#define AMP_VAL_IDX_SHIFT 19
-#define AMP_VAL_IDX_MASK (0x0f<<19)
-
/* Pin Widget NID */
-#define VT1708_HP_NID 0x13
-#define VT1708_DIGOUT_NID 0x14
-#define VT1708_DIGIN_NID 0x16
-#define VT1708_DIGIN_PIN 0x26
#define VT1708_HP_PIN_NID 0x20
#define VT1708_CD_PIN_NID 0x24
-#define VT1709_HP_DAC_NID 0x28
-#define VT1709_DIGOUT_NID 0x13
-#define VT1709_DIGIN_NID 0x17
-#define VT1709_DIGIN_PIN 0x25
-
-#define VT1708B_HP_NID 0x25
-#define VT1708B_DIGOUT_NID 0x12
-#define VT1708B_DIGIN_NID 0x15
-#define VT1708B_DIGIN_PIN 0x21
-
-#define VT1708S_HP_NID 0x25
-#define VT1708S_DIGOUT_NID 0x12
-
-#define VT1702_HP_NID 0x17
-#define VT1702_DIGOUT_NID 0x11
-
enum VIA_HDA_CODEC {
UNKNOWN = -1,
VT1708,
@@ -107,6 +82,39 @@ enum VIA_HDA_CODEC {
(spec)->codec_type == VT1812 ||\
(spec)->codec_type == VT1802)
+#define MAX_NID_PATH_DEPTH 5
+
+/* output-path: DAC -> ... -> pin
+ * idx[] contains the source index number of the next widget;
+ * e.g. idx[0] is the index of the DAC selected by path[1] widget
+ * multi[] indicates whether it's a selector widget with multi-connectors
+ * (i.e. the connection selection is mandatory)
+ * vol_ctl and mute_ctl contains the NIDs for the assigned mixers
+ */
+struct nid_path {
+ int depth;
+ hda_nid_t path[MAX_NID_PATH_DEPTH];
+ unsigned char idx[MAX_NID_PATH_DEPTH];
+ unsigned char multi[MAX_NID_PATH_DEPTH];
+ unsigned int vol_ctl;
+ unsigned int mute_ctl;
+};
+
+/* input-path */
+struct via_input {
+ hda_nid_t pin; /* input-pin or aa-mix */
+ int adc_idx; /* ADC index to be used */
+ int mux_idx; /* MUX index (if any) */
+ const char *label; /* input-source label */
+};
+
+#define VIA_MAX_ADCS 3
+
+enum {
+ STREAM_MULTI_OUT = (1 << 0),
+ STREAM_INDEP_HP = (1 << 1),
+};
+
struct via_spec {
/* codec parameterization */
const struct snd_kcontrol_new *mixers[6];
@@ -115,28 +123,66 @@ struct via_spec {
const struct hda_verb *init_verbs[5];
unsigned int num_iverbs;
- char *stream_name_analog;
+ char stream_name_analog[32];
+ char stream_name_hp[32];
const struct hda_pcm_stream *stream_analog_playback;
const struct hda_pcm_stream *stream_analog_capture;
- char *stream_name_digital;
+ char stream_name_digital[32];
const struct hda_pcm_stream *stream_digital_playback;
const struct hda_pcm_stream *stream_digital_capture;
/* playback */
struct hda_multi_out multiout;
hda_nid_t slave_dig_outs[2];
+ hda_nid_t hp_dac_nid;
+ hda_nid_t speaker_dac_nid;
+ int hp_indep_shared; /* indep HP-DAC is shared with side ch */
+ int opened_streams; /* STREAM_* bits */
+ int active_streams; /* STREAM_* bits */
+ int aamix_mode; /* loopback is enabled for output-path? */
+
+ /* Output-paths:
+ * There are different output-paths depending on the setup.
+ * out_path, hp_path and speaker_path are primary paths. If both
+ * direct DAC and aa-loopback routes are available, these contain
+ * the former paths. Meanwhile *_mix_path contain the paths with
+ * loopback mixer. (Since the loopback is only for front channel,
+ * no out_mix_path for surround channels.)
+ * The HP output has another path, hp_indep_path, which is used in
+ * the independent-HP mode.
+ */
+ struct nid_path out_path[HDA_SIDE + 1];
+ struct nid_path out_mix_path;
+ struct nid_path hp_path;
+ struct nid_path hp_mix_path;
+ struct nid_path hp_indep_path;
+ struct nid_path speaker_path;
+ struct nid_path speaker_mix_path;
/* capture */
unsigned int num_adc_nids;
- const hda_nid_t *adc_nids;
- hda_nid_t mux_nids[3];
+ hda_nid_t adc_nids[VIA_MAX_ADCS];
+ hda_nid_t mux_nids[VIA_MAX_ADCS];
+ hda_nid_t aa_mix_nid;
hda_nid_t dig_in_nid;
- hda_nid_t dig_in_pin;
/* capture source */
- const struct hda_input_mux *input_mux;
- unsigned int cur_mux[3];
+ bool dyn_adc_switch;
+ int num_inputs;
+ struct via_input inputs[AUTO_CFG_MAX_INS + 1];
+ unsigned int cur_mux[VIA_MAX_ADCS];
+
+ /* dynamic DAC switching */
+ unsigned int cur_dac_stream_tag;
+ unsigned int cur_dac_format;
+ unsigned int cur_hp_stream_tag;
+ unsigned int cur_hp_format;
+
+ /* dynamic ADC switching */
+ hda_nid_t cur_adc;
+ unsigned int cur_adc_stream_tag;
+ unsigned int cur_adc_format;
/* PCM information */
struct hda_pcm pcm_rec[3];
@@ -144,28 +190,42 @@ struct via_spec {
/* dynamic controls, init_verbs and input_mux */
struct auto_pin_cfg autocfg;
struct snd_array kctls;
- struct hda_input_mux private_imux[2];
hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
/* HP mode source */
- const struct hda_input_mux *hp_mux;
unsigned int hp_independent_mode;
- unsigned int hp_independent_mode_index;
- unsigned int smart51_enabled;
unsigned int dmic_enabled;
+ unsigned int no_pin_power_ctl;
enum VIA_HDA_CODEC codec_type;
+ /* analog low-power control */
+ bool alc_mode;
+
+ /* smart51 setup */
+ unsigned int smart51_nums;
+ hda_nid_t smart51_pins[2];
+ int smart51_idxs[2];
+ const char *smart51_labels[2];
+ unsigned int smart51_enabled;
+
/* work to check hp jack state */
struct hda_codec *codec;
struct delayed_work vt1708_hp_work;
- int vt1708_jack_detectect;
+ int hp_work_active;
+ int vt1708_jack_detect;
int vt1708_hp_present;
void (*set_widgets_power_state)(struct hda_codec *codec);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
struct hda_loopback_check loopback;
-#endif
+ int num_loopbacks;
+ struct hda_amp_list loopback_list[8];
+
+ /* bind capture-volume */
+ struct hda_bind_ctls *bind_cap_vol;
+ struct hda_bind_ctls *bind_cap_sw;
+
+ struct mutex config_mutex;
};
static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec);
@@ -177,6 +237,7 @@ static struct via_spec * via_new_spec(struct hda_codec *codec)
if (spec == NULL)
return NULL;
+ mutex_init(&spec->config_mutex);
codec->spec = spec;
spec->codec = codec;
spec->codec_type = get_codec_type(codec);
@@ -237,48 +298,46 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec)
#define VIA_JACK_EVENT 0x20
#define VIA_HP_EVENT 0x01
#define VIA_GPIO_EVENT 0x02
-#define VIA_MONO_EVENT 0x03
-#define VIA_SPEAKER_EVENT 0x04
-#define VIA_BIND_HP_EVENT 0x05
+#define VIA_LINE_EVENT 0x03
enum {
VIA_CTL_WIDGET_VOL,
VIA_CTL_WIDGET_MUTE,
VIA_CTL_WIDGET_ANALOG_MUTE,
- VIA_CTL_WIDGET_BIND_PIN_MUTE,
};
-enum {
- AUTO_SEQ_FRONT = 0,
- AUTO_SEQ_SURROUND,
- AUTO_SEQ_CENLFE,
- AUTO_SEQ_SIDE
-};
+static void analog_low_current_mode(struct hda_codec *codec);
+static bool is_aa_path_mute(struct hda_codec *codec);
-static void analog_low_current_mode(struct hda_codec *codec, int stream_idle);
-static int is_aa_path_mute(struct hda_codec *codec);
+#define hp_detect_with_aa(codec) \
+ (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1 && \
+ !is_aa_path_mute(codec))
-static void vt1708_start_hp_work(struct via_spec *spec)
+static void vt1708_stop_hp_work(struct via_spec *spec)
{
if (spec->codec_type != VT1708 || spec->autocfg.hp_pins[0] == 0)
return;
- snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81,
- !spec->vt1708_jack_detectect);
- if (!delayed_work_pending(&spec->vt1708_hp_work))
- schedule_delayed_work(&spec->vt1708_hp_work,
- msecs_to_jiffies(100));
+ if (spec->hp_work_active) {
+ snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81, 1);
+ cancel_delayed_work_sync(&spec->vt1708_hp_work);
+ spec->hp_work_active = 0;
+ }
}
-static void vt1708_stop_hp_work(struct via_spec *spec)
+static void vt1708_update_hp_work(struct via_spec *spec)
{
if (spec->codec_type != VT1708 || spec->autocfg.hp_pins[0] == 0)
return;
- if (snd_hda_get_bool_hint(spec->codec, "analog_loopback_hp_detect") == 1
- && !is_aa_path_mute(spec->codec))
- return;
- snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81,
- !spec->vt1708_jack_detectect);
- cancel_delayed_work_sync(&spec->vt1708_hp_work);
+ if (spec->vt1708_jack_detect &&
+ (spec->active_streams || hp_detect_with_aa(spec->codec))) {
+ if (!spec->hp_work_active) {
+ snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81, 0);
+ schedule_delayed_work(&spec->vt1708_hp_work,
+ msecs_to_jiffies(100));
+ spec->hp_work_active = 1;
+ }
+ } else if (!hp_detect_with_aa(spec->codec))
+ vt1708_stop_hp_work(spec);
}
static void set_widgets_power_state(struct hda_codec *codec)
@@ -295,13 +354,8 @@ static int analog_input_switch_put(struct snd_kcontrol *kcontrol,
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
set_widgets_power_state(codec);
- analog_low_current_mode(snd_kcontrol_chip(kcontrol), -1);
- if (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1) {
- if (is_aa_path_mute(codec))
- vt1708_start_hp_work(codec->spec);
- else
- vt1708_stop_hp_work(codec->spec);
- }
+ analog_low_current_mode(snd_kcontrol_chip(kcontrol));
+ vt1708_update_hp_work(codec->spec);
return change;
}
@@ -315,168 +369,44 @@ static int analog_input_switch_put(struct snd_kcontrol *kcontrol,
.put = analog_input_switch_put, \
.private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) }
-static void via_hp_bind_automute(struct hda_codec *codec);
-
-static int bind_pin_switch_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct via_spec *spec = codec->spec;
- int i;
- int change = 0;
-
- long *valp = ucontrol->value.integer.value;
- int lmute, rmute;
- if (strstr(kcontrol->id.name, "Switch") == NULL) {
- snd_printd("Invalid control!\n");
- return change;
- }
- change = snd_hda_mixer_amp_switch_put(kcontrol,
- ucontrol);
- /* Get mute value */
- lmute = *valp ? 0 : HDA_AMP_MUTE;
- valp++;
- rmute = *valp ? 0 : HDA_AMP_MUTE;
-
- /* Set hp pins */
- if (!spec->hp_independent_mode) {
- for (i = 0; i < spec->autocfg.hp_outs; i++) {
- snd_hda_codec_amp_update(
- codec, spec->autocfg.hp_pins[i],
- 0, HDA_OUTPUT, 0, HDA_AMP_MUTE,
- lmute);
- snd_hda_codec_amp_update(
- codec, spec->autocfg.hp_pins[i],
- 1, HDA_OUTPUT, 0, HDA_AMP_MUTE,
- rmute);
- }
- }
-
- if (!lmute && !rmute) {
- /* Line Outs */
- for (i = 0; i < spec->autocfg.line_outs; i++)
- snd_hda_codec_amp_stereo(
- codec, spec->autocfg.line_out_pins[i],
- HDA_OUTPUT, 0, HDA_AMP_MUTE, 0);
- /* Speakers */
- for (i = 0; i < spec->autocfg.speaker_outs; i++)
- snd_hda_codec_amp_stereo(
- codec, spec->autocfg.speaker_pins[i],
- HDA_OUTPUT, 0, HDA_AMP_MUTE, 0);
- /* unmute */
- via_hp_bind_automute(codec);
-
- } else {
- if (lmute) {
- /* Mute all left channels */
- for (i = 1; i < spec->autocfg.line_outs; i++)
- snd_hda_codec_amp_update(
- codec,
- spec->autocfg.line_out_pins[i],
- 0, HDA_OUTPUT, 0, HDA_AMP_MUTE,
- lmute);
- for (i = 0; i < spec->autocfg.speaker_outs; i++)
- snd_hda_codec_amp_update(
- codec,
- spec->autocfg.speaker_pins[i],
- 0, HDA_OUTPUT, 0, HDA_AMP_MUTE,
- lmute);
- }
- if (rmute) {
- /* mute all right channels */
- for (i = 1; i < spec->autocfg.line_outs; i++)
- snd_hda_codec_amp_update(
- codec,
- spec->autocfg.line_out_pins[i],
- 1, HDA_OUTPUT, 0, HDA_AMP_MUTE,
- rmute);
- for (i = 0; i < spec->autocfg.speaker_outs; i++)
- snd_hda_codec_amp_update(
- codec,
- spec->autocfg.speaker_pins[i],
- 1, HDA_OUTPUT, 0, HDA_AMP_MUTE,
- rmute);
- }
- }
- return change;
-}
-
-#define BIND_PIN_MUTE \
- { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
- .name = NULL, \
- .index = 0, \
- .info = snd_hda_mixer_amp_switch_info, \
- .get = snd_hda_mixer_amp_switch_get, \
- .put = bind_pin_switch_put, \
- .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) }
-
static const struct snd_kcontrol_new via_control_templates[] = {
HDA_CODEC_VOLUME(NULL, 0, 0, 0),
HDA_CODEC_MUTE(NULL, 0, 0, 0),
ANALOG_INPUT_MUTE,
- BIND_PIN_MUTE,
-};
-
-static const hda_nid_t vt1708_adc_nids[2] = {
- /* ADC1-2 */
- 0x15, 0x27
-};
-
-static const hda_nid_t vt1709_adc_nids[3] = {
- /* ADC1-2 */
- 0x14, 0x15, 0x16
-};
-
-static const hda_nid_t vt1708B_adc_nids[2] = {
- /* ADC1-2 */
- 0x13, 0x14
-};
-
-static const hda_nid_t vt1708S_adc_nids[2] = {
- /* ADC1-2 */
- 0x13, 0x14
-};
-
-static const hda_nid_t vt1702_adc_nids[3] = {
- /* ADC1-2 */
- 0x12, 0x20, 0x1F
-};
-
-static const hda_nid_t vt1718S_adc_nids[2] = {
- /* ADC1-2 */
- 0x10, 0x11
-};
-
-static const hda_nid_t vt1716S_adc_nids[2] = {
- /* ADC1-2 */
- 0x13, 0x14
};
-static const hda_nid_t vt2002P_adc_nids[2] = {
- /* ADC1-2 */
- 0x10, 0x11
-};
-static const hda_nid_t vt1812_adc_nids[2] = {
- /* ADC1-2 */
- 0x10, 0x11
-};
+/* add dynamic controls */
+static struct snd_kcontrol_new *__via_clone_ctl(struct via_spec *spec,
+ const struct snd_kcontrol_new *tmpl,
+ const char *name)
+{
+ struct snd_kcontrol_new *knew;
+ snd_array_init(&spec->kctls, sizeof(*knew), 32);
+ knew = snd_array_new(&spec->kctls);
+ if (!knew)
+ return NULL;
+ *knew = *tmpl;
+ if (!name)
+ name = tmpl->name;
+ if (name) {
+ knew->name = kstrdup(name, GFP_KERNEL);
+ if (!knew->name)
+ return NULL;
+ }
+ return knew;
+}
-/* add dynamic controls */
static int __via_add_control(struct via_spec *spec, int type, const char *name,
int idx, unsigned long val)
{
struct snd_kcontrol_new *knew;
- snd_array_init(&spec->kctls, sizeof(*knew), 32);
- knew = snd_array_new(&spec->kctls);
+ knew = __via_clone_ctl(spec, &via_control_templates[type], name);
if (!knew)
return -ENOMEM;
- *knew = via_control_templates[type];
- knew->name = kstrdup(name, GFP_KERNEL);
- if (!knew->name)
- return -ENOMEM;
+ knew->index = idx;
if (get_amp_nid_(val))
knew->subdevice = HDA_SUBDEV_AMP_FLAG;
knew->private_value = val;
@@ -486,21 +416,7 @@ static int __via_add_control(struct via_spec *spec, int type, const char *name,
#define via_add_control(spec, type, name, val) \
__via_add_control(spec, type, name, 0, val)
-static struct snd_kcontrol_new *via_clone_control(struct via_spec *spec,
- const struct snd_kcontrol_new *tmpl)
-{
- struct snd_kcontrol_new *knew;
-
- snd_array_init(&spec->kctls, sizeof(*knew), 32);
- knew = snd_array_new(&spec->kctls);
- if (!knew)
- return NULL;
- *knew = *tmpl;
- knew->name = kstrdup(tmpl->name, GFP_KERNEL);
- if (!knew->name)
- return NULL;
- return knew;
-}
+#define via_clone_control(spec, tmpl) __via_clone_ctl(spec, tmpl, NULL)
static void via_free_kctls(struct hda_codec *codec)
{
@@ -535,58 +451,208 @@ static int via_new_analog_input(struct via_spec *spec, const char *ctlname,
return 0;
}
-static void via_auto_set_output_and_unmute(struct hda_codec *codec,
- hda_nid_t nid, int pin_type,
- int dac_idx)
+#define get_connection_index(codec, mux, nid) \
+ snd_hda_get_conn_index(codec, mux, nid, 0)
+
+static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
+ unsigned int mask)
+{
+ unsigned int caps;
+ if (!nid)
+ return false;
+ caps = get_wcaps(codec, nid);
+ if (dir == HDA_INPUT)
+ caps &= AC_WCAP_IN_AMP;
+ else
+ caps &= AC_WCAP_OUT_AMP;
+ if (!caps)
+ return false;
+ if (query_amp_caps(codec, nid, dir) & mask)
+ return true;
+ return false;
+}
+
+#define have_mute(codec, nid, dir) \
+ check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE)
+
+/* enable/disable the output-route mixers */
+static void activate_output_mix(struct hda_codec *codec, struct nid_path *path,
+ hda_nid_t mix_nid, int idx, bool enable)
+{
+ int i, num, val;
+
+ if (!path)
+ return;
+ num = snd_hda_get_conn_list(codec, mix_nid, NULL);
+ for (i = 0; i < num; i++) {
+ if (i == idx)
+ val = AMP_IN_UNMUTE(i);
+ else
+ val = AMP_IN_MUTE(i);
+ snd_hda_codec_write(codec, mix_nid, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, val);
+ }
+}
+
+/* enable/disable the output-route */
+static void activate_output_path(struct hda_codec *codec, struct nid_path *path,
+ bool enable, bool force)
{
- /* set as output */
- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+ struct via_spec *spec = codec->spec;
+ int i;
+ for (i = 0; i < path->depth; i++) {
+ hda_nid_t src, dst;
+ int idx = path->idx[i];
+ src = path->path[i];
+ if (i < path->depth - 1)
+ dst = path->path[i + 1];
+ else
+ dst = 0;
+ if (enable && path->multi[i])
+ snd_hda_codec_write(codec, dst, 0,
+ AC_VERB_SET_CONNECT_SEL, idx);
+ if (!force && (dst == spec->aa_mix_nid))
+ continue;
+ if (have_mute(codec, dst, HDA_INPUT))
+ activate_output_mix(codec, path, dst, idx, enable);
+ if (!force && (src == path->vol_ctl || src == path->mute_ctl))
+ continue;
+ if (have_mute(codec, src, HDA_OUTPUT)) {
+ int val = enable ? AMP_OUT_UNMUTE : AMP_OUT_MUTE;
+ snd_hda_codec_write(codec, src, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, val);
+ }
+ }
+}
+
+/* set the given pin as output */
+static void init_output_pin(struct hda_codec *codec, hda_nid_t pin,
+ int pin_type)
+{
+ if (!pin)
+ return;
+ snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
pin_type);
- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
- AMP_OUT_UNMUTE);
- if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
- snd_hda_codec_write(codec, nid, 0,
+ if (snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_EAPD)
+ snd_hda_codec_write(codec, pin, 0,
AC_VERB_SET_EAPD_BTLENABLE, 0x02);
}
+static void via_auto_init_output(struct hda_codec *codec,
+ struct nid_path *path, int pin_type)
+{
+ unsigned int caps;
+ hda_nid_t pin;
+
+ if (!path->depth)
+ return;
+ pin = path->path[path->depth - 1];
+
+ init_output_pin(codec, pin, pin_type);
+ caps = query_amp_caps(codec, pin, HDA_OUTPUT);
+ if (caps & AC_AMPCAP_MUTE) {
+ unsigned int val;
+ val = (caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT;
+ snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+ AMP_OUT_MUTE | val);
+ }
+ activate_output_path(codec, path, true, true); /* force on */
+}
static void via_auto_init_multi_out(struct hda_codec *codec)
{
struct via_spec *spec = codec->spec;
+ struct nid_path *path;
int i;
- for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
- hda_nid_t nid = spec->autocfg.line_out_pins[i];
- if (nid)
- via_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
+ for (i = 0; i < spec->autocfg.line_outs + spec->smart51_nums; i++) {
+ path = &spec->out_path[i];
+ if (!i && spec->aamix_mode && spec->out_mix_path.depth)
+ path = &spec->out_mix_path;
+ via_auto_init_output(codec, path, PIN_OUT);
+ }
+}
+
+/* deactivate the inactive headphone-paths */
+static void deactivate_hp_paths(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ int shared = spec->hp_indep_shared;
+
+ if (spec->hp_independent_mode) {
+ activate_output_path(codec, &spec->hp_path, false, false);
+ activate_output_path(codec, &spec->hp_mix_path, false, false);
+ if (shared)
+ activate_output_path(codec, &spec->out_path[shared],
+ false, false);
+ } else if (spec->aamix_mode || !spec->hp_path.depth) {
+ activate_output_path(codec, &spec->hp_indep_path, false, false);
+ activate_output_path(codec, &spec->hp_path, false, false);
+ } else {
+ activate_output_path(codec, &spec->hp_indep_path, false, false);
+ activate_output_path(codec, &spec->hp_mix_path, false, false);
}
}
static void via_auto_init_hp_out(struct hda_codec *codec)
{
struct via_spec *spec = codec->spec;
- hda_nid_t pin;
- int i;
- for (i = 0; i < spec->autocfg.hp_outs; i++) {
- pin = spec->autocfg.hp_pins[i];
- if (pin) /* connect to front */
- via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+ if (!spec->hp_path.depth) {
+ via_auto_init_output(codec, &spec->hp_mix_path, PIN_HP);
+ return;
}
+ deactivate_hp_paths(codec);
+ if (spec->hp_independent_mode)
+ via_auto_init_output(codec, &spec->hp_indep_path, PIN_HP);
+ else if (spec->aamix_mode)
+ via_auto_init_output(codec, &spec->hp_mix_path, PIN_HP);
+ else
+ via_auto_init_output(codec, &spec->hp_path, PIN_HP);
}
-static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin);
+static void via_auto_init_speaker_out(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+
+ if (!spec->autocfg.speaker_outs)
+ return;
+ if (!spec->speaker_path.depth) {
+ via_auto_init_output(codec, &spec->speaker_mix_path, PIN_OUT);
+ return;
+ }
+ if (!spec->aamix_mode) {
+ activate_output_path(codec, &spec->speaker_mix_path,
+ false, false);
+ via_auto_init_output(codec, &spec->speaker_path, PIN_OUT);
+ } else {
+ activate_output_path(codec, &spec->speaker_path, false, false);
+ via_auto_init_output(codec, &spec->speaker_mix_path, PIN_OUT);
+ }
+}
+
+static bool is_smart51_pins(struct hda_codec *codec, hda_nid_t pin);
+static void via_hp_automute(struct hda_codec *codec);
static void via_auto_init_analog_input(struct hda_codec *codec)
{
struct via_spec *spec = codec->spec;
const struct auto_pin_cfg *cfg = &spec->autocfg;
+ hda_nid_t conn[HDA_MAX_CONNECTIONS];
unsigned int ctl;
- int i;
+ int i, num_conns;
+ /* init ADCs */
+ for (i = 0; i < spec->num_adc_nids; i++) {
+ snd_hda_codec_write(codec, spec->adc_nids[i], 0,
+ AC_VERB_SET_AMP_GAIN_MUTE,
+ AMP_IN_UNMUTE(0));
+ }
+
+ /* init pins */
for (i = 0; i < cfg->num_inputs; i++) {
hda_nid_t nid = cfg->inputs[i].pin;
- if (spec->smart51_enabled && is_smart51_pins(spec, nid))
+ if (spec->smart51_enabled && is_smart51_pins(codec, nid))
ctl = PIN_OUT;
else if (cfg->inputs[i].type == AUTO_PIN_MIC)
ctl = PIN_VREF50;
@@ -595,6 +661,35 @@ static void via_auto_init_analog_input(struct hda_codec *codec)
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL, ctl);
}
+
+ /* init input-src */
+ for (i = 0; i < spec->num_adc_nids; i++) {
+ int adc_idx = spec->inputs[spec->cur_mux[i]].adc_idx;
+ /* secondary ADCs must have the unique MUX */
+ if (i > 0 && !spec->mux_nids[i])
+ break;
+ if (spec->mux_nids[adc_idx]) {
+ int mux_idx = spec->inputs[spec->cur_mux[i]].mux_idx;
+ snd_hda_codec_write(codec, spec->mux_nids[adc_idx], 0,
+ AC_VERB_SET_CONNECT_SEL,
+ mux_idx);
+ }
+ if (spec->dyn_adc_switch)
+ break; /* only one input-src */
+ }
+
+ /* init aa-mixer */
+ if (!spec->aa_mix_nid)
+ return;
+ num_conns = snd_hda_get_connections(codec, spec->aa_mix_nid, conn,
+ ARRAY_SIZE(conn));
+ for (i = 0; i < num_conns; i++) {
+ unsigned int caps = get_wcaps(codec, conn[i]);
+ if (get_wcaps_type(caps) == AC_WID_PIN)
+ snd_hda_codec_write(codec, spec->aa_mix_nid, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE,
+ AMP_IN_MUTE(i));
+ }
}
static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid,
@@ -605,9 +700,13 @@ static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid,
unsigned no_presence = (def_conf & AC_DEFCFG_MISC)
>> AC_DEFCFG_MISC_SHIFT
& AC_DEFCFG_MISC_NO_PRESENCE; /* do not support pin sense */
- unsigned present = snd_hda_jack_detect(codec, nid);
struct via_spec *spec = codec->spec;
- if ((spec->smart51_enabled && is_smart51_pins(spec, nid))
+ unsigned present = 0;
+
+ no_presence |= spec->no_pin_power_ctl;
+ if (!no_presence)
+ present = snd_hda_jack_detect(codec, nid);
+ if ((spec->smart51_enabled && is_smart51_pins(codec, nid))
|| ((no_presence || present)
&& get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)) {
*affected_parm = AC_PWRST_D0; /* if it's connected */
@@ -618,124 +717,140 @@ static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid,
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm);
}
-/*
- * input MUX handling
- */
-static int via_mux_enum_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
+static int via_pin_power_ctl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct via_spec *spec = codec->spec;
- return snd_hda_input_mux_info(spec->input_mux, uinfo);
+ static const char * const texts[] = {
+ "Disabled", "Enabled"
+ };
+
+ 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 int via_mux_enum_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int via_pin_power_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct via_spec *spec = codec->spec;
- unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-
- ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
+ ucontrol->value.enumerated.item[0] = !spec->no_pin_power_ctl;
return 0;
}
-static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int via_pin_power_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct via_spec *spec = codec->spec;
- unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
- int ret;
-
- if (!spec->mux_nids[adc_idx])
- return -EINVAL;
- /* switch to D0 beofre change index */
- if (snd_hda_codec_read(codec, spec->mux_nids[adc_idx], 0,
- AC_VERB_GET_POWER_STATE, 0x00) != AC_PWRST_D0)
- snd_hda_codec_write(codec, spec->mux_nids[adc_idx], 0,
- AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+ unsigned int val = !ucontrol->value.enumerated.item[0];
- ret = snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
- spec->mux_nids[adc_idx],
- &spec->cur_mux[adc_idx]);
- /* update jack power state */
+ if (val == spec->no_pin_power_ctl)
+ return 0;
+ spec->no_pin_power_ctl = val;
set_widgets_power_state(codec);
-
- return ret;
+ analog_low_current_mode(codec);
+ return 1;
}
+static const struct snd_kcontrol_new via_pin_power_ctl_enum = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Dynamic Power-Control",
+ .info = via_pin_power_ctl_info,
+ .get = via_pin_power_ctl_get,
+ .put = via_pin_power_ctl_put,
+};
+
+
static int via_independent_hp_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct via_spec *spec = codec->spec;
- return snd_hda_input_mux_info(spec->hp_mux, uinfo);
+ static const char * const texts[] = { "OFF", "ON" };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 2;
+ if (uinfo->value.enumerated.item >= 2)
+ uinfo->value.enumerated.item = 1;
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+ return 0;
}
static int via_independent_hp_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- hda_nid_t nid = kcontrol->private_value;
- unsigned int pinsel;
-
- /* use !! to translate conn sel 2 for VT1718S */
- pinsel = !!snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_CONNECT_SEL,
- 0x00);
- ucontrol->value.enumerated.item[0] = pinsel;
+ struct via_spec *spec = codec->spec;
+ ucontrol->value.enumerated.item[0] = spec->hp_independent_mode;
return 0;
}
-static void activate_ctl(struct hda_codec *codec, const char *name, int active)
-{
- struct snd_kcontrol *ctl = snd_hda_find_mixer_ctl(codec, name);
- if (ctl) {
- ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
- ctl->vd[0].access |= active
- ? 0 : SNDRV_CTL_ELEM_ACCESS_INACTIVE;
- snd_ctl_notify(codec->bus->card,
- SNDRV_CTL_EVENT_MASK_VALUE, &ctl->id);
- }
-}
-
-static hda_nid_t side_mute_channel(struct via_spec *spec)
+/* adjust spec->multiout setup according to the current flags */
+static void setup_playback_multi_pcm(struct via_spec *spec)
{
- switch (spec->codec_type) {
- case VT1708: return 0x1b;
- case VT1709_10CH: return 0x29;
- case VT1708B_8CH: /* fall thru */
- case VT1708S: return 0x27;
- case VT2002P: return 0x19;
- case VT1802: return 0x15;
- case VT1812: return 0x15;
- default: return 0;
+ const struct auto_pin_cfg *cfg = &spec->autocfg;
+ spec->multiout.num_dacs = cfg->line_outs + spec->smart51_nums;
+ spec->multiout.hp_nid = 0;
+ if (!spec->hp_independent_mode) {
+ if (!spec->hp_indep_shared)
+ spec->multiout.hp_nid = spec->hp_dac_nid;
+ } else {
+ if (spec->hp_indep_shared)
+ spec->multiout.num_dacs = cfg->line_outs - 1;
}
}
-static int update_side_mute_status(struct hda_codec *codec)
+/* update DAC setups according to indep-HP switch;
+ * this function is called only when indep-HP is modified
+ */
+static void switch_indep_hp_dacs(struct hda_codec *codec)
{
- /* mute side channel */
struct via_spec *spec = codec->spec;
- unsigned int parm;
- hda_nid_t sw3 = side_mute_channel(spec);
+ int shared = spec->hp_indep_shared;
+ hda_nid_t shared_dac, hp_dac;
- if (sw3) {
- if (VT2002P_COMPATIBLE(spec))
- parm = spec->hp_independent_mode ?
- AMP_IN_MUTE(1) : AMP_IN_UNMUTE(1);
- else
- parm = spec->hp_independent_mode ?
- AMP_OUT_MUTE : AMP_OUT_UNMUTE;
- snd_hda_codec_write(codec, sw3, 0,
- AC_VERB_SET_AMP_GAIN_MUTE, parm);
- if (spec->codec_type == VT1812)
- snd_hda_codec_write(codec, 0x1d, 0,
- AC_VERB_SET_AMP_GAIN_MUTE, parm);
+ if (!spec->opened_streams)
+ return;
+
+ shared_dac = shared ? spec->multiout.dac_nids[shared] : 0;
+ hp_dac = spec->hp_dac_nid;
+ if (spec->hp_independent_mode) {
+ /* switch to indep-HP mode */
+ if (spec->active_streams & STREAM_MULTI_OUT) {
+ __snd_hda_codec_cleanup_stream(codec, hp_dac, 1);
+ __snd_hda_codec_cleanup_stream(codec, shared_dac, 1);
+ }
+ if (spec->active_streams & STREAM_INDEP_HP)
+ snd_hda_codec_setup_stream(codec, hp_dac,
+ spec->cur_hp_stream_tag, 0,
+ spec->cur_hp_format);
+ } else {
+ /* back to HP or shared-DAC */
+ if (spec->active_streams & STREAM_INDEP_HP)
+ __snd_hda_codec_cleanup_stream(codec, hp_dac, 1);
+ if (spec->active_streams & STREAM_MULTI_OUT) {
+ hda_nid_t dac;
+ int ch;
+ if (shared_dac) { /* reset mutli-ch DAC */
+ dac = shared_dac;
+ ch = shared * 2;
+ } else { /* reset HP DAC */
+ dac = hp_dac;
+ ch = 0;
+ }
+ snd_hda_codec_setup_stream(codec, dac,
+ spec->cur_dac_stream_tag, ch,
+ spec->cur_dac_format);
+ }
}
- return 0;
+ setup_playback_multi_pcm(spec);
}
static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
@@ -743,66 +858,46 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct via_spec *spec = codec->spec;
- hda_nid_t nid = kcontrol->private_value;
- unsigned int pinsel = ucontrol->value.enumerated.item[0];
- unsigned int parm0, parm1;
- /* Get Independent Mode index of headphone pin widget */
- spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel
- ? 1 : 0;
- if (spec->codec_type == VT1718S) {
- snd_hda_codec_write(codec, nid, 0,
- AC_VERB_SET_CONNECT_SEL, pinsel ? 2 : 0);
- /* Set correct mute switch for MW3 */
- parm0 = spec->hp_independent_mode ?
- AMP_IN_UNMUTE(0) : AMP_IN_MUTE(0);
- parm1 = spec->hp_independent_mode ?
- AMP_IN_MUTE(1) : AMP_IN_UNMUTE(1);
- snd_hda_codec_write(codec, 0x1b, 0,
- AC_VERB_SET_AMP_GAIN_MUTE, parm0);
- snd_hda_codec_write(codec, 0x1b, 0,
- AC_VERB_SET_AMP_GAIN_MUTE, parm1);
- }
- else
- snd_hda_codec_write(codec, nid, 0,
- AC_VERB_SET_CONNECT_SEL, pinsel);
+ int cur, shared;
- if (spec->codec_type == VT1812)
- snd_hda_codec_write(codec, 0x35, 0,
- AC_VERB_SET_CONNECT_SEL, pinsel);
- if (spec->multiout.hp_nid && spec->multiout.hp_nid
- != spec->multiout.dac_nids[HDA_FRONT])
- snd_hda_codec_setup_stream(codec, spec->multiout.hp_nid,
- 0, 0, 0);
-
- update_side_mute_status(codec);
- /* update HP volume/swtich active state */
- if (spec->codec_type == VT1708S
- || spec->codec_type == VT1702
- || spec->codec_type == VT1718S
- || spec->codec_type == VT1716S
- || VT2002P_COMPATIBLE(spec)) {
- activate_ctl(codec, "Headphone Playback Volume",
- spec->hp_independent_mode);
- activate_ctl(codec, "Headphone Playback Switch",
- spec->hp_independent_mode);
+ mutex_lock(&spec->config_mutex);
+ cur = !!ucontrol->value.enumerated.item[0];
+ if (spec->hp_independent_mode == cur) {
+ mutex_unlock(&spec->config_mutex);
+ return 0;
+ }
+ spec->hp_independent_mode = cur;
+ shared = spec->hp_indep_shared;
+ deactivate_hp_paths(codec);
+ if (cur)
+ activate_output_path(codec, &spec->hp_indep_path, true, false);
+ else {
+ if (shared)
+ activate_output_path(codec, &spec->out_path[shared],
+ true, false);
+ if (spec->aamix_mode || !spec->hp_path.depth)
+ activate_output_path(codec, &spec->hp_mix_path,
+ true, false);
+ else
+ activate_output_path(codec, &spec->hp_path,
+ true, false);
}
+
+ switch_indep_hp_dacs(codec);
+ mutex_unlock(&spec->config_mutex);
+
/* update jack power state */
set_widgets_power_state(codec);
- return 0;
+ via_hp_automute(codec);
+ return 1;
}
-static const struct snd_kcontrol_new via_hp_mixer[2] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Independent HP",
- .info = via_independent_hp_info,
- .get = via_independent_hp_get,
- .put = via_independent_hp_put,
- },
- {
- .iface = NID_MAPPING,
- .name = "Independent HP",
- },
+static const struct snd_kcontrol_new via_hp_mixer = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Independent HP",
+ .info = via_independent_hp_info,
+ .get = via_independent_hp_get,
+ .put = via_independent_hp_put,
};
static int via_hp_build(struct hda_codec *codec)
@@ -810,61 +905,28 @@ static int via_hp_build(struct hda_codec *codec)
struct via_spec *spec = codec->spec;
struct snd_kcontrol_new *knew;
hda_nid_t nid;
- int nums;
- hda_nid_t conn[HDA_MAX_CONNECTIONS];
- switch (spec->codec_type) {
- case VT1718S:
- nid = 0x34;
- break;
- case VT2002P:
- case VT1802:
- nid = 0x35;
- break;
- case VT1812:
- nid = 0x3d;
- break;
- default:
- nid = spec->autocfg.hp_pins[0];
- break;
- }
-
- if (spec->codec_type != VT1708) {
- nums = snd_hda_get_connections(codec, nid,
- conn, HDA_MAX_CONNECTIONS);
- if (nums <= 1)
- return 0;
- }
-
- knew = via_clone_control(spec, &via_hp_mixer[0]);
+ nid = spec->autocfg.hp_pins[0];
+ knew = via_clone_control(spec, &via_hp_mixer);
if (knew == NULL)
return -ENOMEM;
knew->subdevice = HDA_SUBDEV_NID_FLAG | nid;
- knew->private_value = nid;
-
- nid = side_mute_channel(spec);
- if (nid) {
- knew = via_clone_control(spec, &via_hp_mixer[1]);
- if (knew == NULL)
- return -ENOMEM;
- knew->subdevice = nid;
- }
return 0;
}
static void notify_aa_path_ctls(struct hda_codec *codec)
{
+ struct via_spec *spec = codec->spec;
int i;
- struct snd_ctl_elem_id id;
- const char *labels[] = {"Mic", "Front Mic", "Line", "Rear Mic"};
- struct snd_kcontrol *ctl;
-
- memset(&id, 0, sizeof(id));
- id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- for (i = 0; i < ARRAY_SIZE(labels); i++) {
- sprintf(id.name, "%s Playback Volume", labels[i]);
+
+ for (i = 0; i < spec->smart51_nums; i++) {
+ struct snd_kcontrol *ctl;
+ struct snd_ctl_elem_id id;
+ memset(&id, 0, sizeof(id));
+ id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ sprintf(id.name, "%s Playback Volume", spec->smart51_labels[i]);
ctl = snd_hda_find_mixer_ctl(codec, id.name);
if (ctl)
snd_ctl_notify(codec->bus->card,
@@ -876,66 +938,28 @@ static void notify_aa_path_ctls(struct hda_codec *codec)
static void mute_aa_path(struct hda_codec *codec, int mute)
{
struct via_spec *spec = codec->spec;
- hda_nid_t nid_mixer;
- int start_idx;
- int end_idx;
+ int val = mute ? HDA_AMP_MUTE : HDA_AMP_UNMUTE;
int i;
- /* get nid of MW0 and start & end index */
- switch (spec->codec_type) {
- case VT1708:
- nid_mixer = 0x17;
- start_idx = 2;
- end_idx = 4;
- break;
- case VT1709_10CH:
- case VT1709_6CH:
- nid_mixer = 0x18;
- start_idx = 2;
- end_idx = 4;
- break;
- case VT1708B_8CH:
- case VT1708B_4CH:
- case VT1708S:
- case VT1716S:
- nid_mixer = 0x16;
- start_idx = 2;
- end_idx = 4;
- break;
- case VT1718S:
- nid_mixer = 0x21;
- start_idx = 1;
- end_idx = 3;
- break;
- default:
- return;
- }
+
/* check AA path's mute status */
- for (i = start_idx; i <= end_idx; i++) {
- int val = mute ? HDA_AMP_MUTE : HDA_AMP_UNMUTE;
- snd_hda_codec_amp_stereo(codec, nid_mixer, HDA_INPUT, i,
+ for (i = 0; i < spec->smart51_nums; i++) {
+ if (spec->smart51_idxs[i] < 0)
+ continue;
+ snd_hda_codec_amp_stereo(codec, spec->aa_mix_nid,
+ HDA_INPUT, spec->smart51_idxs[i],
HDA_AMP_MUTE, val);
}
}
-static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin)
+
+static bool is_smart51_pins(struct hda_codec *codec, hda_nid_t pin)
{
- const struct auto_pin_cfg *cfg = &spec->autocfg;
+ struct via_spec *spec = codec->spec;
int i;
- for (i = 0; i < cfg->num_inputs; i++) {
- if (pin == cfg->inputs[i].pin)
- return cfg->inputs[i].type <= AUTO_PIN_LINE_IN;
- }
- return 0;
-}
-
-static int via_smart51_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1;
- return 0;
+ for (i = 0; i < spec->smart51_nums; i++)
+ if (spec->smart51_pins[i] == pin)
+ return true;
+ return false;
}
static int via_smart51_get(struct snd_kcontrol *kcontrol,
@@ -943,23 +967,8 @@ static int via_smart51_get(struct snd_kcontrol *kcontrol,
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct via_spec *spec = codec->spec;
- const struct auto_pin_cfg *cfg = &spec->autocfg;
- int on = 1;
- int i;
- for (i = 0; i < cfg->num_inputs; i++) {
- hda_nid_t nid = cfg->inputs[i].pin;
- int ctl = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
- if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
- continue;
- if (cfg->inputs[i].type == AUTO_PIN_MIC &&
- spec->hp_independent_mode && spec->codec_type != VT1718S)
- continue; /* ignore FMic for independent HP */
- if ((ctl & AC_PINCTL_IN_EN) && !(ctl & AC_PINCTL_OUT_EN))
- on = 0;
- }
- *ucontrol->value.integer.value = on;
+ *ucontrol->value.integer.value = spec->smart51_enabled;
return 0;
}
@@ -968,21 +977,14 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol,
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct via_spec *spec = codec->spec;
- const struct auto_pin_cfg *cfg = &spec->autocfg;
int out_in = *ucontrol->value.integer.value
? AC_PINCTL_OUT_EN : AC_PINCTL_IN_EN;
int i;
- for (i = 0; i < cfg->num_inputs; i++) {
- hda_nid_t nid = cfg->inputs[i].pin;
+ for (i = 0; i < spec->smart51_nums; i++) {
+ hda_nid_t nid = spec->smart51_pins[i];
unsigned int parm;
- if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
- continue;
- if (cfg->inputs[i].type == AUTO_PIN_MIC &&
- spec->hp_independent_mode && spec->codec_type != VT1718S)
- continue; /* don't retask FMic for independent HP */
-
parm = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
parm &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
@@ -994,171 +996,65 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol,
mute_aa_path(codec, 1);
notify_aa_path_ctls(codec);
}
- if (spec->codec_type == VT1718S) {
- snd_hda_codec_amp_stereo(
- codec, nid, HDA_OUTPUT, 0, HDA_AMP_MUTE,
- HDA_AMP_UNMUTE);
- }
- if (cfg->inputs[i].type == AUTO_PIN_MIC) {
- if (spec->codec_type == VT1708S
- || spec->codec_type == VT1716S) {
- /* input = index 1 (AOW3) */
- snd_hda_codec_write(
- codec, nid, 0,
- AC_VERB_SET_CONNECT_SEL, 1);
- snd_hda_codec_amp_stereo(
- codec, nid, HDA_OUTPUT,
- 0, HDA_AMP_MUTE, HDA_AMP_UNMUTE);
- }
- }
}
spec->smart51_enabled = *ucontrol->value.integer.value;
set_widgets_power_state(codec);
return 1;
}
-static const struct snd_kcontrol_new via_smart51_mixer[2] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Smart 5.1",
- .count = 1,
- .info = via_smart51_info,
- .get = via_smart51_get,
- .put = via_smart51_put,
- },
- {
- .iface = NID_MAPPING,
- .name = "Smart 5.1",
- }
+static const struct snd_kcontrol_new via_smart51_mixer = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Smart 5.1",
+ .count = 1,
+ .info = snd_ctl_boolean_mono_info,
+ .get = via_smart51_get,
+ .put = via_smart51_put,
};
-static int via_smart51_build(struct via_spec *spec)
+static int via_smart51_build(struct hda_codec *codec)
{
- struct snd_kcontrol_new *knew;
- const struct auto_pin_cfg *cfg = &spec->autocfg;
- hda_nid_t nid;
- int i;
+ struct via_spec *spec = codec->spec;
- if (!cfg)
+ if (!spec->smart51_nums)
return 0;
- if (cfg->line_outs > 2)
- return 0;
-
- knew = via_clone_control(spec, &via_smart51_mixer[0]);
- if (knew == NULL)
+ if (!via_clone_control(spec, &via_smart51_mixer))
return -ENOMEM;
-
- for (i = 0; i < cfg->num_inputs; i++) {
- nid = cfg->inputs[i].pin;
- if (cfg->inputs[i].type <= AUTO_PIN_LINE_IN) {
- knew = via_clone_control(spec, &via_smart51_mixer[1]);
- if (knew == NULL)
- return -ENOMEM;
- knew->subdevice = nid;
- break;
- }
- }
-
return 0;
}
-/* capture mixer elements */
-static const struct snd_kcontrol_new vt1708_capture_mixer[] = {
- HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x27, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x27, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* The multiple "Capture Source" controls confuse alsamixer
- * So call somewhat different..
- */
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 1,
- .info = via_mux_enum_info,
- .get = via_mux_enum_get,
- .put = via_mux_enum_put,
- },
- { } /* end */
-};
-
-/* check AA path's mute statue */
-static int is_aa_path_mute(struct hda_codec *codec)
+/* check AA path's mute status */
+static bool is_aa_path_mute(struct hda_codec *codec)
{
- int mute = 1;
- hda_nid_t nid_mixer;
- int start_idx;
- int end_idx;
- int i;
struct via_spec *spec = codec->spec;
- /* get nid of MW0 and start & end index */
- switch (spec->codec_type) {
- case VT1708B_8CH:
- case VT1708B_4CH:
- case VT1708S:
- case VT1716S:
- nid_mixer = 0x16;
- start_idx = 2;
- end_idx = 4;
- break;
- case VT1702:
- nid_mixer = 0x1a;
- start_idx = 1;
- end_idx = 3;
- break;
- case VT1718S:
- nid_mixer = 0x21;
- start_idx = 1;
- end_idx = 3;
- break;
- case VT2002P:
- case VT1812:
- case VT1802:
- nid_mixer = 0x21;
- start_idx = 0;
- end_idx = 2;
- break;
- default:
- return 0;
- }
- /* check AA path's mute status */
- for (i = start_idx; i <= end_idx; i++) {
- unsigned int con_list = snd_hda_codec_read(
- codec, nid_mixer, 0, AC_VERB_GET_CONNECT_LIST, i/4*4);
- int shift = 8 * (i % 4);
- hda_nid_t nid_pin = (con_list & (0xff << shift)) >> shift;
- unsigned int defconf = snd_hda_codec_get_pincfg(codec, nid_pin);
- if (get_defcfg_connect(defconf) == AC_JACK_PORT_COMPLEX) {
- /* check mute status while the pin is connected */
- int mute_l = snd_hda_codec_amp_read(codec, nid_mixer, 0,
- HDA_INPUT, i) >> 7;
- int mute_r = snd_hda_codec_amp_read(codec, nid_mixer, 1,
- HDA_INPUT, i) >> 7;
- if (!mute_l || !mute_r) {
- mute = 0;
- break;
- }
+ const struct hda_amp_list *p;
+ int i, ch, v;
+
+ for (i = 0; i < spec->num_loopbacks; i++) {
+ p = &spec->loopback_list[i];
+ for (ch = 0; ch < 2; ch++) {
+ v = snd_hda_codec_amp_read(codec, p->nid, ch, p->dir,
+ p->idx);
+ if (!(v & HDA_AMP_MUTE) && v > 0)
+ return false;
}
}
- return mute;
+ return true;
}
/* enter/exit analog low-current mode */
-static void analog_low_current_mode(struct hda_codec *codec, int stream_idle)
+static void __analog_low_current_mode(struct hda_codec *codec, bool force)
{
struct via_spec *spec = codec->spec;
- static int saved_stream_idle = 1; /* saved stream idle status */
- int enable = is_aa_path_mute(codec);
- unsigned int verb = 0;
- unsigned int parm = 0;
+ bool enable;
+ unsigned int verb, parm;
- if (stream_idle == -1) /* stream status did not change */
- enable = enable && saved_stream_idle;
- else {
- enable = enable && stream_idle;
- saved_stream_idle = stream_idle;
- }
+ if (spec->no_pin_power_ctl)
+ enable = false;
+ else
+ enable = is_aa_path_mute(codec) && !spec->opened_streams;
+ if (enable == spec->alc_mode && !force)
+ return;
+ spec->alc_mode = enable;
/* decide low current mode's verb & parameter */
switch (spec->codec_type) {
@@ -1190,122 +1086,77 @@ static void analog_low_current_mode(struct hda_codec *codec, int stream_idle)
snd_hda_codec_write(codec, codec->afg, 0, verb, parm);
}
+static void analog_low_current_mode(struct hda_codec *codec)
+{
+ return __analog_low_current_mode(codec, false);
+}
+
/*
* generic initialization of ADC, input mixers and output mixers
*/
-static const struct hda_verb vt1708_volume_init_verbs[] = {
- /*
- * Unmute ADC0-1 and set the default input to mic-in
- */
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-
- /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
- * mixer widget
- */
- /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
-
- /*
- * Set up output mixers (0x19 - 0x1b)
- */
- /* set vol=0 to output mixers */
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
- /* Setup default input MW0 to PW4 */
- {0x20, AC_VERB_SET_CONNECT_SEL, 0},
- /* PW9 Output enable */
- {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+static const struct hda_verb vt1708_init_verbs[] = {
/* power down jack detect function */
{0x1, 0xf81, 0x1},
{ }
};
-static int via_playback_pcm_open(struct hda_pcm_stream *hinfo,
+static void set_stream_open(struct hda_codec *codec, int bit, bool active)
+{
+ struct via_spec *spec = codec->spec;
+
+ if (active)
+ spec->opened_streams |= bit;
+ else
+ spec->opened_streams &= ~bit;
+ analog_low_current_mode(codec);
+}
+
+static int via_playback_multi_pcm_open(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
struct via_spec *spec = codec->spec;
- int idle = substream->pstr->substream_opened == 1
- && substream->ref_count == 0;
- analog_low_current_mode(codec, idle);
- return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
- hinfo);
+ const struct auto_pin_cfg *cfg = &spec->autocfg;
+ int err;
+
+ spec->multiout.num_dacs = cfg->line_outs + spec->smart51_nums;
+ spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+ set_stream_open(codec, STREAM_MULTI_OUT, true);
+ err = snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
+ hinfo);
+ if (err < 0) {
+ set_stream_open(codec, STREAM_MULTI_OUT, false);
+ return err;
+ }
+ return 0;
}
-static void playback_multi_pcm_prep_0(struct hda_codec *codec,
- unsigned int stream_tag,
- unsigned int format,
- struct snd_pcm_substream *substream)
+static int via_playback_multi_pcm_close(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ set_stream_open(codec, STREAM_MULTI_OUT, false);
+ return 0;
+}
+
+static int via_playback_hp_pcm_open(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
{
struct via_spec *spec = codec->spec;
- struct hda_multi_out *mout = &spec->multiout;
- const hda_nid_t *nids = mout->dac_nids;
- int chs = substream->runtime->channels;
- int i;
- mutex_lock(&codec->spdif_mutex);
- if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
- if (chs == 2 &&
- snd_hda_is_supported_format(codec, mout->dig_out_nid,
- format) &&
- !(codec->spdif_status & IEC958_AES0_NONAUDIO)) {
- mout->dig_out_used = HDA_DIG_ANALOG_DUP;
- /* turn off SPDIF once; otherwise the IEC958 bits won't
- * be updated */
- if (codec->spdif_ctls & AC_DIG1_ENABLE)
- snd_hda_codec_write(codec, mout->dig_out_nid, 0,
- AC_VERB_SET_DIGI_CONVERT_1,
- codec->spdif_ctls &
- ~AC_DIG1_ENABLE & 0xff);
- snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
- stream_tag, 0, format);
- /* turn on again (if needed) */
- if (codec->spdif_ctls & AC_DIG1_ENABLE)
- snd_hda_codec_write(codec, mout->dig_out_nid, 0,
- AC_VERB_SET_DIGI_CONVERT_1,
- codec->spdif_ctls & 0xff);
- } else {
- mout->dig_out_used = 0;
- snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
- 0, 0, 0);
- }
- }
- mutex_unlock(&codec->spdif_mutex);
-
- /* front */
- snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag,
- 0, format);
-
- if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT]
- && !spec->hp_independent_mode)
- /* headphone out will just decode front left/right (stereo) */
- snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag,
- 0, format);
-
- /* extra outputs copied from front */
- for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
- if (mout->extra_out_nid[i])
- snd_hda_codec_setup_stream(codec,
- mout->extra_out_nid[i],
- stream_tag, 0, format);
-
- /* surrounds */
- for (i = 1; i < mout->num_dacs; i++) {
- if (chs >= (i + 1) * 2) /* independent out */
- snd_hda_codec_setup_stream(codec, nids[i], stream_tag,
- i * 2, format);
- else /* copy front */
- snd_hda_codec_setup_stream(codec, nids[i], stream_tag,
- 0, format);
- }
+ if (snd_BUG_ON(!spec->hp_dac_nid))
+ return -EINVAL;
+ set_stream_open(codec, STREAM_INDEP_HP, true);
+ return 0;
+}
+
+static int via_playback_hp_pcm_close(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ set_stream_open(codec, STREAM_INDEP_HP, false);
+ return 0;
}
static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo,
@@ -1315,19 +1166,37 @@ static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo,
struct snd_pcm_substream *substream)
{
struct via_spec *spec = codec->spec;
- struct hda_multi_out *mout = &spec->multiout;
- const hda_nid_t *nids = mout->dac_nids;
- if (substream->number == 0)
- playback_multi_pcm_prep_0(codec, stream_tag, format,
- substream);
- else {
- if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
- spec->hp_independent_mode)
- snd_hda_codec_setup_stream(codec, mout->hp_nid,
- stream_tag, 0, format);
- }
- vt1708_start_hp_work(spec);
+ mutex_lock(&spec->config_mutex);
+ setup_playback_multi_pcm(spec);
+ snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
+ format, substream);
+ /* remember for dynamic DAC switch with indep-HP */
+ spec->active_streams |= STREAM_MULTI_OUT;
+ spec->cur_dac_stream_tag = stream_tag;
+ spec->cur_dac_format = format;
+ mutex_unlock(&spec->config_mutex);
+ vt1708_update_hp_work(spec);
+ return 0;
+}
+
+static int via_playback_hp_pcm_prepare(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ unsigned int stream_tag,
+ unsigned int format,
+ struct snd_pcm_substream *substream)
+{
+ struct via_spec *spec = codec->spec;
+
+ mutex_lock(&spec->config_mutex);
+ if (spec->hp_independent_mode)
+ snd_hda_codec_setup_stream(codec, spec->hp_dac_nid,
+ stream_tag, 0, format);
+ spec->active_streams |= STREAM_INDEP_HP;
+ spec->cur_hp_stream_tag = stream_tag;
+ spec->cur_hp_format = format;
+ mutex_unlock(&spec->config_mutex);
+ vt1708_update_hp_work(spec);
return 0;
}
@@ -1336,38 +1205,27 @@ static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo,
struct snd_pcm_substream *substream)
{
struct via_spec *spec = codec->spec;
- struct hda_multi_out *mout = &spec->multiout;
- const hda_nid_t *nids = mout->dac_nids;
- int i;
- if (substream->number == 0) {
- for (i = 0; i < mout->num_dacs; i++)
- snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0);
-
- if (mout->hp_nid && !spec->hp_independent_mode)
- snd_hda_codec_setup_stream(codec, mout->hp_nid,
- 0, 0, 0);
-
- for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
- if (mout->extra_out_nid[i])
- snd_hda_codec_setup_stream(codec,
- mout->extra_out_nid[i],
- 0, 0, 0);
- mutex_lock(&codec->spdif_mutex);
- if (mout->dig_out_nid &&
- mout->dig_out_used == HDA_DIG_ANALOG_DUP) {
- snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
- 0, 0, 0);
- mout->dig_out_used = 0;
- }
- mutex_unlock(&codec->spdif_mutex);
- } else {
- if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
- spec->hp_independent_mode)
- snd_hda_codec_setup_stream(codec, mout->hp_nid,
- 0, 0, 0);
- }
- vt1708_stop_hp_work(spec);
+ mutex_lock(&spec->config_mutex);
+ snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
+ spec->active_streams &= ~STREAM_MULTI_OUT;
+ mutex_unlock(&spec->config_mutex);
+ vt1708_update_hp_work(spec);
+ return 0;
+}
+
+static int via_playback_hp_pcm_cleanup(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct via_spec *spec = codec->spec;
+
+ mutex_lock(&spec->config_mutex);
+ if (spec->hp_independent_mode)
+ snd_hda_codec_setup_stream(codec, spec->hp_dac_nid, 0, 0, 0);
+ spec->active_streams &= ~STREAM_INDEP_HP;
+ mutex_unlock(&spec->config_mutex);
+ vt1708_update_hp_work(spec);
return 0;
}
@@ -1435,47 +1293,127 @@ static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
return 0;
}
-static const struct hda_pcm_stream vt1708_pcm_analog_playback = {
- .substreams = 2,
+/* analog capture with dynamic ADC switching */
+static int via_dyn_adc_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ unsigned int stream_tag,
+ unsigned int format,
+ struct snd_pcm_substream *substream)
+{
+ struct via_spec *spec = codec->spec;
+ int adc_idx = spec->inputs[spec->cur_mux[0]].adc_idx;
+
+ mutex_lock(&spec->config_mutex);
+ spec->cur_adc = spec->adc_nids[adc_idx];
+ spec->cur_adc_stream_tag = stream_tag;
+ spec->cur_adc_format = format;
+ snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
+ mutex_unlock(&spec->config_mutex);
+ return 0;
+}
+
+static int via_dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct via_spec *spec = codec->spec;
+
+ mutex_lock(&spec->config_mutex);
+ snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
+ spec->cur_adc = 0;
+ mutex_unlock(&spec->config_mutex);
+ return 0;
+}
+
+/* re-setup the stream if running; called from input-src put */
+static bool via_dyn_adc_pcm_resetup(struct hda_codec *codec, int cur)
+{
+ struct via_spec *spec = codec->spec;
+ int adc_idx = spec->inputs[cur].adc_idx;
+ hda_nid_t adc = spec->adc_nids[adc_idx];
+ bool ret = false;
+
+ mutex_lock(&spec->config_mutex);
+ if (spec->cur_adc && spec->cur_adc != adc) {
+ /* stream is running, let's swap the current ADC */
+ __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
+ spec->cur_adc = adc;
+ snd_hda_codec_setup_stream(codec, adc,
+ spec->cur_adc_stream_tag, 0,
+ spec->cur_adc_format);
+ ret = true;
+ }
+ mutex_unlock(&spec->config_mutex);
+ return ret;
+}
+
+static const struct hda_pcm_stream via_pcm_analog_playback = {
+ .substreams = 1,
.channels_min = 2,
.channels_max = 8,
- .nid = 0x10, /* NID to query formats and rates */
+ /* NID is set in via_build_pcms */
.ops = {
- .open = via_playback_pcm_open,
+ .open = via_playback_multi_pcm_open,
+ .close = via_playback_multi_pcm_close,
.prepare = via_playback_multi_pcm_prepare,
.cleanup = via_playback_multi_pcm_cleanup
},
};
+static const struct hda_pcm_stream via_pcm_hp_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ /* NID is set in via_build_pcms */
+ .ops = {
+ .open = via_playback_hp_pcm_open,
+ .close = via_playback_hp_pcm_close,
+ .prepare = via_playback_hp_pcm_prepare,
+ .cleanup = via_playback_hp_pcm_cleanup
+ },
+};
+
static const struct hda_pcm_stream vt1708_pcm_analog_s16_playback = {
- .substreams = 2,
+ .substreams = 1,
.channels_min = 2,
.channels_max = 8,
- .nid = 0x10, /* NID to query formats and rates */
+ /* NID is set in via_build_pcms */
/* We got noisy outputs on the right channel on VT1708 when
* 24bit samples are used. Until any workaround is found,
* disable the 24bit format, so far.
*/
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.ops = {
- .open = via_playback_pcm_open,
+ .open = via_playback_multi_pcm_open,
+ .close = via_playback_multi_pcm_close,
.prepare = via_playback_multi_pcm_prepare,
.cleanup = via_playback_multi_pcm_cleanup
},
};
-static const struct hda_pcm_stream vt1708_pcm_analog_capture = {
- .substreams = 2,
+static const struct hda_pcm_stream via_pcm_analog_capture = {
+ .substreams = 1, /* will be changed in via_build_pcms() */
.channels_min = 2,
.channels_max = 2,
- .nid = 0x15, /* NID to query formats and rates */
+ /* NID is set in via_build_pcms */
.ops = {
.prepare = via_capture_pcm_prepare,
.cleanup = via_capture_pcm_cleanup
},
};
-static const struct hda_pcm_stream vt1708_pcm_digital_playback = {
+static const struct hda_pcm_stream via_pcm_dyn_adc_analog_capture = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ /* NID is set in via_build_pcms */
+ .ops = {
+ .prepare = via_dyn_adc_capture_pcm_prepare,
+ .cleanup = via_dyn_adc_capture_pcm_cleanup,
+ },
+};
+
+static const struct hda_pcm_stream via_pcm_digital_playback = {
.substreams = 1,
.channels_min = 2,
.channels_max = 2,
@@ -1488,19 +1426,48 @@ static const struct hda_pcm_stream vt1708_pcm_digital_playback = {
},
};
-static const struct hda_pcm_stream vt1708_pcm_digital_capture = {
+static const struct hda_pcm_stream via_pcm_digital_capture = {
.substreams = 1,
.channels_min = 2,
.channels_max = 2,
};
+/*
+ * slave controls for virtual master
+ */
+static const char * const via_slave_vols[] = {
+ "Front Playback Volume",
+ "Surround Playback Volume",
+ "Center Playback Volume",
+ "LFE Playback Volume",
+ "Side Playback Volume",
+ "Headphone Playback Volume",
+ "Speaker Playback Volume",
+ NULL,
+};
+
+static const char * const via_slave_sws[] = {
+ "Front Playback Switch",
+ "Surround Playback Switch",
+ "Center Playback Switch",
+ "LFE Playback Switch",
+ "Side Playback Switch",
+ "Headphone Playback Switch",
+ "Speaker Playback Switch",
+ NULL,
+};
+
static int via_build_controls(struct hda_codec *codec)
{
struct via_spec *spec = codec->spec;
struct snd_kcontrol *kctl;
- const struct snd_kcontrol_new *knew;
int err, i;
+ spec->no_pin_power_ctl = 1;
+ if (spec->set_widgets_power_state)
+ if (!via_clone_control(spec, &via_pin_power_ctl_enum))
+ return -ENOMEM;
+
for (i = 0; i < spec->num_mixers; i++) {
err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
if (err < 0)
@@ -1509,6 +1476,7 @@ static int via_build_controls(struct hda_codec *codec)
if (spec->multiout.dig_out_nid) {
err = snd_hda_create_spdif_out_ctls(codec,
+ spec->multiout.dig_out_nid,
spec->multiout.dig_out_nid);
if (err < 0)
return err;
@@ -1524,6 +1492,23 @@ static int via_build_controls(struct hda_codec *codec)
return err;
}
+ /* if we have no master control, let's create it */
+ if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
+ unsigned int vmaster_tlv[4];
+ snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
+ HDA_OUTPUT, vmaster_tlv);
+ err = snd_hda_add_vmaster(codec, "Master Playback Volume",
+ vmaster_tlv, via_slave_vols);
+ if (err < 0)
+ return err;
+ }
+ if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
+ err = snd_hda_add_vmaster(codec, "Master Playback Switch",
+ NULL, via_slave_sws);
+ if (err < 0)
+ return err;
+ }
+
/* assign Capture Source enums to NID */
kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
for (i = 0; kctl && i < kctl->count; i++) {
@@ -1532,23 +1517,6 @@ static int via_build_controls(struct hda_codec *codec)
return err;
}
- /* other nid->control mapping */
- for (i = 0; i < spec->num_mixers; i++) {
- for (knew = spec->mixers[i]; knew->name; knew++) {
- if (knew->iface != NID_MAPPING)
- continue;
- kctl = snd_hda_find_mixer_ctl(codec, knew->name);
- if (kctl == NULL)
- continue;
- err = snd_hda_add_nid(codec, kctl, 0,
- knew->subdevice);
- }
- }
-
- /* init power states */
- set_widgets_power_state(codec);
- analog_low_current_mode(codec, 1);
-
via_free_kctls(codec); /* no longer needed */
return 0;
}
@@ -1558,39 +1526,86 @@ static int via_build_pcms(struct hda_codec *codec)
struct via_spec *spec = codec->spec;
struct hda_pcm *info = spec->pcm_rec;
- codec->num_pcms = 1;
+ codec->num_pcms = 0;
codec->pcm_info = info;
- info->name = spec->stream_name_analog;
- info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
- *(spec->stream_analog_playback);
- info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
- spec->multiout.dac_nids[0];
- info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
- info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
+ if (spec->multiout.num_dacs || spec->num_adc_nids) {
+ snprintf(spec->stream_name_analog,
+ sizeof(spec->stream_name_analog),
+ "%s Analog", codec->chip_name);
+ info->name = spec->stream_name_analog;
- info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
- spec->multiout.max_channels;
+ if (spec->multiout.num_dacs) {
+ if (!spec->stream_analog_playback)
+ spec->stream_analog_playback =
+ &via_pcm_analog_playback;
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
+ *spec->stream_analog_playback;
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
+ spec->multiout.dac_nids[0];
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
+ spec->multiout.max_channels;
+ }
- if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
+ if (!spec->stream_analog_capture) {
+ if (spec->dyn_adc_switch)
+ spec->stream_analog_capture =
+ &via_pcm_dyn_adc_analog_capture;
+ else
+ spec->stream_analog_capture =
+ &via_pcm_analog_capture;
+ }
+ if (spec->num_adc_nids) {
+ info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+ *spec->stream_analog_capture;
+ info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
+ spec->adc_nids[0];
+ if (!spec->dyn_adc_switch)
+ info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
+ spec->num_adc_nids;
+ }
codec->num_pcms++;
info++;
+ }
+
+ if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
+ snprintf(spec->stream_name_digital,
+ sizeof(spec->stream_name_digital),
+ "%s Digital", codec->chip_name);
info->name = spec->stream_name_digital;
info->pcm_type = HDA_PCM_TYPE_SPDIF;
if (spec->multiout.dig_out_nid) {
+ if (!spec->stream_digital_playback)
+ spec->stream_digital_playback =
+ &via_pcm_digital_playback;
info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
- *(spec->stream_digital_playback);
+ *spec->stream_digital_playback;
info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
spec->multiout.dig_out_nid;
}
if (spec->dig_in_nid) {
+ if (!spec->stream_digital_capture)
+ spec->stream_digital_capture =
+ &via_pcm_digital_capture;
info->stream[SNDRV_PCM_STREAM_CAPTURE] =
- *(spec->stream_digital_capture);
+ *spec->stream_digital_capture;
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
spec->dig_in_nid;
}
+ codec->num_pcms++;
+ info++;
}
+ if (spec->hp_dac_nid) {
+ snprintf(spec->stream_name_hp, sizeof(spec->stream_name_hp),
+ "%s HP", codec->chip_name);
+ info->name = spec->stream_name_hp;
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] = via_pcm_hp_playback;
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
+ spec->hp_dac_nid;
+ codec->num_pcms++;
+ info++;
+ }
return 0;
}
@@ -1603,57 +1618,63 @@ static void via_free(struct hda_codec *codec)
via_free_kctls(codec);
vt1708_stop_hp_work(spec);
- kfree(codec->spec);
+ kfree(spec->bind_cap_vol);
+ kfree(spec->bind_cap_sw);
+ kfree(spec);
}
-/* mute internal speaker if HP is plugged */
-static void via_hp_automute(struct hda_codec *codec)
+/* mute/unmute outputs */
+static void toggle_output_mutes(struct hda_codec *codec, int num_pins,
+ hda_nid_t *pins, bool mute)
{
- unsigned int present = 0;
- struct via_spec *spec = codec->spec;
-
- present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]);
-
- if (!spec->hp_independent_mode) {
- struct snd_ctl_elem_id id;
- /* auto mute */
- snd_hda_codec_amp_stereo(
- codec, spec->autocfg.line_out_pins[0], HDA_OUTPUT, 0,
- HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
- /* notify change */
- memset(&id, 0, sizeof(id));
- id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- strcpy(id.name, "Front Playback Switch");
- snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE,
- &id);
+ int i;
+ for (i = 0; i < num_pins; i++) {
+ unsigned int parm = snd_hda_codec_read(codec, pins[i], 0,
+ AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+ if (parm & AC_PINCTL_IN_EN)
+ continue;
+ if (mute)
+ parm &= ~AC_PINCTL_OUT_EN;
+ else
+ parm |= AC_PINCTL_OUT_EN;
+ snd_hda_codec_write(codec, pins[i], 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, parm);
}
}
-/* mute mono out if HP or Line out is plugged */
-static void via_mono_automute(struct hda_codec *codec)
+/* mute internal speaker if line-out is plugged */
+static void via_line_automute(struct hda_codec *codec, int present)
{
- unsigned int hp_present, lineout_present;
struct via_spec *spec = codec->spec;
- if (spec->codec_type != VT1716S)
+ if (!spec->autocfg.speaker_outs)
return;
-
- lineout_present = snd_hda_jack_detect(codec,
+ if (!present)
+ present = snd_hda_jack_detect(codec,
spec->autocfg.line_out_pins[0]);
+ toggle_output_mutes(codec, spec->autocfg.speaker_outs,
+ spec->autocfg.speaker_pins,
+ present);
+}
- /* Mute Mono Out if Line Out is plugged */
- if (lineout_present) {
- snd_hda_codec_amp_stereo(
- codec, 0x2A, HDA_OUTPUT, 0, HDA_AMP_MUTE, HDA_AMP_MUTE);
- return;
- }
+/* mute internal speaker if HP is plugged */
+static void via_hp_automute(struct hda_codec *codec)
+{
+ int present = 0;
+ int nums;
+ struct via_spec *spec = codec->spec;
- hp_present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]);
+ if (!spec->hp_independent_mode && spec->autocfg.hp_pins[0] &&
+ (spec->codec_type != VT1708 || spec->vt1708_jack_detect))
+ present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]);
- if (!spec->hp_independent_mode)
- snd_hda_codec_amp_stereo(
- codec, 0x2A, HDA_OUTPUT, 0, HDA_AMP_MUTE,
- hp_present ? HDA_AMP_MUTE : 0);
+ if (spec->smart51_enabled)
+ nums = spec->autocfg.line_outs + spec->smart51_nums;
+ else
+ nums = spec->autocfg.line_outs;
+ toggle_output_mutes(codec, nums, spec->autocfg.line_out_pins, present);
+
+ via_line_automute(codec, present);
}
static void via_gpio_control(struct hda_codec *codec)
@@ -1678,9 +1699,9 @@ static void via_gpio_control(struct hda_codec *codec)
if (gpio_data == 0x02) {
/* unmute line out */
- snd_hda_codec_amp_stereo(codec, spec->autocfg.line_out_pins[0],
- HDA_OUTPUT, 0, HDA_AMP_MUTE, 0);
-
+ snd_hda_codec_write(codec, spec->autocfg.line_out_pins[0], 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
+ PIN_OUT);
if (vol_counter & 0x20) {
/* decrease volume */
if (vol > master_vol)
@@ -1697,73 +1718,12 @@ static void via_gpio_control(struct hda_codec *codec)
}
} else if (!(gpio_data & 0x02)) {
/* mute line out */
- snd_hda_codec_amp_stereo(codec,
- spec->autocfg.line_out_pins[0],
- HDA_OUTPUT, 0, HDA_AMP_MUTE,
- HDA_AMP_MUTE);
- }
-}
-
-/* mute Internal-Speaker if HP is plugged */
-static void via_speaker_automute(struct hda_codec *codec)
-{
- unsigned int hp_present;
- struct via_spec *spec = codec->spec;
-
- if (!VT2002P_COMPATIBLE(spec))
- return;
-
- hp_present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]);
-
- if (!spec->hp_independent_mode) {
- struct snd_ctl_elem_id id;
- snd_hda_codec_amp_stereo(
- codec, spec->autocfg.speaker_pins[0], HDA_OUTPUT, 0,
- HDA_AMP_MUTE, hp_present ? HDA_AMP_MUTE : 0);
- /* notify change */
- memset(&id, 0, sizeof(id));
- id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- strcpy(id.name, "Speaker Playback Switch");
- snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE,
- &id);
- }
-}
-
-/* mute line-out and internal speaker if HP is plugged */
-static void via_hp_bind_automute(struct hda_codec *codec)
-{
- /* use long instead of int below just to avoid an internal compiler
- * error with gcc 4.0.x
- */
- unsigned long hp_present, present = 0;
- struct via_spec *spec = codec->spec;
- int i;
-
- if (!spec->autocfg.hp_pins[0] || !spec->autocfg.line_out_pins[0])
- return;
-
- hp_present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]);
-
- present = snd_hda_jack_detect(codec, spec->autocfg.line_out_pins[0]);
-
- if (!spec->hp_independent_mode) {
- /* Mute Line-Outs */
- for (i = 0; i < spec->autocfg.line_outs; i++)
- snd_hda_codec_amp_stereo(
- codec, spec->autocfg.line_out_pins[i],
- HDA_OUTPUT, 0,
- HDA_AMP_MUTE, hp_present ? HDA_AMP_MUTE : 0);
- if (hp_present)
- present = hp_present;
+ snd_hda_codec_write(codec, spec->autocfg.line_out_pins[0], 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
+ 0);
}
- /* Speakers */
- for (i = 0; i < spec->autocfg.speaker_outs; i++)
- snd_hda_codec_amp_stereo(
- codec, spec->autocfg.speaker_pins[i], HDA_OUTPUT, 0,
- HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
}
-
/* unsolicited event for jack sensing */
static void via_unsol_event(struct hda_codec *codec,
unsigned int res)
@@ -1775,46 +1735,13 @@ static void via_unsol_event(struct hda_codec *codec,
res &= ~VIA_JACK_EVENT;
- if (res == VIA_HP_EVENT)
+ if (res == VIA_HP_EVENT || res == VIA_LINE_EVENT)
via_hp_automute(codec);
else if (res == VIA_GPIO_EVENT)
via_gpio_control(codec);
- else if (res == VIA_MONO_EVENT)
- via_mono_automute(codec);
- else if (res == VIA_SPEAKER_EVENT)
- via_speaker_automute(codec);
- else if (res == VIA_BIND_HP_EVENT)
- via_hp_bind_automute(codec);
}
-static int via_init(struct hda_codec *codec)
-{
- struct via_spec *spec = codec->spec;
- int i;
- for (i = 0; i < spec->num_iverbs; i++)
- snd_hda_sequence_write(codec, spec->init_verbs[i]);
-
- /* Lydia Add for EAPD enable */
- if (!spec->dig_in_nid) { /* No Digital In connection */
- if (spec->dig_in_pin) {
- snd_hda_codec_write(codec, spec->dig_in_pin, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
- PIN_OUT);
- snd_hda_codec_write(codec, spec->dig_in_pin, 0,
- AC_VERB_SET_EAPD_BTLENABLE, 0x02);
- }
- } else /* enable SPDIF-input pin */
- snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
-
- /* assign slave outs */
- if (spec->slave_dig_outs[0])
- codec->slave_dig_outs = spec->slave_dig_outs;
-
- return 0;
-}
-
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
static int via_suspend(struct hda_codec *codec, pm_message_t state)
{
struct via_spec *spec = codec->spec;
@@ -1833,12 +1760,16 @@ static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)
/*
*/
+
+static int via_init(struct hda_codec *codec);
+
static const struct hda_codec_ops via_patch_ops = {
.build_controls = via_build_controls,
.build_pcms = via_build_pcms,
.init = via_init,
.free = via_free,
-#ifdef SND_HDA_NEEDS_RESUME
+ .unsol_event = via_unsol_event,
+#ifdef CONFIG_PM
.suspend = via_suspend,
#endif
#ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -1846,237 +1777,835 @@ static const struct hda_codec_ops via_patch_ops = {
#endif
};
-/* fill in the dac_nids table from the parsed pin configuration */
-static int vt1708_auto_fill_dac_nids(struct via_spec *spec,
- const struct auto_pin_cfg *cfg)
+static bool is_empty_dac(struct hda_codec *codec, hda_nid_t dac)
{
+ struct via_spec *spec = codec->spec;
int i;
- hda_nid_t nid;
- spec->multiout.num_dacs = cfg->line_outs;
+ for (i = 0; i < spec->multiout.num_dacs; i++) {
+ if (spec->multiout.dac_nids[i] == dac)
+ return false;
+ }
+ if (spec->hp_dac_nid == dac)
+ return false;
+ return true;
+}
- spec->multiout.dac_nids = spec->private_dac_nids;
+static bool __parse_output_path(struct hda_codec *codec, hda_nid_t nid,
+ hda_nid_t target_dac, int with_aa_mix,
+ struct nid_path *path, int depth)
+{
+ struct via_spec *spec = codec->spec;
+ hda_nid_t conn[8];
+ int i, nums;
+
+ if (nid == spec->aa_mix_nid) {
+ if (!with_aa_mix)
+ return false;
+ with_aa_mix = 2; /* mark aa-mix is included */
+ }
+
+ nums = snd_hda_get_connections(codec, nid, conn, ARRAY_SIZE(conn));
+ for (i = 0; i < nums; i++) {
+ if (get_wcaps_type(get_wcaps(codec, conn[i])) != AC_WID_AUD_OUT)
+ continue;
+ if (conn[i] == target_dac || is_empty_dac(codec, conn[i])) {
+ /* aa-mix is requested but not included? */
+ if (!(spec->aa_mix_nid && with_aa_mix == 1))
+ goto found;
+ }
+ }
+ if (depth >= MAX_NID_PATH_DEPTH)
+ return false;
+ for (i = 0; i < nums; i++) {
+ unsigned int type;
+ type = get_wcaps_type(get_wcaps(codec, conn[i]));
+ if (type == AC_WID_AUD_OUT)
+ continue;
+ if (__parse_output_path(codec, conn[i], target_dac,
+ with_aa_mix, path, depth + 1))
+ goto found;
+ }
+ return false;
- for (i = 0; i < 4; i++) {
+ found:
+ path->path[path->depth] = conn[i];
+ path->idx[path->depth] = i;
+ if (nums > 1 && get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_MIX)
+ path->multi[path->depth] = 1;
+ path->depth++;
+ return true;
+}
+
+static bool parse_output_path(struct hda_codec *codec, hda_nid_t nid,
+ hda_nid_t target_dac, int with_aa_mix,
+ struct nid_path *path)
+{
+ if (__parse_output_path(codec, nid, target_dac, with_aa_mix, path, 1)) {
+ path->path[path->depth] = nid;
+ path->depth++;
+ snd_printdd("output-path: depth=%d, %02x/%02x/%02x/%02x/%02x\n",
+ path->depth, path->path[0], path->path[1],
+ path->path[2], path->path[3], path->path[4]);
+ return true;
+ }
+ return false;
+}
+
+static int via_auto_fill_dac_nids(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ const struct auto_pin_cfg *cfg = &spec->autocfg;
+ int i;
+ hda_nid_t nid;
+
+ spec->multiout.num_dacs = 0;
+ spec->multiout.dac_nids = spec->private_dac_nids;
+ for (i = 0; i < cfg->line_outs; i++) {
+ hda_nid_t dac = 0;
nid = cfg->line_out_pins[i];
- if (nid) {
- /* config dac list */
- switch (i) {
- case AUTO_SEQ_FRONT:
- spec->private_dac_nids[i] = 0x10;
- break;
- case AUTO_SEQ_CENLFE:
- spec->private_dac_nids[i] = 0x12;
- break;
- case AUTO_SEQ_SURROUND:
- spec->private_dac_nids[i] = 0x11;
- break;
- case AUTO_SEQ_SIDE:
- spec->private_dac_nids[i] = 0x13;
+ if (!nid)
+ continue;
+ if (parse_output_path(codec, nid, 0, 0, &spec->out_path[i]))
+ dac = spec->out_path[i].path[0];
+ if (!i && parse_output_path(codec, nid, dac, 1,
+ &spec->out_mix_path))
+ dac = spec->out_mix_path.path[0];
+ if (dac)
+ spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
+ }
+ if (!spec->out_path[0].depth && spec->out_mix_path.depth) {
+ spec->out_path[0] = spec->out_mix_path;
+ spec->out_mix_path.depth = 0;
+ }
+ return 0;
+}
+
+static int create_ch_ctls(struct hda_codec *codec, const char *pfx,
+ int chs, bool check_dac, struct nid_path *path)
+{
+ struct via_spec *spec = codec->spec;
+ char name[32];
+ hda_nid_t dac, pin, sel, nid;
+ int err;
+
+ dac = check_dac ? path->path[0] : 0;
+ pin = path->path[path->depth - 1];
+ sel = path->depth > 1 ? path->path[1] : 0;
+
+ if (dac && check_amp_caps(codec, dac, HDA_OUTPUT, AC_AMPCAP_NUM_STEPS))
+ nid = dac;
+ else if (check_amp_caps(codec, pin, HDA_OUTPUT, AC_AMPCAP_NUM_STEPS))
+ nid = pin;
+ else if (check_amp_caps(codec, sel, HDA_OUTPUT, AC_AMPCAP_NUM_STEPS))
+ nid = sel;
+ else
+ nid = 0;
+ if (nid) {
+ sprintf(name, "%s Playback Volume", pfx);
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+ HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ path->vol_ctl = nid;
+ }
+
+ if (dac && check_amp_caps(codec, dac, HDA_OUTPUT, AC_AMPCAP_MUTE))
+ nid = dac;
+ else if (check_amp_caps(codec, pin, HDA_OUTPUT, AC_AMPCAP_MUTE))
+ nid = pin;
+ else if (check_amp_caps(codec, sel, HDA_OUTPUT, AC_AMPCAP_MUTE))
+ nid = sel;
+ else
+ nid = 0;
+ if (nid) {
+ sprintf(name, "%s Playback Switch", pfx);
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
+ HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ path->mute_ctl = nid;
+ }
+ return 0;
+}
+
+static void mangle_smart51(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ struct auto_pin_cfg_item *ins = cfg->inputs;
+ int i, j, nums, attr;
+ int pins[AUTO_CFG_MAX_INS];
+
+ for (attr = INPUT_PIN_ATTR_REAR; attr >= INPUT_PIN_ATTR_NORMAL; attr--) {
+ nums = 0;
+ for (i = 0; i < cfg->num_inputs; i++) {
+ unsigned int def;
+ if (ins[i].type > AUTO_PIN_LINE_IN)
+ continue;
+ def = snd_hda_codec_get_pincfg(codec, ins[i].pin);
+ if (snd_hda_get_input_pin_attr(def) != attr)
+ continue;
+ for (j = 0; j < nums; j++)
+ if (ins[pins[j]].type < ins[i].type) {
+ memmove(pins + j + 1, pins + j,
+ (nums - j) * sizeof(int));
+ break;
+ }
+ pins[j] = i;
+ nums++;
+ }
+ if (cfg->line_outs + nums < 3)
+ continue;
+ for (i = 0; i < nums; i++) {
+ hda_nid_t pin = ins[pins[i]].pin;
+ spec->smart51_pins[spec->smart51_nums++] = pin;
+ cfg->line_out_pins[cfg->line_outs++] = pin;
+ if (cfg->line_outs == 3)
break;
- }
}
+ return;
}
+}
- return 0;
+static void copy_path_mixer_ctls(struct nid_path *dst, struct nid_path *src)
+{
+ dst->vol_ctl = src->vol_ctl;
+ dst->mute_ctl = src->mute_ctl;
}
/* add playback controls from the parsed DAC table */
-static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,
- const struct auto_pin_cfg *cfg)
+static int via_auto_create_multi_out_ctls(struct hda_codec *codec)
{
- char name[32];
+ struct via_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ struct nid_path *path;
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;
+ int i, idx, err;
+ int old_line_outs;
- for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
- nid = cfg->line_out_pins[i];
+ /* check smart51 */
+ old_line_outs = cfg->line_outs;
+ if (cfg->line_outs == 1)
+ mangle_smart51(codec);
- if (!nid)
- continue;
-
- nid_vol = nid_vols[i];
-
- if (i == AUTO_SEQ_CENLFE) {
- /* Center/LFE */
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
- "Center Playback Volume",
- HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
- "LFE Playback Volume",
- HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
- "Center Playback Switch",
- HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
- "LFE Playback Switch",
- HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- } else if (i == AUTO_SEQ_FRONT) {
- /* add control to mixer index 0 */
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
- "Master Front Playback Volume",
- HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
- HDA_INPUT));
- if (err < 0)
- return err;
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
- "Master Front Playback Switch",
- HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
- HDA_INPUT));
- if (err < 0)
- return err;
+ err = via_auto_fill_dac_nids(codec);
+ if (err < 0)
+ return err;
- /* add control to PW3 */
- sprintf(name, "%s Playback Volume", chname[i]);
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
- HDA_COMPOSE_AMP_VAL(nid, 3, 0,
- HDA_OUTPUT));
+ if (spec->multiout.num_dacs < 3) {
+ spec->smart51_nums = 0;
+ cfg->line_outs = old_line_outs;
+ }
+ for (i = 0; i < cfg->line_outs; i++) {
+ hda_nid_t pin, dac;
+ pin = cfg->line_out_pins[i];
+ dac = spec->multiout.dac_nids[i];
+ if (!pin || !dac)
+ continue;
+ path = spec->out_path + i;
+ if (i == HDA_CLFE) {
+ err = create_ch_ctls(codec, "Center", 1, true, path);
if (err < 0)
return err;
- sprintf(name, "%s Playback Switch", chname[i]);
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
- HDA_COMPOSE_AMP_VAL(nid, 3, 0,
- HDA_OUTPUT));
+ err = create_ch_ctls(codec, "LFE", 2, true, path);
if (err < 0)
return err;
} else {
- sprintf(name, "%s Playback Volume", chname[i]);
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
- HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- sprintf(name, "%s Playback Switch", chname[i]);
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
- HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
- HDA_OUTPUT));
+ const char *pfx = chname[i];
+ if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT &&
+ cfg->line_outs == 1)
+ pfx = "Speaker";
+ err = create_ch_ctls(codec, pfx, 3, true, path);
if (err < 0)
return err;
}
+ if (path != spec->out_path + i)
+ copy_path_mixer_ctls(&spec->out_path[i], path);
+ if (path == spec->out_path && spec->out_mix_path.depth)
+ copy_path_mixer_ctls(&spec->out_mix_path, path);
+ }
+
+ idx = get_connection_index(codec, spec->aa_mix_nid,
+ spec->multiout.dac_nids[0]);
+ if (idx >= 0) {
+ /* add control to mixer */
+ const char *name;
+ name = spec->out_mix_path.depth ?
+ "PCM Loopback Playback Volume" : "PCM Playback Volume";
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+ HDA_COMPOSE_AMP_VAL(spec->aa_mix_nid, 3,
+ idx, HDA_INPUT));
+ if (err < 0)
+ return err;
+ name = spec->out_mix_path.depth ?
+ "PCM Loopback Playback Switch" : "PCM Playback Switch";
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
+ HDA_COMPOSE_AMP_VAL(spec->aa_mix_nid, 3,
+ idx, HDA_INPUT));
+ if (err < 0)
+ return err;
}
+ cfg->line_outs = old_line_outs;
+
return 0;
}
-static void create_hp_imux(struct via_spec *spec)
+static int via_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
{
- int i;
- struct hda_input_mux *imux = &spec->private_imux[1];
- static const char * const texts[] = { "OFF", "ON", NULL};
+ struct via_spec *spec = codec->spec;
+ struct nid_path *path;
+ bool check_dac;
+ int i, err;
- /* for hp mode select */
- for (i = 0; texts[i]; i++)
- snd_hda_add_imux_item(imux, texts[i], i, NULL);
+ if (!pin)
+ return 0;
- spec->hp_mux = &spec->private_imux[1];
+ if (!parse_output_path(codec, pin, 0, 0, &spec->hp_indep_path)) {
+ for (i = HDA_SIDE; i >= HDA_CLFE; i--) {
+ if (i < spec->multiout.num_dacs &&
+ parse_output_path(codec, pin,
+ spec->multiout.dac_nids[i], 0,
+ &spec->hp_indep_path)) {
+ spec->hp_indep_shared = i;
+ break;
+ }
+ }
+ }
+ if (spec->hp_indep_path.depth) {
+ spec->hp_dac_nid = spec->hp_indep_path.path[0];
+ if (!spec->hp_indep_shared)
+ spec->hp_path = spec->hp_indep_path;
+ }
+ /* optionally check front-path w/o AA-mix */
+ if (!spec->hp_path.depth)
+ parse_output_path(codec, pin,
+ spec->multiout.dac_nids[HDA_FRONT], 0,
+ &spec->hp_path);
+
+ if (!parse_output_path(codec, pin, spec->multiout.dac_nids[HDA_FRONT],
+ 1, &spec->hp_mix_path) && !spec->hp_path.depth)
+ return 0;
+
+ if (spec->hp_path.depth) {
+ path = &spec->hp_path;
+ check_dac = true;
+ } else {
+ path = &spec->hp_mix_path;
+ check_dac = false;
+ }
+ err = create_ch_ctls(codec, "Headphone", 3, check_dac, path);
+ if (err < 0)
+ return err;
+ if (check_dac)
+ copy_path_mixer_ctls(&spec->hp_mix_path, path);
+ else
+ copy_path_mixer_ctls(&spec->hp_path, path);
+ if (spec->hp_indep_path.depth)
+ copy_path_mixer_ctls(&spec->hp_indep_path, path);
+ return 0;
}
-static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
+static int via_auto_create_speaker_ctls(struct hda_codec *codec)
{
+ struct via_spec *spec = codec->spec;
+ struct nid_path *path;
+ bool check_dac;
+ hda_nid_t pin, dac = 0;
int err;
- if (!pin)
+ pin = spec->autocfg.speaker_pins[0];
+ if (!spec->autocfg.speaker_outs || !pin)
return 0;
- spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */
- spec->hp_independent_mode_index = 1;
+ if (parse_output_path(codec, pin, 0, 0, &spec->speaker_path))
+ dac = spec->speaker_path.path[0];
+ if (!dac)
+ parse_output_path(codec, pin,
+ spec->multiout.dac_nids[HDA_FRONT], 0,
+ &spec->speaker_path);
+ if (!parse_output_path(codec, pin, spec->multiout.dac_nids[HDA_FRONT],
+ 1, &spec->speaker_mix_path) && !dac)
+ return 0;
+
+ /* no AA-path for front? */
+ if (!spec->out_mix_path.depth && spec->speaker_mix_path.depth)
+ dac = 0;
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
- "Headphone Playback Volume",
- HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+ spec->speaker_dac_nid = dac;
+ spec->multiout.extra_out_nid[0] = dac;
+ if (dac) {
+ path = &spec->speaker_path;
+ check_dac = true;
+ } else {
+ path = &spec->speaker_mix_path;
+ check_dac = false;
+ }
+ err = create_ch_ctls(codec, "Speaker", 3, check_dac, path);
if (err < 0)
return err;
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
- "Headphone Playback Switch",
- HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+ if (check_dac)
+ copy_path_mixer_ctls(&spec->speaker_mix_path, path);
+ else
+ copy_path_mixer_ctls(&spec->speaker_path, path);
+ return 0;
+}
+
+#define via_aamix_ctl_info via_pin_power_ctl_info
+
+static int via_aamix_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct via_spec *spec = codec->spec;
+ ucontrol->value.enumerated.item[0] = spec->aamix_mode;
+ return 0;
+}
+
+static void update_aamix_paths(struct hda_codec *codec, int do_mix,
+ struct nid_path *nomix, struct nid_path *mix)
+{
+ if (do_mix) {
+ activate_output_path(codec, nomix, false, false);
+ activate_output_path(codec, mix, true, false);
+ } else {
+ activate_output_path(codec, mix, false, false);
+ activate_output_path(codec, nomix, true, false);
+ }
+}
+
+static int via_aamix_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct via_spec *spec = codec->spec;
+ unsigned int val = ucontrol->value.enumerated.item[0];
+
+ if (val == spec->aamix_mode)
+ return 0;
+ spec->aamix_mode = val;
+ /* update front path */
+ update_aamix_paths(codec, val, &spec->out_path[0], &spec->out_mix_path);
+ /* update HP path */
+ if (!spec->hp_independent_mode) {
+ update_aamix_paths(codec, val, &spec->hp_path,
+ &spec->hp_mix_path);
+ }
+ /* update speaker path */
+ update_aamix_paths(codec, val, &spec->speaker_path,
+ &spec->speaker_mix_path);
+ return 1;
+}
+
+static const struct snd_kcontrol_new via_aamix_ctl_enum = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Loopback Mixing",
+ .info = via_aamix_ctl_info,
+ .get = via_aamix_ctl_get,
+ .put = via_aamix_ctl_put,
+};
+
+static int via_auto_create_loopback_switch(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+
+ if (!spec->aa_mix_nid)
+ return 0; /* no loopback switching available */
+ if (!(spec->out_mix_path.depth || spec->hp_mix_path.depth ||
+ spec->speaker_path.depth))
+ return 0; /* no loopback switching available */
+ if (!via_clone_control(spec, &via_aamix_ctl_enum))
+ return -ENOMEM;
+ return 0;
+}
+
+/* look for ADCs */
+static int via_fill_adcs(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ hda_nid_t nid = codec->start_nid;
+ int i;
+
+ for (i = 0; i < codec->num_nodes; i++, nid++) {
+ unsigned int wcaps = get_wcaps(codec, nid);
+ if (get_wcaps_type(wcaps) != AC_WID_AUD_IN)
+ continue;
+ if (wcaps & AC_WCAP_DIGITAL)
+ continue;
+ if (!(wcaps & AC_WCAP_CONN_LIST))
+ continue;
+ if (spec->num_adc_nids >= ARRAY_SIZE(spec->adc_nids))
+ return -ENOMEM;
+ spec->adc_nids[spec->num_adc_nids++] = nid;
+ }
+ return 0;
+}
+
+/* input-src control */
+static int via_mux_enum_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct via_spec *spec = codec->spec;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = spec->num_inputs;
+ if (uinfo->value.enumerated.item >= spec->num_inputs)
+ uinfo->value.enumerated.item = spec->num_inputs - 1;
+ strcpy(uinfo->value.enumerated.name,
+ spec->inputs[uinfo->value.enumerated.item].label);
+ return 0;
+}
+
+static int via_mux_enum_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct via_spec *spec = codec->spec;
+ unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+
+ ucontrol->value.enumerated.item[0] = spec->cur_mux[idx];
+ return 0;
+}
+
+static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct via_spec *spec = codec->spec;
+ unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ hda_nid_t mux;
+ int cur;
+
+ cur = ucontrol->value.enumerated.item[0];
+ if (cur < 0 || cur >= spec->num_inputs)
+ return -EINVAL;
+ if (spec->cur_mux[idx] == cur)
+ return 0;
+ spec->cur_mux[idx] = cur;
+ if (spec->dyn_adc_switch) {
+ int adc_idx = spec->inputs[cur].adc_idx;
+ mux = spec->mux_nids[adc_idx];
+ via_dyn_adc_pcm_resetup(codec, cur);
+ } else {
+ mux = spec->mux_nids[idx];
+ if (snd_BUG_ON(!mux))
+ return -EINVAL;
+ }
+
+ if (mux) {
+ /* switch to D0 beofre change index */
+ if (snd_hda_codec_read(codec, mux, 0,
+ AC_VERB_GET_POWER_STATE, 0x00) != AC_PWRST_D0)
+ snd_hda_codec_write(codec, mux, 0,
+ AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+ snd_hda_codec_write(codec, mux, 0,
+ AC_VERB_SET_CONNECT_SEL,
+ spec->inputs[cur].mux_idx);
+ }
+
+ /* update jack power state */
+ set_widgets_power_state(codec);
+ return 0;
+}
+
+static const struct snd_kcontrol_new via_input_src_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ /* The multiple "Capture Source" controls confuse alsamixer
+ * So call somewhat different..
+ */
+ /* .name = "Capture Source", */
+ .name = "Input Source",
+ .info = via_mux_enum_info,
+ .get = via_mux_enum_get,
+ .put = via_mux_enum_put,
+};
+
+static int create_input_src_ctls(struct hda_codec *codec, int count)
+{
+ struct via_spec *spec = codec->spec;
+ struct snd_kcontrol_new *knew;
+
+ if (spec->num_inputs <= 1 || !count)
+ return 0; /* no need for single src */
+
+ knew = via_clone_control(spec, &via_input_src_ctl);
+ if (!knew)
+ return -ENOMEM;
+ knew->count = count;
+ return 0;
+}
+
+/* add the powersave loopback-list entry */
+static void add_loopback_list(struct via_spec *spec, hda_nid_t mix, int idx)
+{
+ struct hda_amp_list *list;
+
+ if (spec->num_loopbacks >= ARRAY_SIZE(spec->loopback_list) - 1)
+ return;
+ list = spec->loopback_list + spec->num_loopbacks;
+ list->nid = mix;
+ list->dir = HDA_INPUT;
+ list->idx = idx;
+ spec->num_loopbacks++;
+ spec->loopback.amplist = spec->loopback_list;
+}
+
+static bool is_reachable_nid(struct hda_codec *codec, hda_nid_t src,
+ hda_nid_t dst)
+{
+ return snd_hda_get_conn_index(codec, src, dst, 1) >= 0;
+}
+
+/* add the input-route to the given pin */
+static bool add_input_route(struct hda_codec *codec, hda_nid_t pin)
+{
+ struct via_spec *spec = codec->spec;
+ int c, idx;
+
+ spec->inputs[spec->num_inputs].adc_idx = -1;
+ spec->inputs[spec->num_inputs].pin = pin;
+ for (c = 0; c < spec->num_adc_nids; c++) {
+ if (spec->mux_nids[c]) {
+ idx = get_connection_index(codec, spec->mux_nids[c],
+ pin);
+ if (idx < 0)
+ continue;
+ spec->inputs[spec->num_inputs].mux_idx = idx;
+ } else {
+ if (!is_reachable_nid(codec, spec->adc_nids[c], pin))
+ continue;
+ }
+ spec->inputs[spec->num_inputs].adc_idx = c;
+ /* Can primary ADC satisfy all inputs? */
+ if (!spec->dyn_adc_switch &&
+ spec->num_inputs > 0 && spec->inputs[0].adc_idx != c) {
+ snd_printd(KERN_INFO
+ "via: dynamic ADC switching enabled\n");
+ spec->dyn_adc_switch = 1;
+ }
+ return true;
+ }
+ return false;
+}
+
+static int get_mux_nids(struct hda_codec *codec);
+
+/* parse input-routes; fill ADCs, MUXs and input-src entries */
+static int parse_analog_inputs(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ const struct auto_pin_cfg *cfg = &spec->autocfg;
+ int i, err;
+
+ err = via_fill_adcs(codec);
if (err < 0)
return err;
+ err = get_mux_nids(codec);
+ if (err < 0)
+ return err;
+
+ /* fill all input-routes */
+ for (i = 0; i < cfg->num_inputs; i++) {
+ if (add_input_route(codec, cfg->inputs[i].pin))
+ spec->inputs[spec->num_inputs++].label =
+ hda_get_autocfg_input_label(codec, cfg, i);
+ }
- create_hp_imux(spec);
+ /* check for internal loopback recording */
+ if (spec->aa_mix_nid &&
+ add_input_route(codec, spec->aa_mix_nid))
+ spec->inputs[spec->num_inputs++].label = "Stereo Mixer";
return 0;
}
-/* create playback/capture controls for input pins */
-static int vt_auto_create_analog_input_ctls(struct hda_codec *codec,
- const struct auto_pin_cfg *cfg,
- hda_nid_t cap_nid,
- const hda_nid_t pin_idxs[],
- int num_idxs)
+/* create analog-loopback volume/switch controls */
+static int create_loopback_ctls(struct hda_codec *codec)
{
struct via_spec *spec = codec->spec;
- struct hda_input_mux *imux = &spec->private_imux[0];
- int i, err, idx, type, type_idx = 0;
+ const struct auto_pin_cfg *cfg = &spec->autocfg;
+ const char *prev_label = NULL;
+ int type_idx = 0;
+ int i, j, err, idx;
- /* for internal loopback recording select */
- for (idx = 0; idx < num_idxs; idx++) {
- if (pin_idxs[idx] == 0xff) {
- snd_hda_add_imux_item(imux, "Stereo Mixer", idx, NULL);
- break;
+ if (!spec->aa_mix_nid)
+ return 0;
+
+ for (i = 0; i < cfg->num_inputs; i++) {
+ hda_nid_t pin = cfg->inputs[i].pin;
+ const char *label = hda_get_autocfg_input_label(codec, cfg, i);
+
+ if (prev_label && !strcmp(label, prev_label))
+ type_idx++;
+ else
+ type_idx = 0;
+ prev_label = label;
+ idx = get_connection_index(codec, spec->aa_mix_nid, pin);
+ if (idx >= 0) {
+ err = via_new_analog_input(spec, label, type_idx,
+ idx, spec->aa_mix_nid);
+ if (err < 0)
+ return err;
+ add_loopback_list(spec, spec->aa_mix_nid, idx);
+ }
+
+ /* remember the label for smart51 control */
+ for (j = 0; j < spec->smart51_nums; j++) {
+ if (spec->smart51_pins[j] == pin) {
+ spec->smart51_idxs[j] = idx;
+ spec->smart51_labels[j] = label;
+ break;
+ }
}
}
+ return 0;
+}
+
+/* create mic-boost controls (if present) */
+static int create_mic_boost_ctls(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ const struct auto_pin_cfg *cfg = &spec->autocfg;
+ int i, err;
for (i = 0; i < cfg->num_inputs; i++) {
+ hda_nid_t pin = cfg->inputs[i].pin;
+ unsigned int caps;
const char *label;
- type = cfg->inputs[i].type;
- for (idx = 0; idx < num_idxs; idx++)
- if (pin_idxs[idx] == cfg->inputs[i].pin)
- break;
- if (idx >= num_idxs)
+ char name[32];
+
+ if (cfg->inputs[i].type != AUTO_PIN_MIC)
+ continue;
+ caps = query_amp_caps(codec, pin, HDA_INPUT);
+ if (caps == -1 || !(caps & AC_AMPCAP_NUM_STEPS))
continue;
- if (i > 0 && type == cfg->inputs[i - 1].type)
- type_idx++;
- else
- type_idx = 0;
label = hda_get_autocfg_input_label(codec, cfg, i);
- if (spec->codec_type == VT1708S ||
- spec->codec_type == VT1702 ||
- spec->codec_type == VT1716S)
- err = via_new_analog_input(spec, label, type_idx,
- idx+1, cap_nid);
- else
- err = via_new_analog_input(spec, label, type_idx,
- idx, cap_nid);
+ snprintf(name, sizeof(name), "%s Boost Volume", label);
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+ HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_INPUT));
if (err < 0)
return err;
- snd_hda_add_imux_item(imux, label, idx, NULL);
}
return 0;
}
-/* create playback/capture controls for input pins */
-static int vt1708_auto_create_analog_input_ctls(struct hda_codec *codec,
- const struct auto_pin_cfg *cfg)
+/* create capture and input-src controls for multiple streams */
+static int create_multi_adc_ctls(struct hda_codec *codec)
{
- static const hda_nid_t pin_idxs[] = { 0xff, 0x24, 0x1d, 0x1e, 0x21 };
- return vt_auto_create_analog_input_ctls(codec, cfg, 0x17, pin_idxs,
- ARRAY_SIZE(pin_idxs));
+ struct via_spec *spec = codec->spec;
+ int i, err;
+
+ /* create capture mixer elements */
+ for (i = 0; i < spec->num_adc_nids; i++) {
+ hda_nid_t adc = spec->adc_nids[i];
+ err = __via_add_control(spec, VIA_CTL_WIDGET_VOL,
+ "Capture Volume", i,
+ HDA_COMPOSE_AMP_VAL(adc, 3, 0,
+ HDA_INPUT));
+ if (err < 0)
+ return err;
+ err = __via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+ "Capture Switch", i,
+ HDA_COMPOSE_AMP_VAL(adc, 3, 0,
+ HDA_INPUT));
+ if (err < 0)
+ return err;
+ }
+
+ /* input-source control */
+ for (i = 0; i < spec->num_adc_nids; i++)
+ if (!spec->mux_nids[i])
+ break;
+ err = create_input_src_ctls(codec, i);
+ if (err < 0)
+ return err;
+ return 0;
}
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static const struct hda_amp_list vt1708_loopbacks[] = {
- { 0x17, HDA_INPUT, 1 },
- { 0x17, HDA_INPUT, 2 },
- { 0x17, HDA_INPUT, 3 },
- { 0x17, HDA_INPUT, 4 },
- { } /* end */
-};
-#endif
+/* bind capture volume/switch */
+static struct snd_kcontrol_new via_bind_cap_vol_ctl =
+ HDA_BIND_VOL("Capture Volume", 0);
+static struct snd_kcontrol_new via_bind_cap_sw_ctl =
+ HDA_BIND_SW("Capture Switch", 0);
+
+static int init_bind_ctl(struct via_spec *spec, struct hda_bind_ctls **ctl_ret,
+ struct hda_ctl_ops *ops)
+{
+ struct hda_bind_ctls *ctl;
+ int i;
+
+ ctl = kzalloc(sizeof(*ctl) + sizeof(long) * 4, GFP_KERNEL);
+ if (!ctl)
+ return -ENOMEM;
+ ctl->ops = ops;
+ for (i = 0; i < spec->num_adc_nids; i++)
+ ctl->values[i] =
+ HDA_COMPOSE_AMP_VAL(spec->adc_nids[i], 3, 0, HDA_INPUT);
+ *ctl_ret = ctl;
+ return 0;
+}
+
+/* create capture and input-src controls for dynamic ADC-switch case */
+static int create_dyn_adc_ctls(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ struct snd_kcontrol_new *knew;
+ int err;
+
+ /* set up the bind capture ctls */
+ err = init_bind_ctl(spec, &spec->bind_cap_vol, &snd_hda_bind_vol);
+ if (err < 0)
+ return err;
+ err = init_bind_ctl(spec, &spec->bind_cap_sw, &snd_hda_bind_sw);
+ if (err < 0)
+ return err;
+
+ /* create capture mixer elements */
+ knew = via_clone_control(spec, &via_bind_cap_vol_ctl);
+ if (!knew)
+ return -ENOMEM;
+ knew->private_value = (long)spec->bind_cap_vol;
+
+ knew = via_clone_control(spec, &via_bind_cap_sw_ctl);
+ if (!knew)
+ return -ENOMEM;
+ knew->private_value = (long)spec->bind_cap_sw;
+
+ /* input-source control */
+ err = create_input_src_ctls(codec, 1);
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+/* parse and create capture-related stuff */
+static int via_auto_create_analog_input_ctls(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ int err;
+
+ err = parse_analog_inputs(codec);
+ if (err < 0)
+ return err;
+ if (spec->dyn_adc_switch)
+ err = create_dyn_adc_ctls(codec);
+ else
+ err = create_multi_adc_ctls(codec);
+ if (err < 0)
+ return err;
+ err = create_loopback_ctls(codec);
+ if (err < 0)
+ return err;
+ err = create_mic_boost_ctls(codec);
+ if (err < 0)
+ return err;
+ return 0;
+}
static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid)
{
@@ -2095,7 +2624,7 @@ static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid)
return;
}
-static int vt1708_jack_detectect_get(struct snd_kcontrol *kcontrol,
+static int vt1708_jack_detect_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
@@ -2103,113 +2632,172 @@ static int vt1708_jack_detectect_get(struct snd_kcontrol *kcontrol,
if (spec->codec_type != VT1708)
return 0;
- spec->vt1708_jack_detectect =
- !((snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8) & 0x1);
- ucontrol->value.integer.value[0] = spec->vt1708_jack_detectect;
+ ucontrol->value.integer.value[0] = spec->vt1708_jack_detect;
return 0;
}
-static int vt1708_jack_detectect_put(struct snd_kcontrol *kcontrol,
+static int vt1708_jack_detect_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct via_spec *spec = codec->spec;
- int change;
+ int val;
if (spec->codec_type != VT1708)
return 0;
- spec->vt1708_jack_detectect = ucontrol->value.integer.value[0];
- change = (0x1 & (snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8))
- == !spec->vt1708_jack_detectect;
- if (spec->vt1708_jack_detectect) {
+ val = !!ucontrol->value.integer.value[0];
+ if (spec->vt1708_jack_detect == val)
+ return 0;
+ spec->vt1708_jack_detect = val;
+ if (spec->vt1708_jack_detect &&
+ snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") != 1) {
mute_aa_path(codec, 1);
notify_aa_path_ctls(codec);
}
- return change;
+ via_hp_automute(codec);
+ vt1708_update_hp_work(spec);
+ return 1;
}
-static const struct snd_kcontrol_new vt1708_jack_detectect[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Jack Detect",
- .count = 1,
- .info = snd_ctl_boolean_mono_info,
- .get = vt1708_jack_detectect_get,
- .put = vt1708_jack_detectect_put,
- },
- {} /* end */
+static const struct snd_kcontrol_new vt1708_jack_detect_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Jack Detect",
+ .count = 1,
+ .info = snd_ctl_boolean_mono_info,
+ .get = vt1708_jack_detect_get,
+ .put = vt1708_jack_detect_put,
};
-static int vt1708_parse_auto_config(struct hda_codec *codec)
+static void fill_dig_outs(struct hda_codec *codec);
+static void fill_dig_in(struct hda_codec *codec);
+
+static int via_parse_auto_config(struct hda_codec *codec)
{
struct via_spec *spec = codec->spec;
int err;
- /* Add HP and CD pin config connect bit re-config action */
- vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID);
- vt1708_set_pinconfig_connect(codec, VT1708_CD_PIN_NID);
-
err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
if (err < 0)
return err;
- err = vt1708_auto_fill_dac_nids(spec, &spec->autocfg);
- if (err < 0)
- return err;
if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
- return 0; /* can't find valid BIOS pin config */
+ return -EINVAL;
- err = vt1708_auto_create_multi_out_ctls(spec, &spec->autocfg);
+ err = via_auto_create_multi_out_ctls(codec);
if (err < 0)
return err;
- err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
+ err = via_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]);
if (err < 0)
return err;
- err = vt1708_auto_create_analog_input_ctls(codec, &spec->autocfg);
+ err = via_auto_create_speaker_ctls(codec);
if (err < 0)
return err;
- /* add jack detect on/off control */
- err = snd_hda_add_new_ctls(codec, vt1708_jack_detectect);
+ err = via_auto_create_loopback_switch(codec);
+ if (err < 0)
+ return err;
+ err = via_auto_create_analog_input_ctls(codec);
if (err < 0)
return err;
spec->multiout.max_channels = spec->multiout.num_dacs * 2;
- if (spec->autocfg.dig_outs)
- spec->multiout.dig_out_nid = VT1708_DIGOUT_NID;
- spec->dig_in_pin = VT1708_DIGIN_PIN;
- if (spec->autocfg.dig_in_pin)
- spec->dig_in_nid = VT1708_DIGIN_NID;
+ fill_dig_outs(codec);
+ fill_dig_in(codec);
if (spec->kctls.list)
spec->mixers[spec->num_mixers++] = spec->kctls.list;
- spec->init_verbs[spec->num_iverbs++] = vt1708_volume_init_verbs;
- spec->input_mux = &spec->private_imux[0];
+ if (spec->hp_dac_nid && spec->hp_mix_path.depth) {
+ err = via_hp_build(codec);
+ if (err < 0)
+ return err;
+ }
- if (spec->hp_mux)
- via_hp_build(codec);
+ err = via_smart51_build(codec);
+ if (err < 0)
+ return err;
+
+ /* assign slave outs */
+ if (spec->slave_dig_outs[0])
+ codec->slave_dig_outs = spec->slave_dig_outs;
- via_smart51_build(spec);
return 1;
}
-/* init callback for auto-configuration model -- overriding the default init */
-static int via_auto_init(struct hda_codec *codec)
+static void via_auto_init_dig_outs(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ if (spec->multiout.dig_out_nid)
+ init_output_pin(codec, spec->autocfg.dig_out_pins[0], PIN_OUT);
+ if (spec->slave_dig_outs[0])
+ init_output_pin(codec, spec->autocfg.dig_out_pins[1], PIN_OUT);
+}
+
+static void via_auto_init_dig_in(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ if (!spec->dig_in_nid)
+ return;
+ snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
+}
+
+/* initialize the unsolicited events */
+static void via_auto_init_unsol_event(struct hda_codec *codec)
{
struct via_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ unsigned int ev;
+ int i;
+
+ if (cfg->hp_pins[0] && is_jack_detectable(codec, cfg->hp_pins[0]))
+ snd_hda_codec_write(codec, cfg->hp_pins[0], 0,
+ AC_VERB_SET_UNSOLICITED_ENABLE,
+ AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT);
+
+ if (cfg->speaker_pins[0])
+ ev = VIA_LINE_EVENT;
+ else
+ ev = 0;
+ for (i = 0; i < cfg->line_outs; i++) {
+ if (cfg->line_out_pins[i] &&
+ is_jack_detectable(codec, cfg->line_out_pins[i]))
+ snd_hda_codec_write(codec, cfg->line_out_pins[i], 0,
+ AC_VERB_SET_UNSOLICITED_ENABLE,
+ AC_USRSP_EN | ev | VIA_JACK_EVENT);
+ }
+
+ for (i = 0; i < cfg->num_inputs; i++) {
+ if (is_jack_detectable(codec, cfg->inputs[i].pin))
+ snd_hda_codec_write(codec, cfg->inputs[i].pin, 0,
+ AC_VERB_SET_UNSOLICITED_ENABLE,
+ AC_USRSP_EN | VIA_JACK_EVENT);
+ }
+}
+
+static int via_init(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ int i;
+
+ for (i = 0; i < spec->num_iverbs; i++)
+ snd_hda_sequence_write(codec, spec->init_verbs[i]);
+
+ /* init power states */
+ set_widgets_power_state(codec);
+ __analog_low_current_mode(codec, true);
- via_init(codec);
via_auto_init_multi_out(codec);
via_auto_init_hp_out(codec);
+ via_auto_init_speaker_out(codec);
via_auto_init_analog_input(codec);
+ via_auto_init_dig_outs(codec);
+ via_auto_init_dig_in(codec);
- if (VT2002P_COMPATIBLE(spec)) {
- via_hp_bind_automute(codec);
- } else {
- via_hp_automute(codec);
- via_speaker_automute(codec);
- }
+ via_auto_init_unsol_event(codec);
+
+ via_hp_automute(codec);
+ vt1708_update_hp_work(spec);
return 0;
}
@@ -2226,7 +2814,9 @@ static void vt1708_update_hp_jack_state(struct work_struct *work)
spec->vt1708_hp_present ^= 1;
via_hp_automute(spec->codec);
}
- vt1708_start_hp_work(spec);
+ if (spec->vt1708_jack_detect)
+ schedule_delayed_work(&spec->vt1708_hp_work,
+ msecs_to_jiffies(100));
}
static int get_mux_nids(struct hda_codec *codec)
@@ -2266,437 +2856,36 @@ static int patch_vt1708(struct hda_codec *codec)
if (spec == NULL)
return -ENOMEM;
+ spec->aa_mix_nid = 0x17;
+
+ /* Add HP and CD pin config connect bit re-config action */
+ vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID);
+ vt1708_set_pinconfig_connect(codec, VT1708_CD_PIN_NID);
+
/* automatic parse from the BIOS config */
- err = vt1708_parse_auto_config(codec);
+ err = via_parse_auto_config(codec);
if (err < 0) {
via_free(codec);
return err;
- } else if (!err) {
- printk(KERN_INFO "hda_codec: Cannot set up configuration "
- "from BIOS. Using genenic mode...\n");
}
+ /* add jack detect on/off control */
+ if (!via_clone_control(spec, &vt1708_jack_detect_ctl))
+ return -ENOMEM;
- spec->stream_name_analog = "VT1708 Analog";
- spec->stream_analog_playback = &vt1708_pcm_analog_playback;
/* disable 32bit format on VT1708 */
if (codec->vendor_id == 0x11061708)
spec->stream_analog_playback = &vt1708_pcm_analog_s16_playback;
- spec->stream_analog_capture = &vt1708_pcm_analog_capture;
-
- spec->stream_name_digital = "VT1708 Digital";
- spec->stream_digital_playback = &vt1708_pcm_digital_playback;
- spec->stream_digital_capture = &vt1708_pcm_digital_capture;
-
- if (!spec->adc_nids && spec->input_mux) {
- spec->adc_nids = vt1708_adc_nids;
- spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids);
- get_mux_nids(codec);
- spec->mixers[spec->num_mixers] = vt1708_capture_mixer;
- spec->num_mixers++;
- }
+ spec->init_verbs[spec->num_iverbs++] = vt1708_init_verbs;
codec->patch_ops = via_patch_ops;
- codec->patch_ops.init = via_auto_init;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
- spec->loopback.amplist = vt1708_loopbacks;
-#endif
INIT_DELAYED_WORK(&spec->vt1708_hp_work, vt1708_update_hp_jack_state);
return 0;
}
-/* capture mixer elements */
-static const struct snd_kcontrol_new vt1709_capture_mixer[] = {
- HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x15, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x16, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x16, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* The multiple "Capture Source" controls confuse alsamixer
- * So call somewhat different..
- */
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 1,
- .info = via_mux_enum_info,
- .get = via_mux_enum_get,
- .put = via_mux_enum_put,
- },
- { } /* end */
-};
-
-static const struct hda_verb vt1709_uniwill_init_verbs[] = {
- {0x20, AC_VERB_SET_UNSOLICITED_ENABLE,
- AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
- { }
-};
-
-/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static const struct hda_verb vt1709_10ch_volume_init_verbs[] = {
- /*
- * Unmute ADC0-2 and set the default input to mic-in
- */
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-
- /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
- * mixer widget
- */
- /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
-
- /*
- * Set up output selector (0x1a, 0x1b, 0x29)
- */
- /* set vol=0 to output mixers */
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
- /*
- * Unmute PW3 and PW4
- */
- {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
- /* Set input of PW4 as MW0 */
- {0x20, AC_VERB_SET_CONNECT_SEL, 0},
- /* PW9 Output enable */
- {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
- { }
-};
-
-static const struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = {
- .substreams = 1,
- .channels_min = 2,
- .channels_max = 10,
- .nid = 0x10, /* NID to query formats and rates */
- .ops = {
- .open = via_playback_pcm_open,
- .prepare = via_playback_multi_pcm_prepare,
- .cleanup = via_playback_multi_pcm_cleanup,
- },
-};
-
-static const struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = {
- .substreams = 1,
- .channels_min = 2,
- .channels_max = 6,
- .nid = 0x10, /* NID to query formats and rates */
- .ops = {
- .open = via_playback_pcm_open,
- .prepare = via_playback_multi_pcm_prepare,
- .cleanup = via_playback_multi_pcm_cleanup,
- },
-};
-
-static const struct hda_pcm_stream vt1709_pcm_analog_capture = {
- .substreams = 2,
- .channels_min = 2,
- .channels_max = 2,
- .nid = 0x14, /* NID to query formats and rates */
- .ops = {
- .prepare = via_capture_pcm_prepare,
- .cleanup = via_capture_pcm_cleanup
- },
-};
-
-static const struct hda_pcm_stream vt1709_pcm_digital_playback = {
- .substreams = 1,
- .channels_min = 2,
- .channels_max = 2,
- /* NID is set in via_build_pcms */
- .ops = {
- .open = via_dig_playback_pcm_open,
- .close = via_dig_playback_pcm_close
- },
-};
-
-static const struct hda_pcm_stream vt1709_pcm_digital_capture = {
- .substreams = 1,
- .channels_min = 2,
- .channels_max = 2,
-};
-
-static int vt1709_auto_fill_dac_nids(struct via_spec *spec,
- const struct auto_pin_cfg *cfg)
-{
- int i;
- hda_nid_t nid;
-
- if (cfg->line_outs == 4) /* 10 channels */
- spec->multiout.num_dacs = cfg->line_outs+1; /* AOW0~AOW4 */
- else if (cfg->line_outs == 3) /* 6 channels */
- spec->multiout.num_dacs = cfg->line_outs; /* AOW0~AOW2 */
-
- spec->multiout.dac_nids = spec->private_dac_nids;
-
- if (cfg->line_outs == 4) { /* 10 channels */
- for (i = 0; i < cfg->line_outs; i++) {
- nid = cfg->line_out_pins[i];
- if (nid) {
- /* config dac list */
- switch (i) {
- case AUTO_SEQ_FRONT:
- /* AOW0 */
- spec->private_dac_nids[i] = 0x10;
- break;
- case AUTO_SEQ_CENLFE:
- /* AOW2 */
- spec->private_dac_nids[i] = 0x12;
- break;
- case AUTO_SEQ_SURROUND:
- /* AOW3 */
- spec->private_dac_nids[i] = 0x11;
- break;
- case AUTO_SEQ_SIDE:
- /* AOW1 */
- spec->private_dac_nids[i] = 0x27;
- break;
- default:
- break;
- }
- }
- }
- spec->private_dac_nids[cfg->line_outs] = 0x28; /* AOW4 */
-
- } else if (cfg->line_outs == 3) { /* 6 channels */
- for (i = 0; i < cfg->line_outs; i++) {
- nid = cfg->line_out_pins[i];
- if (nid) {
- /* config dac list */
- switch (i) {
- case AUTO_SEQ_FRONT:
- /* AOW0 */
- spec->private_dac_nids[i] = 0x10;
- break;
- case AUTO_SEQ_CENLFE:
- /* AOW2 */
- spec->private_dac_nids[i] = 0x12;
- break;
- case AUTO_SEQ_SURROUND:
- /* AOW1 */
- spec->private_dac_nids[i] = 0x11;
- break;
- default:
- break;
- }
- }
- }
- }
-
- return 0;
-}
-
-/* add playback controls from the parsed DAC table */
-static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec,
- const struct auto_pin_cfg *cfg)
-{
- char name[32];
- 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;
-
- for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
- nid = cfg->line_out_pins[i];
-
- if (!nid)
- continue;
-
- nid_vol = nid_vols[i];
-
- if (i == AUTO_SEQ_CENLFE) {
- /* Center/LFE */
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
- "Center Playback Volume",
- HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
- "LFE Playback Volume",
- HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
- "Center Playback Switch",
- HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
- "LFE Playback Switch",
- HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- } else if (i == AUTO_SEQ_FRONT) {
- /* ADD control to mixer index 0 */
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
- "Master Front Playback Volume",
- HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
- HDA_INPUT));
- if (err < 0)
- return err;
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
- "Master Front Playback Switch",
- HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
- HDA_INPUT));
- if (err < 0)
- return err;
-
- /* add control to PW3 */
- sprintf(name, "%s Playback Volume", chname[i]);
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
- HDA_COMPOSE_AMP_VAL(nid, 3, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- sprintf(name, "%s Playback Switch", chname[i]);
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
- HDA_COMPOSE_AMP_VAL(nid, 3, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- } else if (i == AUTO_SEQ_SURROUND) {
- sprintf(name, "%s Playback Volume", chname[i]);
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
- HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- sprintf(name, "%s Playback Switch", chname[i]);
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
- HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- } else if (i == AUTO_SEQ_SIDE) {
- sprintf(name, "%s Playback Volume", chname[i]);
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
- HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- sprintf(name, "%s Playback Switch", chname[i]);
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
- HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- }
- }
-
- return 0;
-}
-
-static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
-{
- int err;
-
- if (!pin)
- return 0;
-
- if (spec->multiout.num_dacs == 5) /* 10 channels */
- spec->multiout.hp_nid = VT1709_HP_DAC_NID;
- else if (spec->multiout.num_dacs == 3) /* 6 channels */
- spec->multiout.hp_nid = 0;
- spec->hp_independent_mode_index = 1;
-
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
- "Headphone Playback Volume",
- HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
- "Headphone Playback Switch",
- HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
-
- return 0;
-}
-
-/* create playback/capture controls for input pins */
-static int vt1709_auto_create_analog_input_ctls(struct hda_codec *codec,
- const struct auto_pin_cfg *cfg)
-{
- static const hda_nid_t pin_idxs[] = { 0xff, 0x23, 0x1d, 0x1e, 0x21 };
- return vt_auto_create_analog_input_ctls(codec, cfg, 0x18, pin_idxs,
- ARRAY_SIZE(pin_idxs));
-}
-
-static int vt1709_parse_auto_config(struct hda_codec *codec)
-{
- struct via_spec *spec = codec->spec;
- int err;
-
- err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
- if (err < 0)
- return err;
- err = vt1709_auto_fill_dac_nids(spec, &spec->autocfg);
- if (err < 0)
- return err;
- if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
- return 0; /* can't find valid BIOS pin config */
-
- err = vt1709_auto_create_multi_out_ctls(spec, &spec->autocfg);
- if (err < 0)
- return err;
- err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
- if (err < 0)
- return err;
- err = vt1709_auto_create_analog_input_ctls(codec, &spec->autocfg);
- if (err < 0)
- return err;
-
- spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-
- if (spec->autocfg.dig_outs)
- spec->multiout.dig_out_nid = VT1709_DIGOUT_NID;
- spec->dig_in_pin = VT1709_DIGIN_PIN;
- if (spec->autocfg.dig_in_pin)
- spec->dig_in_nid = VT1709_DIGIN_NID;
-
- if (spec->kctls.list)
- spec->mixers[spec->num_mixers++] = spec->kctls.list;
-
- spec->input_mux = &spec->private_imux[0];
-
- if (spec->hp_mux)
- via_hp_build(codec);
-
- via_smart51_build(spec);
- return 1;
-}
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static const struct hda_amp_list vt1709_loopbacks[] = {
- { 0x18, HDA_INPUT, 1 },
- { 0x18, HDA_INPUT, 2 },
- { 0x18, HDA_INPUT, 3 },
- { 0x18, HDA_INPUT, 4 },
- { } /* end */
-};
-#endif
-
-static int patch_vt1709_10ch(struct hda_codec *codec)
+static int patch_vt1709(struct hda_codec *codec)
{
struct via_spec *spec;
int err;
@@ -2706,528 +2895,19 @@ static int patch_vt1709_10ch(struct hda_codec *codec)
if (spec == NULL)
return -ENOMEM;
- err = vt1709_parse_auto_config(codec);
- if (err < 0) {
- via_free(codec);
- return err;
- } else if (!err) {
- printk(KERN_INFO "hda_codec: Cannot set up configuration. "
- "Using genenic mode...\n");
- }
-
- spec->init_verbs[spec->num_iverbs++] = vt1709_10ch_volume_init_verbs;
- spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs;
-
- spec->stream_name_analog = "VT1709 Analog";
- spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback;
- spec->stream_analog_capture = &vt1709_pcm_analog_capture;
-
- spec->stream_name_digital = "VT1709 Digital";
- spec->stream_digital_playback = &vt1709_pcm_digital_playback;
- spec->stream_digital_capture = &vt1709_pcm_digital_capture;
-
-
- if (!spec->adc_nids && spec->input_mux) {
- spec->adc_nids = vt1709_adc_nids;
- spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
- get_mux_nids(codec);
- spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
- spec->num_mixers++;
- }
-
- codec->patch_ops = via_patch_ops;
-
- codec->patch_ops.init = via_auto_init;
- codec->patch_ops.unsol_event = via_unsol_event;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
- spec->loopback.amplist = vt1709_loopbacks;
-#endif
-
- return 0;
-}
-/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static const struct hda_verb vt1709_6ch_volume_init_verbs[] = {
- /*
- * Unmute ADC0-2 and set the default input to mic-in
- */
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-
- /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
- * mixer widget
- */
- /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
-
- /*
- * Set up output selector (0x1a, 0x1b, 0x29)
- */
- /* set vol=0 to output mixers */
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
- /*
- * Unmute PW3 and PW4
- */
- {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ spec->aa_mix_nid = 0x18;
- /* Set input of PW4 as MW0 */
- {0x20, AC_VERB_SET_CONNECT_SEL, 0},
- /* PW9 Output enable */
- {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
- { }
-};
-
-static int patch_vt1709_6ch(struct hda_codec *codec)
-{
- struct via_spec *spec;
- int err;
-
- /* create a codec specific record */
- spec = via_new_spec(codec);
- if (spec == NULL)
- return -ENOMEM;
-
- err = vt1709_parse_auto_config(codec);
+ err = via_parse_auto_config(codec);
if (err < 0) {
via_free(codec);
return err;
- } else if (!err) {
- printk(KERN_INFO "hda_codec: Cannot set up configuration. "
- "Using genenic mode...\n");
- }
-
- spec->init_verbs[spec->num_iverbs++] = vt1709_6ch_volume_init_verbs;
- spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs;
-
- spec->stream_name_analog = "VT1709 Analog";
- spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback;
- spec->stream_analog_capture = &vt1709_pcm_analog_capture;
-
- spec->stream_name_digital = "VT1709 Digital";
- spec->stream_digital_playback = &vt1709_pcm_digital_playback;
- spec->stream_digital_capture = &vt1709_pcm_digital_capture;
-
-
- if (!spec->adc_nids && spec->input_mux) {
- spec->adc_nids = vt1709_adc_nids;
- spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
- get_mux_nids(codec);
- spec->mixers[spec->num_mixers] = vt1709_capture_mixer;
- spec->num_mixers++;
}
codec->patch_ops = via_patch_ops;
- codec->patch_ops.init = via_auto_init;
- codec->patch_ops.unsol_event = via_unsol_event;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
- spec->loopback.amplist = vt1709_loopbacks;
-#endif
- return 0;
-}
-
-/* capture mixer elements */
-static const struct snd_kcontrol_new vt1708B_capture_mixer[] = {
- HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* The multiple "Capture Source" controls confuse alsamixer
- * So call somewhat different..
- */
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 1,
- .info = via_mux_enum_info,
- .get = via_mux_enum_get,
- .put = via_mux_enum_put,
- },
- { } /* end */
-};
-/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static const struct hda_verb vt1708B_8ch_volume_init_verbs[] = {
- /*
- * Unmute ADC0-1 and set the default input to mic-in
- */
- {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-
- /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
- * mixer widget
- */
- /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
-
- /*
- * Set up output mixers
- */
- /* set vol=0 to output mixers */
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
- /* Setup default input to PW4 */
- {0x1d, AC_VERB_SET_CONNECT_SEL, 0},
- /* PW9 Output enable */
- {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
- /* PW10 Input enable */
- {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
- { }
-};
-
-static const struct hda_verb vt1708B_4ch_volume_init_verbs[] = {
- /*
- * Unmute ADC0-1 and set the default input to mic-in
- */
- {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-
- /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
- * mixer widget
- */
- /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
-
- /*
- * Set up output mixers
- */
- /* set vol=0 to output mixers */
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
- /* Setup default input of PW4 to MW0 */
- {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
- /* PW9 Output enable */
- {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
- /* PW10 Input enable */
- {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
- { }
-};
-
-static const struct hda_verb vt1708B_uniwill_init_verbs[] = {
- {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
- AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
- {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- { }
-};
-
-static int via_pcm_open_close(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- struct snd_pcm_substream *substream)
-{
- int idle = substream->pstr->substream_opened == 1
- && substream->ref_count == 0;
-
- analog_low_current_mode(codec, idle);
- return 0;
-}
-
-static const struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = {
- .substreams = 2,
- .channels_min = 2,
- .channels_max = 8,
- .nid = 0x10, /* NID to query formats and rates */
- .ops = {
- .open = via_playback_pcm_open,
- .prepare = via_playback_multi_pcm_prepare,
- .cleanup = via_playback_multi_pcm_cleanup,
- .close = via_pcm_open_close
- },
-};
-
-static const struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = {
- .substreams = 2,
- .channels_min = 2,
- .channels_max = 4,
- .nid = 0x10, /* NID to query formats and rates */
- .ops = {
- .open = via_playback_pcm_open,
- .prepare = via_playback_multi_pcm_prepare,
- .cleanup = via_playback_multi_pcm_cleanup
- },
-};
-
-static const struct hda_pcm_stream vt1708B_pcm_analog_capture = {
- .substreams = 2,
- .channels_min = 2,
- .channels_max = 2,
- .nid = 0x13, /* NID to query formats and rates */
- .ops = {
- .open = via_pcm_open_close,
- .prepare = via_capture_pcm_prepare,
- .cleanup = via_capture_pcm_cleanup,
- .close = via_pcm_open_close
- },
-};
-
-static const struct hda_pcm_stream vt1708B_pcm_digital_playback = {
- .substreams = 1,
- .channels_min = 2,
- .channels_max = 2,
- /* NID is set in via_build_pcms */
- .ops = {
- .open = via_dig_playback_pcm_open,
- .close = via_dig_playback_pcm_close,
- .prepare = via_dig_playback_pcm_prepare,
- .cleanup = via_dig_playback_pcm_cleanup
- },
-};
-
-static const struct hda_pcm_stream vt1708B_pcm_digital_capture = {
- .substreams = 1,
- .channels_min = 2,
- .channels_max = 2,
-};
-
-/* fill in the dac_nids table from the parsed pin configuration */
-static int vt1708B_auto_fill_dac_nids(struct via_spec *spec,
- const struct auto_pin_cfg *cfg)
-{
- int i;
- hda_nid_t nid;
-
- spec->multiout.num_dacs = cfg->line_outs;
-
- spec->multiout.dac_nids = spec->private_dac_nids;
-
- for (i = 0; i < 4; i++) {
- nid = cfg->line_out_pins[i];
- if (nid) {
- /* config dac list */
- switch (i) {
- case AUTO_SEQ_FRONT:
- spec->private_dac_nids[i] = 0x10;
- break;
- case AUTO_SEQ_CENLFE:
- spec->private_dac_nids[i] = 0x24;
- break;
- case AUTO_SEQ_SURROUND:
- spec->private_dac_nids[i] = 0x11;
- break;
- case AUTO_SEQ_SIDE:
- spec->private_dac_nids[i] = 0x25;
- break;
- }
- }
- }
-
return 0;
}
-/* add playback controls from the parsed DAC table */
-static int vt1708B_auto_create_multi_out_ctls(struct via_spec *spec,
- const struct auto_pin_cfg *cfg)
-{
- char name[32];
- 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;
-
- for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
- nid = cfg->line_out_pins[i];
-
- if (!nid)
- continue;
-
- nid_vol = nid_vols[i];
-
- if (i == AUTO_SEQ_CENLFE) {
- /* Center/LFE */
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
- "Center Playback Volume",
- HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
- "LFE Playback Volume",
- HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
- "Center Playback Switch",
- HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
- "LFE Playback Switch",
- HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- } else if (i == AUTO_SEQ_FRONT) {
- /* add control to mixer index 0 */
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
- "Master Front Playback Volume",
- HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
- HDA_INPUT));
- if (err < 0)
- return err;
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
- "Master Front Playback Switch",
- HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
- HDA_INPUT));
- if (err < 0)
- return err;
-
- /* add control to PW3 */
- sprintf(name, "%s Playback Volume", chname[i]);
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
- HDA_COMPOSE_AMP_VAL(nid, 3, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- sprintf(name, "%s Playback Switch", chname[i]);
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
- HDA_COMPOSE_AMP_VAL(nid, 3, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- } else {
- sprintf(name, "%s Playback Volume", chname[i]);
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
- HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- sprintf(name, "%s Playback Switch", chname[i]);
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
- HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- }
- }
-
- return 0;
-}
-
-static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
-{
- int err;
-
- if (!pin)
- return 0;
-
- spec->multiout.hp_nid = VT1708B_HP_NID; /* AOW3 */
- spec->hp_independent_mode_index = 1;
-
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
- "Headphone Playback Volume",
- HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
- "Headphone Playback Switch",
- HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
-
- create_hp_imux(spec);
-
- return 0;
-}
-
-/* create playback/capture controls for input pins */
-static int vt1708B_auto_create_analog_input_ctls(struct hda_codec *codec,
- const struct auto_pin_cfg *cfg)
-{
- static const hda_nid_t pin_idxs[] = { 0xff, 0x1f, 0x1a, 0x1b, 0x1e };
- return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
- ARRAY_SIZE(pin_idxs));
-}
-
-static int vt1708B_parse_auto_config(struct hda_codec *codec)
-{
- struct via_spec *spec = codec->spec;
- int err;
-
- err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
- if (err < 0)
- return err;
- err = vt1708B_auto_fill_dac_nids(spec, &spec->autocfg);
- if (err < 0)
- return err;
- if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
- return 0; /* can't find valid BIOS pin config */
-
- err = vt1708B_auto_create_multi_out_ctls(spec, &spec->autocfg);
- if (err < 0)
- return err;
- err = vt1708B_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
- if (err < 0)
- return err;
- err = vt1708B_auto_create_analog_input_ctls(codec, &spec->autocfg);
- if (err < 0)
- return err;
-
- spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-
- if (spec->autocfg.dig_outs)
- spec->multiout.dig_out_nid = VT1708B_DIGOUT_NID;
- spec->dig_in_pin = VT1708B_DIGIN_PIN;
- if (spec->autocfg.dig_in_pin)
- spec->dig_in_nid = VT1708B_DIGIN_NID;
-
- if (spec->kctls.list)
- spec->mixers[spec->num_mixers++] = spec->kctls.list;
-
- spec->input_mux = &spec->private_imux[0];
-
- if (spec->hp_mux)
- via_hp_build(codec);
-
- via_smart51_build(spec);
- return 1;
-}
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static const struct hda_amp_list vt1708B_loopbacks[] = {
- { 0x16, HDA_INPUT, 1 },
- { 0x16, HDA_INPUT, 2 },
- { 0x16, HDA_INPUT, 3 },
- { 0x16, HDA_INPUT, 4 },
- { } /* end */
-};
-#endif
-
static void set_widgets_power_state_vt1708B(struct hda_codec *codec)
{
struct via_spec *spec = codec->spec;
@@ -3309,157 +2989,37 @@ static void set_widgets_power_state_vt1708B(struct hda_codec *codec)
}
static int patch_vt1708S(struct hda_codec *codec);
-static int patch_vt1708B_8ch(struct hda_codec *codec)
+static int patch_vt1708B(struct hda_codec *codec)
{
struct via_spec *spec;
int err;
if (get_codec_type(codec) == VT1708BCE)
return patch_vt1708S(codec);
- /* create a codec specific record */
- spec = via_new_spec(codec);
- if (spec == NULL)
- return -ENOMEM;
-
- /* automatic parse from the BIOS config */
- err = vt1708B_parse_auto_config(codec);
- if (err < 0) {
- via_free(codec);
- return err;
- } else if (!err) {
- printk(KERN_INFO "hda_codec: Cannot set up configuration "
- "from BIOS. Using genenic mode...\n");
- }
-
- spec->init_verbs[spec->num_iverbs++] = vt1708B_8ch_volume_init_verbs;
- spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs;
-
- spec->stream_name_analog = "VT1708B Analog";
- spec->stream_analog_playback = &vt1708B_8ch_pcm_analog_playback;
- spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
-
- spec->stream_name_digital = "VT1708B Digital";
- spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
- spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
-
- if (!spec->adc_nids && spec->input_mux) {
- spec->adc_nids = vt1708B_adc_nids;
- spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
- get_mux_nids(codec);
- spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
- spec->num_mixers++;
- }
-
- codec->patch_ops = via_patch_ops;
-
- codec->patch_ops.init = via_auto_init;
- codec->patch_ops.unsol_event = via_unsol_event;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
- spec->loopback.amplist = vt1708B_loopbacks;
-#endif
-
- spec->set_widgets_power_state = set_widgets_power_state_vt1708B;
-
- return 0;
-}
-
-static int patch_vt1708B_4ch(struct hda_codec *codec)
-{
- struct via_spec *spec;
- int err;
/* create a codec specific record */
spec = via_new_spec(codec);
if (spec == NULL)
return -ENOMEM;
+ spec->aa_mix_nid = 0x16;
+
/* automatic parse from the BIOS config */
- err = vt1708B_parse_auto_config(codec);
+ err = via_parse_auto_config(codec);
if (err < 0) {
via_free(codec);
return err;
- } else if (!err) {
- printk(KERN_INFO "hda_codec: Cannot set up configuration "
- "from BIOS. Using genenic mode...\n");
- }
-
- spec->init_verbs[spec->num_iverbs++] = vt1708B_4ch_volume_init_verbs;
- spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs;
-
- spec->stream_name_analog = "VT1708B Analog";
- spec->stream_analog_playback = &vt1708B_4ch_pcm_analog_playback;
- spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
-
- spec->stream_name_digital = "VT1708B Digital";
- spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
- spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
-
- if (!spec->adc_nids && spec->input_mux) {
- spec->adc_nids = vt1708B_adc_nids;
- spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
- get_mux_nids(codec);
- spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
- spec->num_mixers++;
}
codec->patch_ops = via_patch_ops;
- codec->patch_ops.init = via_auto_init;
- codec->patch_ops.unsol_event = via_unsol_event;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
- spec->loopback.amplist = vt1708B_loopbacks;
-#endif
-
spec->set_widgets_power_state = set_widgets_power_state_vt1708B;
return 0;
}
/* Patch for VT1708S */
-
-/* capture mixer elements */
-static const struct snd_kcontrol_new vt1708S_capture_mixer[] = {
- HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x1A, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x1E, 0x0,
- HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* The multiple "Capture Source" controls confuse alsamixer
- * So call somewhat different..
- */
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 1,
- .info = via_mux_enum_info,
- .get = via_mux_enum_get,
- .put = via_mux_enum_put,
- },
- { } /* end */
-};
-
-static const struct hda_verb vt1708S_volume_init_verbs[] = {
- /* Unmute ADC0-1 and set the default input to mic-in */
- {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
- /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the
- * analog-loopback mixer widget */
- /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
-
- /* Setup default input of PW4 to MW0 */
- {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
- /* PW9, PW10 Output enable */
- {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
- {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+static const struct hda_verb vt1708S_init_verbs[] = {
/* Enable Mic Boost Volume backdoor */
{0x1, 0xf98, 0x1},
/* don't bybass mixer */
@@ -3467,277 +3027,6 @@ static const struct hda_verb vt1708S_volume_init_verbs[] = {
{ }
};
-static const struct hda_verb vt1708S_uniwill_init_verbs[] = {
- {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
- AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
- {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- { }
-};
-
-static const struct hda_verb vt1705_uniwill_init_verbs[] = {
- {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
- AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
- {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- { }
-};
-
-static const struct hda_pcm_stream vt1708S_pcm_analog_playback = {
- .substreams = 2,
- .channels_min = 2,
- .channels_max = 8,
- .nid = 0x10, /* NID to query formats and rates */
- .ops = {
- .open = via_playback_pcm_open,
- .prepare = via_playback_multi_pcm_prepare,
- .cleanup = via_playback_multi_pcm_cleanup,
- .close = via_pcm_open_close
- },
-};
-
-static const struct hda_pcm_stream vt1705_pcm_analog_playback = {
- .substreams = 2,
- .channels_min = 2,
- .channels_max = 6,
- .nid = 0x10, /* NID to query formats and rates */
- .ops = {
- .open = via_playback_pcm_open,
- .prepare = via_playback_multi_pcm_prepare,
- .cleanup = via_playback_multi_pcm_cleanup,
- .close = via_pcm_open_close
- },
-};
-
-static const struct hda_pcm_stream vt1708S_pcm_analog_capture = {
- .substreams = 2,
- .channels_min = 2,
- .channels_max = 2,
- .nid = 0x13, /* NID to query formats and rates */
- .ops = {
- .open = via_pcm_open_close,
- .prepare = via_capture_pcm_prepare,
- .cleanup = via_capture_pcm_cleanup,
- .close = via_pcm_open_close
- },
-};
-
-static const struct hda_pcm_stream vt1708S_pcm_digital_playback = {
- .substreams = 1,
- .channels_min = 2,
- .channels_max = 2,
- /* NID is set in via_build_pcms */
- .ops = {
- .open = via_dig_playback_pcm_open,
- .close = via_dig_playback_pcm_close,
- .prepare = via_dig_playback_pcm_prepare,
- .cleanup = via_dig_playback_pcm_cleanup
- },
-};
-
-/* fill in the dac_nids table from the parsed pin configuration */
-static int vt1708S_auto_fill_dac_nids(struct via_spec *spec,
- const struct auto_pin_cfg *cfg)
-{
- int i;
- hda_nid_t nid;
-
- spec->multiout.num_dacs = cfg->line_outs;
-
- spec->multiout.dac_nids = spec->private_dac_nids;
-
- for (i = 0; i < 4; i++) {
- nid = cfg->line_out_pins[i];
- if (nid) {
- /* config dac list */
- switch (i) {
- case AUTO_SEQ_FRONT:
- spec->private_dac_nids[i] = 0x10;
- break;
- case AUTO_SEQ_CENLFE:
- if (spec->codec->vendor_id == 0x11064397)
- spec->private_dac_nids[i] = 0x25;
- else
- spec->private_dac_nids[i] = 0x24;
- break;
- case AUTO_SEQ_SURROUND:
- spec->private_dac_nids[i] = 0x11;
- break;
- case AUTO_SEQ_SIDE:
- spec->private_dac_nids[i] = 0x25;
- break;
- }
- }
- }
-
- /* for Smart 5.1, line/mic inputs double as output pins */
- if (cfg->line_outs == 1) {
- spec->multiout.num_dacs = 3;
- spec->private_dac_nids[AUTO_SEQ_SURROUND] = 0x11;
- if (spec->codec->vendor_id == 0x11064397)
- spec->private_dac_nids[AUTO_SEQ_CENLFE] = 0x25;
- else
- spec->private_dac_nids[AUTO_SEQ_CENLFE] = 0x24;
- }
-
- return 0;
-}
-
-/* add playback controls from the parsed DAC table */
-static int vt1708S_auto_create_multi_out_ctls(struct hda_codec *codec,
- const struct auto_pin_cfg *cfg)
-{
- struct via_spec *spec = codec->spec;
- char name[32];
- static const char * const chname[4] = {
- "Front", "Surround", "C/LFE", "Side"
- };
- hda_nid_t nid_vols[2][4] = { {0x10, 0x11, 0x24, 0x25},
- {0x10, 0x11, 0x25, 0} };
- hda_nid_t nid_mutes[2][4] = { {0x1C, 0x18, 0x26, 0x27},
- {0x1C, 0x18, 0x27, 0} };
- hda_nid_t nid, nid_vol, nid_mute;
- int i, err;
-
- for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
- nid = cfg->line_out_pins[i];
-
- /* for Smart 5.1, there are always at least six channels */
- if (!nid && i > AUTO_SEQ_CENLFE)
- continue;
-
- if (codec->vendor_id == 0x11064397) {
- nid_vol = nid_vols[1][i];
- nid_mute = nid_mutes[1][i];
- } else {
- nid_vol = nid_vols[0][i];
- nid_mute = nid_mutes[0][i];
- }
- if (!nid_vol && !nid_mute)
- continue;
-
- if (i == AUTO_SEQ_CENLFE) {
- /* Center/LFE */
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
- "Center Playback Volume",
- HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
- "LFE Playback Volume",
- HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
- "Center Playback Switch",
- HDA_COMPOSE_AMP_VAL(nid_mute,
- 1, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
- "LFE Playback Switch",
- HDA_COMPOSE_AMP_VAL(nid_mute,
- 2, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- } else if (i == AUTO_SEQ_FRONT) {
- /* add control to mixer index 0 */
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
- "Master Front Playback Volume",
- HDA_COMPOSE_AMP_VAL(0x16, 3, 0,
- HDA_INPUT));
- if (err < 0)
- return err;
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
- "Master Front Playback Switch",
- HDA_COMPOSE_AMP_VAL(0x16, 3, 0,
- HDA_INPUT));
- if (err < 0)
- return err;
-
- /* Front */
- sprintf(name, "%s Playback Volume", chname[i]);
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
- HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- sprintf(name, "%s Playback Switch", chname[i]);
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
- HDA_COMPOSE_AMP_VAL(nid_mute,
- 3, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- } else {
- sprintf(name, "%s Playback Volume", chname[i]);
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
- HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- sprintf(name, "%s Playback Switch", chname[i]);
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
- HDA_COMPOSE_AMP_VAL(nid_mute,
- 3, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- }
- }
-
- return 0;
-}
-
-static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
-{
- int err;
-
- if (!pin)
- return 0;
-
- spec->multiout.hp_nid = VT1708S_HP_NID; /* AOW3 */
- spec->hp_independent_mode_index = 1;
-
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
- "Headphone Playback Volume",
- HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
-
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
- "Headphone Playback Switch",
- HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
-
- create_hp_imux(spec);
-
- return 0;
-}
-
-/* create playback/capture controls for input pins */
-static int vt1708S_auto_create_analog_input_ctls(struct hda_codec *codec,
- const struct auto_pin_cfg *cfg)
-{
- static const hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff };
- return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
- ARRAY_SIZE(pin_idxs));
-}
-
/* fill out digital output widgets; one for master and one for slave outputs */
static void fill_dig_outs(struct hda_codec *codec)
{
@@ -3763,56 +3052,33 @@ static void fill_dig_outs(struct hda_codec *codec)
}
}
-static int vt1708S_parse_auto_config(struct hda_codec *codec)
+static void fill_dig_in(struct hda_codec *codec)
{
struct via_spec *spec = codec->spec;
- int err;
-
- err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
- if (err < 0)
- return err;
- err = vt1708S_auto_fill_dac_nids(spec, &spec->autocfg);
- if (err < 0)
- return err;
- if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
- return 0; /* can't find valid BIOS pin config */
-
- err = vt1708S_auto_create_multi_out_ctls(codec, &spec->autocfg);
- if (err < 0)
- return err;
- err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
- if (err < 0)
- return err;
- err = vt1708S_auto_create_analog_input_ctls(codec, &spec->autocfg);
- if (err < 0)
- return err;
-
- spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-
- fill_dig_outs(codec);
-
- if (spec->kctls.list)
- spec->mixers[spec->num_mixers++] = spec->kctls.list;
-
- spec->input_mux = &spec->private_imux[0];
+ hda_nid_t dig_nid;
+ int i, err;
- if (spec->hp_mux)
- via_hp_build(codec);
+ if (!spec->autocfg.dig_in_pin)
+ return;
- via_smart51_build(spec);
- return 1;
+ dig_nid = codec->start_nid;
+ for (i = 0; i < codec->num_nodes; i++, dig_nid++) {
+ unsigned int wcaps = get_wcaps(codec, dig_nid);
+ if (get_wcaps_type(wcaps) != AC_WID_AUD_IN)
+ continue;
+ if (!(wcaps & AC_WCAP_DIGITAL))
+ continue;
+ if (!(wcaps & AC_WCAP_CONN_LIST))
+ continue;
+ err = get_connection_index(codec, dig_nid,
+ spec->autocfg.dig_in_pin);
+ if (err >= 0) {
+ spec->dig_in_nid = dig_nid;
+ break;
+ }
+ }
}
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static const struct hda_amp_list vt1708S_loopbacks[] = {
- { 0x16, HDA_INPUT, 1 },
- { 0x16, HDA_INPUT, 2 },
- { 0x16, HDA_INPUT, 3 },
- { 0x16, HDA_INPUT, 4 },
- { } /* end */
-};
-#endif
-
static void override_mic_boost(struct hda_codec *codec, hda_nid_t pin,
int offset, int num_steps, int step_size)
{
@@ -3833,62 +3099,21 @@ static int patch_vt1708S(struct hda_codec *codec)
if (spec == NULL)
return -ENOMEM;
+ spec->aa_mix_nid = 0x16;
+ override_mic_boost(codec, 0x1a, 0, 3, 40);
+ override_mic_boost(codec, 0x1e, 0, 3, 40);
+
/* automatic parse from the BIOS config */
- err = vt1708S_parse_auto_config(codec);
+ err = via_parse_auto_config(codec);
if (err < 0) {
via_free(codec);
return err;
- } else if (!err) {
- printk(KERN_INFO "hda_codec: Cannot set up configuration "
- "from BIOS. Using genenic mode...\n");
}
- spec->init_verbs[spec->num_iverbs++] = vt1708S_volume_init_verbs;
- if (codec->vendor_id == 0x11064397)
- spec->init_verbs[spec->num_iverbs++] =
- vt1705_uniwill_init_verbs;
- else
- spec->init_verbs[spec->num_iverbs++] =
- vt1708S_uniwill_init_verbs;
-
- if (codec->vendor_id == 0x11060440)
- spec->stream_name_analog = "VT1818S Analog";
- else if (codec->vendor_id == 0x11064397)
- spec->stream_name_analog = "VT1705 Analog";
- else
- spec->stream_name_analog = "VT1708S Analog";
- if (codec->vendor_id == 0x11064397)
- spec->stream_analog_playback = &vt1705_pcm_analog_playback;
- else
- spec->stream_analog_playback = &vt1708S_pcm_analog_playback;
- spec->stream_analog_capture = &vt1708S_pcm_analog_capture;
-
- if (codec->vendor_id == 0x11060440)
- spec->stream_name_digital = "VT1818S Digital";
- else if (codec->vendor_id == 0x11064397)
- spec->stream_name_digital = "VT1705 Digital";
- else
- spec->stream_name_digital = "VT1708S Digital";
- spec->stream_digital_playback = &vt1708S_pcm_digital_playback;
-
- if (!spec->adc_nids && spec->input_mux) {
- spec->adc_nids = vt1708S_adc_nids;
- spec->num_adc_nids = ARRAY_SIZE(vt1708S_adc_nids);
- get_mux_nids(codec);
- override_mic_boost(codec, 0x1a, 0, 3, 40);
- override_mic_boost(codec, 0x1e, 0, 3, 40);
- spec->mixers[spec->num_mixers] = vt1708S_capture_mixer;
- spec->num_mixers++;
- }
+ spec->init_verbs[spec->num_iverbs++] = vt1708S_init_verbs;
codec->patch_ops = via_patch_ops;
- codec->patch_ops.init = via_auto_init;
- codec->patch_ops.unsol_event = via_unsol_event;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
- spec->loopback.amplist = vt1708S_loopbacks;
-#endif
-
/* correct names for VT1708BCE */
if (get_codec_type(codec) == VT1708BCE) {
kfree(codec->chip_name);
@@ -3896,13 +3121,6 @@ static int patch_vt1708S(struct hda_codec *codec)
snprintf(codec->bus->card->mixername,
sizeof(codec->bus->card->mixername),
"%s %s", codec->vendor_name, codec->chip_name);
- spec->stream_name_analog = "VT1708BCE Analog";
- spec->stream_name_digital = "VT1708BCE Digital";
- }
- /* correct names for VT1818S */
- if (codec->vendor_id == 0x11060440) {
- spec->stream_name_analog = "VT1818S Analog";
- spec->stream_name_digital = "VT1818S Digital";
}
/* correct names for VT1705 */
if (codec->vendor_id == 0x11064397) {
@@ -3918,55 +3136,7 @@ static int patch_vt1708S(struct hda_codec *codec)
/* Patch for VT1702 */
-/* capture mixer elements */
-static const struct snd_kcontrol_new vt1702_capture_mixer[] = {
- HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x20, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x20, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x1F, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x1F, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Digital Mic Boost Capture Volume", 0x1E, 0x0,
- HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* The multiple "Capture Source" controls confuse alsamixer
- * So call somewhat different..
- */
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 1,
- .info = via_mux_enum_info,
- .get = via_mux_enum_get,
- .put = via_mux_enum_put,
- },
- { } /* end */
-};
-
-static const struct hda_verb vt1702_volume_init_verbs[] = {
- /*
- * Unmute ADC0-1 and set the default input to mic-in
- */
- {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x1F, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-
- /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
- * mixer widget
- */
- /* Amp Indices: Mic1 = 1, Line = 1, Mic2 = 3 */
- {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
- {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
- {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-
- /* Setup default input of PW4 to MW0 */
- {0x17, AC_VERB_SET_CONNECT_SEL, 0x1},
- /* PW6 PW7 Output enable */
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
- {0x1C, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+static const struct hda_verb vt1702_init_verbs[] = {
/* mixer enable */
{0x1, 0xF88, 0x3},
/* GPIO 0~2 */
@@ -3974,202 +3144,6 @@ static const struct hda_verb vt1702_volume_init_verbs[] = {
{ }
};
-static const struct hda_verb vt1702_uniwill_init_verbs[] = {
- {0x17, AC_VERB_SET_UNSOLICITED_ENABLE,
- AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
- {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- { }
-};
-
-static const struct hda_pcm_stream vt1702_pcm_analog_playback = {
- .substreams = 2,
- .channels_min = 2,
- .channels_max = 2,
- .nid = 0x10, /* NID to query formats and rates */
- .ops = {
- .open = via_playback_pcm_open,
- .prepare = via_playback_multi_pcm_prepare,
- .cleanup = via_playback_multi_pcm_cleanup,
- .close = via_pcm_open_close
- },
-};
-
-static const struct hda_pcm_stream vt1702_pcm_analog_capture = {
- .substreams = 3,
- .channels_min = 2,
- .channels_max = 2,
- .nid = 0x12, /* NID to query formats and rates */
- .ops = {
- .open = via_pcm_open_close,
- .prepare = via_capture_pcm_prepare,
- .cleanup = via_capture_pcm_cleanup,
- .close = via_pcm_open_close
- },
-};
-
-static const struct hda_pcm_stream vt1702_pcm_digital_playback = {
- .substreams = 2,
- .channels_min = 2,
- .channels_max = 2,
- /* NID is set in via_build_pcms */
- .ops = {
- .open = via_dig_playback_pcm_open,
- .close = via_dig_playback_pcm_close,
- .prepare = via_dig_playback_pcm_prepare,
- .cleanup = via_dig_playback_pcm_cleanup
- },
-};
-
-/* fill in the dac_nids table from the parsed pin configuration */
-static int vt1702_auto_fill_dac_nids(struct via_spec *spec,
- const struct auto_pin_cfg *cfg)
-{
- spec->multiout.num_dacs = 1;
- spec->multiout.dac_nids = spec->private_dac_nids;
-
- if (cfg->line_out_pins[0]) {
- /* config dac list */
- spec->private_dac_nids[0] = 0x10;
- }
-
- return 0;
-}
-
-/* add playback controls from the parsed DAC table */
-static int vt1702_auto_create_line_out_ctls(struct via_spec *spec,
- const struct auto_pin_cfg *cfg)
-{
- int err;
-
- if (!cfg->line_out_pins[0])
- return -1;
-
- /* add control to mixer index 0 */
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
- "Master Front Playback Volume",
- HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
- if (err < 0)
- return err;
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
- "Master Front Playback Switch",
- HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
- if (err < 0)
- return err;
-
- /* Front */
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
- "Front Playback Volume",
- HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
- "Front Playback Switch",
- HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
-
- return 0;
-}
-
-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 * const texts[] = { "ON", "OFF", NULL};
- if (!pin)
- return 0;
- spec->multiout.hp_nid = 0x1D;
- spec->hp_independent_mode_index = 0;
-
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
- "Headphone Playback Volume",
- HDA_COMPOSE_AMP_VAL(0x1D, 3, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
-
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
- "Headphone Playback Switch",
- HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
-
- imux = &spec->private_imux[1];
-
- /* for hp mode select */
- for (i = 0; texts[i]; i++)
- snd_hda_add_imux_item(imux, texts[i], i, NULL);
-
- spec->hp_mux = &spec->private_imux[1];
- return 0;
-}
-
-/* create playback/capture controls for input pins */
-static int vt1702_auto_create_analog_input_ctls(struct hda_codec *codec,
- const struct auto_pin_cfg *cfg)
-{
- static const hda_nid_t pin_idxs[] = { 0x14, 0x15, 0x18, 0xff };
- return vt_auto_create_analog_input_ctls(codec, cfg, 0x1a, pin_idxs,
- ARRAY_SIZE(pin_idxs));
-}
-
-static int vt1702_parse_auto_config(struct hda_codec *codec)
-{
- struct via_spec *spec = codec->spec;
- int err;
-
- err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
- if (err < 0)
- return err;
- err = vt1702_auto_fill_dac_nids(spec, &spec->autocfg);
- if (err < 0)
- return err;
- if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
- return 0; /* can't find valid BIOS pin config */
-
- err = vt1702_auto_create_line_out_ctls(spec, &spec->autocfg);
- if (err < 0)
- return err;
- err = vt1702_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
- if (err < 0)
- return err;
- /* limit AA path volume to 0 dB */
- snd_hda_override_amp_caps(codec, 0x1A, HDA_INPUT,
- (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
- (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
- (0x5 << AC_AMPCAP_STEP_SIZE_SHIFT) |
- (1 << AC_AMPCAP_MUTE_SHIFT));
- err = vt1702_auto_create_analog_input_ctls(codec, &spec->autocfg);
- if (err < 0)
- return err;
-
- spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-
- fill_dig_outs(codec);
-
- if (spec->kctls.list)
- spec->mixers[spec->num_mixers++] = spec->kctls.list;
-
- spec->input_mux = &spec->private_imux[0];
-
- if (spec->hp_mux)
- via_hp_build(codec);
-
- return 1;
-}
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static const struct hda_amp_list vt1702_loopbacks[] = {
- { 0x1A, HDA_INPUT, 1 },
- { 0x1A, HDA_INPUT, 2 },
- { 0x1A, HDA_INPUT, 3 },
- { 0x1A, HDA_INPUT, 4 },
- { } /* end */
-};
-#endif
-
static void set_widgets_power_state_vt1702(struct hda_codec *codec)
{
int imux_is_smixer =
@@ -4211,398 +3185,46 @@ static int patch_vt1702(struct hda_codec *codec)
if (spec == NULL)
return -ENOMEM;
+ spec->aa_mix_nid = 0x1a;
+
+ /* limit AA path volume to 0 dB */
+ snd_hda_override_amp_caps(codec, 0x1A, HDA_INPUT,
+ (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
+ (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
+ (0x5 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+ (1 << AC_AMPCAP_MUTE_SHIFT));
+
/* automatic parse from the BIOS config */
- err = vt1702_parse_auto_config(codec);
+ err = via_parse_auto_config(codec);
if (err < 0) {
via_free(codec);
return err;
- } else if (!err) {
- printk(KERN_INFO "hda_codec: Cannot set up configuration "
- "from BIOS. Using genenic mode...\n");
}
- spec->init_verbs[spec->num_iverbs++] = vt1702_volume_init_verbs;
- spec->init_verbs[spec->num_iverbs++] = vt1702_uniwill_init_verbs;
-
- spec->stream_name_analog = "VT1702 Analog";
- spec->stream_analog_playback = &vt1702_pcm_analog_playback;
- spec->stream_analog_capture = &vt1702_pcm_analog_capture;
-
- spec->stream_name_digital = "VT1702 Digital";
- spec->stream_digital_playback = &vt1702_pcm_digital_playback;
-
- if (!spec->adc_nids && spec->input_mux) {
- spec->adc_nids = vt1702_adc_nids;
- spec->num_adc_nids = ARRAY_SIZE(vt1702_adc_nids);
- get_mux_nids(codec);
- spec->mixers[spec->num_mixers] = vt1702_capture_mixer;
- spec->num_mixers++;
- }
+ spec->init_verbs[spec->num_iverbs++] = vt1702_init_verbs;
codec->patch_ops = via_patch_ops;
- codec->patch_ops.init = via_auto_init;
- codec->patch_ops.unsol_event = via_unsol_event;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
- spec->loopback.amplist = vt1702_loopbacks;
-#endif
-
spec->set_widgets_power_state = set_widgets_power_state_vt1702;
return 0;
}
/* Patch for VT1718S */
-/* capture mixer elements */
-static const struct snd_kcontrol_new vt1718S_capture_mixer[] = {
- HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x29, 0x0,
- HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* The multiple "Capture Source" controls confuse alsamixer
- * So call somewhat different..
- */
- .name = "Input Source",
- .count = 2,
- .info = via_mux_enum_info,
- .get = via_mux_enum_get,
- .put = via_mux_enum_put,
- },
- { } /* end */
-};
-
-static const struct hda_verb vt1718S_volume_init_verbs[] = {
- /*
- * Unmute ADC0-1 and set the default input to mic-in
- */
- {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
+static const struct hda_verb vt1718S_init_verbs[] = {
/* Enable MW0 adjust Gain 5 */
{0x1, 0xfb2, 0x10},
- /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
- * mixer widget
- */
- /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
- /* PW9 PW10 Output enable */
- {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
- {0x2e, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
- /* PW11 Input enable */
- {0x2f, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_IN_EN},
/* Enable Boost Volume backdoor */
{0x1, 0xf88, 0x8},
- /* MW0/1/2/3/4: un-mute index 0 (AOWx), mute index 1 (MW9) */
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- /* set MUX1 = 2 (AOW4), MUX2 = 1 (AOW3) */
- {0x34, AC_VERB_SET_CONNECT_SEL, 0x2},
- {0x35, AC_VERB_SET_CONNECT_SEL, 0x1},
- { }
-};
-
-static const struct hda_verb vt1718S_uniwill_init_verbs[] = {
- {0x28, AC_VERB_SET_UNSOLICITED_ENABLE,
- AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
- {0x24, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x26, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x27, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
{ }
};
-static const struct hda_pcm_stream vt1718S_pcm_analog_playback = {
- .substreams = 2,
- .channels_min = 2,
- .channels_max = 10,
- .nid = 0x8, /* NID to query formats and rates */
- .ops = {
- .open = via_playback_pcm_open,
- .prepare = via_playback_multi_pcm_prepare,
- .cleanup = via_playback_multi_pcm_cleanup,
- .close = via_pcm_open_close,
- },
-};
-
-static const struct hda_pcm_stream vt1718S_pcm_analog_capture = {
- .substreams = 2,
- .channels_min = 2,
- .channels_max = 2,
- .nid = 0x10, /* NID to query formats and rates */
- .ops = {
- .open = via_pcm_open_close,
- .prepare = via_capture_pcm_prepare,
- .cleanup = via_capture_pcm_cleanup,
- .close = via_pcm_open_close,
- },
-};
-
-static const struct hda_pcm_stream vt1718S_pcm_digital_playback = {
- .substreams = 2,
- .channels_min = 2,
- .channels_max = 2,
- /* NID is set in via_build_pcms */
- .ops = {
- .open = via_dig_playback_pcm_open,
- .close = via_dig_playback_pcm_close,
- .prepare = via_dig_playback_pcm_prepare,
- .cleanup = via_dig_playback_pcm_cleanup
- },
-};
-
-static const struct hda_pcm_stream vt1718S_pcm_digital_capture = {
- .substreams = 1,
- .channels_min = 2,
- .channels_max = 2,
-};
-
-/* fill in the dac_nids table from the parsed pin configuration */
-static int vt1718S_auto_fill_dac_nids(struct via_spec *spec,
- const struct auto_pin_cfg *cfg)
-{
- int i;
- hda_nid_t nid;
-
- spec->multiout.num_dacs = cfg->line_outs;
-
- spec->multiout.dac_nids = spec->private_dac_nids;
-
- for (i = 0; i < 4; i++) {
- nid = cfg->line_out_pins[i];
- if (nid) {
- /* config dac list */
- switch (i) {
- case AUTO_SEQ_FRONT:
- spec->private_dac_nids[i] = 0x8;
- break;
- case AUTO_SEQ_CENLFE:
- spec->private_dac_nids[i] = 0xa;
- break;
- case AUTO_SEQ_SURROUND:
- spec->private_dac_nids[i] = 0x9;
- break;
- case AUTO_SEQ_SIDE:
- spec->private_dac_nids[i] = 0xb;
- break;
- }
- }
- }
-
- return 0;
-}
-
-/* add playback controls from the parsed DAC table */
-static int vt1718S_auto_create_multi_out_ctls(struct via_spec *spec,
- const struct auto_pin_cfg *cfg)
-{
- char name[32];
- 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;
- int i, err;
-
- for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
- nid = cfg->line_out_pins[i];
-
- if (!nid)
- continue;
- nid_vol = nid_vols[i];
- nid_mute = nid_mutes[i];
-
- if (i == AUTO_SEQ_CENLFE) {
- /* Center/LFE */
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
- "Center Playback Volume",
- HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
- "LFE Playback Volume",
- HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- err = via_add_control(
- spec, VIA_CTL_WIDGET_MUTE,
- "Center Playback Switch",
- HDA_COMPOSE_AMP_VAL(nid_mute, 1, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- err = via_add_control(
- spec, VIA_CTL_WIDGET_MUTE,
- "LFE Playback Switch",
- HDA_COMPOSE_AMP_VAL(nid_mute, 2, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- } else if (i == AUTO_SEQ_FRONT) {
- /* add control to mixer index 0 */
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
- "Master Front Playback Volume",
- HDA_COMPOSE_AMP_VAL(0x21, 3, 5,
- HDA_INPUT));
- if (err < 0)
- return err;
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
- "Master Front Playback Switch",
- HDA_COMPOSE_AMP_VAL(0x21, 3, 5,
- HDA_INPUT));
- if (err < 0)
- return err;
- /* Front */
- sprintf(name, "%s Playback Volume", chname[i]);
- err = via_add_control(
- spec, VIA_CTL_WIDGET_VOL, name,
- HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
- sprintf(name, "%s Playback Switch", chname[i]);
- err = via_add_control(
- spec, VIA_CTL_WIDGET_MUTE, name,
- HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- } else {
- sprintf(name, "%s Playback Volume", chname[i]);
- err = via_add_control(
- spec, VIA_CTL_WIDGET_VOL, name,
- HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
- sprintf(name, "%s Playback Switch", chname[i]);
- err = via_add_control(
- spec, VIA_CTL_WIDGET_MUTE, name,
- HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- }
- }
- return 0;
-}
-
-static int vt1718S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
-{
- int err;
-
- if (!pin)
- return 0;
-
- spec->multiout.hp_nid = 0xc; /* AOW4 */
- spec->hp_independent_mode_index = 1;
-
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
- "Headphone Playback Volume",
- HDA_COMPOSE_AMP_VAL(0xc, 3, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
-
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
- "Headphone Playback Switch",
- HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
-
- create_hp_imux(spec);
- return 0;
-}
-
-/* create playback/capture controls for input pins */
-static int vt1718S_auto_create_analog_input_ctls(struct hda_codec *codec,
- const struct auto_pin_cfg *cfg)
-{
- static const hda_nid_t pin_idxs[] = { 0x2c, 0x2b, 0x2a, 0x29, 0, 0xff };
- return vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
- ARRAY_SIZE(pin_idxs));
-}
-
-static int vt1718S_parse_auto_config(struct hda_codec *codec)
-{
- struct via_spec *spec = codec->spec;
- int err;
-
- err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
-
- if (err < 0)
- return err;
- err = vt1718S_auto_fill_dac_nids(spec, &spec->autocfg);
- if (err < 0)
- return err;
- if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
- return 0; /* can't find valid BIOS pin config */
-
- err = vt1718S_auto_create_multi_out_ctls(spec, &spec->autocfg);
- if (err < 0)
- return err;
- err = vt1718S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
- if (err < 0)
- return err;
- err = vt1718S_auto_create_analog_input_ctls(codec, &spec->autocfg);
- if (err < 0)
- return err;
-
- spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-
- fill_dig_outs(codec);
-
- if (spec->autocfg.dig_in_pin && codec->vendor_id == 0x11060428)
- spec->dig_in_nid = 0x13;
-
- if (spec->kctls.list)
- spec->mixers[spec->num_mixers++] = spec->kctls.list;
-
- spec->input_mux = &spec->private_imux[0];
-
- if (spec->hp_mux)
- via_hp_build(codec);
-
- via_smart51_build(spec);
-
- return 1;
-}
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static const struct hda_amp_list vt1718S_loopbacks[] = {
- { 0x21, HDA_INPUT, 1 },
- { 0x21, HDA_INPUT, 2 },
- { 0x21, HDA_INPUT, 3 },
- { 0x21, HDA_INPUT, 4 },
- { } /* end */
-};
-#endif
-
static void set_widgets_power_state_vt1718S(struct hda_codec *codec)
{
struct via_spec *spec = codec->spec;
int imux_is_smixer;
- unsigned int parm;
+ unsigned int parm, parm2;
/* MUX6 (1eh) = stereo mixer */
imux_is_smixer =
snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
@@ -4625,7 +3247,7 @@ static void set_widgets_power_state_vt1718S(struct hda_codec *codec)
parm = AC_PWRST_D3;
set_pin_power_state(codec, 0x27, &parm);
snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, parm);
- snd_hda_codec_write(codec, 0xb, 0, AC_VERB_SET_POWER_STATE, parm);
+ parm2 = parm; /* for pin 0x0b */
/* PW2 (26h), AOW2 (ah) */
parm = AC_PWRST_D3;
@@ -4640,6 +3262,9 @@ static void set_widgets_power_state_vt1718S(struct hda_codec *codec)
if (!spec->hp_independent_mode) /* check for redirected HP */
set_pin_power_state(codec, 0x28, &parm);
snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE, parm);
+ if (!spec->hp_independent_mode && parm2 != AC_PWRST_D3)
+ parm = parm2;
+ snd_hda_codec_write(codec, 0xb, 0, AC_VERB_SET_POWER_STATE, parm);
/* MW9 (21h), Mw2 (1ah), AOW0 (8h) */
snd_hda_codec_write(codec, 0x21, 0, AC_VERB_SET_POWER_STATE,
imux_is_smixer ? AC_PWRST_D0 : parm);
@@ -4664,6 +3289,41 @@ static void set_widgets_power_state_vt1718S(struct hda_codec *codec)
}
}
+/* Add a connection to the primary DAC from AA-mixer for some codecs
+ * This isn't listed from the raw info, but the chip has a secret connection.
+ */
+static int add_secret_dac_path(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ int i, nums;
+ hda_nid_t conn[8];
+ hda_nid_t nid;
+
+ if (!spec->aa_mix_nid)
+ return 0;
+ nums = snd_hda_get_connections(codec, spec->aa_mix_nid, conn,
+ ARRAY_SIZE(conn) - 1);
+ for (i = 0; i < nums; i++) {
+ if (get_wcaps_type(get_wcaps(codec, conn[i])) == AC_WID_AUD_OUT)
+ return 0;
+ }
+
+ /* find the primary DAC and add to the connection list */
+ nid = codec->start_nid;
+ for (i = 0; i < codec->num_nodes; i++, nid++) {
+ unsigned int caps = get_wcaps(codec, nid);
+ if (get_wcaps_type(caps) == AC_WID_AUD_OUT &&
+ !(caps & AC_WCAP_DIGITAL)) {
+ conn[nums++] = nid;
+ return snd_hda_override_conn_list(codec,
+ spec->aa_mix_nid,
+ nums, conn);
+ }
+ }
+ return 0;
+}
+
+
static int patch_vt1718S(struct hda_codec *codec)
{
struct via_spec *spec;
@@ -4674,57 +3334,22 @@ static int patch_vt1718S(struct hda_codec *codec)
if (spec == NULL)
return -ENOMEM;
+ spec->aa_mix_nid = 0x21;
+ override_mic_boost(codec, 0x2b, 0, 3, 40);
+ override_mic_boost(codec, 0x29, 0, 3, 40);
+ add_secret_dac_path(codec);
+
/* automatic parse from the BIOS config */
- err = vt1718S_parse_auto_config(codec);
+ err = via_parse_auto_config(codec);
if (err < 0) {
via_free(codec);
return err;
- } else if (!err) {
- printk(KERN_INFO "hda_codec: Cannot set up configuration "
- "from BIOS. Using genenic mode...\n");
}
- spec->init_verbs[spec->num_iverbs++] = vt1718S_volume_init_verbs;
- spec->init_verbs[spec->num_iverbs++] = vt1718S_uniwill_init_verbs;
-
- if (codec->vendor_id == 0x11060441)
- spec->stream_name_analog = "VT2020 Analog";
- else if (codec->vendor_id == 0x11064441)
- spec->stream_name_analog = "VT1828S Analog";
- else
- spec->stream_name_analog = "VT1718S Analog";
- spec->stream_analog_playback = &vt1718S_pcm_analog_playback;
- spec->stream_analog_capture = &vt1718S_pcm_analog_capture;
-
- if (codec->vendor_id == 0x11060441)
- spec->stream_name_digital = "VT2020 Digital";
- else if (codec->vendor_id == 0x11064441)
- spec->stream_name_digital = "VT1828S Digital";
- else
- spec->stream_name_digital = "VT1718S Digital";
- spec->stream_digital_playback = &vt1718S_pcm_digital_playback;
- if (codec->vendor_id == 0x11060428 || codec->vendor_id == 0x11060441)
- spec->stream_digital_capture = &vt1718S_pcm_digital_capture;
-
- if (!spec->adc_nids && spec->input_mux) {
- spec->adc_nids = vt1718S_adc_nids;
- spec->num_adc_nids = ARRAY_SIZE(vt1718S_adc_nids);
- get_mux_nids(codec);
- override_mic_boost(codec, 0x2b, 0, 3, 40);
- override_mic_boost(codec, 0x29, 0, 3, 40);
- spec->mixers[spec->num_mixers] = vt1718S_capture_mixer;
- spec->num_mixers++;
- }
+ spec->init_verbs[spec->num_iverbs++] = vt1718S_init_verbs;
codec->patch_ops = via_patch_ops;
- codec->patch_ops.init = via_auto_init;
- codec->patch_ops.unsol_event = via_unsol_event;
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
- spec->loopback.amplist = vt1718S_loopbacks;
-#endif
-
spec->set_widgets_power_state = set_widgets_power_state_vt1718S;
return 0;
@@ -4770,26 +3395,6 @@ static int vt1716s_dmic_put(struct snd_kcontrol *kcontrol,
return 1;
}
-/* capture mixer elements */
-static const struct snd_kcontrol_new vt1716S_capture_mixer[] = {
- HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x1A, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x1E, 0x0,
- HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Input Source",
- .count = 1,
- .info = via_mux_enum_info,
- .get = via_mux_enum_get,
- .put = via_mux_enum_put,
- },
- { } /* end */
-};
-
static const struct snd_kcontrol_new vt1716s_dmic_mixer[] = {
HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x22, 0x0, HDA_INPUT),
{
@@ -4811,45 +3416,7 @@ static const struct snd_kcontrol_new vt1716S_mono_out_mixer[] = {
{ } /* end */
};
-static const struct hda_verb vt1716S_volume_init_verbs[] = {
- /*
- * Unmute ADC0-1 and set the default input to mic-in
- */
- {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-
- /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
- * mixer widget
- */
- /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-
- /* MUX Indices: Stereo Mixer = 5 */
- {0x17, AC_VERB_SET_CONNECT_SEL, 0x5},
-
- /* Setup default input of PW4 to MW0 */
- {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
-
- /* Setup default input of SW1 as MW0 */
- {0x18, AC_VERB_SET_CONNECT_SEL, 0x1},
-
- /* Setup default input of SW4 as AOW0 */
- {0x28, AC_VERB_SET_CONNECT_SEL, 0x1},
-
- /* PW9 PW10 Output enable */
- {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
- {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
-
- /* Unmute SW1, PW12 */
- {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- /* PW12 Output enable */
- {0x2a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+static const struct hda_verb vt1716S_init_verbs[] = {
/* Enable Boost Volume backdoor */
{0x1, 0xf8a, 0x80},
/* don't bybass mixer */
@@ -4859,272 +3426,6 @@ static const struct hda_verb vt1716S_volume_init_verbs[] = {
{ }
};
-
-static const struct hda_verb vt1716S_uniwill_init_verbs[] = {
- {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
- AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
- {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE,
- AC_USRSP_EN | VIA_MONO_EVENT | VIA_JACK_EVENT},
- {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- { }
-};
-
-static const struct hda_pcm_stream vt1716S_pcm_analog_playback = {
- .substreams = 2,
- .channels_min = 2,
- .channels_max = 6,
- .nid = 0x10, /* NID to query formats and rates */
- .ops = {
- .open = via_playback_pcm_open,
- .prepare = via_playback_multi_pcm_prepare,
- .cleanup = via_playback_multi_pcm_cleanup,
- .close = via_pcm_open_close,
- },
-};
-
-static const struct hda_pcm_stream vt1716S_pcm_analog_capture = {
- .substreams = 2,
- .channels_min = 2,
- .channels_max = 2,
- .nid = 0x13, /* NID to query formats and rates */
- .ops = {
- .open = via_pcm_open_close,
- .prepare = via_capture_pcm_prepare,
- .cleanup = via_capture_pcm_cleanup,
- .close = via_pcm_open_close,
- },
-};
-
-static const struct hda_pcm_stream vt1716S_pcm_digital_playback = {
- .substreams = 2,
- .channels_min = 2,
- .channels_max = 2,
- /* NID is set in via_build_pcms */
- .ops = {
- .open = via_dig_playback_pcm_open,
- .close = via_dig_playback_pcm_close,
- .prepare = via_dig_playback_pcm_prepare,
- .cleanup = via_dig_playback_pcm_cleanup
- },
-};
-
-/* fill in the dac_nids table from the parsed pin configuration */
-static int vt1716S_auto_fill_dac_nids(struct via_spec *spec,
- const struct auto_pin_cfg *cfg)
-{ int i;
- hda_nid_t nid;
-
- spec->multiout.num_dacs = cfg->line_outs;
-
- spec->multiout.dac_nids = spec->private_dac_nids;
-
- for (i = 0; i < 3; i++) {
- nid = cfg->line_out_pins[i];
- if (nid) {
- /* config dac list */
- switch (i) {
- case AUTO_SEQ_FRONT:
- spec->private_dac_nids[i] = 0x10;
- break;
- case AUTO_SEQ_CENLFE:
- spec->private_dac_nids[i] = 0x25;
- break;
- case AUTO_SEQ_SURROUND:
- spec->private_dac_nids[i] = 0x11;
- break;
- }
- }
- }
-
- return 0;
-}
-
-/* add playback controls from the parsed DAC table */
-static int vt1716S_auto_create_multi_out_ctls(struct via_spec *spec,
- const struct auto_pin_cfg *cfg)
-{
- char name[32];
- 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;
- int i, err;
-
- for (i = 0; i <= AUTO_SEQ_CENLFE; i++) {
- nid = cfg->line_out_pins[i];
-
- if (!nid)
- continue;
-
- nid_vol = nid_vols[i];
- nid_mute = nid_mutes[i];
-
- if (i == AUTO_SEQ_CENLFE) {
- err = via_add_control(
- spec, VIA_CTL_WIDGET_VOL,
- "Center Playback Volume",
- HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
- err = via_add_control(
- spec, VIA_CTL_WIDGET_VOL,
- "LFE Playback Volume",
- HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
- err = via_add_control(
- spec, VIA_CTL_WIDGET_MUTE,
- "Center Playback Switch",
- HDA_COMPOSE_AMP_VAL(nid_mute, 1, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- err = via_add_control(
- spec, VIA_CTL_WIDGET_MUTE,
- "LFE Playback Switch",
- HDA_COMPOSE_AMP_VAL(nid_mute, 2, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- } else if (i == AUTO_SEQ_FRONT) {
-
- err = via_add_control(
- spec, VIA_CTL_WIDGET_VOL,
- "Master Front Playback Volume",
- HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_INPUT));
- if (err < 0)
- return err;
- err = via_add_control(
- spec, VIA_CTL_WIDGET_MUTE,
- "Master Front Playback Switch",
- HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_INPUT));
- if (err < 0)
- return err;
-
- sprintf(name, "%s Playback Volume", chname[i]);
- err = via_add_control(
- spec, VIA_CTL_WIDGET_VOL, name,
- HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
- sprintf(name, "%s Playback Switch", chname[i]);
- err = via_add_control(
- spec, VIA_CTL_WIDGET_MUTE, name,
- HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- } else {
- sprintf(name, "%s Playback Volume", chname[i]);
- err = via_add_control(
- spec, VIA_CTL_WIDGET_VOL, name,
- HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
- sprintf(name, "%s Playback Switch", chname[i]);
- err = via_add_control(
- spec, VIA_CTL_WIDGET_MUTE, name,
- HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
- HDA_OUTPUT));
- if (err < 0)
- return err;
- }
- }
- return 0;
-}
-
-static int vt1716S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
-{
- int err;
-
- if (!pin)
- return 0;
-
- spec->multiout.hp_nid = 0x25; /* AOW3 */
- spec->hp_independent_mode_index = 1;
-
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
- "Headphone Playback Volume",
- HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
-
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
- "Headphone Playback Switch",
- HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
-
- create_hp_imux(spec);
- return 0;
-}
-
-/* create playback/capture controls for input pins */
-static int vt1716S_auto_create_analog_input_ctls(struct hda_codec *codec,
- const struct auto_pin_cfg *cfg)
-{
- static const hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff };
- return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
- ARRAY_SIZE(pin_idxs));
-}
-
-static int vt1716S_parse_auto_config(struct hda_codec *codec)
-{
- struct via_spec *spec = codec->spec;
- int err;
-
- err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
- if (err < 0)
- return err;
- err = vt1716S_auto_fill_dac_nids(spec, &spec->autocfg);
- if (err < 0)
- return err;
- if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
- return 0; /* can't find valid BIOS pin config */
-
- err = vt1716S_auto_create_multi_out_ctls(spec, &spec->autocfg);
- if (err < 0)
- return err;
- err = vt1716S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
- if (err < 0)
- return err;
- err = vt1716S_auto_create_analog_input_ctls(codec, &spec->autocfg);
- if (err < 0)
- return err;
-
- spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-
- fill_dig_outs(codec);
-
- if (spec->kctls.list)
- spec->mixers[spec->num_mixers++] = spec->kctls.list;
-
- spec->input_mux = &spec->private_imux[0];
-
- if (spec->hp_mux)
- via_hp_build(codec);
-
- via_smart51_build(spec);
-
- return 1;
-}
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static const struct hda_amp_list vt1716S_loopbacks[] = {
- { 0x16, HDA_INPUT, 1 },
- { 0x16, HDA_INPUT, 2 },
- { 0x16, HDA_INPUT, 3 },
- { 0x16, HDA_INPUT, 4 },
- { } /* end */
-};
-#endif
-
static void set_widgets_power_state_vt1716S(struct hda_codec *codec)
{
struct via_spec *spec = codec->spec;
@@ -5228,35 +3529,18 @@ static int patch_vt1716S(struct hda_codec *codec)
if (spec == NULL)
return -ENOMEM;
+ spec->aa_mix_nid = 0x16;
+ override_mic_boost(codec, 0x1a, 0, 3, 40);
+ override_mic_boost(codec, 0x1e, 0, 3, 40);
+
/* automatic parse from the BIOS config */
- err = vt1716S_parse_auto_config(codec);
+ err = via_parse_auto_config(codec);
if (err < 0) {
via_free(codec);
return err;
- } else if (!err) {
- printk(KERN_INFO "hda_codec: Cannot set up configuration "
- "from BIOS. Using genenic mode...\n");
}
- spec->init_verbs[spec->num_iverbs++] = vt1716S_volume_init_verbs;
- spec->init_verbs[spec->num_iverbs++] = vt1716S_uniwill_init_verbs;
-
- spec->stream_name_analog = "VT1716S Analog";
- spec->stream_analog_playback = &vt1716S_pcm_analog_playback;
- spec->stream_analog_capture = &vt1716S_pcm_analog_capture;
-
- spec->stream_name_digital = "VT1716S Digital";
- spec->stream_digital_playback = &vt1716S_pcm_digital_playback;
-
- if (!spec->adc_nids && spec->input_mux) {
- spec->adc_nids = vt1716S_adc_nids;
- spec->num_adc_nids = ARRAY_SIZE(vt1716S_adc_nids);
- get_mux_nids(codec);
- override_mic_boost(codec, 0x1a, 0, 3, 40);
- override_mic_boost(codec, 0x1e, 0, 3, 40);
- spec->mixers[spec->num_mixers] = vt1716S_capture_mixer;
- spec->num_mixers++;
- }
+ spec->init_verbs[spec->num_iverbs++] = vt1716S_init_verbs;
spec->mixers[spec->num_mixers] = vt1716s_dmic_mixer;
spec->num_mixers++;
@@ -5265,354 +3549,32 @@ static int patch_vt1716S(struct hda_codec *codec)
codec->patch_ops = via_patch_ops;
- codec->patch_ops.init = via_auto_init;
- codec->patch_ops.unsol_event = via_unsol_event;
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
- spec->loopback.amplist = vt1716S_loopbacks;
-#endif
-
spec->set_widgets_power_state = set_widgets_power_state_vt1716S;
return 0;
}
/* for vt2002P */
-/* capture mixer elements */
-static const struct snd_kcontrol_new vt2002P_capture_mixer[] = {
- HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x29, 0x0,
- HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* The multiple "Capture Source" controls confuse alsamixer
- * So call somewhat different..
- */
- /* .name = "Capture Source", */
- .name = "Input Source",
- .count = 2,
- .info = via_mux_enum_info,
- .get = via_mux_enum_get,
- .put = via_mux_enum_put,
- },
- { } /* end */
-};
-
-static const struct hda_verb vt2002P_volume_init_verbs[] = {
+static const struct hda_verb vt2002P_init_verbs[] = {
/* Class-D speaker related verbs */
{0x1, 0xfe0, 0x4},
{0x1, 0xfe9, 0x80},
{0x1, 0xfe2, 0x22},
- /*
- * Unmute ADC0-1 and set the default input to mic-in
- */
- {0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-
- /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
- * mixer widget
- */
- /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-
- /* MUX Indices: Mic = 0 */
- {0x1e, AC_VERB_SET_CONNECT_SEL, 0},
- {0x1f, AC_VERB_SET_CONNECT_SEL, 0},
-
- /* PW9 Output enable */
- {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
-
/* Enable Boost Volume backdoor */
{0x1, 0xfb9, 0x24},
-
- /* MW0/1/4/8: un-mute index 0 (MUXx), un-mute index 1 (MW9) */
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
- /* set MUX0/1/4/8 = 0 (AOW0) */
- {0x34, AC_VERB_SET_CONNECT_SEL, 0},
- {0x35, AC_VERB_SET_CONNECT_SEL, 0},
- {0x37, AC_VERB_SET_CONNECT_SEL, 0},
- {0x3b, AC_VERB_SET_CONNECT_SEL, 0},
-
- /* set PW0 index=0 (MW0) */
- {0x24, AC_VERB_SET_CONNECT_SEL, 0},
-
/* Enable AOW0 to MW9 */
{0x1, 0xfb8, 0x88},
{ }
};
-static const struct hda_verb vt1802_volume_init_verbs[] = {
- /*
- * Unmute ADC0-1 and set the default input to mic-in
- */
- {0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-
- /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
- * mixer widget
- */
- /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-
- /* MUX Indices: Mic = 0 */
- {0x1e, AC_VERB_SET_CONNECT_SEL, 0},
- {0x1f, AC_VERB_SET_CONNECT_SEL, 0},
-
- /* PW9 Output enable */
- {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
+static const struct hda_verb vt1802_init_verbs[] = {
/* Enable Boost Volume backdoor */
{0x1, 0xfb9, 0x24},
-
- /* MW0/1/4/8: un-mute index 0 (MUXx), un-mute index 1 (MW9) */
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
- /* set MUX0/1/4/8 = 0 (AOW0) */
- {0x34, AC_VERB_SET_CONNECT_SEL, 0},
- {0x35, AC_VERB_SET_CONNECT_SEL, 0},
- {0x38, AC_VERB_SET_CONNECT_SEL, 0},
- {0x3c, AC_VERB_SET_CONNECT_SEL, 0},
-
- /* set PW0 index=0 (MW0) */
- {0x24, AC_VERB_SET_CONNECT_SEL, 0},
-
/* Enable AOW0 to MW9 */
{0x1, 0xfb8, 0x88},
{ }
};
-
-static const struct hda_verb vt2002P_uniwill_init_verbs[] = {
- {0x25, AC_VERB_SET_UNSOLICITED_ENABLE,
- AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
- {0x26, AC_VERB_SET_UNSOLICITED_ENABLE,
- AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
- {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- { }
-};
-static const struct hda_verb vt1802_uniwill_init_verbs[] = {
- {0x25, AC_VERB_SET_UNSOLICITED_ENABLE,
- AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
- {0x28, AC_VERB_SET_UNSOLICITED_ENABLE,
- AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
- {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- { }
-};
-
-static const struct hda_pcm_stream vt2002P_pcm_analog_playback = {
- .substreams = 2,
- .channels_min = 2,
- .channels_max = 2,
- .nid = 0x8, /* NID to query formats and rates */
- .ops = {
- .open = via_playback_pcm_open,
- .prepare = via_playback_multi_pcm_prepare,
- .cleanup = via_playback_multi_pcm_cleanup,
- .close = via_pcm_open_close,
- },
-};
-
-static const struct hda_pcm_stream vt2002P_pcm_analog_capture = {
- .substreams = 2,
- .channels_min = 2,
- .channels_max = 2,
- .nid = 0x10, /* NID to query formats and rates */
- .ops = {
- .open = via_pcm_open_close,
- .prepare = via_capture_pcm_prepare,
- .cleanup = via_capture_pcm_cleanup,
- .close = via_pcm_open_close,
- },
-};
-
-static const struct hda_pcm_stream vt2002P_pcm_digital_playback = {
- .substreams = 1,
- .channels_min = 2,
- .channels_max = 2,
- /* NID is set in via_build_pcms */
- .ops = {
- .open = via_dig_playback_pcm_open,
- .close = via_dig_playback_pcm_close,
- .prepare = via_dig_playback_pcm_prepare,
- .cleanup = via_dig_playback_pcm_cleanup
- },
-};
-
-/* fill in the dac_nids table from the parsed pin configuration */
-static int vt2002P_auto_fill_dac_nids(struct via_spec *spec,
- const struct auto_pin_cfg *cfg)
-{
- spec->multiout.num_dacs = 1;
- spec->multiout.dac_nids = spec->private_dac_nids;
- if (cfg->line_out_pins[0])
- spec->private_dac_nids[0] = 0x8;
- return 0;
-}
-
-/* add playback controls from the parsed DAC table */
-static int vt2002P_auto_create_multi_out_ctls(struct via_spec *spec,
- const struct auto_pin_cfg *cfg)
-{
- int err;
- hda_nid_t sw_nid;
-
- if (!cfg->line_out_pins[0])
- return -1;
-
- if (spec->codec_type == VT1802)
- sw_nid = 0x28;
- else
- sw_nid = 0x26;
-
- /* Line-Out: PortE */
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
- "Master Front Playback Volume",
- HDA_COMPOSE_AMP_VAL(0x8, 3, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
- err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE,
- "Master Front Playback Switch",
- HDA_COMPOSE_AMP_VAL(sw_nid, 3, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
-
- return 0;
-}
-
-static int vt2002P_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
-{
- int err;
-
- if (!pin)
- return 0;
-
- spec->multiout.hp_nid = 0x9;
- spec->hp_independent_mode_index = 1;
-
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
- "Headphone Playback Volume",
- HDA_COMPOSE_AMP_VAL(
- spec->multiout.hp_nid, 3, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
-
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
- "Headphone Playback Switch",
- HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
-
- create_hp_imux(spec);
- return 0;
-}
-
-/* create playback/capture controls for input pins */
-static int vt2002P_auto_create_analog_input_ctls(struct hda_codec *codec,
- const struct auto_pin_cfg *cfg)
-{
- struct via_spec *spec = codec->spec;
- struct hda_input_mux *imux = &spec->private_imux[0];
- static const hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0xff };
- int err;
-
- err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
- ARRAY_SIZE(pin_idxs));
- if (err < 0)
- return err;
- /* build volume/mute control of loopback */
- err = via_new_analog_input(spec, "Stereo Mixer", 0, 3, 0x21);
- if (err < 0)
- return err;
-
- /* for digital mic select */
- snd_hda_add_imux_item(imux, "Digital Mic", 4, NULL);
-
- return 0;
-}
-
-static int vt2002P_parse_auto_config(struct hda_codec *codec)
-{
- struct via_spec *spec = codec->spec;
- int err;
-
-
- err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
- if (err < 0)
- return err;
-
- err = vt2002P_auto_fill_dac_nids(spec, &spec->autocfg);
- if (err < 0)
- return err;
-
- if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
- return 0; /* can't find valid BIOS pin config */
-
- err = vt2002P_auto_create_multi_out_ctls(spec, &spec->autocfg);
- if (err < 0)
- return err;
- err = vt2002P_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
- if (err < 0)
- return err;
- err = vt2002P_auto_create_analog_input_ctls(codec, &spec->autocfg);
- if (err < 0)
- return err;
-
- spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-
- fill_dig_outs(codec);
-
- if (spec->kctls.list)
- spec->mixers[spec->num_mixers++] = spec->kctls.list;
-
- spec->input_mux = &spec->private_imux[0];
-
- if (spec->hp_mux)
- via_hp_build(codec);
-
- return 1;
-}
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static const struct hda_amp_list vt2002P_loopbacks[] = {
- { 0x21, HDA_INPUT, 0 },
- { 0x21, HDA_INPUT, 1 },
- { 0x21, HDA_INPUT, 2 },
- { } /* end */
-};
-#endif
-
static void set_widgets_power_state_vt2002P(struct hda_codec *codec)
{
struct via_spec *spec = codec->spec;
@@ -5724,6 +3686,18 @@ static void set_widgets_power_state_vt2002P(struct hda_codec *codec)
AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
}
+/* NIDs 0x24 and 0x33 on VT1802 have connections to non-existing NID 0x3e
+ * Replace this with mixer NID 0x1c
+ */
+static void fix_vt1802_connections(struct hda_codec *codec)
+{
+ static hda_nid_t conn_24[] = { 0x14, 0x1c };
+ static hda_nid_t conn_33[] = { 0x1c };
+
+ snd_hda_override_conn_list(codec, 0x24, ARRAY_SIZE(conn_24), conn_24);
+ snd_hda_override_conn_list(codec, 0x33, ARRAY_SIZE(conn_33), conn_33);
+}
+
/* patch for vt2002P */
static int patch_vt2002P(struct hda_codec *codec)
{
@@ -5735,344 +3709,46 @@ static int patch_vt2002P(struct hda_codec *codec)
if (spec == NULL)
return -ENOMEM;
+ spec->aa_mix_nid = 0x21;
+ override_mic_boost(codec, 0x2b, 0, 3, 40);
+ override_mic_boost(codec, 0x29, 0, 3, 40);
+ if (spec->codec_type == VT1802)
+ fix_vt1802_connections(codec);
+ add_secret_dac_path(codec);
+
/* automatic parse from the BIOS config */
- err = vt2002P_parse_auto_config(codec);
+ err = via_parse_auto_config(codec);
if (err < 0) {
via_free(codec);
return err;
- } else if (!err) {
- printk(KERN_INFO "hda_codec: Cannot set up configuration "
- "from BIOS. Using genenic mode...\n");
}
if (spec->codec_type == VT1802)
- spec->init_verbs[spec->num_iverbs++] =
- vt1802_volume_init_verbs;
- else
- spec->init_verbs[spec->num_iverbs++] =
- vt2002P_volume_init_verbs;
-
- if (spec->codec_type == VT1802)
- spec->init_verbs[spec->num_iverbs++] =
- vt1802_uniwill_init_verbs;
- else
- spec->init_verbs[spec->num_iverbs++] =
- vt2002P_uniwill_init_verbs;
-
- if (spec->codec_type == VT1802)
- spec->stream_name_analog = "VT1802 Analog";
- else
- spec->stream_name_analog = "VT2002P Analog";
- spec->stream_analog_playback = &vt2002P_pcm_analog_playback;
- spec->stream_analog_capture = &vt2002P_pcm_analog_capture;
-
- if (spec->codec_type == VT1802)
- spec->stream_name_digital = "VT1802 Digital";
+ spec->init_verbs[spec->num_iverbs++] = vt1802_init_verbs;
else
- spec->stream_name_digital = "VT2002P Digital";
- spec->stream_digital_playback = &vt2002P_pcm_digital_playback;
-
- if (!spec->adc_nids && spec->input_mux) {
- spec->adc_nids = vt2002P_adc_nids;
- spec->num_adc_nids = ARRAY_SIZE(vt2002P_adc_nids);
- get_mux_nids(codec);
- override_mic_boost(codec, 0x2b, 0, 3, 40);
- override_mic_boost(codec, 0x29, 0, 3, 40);
- spec->mixers[spec->num_mixers] = vt2002P_capture_mixer;
- spec->num_mixers++;
- }
+ spec->init_verbs[spec->num_iverbs++] = vt2002P_init_verbs;
codec->patch_ops = via_patch_ops;
- codec->patch_ops.init = via_auto_init;
- codec->patch_ops.unsol_event = via_unsol_event;
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
- spec->loopback.amplist = vt2002P_loopbacks;
-#endif
-
spec->set_widgets_power_state = set_widgets_power_state_vt2002P;
return 0;
}
/* for vt1812 */
-/* capture mixer elements */
-static const struct snd_kcontrol_new vt1812_capture_mixer[] = {
- HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Front Mic Boost Capture Volume", 0x29, 0x0,
- HDA_INPUT),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- /* The multiple "Capture Source" controls confuse alsamixer
- * So call somewhat different..
- */
- .name = "Input Source",
- .count = 2,
- .info = via_mux_enum_info,
- .get = via_mux_enum_get,
- .put = via_mux_enum_put,
- },
- { } /* end */
-};
-
-static const struct hda_verb vt1812_volume_init_verbs[] = {
- /*
- * Unmute ADC0-1 and set the default input to mic-in
- */
- {0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-
-
- /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
- * mixer widget
- */
- /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-
- /* MUX Indices: Mic = 0 */
- {0x1e, AC_VERB_SET_CONNECT_SEL, 0},
- {0x1f, AC_VERB_SET_CONNECT_SEL, 0},
-
- /* PW9 Output enable */
- {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
-
+static const struct hda_verb vt1812_init_verbs[] = {
/* Enable Boost Volume backdoor */
{0x1, 0xfb9, 0x24},
-
- /* MW0/1/4/13/15: un-mute index 0 (MUXx), un-mute index 1 (MW9) */
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
- {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
- /* set MUX0/1/4/13/15 = 0 (AOW0) */
- {0x34, AC_VERB_SET_CONNECT_SEL, 0},
- {0x35, AC_VERB_SET_CONNECT_SEL, 0},
- {0x38, AC_VERB_SET_CONNECT_SEL, 0},
- {0x3c, AC_VERB_SET_CONNECT_SEL, 0},
- {0x3d, AC_VERB_SET_CONNECT_SEL, 0},
-
/* Enable AOW0 to MW9 */
{0x1, 0xfb8, 0xa8},
{ }
};
-
-static const struct hda_verb vt1812_uniwill_init_verbs[] = {
- {0x33, AC_VERB_SET_UNSOLICITED_ENABLE,
- AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
- {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT },
- {0x28, AC_VERB_SET_UNSOLICITED_ENABLE,
- AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
- {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
- { }
-};
-
-static const struct hda_pcm_stream vt1812_pcm_analog_playback = {
- .substreams = 2,
- .channels_min = 2,
- .channels_max = 2,
- .nid = 0x8, /* NID to query formats and rates */
- .ops = {
- .open = via_playback_pcm_open,
- .prepare = via_playback_multi_pcm_prepare,
- .cleanup = via_playback_multi_pcm_cleanup,
- .close = via_pcm_open_close,
- },
-};
-
-static const struct hda_pcm_stream vt1812_pcm_analog_capture = {
- .substreams = 2,
- .channels_min = 2,
- .channels_max = 2,
- .nid = 0x10, /* NID to query formats and rates */
- .ops = {
- .open = via_pcm_open_close,
- .prepare = via_capture_pcm_prepare,
- .cleanup = via_capture_pcm_cleanup,
- .close = via_pcm_open_close,
- },
-};
-
-static const struct hda_pcm_stream vt1812_pcm_digital_playback = {
- .substreams = 1,
- .channels_min = 2,
- .channels_max = 2,
- /* NID is set in via_build_pcms */
- .ops = {
- .open = via_dig_playback_pcm_open,
- .close = via_dig_playback_pcm_close,
- .prepare = via_dig_playback_pcm_prepare,
- .cleanup = via_dig_playback_pcm_cleanup
- },
-};
-/* fill in the dac_nids table from the parsed pin configuration */
-static int vt1812_auto_fill_dac_nids(struct via_spec *spec,
- const struct auto_pin_cfg *cfg)
-{
- spec->multiout.num_dacs = 1;
- spec->multiout.dac_nids = spec->private_dac_nids;
- if (cfg->line_out_pins[0])
- spec->private_dac_nids[0] = 0x8;
- return 0;
-}
-
-
-/* add playback controls from the parsed DAC table */
-static int vt1812_auto_create_multi_out_ctls(struct via_spec *spec,
- const struct auto_pin_cfg *cfg)
-{
- int err;
-
- if (!cfg->line_out_pins[0])
- return -1;
-
- /* Line-Out: PortE */
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
- "Front Playback Volume",
- HDA_COMPOSE_AMP_VAL(0x8, 3, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
- err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE,
- "Front Playback Switch",
- HDA_COMPOSE_AMP_VAL(0x28, 3, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
-
- return 0;
-}
-
-static int vt1812_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
-{
- int err;
-
- if (!pin)
- return 0;
-
- spec->multiout.hp_nid = 0x9;
- spec->hp_independent_mode_index = 1;
-
-
- err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
- "Headphone Playback Volume",
- HDA_COMPOSE_AMP_VAL(
- spec->multiout.hp_nid, 3, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
-
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
- "Headphone Playback Switch",
- HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
- if (err < 0)
- return err;
-
- create_hp_imux(spec);
- return 0;
-}
-
-/* create playback/capture controls for input pins */
-static int vt1812_auto_create_analog_input_ctls(struct hda_codec *codec,
- const struct auto_pin_cfg *cfg)
-{
- struct via_spec *spec = codec->spec;
- struct hda_input_mux *imux = &spec->private_imux[0];
- static const hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0, 0, 0xff };
- int err;
-
- err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
- ARRAY_SIZE(pin_idxs));
- if (err < 0)
- return err;
-
- /* build volume/mute control of loopback */
- err = via_new_analog_input(spec, "Stereo Mixer", 0, 5, 0x21);
- if (err < 0)
- return err;
-
- /* for digital mic select */
- snd_hda_add_imux_item(imux, "Digital Mic", 6, NULL);
-
- return 0;
-}
-
-static int vt1812_parse_auto_config(struct hda_codec *codec)
-{
- struct via_spec *spec = codec->spec;
- int err;
-
-
- err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
- if (err < 0)
- return err;
- fill_dig_outs(codec);
- err = vt1812_auto_fill_dac_nids(spec, &spec->autocfg);
- if (err < 0)
- return err;
-
- if (!spec->autocfg.line_outs && !spec->autocfg.hp_outs)
- return 0; /* can't find valid BIOS pin config */
-
- err = vt1812_auto_create_multi_out_ctls(spec, &spec->autocfg);
- if (err < 0)
- return err;
- err = vt1812_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
- if (err < 0)
- return err;
- err = vt1812_auto_create_analog_input_ctls(codec, &spec->autocfg);
- if (err < 0)
- return err;
-
- spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-
- fill_dig_outs(codec);
-
- if (spec->kctls.list)
- spec->mixers[spec->num_mixers++] = spec->kctls.list;
-
- spec->input_mux = &spec->private_imux[0];
-
- if (spec->hp_mux)
- via_hp_build(codec);
-
- return 1;
-}
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static const struct hda_amp_list vt1812_loopbacks[] = {
- { 0x21, HDA_INPUT, 0 },
- { 0x21, HDA_INPUT, 1 },
- { 0x21, HDA_INPUT, 2 },
- { } /* end */
-};
-#endif
-
static void set_widgets_power_state_vt1812(struct hda_codec *codec)
{
struct via_spec *spec = codec->spec;
- int imux_is_smixer =
- snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
unsigned int parm;
unsigned int present;
- /* MUX10 (1eh) = stereo mixer */
- imux_is_smixer =
- snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
/* inputs */
/* PW 5/6/7 (29h/2ah/2bh) */
parm = AC_PWRST_D3;
@@ -6166,47 +3842,22 @@ static int patch_vt1812(struct hda_codec *codec)
if (spec == NULL)
return -ENOMEM;
+ spec->aa_mix_nid = 0x21;
+ override_mic_boost(codec, 0x2b, 0, 3, 40);
+ override_mic_boost(codec, 0x29, 0, 3, 40);
+ add_secret_dac_path(codec);
+
/* automatic parse from the BIOS config */
- err = vt1812_parse_auto_config(codec);
+ err = via_parse_auto_config(codec);
if (err < 0) {
via_free(codec);
return err;
- } else if (!err) {
- printk(KERN_INFO "hda_codec: Cannot set up configuration "
- "from BIOS. Using genenic mode...\n");
}
-
- spec->init_verbs[spec->num_iverbs++] = vt1812_volume_init_verbs;
- spec->init_verbs[spec->num_iverbs++] = vt1812_uniwill_init_verbs;
-
- spec->stream_name_analog = "VT1812 Analog";
- spec->stream_analog_playback = &vt1812_pcm_analog_playback;
- spec->stream_analog_capture = &vt1812_pcm_analog_capture;
-
- spec->stream_name_digital = "VT1812 Digital";
- spec->stream_digital_playback = &vt1812_pcm_digital_playback;
-
-
- if (!spec->adc_nids && spec->input_mux) {
- spec->adc_nids = vt1812_adc_nids;
- spec->num_adc_nids = ARRAY_SIZE(vt1812_adc_nids);
- get_mux_nids(codec);
- override_mic_boost(codec, 0x2b, 0, 3, 40);
- override_mic_boost(codec, 0x29, 0, 3, 40);
- spec->mixers[spec->num_mixers] = vt1812_capture_mixer;
- spec->num_mixers++;
- }
+ spec->init_verbs[spec->num_iverbs++] = vt1812_init_verbs;
codec->patch_ops = via_patch_ops;
- codec->patch_ops.init = via_auto_init;
- codec->patch_ops.unsol_event = via_unsol_event;
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
- spec->loopback.amplist = vt1812_loopbacks;
-#endif
-
spec->set_widgets_power_state = set_widgets_power_state_vt1812;
return 0;
}
@@ -6220,37 +3871,37 @@ static const struct hda_codec_preset snd_hda_preset_via[] = {
{ .id = 0x1106170a, .name = "VT1708", .patch = patch_vt1708},
{ .id = 0x1106170b, .name = "VT1708", .patch = patch_vt1708},
{ .id = 0x1106e710, .name = "VT1709 10-Ch",
- .patch = patch_vt1709_10ch},
+ .patch = patch_vt1709},
{ .id = 0x1106e711, .name = "VT1709 10-Ch",
- .patch = patch_vt1709_10ch},
+ .patch = patch_vt1709},
{ .id = 0x1106e712, .name = "VT1709 10-Ch",
- .patch = patch_vt1709_10ch},
+ .patch = patch_vt1709},
{ .id = 0x1106e713, .name = "VT1709 10-Ch",
- .patch = patch_vt1709_10ch},
+ .patch = patch_vt1709},
{ .id = 0x1106e714, .name = "VT1709 6-Ch",
- .patch = patch_vt1709_6ch},
+ .patch = patch_vt1709},
{ .id = 0x1106e715, .name = "VT1709 6-Ch",
- .patch = patch_vt1709_6ch},
+ .patch = patch_vt1709},
{ .id = 0x1106e716, .name = "VT1709 6-Ch",
- .patch = patch_vt1709_6ch},
+ .patch = patch_vt1709},
{ .id = 0x1106e717, .name = "VT1709 6-Ch",
- .patch = patch_vt1709_6ch},
+ .patch = patch_vt1709},
{ .id = 0x1106e720, .name = "VT1708B 8-Ch",
- .patch = patch_vt1708B_8ch},
+ .patch = patch_vt1708B},
{ .id = 0x1106e721, .name = "VT1708B 8-Ch",
- .patch = patch_vt1708B_8ch},
+ .patch = patch_vt1708B},
{ .id = 0x1106e722, .name = "VT1708B 8-Ch",
- .patch = patch_vt1708B_8ch},
+ .patch = patch_vt1708B},
{ .id = 0x1106e723, .name = "VT1708B 8-Ch",
- .patch = patch_vt1708B_8ch},
+ .patch = patch_vt1708B},
{ .id = 0x1106e724, .name = "VT1708B 4-Ch",
- .patch = patch_vt1708B_4ch},
+ .patch = patch_vt1708B},
{ .id = 0x1106e725, .name = "VT1708B 4-Ch",
- .patch = patch_vt1708B_4ch},
+ .patch = patch_vt1708B},
{ .id = 0x1106e726, .name = "VT1708B 4-Ch",
- .patch = patch_vt1708B_4ch},
+ .patch = patch_vt1708B},
{ .id = 0x1106e727, .name = "VT1708B 4-Ch",
- .patch = patch_vt1708B_4ch},
+ .patch = patch_vt1708B},
{ .id = 0x11060397, .name = "VT1708S",
.patch = patch_vt1708S},
{ .id = 0x11061397, .name = "VT1708S",
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index 2e799a9..55f48fb 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -32,7 +32,7 @@
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/slab.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/ac97_codec.h>
@@ -42,6 +42,12 @@
#include <asm/pgtable.h>
#include <asm/cacheflush.h>
+#ifdef CONFIG_KVM_GUEST
+#include <linux/kvm_para.h>
+#else
+#define kvm_para_available() (0)
+#endif
+
MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("Intel 82801AA,82901AB,i810,i820,i830,i840,i845,MX440; SiS 7012; Ali 5455");
MODULE_LICENSE("GPL");
@@ -77,6 +83,7 @@ static int buggy_semaphore;
static int buggy_irq = -1; /* auto-check */
static int xbox;
static int spdif_aclink = -1;
+static int inside_vm = -1;
module_param(index, int, 0444);
MODULE_PARM_DESC(index, "Index value for Intel i8x0 soundcard.");
@@ -94,6 +101,8 @@ module_param(xbox, bool, 0444);
MODULE_PARM_DESC(xbox, "Set to 1 for Xbox, if you have problems with the AC'97 codec detection.");
module_param(spdif_aclink, int, 0444);
MODULE_PARM_DESC(spdif_aclink, "S/PDIF over AC-link.");
+module_param(inside_vm, bool, 0444);
+MODULE_PARM_DESC(inside_vm, "KVM/Parallels optimization.");
/* just for backward compatibility */
static int enable;
@@ -400,6 +409,7 @@ struct intel8x0 {
unsigned buggy_irq: 1; /* workaround for buggy mobos */
unsigned xbox: 1; /* workaround for Xbox AC'97 detection */
unsigned buggy_semaphore: 1; /* workaround for buggy codec semaphore */
+ unsigned inside_vm: 1; /* enable VM optimization */
int spdif_idx; /* SPDIF BAR index; *_SPBAR or -1 if use PCMOUT */
unsigned int sdm_saved; /* SDM reg value */
@@ -1065,8 +1075,18 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *subs
udelay(10);
continue;
}
- if (civ == igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV) &&
- ptr1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb))
+ if (civ != igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV))
+ continue;
+
+ /* IO read operation is very expensive inside virtual machine
+ * as it is emulated. The probability that subsequent PICB read
+ * will return different result is high enough to loop till
+ * timeout here.
+ * Same CIV is strict enough condition to be sure that PICB
+ * is valid inside VM on emulated card. */
+ if (chip->inside_vm)
+ break;
+ if (ptr1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb))
break;
} while (timeout--);
ptr = ichdev->last_pos;
@@ -1884,6 +1904,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
},
{
.subvendor = 0x1028,
+ .subdevice = 0x0189,
+ .name = "Dell Inspiron 9300",
+ .type = AC97_TUNE_HP_MUTE_LED
+ },
+ {
+ .subvendor = 0x1028,
.subdevice = 0x0191,
.name = "Dell Inspiron 8600",
.type = AC97_TUNE_HP_ONLY
@@ -2653,7 +2679,7 @@ static int intel8x0_resume(struct pci_dev *pci)
pci_set_master(pci);
snd_intel8x0_chip_init(chip, 0);
if (request_irq(pci->irq, snd_intel8x0_interrupt,
- IRQF_SHARED, card->shortname, chip)) {
+ IRQF_SHARED, KBUILD_MODNAME, chip)) {
printk(KERN_ERR "intel8x0: unable to grab IRQ %d, "
"disabling device\n", pci->irq);
snd_card_disconnect(card);
@@ -2917,6 +2943,45 @@ static unsigned int sis_codec_bits[3] = {
ICH_PCR, ICH_SCR, ICH_SIS_TCR
};
+static int __devinit snd_intel8x0_inside_vm(struct pci_dev *pci)
+{
+ int result = inside_vm;
+ char *msg = NULL;
+
+ /* check module parameter first (override detection) */
+ if (result >= 0) {
+ msg = result ? "enable (forced) VM" : "disable (forced) VM";
+ goto fini;
+ }
+
+ /* detect KVM and Parallels virtual environments */
+ result = kvm_para_available();
+#ifdef X86_FEATURE_HYPERVISOR
+ result = result || boot_cpu_has(X86_FEATURE_HYPERVISOR);
+#endif
+ if (!result)
+ goto fini;
+
+ /* check for known (emulated) devices */
+ if (pci->subsystem_vendor == 0x1af4 &&
+ pci->subsystem_device == 0x1100) {
+ /* KVM emulated sound, PCI SSID: 1af4:1100 */
+ msg = "enable KVM";
+ } else if (pci->subsystem_vendor == 0x1ab8) {
+ /* Parallels VM emulated sound, PCI SSID: 1ab8:xxxx */
+ msg = "enable Parallels VM";
+ } else {
+ msg = "disable (unknown or VT-d) VM";
+ result = 0;
+ }
+
+fini:
+ if (msg != NULL)
+ printk(KERN_INFO "intel8x0: %s optimization\n", msg);
+
+ return result;
+}
+
static int __devinit snd_intel8x0_create(struct snd_card *card,
struct pci_dev *pci,
unsigned long device_type,
@@ -2984,6 +3049,8 @@ static int __devinit snd_intel8x0_create(struct snd_card *card,
if (xbox)
chip->xbox = 1;
+ chip->inside_vm = snd_intel8x0_inside_vm(pci);
+
if (pci->vendor == PCI_VENDOR_ID_INTEL &&
pci->device == PCI_DEVICE_ID_INTEL_440MX)
chip->fix_nocache = 1; /* enable workaround */
@@ -3112,7 +3179,7 @@ static int __devinit snd_intel8x0_create(struct snd_card *card,
/* request irq after initializaing int_sta_mask, etc */
if (request_irq(pci->irq, snd_intel8x0_interrupt,
- IRQF_SHARED, card->shortname, chip)) {
+ IRQF_SHARED, KBUILD_MODNAME, chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_intel8x0_free(chip);
return -EBUSY;
@@ -3272,7 +3339,7 @@ static void __devexit snd_intel8x0_remove(struct pci_dev *pci)
}
static struct pci_driver driver = {
- .name = "Intel ICH",
+ .name = KBUILD_MODNAME,
.id_table = snd_intel8x0_ids,
.probe = snd_intel8x0_probe,
.remove = __devexit_p(snd_intel8x0_remove),
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c
index f3353b4..0f7041e 100644
--- a/sound/pci/intel8x0m.c
+++ b/sound/pci/intel8x0m.c
@@ -29,7 +29,7 @@
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/slab.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/ac97_codec.h>
@@ -1047,7 +1047,7 @@ static int intel8x0m_resume(struct pci_dev *pci)
}
pci_set_master(pci);
if (request_irq(pci->irq, snd_intel8x0m_interrupt,
- IRQF_SHARED, card->shortname, chip)) {
+ IRQF_SHARED, KBUILD_MODNAME, chip)) {
printk(KERN_ERR "intel8x0m: unable to grab IRQ %d, "
"disabling device\n", pci->irq);
snd_card_disconnect(card);
@@ -1174,7 +1174,7 @@ static int __devinit snd_intel8x0m_create(struct snd_card *card,
port_inited:
if (request_irq(pci->irq, snd_intel8x0m_interrupt, IRQF_SHARED,
- card->shortname, chip)) {
+ KBUILD_MODNAME, chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_intel8x0m_free(chip);
return -EBUSY;
@@ -1325,7 +1325,7 @@ static void __devexit snd_intel8x0m_remove(struct pci_dev *pci)
}
static struct pci_driver driver = {
- .name = "Intel ICH Modem",
+ .name = KBUILD_MODNAME,
.id_table = snd_intel8x0m_ids,
.probe = snd_intel8x0m_probe,
.remove = __devexit_p(snd_intel8x0m_remove),
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
index 6d79570..841864b 100644
--- a/sound/pci/korg1212/korg1212.c
+++ b/sound/pci/korg1212/korg1212.c
@@ -25,7 +25,7 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/wait.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/firmware.h>
@@ -2241,7 +2241,7 @@ static int __devinit snd_korg1212_create(struct snd_card *card, struct pci_dev *
err = request_irq(pci->irq, snd_korg1212_interrupt,
IRQF_SHARED,
- "korg1212", korg1212);
+ KBUILD_MODNAME, korg1212);
if (err) {
snd_printk(KERN_ERR "korg1212: unable to grab IRQ %d\n", pci->irq);
@@ -2477,7 +2477,7 @@ static void __devexit snd_korg1212_remove(struct pci_dev *pci)
}
static struct pci_driver driver = {
- .name = "korg1212",
+ .name = KBUILD_MODNAME,
.id_table = snd_korg1212_ids,
.probe = snd_korg1212_probe,
.remove = __devexit_p(snd_korg1212_remove),
diff --git a/sound/pci/lola/lola.c b/sound/pci/lola/lola.c
index 2692e5a..924168e 100644
--- a/sound/pci/lola/lola.c
+++ b/sound/pci/lola/lola.c
@@ -20,7 +20,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -648,7 +648,7 @@ static int __devinit lola_create(struct snd_card *card, struct pci_dev *pci,
goto errout;
if (request_irq(pci->irq, lola_interrupt, IRQF_SHARED,
- DRVNAME, chip)) {
+ KBUILD_MODNAME, chip)) {
printk(KERN_ERR SFX "unable to grab IRQ %d\n", pci->irq);
err = -EBUSY;
goto errout;
@@ -771,7 +771,7 @@ MODULE_DEVICE_TABLE(pci, lola_ids);
/* pci_driver definition */
static struct pci_driver driver = {
- .name = DRVNAME,
+ .name = KBUILD_MODNAME,
.id_table = lola_ids,
.probe = lola_probe,
.remove = __devexit_p(lola_remove),
diff --git a/sound/pci/lola/lola.h b/sound/pci/lola/lola.h
index d5708e2..f0b1000 100644
--- a/sound/pci/lola/lola.h
+++ b/sound/pci/lola/lola.h
@@ -480,7 +480,7 @@ struct lola {
/* count values in the Vendor Specific Mixer Widget's Audio Widget Capabilities */
#define LOLA_MIXER_SRC_INPUT_PLAY_SEPARATION(res) ((res >> 2) & 0x1f)
-#define LOLA_MIXER_DEST_REC_OUTPUT_SEPATATION(res) ((res >> 7) & 0x1f)
+#define LOLA_MIXER_DEST_REC_OUTPUT_SEPARATION(res) ((res >> 7) & 0x1f)
int lola_codec_write(struct lola *chip, unsigned int nid, unsigned int verb,
unsigned int data, unsigned int extdata);
diff --git a/sound/pci/lola/lola_mixer.c b/sound/pci/lola/lola_mixer.c
index 5d518f1..6b8d648 100644
--- a/sound/pci/lola/lola_mixer.c
+++ b/sound/pci/lola/lola_mixer.c
@@ -144,40 +144,61 @@ int __devinit lola_init_mixer_widget(struct lola *chip, int nid)
chip->mixer.dest_stream_ins = chip->pcm[CAPT].num_streams;
chip->mixer.dest_phys_outs = chip->pin[PLAY].num_pins;
- /* mixer matrix can have unused areas between PhysIn and
+ /* mixer matrix may have unused areas between PhysIn and
* Play or Record and PhysOut zones
*/
chip->mixer.src_stream_out_ofs = chip->mixer.src_phys_ins +
LOLA_MIXER_SRC_INPUT_PLAY_SEPARATION(val);
chip->mixer.dest_phys_out_ofs = chip->mixer.dest_stream_ins +
- LOLA_MIXER_DEST_REC_OUTPUT_SEPATATION(val);
-
- /* example : MixerMatrix of LoLa881
- * 0-------8------16-------8------16
- * | | | | |
- * | INPUT | | INPUT | |
- * | -> |unused | -> |unused |
- * | RECORD| | OUTPUT| |
- * | | | | |
- * 8--------------------------------
- * | | | | |
- * | | | | |
- * |unused |unused |unused |unused |
- * | | | | |
- * | | | | |
- * 16-------------------------------
- * | | | | |
- * | PLAY | | PLAY | |
- * | -> |unused | -> |unused |
- * | RECORD| | OUTPUT| |
- * | | | | |
- * 8--------------------------------
- * | | | | |
- * | | | | |
- * |unused |unused |unused |unused |
- * | | | | |
- * | | | | |
- * 16-------------------------------
+ LOLA_MIXER_DEST_REC_OUTPUT_SEPARATION(val);
+
+ /* example : MixerMatrix of LoLa881 (LoLa16161 uses unused zones)
+ * +-+ 0-------8------16-------8------16
+ * | | | | | | |
+ * |s| | INPUT | | INPUT | |
+ * | |->| -> |unused | -> |unused |
+ * |r| |CAPTURE| | OUTPUT| |
+ * | | | MIX | | MIX | |
+ * |c| 8--------------------------------
+ * | | | | | | |
+ * | | | | | | |
+ * |g| |unused |unused |unused |unused |
+ * | | | | | | |
+ * |a| | | | | |
+ * | | 16-------------------------------
+ * |i| | | | | |
+ * | | | PLAYBK| | PLAYBK| |
+ * |n|->| -> |unused | -> |unused |
+ * | | |CAPTURE| | OUTPUT| |
+ * | | | MIX | | MIX | |
+ * |a| 8--------------------------------
+ * |r| | | | | |
+ * |r| | | | | |
+ * |a| |unused |unused |unused |unused |
+ * |y| | | | | |
+ * | | | | | | |
+ * +++ 16--|---------------|------------
+ * +---V---------------V-----------+
+ * | dest_mix_gain_enable array |
+ * +-------------------------------+
+ */
+ /* example : MixerMatrix of LoLa280
+ * +-+ 0-------8-2
+ * | | | | |
+ * |s| | INPUT | | INPUT
+ * |r|->| -> | | ->
+ * |c| |CAPTURE| | <- OUTPUT
+ * | | | MIX | | MIX
+ * |g| 8----------
+ * |a| | | |
+ * |i| | PLAYBK| | PLAYBACK
+ * |n|->| -> | | ->
+ * | | |CAPTURE| | <- OUTPUT
+ * |a| | MIX | | MIX
+ * |r| 8---|----|-
+ * |r| +---V----V-------------------+
+ * |a| | dest_mix_gain_enable array |
+ * |y| +----------------------------+
*/
if (chip->mixer.src_stream_out_ofs > MAX_AUDIO_INOUT_COUNT ||
chip->mixer.dest_phys_out_ofs > MAX_STREAM_IN_COUNT) {
@@ -192,6 +213,9 @@ int __devinit lola_init_mixer_widget(struct lola *chip, int nid)
(((1U << chip->mixer.dest_phys_outs) - 1)
<< chip->mixer.dest_phys_out_ofs);
+ snd_printdd("Mixer src_mask=%x, dest_mask=%x\n",
+ chip->mixer.src_mask, chip->mixer.dest_mask);
+
return 0;
}
@@ -202,12 +226,19 @@ static int lola_mixer_set_src_gain(struct lola *chip, unsigned int id,
if (!(chip->mixer.src_mask & (1 << id)))
return -EINVAL;
- writew(gain, &chip->mixer.array->src_gain[id]);
oldval = val = readl(&chip->mixer.array->src_gain_enable);
if (on)
val |= (1 << id);
else
val &= ~(1 << id);
+ /* test if values unchanged */
+ if ((val == oldval) &&
+ (gain == readw(&chip->mixer.array->src_gain[id])))
+ return 0;
+
+ snd_printdd("lola_mixer_set_src_gain (id=%d, gain=%d) enable=%x\n",
+ id, gain, val);
+ writew(gain, &chip->mixer.array->src_gain[id]);
writel(val, &chip->mixer.array->src_gain_enable);
lola_codec_flush(chip);
/* inform micro-controller about the new source gain */
@@ -269,6 +300,7 @@ static int lola_mixer_set_mapping_gain(struct lola *chip,
src, dest);
}
+#if 0 /* not used */
static int lola_mixer_set_dest_gains(struct lola *chip, unsigned int id,
unsigned int mask, unsigned short *gains)
{
@@ -289,6 +321,7 @@ static int lola_mixer_set_dest_gains(struct lola *chip, unsigned int id,
return lola_codec_write(chip, chip->mixer.nid,
LOLA_VERB_SET_DESTINATION_GAIN, id, 0);
}
+#endif /* not used */
/*
*/
@@ -376,6 +409,8 @@ static int set_analog_volume(struct lola *chip, int dir,
return 0;
if (external_call)
lola_codec_flush(chip);
+ snd_printdd("set_analog_volume (dir=%d idx=%d, volume=%d)\n",
+ dir, idx, val);
err = lola_codec_write(chip, pin->nid,
LOLA_VERB_SET_AMP_GAIN_MUTE, val, 0);
if (err < 0)
@@ -427,23 +462,40 @@ static int init_mixer_values(struct lola *chip)
{
int i;
- /* all src on */
+ /* all sample rate converters on */
lola_set_src_config(chip, (1 << chip->pin[CAPT].num_pins) - 1, false);
- /* clear all matrix */
+ /* clear all mixer matrix settings */
memset_io(chip->mixer.array, 0, sizeof(*chip->mixer.array));
- /* set src gain to 0dB */
+ /* inform firmware about all updated matrix columns - capture part */
+ for (i = 0; i < chip->mixer.dest_stream_ins; i++)
+ lola_codec_write(chip, chip->mixer.nid,
+ LOLA_VERB_SET_DESTINATION_GAIN,
+ i, 0);
+ /* inform firmware about all updated matrix columns - output part */
+ for (i = 0; i < chip->mixer.dest_phys_outs; i++)
+ lola_codec_write(chip, chip->mixer.nid,
+ LOLA_VERB_SET_DESTINATION_GAIN,
+ chip->mixer.dest_phys_out_ofs + i, 0);
+
+ /* set all digital input source (master) gains to 0dB */
for (i = 0; i < chip->mixer.src_phys_ins; i++)
lola_mixer_set_src_gain(chip, i, 336, true); /* 0dB */
+
+ /* set all digital playback source (master) gains to 0dB */
for (i = 0; i < chip->mixer.src_stream_outs; i++)
lola_mixer_set_src_gain(chip,
i + chip->mixer.src_stream_out_ofs,
336, true); /* 0dB */
- /* set 1:1 dest gain */
+ /* set gain value 0dB diagonally in matrix - part INPUT -> CAPTURE */
for (i = 0; i < chip->mixer.dest_stream_ins; i++) {
int src = i % chip->mixer.src_phys_ins;
lola_mixer_set_mapping_gain(chip, src, i, 336, true);
}
+ /* set gain value 0dB diagonally in matrix , part PLAYBACK -> OUTPUT
+ * (LoLa280 : playback channel 0,2,4,6 linked to output channel 0)
+ * (LoLa280 : playback channel 1,3,5,7 linked to output channel 1)
+ */
for (i = 0; i < chip->mixer.src_stream_outs; i++) {
int src = chip->mixer.src_stream_out_ofs + i;
int dst = chip->mixer.dest_phys_out_ofs +
@@ -693,6 +745,7 @@ static int __devinit create_src_gain_mixer(struct lola *chip,
snd_ctl_new1(&lola_src_gain_mixer, chip));
}
+#if 0 /* not used */
/*
* destination gain (matrix-like) mixer
*/
@@ -781,6 +834,7 @@ static int __devinit create_dest_gain_mixer(struct lola *chip,
return snd_ctl_add(chip->card,
snd_ctl_new1(&lola_dest_gain_mixer, chip));
}
+#endif /* not used */
/*
*/
@@ -798,14 +852,16 @@ int __devinit lola_create_mixer(struct lola *chip)
if (err < 0)
return err;
err = create_src_gain_mixer(chip, chip->mixer.src_phys_ins, 0,
- "Line Source Gain Volume");
+ "Digital Capture Volume");
if (err < 0)
return err;
err = create_src_gain_mixer(chip, chip->mixer.src_stream_outs,
chip->mixer.src_stream_out_ofs,
- "Stream Source Gain Volume");
+ "Digital Playback Volume");
if (err < 0)
return err;
+#if 0
+/* FIXME: buggy mixer matrix handling */
err = create_dest_gain_mixer(chip,
chip->mixer.src_phys_ins, 0,
chip->mixer.dest_stream_ins, 0,
@@ -834,6 +890,6 @@ int __devinit lola_create_mixer(struct lola *chip)
"Stream Playback Volume");
if (err < 0)
return err;
-
+#endif /* FIXME */
return init_mixer_values(chip);
}
diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c
index 1bd7a54..04ae84b 100644
--- a/sound/pci/lx6464es/lx6464es.c
+++ b/sound/pci/lx6464es/lx6464es.c
@@ -762,7 +762,6 @@ static int lx_set_granularity(struct lx6464es *chip, u32 gran)
static int __devinit lx_init_dsp(struct lx6464es *chip)
{
int err;
- u8 mac_address[6];
int i;
snd_printdd("->lx_init_dsp\n");
@@ -787,11 +786,11 @@ static int __devinit lx_init_dsp(struct lx6464es *chip)
/** \todo the mac address should be ready by not, but it isn't,
* so we wait for it */
for (i = 0; i != 1000; ++i) {
- err = lx_dsp_get_mac(chip, mac_address);
+ err = lx_dsp_get_mac(chip);
if (err)
return err;
- if (mac_address[0] || mac_address[1] || mac_address[2] ||
- mac_address[3] || mac_address[4] || mac_address[5])
+ if (chip->mac_address[0] || chip->mac_address[1] || chip->mac_address[2] ||
+ chip->mac_address[3] || chip->mac_address[4] || chip->mac_address[5])
goto mac_ready;
msleep(1);
}
@@ -800,8 +799,8 @@ static int __devinit lx_init_dsp(struct lx6464es *chip)
mac_ready:
snd_printd(LXP "mac address ready read after: %dms\n", i);
snd_printk(LXP "mac address: %02X.%02X.%02X.%02X.%02X.%02X\n",
- mac_address[0], mac_address[1], mac_address[2],
- mac_address[3], mac_address[4], mac_address[5]);
+ chip->mac_address[0], chip->mac_address[1], chip->mac_address[2],
+ chip->mac_address[3], chip->mac_address[4], chip->mac_address[5]);
err = lx_init_get_version_features(chip);
if (err)
@@ -1031,7 +1030,7 @@ static int __devinit snd_lx6464es_create(struct snd_card *card,
chip->port_dsp_bar = pci_ioremap_bar(pci, 2);
err = request_irq(pci->irq, lx_interrupt, IRQF_SHARED,
- card_name, chip);
+ KBUILD_MODNAME, chip);
if (err) {
snd_printk(KERN_ERR LXP "unable to grab IRQ %d\n", pci->irq);
goto request_irq_failed;
@@ -1108,8 +1107,14 @@ static int __devinit snd_lx6464es_probe(struct pci_dev *pci,
goto out_free;
}
- strcpy(card->driver, "lx6464es");
- strcpy(card->shortname, "Digigram LX6464ES");
+ strcpy(card->driver, "LX6464ES");
+ sprintf(card->id, "LX6464ES_%02X%02X%02X",
+ chip->mac_address[3], chip->mac_address[4], chip->mac_address[5]);
+
+ sprintf(card->shortname, "LX6464ES %02X.%02X.%02X.%02X.%02X.%02X",
+ chip->mac_address[0], chip->mac_address[1], chip->mac_address[2],
+ chip->mac_address[3], chip->mac_address[4], chip->mac_address[5]);
+
sprintf(card->longname, "%s at 0x%lx, 0x%p, irq %i",
card->shortname, chip->port_plx,
chip->port_dsp_bar, chip->irq);
@@ -1137,7 +1142,7 @@ static void __devexit snd_lx6464es_remove(struct pci_dev *pci)
static struct pci_driver driver = {
- .name = "Digigram LX6464ES",
+ .name = KBUILD_MODNAME,
.id_table = snd_lx6464es_ids,
.probe = snd_lx6464es_probe,
.remove = __devexit_p(snd_lx6464es_remove),
diff --git a/sound/pci/lx6464es/lx6464es.h b/sound/pci/lx6464es/lx6464es.h
index aea621e..6792eda 100644
--- a/sound/pci/lx6464es/lx6464es.h
+++ b/sound/pci/lx6464es/lx6464es.h
@@ -26,7 +26,7 @@
#define LX6464ES_H
#include <linux/spinlock.h>
-#include <asm/atomic.h>
+#include <linux/atomic.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -69,6 +69,8 @@ struct lx6464es {
struct pci_dev *pci;
int irq;
+ u8 mac_address[6];
+
spinlock_t lock; /* interrupt spinlock */
struct mutex setup_mutex; /* mutex used in hw_params, open
* and close */
diff --git a/sound/pci/lx6464es/lx_core.c b/sound/pci/lx6464es/lx_core.c
index 713f798..8c3e7fc 100644
--- a/sound/pci/lx6464es/lx_core.c
+++ b/sound/pci/lx6464es/lx_core.c
@@ -78,7 +78,8 @@ unsigned long lx_dsp_reg_read(struct lx6464es *chip, int port)
return ioread32(address);
}
-void lx_dsp_reg_readbuf(struct lx6464es *chip, int port, u32 *data, u32 len)
+static void lx_dsp_reg_readbuf(struct lx6464es *chip, int port, u32 *data,
+ u32 len)
{
u32 __iomem *address = lx_dsp_register(chip, port);
int i;
@@ -95,8 +96,8 @@ void lx_dsp_reg_write(struct lx6464es *chip, int port, unsigned data)
iowrite32(data, address);
}
-void lx_dsp_reg_writebuf(struct lx6464es *chip, int port, const u32 *data,
- u32 len)
+static void lx_dsp_reg_writebuf(struct lx6464es *chip, int port,
+ const u32 *data, u32 len)
{
u32 __iomem *address = lx_dsp_register(chip, port);
int i;
@@ -432,7 +433,7 @@ int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq)
return ret;
}
-int lx_dsp_get_mac(struct lx6464es *chip, u8 *mac_address)
+int lx_dsp_get_mac(struct lx6464es *chip)
{
u32 macmsb, maclsb;
@@ -440,12 +441,12 @@ int lx_dsp_get_mac(struct lx6464es *chip, u8 *mac_address)
maclsb = lx_dsp_reg_read(chip, eReg_ADMACESLSB) & 0x00FFFFFF;
/* todo: endianess handling */
- mac_address[5] = ((u8 *)(&maclsb))[0];
- mac_address[4] = ((u8 *)(&maclsb))[1];
- mac_address[3] = ((u8 *)(&maclsb))[2];
- mac_address[2] = ((u8 *)(&macmsb))[0];
- mac_address[1] = ((u8 *)(&macmsb))[1];
- mac_address[0] = ((u8 *)(&macmsb))[2];
+ chip->mac_address[5] = ((u8 *)(&maclsb))[0];
+ chip->mac_address[4] = ((u8 *)(&maclsb))[1];
+ chip->mac_address[3] = ((u8 *)(&maclsb))[2];
+ chip->mac_address[2] = ((u8 *)(&macmsb))[0];
+ chip->mac_address[1] = ((u8 *)(&macmsb))[1];
+ chip->mac_address[0] = ((u8 *)(&macmsb))[2];
return 0;
}
diff --git a/sound/pci/lx6464es/lx_core.h b/sound/pci/lx6464es/lx_core.h
index 6bd9cbb..4d7ff79 100644
--- a/sound/pci/lx6464es/lx_core.h
+++ b/sound/pci/lx6464es/lx_core.h
@@ -72,10 +72,7 @@ enum {
};
unsigned long lx_dsp_reg_read(struct lx6464es *chip, int port);
-void lx_dsp_reg_readbuf(struct lx6464es *chip, int port, u32 *data, u32 len);
void lx_dsp_reg_write(struct lx6464es *chip, int port, unsigned data);
-void lx_dsp_reg_writebuf(struct lx6464es *chip, int port, const u32 *data,
- u32 len);
/* plx register access */
enum {
@@ -116,7 +113,7 @@ int __devinit lx_dsp_get_version(struct lx6464es *chip, u32 *rdsp_version);
int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq);
int lx_dsp_set_granularity(struct lx6464es *chip, u32 gran);
int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data);
-int lx_dsp_get_mac(struct lx6464es *chip, u8 *mac_address);
+int lx_dsp_get_mac(struct lx6464es *chip);
/* low-level pipe handling */
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index 3c40d72..863c8bd 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -39,7 +39,7 @@
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/input.h>
#include <sound/core.h>
@@ -850,11 +850,10 @@ struct snd_m3 {
struct input_dev *input_dev;
char phys[64]; /* physical device path */
#else
- spinlock_t ac97_lock;
struct snd_kcontrol *master_switch;
struct snd_kcontrol *master_volume;
- struct tasklet_struct hwvol_tq;
#endif
+ struct work_struct hwvol_work;
unsigned int in_suspend;
@@ -1609,13 +1608,10 @@ static void snd_m3_update_ptr(struct snd_m3 *chip, struct m3_dma *s)
(without wrap around) in response to volume button presses and then
generating an interrupt. The pair of counters is stored in bits 1-3 and 5-7
of a byte wide register. The meaning of bits 0 and 4 is unknown. */
-static void snd_m3_update_hw_volume(unsigned long private_data)
+static void snd_m3_update_hw_volume(struct work_struct *work)
{
- struct snd_m3 *chip = (struct snd_m3 *) private_data;
+ struct snd_m3 *chip = container_of(work, struct snd_m3, hwvol_work);
int x, val;
-#ifndef CONFIG_SND_MAESTRO3_INPUT
- unsigned long flags;
-#endif
/* Figure out which volume control button was pushed,
based on differences from the default register
@@ -1645,21 +1641,13 @@ static void snd_m3_update_hw_volume(unsigned long private_data)
if (!chip->master_switch || !chip->master_volume)
return;
- /* FIXME: we can't call snd_ac97_* functions since here is in tasklet. */
- spin_lock_irqsave(&chip->ac97_lock, flags);
-
- val = chip->ac97->regs[AC97_MASTER_VOL];
+ val = snd_ac97_read(chip->ac97, AC97_MASTER);
switch (x) {
case 0x88:
/* The counters have not changed, yet we've received a HV
interrupt. According to tests run by various people this
happens when pressing the mute button. */
val ^= 0x8000;
- chip->ac97->regs[AC97_MASTER_VOL] = val;
- outw(val, chip->iobase + CODEC_DATA);
- outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND);
- snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
- &chip->master_switch->id);
break;
case 0xaa:
/* counters increased by 1 -> volume up */
@@ -1667,11 +1655,6 @@ static void snd_m3_update_hw_volume(unsigned long private_data)
val--;
if ((val & 0x7f00) > 0)
val -= 0x0100;
- chip->ac97->regs[AC97_MASTER_VOL] = val;
- outw(val, chip->iobase + CODEC_DATA);
- outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND);
- snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
- &chip->master_volume->id);
break;
case 0x66:
/* counters decreased by 1 -> volume down */
@@ -1679,14 +1662,11 @@ static void snd_m3_update_hw_volume(unsigned long private_data)
val++;
if ((val & 0x7f00) < 0x1f00)
val += 0x0100;
- chip->ac97->regs[AC97_MASTER_VOL] = val;
- outw(val, chip->iobase + CODEC_DATA);
- outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND);
- snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
- &chip->master_volume->id);
break;
}
- spin_unlock_irqrestore(&chip->ac97_lock, flags);
+ if (snd_ac97_update(chip->ac97, AC97_MASTER, val))
+ snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &chip->master_switch->id);
#else
if (!chip->input_dev)
return;
@@ -1730,11 +1710,7 @@ static irqreturn_t snd_m3_interrupt(int irq, void *dev_id)
return IRQ_NONE;
if (status & HV_INT_PENDING)
-#ifdef CONFIG_SND_MAESTRO3_INPUT
- snd_m3_update_hw_volume((unsigned long)chip);
-#else
- tasklet_schedule(&chip->hwvol_tq);
-#endif
+ schedule_work(&chip->hwvol_work);
/*
* ack an assp int if its running
@@ -2000,24 +1976,14 @@ static unsigned short
snd_m3_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
{
struct snd_m3 *chip = ac97->private_data;
-#ifndef CONFIG_SND_MAESTRO3_INPUT
- unsigned long flags;
-#endif
unsigned short data = 0xffff;
if (snd_m3_ac97_wait(chip))
goto fail;
-#ifndef CONFIG_SND_MAESTRO3_INPUT
- spin_lock_irqsave(&chip->ac97_lock, flags);
-#endif
snd_m3_outb(chip, 0x80 | (reg & 0x7f), CODEC_COMMAND);
if (snd_m3_ac97_wait(chip))
- goto fail_unlock;
+ goto fail;
data = snd_m3_inw(chip, CODEC_DATA);
-fail_unlock:
-#ifndef CONFIG_SND_MAESTRO3_INPUT
- spin_unlock_irqrestore(&chip->ac97_lock, flags);
-#endif
fail:
return data;
}
@@ -2026,20 +1992,11 @@ static void
snd_m3_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val)
{
struct snd_m3 *chip = ac97->private_data;
-#ifndef CONFIG_SND_MAESTRO3_INPUT
- unsigned long flags;
-#endif
if (snd_m3_ac97_wait(chip))
return;
-#ifndef CONFIG_SND_MAESTRO3_INPUT
- spin_lock_irqsave(&chip->ac97_lock, flags);
-#endif
snd_m3_outw(chip, val, CODEC_DATA);
snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND);
-#ifndef CONFIG_SND_MAESTRO3_INPUT
- spin_unlock_irqrestore(&chip->ac97_lock, flags);
-#endif
}
@@ -2458,6 +2415,7 @@ static int snd_m3_free(struct snd_m3 *chip)
struct m3_dma *s;
int i;
+ cancel_work_sync(&chip->hwvol_work);
#ifdef CONFIG_SND_MAESTRO3_INPUT
if (chip->input_dev)
input_unregister_device(chip->input_dev);
@@ -2511,6 +2469,7 @@ static int m3_suspend(struct pci_dev *pci, pm_message_t state)
return 0;
chip->in_suspend = 1;
+ cancel_work_sync(&chip->hwvol_work);
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
snd_pcm_suspend_all(chip->pcm);
snd_ac97_suspend(chip->ac97);
@@ -2667,9 +2626,6 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
}
spin_lock_init(&chip->reg_lock);
-#ifndef CONFIG_SND_MAESTRO3_INPUT
- spin_lock_init(&chip->ac97_lock);
-#endif
switch (pci->device) {
case PCI_DEVICE_ID_ESS_ALLEGRO:
@@ -2683,6 +2639,7 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
chip->card = card;
chip->pci = pci;
chip->irq = -1;
+ INIT_WORK(&chip->hwvol_work, snd_m3_update_hw_volume);
chip->external_amp = enable_amp;
if (amp_gpio >= 0 && amp_gpio <= 0x0f)
@@ -2752,12 +2709,8 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
snd_m3_hv_init(chip);
-#ifndef CONFIG_SND_MAESTRO3_INPUT
- tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip);
-#endif
-
if (request_irq(pci->irq, snd_m3_interrupt, IRQF_SHARED,
- card->driver, chip)) {
+ KBUILD_MODNAME, chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_m3_free(chip);
return -ENOMEM;
@@ -2867,8 +2820,8 @@ snd_m3_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
/* TODO enable MIDI IRQ and I/O */
err = snd_mpu401_uart_new(chip->card, 0, MPU401_HW_MPU401,
chip->iobase + MPU401_DATA_PORT,
- MPU401_INFO_INTEGRATED,
- chip->irq, 0, &chip->rmidi);
+ MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK,
+ -1, &chip->rmidi);
if (err < 0)
printk(KERN_WARNING "maestro3: no MIDI support.\n");
#endif
@@ -2885,7 +2838,7 @@ static void __devexit snd_m3_remove(struct pci_dev *pci)
}
static struct pci_driver driver = {
- .name = "Maestro3",
+ .name = KBUILD_MODNAME,
.id_table = snd_m3_ids,
.probe = snd_m3_probe,
.remove = __devexit_p(snd_m3_remove),
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c
index 6c3fd4d..a0bd1d9 100644
--- a/sound/pci/mixart/mixart.c
+++ b/sound/pci/mixart/mixart.c
@@ -25,7 +25,7 @@
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
@@ -1268,7 +1268,7 @@ static int __devinit snd_mixart_probe(struct pci_dev *pci,
}
if (request_irq(pci->irq, snd_mixart_interrupt, IRQF_SHARED,
- CARD_NAME, mgr)) {
+ KBUILD_MODNAME, mgr)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_mixart_free(mgr);
return -EBUSY;
@@ -1381,7 +1381,7 @@ static void __devexit snd_mixart_remove(struct pci_dev *pci)
}
static struct pci_driver driver = {
- .name = "Digigram miXart",
+ .name = KBUILD_MODNAME,
.id_table = snd_mixart_ids,
.probe = snd_mixart_probe,
.remove = __devexit_p(snd_mixart_remove),
diff --git a/sound/pci/mixart/mixart_hwdep.c b/sound/pci/mixart/mixart_hwdep.c
index bf2696a..bfbdc91 100644
--- a/sound/pci/mixart/mixart_hwdep.c
+++ b/sound/pci/mixart/mixart_hwdep.c
@@ -25,6 +25,7 @@
#include <linux/firmware.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
+#include <linux/module.h>
#include <asm/io.h>
#include <sound/core.h>
#include "mixart.h"
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c
index 5a60492..c6c45d9 100644
--- a/sound/pci/nm256/nm256.c
+++ b/sound/pci/nm256/nm256.c
@@ -30,7 +30,7 @@
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/slab.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <linux/mutex.h>
#include <sound/core.h>
@@ -465,7 +465,7 @@ static int snd_nm256_acquire_irq(struct nm256 *chip)
mutex_lock(&chip->irq_mutex);
if (chip->irq < 0) {
if (request_irq(chip->pci->irq, chip->interrupt, IRQF_SHARED,
- chip->card->driver, chip)) {
+ KBUILD_MODNAME, chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->pci->irq);
mutex_unlock(&chip->irq_mutex);
return -EBUSY;
@@ -1743,7 +1743,7 @@ static void __devexit snd_nm256_remove(struct pci_dev *pci)
static struct pci_driver driver = {
- .name = "NeoMagic 256",
+ .name = KBUILD_MODNAME,
.id_table = snd_nm256_ids,
.probe = snd_nm256_probe,
.remove = __devexit_p(snd_nm256_remove),
diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c
index 1026820..62075a5 100644
--- a/sound/pci/rme32.c
+++ b/sound/pci/rme32.c
@@ -74,7 +74,7 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/info.h>
@@ -1355,7 +1355,7 @@ static int __devinit snd_rme32_create(struct rme32 * rme32)
}
if (request_irq(pci->irq, snd_rme32_interrupt, IRQF_SHARED,
- "RME32", rme32)) {
+ KBUILD_MODNAME, rme32)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
return -EBUSY;
}
@@ -1985,7 +1985,7 @@ static void __devexit snd_rme32_remove(struct pci_dev *pci)
}
static struct pci_driver driver = {
- .name = "RME Digi32",
+ .name = KBUILD_MODNAME,
.id_table = snd_rme32_ids,
.probe = snd_rme32_probe,
.remove = __devexit_p(snd_rme32_remove),
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c
index 9ff247f..4585c97 100644
--- a/sound/pci/rme96.c
+++ b/sound/pci/rme96.c
@@ -27,7 +27,7 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/info.h>
@@ -1561,7 +1561,7 @@ snd_rme96_create(struct rme96 *rme96)
}
if (request_irq(pci->irq, snd_rme96_interrupt, IRQF_SHARED,
- "RME96", rme96)) {
+ KBUILD_MODNAME, rme96)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
return -EBUSY;
}
@@ -2396,7 +2396,7 @@ static void __devexit snd_rme96_remove(struct pci_dev *pci)
}
static struct pci_driver driver = {
- .name = "RME Digi96",
+ .name = KBUILD_MODNAME,
.id_table = snd_rme96_ids,
.probe = snd_rme96_probe,
.remove = __devexit_p(snd_rme96_remove),
diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c
index 5fe840b..28dfafb 100644
--- a/sound/pci/sis7019.c
+++ b/sound/pci/sis7019.c
@@ -25,7 +25,7 @@
#include <linux/pci.h>
#include <linux/time.h>
#include <linux/slab.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <sound/core.h>
@@ -1265,8 +1265,8 @@ static int sis_resume(struct pci_dev *pci)
goto error;
}
- if (request_irq(pci->irq, sis_interrupt, IRQF_DISABLED|IRQF_SHARED,
- card->shortname, sis)) {
+ if (request_irq(pci->irq, sis_interrupt, IRQF_SHARED,
+ KBUILD_MODNAME, sis)) {
printk(KERN_ERR "sis7019: unable to regain IRQ %d\n", pci->irq);
goto error;
}
@@ -1371,8 +1371,8 @@ static int __devinit sis_chip_create(struct snd_card *card,
if (rc)
goto error_out_cleanup;
- if (request_irq(pci->irq, sis_interrupt, IRQF_DISABLED|IRQF_SHARED,
- card->shortname, sis)) {
+ if (request_irq(pci->irq, sis_interrupt, IRQF_SHARED,
+ KBUILD_MODNAME, sis)) {
printk(KERN_ERR "unable to allocate irq %d\n", sis->irq);
goto error_out_cleanup;
}
@@ -1478,7 +1478,7 @@ static void __devexit snd_sis7019_remove(struct pci_dev *pci)
}
static struct pci_driver sis7019_driver = {
- .name = "SiS7019",
+ .name = KBUILD_MODNAME,
.id_table = snd_sis7019_ids,
.probe = snd_sis7019_probe,
.remove = __devexit_p(snd_sis7019_remove),
diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c
index 337b9fa..31b6ad3 100644
--- a/sound/pci/sonicvibes.c
+++ b/sound/pci/sonicvibes.c
@@ -28,7 +28,7 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/gameport.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <linux/dma-mapping.h>
#include <sound/core.h>
@@ -1294,7 +1294,7 @@ static int __devinit snd_sonicvibes_create(struct snd_card *card,
sonic->game_port = pci_resource_start(pci, 4);
if (request_irq(pci->irq, snd_sonicvibes_interrupt, IRQF_SHARED,
- "S3 SonicVibes", sonic)) {
+ KBUILD_MODNAME, sonic)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_sonicvibes_free(sonic);
return -EBUSY;
@@ -1493,9 +1493,10 @@ static int __devinit snd_sonic_probe(struct pci_dev *pci,
return err;
}
if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_SONICVIBES,
- sonic->midi_port, MPU401_INFO_INTEGRATED,
- sonic->irq, 0,
- &midi_uart)) < 0) {
+ sonic->midi_port,
+ MPU401_INFO_INTEGRATED |
+ MPU401_INFO_IRQ_HOOK,
+ -1, &midi_uart)) < 0) {
snd_card_free(card);
return err;
}
@@ -1530,7 +1531,7 @@ static void __devexit snd_sonic_remove(struct pci_dev *pci)
}
static struct pci_driver driver = {
- .name = "S3 SonicVibes",
+ .name = KBUILD_MODNAME,
.id_table = snd_sonic_ids,
.probe = snd_sonic_probe,
.remove = __devexit_p(snd_sonic_remove),
diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c
index 6d05818..deb04b9 100644
--- a/sound/pci/trident/trident.c
+++ b/sound/pci/trident/trident.c
@@ -24,7 +24,7 @@
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/time.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/trident.h>
#include <sound/initval.h>
@@ -148,8 +148,9 @@ static int __devinit snd_trident_probe(struct pci_dev *pci,
if (trident->device != TRIDENT_DEVICE_ID_SI7018 &&
(err = snd_mpu401_uart_new(card, 0, MPU401_HW_TRID4DWAVE,
trident->midi_port,
- MPU401_INFO_INTEGRATED,
- trident->irq, 0, &trident->rmidi)) < 0) {
+ MPU401_INFO_INTEGRATED |
+ MPU401_INFO_IRQ_HOOK,
+ -1, &trident->rmidi)) < 0) {
snd_card_free(card);
return err;
}
@@ -172,7 +173,7 @@ static void __devexit snd_trident_remove(struct pci_dev *pci)
}
static struct pci_driver driver = {
- .name = "Trident4DWaveAudio",
+ .name = KBUILD_MODNAME,
.id_table = snd_trident_ids,
.probe = snd_trident_probe,
.remove = __devexit_p(snd_trident_remove),
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
index 2870a4f..61d3c0e 100644
--- a/sound/pci/trident/trident_main.c
+++ b/sound/pci/trident/trident_main.c
@@ -35,6 +35,7 @@
#include <linux/vmalloc.h>
#include <linux/gameport.h>
#include <linux/dma-mapping.h>
+#include <linux/export.h>
#include <sound/core.h>
#include <sound/info.h>
@@ -3598,7 +3599,7 @@ int __devinit snd_trident_create(struct snd_card *card,
trident->port = pci_resource_start(pci, 0);
if (request_irq(pci->irq, snd_trident_interrupt, IRQF_SHARED,
- "Trident Audio", trident)) {
+ KBUILD_MODNAME, trident)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_trident_free(trident);
return -EBUSY;
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index 8c5f8b5..ae98d56 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -53,7 +53,7 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/gameport.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -1175,6 +1175,7 @@ static int snd_via82xx_pcm_open(struct via82xx *chip, struct viadev *viadev,
struct snd_pcm_runtime *runtime = substream->runtime;
int err;
struct via_rate_lock *ratep;
+ bool use_src = false;
runtime->hw = snd_via82xx_hw;
@@ -1196,6 +1197,7 @@ static int snd_via82xx_pcm_open(struct via82xx *chip, struct viadev *viadev,
SNDRV_PCM_RATE_8000_48000);
runtime->hw.rate_min = 8000;
runtime->hw.rate_max = 48000;
+ use_src = true;
} else if (! ratep->rate) {
int idx = viadev->direction ? AC97_RATES_ADC : AC97_RATES_FRONT_DAC;
runtime->hw.rates = chip->ac97->rates[idx];
@@ -1212,6 +1214,12 @@ static int snd_via82xx_pcm_open(struct via82xx *chip, struct viadev *viadev,
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
return err;
+ if (use_src) {
+ err = snd_pcm_hw_rule_noresample(runtime, 48000);
+ if (err < 0)
+ return err;
+ }
+
runtime->private_data = viadev;
viadev->substream = substream;
@@ -2068,8 +2076,9 @@ static int __devinit snd_via686_init_misc(struct via82xx *chip)
pci_write_config_byte(chip->pci, VIA_PNP_CONTROL, legacy_cfg);
if (chip->mpu_res) {
if (snd_mpu401_uart_new(chip->card, 0, MPU401_HW_VIA686A,
- mpu_port, MPU401_INFO_INTEGRATED,
- chip->irq, 0, &chip->rmidi) < 0) {
+ mpu_port, MPU401_INFO_INTEGRATED |
+ MPU401_INFO_IRQ_HOOK, -1,
+ &chip->rmidi) < 0) {
printk(KERN_WARNING "unable to initialize MPU-401"
" at 0x%lx, skipping\n", mpu_port);
legacy &= ~VIA_FUNC_ENABLE_MIDI;
@@ -2377,7 +2386,7 @@ static int __devinit snd_via82xx_create(struct snd_card *card,
chip_type == TYPE_VIA8233 ?
snd_via8233_interrupt : snd_via686_interrupt,
IRQF_SHARED,
- card->driver, chip)) {
+ KBUILD_MODNAME, chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_via82xx_free(chip);
return -EBUSY;
@@ -2611,7 +2620,7 @@ static void __devexit snd_via82xx_remove(struct pci_dev *pci)
}
static struct pci_driver driver = {
- .name = "VIA 82xx Audio",
+ .name = KBUILD_MODNAME,
.id_table = snd_via82xx_ids,
.probe = snd_via82xx_probe,
.remove = __devexit_p(snd_via82xx_remove),
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c
index f7e8bbbe..80a9c2b 100644
--- a/sound/pci/via82xx_modem.c
+++ b/sound/pci/via82xx_modem.c
@@ -37,7 +37,7 @@
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/slab.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -1129,7 +1129,7 @@ static int __devinit snd_via82xx_create(struct snd_card *card,
}
chip->port = pci_resource_start(pci, 0);
if (request_irq(pci->irq, snd_via82xx_interrupt, IRQF_SHARED,
- card->driver, chip)) {
+ KBUILD_MODNAME, chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_via82xx_free(chip);
return -EBUSY;
@@ -1224,7 +1224,7 @@ static void __devexit snd_via82xx_remove(struct pci_dev *pci)
}
static struct pci_driver driver = {
- .name = "VIA 82xx Modem",
+ .name = KBUILD_MODNAME,
.id_table = snd_via82xx_modem_ids,
.probe = snd_via82xx_probe,
.remove = __devexit_p(snd_via82xx_remove),
diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c
index 99a9a81..6765822 100644
--- a/sound/pci/vx222/vx222.c
+++ b/sound/pci/vx222/vx222.c
@@ -22,7 +22,7 @@
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/slab.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/tlv.h>
@@ -169,7 +169,7 @@ static int __devinit snd_vx222_create(struct snd_card *card, struct pci_dev *pci
vx->port[i] = pci_resource_start(pci, i + 1);
if (request_irq(pci->irq, snd_vx_irq_handler, IRQF_SHARED,
- CARD_NAME, chip)) {
+ KBUILD_MODNAME, chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_vx222_free(chip);
return -EBUSY;
@@ -290,7 +290,7 @@ static int snd_vx222_resume(struct pci_dev *pci)
#endif
static struct pci_driver driver = {
- .name = "Digigram VX222",
+ .name = KBUILD_MODNAME,
.id_table = snd_vx222_ids,
.probe = snd_vx222_probe,
.remove = __devexit_p(snd_vx222_remove),
diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c
index 80c6821..e97ddca 100644
--- a/sound/pci/ymfpci/ymfpci.c
+++ b/sound/pci/ymfpci/ymfpci.c
@@ -22,7 +22,7 @@
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/time.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/ymfpci.h>
#include <sound/mpu401.h>
@@ -305,8 +305,9 @@ static int __devinit snd_card_ymfpci_probe(struct pci_dev *pci,
if (chip->mpu_res) {
if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_YMFPCI,
mpu_port[dev],
- MPU401_INFO_INTEGRATED,
- pci->irq, 0, &chip->rawmidi)) < 0) {
+ MPU401_INFO_INTEGRATED |
+ MPU401_INFO_IRQ_HOOK,
+ -1, &chip->rawmidi)) < 0) {
printk(KERN_WARNING "ymfpci: cannot initialize MPU401 at 0x%lx, skipping...\n", mpu_port[dev]);
legacy_ctrl &= ~YMFPCI_LEGACY_MIEN; /* disable MPU401 irq */
pci_write_config_word(pci, PCIR_DSXG_LEGACY, legacy_ctrl);
@@ -345,7 +346,7 @@ static void __devexit snd_card_ymfpci_remove(struct pci_dev *pci)
}
static struct pci_driver driver = {
- .name = "Yamaha DS-1 PCI",
+ .name = KBUILD_MODNAME,
.id_table = snd_ymfpci_ids,
.probe = snd_card_ymfpci_probe,
.remove = __devexit_p(snd_card_ymfpci_remove),
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
index c94c051..03ee4e3 100644
--- a/sound/pci/ymfpci/ymfpci_main.c
+++ b/sound/pci/ymfpci/ymfpci_main.c
@@ -27,6 +27,7 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/mutex.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/control.h>
@@ -897,6 +898,18 @@ static int snd_ymfpci_playback_open_1(struct snd_pcm_substream *substream)
struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_ymfpci_pcm *ypcm;
+ int err;
+
+ runtime->hw = snd_ymfpci_playback;
+ /* FIXME? True value is 256/48 = 5.33333 ms */
+ err = snd_pcm_hw_constraint_minmax(runtime,
+ SNDRV_PCM_HW_PARAM_PERIOD_TIME,
+ 5334, UINT_MAX);
+ if (err < 0)
+ return err;
+ err = snd_pcm_hw_rule_noresample(runtime, 48000);
+ if (err < 0)
+ return err;
ypcm = kzalloc(sizeof(*ypcm), GFP_KERNEL);
if (ypcm == NULL)
@@ -904,11 +917,8 @@ static int snd_ymfpci_playback_open_1(struct snd_pcm_substream *substream)
ypcm->chip = chip;
ypcm->type = PLAYBACK_VOICE;
ypcm->substream = substream;
- runtime->hw = snd_ymfpci_playback;
runtime->private_data = ypcm;
runtime->private_free = snd_ymfpci_pcm_free_substream;
- /* FIXME? True value is 256/48 = 5.33333 ms */
- snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 5333, UINT_MAX);
return 0;
}
@@ -1013,6 +1023,18 @@ static int snd_ymfpci_capture_open(struct snd_pcm_substream *substream,
struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_ymfpci_pcm *ypcm;
+ int err;
+
+ runtime->hw = snd_ymfpci_capture;
+ /* FIXME? True value is 256/48 = 5.33333 ms */
+ err = snd_pcm_hw_constraint_minmax(runtime,
+ SNDRV_PCM_HW_PARAM_PERIOD_TIME,
+ 5334, UINT_MAX);
+ if (err < 0)
+ return err;
+ err = snd_pcm_hw_rule_noresample(runtime, 48000);
+ if (err < 0)
+ return err;
ypcm = kzalloc(sizeof(*ypcm), GFP_KERNEL);
if (ypcm == NULL)
@@ -1022,9 +1044,6 @@ static int snd_ymfpci_capture_open(struct snd_pcm_substream *substream,
ypcm->substream = substream;
ypcm->capture_bank_number = capture_bank_number;
chip->capture_substream[capture_bank_number] = substream;
- runtime->hw = snd_ymfpci_capture;
- /* FIXME? True value is 256/48 = 5.33333 ms */
- snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 5333, UINT_MAX);
runtime->private_data = ypcm;
runtime->private_free = snd_ymfpci_pcm_free_substream;
snd_ymfpci_hw_start(chip);
@@ -1615,7 +1634,7 @@ YMFPCI_DOUBLE("ADC Playback Volume", 0, YDSXGR_PRIADCOUTVOL),
YMFPCI_DOUBLE("ADC Capture Volume", 0, YDSXGR_PRIADCLOOPVOL),
YMFPCI_DOUBLE("ADC Playback Volume", 1, YDSXGR_SECADCOUTVOL),
YMFPCI_DOUBLE("ADC Capture Volume", 1, YDSXGR_SECADCLOOPVOL),
-YMFPCI_DOUBLE("FM Legacy Volume", 0, YDSXGR_LEGACYOUTVOL),
+YMFPCI_DOUBLE("FM Legacy Playback Volume", 0, YDSXGR_LEGACYOUTVOL),
YMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("AC97 ", PLAYBACK,VOLUME), 0, YDSXGR_ZVOUTVOL),
YMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("", CAPTURE,VOLUME), 0, YDSXGR_ZVLOOPVOL),
YMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("AC97 ",PLAYBACK,VOLUME), 1, YDSXGR_SPDIFOUTVOL),
@@ -2380,7 +2399,7 @@ int __devinit snd_ymfpci_create(struct snd_card *card,
return -EBUSY;
}
if (request_irq(pci->irq, snd_ymfpci_interrupt, IRQF_SHARED,
- "YMFPCI", chip)) {
+ KBUILD_MODNAME, chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
snd_ymfpci_free(chip);
return -EBUSY;
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c
index 66488a7..6af41d2 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c
@@ -20,7 +20,7 @@
#include <sound/core.h>
#include <linux/slab.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <pcmcia/ciscode.h>
#include <pcmcia/cisreg.h>
#include "pdaudiocf.h"
diff --git a/sound/sh/aica.c b/sound/sh/aica.c
index 94c6ea7..1120ca4 100644
--- a/sound/sh/aica.c
+++ b/sound/sh/aica.c
@@ -29,7 +29,7 @@
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/wait.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/firmware.h>
#include <linux/timer.h>
diff --git a/sound/sh/sh_dac_audio.c b/sound/sh/sh_dac_audio.c
index 68e0dee..56bcb46 100644
--- a/sound/sh/sh_dac_audio.c
+++ b/sound/sh/sh_dac_audio.c
@@ -27,6 +27,7 @@
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/pcm.h>
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 8224db5..1381db8 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -7,6 +7,8 @@ menuconfig SND_SOC
select SND_PCM
select AC97_BUS if SND_SOC_AC97_BUS
select SND_JACK if INPUT=y || INPUT=SND
+ select REGMAP_I2C if I2C
+ select REGMAP_SPI if SPI_MASTER
---help---
If you want ASoC support, you should say Y here and also to the
@@ -51,6 +53,7 @@ source "sound/soc/nuc900/Kconfig"
source "sound/soc/omap/Kconfig"
source "sound/soc/kirkwood/Kconfig"
source "sound/soc/mid-x86/Kconfig"
+source "sound/soc/mxs/Kconfig"
source "sound/soc/pxa/Kconfig"
source "sound/soc/samsung/Kconfig"
source "sound/soc/s6000/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 1ed61c5..fc4136e 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_SND_SOC) += fsl/
obj-$(CONFIG_SND_SOC) += imx/
obj-$(CONFIG_SND_SOC) += jz4740/
obj-$(CONFIG_SND_SOC) += mid-x86/
+obj-$(CONFIG_SND_SOC) += mxs/
obj-$(CONFIG_SND_SOC) += nuc900/
obj-$(CONFIG_SND_SOC) += omap/
obj-$(CONFIG_SND_SOC) += kirkwood/
diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig
index ae40359..9f6bc55 100644
--- a/sound/soc/blackfin/Kconfig
+++ b/sound/soc/blackfin/Kconfig
@@ -10,13 +10,49 @@ config SND_BF5XX_I2S
config SND_BF5XX_SOC_SSM2602
tristate "SoC SSM2602 Audio support for BF52x ezkit"
- depends on SND_BF5XX_I2S
+ depends on SND_BF5XX_I2S && (SPI_MASTER || I2C)
select SND_BF5XX_SOC_I2S
select SND_SOC_SSM2602
- select I2C
help
Say Y if you want to add support for SoC audio on BF527-EZKIT.
+config SND_SOC_BFIN_EVAL_ADAU1701
+ tristate "Support for the EVAL-ADAU1701MINIZ board on Blackfin eval boards"
+ depends on SND_BF5XX_I2S
+ select SND_BF5XX_SOC_I2S
+ select SND_SOC_ADAU1701
+ select I2C
+ help
+ Say Y if you want to add support for the Analog Devices EVAL-ADAU1701MINIZ
+ board connected to one of the Blackfin evaluation boards like the
+ BF5XX-STAMP or BF5XX-EZKIT.
+
+config SND_SOC_BFIN_EVAL_ADAU1373
+ tristate "Support for the EVAL-ADAU1373 board on Blackfin eval boards"
+ depends on SND_BF5XX_I2S && I2C
+ select SND_BF5XX_SOC_I2S
+ select SND_SOC_ADAU1373
+ help
+ Say Y if you want to add support for the Analog Devices EVAL-ADAU1373
+ board connected to one of the Blackfin evaluation boards like the
+ BF5XX-STAMP or BF5XX-EZKIT.
+
+ Note: This driver assumes that first ADAU1373 DAI is connected to the
+ first SPORT port on the BF5XX board.
+
+config SND_SOC_BFIN_EVAL_ADAV80X
+ tristate "Support for the EVAL-ADAV80X boards on Blackfin eval boards"
+ depends on SND_BF5XX_I2S && (SPI_MASTER || I2C)
+ select SND_BF5XX_SOC_I2S
+ select SND_SOC_ADAV80X
+ help
+ Say Y if you want to add support for the Analog Devices EVAL-ADAV801 or
+ EVAL-ADAV803 board connected to one of the Blackfin evaluation boards
+ like the BF5XX-STAMP or BF5XX-EZKIT.
+
+ Note: This driver assumes that the ADAV80X digital record and playback
+ interfaces are connected to the first SPORT port on the BF5XX board.
+
config SND_BF5XX_SOC_AD73311
tristate "SoC AD73311 Audio support for Blackfin"
depends on SND_BF5XX_I2S
diff --git a/sound/soc/blackfin/Makefile b/sound/soc/blackfin/Makefile
index 49af3f3..1bf86cc 100644
--- a/sound/soc/blackfin/Makefile
+++ b/sound/soc/blackfin/Makefile
@@ -21,9 +21,15 @@ snd-ad1980-objs := bf5xx-ad1980.o
snd-ssm2602-objs := bf5xx-ssm2602.o
snd-ad73311-objs := bf5xx-ad73311.o
snd-ad193x-objs := bf5xx-ad193x.o
+snd-soc-bfin-eval-adau1373-objs := bfin-eval-adau1373.o
+snd-soc-bfin-eval-adau1701-objs := bfin-eval-adau1701.o
+snd-soc-bfin-eval-adav80x-objs := bfin-eval-adav80x.o
obj-$(CONFIG_SND_BF5XX_SOC_AD1836) += snd-ad1836.o
obj-$(CONFIG_SND_BF5XX_SOC_AD1980) += snd-ad1980.o
obj-$(CONFIG_SND_BF5XX_SOC_SSM2602) += snd-ssm2602.o
obj-$(CONFIG_SND_BF5XX_SOC_AD73311) += snd-ad73311.o
obj-$(CONFIG_SND_BF5XX_SOC_AD193X) += snd-ad193x.o
+obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAU1373) += snd-soc-bfin-eval-adau1373.o
+obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAU1701) += snd-soc-bfin-eval-adau1701.o
+obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAV80X) += snd-soc-bfin-eval-adav80x.o
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c
index 98b44b3..56815c1 100644
--- a/sound/soc/blackfin/bf5xx-ac97-pcm.c
+++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c
@@ -418,9 +418,11 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
-int bf5xx_pcm_ac97_new(struct snd_card *card, struct snd_soc_dai *dai,
- struct snd_pcm *pcm)
+static int bf5xx_pcm_ac97_new(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_card *card = rtd->card->snd_card;
+ struct snd_soc_dai *dai = rtd->cpu_dai;
+ struct snd_pcm *pcm = rtd->pcm;
int ret = 0;
pr_debug("%s enter\n", __func__);
diff --git a/sound/soc/blackfin/bf5xx-ad193x.c b/sound/soc/blackfin/bf5xx-ad193x.c
index 2f0f836..5956584 100644
--- a/sound/soc/blackfin/bf5xx-ad193x.c
+++ b/sound/soc/blackfin/bf5xx-ad193x.c
@@ -56,7 +56,7 @@ static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream,
switch (params_rate(params)) {
case 48000:
- clk = 12288000;
+ clk = 24576000;
break;
}
diff --git a/sound/soc/blackfin/bf5xx-ad73311.c b/sound/soc/blackfin/bf5xx-ad73311.c
index 732a247..b94eb7e 100644
--- a/sound/soc/blackfin/bf5xx-ad73311.c
+++ b/sound/soc/blackfin/bf5xx-ad73311.c
@@ -128,7 +128,7 @@ static int snd_ad73311_configure(void)
return 0;
}
-static int bf5xx_probe(struct platform_device *pdev)
+static int bf5xx_probe(struct snd_soc_card *card)
{
int err;
if (gpio_request(GPIO_SE, "AD73311_SE")) {
diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c
index f1fd95b..7565e15 100644
--- a/sound/soc/blackfin/bf5xx-i2s-pcm.c
+++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c
@@ -168,7 +168,7 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
- ret = snd_pcm_hw_constraint_integer(runtime, \
+ ret = snd_pcm_hw_constraint_integer(runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
if (ret < 0)
goto out;
@@ -257,9 +257,11 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
-int bf5xx_pcm_i2s_new(struct snd_card *card, struct snd_soc_dai *dai,
- struct snd_pcm *pcm)
+static int bf5xx_pcm_i2s_new(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_card *card = rtd->card->snd_card;
+ struct snd_soc_dai *dai = rtd->cpu_dai;
+ struct snd_pcm *pcm = rtd->pcm;
int ret = 0;
pr_debug("%s enter\n", __func__);
@@ -304,8 +306,8 @@ static int __devexit bfin_i2s_soc_platform_remove(struct platform_device *pdev)
static struct platform_driver bfin_i2s_pcm_driver = {
.driver = {
- .name = "bfin-i2s-pcm-audio",
- .owner = THIS_MODULE,
+ .name = "bfin-i2s-pcm-audio",
+ .owner = THIS_MODULE,
},
.probe = bfin_i2s_soc_platform_probe,
diff --git a/sound/soc/blackfin/bf5xx-sport.c b/sound/soc/blackfin/bf5xx-sport.c
index a2d4034..2fd9f2a 100644
--- a/sound/soc/blackfin/bf5xx-sport.c
+++ b/sound/soc/blackfin/bf5xx-sport.c
@@ -33,6 +33,7 @@
#include <linux/dma-mapping.h>
#include <linux/gpio.h>
#include <linux/bug.h>
+#include <linux/module.h>
#include <asm/portmux.h>
#include <asm/dma.h>
#include <asm/blackfin.h>
diff --git a/sound/soc/blackfin/bf5xx-tdm-pcm.c b/sound/soc/blackfin/bf5xx-tdm-pcm.c
index 07cfc7a..c95cc03 100644
--- a/sound/soc/blackfin/bf5xx-tdm-pcm.c
+++ b/sound/soc/blackfin/bf5xx-tdm-pcm.c
@@ -283,9 +283,11 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
-static int bf5xx_pcm_tdm_new(struct snd_card *card, struct snd_soc_dai *dai,
- struct snd_pcm *pcm)
+static int bf5xx_pcm_tdm_new(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_card *card = rtd->card->snd_card;
+ struct snd_soc_dai *dai = rtd->cpu_dai;
+ struct snd_pcm *pcm = rtd->pcm;
int ret = 0;
if (!card->dev->dma_mask)
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index 99054cf..fe83d0d 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -9,6 +9,9 @@ config SND_OMAP_SOC_MCBSP
config SND_OMAP_SOC_MCPDM
tristate
+config SND_OMAP_SOC_HDMI
+ tristate
+
config SND_OMAP_SOC_N810
tristate "SoC Audio support for Nokia N810"
depends on SND_OMAP_SOC && MACH_NOKIA_N810 && I2C
@@ -100,6 +103,14 @@ config SND_OMAP_SOC_SDP4430
Say Y if you want to add support for SoC audio on Texas Instruments
SDP4430.
+config SND_OMAP_SOC_OMAP4_HDMI
+ tristate "SoC Audio support for Texas Instruments OMAP4 HDMI"
+ depends on SND_OMAP_SOC && OMAP4_DSS_HDMI && OMAP2_DSS && ARCH_OMAP4
+ select SND_OMAP_SOC_HDMI
+ help
+ Say Y if you want to add support for SoC HDMI audio on Texas Instruments
+ OMAP4 chips
+
config SND_OMAP_SOC_OMAP3_PANDORA
tristate "SoC Audio support for OMAP3 Pandora"
depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3_PANDORA
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile
index 6c2c87e..052fd75 100644
--- a/sound/soc/omap/Makefile
+++ b/sound/soc/omap/Makefile
@@ -1,11 +1,13 @@
# OMAP Platform Support
snd-soc-omap-objs := omap-pcm.o
snd-soc-omap-mcbsp-objs := omap-mcbsp.o
-snd-soc-omap-mcpdm-objs := omap-mcpdm.o mcpdm.o
+snd-soc-omap-mcpdm-objs := omap-mcpdm.o
+snd-soc-omap-hdmi-objs := omap-hdmi.o
obj-$(CONFIG_SND_OMAP_SOC) += snd-soc-omap.o
obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o
obj-$(CONFIG_SND_OMAP_SOC_MCPDM) += snd-soc-omap-mcpdm.o
+obj-$(CONFIG_SND_OMAP_SOC_HDMI) += snd-soc-omap-hdmi.o
# OMAP Machine Support
snd-soc-n810-objs := n810.o
@@ -21,6 +23,7 @@ snd-soc-omap3pandora-objs := omap3pandora.o
snd-soc-omap3beagle-objs := omap3beagle.o
snd-soc-zoom2-objs := zoom2.o
snd-soc-igep0020-objs := igep0020.o
+snd-soc-omap4-hdmi-objs := omap4-hdmi-card.o
obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o
@@ -36,3 +39,4 @@ obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o
obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o
obj-$(CONFIG_SND_OMAP_SOC_ZOOM2) += snd-soc-zoom2.o
obj-$(CONFIG_SND_OMAP_SOC_IGEP0020) += snd-soc-igep0020.o
+obj-$(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) += snd-soc-omap4-hdmi.o
diff --git a/sound/soc/omap/am3517evm.c b/sound/soc/omap/am3517evm.c
index 73dde4a..c1cd4a0 100644
--- a/sound/soc/omap/am3517evm.c
+++ b/sound/soc/omap/am3517evm.c
@@ -19,6 +19,7 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
@@ -43,26 +44,6 @@ static int am3517evm_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
- /* Set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_DSP_B |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0) {
- printk(KERN_ERR "can't set codec DAI configuration\n");
- return ret;
- }
-
- /* Set cpu DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai,
- SND_SOC_DAIFMT_DSP_B |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0) {
- printk(KERN_ERR "can't set cpu DAI configuration\n");
- return ret;
- }
-
/* Set the codec system clock for DAC and ADC */
ret = snd_soc_dai_set_sysclk(codec_dai, 0,
CODEC_CLOCK, SND_SOC_CLOCK_IN);
@@ -110,28 +91,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"MICIN", NULL, "Mic In"},
};
-static int am3517evm_aic23_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_codec *codec = rtd->codec;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
-
- /* Add am3517-evm specific widgets */
- snd_soc_dapm_new_controls(dapm, tlv320aic23_dapm_widgets,
- ARRAY_SIZE(tlv320aic23_dapm_widgets));
-
- /* Set up davinci-evm specific audio path audio_map */
- snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
- /* always connected */
- snd_soc_dapm_enable_pin(dapm, "Line Out");
- snd_soc_dapm_enable_pin(dapm, "Line In");
- snd_soc_dapm_enable_pin(dapm, "Mic In");
-
- snd_soc_dapm_sync(dapm);
-
- return 0;
-}
-
/* Digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link am3517evm_dai = {
.name = "TLV320AIC23",
@@ -140,7 +99,8 @@ static struct snd_soc_dai_link am3517evm_dai = {
.codec_dai_name = "tlv320aic23-hifi",
.platform_name = "omap-pcm-audio",
.codec_name = "tlv320aic23-codec.2-001a",
- .init = am3517evm_aic23_init,
+ .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM,
.ops = &am3517evm_ops,
};
@@ -149,6 +109,11 @@ static struct snd_soc_card snd_soc_am3517evm = {
.name = "am3517evm",
.dai_link = &am3517evm_dai,
.num_links = 1,
+
+ .dapm_widgets = tlv320aic23_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
};
static struct platform_device *am3517evm_snd_device;
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c
index 462cbcb..ccb8a6a 100644
--- a/sound/soc/omap/ams-delta.c
+++ b/sound/soc/omap/ams-delta.c
@@ -25,6 +25,7 @@
#include <linux/gpio.h>
#include <linux/spinlock.h>
#include <linux/tty.h>
+#include <linux/module.h>
#include <sound/soc.h>
#include <sound/jack.h>
@@ -330,7 +331,7 @@ static int cx81801_hangup(struct tty_struct *tty)
return 0;
}
-/* Line discipline .recieve_buf() */
+/* Line discipline .receive_buf() */
static void cx81801_receive(struct tty_struct *tty,
const unsigned char *cp, char *fp, int count)
{
@@ -427,7 +428,8 @@ static struct snd_soc_ops ams_delta_ops = {
/* Board specific codec bias level control */
static int ams_delta_set_bias_level(struct snd_soc_card *card,
- enum snd_soc_bias_level level)
+ struct snd_soc_dapm_context *dapm,
+ enum snd_soc_bias_level level)
{
struct snd_soc_codec *codec = card->rtd->codec;
@@ -513,7 +515,7 @@ static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
}
/* Set codec bias level */
- ams_delta_set_bias_level(card, SND_SOC_BIAS_STANDBY);
+ ams_delta_set_bias_level(card, dapm, SND_SOC_BIAS_STANDBY);
/* Add hook switch - can be used to control the codec from userspace
* even if line discipline fails */
@@ -568,7 +570,6 @@ static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_disable_pin(dapm, "Speaker");
snd_soc_dapm_disable_pin(dapm, "AGCIN");
snd_soc_dapm_disable_pin(dapm, "AGCOUT");
- snd_soc_dapm_sync(dapm);
/* Add virtual switch */
ret = snd_soc_add_controls(codec, ams_delta_audio_controls,
@@ -648,7 +649,9 @@ static void __exit ams_delta_module_exit(void)
ams_delta_hook_switch_gpios);
/* Keep modem power on */
- ams_delta_set_bias_level(&ams_delta_audio_card, SND_SOC_BIAS_STANDBY);
+ ams_delta_set_bias_level(&ams_delta_audio_card,
+ &ams_delta_audio_card.rtd[0].codec->dapm,
+ SND_SOC_BIAS_STANDBY);
platform_device_unregister(cx20442_platform_device);
platform_device_unregister(ams_delta_audio_platform_device);
diff --git a/sound/soc/omap/igep0020.c b/sound/soc/omap/igep0020.c
index 0ae3470..591fbf8 100644
--- a/sound/soc/omap/igep0020.c
+++ b/sound/soc/omap/igep0020.c
@@ -21,6 +21,7 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
@@ -38,29 +39,8 @@ static int igep2_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
- /* Set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0) {
- printk(KERN_ERR "can't set codec DAI configuration\n");
- return ret;
- }
-
- /* Set cpu DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0) {
- printk(KERN_ERR "can't set cpu DAI configuration\n");
- return ret;
- }
-
/* Set the codec system clock for DAC and ADC */
ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
SND_SOC_CLOCK_IN);
@@ -84,6 +64,8 @@ static struct snd_soc_dai_link igep2_dai = {
.codec_dai_name = "twl4030-hifi",
.platform_name = "omap-pcm-audio",
.codec_name = "twl4030-codec",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM,
.ops = &igep2_ops,
};
diff --git a/sound/soc/omap/mcpdm.c b/sound/soc/omap/mcpdm.c
deleted file mode 100644
index 928f037..0000000
--- a/sound/soc/omap/mcpdm.c
+++ /dev/null
@@ -1,470 +0,0 @@
-/*
- * mcpdm.c -- McPDM interface driver
- *
- * Author: Jorge Eduardo Candelaria <x0107209@ti.com>
- * Copyright (C) 2009 - Texas Instruments, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program 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 program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/wait.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-
-#include "mcpdm.h"
-
-static struct omap_mcpdm *mcpdm;
-
-static inline void omap_mcpdm_write(u16 reg, u32 val)
-{
- __raw_writel(val, mcpdm->io_base + reg);
-}
-
-static inline int omap_mcpdm_read(u16 reg)
-{
- return __raw_readl(mcpdm->io_base + reg);
-}
-
-static void omap_mcpdm_reg_dump(void)
-{
- dev_dbg(mcpdm->dev, "***********************\n");
- dev_dbg(mcpdm->dev, "IRQSTATUS_RAW: 0x%04x\n",
- omap_mcpdm_read(MCPDM_IRQSTATUS_RAW));
- dev_dbg(mcpdm->dev, "IRQSTATUS: 0x%04x\n",
- omap_mcpdm_read(MCPDM_IRQSTATUS));
- dev_dbg(mcpdm->dev, "IRQENABLE_SET: 0x%04x\n",
- omap_mcpdm_read(MCPDM_IRQENABLE_SET));
- dev_dbg(mcpdm->dev, "IRQENABLE_CLR: 0x%04x\n",
- omap_mcpdm_read(MCPDM_IRQENABLE_CLR));
- dev_dbg(mcpdm->dev, "IRQWAKE_EN: 0x%04x\n",
- omap_mcpdm_read(MCPDM_IRQWAKE_EN));
- dev_dbg(mcpdm->dev, "DMAENABLE_SET: 0x%04x\n",
- omap_mcpdm_read(MCPDM_DMAENABLE_SET));
- dev_dbg(mcpdm->dev, "DMAENABLE_CLR: 0x%04x\n",
- omap_mcpdm_read(MCPDM_DMAENABLE_CLR));
- dev_dbg(mcpdm->dev, "DMAWAKEEN: 0x%04x\n",
- omap_mcpdm_read(MCPDM_DMAWAKEEN));
- dev_dbg(mcpdm->dev, "CTRL: 0x%04x\n",
- omap_mcpdm_read(MCPDM_CTRL));
- dev_dbg(mcpdm->dev, "DN_DATA: 0x%04x\n",
- omap_mcpdm_read(MCPDM_DN_DATA));
- dev_dbg(mcpdm->dev, "UP_DATA: 0x%04x\n",
- omap_mcpdm_read(MCPDM_UP_DATA));
- dev_dbg(mcpdm->dev, "FIFO_CTRL_DN: 0x%04x\n",
- omap_mcpdm_read(MCPDM_FIFO_CTRL_DN));
- dev_dbg(mcpdm->dev, "FIFO_CTRL_UP: 0x%04x\n",
- omap_mcpdm_read(MCPDM_FIFO_CTRL_UP));
- dev_dbg(mcpdm->dev, "DN_OFFSET: 0x%04x\n",
- omap_mcpdm_read(MCPDM_DN_OFFSET));
- dev_dbg(mcpdm->dev, "***********************\n");
-}
-
-/*
- * Takes the McPDM module in and out of reset state.
- * Uplink and downlink can be reset individually.
- */
-static void omap_mcpdm_reset_capture(int reset)
-{
- int ctrl = omap_mcpdm_read(MCPDM_CTRL);
-
- if (reset)
- ctrl |= SW_UP_RST;
- else
- ctrl &= ~SW_UP_RST;
-
- omap_mcpdm_write(MCPDM_CTRL, ctrl);
-}
-
-static void omap_mcpdm_reset_playback(int reset)
-{
- int ctrl = omap_mcpdm_read(MCPDM_CTRL);
-
- if (reset)
- ctrl |= SW_DN_RST;
- else
- ctrl &= ~SW_DN_RST;
-
- omap_mcpdm_write(MCPDM_CTRL, ctrl);
-}
-
-/*
- * Enables the transfer through the PDM interface to/from the Phoenix
- * codec by enabling the corresponding UP or DN channels.
- */
-void omap_mcpdm_start(int stream)
-{
- int ctrl = omap_mcpdm_read(MCPDM_CTRL);
-
- if (stream)
- ctrl |= mcpdm->up_channels;
- else
- ctrl |= mcpdm->dn_channels;
-
- omap_mcpdm_write(MCPDM_CTRL, ctrl);
-}
-
-/*
- * Disables the transfer through the PDM interface to/from the Phoenix
- * codec by disabling the corresponding UP or DN channels.
- */
-void omap_mcpdm_stop(int stream)
-{
- int ctrl = omap_mcpdm_read(MCPDM_CTRL);
-
- if (stream)
- ctrl &= ~mcpdm->up_channels;
- else
- ctrl &= ~mcpdm->dn_channels;
-
- omap_mcpdm_write(MCPDM_CTRL, ctrl);
-}
-
-/*
- * Configures McPDM uplink for audio recording.
- * This function should be called before omap_mcpdm_start.
- */
-int omap_mcpdm_capture_open(struct omap_mcpdm_link *uplink)
-{
- int irq_mask = 0;
- int ctrl;
-
- if (!uplink)
- return -EINVAL;
-
- mcpdm->uplink = uplink;
-
- /* Enable irq request generation */
- irq_mask |= uplink->irq_mask & MCPDM_UPLINK_IRQ_MASK;
- omap_mcpdm_write(MCPDM_IRQENABLE_SET, irq_mask);
-
- /* Configure uplink threshold */
- if (uplink->threshold > UP_THRES_MAX)
- uplink->threshold = UP_THRES_MAX;
-
- omap_mcpdm_write(MCPDM_FIFO_CTRL_UP, uplink->threshold);
-
- /* Configure DMA controller */
- omap_mcpdm_write(MCPDM_DMAENABLE_SET, DMA_UP_ENABLE);
-
- /* Set pdm out format */
- ctrl = omap_mcpdm_read(MCPDM_CTRL);
- ctrl &= ~PDMOUTFORMAT;
- ctrl |= uplink->format & PDMOUTFORMAT;
-
- /* Uplink channels */
- mcpdm->up_channels = uplink->channels & (PDM_UP_MASK | PDM_STATUS_MASK);
-
- omap_mcpdm_write(MCPDM_CTRL, ctrl);
-
- return 0;
-}
-
-/*
- * Configures McPDM downlink for audio playback.
- * This function should be called before omap_mcpdm_start.
- */
-int omap_mcpdm_playback_open(struct omap_mcpdm_link *downlink)
-{
- int irq_mask = 0;
- int ctrl;
-
- if (!downlink)
- return -EINVAL;
-
- mcpdm->downlink = downlink;
-
- /* Enable irq request generation */
- irq_mask |= downlink->irq_mask & MCPDM_DOWNLINK_IRQ_MASK;
- omap_mcpdm_write(MCPDM_IRQENABLE_SET, irq_mask);
-
- /* Configure uplink threshold */
- if (downlink->threshold > DN_THRES_MAX)
- downlink->threshold = DN_THRES_MAX;
-
- omap_mcpdm_write(MCPDM_FIFO_CTRL_DN, downlink->threshold);
-
- /* Enable DMA request generation */
- omap_mcpdm_write(MCPDM_DMAENABLE_SET, DMA_DN_ENABLE);
-
- /* Set pdm out format */
- ctrl = omap_mcpdm_read(MCPDM_CTRL);
- ctrl &= ~PDMOUTFORMAT;
- ctrl |= downlink->format & PDMOUTFORMAT;
-
- /* Downlink channels */
- mcpdm->dn_channels = downlink->channels & (PDM_DN_MASK | PDM_CMD_MASK);
-
- omap_mcpdm_write(MCPDM_CTRL, ctrl);
-
- return 0;
-}
-
-/*
- * Cleans McPDM uplink configuration.
- * This function should be called when the stream is closed.
- */
-int omap_mcpdm_capture_close(struct omap_mcpdm_link *uplink)
-{
- int irq_mask = 0;
-
- if (!uplink)
- return -EINVAL;
-
- /* Disable irq request generation */
- irq_mask |= uplink->irq_mask & MCPDM_UPLINK_IRQ_MASK;
- omap_mcpdm_write(MCPDM_IRQENABLE_CLR, irq_mask);
-
- /* Disable DMA request generation */
- omap_mcpdm_write(MCPDM_DMAENABLE_CLR, DMA_UP_ENABLE);
-
- /* Clear Downlink channels */
- mcpdm->up_channels = 0;
-
- mcpdm->uplink = NULL;
-
- return 0;
-}
-
-/*
- * Cleans McPDM downlink configuration.
- * This function should be called when the stream is closed.
- */
-int omap_mcpdm_playback_close(struct omap_mcpdm_link *downlink)
-{
- int irq_mask = 0;
-
- if (!downlink)
- return -EINVAL;
-
- /* Disable irq request generation */
- irq_mask |= downlink->irq_mask & MCPDM_DOWNLINK_IRQ_MASK;
- omap_mcpdm_write(MCPDM_IRQENABLE_CLR, irq_mask);
-
- /* Disable DMA request generation */
- omap_mcpdm_write(MCPDM_DMAENABLE_CLR, DMA_DN_ENABLE);
-
- /* clear Downlink channels */
- mcpdm->dn_channels = 0;
-
- mcpdm->downlink = NULL;
-
- return 0;
-}
-
-static irqreturn_t omap_mcpdm_irq_handler(int irq, void *dev_id)
-{
- struct omap_mcpdm *mcpdm_irq = dev_id;
- int irq_status;
-
- irq_status = omap_mcpdm_read(MCPDM_IRQSTATUS);
-
- /* Acknowledge irq event */
- omap_mcpdm_write(MCPDM_IRQSTATUS, irq_status);
-
- if (irq & MCPDM_DN_IRQ_FULL) {
- dev_err(mcpdm_irq->dev, "DN FIFO error %x\n", irq_status);
- omap_mcpdm_reset_playback(1);
- omap_mcpdm_playback_open(mcpdm_irq->downlink);
- omap_mcpdm_reset_playback(0);
- }
-
- if (irq & MCPDM_DN_IRQ_EMPTY) {
- dev_err(mcpdm_irq->dev, "DN FIFO error %x\n", irq_status);
- omap_mcpdm_reset_playback(1);
- omap_mcpdm_playback_open(mcpdm_irq->downlink);
- omap_mcpdm_reset_playback(0);
- }
-
- if (irq & MCPDM_DN_IRQ) {
- dev_dbg(mcpdm_irq->dev, "DN write request\n");
- }
-
- if (irq & MCPDM_UP_IRQ_FULL) {
- dev_err(mcpdm_irq->dev, "UP FIFO error %x\n", irq_status);
- omap_mcpdm_reset_capture(1);
- omap_mcpdm_capture_open(mcpdm_irq->uplink);
- omap_mcpdm_reset_capture(0);
- }
-
- if (irq & MCPDM_UP_IRQ_EMPTY) {
- dev_err(mcpdm_irq->dev, "UP FIFO error %x\n", irq_status);
- omap_mcpdm_reset_capture(1);
- omap_mcpdm_capture_open(mcpdm_irq->uplink);
- omap_mcpdm_reset_capture(0);
- }
-
- if (irq & MCPDM_UP_IRQ) {
- dev_dbg(mcpdm_irq->dev, "UP write request\n");
- }
-
- return IRQ_HANDLED;
-}
-
-int omap_mcpdm_request(void)
-{
- int ret;
-
- clk_enable(mcpdm->clk);
-
- spin_lock(&mcpdm->lock);
-
- if (!mcpdm->free) {
- dev_err(mcpdm->dev, "McPDM interface is in use\n");
- spin_unlock(&mcpdm->lock);
- ret = -EBUSY;
- goto err;
- }
- mcpdm->free = 0;
-
- spin_unlock(&mcpdm->lock);
-
- /* Disable lines while request is ongoing */
- omap_mcpdm_write(MCPDM_CTRL, 0x00);
-
- ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler,
- 0, "McPDM", (void *)mcpdm);
- if (ret) {
- dev_err(mcpdm->dev, "Request for McPDM IRQ failed\n");
- goto err;
- }
-
- return 0;
-
-err:
- clk_disable(mcpdm->clk);
- return ret;
-}
-
-void omap_mcpdm_free(void)
-{
- spin_lock(&mcpdm->lock);
- if (mcpdm->free) {
- dev_err(mcpdm->dev, "McPDM interface is already free\n");
- spin_unlock(&mcpdm->lock);
- return;
- }
- mcpdm->free = 1;
- spin_unlock(&mcpdm->lock);
-
- clk_disable(mcpdm->clk);
-
- free_irq(mcpdm->irq, (void *)mcpdm);
-}
-
-/* Enable/disable DC offset cancelation for the analog
- * headset path (PDM channels 1 and 2).
- */
-int omap_mcpdm_set_offset(int offset1, int offset2)
-{
- int offset;
-
- if ((offset1 > DN_OFST_MAX) || (offset2 > DN_OFST_MAX))
- return -EINVAL;
-
- offset = (offset1 << DN_OFST_RX1) | (offset2 << DN_OFST_RX2);
-
- /* offset cancellation for channel 1 */
- if (offset1)
- offset |= DN_OFST_RX1_EN;
- else
- offset &= ~DN_OFST_RX1_EN;
-
- /* offset cancellation for channel 2 */
- if (offset2)
- offset |= DN_OFST_RX2_EN;
- else
- offset &= ~DN_OFST_RX2_EN;
-
- omap_mcpdm_write(MCPDM_DN_OFFSET, offset);
-
- return 0;
-}
-
-int __devinit omap_mcpdm_probe(struct platform_device *pdev)
-{
- struct resource *res;
- int ret = 0;
-
- mcpdm = kzalloc(sizeof(struct omap_mcpdm), GFP_KERNEL);
- if (!mcpdm) {
- ret = -ENOMEM;
- goto exit;
- }
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL) {
- dev_err(&pdev->dev, "no resource\n");
- goto err_resource;
- }
-
- spin_lock_init(&mcpdm->lock);
- mcpdm->free = 1;
- mcpdm->io_base = ioremap(res->start, resource_size(res));
- if (!mcpdm->io_base) {
- ret = -ENOMEM;
- goto err_resource;
- }
-
- mcpdm->irq = platform_get_irq(pdev, 0);
-
- mcpdm->clk = clk_get(&pdev->dev, "pdm_ck");
- if (IS_ERR(mcpdm->clk)) {
- ret = PTR_ERR(mcpdm->clk);
- dev_err(&pdev->dev, "unable to get pdm_ck: %d\n", ret);
- goto err_clk;
- }
-
- mcpdm->dev = &pdev->dev;
- platform_set_drvdata(pdev, mcpdm);
-
- return 0;
-
-err_clk:
- iounmap(mcpdm->io_base);
-err_resource:
- kfree(mcpdm);
-exit:
- return ret;
-}
-
-int __devexit omap_mcpdm_remove(struct platform_device *pdev)
-{
- struct omap_mcpdm *mcpdm_ptr = platform_get_drvdata(pdev);
-
- platform_set_drvdata(pdev, NULL);
-
- clk_put(mcpdm_ptr->clk);
-
- iounmap(mcpdm_ptr->io_base);
-
- mcpdm_ptr->clk = NULL;
- mcpdm_ptr->free = 0;
- mcpdm_ptr->dev = NULL;
-
- kfree(mcpdm_ptr);
-
- return 0;
-}
-
diff --git a/sound/soc/omap/mcpdm.h b/sound/soc/omap/mcpdm.h
deleted file mode 100644
index df3e16f..0000000
--- a/sound/soc/omap/mcpdm.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * mcpdm.h -- Defines for McPDM driver
- *
- * Author: Jorge Eduardo Candelaria <x0107209@ti.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program 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 program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-/* McPDM registers */
-
-#define MCPDM_REVISION 0x00
-#define MCPDM_SYSCONFIG 0x10
-#define MCPDM_IRQSTATUS_RAW 0x24
-#define MCPDM_IRQSTATUS 0x28
-#define MCPDM_IRQENABLE_SET 0x2C
-#define MCPDM_IRQENABLE_CLR 0x30
-#define MCPDM_IRQWAKE_EN 0x34
-#define MCPDM_DMAENABLE_SET 0x38
-#define MCPDM_DMAENABLE_CLR 0x3C
-#define MCPDM_DMAWAKEEN 0x40
-#define MCPDM_CTRL 0x44
-#define MCPDM_DN_DATA 0x48
-#define MCPDM_UP_DATA 0x4C
-#define MCPDM_FIFO_CTRL_DN 0x50
-#define MCPDM_FIFO_CTRL_UP 0x54
-#define MCPDM_DN_OFFSET 0x58
-
-/*
- * MCPDM_IRQ bit fields
- * IRQSTATUS_RAW, IRQSTATUS, IRQENABLE_SET, IRQENABLE_CLR
- */
-
-#define MCPDM_DN_IRQ (1 << 0)
-#define MCPDM_DN_IRQ_EMPTY (1 << 1)
-#define MCPDM_DN_IRQ_ALMST_EMPTY (1 << 2)
-#define MCPDM_DN_IRQ_FULL (1 << 3)
-
-#define MCPDM_UP_IRQ (1 << 8)
-#define MCPDM_UP_IRQ_EMPTY (1 << 9)
-#define MCPDM_UP_IRQ_ALMST_FULL (1 << 10)
-#define MCPDM_UP_IRQ_FULL (1 << 11)
-
-#define MCPDM_DOWNLINK_IRQ_MASK 0x00F
-#define MCPDM_UPLINK_IRQ_MASK 0xF00
-
-/*
- * MCPDM_DMAENABLE bit fields
- */
-
-#define DMA_DN_ENABLE 0x1
-#define DMA_UP_ENABLE 0x2
-
-/*
- * MCPDM_CTRL bit fields
- */
-
-#define PDM_UP1_EN 0x0001
-#define PDM_UP2_EN 0x0002
-#define PDM_UP3_EN 0x0004
-#define PDM_DN1_EN 0x0008
-#define PDM_DN2_EN 0x0010
-#define PDM_DN3_EN 0x0020
-#define PDM_DN4_EN 0x0040
-#define PDM_DN5_EN 0x0080
-#define PDMOUTFORMAT 0x0100
-#define CMD_INT 0x0200
-#define STATUS_INT 0x0400
-#define SW_UP_RST 0x0800
-#define SW_DN_RST 0x1000
-#define PDM_UP_MASK 0x007
-#define PDM_DN_MASK 0x0F8
-#define PDM_CMD_MASK 0x200
-#define PDM_STATUS_MASK 0x400
-
-
-#define PDMOUTFORMAT_LJUST (0 << 8)
-#define PDMOUTFORMAT_RJUST (1 << 8)
-
-/*
- * MCPDM_FIFO_CTRL bit fields
- */
-
-#define UP_THRES_MAX 0xF
-#define DN_THRES_MAX 0xF
-
-/*
- * MCPDM_DN_OFFSET bit fields
- */
-
-#define DN_OFST_RX1_EN 0x0001
-#define DN_OFST_RX2_EN 0x0100
-
-#define DN_OFST_RX1 1
-#define DN_OFST_RX2 9
-#define DN_OFST_MAX 0x1F
-
-#define MCPDM_UPLINK 1
-#define MCPDM_DOWNLINK 2
-
-struct omap_mcpdm_link {
- int irq_mask;
- int threshold;
- int format;
- int channels;
-};
-
-struct omap_mcpdm_platform_data {
- unsigned long phys_base;
- u16 irq;
-};
-
-struct omap_mcpdm {
- struct device *dev;
- unsigned long phys_base;
- void __iomem *io_base;
- u8 free;
- int irq;
-
- spinlock_t lock;
- struct omap_mcpdm_platform_data *pdata;
- struct clk *clk;
- struct omap_mcpdm_link *downlink;
- struct omap_mcpdm_link *uplink;
- struct completion irq_completion;
-
- int dn_channels;
- int up_channels;
-};
-
-extern void omap_mcpdm_start(int stream);
-extern void omap_mcpdm_stop(int stream);
-extern int omap_mcpdm_capture_open(struct omap_mcpdm_link *uplink);
-extern int omap_mcpdm_playback_open(struct omap_mcpdm_link *downlink);
-extern int omap_mcpdm_capture_close(struct omap_mcpdm_link *uplink);
-extern int omap_mcpdm_playback_close(struct omap_mcpdm_link *downlink);
-extern int omap_mcpdm_request(void);
-extern void omap_mcpdm_free(void);
-extern int omap_mcpdm_set_offset(int offset1, int offset2);
-int __devinit omap_mcpdm_probe(struct platform_device *pdev);
-int __devexit omap_mcpdm_remove(struct platform_device *pdev);
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c
index 83d213b..fc6209b 100644
--- a/sound/soc/omap/n810.c
+++ b/sound/soc/omap/n810.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2008 Nokia Corporation
*
- * Contact: Jarkko Nikula <jhnikula@gmail.com>
+ * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -31,6 +31,7 @@
#include <asm/mach-types.h>
#include <mach/hardware.h>
#include <linux/gpio.h>
+#include <linux/module.h>
#include <plat/mcbsp.h>
#include "omap-mcbsp.h"
@@ -115,25 +116,8 @@ static int n810_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int err;
- /* Set codec DAI configuration */
- err = snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (err < 0)
- return err;
-
- /* Set cpu DAI configuration */
- err = snd_soc_dai_set_fmt(cpu_dai,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (err < 0)
- return err;
-
/* Set the codec system clock for DAC and ADC */
err = snd_soc_dai_set_sysclk(codec_dai, 0, 12000000,
SND_SOC_CLOCK_IN);
@@ -274,7 +258,6 @@ static int n810_aic33_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
- int err;
/* Not connected */
snd_soc_dapm_nc_pin(dapm, "MONO_LOUT");
@@ -286,21 +269,6 @@ static int n810_aic33_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_nc_pin(dapm, "LINE2L");
snd_soc_dapm_nc_pin(dapm, "LINE2R");
- /* Add N810 specific controls */
- err = snd_soc_add_controls(codec, aic33_n810_controls,
- ARRAY_SIZE(aic33_n810_controls));
- if (err < 0)
- return err;
-
- /* Add N810 specific widgets */
- snd_soc_dapm_new_controls(dapm, aic33_dapm_widgets,
- ARRAY_SIZE(aic33_dapm_widgets));
-
- /* Set up N810 specific audio path audio_map */
- snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
- snd_soc_dapm_sync(dapm);
-
return 0;
}
@@ -312,6 +280,8 @@ static struct snd_soc_dai_link n810_dai = {
.platform_name = "omap-pcm-audio",
.codec_name = "tlv320aic3x-codec.2-0018",
.codec_dai_name = "tlv320aic3x-hifi",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM,
.init = n810_aic33_init,
.ops = &n810_ops,
};
@@ -321,6 +291,13 @@ static struct snd_soc_card snd_soc_n810 = {
.name = "N810",
.dai_link = &n810_dai,
.num_links = 1,
+
+ .controls = aic33_n810_controls,
+ .num_controls = ARRAY_SIZE(aic33_n810_controls),
+ .dapm_widgets = aic33_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(aic33_dapm_widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
};
static struct platform_device *n810_snd_device;
@@ -402,6 +379,6 @@ static void __exit n810_soc_exit(void)
module_init(n810_soc_init);
module_exit(n810_soc_exit);
-MODULE_AUTHOR("Jarkko Nikula <jhnikula@gmail.com>");
+MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
MODULE_DESCRIPTION("ALSA SoC Nokia N810");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 4b82290..4314647 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2008 Nokia Corporation
*
- * Contact: Jarkko Nikula <jhnikula@gmail.com>
+ * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
* Peter Ujfalusi <peter.ujfalusi@ti.com>
*
* This program is free software; you can redistribute it and/or
@@ -317,6 +317,10 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
return 0;
}
+ regs->rcr2 &= ~(RPHASE | RFRLEN2(0x7f) | RWDLEN2(7));
+ regs->xcr2 &= ~(RPHASE | XFRLEN2(0x7f) | XWDLEN2(7));
+ regs->rcr1 &= ~(RFRLEN1(0x7f) | RWDLEN1(7));
+ regs->xcr1 &= ~(XFRLEN1(0x7f) | XWDLEN1(7));
format = mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK;
wpf = channels = params_channels(params);
if (channels == 2 && (format == SND_SOC_DAIFMT_I2S ||
@@ -369,6 +373,8 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
framesize = wlen * channels;
/* Set FS period and length in terms of bit clock periods */
+ regs->srgr2 &= ~FPER(0xfff);
+ regs->srgr1 &= ~FWID(0xff);
switch (format) {
case SND_SOC_DAIFMT_I2S:
case SND_SOC_DAIFMT_LEFT_J:
@@ -398,7 +404,7 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
{
struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
- unsigned int temp_fmt = fmt;
+ bool inv_fs = false;
if (mcbsp_data->configured)
return 0;
@@ -430,21 +436,21 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
regs->xcr2 |= XDATDLY(0);
regs->spcr1 |= RJUST(2);
/* Invert FS polarity configuration */
- temp_fmt ^= SND_SOC_DAIFMT_NB_IF;
+ inv_fs = true;
break;
case SND_SOC_DAIFMT_DSP_A:
/* 1-bit data delay */
regs->rcr2 |= RDATDLY(1);
regs->xcr2 |= XDATDLY(1);
/* Invert FS polarity configuration */
- temp_fmt ^= SND_SOC_DAIFMT_NB_IF;
+ inv_fs = true;
break;
case SND_SOC_DAIFMT_DSP_B:
/* 0-bit data delay */
regs->rcr2 |= RDATDLY(0);
regs->xcr2 |= XDATDLY(0);
/* Invert FS polarity configuration */
- temp_fmt ^= SND_SOC_DAIFMT_NB_IF;
+ inv_fs = true;
break;
default:
/* Unsupported data format */
@@ -468,7 +474,7 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
}
/* Set bit clock (CLKX/CLKR) and FS polarities */
- switch (temp_fmt & SND_SOC_DAIFMT_INV_MASK) {
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
/*
* Normal BCLK + FS.
@@ -489,6 +495,8 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
default:
return -EINVAL;
}
+ if (inv_fs == true)
+ regs->pcr0 ^= FSXP | FSRP;
return 0;
}
@@ -503,6 +511,7 @@ static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_dai *cpu_dai,
return -ENODEV;
mcbsp_data->clk_div = div;
+ regs->srgr1 &= ~CLKGDV(0xff);
regs->srgr1 |= CLKGDV(div - 1);
return 0;
@@ -516,11 +525,12 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
int err = 0;
- if (mcbsp_data->active)
+ if (mcbsp_data->active) {
if (freq == mcbsp_data->in_freq)
return 0;
else
return -EBUSY;
+ }
/* The McBSP signal muxing functions are only available on McBSP1 */
if (clk_id == OMAP_MCBSP_CLKR_SRC_CLKR ||
@@ -531,6 +541,8 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
return -EINVAL;
mcbsp_data->in_freq = freq;
+ regs->srgr2 &= ~CLKSM;
+ regs->pcr0 &= ~SCLKME;
switch (clk_id) {
case OMAP_MCBSP_SYSCLK_CLK:
@@ -605,8 +617,7 @@ static int mcbsp_dai_probe(struct snd_soc_dai *dai)
return 0;
}
-static struct snd_soc_dai_driver omap_mcbsp_dai =
-{
+static struct snd_soc_dai_driver omap_mcbsp_dai = {
.probe = mcbsp_dai_probe,
.playback = {
.channels_min = 1,
@@ -786,6 +797,6 @@ static void __exit snd_omap_mcbsp_exit(void)
}
module_exit(snd_omap_mcbsp_exit);
-MODULE_AUTHOR("Jarkko Nikula <jhnikula@gmail.com>");
+MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
MODULE_DESCRIPTION("OMAP I2S SoC Interface");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h
index 9a7dedd..65cde9d 100644
--- a/sound/soc/omap/omap-mcbsp.h
+++ b/sound/soc/omap/omap-mcbsp.h
@@ -3,7 +3,7 @@
*
* Copyright (C) 2008 Nokia Corporation
*
- * Contact: Jarkko Nikula <jhnikula@gmail.com>
+ * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
* Peter Ujfalusi <peter.ujfalusi@ti.com>
*
* This program is free software; you can redistribute it and/or
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c
index bed09c2..41d1706 100644
--- a/sound/soc/omap/omap-mcpdm.c
+++ b/sound/soc/omap/omap-mcpdm.c
@@ -1,11 +1,12 @@
/*
* omap-mcpdm.c -- OMAP ALSA SoC DAI driver using McPDM port
*
- * Copyright (C) 2009 Texas Instruments
+ * Copyright (C) 2009 - 2011 Texas Instruments
*
- * Author: Misael Lopez Cruz <x0052729@ti.com>
+ * Author: Misael Lopez Cruz <misael.lopez@ti.com>
* Contact: Jorge Eduardo Candelaria <x0107209@ti.com>
* Margarita Olaya <magi.olaya@ti.com>
+ * Peter Ujfalusi <peter.ujfalusi@ti.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -25,41 +26,42 @@
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
-#include <sound/initval.h>
#include <sound/soc.h>
#include <plat/dma.h>
-#include <plat/mcbsp.h>
-#include "mcpdm.h"
+#include <plat/omap_hwmod.h>
+#include "omap-mcpdm.h"
#include "omap-pcm.h"
-struct omap_mcpdm_data {
- struct omap_mcpdm_link *links;
- int active;
-};
+struct omap_mcpdm {
+ struct device *dev;
+ unsigned long phys_base;
+ void __iomem *io_base;
+ int irq;
-static struct omap_mcpdm_link omap_mcpdm_links[] = {
- /* downlink */
- {
- .irq_mask = MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL,
- .threshold = 1,
- .format = PDMOUTFORMAT_LJUST,
- },
- /* uplink */
- {
- .irq_mask = MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL,
- .threshold = 1,
- .format = PDMOUTFORMAT_LJUST,
- },
-};
+ struct mutex mutex;
+
+ /* channel data */
+ u32 dn_channels;
+ u32 up_channels;
+
+ /* McPDM FIFO thresholds */
+ u32 dn_threshold;
+ u32 up_threshold;
-static struct omap_mcpdm_data mcpdm_data = {
- .links = omap_mcpdm_links,
- .active = 0,
+ /* McPDM dn offsets for rx1, and 2 channels */
+ u32 dn_rx_offset;
};
/*
@@ -71,88 +73,259 @@ static struct omap_pcm_dma_data omap_mcpdm_dai_dma_params[] = {
.dma_req = OMAP44XX_DMA_MCPDM_DL,
.data_type = OMAP_DMA_DATA_TYPE_S32,
.sync_mode = OMAP_DMA_SYNC_PACKET,
- .packet_size = 16,
- .port_addr = OMAP44XX_MCPDM_L3_BASE + MCPDM_DN_DATA,
+ .port_addr = OMAP44XX_MCPDM_L3_BASE + MCPDM_REG_DN_DATA,
},
{
.name = "Audio capture",
.dma_req = OMAP44XX_DMA_MCPDM_UP,
.data_type = OMAP_DMA_DATA_TYPE_S32,
.sync_mode = OMAP_DMA_SYNC_PACKET,
- .packet_size = 16,
- .port_addr = OMAP44XX_MCPDM_L3_BASE + MCPDM_UP_DATA,
+ .port_addr = OMAP44XX_MCPDM_L3_BASE + MCPDM_REG_UP_DATA,
},
};
-static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+static inline void omap_mcpdm_write(struct omap_mcpdm *mcpdm, u16 reg, u32 val)
{
- int err = 0;
+ __raw_writel(val, mcpdm->io_base + reg);
+}
- if (!dai->active)
- err = omap_mcpdm_request();
+static inline int omap_mcpdm_read(struct omap_mcpdm *mcpdm, u16 reg)
+{
+ return __raw_readl(mcpdm->io_base + reg);
+}
- return err;
+#ifdef DEBUG
+static void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm)
+{
+ dev_dbg(mcpdm->dev, "***********************\n");
+ dev_dbg(mcpdm->dev, "IRQSTATUS_RAW: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_REG_IRQSTATUS_RAW));
+ dev_dbg(mcpdm->dev, "IRQSTATUS: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_REG_IRQSTATUS));
+ dev_dbg(mcpdm->dev, "IRQENABLE_SET: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_REG_IRQENABLE_SET));
+ dev_dbg(mcpdm->dev, "IRQENABLE_CLR: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_REG_IRQENABLE_CLR));
+ dev_dbg(mcpdm->dev, "IRQWAKE_EN: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_REG_IRQWAKE_EN));
+ dev_dbg(mcpdm->dev, "DMAENABLE_SET: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_REG_DMAENABLE_SET));
+ dev_dbg(mcpdm->dev, "DMAENABLE_CLR: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_REG_DMAENABLE_CLR));
+ dev_dbg(mcpdm->dev, "DMAWAKEEN: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_REG_DMAWAKEEN));
+ dev_dbg(mcpdm->dev, "CTRL: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL));
+ dev_dbg(mcpdm->dev, "DN_DATA: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_REG_DN_DATA));
+ dev_dbg(mcpdm->dev, "UP_DATA: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_REG_UP_DATA));
+ dev_dbg(mcpdm->dev, "FIFO_CTRL_DN: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_REG_FIFO_CTRL_DN));
+ dev_dbg(mcpdm->dev, "FIFO_CTRL_UP: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_REG_FIFO_CTRL_UP));
+ dev_dbg(mcpdm->dev, "***********************\n");
}
+#else
+static void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm) {}
+#endif
-static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+/*
+ * Enables the transfer through the PDM interface to/from the Phoenix
+ * codec by enabling the corresponding UP or DN channels.
+ */
+static void omap_mcpdm_start(struct omap_mcpdm *mcpdm)
+{
+ u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
+
+ ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
+ omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
+
+ ctrl |= mcpdm->dn_channels | mcpdm->up_channels;
+ omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
+
+ ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
+ omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
+}
+
+/*
+ * Disables the transfer through the PDM interface to/from the Phoenix
+ * codec by disabling the corresponding UP or DN channels.
+ */
+static void omap_mcpdm_stop(struct omap_mcpdm *mcpdm)
+{
+ u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
+
+ ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
+ omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
+
+ ctrl &= ~(mcpdm->dn_channels | mcpdm->up_channels);
+ omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
+
+ ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
+ omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
+
+}
+
+/*
+ * Is the physical McPDM interface active.
+ */
+static inline int omap_mcpdm_active(struct omap_mcpdm *mcpdm)
+{
+ return omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL) &
+ (MCPDM_PDM_DN_MASK | MCPDM_PDM_UP_MASK);
+}
+
+/*
+ * Configures McPDM uplink, and downlink for audio.
+ * This function should be called before omap_mcpdm_start.
+ */
+static void omap_mcpdm_open_streams(struct omap_mcpdm *mcpdm)
+{
+ omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_SET,
+ MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL |
+ MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL);
+
+ /* Enable DN RX1/2 offset cancellation feature, if configured */
+ if (mcpdm->dn_rx_offset) {
+ u32 dn_offset = mcpdm->dn_rx_offset;
+
+ omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, dn_offset);
+ dn_offset |= (MCPDM_DN_OFST_RX1_EN | MCPDM_DN_OFST_RX2_EN);
+ omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, dn_offset);
+ }
+
+ omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_DN, mcpdm->dn_threshold);
+ omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_UP, mcpdm->up_threshold);
+
+ omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_SET,
+ MCPDM_DMA_DN_ENABLE | MCPDM_DMA_UP_ENABLE);
+}
+
+/*
+ * Cleans McPDM uplink, and downlink configuration.
+ * This function should be called when the stream is closed.
+ */
+static void omap_mcpdm_close_streams(struct omap_mcpdm *mcpdm)
+{
+ /* Disable irq request generation for downlink */
+ omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_CLR,
+ MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL);
+
+ /* Disable DMA request generation for downlink */
+ omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_CLR, MCPDM_DMA_DN_ENABLE);
+
+ /* Disable irq request generation for uplink */
+ omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_CLR,
+ MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL);
+
+ /* Disable DMA request generation for uplink */
+ omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_CLR, MCPDM_DMA_UP_ENABLE);
+
+ /* Disable RX1/2 offset cancellation */
+ if (mcpdm->dn_rx_offset)
+ omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, 0);
+}
+
+static irqreturn_t omap_mcpdm_irq_handler(int irq, void *dev_id)
+{
+ struct omap_mcpdm *mcpdm = dev_id;
+ int irq_status;
+
+ irq_status = omap_mcpdm_read(mcpdm, MCPDM_REG_IRQSTATUS);
+
+ /* Acknowledge irq event */
+ omap_mcpdm_write(mcpdm, MCPDM_REG_IRQSTATUS, irq_status);
+
+ if (irq_status & MCPDM_DN_IRQ_FULL)
+ dev_dbg(mcpdm->dev, "DN (playback) FIFO Full\n");
+
+ if (irq_status & MCPDM_DN_IRQ_EMPTY)
+ dev_dbg(mcpdm->dev, "DN (playback) FIFO Empty\n");
+
+ if (irq_status & MCPDM_DN_IRQ)
+ dev_dbg(mcpdm->dev, "DN (playback) write request\n");
+
+ if (irq_status & MCPDM_UP_IRQ_FULL)
+ dev_dbg(mcpdm->dev, "UP (capture) FIFO Full\n");
+
+ if (irq_status & MCPDM_UP_IRQ_EMPTY)
+ dev_dbg(mcpdm->dev, "UP (capture) FIFO Empty\n");
+
+ if (irq_status & MCPDM_UP_IRQ)
+ dev_dbg(mcpdm->dev, "UP (capture) write request\n");
+
+ return IRQ_HANDLED;
+}
+
+static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
{
- if (!dai->active)
- omap_mcpdm_free();
+ struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
+
+ mutex_lock(&mcpdm->mutex);
+
+ if (!dai->active) {
+ pm_runtime_get_sync(mcpdm->dev);
+
+ /* Enable watch dog for ES above ES 1.0 to avoid saturation */
+ if (omap_rev() != OMAP4430_REV_ES1_0) {
+ u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
+
+ omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL,
+ ctrl | MCPDM_WD_EN);
+ }
+ omap_mcpdm_open_streams(mcpdm);
+ }
+
+ mutex_unlock(&mcpdm->mutex);
+
+ return 0;
}
-static int omap_mcpdm_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct omap_mcpdm_data *mcpdm_priv = snd_soc_dai_get_drvdata(dai);
- int stream = substream->stream;
- int err = 0;
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- if (!mcpdm_priv->active++)
- omap_mcpdm_start(stream);
- break;
+ struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- if (!--mcpdm_priv->active)
- omap_mcpdm_stop(stream);
- break;
- default:
- err = -EINVAL;
+ mutex_lock(&mcpdm->mutex);
+
+ if (!dai->active) {
+ if (omap_mcpdm_active(mcpdm)) {
+ omap_mcpdm_stop(mcpdm);
+ omap_mcpdm_close_streams(mcpdm);
+ }
+
+ if (!omap_mcpdm_active(mcpdm))
+ pm_runtime_put_sync(mcpdm->dev);
}
- return err;
+ mutex_unlock(&mcpdm->mutex);
}
static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct omap_mcpdm_data *mcpdm_priv = snd_soc_dai_get_drvdata(dai);
- struct omap_mcpdm_link *mcpdm_links = mcpdm_priv->links;
+ struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
int stream = substream->stream;
- int channels, err, link_mask = 0;
-
- snd_soc_dai_set_dma_data(dai, substream,
- &omap_mcpdm_dai_dma_params[stream]);
+ struct omap_pcm_dma_data *dma_data;
+ int channels;
+ int link_mask = 0;
channels = params_channels(params);
switch (channels) {
+ case 5:
+ if (stream == SNDRV_PCM_STREAM_CAPTURE)
+ /* up to 3 channels for capture */
+ return -EINVAL;
+ link_mask |= 1 << 4;
case 4:
if (stream == SNDRV_PCM_STREAM_CAPTURE)
- /* up to 2 channels for capture */
+ /* up to 3 channels for capture */
return -EINVAL;
link_mask |= 1 << 3;
case 3:
- if (stream == SNDRV_PCM_STREAM_CAPTURE)
- /* up to 2 channels for capture */
- return -EINVAL;
link_mask |= 1 << 2;
case 2:
link_mask |= 1 << 1;
@@ -164,95 +337,187 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
+ dma_data = &omap_mcpdm_dai_dma_params[stream];
+
+ /* Configure McPDM channels, and DMA packet size */
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
- mcpdm_links[stream].channels = link_mask << 3;
- err = omap_mcpdm_playback_open(&mcpdm_links[stream]);
+ mcpdm->dn_channels = link_mask << 3;
+ dma_data->packet_size =
+ (MCPDM_DN_THRES_MAX - mcpdm->dn_threshold) * channels;
} else {
- mcpdm_links[stream].channels = link_mask << 0;
- err = omap_mcpdm_capture_open(&mcpdm_links[stream]);
+ mcpdm->up_channels = link_mask << 0;
+ dma_data->packet_size = mcpdm->up_threshold * channels;
}
- return err;
+ snd_soc_dai_set_dma_data(dai, substream, dma_data);
+
+ return 0;
}
-static int omap_mcpdm_dai_hw_free(struct snd_pcm_substream *substream,
+static int omap_mcpdm_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct omap_mcpdm_data *mcpdm_priv = snd_soc_dai_get_drvdata(dai);
- struct omap_mcpdm_link *mcpdm_links = mcpdm_priv->links;
- int stream = substream->stream;
- int err;
+ struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- err = omap_mcpdm_playback_close(&mcpdm_links[stream]);
- else
- err = omap_mcpdm_capture_close(&mcpdm_links[stream]);
+ if (!omap_mcpdm_active(mcpdm)) {
+ omap_mcpdm_start(mcpdm);
+ omap_mcpdm_reg_dump(mcpdm);
+ }
- return err;
+ return 0;
}
static struct snd_soc_dai_ops omap_mcpdm_dai_ops = {
.startup = omap_mcpdm_dai_startup,
.shutdown = omap_mcpdm_dai_shutdown,
- .trigger = omap_mcpdm_dai_trigger,
.hw_params = omap_mcpdm_dai_hw_params,
- .hw_free = omap_mcpdm_dai_hw_free,
+ .prepare = omap_mcpdm_prepare,
};
-#define OMAP_MCPDM_RATES (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
-#define OMAP_MCPDM_FORMATS (SNDRV_PCM_FMTBIT_S32_LE)
+static int omap_mcpdm_probe(struct snd_soc_dai *dai)
+{
+ struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
+ int ret;
-static int omap_mcpdm_dai_probe(struct snd_soc_dai *dai)
+ pm_runtime_enable(mcpdm->dev);
+
+ /* Disable lines while request is ongoing */
+ pm_runtime_get_sync(mcpdm->dev);
+ omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, 0x00);
+
+ ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler,
+ 0, "McPDM", (void *)mcpdm);
+
+ pm_runtime_put_sync(mcpdm->dev);
+
+ if (ret) {
+ dev_err(mcpdm->dev, "Request for IRQ failed\n");
+ pm_runtime_disable(mcpdm->dev);
+ }
+
+ /* Configure McPDM threshold values */
+ mcpdm->dn_threshold = 2;
+ mcpdm->up_threshold = MCPDM_UP_THRES_MAX - 3;
+ return ret;
+}
+
+static int omap_mcpdm_remove(struct snd_soc_dai *dai)
{
- snd_soc_dai_set_drvdata(dai, &mcpdm_data);
+ struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
+
+ free_irq(mcpdm->irq, (void *)mcpdm);
+ pm_runtime_disable(mcpdm->dev);
+
return 0;
}
+#define OMAP_MCPDM_RATES (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+#define OMAP_MCPDM_FORMATS SNDRV_PCM_FMTBIT_S32_LE
+
static struct snd_soc_dai_driver omap_mcpdm_dai = {
- .probe = omap_mcpdm_dai_probe,
+ .probe = omap_mcpdm_probe,
+ .remove = omap_mcpdm_remove,
+ .probe_order = SND_SOC_COMP_ORDER_LATE,
+ .remove_order = SND_SOC_COMP_ORDER_EARLY,
.playback = {
.channels_min = 1,
- .channels_max = 4,
+ .channels_max = 5,
.rates = OMAP_MCPDM_RATES,
.formats = OMAP_MCPDM_FORMATS,
},
.capture = {
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 3,
.rates = OMAP_MCPDM_RATES,
.formats = OMAP_MCPDM_FORMATS,
},
.ops = &omap_mcpdm_dai_ops,
};
+void omap_mcpdm_configure_dn_offsets(struct snd_soc_pcm_runtime *rtd,
+ u8 rx1, u8 rx2)
+{
+ struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+
+ mcpdm->dn_rx_offset = MCPDM_DNOFST_RX1(rx1) | MCPDM_DNOFST_RX2(rx2);
+}
+EXPORT_SYMBOL_GPL(omap_mcpdm_configure_dn_offsets);
+
static __devinit int asoc_mcpdm_probe(struct platform_device *pdev)
{
- int ret;
+ struct omap_mcpdm *mcpdm;
+ struct resource *res;
+ int ret = 0;
+
+ mcpdm = kzalloc(sizeof(struct omap_mcpdm), GFP_KERNEL);
+ if (!mcpdm)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, mcpdm);
+
+ mutex_init(&mcpdm->mutex);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "no resource\n");
+ goto err_res;
+ }
+
+ if (!request_mem_region(res->start, resource_size(res), "McPDM")) {
+ ret = -EBUSY;
+ goto err_res;
+ }
+
+ mcpdm->io_base = ioremap(res->start, resource_size(res));
+ if (!mcpdm->io_base) {
+ ret = -ENOMEM;
+ goto err_iomap;
+ }
+
+ mcpdm->irq = platform_get_irq(pdev, 0);
+ if (mcpdm->irq < 0) {
+ ret = mcpdm->irq;
+ goto err_irq;
+ }
+
+ mcpdm->dev = &pdev->dev;
- ret = omap_mcpdm_probe(pdev);
- if (ret < 0)
- return ret;
ret = snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai);
- if (ret < 0)
- omap_mcpdm_remove(pdev);
+ if (!ret)
+ return 0;
+
+err_irq:
+ iounmap(mcpdm->io_base);
+err_iomap:
+ release_mem_region(res->start, resource_size(res));
+err_res:
+ kfree(mcpdm);
return ret;
}
static int __devexit asoc_mcpdm_remove(struct platform_device *pdev)
{
+ struct omap_mcpdm *mcpdm = platform_get_drvdata(pdev);
+ struct resource *res;
+
snd_soc_unregister_dai(&pdev->dev);
- omap_mcpdm_remove(pdev);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ iounmap(mcpdm->io_base);
+ release_mem_region(res->start, resource_size(res));
+
+ kfree(mcpdm);
return 0;
}
static struct platform_driver asoc_mcpdm_driver = {
.driver = {
- .name = "omap-mcpdm-dai",
- .owner = THIS_MODULE,
+ .name = "omap-mcpdm",
+ .owner = THIS_MODULE,
},
- .probe = asoc_mcpdm_probe,
- .remove = __devexit_p(asoc_mcpdm_remove),
+ .probe = asoc_mcpdm_probe,
+ .remove = __devexit_p(asoc_mcpdm_remove),
};
static int __init snd_omap_mcpdm_init(void)
@@ -267,6 +532,6 @@ static void __exit snd_omap_mcpdm_exit(void)
}
module_exit(snd_omap_mcpdm_exit);
-MODULE_AUTHOR("Misael Lopez Cruz <x0052729@ti.com>");
+MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>");
MODULE_DESCRIPTION("OMAP PDM SoC Interface");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
index e6a6b99..9563728 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2008 Nokia Corporation
*
- * Contact: Jarkko Nikula <jhnikula@gmail.com>
+ * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
* Peter Ujfalusi <peter.ujfalusi@ti.com>
*
* This program is free software; you can redistribute it and/or
@@ -24,6 +24,7 @@
#include <linux/dma-mapping.h>
#include <linux/slab.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -198,6 +199,14 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream)
OMAP_DMA_LAST_IRQ | OMAP_DMA_BLOCK_IRQ);
else if (!substream->runtime->no_period_wakeup)
omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ);
+ else {
+ /*
+ * No period wakeup:
+ * we need to disable BLOCK_IRQ, which is enabled by the omap
+ * dma core at request dma time.
+ */
+ omap_disable_dma_irq(prtd->dma_ch, OMAP_DMA_BLOCK_IRQ);
+ }
if (!(cpu_class_is_omap1())) {
omap_set_dma_src_burst_mode(prtd->dma_ch,
@@ -324,7 +333,7 @@ static struct snd_pcm_ops omap_pcm_ops = {
.mmap = omap_pcm_mmap,
};
-static u64 omap_pcm_dmamask = DMA_BIT_MASK(64);
+static u64 omap_pcm_dmamask = DMA_BIT_MASK(32);
static int omap_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
int stream)
@@ -366,15 +375,17 @@ static void omap_pcm_free_dma_buffers(struct snd_pcm *pcm)
}
}
-static int omap_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
- struct snd_pcm *pcm)
+static int omap_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_card *card = rtd->card->snd_card;
+ struct snd_soc_dai *dai = rtd->cpu_dai;
+ struct snd_pcm *pcm = rtd->pcm;
int ret = 0;
if (!card->dev->dma_mask)
card->dev->dma_mask = &omap_pcm_dmamask;
if (!card->dev->coherent_dma_mask)
- card->dev->coherent_dma_mask = DMA_BIT_MASK(64);
+ card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
if (dai->driver->playback.channels_min) {
ret = omap_pcm_preallocate_dma_buffer(pcm,
@@ -434,6 +445,6 @@ static void __exit snd_omap_pcm_exit(void)
}
module_exit(snd_omap_pcm_exit);
-MODULE_AUTHOR("Jarkko Nikula <jhnikula@gmail.com>");
+MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
MODULE_DESCRIPTION("OMAP PCM DMA module");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap-pcm.h b/sound/soc/omap/omap-pcm.h
index a0ed1db..f95fe30 100644
--- a/sound/soc/omap/omap-pcm.h
+++ b/sound/soc/omap/omap-pcm.h
@@ -3,7 +3,7 @@
*
* Copyright (C) 2008 Nokia Corporation
*
- * Contact: Jarkko Nikula <jhnikula@gmail.com>
+ * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
* Peter Ujfalusi <peter.ujfalusi@ti.com>
*
* This program is free software; you can redistribute it and/or
diff --git a/sound/soc/omap/omap3beagle.c b/sound/soc/omap/omap3beagle.c
index 40db813..3357dcc 100644
--- a/sound/soc/omap/omap3beagle.c
+++ b/sound/soc/omap/omap3beagle.c
@@ -21,6 +21,7 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
diff --git a/sound/soc/omap/omap3evm.c b/sound/soc/omap/omap3evm.c
index 0daa044..6857895 100644
--- a/sound/soc/omap/omap3evm.c
+++ b/sound/soc/omap/omap3evm.c
@@ -19,6 +19,7 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
@@ -36,29 +37,8 @@ static int omap3evm_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
- /* Set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0) {
- printk(KERN_ERR "Can't set codec DAI configuration\n");
- return ret;
- }
-
- /* Set cpu DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0) {
- printk(KERN_ERR "Can't set cpu DAI configuration\n");
- return ret;
- }
-
/* Set the codec system clock for DAC and ADC */
ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
SND_SOC_CLOCK_IN);
@@ -82,6 +62,8 @@ static struct snd_soc_dai_link omap3evm_dai = {
.codec_dai_name = "twl4030-hifi",
.platform_name = "omap-pcm-audio",
.codec_name = "twl4030-codec",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM,
.ops = &omap3evm_ops,
};
diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c
index 8047c52..7605c37 100644
--- a/sound/soc/omap/omap3pandora.c
+++ b/sound/soc/omap/omap3pandora.c
@@ -24,6 +24,7 @@
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/regulator/consumer.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -48,24 +49,8 @@ static int omap3pandora_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- int fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS;
int ret;
- /* Set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai, fmt);
- if (ret < 0) {
- pr_err(PREFIX "can't set codec DAI configuration\n");
- return ret;
- }
-
- /* Set cpu DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
- if (ret < 0) {
- pr_err(PREFIX "can't set cpu DAI configuration\n");
- return ret;
- }
-
/* Set the codec system clock for DAC and ADC */
ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
SND_SOC_CLOCK_IN);
@@ -189,10 +174,8 @@ static int omap3pandora_out_init(struct snd_soc_pcm_runtime *rtd)
if (ret < 0)
return ret;
- snd_soc_dapm_add_routes(dapm, omap3pandora_out_map,
+ return snd_soc_dapm_add_routes(dapm, omap3pandora_out_map,
ARRAY_SIZE(omap3pandora_out_map));
-
- return snd_soc_dapm_sync(dapm);
}
static int omap3pandora_in_init(struct snd_soc_pcm_runtime *rtd)
@@ -212,10 +195,8 @@ static int omap3pandora_in_init(struct snd_soc_pcm_runtime *rtd)
if (ret < 0)
return ret;
- snd_soc_dapm_add_routes(dapm, omap3pandora_in_map,
+ return snd_soc_dapm_add_routes(dapm, omap3pandora_in_map,
ARRAY_SIZE(omap3pandora_in_map));
-
- return snd_soc_dapm_sync(dapm);
}
static struct snd_soc_ops omap3pandora_ops = {
@@ -231,6 +212,8 @@ static struct snd_soc_dai_link omap3pandora_dai[] = {
.codec_dai_name = "twl4030-hifi",
.platform_name = "omap-pcm-audio",
.codec_name = "twl4030-codec",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
.ops = &omap3pandora_ops,
.init = omap3pandora_out_init,
}, {
@@ -240,6 +223,8 @@ static struct snd_soc_dai_link omap3pandora_dai[] = {
.codec_dai_name = "twl4030-hifi",
.platform_name = "omap-pcm-audio",
.codec_name = "twl4030-codec",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
.ops = &omap3pandora_ops,
.init = omap3pandora_in_init,
}
diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c
index 7e75e77..351ec9d 100644
--- a/sound/soc/omap/osk5912.c
+++ b/sound/soc/omap/osk5912.c
@@ -30,6 +30,7 @@
#include <asm/mach-types.h>
#include <mach/hardware.h>
#include <linux/gpio.h>
+#include <linux/module.h>
#include <plat/mcbsp.h>
#include "omap-mcbsp.h"
@@ -55,29 +56,8 @@ static int osk_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int err;
- /* Set codec DAI configuration */
- err = snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_DSP_B |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (err < 0) {
- printk(KERN_ERR "can't set codec DAI configuration\n");
- return err;
- }
-
- /* Set cpu DAI configuration */
- err = snd_soc_dai_set_fmt(cpu_dai,
- SND_SOC_DAIFMT_DSP_B |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (err < 0) {
- printk(KERN_ERR "can't set cpu DAI configuration\n");
- return err;
- }
-
/* Set the codec system clock for DAC and ADC */
err =
snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, SND_SOC_CLOCK_IN);
@@ -112,27 +92,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"MICIN", NULL, "Mic Jack"},
};
-static int osk_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_codec *codec = rtd->codec;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
-
- /* Add osk5912 specific widgets */
- snd_soc_dapm_new_controls(dapm, tlv320aic23_dapm_widgets,
- ARRAY_SIZE(tlv320aic23_dapm_widgets));
-
- /* Set up osk5912 specific audio path audio_map */
- snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
- snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
- snd_soc_dapm_enable_pin(dapm, "Line In");
- snd_soc_dapm_enable_pin(dapm, "Mic Jack");
-
- snd_soc_dapm_sync(dapm);
-
- return 0;
-}
-
/* Digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link osk_dai = {
.name = "TLV320AIC23",
@@ -141,7 +100,8 @@ static struct snd_soc_dai_link osk_dai = {
.codec_dai_name = "tlv320aic23-hifi",
.platform_name = "omap-pcm-audio",
.codec_name = "tlv320aic23-codec",
- .init = osk_tlv320aic23_init,
+ .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM,
.ops = &osk_ops,
};
@@ -150,6 +110,11 @@ static struct snd_soc_card snd_soc_card_osk = {
.name = "OSK5912",
.dai_link = &osk_dai,
.num_links = 1,
+
+ .dapm_widgets = tlv320aic23_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
};
static struct platform_device *osk_snd_device;
diff --git a/sound/soc/omap/overo.c b/sound/soc/omap/overo.c
index bbcf380..c3550ae 100644
--- a/sound/soc/omap/overo.c
+++ b/sound/soc/omap/overo.c
@@ -21,6 +21,7 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
@@ -38,29 +39,8 @@ static int overo_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
- /* Set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0) {
- printk(KERN_ERR "can't set codec DAI configuration\n");
- return ret;
- }
-
- /* Set cpu DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0) {
- printk(KERN_ERR "can't set cpu DAI configuration\n");
- return ret;
- }
-
/* Set the codec system clock for DAC and ADC */
ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
SND_SOC_CLOCK_IN);
@@ -84,6 +64,8 @@ static struct snd_soc_dai_link overo_dai = {
.codec_dai_name = "twl4030-hifi",
.platform_name = "omap-pcm-audio",
.codec_name = "twl4030-codec",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM,
.ops = &overo_ops,
};
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c
index 0aae998..4cabb74 100644
--- a/sound/soc/omap/rx51.c
+++ b/sound/soc/omap/rx51.c
@@ -5,7 +5,7 @@
*
* Contact: Peter Ujfalusi <peter.ujfalusi@ti.com>
* Eduardo Valentin <eduardo.valentin@nokia.com>
- * Jarkko Nikula <jhnikula@gmail.com>
+ * Jarkko Nikula <jarkko.nikula@bitmer.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -26,6 +26,7 @@
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/jack.h>
#include <sound/pcm.h>
@@ -115,24 +116,6 @@ static int rx51_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- int err;
-
- /* Set codec DAI configuration */
- err = snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_DSP_A |
- SND_SOC_DAIFMT_IB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (err < 0)
- return err;
-
- /* Set cpu DAI configuration */
- err = snd_soc_dai_set_fmt(cpu_dai,
- SND_SOC_DAIFMT_DSP_A |
- SND_SOC_DAIFMT_IB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (err < 0)
- return err;
/* Set the codec system clock for DAC and ADC */
return snd_soc_dai_set_sysclk(codec_dai, 0, 19200000,
@@ -335,8 +318,6 @@ static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
if (err < 0)
return err;
- snd_soc_dapm_sync(dapm);
-
/* AV jack detection */
err = snd_soc_jack_new(codec, "AV Jack",
SND_JACK_HEADSET | SND_JACK_VIDEOOUT,
@@ -377,6 +358,8 @@ static struct snd_soc_dai_link rx51_dai[] = {
.codec_dai_name = "tlv320aic3x-hifi",
.platform_name = "omap-pcm-audio",
.codec_name = "tlv320aic3x-codec.2-0018",
+ .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF |
+ SND_SOC_DAIFMT_CBM_CFM,
.init = rx51_aic34_init,
.ops = &rx51_ops,
},
diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c
index 3f72d17..e8fbf8e 100644
--- a/sound/soc/omap/sdp3430.c
+++ b/sound/soc/omap/sdp3430.c
@@ -36,7 +36,8 @@
#include <plat/mcbsp.h>
/* Register descriptions for twl4030 codec part */
-#include <linux/mfd/twl4030-codec.h>
+#include <linux/mfd/twl4030-audio.h>
+#include <linux/module.h>
#include "omap-mcbsp.h"
#include "omap-pcm.h"
@@ -53,29 +54,8 @@ static int sdp3430_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
- /* Set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0) {
- printk(KERN_ERR "can't set codec DAI configuration\n");
- return ret;
- }
-
- /* Set cpu DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0) {
- printk(KERN_ERR "can't set cpu DAI configuration\n");
- return ret;
- }
-
/* Set the codec system clock for DAC and ADC */
ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
SND_SOC_CLOCK_IN);
@@ -91,49 +71,6 @@ static struct snd_soc_ops sdp3430_ops = {
.hw_params = sdp3430_hw_params,
};
-static int sdp3430_hw_voice_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- int ret;
-
- /* Set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_DSP_A |
- SND_SOC_DAIFMT_IB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret) {
- printk(KERN_ERR "can't set codec DAI configuration\n");
- return ret;
- }
-
- /* Set cpu DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai,
- SND_SOC_DAIFMT_DSP_A |
- SND_SOC_DAIFMT_IB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0) {
- printk(KERN_ERR "can't set cpu DAI configuration\n");
- return ret;
- }
-
- /* Set the codec system clock for DAC and ADC */
- ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
- SND_SOC_CLOCK_IN);
- if (ret < 0) {
- printk(KERN_ERR "can't set codec system clock\n");
- return ret;
- }
-
- return 0;
-}
-
-static struct snd_soc_ops sdp3430_voice_ops = {
- .hw_params = sdp3430_hw_voice_params,
-};
-
/* Headset jack */
static struct snd_soc_jack hs_jack;
@@ -193,15 +130,6 @@ static int sdp3430_twl4030_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret;
- /* Add SDP3430 specific widgets */
- ret = snd_soc_dapm_new_controls(dapm, sdp3430_twl4030_dapm_widgets,
- ARRAY_SIZE(sdp3430_twl4030_dapm_widgets));
- if (ret)
- return ret;
-
- /* Set up SDP3430 specific audio path audio_map */
- snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
/* SDP3430 connected pins */
snd_soc_dapm_enable_pin(dapm, "Ext Mic");
snd_soc_dapm_enable_pin(dapm, "Ext Spk");
@@ -223,10 +151,6 @@ static int sdp3430_twl4030_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_nc_pin(dapm, "CARKITL");
snd_soc_dapm_nc_pin(dapm, "CARKITR");
- ret = snd_soc_dapm_sync(dapm);
- if (ret)
- return ret;
-
/* Headset jack detection */
ret = snd_soc_jack_new(codec, "Headset Jack",
SND_JACK_HEADSET, &hs_jack);
@@ -267,6 +191,8 @@ static struct snd_soc_dai_link sdp3430_dai[] = {
.codec_dai_name = "twl4030-hifi",
.platform_name = "omap-pcm-audio",
.codec_name = "twl4030-codec",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM,
.init = sdp3430_twl4030_init,
.ops = &sdp3430_ops,
},
@@ -277,8 +203,10 @@ static struct snd_soc_dai_link sdp3430_dai[] = {
.codec_dai_name = "twl4030-voice",
.platform_name = "omap-pcm-audio",
.codec_name = "twl4030-codec",
+ .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF |
+ SND_SOC_DAIFMT_CBM_CFM,
.init = sdp3430_twl4030_voice_init,
- .ops = &sdp3430_voice_ops,
+ .ops = &sdp3430_ops,
},
};
@@ -287,6 +215,11 @@ static struct snd_soc_card snd_soc_sdp3430 = {
.name = "SDP3430",
.dai_link = sdp3430_dai,
.num_links = ARRAY_SIZE(sdp3430_dai),
+
+ .dapm_widgets = sdp3430_twl4030_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sdp3430_twl4030_dapm_widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
};
static struct platform_device *sdp3430_snd_device;
diff --git a/sound/soc/omap/sdp4430.c b/sound/soc/omap/sdp4430.c
index 189e039..03d9fa4 100644
--- a/sound/soc/omap/sdp4430.c
+++ b/sound/soc/omap/sdp4430.c
@@ -21,6 +21,9 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/mfd/twl6040.h>
+#include <linux/module.h>
+
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
@@ -30,12 +33,10 @@
#include <plat/hardware.h>
#include <plat/mux.h>
-#include "mcpdm.h"
+#include "omap-mcpdm.h"
#include "omap-pcm.h"
#include "../codecs/twl6040.h"
-static int twl6040_power_mode;
-
static int sdp4430_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -44,13 +45,13 @@ static int sdp4430_hw_params(struct snd_pcm_substream *substream,
int clk_id, freq;
int ret;
- if (twl6040_power_mode) {
- clk_id = TWL6040_SYSCLK_SEL_HPPLL;
+ clk_id = twl6040_get_clk_id(rtd->codec);
+ if (clk_id == TWL6040_SYSCLK_SEL_HPPLL)
freq = 38400000;
- } else {
- clk_id = TWL6040_SYSCLK_SEL_LPPLL;
+ else if (clk_id == TWL6040_SYSCLK_SEL_LPPLL)
freq = 32768;
- }
+ else
+ return -EINVAL;
/* set the codec mclk */
ret = snd_soc_dai_set_sysclk(codec_dai, clk_id, freq,
@@ -81,35 +82,6 @@ static struct snd_soc_jack_pin hs_jack_pins[] = {
},
};
-static int sdp4430_get_power_mode(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = twl6040_power_mode;
- return 0;
-}
-
-static int sdp4430_set_power_mode(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- if (twl6040_power_mode == ucontrol->value.integer.value[0])
- return 0;
-
- twl6040_power_mode = ucontrol->value.integer.value[0];
-
- return 1;
-}
-
-static const char *power_texts[] = {"Low-Power", "High-Performance"};
-
-static const struct soc_enum sdp4430_enum[] = {
- SOC_ENUM_SINGLE_EXT(2, power_texts),
-};
-
-static const struct snd_kcontrol_new sdp4430_controls[] = {
- SOC_ENUM_EXT("TWL6040 Power Mode", sdp4430_enum[0],
- sdp4430_get_power_mode, sdp4430_set_power_mode),
-};
-
/* SDP4430 machine DAPM */
static const struct snd_soc_dapm_widget sdp4430_twl6040_dapm_widgets[] = {
SND_SOC_DAPM_MIC("Ext Mic", NULL),
@@ -117,7 +89,7 @@ static const struct snd_soc_dapm_widget sdp4430_twl6040_dapm_widgets[] = {
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_HP("Headset Stereophone", NULL),
SND_SOC_DAPM_SPK("Earphone Spk", NULL),
- SND_SOC_DAPM_INPUT("Aux/FM Stereo In"),
+ SND_SOC_DAPM_INPUT("FM Stereo In"),
};
static const struct snd_soc_dapm_route audio_map[] = {
@@ -142,42 +114,22 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"Earphone Spk", NULL, "EP"},
/* Aux/FM Stereo In: AFML, AFMR */
- {"AFML", NULL, "Aux/FM Stereo In"},
- {"AFMR", NULL, "Aux/FM Stereo In"},
+ {"AFML", NULL, "FM Stereo In"},
+ {"AFMR", NULL, "FM Stereo In"},
};
static int sdp4430_twl6040_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
- int ret;
-
- /* Add SDP4430 specific controls */
- ret = snd_soc_add_controls(codec, sdp4430_controls,
- ARRAY_SIZE(sdp4430_controls));
- if (ret)
- return ret;
+ int ret, hs_trim;
- /* Add SDP4430 specific widgets */
- ret = snd_soc_dapm_new_controls(dapm, sdp4430_twl6040_dapm_widgets,
- ARRAY_SIZE(sdp4430_twl6040_dapm_widgets));
- if (ret)
- return ret;
-
- /* Set up SDP4430 specific audio path audio_map */
- snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
- /* SDP4430 connected pins */
- snd_soc_dapm_enable_pin(dapm, "Ext Mic");
- snd_soc_dapm_enable_pin(dapm, "Ext Spk");
- snd_soc_dapm_enable_pin(dapm, "AFML");
- snd_soc_dapm_enable_pin(dapm, "AFMR");
- snd_soc_dapm_enable_pin(dapm, "Headset Mic");
- snd_soc_dapm_enable_pin(dapm, "Headset Stereophone");
-
- ret = snd_soc_dapm_sync(dapm);
- if (ret)
- return ret;
+ /*
+ * Configure McPDM offset cancellation based on the HSOTRIM value from
+ * twl6040.
+ */
+ hs_trim = twl6040_get_trim_value(codec, TWL6040_TRIM_HSOTRIM);
+ omap_mcpdm_configure_dn_offsets(rtd, TWL6040_HSF_TRIM_LEFT(hs_trim),
+ TWL6040_HSF_TRIM_RIGHT(hs_trim));
/* Headset jack detection */
ret = snd_soc_jack_new(codec, "Headset Jack",
@@ -200,8 +152,8 @@ static int sdp4430_twl6040_init(struct snd_soc_pcm_runtime *rtd)
static struct snd_soc_dai_link sdp4430_dai = {
.name = "TWL6040",
.stream_name = "TWL6040",
- .cpu_dai_name ="omap-mcpdm-dai",
- .codec_dai_name = "twl6040-hifi",
+ .cpu_dai_name = "omap-mcpdm",
+ .codec_dai_name = "twl6040-legacy",
.platform_name = "omap-pcm-audio",
.codec_name = "twl6040-codec",
.init = sdp4430_twl6040_init,
@@ -213,6 +165,11 @@ static struct snd_soc_card snd_soc_sdp4430 = {
.name = "SDP4430",
.dai_link = &sdp4430_dai,
.num_links = 1,
+
+ .dapm_widgets = sdp4430_twl6040_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sdp4430_twl6040_dapm_widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
};
static struct platform_device *sdp4430_snd_device;
@@ -237,9 +194,6 @@ static int __init sdp4430_soc_init(void)
if (ret)
goto err;
- /* Codec starts in HP mode */
- twl6040_power_mode = 1;
-
return 0;
err:
diff --git a/sound/soc/omap/zoom2.c b/sound/soc/omap/zoom2.c
index 0170994..7641a7f 100644
--- a/sound/soc/omap/zoom2.c
+++ b/sound/soc/omap/zoom2.c
@@ -32,7 +32,8 @@
#include <plat/mcbsp.h>
/* Register descriptions for twl4030 codec part */
-#include <linux/mfd/twl4030-codec.h>
+#include <linux/mfd/twl4030-audio.h>
+#include <linux/module.h>
#include "omap-mcbsp.h"
#include "omap-pcm.h"
@@ -44,29 +45,8 @@ static int zoom2_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
- /* Set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0) {
- printk(KERN_ERR "can't set codec DAI configuration\n");
- return ret;
- }
-
- /* Set cpu DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0) {
- printk(KERN_ERR "can't set cpu DAI configuration\n");
- return ret;
- }
-
/* Set the codec system clock for DAC and ADC */
ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
SND_SOC_CLOCK_IN);
@@ -82,49 +62,6 @@ static struct snd_soc_ops zoom2_ops = {
.hw_params = zoom2_hw_params,
};
-static int zoom2_hw_voice_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- int ret;
-
- /* Set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_DSP_A |
- SND_SOC_DAIFMT_IB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret) {
- printk(KERN_ERR "can't set codec DAI configuration\n");
- return ret;
- }
-
- /* Set cpu DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai,
- SND_SOC_DAIFMT_DSP_A |
- SND_SOC_DAIFMT_IB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0) {
- printk(KERN_ERR "can't set cpu DAI configuration\n");
- return ret;
- }
-
- /* Set the codec system clock for DAC and ADC */
- ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
- SND_SOC_CLOCK_IN);
- if (ret < 0) {
- printk(KERN_ERR "can't set codec system clock\n");
- return ret;
- }
-
- return 0;
-}
-
-static struct snd_soc_ops zoom2_voice_ops = {
- .hw_params = zoom2_hw_voice_params,
-};
-
/* Zoom2 machine DAPM */
static const struct snd_soc_dapm_widget zoom2_twl4030_dapm_widgets[] = {
SND_SOC_DAPM_MIC("Ext Mic", NULL),
@@ -162,23 +99,6 @@ static int zoom2_twl4030_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
- int ret;
-
- /* Add Zoom2 specific widgets */
- ret = snd_soc_dapm_new_controls(dapm, zoom2_twl4030_dapm_widgets,
- ARRAY_SIZE(zoom2_twl4030_dapm_widgets));
- if (ret)
- return ret;
-
- /* Set up Zoom2 specific audio path audio_map */
- snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
- /* Zoom2 connected pins */
- snd_soc_dapm_enable_pin(dapm, "Ext Mic");
- snd_soc_dapm_enable_pin(dapm, "Ext Spk");
- snd_soc_dapm_enable_pin(dapm, "Headset Mic");
- snd_soc_dapm_enable_pin(dapm, "Headset Stereophone");
- snd_soc_dapm_enable_pin(dapm, "Aux In");
/* TWL4030 not connected pins */
snd_soc_dapm_nc_pin(dapm, "CARKITMIC");
@@ -190,9 +110,7 @@ static int zoom2_twl4030_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_nc_pin(dapm, "CARKITL");
snd_soc_dapm_nc_pin(dapm, "CARKITR");
- ret = snd_soc_dapm_sync(dapm);
-
- return ret;
+ return 0;
}
static int zoom2_twl4030_voice_init(struct snd_soc_pcm_runtime *rtd)
@@ -217,6 +135,8 @@ static struct snd_soc_dai_link zoom2_dai[] = {
.codec_dai_name = "twl4030-hifi",
.platform_name = "omap-pcm-audio",
.codec_name = "twl4030-codec",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM,
.init = zoom2_twl4030_init,
.ops = &zoom2_ops,
},
@@ -227,8 +147,10 @@ static struct snd_soc_dai_link zoom2_dai[] = {
.codec_dai_name = "twl4030-voice",
.platform_name = "omap-pcm-audio",
.codec_name = "twl4030-codec",
+ .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF |
+ SND_SOC_DAIFMT_CBM_CFM,
.init = zoom2_twl4030_voice_init,
- .ops = &zoom2_voice_ops,
+ .ops = &zoom2_ops,
},
};
@@ -237,6 +159,11 @@ static struct snd_soc_card snd_soc_zoom2 = {
.name = "Zoom2",
.dai_link = zoom2_dai,
.num_links = ARRAY_SIZE(zoom2_dai),
+
+ .dapm_widgets = zoom2_twl4030_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(zoom2_twl4030_dapm_widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
};
static struct platform_device *zoom2_snd_device;