aboutsummaryrefslogtreecommitdiff
path: root/sound/pci/hda
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda')
-rw-r--r--sound/pci/hda/hda_codec.c2
-rw-r--r--sound/pci/hda/hda_codec.h2
-rw-r--r--sound/pci/hda/hda_hwdep.c2
-rw-r--r--sound/pci/hda/hda_intel.c306
-rw-r--r--sound/pci/hda/hda_proc.c5
-rw-r--r--sound/pci/hda/patch_analog.c38
-rw-r--r--sound/pci/hda/patch_conexant.c33
-rw-r--r--sound/pci/hda/patch_realtek.c548
-rw-r--r--sound/pci/hda/patch_sigmatel.c71
9 files changed, 854 insertions, 153 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index a6be6e3e871..d2e1093f8e9 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -2335,7 +2335,7 @@ int snd_hda_check_board_config(struct hda_codec *codec,
if (!tbl)
return -1;
if (tbl->value >= 0 && tbl->value < num_configs) {
-#ifdef CONFIG_SND_DEBUG_DETECT
+#ifdef CONFIG_SND_DEBUG_VERBOSE
char tmp[10];
const char *model = NULL;
if (models)
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index dcd390b2bba..efc682888b3 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -78,7 +78,7 @@ enum {
#define AC_VERB_GET_BEEP_CONTROL 0x0f0a
#define AC_VERB_GET_EAPD_BTLENABLE 0x0f0c
#define AC_VERB_GET_DIGI_CONVERT_1 0x0f0d
-#define AC_VERB_GET_DIGI_CONVERT_2 0x0f0e
+#define AC_VERB_GET_DIGI_CONVERT_2 0x0f0e /* unused */
#define AC_VERB_GET_VOLUME_KNOB_CONTROL 0x0f0f
/* f10-f1a: GPIO */
#define AC_VERB_GET_GPIO_DATA 0x0f15
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c
index 2177d9af533..6e18a422d99 100644
--- a/sound/pci/hda/hda_hwdep.c
+++ b/sound/pci/hda/hda_hwdep.c
@@ -88,7 +88,7 @@ static int hda_hwdep_ioctl_compat(struct snd_hwdep *hw, struct file *file,
static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file)
{
-#ifndef CONFIG_SND_DEBUG_DETECT
+#ifndef CONFIG_SND_DEBUG_VERBOSE
if (!capable(CAP_SYS_RAWIO))
return -EACCES;
#endif
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index b3a618eb42c..16715a68ba5 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -55,6 +55,7 @@ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
static char *model[SNDRV_CARDS];
static int position_fix[SNDRV_CARDS];
+static int bdl_pos_adj[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
static int single_cmd;
static int enable_msi;
@@ -69,7 +70,9 @@ module_param_array(model, charp, NULL, 0444);
MODULE_PARM_DESC(model, "Use the given board model.");
module_param_array(position_fix, int, NULL, 0444);
MODULE_PARM_DESC(position_fix, "Fix DMA pointer "
- "(0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size).");
+ "(0 = auto, 1 = none, 2 = POSBUF).");
+module_param_array(bdl_pos_adj, int, NULL, 0644);
+MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset.");
module_param_array(probe_mask, int, NULL, 0444);
MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1).");
module_param(single_cmd, bool, 0444);
@@ -197,6 +200,10 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
#define ATIHDMI_NUM_CAPTURE 0
#define ATIHDMI_NUM_PLAYBACK 1
+/* TERA has 4 playback and 3 capture */
+#define TERA_NUM_CAPTURE 3
+#define TERA_NUM_PLAYBACK 4
+
/* this number is statically defined for simplicity */
#define MAX_AZX_DEV 16
@@ -259,9 +266,8 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
/* position fix mode */
enum {
POS_FIX_AUTO,
- POS_FIX_NONE,
+ POS_FIX_LPIB,
POS_FIX_POSBUF,
- POS_FIX_FIFO,
};
/* Defines for ATI HD Audio support in SB450 south bridge */
@@ -285,6 +291,7 @@ struct azx_dev {
u32 *posbuf; /* position buffer pointer */
unsigned int bufsize; /* size of the play buffer in bytes */
+ unsigned int period_bytes; /* size of the period in bytes */
unsigned int frags; /* number for period in the play buffer */
unsigned int fifo_size; /* FIFO size */
@@ -301,11 +308,11 @@ struct azx_dev {
*/
unsigned char stream_tag; /* assigned stream */
unsigned char index; /* stream index */
- /* for sanity check of position buffer */
- unsigned int period_intr;
unsigned int opened :1;
unsigned int running :1;
+ unsigned int irq_pending :1;
+ unsigned int irq_ignore :1;
};
/* CORB/RIRB */
@@ -323,6 +330,7 @@ struct azx_rb {
struct azx {
struct snd_card *card;
struct pci_dev *pci;
+ int dev_index;
/* chip type specific */
int driver_type;
@@ -366,9 +374,13 @@ struct azx {
unsigned int single_cmd :1;
unsigned int polling_mode :1;
unsigned int msi :1;
+ unsigned int irq_pending_warned :1;
/* for debugging */
unsigned int last_cmd; /* last issued command (to sync) */
+
+ /* for pending irqs */
+ struct work_struct irq_pending_work;
};
/* driver types */
@@ -381,6 +393,7 @@ enum {
AZX_DRIVER_SIS,
AZX_DRIVER_ULI,
AZX_DRIVER_NVIDIA,
+ AZX_DRIVER_TERA,
};
static char *driver_short_names[] __devinitdata = {
@@ -392,6 +405,7 @@ static char *driver_short_names[] __devinitdata = {
[AZX_DRIVER_SIS] = "HDA SIS966",
[AZX_DRIVER_ULI] = "HDA ULI M5461",
[AZX_DRIVER_NVIDIA] = "HDA NVidia",
+ [AZX_DRIVER_TERA] = "HDA Teradici",
};
/*
@@ -426,11 +440,6 @@ static char *driver_short_names[] __devinitdata = {
/* for pcm support */
#define get_azx_dev(substream) (substream->runtime->private_data)
-/* Get the upper 32bit of the given dma_addr_t
- * Compiler should optimize and eliminate the code if dma_addr_t is 32bit
- */
-#define upper_32bit(addr) (sizeof(addr) > 4 ? (u32)((addr) >> 32) : (u32)0)
-
static int azx_acquire_irq(struct azx *chip, int do_disconnect);
/*
@@ -461,7 +470,7 @@ static void azx_init_cmd_io(struct azx *chip)
chip->corb.addr = chip->rb.addr;
chip->corb.buf = (u32 *)chip->rb.area;
azx_writel(chip, CORBLBASE, (u32)chip->corb.addr);
- azx_writel(chip, CORBUBASE, upper_32bit(chip->corb.addr));
+ azx_writel(chip, CORBUBASE, upper_32_bits(chip->corb.addr));
/* set the corb size to 256 entries (ULI requires explicitly) */
azx_writeb(chip, CORBSIZE, 0x02);
@@ -476,7 +485,7 @@ static void azx_init_cmd_io(struct azx *chip)
chip->rirb.addr = chip->rb.addr + 2048;
chip->rirb.buf = (u32 *)(chip->rb.area + 2048);
azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr);
- azx_writel(chip, RIRBUBASE, upper_32bit(chip->rirb.addr));
+ azx_writel(chip, RIRBUBASE, upper_32_bits(chip->rirb.addr));
/* set the rirb size to 256 entries (ULI requires explicitly) */
azx_writeb(chip, RIRBSIZE, 0x02);
@@ -847,7 +856,7 @@ static void azx_init_chip(struct azx *chip)
/* program the position buffer */
azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr);
- azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr));
+ azx_writel(chip, DPUBASE, upper_32_bits(chip->posbuf.addr));
chip->initialized = 1;
}
@@ -908,6 +917,8 @@ static void azx_init_pci(struct azx *chip)
}
+static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev);
+
/*
* interrupt handler
*/
@@ -930,11 +941,23 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
azx_dev = &chip->azx_dev[i];
if (status & azx_dev->sd_int_sta_mask) {
azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);
- if (azx_dev->substream && azx_dev->running) {
- azx_dev->period_intr++;
+ if (!azx_dev->substream || !azx_dev->running)
+ continue;
+ /* ignore the first dummy IRQ (due to pos_adj) */
+ if (azx_dev->irq_ignore) {
+ azx_dev->irq_ignore = 0;
+ continue;
+ }
+ /* check whether this IRQ is really acceptable */
+ if (azx_position_ok(chip, azx_dev)) {
+ azx_dev->irq_pending = 0;
spin_unlock(&chip->reg_lock);
snd_pcm_period_elapsed(azx_dev->substream);
spin_lock(&chip->reg_lock);
+ } else {
+ /* bogus IRQ, process it later */
+ azx_dev->irq_pending = 1;
+ schedule_work(&chip->irq_pending_work);
}
}
}
@@ -959,59 +982,107 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
/*
+ * set up a BDL entry
+ */
+static int setup_bdle(struct snd_pcm_substream *substream,
+ struct azx_dev *azx_dev, u32 **bdlp,
+ int ofs, int size, int with_ioc)
+{
+ struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
+ u32 *bdl = *bdlp;
+
+ while (size > 0) {
+ dma_addr_t addr;
+ int chunk;
+
+ if (azx_dev->frags >= AZX_MAX_BDL_ENTRIES)
+ return -EINVAL;
+
+ addr = snd_pcm_sgbuf_get_addr(sgbuf, ofs);
+ /* program the address field of the BDL entry */
+ bdl[0] = cpu_to_le32((u32)addr);
+ bdl[1] = cpu_to_le32(upper_32_bits(addr));
+ /* program the size field of the BDL entry */
+ chunk = PAGE_SIZE - (ofs % PAGE_SIZE);
+ if (size < chunk)
+ chunk = size;
+ bdl[2] = cpu_to_le32(chunk);
+ /* program the IOC to enable interrupt
+ * only when the whole fragment is processed
+ */
+ size -= chunk;
+ bdl[3] = (size || !with_ioc) ? 0 : cpu_to_le32(0x01);
+ bdl += 4;
+ azx_dev->frags++;
+ ofs += chunk;
+ }
+ *bdlp = bdl;
+ return ofs;
+}
+
+/*
* set up BDL entries
*/
-static int azx_setup_periods(struct snd_pcm_substream *substream,
+static int azx_setup_periods(struct azx *chip,
+ struct snd_pcm_substream *substream,
struct azx_dev *azx_dev)
{
- struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
u32 *bdl;
int i, ofs, periods, period_bytes;
+ int pos_adj;
/* reset BDL address */
azx_sd_writel(azx_dev, SD_BDLPL, 0);
azx_sd_writel(azx_dev, SD_BDLPU, 0);
period_bytes = snd_pcm_lib_period_bytes(substream);
+ azx_dev->period_bytes = period_bytes;
periods = azx_dev->bufsize / period_bytes;
/* program the initial BDL entries */
bdl = (u32 *)azx_dev->bdl.area;
ofs = 0;
azx_dev->frags = 0;
- for (i = 0; i < periods; i++) {
- int size, rest;
- if (i >= AZX_MAX_BDL_ENTRIES) {
- snd_printk(KERN_ERR "Too many BDL entries: "
- "buffer=%d, period=%d\n",
- azx_dev->bufsize, period_bytes);
- /* reset */
- azx_sd_writel(azx_dev, SD_BDLPL, 0);
- azx_sd_writel(azx_dev, SD_BDLPU, 0);
- return -EINVAL;
+ azx_dev->irq_ignore = 0;
+ pos_adj = bdl_pos_adj[chip->dev_index];
+ if (pos_adj > 0) {
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ pos_adj = (pos_adj * runtime->rate + 47999) / 48000;
+ if (!pos_adj)
+ pos_adj = 1;
+ pos_adj = frames_to_bytes(runtime, pos_adj);
+ if (pos_adj >= period_bytes) {
+ snd_printk(KERN_WARNING "Too big adjustment %d\n",
+ bdl_pos_adj[chip->dev_index]);
+ pos_adj = 0;
+ } else {
+ ofs = setup_bdle(substream, azx_dev,
+ &bdl, ofs, pos_adj, 1);
+ if (ofs < 0)
+ goto error;
+ azx_dev->irq_ignore = 1;
}
- rest = period_bytes;
- do {
- dma_addr_t addr = snd_pcm_sgbuf_get_addr(sgbuf, ofs);
- /* program the address field of the BDL entry */
- bdl[0] = cpu_to_le32((u32)addr);
- bdl[1] = cpu_to_le32(upper_32bit(addr));
- /* program the size field of the BDL entry */
- size = PAGE_SIZE - (ofs % PAGE_SIZE);
- if (rest < size)
- size = rest;
- bdl[2] = cpu_to_le32(size);
- /* program the IOC to enable interrupt
- * only when the whole fragment is processed
- */
- rest -= size;
- bdl[3] = rest ? 0 : cpu_to_le32(0x01);
- bdl += 4;
- azx_dev->frags++;
- ofs += size;
- } while (rest > 0);
+ } else
+ pos_adj = 0;
+ for (i = 0; i < periods; i++) {
+ if (i == periods - 1 && pos_adj)
+ ofs = setup_bdle(substream, azx_dev, &bdl, ofs,
+ period_bytes - pos_adj, 0);
+ else
+ ofs = setup_bdle(substream, azx_dev, &bdl, ofs,
+ period_bytes, 1);
+ if (ofs < 0)
+ goto error;
}
return 0;
+
+ error:
+ snd_printk(KERN_ERR "Too many BDL entries: buffer=%d, period=%d\n",
+ azx_dev->bufsize, period_bytes);
+ /* reset */
+ azx_sd_writel(azx_dev, SD_BDLPL, 0);
+ azx_sd_writel(azx_dev, SD_BDLPU, 0);
+ return -EINVAL;
}
/*
@@ -1062,7 +1133,7 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
/* lower BDL address */
azx_sd_writel(azx_dev, SD_BDLPL, (u32)azx_dev->bdl.addr);
/* upper BDL address */
- azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl.addr));
+ azx_sd_writel(azx_dev, SD_BDLPU, upper_32_bits(azx_dev->bdl.addr));
/* enable the position buffer */
if (chip->position_fix == POS_FIX_POSBUF ||
@@ -1085,7 +1156,7 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
*/
static unsigned int azx_max_codecs[] __devinitdata = {
- [AZX_DRIVER_ICH] = 3,
+ [AZX_DRIVER_ICH] = 4, /* Some ICH9 boards use SD3 */
[AZX_DRIVER_SCH] = 3,
[AZX_DRIVER_ATI] = 4,
[AZX_DRIVER_ATIHDMI] = 4,
@@ -1093,6 +1164,7 @@ static unsigned int azx_max_codecs[] __devinitdata = {
[AZX_DRIVER_SIS] = 3, /* FIXME: correct? */
[AZX_DRIVER_ULI] = 3, /* FIXME: correct? */
[AZX_DRIVER_NVIDIA] = 3, /* FIXME: correct? */
+ [AZX_DRIVER_TERA] = 1,
};
static int __devinit azx_codec_create(struct azx *chip, const char *model,
@@ -1316,7 +1388,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
snd_printdd("azx_pcm_prepare: bufsize=0x%x, format=0x%x\n",
azx_dev->bufsize, azx_dev->format_val);
- if (azx_setup_periods(substream, azx_dev) < 0)
+ if (azx_setup_periods(chip, substream, azx_dev) < 0)
return -EINVAL;
azx_setup_controller(chip, azx_dev);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -1421,35 +1493,113 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
return 0;
}
-static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream)
+static unsigned int azx_get_position(struct azx *chip,
+ struct azx_dev *azx_dev)
{
- struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
- struct azx *chip = apcm->chip;
- struct azx_dev *azx_dev = get_azx_dev(substream);
unsigned int pos;
if (chip->position_fix == POS_FIX_POSBUF ||
chip->position_fix == POS_FIX_AUTO) {
/* use the position buffer */
pos = le32_to_cpu(*azx_dev->posbuf);
- if (chip->position_fix == POS_FIX_AUTO &&
- azx_dev->period_intr == 1 && !pos) {
- printk(KERN_WARNING
- "hda-intel: Invalid position buffer, "
- "using LPIB read method instead.\n");
- chip->position_fix = POS_FIX_NONE;
- goto read_lpib;
- }
} else {
- read_lpib:
/* read LPIB */
pos = azx_sd_readl(azx_dev, SD_LPIB);
- if (chip->position_fix == POS_FIX_FIFO)
- pos += azx_dev->fifo_size;
}
if (pos >= azx_dev->bufsize)
pos = 0;
- return bytes_to_frames(substream->runtime, pos);
+ return pos;
+}
+
+static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream)
+{
+ struct azx_pcm *apcm = snd_pcm_substream_chip(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));
+}
+
+/*
+ * Check whether the current DMA position is acceptable for updating
+ * periods. Returns non-zero if it's OK.
+ *
+ * Many HD-audio controllers appear pretty inaccurate about
+ * the update-IRQ timing. The IRQ is issued before actually the
+ * data is processed. So, we need to process it afterwords in a
+ * workqueue.
+ */
+static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
+{
+ unsigned int pos;
+
+ pos = azx_get_position(chip, azx_dev);
+ if (chip->position_fix == POS_FIX_AUTO) {
+ if (!pos) {
+ printk(KERN_WARNING
+ "hda-intel: Invalid position buffer, "
+ "using LPIB read method instead.\n");
+ chip->position_fix = POS_FIX_LPIB;
+ pos = azx_get_position(chip, azx_dev);
+ } else
+ chip->position_fix = POS_FIX_POSBUF;
+ }
+
+ if (pos % azx_dev->period_bytes > azx_dev->period_bytes / 2)
+ return 0; /* NG - it's below the period boundary */
+ return 1; /* OK, it's fine */
+}
+
+/*
+ * The work for pending PCM period updates.
+ */
+static void azx_irq_pending_work(struct work_struct *work)
+{
+ struct azx *chip = container_of(work, struct azx, irq_pending_work);
+ int i, pending;
+
+ if (!chip->irq_pending_warned) {
+ printk(KERN_WARNING
+ "hda-intel: IRQ timing workaround is activated "
+ "for card #%d. Suggest a bigger bdl_pos_adj.\n",
+ chip->card->number);
+ chip->irq_pending_warned = 1;
+ }
+
+ for (;;) {
+ pending = 0;
+ spin_lock_irq(&chip->reg_lock);
+ for (i = 0; i < chip->num_streams; i++) {
+ struct azx_dev *azx_dev = &chip->azx_dev[i];
+ if (!azx_dev->irq_pending ||
+ !azx_dev->substream ||
+ !azx_dev->running)
+ continue;
+ if (azx_position_ok(chip, azx_dev)) {
+ azx_dev->irq_pending = 0;
+ spin_unlock(&chip->reg_lock);
+ snd_pcm_period_elapsed(azx_dev->substream);
+ spin_lock(&chip->reg_lock);
+ } else
+ pending++;
+ }
+ spin_unlock_irq(&chip->reg_lock);
+ if (!pending)
+ return;
+ cond_resched();
+ }
+}
+
+/* clear irq_pending flags and assure no on-going workq */
+static void azx_clear_irq_pending(struct azx *chip)
+{
+ int i;
+
+ spin_lock_irq(&chip->reg_lock);
+ for (i = 0; i < chip->num_streams; i++)
+ chip->azx_dev[i].irq_pending = 0;
+ spin_unlock_irq(&chip->reg_lock);
+ flush_scheduled_work();
}
static struct snd_pcm_ops azx_pcm_ops = {
@@ -1676,6 +1826,7 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state)
int i;
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+ azx_clear_irq_pending(chip);
for (i = 0; i < AZX_MAX_PCMS; i++)
snd_pcm_suspend_all(chip->pcm[i]);
if (chip->initialized)
@@ -1732,6 +1883,7 @@ static int azx_free(struct azx *chip)
int i;
if (chip->initialized) {
+ azx_clear_irq_pending(chip);
for (i = 0; i < chip->num_streams; i++)
azx_stream_stop(chip, &chip->azx_dev[i]);
azx_stop_chip(chip);
@@ -1770,9 +1922,9 @@ 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(0x1028, 0x01cc, "Dell D820", POS_FIX_NONE),
- SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_NONE),
- SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_NONE),
+ SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB),
+ SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB),
+ SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB),
{}
};
@@ -1857,12 +2009,25 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
chip->irq = -1;
chip->driver_type = driver_type;
chip->msi = enable_msi;
+ chip->dev_index = dev;
+ INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work);
chip->position_fix = check_position_fix(chip, position_fix[dev]);
check_probe_mask(chip, dev);
chip->single_cmd = single_cmd;
+ if (bdl_pos_adj[dev] < 0) {
+ switch (chip->driver_type) {
+ case AZX_DRIVER_ICH:
+ bdl_pos_adj[dev] = 1;
+ break;
+ default:
+ bdl_pos_adj[dev] = 32;
+ break;
+ }
+ }
+
#if BITS_PER_LONG != 64
/* Fix up base address on ULI M5461 */
if (chip->driver_type == AZX_DRIVER_ULI) {
@@ -2089,6 +2254,7 @@ static struct pci_device_id azx_ids[] = {
{ PCI_DEVICE(0x8086, 0x27d8), .driver_data = AZX_DRIVER_ICH },
{ PCI_DEVICE(0x8086, 0x269a), .driver_data = AZX_DRIVER_ICH },
{ PCI_DEVICE(0x8086, 0x284b), .driver_data = AZX_DRIVER_ICH },
+ { PCI_DEVICE(0x8086, 0x2911), .driver_data = AZX_DRIVER_ICH },
{ PCI_DEVICE(0x8086, 0x293e), .driver_data = AZX_DRIVER_ICH },
{ PCI_DEVICE(0x8086, 0x293f), .driver_data = AZX_DRIVER_ICH },
{ PCI_DEVICE(0x8086, 0x3a3e), .driver_data = AZX_DRIVER_ICH },
@@ -2141,6 +2307,8 @@ static struct pci_device_id azx_ids[] = {
{ PCI_DEVICE(0x10de, 0x0bd5), .driver_data = AZX_DRIVER_NVIDIA },
{ PCI_DEVICE(0x10de, 0x0bd6), .driver_data = AZX_DRIVER_NVIDIA },
{ PCI_DEVICE(0x10de, 0x0bd7), .driver_data = AZX_DRIVER_NVIDIA },
+ /* Teradici */
+ { PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, azx_ids);
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index 5633f77f8f3..1e5aff5c48d 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -366,8 +366,6 @@ static void print_digital_conv(struct snd_info_buffer *buffer,
{
unsigned int digi1 = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_DIGI_CONVERT_1, 0);
- unsigned int digi2 = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_DIGI_CONVERT_2, 0);
snd_iprintf(buffer, " Digital:");
if (digi1 & AC_DIG1_ENABLE)
snd_iprintf(buffer, " Enabled");
@@ -386,7 +384,8 @@ static void print_digital_conv(struct snd_info_buffer *buffer,
if (digi1 & AC_DIG1_LEVEL)
snd_iprintf(buffer, " GenLevel");
snd_iprintf(buffer, "\n");
- snd_iprintf(buffer, " Digital category: 0x%x\n", digi2 & AC_DIG2_CC);
+ snd_iprintf(buffer, " Digital category: 0x%x\n",
+ (digi1 >> 8) & AC_DIG2_CC);
}
static const char *get_pwr_state(u32 state)
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index a99e86d7427..e8003d99f0b 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -23,7 +23,6 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/pci.h>
-#include <linux/mutex.h>
#include <sound/core.h>
#include "hda_codec.h"
@@ -64,7 +63,6 @@ struct ad198x_spec {
/* PCM information */
struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
- struct mutex amp_mutex; /* PCM volume/mute control mutex */
unsigned int spdif_route;
/* dynamic controls, init_verbs and input_mux */
@@ -1618,6 +1616,7 @@ static const char *ad1981_models[AD1981_MODELS] = {
static struct snd_pci_quirk ad1981_cfg_tbl[] = {
SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD),
+ SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD),
/* All HP models */
SND_PCI_QUIRK(0x103c, 0, "HP nx", AD1981_HP),
SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA),
@@ -2623,7 +2622,7 @@ static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
{
struct ad198x_spec *spec = codec->spec;
hda_nid_t nid;
- int idx, err;
+ int i, idx, err;
char name[32];
if (! pin)
@@ -2631,16 +2630,26 @@ static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
idx = ad1988_pin_idx(pin);
nid = ad1988_idx_to_dac(codec, idx);
- /* 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 */
- sprintf(name, "%s Playback Volume", pfx);
- if ((err = add_control(spec, AD_CTL_WIDGET_VOL, name,
- HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
- return err;
+ /* check whether the corresponding DAC was already taken */
+ for (i = 0; i < spec->autocfg.line_outs; i++) {
+ hda_nid_t pin = spec->autocfg.line_out_pins[i];
+ hda_nid_t dac = ad1988_idx_to_dac(codec, ad1988_pin_idx(pin));
+ if (dac == nid)
+ break;
+ }
+ if (i >= spec->autocfg.line_outs) {
+ /* 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 */
+ sprintf(name, "%s Playback Volume", pfx);
+ err = add_control(spec, AD_CTL_WIDGET_VOL, name,
+ HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ }
nid = ad1988_mixer_nids[idx];
sprintf(name, "%s Playback Switch", pfx);
if ((err = add_control(spec, AD_CTL_BIND_MUTE, name,
@@ -3177,7 +3186,6 @@ static int patch_ad1884(struct hda_codec *codec)
if (spec == NULL)
return -ENOMEM;
- mutex_init(&spec->amp_mutex);
codec->spec = spec;
spec->multiout.max_channels = 2;
@@ -3847,7 +3855,6 @@ static int patch_ad1884a(struct hda_codec *codec)
if (spec == NULL)
return -ENOMEM;
- mutex_init(&spec->amp_mutex);
codec->spec = spec;
spec->multiout.max_channels = 2;
@@ -4152,7 +4159,6 @@ static int patch_ad1882(struct hda_codec *codec)
if (spec == NULL)
return -ENOMEM;
- mutex_init(&spec->amp_mutex);
codec->spec = spec;
spec->multiout.max_channels = 6;
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 36fd8526003..7c1eb23f0ce 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -82,7 +82,6 @@ struct conexant_spec {
/* PCM information */
struct hda_pcm pcm_rec[2]; /* used in build_pcms() */
- struct mutex amp_mutex; /* PCM volume/mute control mutex */
unsigned int spdif_route;
/* dynamic controls, init_verbs and input_mux */
@@ -687,7 +686,7 @@ static struct snd_kcontrol_new cxt5045_mixers_hp530[] = {
static struct hda_verb cxt5045_init_verbs[] = {
/* Line in, Mic */
- {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
/* HP, Amp */
{0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
@@ -907,10 +906,12 @@ static struct snd_pci_quirk cxt5045_cfg_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV9533EG", CXT5045_LAPTOP_HPSENSE),
SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HP530),
SND_PCI_QUIRK(0x103c, 0x30d9, "HP Spartan", 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),
SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP_HPMICSENSE),
- SND_PCI_QUIRK(0x1734, 0x110e, "Fujitsu V5505", CXT5045_LAPTOP_HPSENSE),
+ SND_PCI_QUIRK(0x1734, 0x110e, "Fujitsu V5505",
+ CXT5045_LAPTOP_HPMICSENSE),
SND_PCI_QUIRK(0x1509, 0x1e40, "FIC", CXT5045_LAPTOP_HPMICSENSE),
SND_PCI_QUIRK(0x1509, 0x2f05, "FIC", CXT5045_LAPTOP_HPMICSENSE),
SND_PCI_QUIRK(0x1509, 0x2f06, "FIC", CXT5045_LAPTOP_HPMICSENSE),
@@ -928,7 +929,6 @@ static int patch_cxt5045(struct hda_codec *codec)
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (!spec)
return -ENOMEM;
- mutex_init(&spec->amp_mutex);
codec->spec = spec;
spec->multiout.max_channels = 2;
@@ -963,6 +963,7 @@ static int patch_cxt5045(struct hda_codec *codec)
codec->patch_ops.init = cxt5045_init;
break;
case CXT5045_LAPTOP_MICSENSE:
+ codec->patch_ops.unsol_event = cxt5045_hp_unsol_event;
spec->input_mux = &cxt5045_capture_source;
spec->num_init_verbs = 2;
spec->init_verbs[1] = cxt5045_mic_sense_init_verbs;
@@ -1007,15 +1008,19 @@ static int patch_cxt5045(struct hda_codec *codec)
#endif
}
- /*
- * Fix max PCM level to 0 dB
- * (originall it has 0x2b steps with 0dB offset 0x14)
- */
- snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT,
- (0x14 << AC_AMPCAP_OFFSET_SHIFT) |
- (0x14 << AC_AMPCAP_NUM_STEPS_SHIFT) |
- (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
- (1 << AC_AMPCAP_MUTE_SHIFT));
+ switch (codec->subsystem_id >> 16) {
+ case 0x103c:
+ /* HP laptop has a really bad sound over 0dB on NID 0x17.
+ * Fix max PCM level to 0 dB
+ * (originall it has 0x2b steps with 0dB offset 0x14)
+ */
+ snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT,
+ (0x14 << AC_AMPCAP_OFFSET_SHIFT) |
+ (0x14 << AC_AMPCAP_NUM_STEPS_SHIFT) |
+ (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+ (1 << AC_AMPCAP_MUTE_SHIFT));
+ break;
+ }
return 0;
}
@@ -1477,7 +1482,6 @@ static int patch_cxt5047(struct hda_codec *codec)
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (!spec)
return -ENOMEM;
- mutex_init(&spec->amp_mutex);
codec->spec = spec;
spec->multiout.max_channels = 2;
@@ -1736,7 +1740,6 @@ static int patch_cxt5051(struct hda_codec *codec)
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (!spec)
return -ENOMEM;
- mutex_init(&spec->amp_mutex);
codec->spec = spec;
codec->patch_ops = conexant_patch_ops;
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index b0a2a262ece..2807bc840d2 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -163,6 +163,10 @@ enum {
ALC662_LENOVO_101E,
ALC662_ASUS_EEEPC_P701,
ALC662_ASUS_EEEPC_EP20,
+ ALC663_ASUS_M51VA,
+ ALC663_ASUS_G71V,
+ ALC663_ASUS_H13,
+ ALC663_ASUS_G50V,
ALC662_AUTO,
ALC662_MODEL_LAST,
};
@@ -205,6 +209,7 @@ enum {
ALC883_MITAC,
ALC883_CLEVO_M720,
ALC883_FUJITSU_PI2515,
+ ALC883_3ST_6ch_INTEL,
ALC883_AUTO,
ALC883_MODEL_LAST,
};
@@ -280,6 +285,10 @@ struct alc_spec {
#ifdef CONFIG_SND_HDA_POWER_SAVE
struct hda_loopback_check loopback;
#endif
+
+ /* for PLL fix */
+ hda_nid_t pll_nid;
+ unsigned int pll_coef_idx, pll_coef_bit;
};
/*
@@ -747,6 +756,38 @@ static struct hda_verb alc_gpio3_init_verbs[] = {
{ }
};
+/*
+ * Fix hardware PLL issue
+ * On some codecs, the analog PLL gating control must be off while
+ * the default value is 1.
+ */
+static void alc_fix_pll(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ unsigned int val;
+
+ if (!spec->pll_nid)
+ return;
+ snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
+ spec->pll_coef_idx);
+ val = snd_hda_codec_read(codec, spec->pll_nid, 0,
+ AC_VERB_GET_PROC_COEF, 0);
+ 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,
+ val & ~(1 << spec->pll_coef_bit));
+}
+
+static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
+ unsigned int coef_idx, unsigned int coef_bit)
+{
+ struct alc_spec *spec = codec->spec;
+ spec->pll_nid = nid;
+ spec->pll_coef_idx = coef_idx;
+ spec->pll_coef_bit = coef_bit;
+ alc_fix_pll(codec);
+}
+
static void alc_sku_automute(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
@@ -776,6 +817,24 @@ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
alc_sku_automute(codec);
}
+/* additional initialization for ALC888 variants */
+static void alc888_coef_init(struct hda_codec *codec)
+{
+ unsigned int tmp;
+
+ snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
+ tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
+ snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
+ if ((tmp & 0xf0) == 2)
+ /* alc888S-VC */
+ snd_hda_codec_read(codec, 0x20, 0,
+ AC_VERB_SET_PROC_COEF, 0x830);
+ else
+ /* alc888-VB */
+ snd_hda_codec_read(codec, 0x20, 0,
+ AC_VERB_SET_PROC_COEF, 0x3030);
+}
+
/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
* 31 ~ 16 : Manufacture ID
* 15 ~ 8 : SKU ID
@@ -851,8 +910,10 @@ do_sku:
case 0x10ec0267:
case 0x10ec0268:
case 0x10ec0269:
+ case 0x10ec0660:
+ case 0x10ec0662:
+ case 0x10ec0663:
case 0x10ec0862:
- case 0x10ec0662:
case 0x10ec0889:
snd_hda_codec_write(codec, 0x14, 0,
AC_VERB_SET_EAPD_BTLENABLE, 2);
@@ -877,7 +938,6 @@ do_sku:
case 0x10ec0882:
case 0x10ec0883:
case 0x10ec0885:
- case 0x10ec0888:
case 0x10ec0889:
snd_hda_codec_write(codec, 0x20, 0,
AC_VERB_SET_COEF_INDEX, 7);
@@ -889,6 +949,9 @@ do_sku:
AC_VERB_SET_PROC_COEF,
tmp | 0x2010);
break;
+ case 0x10ec0888:
+ alc888_coef_init(codec);
+ break;
case 0x10ec0267:
case 0x10ec0268:
snd_hda_codec_write(codec, 0x20, 0,
@@ -2373,6 +2436,8 @@ static int alc_init(struct hda_codec *codec)
struct alc_spec *spec = codec->spec;
unsigned int i;
+ alc_fix_pll(codec);
+
for (i = 0; i < spec->num_init_verbs; i++)
snd_hda_sequence_write(codec, spec->init_verbs[i]);
@@ -3009,6 +3074,7 @@ static struct snd_pci_quirk alc880_cfg_tbl[] = {
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", ALC880_UNIWILL),
SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
@@ -5101,7 +5167,7 @@ static struct snd_pci_quirk alc260_cfg_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013),
SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
- SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP),
+ SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_3013),
SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
@@ -6127,6 +6193,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
+ SND_PCI_QUIRK(0x106b, 0x00a0, "Apple iMac 24''", ALC885_IMAC24),
SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
@@ -6353,7 +6420,9 @@ static void alc882_auto_init_analog_input(struct hda_codec *codec)
continue;
vref = PIN_IN;
if (1 /*i <= AUTO_PIN_FRONT_MIC*/) {
- if (snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP) &
+ unsigned int pincap;
+ pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
+ if ((pincap >> AC_PINCAP_VREF_SHIFT) &
AC_PINCAP_VREF_80)
vref = PIN_VREF80;
}
@@ -6450,8 +6519,9 @@ static int patch_alc882(struct hda_codec *codec)
case 0x106b1000: /* iMac 24 */
board_config = ALC885_IMAC24;
break;
- case 0x106b00a1: /* Macbook */
+ case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */
case 0x106b2c00: /* Macbook Pro rev3 */
+ case 0x106b3600: /* Macbook 3.1 */
board_config = ALC885_MBP3;
break;
default:
@@ -6485,14 +6555,20 @@ static int patch_alc882(struct hda_codec *codec)
if (board_config != ALC882_AUTO)
setup_preset(spec, &alc882_presets[board_config]);
- spec->stream_name_analog = "ALC882 Analog";
+ if (codec->vendor_id == 0x10ec0885) {
+ spec->stream_name_analog = "ALC885 Analog";
+ spec->stream_name_digital = "ALC885 Digital";
+ } else {
+ spec->stream_name_analog = "ALC882 Analog";
+ spec->stream_name_digital = "ALC882 Digital";
+ }
+
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_name_digital = "ALC882 Digital";
spec->stream_digital_playback = &alc882_pcm_digital_playback;
spec->stream_digital_capture = &alc882_pcm_digital_capture;
@@ -6569,6 +6645,16 @@ static struct hda_input_mux alc883_capture_source = {
},
};
+static struct hda_input_mux alc883_3stack_6ch_intel = {
+ .num_items = 4,
+ .items = {
+ { "Mic", 0x1 },
+ { "Front Mic", 0x0 },
+ { "Line", 0x2 },
+ { "CD", 0x4 },
+ },
+};
+
static struct hda_input_mux alc883_lenovo_101e_capture_source = {
.num_items = 2,
.items = {
@@ -6650,6 +6736,48 @@ static struct hda_channel_mode alc883_3ST_6ch_modes[3] = {
};
/*
+ * 2ch mode
+ */
+static 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 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 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 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 },
+};
+
+/*
* 6ch mode
*/
static struct hda_verb alc883_sixstack_ch6_init[] = {
@@ -6881,15 +7009,54 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
{ } /* end */
};
+static 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", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+ HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+ HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ /* .name = "Capture Source", */
+ .name = "Input Source",
+ .count = 2,
+ .info = alc883_mux_enum_info,
+ .get = alc883_mux_enum_get,
+ .put = alc883_mux_enum_put,
+ },
+ { } /* end */
+};
+
static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 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_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 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),
@@ -7729,6 +7896,7 @@ static const char *alc883_models[ALC883_MODEL_LAST] = {
[ALC883_MITAC] = "mitac",
[ALC883_CLEVO_M720] = "clevo-m720",
[ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
+ [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel",
[ALC883_AUTO] = "auto",
};
@@ -7786,6 +7954,8 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
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, 0xd601, "D102GGC", ALC883_3ST_6ch),
{}
};
@@ -7824,6 +7994,18 @@ static struct alc_config_preset alc883_presets[] = {
.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,
+ .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,
+ },
[ALC883_6ST_DIG] = {
.mixers = { alc883_base_mixer, alc883_chmode_mixer },
.init_verbs = { alc883_init_verbs },
@@ -8145,6 +8327,8 @@ static int patch_alc883(struct hda_codec *codec)
codec->spec = spec;
+ alc_fix_pll_init(codec, 0x20, 0x0a, 10);
+
board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST,
alc883_models,
alc883_cfg_tbl);
@@ -8171,12 +8355,25 @@ static int patch_alc883(struct hda_codec *codec)
if (board_config != ALC883_AUTO)
setup_preset(spec, &alc883_presets[board_config]);
- spec->stream_name_analog = "ALC883 Analog";
+ switch (codec->vendor_id) {
+ case 0x10ec0888:
+ spec->stream_name_analog = "ALC888 Analog";
+ spec->stream_name_digital = "ALC888 Digital";
+ break;
+ case 0x10ec0889:
+ spec->stream_name_analog = "ALC889 Analog";
+ spec->stream_name_digital = "ALC889 Digital";
+ break;
+ default:
+ spec->stream_name_analog = "ALC883 Analog";
+ spec->stream_name_digital = "ALC883 Digital";
+ break;
+ }
+
spec->stream_analog_playback = &alc883_pcm_analog_playback;
spec->stream_analog_capture = &alc883_pcm_analog_capture;
spec->stream_analog_alt_capture = &alc883_pcm_analog_alt_capture;
- spec->stream_name_digital = "ALC883 Digital";
spec->stream_digital_playback = &alc883_pcm_digital_playback;
spec->stream_digital_capture = &alc883_pcm_digital_capture;
@@ -8189,6 +8386,9 @@ static int patch_alc883(struct hda_codec *codec)
codec->patch_ops = alc_patch_ops;
if (board_config == ALC883_AUTO)
spec->init_hook = alc883_auto_init;
+ else if (codec->vendor_id == 0x10ec0888)
+ spec->init_hook = alc888_coef_init;
+
#ifdef CONFIG_SND_HDA_POWER_SAVE
if (!spec->loopback.amplist)
spec->loopback.amplist = alc883_loopbacks;
@@ -9522,6 +9722,8 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = {
SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD),
SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD),
+ SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
+ ALC262_SONY_ASSAMD),
SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA),
@@ -9729,6 +9931,8 @@ static int patch_alc262(struct hda_codec *codec)
}
#endif
+ alc_fix_pll_init(codec, 0x20, 0x0a, 10);
+
board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
alc262_models,
alc262_cfg_tbl);
@@ -10674,12 +10878,18 @@ static int patch_alc268(struct hda_codec *codec)
if (board_config != ALC268_AUTO)
setup_preset(spec, &alc268_presets[board_config]);
- spec->stream_name_analog = "ALC268 Analog";
+ if (codec->vendor_id == 0x10ec0267) {
+ spec->stream_name_analog = "ALC267 Analog";
+ spec->stream_name_digital = "ALC267 Digital";
+ } else {
+ spec->stream_name_analog = "ALC268 Analog";
+ spec->stream_name_digital = "ALC268 Digital";
+ }
+
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_name_digital = "ALC268 Digital";
spec->stream_digital_playback = &alc268_pcm_digital_playback;
if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
@@ -11033,6 +11243,8 @@ static int patch_alc269(struct hda_codec *codec)
codec->spec = spec;
+ alc_fix_pll_init(codec, 0x20, 0x04, 15);
+
board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
alc269_models,
alc269_cfg_tbl);
@@ -12631,6 +12843,12 @@ static struct hda_verb alc861vd_eapd_verbs[] = {
{ }
};
+static struct hda_verb alc660vd_eapd_verbs[] = {
+ {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
+ {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
+ { }
+};
+
static 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)},
@@ -12786,6 +13004,7 @@ static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO),
SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO),
+ SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 N200", ALC861VD_LENOVO),
SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
{}
};
@@ -13168,11 +13387,19 @@ static int patch_alc861vd(struct hda_codec *codec)
if (board_config != ALC861VD_AUTO)
setup_preset(spec, &alc861vd_presets[board_config]);
- spec->stream_name_analog = "ALC861VD Analog";
+ if (codec->vendor_id == 0x10ec0660) {
+ spec->stream_name_analog = "ALC660-VD Analog";
+ spec->stream_name_digital = "ALC660-VD Digital";
+ /* always turn on EAPD */
+ spec->init_verbs[spec->num_init_verbs++] = alc660vd_eapd_verbs;
+ } else {
+ spec->stream_name_analog = "ALC861VD Analog";
+ spec->stream_name_digital = "ALC861VD Digital";
+ }
+
spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
- spec->stream_name_digital = "ALC861VD Digital";
spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
@@ -13251,6 +13478,23 @@ static struct hda_input_mux alc662_eeepc_capture_source = {
},
};
+static struct hda_input_mux alc663_capture_source = {
+ .num_items = 3,
+ .items = {
+ { "Mic", 0x0 },
+ { "Front Mic", 0x1 },
+ { "Line", 0x2 },
+ },
+};
+
+static struct hda_input_mux alc663_m51va_capture_source = {
+ .num_items = 2,
+ .items = {
+ { "Ext-Mic", 0x0 },
+ { "D-Mic", 0x9 },
+ },
+};
+
#define alc662_mux_enum_info alc_mux_enum_info
#define alc662_mux_enum_get alc_mux_enum_get
#define alc662_mux_enum_put alc882_mux_enum_put
@@ -13431,6 +13675,44 @@ static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
{ } /* end */
};
+static struct snd_kcontrol_new alc663_m51va_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_MUTE("DMic Playback Switch", 0x23, 0x9, HDA_INPUT),
+ { } /* end */
+};
+
+static 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("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+ { } /* end */
+};
+
+static 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("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_MUTE("i-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 struct snd_kcontrol_new alc662_chmode_mixer[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -13501,6 +13783,11 @@ static struct hda_verb alc662_init_verbs[] = {
{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+
+ /* always trun on EAPD */
+ {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
+ {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
+
{ }
};
@@ -13571,6 +13858,43 @@ static struct hda_verb alc662_auto_init_verbs[] = {
{ }
};
+static struct hda_verb alc663_m51va_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 */
+
+ {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 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 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},
+ {}
+};
+
/* capture mixer elements */
static struct snd_kcontrol_new alc662_capture_mixer[] = {
HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
@@ -13692,6 +14016,125 @@ static void alc662_eeepc_ep20_inithook(struct hda_codec *codec)
alc662_eeepc_ep20_automute(codec);
}
+static void alc663_m51va_speaker_automute(struct hda_codec *codec)
+{
+ unsigned int present;
+ unsigned char bits;
+
+ present = snd_hda_codec_read(codec, 0x21, 0,
+ AC_VERB_GET_PIN_SENSE, 0)
+ & AC_PINSENSE_PRESENCE;
+ bits = present ? HDA_AMP_MUTE : 0;
+ snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+ HDA_AMP_MUTE, bits);
+}
+
+static void alc663_m51va_mic_automute(struct hda_codec *codec)
+{
+ unsigned int present;
+
+ present = snd_hda_codec_read(codec, 0x18, 0,
+ AC_VERB_GET_PIN_SENSE, 0)
+ & AC_PINSENSE_PRESENCE;
+ snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+ 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
+ snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+ 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
+ snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+ 0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
+ snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+ 0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
+}
+
+static void alc663_m51va_unsol_event(struct hda_codec *codec,
+ unsigned int res)
+{
+ switch (res >> 26) {
+ case ALC880_HP_EVENT:
+ alc663_m51va_speaker_automute(codec);
+ break;
+ case ALC880_MIC_EVENT:
+ alc663_m51va_mic_automute(codec);
+ break;
+ }
+}
+
+static void alc663_m51va_inithook(struct hda_codec *codec)
+{
+ alc663_m51va_speaker_automute(codec);
+ alc663_m51va_mic_automute(codec);
+}
+
+static void alc663_g71v_hp_automute(struct hda_codec *codec)
+{
+ unsigned int present;
+ unsigned char bits;
+
+ present = snd_hda_codec_read(codec, 0x21, 0,
+ AC_VERB_GET_PIN_SENSE, 0)
+ & AC_PINSENSE_PRESENCE;
+ bits = present ? HDA_AMP_MUTE : 0;
+ snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
+ HDA_AMP_MUTE, bits);
+ snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+ HDA_AMP_MUTE, bits);
+}
+
+static void alc663_g71v_front_automute(struct hda_codec *codec)
+{
+ unsigned int present;
+ unsigned char bits;
+
+ present = snd_hda_codec_read(codec, 0x15, 0,
+ AC_VERB_GET_PIN_SENSE, 0)
+ & AC_PINSENSE_PRESENCE;
+ bits = present ? HDA_AMP_MUTE : 0;
+ snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+ HDA_AMP_MUTE, bits);
+}
+
+static void alc663_g71v_unsol_event(struct hda_codec *codec,
+ unsigned int res)
+{
+ switch (res >> 26) {
+ case ALC880_HP_EVENT:
+ alc663_g71v_hp_automute(codec);
+ break;
+ case ALC880_FRONT_EVENT:
+ alc663_g71v_front_automute(codec);
+ break;
+ case ALC880_MIC_EVENT:
+ alc662_eeepc_mic_automute(codec);
+ break;
+ }
+}
+
+static void alc663_g71v_inithook(struct hda_codec *codec)
+{
+ alc663_g71v_front_automute(codec);
+ alc663_g71v_hp_automute(codec);
+ alc662_eeepc_mic_automute(codec);
+}
+
+static void alc663_g50v_unsol_event(struct hda_codec *codec,
+ unsigned int res)
+{
+ switch (res >> 26) {
+ case ALC880_HP_EVENT:
+ alc663_m51va_speaker_automute(codec);
+ break;
+ case ALC880_MIC_EVENT:
+ alc662_eeepc_mic_automute(codec);
+ break;
+ }
+}
+
+static void alc663_g50v_inithook(struct hda_codec *codec)
+{
+ alc663_m51va_speaker_automute(codec);
+ alc662_eeepc_mic_automute(codec);
+}
+
#ifdef CONFIG_SND_HDA_POWER_SAVE
#define alc662_loopbacks alc880_loopbacks
#endif
@@ -13714,14 +14157,24 @@ static const char *alc662_models[ALC662_MODEL_LAST] = {
[ALC662_LENOVO_101E] = "lenovo-101e",
[ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
[ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
+ [ALC663_ASUS_M51VA] = "m51va",
+ [ALC663_ASUS_G71V] = "g71v",
+ [ALC663_ASUS_H13] = "h13",
+ [ALC663_ASUS_G50V] = "g50v",
[ALC662_AUTO] = "auto",
};
static struct snd_pci_quirk alc662_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS G71V", ALC663_ASUS_G71V),
+ SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
+ SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS M51VA", ALC663_ASUS_G50V),
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(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
+ SND_PCI_QUIRK(0x1854, 0x2000, "ASUS H13-2000", ALC663_ASUS_H13),
+ SND_PCI_QUIRK(0x1854, 0x2001, "ASUS H13-2001", ALC663_ASUS_H13),
+ SND_PCI_QUIRK(0x1854, 0x2002, "ASUS H13-2002", ALC663_ASUS_H13),
{}
};
@@ -13809,7 +14262,53 @@ static struct alc_config_preset alc662_presets[] = {
.unsol_event = alc662_eeepc_ep20_unsol_event,
.init_hook = alc662_eeepc_ep20_inithook,
},
-
+ [ALC663_ASUS_M51VA] = {
+ .mixers = { alc663_m51va_mixer, alc662_capture_mixer},
+ .init_verbs = { alc662_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,
+ .input_mux = &alc663_m51va_capture_source,
+ .unsol_event = alc663_m51va_unsol_event,
+ .init_hook = alc663_m51va_inithook,
+ },
+ [ALC663_ASUS_G71V] = {
+ .mixers = { alc663_g71v_mixer, alc662_capture_mixer},
+ .init_verbs = { alc662_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,
+ .input_mux = &alc662_eeepc_capture_source,
+ .unsol_event = alc663_g71v_unsol_event,
+ .init_hook = alc663_g71v_inithook,
+ },
+ [ALC663_ASUS_H13] = {
+ .mixers = { alc663_m51va_mixer, alc662_capture_mixer},
+ .init_verbs = { alc662_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,
+ .input_mux = &alc663_m51va_capture_source,
+ .unsol_event = alc663_m51va_unsol_event,
+ .init_hook = alc663_m51va_inithook,
+ },
+ [ALC663_ASUS_G50V] = {
+ .mixers = { alc663_g50v_mixer, alc662_capture_mixer},
+ .init_verbs = { alc662_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 = alc663_g50v_unsol_event,
+ .init_hook = alc663_g50v_inithook,
+ },
};
@@ -14082,6 +14581,8 @@ static int patch_alc662(struct hda_codec *codec)
codec->spec = spec;
+ alc_fix_pll_init(codec, 0x20, 0x04, 15);
+
board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
alc662_models,
alc662_cfg_tbl);
@@ -14108,11 +14609,17 @@ static int patch_alc662(struct hda_codec *codec)
if (board_config != ALC662_AUTO)
setup_preset(spec, &alc662_presets[board_config]);
- spec->stream_name_analog = "ALC662 Analog";
+ if (codec->vendor_id == 0x10ec0663) {
+ spec->stream_name_analog = "ALC663 Analog";
+ spec->stream_name_digital = "ALC663 Digital";
+ } else {
+ spec->stream_name_analog = "ALC662 Analog";
+ spec->stream_name_digital = "ALC662 Digital";
+ }
+
spec->stream_analog_playback = &alc662_pcm_analog_playback;
spec->stream_analog_capture = &alc662_pcm_analog_capture;
- spec->stream_name_digital = "ALC662 Digital";
spec->stream_digital_playback = &alc662_pcm_digital_playback;
spec->stream_digital_capture = &alc662_pcm_digital_capture;
@@ -14151,6 +14658,7 @@ struct hda_codec_preset snd_hda_preset_realtek[] = {
.patch = patch_alc883 },
{ .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
.patch = patch_alc662 },
+ { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
{ .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
{ .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
{ .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index a4f44a00bae..08cb77f5188 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -636,21 +636,28 @@ static struct hda_verb stac92hd71bxx_core_init[] = {
{ 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
};
+#define HD_DISABLE_PORTF 3
static struct hda_verb stac92hd71bxx_analog_core_init[] = {
+ /* start of config #1 */
+
+ /* connect port 0f to audio mixer */
+ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
+ { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
+ /* unmute right and left channels for node 0x0f */
+ { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ /* start of config #2 */
+
/* set master volume and direct control */
{ 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
/* connect headphone jack to dac1 */
{ 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
- /* connect ports 0d and 0f to audio mixer */
+ /* connect port 0d to audio mixer */
{ 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2},
- { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
- { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
/* unmute dac0 input in audio mixer */
{ 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
- /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
+ /* unmute right and left channels for nodes 0x0a, 0xd */
{ 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
{ 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
{}
};
@@ -818,6 +825,9 @@ static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("PC Beep Volume", 0x17, 0x2, HDA_INPUT),
+ HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT),
+
HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT),
HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT),
{ } /* end */
@@ -1317,13 +1327,13 @@ static unsigned int ref92hd71bxx_pin_configs[10] = {
0x90a000f0, 0x01452050,
};
-static unsigned int dell_m4_1_pin_configs[13] = {
+static unsigned int dell_m4_1_pin_configs[10] = {
0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110,
0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0,
0x40f000f0, 0x4f0000f0,
};
-static unsigned int dell_m4_2_pin_configs[13] = {
+static unsigned int dell_m4_2_pin_configs[10] = {
0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0,
0x40f000f0, 0x044413b0,
@@ -1754,12 +1764,8 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = {
"unknown Dell", STAC_9205_DELL_M42),
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
"Dell Precision", STAC_9205_DELL_M43),
- SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
- "Dell Precision", STAC_9205_DELL_M43),
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
"Dell Precision", STAC_9205_DELL_M43),
- SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
- "Dell Precision", STAC_9205_DELL_M43),
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
"Dell Precision", STAC_9205_DELL_M43),
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
@@ -1770,18 +1776,14 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = {
"Dell Precision", STAC_9205_DELL_M43),
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
"Dell Precision M4300", STAC_9205_DELL_M43),
- SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
- "Dell Precision", STAC_9205_DELL_M43),
- SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
- "Dell Inspiron", STAC_9205_DELL_M44),
- SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
- "Dell Inspiron", STAC_9205_DELL_M44),
- SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
- "Dell Inspiron", STAC_9205_DELL_M44),
- SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
- "Dell Inspiron", STAC_9205_DELL_M44),
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
"unknown Dell", STAC_9205_DELL_M42),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
+ "Dell Precision", STAC_9205_DELL_M43),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
+ "Dell Precision", STAC_9205_DELL_M43),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
+ "Dell Precision", STAC_9205_DELL_M43),
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
"Dell Inspiron", STAC_9205_DELL_M44),
SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
@@ -3103,13 +3105,16 @@ static int stac92xx_init(struct hda_codec *codec)
0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
int def_conf = snd_hda_codec_read(codec, spec->pwr_nids[i],
0, AC_VERB_GET_CONFIG_DEFAULT, 0);
+ def_conf = get_defcfg_connect(def_conf);
/* outputs are only ports capable of power management
* any attempts on powering down a input port cause the
* referenced VREF to act quirky.
*/
if (pinctl & AC_PINCTL_IN_EN)
continue;
- if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED)
+ /* skip any ports that don't have jacks since presence
+ * detection is useless */
+ if (def_conf && def_conf != AC_JACK_PORT_FIXED)
continue;
enable_pin_detect(codec, spec->pwr_nids[i], event | i);
codec->patch_ops.unsol_event(codec, (event | i) << 26);
@@ -3614,6 +3619,7 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
codec->spec = spec;
spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
+ spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
spec->pin_nids = stac92hd71bxx_pin_nids;
spec->board_config = snd_hda_check_board_config(codec,
STAC_92HD71BXX_MODELS,
@@ -3642,6 +3648,19 @@ again:
spec->mixer = stac92hd71bxx_mixer;
spec->init = stac92hd71bxx_core_init;
break;
+ case 0x111d7608: /* 5 Port with Analog Mixer */
+ /* no output amps */
+ spec->num_pwrs = 0;
+ spec->mixer = stac92hd71bxx_analog_mixer;
+
+ /* disable VSW */
+ spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF];
+ stac92xx_set_config_reg(codec, 0xf, 0x40f000f0);
+ break;
+ case 0x111d7603: /* 6 Port with Analog Mixer */
+ /* no output amps */
+ spec->num_pwrs = 0;
+ /* fallthru */
default:
spec->mixer = stac92hd71bxx_analog_mixer;
spec->init = stac92hd71bxx_analog_core_init;
@@ -3653,22 +3672,19 @@ again:
/* GPIO0 High = EAPD */
spec->gpio_mask = 0x01;
spec->gpio_dir = 0x01;
- spec->gpio_mask = 0x01;
spec->gpio_data = 0x01;
spec->mux_nids = stac92hd71bxx_mux_nids;
spec->adc_nids = stac92hd71bxx_adc_nids;
spec->dmic_nids = stac92hd71bxx_dmic_nids;
spec->dmux_nids = stac92hd71bxx_dmux_nids;
+ spec->pwr_nids = stac92hd71bxx_pwr_nids;
spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
- spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
- spec->pwr_nids = stac92hd71bxx_pwr_nids;
-
spec->multiout.num_dacs = 1;
spec->multiout.hp_nid = 0x11;
spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
@@ -4306,10 +4322,11 @@ struct hda_codec_preset snd_hda_preset_sigmatel[] = {
{ .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
{ .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
{ .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
+ { .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx},
+ { .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx},
{ .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
{ .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
{ .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
- { .id = 0x111d7608, .name = "92HD71BXX", .patch = patch_stac92hd71bxx },
{ .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
{ .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
{ .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },